diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a824900f4..8352de555 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,6 +16,20 @@ updates: - package-ecosystem: npm directory: "/frontend" versioning-strategy: increase + groups: + frontend-angular-dependencies: + patterns: + - "@angular*" + - "@ng-*" + - "ngx-*" + frontend-jest-dependencies: + patterns: + - "@types/jest" + - "jest" + frontend-eslint-dependencies: + patterns: + - "@typescript-eslint*" + - "eslint" schedule: interval: daily open-pull-requests-limit: 10 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f896a0631..d097318ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,8 +27,17 @@ jobs: node-version: ${{ matrix.node }} registry-url: "https://registry.npmjs.org" - - name: Install 1.70.x Rust toolchain - uses: dtolnay/rust-toolchain@1.70 + - name: Read rust-toolchain file from repository + id: gettoolchain + run: echo "::set-output name=toolchain::$(cat rust-toolchain)" + working-directory: ${{ matrix.node }}/${{ matrix.flavor }} + + - name: Install ${{ steps.gettoolchain.outputs.toolchain }} Rust toolchain + # Latest version available on this commit is 1.71.1 + # Commit date is Aug 3, 2023 + uses: dtolnay/rust-toolchain@f361669954a8ecfc00a3443f35f9ac8e610ffc06 + with: + toolchain: ${{ steps.gettoolchain.outputs.toolchain }} - name: Install if: ${{ matrix.flavor == 'dev'}} diff --git a/.github/workflows/get_backend_hash.yml b/.github/workflows/get_backend_hash.yml new file mode 100644 index 000000000..57950dee4 --- /dev/null +++ b/.github/workflows/get_backend_hash.yml @@ -0,0 +1,19 @@ +name: 'Print backend hashes' + +on: [workflow_dispatch] + +jobs: + print-backend-sha: + runs-on: 'ubuntu-latest' + name: Print backend hashes + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: repo + + - name: Run script + working-directory: repo + run: | + chmod +x ./scripts/get_backend_hash.sh + sh ./scripts/get_backend_hash.sh diff --git a/.github/workflows/on-tag.yml b/.github/workflows/on-tag.yml index 5d8d71104..55a5585cc 100644 --- a/.github/workflows/on-tag.yml +++ b/.github/workflows/on-tag.yml @@ -68,17 +68,17 @@ jobs: run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin - name: Checkout project - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Init repo for Dockerization run: docker/init.sh "$TAG" - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 id: qemu - name: Setup Docker buildx action - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 id: buildx - name: Available platforms @@ -98,7 +98,7 @@ jobs: docker buildx build \ --cache-from "type=local,src=/tmp/.buildx-cache" \ --cache-to "type=local,dest=/tmp/.buildx-cache" \ - --platform linux/amd64,linux/arm64,linux/arm/v7 \ + --platform linux/amd64,linux/arm64 \ --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG \ --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:latest \ --output "type=registry" ./${{ matrix.service }}/ \ diff --git a/GNUmakefile b/GNUmakefile deleted file mode 100755 index de1144025..000000000 --- a/GNUmakefile +++ /dev/null @@ -1,47 +0,0 @@ -# If you see pwd_unknown showing up check permissions -PWD ?= pwd_unknown - -# DATABASE DEPLOY FOLDER CONFIG - default ./data -ifeq ($(data),) -DATA := data -export DATA -else -DATA := $(data) -export DATA -endif - -.PHONY: help -help: - @echo '' - @echo '' - @echo ' Usage: make [COMMAND]' - @echo '' - @echo ' make all # build init mempool and electrs' - @echo ' make init # setup some useful configs' - @echo ' make mempool # build q dockerized mempool.space' - @echo ' make electrs # build a docker electrs image' - @echo '' - -.PHONY: init -init: - @echo '' - mkdir -p $(DATA) $(DATA)/mysql $(DATA)/mysql/data - #REF: https://github.com/mempool/mempool/blob/master/docker/README.md - cat docker/docker-compose.yml > docker-compose.yml - cat backend/mempool-config.sample.json > backend/mempool-config.json -.PHONY: mempool -mempool: init - @echo '' - docker-compose up --force-recreate --always-recreate-deps - @echo '' -.PHONY: electrs -electrum: - #REF: https://hub.docker.com/r/beli/electrum - @echo '' - docker build -f docker/electrum/Dockerfile . - @echo '' -.PHONY: all -all: init - make mempool -####################### --include Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 53016c66f..000000000 --- a/Makefile +++ /dev/null @@ -1 +0,0 @@ -# For additional configs/scripting diff --git a/backend/README.md b/backend/README.md index 6a0cb821c..e5d9dabdd 100644 --- a/backend/README.md +++ b/backend/README.md @@ -85,7 +85,7 @@ Install dependencies with `npm` and build the backend: ``` cd backend -npm install +npm install --no-install-links # npm@9.4.2 and later can omit the --no-install-links npm run build ``` diff --git a/backend/package-lock.json b/backend/package-lock.json index f5452e908..c8dea34c0 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -12,7 +12,7 @@ "@babel/core": "^7.21.3", "@mempool/electrum-client": "1.1.9", "@types/node": "^18.15.3", - "axios": "~1.4.0", + "axios": "~1.5.0", "bitcoinjs-lib": "~6.1.3", "crypto-js": "~4.1.1", "express": "~4.18.2", @@ -2321,9 +2321,9 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -9397,9 +9397,9 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", "requires": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", diff --git a/backend/package.json b/backend/package.json index 500cbf93c..2db8f2046 100644 --- a/backend/package.json +++ b/backend/package.json @@ -41,7 +41,7 @@ "@babel/core": "^7.21.3", "@mempool/electrum-client": "1.1.9", "@types/node": "^18.15.3", - "axios": "~1.4.0", + "axios": "~1.5.0", "bitcoinjs-lib": "~6.1.3", "crypto-js": "~4.1.1", "express": "~4.18.2", diff --git a/backend/rust-gbt/src/gbt.rs b/backend/rust-gbt/src/gbt.rs index 0bf7f9999..fb28dc299 100644 --- a/backend/rust-gbt/src/gbt.rs +++ b/backend/rust-gbt/src/gbt.rs @@ -335,13 +335,15 @@ fn set_relatives(txid: u32, audit_pool: &mut AuditPool) { let mut total_sigops: u32 = 0; for ancestor_id in &ancestors { - let Some(ancestor) = audit_pool + if let Some(ancestor) = audit_pool .get(*ancestor_id as usize) - .expect("audit_pool contains all ancestors") else { todo!() }; - total_fee += ancestor.fee; - total_sigop_adjusted_weight += ancestor.sigop_adjusted_weight; - total_sigop_adjusted_vsize += ancestor.sigop_adjusted_vsize; - total_sigops += ancestor.sigops; + .expect("audit_pool contains all ancestors") + { + total_fee += ancestor.fee; + total_sigop_adjusted_weight += ancestor.sigop_adjusted_weight; + total_sigop_adjusted_vsize += ancestor.sigop_adjusted_vsize; + total_sigops += ancestor.sigops; + } else { todo!() }; } if let Some(Some(tx)) = audit_pool.get_mut(txid as usize) { diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts index 2370fe7a1..8097a2465 100644 --- a/backend/src/__tests__/config.test.ts +++ b/backend/src/__tests__/config.test.ts @@ -191,30 +191,31 @@ describe('Mempool Backend Config', () => { } continue; } - switch (typeof value) { - case 'object': { - if (Array.isArray(value)) { - continue; - } else { - parseJson(value, key); - } - break; - } - default: { + + if (root) { //The flattened string, i.e, __MEMPOOL_ENABLED__ const replaceStr = `${root ? '__' + root + '_' : '__'}${key}__`; //The string used as the environment variable, i.e, MEMPOOL_ENABLED const envVarStr = `${root ? root : ''}_${key}`; + let defaultEntry; //The string used as the default value, to be checked as a regex, i.e, __MEMPOOL_ENABLED__=${MEMPOOL_ENABLED:=(.*)} - const defaultEntry = replaceStr + '=' + '\\${' + envVarStr + ':=(.*)' + '}'; - - if (process.env.CI) { - console.log(`looking for ${defaultEntry} in the start.sh script`); + if (Array.isArray(value)) { + defaultEntry = `${replaceStr}=\${${envVarStr}:=[]}`; + if (process.env.CI) { + console.log(`looking for ${defaultEntry} in the start.sh script`); + } + //Regex matching does not work with the array values + expect(startSh).toContain(defaultEntry); + } else { + defaultEntry = replaceStr + '=' + '\\${' + envVarStr + ':=(.*)' + '}'; + if (process.env.CI) { + console.log(`looking for ${defaultEntry} in the start.sh script`); + } + const re = new RegExp(defaultEntry); + expect(startSh).toMatch(re); } - const re = new RegExp(defaultEntry); - expect(startSh).toMatch(re); //The string that actually replaces the values in the config file const sedStr = 'sed -i "s!' + replaceStr + '!${' + replaceStr + '}!g" mempool-config.json'; @@ -222,11 +223,13 @@ describe('Mempool Backend Config', () => { console.log(`looking for ${sedStr} in the start.sh script`); } expect(startSh).toContain(sedStr); - break; } + else { + parseJson(value, key); } } } + parseJson(fixture); }); }); diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index a44720d83..d6d4327cb 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -75,9 +75,9 @@ class FailoverRouter { const results = await Promise.allSettled(this.hosts.map(async (host) => { if (host.socket) { - return this.pollConnection.get('/blocks/tip/height', { socketPath: host.host, timeout: 2000 }); + return this.pollConnection.get('/blocks/tip/height', { socketPath: host.host, timeout: 5000 }); } else { - return this.pollConnection.get(host.host + '/blocks/tip/height', { timeout: 2000 }); + return this.pollConnection.get(host.host + '/blocks/tip/height', { timeout: 5000 }); } })); const maxHeight = results.reduce((max, result) => Math.max(max, result.status === 'fulfilled' ? result.value?.data || 0 : 0), 0); diff --git a/backend/src/api/difficulty-adjustment.ts b/backend/src/api/difficulty-adjustment.ts index 23d0c33de..d93a5f91a 100644 --- a/backend/src/api/difficulty-adjustment.ts +++ b/backend/src/api/difficulty-adjustment.ts @@ -32,13 +32,13 @@ export interface DifficultyAdjustment { export function calcBitsDifference(oldBits: number, newBits: number): number { // Must be // - integer - // - highest exponent is 0x1f, so max value (as integer) is 0x1f0000ff + // - highest exponent is 0x20, so max value (as integer) is 0x207fffff // - min value is 1 (exponent = 0) // - highest bit of the number-part is +- sign, it must not be 1 const verifyBits = (bits: number): void => { if ( Math.floor(bits) !== bits || - bits > 0x1f0000ff || + bits > 0x207fffff || bits < 1 || (bits & 0x00800000) !== 0 || (bits & 0x007fffff) === 0 diff --git a/backend/src/api/explorer/nodes.routes.ts b/backend/src/api/explorer/nodes.routes.ts index e2dbcb0b6..3636abe2b 100644 --- a/backend/src/api/explorer/nodes.routes.ts +++ b/backend/src/api/explorer/nodes.routes.ts @@ -42,6 +42,12 @@ class NodesRoutes { switch (config.MEMPOOL.NETWORK) { case 'testnet': nodesList = [ + '0259db43b4e4ac0ff12a805f2d81e521253ba2317f6739bc611d8e2fa156d64256', + '0352b9944b9a52bd2116c91f1ba70c4ef851ac5ba27e1b20f1d92da3ade010dd10', + '03424f5a7601eaa47482cb17100b31a84a04d14fb44b83a57eeceffd8e299878e3', + '032850492ee61a5f7006a2fda6925e4b4ec3782f2b6de2ff0e439ef5a38c3b2470', + '022c80bace98831c44c32fb69755f2b353434e0ee9e7fbda29507f7ef8abea1421', + '02c3559c833e6f99f9ca05fe503e0b4e7524dea9121344edfd3e811101e0c28680', '032c7c7819276c4f706a04df1a0f1e10a5495994a7be4c1d3d28ca766e5a2b957b', '025a7e38c2834dd843591a4d23d5f09cdeb77ddca85f673c2d944a14220ff14cf7', '0395e2731a1673ef21d7a16a727c4fc4d4c35a861c428ce2c819c53d2b81c8bd55', @@ -64,6 +70,12 @@ class NodesRoutes { break; case 'signet': nodesList = [ + '029fe3621fc0c6e08056a14b868f8fb9acca1aa28a129512f6cea0f0d7654d9f92', + '02f60cd7a3a4f1c953dd9554a6ebd51a34f8b10b8124b7fc43a0b381139b55c883', + '03cbbf581774700865eebd1be42d022bc004ba30881274ab304e088a25d70e773d', + '0243348cb3741cfe2d8485fa8375c29c7bc7cbb67577c363cb6987a5e5fd0052cc', + '02cb73e631af44bee600d80f8488a9194c9dc5c7590e575c421a070d1be05bc8e9', + '0306f55ee631aa1e2cd4d9b2bfcbc14404faec5c541cef8b2e6f779061029d09c4', '03ddab321b760433cbf561b615ef62ac7d318630c5f51d523aaf5395b90b751956', '033d92c7bfd213ef1b34c90e985fb5dc77f9ec2409d391492484e57a44c4aca1de', '02ad010dda54253c1eb9efe38b0760657a3b43ecad62198c359c051c9d99d45781', @@ -86,6 +98,12 @@ class NodesRoutes { break; default: nodesList = [ + '02b12b889fe3c943cb05645921040ef13d6d397a2e7a4ad000e28500c505ff26d6', + '0302240ac9d71b39617cbde2764837ec3d6198bd6074b15b75d2ff33108e89d2e1', + '03364a8ace313376e5e4b68c954e287c6388e16df9e9fdbaf0363ecac41105cbf6', + '03229ab4b7f692753e094b93df90530150680f86b535b5183b0cffd75b3df583fc', + '03a696eb7acde991c1be97a58a9daef416659539ae462b897f5e9ae361f990228e', + '0248bf26cf3a63ab8870f34dc0ec9e6c8c6288cdba96ba3f026f34ec0f13ac4055', '03fbc17549ec667bccf397ababbcb4cdc0e3394345e4773079ab2774612ec9be61', '03da9a8623241ccf95f19cd645c6cecd4019ac91570e976eb0a128bebbc4d8a437', '03ca5340cf85cb2e7cf076e489f785410838de174e40be62723e8a60972ad75144', diff --git a/backend/src/api/mempool-blocks.ts b/backend/src/api/mempool-blocks.ts index 1de4bbee7..15f9b6cf7 100644 --- a/backend/src/api/mempool-blocks.ts +++ b/backend/src/api/mempool-blocks.ts @@ -451,6 +451,7 @@ class MempoolBlocks { private processBlockTemplates(mempool: { [txid: string]: MempoolTransactionExtended }, blocks: string[][], blockWeights: number[] | null, rates: [string, number][], clusters: string[][], accelerations, accelerationPool, saveResults): MempoolBlockWithTransactions[] { for (const [txid, rate] of rates) { if (txid in mempool) { + mempool[txid].cpfpDirty = (rate !== mempool[txid].effectiveFeePerVsize); mempool[txid].effectiveFeePerVsize = rate; mempool[txid].cpfpChecked = false; } @@ -494,6 +495,9 @@ class MempoolBlocks { } } }); + if (mempoolTx.ancestors?.length !== ancestors.length || mempoolTx.descendants?.length !== descendants.length) { + mempoolTx.cpfpDirty = true; + } Object.assign(mempoolTx, {ancestors, descendants, bestDescendant: null, cpfpChecked: true}); } } @@ -531,12 +535,21 @@ class MempoolBlocks { const acceleration = accelerations[txid]; if (isAccelerated[txid] || (acceleration && (!accelerationPool || acceleration.pools.includes(accelerationPool)))) { + if (!mempoolTx.acceleration) { + mempoolTx.cpfpDirty = true; + } mempoolTx.acceleration = true; for (const ancestor of mempoolTx.ancestors || []) { + if (!mempool[ancestor.txid].acceleration) { + mempool[ancestor.txid].cpfpDirty = true; + } mempool[ancestor.txid].acceleration = true; isAccelerated[ancestor.txid] = true; } } else { + if (mempoolTx.acceleration) { + mempoolTx.cpfpDirty = true; + } delete mempoolTx.acceleration; } diff --git a/backend/src/api/statistics/statistics-api.ts b/backend/src/api/statistics/statistics-api.ts index 9df12d704..9518c4a0d 100644 --- a/backend/src/api/statistics/statistics-api.ts +++ b/backend/src/api/statistics/statistics-api.ts @@ -171,6 +171,7 @@ class StatisticsApi { private getQueryForDaysAvg(div: number, interval: string) { return `SELECT UNIX_TIMESTAMP(added) as added, + CAST(avg(unconfirmed_transactions) as DOUBLE) as unconfirmed_transactions, CAST(avg(vbytes_per_second) as DOUBLE) as vbytes_per_second, CAST(avg(vsize_1) as DOUBLE) as vsize_1, CAST(avg(vsize_2) as DOUBLE) as vsize_2, @@ -219,6 +220,7 @@ class StatisticsApi { private getQueryForDays(div: number, interval: string) { return `SELECT UNIX_TIMESTAMP(added) as added, + CAST(avg(unconfirmed_transactions) as DOUBLE) as unconfirmed_transactions, CAST(avg(vbytes_per_second) as DOUBLE) as vbytes_per_second, vsize_1, vsize_2, @@ -401,6 +403,7 @@ class StatisticsApi { return statistic.map((s) => { return { added: s.added, + count: s.unconfirmed_transactions, vbytes_per_second: s.vbytes_per_second, mempool_byte_weight: s.mempool_byte_weight, total_fee: s.total_fee, diff --git a/backend/src/api/transaction-utils.ts b/backend/src/api/transaction-utils.ts index 02ee7c055..ef4a34012 100644 --- a/backend/src/api/transaction-utils.ts +++ b/backend/src/api/transaction-utils.ts @@ -5,6 +5,7 @@ import bitcoinApi, { bitcoinCoreApi } from './bitcoin/bitcoin-api-factory'; import * as bitcoinjs from 'bitcoinjs-lib'; import logger from '../logger'; import config from '../config'; +import pLimit from '../utils/p-limit'; class TransactionUtils { constructor() { } @@ -74,8 +75,12 @@ class TransactionUtils { public async $getMempoolTransactionsExtended(txids: string[], addPrevouts = false, lazyPrevouts = false, forceCore = false): Promise { if (forceCore || config.MEMPOOL.BACKEND !== 'esplora') { - const results = await Promise.allSettled(txids.map(txid => this.$getTransactionExtended(txid, addPrevouts, lazyPrevouts, forceCore, true))); - return (results.filter(r => r.status === 'fulfilled') as PromiseFulfilledResult[]).map(r => r.value); + const limiter = pLimit(8); // Run 8 requests at a time + const results = await Promise.allSettled(txids.map( + txid => limiter(() => this.$getMempoolTransactionExtended(txid, addPrevouts, lazyPrevouts, forceCore)) + )); + return results.filter(reply => reply.status === 'fulfilled') + .map(r => (r as PromiseFulfilledResult).value); } else { const transactions = await bitcoinApi.$getMempoolTransactions(txids); return transactions.map(transaction => { diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 9cb24df10..c50941f39 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -486,6 +486,7 @@ class WebsocketHandler { // pre-compute address transactions const addressCache = this.makeAddressCache(newTransactions); + const removedAddressCache = this.makeAddressCache(deletedTransactions); this.wss.clients.forEach(async (client) => { if (client.readyState !== WebSocket.OPEN) { @@ -526,11 +527,15 @@ class WebsocketHandler { } if (client['track-address']) { - const foundTransactions = Array.from(addressCache[client['track-address']]?.values() || []); + const newTransactions = Array.from(addressCache[client['track-address']]?.values() || []); + const removedTransactions = Array.from(removedAddressCache[client['track-address']]?.values() || []); // txs may be missing prevouts in non-esplora backends // so fetch the full transactions now - const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(foundTransactions) : foundTransactions; + const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(newTransactions) : newTransactions; + if (removedTransactions.length) { + response['address-removed-transactions'] = JSON.stringify(removedTransactions); + } if (fullTransactions.length) { response['address-transactions'] = JSON.stringify(fullTransactions); } @@ -586,13 +591,25 @@ class WebsocketHandler { const mempoolTx = newMempool[trackTxid]; if (mempoolTx && mempoolTx.position) { - response['txPosition'] = JSON.stringify({ + const positionData = { txid: trackTxid, position: { ...mempoolTx.position, accelerated: mempoolTx.acceleration || undefined, } - }); + }; + if (mempoolTx.cpfpDirty) { + positionData['cpfp'] = { + ancestors: mempoolTx.ancestors, + bestDescendant: mempoolTx.bestDescendant || null, + descendants: mempoolTx.descendants || null, + effectiveFeePerVsize: mempoolTx.effectiveFeePerVsize || null, + sigops: mempoolTx.sigops, + adjustedVsize: mempoolTx.adjustedVsize, + acceleration: mempoolTx.acceleration + }; + } + response['txPosition'] = JSON.stringify(positionData); } } diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index c08846191..b013f2f26 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -104,6 +104,7 @@ export interface MempoolTransactionExtended extends TransactionExtended { adjustedFeePerVsize: number; inputs?: number[]; lastBoosted?: number; + cpfpDirty?: boolean; } export interface AuditTransaction { diff --git a/backend/src/utils/p-limit.ts b/backend/src/utils/p-limit.ts new file mode 100644 index 000000000..20cead411 --- /dev/null +++ b/backend/src/utils/p-limit.ts @@ -0,0 +1,179 @@ +/* +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* +How it works: +`this._head` is an instance of `Node` which keeps track of its current value and nests +another instance of `Node` that keeps the value that comes after it. When a value is +provided to `.enqueue()`, the code needs to iterate through `this._head`, going deeper +and deeper to find the last value. However, iterating through every single item is slow. +This problem is solved by saving a reference to the last value as `this._tail` so that +it can reference it to add a new value. +*/ + +class Node { + value; + next; + + constructor(value) { + this.value = value; + } +} + +class Queue { + private _head; + private _tail; + private _size; + + constructor() { + this.clear(); + } + + enqueue(value) { + const node = new Node(value); + + if (this._head) { + this._tail.next = node; + this._tail = node; + } else { + this._head = node; + this._tail = node; + } + + this._size++; + } + + dequeue() { + const current = this._head; + if (!current) { + return; + } + + this._head = this._head.next; + this._size--; + return current.value; + } + + clear() { + this._head = undefined; + this._tail = undefined; + this._size = 0; + } + + get size() { + return this._size; + } + + *[Symbol.iterator]() { + let current = this._head; + + while (current) { + yield current.value; + current = current.next; + } + } +} + +interface LimitFunction { + readonly activeCount: number; + readonly pendingCount: number; + clearQueue: () => void; + ( + fn: (...args: Arguments) => PromiseLike | ReturnType, + ...args: Arguments + ): Promise; +} + +export default function pLimit(concurrency: number): LimitFunction { + if ( + !( + (Number.isInteger(concurrency) || + concurrency === Number.POSITIVE_INFINITY) && + concurrency > 0 + ) + ) { + throw new TypeError('Expected `concurrency` to be a number from 1 and up'); + } + + const queue = new Queue(); + let activeCount = 0; + + const next = () => { + activeCount--; + + if (queue.size > 0) { + queue.dequeue()(); + } + }; + + const run = async (fn, resolve, args) => { + activeCount++; + + const result = (async () => fn(...args))(); + + resolve(result); + + try { + await result; + } catch {} + + next(); + }; + + const enqueue = (fn, resolve, args) => { + queue.enqueue(run.bind(undefined, fn, resolve, args)); + + (async () => { + // This function needs to wait until the next microtask before comparing + // `activeCount` to `concurrency`, because `activeCount` is updated asynchronously + // when the run function is dequeued and called. The comparison in the if-statement + // needs to happen asynchronously as well to get an up-to-date value for `activeCount`. + await Promise.resolve(); + + if (activeCount < concurrency && queue.size > 0) { + queue.dequeue()(); + } + })(); + }; + + const generator = (fn, ...args) => + new Promise((resolve) => { + enqueue(fn, resolve, args); + }); + + Object.defineProperties(generator, { + activeCount: { + get: () => activeCount, + }, + pendingCount: { + get: () => queue.size, + }, + clearQueue: { + value: () => { + queue.clear(); + }, + }, + }); + + return generator as any; +} diff --git a/contributors/TheBlueMatt.txt b/contributors/TheBlueMatt.txt new file mode 100644 index 000000000..77b39e982 --- /dev/null +++ b/contributors/TheBlueMatt.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file with sha256 hash c80c5ee4c71c5a76a1f6cd35339bd0c45b25b491933ea7b02a66470e9f43a6fd. + +Signed: TheBlueMatt diff --git a/contributors/orangesurf.txt b/contributors/orangesurf.txt new file mode 100644 index 000000000..c760a9125 --- /dev/null +++ b/contributors/orangesurf.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of September 12, 2023. + +Signed: orange surf diff --git a/docker/backend/Dockerfile b/docker/backend/Dockerfile index bbe4df3d2..96b1a2d5b 100644 --- a/docker/backend/Dockerfile +++ b/docker/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16.16.0-buster-slim AS builder +FROM node:20.8.0-buster-slim AS builder ARG commitHash ENV MEMPOOL_COMMIT_HASH=${commitHash} @@ -17,7 +17,7 @@ ENV PATH="/root/.cargo/bin:$PATH" RUN npm install --omit=dev --omit=optional RUN npm run package -FROM node:16.16.0-buster-slim +FROM node:20.8.0-buster-slim WORKDIR /backend diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index e283d1171..aa084133f 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -52,7 +52,7 @@ "REST_API_URL": "__ESPLORA_REST_API_URL__", "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__", "RETRY_UNIX_SOCKET_AFTER": __ESPLORA_RETRY_UNIX_SOCKET_AFTER__, - "FALLBACK": __ESPLORA_FALLBACK__, + "FALLBACK": __ESPLORA_FALLBACK__ }, "SECOND_CORE_RPC": { "HOST": "__SECOND_CORE_RPC_HOST__", diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 681872681..1bfb06c24 100755 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -53,6 +53,7 @@ __ELECTRUM_TLS_ENABLED__=${ELECTRUM_TLS_ENABLED:=false} __ESPLORA_REST_API_URL__=${ESPLORA_REST_API_URL:=http://127.0.0.1:3000} __ESPLORA_UNIX_SOCKET_PATH__=${ESPLORA_UNIX_SOCKET_PATH:="null"} __ESPLORA_RETRY_UNIX_SOCKET_AFTER__=${ESPLORA_RETRY_UNIX_SOCKET_AFTER:=30000} +__ESPLORA_FALLBACK__=${ESPLORA_FALLBACK:=[]} # SECOND_CORE_RPC __SECOND_CORE_RPC_HOST__=${SECOND_CORE_RPC_HOST:=127.0.0.1} @@ -138,7 +139,7 @@ __MEMPOOL_SERVICES_API__=${MEMPOOL_SERVICES_API:=""} __MEMPOOL_SERVICES_ACCELERATIONS__=${MEMPOOL_SERVICES_ACCELERATIONS:=false} # REDIS -__REDIS_ENABLED__=${REDIS_ENABLED:=true} +__REDIS_ENABLED__=${REDIS_ENABLED:=false} __REDIS_UNIX_SOCKET_PATH__=${REDIS_UNIX_SOCKET_PATH:=true} mkdir -p "${__MEMPOOL_CACHE_DIR__}" @@ -192,6 +193,7 @@ sed -i "s!__ELECTRUM_TLS_ENABLED__!${__ELECTRUM_TLS_ENABLED__}!g" mempool-config sed -i "s!__ESPLORA_REST_API_URL__!${__ESPLORA_REST_API_URL__}!g" mempool-config.json sed -i "s!__ESPLORA_UNIX_SOCKET_PATH__!${__ESPLORA_UNIX_SOCKET_PATH__}!g" mempool-config.json sed -i "s!__ESPLORA_RETRY_UNIX_SOCKET_AFTER__!${__ESPLORA_RETRY_UNIX_SOCKET_AFTER__}!g" mempool-config.json +sed -i "s!__ESPLORA_FALLBACK__!${__ESPLORA_FALLBACK__}!g" mempool-config.json sed -i "s!__SECOND_CORE_RPC_HOST__!${__SECOND_CORE_RPC_HOST__}!g" mempool-config.json sed -i "s!__SECOND_CORE_RPC_PORT__!${__SECOND_CORE_RPC_PORT__}!g" mempool-config.json diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 68e73a1c8..4e1094306 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -38,7 +38,7 @@ services: MYSQL_USER: "mempool" MYSQL_PASSWORD: "mempool" MYSQL_ROOT_PASSWORD: "admin" - image: mariadb:10.5.8 + image: mariadb:10.5.21 user: "1000:1000" restart: on-failure stop_grace_period: 1m diff --git a/docker/electrum/Dockerfile b/docker/electrum/Dockerfile deleted file mode 100644 index b7af48989..000000000 --- a/docker/electrum/Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -FROM ubuntu:18.04 -MAINTAINER mempool.space developers -EXPOSE 50002 - -# runs as UID 1000 GID 1000 inside the container - -ENV VERSION 4.0.9 -RUN set -x \ - && apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gpg gpg-agent dirmngr \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends wget xpra python3-pyqt5 python3-wheel python3-pip python3-setuptools libsecp256k1-0 libsecp256k1-dev python3-numpy python3-dev build-essential \ - && wget -O /tmp/Electrum-${VERSION}.tar.gz https://download.electrum.org/${VERSION}/Electrum-${VERSION}.tar.gz \ - && wget -O /tmp/Electrum-${VERSION}.tar.gz.asc https://download.electrum.org/${VERSION}/Electrum-${VERSION}.tar.gz.asc \ - && gpg --keyserver keys.gnupg.net --recv-keys 6694D8DE7BE8EE5631BED9502BD5824B7F9470E6 \ - && gpg --verify /tmp/Electrum-${VERSION}.tar.gz.asc /tmp/Electrum-${VERSION}.tar.gz \ - && pip3 install /tmp/Electrum-${VERSION}.tar.gz \ - && test -f /usr/local/bin/electrum \ - && rm -vrf /tmp/Electrum-${VERSION}.tar.gz /tmp/Electrum-${VERSION}.tar.gz.asc ${HOME}/.gnupg \ - && apt-get purge --autoremove -y python3-wheel python3-pip python3-setuptools python3-dev build-essential libsecp256k1-dev curl gpg gpg-agent dirmngr \ - && apt-get clean && rm -rf /var/lib/apt/lists/* \ - && useradd -d /home/mempool -m mempool \ - && mkdir /electrum \ - && ln -s /electrum /home/mempool/.electrum \ - && chown mempool:mempool /electrum - -USER mempool -ENV HOME /home/mempool -WORKDIR /home/mempool -VOLUME /electrum - -CMD ["/usr/bin/xpra", "start", ":100", "--start-child=/usr/local/bin/electrum", "--bind-tcp=0.0.0.0:50002","--daemon=yes", "--notifications=no", "--mdns=no", "--pulseaudio=no", "--html=off", "--speaker=disabled", "--microphone=disabled", "--webcam=no", "--printing=no", "--dbus-launch=", "--exit-with-children"] -ENTRYPOINT ["electrum"] diff --git a/docker/frontend/Dockerfile b/docker/frontend/Dockerfile index b54612e3d..4d04ae88f 100644 --- a/docker/frontend/Dockerfile +++ b/docker/frontend/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16.16.0-buster-slim AS builder +FROM node:20.8.0-buster-slim AS builder ARG commitHash ENV DOCKER_COMMIT_HASH=${commitHash} @@ -13,7 +13,7 @@ RUN npm install --omit=dev --omit=optional RUN npm run build -FROM nginx:1.17.8-alpine +FROM nginx:1.24.0-alpine WORKDIR /patch diff --git a/docker/frontend/entrypoint.sh b/docker/frontend/entrypoint.sh index 7d5ee313d..4e14aefac 100644 --- a/docker/frontend/entrypoint.sh +++ b/docker/frontend/entrypoint.sh @@ -39,6 +39,7 @@ __AUDIT__=${AUDIT:=false} __MAINNET_BLOCK_AUDIT_START_HEIGHT__=${MAINNET_BLOCK_AUDIT_START_HEIGHT:=0} __TESTNET_BLOCK_AUDIT_START_HEIGHT__=${TESTNET_BLOCK_AUDIT_START_HEIGHT:=0} __SIGNET_BLOCK_AUDIT_START_HEIGHT__=${SIGNET_BLOCK_AUDIT_START_HEIGHT:=0} +__ACCELERATOR__=${ACCELERATOR:=false} __HISTORICAL_PRICE__=${HISTORICAL_PRICE:=true} # Export as environment variables to be used by envsubst @@ -65,6 +66,7 @@ export __AUDIT__ export __MAINNET_BLOCK_AUDIT_START_HEIGHT__ export __TESTNET_BLOCK_AUDIT_START_HEIGHT__ export __SIGNET_BLOCK_AUDIT_START_HEIGHT__ +export __ACCELERATOR__ export __HISTORICAL_PRICE__ folder=$(find /var/www/mempool -name "config.js" | xargs dirname) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 97c023be0..36049f9f0 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.1.4", - "@angular/animations": "^16.1.5", - "@angular/cli": "^16.1.4", - "@angular/common": "^16.1.5", - "@angular/compiler": "^16.1.5", - "@angular/core": "^16.1.5", - "@angular/forms": "^16.1.5", - "@angular/localize": "^16.1.5", - "@angular/platform-browser": "^16.1.5", - "@angular/platform-browser-dynamic": "^16.1.5", - "@angular/platform-server": "^16.1.5", - "@angular/router": "^16.1.5", + "@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", "@fortawesome/angular-fontawesome": "~0.13.0", "@fortawesome/fontawesome-common-types": "~6.4.0", "@fortawesome/fontawesome-svg-core": "~6.4.0", @@ -59,9 +59,9 @@ "optionalDependencies": { "@cypress/schematic": "^2.5.0", "@types/cypress": "^1.1.3", - "cypress": "^12.17.2", - "cypress-fail-on-console-error": "~4.0.3", - "cypress-wait-until": "^2.0.0", + "cypress": "^13.2.0", + "cypress-fail-on-console-error": "~5.0.0", + "cypress-wait-until": "^2.0.1", "mock-socket": "~9.2.1", "start-server-and-test": "~2.0.0" } @@ -88,11 +88,11 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1601.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1601.4.tgz", - "integrity": "sha512-OOSbNlDy+Q3jY0oFHaq8kkna9HYI1zaS8IHeCIDP6T/ZIAVad4+HqXAL4SKQrKJikkoBQv1Z/eaDBL5XPFK9Bw==", + "version": "0.1602.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.0.tgz", + "integrity": "sha512-ZRmUTBeD+uGr605eOHnsovEn6f1mOBI+kxP64DRvagNweX5TN04s3iyQ8jmLSAHQD9ush31LFxv3dVNxv3ceXQ==", "dependencies": { - "@angular-devkit/core": "16.1.4", + "@angular-devkit/core": "16.2.0", "rxjs": "7.8.1" }, "engines": { @@ -102,39 +102,39 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.1.4.tgz", - "integrity": "sha512-LiHM7R20fTHg/eM+Iabotj08edP5wVBQahRfVNLxERo8X6VJgSjVChnsh3AQJkRywlGuFe20AOQYpyLyN367Ug==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.0.tgz", + "integrity": "sha512-miylwjOqvlKmYrzS84bjRaJrecZxOXH9xsPVvQE8VBe8UKePJjRAL6yyOqXUOGtzlch2YmT98RAnuni7y0FEAw==", "dependencies": { "@ampproject/remapping": "2.2.1", - "@angular-devkit/architect": "0.1601.4", - "@angular-devkit/build-webpack": "0.1601.4", - "@angular-devkit/core": "16.1.4", - "@babel/core": "7.22.5", - "@babel/generator": "7.22.7", + "@angular-devkit/architect": "0.1602.0", + "@angular-devkit/build-webpack": "0.1602.0", + "@angular-devkit/core": "16.2.0", + "@babel/core": "7.22.9", + "@babel/generator": "7.22.9", "@babel/helper-annotate-as-pure": "7.22.5", - "@babel/helper-split-export-declaration": "7.22.5", + "@babel/helper-split-export-declaration": "7.22.6", "@babel/plugin-proposal-async-generator-functions": "7.20.7", "@babel/plugin-transform-async-to-generator": "7.22.5", - "@babel/plugin-transform-runtime": "7.22.5", - "@babel/preset-env": "7.22.5", - "@babel/runtime": "7.22.5", + "@babel/plugin-transform-runtime": "7.22.9", + "@babel/preset-env": "7.22.9", + "@babel/runtime": "7.22.6", "@babel/template": "7.22.5", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "16.1.4", + "@ngtools/webpack": "16.2.0", "@vitejs/plugin-basic-ssl": "1.0.1", "ansi-colors": "4.1.3", "autoprefixer": "10.4.14", - "babel-loader": "9.1.2", + "babel-loader": "9.1.3", "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.21.5", - "cacache": "17.1.3", "chokidar": "3.5.3", "copy-webpack-plugin": "11.0.0", - "critters": "0.0.19", + "critters": "0.0.20", "css-loader": "6.8.1", - "esbuild-wasm": "0.17.19", - "fast-glob": "3.2.12", + "esbuild-wasm": "0.18.17", + "fast-glob": "3.3.1", + "guess-parser": "0.4.22", "https-proxy-agent": "5.0.1", "inquirer": "8.2.4", "jsonc-parser": "3.2.0", @@ -143,31 +143,31 @@ "less-loader": "11.1.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.1", - "magic-string": "0.30.0", + "magic-string": "0.30.1", "mini-css-extract-plugin": "2.7.6", "mrmime": "1.0.1", "open": "8.4.2", "ora": "5.4.1", "parse5-html-rewriting-stream": "7.0.0", "picomatch": "2.3.1", - "piscina": "3.2.0", - "postcss": "8.4.24", - "postcss-loader": "7.3.2", + "piscina": "4.0.0", + "postcss": "8.4.27", + "postcss-loader": "7.3.3", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", - "sass": "1.63.2", - "sass-loader": "13.3.1", - "semver": "7.5.3", + "sass": "1.64.1", + "sass-loader": "13.3.2", + "semver": "7.5.4", "source-map-loader": "4.0.1", "source-map-support": "0.5.21", - "terser": "5.17.7", + "terser": "5.19.2", "text-table": "0.2.0", "tree-kill": "1.2.2", - "tslib": "2.5.3", - "vite": "4.3.9", - "webpack": "5.86.0", + "tslib": "2.6.1", + "vite": "4.4.7", + "webpack": "5.88.2", "webpack-dev-middleware": "6.1.1", - "webpack-dev-server": "4.15.0", + "webpack-dev-server": "4.15.1", "webpack-merge": "5.9.0", "webpack-subresource-integrity": "5.1.0" }, @@ -177,7 +177,7 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.17.19" + "esbuild": "0.18.17" }, "peerDependencies": { "@angular/compiler-cli": "^16.0.0", @@ -222,19 +222,423 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@ngtools/webpack": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.1.4.tgz", - "integrity": "sha512-+8bfavDH8eWxjlJFYr6bkjcRHhy95j+f8oNn7/sGLNu4L96nuE2AZ011XIu2dJahCnNiBvwc1EpkKa92t9rkaA==", - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.1" }, - "peerDependencies": { - "@angular/compiler-cli": "^16.0.0", - "typescript": ">=4.9.3 <5.2", - "webpack": "^5.54.0" + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-arm": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz", + "integrity": "sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz", + "integrity": "sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz", + "integrity": "sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/darwin-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz", + "integrity": "sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/darwin-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz", + "integrity": "sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz", + "integrity": "sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/freebsd-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz", + "integrity": "sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-arm": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz", + "integrity": "sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz", + "integrity": "sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-ia32": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz", + "integrity": "sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-loong64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz", + "integrity": "sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-mips64el": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz", + "integrity": "sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-ppc64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz", + "integrity": "sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-riscv64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz", + "integrity": "sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-s390x": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz", + "integrity": "sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz", + "integrity": "sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/netbsd-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz", + "integrity": "sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/openbsd-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz", + "integrity": "sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/sunos-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz", + "integrity": "sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz", + "integrity": "sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-ia32": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz", + "integrity": "sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz", + "integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/esbuild": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz", + "integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==", + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.17", + "@esbuild/android-arm64": "0.18.17", + "@esbuild/android-x64": "0.18.17", + "@esbuild/darwin-arm64": "0.18.17", + "@esbuild/darwin-x64": "0.18.17", + "@esbuild/freebsd-arm64": "0.18.17", + "@esbuild/freebsd-x64": "0.18.17", + "@esbuild/linux-arm": "0.18.17", + "@esbuild/linux-arm64": "0.18.17", + "@esbuild/linux-ia32": "0.18.17", + "@esbuild/linux-loong64": "0.18.17", + "@esbuild/linux-mips64el": "0.18.17", + "@esbuild/linux-ppc64": "0.18.17", + "@esbuild/linux-riscv64": "0.18.17", + "@esbuild/linux-s390x": "0.18.17", + "@esbuild/linux-x64": "0.18.17", + "@esbuild/netbsd-x64": "0.18.17", + "@esbuild/openbsd-x64": "0.18.17", + "@esbuild/sunos-x64": "0.18.17", + "@esbuild/win32-arm64": "0.18.17", + "@esbuild/win32-ia32": "0.18.17", + "@esbuild/win32-x64": "0.18.17" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" } }, "node_modules/@angular-devkit/build-angular/node_modules/loader-utils": { @@ -245,31 +649,12 @@ "node": ">= 12.13.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" - }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1601.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1601.4.tgz", - "integrity": "sha512-GC1y//ScAYbYQ68Wri2QgTEekC4hRxBC+xEkYL9OFiAMQ4mcN+eYvbkQBX8enJwDMXpkYfLR6VV8cChjAVYIgg==", + "version": "0.1602.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.0.tgz", + "integrity": "sha512-KdSr6iAcO30i/LIGL8mYi+d1buVXuDCp2dptzEJ4vxReOMFJca90KLwb+tVHEqqnDb0WkNfWm8Ii2QYh2FrNyA==", "dependencies": { - "@angular-devkit/architect": "0.1601.4", + "@angular-devkit/architect": "0.1602.0", "rxjs": "7.8.1" }, "engines": { @@ -283,9 +668,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.1.4.tgz", - "integrity": "sha512-WCAzNi9LxpFIi2WVPaJQd2kHPqCnCexWzUZN05ltJuBGCQL1O+LgRHGwnQ4WZoqmrF5tcWt2a3GFtJ3DgMc1hw==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.0.tgz", + "integrity": "sha512-l1k6Rqm3YM16BEn3CWyQKrk9xfu+2ux7Bw3oS+h1TO4/RoxO2PgHj8LLRh/WNrYVarhaqO7QZ5ePBkXNMkzJ1g==", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -327,10 +712,27 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, + "node_modules/@angular-devkit/schematics": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.0.tgz", + "integrity": "sha512-QMDJXPE0+YQJ9Ap3MMzb0v7rx6ZbBEokmHgpdIjN3eILYmbAdsSGE8HTV8NjS9nKmcyE9OGzFCMb7PFrDTlTAw==", + "dependencies": { + "@angular-devkit/core": "16.2.0", + "jsonc-parser": "3.2.0", + "magic-string": "0.30.1", + "ora": "5.4.1", + "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/@angular/animations": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.1.5.tgz", - "integrity": "sha512-CUm81m1N00EIza8LH81BJ+PoR23HzfoD+8ltASya9D0VurB6hlv0Axa5kQ0o02PQwCAU1a6RUUTsTjODc/mUYA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.2.2.tgz", + "integrity": "sha512-p0QefudkPGXjq9inZDrtW6WJrDcSeL+Nkc8lxubjg5fLQATKWKpsUBb+u2xEVu8OvWqj8BvrZUDnXYLyTdM4vw==", "dependencies": { "tslib": "^2.3.0" }, @@ -338,18 +740,18 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "16.1.5" + "@angular/core": "16.2.2" } }, "node_modules/@angular/cli": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.1.4.tgz", - "integrity": "sha512-coSOLVLpOCOD5q9K9EAFFMrTES+HtdJiLy/iI9kdKNCKWUJpm8/svZ3JZOej3vPxYEp0AokXNOwORQnX21/qZQ==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.0.tgz", + "integrity": "sha512-xT8vJOyw6Rc2364XDW2jHagLgKu7342ktd/lt+c0u6R+AB2XVFMePR7VceLohX9N/vRUsbQ0nVSZr+ru/hA+HA==", "dependencies": { - "@angular-devkit/architect": "0.1601.4", - "@angular-devkit/core": "16.1.4", - "@angular-devkit/schematics": "16.1.4", - "@schematics/angular": "16.1.4", + "@angular-devkit/architect": "0.1602.0", + "@angular-devkit/core": "16.2.0", + "@angular-devkit/schematics": "16.2.0", + "@schematics/angular": "16.2.0", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "4.1.1", @@ -361,7 +763,7 @@ "ora": "5.4.1", "pacote": "15.2.0", "resolve": "1.22.2", - "semver": "7.5.3", + "semver": "7.5.4", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, @@ -374,38 +776,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/@angular-devkit/schematics": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.1.4.tgz", - "integrity": "sha512-yjRgwHAfFaeuimgbQtjwSUyXzEHpMSdTRb2zg+TOp6skoGvHOG8xXFJ7DjBkSMeAQdFF0fkxhPS9YmlxqNc+7A==", - "dependencies": { - "@angular-devkit/core": "16.1.4", - "jsonc-parser": "3.2.0", - "magic-string": "0.30.0", - "ora": "5.4.1", - "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/@angular/cli/node_modules/@schematics/angular": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.1.4.tgz", - "integrity": "sha512-XfoeL+aBVIR/DzgVKGVhHW/TGQnqWvngyJVuCwXEVWzNfjxHYFkchXa78OItpAvTEr6/Y0Me9FQVAGVA4mMUyg==", - "dependencies": { - "@angular-devkit/core": "16.1.4", - "@angular-devkit/schematics": "16.1.4", - "jsonc-parser": "3.2.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, "node_modules/@angular/cli/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -449,20 +819,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/@angular/cli/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular/cli/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -513,9 +869,9 @@ } }, "node_modules/@angular/common": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.1.5.tgz", - "integrity": "sha512-XQVIpICniWXXMoXsr6X7Q3pVcYBeQ0FZF06BNNolkkkVuReYpqr3TwWrZfuB9TUmxdF6R5WZ+M3NAdXodDDUNA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.2.2.tgz", + "integrity": "sha512-2ww8/heDHkfJEBwjakbQeleq610ljcvytNs6ZN1xiXib060xMP+xx17Oa9I3onhi369JsKCHkMR5Qs2U5af1uA==", "dependencies": { "tslib": "^2.3.0" }, @@ -523,14 +879,14 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "16.1.5", + "@angular/core": "16.2.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.1.5.tgz", - "integrity": "sha512-QNyisdr9lEN43v/e/fjS0H1vrJBMY8lIGpxVY1OOERFjA1clfMhaz5fiPE3vWFV5TOm3/ym9z2xuRXM6UoyWoA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.2.2.tgz", + "integrity": "sha512-0X9i5NsqjX++0gmFy0fy2Uc5dHJMxDq6Yu/j1L3RdbvycL1GW+P8GgPfIvD/+v/YiDqpOHQswQXLbkcHw1+svA==", "dependencies": { "tslib": "^2.3.0" }, @@ -538,7 +894,7 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "16.1.5" + "@angular/core": "16.2.2" }, "peerDependenciesMeta": { "@angular/core": { @@ -547,9 +903,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.1.5.tgz", - "integrity": "sha512-j20hmPyM+rLJDU1y0ta9Uf7+o2oGjvGWGpyANbpuTlAfA1+VN5G3xD53FnNcmO6LZuAw0wDw6NDAyy+G55o8xQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.2.2.tgz", + "integrity": "sha512-+4i7o0yBc6xSljO8rdYL1G9AiZr2OW5dJAHfPuO21yNhp9BjIJ/TW+Sw1+o/WH4Gnim9adtnonL18UM+vuYeXg==", "dependencies": { "@babel/core": "7.22.5", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -569,7 +925,7 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/compiler": "16.1.5", + "@angular/compiler": "16.2.2", "typescript": ">=4.9.3 <5.2" } }, @@ -663,9 +1019,9 @@ } }, "node_modules/@angular/core": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.1.5.tgz", - "integrity": "sha512-xmk+WeL3qtFb3BM2hsEq/kGHJinqaTNVJkK/m4TiGArY+hjJwfCOeuTss7nOkKXvhRkZxU9VP0tej1w3QV5Yzw==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.2.2.tgz", + "integrity": "sha512-l6nJlppguroov7eByBIpbxn/mEPcQrL//Ru1TSPzTtXOLR1p41VqPMaeJXj7xYVx7im57YLTDPAjhtLzkUT/Ow==", "dependencies": { "tslib": "^2.3.0" }, @@ -678,9 +1034,9 @@ } }, "node_modules/@angular/forms": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.1.5.tgz", - "integrity": "sha512-4E/5msvODs5tixlkB1iHPsRv7jHj189WMpN2n7LKXT+l+jA3/rD2AbGnYVKR04gymN2x/HQ/qOrbvrqv3E1NBw==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.2.2.tgz", + "integrity": "sha512-Q3GmOCLSD5BXSjvlLkMsJLXWXb4SO0gA2Aya8JaG1y0doQT/CdGcYXrsCrCT3ot13wqp0HdGQ/ATNd0cNjmz2A==", "dependencies": { "tslib": "^2.3.0" }, @@ -688,9 +1044,9 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "16.1.5", - "@angular/core": "16.1.5", - "@angular/platform-browser": "16.1.5", + "@angular/common": "16.2.2", + "@angular/core": "16.2.2", + "@angular/platform-browser": "16.2.2", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -704,12 +1060,12 @@ } }, "node_modules/@angular/localize": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-16.1.5.tgz", - "integrity": "sha512-8ApTdmv4sH0VbW9kVNanze5DEmb3OPIGzbD19jzvUSb6mTVMfUcQrsf4h+H8+cT+epBhor8RgVeVbUJaUbaLNQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-16.2.2.tgz", + "integrity": "sha512-6WO8icVzOGAjZd0Zm4mXisg1ljhmB1+UFSjUdHWrXd0QxAKKhHuI2P91v8J+5j1wl27JIKzTVA7+/gnNQMmGsw==", "dependencies": { "@babel/core": "7.22.5", - "fast-glob": "3.2.12", + "fast-glob": "3.3.0", "yargs": "^17.2.1" }, "bin": { @@ -721,8 +1077,8 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/compiler": "16.1.5", - "@angular/compiler-cli": "16.1.5" + "@angular/compiler": "16.2.2", + "@angular/compiler-cli": "16.2.2" } }, "node_modules/@angular/localize/node_modules/ansi-styles": { @@ -815,9 +1171,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.1.5.tgz", - "integrity": "sha512-TLM29KPr0A0pQ0YEmSy0JUOkfBXfwfBFzXQSt9SOiUs0wgDVVLMdGOpR/tbvBx2QfrSU3qgOX8P1FXIPJch6TQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.2.2.tgz", + "integrity": "sha512-9RwUiHYCAmEirXqwWL/rPfXHMkU9PnpGinok6tmHF8agAmJs1kMWZedxG0GnreTzpTlBu/dI/4v6VDfR9S/D6Q==", "dependencies": { "tslib": "^2.3.0" }, @@ -825,9 +1181,9 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/animations": "16.1.5", - "@angular/common": "16.1.5", - "@angular/core": "16.1.5" + "@angular/animations": "16.2.2", + "@angular/common": "16.2.2", + "@angular/core": "16.2.2" }, "peerDependenciesMeta": { "@angular/animations": { @@ -836,9 +1192,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.1.5.tgz", - "integrity": "sha512-ugdIXeN5IVj9o15ywH32hxNI0ZLyakpBGqMTHZSeEhU/uN6ajAJX7z6okdMbJ7dlTyBO8eFV1KDX3aAz+sK9bg==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.2.2.tgz", + "integrity": "sha512-EOGDZ+oABB/aNiBR//wxc6McycjF99/9ds74Q6WoHiNy8CYkzH3plr5pHoy4zkriSyqzoETg2tCu7jSiiMbjRg==", "dependencies": { "tslib": "^2.3.0" }, @@ -846,16 +1202,16 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "16.1.5", - "@angular/compiler": "16.1.5", - "@angular/core": "16.1.5", - "@angular/platform-browser": "16.1.5" + "@angular/common": "16.2.2", + "@angular/compiler": "16.2.2", + "@angular/core": "16.2.2", + "@angular/platform-browser": "16.2.2" } }, "node_modules/@angular/platform-server": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-16.1.5.tgz", - "integrity": "sha512-hpsjqgEylaE3SFObrVzNLq3g37mM8hUWas0+Gl3/BIsnGxiIuArhW9mhgYjoIgAOhl+jqDiAU1a5eNzivvOMtQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-16.2.2.tgz", + "integrity": "sha512-mvJsmPJMG6GzzGvOMSkjPgE9zHpuWkFfaO6HTSj0GvxyvxjrlQKsVW87gxEgqfTdhN4JbgmMA4eC9x8625VPyg==", "dependencies": { "tslib": "^2.3.0", "xhr2": "^0.2.0" @@ -864,17 +1220,17 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/animations": "16.1.5", - "@angular/common": "16.1.5", - "@angular/compiler": "16.1.5", - "@angular/core": "16.1.5", - "@angular/platform-browser": "16.1.5" + "@angular/animations": "16.2.2", + "@angular/common": "16.2.2", + "@angular/compiler": "16.2.2", + "@angular/core": "16.2.2", + "@angular/platform-browser": "16.2.2" } }, "node_modules/@angular/router": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.1.5.tgz", - "integrity": "sha512-L1gyWA16U+XgcxWmemWjy08/OPCjch9sBEiHaikuW8i9Ys0nx9ic3wh8Fyu6cVKQE9aQZ7xLYT5CdPPwYxclTw==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.2.2.tgz", + "integrity": "sha512-r4KMVUVEWqjOZK0ZUsY8jRqscseGvgcigcikvYJwfxPqtCGYY7RoVAFY7HUtmXC0GAv1aIybK5o/MKTLaecD5Q==", "dependencies": { "tslib": "^2.3.0" }, @@ -882,9 +1238,9 @@ "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "16.1.5", - "@angular/core": "16.1.5", - "@angular/platform-browser": "16.1.5", + "@angular/common": "16.2.2", + "@angular/core": "16.2.2", + "@angular/platform-browser": "16.2.2", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -950,9 +1306,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.7.tgz", - "integrity": "sha512-p+jPjMG+SI8yvIaxGgeW24u7q9+5+TGpZh8/CuB7RhBKd7RCy8FayNEFNNKrNK/eUcY/4ExQqLmyrvBXKsIcwQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", "dependencies": { "@babel/types": "^7.22.5", "@jridgewell/gen-mapping": "^0.3.2", @@ -989,11 +1345,11 @@ } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz", - "integrity": "sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.10.tgz", + "integrity": "sha512-Av0qubwDQxC56DoUReVDeLfMEjYYSN1nZrTUrWkXd7hpU73ymRANkbuDm3yni9npkn+RXy9nNbEJZEzXr7xrfQ==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.10" }, "engines": { "node": ">=6.9.0" @@ -1039,9 +1395,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz", - "integrity": "sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.10.tgz", + "integrity": "sha512-5IBb77txKYQPpOEdUdIhBx8VrZyDCQ+H82H0+5dX1TmuscP5vJKEE3cKurjtIw/vFwzbVH48VweE78kVDBrqjA==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.5", @@ -1060,17 +1416,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -1104,9 +1449,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz", - "integrity": "sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", + "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -1115,7 +1460,7 @@ "resolve": "^1.14.2" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/helper-environment-visitor": { @@ -1189,17 +1534,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", @@ -1274,9 +1608,9 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", - "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { "@babel/types": "^7.22.5" }, @@ -1663,13 +1997,13 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz", - "integrity": "sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.10.tgz", + "integrity": "sha512-eueE8lvKVzq5wIObKK/7dvoeKJ+xc6TvRn6aysIjS6pSCeLy7S/eVi7pEQknZqyqvzaNKdDtem8nUNTBgDVR2g==", "dependencies": { "@babel/helper-environment-visitor": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.9", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -1710,9 +2044,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz", - "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.10.tgz", + "integrity": "sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -1776,17 +2110,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", @@ -1803,9 +2126,9 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz", - "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.10.tgz", + "integrity": "sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -2149,9 +2472,9 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz", - "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.10.tgz", + "integrity": "sha512-MMkQqZAZ+MGj+jGTG3OTuhKeBpNcO+0oCEbrGNEaOmiEn+1MzRyQlYsruGiU8RTK3zV6XwrVJTmwiDOyYK6J9g==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", @@ -2225,12 +2548,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz", - "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", + "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", - "regenerator-transform": "^0.15.1" + "regenerator-transform": "^0.15.2" }, "engines": { "node": ">=6.9.0" @@ -2254,16 +2577,16 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.5.tgz", - "integrity": "sha512-bg4Wxd1FWeFx3daHFTWk1pkSWK/AyQuiyAoeZAOkAOUBjnZPH6KT7eMxouV47tQ6hl6ax2zyAWBdWZXbrvXlaw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz", + "integrity": "sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ==", "dependencies": { "@babel/helper-module-imports": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.3", - "babel-plugin-polyfill-corejs3": "^0.8.1", - "babel-plugin-polyfill-regenerator": "^0.5.0", - "semver": "^6.3.0" + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -2352,9 +2675,9 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz", - "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", + "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -2411,12 +2734,12 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.5.tgz", - "integrity": "sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz", + "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==", "dependencies": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.22.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", @@ -2441,13 +2764,13 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.7", "@babel/plugin-transform-async-to-generator": "^7.22.5", "@babel/plugin-transform-block-scoped-functions": "^7.22.5", "@babel/plugin-transform-block-scoping": "^7.22.5", "@babel/plugin-transform-class-properties": "^7.22.5", "@babel/plugin-transform-class-static-block": "^7.22.5", - "@babel/plugin-transform-classes": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.6", "@babel/plugin-transform-computed-properties": "^7.22.5", "@babel/plugin-transform-destructuring": "^7.22.5", "@babel/plugin-transform-dotall-regex": "^7.22.5", @@ -2472,7 +2795,7 @@ "@babel/plugin-transform-object-rest-spread": "^7.22.5", "@babel/plugin-transform-object-super": "^7.22.5", "@babel/plugin-transform-optional-catch-binding": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.6", "@babel/plugin-transform-parameters": "^7.22.5", "@babel/plugin-transform-private-methods": "^7.22.5", "@babel/plugin-transform-private-property-in-object": "^7.22.5", @@ -2490,11 +2813,11 @@ "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/preset-modules": "^0.1.5", "@babel/types": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.3", - "babel-plugin-polyfill-corejs3": "^0.8.1", - "babel-plugin-polyfill-regenerator": "^0.5.0", - "core-js-compat": "^3.30.2", - "semver": "^6.3.0" + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -2512,9 +2835,9 @@ } }, "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", + "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", @@ -2523,7 +2846,7 @@ "esutils": "^2.0.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/regjsgen": { @@ -2532,9 +2855,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", - "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -2575,21 +2898,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", + "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", "dependencies": { "@babel/helper-string-parser": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.5", @@ -2704,9 +3016,9 @@ } }, "node_modules/@cypress/request": { - "version": "2.88.11", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.11.tgz", - "integrity": "sha512-M83/wfQ1EkspjkE2lNWNV5ui2Cv7UCv1swW1DqljahbzLVWltcsexQh8jYtuS/vzFXP+HySntGM83ZXA9fn17w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", + "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", "optional": true, "dependencies": { "aws-sign2": "~0.7.0", @@ -2722,9 +3034,9 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "~6.10.3", + "qs": "6.10.4", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", + "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", "uuid": "^8.3.2" }, @@ -2792,9 +3104,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], @@ -2807,9 +3119,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "cpu": [ "arm64" ], @@ -2822,9 +3134,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "cpu": [ "x64" ], @@ -2837,9 +3149,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "cpu": [ "arm64" ], @@ -2852,9 +3164,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "cpu": [ "x64" ], @@ -2867,9 +3179,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "cpu": [ "arm64" ], @@ -2882,9 +3194,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "cpu": [ "x64" ], @@ -2897,9 +3209,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "cpu": [ "arm" ], @@ -2912,9 +3224,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "cpu": [ "arm64" ], @@ -2927,9 +3239,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "cpu": [ "ia32" ], @@ -2942,9 +3254,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], @@ -2957,9 +3269,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "cpu": [ "mips64el" ], @@ -2972,9 +3284,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "cpu": [ "ppc64" ], @@ -2987,9 +3299,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "cpu": [ "riscv64" ], @@ -3002,9 +3314,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "cpu": [ "s390x" ], @@ -3017,9 +3329,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "cpu": [ "x64" ], @@ -3032,9 +3344,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "cpu": [ "x64" ], @@ -3047,9 +3359,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "cpu": [ "x64" ], @@ -3062,9 +3374,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "cpu": [ "x64" ], @@ -3077,9 +3389,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "cpu": [ "arm64" ], @@ -3092,9 +3404,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "cpu": [ "ia32" ], @@ -3107,9 +3419,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], @@ -3522,12 +3834,19 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@nicolo-ribaudo/semver-v6": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz", - "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==", - "bin": { - "semver": "bin/semver.js" + "node_modules/@ngtools/webpack": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.0.tgz", + "integrity": "sha512-c9jv4r7GnLTpnPOeF+a9yAm/3/2wwl9lMBU32i9hlY+q/Hqde4PiL95bUOLnRRL1I64DV7BFTlSZqSPgDpFXZQ==", + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^16.0.0", + "typescript": ">=4.9.3 <5.2", + "webpack": "^5.54.0" } }, "node_modules/@nodelib/fs.scandir": { @@ -3709,6 +4028,21 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@schematics/angular": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.0.tgz", + "integrity": "sha512-Ib0/ZCkjWt7a5p3209JVwEWwf41v03K3ylvlxLIEo1ZGijAZAlrBj4GrA5YQ+TmPm2hRyt+owss7x91/x+i0Gw==", + "dependencies": { + "@angular-devkit/core": "16.2.0", + "@angular-devkit/schematics": "16.2.0", + "jsonc-parser": "3.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, "node_modules/@sideway/address": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", @@ -3999,9 +4333,9 @@ "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" }, "node_modules/@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==" + "version": "18.17.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.18.tgz", + "integrity": "sha512-/4QOuy3ZpV7Ya1GTRz5CYSz3DgkKpyUptXuQ5PPce7uuyJAOR7r9FhkmxJfvcNUXyklbC63a+YvB3jxy7s9ngw==" }, "node_modules/@types/qrcode": { "version": "1.5.0", @@ -4444,6 +4778,92 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@wessberg/ts-evaluator": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/@wessberg/ts-evaluator/-/ts-evaluator-0.0.27.tgz", + "integrity": "sha512-7gOpVm3yYojUp/Yn7F4ZybJRxyqfMNf0LXK5KJiawbPfL0XTsJV+0mgrEDjOIR6Bi0OYk2Cyg4tjFu1r8MCZaA==", + "deprecated": "this package has been renamed to ts-evaluator. Please install ts-evaluator instead", + "dependencies": { + "chalk": "^4.1.0", + "jsdom": "^16.4.0", + "object-path": "^0.11.5", + "tslib": "^2.0.3" + }, + "engines": { + "node": ">=10.1.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/wessberg/ts-evaluator?sponsor=1" + }, + "peerDependencies": { + "typescript": ">=3.2.x || >= 4.x" + } + }, + "node_modules/@wessberg/ts-evaluator/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wessberg/ts-evaluator/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/@wessberg/ts-evaluator/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wessberg/ts-evaluator/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@wessberg/ts-evaluator/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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@wessberg/ts-evaluator/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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -4492,6 +4912,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -4874,8 +5303,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "optional": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/at-least-node": { "version": "1.0.0", @@ -4972,11 +5400,11 @@ } }, "node_modules/babel-loader": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", - "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "dependencies": { - "find-cache-dir": "^3.3.2", + "find-cache-dir": "^4.0.0", "schema-utils": "^4.0.0" }, "engines": { @@ -5003,39 +5431,47 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.4.tgz", - "integrity": "sha512-9WeK9snM1BfxB38goUEv2FLnA6ja07UMfazFHzCXUb3NyDZAwfXvQiURQ6guTTMeHcOsdknULm1PDhs4uWtKyA==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", + "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.4.1", - "@nicolo-ribaudo/semver-v6": "^6.3.3" + "@babel/helper-define-polyfill-provider": "^0.4.2", + "semver": "^6.3.1" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.2.tgz", - "integrity": "sha512-Cid+Jv1BrY9ReW9lIfNlNpsI53N+FN7gE+f73zLAUbr9C52W4gKLWSByx47pfDJsEysojKArqOtOKZSVIIUTuQ==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", + "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.1", + "@babel/helper-define-polyfill-provider": "^0.4.2", "core-js-compat": "^3.31.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.1.tgz", - "integrity": "sha512-L8OyySuI6OSQ5hFy9O+7zFjyr4WhAfRjLIOkhQGYl+emwJkd/S4XXT1JpfrgR1jrQ1NcGiOh+yAdGlF8pnC3Jw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", + "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.1" + "@babel/helper-define-polyfill-provider": "^0.4.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/balanced-match": { @@ -5304,6 +5740,11 @@ "browser-pack-flat": "cli.js" } }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, "node_modules/browser-resolve": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", @@ -5580,9 +6021,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "funding": [ { "type": "opencollective", @@ -5598,9 +6039,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", "update-browserslist-db": "^1.0.11" }, "bin": { @@ -5805,9 +6246,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001516", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001516.tgz", - "integrity": "sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==", + "version": "1.0.30001522", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz", + "integrity": "sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==", "funding": [ { "type": "opencollective", @@ -6122,7 +6563,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "optional": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -6135,6 +6575,11 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, "node_modules/common-shakeify": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/common-shakeify/-/common-shakeify-1.1.1.tgz", @@ -6156,11 +6601,6 @@ "node": ">=4.0.0" } }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" - }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -6354,11 +6794,11 @@ } }, "node_modules/core-js-compat": { - "version": "3.31.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.31.1.tgz", - "integrity": "sha512-wIDWd2s5/5aJSdpOJHfSibxNODxoGoWOBHt8JSPB41NOE94M7kuTPZCYLOlTtuoXTsBPKobpJ6T+y0SSy5L9SA==", + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.1.tgz", + "integrity": "sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA==", "dependencies": { - "browserslist": "^4.21.9" + "browserslist": "^4.21.10" }, "funding": { "type": "opencollective", @@ -6471,9 +6911,9 @@ "dev": true }, "node_modules/critters": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.19.tgz", - "integrity": "sha512-Fm4ZAXsG0VzWy1U30rP4qxbaWGSsqXDgSupJW1OUJGDAs0KWC+j37v7p5a2kZ9BPJvhRzWm3be+Hc9WvQOBUOw==", + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz", + "integrity": "sha512-CImNRorKOl5d8TWcnAz5n5izQ6HFsvz29k327/ELy6UFcmbiZNOsinaKvzv16WZR0P6etfSWYzE47C4/56B3Uw==", "dependencies": { "chalk": "^4.1.0", "css-select": "^5.1.0", @@ -6644,6 +7084,27 @@ "node": ">=4" } }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -6652,15 +7113,15 @@ "peer": true }, "node_modules/cypress": { - "version": "12.17.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.17.2.tgz", - "integrity": "sha512-hxWAaWbqQBzzMuadSGSuQg5PDvIGOovm6xm0hIfpCVcORsCAj/gF2p0EvfnJ4f+jK2PCiDgP6D2eeE9/FK4Mjg==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.2.0.tgz", + "integrity": "sha512-AvDQxBydE771GTq0TR4ZUBvv9m9ffXuB/ueEtpDF/6gOcvFR96amgwSJP16Yhqw6VhmwqspT5nAGzoxxB+D89g==", "hasInstallScript": true, "optional": true, "dependencies": { - "@cypress/request": "^2.88.11", + "@cypress/request": "^3.0.0", "@cypress/xvfb": "^1.2.4", - "@types/node": "^14.14.31", + "@types/node": "^18.17.5", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", @@ -6693,6 +7154,7 @@ "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", + "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "semver": "^7.5.3", @@ -6705,13 +7167,13 @@ "cypress": "bin/cypress" }, "engines": { - "node": "^14.0.0 || ^16.0.0 || >=18.0.0" + "node": "^16.0.0 || ^18.0.0 || >=20.0.0" } }, "node_modules/cypress-fail-on-console-error": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/cypress-fail-on-console-error/-/cypress-fail-on-console-error-4.0.3.tgz", - "integrity": "sha512-v2nPupd2brtxKLkDQX58SbEPWRF/2nDbqPTnYyhPIYHqG7U3P2dGUZ3zraETKKoLhU3+C0otjgB6Vg/bHhocQw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cypress-fail-on-console-error/-/cypress-fail-on-console-error-5.0.0.tgz", + "integrity": "sha512-xui/aSu8rmExZjZNgId3iX0MsGZih6ZoFH+54vNHrK3HaqIZZX5hUuNhAcmfSoM1rIDc2DeITeVaMn/hiQ9IWQ==", "optional": true, "dependencies": { "chai": "^4.3.4", @@ -6721,19 +7183,9 @@ } }, "node_modules/cypress-wait-until": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cypress-wait-until/-/cypress-wait-until-2.0.0.tgz", - "integrity": "sha512-ulUZyrWBn+OuC8oiQuGKAScDYfpaWnE3dEE/raUo64w4RHQxZrQ/iMIWT4ZjGMMPr3P+BFEALCRnjQeRqzZj6g==", - "optional": true, - "engines": { - "node": ">=18.16.0", - "npm": ">=9.5.1" - } - }, - "node_modules/cypress/node_modules/@types/node": { - "version": "14.18.53", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.53.tgz", - "integrity": "sha512-soGmOpVBUq+gaBMwom1M+krC/NNbWlosh4AtGA03SyWNDiqSKtwp7OulO1M6+mg8YkHMvJ/y0AkCeO8d1hNb7A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cypress-wait-until/-/cypress-wait-until-2.0.1.tgz", + "integrity": "sha512-+IyVnYNiaX1+C+V/LazrJWAi/CqiwfNoRSrFviECQEyolW1gDRy765PZosL2alSSGK8V10Y7BGfOQyZUDgmnjQ==", "optional": true }, "node_modules/cypress/node_modules/ansi-styles": { @@ -6921,6 +7373,19 @@ "node": ">=0.10" } }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/date-format": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", @@ -6961,6 +7426,11 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -7031,7 +7501,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "optional": true, "engines": { "node": ">=0.4.0" } @@ -7228,6 +7697,25 @@ } ] }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "engines": { + "node": ">=8" + } + }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", @@ -7320,9 +7808,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "node_modules/electron-to-chromium": { - "version": "1.4.463", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.463.tgz", - "integrity": "sha512-fT3hvdUWLjDbaTGzyOjng/CQhQJSQP8ThO3XZAoaxHvHo2kUXiRQVMj9M235l8uDFiNPsPa6KHT1p3RaR6ugRw==" + "version": "1.4.500", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.500.tgz", + "integrity": "sha512-P38NO8eOuWOKY1sQk5yE0crNtrjgjJj6r3NrbIKtG18KzCHmHE2Bt+aQA7/y0w3uYsHWxDa6icOohzjLJ4vJ4A==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -7662,9 +8150,9 @@ } }, "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -7673,34 +8161,34 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "node_modules/esbuild-wasm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.19.tgz", - "integrity": "sha512-X9UQEMJMZXwlGCfqcBmJ1jEa+KrLfd+gCBypO/TSzo5hZvbVwFqpxj1YCuX54ptTF75wxmrgorR4RL40AKtLVg==", + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.18.17.tgz", + "integrity": "sha512-9OHGcuRzy+I8ziF9FzjfKLWAPbvi0e/metACVg9k6bK+SI4FFxeV6PcZsz8RIVaMD4YNehw+qj6UMR3+qj/EuQ==", "bin": { "esbuild": "bin/esbuild" }, @@ -8595,9 +9083,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -8740,19 +9228,18 @@ } }, "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/find-up": { @@ -9166,6 +9653,17 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, + "node_modules/guess-parser": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/guess-parser/-/guess-parser-0.4.22.tgz", + "integrity": "sha512-KcUWZ5ACGaBM69SbqwVIuWGoSAgD+9iJnchR9j/IarVI1jHVeXv+bUXBIMeqVMSKt3zrn0Dgf9UpcOEpPBLbSg==", + "dependencies": { + "@wessberg/ts-evaluator": "0.0.27" + }, + "peerDependencies": { + "typescript": ">=3.7.5" + } + }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -9342,6 +9840,17 @@ "wbuf": "^1.1.0" } }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/html-entities": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", @@ -10076,6 +10585,11 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, "node_modules/is-regex": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", @@ -10299,9 +10813,9 @@ } }, "node_modules/jiti": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", - "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==", + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.3.tgz", + "integrity": "sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==", "bin": { "jiti": "bin/jiti.js" } @@ -10358,6 +10872,101 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "optional": true }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/jsdom/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -11082,38 +11691,16 @@ } }, "node_modules/magic-string": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", - "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", + "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "@jridgewell/sourcemap-codec": "^1.4.15" }, "engines": { "node": ">=12" } }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -11945,9 +12532,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", "optional": true, "bin": { "node-gyp-build": "bin.js", @@ -12126,6 +12713,11 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -12150,6 +12742,14 @@ "node": ">= 0.4" } }, + "node_modules/object-path": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", + "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", + "engines": { + "node": ">= 10.12.0" + } + }, "node_modules/object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", @@ -12697,9 +13297,9 @@ } }, "node_modules/piscina": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.0.0.tgz", + "integrity": "sha512-641nAmJS4k4iqpNUqfggqUBUMmlw0ZoM5VZKdQkV2e970Inn3Tk9kroCc1wpsYLD07vCwpys5iY0d3xI/9WkTg==", "dependencies": { "eventemitter-asyncresource": "^1.0.0", "hdr-histogram-js": "^2.0.1", @@ -12710,14 +13310,93 @@ } }, "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dependencies": { - "find-up": "^4.0.0" + "find-up": "^6.3.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/pkg-dir/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pngjs": { @@ -12740,9 +13419,9 @@ } }, "node_modules/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.4.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", + "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", "funding": [ { "type": "opencollective", @@ -12767,13 +13446,12 @@ } }, "node_modules/postcss-loader": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.2.tgz", - "integrity": "sha512-c7qDlXErX6n0VT+LUsW+nwefVtTu3ORtVvK8EXuUIDcxo+b/euYqpuHlJAvePb0Af5e8uMjR/13e0lTuYifaig==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", + "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", "dependencies": { - "cosmiconfig": "^8.1.3", + "cosmiconfig": "^8.2.0", "jiti": "^1.18.2", - "klona": "^2.0.6", "semver": "^7.3.8" }, "engines": { @@ -12982,8 +13660,7 @@ "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "optional": true + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, "node_modules/public-encrypt": { "version": "4.0.3", @@ -13101,6 +13778,11 @@ "node": ">=0.4.x" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -13309,9 +13991,9 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dependencies": { "@babel/runtime": "^7.8.4" } @@ -13572,9 +14254,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { - "version": "1.63.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.2.tgz", - "integrity": "sha512-u56TU0AIFqMtauKl/OJ1AeFsXqRHkgO7nCWmHaDwfxDo9GUMSqBA4NEh6GMuh1CYVM7zuROYtZrHzPc2ixK+ww==", + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.1.tgz", + "integrity": "sha512-16rRACSOFEE8VN7SCgBu1MpYCyN7urj9At898tyzdXFhC+a+yOX5dXwAR7L8/IdPJ1NB8OYoXmD55DM30B2kEQ==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -13588,11 +14270,10 @@ } }, "node_modules/sass-loader": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.1.tgz", - "integrity": "sha512-cBTxmgyVA1nXPvIK4brjJMXOMJ2v2YrQEuHqLw3LylGb3gsR6jAvdjHMcy/+JGTmmIF9SauTrLLR7bsWDMWqgg==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", + "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", "dependencies": { - "klona": "^2.0.6", "neo-async": "^2.6.2" }, "engines": { @@ -13630,6 +14311,17 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", @@ -14638,6 +15330,11 @@ "node": ">=0.10" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, "node_modules/syntax-error": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", @@ -14704,9 +15401,9 @@ } }, "node_modules/terser": { - "version": "5.17.7", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.7.tgz", - "integrity": "sha512-/bi0Zm2C6VAexlGgLlVxA0P2lru/sdLyfCVaRMfKVo9nWxbmz7f/sD8VPybPeSUJaJcwmCJis9pBIhcVcG1QcQ==", + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -14954,16 +15651,36 @@ } }, "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "optional": true, + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dependencies": { - "psl": "^1.1.28", "punycode": "^2.1.1" }, "engines": { - "node": ">=0.8" + "node": ">=8" } }, "node_modules/transform-ast": { @@ -15099,9 +15816,9 @@ } }, "node_modules/tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -15441,6 +16158,15 @@ "querystring": "0.2.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/url/node_modules/punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", @@ -15516,13 +16242,13 @@ } }, "node_modules/vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz", + "integrity": "sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==", "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.26", + "rollup": "^3.25.2" }, "bin": { "vite": "bin/vite.js" @@ -15530,12 +16256,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -15548,6 +16278,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -15577,6 +16310,26 @@ "node": ">=0.10.0" } }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/wait-on": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz", @@ -15624,10 +16377,18 @@ "defaults": "^1.0.3" } }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "engines": { + "node": ">=10.4" + } + }, "node_modules/webpack": { - "version": "5.86.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", - "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", @@ -15638,7 +16399,7 @@ "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.1", + "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -15648,7 +16409,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", @@ -15698,9 +16459,9 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.0.tgz", - "integrity": "sha512-HmNB5QeSl1KpulTBQ8UT4FPrByYyaLxpJoQ0+s7EvUrMc16m0ZS1sgb1XGqzmgCPk0c9y+aaXxn11tbLzuM7NQ==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -15708,7 +16469,7 @@ "@types/serve-index": "^1.9.1", "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", + "@types/ws": "^8.5.5", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.0.11", "chokidar": "^3.5.3", @@ -15777,6 +16538,26 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "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/webpack-merge": { "version": "5.9.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", @@ -15874,6 +16655,32 @@ "node": ">=0.8.0" } }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -16042,15 +16849,15 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "engines": { - "node": ">=10.0.0" + "node": ">=8.3.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "utf-8-validate": "^5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -16069,6 +16876,16 @@ "node": ">= 6" } }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -16274,49 +17091,49 @@ } }, "@angular-devkit/architect": { - "version": "0.1601.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1601.4.tgz", - "integrity": "sha512-OOSbNlDy+Q3jY0oFHaq8kkna9HYI1zaS8IHeCIDP6T/ZIAVad4+HqXAL4SKQrKJikkoBQv1Z/eaDBL5XPFK9Bw==", + "version": "0.1602.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.0.tgz", + "integrity": "sha512-ZRmUTBeD+uGr605eOHnsovEn6f1mOBI+kxP64DRvagNweX5TN04s3iyQ8jmLSAHQD9ush31LFxv3dVNxv3ceXQ==", "requires": { - "@angular-devkit/core": "16.1.4", + "@angular-devkit/core": "16.2.0", "rxjs": "7.8.1" } }, "@angular-devkit/build-angular": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.1.4.tgz", - "integrity": "sha512-LiHM7R20fTHg/eM+Iabotj08edP5wVBQahRfVNLxERo8X6VJgSjVChnsh3AQJkRywlGuFe20AOQYpyLyN367Ug==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.0.tgz", + "integrity": "sha512-miylwjOqvlKmYrzS84bjRaJrecZxOXH9xsPVvQE8VBe8UKePJjRAL6yyOqXUOGtzlch2YmT98RAnuni7y0FEAw==", "requires": { "@ampproject/remapping": "2.2.1", - "@angular-devkit/architect": "0.1601.4", - "@angular-devkit/build-webpack": "0.1601.4", - "@angular-devkit/core": "16.1.4", - "@babel/core": "7.22.5", - "@babel/generator": "7.22.7", + "@angular-devkit/architect": "0.1602.0", + "@angular-devkit/build-webpack": "0.1602.0", + "@angular-devkit/core": "16.2.0", + "@babel/core": "7.22.9", + "@babel/generator": "7.22.9", "@babel/helper-annotate-as-pure": "7.22.5", - "@babel/helper-split-export-declaration": "7.22.5", + "@babel/helper-split-export-declaration": "7.22.6", "@babel/plugin-proposal-async-generator-functions": "7.20.7", "@babel/plugin-transform-async-to-generator": "7.22.5", - "@babel/plugin-transform-runtime": "7.22.5", - "@babel/preset-env": "7.22.5", - "@babel/runtime": "7.22.5", + "@babel/plugin-transform-runtime": "7.22.9", + "@babel/preset-env": "7.22.9", + "@babel/runtime": "7.22.6", "@babel/template": "7.22.5", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "16.1.4", + "@ngtools/webpack": "16.2.0", "@vitejs/plugin-basic-ssl": "1.0.1", "ansi-colors": "4.1.3", "autoprefixer": "10.4.14", - "babel-loader": "9.1.2", + "babel-loader": "9.1.3", "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.21.5", - "cacache": "17.1.3", "chokidar": "3.5.3", "copy-webpack-plugin": "11.0.0", - "critters": "0.0.19", + "critters": "0.0.20", "css-loader": "6.8.1", - "esbuild": "0.17.19", - "esbuild-wasm": "0.17.19", - "fast-glob": "3.2.12", + "esbuild": "0.18.17", + "esbuild-wasm": "0.18.17", + "fast-glob": "3.3.1", + "guess-parser": "0.4.22", "https-proxy-agent": "5.0.1", "inquirer": "8.2.4", "jsonc-parser": "3.2.0", @@ -16325,74 +17142,258 @@ "less-loader": "11.1.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.1", - "magic-string": "0.30.0", + "magic-string": "0.30.1", "mini-css-extract-plugin": "2.7.6", "mrmime": "1.0.1", "open": "8.4.2", "ora": "5.4.1", "parse5-html-rewriting-stream": "7.0.0", "picomatch": "2.3.1", - "piscina": "3.2.0", - "postcss": "8.4.24", - "postcss-loader": "7.3.2", + "piscina": "4.0.0", + "postcss": "8.4.27", + "postcss-loader": "7.3.3", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", - "sass": "1.63.2", - "sass-loader": "13.3.1", - "semver": "7.5.3", + "sass": "1.64.1", + "sass-loader": "13.3.2", + "semver": "7.5.4", "source-map-loader": "4.0.1", "source-map-support": "0.5.21", - "terser": "5.17.7", + "terser": "5.19.2", "text-table": "0.2.0", "tree-kill": "1.2.2", - "tslib": "2.5.3", - "vite": "4.3.9", - "webpack": "5.86.0", + "tslib": "2.6.1", + "vite": "4.4.7", + "webpack": "5.88.2", "webpack-dev-middleware": "6.1.1", - "webpack-dev-server": "4.15.0", + "webpack-dev-server": "4.15.1", "webpack-merge": "5.9.0", "webpack-subresource-integrity": "5.1.0" }, "dependencies": { - "@ngtools/webpack": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.1.4.tgz", - "integrity": "sha512-+8bfavDH8eWxjlJFYr6bkjcRHhy95j+f8oNn7/sGLNu4L96nuE2AZ011XIu2dJahCnNiBvwc1EpkKa92t9rkaA==", - "requires": {} + "@babel/core": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@esbuild/android-arm": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz", + "integrity": "sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz", + "integrity": "sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==", + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz", + "integrity": "sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==", + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz", + "integrity": "sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==", + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz", + "integrity": "sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==", + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz", + "integrity": "sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==", + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz", + "integrity": "sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==", + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz", + "integrity": "sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==", + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz", + "integrity": "sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==", + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz", + "integrity": "sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz", + "integrity": "sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz", + "integrity": "sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==", + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz", + "integrity": "sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==", + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz", + "integrity": "sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==", + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz", + "integrity": "sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==", + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz", + "integrity": "sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==", + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz", + "integrity": "sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==", + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz", + "integrity": "sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==", + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz", + "integrity": "sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==", + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz", + "integrity": "sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==", + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz", + "integrity": "sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==", + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz", + "integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==", + "optional": true + }, + "esbuild": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz", + "integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==", + "optional": true, + "requires": { + "@esbuild/android-arm": "0.18.17", + "@esbuild/android-arm64": "0.18.17", + "@esbuild/android-x64": "0.18.17", + "@esbuild/darwin-arm64": "0.18.17", + "@esbuild/darwin-x64": "0.18.17", + "@esbuild/freebsd-arm64": "0.18.17", + "@esbuild/freebsd-x64": "0.18.17", + "@esbuild/linux-arm": "0.18.17", + "@esbuild/linux-arm64": "0.18.17", + "@esbuild/linux-ia32": "0.18.17", + "@esbuild/linux-loong64": "0.18.17", + "@esbuild/linux-mips64el": "0.18.17", + "@esbuild/linux-ppc64": "0.18.17", + "@esbuild/linux-riscv64": "0.18.17", + "@esbuild/linux-s390x": "0.18.17", + "@esbuild/linux-x64": "0.18.17", + "@esbuild/netbsd-x64": "0.18.17", + "@esbuild/openbsd-x64": "0.18.17", + "@esbuild/sunos-x64": "0.18.17", + "@esbuild/win32-arm64": "0.18.17", + "@esbuild/win32-ia32": "0.18.17", + "@esbuild/win32-x64": "0.18.17" + } + }, + "fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } }, "loader-utils": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==" - }, - "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" } } }, "@angular-devkit/build-webpack": { - "version": "0.1601.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1601.4.tgz", - "integrity": "sha512-GC1y//ScAYbYQ68Wri2QgTEekC4hRxBC+xEkYL9OFiAMQ4mcN+eYvbkQBX8enJwDMXpkYfLR6VV8cChjAVYIgg==", + "version": "0.1602.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.0.tgz", + "integrity": "sha512-KdSr6iAcO30i/LIGL8mYi+d1buVXuDCp2dptzEJ4vxReOMFJca90KLwb+tVHEqqnDb0WkNfWm8Ii2QYh2FrNyA==", "requires": { - "@angular-devkit/architect": "0.1601.4", + "@angular-devkit/architect": "0.1602.0", "rxjs": "7.8.1" } }, "@angular-devkit/core": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.1.4.tgz", - "integrity": "sha512-WCAzNi9LxpFIi2WVPaJQd2kHPqCnCexWzUZN05ltJuBGCQL1O+LgRHGwnQ4WZoqmrF5tcWt2a3GFtJ3DgMc1hw==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.0.tgz", + "integrity": "sha512-l1k6Rqm3YM16BEn3CWyQKrk9xfu+2ux7Bw3oS+h1TO4/RoxO2PgHj8LLRh/WNrYVarhaqO7QZ5ePBkXNMkzJ1g==", "requires": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -16419,23 +17420,35 @@ } } }, + "@angular-devkit/schematics": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.0.tgz", + "integrity": "sha512-QMDJXPE0+YQJ9Ap3MMzb0v7rx6ZbBEokmHgpdIjN3eILYmbAdsSGE8HTV8NjS9nKmcyE9OGzFCMb7PFrDTlTAw==", + "requires": { + "@angular-devkit/core": "16.2.0", + "jsonc-parser": "3.2.0", + "magic-string": "0.30.1", + "ora": "5.4.1", + "rxjs": "7.8.1" + } + }, "@angular/animations": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.1.5.tgz", - "integrity": "sha512-CUm81m1N00EIza8LH81BJ+PoR23HzfoD+8ltASya9D0VurB6hlv0Axa5kQ0o02PQwCAU1a6RUUTsTjODc/mUYA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.2.2.tgz", + "integrity": "sha512-p0QefudkPGXjq9inZDrtW6WJrDcSeL+Nkc8lxubjg5fLQATKWKpsUBb+u2xEVu8OvWqj8BvrZUDnXYLyTdM4vw==", "requires": { "tslib": "^2.3.0" } }, "@angular/cli": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.1.4.tgz", - "integrity": "sha512-coSOLVLpOCOD5q9K9EAFFMrTES+HtdJiLy/iI9kdKNCKWUJpm8/svZ3JZOej3vPxYEp0AokXNOwORQnX21/qZQ==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.0.tgz", + "integrity": "sha512-xT8vJOyw6Rc2364XDW2jHagLgKu7342ktd/lt+c0u6R+AB2XVFMePR7VceLohX9N/vRUsbQ0nVSZr+ru/hA+HA==", "requires": { - "@angular-devkit/architect": "0.1601.4", - "@angular-devkit/core": "16.1.4", - "@angular-devkit/schematics": "16.1.4", - "@schematics/angular": "16.1.4", + "@angular-devkit/architect": "0.1602.0", + "@angular-devkit/core": "16.2.0", + "@angular-devkit/schematics": "16.2.0", + "@schematics/angular": "16.2.0", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "4.1.1", @@ -16447,33 +17460,11 @@ "ora": "5.4.1", "pacote": "15.2.0", "resolve": "1.22.2", - "semver": "7.5.3", + "semver": "7.5.4", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, "dependencies": { - "@angular-devkit/schematics": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.1.4.tgz", - "integrity": "sha512-yjRgwHAfFaeuimgbQtjwSUyXzEHpMSdTRb2zg+TOp6skoGvHOG8xXFJ7DjBkSMeAQdFF0fkxhPS9YmlxqNc+7A==", - "requires": { - "@angular-devkit/core": "16.1.4", - "jsonc-parser": "3.2.0", - "magic-string": "0.30.0", - "ora": "5.4.1", - "rxjs": "7.8.1" - } - }, - "@schematics/angular": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.1.4.tgz", - "integrity": "sha512-XfoeL+aBVIR/DzgVKGVhHW/TGQnqWvngyJVuCwXEVWzNfjxHYFkchXa78OItpAvTEr6/Y0Me9FQVAGVA4mMUyg==", - "requires": { - "@angular-devkit/core": "16.1.4", - "@angular-devkit/schematics": "16.1.4", - "jsonc-parser": "3.2.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -16505,14 +17496,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "requires": { - "lru-cache": "^6.0.0" - } - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -16550,25 +17533,25 @@ } }, "@angular/common": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.1.5.tgz", - "integrity": "sha512-XQVIpICniWXXMoXsr6X7Q3pVcYBeQ0FZF06BNNolkkkVuReYpqr3TwWrZfuB9TUmxdF6R5WZ+M3NAdXodDDUNA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.2.2.tgz", + "integrity": "sha512-2ww8/heDHkfJEBwjakbQeleq610ljcvytNs6ZN1xiXib060xMP+xx17Oa9I3onhi369JsKCHkMR5Qs2U5af1uA==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.1.5.tgz", - "integrity": "sha512-QNyisdr9lEN43v/e/fjS0H1vrJBMY8lIGpxVY1OOERFjA1clfMhaz5fiPE3vWFV5TOm3/ym9z2xuRXM6UoyWoA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.2.2.tgz", + "integrity": "sha512-0X9i5NsqjX++0gmFy0fy2Uc5dHJMxDq6Yu/j1L3RdbvycL1GW+P8GgPfIvD/+v/YiDqpOHQswQXLbkcHw1+svA==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler-cli": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.1.5.tgz", - "integrity": "sha512-j20hmPyM+rLJDU1y0ta9Uf7+o2oGjvGWGpyANbpuTlAfA1+VN5G3xD53FnNcmO6LZuAw0wDw6NDAyy+G55o8xQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.2.2.tgz", + "integrity": "sha512-+4i7o0yBc6xSljO8rdYL1G9AiZr2OW5dJAHfPuO21yNhp9BjIJ/TW+Sw1+o/WH4Gnim9adtnonL18UM+vuYeXg==", "requires": { "@babel/core": "7.22.5", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -16648,17 +17631,17 @@ } }, "@angular/core": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.1.5.tgz", - "integrity": "sha512-xmk+WeL3qtFb3BM2hsEq/kGHJinqaTNVJkK/m4TiGArY+hjJwfCOeuTss7nOkKXvhRkZxU9VP0tej1w3QV5Yzw==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.2.2.tgz", + "integrity": "sha512-l6nJlppguroov7eByBIpbxn/mEPcQrL//Ru1TSPzTtXOLR1p41VqPMaeJXj7xYVx7im57YLTDPAjhtLzkUT/Ow==", "requires": { "tslib": "^2.3.0" } }, "@angular/forms": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.1.5.tgz", - "integrity": "sha512-4E/5msvODs5tixlkB1iHPsRv7jHj189WMpN2n7LKXT+l+jA3/rD2AbGnYVKR04gymN2x/HQ/qOrbvrqv3E1NBw==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.2.2.tgz", + "integrity": "sha512-Q3GmOCLSD5BXSjvlLkMsJLXWXb4SO0gA2Aya8JaG1y0doQT/CdGcYXrsCrCT3ot13wqp0HdGQ/ATNd0cNjmz2A==", "requires": { "tslib": "^2.3.0" } @@ -16670,12 +17653,12 @@ "dev": true }, "@angular/localize": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-16.1.5.tgz", - "integrity": "sha512-8ApTdmv4sH0VbW9kVNanze5DEmb3OPIGzbD19jzvUSb6mTVMfUcQrsf4h+H8+cT+epBhor8RgVeVbUJaUbaLNQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-16.2.2.tgz", + "integrity": "sha512-6WO8icVzOGAjZd0Zm4mXisg1ljhmB1+UFSjUdHWrXd0QxAKKhHuI2P91v8J+5j1wl27JIKzTVA7+/gnNQMmGsw==", "requires": { "@babel/core": "7.22.5", - "fast-glob": "3.2.12", + "fast-glob": "3.3.0", "yargs": "^17.2.1" }, "dependencies": { @@ -16747,34 +17730,34 @@ } }, "@angular/platform-browser": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.1.5.tgz", - "integrity": "sha512-TLM29KPr0A0pQ0YEmSy0JUOkfBXfwfBFzXQSt9SOiUs0wgDVVLMdGOpR/tbvBx2QfrSU3qgOX8P1FXIPJch6TQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.2.2.tgz", + "integrity": "sha512-9RwUiHYCAmEirXqwWL/rPfXHMkU9PnpGinok6tmHF8agAmJs1kMWZedxG0GnreTzpTlBu/dI/4v6VDfR9S/D6Q==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-browser-dynamic": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.1.5.tgz", - "integrity": "sha512-ugdIXeN5IVj9o15ywH32hxNI0ZLyakpBGqMTHZSeEhU/uN6ajAJX7z6okdMbJ7dlTyBO8eFV1KDX3aAz+sK9bg==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.2.2.tgz", + "integrity": "sha512-EOGDZ+oABB/aNiBR//wxc6McycjF99/9ds74Q6WoHiNy8CYkzH3plr5pHoy4zkriSyqzoETg2tCu7jSiiMbjRg==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-server": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-16.1.5.tgz", - "integrity": "sha512-hpsjqgEylaE3SFObrVzNLq3g37mM8hUWas0+Gl3/BIsnGxiIuArhW9mhgYjoIgAOhl+jqDiAU1a5eNzivvOMtQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-16.2.2.tgz", + "integrity": "sha512-mvJsmPJMG6GzzGvOMSkjPgE9zHpuWkFfaO6HTSj0GvxyvxjrlQKsVW87gxEgqfTdhN4JbgmMA4eC9x8625VPyg==", "requires": { "tslib": "^2.3.0", "xhr2": "^0.2.0" } }, "@angular/router": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.1.5.tgz", - "integrity": "sha512-L1gyWA16U+XgcxWmemWjy08/OPCjch9sBEiHaikuW8i9Ys0nx9ic3wh8Fyu6cVKQE9aQZ7xLYT5CdPPwYxclTw==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.2.2.tgz", + "integrity": "sha512-r4KMVUVEWqjOZK0ZUsY8jRqscseGvgcigcikvYJwfxPqtCGYY7RoVAFY7HUtmXC0GAv1aIybK5o/MKTLaecD5Q==", "requires": { "tslib": "^2.3.0" } @@ -16827,9 +17810,9 @@ } }, "@babel/generator": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.7.tgz", - "integrity": "sha512-p+jPjMG+SI8yvIaxGgeW24u7q9+5+TGpZh8/CuB7RhBKd7RCy8FayNEFNNKrNK/eUcY/4ExQqLmyrvBXKsIcwQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", "requires": { "@babel/types": "^7.22.5", "@jridgewell/gen-mapping": "^0.3.2", @@ -16862,11 +17845,11 @@ } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz", - "integrity": "sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.10.tgz", + "integrity": "sha512-Av0qubwDQxC56DoUReVDeLfMEjYYSN1nZrTUrWkXd7hpU73ymRANkbuDm3yni9npkn+RXy9nNbEJZEzXr7xrfQ==", "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.10" } }, "@babel/helper-compilation-targets": { @@ -16902,9 +17885,9 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz", - "integrity": "sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.10.tgz", + "integrity": "sha512-5IBb77txKYQPpOEdUdIhBx8VrZyDCQ+H82H0+5dX1TmuscP5vJKEE3cKurjtIw/vFwzbVH48VweE78kVDBrqjA==", "requires": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.5", @@ -16917,14 +17900,6 @@ "semver": "^6.3.1" }, "dependencies": { - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - }, "semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -16950,9 +17925,9 @@ } }, "@babel/helper-define-polyfill-provider": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz", - "integrity": "sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", + "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", "requires": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -17009,16 +17984,6 @@ "@babel/helper-simple-access": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "@babel/helper-validator-identifier": "^7.22.5" - }, - "dependencies": { - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - } } }, "@babel/helper-optimise-call-expression": { @@ -17071,9 +18036,9 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", - "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "requires": { "@babel/types": "^7.22.5" } @@ -17326,13 +18291,13 @@ } }, "@babel/plugin-transform-async-generator-functions": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz", - "integrity": "sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.10.tgz", + "integrity": "sha512-eueE8lvKVzq5wIObKK/7dvoeKJ+xc6TvRn6aysIjS6pSCeLy7S/eVi7pEQknZqyqvzaNKdDtem8nUNTBgDVR2g==", "requires": { "@babel/helper-environment-visitor": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.9", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, @@ -17355,9 +18320,9 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz", - "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.10.tgz", + "integrity": "sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg==", "requires": { "@babel/helper-plugin-utils": "^7.22.5" } @@ -17395,16 +18360,6 @@ "@babel/helper-replace-supers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "globals": "^11.1.0" - }, - "dependencies": { - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - } } }, "@babel/plugin-transform-computed-properties": { @@ -17417,9 +18372,9 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz", - "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.10.tgz", + "integrity": "sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw==", "requires": { "@babel/helper-plugin-utils": "^7.22.5" } @@ -17625,9 +18580,9 @@ } }, "@babel/plugin-transform-optional-chaining": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz", - "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.10.tgz", + "integrity": "sha512-MMkQqZAZ+MGj+jGTG3OTuhKeBpNcO+0oCEbrGNEaOmiEn+1MzRyQlYsruGiU8RTK3zV6XwrVJTmwiDOyYK6J9g==", "requires": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", @@ -17671,12 +18626,12 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz", - "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", + "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", "requires": { "@babel/helper-plugin-utils": "^7.22.5", - "regenerator-transform": "^0.15.1" + "regenerator-transform": "^0.15.2" } }, "@babel/plugin-transform-reserved-words": { @@ -17688,16 +18643,16 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.5.tgz", - "integrity": "sha512-bg4Wxd1FWeFx3daHFTWk1pkSWK/AyQuiyAoeZAOkAOUBjnZPH6KT7eMxouV47tQ6hl6ax2zyAWBdWZXbrvXlaw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz", + "integrity": "sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ==", "requires": { "@babel/helper-module-imports": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.3", - "babel-plugin-polyfill-corejs3": "^0.8.1", - "babel-plugin-polyfill-regenerator": "^0.5.0", - "semver": "^6.3.0" + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "semver": "^6.3.1" }, "dependencies": { "semver": { @@ -17749,9 +18704,9 @@ } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz", - "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", + "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", "requires": { "@babel/helper-plugin-utils": "^7.22.5" } @@ -17784,12 +18739,12 @@ } }, "@babel/preset-env": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.5.tgz", - "integrity": "sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz", + "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==", "requires": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.22.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", @@ -17814,13 +18769,13 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.7", "@babel/plugin-transform-async-to-generator": "^7.22.5", "@babel/plugin-transform-block-scoped-functions": "^7.22.5", "@babel/plugin-transform-block-scoping": "^7.22.5", "@babel/plugin-transform-class-properties": "^7.22.5", "@babel/plugin-transform-class-static-block": "^7.22.5", - "@babel/plugin-transform-classes": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.6", "@babel/plugin-transform-computed-properties": "^7.22.5", "@babel/plugin-transform-destructuring": "^7.22.5", "@babel/plugin-transform-dotall-regex": "^7.22.5", @@ -17845,7 +18800,7 @@ "@babel/plugin-transform-object-rest-spread": "^7.22.5", "@babel/plugin-transform-object-super": "^7.22.5", "@babel/plugin-transform-optional-catch-binding": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.6", "@babel/plugin-transform-parameters": "^7.22.5", "@babel/plugin-transform-private-methods": "^7.22.5", "@babel/plugin-transform-private-property-in-object": "^7.22.5", @@ -17863,11 +18818,11 @@ "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/preset-modules": "^0.1.5", "@babel/types": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.3", - "babel-plugin-polyfill-corejs3": "^0.8.1", - "babel-plugin-polyfill-regenerator": "^0.5.0", - "core-js-compat": "^3.30.2", - "semver": "^6.3.0" + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" }, "dependencies": { "semver": { @@ -17878,9 +18833,9 @@ } }, "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", + "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", @@ -17895,9 +18850,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "@babel/runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", - "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "requires": { "regenerator-runtime": "^0.13.11" } @@ -17927,22 +18882,12 @@ "@babel/types": "^7.22.5", "debug": "^4.1.0", "globals": "^11.1.0" - }, - "dependencies": { - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - } } }, "@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", + "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", "requires": { "@babel/helper-string-parser": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.5", @@ -18043,9 +18988,9 @@ } }, "@cypress/request": { - "version": "2.88.11", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.11.tgz", - "integrity": "sha512-M83/wfQ1EkspjkE2lNWNV5ui2Cv7UCv1swW1DqljahbzLVWltcsexQh8jYtuS/vzFXP+HySntGM83ZXA9fn17w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", + "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", "optional": true, "requires": { "aws-sign2": "~0.7.0", @@ -18061,9 +19006,9 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "~6.10.3", + "qs": "6.10.4", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", + "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", "uuid": "^8.3.2" } @@ -18122,135 +19067,135 @@ "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" }, "@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "optional": true }, "@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "optional": true }, "@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "optional": true }, "@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "optional": true }, "@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "optional": true }, "@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "optional": true }, "@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "optional": true }, "@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "optional": true }, "@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "optional": true }, "@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "optional": true }, "@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "optional": true }, "@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "optional": true }, "@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "optional": true }, "@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "optional": true }, "@eslint/eslintrc": { @@ -18545,10 +19490,11 @@ "tslib": "^2.3.0" } }, - "@nicolo-ribaudo/semver-v6": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz", - "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==" + "@ngtools/webpack": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.0.tgz", + "integrity": "sha512-c9jv4r7GnLTpnPOeF+a9yAm/3/2wwl9lMBU32i9hlY+q/Hqde4PiL95bUOLnRRL1I64DV7BFTlSZqSPgDpFXZQ==", + "requires": {} }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -18677,6 +19623,16 @@ "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", "peer": true }, + "@schematics/angular": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.0.tgz", + "integrity": "sha512-Ib0/ZCkjWt7a5p3209JVwEWwf41v03K3ylvlxLIEo1ZGijAZAlrBj4GrA5YQ+TmPm2hRyt+owss7x91/x+i0Gw==", + "requires": { + "@angular-devkit/core": "16.2.0", + "@angular-devkit/schematics": "16.2.0", + "jsonc-parser": "3.2.0" + } + }, "@sideway/address": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", @@ -18949,9 +19905,9 @@ "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" }, "@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==" + "version": "18.17.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.18.tgz", + "integrity": "sha512-/4QOuy3ZpV7Ya1GTRz5CYSz3DgkKpyUptXuQ5PPce7uuyJAOR7r9FhkmxJfvcNUXyklbC63a+YvB3jxy7s9ngw==" }, "@types/qrcode": { "version": "1.5.0", @@ -19293,6 +20249,62 @@ "@xtuc/long": "4.2.2" } }, + "@wessberg/ts-evaluator": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/@wessberg/ts-evaluator/-/ts-evaluator-0.0.27.tgz", + "integrity": "sha512-7gOpVm3yYojUp/Yn7F4ZybJRxyqfMNf0LXK5KJiawbPfL0XTsJV+0mgrEDjOIR6Bi0OYk2Cyg4tjFu1r8MCZaA==", + "requires": { + "chalk": "^4.1.0", + "jsdom": "^16.4.0", + "object-path": "^0.11.5", + "tslib": "^2.0.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==", + "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==", + "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==", + "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==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "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==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -19332,6 +20344,15 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -19630,8 +20651,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "optional": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "at-least-node": { "version": "1.0.0", @@ -19696,11 +20716,11 @@ } }, "babel-loader": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", - "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "requires": { - "find-cache-dir": "^3.3.2", + "find-cache-dir": "^4.0.0", "schema-utils": "^4.0.0" } }, @@ -19717,30 +20737,37 @@ } }, "babel-plugin-polyfill-corejs2": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.4.tgz", - "integrity": "sha512-9WeK9snM1BfxB38goUEv2FLnA6ja07UMfazFHzCXUb3NyDZAwfXvQiURQ6guTTMeHcOsdknULm1PDhs4uWtKyA==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", + "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", "requires": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.4.1", - "@nicolo-ribaudo/semver-v6": "^6.3.3" + "@babel/helper-define-polyfill-provider": "^0.4.2", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } } }, "babel-plugin-polyfill-corejs3": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.2.tgz", - "integrity": "sha512-Cid+Jv1BrY9ReW9lIfNlNpsI53N+FN7gE+f73zLAUbr9C52W4gKLWSByx47pfDJsEysojKArqOtOKZSVIIUTuQ==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", + "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.4.1", + "@babel/helper-define-polyfill-provider": "^0.4.2", "core-js-compat": "^3.31.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.1.tgz", - "integrity": "sha512-L8OyySuI6OSQ5hFy9O+7zFjyr4WhAfRjLIOkhQGYl+emwJkd/S4XXT1JpfrgR1jrQ1NcGiOh+yAdGlF8pnC3Jw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", + "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.4.1" + "@babel/helper-define-polyfill-provider": "^0.4.2" } }, "balanced-match": { @@ -19952,6 +20979,11 @@ "wrap-comment": "^1.0.0" } }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, "browser-resolve": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", @@ -20201,13 +21233,13 @@ } }, "browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "requires": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", "update-browserslist-db": "^1.0.11" } }, @@ -20352,9 +21384,9 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, "caniuse-lite": { - "version": "1.0.30001516", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001516.tgz", - "integrity": "sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==" + "version": "1.0.30001522", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz", + "integrity": "sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==" }, "caseless": { "version": "0.12.0", @@ -20581,7 +21613,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "optional": true, "requires": { "delayed-stream": "~1.0.0" } @@ -20591,6 +21622,11 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, "common-shakeify": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/common-shakeify/-/common-shakeify-1.1.1.tgz", @@ -20609,11 +21645,6 @@ "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", "optional": true }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" - }, "compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -20759,11 +21790,11 @@ } }, "core-js-compat": { - "version": "3.31.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.31.1.tgz", - "integrity": "sha512-wIDWd2s5/5aJSdpOJHfSibxNODxoGoWOBHt8JSPB41NOE94M7kuTPZCYLOlTtuoXTsBPKobpJ6T+y0SSy5L9SA==", + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.1.tgz", + "integrity": "sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA==", "requires": { - "browserslist": "^4.21.9" + "browserslist": "^4.21.10" } }, "core-util-is": { @@ -20861,9 +21892,9 @@ "dev": true }, "critters": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.19.tgz", - "integrity": "sha512-Fm4ZAXsG0VzWy1U30rP4qxbaWGSsqXDgSupJW1OUJGDAs0KWC+j37v7p5a2kZ9BPJvhRzWm3be+Hc9WvQOBUOw==", + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz", + "integrity": "sha512-CImNRorKOl5d8TWcnAz5n5izQ6HFsvz29k327/ELy6UFcmbiZNOsinaKvzv16WZR0P6etfSWYzE47C4/56B3Uw==", "requires": { "chalk": "^4.1.0", "css-select": "^5.1.0", @@ -20984,6 +22015,26 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + } + } + }, "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -20992,14 +22043,14 @@ "peer": true }, "cypress": { - "version": "12.17.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.17.2.tgz", - "integrity": "sha512-hxWAaWbqQBzzMuadSGSuQg5PDvIGOovm6xm0hIfpCVcORsCAj/gF2p0EvfnJ4f+jK2PCiDgP6D2eeE9/FK4Mjg==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.2.0.tgz", + "integrity": "sha512-AvDQxBydE771GTq0TR4ZUBvv9m9ffXuB/ueEtpDF/6gOcvFR96amgwSJP16Yhqw6VhmwqspT5nAGzoxxB+D89g==", "optional": true, "requires": { - "@cypress/request": "^2.88.11", + "@cypress/request": "^3.0.0", "@cypress/xvfb": "^1.2.4", - "@types/node": "^14.14.31", + "@types/node": "^18.17.5", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", @@ -21032,6 +22083,7 @@ "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", + "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "semver": "^7.5.3", @@ -21041,12 +22093,6 @@ "yauzl": "^2.10.0" }, "dependencies": { - "@types/node": { - "version": "14.18.53", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.53.tgz", - "integrity": "sha512-soGmOpVBUq+gaBMwom1M+krC/NNbWlosh4AtGA03SyWNDiqSKtwp7OulO1M6+mg8YkHMvJ/y0AkCeO8d1hNb7A==", - "optional": true - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -21163,9 +22209,9 @@ } }, "cypress-fail-on-console-error": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/cypress-fail-on-console-error/-/cypress-fail-on-console-error-4.0.3.tgz", - "integrity": "sha512-v2nPupd2brtxKLkDQX58SbEPWRF/2nDbqPTnYyhPIYHqG7U3P2dGUZ3zraETKKoLhU3+C0otjgB6Vg/bHhocQw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cypress-fail-on-console-error/-/cypress-fail-on-console-error-5.0.0.tgz", + "integrity": "sha512-xui/aSu8rmExZjZNgId3iX0MsGZih6ZoFH+54vNHrK3HaqIZZX5hUuNhAcmfSoM1rIDc2DeITeVaMn/hiQ9IWQ==", "optional": true, "requires": { "chai": "^4.3.4", @@ -21175,9 +22221,9 @@ } }, "cypress-wait-until": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cypress-wait-until/-/cypress-wait-until-2.0.0.tgz", - "integrity": "sha512-ulUZyrWBn+OuC8oiQuGKAScDYfpaWnE3dEE/raUo64w4RHQxZrQ/iMIWT4ZjGMMPr3P+BFEALCRnjQeRqzZj6g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cypress-wait-until/-/cypress-wait-until-2.0.1.tgz", + "integrity": "sha512-+IyVnYNiaX1+C+V/LazrJWAi/CqiwfNoRSrFviECQEyolW1gDRy765PZosL2alSSGK8V10Y7BGfOQyZUDgmnjQ==", "optional": true }, "d": { @@ -21203,6 +22249,16 @@ "assert-plus": "^1.0.0" } }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, "date-format": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", @@ -21229,6 +22285,11 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -21286,8 +22347,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "optional": true + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "delegate": { "version": "3.2.0", @@ -21442,6 +22502,21 @@ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==" + } + } + }, "domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", @@ -21524,9 +22599,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.4.463", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.463.tgz", - "integrity": "sha512-fT3hvdUWLjDbaTGzyOjng/CQhQJSQP8ThO3XZAoaxHvHo2kUXiRQVMj9M235l8uDFiNPsPa6KHT1p3RaR6ugRw==" + "version": "1.4.500", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.500.tgz", + "integrity": "sha512-P38NO8eOuWOKY1sQk5yE0crNtrjgjJj6r3NrbIKtG18KzCHmHE2Bt+aQA7/y0w3uYsHWxDa6icOohzjLJ4vJ4A==" }, "elliptic": { "version": "6.5.4", @@ -21812,38 +22887,38 @@ } }, "esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "requires": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "esbuild-wasm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.19.tgz", - "integrity": "sha512-X9UQEMJMZXwlGCfqcBmJ1jEa+KrLfd+gCBypO/TSzo5hZvbVwFqpxj1YCuX54ptTF75wxmrgorR4RL40AKtLVg==" + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.18.17.tgz", + "integrity": "sha512-9OHGcuRzy+I8ziF9FzjfKLWAPbvi0e/metACVg9k6bK+SI4FFxeV6PcZsz8RIVaMD4YNehw+qj6UMR3+qj/EuQ==" }, "escalade": { "version": "3.1.1", @@ -22515,9 +23590,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -22635,13 +23710,12 @@ } }, "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" } }, "find-up": { @@ -22944,6 +24018,14 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, + "guess-parser": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/guess-parser/-/guess-parser-0.4.22.tgz", + "integrity": "sha512-KcUWZ5ACGaBM69SbqwVIuWGoSAgD+9iJnchR9j/IarVI1jHVeXv+bUXBIMeqVMSKt3zrn0Dgf9UpcOEpPBLbSg==", + "requires": { + "@wessberg/ts-evaluator": "0.0.27" + } + }, "handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -23079,6 +24161,14 @@ "wbuf": "^1.1.0" } }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, "html-entities": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", @@ -23578,6 +24668,11 @@ "isobject": "^3.0.1" } }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, "is-regex": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", @@ -23728,9 +24823,9 @@ } }, "jiti": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", - "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==" + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.3.tgz", + "integrity": "sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==" }, "joi": { "version": "17.9.2", @@ -23777,6 +24872,77 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "optional": true }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==" + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + } + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -24328,26 +25494,11 @@ } }, "magic-string": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", - "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", + "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==", "requires": { - "@jridgewell/sourcemap-codec": "^1.4.13" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } + "@jridgewell/sourcemap-codec": "^1.4.15" } }, "make-error": { @@ -25009,9 +26160,9 @@ } }, "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", "optional": true }, "node-releases": { @@ -25140,6 +26291,11 @@ "boolbase": "^1.0.0" } }, + "nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -25155,6 +26311,11 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, + "object-path": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", + "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==" + }, "object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", @@ -25557,9 +26718,9 @@ "optional": true }, "piscina": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.0.0.tgz", + "integrity": "sha512-641nAmJS4k4iqpNUqfggqUBUMmlw0ZoM5VZKdQkV2e970Inn3Tk9kroCc1wpsYLD07vCwpys5iY0d3xI/9WkTg==", "requires": { "eventemitter-asyncresource": "^1.0.0", "hdr-histogram-js": "^2.0.1", @@ -25568,11 +26729,56 @@ } }, "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "requires": { - "find-up": "^4.0.0" + "find-up": "^6.3.0" + }, + "dependencies": { + "find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "requires": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + } + }, + "locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "requires": { + "p-locate": "^6.0.0" + } + }, + "p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "requires": { + "yocto-queue": "^1.0.0" + } + }, + "p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "requires": { + "p-limit": "^4.0.0" + } + }, + "path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==" + }, + "yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==" + } } }, "pngjs": { @@ -25587,9 +26793,9 @@ "peer": true }, "postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.4.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", + "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -25597,13 +26803,12 @@ } }, "postcss-loader": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.2.tgz", - "integrity": "sha512-c7qDlXErX6n0VT+LUsW+nwefVtTu3ORtVvK8EXuUIDcxo+b/euYqpuHlJAvePb0Af5e8uMjR/13e0lTuYifaig==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", + "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", "requires": { - "cosmiconfig": "^8.1.3", + "cosmiconfig": "^8.2.0", "jiti": "^1.18.2", - "klona": "^2.0.6", "semver": "^7.3.8" } }, @@ -25738,8 +26943,7 @@ "psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "optional": true + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, "public-encrypt": { "version": "4.0.3", @@ -25833,6 +27037,11 @@ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -25994,9 +27203,9 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "requires": { "@babel/runtime": "^7.8.4" } @@ -26185,9 +27394,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sass": { - "version": "1.63.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.2.tgz", - "integrity": "sha512-u56TU0AIFqMtauKl/OJ1AeFsXqRHkgO7nCWmHaDwfxDo9GUMSqBA4NEh6GMuh1CYVM7zuROYtZrHzPc2ixK+ww==", + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.1.tgz", + "integrity": "sha512-16rRACSOFEE8VN7SCgBu1MpYCyN7urj9At898tyzdXFhC+a+yOX5dXwAR7L8/IdPJ1NB8OYoXmD55DM30B2kEQ==", "requires": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -26195,11 +27404,10 @@ } }, "sass-loader": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.1.tgz", - "integrity": "sha512-cBTxmgyVA1nXPvIK4brjJMXOMJ2v2YrQEuHqLw3LylGb3gsR6jAvdjHMcy/+JGTmmIF9SauTrLLR7bsWDMWqgg==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", + "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", "requires": { - "klona": "^2.0.6", "neo-async": "^2.6.2" } }, @@ -26209,6 +27417,14 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "requires": { + "xmlchars": "^2.2.0" + } + }, "schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", @@ -26992,6 +28208,11 @@ "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==" }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, "syntax-error": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", @@ -27044,9 +28265,9 @@ } }, "terser": { - "version": "5.17.7", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.7.tgz", - "integrity": "sha512-/bi0Zm2C6VAexlGgLlVxA0P2lru/sdLyfCVaRMfKVo9nWxbmz7f/sD8VPybPeSUJaJcwmCJis9pBIhcVcG1QcQ==", + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", "requires": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -27233,12 +28454,28 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "optional": true, + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==" + } + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "requires": { - "psl": "^1.1.28", "punycode": "^2.1.1" } }, @@ -27325,9 +28562,9 @@ } }, "tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" }, "tsutils": { "version": "3.21.0", @@ -27571,6 +28808,15 @@ } } }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -27626,14 +28872,14 @@ } }, "vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz", + "integrity": "sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==", "requires": { - "esbuild": "^0.17.5", + "esbuild": "^0.18.10", "fsevents": "~2.3.2", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "postcss": "^8.4.26", + "rollup": "^3.25.2" } }, "vm-browserify": { @@ -27648,6 +28894,22 @@ "optional": true, "peer": true }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "requires": { + "xml-name-validator": "^3.0.0" + } + }, "wait-on": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz", @@ -27686,10 +28948,15 @@ "defaults": "^1.0.3" } }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" + }, "webpack": { - "version": "5.86.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", - "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "requires": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", @@ -27700,7 +28967,7 @@ "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.1", + "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -27710,7 +28977,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", @@ -27753,9 +29020,9 @@ } }, "webpack-dev-server": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.0.tgz", - "integrity": "sha512-HmNB5QeSl1KpulTBQ8UT4FPrByYyaLxpJoQ0+s7EvUrMc16m0ZS1sgb1XGqzmgCPk0c9y+aaXxn11tbLzuM7NQ==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "requires": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -27763,7 +29030,7 @@ "@types/serve-index": "^1.9.1", "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", + "@types/ws": "^8.5.5", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.0.11", "chokidar": "^3.5.3", @@ -27800,6 +29067,12 @@ "range-parser": "^1.2.1", "schema-utils": "^4.0.0" } + }, + "ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "requires": {} } } }, @@ -27840,6 +29113,29 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -27969,9 +29265,9 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "requires": {} }, "xhr2": { @@ -27979,6 +29275,16 @@ "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.2.1.tgz", "integrity": "sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw==" }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, "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 7f6f34060..214cf9ff6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -35,7 +35,7 @@ "start:local-staging": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local-staging", "start:mixed": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c mixed", "build": "npm run generate-config && npm run ng -- build --configuration production --localize && npm run sync-assets && npm run build-mempool.js", - "sync-assets": "rsync -av ./src/resources ./dist/mempool/browser && node sync-assets.js 'dist/mempool/browser/resources'", + "sync-assets": "rsync -av ./src/resources ./dist/mempool/browser && node sync-assets.js 'dist/mempool/browser/resources/'", "sync-assets-dev": "node sync-assets.js 'src/resources/'", "generate-config": "node generate-config.js", "build-mempool.js": "npm run build-mempool-js && npm run build-mempool-liquid-js && npm run build-mempool-bisq-js", @@ -61,18 +61,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.1.4", - "@angular/animations": "^16.1.5", - "@angular/cli": "^16.1.4", - "@angular/common": "^16.1.5", - "@angular/compiler": "^16.1.5", - "@angular/core": "^16.1.5", - "@angular/forms": "^16.1.5", - "@angular/localize": "^16.1.5", - "@angular/platform-browser": "^16.1.5", - "@angular/platform-browser-dynamic": "^16.1.5", - "@angular/platform-server": "^16.1.5", - "@angular/router": "^16.1.5", + "@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", "@fortawesome/angular-fontawesome": "~0.13.0", "@fortawesome/fontawesome-common-types": "~6.4.0", "@fortawesome/fontawesome-svg-core": "~6.4.0", @@ -111,9 +111,9 @@ "optionalDependencies": { "@cypress/schematic": "^2.5.0", "@types/cypress": "^1.1.3", - "cypress": "^12.17.2", - "cypress-fail-on-console-error": "~4.0.3", - "cypress-wait-until": "^2.0.0", + "cypress": "^13.2.0", + "cypress-fail-on-console-error": "~5.0.0", + "cypress-wait-until": "^2.0.1", "mock-socket": "~9.2.1", "start-server-and-test": "~2.0.0" }, diff --git a/frontend/proxy.conf.local-esplora.js b/frontend/proxy.conf.local-esplora.js index 8bb57e623..a7137f3bc 100644 --- a/frontend/proxy.conf.local-esplora.js +++ b/frontend/proxy.conf.local-esplora.js @@ -112,6 +112,14 @@ PROXY_CONFIG.push(...[ "^/testnet": "" }, }, + { + context: ['/api/v1/services/**'], + target: `http://localhost:9000`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, { context: ['/api/v1/**'], target: `http://127.0.0.1:8999`, diff --git a/frontend/proxy.conf.local.js b/frontend/proxy.conf.local.js index b2fb1bb27..3a502e0ed 100644 --- a/frontend/proxy.conf.local.js +++ b/frontend/proxy.conf.local.js @@ -112,6 +112,14 @@ PROXY_CONFIG.push(...[ "^/testnet": "" }, }, + { + context: ['/api/v1/services/**'], + target: `http://localhost:9000`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, { context: ['/api/v1/**'], target: `http://localhost:8999`, diff --git a/frontend/proxy.conf.mixed.js b/frontend/proxy.conf.mixed.js index c0c7157ff..76bb06607 100644 --- a/frontend/proxy.conf.mixed.js +++ b/frontend/proxy.conf.mixed.js @@ -95,6 +95,14 @@ if (configContent && configContent.BASE_MODULE === 'bisq') { } PROXY_CONFIG.push(...[ + { + context: ['/api/v1/services/**'], + target: `http://localhost:9000`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, { context: ['/api/v1/**'], target: `http://localhost:8999`, diff --git a/frontend/src/app/bisq/bisq-address/bisq-address.component.ts b/frontend/src/app/bisq/bisq-address/bisq-address.component.ts index 7711c4d3c..1e4f0a178 100644 --- a/frontend/src/app/bisq/bisq-address/bisq-address.component.ts +++ b/frontend/src/app/bisq/bisq-address/bisq-address.component.ts @@ -41,6 +41,7 @@ export class BisqAddressComponent implements OnInit, OnDestroy { document.body.scrollTo(0, 0); this.addressString = params.get('id') || ''; this.seoService.setTitle($localize`:@@bisq-address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`); + this.seoService.setDescription($localize`:@@meta.description.bisq.address:See current balance, pending transactions, and history of confirmed transactions for BSQ address ${this.addressString}:INTERPOLATION:.`); return this.bisqApiService.getAddress$(this.addressString) .pipe( diff --git a/frontend/src/app/bisq/bisq-block/bisq-block.component.ts b/frontend/src/app/bisq/bisq-block/bisq-block.component.ts index 206a18031..59bb16a9e 100644 --- a/frontend/src/app/bisq/bisq-block/bisq-block.component.ts +++ b/frontend/src/app/bisq/bisq-block/bisq-block.component.ts @@ -69,6 +69,7 @@ export class BisqBlockComponent implements OnInit, OnDestroy { this.location.replaceState( this.router.createUrlTree(['/bisq/block/', hash]).toString() ); + this.seoService.updateCanonical(this.location.path()); return this.bisqApiService.getBlock$(this.blockHash) .pipe(catchError(this.caughtHttpError.bind(this))); }), @@ -88,6 +89,7 @@ export class BisqBlockComponent implements OnInit, OnDestroy { this.isLoading = false; this.blockHeight = block.height; this.seoService.setTitle($localize`:@@bisq-block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.hash}:BLOCK_HASH:`); + this.seoService.setDescription($localize`:@@meta.description.bisq.block:See all BSQ transactions in Bitcoin block ${block.height}:BLOCK_HEIGHT: (block hash ${block.hash}:BLOCK_HASH:).`); this.block = block; }); } diff --git a/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.ts b/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.ts index 8d9ed3c11..7ab742655 100644 --- a/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.ts +++ b/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.ts @@ -36,6 +36,7 @@ export class BisqBlocksComponent implements OnInit { ngOnInit(): void { this.websocketService.want(['blocks']); this.seoService.setTitle($localize`:@@8a7b4bd44c0ac71b2e72de0398b303257f7d2f54:Blocks`); + this.seoService.setDescription($localize`:@@meta.description.bisq.blocks:See a list of recent Bitcoin blocks with BSQ transactions, total BSQ sent per block, and more.`); this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10); this.loadingItems = Array(this.itemsPerPage); if (document.body.clientWidth < 670) { diff --git a/frontend/src/app/bisq/bisq-dashboard/bisq-dashboard.component.ts b/frontend/src/app/bisq/bisq-dashboard/bisq-dashboard.component.ts index fe36f1b53..ebcb8a067 100644 --- a/frontend/src/app/bisq/bisq-dashboard/bisq-dashboard.component.ts +++ b/frontend/src/app/bisq/bisq-dashboard/bisq-dashboard.component.ts @@ -29,7 +29,8 @@ export class BisqDashboardComponent implements OnInit { ) { } ngOnInit(): void { - this.seoService.setTitle(`Markets`); + this.seoService.setTitle($localize`:@@meta.title.bisq.markets:Markets`); + this.seoService.setDescription($localize`:@@meta.description.bisq.markets:Explore the full Bitcoin ecosystem with The Mempool Open Projectâ„¢. See Bisq market prices, trading activity, and more.`); this.websocketService.want(['blocks']); this.volumes$ = this.bisqApiService.getAllVolumesDay$() diff --git a/frontend/src/app/bisq/bisq-main-dashboard/bisq-main-dashboard.component.ts b/frontend/src/app/bisq/bisq-main-dashboard/bisq-main-dashboard.component.ts index d1b8480f7..e7e4471c9 100644 --- a/frontend/src/app/bisq/bisq-main-dashboard/bisq-main-dashboard.component.ts +++ b/frontend/src/app/bisq/bisq-main-dashboard/bisq-main-dashboard.component.ts @@ -34,6 +34,7 @@ export class BisqMainDashboardComponent implements OnInit { ngOnInit(): void { this.seoService.resetTitle(); + this.seoService.resetDescription(); this.websocketService.want(['blocks']); this.usdPrice$ = this.stateService.conversions$.asObservable().pipe( diff --git a/frontend/src/app/bisq/bisq-market/bisq-market.component.ts b/frontend/src/app/bisq/bisq-market/bisq-market.component.ts index c9dde4115..f81b4d891 100644 --- a/frontend/src/app/bisq/bisq-market/bisq-market.component.ts +++ b/frontend/src/app/bisq/bisq-market/bisq-market.component.ts @@ -48,7 +48,8 @@ export class BisqMarketComponent implements OnInit, OnDestroy { map(([markets, routeParams]) => { const pair = routeParams.get('pair'); const pairUpperCase = pair.replace('_', '/').toUpperCase(); - this.seoService.setTitle(`Bisq market: ${pairUpperCase}`); + this.seoService.setTitle($localize`:@@meta.title.bisq.market:Bisq market: ${pairUpperCase}`); + this.seoService.setDescription($localize`:@@meta.description.bisq.market:See price history, current buy/sell offers, and latest trades for the ${pairUpperCase} market on Bisq.`); return { pair: pairUpperCase, diff --git a/frontend/src/app/bisq/bisq-stats/bisq-stats.component.ts b/frontend/src/app/bisq/bisq-stats/bisq-stats.component.ts index 5ec5964b4..58819d9cf 100644 --- a/frontend/src/app/bisq/bisq-stats/bisq-stats.component.ts +++ b/frontend/src/app/bisq/bisq-stats/bisq-stats.component.ts @@ -26,6 +26,7 @@ export class BisqStatsComponent implements OnInit { this.websocketService.want(['blocks']); this.seoService.setTitle($localize`:@@2a30a4cdb123a03facc5ab8c5b3e6d8b8dbbc3d4:BSQ statistics`); + this.seoService.setDescription($localize`:@@meta.description.bisq.stats:See high-level stats on the BSQ economy: supply metrics, number of addresses, BSQ price, market cap, and more.`); this.stateService.bsqPrice$ .subscribe((bsqPrice) => { this.price = bsqPrice; diff --git a/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.ts b/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.ts index 4951643c8..1818e105f 100644 --- a/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.ts +++ b/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.ts @@ -48,6 +48,7 @@ export class BisqTransactionComponent implements OnInit, OnDestroy { document.body.scrollTo(0, 0); this.txId = params.get('id') || ''; this.seoService.setTitle($localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:`); + this.seoService.setDescription($localize`:@@meta.description.bisq.transaction:See inputs, outputs, transaction type, burnt amount, and more for transaction with txid ${this.txId}:INTERPOLATION:.`); if (history.state.data) { return of(history.state.data); } diff --git a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts index 212030e77..be5455639 100644 --- a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts +++ b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts @@ -79,6 +79,7 @@ export class BisqTransactionsComponent implements OnInit, OnDestroy { ngOnInit(): void { this.websocketService.want(['blocks']); this.seoService.setTitle($localize`:@@add4cd82e3e38a3110fe67b3c7df56e9602644ee:Transactions`); + this.seoService.setDescription($localize`:@@meta.description.bisq.transactions:See recent BSQ transactions: amount, txid, associated Bitcoin block, transaction type, and more.`); this.radioGroupForm = this.formBuilder.group({ txTypes: [this.txTypesDefaultChecked], diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index d5c82b784..ad05b7d71 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -4,12 +4,13 @@ ®
- v{{ packetJsonVersion }} [{{ frontendGitCommitHash }}] + v{{ packetJsonVersion }} [{{ frontendGitCommitHash }}] + [{{ stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE }}]
-
The Mempool Open Source Project
+
The Mempool Open Source Project ®

Our mempool and blockchain explorer for the Bitcoin community, focusing on the transaction fee market and multi-layer ecosystem, completely self-hosted without any trusted third-parties.

@@ -242,7 +243,7 @@ RoninDojo - + Citadel diff --git a/frontend/src/app/components/about/about.component.scss b/frontend/src/app/components/about/about.component.scss index 2a5710ca1..f7aa0b965 100644 --- a/frontend/src/app/components/about/about.component.scss +++ b/frontend/src/app/components/about/about.component.scss @@ -22,6 +22,7 @@ .intro { margin: 25px auto 30px; + margin-top: 25px; width: 250px; display: flex; flex-direction: column; diff --git a/frontend/src/app/components/about/about.component.ts b/frontend/src/app/components/about/about.component.ts index 4bf7869de..8aa0422e8 100644 --- a/frontend/src/app/components/about/about.component.ts +++ b/frontend/src/app/components/about/about.component.ts @@ -43,6 +43,7 @@ export class AboutComponent implements OnInit { ngOnInit() { this.backendInfo$ = this.stateService.backendInfo$; this.seoService.setTitle($localize`:@@004b222ff9ef9dd4771b777950ca1d0e4cd4348a:About`); + this.seoService.setDescription($localize`:@@meta.description.about:Learn more about The Mempool Open Source Project®\: enterprise sponsors, individual sponsors, integrations, who contributes, FOSS licensing, and more.`); this.websocketService.want(['blocks']); this.profiles$ = this.apiService.getAboutPageProfiles$().pipe( diff --git a/frontend/src/app/components/accelerate-preview/accelerate-fee-graph.component.html b/frontend/src/app/components/accelerate-preview/accelerate-fee-graph.component.html new file mode 100644 index 000000000..fe0718ecc --- /dev/null +++ b/frontend/src/app/components/accelerate-preview/accelerate-fee-graph.component.html @@ -0,0 +1,21 @@ +
+
+ +
+
+
+

+ {{ bar.label }} + + + +

+
+
+ {{ bar.class === 'tx' ? '' : '+' }} {{ bar.fee | number }} sat +
+
+
+
+
+
diff --git a/frontend/src/app/components/accelerate-preview/accelerate-fee-graph.component.scss b/frontend/src/app/components/accelerate-preview/accelerate-fee-graph.component.scss new file mode 100644 index 000000000..6137b53ee --- /dev/null +++ b/frontend/src/app/components/accelerate-preview/accelerate-fee-graph.component.scss @@ -0,0 +1,157 @@ +.fee-graph { + height: 100%; + min-width: 120px; + width: 120px; + max-height: 90vh; + margin-left: 4em; + margin-right: 1.5em; + padding-bottom: 63px; + + .column { + width: 100%; + height: 100%; + position: relative; + background: #181b2d; + + .bar { + position: absolute; + bottom: 0; + left: 0; + right: 0; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + .fill { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + opacity: 0.75; + pointer-events: none; + } + + .fee { + font-size: 0.9em; + opacity: 0; + pointer-events: none; + } + + .spacer { + width: 100%; + height: 1px; + flex-grow: 1; + pointer-events: none; + } + + .line { + position: absolute; + right: 0; + top: 0; + left: -4.5em; + border-top: dashed white 1.5px; + + .fee-rate { + width: 100%; + position: absolute; + left: 0; + right: 0.2em; + font-size: 0.8em; + display: flex; + flex-direction: row-reverse; + justify-content: space-between; + margin: 0; + + .label { + margin-right: .2em; + } + + .rate .symbol { + color: white; + } + } + } + + &.tx { + .fill { + background: #3bcc49; + } + .line { + .fee-rate { + top: 0; + } + } + .fee { + position: absolute; + opacity: 1; + z-index: 11; + } + } + + &.target { + .fill { + background: #653b9c; + } + .fee { + position: absolute; + opacity: 1; + z-index: 11; + } + .line .fee-rate { + bottom: 2px; + } + } + + &.max { + cursor: pointer; + .line .fee-rate { + .label { + opacity: 0; + } + bottom: 2px; + } + &.active, &:hover { + .fill { + background: #105fb0; + } + .line { + .fee-rate .label { + opacity: 1; + } + } + } + } + + &:hover { + .fill { + z-index: 10; + } + .line { + z-index: 11; + } + .fee { + opacity: 1; + z-index: 12; + } + } + } + + &:hover > .bar:not(:hover) { + &.target, &.max { + .fee { + opacity: 0; + } + .line .fee-rate .label { + opacity: 0; + } + } + &.max { + .fill { + background: none; + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/components/accelerate-preview/accelerate-fee-graph.component.ts b/frontend/src/app/components/accelerate-preview/accelerate-fee-graph.component.ts new file mode 100644 index 000000000..4d746a0d9 --- /dev/null +++ b/frontend/src/app/components/accelerate-preview/accelerate-fee-graph.component.ts @@ -0,0 +1,96 @@ +import { Component, OnInit, Input, Output, OnChanges, EventEmitter, HostListener, Inject, LOCALE_ID } from '@angular/core'; +import { StateService } from '../../services/state.service'; +import { Outspend, Transaction, Vin, Vout } from '../../interfaces/electrs.interface'; +import { Router } from '@angular/router'; +import { ReplaySubject, merge, Subscription, of } from 'rxjs'; +import { tap, switchMap } from 'rxjs/operators'; +import { ApiService } from '../../services/api.service'; +import { AccelerationEstimate, RateOption } from './accelerate-preview.component'; + +interface GraphBar { + rate: number; + style: any; + class: 'tx' | 'target' | 'max'; + label: string; + active?: boolean; + rateIndex?: number; + fee?: number; +} + +@Component({ + selector: 'app-accelerate-fee-graph', + templateUrl: './accelerate-fee-graph.component.html', + styleUrls: ['./accelerate-fee-graph.component.scss'], +}) +export class AccelerateFeeGraphComponent implements OnInit, OnChanges { + @Input() tx: Transaction; + @Input() estimate: AccelerationEstimate; + @Input() maxRateOptions: RateOption[] = []; + @Input() maxRateIndex: number = 0; + @Output() setUserBid = new EventEmitter<{ fee: number, index: number }>(); + + bars: GraphBar[] = []; + tooltipPosition = { x: 0, y: 0 }; + + ngOnInit(): void { + this.initGraph(); + } + + ngOnChanges(): void { + this.initGraph(); + } + + initGraph(): void { + if (!this.tx || !this.estimate) { + return; + } + const maxRate = Math.max(...this.maxRateOptions.map(option => option.rate)); + const baseRate = this.estimate.txSummary.effectiveFee / this.estimate.txSummary.effectiveVsize; + const baseHeight = baseRate / maxRate; + const bars: GraphBar[] = this.maxRateOptions.slice().reverse().map(option => { + return { + rate: option.rate, + style: this.getStyle(option.rate, maxRate, baseHeight), + class: 'max', + label: 'maximum', + active: option.index === this.maxRateIndex, + rateIndex: option.index, + fee: option.fee, + } + }); + bars.push({ + rate: this.estimate.targetFeeRate, + style: this.getStyle(this.estimate.targetFeeRate, maxRate, baseHeight), + class: 'target', + label: 'next block', + fee: this.estimate.nextBlockFee - this.estimate.txSummary.effectiveFee + }); + bars.push({ + rate: baseRate, + style: this.getStyle(baseRate, maxRate, 0), + class: 'tx', + label: '', + fee: this.estimate.txSummary.effectiveFee, + }); + this.bars = bars; + } + + getStyle(rate, maxRate, base) { + const top = (rate / maxRate); + return { + height: `${(top - base) * 100}%`, + bottom: base ? `${base * 100}%` : '0', + } + } + + onClick(event, bar): void { + if (bar.rateIndex != null) { + this.setUserBid.emit({ fee: bar.fee, index: bar.rateIndex }); + } + } + + @HostListener('pointermove', ['$event']) + onPointerMove(event) { + this.tooltipPosition = { x: event.offsetX, y: event.offsetY }; + } +} diff --git a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.html b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.html new file mode 100644 index 000000000..9bb66eda1 --- /dev/null +++ b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.html @@ -0,0 +1,262 @@ +
+
+
+ Transaction has now been submitted to mining pools for acceleration. You can track the progress here. +
+
+
+ +
+
+ +
+
+ +
+ + + + + +
+
Your transaction
+
+
+ + Plus {{ estimate.txSummary.ancestorCount - 1 }} unconfirmed ancestor{{ estimate.txSummary.ancestorCount > 2 ? 's' : ''}}. + + + + + + + + + + + + + + + + + + +
+ Virtual size +
+ Size in vbytes of this transaction and its unconfirmed ancestors +
+ In-band fees + + {{ estimate.txSummary.effectiveFee | number : '1.0-0' }} sats +
+ Fees already paid by this transaction and its unconfirmed ancestors +
+
+
+
+
How much more are you willing to pay?
+
+
+ + Choose the maximum extra transaction fee you're willing to pay to get into the next block.
+ If the estimated next block rate rises beyond this limit, we will automatically cancel your acceleration request. +
+
+
+
+ + + +
+
+
+
+
+ +
Acceleration summary
+
+
+
+
+ Estimated cost +
+
+ Maximum cost +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Next block market rate + + {{ estimate.targetFeeRate | number : '1.0-0' }} + sat/vB
+ Estimated extra fee required + + {{ math.max(0, estimate.nextBlockFee - estimate.txSummary.effectiveFee) | number }} + + sats + +
+ Your maximum + + ~{{ ((estimate.txSummary.effectiveFee + userBid) / estimate.txSummary.effectiveVsize) | number : '1.0-0' }} + sat/vB
+ The maximum extra transaction fee you could pay + + + {{ userBid | number }} + + + sats + +
+ Mempool Acceleratorâ„¢ fees +
+ mempool.space fee + + +{{ estimate.mempoolBaseFee | number }} + + sats + +
+ Transaction vsize fee + + +{{ estimate.vsizeFee | number }} + + sats + +
+ Estimated acceleration cost + + + {{ estimate.cost + estimate.mempoolBaseFee + estimate.vsizeFee | number }} + + + sats + +
+ If your tx is accelerated to {{ estimate.targetFeeRate | number : '1.0-0' }} sat/vB +
+ Maximum acceleration cost + + + {{ maxCost | number }} + + + sats + + + +
+ If your tx is accelerated to ~{{ ((estimate.txSummary.effectiveFee + userBid) / estimate.txSummary.effectiveVsize) | number : '1.0-0' }} sat/vB +
+ Available balance + + {{ estimate.userBalance | number }} + + sats + + + +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
\ No newline at end of file diff --git a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.scss b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.scss new file mode 100644 index 000000000..433c05520 --- /dev/null +++ b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.scss @@ -0,0 +1,88 @@ +.fee-card { + padding: 15px; + background-color: #1d1f31; + + .feerate { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + .fee { + font-size: 1.2em; + } + .rate { + font-size: 0.9em; + .symbol { + color: white; + } + } + } +} + +.btn-border { + border: solid 1px black; + background-color: #0c4a87; +} + +.feerate.active { + background-color: #105fb0 !important; + opacity: 1; + border: 1px solid white !important; +} + +.estimateDisabled { + opacity: 0.5; + pointer-events: none; +} + +.table-toggle { + width: 100%; + margin-top: 0.5em; +} + +.table-accelerator { + tr { + text-wrap: wrap; + + td { + padding-top: 0; + padding-bottom: 0; + vertical-align: baseline; + } + + &.group-first { + td { + padding-top: 0.75rem; + } + } + &.group-last { + td { + padding-bottom: 0.75rem; + } + } + } + td { + &:first-child { + width: 100vw; + } + &.info { + color: #6c757d; + } + &.amt { + text-align: right; + padding-right: 0.2em; + } + &.units { + padding-left: 0.2em; + white-space: nowrap; + } + } +} + +.accelerate-cols { + display: flex; + flex-direction: row; + align-items: stretch; + margin-top: 1em; +} \ No newline at end of file diff --git a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts new file mode 100644 index 000000000..1c356a80b --- /dev/null +++ b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts @@ -0,0 +1,205 @@ +import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges, HostListener } from '@angular/core'; +import { ApiService } from '../../services/api.service'; +import { Subscription, catchError, of, tap } from 'rxjs'; +import { StorageService } from '../../services/storage.service'; +import { Transaction } from '../../interfaces/electrs.interface'; +import { nextRoundNumber } from '../../shared/common.utils'; + +export type AccelerationEstimate = { + txSummary: TxSummary; + nextBlockFee: number; + targetFeeRate: number; + userBalance: number; + enoughBalance: boolean; + cost: number; + mempoolBaseFee: number; + vsizeFee: number; +} +export type TxSummary = { + txid: string; // txid of the current transaction + effectiveVsize: number; // Total vsize of the dependency tree + effectiveFee: number; // Total fee of the dependency tree in sats + ancestorCount: number; // Number of ancestors +} + +export interface RateOption { + fee: number; + rate: number; + index: number; +} + +export const MIN_BID_RATIO = 1; +export const DEFAULT_BID_RATIO = 2; +export const MAX_BID_RATIO = 4; + +@Component({ + selector: 'app-accelerate-preview', + templateUrl: 'accelerate-preview.component.html', + styleUrls: ['accelerate-preview.component.scss'] +}) +export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges { + @Input() tx: Transaction | undefined; + @Input() scrollEvent: boolean; + + math = Math; + error = ''; + showSuccess = false; + estimateSubscription: Subscription; + accelerationSubscription: Subscription; + estimate: any; + hasAncestors: boolean = false; + minExtraCost = 0; + minBidAllowed = 0; + maxBidAllowed = 0; + defaultBid = 0; + maxCost = 0; + userBid = 0; + selectFeeRateIndex = 1; + showTable: 'estimated' | 'maximum' = 'maximum'; + isMobile: boolean = window.innerWidth <= 767.98; + + maxRateOptions: RateOption[] = []; + + constructor( + private apiService: ApiService, + private storageService: StorageService + ) { } + + ngOnDestroy(): void { + if (this.estimateSubscription) { + this.estimateSubscription.unsubscribe(); + } + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.scrollEvent) { + this.scrollToPreview('acceleratePreviewAnchor', 'center'); + } + } + + ngOnInit() { + this.estimateSubscription = this.apiService.estimate$(this.tx.txid).pipe( + tap((response) => { + if (response.status === 204) { + this.estimate = undefined; + this.error = `cannot_accelerate_tx`; + this.scrollToPreviewWithTimeout('mempoolError', 'center'); + this.estimateSubscription.unsubscribe(); + } else { + this.estimate = response.body; + if (!this.estimate) { + this.error = `cannot_accelerate_tx`; + this.scrollToPreviewWithTimeout('mempoolError', 'center'); + this.estimateSubscription.unsubscribe(); + } + + if (this.estimate.userBalance <= 0) { + if (this.isLoggedIn()) { + this.error = `not_enough_balance`; + this.scrollToPreviewWithTimeout('mempoolError', 'center'); + } + } + + this.hasAncestors = this.estimate.txSummary.ancestorCount > 1; + + // Make min extra fee at least 50% of the current tx fee + this.minExtraCost = nextRoundNumber(Math.max(this.estimate.cost * 2, this.estimate.txSummary.effectiveFee)); + + this.maxRateOptions = [1, 2, 4].map((multiplier, index) => { + return { + fee: this.minExtraCost * multiplier, + rate: (this.estimate.txSummary.effectiveFee + (this.minExtraCost * multiplier)) / this.estimate.txSummary.effectiveVsize, + index, + }; + }); + + this.minBidAllowed = this.minExtraCost * MIN_BID_RATIO; + this.defaultBid = this.minExtraCost * DEFAULT_BID_RATIO; + this.maxBidAllowed = this.minExtraCost * MAX_BID_RATIO; + + this.userBid = this.defaultBid; + if (this.userBid < this.minBidAllowed) { + this.userBid = this.minBidAllowed; + } else if (this.userBid > this.maxBidAllowed) { + this.userBid = this.maxBidAllowed; + } + this.maxCost = this.userBid + this.estimate.mempoolBaseFee + this.estimate.vsizeFee; + + if (!this.error) { + this.scrollToPreview('acceleratePreviewAnchor', 'center'); + } + } + }), + catchError((response) => { + this.estimate = undefined; + this.error = response.error; + this.scrollToPreviewWithTimeout('mempoolError', 'center'); + this.estimateSubscription.unsubscribe(); + return of(null); + }) + ).subscribe(); + } + + /** + * User changed his bid + */ + setUserBid({ fee, index }: { fee: number, index: number}) { + if (this.estimate) { + this.selectFeeRateIndex = index; + this.userBid = Math.max(0, fee); + this.maxCost = this.userBid + this.estimate.mempoolBaseFee + this.estimate.vsizeFee; + } + } + + /** + * Scroll to element id with or without setTimeout + */ + scrollToPreviewWithTimeout(id: string, position: ScrollLogicalPosition) { + setTimeout(() => { + this.scrollToPreview(id, position); + }, 100); + } + scrollToPreview(id: string, position: ScrollLogicalPosition) { + const acceleratePreviewAnchor = document.getElementById(id); + if (acceleratePreviewAnchor) { + acceleratePreviewAnchor.scrollIntoView({ + behavior: 'smooth', + inline: position, + block: position, + }); + } +} + + /** + * Send acceleration request + */ + accelerate() { + if (this.accelerationSubscription) { + this.accelerationSubscription.unsubscribe(); + } + this.accelerationSubscription = this.apiService.accelerate$( + this.tx.txid, + this.userBid + ).subscribe({ + next: () => { + this.showSuccess = true; + this.scrollToPreviewWithTimeout('successAlert', 'center'); + this.estimateSubscription.unsubscribe(); + }, + error: (response) => { + this.error = response.error; + this.scrollToPreviewWithTimeout('mempoolError', 'center'); + } + }); + } + + isLoggedIn() { + const auth = this.storageService.getAuth(); + return auth !== null; + } + + @HostListener('window:resize', ['$event']) + onResize(): void { + this.isMobile = window.innerWidth <= 767.98; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/address/address-preview.component.ts b/frontend/src/app/components/address/address-preview.component.ts index 844def9fd..9bc6e967f 100644 --- a/frontend/src/app/components/address/address-preview.component.ts +++ b/frontend/src/app/components/address/address-preview.component.ts @@ -9,6 +9,7 @@ import { AudioService } from '../../services/audio.service'; import { ApiService } from '../../services/api.service'; import { of, merge, Subscription, Observable } from 'rxjs'; import { SeoService } from '../../services/seo.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; import { AddressInformation } from '../../interfaces/node-api.interface'; @Component({ @@ -68,6 +69,7 @@ export class AddressPreviewComponent implements OnInit, OnDestroy { this.addressString = this.addressString.toLowerCase(); } this.seoService.setTitle($localize`:@@address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.address:See mempool transactions, confirmed transactions, balance, and more for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} address ${this.addressString}:INTERPOLATION:.`); return (this.addressString.match(/04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}/) ? this.electrsApiService.getPubKeyAddress$(this.addressString) diff --git a/frontend/src/app/components/address/address.component.ts b/frontend/src/app/components/address/address.component.ts index 3c79f2823..0e10b207f 100644 --- a/frontend/src/app/components/address/address.component.ts +++ b/frontend/src/app/components/address/address.component.ts @@ -9,6 +9,7 @@ import { AudioService } from '../../services/audio.service'; import { ApiService } from '../../services/api.service'; import { of, merge, Subscription, Observable } from 'rxjs'; import { SeoService } from '../../services/seo.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; import { AddressInformation } from '../../interfaces/node-api.interface'; @Component({ @@ -76,6 +77,7 @@ export class AddressComponent implements OnInit, OnDestroy { this.addressString = this.addressString.toLowerCase(); } this.seoService.setTitle($localize`:@@address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.address:See mempool transactions, confirmed transactions, balance, and more for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} address ${this.addressString}:INTERPOLATION:.`); return merge( of(true), @@ -172,6 +174,11 @@ export class AddressComponent implements OnInit, OnDestroy { this.addTransaction(tx); }); + this.stateService.mempoolRemovedTransactions$ + .subscribe(tx => { + this.removeTransaction(tx); + }); + this.stateService.blockTransactions$ .subscribe((transaction) => { const tx = this.transactions.find((t) => t.txid === transaction.txid); @@ -220,6 +227,30 @@ export class AddressComponent implements OnInit, OnDestroy { return true; } + removeTransaction(transaction: Transaction): boolean { + const index = this.transactions.findIndex(((tx) => tx.txid === transaction.txid)); + if (index === -1) { + return false; + } + + this.transactions.splice(index, 1); + this.transactions = this.transactions.slice(); + this.txCount--; + + transaction.vin.forEach((vin) => { + if (vin?.prevout?.scriptpubkey_address === this.address.address) { + this.sent -= vin.prevout.value; + } + }); + transaction.vout.forEach((vout) => { + if (vout?.scriptpubkey_address === this.address.address) { + this.received -= vout.value; + } + }); + + return true; + } + loadMore() { if (this.isLoadingTransactions || !this.totalConfirmedTxCount || this.loadedConfirmedTxCount >= this.totalConfirmedTxCount) { return; diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts index bc38d3c10..c9b044b34 100644 --- a/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts @@ -40,6 +40,7 @@ export class AssetsNavComponent implements OnInit { ngOnInit(): void { this.seoService.setTitle($localize`:@@ee8f8008bae6ce3a49840c4e1d39b4af23d4c263:Assets`); + this.seoService.setDescription($localize`:@@meta.description.liquid.assets:Explore all the assets issued on the Liquid network like L-BTC, L-CAD, USDT, and more.`); this.typeaheadSearchFn = this.typeaheadSearch; this.searchForm = this.formBuilder.group({ 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 66a594643..b4c4e9a3b 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 @@ -64,6 +64,7 @@ export class BlockFeeRatesGraphComponent implements OnInit { ngOnInit(): void { this.seoService.setTitle($localize`:@@ed8e33059967f554ff06b4f5b6049c465b92d9b3:Block Fee Rates`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-fee-rates:See Bitcoin feerates visualized over time, including minimum and maximum feerates per block along with feerates at various percentiles.`); this.miningWindowPreference = this.miningService.getDefaultTimespan('24h'); this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); 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 051d24848..722929f9e 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 @@ -65,6 +65,7 @@ export class BlockFeesGraphComponent implements OnInit { ngOnInit(): void { this.seoService.setTitle($localize`:@@6c453b11fd7bd159ae30bc381f367bc736d86909:Block Fees`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-fees:See the average mining fees earned per Bitcoin block visualized in BTC and USD over time.`); this.miningWindowPreference = this.miningService.getDefaultTimespan('1m'); this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); @@ -192,7 +193,7 @@ export class BlockFeesGraphComponent implements OnInit { { name: 'Fees ' + this.currency, inactiveColor: 'rgb(110, 112, 121)', - textStyle: { + textStyle: { color: 'white', }, icon: 'roundRect', 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 46aebdd6e..299044dbb 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 @@ -61,6 +61,7 @@ export class BlockHealthGraphComponent implements OnInit { ngOnInit(): void { this.seoService.setTitle($localize`:@@d7d5fcf50179ad70c938491c517efb82de2c8146:Block Health`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-health:See Bitcoin block health visualized over time. Block health is a measure of how many expected transactions were included in an actual mined block. Expected transactions are determined using Mempool's re-implementation of Bitcoin Core's transaction selection algorithm.`); this.miningWindowPreference = '24h';//this.miningService.getDefaultTimespan('24h'); this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); 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 634d0f524..c32216db9 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 @@ -70,9 +70,11 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On this.canvas.nativeElement.addEventListener('webglcontextlost', this.handleContextLost, false); this.canvas.nativeElement.addEventListener('webglcontextrestored', this.handleContextRestored, false); this.gl = this.canvas.nativeElement.getContext('webgl'); - this.initCanvas(); - this.resizeCanvas(); + if (this.gl) { + this.initCanvas(); + this.resizeCanvas(); + } } ngOnChanges(changes): void { @@ -195,10 +197,16 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On cancelAnimationFrame(this.animationFrameRequest); this.animationFrameRequest = null; this.running = false; + this.gl = null; } handleContextRestored(event): void { - this.initCanvas(); + if (this.canvas?.nativeElement) { + this.gl = this.canvas.nativeElement.getContext('webgl'); + if (this.gl) { + this.initCanvas(); + } + } } @HostListener('window:resize', ['$event']) @@ -224,6 +232,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On } compileShader(src, type): WebGLShader { + if (!this.gl) { + return; + } const shader = this.gl.createShader(type); this.gl.shaderSource(shader, src); @@ -237,6 +248,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On } buildShaderProgram(shaderInfo): WebGLProgram { + if (!this.gl) { + return; + } const program = this.gl.createProgram(); shaderInfo.forEach((desc) => { @@ -273,7 +287,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On now = performance.now(); } // skip re-render if there's no change to the scene - if (this.scene) { + if (this.scene && this.gl) { /* SET UP SHADER UNIFORMS */ // screen dimensions this.gl.uniform2f(this.gl.getUniformLocation(this.shaderProgram, 'screenSize'), this.displayWidth, this.displayHeight); 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 2d8a6f858..505da17a5 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 @@ -63,6 +63,7 @@ export class BlockRewardsGraphComponent implements OnInit { ngOnInit(): void { this.seoService.setTitle($localize`:@@8ba8fe810458280a83df7fdf4c614dfc1a826445:Block Rewards`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-rewards:See Bitcoin block rewards in BTC and USD visualized over time. Block rewards are the total funds miners earn from the block subsidy and fees.`); this.miningWindowPreference = this.miningService.getDefaultTimespan('3m'); this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); @@ -191,7 +192,7 @@ export class BlockRewardsGraphComponent implements OnInit { { name: 'Rewards ' + this.currency, inactiveColor: 'rgb(110, 112, 121)', - textStyle: { + textStyle: { color: 'white', }, icon: 'roundRect', 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 8477af588..e42c6a8df 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 @@ -60,6 +60,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit { let firstRun = true; this.seoService.setTitle($localize`:@@56fa1cd221491b6478998679cba2dc8d55ba330d:Block Sizes and Weights`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-sizes:See Bitcoin block sizes (MB) and block weights (weight units) visualized over time.`); this.miningWindowPreference = this.miningService.getDefaultTimespan('24h'); this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); diff --git a/frontend/src/app/components/block/block-preview.component.ts b/frontend/src/app/components/block/block-preview.component.ts index 7c10dab6f..c4dfe40df 100644 --- a/frontend/src/app/components/block/block-preview.component.ts +++ b/frontend/src/app/components/block/block-preview.component.ts @@ -8,6 +8,7 @@ import { SeoService } from '../../services/seo.service'; import { OpenGraphService } from '../../services/opengraph.service'; import { BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface'; import { ApiService } from '../../services/api.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component'; @Component({ @@ -97,6 +98,11 @@ export class BlockPreviewComponent implements OnInit, OnDestroy { this.blockHeight = block.height; this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`); + if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) { + this.seoService.setDescription($localize`:@@meta.description.liquid.block:See size, weight, fee range, included transactions, and more for Liquid${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`); + } else { + this.seoService.setDescription($localize`:@@meta.description.bitcoin.block:See size, weight, fee range, included transactions, audit (expected v actual), and more for Bitcoin${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`); + } this.isLoadingBlock = false; this.setBlockSubsidy(); if (block?.extras?.reward !== undefined) { diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index 5d5233512..bb83494c5 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -13,6 +13,7 @@ import { BlockAudit, BlockExtended, TransactionStripped } from '../../interfaces import { ApiService } from '../../services/api.service'; import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component'; import { detectWebGL } from '../../shared/graphs.utils'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; import { PriceService, Price } from '../../services/price.service'; import { CacheService } from '../../services/cache.service'; @@ -165,7 +166,6 @@ export class BlockComponent implements OnInit, OnDestroy { this.page = 1; this.error = undefined; this.fees = undefined; - this.stateService.markBlock$.next({}); if (history.state.data && history.state.data.blockHeight) { this.blockHeight = history.state.data.blockHeight; @@ -175,6 +175,7 @@ export class BlockComponent implements OnInit, OnDestroy { let isBlockHeight = false; if (/^[0-9]+$/.test(blockHash)) { isBlockHeight = true; + this.stateService.markBlock$.next({ blockHeight: parseInt(blockHash, 10)}); } else { this.blockHash = blockHash; } @@ -201,6 +202,7 @@ export class BlockComponent implements OnInit, OnDestroy { this.location.replaceState( this.router.createUrlTree([(this.network ? '/' + this.network : '') + '/block/', hash]).toString() ); + this.seoService.updateCanonical(this.location.path()); return this.apiService.getBlock$(hash).pipe( catchError((err) => { this.error = err; @@ -261,6 +263,11 @@ export class BlockComponent implements OnInit, OnDestroy { this.setNextAndPreviousBlockLink(); this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`); + if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) { + this.seoService.setDescription($localize`:@@meta.description.liquid.block:See size, weight, fee range, included transactions, and more for Liquid${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`); + } else { + this.seoService.setDescription($localize`:@@meta.description.bitcoin.block:See size, weight, fee range, included transactions, audit (expected v actual), and more for Bitcoin${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`); + } this.isLoadingBlock = false; this.setBlockSubsidy(); if (block?.extras?.reward !== undefined) { @@ -325,7 +332,7 @@ export class BlockComponent implements OnInit, OnDestroy { ]); }) ) - .subscribe(([transactions, blockAudit]) => { + .subscribe(([transactions, blockAudit]) => { if (transactions) { this.strippedTransactions = transactions; } else { @@ -680,7 +687,7 @@ export class BlockComponent implements OnInit, OnDestroy { this.setAuditAvailable(false); } } - + isAuditAvailableFromBlockHeight(blockHeight: number): boolean { if (!this.auditSupported) { return false; @@ -729,4 +736,4 @@ export class BlockComponent implements OnInit, OnDestroy { this.block.canonical = block.id; } } -} \ No newline at end of file +} diff --git a/frontend/src/app/components/blockchain/blockchain.component.html b/frontend/src/app/components/blockchain/blockchain.component.html index 2c3f1ad8c..5f625e4b3 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.html +++ b/frontend/src/app/components/blockchain/blockchain.component.html @@ -1,5 +1,5 @@
-
+
diff --git a/frontend/src/app/components/blockchain/blockchain.component.scss b/frontend/src/app/components/blockchain/blockchain.component.scss index 135a8b842..eacd16118 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.scss +++ b/frontend/src/app/components/blockchain/blockchain.component.scss @@ -26,15 +26,7 @@ position: absolute; left: 0; top: 75px; - --divider-offset: 50vw; - --mempool-offset: 0px; - transform: translateX(calc(var(--divider-offset) + var(--mempool-offset))); -} - -.blockchain-wrapper.time-ltr { - .position-container { - transform: translateX(calc(100vw - var(--divider-offset) - var(--mempool-offset))); - } + transform: translateX(1280px); } .black-background { diff --git a/frontend/src/app/components/blockchain/blockchain.component.ts b/frontend/src/app/components/blockchain/blockchain.component.ts index 7619587d8..2293b9479 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.ts +++ b/frontend/src/app/components/blockchain/blockchain.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, Output, EventEmitter, HostListener, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, Output, EventEmitter, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core'; import { firstValueFrom, Subscription } from 'rxjs'; import { StateService } from '../../services/state.service'; @@ -8,12 +8,13 @@ import { StateService } from '../../services/state.service'; styleUrls: ['./blockchain.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class BlockchainComponent implements OnInit, OnDestroy { +export class BlockchainComponent implements OnInit, OnDestroy, OnChanges { @Input() pages: any[] = []; @Input() pageIndex: number; @Input() blocksPerPage: number = 8; @Input() minScrollWidth: number = 0; @Input() scrollableMempool: boolean = false; + @Input() containerWidth: number; @Output() mempoolOffsetChange: EventEmitter = new EventEmitter(); @@ -26,8 +27,11 @@ export class BlockchainComponent implements OnInit, OnDestroy { loadingTip: boolean = true; connected: boolean = true; - dividerOffset: number = 0; - mempoolOffset: number = 0; + dividerOffset: number | null = null; + mempoolOffset: number | null = null; + positionStyle = { + transform: "translateX(1280px)", + }; constructor( public stateService: StateService, @@ -39,6 +43,7 @@ export class BlockchainComponent implements OnInit, OnDestroy { this.network = this.stateService.network; this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { this.timeLtr = !!ltr; + this.updateStyle(); }); this.connectionStateSubscription = this.stateService.connectionState$.subscribe(state => { this.connected = (state === 2); @@ -62,44 +67,68 @@ export class BlockchainComponent implements OnInit, OnDestroy { const prevOffset = this.mempoolOffset; this.mempoolOffset = 0; this.mempoolOffsetChange.emit(0); + this.updateStyle(); setTimeout(() => { this.ltrTransitionEnabled = true; this.flipping = true; this.stateService.timeLtr.next(!this.timeLtr); + this.cd.markForCheck(); setTimeout(() => { this.ltrTransitionEnabled = false; this.flipping = false; this.mempoolOffset = prevOffset; - this.mempoolOffsetChange.emit(this.mempoolOffset); + this.mempoolOffsetChange.emit((this.mempoolOffset || 0)); + this.updateStyle(); + this.cd.markForCheck(); }, 1000); }, 0); - this.cd.markForCheck(); } onMempoolWidthChange(width): void { if (this.flipping) { return; } - this.mempoolOffset = Math.max(0, width - this.dividerOffset); - this.cd.markForCheck(); + this.mempoolOffset = Math.max(0, width - (this.dividerOffset || 0)); + this.updateStyle(); this.mempoolOffsetChange.emit(this.mempoolOffset); } - @HostListener('window:resize', ['$event']) + updateStyle(): void { + if (this.dividerOffset == null || this.mempoolOffset == null) { + return; + } + const oldTransform = this.positionStyle.transform; + this.positionStyle = this.timeLtr ? { + transform: `translateX(calc(100vw - ${this.dividerOffset + this.mempoolOffset}px)`, + } : { + transform: `translateX(${this.dividerOffset + this.mempoolOffset}px)`, + }; + if (oldTransform !== this.positionStyle.transform) { + this.cd.detectChanges(); + } + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.containerWidth) { + this.onResize(); + } + } + onResize(): void { - if (window.innerWidth >= 768) { + const width = this.containerWidth || window.innerWidth; + if (width >= 768) { if (this.stateService.isLiquid()) { this.dividerOffset = 420; } else { - this.dividerOffset = window.innerWidth * 0.5; + this.dividerOffset = width * 0.5; } } else { if (this.stateService.isLiquid()) { - this.dividerOffset = window.innerWidth * 0.5; + this.dividerOffset = width * 0.5; } else { - this.dividerOffset = window.innerWidth * 0.95; + this.dividerOffset = width * 0.95; } } - this.cd.markForCheck(); + this.updateStyle(); } } diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.ts b/frontend/src/app/components/blocks-list/blocks-list.component.ts index cec925270..aa361d9dc 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.ts +++ b/frontend/src/app/components/blocks-list/blocks-list.component.ts @@ -5,6 +5,8 @@ import { BlockExtended } from '../../interfaces/node-api.interface'; import { ApiService } from '../../services/api.service'; import { StateService } from '../../services/state.service'; import { WebsocketService } from '../../services/websocket.service'; +import { SeoService } from '../../services/seo.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; @Component({ selector: 'app-blocks-list', @@ -35,6 +37,7 @@ export class BlocksList implements OnInit { private websocketService: WebsocketService, public stateService: StateService, private cd: ChangeDetectorRef, + private seoService: SeoService, ) { } @@ -50,6 +53,14 @@ export class BlocksList implements OnInit { this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()]; this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5; + this.seoService.setTitle($localize`:@@meta.title.blocks-list:Blocks`); + if( this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet' ) { + this.seoService.setDescription($localize`:@@meta.description.liquid.blocks:See the most recent Liquid${seoDescriptionNetwork(this.stateService.network)} blocks along with basic stats such as block height, block size, and more.`); + } else { + this.seoService.setDescription($localize`:@@meta.description.bitcoin.blocks:See the most recent Bitcoin${seoDescriptionNetwork(this.stateService.network)} blocks along with basic stats such as block height, block reward, block size, and more.`); + } + + this.blocks$ = combineLatest([ this.fromHeightSubject.pipe( switchMap((fromBlockHeight) => { @@ -129,4 +140,4 @@ export class BlocksList implements OnInit { isEllipsisActive(e): boolean { return (e.offsetWidth < e.scrollWidth); } -} \ No newline at end of file +} diff --git a/frontend/src/app/components/difficulty/difficulty.component.ts b/frontend/src/app/components/difficulty/difficulty.component.ts index 7f305416f..81084f524 100644 --- a/frontend/src/app/components/difficulty/difficulty.component.ts +++ b/frontend/src/app/components/difficulty/difficulty.component.ts @@ -194,7 +194,7 @@ export class DifficultyComponent implements OnInit { @HostListener('pointerdown', ['$event']) onPointerDown(event): void { - if (this.epochSvgElement.nativeElement?.contains(event.target)) { + if (this.epochSvgElement?.nativeElement?.contains(event.target)) { this.onPointerMove(event); event.preventDefault(); } @@ -202,7 +202,7 @@ export class DifficultyComponent implements OnInit { @HostListener('pointermove', ['$event']) onPointerMove(event): void { - if (this.epochSvgElement.nativeElement?.contains(event.target)) { + if (this.epochSvgElement?.nativeElement?.contains(event.target)) { this.tooltipPosition = { x: event.clientX, y: event.clientY }; this.cd.markForCheck(); } diff --git a/frontend/src/app/components/fiat-selector/fiat-selector.component.html b/frontend/src/app/components/fiat-selector/fiat-selector.component.html index eec6f4b0a..4fa55deb9 100644 --- a/frontend/src/app/components/fiat-selector/fiat-selector.component.html +++ b/frontend/src/app/components/fiat-selector/fiat-selector.component.html @@ -1,5 +1,5 @@
- +
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 62cc71ca6..592aba60b 100644 --- a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts +++ b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts @@ -12,6 +12,7 @@ import { MiningService } from '../../services/mining.service'; import { download } from '../../shared/graphs.utils'; import { ActivatedRoute } from '@angular/router'; import { StateService } from '../../services/state.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; @Component({ selector: 'app-hashrate-chart', @@ -71,6 +72,7 @@ export class HashrateChartComponent implements OnInit { this.miningWindowPreference = '1y'; } else { this.seoService.setTitle($localize`:@@3510fc6daa1d975f331e3a717bdf1a34efa06dff:Hashrate & Difficulty`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.hashrate:See hashrate and difficulty for the Bitcoin${seoDescriptionNetwork(this.network)} network visualized over time.`); this.miningWindowPreference = this.miningService.getDefaultTimespan('3m'); } this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); @@ -256,7 +258,7 @@ export class HashrateChartComponent implements OnInit { let difficultyPowerOfTen = hashratePowerOfTen; let difficulty = tick.data[1]; if (difficulty === null) { - difficultyString = `${tick.marker} ${tick.seriesName}: No data
`; + difficultyString = `${tick.marker} ${tick.seriesName}: No data
`; } else { if (this.isMobile()) { difficultyPowerOfTen = selectPowerOfTen(tick.data[1]); diff --git a/frontend/src/app/components/language-selector/language-selector.component.html b/frontend/src/app/components/language-selector/language-selector.component.html index 41e0efb0e..bfd36af77 100644 --- a/frontend/src/app/components/language-selector/language-selector.component.html +++ b/frontend/src/app/components/language-selector/language-selector.component.html @@ -1,5 +1,5 @@
-
diff --git a/frontend/src/app/components/master-page/master-page.component.html b/frontend/src/app/components/master-page/master-page.component.html index f12fbc960..8863b335f 100644 --- a/frontend/src/app/components/master-page/master-page.component.html +++ b/frontend/src/app/components/master-page/master-page.component.html @@ -1,6 +1,20 @@ -
+ - +
+ -
- -
+
+ + +
+ +
+ +
+ +
+
- diff --git a/frontend/src/app/components/master-page/master-page.component.scss b/frontend/src/app/components/master-page/master-page.component.scss index 95b9474b9..b82d973de 100644 --- a/frontend/src/app/components/master-page/master-page.component.scss +++ b/frontend/src/app/components/master-page/master-page.component.scss @@ -1,3 +1,11 @@ +.sticky-header { + position: sticky; + position: -webkit-sticky; + top: 0; + width: 100%; + z-index: 100; +} + li.nav-item.active { background-color: #653b9c; } @@ -86,7 +94,6 @@ li.nav-item { .navbar-brand { position: relative; - height: 65px; } .navbar-brand.dual-logos { @@ -102,7 +109,7 @@ nav { .connection-badge { position: absolute; - top: 22px; + top: 12px; width: 100%; } @@ -209,4 +216,26 @@ nav { margin-left: 5px; margin-right: 0px; } +} + +.profile_image_container { + width: 35px; + margin-right: 15px; + text-align: center; + align-self: center; + cursor: pointer; + &.anon { + border: 1.5px solid lightgrey; + color: lightgrey; + border-radius: 5px; + } +} +.profile_image { + height: 35px; + border-radius: 5px; +} + +main { + transition: 0.2s; + transition-property: max-width; } \ No newline at end of file diff --git a/frontend/src/app/components/master-page/master-page.component.ts b/frontend/src/app/components/master-page/master-page.component.ts index 99bccebb5..a92f77cf9 100644 --- a/frontend/src/app/components/master-page/master-page.component.ts +++ b/frontend/src/app/components/master-page/master-page.component.ts @@ -1,9 +1,13 @@ -import { Component, OnInit, Input } from '@angular/core'; +import { Component, OnInit, Input, ViewChild } from '@angular/core'; +import { Router } from '@angular/router'; import { Env, StateService } from '../../services/state.service'; import { Observable, merge, of } from 'rxjs'; import { LanguageService } from '../../services/language.service'; import { EnterpriseService } from '../../services/enterprise.service'; import { NavigationService } from '../../services/navigation.service'; +import { MenuComponent } from '../menu/menu.component'; +import { StorageService } from '../../services/storage.service'; +import { ApiService } from '../../services/api.service'; @Component({ selector: 'app-master-page', @@ -25,12 +29,21 @@ export class MasterPageComponent implements OnInit { networkPaths: { [network: string]: string }; networkPaths$: Observable>; footerVisible = true; + user: any = undefined; + servicesEnabled = false; + menuOpen = false; + + @ViewChild(MenuComponent) + public menuComponent!: MenuComponent; constructor( public stateService: StateService, private languageService: LanguageService, private enterpriseService: EnterpriseService, private navigationService: NavigationService, + private storageService: StorageService, + private apiService: ApiService, + private router: Router, ) { } ngOnInit(): void { @@ -51,17 +64,47 @@ export class MasterPageComponent implements OnInit { this.footerVisible = this.footerVisibleOverride; } }); + + this.servicesEnabled = this.officialMempoolSpace && this.stateService.env.ACCELERATOR === true && this.stateService.network === ''; + this.refreshAuth(); + + const isServicesPage = this.router.url.includes('/services/'); + this.menuOpen = isServicesPage && !this.isSmallScreen(); } collapse(): void { this.navCollapsed = !this.navCollapsed; } + isSmallScreen() { + return window.innerWidth <= 767.98; + } + onResize(): void { - this.isMobile = window.innerWidth <= 767.98; + this.isMobile = this.isSmallScreen(); } brandClick(e): void { this.stateService.resetScroll$.next(true); } + + onLoggedOut(): void { + this.refreshAuth(); + } + + refreshAuth(): void { + this.user = this.storageService.getAuth()?.user ?? null; + } + + hamburgerClick(event): void { + if (this.menuComponent) { + this.menuComponent.hamburgerClick(); + this.menuOpen = this.menuComponent.navOpen; + event.stopPropagation(); + } + } + + menuToggled(isOpen: boolean): void { + this.menuOpen = isOpen; + } } 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 6e0b21196..c11bedacd 100644 --- a/frontend/src/app/components/mempool-block/mempool-block.component.ts +++ b/frontend/src/app/components/mempool-block/mempool-block.component.ts @@ -5,6 +5,7 @@ import { switchMap, map, tap, filter } from 'rxjs/operators'; import { MempoolBlock, TransactionStripped } from '../../interfaces/websocket.interface'; import { Observable, BehaviorSubject } from 'rxjs'; import { SeoService } from '../../services/seo.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; import { WebsocketService } from '../../services/websocket.service'; @Component({ @@ -54,6 +55,7 @@ export class MempoolBlockComponent implements OnInit, OnDestroy { const ordinal = this.getOrdinal(mempoolBlocks[this.mempoolBlockIndex]); this.ordinal$.next(ordinal); this.seoService.setTitle(ordinal); + this.seoService.setDescription($localize`:@@meta.description.mempool-block:See stats for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} transactions in the mempool: fee range, aggregate size, and more. Mempool blocks are updated in real-time as the network receives new transactions.`); mempoolBlocks[this.mempoolBlockIndex].isStack = mempoolBlocks[this.mempoolBlockIndex].blockVSize > this.stateService.blockVSize; return mempoolBlocks[this.mempoolBlockIndex]; }) diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 2269d38a9..0ddbbd4b7 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -31,6 +31,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { @Input() spotlight: number = 0; @Input() getHref?: (index) => string = (index) => `/mempool-block/${index}`; @Input() allBlocks: boolean = false; + @Input() forceRtl: boolean = false; mempoolWidth: number = 0; @Output() widthChange: EventEmitter = new EventEmitter(); @@ -96,13 +97,17 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { ngOnInit() { this.chainTip = this.stateService.latestBlockHeight; + const width = this.containerOffset + (this.stateService.env.MEMPOOL_BLOCKS_AMOUNT) * this.blockOffset; + this.mempoolWidth = width; + this.widthChange.emit(this.mempoolWidth); + if (['', 'testnet', 'signet'].includes(this.stateService.network)) { this.enabledMiningInfoIfNeeded(this.location.path()); this.location.onUrlChange((url) => this.enabledMiningInfoIfNeeded(url)); } this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { - this.timeLtr = !!ltr; + this.timeLtr = !this.forceRtl && !!ltr; this.cd.markForCheck(); }); @@ -114,11 +119,6 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { }); this.reduceEmptyBlocksToFitScreen(this.mempoolEmptyBlocks); - this.mempoolBlocks.map(() => { - this.updateMempoolBlockStyles(); - this.calculateTransactionPosition(); - }); - this.reduceMempoolBlocksToFitScreen(this.mempoolBlocks); this.isTabHiddenSubscription = this.stateService.isTabHidden$.subscribe((tabHidden) => this.tabHidden = tabHidden); this.loadingBlocks$ = combineLatest([ this.stateService.isLoadingWebSocket$, @@ -165,11 +165,11 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { return this.mempoolBlocks; }), tap(() => { - this.cd.markForCheck(); const width = this.containerOffset + this.mempoolBlocks.length * this.blockOffset; if (this.mempoolWidth !== width) { this.mempoolWidth = width; this.widthChange.emit(this.mempoolWidth); + this.cd.markForCheck(); } }) ); @@ -206,21 +206,26 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { if (!block) { return; } + + const isNewBlock = block.height > this.chainTip; + if (this.chainTip === -1) { this.animateEntry = block.height === this.stateService.latestBlockHeight; } else { - this.animateEntry = block.height > this.chainTip; + this.animateEntry = isNewBlock; } this.chainTip = this.stateService.latestBlockHeight; - if ((block?.extras?.similarity == null || block?.extras?.similarity > 0.5) && !this.tabHidden) { + if (isNewBlock && (block?.extras?.similarity == null || block?.extras?.similarity > 0.5) && !this.tabHidden) { this.blockIndex++; } + this.cd.markForCheck(); }); this.chainTipSubscription = this.stateService.chainTip$.subscribe((height) => { if (this.chainTip === -1) { this.chainTip = height; + this.cd.markForCheck(); } }); @@ -258,6 +263,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { this.blockPadding = 0.24 * this.blockWidth; this.containerOffset = 0.32 * this.blockWidth; this.blockOffset = this.blockWidth + this.blockPadding; + this.cd.markForCheck(); } } @@ -276,6 +282,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { onResize(): void { this.animateEntry = false; this.reduceEmptyBlocksToFitScreen(this.mempoolEmptyBlocks); + this.cd.markForCheck(); } trackByFn(index: number, block: MempoolBlock) { @@ -283,7 +290,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { } reduceEmptyBlocksToFitScreen(blocks: MempoolBlock[]): MempoolBlock[] { - const innerWidth = this.stateService.env.BASE_MODULE !== 'liquid' && window.innerWidth <= 767.98 ? window.innerWidth : window.innerWidth / 2; + const innerWidth = this.containerWidth || (this.stateService.env.BASE_MODULE !== 'liquid' && window.innerWidth <= 767.98 ? window.innerWidth : window.innerWidth / 2); let blocksAmount = this.stateService.env.MEMPOOL_BLOCKS_AMOUNT; if (!this.allBlocks) { blocksAmount = Math.min(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT, Math.floor(innerWidth / (this.blockWidth + this.blockPadding))); @@ -306,7 +313,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { } reduceMempoolBlocksToFitScreen(blocks: MempoolBlock[]): MempoolBlock[] { - const innerWidth = this.stateService.env.BASE_MODULE !== 'liquid' && window.innerWidth <= 767.98 ? window.innerWidth : window.innerWidth / 2; + const innerWidth = this.containerWidth || (this.stateService.env.BASE_MODULE !== 'liquid' && window.innerWidth <= 767.98 ? window.innerWidth : window.innerWidth / 2); let blocksAmount = this.stateService.env.MEMPOOL_BLOCKS_AMOUNT; if (this.count) { blocksAmount = 8; @@ -316,7 +323,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { while (blocks.length > blocksAmount) { const block = blocks.pop(); if (!this.count) { - const lastBlock = blocks[0]; + const lastBlock = blocks[blocks.length - 1]; lastBlock.blockSize += block.blockSize; lastBlock.blockVSize += block.blockVSize; lastBlock.nTx += block.nTx; @@ -327,7 +334,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { } } if (blocks.length) { - blocks[0].isStack = blocks[0].blockVSize > this.stateService.blockVSize; + blocks[blocks.length - 1].isStack = blocks[blocks.length - 1].blockVSize > this.stateService.blockVSize; } return blocks; } 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 6c9795c89..935e79b2c 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit, Input, Inject, LOCALE_ID, ChangeDetectionStrategy, OnChanges } from '@angular/core'; import { VbytesPipe } from '../../shared/pipes/bytes-pipe/vbytes.pipe'; import { WuBytesPipe } from '../../shared/pipes/bytes-pipe/wubytes.pipe'; +import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe'; import { formatNumber } from '@angular/common'; import { OptimizedMempoolStats } from '../../interfaces/node-api.interface'; import { StateService } from '../../services/state.service'; @@ -26,6 +27,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { @Input() data: any[]; @Input() filterSize = 100000; @Input() limitFilterFee = 1; + @Input() hideCount: boolean = false; @Input() height: number | string = 200; @Input() top: number | string = 20; @Input() right: number | string = 10; @@ -50,10 +52,13 @@ export class MempoolGraphComponent implements OnInit, OnChanges { inverted: boolean; chartInstance: any = undefined; weightMode: boolean = false; + isWidget: boolean = false; + showCount: boolean = true; constructor( private vbytesPipe: VbytesPipe, private wubytesPipe: WuBytesPipe, + private amountShortenerPipe: AmountShortenerPipe, private stateService: StateService, private storageService: StorageService, @Inject(LOCALE_ID) private locale: string, @@ -62,12 +67,16 @@ export class MempoolGraphComponent implements OnInit, OnChanges { ngOnInit(): void { this.isLoading = true; this.inverted = this.storageService.getValue('inverted-graph') === 'true'; + this.isWidget = this.template === 'widget'; + this.showCount = !this.isWidget && !this.hideCount; } - ngOnChanges() { + ngOnChanges(changes) { if (!this.data) { return; } + this.isWidget = this.template === 'widget'; + this.showCount = !this.isWidget && !this.hideCount; this.windowPreference = this.windowPreferenceOverride ? this.windowPreferenceOverride : this.storageService.getValue('graphWindowPreference'); this.mempoolVsizeFeesData = this.handleNewMempoolData(this.data.concat([])); this.mountFeeChart(); @@ -96,10 +105,12 @@ export class MempoolGraphComponent implements OnInit, OnChanges { mempoolStats.reverse(); const labels = mempoolStats.map(stats => stats.added); const finalArrayVByte = this.generateArray(mempoolStats); + const finalArrayCount = this.generateCountArray(mempoolStats); return { labels: labels, - series: finalArrayVByte + series: finalArrayVByte, + countSeries: finalArrayCount, }; } @@ -124,9 +135,13 @@ export class MempoolGraphComponent implements OnInit, OnChanges { return finalArray; } + generateCountArray(mempoolStats: OptimizedMempoolStats[]) { + return mempoolStats.filter(stats => stats.count > 0).map(stats => [stats.added * 1000, stats.count]); + } + mountFeeChart() { this.orderLevels(); - const { series } = this.mempoolVsizeFeesData; + const { series, countSeries } = this.mempoolVsizeFeesData; const seriesGraph = []; const newColors = []; @@ -178,6 +193,29 @@ export class MempoolGraphComponent implements OnInit, OnChanges { }); } } + if (this.showCount) { + newColors.push('white'); + seriesGraph.push({ + zlevel: 1, + yAxisIndex: 1, + name: 'count', + type: 'line', + stack: 'count', + smooth: false, + markPoint: false, + lineStyle: { + width: 2, + opacity: 1, + }, + symbol: 'none', + silent: true, + areaStyle: { + color: null, + opacity: 0, + }, + data: countSeries, + }); + } this.mempoolVsizeFeesOptions = { series: this.inverted ? [...seriesGraph].reverse() : seriesGraph, @@ -201,7 +239,11 @@ export class MempoolGraphComponent implements OnInit, OnChanges { label: { formatter: (params: any) => { if (params.axisDimension === 'y') { - return this.vbytesPipe.transform(params.value, 2, 'vB', 'MvB', true) + if (params.axisIndex === 0) { + return this.vbytesPipe.transform(params.value, 2, 'vB', 'MvB', true); + } else { + return this.amountShortenerPipe.transform(params.value, 2, undefined, true); + } } else { return formatterXAxis(this.locale, this.windowPreference, params.value); } @@ -214,7 +256,11 @@ export class MempoolGraphComponent implements OnInit, OnChanges { const itemFormatted = []; let totalParcial = 0; let progressPercentageText = ''; - const items = this.inverted ? [...params].reverse() : params; + let countItem; + let items = this.inverted ? [...params].reverse() : params; + if (items[items.length - 1].seriesName === 'count') { + countItem = items.pop(); + } items.map((item: any, index: number) => { totalParcial += item.value[1]; const progressPercentage = (item.value[1] / totalValue) * 100; @@ -276,6 +322,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { `); }); const classActive = (this.template === 'advanced') ? 'fees-wrapper-tooltip-chart-advanced' : ''; + const titleCount = $localize`Count`; const titleRange = $localize`Range`; const titleSize = $localize`:@@7faaaa08f56427999f3be41df1093ce4089bbd75:Size`; const titleSum = $localize`Sum`; @@ -286,6 +333,25 @@ export class MempoolGraphComponent implements OnInit, OnChanges { ${this.vbytesPipe.transform(totalValue, 2, 'vB', 'MvB', false)}
+ ` + + (this.showCount && countItem ? ` + + + + + + + +
+ + + ${titleCount} + + + ${this.amountShortenerPipe.transform(countItem.value[1], 2, undefined, true)} +
+ ` : '') + + ` @@ -305,12 +371,12 @@ export class MempoolGraphComponent implements OnInit, OnChanges { `; } }, - dataZoom: (this.template === 'widget' && this.isMobile()) ? null : [{ + dataZoom: (this.isWidget && this.isMobile()) ? null : [{ type: 'inside', realtime: true, - zoomLock: (this.template === 'widget') ? true : false, + zoomLock: (this.isWidget) ? true : false, zoomOnMouseWheel: (this.template === 'advanced') ? true : false, - moveOnMouseMove: (this.template === 'widget') ? true : false, + moveOnMouseMove: (this.isWidget) ? true : false, maxSpan: 100, minSpan: 10, }, { @@ -339,7 +405,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { }, xAxis: [ { - name: this.template === 'widget' ? '' : formatterXAxisLabel(this.locale, this.windowPreference), + name: this.isWidget ? '' : formatterXAxisLabel(this.locale, this.windowPreference), nameLocation: 'middle', nameTextStyle: { padding: [20, 0, 0, 0], @@ -357,7 +423,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { }, } ], - yAxis: { + yAxis: [{ type: 'value', axisLine: { onZero: false }, axisLabel: { @@ -371,7 +437,17 @@ export class MempoolGraphComponent implements OnInit, OnChanges { opacity: 0.25, } } - }, + }, this.showCount ? { + type: 'value', + position: 'right', + axisLine: { onZero: false }, + axisLabel: { + formatter: (value: number) => (`${this.amountShortenerPipe.transform(value, 2, undefined, true)}`), + }, + splitLine: { + show: false, + } + } : null], }; } diff --git a/frontend/src/app/components/menu/menu.component.html b/frontend/src/app/components/menu/menu.component.html new file mode 100644 index 000000000..e89ace64a --- /dev/null +++ b/frontend/src/app/components/menu/menu.component.html @@ -0,0 +1,31 @@ + \ No newline at end of file diff --git a/frontend/src/app/components/menu/menu.component.scss b/frontend/src/app/components/menu/menu.component.scss new file mode 100644 index 000000000..f1f39b1de --- /dev/null +++ b/frontend/src/app/components/menu/menu.component.scss @@ -0,0 +1,48 @@ +.sidenav { + z-index: 1; + background-color: transparent; + width: 225px; + height: calc(100vh - 65px); + position: sticky; + top: 65px; + transition: 0.25s; + margin-left: -250px; + box-shadow: 5px 0px 30px 0px #000; + padding-bottom: 20px; +} + +.scrollable { + overflow-x: hidden; + overflow-y: scroll; +} + +.sidenav.open { + margin-left: 0px; + left: 0px; + display: block; +} + +.sidenav a, button{ + text-decoration: none; + color: lightgray; + margin-left: 20px; +} +.sidenav a:hover { + color: white; +} +.sidenav nav { + width: 100%; + height: calc(100vh - 65px); + background-color: #1d1f31; + padding-left: 20px; + padding-right: 20px; + padding-top: 20px; + padding-bottom: 20px; + @media (max-width: 991px) { + padding-bottom: 200px; + } +} + +@media screen and (max-height: 450px) { + .sidenav a {font-size: 18px;} +} \ No newline at end of file diff --git a/frontend/src/app/components/menu/menu.component.ts b/frontend/src/app/components/menu/menu.component.ts new file mode 100644 index 000000000..28ba0a1ad --- /dev/null +++ b/frontend/src/app/components/menu/menu.component.ts @@ -0,0 +1,101 @@ +import { Component, OnInit, Input, Output, EventEmitter, HostListener, OnDestroy } from '@angular/core'; +import { Observable } from 'rxjs'; +import { ApiService } from '../../services/api.service'; +import { MenuGroup } from '../../interfaces/services.interface'; +import { StorageService } from '../../services/storage.service'; +import { Router, NavigationStart } from '@angular/router'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-menu', + templateUrl: './menu.component.html', + styleUrls: ['./menu.component.scss'] +}) + +export class MenuComponent implements OnInit, OnDestroy { + @Input() navOpen: boolean = false; + @Output() loggedOut = new EventEmitter(); + @Output() menuToggled = new EventEmitter(); + + userMenuGroups$: Observable | undefined; + userAuth: any | undefined; + isServicesPage = false; + + constructor( + private apiService: ApiService, + private storageService: StorageService, + private router: Router, + private stateService: StateService + ) {} + + ngOnInit(): void { + this.userAuth = this.storageService.getAuth(); + + if (this.stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE) { + this.userMenuGroups$ = this.apiService.getUserMenuGroups$(); + } + + this.isServicesPage = this.router.url.includes('/services/'); + this.router.events.subscribe((event) => { + if (event instanceof NavigationStart) { + if (!this.isServicesPage) { + this.toggleMenu(false); + } + } + }); + } + + toggleMenu(toggled: boolean) { + this.navOpen = toggled; + this.menuToggled.emit(toggled); + } + + isSmallScreen() { + return window.innerWidth <= 767.98; + } + + logout(): void { + this.apiService.logout$().subscribe(() => { + this.loggedOut.emit(true); + if (this.stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE) { + this.userMenuGroups$ = this.apiService.getUserMenuGroups$(); + this.router.navigateByUrl('/'); + } + }); + } + + onLinkClick(link) { + if (!this.isServicesPage || this.isSmallScreen()) { + this.toggleMenu(false); + } + this.router.navigateByUrl(link); + } + + hamburgerClick() { + this.toggleMenu(!this.navOpen); + this.stateService.menuOpen$.next(this.navOpen); + } + + @HostListener('window:click', ['$event']) + onClick(event) { + const isServicesPageOnMobile = this.isServicesPage && this.isSmallScreen(); + const cssClasses = event.target.className; + + if (!cssClasses.indexOf) { // Click on chart or non html thingy, close the menu + if (!this.isServicesPage || isServicesPageOnMobile) { + this.toggleMenu(false); + } + return; + } + + const isHamburger = cssClasses.indexOf('profile_image') !== -1; + const isMenu = cssClasses.indexOf('menu-click') !== -1; + if (!isHamburger && !isMenu && (!this.isServicesPage || isServicesPageOnMobile)) { + this.toggleMenu(false); + } + } + + ngOnDestroy(): void { + this.stateService.menuOpen$.next(false); + } +} diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.ts b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.ts index 6353ab8b8..b3b2093ce 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.ts +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.ts @@ -18,6 +18,7 @@ export class MiningDashboardComponent implements OnInit, AfterViewInit { private router: Router ) { this.seoService.setTitle($localize`:@@a681a4e2011bb28157689dbaa387de0dd0aa0c11:Mining Dashboard`); + this.seoService.setDescription($localize`:@@meta.description.mining.dashboard:Get real-time Bitcoin mining stats like hashrate, difficulty adjustment, block rewards, pool dominance, and more.`); } ngOnInit(): void { @@ -29,7 +30,7 @@ export class MiningDashboardComponent implements OnInit, AfterViewInit { this.router.events.subscribe((e: NavigationStart) => { if (e.type === EventType.NavigationStart) { if (e.url.indexOf('graphs') === -1) { // The mining dashboard and the graph component are part of the same module so we can't use ngAfterViewInit in graphs.component.ts to blur the input - this.stateService.focusSearchInputDesktop(); + this.stateService.focusSearchInputDesktop(); } } }); 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 ea3a52e8e..91475040c 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts @@ -56,6 +56,7 @@ export class PoolRankingComponent implements OnInit { this.miningWindowPreference = '1w'; } else { this.seoService.setTitle($localize`:@@mining.mining-pools:Mining Pools`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.pool-ranking:See the top Bitcoin mining pools ranked by number of blocks mined, over your desired timeframe.`); this.miningWindowPreference = this.miningService.getDefaultTimespan('24h'); } this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); @@ -116,7 +117,7 @@ export class PoolRankingComponent implements OnInit { } else if (this.widget) { poolShareThreshold = 1; } - + const data: object[] = []; let totalShareOther = 0; let totalBlockOther = 0; diff --git a/frontend/src/app/components/pool/pool-preview.component.ts b/frontend/src/app/components/pool/pool-preview.component.ts index 927291f07..b2302b9a7 100644 --- a/frontend/src/app/components/pool/pool-preview.component.ts +++ b/frontend/src/app/components/pool/pool-preview.component.ts @@ -83,6 +83,7 @@ export class PoolPreviewComponent implements OnInit { } this.seoService.setTitle(poolStats.pool.name); + this.seoService.setDescription($localize`:@@meta.description.mining.pool:See mining pool stats for ${poolStats.pool.name}\: most recent mined blocks, hashrate over time, total block reward to date, known coinbase addresses, and more.`); let regexes = '"'; for (const regex of poolStats.pool.regexes) { regexes += regex + '", "'; diff --git a/frontend/src/app/components/pool/pool.component.ts b/frontend/src/app/components/pool/pool.component.ts index a14d2a9b0..0d465bc3c 100644 --- a/frontend/src/app/components/pool/pool.component.ts +++ b/frontend/src/app/components/pool/pool.component.ts @@ -83,6 +83,7 @@ export class PoolComponent implements OnInit { }), map((poolStats) => { this.seoService.setTitle(poolStats.pool.name); + this.seoService.setDescription($localize`:@@meta.description.mining.pool:See mining pool stats for ${poolStats.pool.name}\: most recent mined blocks, hashrate over time, total block reward to date, known coinbase addresses, and more.`); let regexes = '"'; for (const regex of poolStats.pool.regexes) { regexes += regex + '", "'; diff --git a/frontend/src/app/components/privacy-policy/privacy-policy.component.ts b/frontend/src/app/components/privacy-policy/privacy-policy.component.ts index f84903043..b98390731 100644 --- a/frontend/src/app/components/privacy-policy/privacy-policy.component.ts +++ b/frontend/src/app/components/privacy-policy/privacy-policy.component.ts @@ -1,5 +1,6 @@ import { Component } from '@angular/core'; import { Env, StateService } from '../../services/state.service'; +import { SeoService } from '../../services/seo.service'; @Component({ selector: 'app-privacy-policy', @@ -11,5 +12,11 @@ export class PrivacyPolicyComponent { constructor( private stateService: StateService, + private seoService: SeoService, ) { } + + ngOnInit(): void { + this.seoService.setTitle('Privacy Policy'); + this.seoService.setDescription('Trusted third parties are security holes, as are trusted first parties...you should only trust your own self-hosted instance of The Mempool Open Source Project®.'); + } } diff --git a/frontend/src/app/components/push-transaction/push-transaction.component.ts b/frontend/src/app/components/push-transaction/push-transaction.component.ts index 8ee2af3f7..cbc5d905a 100644 --- a/frontend/src/app/components/push-transaction/push-transaction.component.ts +++ b/frontend/src/app/components/push-transaction/push-transaction.component.ts @@ -1,6 +1,9 @@ import { Component, OnInit } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { ApiService } from '../../services/api.service'; +import { StateService } from '../../services/state.service'; +import { SeoService } from '../../services/seo.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; @Component({ selector: 'app-push-transaction', @@ -16,12 +19,17 @@ export class PushTransactionComponent implements OnInit { constructor( private formBuilder: UntypedFormBuilder, private apiService: ApiService, + public stateService: StateService, + private seoService: SeoService, ) { } ngOnInit(): void { this.pushTxForm = this.formBuilder.group({ txHash: ['', Validators.required], }); + + this.seoService.setTitle($localize`:@@meta.title.push-tx:Broadcast Transaction`); + this.seoService.setDescription($localize`:@@meta.description.push-tx:Broadcast a transaction to the ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} network using the transaction's hash.`); } postTx() { diff --git a/frontend/src/app/components/rate-unit-selector/rate-unit-selector.component.html b/frontend/src/app/components/rate-unit-selector/rate-unit-selector.component.html index a2be9df87..7dab6908c 100644 --- a/frontend/src/app/components/rate-unit-selector/rate-unit-selector.component.html +++ b/frontend/src/app/components/rate-unit-selector/rate-unit-selector.component.html @@ -1,5 +1,5 @@
-
diff --git a/frontend/src/app/components/rbf-list/rbf-list.component.ts b/frontend/src/app/components/rbf-list/rbf-list.component.ts index b6e178270..1ae14702b 100644 --- a/frontend/src/app/components/rbf-list/rbf-list.component.ts +++ b/frontend/src/app/components/rbf-list/rbf-list.component.ts @@ -6,6 +6,8 @@ import { WebsocketService } from '../../services/websocket.service'; import { RbfTree } from '../../interfaces/node-api.interface'; import { ApiService } from '../../services/api.service'; import { StateService } from '../../services/state.service'; +import { SeoService } from '../../services/seo.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; @Component({ selector: 'app-rbf-list', @@ -26,6 +28,7 @@ export class RbfList implements OnInit, OnDestroy { private apiService: ApiService, public stateService: StateService, private websocketService: WebsocketService, + private seoService: SeoService, ) { } ngOnInit(): void { @@ -51,9 +54,12 @@ export class RbfList implements OnInit, OnDestroy { this.isLoading = false; }) ); + + this.seoService.setTitle($localize`:@@meta.title.rbf-list:RBF Replacements`); + this.seoService.setDescription($localize`:@@meta.description.rbf-list:See the most recent RBF replacements on the Bitcoin${seoDescriptionNetwork(this.stateService.network)} network, updated in real-time.`); } ngOnDestroy(): void { this.websocketService.stopTrackRbf(); } -} \ No newline at end of file +} diff --git a/frontend/src/app/components/start/start.component.html b/frontend/src/app/components/start/start.component.html index 5cf7b4fd9..862baf80a 100644 --- a/frontend/src/app/components/start/start.component.html +++ b/frontend/src/app/components/start/start.component.html @@ -10,15 +10,26 @@
{{ eventName }} in {{ countdown | number }} block{{ countdown === 1 ? '' : 's' }}!
-
+
- +
diff --git a/frontend/src/app/components/start/start.component.scss b/frontend/src/app/components/start/start.component.scss index f23235035..ec70506f2 100644 --- a/frontend/src/app/components/start/start.component.scss +++ b/frontend/src/app/components/start/start.component.scss @@ -6,6 +6,24 @@ overflow-y: hidden; scrollbar-width: none; -ms-overflow-style: none; + width: 100%; + + transform: translateX(0px); + transition: transform 0; + + &.menu-open { + transform: translateX(-112.5px); + transition: transform 0.25s; + } + + &.menu-closing { + transform: translateX(0px); + transition: transform 0.25s; + } + + &.with-menu { + width: calc(100% + 120px); + } } #blockchain-container::-webkit-scrollbar { diff --git a/frontend/src/app/components/start/start.component.ts b/frontend/src/app/components/start/start.component.ts index 22e39b2de..1326f7119 100644 --- a/frontend/src/app/components/start/start.component.ts +++ b/frontend/src/app/components/start/start.component.ts @@ -1,4 +1,4 @@ -import { Component, ElementRef, HostListener, OnInit, OnDestroy, ViewChild, Input, DoCheck } from '@angular/core'; +import { Component, ElementRef, HostListener, OnInit, OnDestroy, ViewChild, Input, ChangeDetectorRef, ChangeDetectionStrategy, AfterViewChecked } from '@angular/core'; import { Subscription } from 'rxjs'; import { MarkBlockState, StateService } from '../../services/state.service'; import { specialBlocks } from '../../app.constants'; @@ -8,8 +8,9 @@ import { BlockExtended } from '../../interfaces/node-api.interface'; selector: 'app-start', templateUrl: './start.component.html', styleUrls: ['./start.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) -export class StartComponent implements OnInit, OnDestroy, DoCheck { +export class StartComponent implements OnInit, AfterViewChecked, OnDestroy { @Input() showLoadingIndicator = false; interval = 60; @@ -23,13 +24,15 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { timeLtrSubscription: Subscription; timeLtr: boolean = this.stateService.timeLtr.value; chainTipSubscription: Subscription; - chainTip: number = -1; + chainTip: number = 100; tipIsSet: boolean = false; lastMark: MarkBlockState; markBlockSubscription: Subscription; blockCounterSubscription: Subscription; + @ViewChild('blockchainWrapper', { static: true }) blockchainWrapper: ElementRef; @ViewChild('blockchainContainer') blockchainContainer: ElementRef; - resetScrollSubscription: Subscription; + resetScrollSubscription: Subscription; + menuSubscription: Subscription; isMobile: boolean = false; isiOS: boolean = false; @@ -39,7 +42,8 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { blocksPerPage: number = 1; pageWidth: number; firstPageWidth: number; - minScrollWidth: number; + minScrollWidth: number = 40 + (155 * (8 + (2 * Math.ceil(window.innerWidth / 155)))); + currentScrollWidth: number = null; pageIndex: number = 0; pages: any[] = []; pendingMark: number | null = null; @@ -47,19 +51,24 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { lastUpdate: number = 0; lastMouseX: number; velocity: number = 0; - mempoolOffset: number = 0; + mempoolOffset: number = null; + mempoolWidth: number = 0; + scrollLeft: number = null; + + chainWidth: number = window.innerWidth; + menuOpen: boolean = false; + menuSliding: boolean = false; + menuTimeout: number; + + hasMenu = false; constructor( private stateService: StateService, + private cd: ChangeDetectorRef, ) { this.isiOS = ['iPhone','iPod','iPad'].includes((navigator as any)?.userAgentData?.platform || navigator.platform); - } - - ngDoCheck(): void { - if (this.pendingOffset != null) { - const offset = this.pendingOffset; - this.pendingOffset = null; - this.addConvertedScrollOffset(offset); + if (this.stateService.network === '') { + this.hasMenu = true; } } @@ -69,6 +78,7 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { this.blockCount = blocks.length; this.dynamicBlocksAmount = Math.min(this.blockCount, this.stateService.env.KEEP_BLOCKS_AMOUNT, 8); this.firstPageWidth = 40 + (this.blockWidth * this.dynamicBlocksAmount); + this.minScrollWidth = 40 + (8 * this.blockWidth) + (this.pageWidth * 2); if (this.blockCount <= Math.min(8, this.stateService.env.KEEP_BLOCKS_AMOUNT)) { this.onResize(); } @@ -114,7 +124,7 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { this.scrollToBlock(scrollToHeight); } } - if (!this.tipIsSet || (blockHeight < 0 && !this.mempoolOffset)) { + if (!this.tipIsSet || (blockHeight < 0 && this.mempoolOffset == null)) { this.pendingMark = blockHeight; } } @@ -151,17 +161,56 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { this.stateService.resetScroll$.next(false); } }); + + this.menuSubscription = this.stateService.menuOpen$.subscribe((open) => { + if (this.menuOpen !== open) { + this.menuOpen = open; + this.applyMenuScroll(this.menuOpen); + } + }); + } + + ngAfterViewChecked(): void { + if (this.currentScrollWidth !== this.blockchainContainer?.nativeElement?.scrollWidth) { + this.currentScrollWidth = this.blockchainContainer?.nativeElement?.scrollWidth; + if (this.pendingOffset != null) { + const delta = this.pendingOffset - (this.mempoolOffset || 0); + this.mempoolOffset = this.pendingOffset; + this.currentScrollWidth = this.blockchainContainer?.nativeElement?.scrollWidth; + this.pendingOffset = null; + this.addConvertedScrollOffset(delta); + this.applyPendingMarkArrow(); + } else { + this.applyScrollLeft(); + } + } } onMempoolOffsetChange(offset): void { - const delta = offset - this.mempoolOffset; - this.addConvertedScrollOffset(delta); - this.mempoolOffset = offset; - this.applyPendingMarkArrow(); + if (offset !== this.mempoolOffset) { + this.pendingOffset = offset; + } + } + + applyScrollLeft(): void { + if (this.blockchainContainer?.nativeElement?.scrollWidth) { + let lastScrollLeft = null; + while (this.scrollLeft < 0 && this.shiftPagesForward() && lastScrollLeft !== this.scrollLeft) { + lastScrollLeft = this.scrollLeft; + this.scrollLeft += this.pageWidth; + } + lastScrollLeft = null; + while (this.scrollLeft > this.blockchainContainer.nativeElement.scrollWidth && this.shiftPagesBack() && lastScrollLeft !== this.scrollLeft) { + lastScrollLeft = this.scrollLeft; + this.scrollLeft -= this.pageWidth; + } + this.blockchainContainer.nativeElement.scrollLeft = this.scrollLeft; + } + this.cd.detectChanges(); } applyPendingMarkArrow(): void { - if (this.pendingMark != null) { + if (this.pendingMark != null && this.pendingMark <= this.chainTip) { if (this.pendingMark < 0) { this.scrollToBlock(this.chainTip - this.pendingMark); } else { @@ -171,39 +220,48 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { } } + applyMenuScroll(opening: boolean): void { + this.menuSliding = true; + window.clearTimeout(this.menuTimeout); + this.menuTimeout = window.setTimeout(() => { + this.menuSliding = false; + this.cd.markForCheck(); + }, 300); + } + @HostListener('window:resize', ['$event']) onResize(): void { - this.isMobile = window.innerWidth <= 767.98; + this.chainWidth = window.innerWidth; + this.isMobile = this.chainWidth <= 767.98; let firstVisibleBlock; let offset; - if (this.blockchainContainer?.nativeElement != null) { - this.pages.forEach(page => { - const left = page.offset - this.getConvertedScrollOffset(); - const right = left + this.pageWidth; - if (left <= 0 && right > 0) { - const blockIndex = Math.max(0, Math.floor(left / -this.blockWidth)); - firstVisibleBlock = page.height - blockIndex; - offset = left + (blockIndex * this.blockWidth); - } - }); - } + this.pages.forEach(page => { + const left = page.offset - this.getConvertedScrollOffset(this.scrollLeft); + const right = left + this.pageWidth; + if (left <= 0 && right > 0) { + const blockIndex = Math.max(0, Math.floor(left / -this.blockWidth)); + firstVisibleBlock = page.height - blockIndex; + offset = left + (blockIndex * this.blockWidth); + } + }); - this.blocksPerPage = Math.ceil(window.innerWidth / this.blockWidth); + this.blocksPerPage = Math.ceil(this.chainWidth / this.blockWidth); this.pageWidth = this.blocksPerPage * this.blockWidth; - this.minScrollWidth = this.firstPageWidth + (this.pageWidth * 2); + this.minScrollWidth = 40 + (8 * this.blockWidth) + (this.pageWidth * 2); if (firstVisibleBlock != null) { - this.scrollToBlock(firstVisibleBlock, offset + (this.isMobile ? this.blockWidth : 0)); + this.scrollToBlock(firstVisibleBlock, offset); } else { this.updatePages(); } + this.cd.markForCheck(); } onMouseDown(event: MouseEvent) { if (!(event.which > 1 || event.button > 0)) { this.mouseDragStartX = event.clientX; this.resetMomentum(event.clientX); - this.blockchainScrollLeftInit = this.blockchainContainer.nativeElement.scrollLeft; + this.blockchainScrollLeftInit = this.scrollLeft; } } onPointerDown(event: PointerEvent) { @@ -229,8 +287,8 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { if (this.mouseDragStartX != null) { this.updateVelocity(event.clientX); this.stateService.setBlockScrollingInProgress(true); - this.blockchainContainer.nativeElement.scrollLeft = - this.blockchainScrollLeftInit + this.mouseDragStartX - event.clientX; + this.scrollLeft = this.blockchainScrollLeftInit + this.mouseDragStartX - event.clientX; + this.applyScrollLeft(); } } @HostListener('document:mouseup', []) @@ -286,25 +344,31 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { } else { this.velocity += dv; } - this.blockchainContainer.nativeElement.scrollLeft -= displacement; + this.scrollLeft -= displacement; + this.applyScrollLeft(); this.animateMomentum(); } }); } onScroll(e) { + if (this.blockchainContainer?.nativeElement?.scrollLeft == null) { + return; + } + this.scrollLeft = this.blockchainContainer?.nativeElement?.scrollLeft; const middlePage = this.pageIndex === 0 ? this.pages[0] : this.pages[1]; // compensate for css transform - const translation = (this.isMobile ? window.innerWidth * 0.95 : window.innerWidth * 0.5); + const translation = (this.isMobile ? this.chainWidth * 0.95 : this.chainWidth * 0.5); const backThreshold = middlePage.offset + (this.pageWidth * 0.5) + translation; const forwardThreshold = middlePage.offset - (this.pageWidth * 0.5) + translation; - const scrollLeft = this.getConvertedScrollOffset(); - if (scrollLeft > backThreshold) { + this.scrollLeft = this.blockchainContainer.nativeElement.scrollLeft; + const offsetScroll = this.getConvertedScrollOffset(this.scrollLeft); + if (offsetScroll > backThreshold) { if (this.shiftPagesBack()) { this.addConvertedScrollOffset(-this.pageWidth); this.blockchainScrollLeftInit -= this.pageWidth; } - } else if (scrollLeft < forwardThreshold) { + } else if (offsetScroll < forwardThreshold) { if (this.shiftPagesForward()) { this.addConvertedScrollOffset(this.pageWidth); this.blockchainScrollLeftInit += this.pageWidth; @@ -313,10 +377,6 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { } scrollToBlock(height, blockOffset = 0) { - if (!this.blockchainContainer?.nativeElement) { - setTimeout(() => { this.scrollToBlock(height, blockOffset); }, 50); - return; - } if (this.isMobile) { blockOffset -= this.blockWidth; } @@ -324,15 +384,15 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { const pages = []; this.pageIndex = Math.max(viewingPageIndex - 1, 0); let viewingPage = this.getPageAt(viewingPageIndex); - const isLastPage = viewingPage.height < this.blocksPerPage; + const isLastPage = viewingPage.height <= 0; if (isLastPage) { this.pageIndex = Math.max(viewingPageIndex - 2, 0); viewingPage = this.getPageAt(viewingPageIndex); } - const left = viewingPage.offset - this.getConvertedScrollOffset(); + const left = viewingPage.offset - this.getConvertedScrollOffset(this.scrollLeft); const blockIndex = viewingPage.height - height; const targetOffset = (this.blockWidth * blockIndex) + left; - let deltaOffset = targetOffset - blockOffset; + const deltaOffset = targetOffset - blockOffset; if (isLastPage) { pages.push(this.getPageAt(viewingPageIndex - 2)); @@ -362,6 +422,7 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { pages.push(this.getPageAt(this.pageIndex + 1)); pages.push(this.getPageAt(this.pageIndex + 2)); this.pages = pages; + this.cd.markForCheck(); } shiftPagesBack(): boolean { @@ -414,49 +475,46 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck { blockInViewport(height: number): boolean { const firstHeight = this.pages[0].height; - const translation = (this.isMobile ? window.innerWidth * 0.95 : window.innerWidth * 0.5); - const firstX = this.pages[0].offset - this.getConvertedScrollOffset() + translation; + const translation = (this.isMobile ? this.chainWidth * 0.95 : this.chainWidth * 0.5); + const firstX = this.pages[0].offset - this.getConvertedScrollOffset(this.scrollLeft) + translation; const xPos = firstX + ((firstHeight - height) * 155); - return xPos > -55 && xPos < (window.innerWidth - 100); + return xPos > -55 && xPos < (this.chainWidth - 100); } - getConvertedScrollOffset(): number { + getConvertedScrollOffset(scrollLeft): number { if (this.timeLtr) { - return -(this.blockchainContainer?.nativeElement?.scrollLeft || 0) - this.mempoolOffset; + return -(scrollLeft || 0) - (this.mempoolOffset || 0); } else { - return (this.blockchainContainer?.nativeElement?.scrollLeft || 0) - this.mempoolOffset; + return (scrollLeft || 0) - (this.mempoolOffset || 0); } } setScrollLeft(offset: number): void { if (this.timeLtr) { - this.blockchainContainer.nativeElement.scrollLeft = offset - this.mempoolOffset; + this.scrollLeft = offset - (this.mempoolOffset || 0); } else { - this.blockchainContainer.nativeElement.scrollLeft = offset + this.mempoolOffset; + this.scrollLeft = offset + (this.mempoolOffset || 0); } + this.applyScrollLeft(); } addConvertedScrollOffset(offset: number): void { - if (!this.blockchainContainer?.nativeElement) { - this.pendingOffset = offset; - return; - } if (this.timeLtr) { - this.blockchainContainer.nativeElement.scrollLeft -= offset; + this.scrollLeft -= offset; } else { - this.blockchainContainer.nativeElement.scrollLeft += offset; + this.scrollLeft += offset; } + this.applyScrollLeft(); } ngOnDestroy() { - if (this.blockchainContainer?.nativeElement) { - // clean up scroll position to prevent caching wrong scroll in Firefox - this.setScrollLeft(0); - } + // clean up scroll position to prevent caching wrong scroll in Firefox + this.setScrollLeft(0); this.timeLtrSubscription.unsubscribe(); this.chainTipSubscription.unsubscribe(); this.markBlockSubscription.unsubscribe(); this.blockCounterSubscription.unsubscribe(); this.resetScrollSubscription.unsubscribe(); + this.menuSubscription.unsubscribe(); } } diff --git a/frontend/src/app/components/statistics/statistics.component.html b/frontend/src/app/components/statistics/statistics.component.html index 29089e43d..02a26ed52 100644 --- a/frontend/src/app/components/statistics/statistics.component.html +++ b/frontend/src/app/components/statistics/statistics.component.html @@ -69,6 +69,12 @@ + +

Transaction

@@ -66,12 +73,22 @@
-
+ + +
+

Accelerate

+
+
+ +
+ +
+
@@ -92,16 +109,16 @@
- +
ETAETA - + In several hours (or more) - Accelerate + Accelerate @@ -109,9 +126,9 @@ - + - Accelerate + Accelerate diff --git a/frontend/src/app/components/transaction/transaction.component.scss b/frontend/src/app/components/transaction/transaction.component.scss index 5bef401d7..2e076600e 100644 --- a/frontend/src/app/components/transaction/transaction.component.scss +++ b/frontend/src/app/components/transaction/transaction.component.scss @@ -130,7 +130,7 @@ } .table { - tr td { + tr td { padding: 0.75rem 0.5rem; @media (min-width: 576px) { padding: 0.75rem 0.75rem; @@ -138,7 +138,7 @@ &:last-child { text-align: right; @media (min-width: 850px) { - text-align: left; + text-align: left; } } .btn { @@ -218,21 +218,52 @@ } } +.link.accelerator { + cursor: pointer; +} + .eta { display: flex; - justify-content: end; flex-wrap: wrap; align-content: center; @media (min-width: 850px) { - justify-content: space-between; + justify-content: left !important; } } .accelerate { + display: flex !important; align-self: auto; margin-top: 3px; - @media (min-width: 850px) { - justify-self: start; + margin-left: auto; + background-color: #653b9c; + @media (max-width: 849px) { + margin-left: 5px; + } +} + +.etaDeepMempool { + display: flex !important; + justify-content: end; + flex-wrap: wrap; + align-content: center; + @media (max-width: 995px) { + justify-content: left !important; + } + @media (max-width: 849px) { + justify-content: right !important; + } +} + +.accelerateDeepMempool { + align-self: auto; + margin-top: 3px; + margin-left: auto; + background-color: #653b9c; + @media (max-width: 995px) { margin-left: 0px; } -} \ No newline at end of file + @media (max-width: 849px) { + margin-left: 5px; + } +} diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index f1f3850e4..505c4686d 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -19,6 +19,8 @@ import { WebsocketService } from '../../services/websocket.service'; import { AudioService } from '../../services/audio.service'; import { ApiService } from '../../services/api.service'; import { SeoService } from '../../services/seo.service'; +import { StorageService } from '../../services/storage.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; import { BlockExtended, CpfpInfo, RbfTree, MempoolPosition, DifficultyAdjustment } from '../../interfaces/node-api.interface'; import { LiquidUnblinding } from './liquid-ublinding'; import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; @@ -88,6 +90,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { rbfEnabled: boolean; taprootEnabled: boolean; hasEffectiveFeeRate: boolean; + accelerateCtaType: 'alert' | 'button' = 'alert'; + acceleratorAvailable: boolean = this.stateService.env.OFFICIAL_MEMPOOL_SPACE && this.stateService.env.ACCELERATOR && this.stateService.network === ''; + showAccelerationSummary = false; + scrollIntoAccelPreview = false; @ViewChild('graphContainer') graphContainer: ElementRef; @@ -104,14 +110,22 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { private apiService: ApiService, private seoService: SeoService, private priceService: PriceService, + private storageService: StorageService ) {} ngOnInit() { + this.acceleratorAvailable = this.stateService.env.OFFICIAL_MEMPOOL_SPACE && this.stateService.env.ACCELERATOR && this.stateService.network === ''; + this.websocketService.want(['blocks', 'mempool-blocks']); this.stateService.networkChanged$.subscribe( - (network) => (this.network = network) + (network) => { + this.network = network; + this.acceleratorAvailable = this.stateService.env.OFFICIAL_MEMPOOL_SPACE && this.stateService.env.ACCELERATOR && this.stateService.network === ''; + } ); + this.accelerateCtaType = (this.storageService.getValue('accel-cta-type') as 'alert' | 'button') ?? 'alert'; + this.setFlowEnabled(); this.flowPrefSubscription = this.stateService.hideFlow.subscribe((hide) => { this.hideFlow = !!hide; @@ -161,34 +175,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { }) ) .subscribe((cpfpInfo) => { - if (!cpfpInfo || !this.tx) { - this.cpfpInfo = null; - this.hasEffectiveFeeRate = false; - return; - } - // merge ancestors/descendants - const relatives = [...(cpfpInfo.ancestors || []), ...(cpfpInfo.descendants || [])]; - if (cpfpInfo.bestDescendant && !cpfpInfo.descendants?.length) { - relatives.push(cpfpInfo.bestDescendant); - } - const hasRelatives = !!relatives.length; - if (!cpfpInfo.effectiveFeePerVsize && hasRelatives) { - let totalWeight = - this.tx.weight + - relatives.reduce((prev, val) => prev + val.weight, 0); - let totalFees = - this.tx.fee + - relatives.reduce((prev, val) => prev + val.fee, 0); - this.tx.effectiveFeePerVsize = totalFees / (totalWeight / 4); - } else { - this.tx.effectiveFeePerVsize = cpfpInfo.effectiveFeePerVsize; - } - if (cpfpInfo.acceleration) { - this.tx.acceleration = cpfpInfo.acceleration; - } - - this.cpfpInfo = cpfpInfo; - this.hasEffectiveFeeRate = hasRelatives || (this.tx.effectiveFeePerVsize && (Math.abs(this.tx.effectiveFeePerVsize - this.tx.feePerVsize) > 0.01)); + this.setCpfpInfo(cpfpInfo); }); this.fetchRbfSubscription = this.fetchRbfHistory$ @@ -259,6 +246,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { mempoolPosition: this.mempoolPosition }); this.txInBlockIndex = this.mempoolPosition.block; + + if (txPosition.cpfp !== undefined) { + this.setCpfpInfo(txPosition.cpfp); + } } } else { this.mempoolPosition = null; @@ -297,6 +288,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.seoService.setTitle( $localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:` ); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.transaction:Get real-time status, addresses, fees, script info, and more for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} transaction with txid {txid}.`); this.resetTransaction(); return merge( of(true), @@ -399,7 +391,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.blockConversion = price; }) ).subscribe(); - + setTimeout(() => { this.applyFragment(); }, 0); }, (error) => { @@ -486,6 +478,20 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.setGraphSize(); } + dismissAccelAlert(): void { + this.storageService.setValue('accel-cta-type', 'button'); + this.accelerateCtaType = 'button'; + } + + onAccelerateClicked() { + if (!this.txId) { + return; + } + this.showAccelerationSummary = true && this.acceleratorAvailable; + this.scrollIntoAccelPreview = !this.scrollIntoAccelPreview; + return false; + } + handleLoadElectrsTransactionError(error: any): Observable { if (error.status === 404 && /^[a-fA-F0-9]{64}$/.test(this.txId)) { this.websocketService.startMultiTrackTransaction(this.txId); @@ -507,6 +513,37 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { }); } + setCpfpInfo(cpfpInfo: CpfpInfo): void { + if (!cpfpInfo || !this.tx) { + this.cpfpInfo = null; + this.hasEffectiveFeeRate = false; + return; + } + // merge ancestors/descendants + const relatives = [...(cpfpInfo.ancestors || []), ...(cpfpInfo.descendants || [])]; + if (cpfpInfo.bestDescendant && !cpfpInfo.descendants?.length) { + relatives.push(cpfpInfo.bestDescendant); + } + const hasRelatives = !!relatives.length; + if (!cpfpInfo.effectiveFeePerVsize && hasRelatives) { + const totalWeight = + this.tx.weight + + relatives.reduce((prev, val) => prev + val.weight, 0); + const totalFees = + this.tx.fee + + relatives.reduce((prev, val) => prev + val.fee, 0); + this.tx.effectiveFeePerVsize = totalFees / (totalWeight / 4); + } else { + this.tx.effectiveFeePerVsize = cpfpInfo.effectiveFeePerVsize; + } + if (cpfpInfo.acceleration) { + this.tx.acceleration = cpfpInfo.acceleration; + } + + this.cpfpInfo = cpfpInfo; + this.hasEffectiveFeeRate = hasRelatives || (this.tx.effectiveFeePerVsize && (Math.abs(this.tx.effectiveFeePerVsize - this.tx.feePerVsize) > 0.01)); + } + setFeatures(): void { if (this.tx) { this.segwitEnabled = !this.tx.status.confirmed || isFeatureActive(this.stateService.network, this.tx.status.block_height, 'segwit'); diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index 31fabd06f..8a34bf768 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -69,6 +69,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { ngOnInit(): void { this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$; this.seoService.resetTitle(); + this.seoService.resetDescription(); this.websocketService.want(['blocks', 'stats', 'mempool-blocks', 'live-2h-chart']); this.websocketService.startTrackRbfSummary(); this.network$ = merge(of(''), this.stateService.networkChanged$); diff --git a/frontend/src/app/docs/api-docs/api-docs.component.scss b/frontend/src/app/docs/api-docs/api-docs.component.scss index 8e4c0c7a9..b90b843d9 100644 --- a/frontend/src/app/docs/api-docs/api-docs.component.scss +++ b/frontend/src/app/docs/api-docs/api-docs.component.scss @@ -155,7 +155,7 @@ ul.no-bull.block-audit code{ #doc-nav-desktop.fixed { float: unset; position: fixed; - top: 20px; + top: 80px; overflow-y: auto; height: calc(100vh - 50px); scrollbar-color: #2d3348 #11131f; diff --git a/frontend/src/app/docs/api-docs/api-docs.component.ts b/frontend/src/app/docs/api-docs/api-docs.component.ts index 62a0fadba..b0ae5967d 100644 --- a/frontend/src/app/docs/api-docs/api-docs.component.ts +++ b/frontend/src/app/docs/api-docs/api-docs.component.ts @@ -43,7 +43,7 @@ export class ApiDocsComponent implements OnInit, AfterViewInit { if (this.faqTemplates) { this.faqTemplates.forEach((x) => this.dict[x.type] = x.template); } - this.desktopDocsNavPosition = ( window.pageYOffset > 182 ) ? "fixed" : "relative"; + this.desktopDocsNavPosition = ( window.pageYOffset > 115 ) ? "fixed" : "relative"; this.mobileViewport = window.innerWidth <= 992; } @@ -113,7 +113,7 @@ export class ApiDocsComponent implements OnInit, AfterViewInit { } onDocScroll() { - this.desktopDocsNavPosition = ( window.pageYOffset > 182 ) ? "fixed" : "relative"; + this.desktopDocsNavPosition = ( window.pageYOffset > 115 ) ? "fixed" : "relative"; } anchorLinkClick( event: any ) { diff --git a/frontend/src/app/docs/docs/docs.component.ts b/frontend/src/app/docs/docs/docs.component.ts index 3e74ba959..2793fd70d 100644 --- a/frontend/src/app/docs/docs/docs.component.ts +++ b/frontend/src/app/docs/docs/docs.component.ts @@ -28,21 +28,6 @@ export class DocsComponent implements OnInit { ngOnInit(): void { this.websocket.want(['blocks']); - const url = this.route.snapshot.url; - if (url[0].path === "faq" ) { - this.activeTab = 0; - this.seoService.setTitle($localize`:@@docs.faq.button-title:FAQ`); - } else if( url[1].path === "rest" ) { - this.activeTab = 1; - this.seoService.setTitle($localize`:@@e351b40b3869a5c7d19c3d4918cb1ac7aaab95c4:API`); - } else if( url[1].path === "websocket" ) { - this.activeTab = 2; - this.seoService.setTitle($localize`:@@e351b40b3869a5c7d19c3d4918cb1ac7aaab95c4:API`); - } else { - this.activeTab = 3; - this.seoService.setTitle($localize`:@@e351b40b3869a5c7d19c3d4918cb1ac7aaab95c4:API`); - } - this.env = this.stateService.env; this.showWebSocketTab = ( ! ( ( this.stateService.network === "bisq" ) || ( this.stateService.network === "liquidtestnet" ) ) ); this.showFaqTab = ( this.env.BASE_MODULE === 'mempool' ) ? true : false; @@ -51,6 +36,40 @@ export class DocsComponent implements OnInit { document.querySelector( "html" ).style.scrollBehavior = "smooth"; } + ngDoCheck(): void { + + const url = this.route.snapshot.url; + + if (url[0].path === "faq" ) { + this.activeTab = 0; + this.seoService.setTitle($localize`:@@meta.title.docs.faq:FAQ`); + this.seoService.setDescription($localize`:@@meta.description.docs.faq:Get answers to common questions like: What is a mempool? Why isn't my transaction confirming? How can I run my own instance of The Mempool Open Source Project? And more.`); + } else if( url[1].path === "rest" ) { + this.activeTab = 1; + this.seoService.setTitle($localize`:@@meta.title.docs.rest:REST API`); + if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) { + this.seoService.setDescription($localize`:@@meta.description.docs.rest-liquid:Documentation for the liquid.network REST API service: get info on addresses, transactions, assets, blocks, and more.`); + } else if( this.stateService.network === 'bisq' ) { + this.seoService.setDescription($localize`:@@meta.description.docs.rest-bisq:Documentation for the bisq.markets REST API service: get info on recent trades, current offers, transactions, network state, and more.`); + } else { + this.seoService.setDescription($localize`:@@meta.description.docs.rest-bitcoin:Documentation for the mempool.space REST API service: get info on addresses, transactions, blocks, fees, mining, the Lightning network, and more.`); + } + } else if( url[1].path === "websocket" ) { + this.activeTab = 2; + this.seoService.setTitle($localize`:@@meta.title.docs.websocket:WebSocket API`); + if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) { + this.seoService.setDescription($localize`:@@meta.description.docs.websocket-liquid:Documentation for the liquid.network WebSocket API service: get real-time info on blocks, mempools, transactions, addresses, and more.`); + } else { + this.seoService.setDescription($localize`:@@meta.description.docs.websocket-bitcoin:Documentation for the mempool.space WebSocket API service: get real-time info on blocks, mempools, transactions, addresses, and more.`); + } + } else { + this.activeTab = 3; + this.seoService.setTitle($localize`:@@meta.title.docs.websocket:Electrum RPC`); + this.seoService.setDescription($localize`:@@meta.description.docs.electrumrpc:Documentation for our Electrum RPC interface: get instant, convenient, and reliable access to an Esplora instance.`); + } + + } + ngOnDestroy(): void { document.querySelector( "html" ).style.scrollBehavior = "auto"; } diff --git a/frontend/src/app/interfaces/electrs.interface.ts b/frontend/src/app/interfaces/electrs.interface.ts index 5c15b0ae4..2d604a9de 100644 --- a/frontend/src/app/interfaces/electrs.interface.ts +++ b/frontend/src/app/interfaces/electrs.interface.ts @@ -19,7 +19,7 @@ export interface Transaction { ancestors?: Ancestor[]; bestDescendant?: BestDescendant | null; cpfpChecked?: boolean; - acceleration?: number; + acceleration?: boolean; deleteAfter?: number; _unblinded?: any; _deduced?: boolean; diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index fbf86aeb4..08de11a6a 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -2,6 +2,7 @@ import { Block, Transaction } from "./electrs.interface"; export interface OptimizedMempoolStats { added: number; + count: number; vbytes_per_second: number; total_fee: number; mempool_byte_weight: number; @@ -27,7 +28,7 @@ export interface CpfpInfo { effectiveFeePerVsize?: number; sigops?: number; adjustedVsize?: number; - acceleration?: number; + acceleration?: boolean; } export interface RbfInfo { diff --git a/frontend/src/app/interfaces/services.interface.ts b/frontend/src/app/interfaces/services.interface.ts new file mode 100644 index 000000000..d79e47812 --- /dev/null +++ b/frontend/src/app/interfaces/services.interface.ts @@ -0,0 +1,13 @@ +import { IconName } from '@fortawesome/fontawesome-common-types'; + +export type MenuItem = { + title: string; + i18n: string; + faIcon: IconName; + link: string; +}; +export type MenuGroup = { + title: string; + i18n: string; + items: MenuItem[]; +} diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index 43ab1e5f4..1d0414de7 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -95,7 +95,7 @@ export interface TransactionStripped { } export interface IBackendInfo { - hostname: string; + hostname?: string; gitCommit: string; version: string; } diff --git a/frontend/src/app/lightning/channel/channel-preview.component.ts b/frontend/src/app/lightning/channel/channel-preview.component.ts index 9c7fdc1d6..7e3152513 100644 --- a/frontend/src/app/lightning/channel/channel-preview.component.ts +++ b/frontend/src/app/lightning/channel/channel-preview.component.ts @@ -34,6 +34,7 @@ export class ChannelPreviewComponent implements OnInit { this.openGraphService.waitFor('channel-data-' + this.shortId); this.error = null; this.seoService.setTitle(`Channel: ${params.get('short_id')}`); + this.seoService.setDescription($localize`:@@meta.description.lightning.channel:Overview for Lightning channel ${params.get('short_id')}. See channel capacity, the Lightning nodes involved, related on-chain transactions, and more.`); return this.lightningApiService.getChannel$(params.get('short_id')) .pipe( tap((data) => { diff --git a/frontend/src/app/lightning/channel/channel.component.ts b/frontend/src/app/lightning/channel/channel.component.ts index 052225cc3..a26101bdb 100644 --- a/frontend/src/app/lightning/channel/channel.component.ts +++ b/frontend/src/app/lightning/channel/channel.component.ts @@ -35,6 +35,7 @@ export class ChannelComponent implements OnInit { .pipe( tap((value) => { this.seoService.setTitle($localize`Channel: ${value.short_id}`); + this.seoService.setDescription($localize`:@@meta.description.lightning.channel:Overview for Lightning channel ${value.short_id}. See channel capacity, the Lightning nodes involved, related on-chain transactions, and more.`); }), catchError((err) => { this.error = err; diff --git a/frontend/src/app/lightning/group/group-preview.component.ts b/frontend/src/app/lightning/group/group-preview.component.ts index 5fd730931..fc81eab38 100644 --- a/frontend/src/app/lightning/group/group-preview.component.ts +++ b/frontend/src/app/lightning/group/group-preview.component.ts @@ -31,6 +31,7 @@ export class GroupPreviewComponent implements OnInit { ngOnInit(): void { this.seoService.setTitle(`Mempool.Space Lightning Nodes`); + this.seoService.setDescription(`See all Lightning nodes run by mempool.space -- these are the nodes that provide the data on the mempool.space Lightning dashboard.`); this.nodes$ = this.activatedRoute.paramMap .pipe( diff --git a/frontend/src/app/lightning/group/group.component.ts b/frontend/src/app/lightning/group/group.component.ts index 71ca17a4a..0786076ed 100644 --- a/frontend/src/app/lightning/group/group.component.ts +++ b/frontend/src/app/lightning/group/group.component.ts @@ -39,6 +39,7 @@ export class GroupComponent implements OnInit { }); this.seoService.setTitle(`Mempool.space Lightning Nodes`); + this.seoService.setDescription(`See all Lightning nodes run by mempool.space -- these are the nodes that provide the data on the mempool.space Lightning dashboard.`); this.nodes$ = this.lightningApiService.getNodGroupNodes$('mempool.space') .pipe( 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 e58d5f124..ba5ee3db2 100644 --- a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.ts +++ b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.ts @@ -25,6 +25,7 @@ export class LightningDashboardComponent implements OnInit, AfterViewInit { ngOnInit(): void { this.seoService.setTitle($localize`:@@142e923d3b04186ac6ba23387265d22a2fa404e0:Lightning Explorer`); + this.seoService.setDescription($localize`:@@meta.description.lightning.dashboard:Get stats on the Lightning network (aggregate capacity, connectivity, etc) and Lightning nodes (channels, liquidity, etc) and Lightning channels (status, fees, etc).`); this.nodesRanking$ = this.lightningApiService.getNodesRanking$().pipe(share()); this.statistics$ = this.lightningApiService.getLatestStatistics$().pipe(share()); diff --git a/frontend/src/app/lightning/node/node-preview.component.ts b/frontend/src/app/lightning/node/node-preview.component.ts index 56753b18b..d47a8c5ad 100644 --- a/frontend/src/app/lightning/node/node-preview.component.ts +++ b/frontend/src/app/lightning/node/node-preview.component.ts @@ -49,6 +49,7 @@ export class NodePreviewComponent implements OnInit { }), map((node) => { this.seoService.setTitle(`Node: ${node.alias}`); + this.seoService.setDescription($localize`:@@meta.description.lightning.node:Overview for the Lightning network node named ${node.alias}. See channels, capacity, location, fee stats, and more.`); const socketsObject = []; const socketTypesMap = {}; diff --git a/frontend/src/app/lightning/node/node.component.ts b/frontend/src/app/lightning/node/node.component.ts index 06ae50df2..56f48bf65 100644 --- a/frontend/src/app/lightning/node/node.component.ts +++ b/frontend/src/app/lightning/node/node.component.ts @@ -60,6 +60,7 @@ export class NodeComponent implements OnInit { }), map((node) => { this.seoService.setTitle($localize`Node: ${node.alias}`); + this.seoService.setDescription($localize`:@@meta.description.lightning.node:Overview for the Lightning network node named ${node.alias}. See channels, capacity, location, fee stats, and more.`); this.clearnetSocketCount = 0; this.torSocketCount = 0; 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 bf4117b30..3090a803c 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 @@ -26,7 +26,7 @@ export class NodesChannelsMap implements OnInit { @Input() disableSpinner = false; @Output() readyEvent = new EventEmitter(); - channelsObservable: Observable; + channelsObservable: Observable; center: number[] | undefined; zoom: number | undefined; @@ -41,7 +41,7 @@ export class NodesChannelsMap implements OnInit { chartOptions: EChartsOption = {}; chartInitOptions = { renderer: 'canvas', - }; + }; constructor( private seoService: SeoService, @@ -64,15 +64,16 @@ export class NodesChannelsMap implements OnInit { this.zoom = 1.4; this.center = [0, 10]; } - + if (this.style === 'graph') { this.seoService.setTitle($localize`Lightning Nodes Channels World Map`); + this.seoService.setDescription($localize`:@@meta.description.lightning.node-map:See the channels of non-Tor Lightning network nodes visualized on a world map. Hover/tap on points on the map for node names and details.`); } if (['nodepage', 'channelpage'].includes(this.style)) { this.nodeSize = 8; } - + this.channelsObservable = this.activatedRoute.paramMap .pipe( delay(100), @@ -81,7 +82,7 @@ export class NodesChannelsMap implements OnInit { if (this.style === 'channelpage' && this.channel.length === 0 || !this.hasLocation) { this.isLoading = false; } - + return zip( this.assetsService.getWorldMapJson$, this.style !== 'channelpage' ? this.apiService.getChannelsGeo$(params.get('public_key') ?? undefined, this.style) : [''], @@ -140,7 +141,7 @@ export class NodesChannelsMap implements OnInit { // on top of each other let random = Math.random() * 2 * Math.PI; let random2 = Math.random() * 0.01; - + if (!nodesPubkeys[node1UniqueId]) { nodes.push([ channel[node1GpsLat] + random2 * Math.cos(random), @@ -167,7 +168,7 @@ export class NodesChannelsMap implements OnInit { } const channelLoc = []; - channelLoc.push(nodesPubkeys[node1UniqueId].slice(0, 2)); + channelLoc.push(nodesPubkeys[node1UniqueId].slice(0, 2)); channelLoc.push(nodesPubkeys[node2UniqueId].slice(0, 2)); channelsLoc.push(channelLoc); } @@ -326,7 +327,7 @@ export class NodesChannelsMap implements OnInit { this.chartInstance.on('finished', () => { this.isLoading = false; }); - + if (this.style === 'widget') { this.chartInstance.getZr().on('click', (e) => { this.zone.run(() => { @@ -335,7 +336,7 @@ export class NodesChannelsMap implements OnInit { }); }); } - + this.chartInstance.on('click', (e) => { if (e.data) { this.zone.run(() => { 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 e0fd80a53..ea80d8799 100644 --- a/frontend/src/app/lightning/nodes-map/nodes-map.component.ts +++ b/frontend/src/app/lightning/nodes-map/nodes-map.component.ts @@ -48,6 +48,7 @@ export class NodesMap implements OnInit, OnChanges { ngOnInit(): void { if (!this.widget) { this.seoService.setTitle($localize`:@@af8560ca50882114be16c951650f83bca73161a7:Lightning Nodes World Map`); + this.seoService.setDescription($localize`:@@meta.description.lightning.node-channel-map:See the locations of non-Tor Lightning network nodes visualized on a world map. Hover/tap on points on the map for node names and details.`); } if (!this.inputNodes$) { @@ -113,7 +114,7 @@ export class NodesMap implements OnInit, OnChanges { node[3], // Alias node[2], // Public key node[5], // Channels - node[6].en, // Country + node[6]?.en, // Country node[7], // ISO Code ]); } 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 db04e9e00..f62a6a244 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 @@ -65,6 +65,7 @@ export class NodesNetworksChartComponent implements OnInit { this.miningWindowPreference = '3y'; } else { this.seoService.setTitle($localize`:@@b420668a91f8ebaf6e6409c4ba87f1d45961d2bd:Lightning Nodes Per Network`); + this.seoService.setDescription($localize`:@@meta.description.lightning.nodes-network:See the number of Lightning network nodes visualized over time by network: clearnet only (IPv4, IPv6), darknet (Tor, I2p, cjdns), and both.`); this.miningWindowPreference = this.miningService.getDefaultTimespan('all'); } this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); @@ -375,7 +376,7 @@ export class NodesNetworksChartComponent implements OnInit { // We create dummy duplicated series so when we use the data zoom, the y axis // both scales properly const invisibleSerie = {...serie}; - invisibleSerie.name = 'ignored' + Math.random().toString(); + invisibleSerie.name = 'ignored' + Math.random().toString(); invisibleSerie.stack = 'ignored'; invisibleSerie.yAxisIndex = 1; invisibleSerie.lineStyle = { 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 b4621d7bf..5bfa0fc2c 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 @@ -44,7 +44,7 @@ export class NodesPerCountryChartComponent implements OnInit { ngOnInit(): void { this.seoService.setTitle($localize`:@@9d3ad4c6623870d96b65fb7a708fed6ce7c20044:Lightning Nodes Per Country`); - + this.seoService.setDescription($localize`:@@meta.description.lightning.nodes-country-overview:See a geographical breakdown of the Lightning network: how many Lightning nodes are hosted in countries around the world, aggregate BTC capacity for each country, and more.`); this.nodesPerCountryObservable$ = this.apiService.getNodesPerCountry$() .pipe( map(data => { 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 01eb6d1cf..19dd999ee 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 @@ -33,6 +33,7 @@ export class NodesPerCountry implements OnInit { .pipe( map(response => { this.seoService.setTitle($localize`Lightning nodes in ${response.country.en}`); + this.seoService.setDescription($localize`:@@meta.description.lightning.nodes-country:Explore all the Lightning nodes hosted in ${response.country.en} and see an overview of each node's capacity, number of open channels, and more.`); this.country = { name: response.country.en, @@ -47,7 +48,7 @@ export class NodesPerCountry implements OnInit { iso: response.nodes[i].iso_code, }; } - + const sumLiquidity = response.nodes.reduce((partialSum, a) => partialSum + a.capacity, 0); const sumChannels = response.nodes.reduce((partialSum, a) => partialSum + a.channels, 0); const isps = {}; @@ -70,14 +71,14 @@ export class NodesPerCountry implements OnInit { isps[node.isp].asns.push(node.as_number); } isps[node.isp].count++; - + if (isps[node.isp].count > topIsp.count) { topIsp.count = isps[node.isp].count; topIsp.id = isps[node.isp].asns.join(','); topIsp.name = node.isp; } } - + return { nodes: response.nodes, sumLiquidity: sumLiquidity, diff --git a/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp-preview.component.ts b/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp-preview.component.ts index b823a5188..313353ab8 100644 --- a/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp-preview.component.ts +++ b/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp-preview.component.ts @@ -42,6 +42,7 @@ export class NodesPerISPPreview implements OnInit { id: this.route.snapshot.params.isp.split(',').join(', ') }; this.seoService.setTitle($localize`Lightning nodes on ISP: ${response.isp} [AS${this.route.snapshot.params.isp}]`); + this.seoService.setDescription($localize`:@@meta.description.lightning.nodes-isp:Browse all Bitcoin Lightning nodes using the ${response.isp} [AS${this.route.snapshot.params.isp}] ISP and see aggregate stats like total number of nodes, total capacity, and more for the ISP.`); for (const i in response.nodes) { response.nodes[i].geolocation = { diff --git a/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp.component.ts b/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp.component.ts index e87482583..d4f27975c 100644 --- a/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp.component.ts +++ b/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp.component.ts @@ -37,6 +37,7 @@ export class NodesPerISP implements OnInit { id: this.route.snapshot.params.isp.split(',').join(', ') }; this.seoService.setTitle($localize`Lightning nodes on ISP: ${response.isp} [AS${this.route.snapshot.params.isp}]`); + this.seoService.setDescription($localize`:@@meta.description.lightning.nodes-isp:Browse all Bitcoin Lightning nodes using the ${response.isp} [AS${this.route.snapshot.params.isp}] ISP and see aggregate stats like total number of nodes, total capacity, and more for the ISP.`); for (const i in response.nodes) { response.nodes[i].geolocation = { diff --git a/frontend/src/app/lightning/nodes-ranking/oldest-nodes/oldest-nodes.component.ts b/frontend/src/app/lightning/nodes-ranking/oldest-nodes/oldest-nodes.component.ts index 6ee9ed231..d83f3db0a 100644 --- a/frontend/src/app/lightning/nodes-ranking/oldest-nodes/oldest-nodes.component.ts +++ b/frontend/src/app/lightning/nodes-ranking/oldest-nodes/oldest-nodes.component.ts @@ -25,6 +25,7 @@ export class OldestNodes implements OnInit { ngOnInit(): void { if (!this.widget) { this.seoService.setTitle($localize`Oldest lightning nodes`); + this.seoService.setDescription($localize`:@@meta.description.lightning.ranking.oldest:See the oldest nodes on the Lightning network along with their capacity, number of channels, location, etc.`); } for (let i = 1; i <= (this.widget ? 10 : 100); ++i) { diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts index 50190f5ab..054fa2f3c 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts @@ -15,7 +15,7 @@ import { LightningApiService } from '../../lightning-api.service'; export class TopNodesPerCapacity implements OnInit { @Input() nodes$: Observable; @Input() widget: boolean = false; - + topNodesPerCapacity$: Observable; skeletonRows: number[] = []; currency$: Observable; @@ -31,6 +31,7 @@ export class TopNodesPerCapacity implements OnInit { if (!this.widget) { this.seoService.setTitle($localize`:@@2d9883d230a47fbbb2ec969e32a186597ea27405:Liquidity Ranking`); + this.seoService.setDescription($localize`:@@meta.description.lightning.ranking.liquidity:See Lightning nodes with the most BTC liquidity deployed along with high-level stats like number of open channels, location, node age, and more.`); } for (let i = 1; i <= (this.widget ? 6 : 100); ++i) { diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts index 607ec2a99..3de177cc7 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts @@ -35,6 +35,7 @@ export class TopNodesPerChannels implements OnInit { if (this.widget === false) { this.seoService.setTitle($localize`:@@c50bf442cf99f6fc5f8b687c460f33234b879869:Connectivity Ranking`); + this.seoService.setDescription($localize`:@@meta.description.lightning.ranking.channels:See Lightning nodes with the most channels open along with high-level stats like total node capacity, node age, and more.`); this.topNodesPerChannels$ = this.apiService.getTopNodesByChannels$().pipe( map((ranking) => { diff --git a/frontend/src/app/lightning/nodes-rankings-dashboard/nodes-rankings-dashboard.component.ts b/frontend/src/app/lightning/nodes-rankings-dashboard/nodes-rankings-dashboard.component.ts index 90342c557..46becb793 100644 --- a/frontend/src/app/lightning/nodes-rankings-dashboard/nodes-rankings-dashboard.component.ts +++ b/frontend/src/app/lightning/nodes-rankings-dashboard/nodes-rankings-dashboard.component.ts @@ -20,6 +20,7 @@ export class NodesRankingsDashboard implements OnInit { ngOnInit(): void { this.seoService.setTitle($localize`Top lightning nodes`); + this.seoService.setDescription($localize`:@@meta.description.lightning.rankings-dashboard:See top the Lightning network nodes ranked by liquidity, connectivity, and age.`); this.nodesRanking$ = this.lightningApiService.getNodesRanking$().pipe(share()); } } 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 dd034eabd..41e170de6 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 @@ -64,6 +64,7 @@ export class LightningStatisticsChartComponent implements OnInit { this.miningWindowPreference = '3y'; } else { this.seoService.setTitle($localize`:@@ea8db27e6db64f8b940711948c001a1100e5fe9f:Lightning Network Capacity`); + this.seoService.setDescription($localize`:@@meta.description.lightning.stats-chart:See the capacity of the Lightning network visualized over time in terms of the number of open channels and total bitcoin capacity.`); this.miningWindowPreference = this.miningService.getDefaultTimespan('all'); } this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 798df72c1..744474f9d 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -4,10 +4,13 @@ import { CpfpInfo, OptimizedMempoolStats, AddressInformation, LiquidPegs, ITrans PoolStat, BlockExtended, TransactionStripped, RewardStats, AuditScore, BlockSizesAndWeights, RbfTree, BlockAudit } from '../interfaces/node-api.interface'; import { Observable, of } from 'rxjs'; import { StateService } from './state.service'; -import { WebsocketResponse } from '../interfaces/websocket.interface'; +import { IBackendInfo, WebsocketResponse } from '../interfaces/websocket.interface'; import { Outspend, Transaction } from '../interfaces/electrs.interface'; import { Conversion } from './price.service'; +import { MenuGroup } from '../interfaces/services.interface'; +import { StorageService } from './storage.service'; +// Todo - move to config.json const SERVICES_API_PREFIX = `/api/v1/services`; @Injectable({ @@ -20,6 +23,7 @@ export class ApiService { constructor( private httpClient: HttpClient, private stateService: StateService, + private storageService: StorageService ) { this.apiBaseUrl = ''; // use relative URL by default if (!stateService.isBrowser) { // except when inside AU SSR process @@ -32,6 +36,12 @@ export class ApiService { } this.apiBasePath = network ? '/' + network : ''; }); + + if (this.stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE) { + this.getServicesBackendInfo$().subscribe(version => { + this.stateService.servicesBackendInfo$.next(version); + }) + } } list2HStatistics$(): Observable { @@ -95,7 +105,7 @@ export class ApiService { } getAboutPageProfiles$(): Observable { - return this.httpClient.get(this.apiBaseUrl + '/api/v1/about-page'); + return this.httpClient.get(this.apiBaseUrl + '/api/v1/services/sponsors'); } getOgs$(): Observable { @@ -334,9 +344,50 @@ export class ApiService { /** * Services */ - getNodeOwner$(publicKey: string) { + + getNodeOwner$(publicKey: string): Observable { let params = new HttpParams() .set('node_public_key', publicKey); return this.httpClient.get(`${SERVICES_API_PREFIX}/lightning/claim/current`, { params, observe: 'response' }); } + + getUserMenuGroups$(): Observable { + const auth = this.storageService.getAuth(); + if (!auth) { + return of(null); + } + + return this.httpClient.get(`${SERVICES_API_PREFIX}/account/menu`); + } + + getUserInfo$(): Observable { + const auth = this.storageService.getAuth(); + if (!auth) { + return of(null); + } + + return this.httpClient.get(`${SERVICES_API_PREFIX}/account`); + } + + logout$(): Observable { + const auth = this.storageService.getAuth(); + if (!auth) { + return of(null); + } + + localStorage.removeItem('auth'); + return this.httpClient.post(`${SERVICES_API_PREFIX}/auth/logout`, {}); + } + + getServicesBackendInfo$(): Observable { + return this.httpClient.get(`${SERVICES_API_PREFIX}/version`); + } + + estimate$(txInput: string) { + return this.httpClient.post(`${SERVICES_API_PREFIX}/accelerator/estimate`, { txInput: txInput }, { observe: 'response' }); + } + + accelerate$(txInput: string, userBid: number) { + return this.httpClient.post(`${SERVICES_API_PREFIX}/accelerator/accelerate`, { txInput: txInput, userBid: userBid }); + } } diff --git a/frontend/src/app/services/seo.service.ts b/frontend/src/app/services/seo.service.ts index 4fc25be52..3d095e1c3 100644 --- a/frontend/src/app/services/seo.service.ts +++ b/frontend/src/app/services/seo.service.ts @@ -10,6 +10,9 @@ import { StateService } from './state.service'; export class SeoService { network = ''; baseTitle = 'mempool'; + baseDescription = 'Explore the full Bitcoin ecosystem with The Mempool Open Projectâ„¢.'; + + canonicalLink: HTMLElement = document.getElementById('canonical'); constructor( private titleService: Title, @@ -52,6 +55,28 @@ export class SeoService { this.resetTitle(); } + setDescription(newDescription: string): void { + this.metaService.updateTag({ name: 'description', content: newDescription}); + this.metaService.updateTag({ name: 'twitter:description', content: newDescription}); + this.metaService.updateTag({ property: 'og:description', content: newDescription}); + } + + resetDescription(): void { + this.metaService.updateTag({ name: 'description', content: this.getDescription()}); + this.metaService.updateTag({ name: 'twitter:description', content: this.getDescription()}); + this.metaService.updateTag({ property: 'og:description', content: this.getDescription()}); + } + + updateCanonical(path) { + let domain = 'mempool.space'; + if (this.stateService.env.BASE_MODULE === 'liquid') { + domain = 'liquid.network'; + } else if (this.stateService.env.BASE_MODULE === 'bisq') { + domain = 'bisq.markets'; + } + this.canonicalLink.setAttribute('href', 'https://' + domain + path); + } + getTitle(): string { if (this.network === 'testnet') return this.baseTitle + ' - Bitcoin Testnet'; @@ -66,6 +91,15 @@ export class SeoService { return this.baseTitle + ' - ' + (this.network ? this.ucfirst(this.network) : 'Bitcoin') + ' Explorer'; } + getDescription(): string { + if ( (this.network === 'testnet') || (this.network === 'signet') || (this.network === '') || (this.network == 'mainnet') ) + return this.baseDescription + ' See the real-time status of your transactions, browse network stats, and more.'; + if ( (this.network === 'liquid') || (this.network === 'liquidtestnet') ) + return this.baseDescription + ' See Liquid transactions & assets, get network info, and more.'; + if (this.network === 'bisq') + return this.baseDescription + ' See Bisq market prices, trading activity, and more.'; + } + ucfirst(str: string) { return str.charAt(0).toUpperCase() + str.slice(1); } diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index 91e4d7475..db1268379 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -2,12 +2,13 @@ import { Inject, Injectable, PLATFORM_ID, LOCALE_ID } from '@angular/core'; import { ReplaySubject, BehaviorSubject, Subject, fromEvent, Observable, merge } from 'rxjs'; import { Transaction } from '../interfaces/electrs.interface'; import { IBackendInfo, MempoolBlock, MempoolBlockDelta, MempoolInfo, Recommendedfees, ReplacedTransaction, ReplacementInfo, TransactionStripped } from '../interfaces/websocket.interface'; -import { BlockExtended, DifficultyAdjustment, MempoolPosition, OptimizedMempoolStats, RbfTree } from '../interfaces/node-api.interface'; +import { BlockExtended, CpfpInfo, DifficultyAdjustment, MempoolPosition, OptimizedMempoolStats, RbfTree } from '../interfaces/node-api.interface'; import { Router, NavigationStart } from '@angular/router'; import { isPlatformBrowser } from '@angular/common'; import { filter, map, scan, shareReplay } from 'rxjs/operators'; import { StorageService } from './storage.service'; import { hasTouchScreen } from '../shared/pipes/bytes-pipe/utils'; +import { ApiService } from './api.service'; export interface MarkBlockState { blockHeight?: number; @@ -48,6 +49,8 @@ export interface Env { SIGNET_BLOCK_AUDIT_START_HEIGHT: number; HISTORICAL_PRICE: boolean; ACCELERATOR: boolean; + GIT_COMMIT_HASH_MEMPOOL_SPACE?: string; + PACKAGE_JSON_VERSION_MEMPOOL_SPACE?: string; } const defaultEnv: Env = { @@ -113,13 +116,15 @@ export class StateService { utxoSpent$ = new Subject(); difficultyAdjustment$ = new ReplaySubject(1); mempoolTransactions$ = new Subject(); - mempoolTxPosition$ = new Subject<{ txid: string, position: MempoolPosition}>(); + mempoolTxPosition$ = new Subject<{ txid: string, position: MempoolPosition, cpfp: CpfpInfo | null}>(); + mempoolRemovedTransactions$ = new Subject(); blockTransactions$ = new Subject(); isLoadingWebSocket$ = new ReplaySubject(1); isLoadingMempool$ = new BehaviorSubject(true); vbytesPerSecond$ = new ReplaySubject(1); previousRetarget$ = new ReplaySubject(1); backendInfo$ = new ReplaySubject(1); + servicesBackendInfo$ = new ReplaySubject(1); loadingIndicators$ = new ReplaySubject(1); recommendedFees$ = new ReplaySubject(1); chainTip$ = new ReplaySubject(-1); @@ -143,6 +148,7 @@ export class StateService { rateUnits$: BehaviorSubject; searchFocus$: Subject = new Subject(); + menuOpen$: BehaviorSubject = new BehaviorSubject(false); constructor( @Inject(PLATFORM_ID) private platformId: any, diff --git a/frontend/src/app/services/storage.service.ts b/frontend/src/app/services/storage.service.ts index 60d66b284..5a69d220b 100644 --- a/frontend/src/app/services/storage.service.ts +++ b/frontend/src/app/services/storage.service.ts @@ -56,4 +56,12 @@ export class StorageService { console.log(e); } } + + getAuth(): any | null { + try { + return JSON.parse(localStorage.getItem('auth')); + } catch(e) { + return null; + } + } } diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index af2a15e8c..22da49f06 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -358,6 +358,12 @@ export class WebsocketService { }); } + if (response['address-removed-transactions']) { + response['address-removed-transactions'].forEach((addressTransaction: Transaction) => { + this.stateService.mempoolRemovedTransactions$.next(addressTransaction); + }); + } + if (response['block-transactions']) { response['block-transactions'].forEach((addressTransaction: Transaction) => { this.stateService.blockTransactions$.next(addressTransaction); diff --git a/frontend/src/app/shared/common.utils.ts b/frontend/src/app/shared/common.utils.ts index 7d206f4b5..a04fa1663 100644 --- a/frontend/src/app/shared/common.utils.ts +++ b/frontend/src/app/shared/common.utils.ts @@ -135,4 +135,21 @@ export function haversineDistance(lat1: number, lon1: number, lat2: number, lon2 export function kmToMiles(km: number): number { return km * 0.62137119; +} + +const roundNumbers = [1, 2, 5, 10, 15, 20, 25, 50, 75, 100, 125, 150, 175, 200, 250, 300, 350, 400, 450, 500, 600, 700, 750, 800, 900, 1000]; +export function nextRoundNumber(num: number): number { + const log = Math.floor(Math.log10(num)); + const factor = log >= 3 ? Math.pow(10, log - 2) : 1; + num /= factor; + return factor * (roundNumbers.find(val => val >= num) || roundNumbers[roundNumbers.length - 1]); +} + +export function seoDescriptionNetwork(network: string): string { + if( network === 'liquidtestnet' || network === 'testnet' ) { + return ' Testnet'; + } else if( network === 'signet' || network === 'testnet' ) { + return ' ' + network.charAt(0).toUpperCase() + network.slice(1); + } + return ''; } \ No newline at end of file diff --git a/frontend/src/app/shared/components/confirmations/confirmations.component.html b/frontend/src/app/shared/components/confirmations/confirmations.component.html index db3f1f38a..4ad3cb33a 100644 --- a/frontend/src/app/shared/components/confirmations/confirmations.component.html +++ b/frontend/src/app/shared/components/confirmations/confirmations.component.html @@ -1,19 +1,19 @@ - - + - + - + - + \ No newline at end of file diff --git a/frontend/src/app/shared/components/confirmations/confirmations.component.scss b/frontend/src/app/shared/components/confirmations/confirmations.component.scss index e69de29bb..c8af7dd76 100644 --- a/frontend/src/app/shared/components/confirmations/confirmations.component.scss +++ b/frontend/src/app/shared/components/confirmations/confirmations.component.scss @@ -0,0 +1,4 @@ +.no-cursor { + cursor: default !important; + pointer-events: none; +} \ No newline at end of file diff --git a/frontend/src/app/shared/components/geolocation/geolocation.component.ts b/frontend/src/app/shared/components/geolocation/geolocation.component.ts index 9cce1ea08..1a498a1b2 100644 --- a/frontend/src/app/shared/components/geolocation/geolocation.component.ts +++ b/frontend/src/app/shared/components/geolocation/geolocation.component.ts @@ -20,6 +20,11 @@ export class GeolocationComponent implements OnChanges { formattedLocation: string = ''; ngOnChanges(): void { + if (!this.data) { + this.formattedLocation = '-'; + return; + } + const city = this.data.city ? this.data.city : ''; const subdivisionLikeCity = this.data.city === this.data.subdivision; let subdivision = this.data.subdivision; diff --git a/frontend/src/app/shared/components/global-footer/global-footer.component.html b/frontend/src/app/shared/components/global-footer/global-footer.component.html index 0b9c20387..34d47379e 100644 --- a/frontend/src/app/shared/components/global-footer/global-footer.component.html +++ b/frontend/src/app/shared/components/global-footer/global-footer.component.html @@ -1,12 +1,17 @@ -