From 39c8303d88beef416c60bbe007e41defbbe41e92 Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Fri, 16 Aug 2024 15:16:38 -0300 Subject: [PATCH 01/25] Add new sdk methods to flyover service --- jest.config.js | 1 + src/common/services/FlyoverService.ts | 56 +++++++++++++++++++ .../common/services/FlyoverService.spec.ts | 29 ++++++++-- 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/jest.config.js b/jest.config.js index 86f530e0a..90fc2729c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -13,4 +13,5 @@ module.exports = { coverageProvider: 'v8', transformIgnorePatterns: ['node_modules/(?!axios)/'], setupFilesAfterEnv: ['/setup-jest.js'], + silent: true, }; diff --git a/src/common/services/FlyoverService.ts b/src/common/services/FlyoverService.ts index 8f50b206e..c22f811aa 100644 --- a/src/common/services/FlyoverService.ts +++ b/src/common/services/FlyoverService.ts @@ -3,6 +3,7 @@ import { AcceptedPegoutQuote, Flyover, LiquidityProvider, PegoutQuote, Quote, AcceptedQuote, + FlyoverUtils, } from '@rsksmart/flyover-sdk'; import * as constants from '@/common/store/constants'; import { @@ -443,4 +444,59 @@ export default class FlyoverService { } }); } + + public getAvailableLiquidity(): Promise<{peginLiquidity: WeiBig, pegoutLiquidity: SatoshiBig}> { + return new Promise((resolve, reject) => { + this.flyover?.getAvailableLiquidity() + .then(({ peginLiquidityAmount, pegoutLiquidityAmount }) => { + const peginLiquidity = new WeiBig(peginLiquidityAmount, 'wei'); + const pegoutLiquidity = new SatoshiBig(pegoutLiquidityAmount, 'satoshi'); + resolve({ peginLiquidity, pegoutLiquidity }); + }) + .catch((error) => { + reject(new ServiceError( + 'FlyoverService', + 'getAvailableLiquidity', + 'There was an error getting the available liquidity from the Flyover server', + error.message, + )); + }); + }); + } + + public getPeginStatus(quoteHash: string) { + return new Promise((resolve, reject) => { + this.flyover?.getPeginStatus(quoteHash) + .then((detailedStatus) => { + const status = FlyoverUtils.getSimpleQuoteStatus(detailedStatus.status.state); + resolve(status); + }) + .catch((error) => { + reject(new ServiceError( + 'FlyoverService', + 'getPeginStatus', + 'There was an error getting the status of the peg-in transaction from the Flyover server', + error.message, + )); + }); + }); + } + + public getPegoutStatus(quoteHash: string) { + return new Promise((resolve, reject) => { + this.flyover?.getPegoutStatus(quoteHash) + .then((detailedStatus) => { + const status = FlyoverUtils.getSimpleQuoteStatus(detailedStatus.status.state); + resolve(status); + }) + .catch((error) => { + reject(new ServiceError( + 'FlyoverService', + 'getPegoutStatus', + 'There was an error getting the status of the peg-out transaction from the Flyover server', + error.message, + )); + }); + }); + } } diff --git a/tests/unit/common/services/FlyoverService.spec.ts b/tests/unit/common/services/FlyoverService.spec.ts index d4329493d..d04ad3444 100644 --- a/tests/unit/common/services/FlyoverService.spec.ts +++ b/tests/unit/common/services/FlyoverService.spec.ts @@ -1,9 +1,10 @@ import FlyoverService from '@/common/services/FlyoverService'; import { EnvironmentAccessorService } from '@/common/services/enviroment-accessor.service'; import { SatoshiBig, WeiBig } from '@/common/types'; -import { Flyover } from '@rsksmart/flyover-sdk'; +import { Flyover, FlyoverUtils } from '@rsksmart/flyover-sdk'; import * as constants from '@/common/store/constants'; import sinon from 'sinon'; +import { ServiceError } from '@/common/utils'; describe('FlyoverService', () => { let flyoverService: FlyoverService; @@ -128,8 +129,6 @@ describe('FlyoverService', () => { expect(provider).toHaveProperty('id'); expect(provider).toHaveProperty('name'); }); - - test.todo('should handle errors when fetching providers'); }); describe('getPegoutQuotes', () => { @@ -324,6 +323,7 @@ describe('FlyoverService', () => { const btcRefundAddress = 'n2y5V6LYszsrsxkMdMypL98YQxtBoLCXdc'; const btcRecipientAddress = 'n2y5V6LYszsrsxkMdMypL98YQxtBoLCXdc'; const valueToTransfer = new WeiBig('0.005', 'rbtc'); + const expectedTotalAmount = 5255689215476000n; const quotes = await flyoverService.getPegoutQuotes( rskRefundAddress, @@ -341,7 +341,28 @@ describe('FlyoverService', () => { expect(acceptedQuote).toBe('txHash'); expect(spyAcceptPegoutQuote).toHaveBeenCalled(); expect(spyIsValidAcceptedQuote).toHaveBeenCalled(); - expect(spyDepositPegout).toHaveBeenCalledWith(flyoverService['pegoutQuotes'][0], 'signature', 5255689215476000n); + expect(spyDepositPegout).toHaveBeenCalledWith(flyoverService['pegoutQuotes'][0], 'signature', expectedTotalAmount); + expect(FlyoverUtils.getQuoteTotal(flyoverService['pegoutQuotes'][0])).toEqual(expectedTotalAmount); + }); + }); + + describe('getAvailableLiquidity', () => { + it('should return the available liquidity', async () => { + const stubedInstance = sinon.createStubInstance(Flyover); + flyoverService.flyover = stubedInstance; + stubedInstance.getAvailableLiquidity.resolves({ + peginLiquidityAmount: 1000000000000000000n, + pegoutLiquidityAmount: 1000000000000000000n, + }); + const liquidity = await flyoverService.getAvailableLiquidity(); + expect(liquidity.peginLiquidity).toBeInstanceOf(WeiBig); + expect(liquidity.pegoutLiquidity).toBeInstanceOf(SatoshiBig); + }); + it('should throw an error if the available liquidity is not found', async () => { + const stubedInstance = sinon.createStubInstance(Flyover); + flyoverService.flyover = stubedInstance; + stubedInstance.getAvailableLiquidity.rejects(); + await expect(flyoverService.getAvailableLiquidity()).rejects.toThrowError(ServiceError); }); }); }); From 38c88f9448eb0239c4d812cd5d8110a31d83ae5f Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Tue, 10 Sep 2024 15:10:03 -0300 Subject: [PATCH 02/25] Set version to 2.3.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e9e122955..ad172e37b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "PowPeg", - "version": "2.2.1", + "version": "2.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "PowPeg", - "version": "2.2.1", + "version": "2.3.0", "dependencies": { "@leather.io/rpc": "^2.0.2", "@ledgerhq/devices": "6.27.1", diff --git a/package.json b/package.json index f251cc9d5..81380f672 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "PowPeg", - "version": "2.2.1", + "version": "2.3.0", "private": true, "scripts": { "serve": "vue-cli-service serve", From f5cabe60d77bff17387f5a108ec5cb34fdf5a84a Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Mon, 9 Sep 2024 16:24:09 -0300 Subject: [PATCH 03/25] Save quote hash --- src/common/types/TxInfo.ts | 1 + src/pegin/components/create/ConfirmTx.vue | 1 + src/pegout/components/FlyoverPegout.vue | 5 +++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/common/types/TxInfo.ts b/src/common/types/TxInfo.ts index 18dc876a5..8ac804235 100644 --- a/src/common/types/TxInfo.ts +++ b/src/common/types/TxInfo.ts @@ -10,4 +10,5 @@ export interface TxInfo { btcEstimatedFee?: number; provider?: string; details?: Record; + quoteHash?: string; } diff --git a/src/pegin/components/create/ConfirmTx.vue b/src/pegin/components/create/ConfirmTx.vue index d01022adb..85c4db015 100644 --- a/src/pegin/components/create/ConfirmTx.vue +++ b/src/pegin/components/create/ConfirmTx.vue @@ -171,6 +171,7 @@ export default defineComponent({ recipientAddress: recipientAddress.value, blocksToCompleteTransaction: selectedQuote.value.quote.confirmations, }, + quoteHash: selectedQuote.value.quoteHash, })); const nativeProps = computed(() => ({ diff --git a/src/pegout/components/FlyoverPegout.vue b/src/pegout/components/FlyoverPegout.vue index 501c0d95b..6bcf00ebb 100644 --- a/src/pegout/components/FlyoverPegout.vue +++ b/src/pegout/components/FlyoverPegout.vue @@ -110,7 +110,7 @@ import { import { mdiArrowLeft, mdiArrowRight } from '@mdi/js'; import { FlyoverPegoutState, ObjectDifference, PegOutTxState, QuotePegOut2WP, - SatoshiBig, TxStatusType, WeiBig, + SatoshiBig, TxInfo, TxStatusType, WeiBig, } from '@/common/types'; import { appendRecaptcha, Machine, ServiceError, validateAddress, @@ -280,7 +280,7 @@ export default defineComponent({ .toRBTCTrimmedString(); } - const registerFlyover = computed(() => ({ + const registerFlyover = computed(() => ({ sessionId: '', txHash: flyoverPegoutState.value.txHash as string, type: TxStatusType.PEGOUT.toLowerCase(), @@ -294,6 +294,7 @@ export default defineComponent({ recipientAddress: flyoverPegoutState.value.btcRecipientAddress, blocksToCompleteTransaction: selectedQuote.value.quote.depositConfirmations, }, + quoteHash: selectedQuote.value.quoteHash, })); const registerPegout = computed(() => ({ From 2aa3d6a1b88022789efc06a5bbebaee7e38220ed Mon Sep 17 00:00:00 2001 From: ronaldsg Date: Fri, 20 Sep 2024 13:46:51 -0500 Subject: [PATCH 04/25] Add xverse wallet support for Pegin --- jest.config.js | 4 + package-lock.json | 101 +++++++++++- package.json | 1 + src/assets/wallet-icons/xverse-white.png | Bin 0 -> 963 bytes src/assets/wallet-icons/xverse.png | Bin 0 -> 944 bytes .../exchange/SelectBitcoinWallet.vue | 3 + src/common/services/XverseService.ts | 144 ++++++++++++++++++ src/common/services/index.ts | 1 + src/common/store/constants.ts | 1 + src/common/types/Common.ts | 6 + src/common/types/pegInTx.ts | 2 +- src/common/utils/btcAddressUtils.ts | 14 ++ src/common/walletConf.json | 12 ++ src/pegin/components/create/SendBitcoin.vue | 5 + .../middleware/TxBuilder/XverseTxBuilder.ts | 78 ++++++++++ src/pegin/store/PeginTx/actions.ts | 5 +- src/pegin/store/PeginTx/getters.ts | 9 ++ tests/unit/common/services/XverseService.ts | 140 +++++++++++++++++ 18 files changed, 520 insertions(+), 6 deletions(-) create mode 100644 src/assets/wallet-icons/xverse-white.png create mode 100644 src/assets/wallet-icons/xverse.png create mode 100644 src/common/services/XverseService.ts create mode 100644 src/pegin/middleware/TxBuilder/XverseTxBuilder.ts create mode 100644 tests/unit/common/services/XverseService.ts diff --git a/jest.config.js b/jest.config.js index 90fc2729c..10a02b966 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,4 +1,8 @@ module.exports = { + transform: { + '^.+\\.vue$': '@vue/vue3-jest', + '^.+\\.(mts|mjs|jsx|ts|tsx)$': 'ts-jest', + }, preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel', collectCoverage: true, collectCoverageFrom: ['src/(common|pegin)/(providers|services|utils)/*.ts'], diff --git a/package-lock.json b/package-lock.json index ad172e37b..b534f4c51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ "moment": "^2.29.4", "os-browserify": "^0.3.0", "process": "^0.11.10", + "sats-connect": "^2.8.0", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "text-encoding": "^0.7.0", @@ -7102,6 +7103,39 @@ "version": "1.0.1", "license": "ISC" }, + "node_modules/@sats-connect/core": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@sats-connect/core/-/core-0.2.2.tgz", + "integrity": "sha512-nl3zPnV1UBllYAniDfhM/oSFGQ2qy4cCg1YwxJZ+RQMwlTMrVh2f3lJ//dIIo9RgQPrtHpwrAaaWW0VpfqDQbg==", + "dependencies": { + "axios": "1.7.4", + "bitcoin-address-validation": "2.2.3", + "buffer": "6.0.3", + "jsontokens": "4.0.1", + "lodash.omit": "4.5.0", + "valibot": "0.33.2" + } + }, + "node_modules/@sats-connect/core/node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, + "node_modules/@sats-connect/core/node_modules/bitcoin-address-validation": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/bitcoin-address-validation/-/bitcoin-address-validation-2.2.3.tgz", + "integrity": "sha512-1uGCGl26Ye8JG5qcExtFLQfuib6qEZWNDo1ZlLlwp/z7ygUFby3IxolgEfgMGaC+LG9csbVASLcH8fRLv7DIOg==", + "dependencies": { + "base58-js": "^1.0.0", + "bech32": "^2.0.0", + "sha256-uint8array": "^0.10.3" + } + }, + "node_modules/@sats-connect/ui": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@sats-connect/ui/-/ui-0.0.6.tgz", + "integrity": "sha512-H3bFFhr9CcY1oNosNi/QJszmMHSht4U19bUWfM3vzayAKgV4ebY6iUnRK5g3p2rVLLWVzlpaw1J9m+7JWwyBfA==" + }, "node_modules/@scure/base": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.6.tgz", @@ -10768,11 +10802,11 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.3.tgz", - "integrity": "sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -11153,6 +11187,14 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/base58-js": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/base58-js/-/base58-js-1.0.5.tgz", + "integrity": "sha512-LkkAPP8Zu+c0SVNRTRVDyMfKVORThX+rCViget00xdgLRrKkClCTz1T7cIrpr69ShwV5XJuuoZvMvJ43yURwkA==", + "engines": { + "node": ">= 8" + } + }, "node_modules/base64-js": { "version": "1.5.1", "funding": [ @@ -22502,6 +22544,11 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" + }, "node_modules/lodash.truncate": { "version": "4.4.2", "dev": true, @@ -26511,6 +26558,42 @@ } } }, + "node_modules/sats-connect": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/sats-connect/-/sats-connect-2.8.0.tgz", + "integrity": "sha512-eYdpPoAXn6ud1hMZnQGowO1F0f9fS3jmE5Hq1F3VxXUbAvT2YmA72PBtG6QN/cdMuFZ5x1ce6I/fl270WSXqjw==", + "dependencies": { + "@sats-connect/core": "0.2.2", + "@sats-connect/make-default-provider-config": "0.0.5", + "@sats-connect/ui": "0.0.6" + } + }, + "node_modules/sats-connect/node_modules/@sats-connect/make-default-provider-config": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@sats-connect/make-default-provider-config/-/make-default-provider-config-0.0.5.tgz", + "integrity": "sha512-b/v4IeDEde5DqFOdMbMmf3B0t/lxlKnY04f3YIUWe1khOg3S6VdcK9Mqva+WUOsJHBTIA5b4hK7CqfMjx1Ic+w==", + "dependencies": { + "@sats-connect/ui": "0.0.6", + "bowser": "2.11.0" + }, + "peerDependencies": { + "@sats-connect/core": "*", + "typescript": "5.4.4" + } + }, + "node_modules/sats-connect/node_modules/typescript": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", + "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/sax": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", @@ -26844,6 +26927,11 @@ "sha.js": "bin.js" } }, + "node_modules/sha256-uint8array": { + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/sha256-uint8array/-/sha256-uint8array-0.10.7.tgz", + "integrity": "sha512-1Q6JQU4tX9NqsDGodej6pkrUVQVNapLZnvkwIhddH/JqzBZF1fSaxSWNY6sziXBE8aEa2twtGkXUrwzGeZCMpQ==" + }, "node_modules/shallow-clone": { "version": "3.0.1", "license": "MIT", @@ -29246,6 +29334,11 @@ "node": ">= 8" } }, + "node_modules/valibot": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.33.2.tgz", + "integrity": "sha512-ZpFWuI+bs5+PP66q4zVFn4e4t/s5jmMw5iPBZmGUoi8iQqXyU9YY/BLCAyk62Z/bNS8qdUNBEyx52952qdqW3w==" + }, "node_modules/valid-url": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", diff --git a/package.json b/package.json index 81380f672..31f7efe1b 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "moment": "^2.29.4", "os-browserify": "^0.3.0", "process": "^0.11.10", + "sats-connect": "^2.8.0", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "text-encoding": "^0.7.0", diff --git a/src/assets/wallet-icons/xverse-white.png b/src/assets/wallet-icons/xverse-white.png new file mode 100644 index 0000000000000000000000000000000000000000..76b3e19ab399efeca2e84400dc9f883b7cab3884 GIT binary patch literal 963 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVkr05M1pgl1mAh%j*h z6I`|A0%imoq;2)dU$H=nv%n*=n1O*?7=#%aX3dcRniiQE5>XQ2>tmIipR1RclAn~S zSCLx)(#2p?VFhI7rj{fsROII56h?X&sHg;q@=(~U%$M(T(8_%FTW^V-_X+1Qs2Nx-^fT8 zs6w~6GOr}DLN~8i8Da>`9GBGM%@E9OzK% zs1tVhf2a9G@)50$D)ENntP{_7uy)*froCwT(tM%MYv)S5r> Nnx3wHF6*2UngC^jDYgIr literal 0 HcmV?d00001 diff --git a/src/assets/wallet-icons/xverse.png b/src/assets/wallet-icons/xverse.png new file mode 100644 index 0000000000000000000000000000000000000000..c65e0b6640571aa159986b58ed2dc35d2cb8e4ad GIT binary patch literal 944 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVkr05M1pgl1mAh%j*h z6I`|A0%imoq;2)dU$H=nv%n*=n1O*?7=#%aX3dcRniiQE5>XQ2>tmIipR1RclAn~S zSCLx)(#2p?VFhI7rj{fsROII56h?X&sHg;q@=(~U%$M(T(8_%FTW^V-_X+1Qs2Nx-^fT8 zs6w~6GOr}DLN~8i8Da>`9GBGMt<@S1PD>ORIVTITM=-E@{7_X$6q>;B zp7+#K{oGl7PxWGN?U|lm;_jtst7ZAvXM*y^_8I$b?Rllxs;t12$IFmzsu&o+f1&k@ zgP;S)qsBeji}cfjHlJ+Y`kZI3Lh+n{D(c)`fc$*FOAKBig|r^>#s=ElU*h34H;kzf2sB+Zc8%5IhjyRlB-A z+?*+ZL89wS{##pn1+jSs-_>5^XqfGMZks;KhOzq3dKt|%EsxebPv5WoNJ0Nx#;yf( spYwfFd!aY4jGN=R{|U7W?GElLCbz~U{&f?=Z-LUGr>mdKI;Vst02W6VQvd(} literal 0 HcmV?d00001 diff --git a/src/common/components/exchange/SelectBitcoinWallet.vue b/src/common/components/exchange/SelectBitcoinWallet.vue index 4a44919ae..80c595d14 100644 --- a/src/common/components/exchange/SelectBitcoinWallet.vue +++ b/src/common/components/exchange/SelectBitcoinWallet.vue @@ -89,6 +89,9 @@ export default { case constants.WALLET_NAMES.LEATHER.long_name: wallet = constants.WALLET_NAMES.LEATHER.short_name; break; + case constants.WALLET_NAMES.XVERSE.long_name: + wallet = constants.WALLET_NAMES.XVERSE.short_name; + break; default: wallet = ''; break; diff --git a/src/common/services/XverseService.ts b/src/common/services/XverseService.ts new file mode 100644 index 000000000..9725c7edd --- /dev/null +++ b/src/common/services/XverseService.ts @@ -0,0 +1,144 @@ +/* eslint-disable class-methods-use-this */ +import Wallet, { AddressPurpose, BitcoinNetworkType } from 'sats-connect'; +import * as bitcoin from 'bitcoinjs-lib'; +import { WalletService } from '@/common/services/index'; +import * as constants from '@/common/store/constants'; +import { + WalletAddress, Tx, SignedTx, BtcAccount, Step, + XverseTx, +} from '../types'; + +export default class XverseService extends WalletService { + satsBtcNetwork: BitcoinNetworkType; + + constructor() { + super(); + switch (this.network) { + case constants.BTC_NETWORK_MAINNET: + this.satsBtcNetwork = BitcoinNetworkType.Mainnet; + break; + default: + this.satsBtcNetwork = BitcoinNetworkType.Testnet; + break; + } + } + + getAccountAddresses(): Promise { + return new Promise((resolve, reject) => { + const walletAddresses: WalletAddress[] = []; + const payload = { + purposes: ['payment'] as AddressPurpose[], + message: 'Welcome to the 2wp-app, please select your Bitcoin account to start.', + network: { + type: this.satsBtcNetwork, + }, + }; + Wallet.request('getAddresses', payload) + .then((response) => { + if (response.status === 'error') { + reject(new Error(response.error.message)); + } else { + response.result.addresses + .forEach((addr: { address: string; publicKey: string; }) => { + walletAddresses.push({ + address: addr.address, + publicKey: addr.publicKey, + derivationPath: '', + }); + }); + } + resolve(walletAddresses); + }) + .catch(reject); + }); + } + + sign(tx: Tx): Promise { + const xverseTx = tx as XverseTx; + return new Promise((resolve, reject) => { + const signInputs: Record = {}; + xverseTx.inputs.forEach((input: { address: string; idx: number; }, inputIdx: number) => { + if (signInputs[input.address]) { + signInputs[input.address].push(inputIdx); + } else { + signInputs[input.address] = [inputIdx]; + } + }); + const signPsbtOptions = { + psbt: xverseTx.base64UnsignedPsbt, + signInputs, + broadcast: false, + }; + Wallet.request('signPsbt', signPsbtOptions) + .then((response) => { + if (response.status === 'error') { + reject(new Error(response.error.message)); + } else { + const signedPsbt = bitcoin.Psbt.fromBase64(response.result.psbt as string); + if (!signedPsbt.validateSignaturesOfAllInputs()) { + reject(new Error('Invalid signature provided')); + } else { + resolve({ + signedTx: signedPsbt.finalizeAllInputs().extractTransaction().toHex(), + }); + } + } + }) + .catch(() => reject(new Error('Invalid psbt provided'))); + }); + } + + isConnected(): Promise { + return Promise.resolve(true); + } + + reconnect(): Promise { + return new Promise((resolve, reject) => { + this.getAccountAddresses() + .then(() => resolve()) + .catch(reject); + }); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getXpub(accountType: BtcAccount, accountNumber: number): Promise { + throw new Error('Method not supported.'); + } + + areEnoughUnusedAddresses(): boolean { + return this.addressesToFetch.segwit.lastIndex >= 1; + } + + availableAccounts(): BtcAccount[] { + return [constants.BITCOIN_SEGWIT_ADDRESS]; + } + + name(): Record<'formal_name' | 'short_name' | 'long_name', string> { + return constants.WALLET_NAMES.XVERSE; + } + + confirmationSteps(): Step[] { + return [ + { + title: 'Transaction information', + subtitle: '', + outputsToshow: { + opReturn: { + value: false, + amount: true, + }, + change: { + address: true, + amount: true, + }, + federation: { + address: true, + amount: true, + }, + }, + fullAmount: false, + fee: true, + }, + ]; + } +} diff --git a/src/common/services/index.ts b/src/common/services/index.ts index 17c102547..be5b73a3a 100644 --- a/src/common/services/index.ts +++ b/src/common/services/index.ts @@ -4,3 +4,4 @@ export { default as TrezorService } from './TrezorService'; export { default as LedgerService } from './LedgerService'; export { default as LeatherService } from './LeatherService'; export { default as FlyoverService } from './FlyoverService'; +export { default as XverseService } from './XverseService'; diff --git a/src/common/store/constants.ts b/src/common/store/constants.ts index a7796c314..2b02be99d 100644 --- a/src/common/store/constants.ts +++ b/src/common/store/constants.ts @@ -3,6 +3,7 @@ export const WALLET_NAMES = { TREZOR: { formal_name: 'Trezor', short_name: 'trezor', long_name: 'WALLET_TREZOR' }, METAMASK: { formal_name: 'Metamask', short_name: 'metamask', long_name: 'WALLET_METAMASK' }, LEATHER: { formal_name: 'Leather', short_name: 'leather', long_name: 'WALLET_LEATHER' }, + XVERSE: { formal_name: 'XVerse', short_name: 'xverse', long_name: 'WALLET_XVERSE' }, } as const; export const OPERATION_TYPE = 'OPERATION_TYPE'; diff --git a/src/common/types/Common.ts b/src/common/types/Common.ts index fa5c5b291..182b7871d 100644 --- a/src/common/types/Common.ts +++ b/src/common/types/Common.ts @@ -109,6 +109,7 @@ export interface PsbtExtendedInput { value: number; script: Buffer; }; + redeemScript?: Buffer; } export interface NormalizedSummary { @@ -140,3 +141,8 @@ export enum AppLocale { LOCALE_EN = 'en', LOCALE_ES = 'es', } + +export interface XverseTx extends Tx { + base64UnsignedPsbt: string; + inputs: Array<{idx: number; address: string}>; +} diff --git a/src/common/types/pegInTx.ts b/src/common/types/pegInTx.ts index 601ecc39e..a35980eec 100644 --- a/src/common/types/pegInTx.ts +++ b/src/common/types/pegInTx.ts @@ -7,7 +7,7 @@ export type BtcAccount = 'BITCOIN_LEGACY_ADDRESS' | 'BITCOIN_SEGWIT_ADDRESS' | 'BITCOIN_NATIVE_SEGWIT_ADDRESS'; -export type BtcWallet = 'WALLET_LEDGER' | 'WALLET_TREZOR' | 'WALLET_LEATHER'; +export type BtcWallet = 'WALLET_LEDGER' | 'WALLET_TREZOR' | 'WALLET_LEATHER' | 'WALLET_XVERSE'; export type MiningSpeedFee = 'BITCOIN_SLOW_FEE_LEVEL' | 'BITCOIN_AVERAGE_FEE_LEVEL' | diff --git a/src/common/utils/btcAddressUtils.ts b/src/common/utils/btcAddressUtils.ts index 73ea16682..f013f8dce 100644 --- a/src/common/utils/btcAddressUtils.ts +++ b/src/common/utils/btcAddressUtils.ts @@ -52,3 +52,17 @@ export function validateAddress(address: string): {valid: boolean; addressType: } return { valid, addressType }; } + +function compressPublicKey(pubKey: string) { + const { publicKey } = bitcoin.ECPair.fromPublicKey(Buffer.from(pubKey, 'hex')); + return publicKey.toString('hex'); +} + +export function getP2SHRedeemScript(publicKey: string, network: bitcoin.Network) { + const pubkey = compressPublicKey(publicKey); + const pair = bitcoin.ECPair.fromPublicKey(Buffer.from(pubkey, 'hex')); + const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: pair.publicKey, network }); + const p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh, network }); + const redeem = p2sh.redeem?.output; + return redeem; +} diff --git a/src/common/walletConf.json b/src/common/walletConf.json index 0f2d66c06..390f6b0d9 100644 --- a/src/common/walletConf.json +++ b/src/common/walletConf.json @@ -35,6 +35,18 @@ "btnClass": "btn-leather", "kind": "Software Wallet", "installation": "https://leather.io/install-extension" + }, + { + "name": "Xverse", + "icon": "wallet-icons/xverse.png", + "iconWhite": "wallet-icons/xverse-white.png", + "constant": "WALLET_XVERSE", + "pegin": true, + "pegout": false, + "hover": false, + "btnClass": "btn-xverse", + "kind": "Software Wallet", + "installation": "https://www.xverse.app/download" } ] } diff --git a/src/pegin/components/create/SendBitcoin.vue b/src/pegin/components/create/SendBitcoin.vue index 2a41262fa..31a0531e5 100644 --- a/src/pegin/components/create/SendBitcoin.vue +++ b/src/pegin/components/create/SendBitcoin.vue @@ -51,6 +51,7 @@ import TxErrorDialog from '@/common/components/exchange/TxErrorDialog.vue'; import { TrezorError } from '@/common/types/exception/TrezorError'; import LeatherTxBuilder from '@/pegin/middleware/TxBuilder/LeatherTxBuilder'; import PeginTxService from '@/pegin/services/PeginTxService'; +import XverseTxBuilder from '@/pegin/middleware/TxBuilder/XverseTxBuilder'; export default defineComponent({ name: 'SendBitcoin', @@ -193,6 +194,10 @@ export default defineComponent({ txBuilder.value = new LeatherTxBuilder(); currentWallet.value = constants.WALLET_NAMES.LEATHER.short_name; break; + case constants.WALLET_NAMES.XVERSE.long_name: + txBuilder.value = new XverseTxBuilder(); + currentWallet.value = constants.WALLET_NAMES.XVERSE.short_name; + break; default: txBuilder.value = new TrezorTxBuilder(); break; diff --git a/src/pegin/middleware/TxBuilder/XverseTxBuilder.ts b/src/pegin/middleware/TxBuilder/XverseTxBuilder.ts new file mode 100644 index 000000000..e14ded5fe --- /dev/null +++ b/src/pegin/middleware/TxBuilder/XverseTxBuilder.ts @@ -0,0 +1,78 @@ +import { ApiService } from '@/common/services'; +import store from '@/common/store'; +import { + NormalizedInput, NormalizedTx, PsbtExtendedInput, + XverseTx, +} from '@/common/types'; +import * as bitcoin from 'bitcoinjs-lib'; +import * as constants from '@/common/store/constants'; +import { getP2SHRedeemScript } from '@/common/utils'; +import TxBuilder from './TxBuilder'; + +export default class XverseTxBuilder extends TxBuilder { + buildTx(normalizedTx: NormalizedTx): Promise { + return new Promise((resolve, reject) => { + const psbt = new bitcoin.Psbt({ network: this.network }); + this.getExtendedInputs(normalizedTx.inputs) + .then((extendedInputs) => { + psbt.addInputs(extendedInputs); + normalizedTx.outputs.forEach((normalizedOutput) => { + if (normalizedOutput.op_return_data) { + const buffer = Buffer.from(normalizedOutput.op_return_data, 'hex'); + const script: bitcoin.Payment = bitcoin.payments.embed({ data: [buffer] }); + if (script.output) { + psbt.addOutput({ + script: script.output, + value: 0, + }); + } + } else if (normalizedOutput.address) { + psbt.addOutput({ + address: normalizedOutput.address, + value: Number(normalizedOutput.amount), + }); + } + }); + const inputs = normalizedTx.inputs + .map((input) => ({ + address: input.address, + idx: input.prev_index, + })); + resolve({ + coin: this.coin, + inputs, + outputs: normalizedTx.outputs, + base64UnsignedPsbt: psbt.toBase64(), + }); + }) + .catch(reject); + }); + } + + private getExtendedInputs(normalizedInputs: Array) + :Promise> { + return new Promise>((resolve, reject) => { + const psbtExtendedInputs: Array = []; + const hexUtxoPromises = normalizedInputs + .map((input) => ApiService.getTxHex(input.prev_hash)); + Promise.all(hexUtxoPromises) + .then((hexUtxos) => { + normalizedInputs.forEach((normalizedInput, idx) => { + const utxo = bitcoin.Transaction.fromHex(hexUtxos[idx]); + const pubKey = store.getters[`pegInTx/${constants.PEGIN_TX_GET_ADDRESS_PUBLIC_KEY}`](normalizedInput.address); + psbtExtendedInputs.push({ + hash: normalizedInput.prev_hash, + index: normalizedInput.prev_index, + witnessUtxo: { + value: utxo.outs[normalizedInput.prev_index].value, + script: utxo.outs[normalizedInput.prev_index].script, + }, + redeemScript: getP2SHRedeemScript(pubKey, this.network), + }); + }); + resolve(psbtExtendedInputs); + }) + .catch(reject); + }); + } +} diff --git a/src/pegin/store/PeginTx/actions.ts b/src/pegin/store/PeginTx/actions.ts index be1efdc82..69e2e1813 100644 --- a/src/pegin/store/PeginTx/actions.ts +++ b/src/pegin/store/PeginTx/actions.ts @@ -4,7 +4,7 @@ import * as rskUtils from '@rsksmart/rsk-utils'; import * as constants from '@/common/store/constants'; import { ApiService, LedgerService, - TrezorService, LeatherService, + TrezorService, LeatherService, XverseService, } from '@/common/services'; import SatoshiBig from '@/common/types/SatoshiBig'; import { EnvironmentAccessorService } from '@/common/services/enviroment-accessor.service'; @@ -45,6 +45,9 @@ export const actions: ActionTree = { case constants.WALLET_NAMES.LEATHER.long_name: commit(constants.PEGIN_TX_SET_WALLET_SERVICE, new LeatherService()); break; + case constants.WALLET_NAMES.XVERSE.long_name: + commit(constants.PEGIN_TX_SET_WALLET_SERVICE, new XverseService()); + break; default: commit(constants.PEGIN_TX_SET_WALLET_SERVICE, undefined); break; diff --git a/src/pegin/store/PeginTx/getters.ts b/src/pegin/store/PeginTx/getters.ts index e2dd8b723..d46e6080c 100644 --- a/src/pegin/store/PeginTx/getters.ts +++ b/src/pegin/store/PeginTx/getters.ts @@ -17,6 +17,9 @@ export const getters: GetterTree = { case constants.WALLET_NAMES.LEATHER.long_name: { return constants.WALLET_NAMES.LEATHER.formal_name; } + case constants.WALLET_NAMES.XVERSE.long_name: { + return constants.WALLET_NAMES.XVERSE.formal_name; + } default: { return 'wallet'; } @@ -167,6 +170,9 @@ export const getters: GetterTree = { case constants.WALLET_NAMES.LEATHER.long_name: isHdWallet = false; break; + case constants.WALLET_NAMES.XVERSE.long_name: + isHdWallet = false; + break; default: isHdWallet = false; break; @@ -185,6 +191,9 @@ export const getters: GetterTree = { case constants.WALLET_NAMES.LEATHER.long_name: isSfWallet = true; break; + case constants.WALLET_NAMES.XVERSE.long_name: + isSfWallet = true; + break; default: isSfWallet = false; break; diff --git a/tests/unit/common/services/XverseService.ts b/tests/unit/common/services/XverseService.ts new file mode 100644 index 000000000..ac61192e1 --- /dev/null +++ b/tests/unit/common/services/XverseService.ts @@ -0,0 +1,140 @@ +import { EnvironmentAccessorService } from '@/common/services/enviroment-accessor.service'; +import * as constants from '@/common/store/constants'; +import sinon from 'sinon'; +import Wallet, { AddressPurpose, AddressType } from 'sats-connect'; +import { WalletService, XverseService } from '@/common/services'; + +const initEnvironment = () => { + const defaultEnvironmentVariables = { + vueAppCoin: constants.BTC_NETWORK_TESTNET, + vueAppManifestAppUrl: '', + vueAppManifestEmail: '', + vueAppWalletAddressPerCall: 5, + vueAppWalletAddressHardStop: 100, + }; + EnvironmentAccessorService.initializeEnvironmentVariables(defaultEnvironmentVariables); +}; + +describe('Xverse Service:', () => { + // let request: sinon.SinonStub<[XverseRequestArgs], Promise>; + // let mockedXverseProvider: sinon.SinonStubbedInstance; + + beforeEach(initEnvironment); + afterEach(() => sinon.restore()); + + it('should create a XverseService instance', () => { + const xverseService = new XverseService(); + expect(xverseService).toBeInstanceOf(XverseService); + expect(xverseService).toBeInstanceOf(WalletService); + }); + + it('should return a single address since that is the current amount supported by xverse', () => { + sinon.stub(Wallet, 'request').resolves({ + status: 'success', + result: { + addresses: [ + { + address: 'testAddress', + publicKey: 'testPublicKey', + purpose: AddressPurpose.Payment, + addressType: AddressType.p2pkh, + }, + ], + }, + }); + const xverseService = new XverseService(); + xverseService.getAccountAddresses().then((addresses) => { + expect(addresses.length).toBe(1); + expect(addresses[0].address).toBe('testAddress'); + expect(addresses[0].publicKey).toBe('testPublicKey'); + }); + }); + + it('should handle the error case when the wallet are not available', () => { + sinon.stub(Wallet, 'request').resolves({ + status: 'error', + error: { + code: 1, + message: 'Wallet not available', + }, + }); + const xverseService = new XverseService(); + expect(xverseService.getAccountAddresses()) + .rejects + .toThrow('Wallet not available'); + }); + + it('should return an error when the psbt are wrong', () => { + sinon.stub(Wallet, 'request').resolves({ + status: 'success', + result: { + psbt: 'cHNidP8BAHECAAAAAW4TCBaK74DxafvrRdWpF32Gg5eVRs1DJX9YHz2v9jduAQAAAAD9', + }, + }); + const xverseService = new XverseService(); + const xverseTx = { + coin: 'test', + inputs: [ + { + addres: '2Mxv1YkAXpTMcq2at1it9QRfq8bDX82N99J', + idx: 2, + }, + ], + outputs: [ + { + amount: '0', + op_return_data: '52534b5401aFf12FA1c482BEab1D70C68fe0Fc5825447A9818', + }, + { + address: '2N3JQb9erL1SnAr3NTMrZiPQQ8dcjJp4idV', + amount: '500000', + }, + { + address: '2Mxv1YkAXpTMcq2at1it9QRfq8bDX82N99J', + amount: '982474', + }, + ], + base64UnsignedPsbt: 'cHNidP8BAJcCAAAAAboaf2woNcottY/Ax+9lbYi349++WmdwYZPyOp8nXg5tAgAAAAD/////AwAAAAAAAAAAG2oZUlNLVAGv8S+hxIK+qx1wxo/g/FglRHqYGCChBwAAAAAAF6kUbkta6F2G5NsObl2wn4wnYyjNvz+Hyv0OAAAAAAAXqRQ+Lnd+D2z9GnchcMB/v3/pWn8CfYcAAAAAAAEBIL60FgAAAAAAF6kUPi53fg9s/Rp3IXDAf79/6Vp/An2HAQQWABSmO24c7Zf0uweZC7P9rNOrMR7sqwAAAAA=', + }; + expect(xverseService.sign(xverseTx)) + .rejects + .toThrow('Invalid psbt provided'); + }); + + it('should return an error when the psbt has some unsigned input', () => { + sinon.stub(Wallet, 'request').resolves({ + status: 'success', + result: { + psbt: 'cHNidP8BAJcCAAAAAboaf2woNcottY/Ax+9lbYi349++WmdwYZPyOp8nXg5tAgAAAAD/////AwAAAAAAAAAAG2oZUlNLVAGv8S+hxIK+qx1wxo/g/FglRHqYGCChBwAAAAAAF6kUbkta6F2G5NsObl2wn4wnYyjNvz+Hyv0OAAAAAAAXqRQ+Lnd+D2z9GnchcMB/v3/pWn8CfYcAAAAAAAEBIL60FgAAAAAAF6kUPi53fg9s/Rp3IXDAf79/6Vp/An2HAQQWABSmO24c7Zf0uweZC7P9rNOrMR7sqwAAAAA=', + }, + }); + const xverseService = new XverseService(); + const xverseTx = { + coin: 'test', + inputs: [ + { + addres: '2Mxv1YkAXpTMcq2at1it9QRfq8bDX82N99J', + idx: 2, + }, + ], + outputs: [ + { + amount: '0', + op_return_data: '52534b5401aFf12FA1c482BEab1D70C68fe0Fc5825447A9818', + }, + { + address: '2N3JQb9erL1SnAr3NTMrZiPQQ8dcjJp4idV', + amount: '500000', + }, + { + address: '2Mxv1YkAXpTMcq2at1it9QRfq8bDX82N99J', + amount: '982474', + }, + ], + base64UnsignedPsbt: 'cHNidP8BAJcCAAAAAboaf2woNcottY/Ax+9lbYi349++WmdwYZPyOp8nXg5tAgAAAAD/////AwAAAAAAAAAAG2oZUlNLVAGv8S+hxIK+qx1wxo/g/FglRHqYGCChBwAAAAAAF6kUbkta6F2G5NsObl2wn4wnYyjNvz+Hyv0OAAAAAAAXqRQ+Lnd+D2z9GnchcMB/v3/pWn8CfYcAAAAAAAEBIL60FgAAAAAAF6kUPi53fg9s/Rp3IXDAf79/6Vp/An2HAQQWABSmO24c7Zf0uweZC7P9rNOrMR7sqwAAAAA=', + }; + expect(xverseService.sign(xverseTx)) + .rejects + .toThrow('Invalid psbt provided'); + }); +}); From 1e5f007efc6a118e150b1d448a155c8b1b2cdc47 Mon Sep 17 00:00:00 2001 From: ronaldsg Date: Mon, 23 Sep 2024 19:25:31 -0500 Subject: [PATCH 05/25] Downgrade sats-connect version --- package-lock.json | 90 ++++++++++++++----- package.json | 2 +- ...XverseService.ts => XverseService.spec.ts} | 0 3 files changed, 69 insertions(+), 23 deletions(-) rename tests/unit/common/services/{XverseService.ts => XverseService.spec.ts} (100%) diff --git a/package-lock.json b/package-lock.json index b534f4c51..b8a4e23f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "moment": "^2.29.4", "os-browserify": "^0.3.0", "process": "^0.11.10", - "sats-connect": "^2.8.0", + "sats-connect": "2.3.x", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "text-encoding": "^0.7.0", @@ -7104,16 +7104,25 @@ "license": "ISC" }, "node_modules/@sats-connect/core": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@sats-connect/core/-/core-0.2.2.tgz", - "integrity": "sha512-nl3zPnV1UBllYAniDfhM/oSFGQ2qy4cCg1YwxJZ+RQMwlTMrVh2f3lJ//dIIo9RgQPrtHpwrAaaWW0VpfqDQbg==", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@sats-connect/core/-/core-0.0.8.tgz", + "integrity": "sha512-vb7drnd8lFfO4ahCzaVAFkX1eHF1J7jheJl2V/JuuJd5f1sy6nHeNzKMp1zmiuql8uNwe0Sx1WrK1I+4tUmDHg==", "dependencies": { - "axios": "1.7.4", + "axios": "1.6.8", "bitcoin-address-validation": "2.2.3", "buffer": "6.0.3", "jsontokens": "4.0.1", - "lodash.omit": "4.5.0", - "valibot": "0.33.2" + "lodash.omit": "4.5.0" + } + }, + "node_modules/@sats-connect/core/node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/@sats-connect/core/node_modules/bech32": { @@ -26559,28 +26568,70 @@ } }, "node_modules/sats-connect": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/sats-connect/-/sats-connect-2.8.0.tgz", - "integrity": "sha512-eYdpPoAXn6ud1hMZnQGowO1F0f9fS3jmE5Hq1F3VxXUbAvT2YmA72PBtG6QN/cdMuFZ5x1ce6I/fl270WSXqjw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sats-connect/-/sats-connect-2.3.1.tgz", + "integrity": "sha512-3KzqRO5KVBlge7Q4a/L828SfCkFD+M4MVdtgJZS+L+oHiDYoXlLkvnu3almh9Ynhcm0HnsGmVH1pKVL0lonjyQ==", "dependencies": { - "@sats-connect/core": "0.2.2", - "@sats-connect/make-default-provider-config": "0.0.5", + "@sats-connect/core": "0.0.8", + "@sats-connect/make-default-provider-config": "0.0.4", "@sats-connect/ui": "0.0.6" } }, "node_modules/sats-connect/node_modules/@sats-connect/make-default-provider-config": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@sats-connect/make-default-provider-config/-/make-default-provider-config-0.0.5.tgz", - "integrity": "sha512-b/v4IeDEde5DqFOdMbMmf3B0t/lxlKnY04f3YIUWe1khOg3S6VdcK9Mqva+WUOsJHBTIA5b4hK7CqfMjx1Ic+w==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@sats-connect/make-default-provider-config/-/make-default-provider-config-0.0.4.tgz", + "integrity": "sha512-PsLzg1hV3FxMXUp9XrOUmDJgbuyR4VDHq/7mh1O1CtC3dDZQnJFa+Ue43duPMmUaRGinuVKtS2hnMhPLyURdGA==", "dependencies": { - "@sats-connect/ui": "0.0.6", + "@sats-connect/core": "0.0.7", + "@sats-connect/ui": "0.0.5-c661c02", "bowser": "2.11.0" }, "peerDependencies": { - "@sats-connect/core": "*", "typescript": "5.4.4" } }, + "node_modules/sats-connect/node_modules/@sats-connect/make-default-provider-config/node_modules/@sats-connect/core": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@sats-connect/core/-/core-0.0.7.tgz", + "integrity": "sha512-4m5amq+orHDbqLqCRWojvDQigKAys33Ntwc7U5xNtFeib4j+DpYz6lVAL/s3cay1kq03WUZ+Gil3l5rv+5bQWQ==", + "dependencies": { + "axios": "1.6.8", + "bitcoin-address-validation": "2.2.3", + "buffer": "6.0.3", + "jsontokens": "4.0.1", + "lodash.omit": "4.5.0" + } + }, + "node_modules/sats-connect/node_modules/@sats-connect/make-default-provider-config/node_modules/@sats-connect/ui": { + "version": "0.0.5-c661c02", + "resolved": "https://registry.npmjs.org/@sats-connect/ui/-/ui-0.0.5-c661c02.tgz", + "integrity": "sha512-6MUXFDGTapBhZAxb6deAdqKuB64GOe6k927gGww5JYwVnOUCaHGDcfaZ/lwexzYL45u8RJof12I4np7MgS+Bwg==" + }, + "node_modules/sats-connect/node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/sats-connect/node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, + "node_modules/sats-connect/node_modules/bitcoin-address-validation": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/bitcoin-address-validation/-/bitcoin-address-validation-2.2.3.tgz", + "integrity": "sha512-1uGCGl26Ye8JG5qcExtFLQfuib6qEZWNDo1ZlLlwp/z7ygUFby3IxolgEfgMGaC+LG9csbVASLcH8fRLv7DIOg==", + "dependencies": { + "base58-js": "^1.0.0", + "bech32": "^2.0.0", + "sha256-uint8array": "^0.10.3" + } + }, "node_modules/sats-connect/node_modules/typescript": { "version": "5.4.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", @@ -29334,11 +29385,6 @@ "node": ">= 8" } }, - "node_modules/valibot": { - "version": "0.33.2", - "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.33.2.tgz", - "integrity": "sha512-ZpFWuI+bs5+PP66q4zVFn4e4t/s5jmMw5iPBZmGUoi8iQqXyU9YY/BLCAyk62Z/bNS8qdUNBEyx52952qdqW3w==" - }, "node_modules/valid-url": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", diff --git a/package.json b/package.json index 31f7efe1b..be6b5fc4a 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "moment": "^2.29.4", "os-browserify": "^0.3.0", "process": "^0.11.10", - "sats-connect": "^2.8.0", + "sats-connect": "2.3.x", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "text-encoding": "^0.7.0", diff --git a/tests/unit/common/services/XverseService.ts b/tests/unit/common/services/XverseService.spec.ts similarity index 100% rename from tests/unit/common/services/XverseService.ts rename to tests/unit/common/services/XverseService.spec.ts From 27dc8e0eaad121746d136a2198b8b729dc8d3e02 Mon Sep 17 00:00:00 2001 From: ronaldsg Date: Thu, 26 Sep 2024 02:22:19 -0500 Subject: [PATCH 06/25] Increasin unit test for Xverse wallet services and Tx builder --- package.json | 1 + src/common/services/XverseService.ts | 2 +- .../components/XverseTxBuilder.spec.ts | 182 ++++++++++++++++++ 3 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 tests/unit/pegin/services/components/XverseTxBuilder.spec.ts diff --git a/package.json b/package.json index be6b5fc4a..dfe1d0f3c 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "build": "vue-cli-service build", "test": "vue-cli-service test:unit --env=./tests/jsdom-env.js --coverageReporters=lcov --collect-coverage", "test:unit": "vue-cli-service test:unit --env=./tests/jsdom-env.js --coverageReporters=lcov --collect-coverage", + "test:unit-logs": "vue-cli-service test:unit --env=./tests/jsdom-env.js --coverageReporters=lcov --silent=false --collect-coverage", "lint": "vue-cli-service lint", "scanner": "npx sonar-scanner" }, diff --git a/src/common/services/XverseService.ts b/src/common/services/XverseService.ts index 9725c7edd..d79c667d1 100644 --- a/src/common/services/XverseService.ts +++ b/src/common/services/XverseService.ts @@ -28,7 +28,7 @@ export default class XverseService extends WalletService { const walletAddresses: WalletAddress[] = []; const payload = { purposes: ['payment'] as AddressPurpose[], - message: 'Welcome to the 2wp-app, please select your Bitcoin account to start.', + message: 'Welcome to the Powpeg app, please select your Bitcoin account to start.', network: { type: this.satsBtcNetwork, }, diff --git a/tests/unit/pegin/services/components/XverseTxBuilder.spec.ts b/tests/unit/pegin/services/components/XverseTxBuilder.spec.ts new file mode 100644 index 000000000..32552f841 --- /dev/null +++ b/tests/unit/pegin/services/components/XverseTxBuilder.spec.ts @@ -0,0 +1,182 @@ +import { expect } from 'chai'; +import sinon from 'sinon'; +import { ApiService } from '@/common/services'; +import store from '@/common/store'; +import * as constants from '@/common/store/constants'; +import XverseTxBuilder from '@/pegin/middleware/TxBuilder/XverseTxBuilder'; +import { NormalizedTx, NormalizedInput } from '@/common/types'; +import axios, { AxiosHeaders, AxiosResponse } from 'axios'; +import { EnvironmentAccessorService } from '@/common/services/enviroment-accessor.service'; + +const txHex1 = '01000000022d2d5d12644b7f46bd2c094eb663f074f1042fa0a522b59d338cedde83aa5661000000006b483045022100b247c5947c69ab0e6249c587e2792cc5b723a356f796d092b1c2493ed5a74d3a02203e72fc592318ed72b2537859e6d02d91c61da1f27fcb066a566ce20d87e90178012103cb3b06dff127665fc0173c4910b8c254924627cd27decaaf9771f0566b859fdefdffffff57497ac2292f1dec0baba43abbbb02059164309c5f384b64ac4a931c0ae96177010000006a473044022026fa68c558f028258a4f489ecbbe0c5457825f5f7bedaabbcac82b5a64793dc402202aa1996f62728adfe78e1b7b31481397b8bdb20b004b161c3f121a972660746b01210264f3f31d1a81ab1062fce2187dad0c0efb1cee194f5c1ca520bf0a1295df6ee5fdffffff01f44f05000000000017a914a8e241e997f18c2dc0611cc6cb2d889e17f34f378700000000'; + +function getTxHex(expectedHex: string): Promise { + return new Promise((resolve) => { + resolve( + { + data: { hex: expectedHex }, + status: 200, + statusText: 'OK', + headers: {}, + config: { headers: new AxiosHeaders() }, + }, + ); + }); +} + +function setEnvironment() { + const defaultEnvironmentVariables = { + vueAppCoin: constants.BTC_NETWORK_TESTNET, + vueAppRskNodeHost: '', + vueAppApiBaseUrl: 'https://api.2wp.testnet.rootstock.io', + }; + EnvironmentAccessorService.initializeEnvironmentVariables(defaultEnvironmentVariables); +} + +describe('XverseTxBuilder', () => { + let xverseTxBuilder: XverseTxBuilder; + + beforeEach(() => { + setEnvironment(); + xverseTxBuilder = new XverseTxBuilder(); + }); + + afterEach(() => { + sinon.restore(); + }); + + describe('buildTx', () => { + it('should build a transaction successfully', async () => { + const normalizedTx: NormalizedTx = { + inputs: [ + { + address: '2N8eCZA1Su5ysSDKqDGSMNH8KgFi1L5jEYh', + prev_hash: 'c31556bf6a6b6c0a57387a88ad69a8cc7c159362d25d4870bffa3c005293375e', + prev_index: 0, + amount: '348148', + }, + ], + outputs: [ + { + address: '2N15XxmYFrp9e1cjCruQVNgYF3cuYQxvtqX', + amount: '1000', + }, + ], + coin: 'test', + }; + store.commit( + `pegInTx/${constants.PEGIN_TX_SET_ADDRESS_LIST}`, + [ + { + derivationPath: "m/49'/1'/0'/1/2", + address: '2N8eCZA1Su5ysSDKqDGSMNH8KgFi1L5jEYh', + publicKey: '02dc57829f1a5001646eb64edcecd797d5cbd0fcb24fb5a37d3084309a9201537c', + unused: false, + }, + { + derivationPath: "m/49'/1'/0'/0/3", + address: '2MzYn6qw7fbV7BtsoT6yBVV8nrbp37f6Uju', + publicKey: '0321afc4e7457e83aedecb1995ea2331d2aeff18a38f14ea710f35924d16d35a30', + unused: true, + }, + ], + ); + sinon.stub(axios, 'get').resolves(getTxHex(txHex1)); + + const result = await xverseTxBuilder.buildTx(normalizedTx); + + expect(result).to.have.property('coin'); + expect(result).to.have.property('inputs').that.is.an('array').with.lengthOf(1); + expect(result).to.have.property('outputs').that.is.an('array').with.lengthOf(1); + expect(result).to.have.property('base64UnsignedPsbt').that.is.a('string'); + }); + + it('should handle errors when building a transaction', async () => { + const normalizedTx: NormalizedTx = { + inputs: [ + { + address: '2N8eCZA1Su5ysSDKqDGSMNH8KgFi1L5jEYh', + prev_hash: 'c31556bf6a6b6c0a57387a88ad69a8cc7c159362d25d4870bffa3c005293375e', + prev_index: 0, + amount: '348148', + }, + ], + outputs: [ + { + address: '2N15XxmYFrp9e1cjCruQVNgYF3cuYQxvtqX', + amount: '1000', + }, + ], + coin: '', + }; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + sinon.stub(xverseTxBuilder, 'getExtendedInputs').rejects(new Error('Test error')); + + try { + await xverseTxBuilder.buildTx(normalizedTx); + } catch (error) { + expect(error).to.be.an('error').with.property('message', 'Test error'); + } + }); + }); + + describe('getExtendedInputs', () => { + it('should get extended inputs successfully', async () => { + const normalizedInputs: NormalizedInput[] = [ + { + address: '2N8eCZA1Su5ysSDKqDGSMNH8KgFi1L5jEYh', + prev_hash: 'c31556bf6a6b6c0a57387a88ad69a8cc7c159362d25d4870bffa3c005293375e', + prev_index: 0, + amount: '348148', + }, + ]; + store.commit( + `pegInTx/${constants.PEGIN_TX_SET_ADDRESS_LIST}`, + [ + { + derivationPath: "m/49'/1'/0'/1/2", + address: '2N8eCZA1Su5ysSDKqDGSMNH8KgFi1L5jEYh', + publicKey: '02dc57829f1a5001646eb64edcecd797d5cbd0fcb24fb5a37d3084309a9201537c', + unused: false, + }, + { + derivationPath: "m/49'/1'/0'/0/3", + address: '2MzYn6qw7fbV7BtsoT6yBVV8nrbp37f6Uju', + publicKey: '0321afc4e7457e83aedecb1995ea2331d2aeff18a38f14ea710f35924d16d35a30', + unused: true, + }, + ], + ); + sinon.stub(axios, 'get').resolves(getTxHex(txHex1)); + // eslint-disable-next-line dot-notation + const result = await xverseTxBuilder['getExtendedInputs'](normalizedInputs); + + expect(result).to.be.an('array').with.lengthOf(1); + expect(result[0]).to.have.property('hash', 'c31556bf6a6b6c0a57387a88ad69a8cc7c159362d25d4870bffa3c005293375e'); + expect(result[0]).to.have.property('index', 0); + expect(result[0]).to.have.property('witnessUtxo').that.is.an('object'); + expect(result[0]).to.have.property('redeemScript').that.is.an.instanceOf(Buffer); + }); + + it('should handle errors when getting extended inputs', async () => { + const normalizedInputs: NormalizedInput[] = [ + { + address: 'testAddress1', + prev_hash: 'testHash1', + prev_index: 0, + amount: '', + }, + ]; + + sinon.stub(ApiService, 'getTxHex').rejects(new Error('Tx not found')); + + try { + // eslint-disable-next-line dot-notation + await xverseTxBuilder['getExtendedInputs'](normalizedInputs); + } catch (error) { + expect(error).to.be.an('error').with.property('message', 'Tx not found'); + } + }); + }); +}); From 79b12a1fa228abaeefc4f9e56cda6cd206458e6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:24:52 +0000 Subject: [PATCH 07/25] build(deps): bump webpack from 5.88.2 to 5.94.0 Bumps [webpack](https://github.com/webpack/webpack) from 5.88.2 to 5.94.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.88.2...v5.94.0) --- updated-dependencies: - dependency-name: webpack dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 198 +++++++++++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 91 deletions(-) diff --git a/package-lock.json b/package-lock.json index b8a4e23f4..424fb2642 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5908,8 +5908,9 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "license": "MIT", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -8150,26 +8151,18 @@ }, "node_modules/@types/eslint": { "version": "8.44.2", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { - "version": "1.0.1", - "devOptional": true, - "license": "MIT" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "devOptional": true }, "node_modules/@types/express": { "version": "4.17.17", @@ -10041,9 +10034,10 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.6", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "devOptional": true, - "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -10051,23 +10045,27 @@ }, "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.11.6", - "devOptional": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "devOptional": true }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.6", - "devOptional": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "devOptional": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "devOptional": true, - "license": "MIT" + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "devOptional": true }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "devOptional": true, - "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -10076,62 +10074,69 @@ }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.6", - "devOptional": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "devOptional": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "devOptional": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" + "@webassemblyjs/wasm-gen": "1.12.1" } }, "node_modules/@webassemblyjs/ieee754": { "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "devOptional": true, - "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "devOptional": true, - "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { "version": "1.11.6", - "devOptional": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "devOptional": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.6", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "devOptional": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.6", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "devOptional": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", "@webassemblyjs/leb128": "1.11.6", @@ -10139,22 +10144,24 @@ } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.6", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "devOptional": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.6", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "devOptional": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", @@ -10163,11 +10170,12 @@ } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.6", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "devOptional": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -10181,13 +10189,15 @@ }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", - "devOptional": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "devOptional": true }, "node_modules/@xtuc/long": { "version": "4.2.2", - "devOptional": true, - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "devOptional": true }, "node_modules/abab": { "version": "2.0.6", @@ -10270,10 +10280,11 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "devOptional": true, - "license": "MIT", "peerDependencies": { "acorn": "^8" } @@ -28169,9 +28180,10 @@ } }, "node_modules/terser": { - "version": "5.19.2", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "devOptional": true, - "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -28186,15 +28198,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.9", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "devOptional": true, - "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" + "terser": "^5.26.0" }, "engines": { "node": ">= 10.13.0" @@ -29824,9 +29837,10 @@ } }, "node_modules/watchpack": { - "version": "2.4.0", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "devOptional": true, - "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -31406,33 +31420,33 @@ } }, "node_modules/webpack": { - "version": "5.88.2", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", "devOptional": true, - "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { @@ -31858,9 +31872,10 @@ "license": "MIT" }, "node_modules/webpack/node_modules/enhanced-resolve": { - "version": "5.15.0", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "devOptional": true, - "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -31888,8 +31903,9 @@ }, "node_modules/webpack/node_modules/tapable": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "devOptional": true, - "license": "MIT", "engines": { "node": ">=6" } From 99f4d7f94b52e3cec835b339b3519a0c1ceed5b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:21:50 +0000 Subject: [PATCH 08/25] build(deps): bump body-parser and express Bumps [body-parser](https://github.com/expressjs/body-parser) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `body-parser` from 1.20.2 to 1.20.3 - [Release notes](https://github.com/expressjs/body-parser/releases) - [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/body-parser/compare/1.20.2...1.20.3) Updates `express` from 4.19.2 to 4.21.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0) --- updated-dependencies: - dependency-name: body-parser dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 244 +++++++++++++++++++++++++++++++++------------- 1 file changed, 176 insertions(+), 68 deletions(-) diff --git a/package-lock.json b/package-lock.json index 424fb2642..065713c05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11487,9 +11487,9 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -11500,7 +11500,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -11525,21 +11525,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/bonjour-service": { "version": "1.1.1", "dev": true, @@ -11845,8 +11830,9 @@ }, "node_modules/bytes": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -12728,8 +12714,9 @@ }, "node_modules/content-type": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -14261,6 +14248,7 @@ "node_modules/encodeurl": { "version": "1.0.2", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -16707,37 +16695,37 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -16757,6 +16745,15 @@ "ms": "2.0.0" } }, + "node_modules/express/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -16764,25 +16761,50 @@ "dev": true }, "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.7", - "dev": true, - "license": "MIT" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true }, - "node_modules/express/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "node_modules/express/node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8.0" + } + }, + "node_modules/express/node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" } }, + "node_modules/express/node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, "node_modules/ext": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", @@ -17130,12 +17152,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -17148,16 +17171,27 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, - "node_modules/finalhandler/node_modules/ms": { + "node_modules/finalhandler/node_modules/encodeurl": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, - "license": "MIT" + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, "node_modules/find-cache-dir": { "version": "3.3.2", @@ -22993,8 +23027,9 @@ }, "node_modules/media-typer": { "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -23045,9 +23080,13 @@ "license": "MIT" }, "node_modules/merge-descriptors": { - "version": "1.0.1", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "MIT" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-source-map": { "version": "1.1.0", @@ -25649,10 +25688,11 @@ } }, "node_modules/qs": { - "version": "6.11.2", - "license": "BSD-3-Clause", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -26777,6 +26817,7 @@ "node_modules/send": { "version": "0.18.0", "license": "MIT", + "peer": true, "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -26799,17 +26840,20 @@ "node_modules/send/node_modules/debug": { "version": "2.6.9", "license": "MIT", + "peer": true, "dependencies": { "ms": "2.0.0" } }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/send/node_modules/ms": { "version": "2.1.3", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/serialize-error": { "version": "7.0.1", @@ -26917,18 +26961,76 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "license": "MIT", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/serve-static/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-static/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static/node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "license": "ISC" @@ -27041,12 +27143,17 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "license": "MIT", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -28844,8 +28951,9 @@ }, "node_modules/type-is": { "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, - "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" From 88fe6b50cec0cc95e4e1d33a723d1e3360e2fa83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:21:10 +0000 Subject: [PATCH 09/25] build(deps): bump path-to-regexp and express Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `path-to-regexp` from 1.8.0 to 1.9.0 - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v1.8.0...v1.9.0) Updates `express` from 4.19.2 to 4.21.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 065713c05..3a8e1e8b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24502,9 +24502,10 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "1.8.0", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", "dev": true, - "license": "MIT", "dependencies": { "isarray": "0.0.1" } From b9aa8afd398be89eee3455dcb76620b92f6d1dc3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:24:45 +0000 Subject: [PATCH 10/25] build(deps): bump micromatch from 4.0.5 to 4.0.8 Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8. - [Release notes](https://github.com/micromatch/micromatch/releases) - [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/micromatch/compare/4.0.5...4.0.8) --- updated-dependencies: - dependency-name: micromatch dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a8e1e8b7..06c825eec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23188,10 +23188,11 @@ "license": "MIT" }, "node_modules/micromatch": { - "version": "4.0.5", - "license": "MIT", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { From 06e58f09823f9b3166dbfa3b53b0c3988d64e43b Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Thu, 26 Sep 2024 17:13:01 -0300 Subject: [PATCH 11/25] Change displayed amount for flyover pegouts --- src/common/views/SuccessTx.vue | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/common/views/SuccessTx.vue b/src/common/views/SuccessTx.vue index d4005dfcd..21878fc1c 100644 --- a/src/common/views/SuccessTx.vue +++ b/src/common/views/SuccessTx.vue @@ -51,7 +51,9 @@ import { defineComponent, computed, PropType } from 'vue'; import { useAction, useGetter, useState } from '@/common/store/helper'; import * as constants from '@/common/store/constants'; import { useRouter } from 'vue-router'; -import { PegInTxState, SatoshiBig, TxStatusType } from '@/common/types'; +import { + PegInTxState, PegOutTxState, SatoshiBig, TxStatusType, +} from '@/common/types'; import EnvironmentContextProviderService from '@/common/providers/EnvironmentContextProvider'; export default defineComponent({ @@ -70,12 +72,23 @@ export default defineComponent({ const clearStatus = useAction('status', constants.STATUS_CLEAR); const router = useRouter(); const pegInTxState = useState('pegInTx'); + const pegOutTxState = useState('pegOutTx'); const environmentContext = EnvironmentContextProviderService.getEnvironmentContext(); const estimatedBtcToReceive = useGetter('pegOutTx', constants.PEGOUT_TX_GET_ESTIMATED_BTC_TO_RECEIVE); - const amount = computed(() => (props.type === (TxStatusType.PEGIN).toLowerCase() - ? pegInTxState.value.amountToTransfer.toBTCTrimmedString() - : estimatedBtcToReceive.value.toBTCTrimmedString())); + const amount = computed(() => { + switch (props.type.toUpperCase()) { + case TxStatusType.PEGIN || TxStatusType.FLYOVER_PEGIN: + return pegInTxState.value.amountToTransfer.toBTCTrimmedString(); + case TxStatusType.PEGOUT: + return estimatedBtcToReceive.value.toBTCTrimmedString(); + case TxStatusType.FLYOVER_PEGOUT: + return pegOutTxState.value.amountToTransfer.toRBTCTrimmedString(); + default: + return ''; + } + }); + const symbol = computed(() => (props.type === (TxStatusType.PEGIN).toLowerCase() ? environmentContext.getRbtcTicker() : environmentContext.getBtcTicker())); From 308fd98021d5c820c8d4e8f25cad3f9bc1d37118 Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Thu, 26 Sep 2024 17:13:39 -0300 Subject: [PATCH 12/25] Remove old confirmation page --- src/pegout/components/Confirmation.vue | 135 ------------------------ src/pegout/components/FlyoverPegout.vue | 4 +- src/pegout/views/PegOut.vue | 2 - 3 files changed, 1 insertion(+), 140 deletions(-) delete mode 100644 src/pegout/components/Confirmation.vue diff --git a/src/pegout/components/Confirmation.vue b/src/pegout/components/Confirmation.vue deleted file mode 100644 index d83a33e77..000000000 --- a/src/pegout/components/Confirmation.vue +++ /dev/null @@ -1,135 +0,0 @@ - - - diff --git a/src/pegout/components/FlyoverPegout.vue b/src/pegout/components/FlyoverPegout.vue index 6bcf00ebb..55ae624d4 100644 --- a/src/pegout/components/FlyoverPegout.vue +++ b/src/pegout/components/FlyoverPegout.vue @@ -136,8 +136,7 @@ export default defineComponent({ required: true, }, }, - setup(props, context) { - const nextPage = 'Confirmation'; + setup(props) { const showTxErrorDialog = ref(false); const txError = ref(new ServiceError('', '', '', '')); const environmentContext = EnvironmentContextProviderService.getEnvironmentContext(); @@ -264,7 +263,6 @@ export default defineComponent({ : pegOutTxState.value.txHash, }, }); - context.emit('changePage', nextPage); } function getLPName(): string { diff --git a/src/pegout/views/PegOut.vue b/src/pegout/views/PegOut.vue index bcd5ad695..619a87980 100644 --- a/src/pegout/views/PegOut.vue +++ b/src/pegout/views/PegOut.vue @@ -15,13 +15,11 @@ import FlyoverPegout from '@/pegout/components/FlyoverPegout.vue'; import { Machine } from '@/common/utils'; import { useAction, useGetter } from '@/common/store/helper'; import { Feature, FeatureNames } from '@/common/types'; -import Confirmation from '../components/Confirmation.vue'; export default defineComponent({ name: 'PegOut', components: { PegOutForm, - Confirmation, FlyoverPegout, }, setup() { From 9ffeb7ee5fcef91e1bc959bb538a3dcc00725c08 Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Mon, 30 Sep 2024 14:31:12 -0300 Subject: [PATCH 13/25] Show btc tx id of successful pegout --- src/common/components/status/TxPegout.vue | 2 ++ src/common/types/Common.ts | 1 + src/common/types/store.ts | 1 + 3 files changed, 4 insertions(+) diff --git a/src/common/components/status/TxPegout.vue b/src/common/components/status/TxPegout.vue index 70641a628..0266fc2a9 100644 --- a/src/common/components/status/TxPegout.vue +++ b/src/common/components/status/TxPegout.vue @@ -61,6 +61,7 @@ export default defineComponent({ const status = txDetails.value as PegoutStatusDataModel; const valueRequested = new SatoshiBig(status.valueRequestedInSatoshis, 'satoshi').toBTCTrimmedString(); const amountSent = new WeiBig(valueRequested, 'rbtc').plus(calculatedGasFee.value).toRBTCTrimmedString(); + const btcTxId = status.status === PegoutStatus.RELEASE_BTC ? status.btcTxId : ''; return { amountFromString: amountSent, amountReceivedString: amountToBeReceived.value, @@ -71,6 +72,7 @@ export default defineComponent({ txId: status.rskTxHash ? status.rskTxHash : props.txId, estimatedFee: Number(pegOutEstimatedFee.value.toBTCTrimmedString()), status: status.status, + btcTxId, }; }); diff --git a/src/common/types/Common.ts b/src/common/types/Common.ts index 182b7871d..a7a7613f6 100644 --- a/src/common/types/Common.ts +++ b/src/common/types/Common.ts @@ -126,6 +126,7 @@ export interface NormalizedSummary { federationAddress?: string; total?: string; status?: PegStatus | PegoutStatus; + btcTxId?: string; } export type AddressType = 'BITCOIN_LEGACY_ADDRESS' | 'BITCOIN_SEGWIT_ADDRESS' | 'BITCOIN_NATIVE_SEGWIT_ADDRESS' | diff --git a/src/common/types/store.ts b/src/common/types/store.ts index b67a43e60..fea932829 100644 --- a/src/common/types/store.ts +++ b/src/common/types/store.ts @@ -66,6 +66,7 @@ export interface PegoutStatusDataModel { btcRawTransaction: string; fees: number; estimatedFee: SatoshiBig; + btcTxId: string; } export interface FlyoverStatusModel { From f10a8942eca11392f2a935155bb030912e3e8f62 Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Mon, 30 Sep 2024 16:51:46 -0300 Subject: [PATCH 14/25] Change success text and btc fee estimation on status page --- src/common/utils/utils.ts | 7 ++++++- src/common/views/SuccessTx.vue | 21 ++++++--------------- src/status/store/actions.ts | 2 +- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/common/utils/utils.ts b/src/common/utils/utils.ts index cccd51d6c..5bfb79333 100644 --- a/src/common/utils/utils.ts +++ b/src/common/utils/utils.ts @@ -73,7 +73,7 @@ export function getRskAddressExplorerUrl(address: string) { return `${getRskBaseExplorerUrl()}/address/${address}`; } -export function getEstimatedFee(): Promise { +export function getEstimatedFee(pegoutAlreadyRequested = false): Promise { return new Promise((resolve, reject) => { const bridgeService = new BridgeService(); Promise.all([ @@ -81,6 +81,11 @@ export function getEstimatedFee(): Promise { bridgeService.getQueuedPegoutsCount(), ]) .then(([nextPegoutCost, pegoutQueueCount]) => { + if (pegoutAlreadyRequested && pegoutQueueCount !== 0n) { + const currentEstimatedFee = nextPegoutCost / pegoutQueueCount; + resolve(new SatoshiBig(currentEstimatedFee, 'satoshi')); + return; + } const estimatedFee = nextPegoutCost / (pegoutQueueCount + 1n); resolve(new SatoshiBig(estimatedFee, 'satoshi')); }) diff --git a/src/common/views/SuccessTx.vue b/src/common/views/SuccessTx.vue index 21878fc1c..c561394a5 100644 --- a/src/common/views/SuccessTx.vue +++ b/src/common/views/SuccessTx.vue @@ -10,11 +10,7 @@
- - You will receive {{ amount }} {{ symbol }} on your address -
-
- + {{ willReceiveText }}
@@ -76,23 +72,19 @@ export default defineComponent({ const environmentContext = EnvironmentContextProviderService.getEnvironmentContext(); const estimatedBtcToReceive = useGetter('pegOutTx', constants.PEGOUT_TX_GET_ESTIMATED_BTC_TO_RECEIVE); - const amount = computed(() => { + const willReceiveText = computed(() => { switch (props.type.toUpperCase()) { case TxStatusType.PEGIN || TxStatusType.FLYOVER_PEGIN: - return pegInTxState.value.amountToTransfer.toBTCTrimmedString(); + return `You will receive ${pegInTxState.value.amountToTransfer.toBTCTrimmedString()} ${environmentContext.getRbtcTicker()}`; case TxStatusType.PEGOUT: - return estimatedBtcToReceive.value.toBTCTrimmedString(); + return `You will receive approximately ${estimatedBtcToReceive.value.toBTCTrimmedString()} ${environmentContext.getBtcTicker()}`; case TxStatusType.FLYOVER_PEGOUT: - return pegOutTxState.value.amountToTransfer.toRBTCTrimmedString(); + return `You will receive ${pegOutTxState.value.amountToTransfer.toRBTCTrimmedString()} ${environmentContext.getBtcTicker()}`; default: return ''; } }); - const symbol = computed(() => (props.type === (TxStatusType.PEGIN).toLowerCase() - ? environmentContext.getRbtcTicker() - : environmentContext.getBtcTicker())); - function goHome() { clearStatus(); router.push({ name: 'Home' }); @@ -108,8 +100,7 @@ export default defineComponent({ return { mdiContentCopy, - amount, - symbol, + willReceiveText, pegInTxState, copyToClipboard, goHome, diff --git a/src/status/store/actions.ts b/src/status/store/actions.ts index e40aff762..e1c29b925 100644 --- a/src/status/store/actions.ts +++ b/src/status/store/actions.ts @@ -32,7 +32,7 @@ export const actions: ActionTree = { }, [constants.STATUS_GET_ESTIMATED_FEE]: async ({ commit }) => { try { - const estimatedFee = await getEstimatedFee(); + const estimatedFee = await getEstimatedFee(true); commit(constants.STATUS_SET_BTC_ESTIMATED_FEE, new SatoshiBig(estimatedFee, 'satoshi')); } catch (e) { commit(constants.STATUS_SET_BTC_ESTIMATED_FEE, new SatoshiBig(0, 'satoshi')); From 6aecf2c01befd48c8781fcddbbbe1131a1718578 Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Thu, 19 Sep 2024 16:51:54 -0300 Subject: [PATCH 15/25] Get flyover tx status based on quote hash --- .../components/status/PegoutProgressBar.vue | 166 ------------------ .../components/status/StatusProgressBar.vue | 87 +++++++-- src/common/store/constants.ts | 5 +- src/common/types/store.ts | 10 +- src/common/utils/utils.ts | 4 +- src/status/store/actions.ts | 67 +++++-- src/status/store/mutations.ts | 3 + src/status/views/Status.vue | 12 +- 8 files changed, 157 insertions(+), 197 deletions(-) delete mode 100644 src/common/components/status/PegoutProgressBar.vue diff --git a/src/common/components/status/PegoutProgressBar.vue b/src/common/components/status/PegoutProgressBar.vue deleted file mode 100644 index c5f3fc216..000000000 --- a/src/common/components/status/PegoutProgressBar.vue +++ /dev/null @@ -1,166 +0,0 @@ - - - diff --git a/src/common/components/status/StatusProgressBar.vue b/src/common/components/status/StatusProgressBar.vue index 623c2b798..92f39193c 100644 --- a/src/common/components/status/StatusProgressBar.vue +++ b/src/common/components/status/StatusProgressBar.vue @@ -6,10 +6,9 @@
+ :id="`indicator-${timeLineData[0][1]}${txFailed?'-error':''}`">
- @@ -37,7 +35,6 @@

{{ timeLineData[0][0] }}

-

{{ timeLineData[4][0] }}

@@ -73,6 +69,7 @@ import { TxStatusType, } from '@/common/types'; import { PegStatus, FlyoverStatus } from '@/common/store/constants'; +import EnvironmentContextProviderService from '@/common/providers/EnvironmentContextProvider'; export default defineComponent({ name: 'StatusProgressBar', @@ -83,6 +80,11 @@ export default defineComponent({ }, setup(props) { const status = useState('status'); + const environmentContext = EnvironmentContextProviderService.getEnvironmentContext(); + const btcTicker = environmentContext.getBtcTicker(); + const rbtcTicker = environmentContext.getRbtcTicker(); + const txFailed = computed(() => props.txWithError + || status.value.flyoverStatus === FlyoverStatus.FAILED); const txDetails = useStateAttribute('status', 'txDetails'); const isPegOut = computed((): boolean => status.value.type === TxStatusType.PEGOUT || status.value.type === TxStatusType.FLYOVER_PEGOUT); @@ -99,8 +101,8 @@ export default defineComponent({ } return require('@/assets/status/rbtc.svg'); }); - const initialImgSize = computed(() => (props.txWithError ? 32 : 12)); - const barColor = computed(() => (props.txWithError ? 'red' : 'green')); + const initialImgSize = computed(() => (txFailed.value ? 32 : 12)); + const barColor = computed(() => (txFailed.value ? 'red' : 'green')); const timeLineData = computed(() => { let labelOne = 'Transaction Broadcasted'; let labelTwo = 'Transaction Confirmed'; @@ -116,7 +118,38 @@ export default defineComponent({ } else if (isPegOut.value) { labelThree = 'Sent to Bitcoin'; if (props.isFlyover) { - zero = txDetails.value.status === FlyoverStatus.COMPLETED ? 100 : 50; + labelOne = `Send ${rbtcTicker} to Liquidity Provider`; + labelTwo = `Liquidity Provider received ${rbtcTicker}`; + labelThree = `Liquidity Provider send ${btcTicker}`; + switch (status.value.flyoverStatus) { + case FlyoverStatus.PENDING: + zero = 100; + first = 100; + second = 70; + break; + case FlyoverStatus.SUCCESS: + zero = 100; + first = 100; + second = 100; + third = 100; + break; + case FlyoverStatus.FAILED: + zero = 100; + labelOne = 'Error occurred'; + labelTwo = ''; + labelThree = ''; + break; + default: + zero = 0; + first = 0; + second = 0; + third = 0; + fourth = 0; + labelOne = ''; + labelTwo = ''; + labelThree = ''; + break; + } } else { switch (txDetails.value.status as PegoutStatus) { case PegoutStatus.PENDING: @@ -166,7 +199,38 @@ export default defineComponent({ } } } else if (props.isFlyover) { - zero = txDetails.value.status === FlyoverStatus.COMPLETED ? 100 : 50; + labelOne = `Send ${btcTicker} to Liquidity Provider`; + labelTwo = `Liquidity Provider received ${btcTicker}`; + labelThree = `Liquidity Provider send ${rbtcTicker}`; + switch (status.value.flyoverStatus) { + case FlyoverStatus.PENDING: + zero = 100; + first = 100; + second = 70; + break; + case FlyoverStatus.SUCCESS: + zero = 100; + first = 100; + second = 100; + third = 100; + break; + case FlyoverStatus.FAILED: + zero = 100; + labelOne = 'Error occurred'; + labelTwo = ''; + labelThree = ''; + break; + default: + zero = 0; + first = 0; + second = 0; + third = 0; + fourth = 0; + labelOne = ''; + labelTwo = ''; + labelThree = ''; + break; + } } else { const txDetailsPegIn = txDetails.value as PeginStatus; const btc = txDetailsPegIn.btc as BtcPeginStatus; @@ -240,7 +304,7 @@ export default defineComponent({ }; }); const imgStep1 = computed(() => { - if (props.txWithError) return require('@/assets/status/ellipse_error.svg'); + if (txFailed.value) return require('@/assets/status/ellipse_error.svg'); if (timeLineData.value[0][1] === 100) return require('@/assets/status/ellipse.svg'); return require('@/assets/status/ellipse_empty.svg'); }); @@ -266,6 +330,7 @@ export default defineComponent({ imgStep3, initialImgSize, barColor, + txFailed, }; }, }); diff --git a/src/common/store/constants.ts b/src/common/store/constants.ts index 2b02be99d..c4b4ec06d 100644 --- a/src/common/store/constants.ts +++ b/src/common/store/constants.ts @@ -262,6 +262,7 @@ export const STATUS_CLEAR = 'STATUS_CLEAR'; export const PEGOUT_TX_ADD_BITCOIN_PRICE = 'PEGOUT_TX_ADD_BITCOIN_PRICE'; export const STATUS_GET_ESTIMATED_FEE = 'STATUS_GET_ESTIMATED_FEE'; export const STATUS_GET_ESTIMATED_RELEASE_TIME_IN_MINUTES = 'STATUS_GET_ESTIMATED_RELEASE_TIME_IN_MINUTES'; +export const STATUS_GET_FLYOVER_STATUS = 'STATUS_GET_FLYOVER_STATUS'; // Status mutations export const STATUS_SET_TX_DETAILS = 'STATUS_SET_TX_DETAILS'; @@ -269,6 +270,7 @@ export const STATUS_SET_TX_TYPE = 'STATUS_SET_TX_TYPE'; export const STATUS_SET_CLEAR = 'STATUS_SET_CLEAR'; export const STATUS_SET_BTC_ESTIMATED_FEE = 'STATUS_SET_BTC_ESTIMATED_FEE'; export const STATUS_SET_ESTIMATED_RELEASE_TIME_IN_MINUTES = 'STATUS_SET_ESTIMATED_RELEASE_TIME_IN_MINUTES'; +export const STATUS_SET_FLYOVER_STATUS = 'STATUS_SET_FLYOVER_STATUS'; // Status getters export const STATUS_IS_REJECTED = 'STATUS_IS_REJECTED'; @@ -291,7 +293,8 @@ export enum PegStatus { export enum FlyoverStatus { PENDING = 'PENDING', - COMPLETED = 'COMPLETED', + SUCCESS = 'SUCCESS', + FAILED = 'FAILED', } export const LEDGER_STATUS_CODES = { diff --git a/src/common/types/store.ts b/src/common/types/store.ts index fea932829..345f1b6c6 100644 --- a/src/common/types/store.ts +++ b/src/common/types/store.ts @@ -3,13 +3,19 @@ import { PegStatus } from '@/common/store/constants'; import SatoshiBig from '@/common/types/SatoshiBig'; import { PegInTxState } from '@/common/types/pegInTx'; import { SessionState } from '@/common/types/session'; -import { PegOutTxState } from './pegOutTx'; +import { PegOutTxState } from '@/common/types/pegOutTx'; +import { FlyoverPeginState } from '@/common/types/FlyoverPegin'; +import { FlyoverPegoutState } from '@/common/types/FlyoverPegout'; +import { StatusState } from '@/common/types/Status'; export interface RootState { pegInTx?: PegInTxState, web3Session?: SessionState, pegOutTx?: PegOutTxState, version: string; + status?: StatusState; + flyoverPegin?: FlyoverPeginState; + flyoverPegout?: FlyoverPegoutState; } export interface BtcPeginStatus { @@ -79,6 +85,7 @@ export interface FlyoverStatusModel { status: string; senderAddress: string; recipientAddress: string; + quoteHash: string; } export enum TxStatusType { @@ -96,4 +103,5 @@ export interface TxStatus { type: TxStatusType; pegOutEstimatedFee: SatoshiBig; estimatedReleaseTimeInMinutes: Duration; + flyoverStatus?: string; } diff --git a/src/common/utils/utils.ts b/src/common/utils/utils.ts index 5bfb79333..0de917604 100644 --- a/src/common/utils/utils.ts +++ b/src/common/utils/utils.ts @@ -199,7 +199,7 @@ export function setStatusMessage(txType: string, status: string): TxStatusMessag activeMessageStyle = 'statusProgress'; isRejected = false; break; - case constants.FlyoverStatus.COMPLETED: + case constants.FlyoverStatus.SUCCESS: statusMessage = 'Your transaction was successfully processed!'; activeMessageStyle = 'statusSuccess'; isRejected = false; @@ -214,7 +214,7 @@ export function setStatusMessage(txType: string, status: string): TxStatusMessag activeMessageStyle = 'statusProgress'; isRejected = false; break; - case constants.FlyoverStatus.COMPLETED: + case constants.FlyoverStatus.SUCCESS: statusMessage = 'Your transaction was successfully processed!'; activeMessageStyle = 'statusSuccess'; isRejected = false; diff --git a/src/status/store/actions.ts b/src/status/store/actions.ts index e1c29b925..b124a9f5c 100644 --- a/src/status/store/actions.ts +++ b/src/status/store/actions.ts @@ -2,6 +2,7 @@ import { ActionTree } from 'vuex'; import Web3 from 'web3'; import moment from 'moment'; import { + FlyoverStatusModel, PegoutStatusDataModel, RootState, SatoshiBig, TxStatus, TxStatusType, } from '@/common/types'; @@ -15,21 +16,33 @@ export const actions: ActionTree = { [constants.STATUS_CLEAR]: ({ commit }) => { commit(constants.STATUS_SET_CLEAR); }, - [constants.STATUS_GET_TX_STATUS]: ({ commit, dispatch }, txId: string) => { - Promise.all([ - ApiService.getTxStatus(txId), - dispatch(constants.STATUS_GET_ESTIMATED_FEE), - ]) - .then(([status]) => { - commit(constants.STATUS_SET_TX_DETAILS, status.txDetails); - commit(constants.STATUS_SET_TX_TYPE, status.type); - return dispatch(constants.STATUS_GET_ESTIMATED_RELEASE_TIME_IN_MINUTES); - }) - .catch(() => { - commit(constants.STATUS_SET_TX_DETAILS, undefined); - commit(constants.STATUS_SET_TX_TYPE, TxStatusType.UNEXPECTED_ERROR); - }); - }, + [constants.STATUS_GET_TX_STATUS]: + ({ commit, dispatch }, txId: string) => new Promise((resolve, reject) => { + Promise.all([ + ApiService.getTxStatus(txId), + dispatch(constants.STATUS_GET_ESTIMATED_FEE), + ]) + .then(([status]) => { + commit(constants.STATUS_SET_TX_DETAILS, status.txDetails); + commit(constants.STATUS_SET_TX_TYPE, status.type); + const nextActions = []; + if (status.type === TxStatusType.FLYOVER_PEGIN + || status.type === TxStatusType.FLYOVER_PEGOUT) { + nextActions.push(dispatch( + constants.STATUS_GET_FLYOVER_STATUS, + (status.txDetails as FlyoverStatusModel).quoteHash, + )); + } + nextActions.push(dispatch(constants.STATUS_GET_ESTIMATED_RELEASE_TIME_IN_MINUTES)); + return Promise.all(nextActions); + }) + .then(resolve) + .catch(() => { + commit(constants.STATUS_SET_TX_DETAILS, undefined); + commit(constants.STATUS_SET_TX_TYPE, TxStatusType.UNEXPECTED_ERROR); + reject(); + }); + }), [constants.STATUS_GET_ESTIMATED_FEE]: async ({ commit }) => { try { const estimatedFee = await getEstimatedFee(true); @@ -64,4 +77,28 @@ export const actions: ActionTree = { } resolve(); }), + [constants.STATUS_GET_FLYOVER_STATUS]: async ({ + state, commit, dispatch, rootState, + }, quoteHash) => { + let status; + try { + if (state.type === TxStatusType.FLYOVER_PEGIN) { + const flyoverService = rootState.flyoverPegin?.flyoverService; + await dispatch(`flyoverPegin/${constants.FLYOVER_PEGIN_INIT}`, null, { root: true }); + flyoverService?.useLiquidityProvider(1); + status = await flyoverService?.getPeginStatus(quoteHash); + } + if (state.type === TxStatusType.FLYOVER_PEGOUT) { + const flyoverService = rootState.flyoverPegout?.flyoverService; + await dispatch(`flyoverPegout/${constants.FLYOVER_PEGOUT_INIT}`, null, { root: true }); + await dispatch(`flyoverPegout/${constants.FLYOVER_PEGOUT_GET_PROVIDERS}`, null, { root: true }); + flyoverService?.useLiquidityProvider(1); + status = await rootState.flyoverPegout?.flyoverService.getPegoutStatus(quoteHash); + } + } catch (e) { + status = 'NOT_FOUND'; + } finally { + commit(constants.STATUS_SET_FLYOVER_STATUS, status); + } + }, }; diff --git a/src/status/store/mutations.ts b/src/status/store/mutations.ts index 433bc1a9d..bf58e2859 100644 --- a/src/status/store/mutations.ts +++ b/src/status/store/mutations.ts @@ -26,4 +26,7 @@ export const mutations: MutationTree = { (state: TxStatus, releaseTime: Duration) => { state.estimatedReleaseTimeInMinutes = releaseTime; }, + [constants.STATUS_SET_FLYOVER_STATUS]: (state, status) => { + state.flyoverStatus = status; + }, }; diff --git a/src/status/views/Status.vue b/src/status/views/Status.vue index 531e7875a..1edf6c62a 100644 --- a/src/status/views/Status.vue +++ b/src/status/views/Status.vue @@ -18,7 +18,7 @@ Estimated time: {{ releaseTimeText }} - + + + + Searching... + + From 58783e3b01e372ff12a0db568843b092c8bff5ce Mon Sep 17 00:00:00 2001 From: ronaldsg Date: Mon, 12 Aug 2024 15:24:41 -0500 Subject: [PATCH 16/25] Set base of pwa for 2wp-app --- package-lock.json | 871 +++++++++++++++++- package.json | 2 + public/img/icons/android-chrome-192x192.png | Bin 0 -> 9416 bytes public/img/icons/android-chrome-512x512.png | Bin 0 -> 29808 bytes .../icons/android-chrome-maskable-192x192.png | Bin 0 -> 6401 bytes .../icons/android-chrome-maskable-512x512.png | Bin 0 -> 23038 bytes public/img/icons/apple-touch-icon-120x120.png | Bin 0 -> 3369 bytes public/img/icons/apple-touch-icon-152x152.png | Bin 0 -> 4046 bytes public/img/icons/apple-touch-icon-180x180.png | Bin 0 -> 4678 bytes public/img/icons/apple-touch-icon-60x60.png | Bin 0 -> 1491 bytes public/img/icons/apple-touch-icon-76x76.png | Bin 0 -> 1823 bytes public/img/icons/apple-touch-icon.png | Bin 0 -> 4678 bytes public/img/icons/favicon-16x16.png | Bin 0 -> 799 bytes public/img/icons/favicon-32x32.png | Bin 0 -> 1271 bytes .../img/icons/msapplication-icon-144x144.png | Bin 0 -> 1169 bytes public/img/icons/mstile-150x150.png | Bin 0 -> 4282 bytes public/img/icons/safari-pinned-tab.svg | 3 + public/robots.txt | 2 + src/registerServiceWorker.ts | 32 + src/vuex.d.ts | 0 20 files changed, 906 insertions(+), 4 deletions(-) create mode 100644 public/img/icons/android-chrome-192x192.png create mode 100644 public/img/icons/android-chrome-512x512.png create mode 100644 public/img/icons/android-chrome-maskable-192x192.png create mode 100644 public/img/icons/android-chrome-maskable-512x512.png create mode 100644 public/img/icons/apple-touch-icon-120x120.png create mode 100644 public/img/icons/apple-touch-icon-152x152.png create mode 100644 public/img/icons/apple-touch-icon-180x180.png create mode 100644 public/img/icons/apple-touch-icon-60x60.png create mode 100644 public/img/icons/apple-touch-icon-76x76.png create mode 100644 public/img/icons/apple-touch-icon.png create mode 100644 public/img/icons/favicon-16x16.png create mode 100644 public/img/icons/favicon-32x32.png create mode 100644 public/img/icons/msapplication-icon-144x144.png create mode 100644 public/img/icons/mstile-150x150.png create mode 100644 public/img/icons/safari-pinned-tab.svg create mode 100644 public/robots.txt create mode 100644 src/registerServiceWorker.ts delete mode 100644 src/vuex.d.ts diff --git a/package-lock.json b/package-lock.json index 06c825eec..3de0e261c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "os-browserify": "^0.3.0", "process": "^0.11.10", "sats-connect": "2.3.x", + "register-service-worker": "^1.7.2", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "text-encoding": "^0.7.0", @@ -76,6 +77,7 @@ "@typescript-eslint/parser": "^5.62.0", "@vue/cli-plugin-babel": "~5.0.0", "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-plugin-pwa": "^5.0.8", "@vue/cli-plugin-router": "~5.0.0", "@vue/cli-plugin-typescript": "~5.0.0", "@vue/cli-plugin-unit-jest": "~5.0.0", @@ -6820,6 +6822,100 @@ "node": ">=10" } }, + "node_modules/@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/plugin-replace/node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, "node_modules/@rsksmart/bridges-core-sdk": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@rsksmart/bridges-core-sdk/-/bridges-core-sdk-0.3.3.tgz", @@ -7565,6 +7661,27 @@ "npm": ">=6.0.0" } }, + "node_modules/@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "dev": true, + "dependencies": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "node_modules/@surma/rollup-plugin-off-main-thread/node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, "node_modules/@swan-bitcoin/xpub-lib": { "version": "0.1.5", "license": "MIT", @@ -8378,6 +8495,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/responselike": { "version": "1.0.0", "dev": true, @@ -8482,6 +8608,12 @@ "version": "7.0.0", "license": "MIT" }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true + }, "node_modules/@types/w3c-web-usb": { "version": "1.0.6", "license": "MIT" @@ -9121,6 +9253,21 @@ "eslint": ">=7.5.0" } }, + "node_modules/@vue/cli-plugin-pwa": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-pwa/-/cli-plugin-pwa-5.0.8.tgz", + "integrity": "sha512-MnD9Y6I3nX7c/NawpsJtbXaGFjI9LT5Az7IQjpshS65+yvuOcxV2j/tCjPTrja+zd1VmB4DZUhrfUU2exSBfGg==", + "dev": true, + "dependencies": { + "@vue/cli-shared-utils": "^5.0.8", + "html-webpack-plugin": "^5.1.0", + "webpack": "^5.54.0", + "workbox-webpack-plugin": "^6.1.0" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, "node_modules/@vue/cli-plugin-router": { "version": "5.0.8", "dev": true, @@ -11818,6 +11965,18 @@ "node": ">=8.0.0" } }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/builtin-status-codes": { "version": "3.0.0", "license": "MIT" @@ -12509,6 +12668,15 @@ "node": ">= 12" } }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/commondir": { "version": "1.0.1", "license": "MIT" @@ -12931,7 +13099,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "peer": true, "engines": { "node": ">=8" } @@ -14172,6 +14339,21 @@ "node": ">=10.0.0" } }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/electron": { "version": "24.8.8", "resolved": "https://registry.npmjs.org/electron/-/electron-24.8.8.tgz", @@ -16952,6 +17134,12 @@ "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==" }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "dev": true + }, "node_modules/fastq": { "version": "1.15.0", "license": "ISC", @@ -17140,6 +17328,36 @@ "version": "1.0.0", "license": "MIT" }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -17787,6 +18005,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true + }, "node_modules/get-package-type": { "version": "0.1.0", "dev": true, @@ -18569,6 +18793,12 @@ "postcss": "^8.1.0" } }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true + }, "node_modules/ieee754": { "version": "1.2.1", "funding": [ @@ -19060,6 +19290,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "node_modules/is-nan": { "version": "1.3.2", "license": "MIT", @@ -19111,6 +19347,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -19168,6 +19413,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-shared-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", @@ -19453,6 +19707,100 @@ "node": ">=8" } }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/javascript-stringify": { "version": "2.1.0", "dev": true, @@ -22036,6 +22384,15 @@ "node >= 0.2.0" ] }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jsonschema": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.2.2.tgz", @@ -22603,6 +22960,12 @@ "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true + }, "node_modules/lodash.truncate": { "version": "4.4.2", "dev": true, @@ -25274,7 +25637,6 @@ "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "peer": true, "engines": { "node": ">=6" }, @@ -26028,6 +26390,11 @@ "node": ">=4" } }, + "node_modules/register-service-worker": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/register-service-worker/-/register-service-worker-1.7.2.tgz", + "integrity": "sha512-CiD3ZSanZqcMPRhtfct5K9f7i3OLCcBBWsJjLh1gW9RO/nS94sVzY59iS+fgYBOBqaBpf4EzfqUF3j9IG+xo8A==" + }, "node_modules/regjsparser": { "version": "0.9.1", "license": "BSD-2-Clause", @@ -26412,6 +26779,81 @@ "license": "BSD-3-Clause", "optional": true }, + "node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup-plugin-terser/node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/rpc-websockets": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.11.0.tgz", @@ -27391,6 +27833,12 @@ "node": ">=10" } }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, "node_modules/source-map": { "version": "0.6.1", "license": "BSD-3-Clause", @@ -27414,6 +27862,13 @@ "source-map": "^0.6.0" } }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true + }, "node_modules/spdx-correct": { "version": "3.2.0", "dev": true, @@ -27666,6 +28121,32 @@ "version": "8.0.0", "license": "MIT" }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", @@ -27712,6 +28193,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "license": "MIT", @@ -27730,6 +28225,15 @@ "node": ">=8" } }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/strip-dirs": { "version": "2.1.0", "dev": true, @@ -28214,7 +28718,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "peer": true, "engines": { "node": ">=8" } @@ -29291,7 +29794,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "peer": true, "dependencies": { "crypto-random-string": "^2.0.0" }, @@ -32212,6 +32714,367 @@ "integrity": "sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==", "peer": true }, + "node_modules/workbox-background-sync": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", + "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", + "dev": true, + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", + "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-build": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", + "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", + "dev": true, + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.11.1", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-replace": "^2.4.1", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "rollup-plugin-terser": "^7.0.0", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "6.6.0", + "workbox-broadcast-update": "6.6.0", + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-google-analytics": "6.6.0", + "workbox-navigation-preload": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-range-requests": "6.6.0", + "workbox-recipes": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0", + "workbox-streams": "6.6.0", + "workbox-sw": "6.6.0", + "workbox-window": "6.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/workbox-build/node_modules/@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "dev": true, + "dependencies": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/workbox-build/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/workbox-build/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/workbox-build/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/workbox-build/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dev": true, + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workbox-build/node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dev": true, + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/workbox-build/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/workbox-build/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/workbox-build/node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/workbox-build/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "node_modules/workbox-build/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", + "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", + "deprecated": "workbox-background-sync@6.6.0", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", + "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==", + "dev": true + }, + "node_modules/workbox-expiration": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", + "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", + "dev": true, + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-google-analytics": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", + "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", + "deprecated": "It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained", + "dev": true, + "dependencies": { + "workbox-background-sync": "6.6.0", + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", + "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-precaching": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", + "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-range-requests": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", + "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-recipes": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", + "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", + "dev": true, + "dependencies": { + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-routing": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", + "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-strategies": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", + "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-streams": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", + "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0" + } + }, + "node_modules/workbox-sw": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", + "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==", + "dev": true + }, + "node_modules/workbox-webpack-plugin": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", + "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "^2.1.0", + "pretty-bytes": "^5.4.1", + "upath": "^1.2.0", + "webpack-sources": "^1.4.3", + "workbox-build": "6.6.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "webpack": "^4.4.0 || ^5.9.0" + } + }, + "node_modules/workbox-webpack-plugin/node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/workbox-window": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", + "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", + "dev": true, + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "6.6.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "license": "MIT", diff --git a/package.json b/package.json index dfe1d0f3c..5b00cbb36 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "os-browserify": "^0.3.0", "process": "^0.11.10", "sats-connect": "2.3.x", + "register-service-worker": "^1.7.2", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "text-encoding": "^0.7.0", @@ -81,6 +82,7 @@ "@typescript-eslint/parser": "^5.62.0", "@vue/cli-plugin-babel": "~5.0.0", "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-plugin-pwa": "^5.0.8", "@vue/cli-plugin-router": "~5.0.0", "@vue/cli-plugin-typescript": "~5.0.0", "@vue/cli-plugin-unit-jest": "~5.0.0", diff --git a/public/img/icons/android-chrome-192x192.png b/public/img/icons/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..b02aa64d97167ad649e496908b35f14c603d9249 GIT binary patch literal 9416 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 literal 0 HcmV?d00001 diff --git a/public/img/icons/apple-touch-icon-120x120.png b/public/img/icons/apple-touch-icon-120x120.png new file mode 100644 index 0000000000000000000000000000000000000000..1427cf62752646ad7217df0a61aa01fdef7475d1 GIT binary patch literal 3369 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 ROru=^AazZ3N)e9H{|11FNXq~K literal 0 HcmV?d00001 diff --git a/public/img/icons/apple-touch-icon-152x152.png b/public/img/icons/apple-touch-icon-152x152.png new file mode 100644 index 0000000000000000000000000000000000000000..f24d454a2ecb8851bb893192b64ee09386d30e24 GIT binary patch literal 4046 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 cK^5JQ0?3d{m_4Kdj*!1;003@kYpI!lw*K!+ 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�MrHbYR_buu=L>f*wO=Er8~{qfkYT+HoHag8)VqJoC-#@ zNT})4xRE%sP-B9?xmL5!2Y8VLa?yj@Y@r1C)6o~9GF9nWG!SI2VJ$>ejtUE%Qv&r_ zYLgZ0h3iIrw7{TyurC(g^$XT%PP5`FB3aFpP&fM-8!J#3I_ujG?;7(Xv5ni%BjYP4 z^+oydy=)_&bdxYJx`X%G5PFkUB%3h6RiOs^F?#ojsB%DbfhqzGhuv4)S1%vw@PDyE z3xWF{Y^0>+=Wg! z{>z@$rD6ej*V- z^$zKIOWOfdN4~7@ndhru01+3cxwD&_Muyja({*O;-5VnF(e$WDALNStE{1{F#ts+VR{o zSlQ*@U=Du8fgKW$lU~)O)b6FS?H1SSnKVIC=DOvbo8IUvM zVf+U4YxG%qLGd%ew7Jp8>@U`ew+A#Q=2oJHNH@_f!WadS20$KZEZ+BHAvU@FB zzRCYN5r+Z#g`C^hrH$yW7ABstwjvMM*CHGzY41bbo2zy$6E8DAOPn zUnHG?e7?u7pQ}Kqbu1jEd+=mcGea4aL6V4g(m*b7x}z|ijsjb3e|tf-3&^JK{=sWz z8sqIu9jy)#J}n}cXqtXmkb-NDVPcAKn=G9uX42zYvufu_OCr>xJ=oTNp8WA5wEqvM z{r~m8;7_C>U68iRr@|rd7UYhON#(-S_+Uf>s)hhPU{{exlxc&eD literal 0 HcmV?d00001 diff --git a/public/img/icons/apple-touch-icon-60x60.png b/public/img/icons/apple-touch-icon-60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..cf10a5602e653bb126332934e2b7f34081c19a01 GIT binary patch literal 1491 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

aZW9cb|x>1jZDoAu$NpeWiVk@{x{! zmmBmDgx|qNN?LyIrl9$qmj{KjZ8zpa=4edK3FuFS$KFl}bWPoO*Ax#Z1c2#3JAN(O zYhi>`%H9fSnLkAq|5vs>+?U*bdfMc6TmDu+QqnN9xgfZsG25($^;v7U1nBl9Q^o*i z)&?UaYZ=~7XZa75xPKB1s~MB1m<*dN08pqiy*q!)_Kc|;EZs3&nNdMQ5#LFu+J z?*($vO)$hkMOVc16f-ep;K@_~&Y6t?0t9I0(lBkZBfic|u)3pK$Xv=A@jUQnB2sC` zbI)L9m;VNkWOao}2c3b4_u4+bg zuf-@d1$?asdD1~mORQ02#!&1Xm#41*xz}wETNqKb;kueQ*~OpcAXTpJFYUYcKoA&Z z8Ke=2Vh~cu_uTb&6AH75L!k8zo~&wRsDLs^3YkD2!~;%u6sFrzV2A5(FQ|3}+0-K- zWX)W2yq%?^)iKhyMGPB5*DnWBaLqAHLJ47;r5nvkeq3u_?J{Xaf_}6I+xpLwKS7NC z|KYU%zup)8i85jc)^Yt*I0W8;+zHUI3V7@o;3DUYasdq>DFK%im4J)F?;|B-<=}8R z>HESGa5)KyCnGII|E+YX&h4Y+xCRvyX@oGhhG4 j58+{W$RJv~NLLKlV4)8v^7hU(R-4l(}$teLl` literal 0 HcmV?d00001 diff --git a/public/img/icons/favicon-16x16.png b/public/img/icons/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..42af00963d81b8e39a30435c60ac482d1f8756e0 GIT binary patch literal 799 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>WRE8{w#)hawXn|-Xp4{E;v!=;4B^%-x&;Cm1 zP>^*#n_J!T^1SBMI!C4h-R53dN8`?ylD}d{L%(vZvUKT)~-CgWFQy3lt zIqW5#zOL*K8HL%o&D;R|TePl5?VWhq^wrj^qed%lKKkpp-FogeyEi+p zE?K8rW7E1fuEJ{5jaaAp0~aIt+keS?T)@vXM=*X}V#VGMCm1~v-+0wr{w3CJ-R8wG zS@XVpzqP-5Mf0H?y-zh=XVL>S6E;rKnDmrMQlmoKbK9p$evXN`oe{6g>lvi)-+#c) zb+Al&$zRqtWk1@VTt6MPmq9d7^!kmXZn8k{sFt`!l%ynwlArU1(iRB6fMfqu& zIjIUIl?AB^nFS@u3=9=>9)IHDC=AokIOTu(jOWuJ24-b$y<~1-Wnu5hBFw@HE)6D! wQ<#-EhbWxBaplC3Ge=~Ou%B-5Sm33{@Jd{;RG<|Mp00i_>zopr0DGh}-~a#s literal 0 HcmV?d00001 diff --git a/public/img/icons/favicon-32x32.png b/public/img/icons/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..46ca04dee251a4fa85a2891a145fbe20cc619d96 GIT binary patch literal 1271 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 + + diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 000000000..eb0536286 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/src/registerServiceWorker.ts b/src/registerServiceWorker.ts new file mode 100644 index 000000000..e32aa92b8 --- /dev/null +++ b/src/registerServiceWorker.ts @@ -0,0 +1,32 @@ +/* eslint-disable no-console */ + +import { register } from 'register-service-worker'; + +if (process.env.NODE_ENV === 'production') { + register(`${process.env.BASE_URL}service-worker.js`, { + ready() { + console.log( + 'App is being served from cache by a service worker.\n' + + 'For more details, visit https://goo.gl/AFskqB', + ); + }, + registered() { + console.log('Service worker has been registered.'); + }, + cached() { + console.log('Content has been cached for offline use.'); + }, + updatefound() { + console.log('New content is downloading.'); + }, + updated() { + console.log('New content is available; please refresh.'); + }, + offline() { + console.log('No internet connection found. App is running in offline mode.'); + }, + error(error) { + console.error('Error during service worker registration:', error); + }, + }); +} diff --git a/src/vuex.d.ts b/src/vuex.d.ts deleted file mode 100644 index e69de29bb..000000000 From 9a98ad511bcf13fd3325892be5415c5df9b07c59 Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Tue, 13 Aug 2024 10:55:38 -0300 Subject: [PATCH 17/25] Add pwa config --- public/img/icons/favicon-16x16.png | Bin 799 -> 456 bytes public/img/icons/favicon-32x32.png | Bin 1271 -> 887 bytes public/img/icons/maskable_icon.png | Bin 0 -> 40382 bytes public/img/icons/maskable_icon_x192.png | Bin 0 -> 4026 bytes public/img/icons/maskable_icon_x384.png | Bin 0 -> 9978 bytes public/img/icons/maskable_icon_x512.png | Bin 0 -> 14817 bytes public/index.html | 2 +- vue.config.js | 40 ++++++++++++++++++++++++ 8 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 public/img/icons/maskable_icon.png create mode 100644 public/img/icons/maskable_icon_x192.png create mode 100644 public/img/icons/maskable_icon_x384.png create mode 100644 public/img/icons/maskable_icon_x512.png diff --git a/public/img/icons/favicon-16x16.png b/public/img/icons/favicon-16x16.png index 42af00963d81b8e39a30435c60ac482d1f8756e0..8976969fbd8dfd322892bd81a41ae1ab9f21fb43 100644 GIT binary patch delta 441 zcmV;q0Y?6x2FL@D8Gi-<001BJ|6u?C010qNS#tmY4#WTe4#WYKD-Ig~00DYQL_t(| zoTXB`P6AO79Tk-ojA$^%U}8+96tu#Qt!;$(0n%uxSlQCrsVxnDfN^PTSxdUr77GhW zG``~ld_6oC}ea|)*O_WQX~W+quXUfk~!@s`?O9au7>Kk<9{QkkuL;xrA|Bcqg02y z+`ZRj(Z5qsGru^98tn214Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>WRE8{w#)hawXn|-Xp4{E;v!=;4B^%-x&;Cm1 zP>^*#n_J!T^1SBMI!C4h-R53dN8`?ylD}d{L%(vZvUKT)~-CgWFQy3lt zIqW5#zOL*K8HL%o&D;R|TePl5?VWhq^wrj^qed%lKKkpp-FogeyEi+p zE?K8rW7E1fuEJ{5jaaAp0~aIt+keS?T)@vXM=*X}V#VGMCm1~v-+0wr{w3CJ-R8wG zS@XVpzqP-5Mf0H?y-zh=XVL>S6E;rKnDmrMQlmoKbK9p$evXN`oe{6g>lvi)-+#c) zb+Al&$zRqtWk1@VTt6MPmq9d7^!kmXZn8k{sFt`!l%ynwlArU1(iRB6fMfqu& zIjIUIl?AB^nFS@u3=9=>9)IHDC=AokIOTu(jOWuJ24-b$y<~1-Wnu5hBFw@HE)6D! wQ<#-EhbWxBaplC3Ge=~Ou%B-5Sm33{@Jd{;RG<|Mp00i_>zopr0DGh}-~a#s diff --git a/public/img/icons/favicon-32x32.png b/public/img/icons/favicon-32x32.png index 46ca04dee251a4fa85a2891a145fbe20cc619d96..91726088b3b04010979fea472681c2a9e51419df 100644 GIT binary patch delta 875 zcmV-x1C;#t3HJt&8Gi-<0047(dh`GQ010qNS#tmY4#WTe4#WYKD-Ig~00SvWL_t(| zoYhx7Q&T|{y#m1m(L^$i_|#&jJ7aCQdm01hN0u}3k=w4K?*6=*l0;g z?E;n*;tVNJ^W{gPe0t9&`{w1nU6Pj}!*GivZ+G9lXYW0G?tf;0h>qzDZGg_$&L@EA zxR;(pFH?NNC!VvLbz08-qTJTs-UA2>_0ii$*C^n-V2%L@K#dv&s??5p3m`Ey+!EXb z#$%XEum9{V09Ei#=3E0nswYE(RIMLTerJ!mvB=Fq^85N|qp+tfjS@iO&M-ZDc-7od zerKPOYefMh^MC0NE#CDjoncM}UY!Z@w?{lz>c{l-O_?$uf42t!GOf;x*mmL(#2Z~K z(01{F9=!ZPnb{!kt^u&h0TQo@Vh)z&wYNt4&G)ep_{6;Zq&NU1rYabxWlb>kM<5Vj~a&N`KX~YWzv><5aW-fF0_DC}PnD*)1#F zE%95XR;L5fx7{27(9v|qY>rb{=0He4N`)p9@bwGMK)?_jYjh^N<%s}5GSoE9?O1lZ zuN+Va5!V;0XE)S0Guz;Ulx5UgHYEsDirca3&Zsoa+B&p2@kb%Xh?3&H2{9=Q~ zCjemRmLRD-^C%Ta){S)q0Q|rm@HFgv{x>{L`wz-+f?=1-zUlw~002ovPDHLkV1n61 BmRJA) literal 1271 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

O`DsqoQ6(3?)Gq}snhR1qKc!q` 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 literal 0 HcmV?d00001 diff --git a/public/img/icons/maskable_icon_x192.png b/public/img/icons/maskable_icon_x192.png new file mode 100644 index 0000000000000000000000000000000000000000..363436f48056332558cda8da850c0cce01e016bd GIT binary patch literal 4026 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 TOHDys#sLjgU6op;r(ypCcbaga literal 0 HcmV?d00001 diff --git a/public/img/icons/maskable_icon_x384.png b/public/img/icons/maskable_icon_x384.png new file mode 100644 index 0000000000000000000000000000000000000000..6f31ac7e293adf53875a8140f9e60d368a9dbb4b GIT binary patch literal 9978 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 literal 0 HcmV?d00001 diff --git a/public/img/icons/maskable_icon_x512.png b/public/img/icons/maskable_icon_x512.png new file mode 100644 index 0000000000000000000000000000000000000000..d143c5d82b943ca4efc19216d6ad248a2ca298a5 GIT binary patch literal 14817 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�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 literal 0 HcmV?d00001 diff --git a/public/index.html b/public/index.html index f6e727901..fdbc22b32 100644 --- a/public/index.html +++ b/public/index.html @@ -5,7 +5,7 @@ - <%= htmlWebpackPlugin.options.title %> + 2-Way Peg App diff --git a/vue.config.js b/vue.config.js index aa177edd6..671154dba 100644 --- a/vue.config.js +++ b/vue.config.js @@ -5,6 +5,46 @@ const { defineConfig } = require('@vue/cli-service'); const { VuetifyPlugin } = require('webpack-plugin-vuetify'); module.exports = defineConfig({ + pwa: { + name: '2-Way Peg App', + themeColor: '#FF9800', + iconPaths: { + favicon32: 'img/icons/favicon-32x32.png', + favicon16: 'img/icons/favicon-16x16.png', + }, + manifestOptions: { + id: '2wp-app', + short_name: '2WP App', + description: 'Bridging Bitcoin and Rootstock', + start_url: '/', + icons: [ + { + purpose: 'any maskable', + sizes: '1024x1024', + src: 'img/icons/maskable_icon.png', + type: 'image/png', + }, + { + purpose: 'maskable', + sizes: '192x192', + src: 'img/icons/maskable_icon_x192.png', + type: 'image/png', + }, + { + purpose: 'maskable', + sizes: '384x384', + src: 'img/icons/maskable_icon_x384.png', + type: 'image/png', + }, + { + purpose: 'maskable', + sizes: '512x512', + src: 'img/icons/maskable_icon_x512.png', + type: 'image/png', + }, + ], + }, + }, transpileDependencies: true, configureWebpack: { resolve: { From 97bcbeda253c5d72925c8ef4e808adfc2c4919b7 Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Wed, 14 Aug 2024 17:15:47 -0300 Subject: [PATCH 18/25] Store searches in indexedDB --- package-lock.json | 20 ++++++++++++---- package.json | 1 + src/db.ts | 47 +++++++++++++++++++++++++++++++++++++ src/status/store/actions.ts | 2 ++ 4 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 src/db.ts diff --git a/package-lock.json b/package-lock.json index 3de0e261c..949f879b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "crypto-browserify": "^3.12.0", "ethers": "^5.7.2", "https-browserify": "^1.0.0", + "idb": "^8.0.0", "jest-environment-jsdom": "^27.5.1", "lodash": "^4.17.21", "markdown-it": "^14.1.0", @@ -18794,10 +18795,9 @@ } }, "node_modules/idb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", - "dev": true + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/idb/-/idb-8.0.0.tgz", + "integrity": "sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw==" }, "node_modules/ieee754": { "version": "1.2.1", @@ -32724,6 +32724,12 @@ "workbox-core": "6.6.0" } }, + "node_modules/workbox-background-sync/node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true + }, "node_modules/workbox-broadcast-update": { "version": "6.6.0", "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", @@ -32936,6 +32942,12 @@ "workbox-core": "6.6.0" } }, + "node_modules/workbox-expiration/node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true + }, "node_modules/workbox-google-analytics": { "version": "6.6.0", "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", diff --git a/package.json b/package.json index 5b00cbb36..43943f095 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "crypto-browserify": "^3.12.0", "ethers": "^5.7.2", "https-browserify": "^1.0.0", + "idb": "^8.0.0", "jest-environment-jsdom": "^27.5.1", "lodash": "^4.17.21", "markdown-it": "^14.1.0", diff --git a/src/db.ts b/src/db.ts new file mode 100644 index 000000000..02ef3fa6d --- /dev/null +++ b/src/db.ts @@ -0,0 +1,47 @@ +import { openDB, DBSchema } from 'idb'; + +interface TwoWayPegDB extends DBSchema { + transactions: { + key: string; + value: { + txId: string; + status: string; + lastUpdated: number; + }; + indexes: { 'by-last-updated': number }; + }; +} + +const DB_NAME = '2wp-app'; +const DB_VERSION = 1; +const DB_STORE_NAME = 'transactions'; + +const dbPromise = openDB(DB_NAME, DB_VERSION, { + upgrade(upgradedDB) { + const store = upgradedDB.createObjectStore(DB_STORE_NAME, { keyPath: 'txId' }); + store.createIndex('by-last-updated', 'lastUpdated'); + }, +}); + +export async function get(key: string) { + return (await dbPromise).get(DB_STORE_NAME, key); +} + +export async function getMany(count = 10) { + return (await dbPromise).getAll(DB_STORE_NAME, null, count); +} + +export async function set(val: { txId: string; status: string; }) { + return (await dbPromise).put( + DB_STORE_NAME, + { + txId: val.txId, + status: val.status, + lastUpdated: Date.now(), + }, + ); +} + +export async function del(key: string) { + return (await dbPromise).delete(DB_STORE_NAME, key); +} diff --git a/src/status/store/actions.ts b/src/status/store/actions.ts index b124a9f5c..981f0cfa4 100644 --- a/src/status/store/actions.ts +++ b/src/status/store/actions.ts @@ -11,6 +11,7 @@ import * as constants from '@/common/store/constants'; import { ApiService } from '@/common/services'; import { BridgeService } from '@/common/services/BridgeService'; import { getEstimatedFee } from '@/common/utils'; +import { set } from '@/db'; export const actions: ActionTree = { [constants.STATUS_CLEAR]: ({ commit }) => { @@ -25,6 +26,7 @@ export const actions: ActionTree = { .then(([status]) => { commit(constants.STATUS_SET_TX_DETAILS, status.txDetails); commit(constants.STATUS_SET_TX_TYPE, status.type); + set({ txId, status: status.txDetails?.status ?? 'UNKNOWN' }); const nextActions = []; if (status.type === TxStatusType.FLYOVER_PEGIN || status.type === TxStatusType.FLYOVER_PEGOUT) { From ae910e779c1d3ff12075ff2193ed0e2a9049114e Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Wed, 14 Aug 2024 17:51:05 -0300 Subject: [PATCH 19/25] Fake indexedDB for testing --- .eslintrc.js | 1 + package-lock.json | 10 ++++++++++ package.json | 1 + setup-jest.js | 1 + 4 files changed, 13 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index a075f6a13..bd08524b2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -34,6 +34,7 @@ module.exports = { 'vuejs-accessibility/mouse-events-have-key-events': 'off', 'import/extensions': 'off', 'global-require': 'off', + 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], }, overrides: [ { diff --git a/package-lock.json b/package-lock.json index 949f879b4..93f8b7172 100644 --- a/package-lock.json +++ b/package-lock.json @@ -96,6 +96,7 @@ "eslint-plugin-import": "^2.28.0", "eslint-plugin-vue": "^8.7.1", "eslint-plugin-vuejs-accessibility": "^1.2.0", + "fake-indexeddb": "^6.0.0", "geckodriver": "^4.4.0", "jest": "^27.5.1", "sass": "^1.64.2", @@ -17064,6 +17065,15 @@ "node": "> 0.1.90" } }, + "node_modules/fake-indexeddb": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/fake-indexeddb/-/fake-indexeddb-6.0.0.tgz", + "integrity": "sha512-YEboHE5VfopUclOck7LncgIqskAqnv4q0EWbYCaxKKjAvO93c+TJIaBuGy8CBFdbg9nKdpN3AuPRwVBJ4k7NrQ==", + "dev": true, + "engines": { + "node": ">=18" + } + }, "node_modules/fake-merkle-patricia-tree": { "version": "1.0.1", "license": "ISC", diff --git a/package.json b/package.json index 43943f095..dc0347297 100644 --- a/package.json +++ b/package.json @@ -101,6 +101,7 @@ "eslint-plugin-import": "^2.28.0", "eslint-plugin-vue": "^8.7.1", "eslint-plugin-vuejs-accessibility": "^1.2.0", + "fake-indexeddb": "^6.0.0", "geckodriver": "^4.4.0", "jest": "^27.5.1", "sass": "^1.64.2", diff --git a/setup-jest.js b/setup-jest.js index 7c97c034f..43f7fb8a6 100644 --- a/setup-jest.js +++ b/setup-jest.js @@ -1,3 +1,4 @@ import { TextEncoder, TextDecoder } from 'util'; +import 'fake-indexeddb/auto'; Object.assign(global, { TextDecoder, TextEncoder }); From c3e836571df614f16877caa2c7d2db8d4d2547fa Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Thu, 15 Aug 2024 15:15:53 -0300 Subject: [PATCH 20/25] Show last txs in status page --- src/db.ts | 5 +++- src/status/views/Status.vue | 50 ++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/db.ts b/src/db.ts index 02ef3fa6d..a78437445 100644 --- a/src/db.ts +++ b/src/db.ts @@ -28,7 +28,10 @@ export async function get(key: string) { } export async function getMany(count = 10) { - return (await dbPromise).getAll(DB_STORE_NAME, null, count); + const db = await dbPromise; + const indexed = await db.getAllFromIndex(DB_STORE_NAME, 'by-last-updated'); + const byDescOrder = indexed.splice(-count).reverse(); + return byDescOrder; } export async function set(val: { txId: string; status: string; }) { diff --git a/src/status/views/Status.vue b/src/status/views/Status.vue index 1edf6c62a..f6e06a9f4 100644 --- a/src/status/views/Status.vue +++ b/src/status/views/Status.vue @@ -36,6 +36,33 @@ Searching... + + + Last transactions + + + + Transaction ID + Status + + + + + + + {{ tx.txId }} + + + + + {{ tx.status }} + + + + + @@ -44,7 +71,7 @@ import { computed, ref, watch, defineComponent, onUnmounted, } from 'vue'; import { useRoute, useRouter } from 'vue-router'; -import { mdiMagnify } from '@mdi/js'; +import { mdiMagnify, mdiOpenInNew } from '@mdi/js'; import TxPegout from '@/common/components/status/TxPegout.vue'; import TxPegin from '@/common/components/status/TxPegin.vue'; import { @@ -58,6 +85,8 @@ import { } from '@/common/store/helper'; import StatusProgressBar from '@/common/components/status/StatusProgressBar.vue'; import { PegStatus } from '@/common/store/constants'; +import { getBtcTxExplorerUrl, getRskTxExplorerUrl } from '@/common/utils'; +import { getMany } from '@/db'; export default defineComponent({ name: 'StatusSearch', @@ -189,9 +218,25 @@ export default defineComponent({ router.replace({ name: 'Home' }); } + function getExplorerUrl(id: string) { + let url = ''; + if (id.startsWith('0x')) { + url = getRskTxExplorerUrl(id); + } else { + url = getBtcTxExplorerUrl(id); + } + return url; + } + + const lastTxs = ref(); + async function getLastTxs() { + lastTxs.value = await getMany(); + } + watch(route, onUrlChange, { immediate: true, deep: true }); clearStatus(); + getLastTxs(); onUnmounted(clean); @@ -214,6 +259,9 @@ export default defineComponent({ rules, txWithErrorType, txWithError, + lastTxs, + mdiOpenInNew, + getExplorerUrl, }; }, }); From f3469ba741af3d512f3a3eab656f5513ca7bb2ee Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Mon, 7 Oct 2024 15:35:04 -0300 Subject: [PATCH 21/25] Update app name --- public/index.html | 2 +- vue.config.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/index.html b/public/index.html index fdbc22b32..11e4e8f57 100644 --- a/public/index.html +++ b/public/index.html @@ -5,7 +5,7 @@ - 2-Way Peg App + PowPeg diff --git a/vue.config.js b/vue.config.js index 671154dba..0f4463551 100644 --- a/vue.config.js +++ b/vue.config.js @@ -6,15 +6,15 @@ const { VuetifyPlugin } = require('webpack-plugin-vuetify'); module.exports = defineConfig({ pwa: { - name: '2-Way Peg App', + name: 'PowPeg', themeColor: '#FF9800', iconPaths: { favicon32: 'img/icons/favicon-32x32.png', favicon16: 'img/icons/favicon-16x16.png', }, manifestOptions: { - id: '2wp-app', - short_name: '2WP App', + id: 'powpeg', + short_name: 'PowPeg', description: 'Bridging Bitcoin and Rootstock', start_url: '/', icons: [ From c925f00418b2ed5bb9325d8bbac7bdb9c8a69a64 Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Wed, 9 Oct 2024 16:17:00 -0300 Subject: [PATCH 22/25] Try background periodic sync --- package-lock.json | 1080 ++++++++++++++++++---------------- package.json | 5 +- src/App.vue | 2 +- src/db.ts | 6 +- src/main.ts | 1 + src/registerServiceWorker.ts | 18 +- src/service-worker.ts | 86 +++ src/status/views/Status.vue | 11 +- tsconfig.json | 3 +- vue.config.js | 5 + 10 files changed, 678 insertions(+), 539 deletions(-) create mode 100644 src/service-worker.ts diff --git a/package-lock.json b/package-lock.json index 93f8b7172..8498adcb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,8 +48,8 @@ "moment": "^2.29.4", "os-browserify": "^0.3.0", "process": "^0.11.10", - "sats-connect": "2.3.x", "register-service-worker": "^1.7.2", + "sats-connect": "2.3.x", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "text-encoding": "^0.7.0", @@ -61,7 +61,8 @@ "vuetify": "^3.5.17", "vuex": "^4.1.0", "web3": "^4.8.0", - "web3-eth-contract": "^1.10.0" + "web3-eth-contract": "^1.10.0", + "workbox-precaching": "^7.1.0" }, "devDependencies": { "@intlify/vue-i18n-loader": "^4.2.0", @@ -148,39 +149,41 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", - "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.25.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.22.9", - "license": "MIT", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.7.tgz", + "integrity": "sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.22.11", - "license": "MIT", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.7.tgz", + "integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-compilation-targets": "^7.22.10", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.11", - "@babel/parser": "^7.22.11", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.11", - "@babel/types": "^7.22.11", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helpers": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", @@ -194,15 +197,20 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, "node_modules/@babel/generator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz", - "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", + "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", "dependencies": { - "@babel/types": "^7.23.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" + "@babel/types": "^7.25.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" @@ -229,12 +237,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.10", - "license": "MIT", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", + "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.5", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -335,26 +344,26 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", - "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", + "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", "dependencies": { - "@babel/types": "^7.24.0" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", - "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", + "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.24.3", - "@babel/helper-simple-access": "^7.24.5", - "@babel/helper-split-export-declaration": "^7.24.5", - "@babel/helper-validator-identifier": "^7.24.5" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -413,11 +422,12 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", - "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", + "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", "dependencies": { - "@babel/types": "^7.24.5" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -445,25 +455,25 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", - "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", - "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", + "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", "engines": { "node": ">=6.9.0" } @@ -481,34 +491,38 @@ } }, "node_modules/@babel/helpers": { - "version": "7.22.11", - "license": "MIT", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", + "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.11", - "@babel/types": "^7.22.11" + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz", - "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz", + "integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==", + "dependencies": { + "@babel/types": "^7.25.7" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -2145,32 +2159,29 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", + "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz", - "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==", - "dependencies": { - "@babel/code-frame": "^7.23.4", - "@babel/generator": "^7.23.4", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.4", - "@babel/types": "^7.23.4", - "debug": "^4.1.0", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", + "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", + "dependencies": { + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -2178,12 +2189,12 @@ } }, "node_modules/@babel/types": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", - "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz", + "integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==", "dependencies": { - "@babel/helper-string-parser": "^7.24.1", - "@babel/helper-validator-identifier": "^7.24.5", + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -5873,12 +5884,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "license": "MIT", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -5892,8 +5904,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "license": "MIT", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } @@ -6847,26 +6860,6 @@ } } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, "node_modules/@rollup/plugin-replace": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", @@ -8497,15 +8490,6 @@ "csstype": "^3.0.2" } }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/responselike": { "version": "1.0.0", "dev": true, @@ -9270,6 +9254,392 @@ "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" } }, + "node_modules/@vue/cli-plugin-pwa/node_modules/@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "dev": true, + "dependencies": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dev": true, + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-background-sync": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", + "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", + "dev": true, + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-broadcast-update": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", + "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-build": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", + "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", + "dev": true, + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.11.1", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-replace": "^2.4.1", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "rollup-plugin-terser": "^7.0.0", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "6.6.0", + "workbox-broadcast-update": "6.6.0", + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-google-analytics": "6.6.0", + "workbox-navigation-preload": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-range-requests": "6.6.0", + "workbox-recipes": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0", + "workbox-streams": "6.6.0", + "workbox-sw": "6.6.0", + "workbox-window": "6.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-build/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dev": true, + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-cacheable-response": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", + "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", + "deprecated": "workbox-background-sync@6.6.0", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", + "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==", + "dev": true + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-expiration": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", + "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", + "dev": true, + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-google-analytics": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", + "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", + "deprecated": "It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained", + "dev": true, + "dependencies": { + "workbox-background-sync": "6.6.0", + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-navigation-preload": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", + "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-precaching": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", + "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-range-requests": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", + "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-recipes": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", + "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", + "dev": true, + "dependencies": { + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-routing": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", + "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-strategies": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", + "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-streams": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", + "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", + "dev": true, + "dependencies": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-sw": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", + "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==", + "dev": true + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-webpack-plugin": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", + "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "^2.1.0", + "pretty-bytes": "^5.4.1", + "upath": "^1.2.0", + "webpack-sources": "^1.4.3", + "workbox-build": "6.6.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "webpack": "^4.4.0 || ^5.9.0" + } + }, + "node_modules/@vue/cli-plugin-pwa/node_modules/workbox-window": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", + "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", + "dev": true, + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "6.6.0" + } + }, "node_modules/@vue/cli-plugin-router": { "version": "5.0.8", "dev": true, @@ -11821,7 +12191,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.10", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "funding": [ { "type": "opencollective", @@ -11836,12 +12208,11 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -12187,9 +12558,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001646", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001646.tgz", - "integrity": "sha512-dRg00gudiBDDTmUhClSdv3hqRfpbOnU28IpI1T6PBTLWa+kOj0681C8uML3PifYfREuBrVjDGhL3adYpBT6spw==", + "version": "1.0.30001667", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", + "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", "funding": [ { "type": "opencollective", @@ -12893,6 +13264,7 @@ }, "node_modules/convert-source-map": { "version": "1.9.0", + "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -14375,8 +14747,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.502", - "license": "ISC" + "version": "1.5.33", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.33.tgz", + "integrity": "sha512-+cYTcFB1QqD4j4LegwLfpCNxifb6dDFUAwk6RsLusCwIaZI6or2f+q8rs5tTB2YC53HhOlIbEaqHMAAC8IOIwA==" }, "node_modules/electron/node_modules/@types/node": { "version": "18.17.11", @@ -14713,8 +15086,9 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "license": "MIT", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "engines": { "node": ">=6" } @@ -17146,9 +17520,9 @@ "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==" }, "node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.2.tgz", + "integrity": "sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row==", "dev": true }, "node_modules/fastq": { @@ -19751,9 +20125,9 @@ } }, "node_modules/jake/node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "dev": true }, "node_modules/jake/node_modules/chalk": { @@ -22181,13 +22555,14 @@ "license": "MIT" }, "node_modules/jsesc": { - "version": "2.5.2", - "license": "MIT", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-bigint": { @@ -24116,8 +24491,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.13", - "license": "MIT" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/nopt": { "version": "6.0.0", @@ -24928,8 +25304,9 @@ "license": "MIT" }, "node_modules/picocolors": { - "version": "1.0.0", - "license": "ISC" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -26790,9 +27167,9 @@ "optional": true }, "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -29855,7 +30232,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "funding": [ { "type": "opencollective", @@ -29870,10 +30249,9 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -32724,377 +33102,35 @@ "integrity": "sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==", "peer": true }, - "node_modules/workbox-background-sync": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", - "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", - "dev": true, - "dependencies": { - "idb": "^7.0.1", - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-background-sync/node_modules/idb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", - "dev": true - }, - "node_modules/workbox-broadcast-update": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", - "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", - "dev": true, - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-build": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", - "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", - "dev": true, - "dependencies": { - "@apideck/better-ajv-errors": "^0.3.1", - "@babel/core": "^7.11.1", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.2", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-node-resolve": "^11.2.1", - "@rollup/plugin-replace": "^2.4.1", - "@surma/rollup-plugin-off-main-thread": "^2.2.3", - "ajv": "^8.6.0", - "common-tags": "^1.8.0", - "fast-json-stable-stringify": "^2.1.0", - "fs-extra": "^9.0.1", - "glob": "^7.1.6", - "lodash": "^4.17.20", - "pretty-bytes": "^5.3.0", - "rollup": "^2.43.1", - "rollup-plugin-terser": "^7.0.0", - "source-map": "^0.8.0-beta.0", - "stringify-object": "^3.3.0", - "strip-comments": "^2.0.1", - "tempy": "^0.6.0", - "upath": "^1.2.0", - "workbox-background-sync": "6.6.0", - "workbox-broadcast-update": "6.6.0", - "workbox-cacheable-response": "6.6.0", - "workbox-core": "6.6.0", - "workbox-expiration": "6.6.0", - "workbox-google-analytics": "6.6.0", - "workbox-navigation-preload": "6.6.0", - "workbox-precaching": "6.6.0", - "workbox-range-requests": "6.6.0", - "workbox-recipes": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0", - "workbox-streams": "6.6.0", - "workbox-sw": "6.6.0", - "workbox-window": "6.6.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/workbox-build/node_modules/@apideck/better-ajv-errors": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", - "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", - "dev": true, - "dependencies": { - "json-schema": "^0.4.0", - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "ajv": ">=8" - } - }, - "node_modules/workbox-build/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/workbox-build/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/workbox-build/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/workbox-build/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dev": true, - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/workbox-build/node_modules/tempy": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", - "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/workbox-build/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/workbox-build/node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/workbox-build/node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/workbox-build/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "node_modules/workbox-build/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/workbox-cacheable-response": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", - "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", - "deprecated": "workbox-background-sync@6.6.0", - "dev": true, - "dependencies": { - "workbox-core": "6.6.0" - } - }, "node_modules/workbox-core": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", - "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==", - "dev": true - }, - "node_modules/workbox-expiration": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", - "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", - "dev": true, - "dependencies": { - "idb": "^7.0.1", - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-expiration/node_modules/idb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", - "dev": true - }, - "node_modules/workbox-google-analytics": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", - "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", - "deprecated": "It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained", - "dev": true, - "dependencies": { - "workbox-background-sync": "6.6.0", - "workbox-core": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0" - } - }, - "node_modules/workbox-navigation-preload": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", - "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", - "dev": true, - "dependencies": { - "workbox-core": "6.6.0" - } + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.1.0.tgz", + "integrity": "sha512-5KB4KOY8rtL31nEF7BfvU7FMzKT4B5TkbYa2tzkS+Peqj0gayMT9SytSFtNzlrvMaWgv6y/yvP9C0IbpFjV30Q==" }, "node_modules/workbox-precaching": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", - "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", - "dev": true, - "dependencies": { - "workbox-core": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0" - } - }, - "node_modules/workbox-range-requests": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", - "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", - "dev": true, - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-recipes": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", - "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", - "dev": true, + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.1.0.tgz", + "integrity": "sha512-LyxzQts+UEpgtmfnolo0hHdNjoB7EoRWcF7EDslt+lQGd0lW4iTvvSe3v5JiIckQSB5KTW5xiCqjFviRKPj1zA==", "dependencies": { - "workbox-cacheable-response": "6.6.0", - "workbox-core": "6.6.0", - "workbox-expiration": "6.6.0", - "workbox-precaching": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0" + "workbox-core": "7.1.0", + "workbox-routing": "7.1.0", + "workbox-strategies": "7.1.0" } }, "node_modules/workbox-routing": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", - "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", - "dev": true, + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.1.0.tgz", + "integrity": "sha512-oOYk+kLriUY2QyHkIilxUlVcFqwduLJB7oRZIENbqPGeBP/3TWHYNNdmGNhz1dvKuw7aqvJ7CQxn27/jprlTdg==", "dependencies": { - "workbox-core": "6.6.0" + "workbox-core": "7.1.0" } }, "node_modules/workbox-strategies": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", - "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", - "dev": true, - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-streams": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", - "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", - "dev": true, - "dependencies": { - "workbox-core": "6.6.0", - "workbox-routing": "6.6.0" - } - }, - "node_modules/workbox-sw": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", - "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==", - "dev": true - }, - "node_modules/workbox-webpack-plugin": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", - "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "^2.1.0", - "pretty-bytes": "^5.4.1", - "upath": "^1.2.0", - "webpack-sources": "^1.4.3", - "workbox-build": "6.6.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "webpack": "^4.4.0 || ^5.9.0" - } - }, - "node_modules/workbox-webpack-plugin/node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "node_modules/workbox-window": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", - "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", - "dev": true, + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.1.0.tgz", + "integrity": "sha512-/UracPiGhUNehGjRm/tLUQ+9PtWmCbRufWtV0tNrALuf+HZ4F7cmObSEK+E4/Bx1p8Syx2tM+pkIrvtyetdlew==", "dependencies": { - "@types/trusted-types": "^2.0.2", - "workbox-core": "6.6.0" + "workbox-core": "7.1.0" } }, "node_modules/wrap-ansi": { diff --git a/package.json b/package.json index dc0347297..632208d7a 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,8 @@ "moment": "^2.29.4", "os-browserify": "^0.3.0", "process": "^0.11.10", - "sats-connect": "2.3.x", "register-service-worker": "^1.7.2", + "sats-connect": "2.3.x", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "text-encoding": "^0.7.0", @@ -66,7 +66,8 @@ "vuetify": "^3.5.17", "vuex": "^4.1.0", "web3": "^4.8.0", - "web3-eth-contract": "^1.10.0" + "web3-eth-contract": "^1.10.0", + "workbox-precaching": "^7.1.0" }, "devDependencies": { "@intlify/vue-i18n-loader": "^4.2.0", diff --git a/src/App.vue b/src/App.vue index 2b7baa84e..07bd217e4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -49,7 +49,7 @@ export default { connect-src 'self' 'unsafe-inline' https://www.clarity.ms/s/0.7.16/clarity.js wss://* https://*.hotjar.com https://*.hotjar.io https://www.clarity.ms/s/* wss://*.hotjar.com ${envVariables.vueAppApiBaseUrl} ${envVariables.vueAppRskNodeHost} https://lps.testnet.flyover.rif.technology https://lps.flyover.rif.technology https://api.coingecko.com https://*.clarity.ms https://www.clarity.ms/* ; object-src 'none'; frame-src https://connect.trezor.io https://www.google.com/; - worker-src 'none'; + worker-src 'self'; `; return response; }); diff --git a/src/db.ts b/src/db.ts index a78437445..72a718ce9 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,6 +1,6 @@ import { openDB, DBSchema } from 'idb'; -interface TwoWayPegDB extends DBSchema { +interface PowPegDB extends DBSchema { transactions: { key: string; value: { @@ -12,11 +12,11 @@ interface TwoWayPegDB extends DBSchema { }; } -const DB_NAME = '2wp-app'; +const DB_NAME = 'powpeg'; const DB_VERSION = 1; const DB_STORE_NAME = 'transactions'; -const dbPromise = openDB(DB_NAME, DB_VERSION, { +const dbPromise = openDB(DB_NAME, DB_VERSION, { upgrade(upgradedDB) { const store = upgradedDB.createObjectStore(DB_STORE_NAME, { keyPath: 'txId' }); store.createIndex('by-last-updated', 'lastUpdated'); diff --git a/src/main.ts b/src/main.ts index 70d07d6fb..85be560e7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,6 +8,7 @@ import router from './common/router'; import store from './common/store'; import { vuetify } from './common/plugins/vuetify'; import '@/common/styles/main.scss'; +import './registerServiceWorker'; // These environment variables were been set at service/component layer instead of been // globally set up. We should consider removing them diff --git a/src/registerServiceWorker.ts b/src/registerServiceWorker.ts index e32aa92b8..d7385e7d0 100644 --- a/src/registerServiceWorker.ts +++ b/src/registerServiceWorker.ts @@ -4,11 +4,19 @@ import { register } from 'register-service-worker'; if (process.env.NODE_ENV === 'production') { register(`${process.env.BASE_URL}service-worker.js`, { - ready() { - console.log( - 'App is being served from cache by a service worker.\n' - + 'For more details, visit https://goo.gl/AFskqB', - ); + ready(registration) { + if ('periodicSync' in registration) { + navigator.permissions.query({ name: 'periodic-background-sync' as PermissionName }) + .then((permission) => { + if (permission.state === 'granted') { + // @ts-expect-error not periodicsync ts support + registration.periodicSync.register('update-txs', { minInterval: 1000 * 60 * 60 }); // 1 hour + } + }) + .catch((error) => { + console.error('Periodic Sync registration failed', error); + }); + } }, registered() { console.log('Service worker has been registered.'); diff --git a/src/service-worker.ts b/src/service-worker.ts new file mode 100644 index 000000000..cfeba199b --- /dev/null +++ b/src/service-worker.ts @@ -0,0 +1,86 @@ +import { precacheAndRoute } from 'workbox-precaching'; +import { openDB, DBSchema } from 'idb'; + +// workaround to access service worker global scope via self +declare const self: ServiceWorkerGlobalScope; + +// eslint-disable-next-line no-underscore-dangle +precacheAndRoute(self.__WB_MANIFEST); + +interface PowPegDB extends DBSchema { + transactions: { + key: string; + value: { + txId: string; + status: string; + lastUpdated: number; + }; + indexes: { 'by-last-updated': number }; + }; +} + +const DB_NAME = 'powpeg'; +const DB_VERSION = 1; +const DB_STORE_NAME = 'transactions'; + +const dbPromise = openDB(DB_NAME, DB_VERSION, { + upgrade(upgradedDB) { + const store = upgradedDB.createObjectStore(DB_STORE_NAME, { keyPath: 'txId' }); + store.createIndex('by-last-updated', 'lastUpdated'); + }, +}); + +async function getMany(count = 10) { + const db = await dbPromise; + const indexed = await db.getAllFromIndex(DB_STORE_NAME, 'by-last-updated'); + const byDescOrder = indexed.splice(-count).reverse(); + return byDescOrder; +} + +async function set(val: { txId: string; status: string; }) { + return (await dbPromise).put( + DB_STORE_NAME, + { + txId: val.txId, + status: val.status, + lastUpdated: Date.now(), + }, + ); +} + +async function getUpdatedStatuses() { + // get txs from db + const txs = await getMany(); + // fetch updated statuses + const updatedTxs = await Promise.all(txs.map((tx) => fetch(`${process.env.VUE_APP_API_BASE_URL}/tx-status/${tx.txId}`))); + // create updated txs to store in db + const updatedTxsToStore = await Promise.all(updatedTxs.map(async (tx) => { + const { type, txDetails } = await tx.json(); + if (type === 'PEGIN') { + return { + txId: txDetails.btc.txId, + status: txDetails.status, + }; + } + if (type === 'PEGOUT') { + return { + txId: txDetails.originatingRskTxHash, + status: txDetails.status, + }; + } + return { + txId: '', + status: '', + }; + })); + // store updated txs in db + await Promise.all(updatedTxsToStore.map((tx) => set(tx))); +} + +self.addEventListener('periodicsync', (event) => { + // @ts-expect-error not periodicsync ts support + if (event.tag === 'update-txs') { + // @ts-expect-error not periodicsync ts support + event.waitUntil(getUpdatedStatuses()); + } +}); diff --git a/src/status/views/Status.vue b/src/status/views/Status.vue index f6e06a9f4..1d0141422 100644 --- a/src/status/views/Status.vue +++ b/src/status/views/Status.vue @@ -188,6 +188,11 @@ export default defineComponent({ loading.value = false; } + const lastTxs = ref(); + async function getLastTxs() { + lastTxs.value = await getMany(); + } + function getPegStatus() { if (!isValidTxId.value) clean(); else if (route.path !== `/status/txId/${txId.value}`) { @@ -199,6 +204,7 @@ export default defineComponent({ clean(); loading.value = true; setTxStatus(txId.value) + .then(getLastTxs) .then(() => { loading.value = false; }); @@ -228,11 +234,6 @@ export default defineComponent({ return url; } - const lastTxs = ref(); - async function getLastTxs() { - lastTxs.value = await getMany(); - } - watch(route, onUrlChange, { immediate: true, deep: true }); clearStatus(); diff --git a/tsconfig.json b/tsconfig.json index 1e364344f..ed2281b44 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,7 +32,8 @@ "es6", "dom", "dom.iterable", - "scripthost" + "scripthost", + "webworker" ] }, "include": [ diff --git a/vue.config.js b/vue.config.js index 0f4463551..401be429c 100644 --- a/vue.config.js +++ b/vue.config.js @@ -44,6 +44,11 @@ module.exports = defineConfig({ }, ], }, + workboxPluginMode: 'InjectManifest', + workboxOptions: { + swSrc: './src/service-worker.ts', + swDest: 'service-worker.js', + }, }, transpileDependencies: true, configureWebpack: { From 31e0926856ec5840cddd9b8f69d27f360ec3fbdf Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Mon, 14 Oct 2024 10:53:44 -0300 Subject: [PATCH 23/25] Update status view and reuse db utils --- src/service-worker.ts | 48 +++++++------------------------------ src/status/views/Status.vue | 6 +++++ 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/src/service-worker.ts b/src/service-worker.ts index cfeba199b..21927f7dc 100644 --- a/src/service-worker.ts +++ b/src/service-worker.ts @@ -1,5 +1,5 @@ import { precacheAndRoute } from 'workbox-precaching'; -import { openDB, DBSchema } from 'idb'; +import { getMany, set } from './db'; // workaround to access service worker global scope via self declare const self: ServiceWorkerGlobalScope; @@ -7,45 +7,12 @@ declare const self: ServiceWorkerGlobalScope; // eslint-disable-next-line no-underscore-dangle precacheAndRoute(self.__WB_MANIFEST); -interface PowPegDB extends DBSchema { - transactions: { - key: string; - value: { - txId: string; - status: string; - lastUpdated: number; - }; - indexes: { 'by-last-updated': number }; - }; -} - -const DB_NAME = 'powpeg'; -const DB_VERSION = 1; -const DB_STORE_NAME = 'transactions'; - -const dbPromise = openDB(DB_NAME, DB_VERSION, { - upgrade(upgradedDB) { - const store = upgradedDB.createObjectStore(DB_STORE_NAME, { keyPath: 'txId' }); - store.createIndex('by-last-updated', 'lastUpdated'); - }, -}); - -async function getMany(count = 10) { - const db = await dbPromise; - const indexed = await db.getAllFromIndex(DB_STORE_NAME, 'by-last-updated'); - const byDescOrder = indexed.splice(-count).reverse(); - return byDescOrder; -} - -async function set(val: { txId: string; status: string; }) { - return (await dbPromise).put( - DB_STORE_NAME, - { - txId: val.txId, - status: val.status, - lastUpdated: Date.now(), - }, - ); +async function updateView() { + self.clients.matchAll().then((clients) => { + clients.forEach((client) => { + client.postMessage('update-view'); + }); + }); } async function getUpdatedStatuses() { @@ -75,6 +42,7 @@ async function getUpdatedStatuses() { })); // store updated txs in db await Promise.all(updatedTxsToStore.map((tx) => set(tx))); + await updateView(); } self.addEventListener('periodicsync', (event) => { diff --git a/src/status/views/Status.vue b/src/status/views/Status.vue index 1d0141422..63344be9a 100644 --- a/src/status/views/Status.vue +++ b/src/status/views/Status.vue @@ -239,6 +239,12 @@ export default defineComponent({ clearStatus(); getLastTxs(); + navigator.serviceWorker.addEventListener('message', async (evt) => { + if (evt.data === 'update-view') { + await getLastTxs(); + } + }); + onUnmounted(clean); return { From 092c4516c5075e7afc5b4f73ea0a31da53946b48 Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Tue, 15 Oct 2024 16:05:16 -0300 Subject: [PATCH 24/25] Add notifications --- src/common/views/Home.vue | 33 ++++++++++++++++++++++++++++++++- src/registerServiceWorker.ts | 5 +++++ src/service-worker.ts | 5 ++++- src/status/views/Status.vue | 4 ++-- src/webworker.d.ts | 6 ++++++ 5 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/webworker.d.ts diff --git a/src/common/views/Home.vue b/src/common/views/Home.vue index 4ce377150..63abf027c 100644 --- a/src/common/views/Home.vue +++ b/src/common/views/Home.vue @@ -62,10 +62,13 @@
Already made a transaction? - + Transaction Status +
To learn about the various RBTC access methods, visit @@ -183,6 +186,33 @@ export default { if (route.path !== '/status') router.push('/status'); } + const unreadNotifications = ref(0); + + function showNotification() { + Notification.requestPermission() + .then((permission) => { + if (permission === 'granted') { + const notification = new Notification('PowPeg', { + body: 'New transaction status available', + }); + notification.onshow = () => { + unreadNotifications.value += 1; + navigator.setAppBadge(unreadNotifications.value); + }; + notification.onclose = () => { + unreadNotifications.value -= 1; + navigator.setAppBadge(unreadNotifications.value); + }; + } + }); + } + + navigator.serviceWorker.addEventListener('message', (evt) => { + if (evt.data === 'update-view') { + showNotification(); + } + }); + getBtcPrice(); clearPegin(); clearPegOut(); @@ -190,6 +220,7 @@ export default { addPeg(); return { + unreadNotifications, environmentContext, isAllowedBrowser, toStatusSearch, diff --git a/src/registerServiceWorker.ts b/src/registerServiceWorker.ts index d7385e7d0..e2aba3d3f 100644 --- a/src/registerServiceWorker.ts +++ b/src/registerServiceWorker.ts @@ -17,6 +17,11 @@ if (process.env.NODE_ENV === 'production') { console.error('Periodic Sync registration failed', error); }); } + Notification.requestPermission().then((permission) => { + if (permission === 'granted') { + console.log('Notification permission granted.'); + } + }); }, registered() { console.log('Service worker has been registered.'); diff --git a/src/service-worker.ts b/src/service-worker.ts index 21927f7dc..c271bcec2 100644 --- a/src/service-worker.ts +++ b/src/service-worker.ts @@ -42,7 +42,10 @@ async function getUpdatedStatuses() { })); // store updated txs in db await Promise.all(updatedTxsToStore.map((tx) => set(tx))); - await updateView(); + + if (updatedTxsToStore.length > 0) { + await updateView(); + } } self.addEventListener('periodicsync', (event) => { diff --git a/src/status/views/Status.vue b/src/status/views/Status.vue index 63344be9a..9b0c95df8 100644 --- a/src/status/views/Status.vue +++ b/src/status/views/Status.vue @@ -42,8 +42,8 @@ - Transaction ID - Status + Transaction ID + Status diff --git a/src/webworker.d.ts b/src/webworker.d.ts new file mode 100644 index 000000000..a55366736 --- /dev/null +++ b/src/webworker.d.ts @@ -0,0 +1,6 @@ +interface Navigator { + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Navigator/clearAppBadge) */ + clearAppBadge(): Promise; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Navigator/setAppBadge) */ + setAppBadge(contents?: number): Promise; +} From d1412ceed98770e454e26af440b68cc7260b4d59 Mon Sep 17 00:00:00 2001 From: lserra-iov Date: Mon, 21 Oct 2024 11:59:13 -0300 Subject: [PATCH 25/25] Trigger tx search on txid click and sync notifications in app --- src/App.vue | 58 ++++++++++++++++++++- src/common/providers/UnreadNotifications.ts | 8 +++ src/common/views/Home.vue | 34 +++--------- src/status/views/Status.vue | 11 ++-- 4 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 src/common/providers/UnreadNotifications.ts diff --git a/src/App.vue b/src/App.vue index 07bd217e4..69ce33273 100644 --- a/src/App.vue +++ b/src/App.vue @@ -13,7 +13,9 @@