From 57af428afd99961f167ebf1698df4123104c538c Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 12 May 2025 20:43:53 +0000 Subject: [PATCH 001/103] feat: Add lighthouse timespan --- packages/arb-token-bridge-ui/package.json | 3 + .../src/components/TransferPanel/TokenRow.tsx | 1 + .../components/TransferPanel/TokenSearch.tsx | 1 - .../common/NetworkSelectionContainer.tsx | 3 + .../tests/perf/switchNetwork.js | 63 ++ yarn.lock | 775 +++++++++++++++++- 6 files changed, 811 insertions(+), 35 deletions(-) create mode 100644 packages/arb-token-bridge-ui/tests/perf/switchNetwork.js diff --git a/packages/arb-token-bridge-ui/package.json b/packages/arb-token-bridge-ui/package.json index 98a4ee6d54..734a657473 100644 --- a/packages/arb-token-bridge-ui/package.json +++ b/packages/arb-token-bridge-ui/package.json @@ -64,6 +64,7 @@ "start": "next start", "test": "vitest --config vitest.config.ts --watch", "test:ci": "vitest --config vitest.config.ts --run", + "test:perf": "ts-node --project ./tests/perf/tsconfig.json ./tests/perf/switchNetwork.ts", "lint": "tsc && eslint", "lint:fix": "tsc && eslint --quiet --fix", "prettier:format": "prettier --config-precedence file-override --write \"src/**/*.{tsx,ts,scss,md,json}\"", @@ -118,11 +119,13 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-zustand-rules": "https://github.com/OffchainLabs/eslint-plugin-zustand-rules", "happy-dom": "^17.4.4", + "lighthouse": "^12.6.0", "patch-package": "^8.0.0", "postcss": "^8.5.3", "postinstall-postinstall": "^2.1.0", "prettier": "^2.7.1", "prettier-plugin-tailwindcss": "^0.1.11", + "puppeteer": "^24.8.2", "satori": "^0.12.2", "start-server-and-test": "^2.0.11", "tailwindcss": "^3.4.16", diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx index d0a5cd9358..91bb39e65d 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx @@ -341,6 +341,7 @@ export function TokenRow({ onClick={() => onTokenSelected(token)} style={{ ...style, minHeight: '84px' }} disabled={!tokenIsBridgeable} + aria-label={`Select ${token?.symbol}`} className={twMerge( 'flex w-full flex-row items-center justify-between px-4 py-3 transition duration-200 hover:bg-white/10', tokenIsBridgeable diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx index da06258931..c70253c962 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx @@ -542,7 +542,6 @@ function TokensPanel({ errorMessage={errorMessage} onSubmit={addNewToken} SearchInputButton={AddButton} - dataCy="tokenSearchList" isDialog={true} > diff --git a/packages/arb-token-bridge-ui/src/components/common/NetworkSelectionContainer.tsx b/packages/arb-token-bridge-ui/src/components/common/NetworkSelectionContainer.tsx index 4c6b0e7d85..a91ae6a707 100644 --- a/packages/arb-token-bridge-ui/src/components/common/NetworkSelectionContainer.tsx +++ b/packages/arb-token-bridge-ui/src/components/common/NetworkSelectionContainer.tsx @@ -155,6 +155,9 @@ export function NetworkButton({ )} disabled={disabled} onClick={onClick} + aria-label={ + (isSource ? 'From ' : 'To ') + getNetworkName(selectedChainId) + } > {isSource ? 'From:' : 'To: '} {getNetworkName(selectedChainId)} diff --git a/packages/arb-token-bridge-ui/tests/perf/switchNetwork.js b/packages/arb-token-bridge-ui/tests/perf/switchNetwork.js new file mode 100644 index 0000000000..9b5ae6ee86 --- /dev/null +++ b/packages/arb-token-bridge-ui/tests/perf/switchNetwork.js @@ -0,0 +1,63 @@ +import puppeteer from 'puppeteer' +import { writeFileSync } from 'fs' +import { startFlow, desktopConfig } from 'lighthouse' + +// Setup the browser and Lighthouse. +const browser = await puppeteer.launch({ headless: false }) +const page = await browser.newPage() + +const flow = await startFlow(page, { + config: desktopConfig +}) + +await flow.navigate( + 'http://localhost:3000/?destinationChain=arbitrum-one&sourceChain=ethereum' +) + +await flow.startTimespan() + +// Accept ToS +await page.click('[aria-label="Agree to Terms and Continue"]') + +// Type amount +const input = await page.waitForSelector('[aria-label="Amount input"]') +await input?.type('2') +await page.waitForSelector('[aria-label="Route arbitrum"]') + +// Switch network +await page.click('[aria-label="Switch Networks"]') +await page.waitForSelector("[aria-label='From Arbitrum One']") + +// Open token selection +await page.click("[aria-label='Select Token']") +const tokenInput = await page.waitForSelector( + "[placeholder='Search by token name, symbol, or address']" +) +await tokenInput?.type('USDC') +await page.click('[aria-label="Select USDC.e"]') +await page.waitForSelector("xpath///button[contains(., 'USDC.e')]") + +// Open chain selection +await page.click("[aria-label='From Arbitrum One']") +const chainInput = await page.waitForSelector( + '[placeholder="Search a network name"]' +) +await chainInput?.type('Xai') + +const xaiRow = await page.waitForSelector('[aria-label="Switch to Xai"]') +await xaiRow?.click() +await page.waitForSelector("[aria-label='From Xai']") + +await flow.endTimespan() +await flow.snapshot() + +// Get the comprehensive flow report. +writeFileSync('report.html', await flow.generateReport()) +// Save results as JSON. +writeFileSync( + 'flow-result.json', + JSON.stringify(await flow.createFlowResult(), null, 2) +) + +// Cleanup. +await browser.close() diff --git a/yarn.lock b/yarn.lock index cc333a435e..14008eb5bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -99,7 +99,23 @@ async-mutex "^0.4.0" ethers "^5.1.0" -"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.22.5", "@babel/code-frame@^7.26.2": +"@babel/code-frame@^7.0.0": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz" + integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== + dependencies: + "@babel/highlight" "^7.22.5" + +"@babel/code-frame@^7.26.2": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== @@ -269,6 +285,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + "@babel/helper-validator-option@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" @@ -292,6 +313,16 @@ "@babel/traverse" "^7.22.5" "@babel/types" "^7.22.5" +"@babel/highlight@^7.22.5": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.9.tgz#8141ce68fc73757946f983b343f1231f4691acc6" + integrity sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/parser@^7.14.7", "@babel/parser@^7.22.5", "@babel/parser@^7.26.8": version "7.26.8" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.8.tgz#deca2b4d99e5e1b1553843b99823f118da6107c2" @@ -1780,6 +1811,47 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.9.tgz#50dea3616bc8191fb8e112283b49eaff03e78429" integrity sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg== +"@formatjs/ecma402-abstract@2.3.4": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz#e90c5a846ba2b33d92bc400fdd709da588280fbc" + integrity sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA== + dependencies: + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/intl-localematcher" "0.6.1" + decimal.js "^10.4.3" + tslib "^2.8.0" + +"@formatjs/fast-memoize@2.2.7": + version "2.2.7" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz#707f9ddaeb522a32f6715bb7950b0831f4cc7b15" + integrity sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ== + dependencies: + tslib "^2.8.0" + +"@formatjs/icu-messageformat-parser@2.11.2": + version "2.11.2" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.2.tgz#85aea211bea40aa81ee1d44ac7accc3cf5500a73" + integrity sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + "@formatjs/icu-skeleton-parser" "1.8.14" + tslib "^2.8.0" + +"@formatjs/icu-skeleton-parser@1.8.14": + version "1.8.14" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.14.tgz#b9581d00363908efb29817fdffc32b79f41dabe5" + integrity sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + tslib "^2.8.0" + +"@formatjs/intl-localematcher@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz#25dc30675320bf65a9d7f73876fc1e4064c0e299" + integrity sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg== + dependencies: + tslib "^2.8.0" + "@foundry-rs/easy-foundryup@^0.1.3": version "0.1.3" resolved "https://registry.npmjs.org/@foundry-rs/easy-foundryup/-/easy-foundryup-0.1.3.tgz" @@ -1814,7 +1886,7 @@ resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz" integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== -"@hapi/topo@^5.1.0": +"@hapi/topo@^5.0.0", "@hapi/topo@^5.1.0": version "5.1.0" resolved "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz" integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== @@ -2516,14 +2588,28 @@ dependencies: "@noble/hashes" "1.4.0" -"@noble/curves@1.8.2", "@noble/curves@~1.8.1": +"@noble/curves@1.8.2": version "1.8.2" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.2.tgz#8f24c037795e22b90ae29e222a856294c1d9ffc7" integrity sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g== dependencies: "@noble/hashes" "1.7.2" -"@noble/curves@^1.4.2", "@noble/curves@^1.6.0", "@noble/curves@^1.8.1", "@noble/curves@^1.9.1", "@noble/curves@~1.9.0": +"@noble/curves@^1.4.2", "@noble/curves@^1.8.1", "@noble/curves@~1.8.1": + version "1.8.1" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.1.tgz#19bc3970e205c99e4bdb1c64a4785706bce497ff" + integrity sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ== + dependencies: + "@noble/hashes" "1.7.1" + +"@noble/curves@^1.6.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.0.tgz#fe035a23959e6aeadf695851b51a87465b5ba8f7" + integrity sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ== + dependencies: + "@noble/hashes" "1.7.0" + +"@noble/curves@^1.9.1", "@noble/curves@~1.9.0": version "1.9.1" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.1.tgz#9654a0bc6c13420ae252ddcf975eaf0f58f0a35c" integrity sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA== @@ -2540,6 +2626,16 @@ resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== +"@noble/hashes@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.0.tgz#5d9e33af2c7d04fee35de1519b80c958b2e35e39" + integrity sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w== + +"@noble/hashes@1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.1.tgz#5738f6d765710921e7a751e00c20ae091ed8db0f" + integrity sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ== + "@noble/hashes@1.7.2", "@noble/hashes@~1.7.1": version "1.7.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.2.tgz#d53c65a21658fb02f3303e7ee3ba89d6754c64b4" @@ -2847,6 +2943,14 @@ "@parcel/watcher-win32-ia32" "2.4.1" "@parcel/watcher-win32-x64" "2.4.1" +"@paulirish/trace_engine@0.0.52": + version "0.0.52" + resolved "https://registry.yarnpkg.com/@paulirish/trace_engine/-/trace_engine-0.0.52.tgz#54c48e82a59231ff1b25f07ad699c831b2ad6638" + integrity sha512-RSIDdpvYRJIaXUSiJfTYxVRtjq3FPjU8FPT5BkpYXS4H7ofExEb4tZBXcqlRoriA8ykVTClgbqabmoI32n5zRQ== + dependencies: + legacy-javascript latest + third-party-web latest + "@paulmillr/qr@^0.2.1": version "0.2.1" resolved "https://registry.yarnpkg.com/@paulmillr/qr/-/qr-0.2.1.tgz#76ade7080be4ac4824f638146fd8b6db1805eeca" @@ -2874,6 +2978,19 @@ resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== +"@puppeteer/browsers@2.10.4": + version "2.10.4" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.10.4.tgz#9f8923b206f7932a06d32271b14bbea3368b38f2" + integrity sha512-9DxbZx+XGMNdjBynIs4BRSz+M3iRDeB7qRcAr6UORFLphCIM2x3DXgOucvADiifcqCE4XePFUKcnaAMyGbrDlQ== + dependencies: + debug "^4.4.0" + extract-zip "^2.0.1" + progress "^2.0.3" + proxy-agent "^6.5.0" + semver "^7.7.1" + tar-fs "^3.0.8" + yargs "^17.7.2" + "@rainbow-me/rainbowkit@^2.2.4": version "2.2.4" resolved "https://registry.yarnpkg.com/@rainbow-me/rainbowkit/-/rainbowkit-2.2.4.tgz#a02b79b8be3838046cf4ef54d2d014ac9301fe3b" @@ -3193,6 +3310,15 @@ "@sentry-internal/browser-utils" "9.13.0" "@sentry/core" "9.13.0" +"@sentry-internal/tracing@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.120.3.tgz#a54e67c39d23576a72b3f349c1a3fae13e27f2f1" + integrity sha512-Ausx+Jw1pAMbIBHStoQ6ZqDZR60PsCByvHdw/jdH9AqPrNE9xlBSf9EwcycvmrzwyKspSLaB52grlje2cRIUMg== + dependencies: + "@sentry/core" "7.120.3" + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + "@sentry/browser@9.13.0": version "9.13.0" resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-9.13.0.tgz#76cf662656c7c7ddfd36081b6e8ba05c385fe823" @@ -3204,11 +3330,40 @@ "@sentry-internal/replay-canvas" "9.13.0" "@sentry/core" "9.13.0" +"@sentry/core@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.120.3.tgz#88ae2f8c242afce59e32bdee7f866d8788e86c03" + integrity sha512-vyy11fCGpkGK3qI5DSXOjgIboBZTriw0YDx/0KyX5CjIjDDNgp5AGgpgFkfZyiYiaU2Ww3iFuKo4wHmBusz1uA== + dependencies: + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + "@sentry/core@9.13.0": version "9.13.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-9.13.0.tgz#3269cab4ba34fa0928f04936ddb82182069cb568" integrity sha512-Zn1Qec5XNkNRE/M5QjL6YJLghETg6P188G/v2OzdHdHIRf0Y58/SnJilu3louF+ogos6kaSqqdMgzqKgZ8tCdg== +"@sentry/integrations@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.120.3.tgz#ea6812b77dea7d0090a5cf85383f154b3bd5b073" + integrity sha512-6i/lYp0BubHPDTg91/uxHvNui427df9r17SsIEXa2eKDwQ9gW2qRx5IWgvnxs2GV/GfSbwcx4swUB3RfEWrXrQ== + dependencies: + "@sentry/core" "7.120.3" + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + localforage "^1.8.1" + +"@sentry/node@^7.0.0": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.120.3.tgz#59a54e1bfccffd28e7d502a5eefea615f07e13f5" + integrity sha512-t+QtekZedEfiZjbkRAk1QWJPnJlFBH/ti96tQhEq7wmlk3VszDXraZvLWZA0P2vXyglKzbWRGkT31aD3/kX+5Q== + dependencies: + "@sentry-internal/tracing" "7.120.3" + "@sentry/core" "7.120.3" + "@sentry/integrations" "7.120.3" + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + "@sentry/react@^9.13.0": version "9.13.0" resolved "https://registry.yarnpkg.com/@sentry/react/-/react-9.13.0.tgz#8dc7b7d05b3e33984dc70162b584dc42c0413495" @@ -3218,6 +3373,18 @@ "@sentry/core" "9.13.0" hoist-non-react-statics "^3.3.2" +"@sentry/types@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.120.3.tgz#25f69ae27f0c8430f1863ad2a9ee9cab7fccf232" + integrity sha512-C4z+3kGWNFJ303FC+FxAd4KkHvxpNFYAFN8iMIgBwJdpIl25KZ8Q/VdGn0MLLUEHNLvjob0+wvwlcRBBNLXOow== + +"@sentry/utils@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.120.3.tgz#0cc891c315d3894eb80c2e7298efd7437e939a5d" + integrity sha512-UDAOQJtJDxZHQ5Nm1olycBIsz2wdGX8SdzyGVHmD8EOQYAeDZQyIlQYohDe9nazdIOQLZCIc3fU0G9gqVLkaGQ== + dependencies: + "@sentry/types" "7.120.3" + "@shuding/opentype.js@1.4.0-beta.0": version "1.4.0-beta.0" resolved "https://registry.yarnpkg.com/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz#5d1e7e9e056f546aad41df1c5043f8f85d39e24b" @@ -3226,7 +3393,7 @@ fflate "^0.7.3" string.prototype.codepointat "^0.2.1" -"@sideway/address@^4.1.5": +"@sideway/address@^4.1.3", "@sideway/address@^4.1.5": version "4.1.5" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== @@ -3621,6 +3788,11 @@ resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276" integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A== +"@tootallnate/quickjs-emscripten@^0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" + integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== + "@tsconfig/node10@^1.0.7": version "1.0.9" resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" @@ -3967,9 +4139,9 @@ cypress "*" "@types/trusted-types@^2.0.2": - version "2.0.3" - resolved "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz" - integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g== + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== "@types/uglify-js@*": version "3.17.1" @@ -4591,7 +4763,7 @@ "@walletconnect/safe-json" "^1.0.2" events "^3.3.0" -"@walletconnect/jsonrpc-types@1.0.4", "@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": +"@walletconnect/jsonrpc-types@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz#ce1a667d79eadf2a2d9d002c152ceb68739c230c" integrity sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ== @@ -4599,6 +4771,14 @@ events "^3.3.0" keyvaluestorage-interface "^1.0.0" +"@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.3.tgz" + integrity sha512-iIQ8hboBl3o5ufmJ8cuduGad0CQm3ZlsHtujv9Eu16xq89q+BG7Nh5VLxxUgmtpnrePgFkTwXirCTkwJH1v+Yw== + dependencies: + keyvaluestorage-interface "^1.0.0" + tslib "1.14.1" + "@walletconnect/jsonrpc-utils@1.0.8", "@walletconnect/jsonrpc-utils@^1.0.6", "@walletconnect/jsonrpc-utils@^1.0.8": version "1.0.8" resolved "https://registry.npmjs.org/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz" @@ -4876,6 +5056,11 @@ aes-js@4.0.0-beta.5: resolved "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz" integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== +agent-base@^7.1.0, agent-base@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" + integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== + agentkeepalive@^4.5.0: version "4.6.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" @@ -4957,6 +5142,13 @@ ansi-regex@^6.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" @@ -5217,6 +5409,13 @@ ast-types-flow@^0.0.8: resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz" integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== +ast-types@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" + integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== + dependencies: + tslib "^2.0.1" + astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" @@ -5306,7 +5505,7 @@ aws4@^1.8.0: resolved "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== -axe-core@^4.10.0: +axe-core@^4.10.0, axe-core@^4.10.3: version "4.10.3" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.3.tgz#04145965ac7894faddbac30861e5d8f11bfd14fc" integrity sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg== @@ -5492,6 +5691,11 @@ base64-js@^1.3.1: resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +basic-ftp@^5.0.2: + version "5.0.5" + resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.0.5.tgz#14a474f5fffecca1f4f406f1c26b18f800225ac0" + integrity sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg== + batch@0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz" @@ -5948,6 +6152,15 @@ chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@^5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8" @@ -6039,7 +6252,30 @@ chownr@^1.1.1: resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== -ci-info@^3.2.0, ci-info@^3.7.0: +chrome-launcher@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-1.2.0.tgz#bba61f558f450aef70bbda1f011c83c31c129302" + integrity sha512-JbuGuBNss258bvGil7FT4HKdC3SC2K7UAEUqiPy3ACS3Yxo3hAW6bvFpCu2HsIJLgTqxgEX6BkujvzZfLpUD0Q== + dependencies: + "@types/node" "*" + escape-string-regexp "^4.0.0" + is-wsl "^2.2.0" + lighthouse-logger "^2.0.1" + +chromium-bidi@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-5.1.0.tgz#8d0e47f7ac9270262df29792318dd5378e983e62" + integrity sha512-9MSRhWRVoRPDG0TgzkHrshFSJJNZzfY5UFqUMuksg7zL1yoZIZ3jLB0YAgHclbiAxPI86pBnwDX1tbzoiV8aFw== + dependencies: + mitt "^3.0.1" + zod "^3.24.1" + +ci-info@^3.2.0: + version "3.8.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + +ci-info@^3.7.0: version "3.9.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== @@ -6161,6 +6397,13 @@ clsx@^1.0.4, clsx@^1.1.1, clsx@^1.2.1: resolved "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" @@ -6168,6 +6411,11 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" @@ -6291,6 +6539,18 @@ confbox@^0.1.7: resolved "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz" integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA== +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + connect-history-api-fallback@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz" @@ -6402,6 +6662,16 @@ cors@^2.8.5: object-assign "^4" vary "^1" +cosmiconfig@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" + integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== + dependencies: + env-paths "^2.2.1" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + crc-32@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" @@ -6445,6 +6715,16 @@ crypto-js@^4.1.1: resolved "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz" integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +csp_evaluator@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/csp_evaluator/-/csp_evaluator-1.1.5.tgz#33788d695b7b539b17d5b6eba494431ce931faff" + integrity sha512-EL/iN9etCTzw/fBnp0/uj0f5BOOGvZut2mzsiiBZ/FdT6gFQCKRO/tmcKOxn5drWZ2Ndm/xBb1SI4zwWbGtmIw== + css-background-parser@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/css-background-parser/-/css-background-parser-0.1.0.tgz#48a17f7fe6d4d4f1bca3177ddf16c5617950741b" @@ -6602,6 +6882,11 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +data-uri-to-buffer@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz#8a58bb67384b261a38ef18bea1810cb01badd28b" + integrity sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw== + data-view-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" @@ -6646,13 +6931,20 @@ dayjs@^1.10.4, dayjs@^1.11.13: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== -debug@2.6.9: +debug@2.6.9, debug@^2.6.9: 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" +debug@4, debug@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + debug@4.3.5: version "4.3.5" resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" @@ -6660,13 +6952,6 @@ debug@4.3.5: dependencies: ms "2.1.2" -debug@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== - dependencies: - ms "^2.1.3" - debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" @@ -6693,6 +6978,11 @@ decamelize@^1.2.0: resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== +decimal.js@^10.4.3: + version "10.5.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.5.0.tgz#0f371c7cf6c4898ce0afb09836db73cd82010f22" + integrity sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw== + decode-uri-component@^0.2.0, decode-uri-component@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz" @@ -6873,6 +7163,15 @@ defu@^6.1.3, defu@^6.1.4: resolved "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz" integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== +degenerator@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-5.0.1.tgz#9403bf297c6dad9a1ece409b37db27954f91f2f5" + integrity sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ== + dependencies: + ast-types "^0.13.4" + escodegen "^2.1.0" + esprima "^4.0.1" + delay@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" @@ -6938,6 +7237,16 @@ detect-node@^2.0.4: resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== +devtools-protocol@0.0.1439962: + version "0.0.1439962" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1439962.tgz#395c5ca1cd83aa451c667056a025f9873c4598c1" + integrity sha512-jJF48UdryzKiWhJ1bLKr7BFWUQCEIT5uCNbDLqkQJBtkFxYzILJH44WN0PDKMIlGDN7Utb8vyUY85C3w4R/t2g== + +devtools-protocol@0.0.1445099: + version "0.0.1445099" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1445099.tgz#fd4c8e5348621e43322f8d5cfd40902a49410197" + integrity sha512-GEuIbCLU2Iu6Sg05GeWS7ksijhOUZIDJD2YBUNRanK7SLKjeci1uxUUomu2VNvygQRuoq/vtnTYrgPZBEiYNMA== + didyoumean@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz" @@ -7079,6 +7388,13 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + dotenv-parse-variables@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/dotenv-parse-variables/-/dotenv-parse-variables-2.0.0.tgz" @@ -7285,6 +7601,18 @@ env-cmd@^10.1.0: commander "^4.0.0" cross-spawn "^7.0.0" +env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + error-stack-parser@^2.0.6: version "2.1.4" resolved "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz" @@ -7536,6 +7864,17 @@ escape-string-regexp@^4.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +escodegen@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" + integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionalDependencies: + source-map "~0.6.1" + eslint-config-prettier@^10.1.5: version "10.1.5" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz#00c18d7225043b6fbce6a665697377998d453782" @@ -7793,7 +8132,7 @@ espree@^9.6.0, espree@^9.6.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" -esprima@^4.0.0: +esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -8197,7 +8536,7 @@ extension-port-stream@^3.0.0: readable-stream "^3.6.2 || ^4.4.2" webextension-polyfill ">=0.10.0 <1.0" -extract-zip@2.0.1: +extract-zip@2.0.1, extract-zip@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz" integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== @@ -8817,6 +9156,15 @@ get-symbol-description@^1.1.0: es-errors "^1.3.0" get-intrinsic "^1.2.6" +get-uri@^6.0.1: + version "6.0.4" + resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.4.tgz#6daaee9e12f9759e19e55ba313956883ef50e0a7" + integrity sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ== + dependencies: + basic-ftp "^5.0.2" + data-uri-to-buffer "^6.0.2" + debug "^4.3.4" + getos@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz" @@ -8980,7 +9328,7 @@ gql.tada@^1.8.2: "@gql.tada/cli-utils" "1.6.3" "@gql.tada/internal" "1.0.8" -graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.6: +graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.6: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -9292,11 +9640,24 @@ http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" +http-link-header@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/http-link-header/-/http-link-header-1.1.3.tgz#b367b7a0ad1cf14027953f31aa1df40bb433da2a" + integrity sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ== + http-parser-js@>=0.5.1: version "0.5.8" resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz" integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== +http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.1: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + http-proxy-middleware@^2.0.3: version "2.0.9" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz#e9e63d68afaa4eee3d147f39149ab84c0c2815ef" @@ -9331,6 +9692,14 @@ http-signature@~1.3.6: jsprim "^2.0.2" sshpk "^1.14.1" +https-proxy-agent@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz" @@ -9397,6 +9766,16 @@ ignore@^7.0.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.4.tgz#a12c70d0f2607c5bf508fb65a40c75f037d7a078" integrity sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A== +image-ssim@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/image-ssim/-/image-ssim-0.2.0.tgz#83b42c7a2e6e4b85505477fe6917f5dbc56420e5" + integrity sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" @@ -9405,6 +9784,14 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-fresh@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" @@ -9459,6 +9846,16 @@ internal-slot@^1.0.4, internal-slot@^1.1.0: hasown "^2.0.2" side-channel "^1.1.0" +intl-messageformat@^10.5.3: + version "10.7.16" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.7.16.tgz#d909f9f9f4ab857fbe681d559b958dd4dd9f665a" + integrity sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/icu-messageformat-parser" "2.11.2" + tslib "^2.8.0" + into-stream@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz" @@ -9467,6 +9864,14 @@ into-stream@^3.1.0: from2 "^2.1.1" p-is-promise "^1.1.0" +ip-address@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" + integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== + dependencies: + jsbn "1.1.0" + sprintf-js "^1.1.3" + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" @@ -9512,6 +9917,11 @@ is-array-buffer@^3.0.2, is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: call-bound "^1.0.3" get-intrinsic "^1.2.6" +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + is-arrayish@^0.3.1: version "0.3.2" resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" @@ -9671,6 +10081,11 @@ is-number@^7.0.0: resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + is-object@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz" @@ -10018,7 +10433,7 @@ jju@^1.4.0: resolved "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz" integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== -joi@^17.13.3, joi@^17.7.0: +joi@^17.13.3: version "17.13.3" resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.3.tgz#0f5cc1169c999b30d344366d384b12d92558bcec" integrity sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA== @@ -10029,11 +10444,32 @@ joi@^17.13.3, joi@^17.7.0: "@sideway/formula" "^3.0.1" "@sideway/pinpoint" "^2.0.0" +joi@^17.7.0: + version "17.9.2" + resolved "https://registry.npmjs.org/joi/-/joi-17.9.2.tgz" + integrity sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.1" + "@sideway/pinpoint" "^2.0.0" + +jpeg-js@^0.4.1, jpeg-js@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa" + integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg== + js-cookie@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz" integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== +js-library-detector@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/js-library-detector/-/js-library-detector-6.7.0.tgz#5075c71fcf835b71133bca13363b91509a39235a" + integrity sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA== + js-sha3@0.8.0: version "0.8.0" resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" @@ -10059,6 +10495,11 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +jsbn@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" + integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" @@ -10084,6 +10525,11 @@ json-buffer@3.0.1: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + json-rpc-engine@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz" @@ -10255,6 +10701,11 @@ lazy-ass@1.6.0, lazy-ass@^1.6.0: resolved "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz" integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== +legacy-javascript@latest: + version "0.0.1" + resolved "https://registry.yarnpkg.com/legacy-javascript/-/legacy-javascript-0.0.1.tgz#6bf2ac6b70b4555d9e4bfe9e4fc81675fede88cf" + integrity sha512-lPyntS4/aS7jpuvOlitZDFifBCb4W8L/3QU0PLbUTUj+zYah8rfVjYic88yG7ZKTxhS5h9iz7duT8oUXKszLhg== + levn@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" @@ -10263,6 +10714,60 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" + +lighthouse-logger@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz#48895f639b61cca89346bb6f47f7403a3895fa02" + integrity sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ== + dependencies: + debug "^2.6.9" + marky "^1.2.2" + +lighthouse-stack-packs@1.12.2: + version "1.12.2" + resolved "https://registry.yarnpkg.com/lighthouse-stack-packs/-/lighthouse-stack-packs-1.12.2.tgz#dbe0ccdbc381784ef176f4f8c2367ac5b077d6ca" + integrity sha512-Ug8feS/A+92TMTCK6yHYLwaFMuelK/hAKRMdldYkMNwv+d9PtWxjXEg6rwKtsUXTADajhdrhXyuNCJ5/sfmPFw== + +lighthouse@^12.6.0: + version "12.6.0" + resolved "https://registry.yarnpkg.com/lighthouse/-/lighthouse-12.6.0.tgz#09cb7a3569236a05c0f31bb0fa52bf03e9fbd040" + integrity sha512-ufYw6dBR0PDEpO4pj45zRStatdTvBSi/LTXgs6ULmadSLTNXklP3XGGGuL7SA9pE/NltGbs5zQOA/ICQao1ywA== + dependencies: + "@paulirish/trace_engine" "0.0.52" + "@sentry/node" "^7.0.0" + axe-core "^4.10.3" + chrome-launcher "^1.1.2" + configstore "^5.0.1" + csp_evaluator "1.1.5" + devtools-protocol "0.0.1445099" + enquirer "^2.3.6" + http-link-header "^1.1.1" + intl-messageformat "^10.5.3" + jpeg-js "^0.4.4" + js-library-detector "^6.7.0" + lighthouse-logger "^2.0.1" + lighthouse-stack-packs "1.12.2" + lodash-es "^4.17.21" + lookup-closest-locale "6.2.0" + metaviewport-parser "0.3.0" + open "^8.4.0" + parse-cache-control "1.0.1" + puppeteer-core "^24.6.1" + robots-parser "^3.0.1" + semver "^5.3.0" + speedline-core "^1.4.3" + third-party-web "^0.26.6" + tldts-icann "^6.1.16" + ws "^7.0.0" + yargs "^17.3.1" + yargs-parser "^21.0.0" + lilconfig@^3.0.0, lilconfig@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" @@ -10363,6 +10868,13 @@ local-pkg@^0.4.3: resolved "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz" integrity sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g== +localforage@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== + dependencies: + lie "3.1.1" + locate-path@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" @@ -10462,6 +10974,11 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" +lookup-closest-locale@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/lookup-closest-locale/-/lookup-closest-locale-6.2.0.tgz#57f665e604fd26f77142d48152015402b607bcf3" + integrity sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ== + loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" @@ -10518,6 +11035,11 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +lru-cache@^7.14.1: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + lz-string@^1.4.4, lz-string@^1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz" @@ -10574,6 +11096,11 @@ map-stream@~0.1.0: resolved "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz" integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== +marky@^1.2.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/marky/-/marky-1.3.0.tgz#422b63b0baf65022f02eda61a238eccdbbc14997" + integrity sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ== + math-intrinsics@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" @@ -10628,6 +11155,11 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +metaviewport-parser@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/metaviewport-parser/-/metaviewport-parser-0.3.0.tgz#6af1e99b5eaf250c049e0af1e84143a39750dea6" + integrity sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ== + methods@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" @@ -10739,6 +11271,11 @@ mipd@0.0.7: resolved "https://registry.yarnpkg.com/mipd/-/mipd-0.0.7.tgz#bb5559e21fa18dc3d9fe1c08902ef14b7ce32fd9" integrity sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg== +mitt@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1" + integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== + mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: version "0.5.3" resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz" @@ -10862,6 +11399,11 @@ negotiator@^1.0.0: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== +netmask@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" + integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== + next-query-params@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/next-query-params/-/next-query-params-5.1.0.tgz#4a013c001b87474188e581aa70298c0be3fa3152" @@ -11193,7 +11735,7 @@ open@^7.4.2: is-docker "^2.0.0" is-wsl "^2.1.1" -open@^8.0.9: +open@^8.0.9, open@^8.4.0: version "8.4.2" resolved "https://registry.npmjs.org/open/-/open-8.4.2.tgz" integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== @@ -11383,6 +11925,28 @@ p-try@^2.0.0: resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pac-proxy-agent@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz#9cfaf33ff25da36f6147a20844230ec92c06e5df" + integrity sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA== + dependencies: + "@tootallnate/quickjs-emscripten" "^0.23.0" + agent-base "^7.1.2" + debug "^4.3.4" + get-uri "^6.0.1" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.6" + pac-resolver "^7.0.1" + socks-proxy-agent "^8.0.5" + +pac-resolver@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-7.0.1.tgz#54675558ea368b64d210fd9c92a640b5f3b8abb6" + integrity sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg== + dependencies: + degenerator "^5.0.0" + netmask "^2.0.2" + package-hash@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz" @@ -11418,6 +11982,11 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-cache-control@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" + integrity sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg== + parse-css-color@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/parse-css-color/-/parse-css-color-0.2.1.tgz#b687a583f2e42e66ffdfce80a570706966e807c9" @@ -11438,6 +12007,16 @@ parse-entities@^2.0.0: is-decimal "^1.0.0" is-hexadecimal "^1.0.0" +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + parse5-htmlparser2-tree-adapter@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz" @@ -11929,6 +12508,11 @@ process@^0.11.10: resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== +progress@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" @@ -11953,6 +12537,20 @@ proxy-addr@^2.0.7, proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-agent@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.5.0.tgz#9e49acba8e4ee234aacb539f89ed9c23d02f232d" + integrity sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A== + dependencies: + agent-base "^7.1.2" + debug "^4.3.4" + http-proxy-agent "^7.0.1" + https-proxy-agent "^7.0.6" + lru-cache "^7.14.1" + pac-proxy-agent "^7.1.0" + proxy-from-env "^1.1.0" + socks-proxy-agent "^8.0.5" + proxy-compare@2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/proxy-compare/-/proxy-compare-2.5.1.tgz#17818e33d1653fbac8c2ec31406bce8a2966f600" @@ -11998,9 +12596,33 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== +puppeteer-core@24.8.2, puppeteer-core@^24.6.1: + version "24.8.2" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-24.8.2.tgz#f3e939e39e001d9933e79d980371e380d9e535c1" + integrity sha512-wNw5cRZOHiFibWc0vdYCYO92QuKTbJ8frXiUfOq/UGJWMqhPoBThTKkV+dJ99YyWfzJ2CfQQ4T1nhhR0h8FlVw== + dependencies: + "@puppeteer/browsers" "2.10.4" + chromium-bidi "5.1.0" + debug "^4.4.0" + devtools-protocol "0.0.1439962" + typed-query-selector "^2.12.0" + ws "^8.18.2" + +puppeteer@^24.8.2: + version "24.8.2" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-24.8.2.tgz#3ee6cfe74e4cc8dc4dd5cb4b553f4d4416df935f" + integrity sha512-Sn6SBPwJ6ASFvQ7knQkR+yG7pcmr4LfXzmoVp3NR0xXyBbPhJa8a8ybtb6fnw1g/DD/2t34//yirubVczko37w== + dependencies: + "@puppeteer/browsers" "2.10.4" + chromium-bidi "5.1.0" + cosmiconfig "^9.0.0" + devtools-protocol "0.0.1439962" + puppeteer-core "24.8.2" + typed-query-selector "^2.12.0" + qrcode@1.5.3: version "1.5.3" - resolved "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.3.tgz#03afa80912c0dccf12bc93f615a535aad1066170" integrity sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg== dependencies: dijkstrajs "^1.0.1" @@ -12553,6 +13175,11 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +robots-parser@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/robots-parser/-/robots-parser-3.0.1.tgz#3d8a3cdfa8ac240cbb062a4bd16fcc0e0fb9ed23" + integrity sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ== + rollup@^4.20.0, rollup@^4.30.1: version "4.39.0" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.39.0.tgz#9dc1013b70c0e2cb70ef28350142e9b81b3f640c" @@ -12741,7 +13368,7 @@ selfsigned@^2.1.1: dependencies: node-forge "^1" -semver@^5.6.0: +semver@^5.3.0, semver@^5.6.0: version "5.7.2" resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== @@ -13066,6 +13693,11 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + socket.io-client@^4.5.1: version "4.8.1" resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.8.1.tgz#1941eca135a5490b94281d0323fe2a35f6f291cb" @@ -13093,6 +13725,23 @@ sockjs@^0.3.24: uuid "^8.3.2" websocket-driver "^0.7.4" +socks-proxy-agent@^8.0.5: + version "8.0.5" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz#b9cdb4e7e998509d7659d689ce7697ac21645bee" + integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw== + dependencies: + agent-base "^7.1.2" + debug "^4.3.4" + socks "^2.8.3" + +socks@^2.8.3: + version "2.8.4" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.4.tgz#07109755cdd4da03269bda4725baa061ab56d5cc" + integrity sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ== + dependencies: + ip-address "^9.0.5" + smart-buffer "^4.2.0" + sonic-boom@^2.2.1: version "2.8.0" resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz" @@ -13196,6 +13845,15 @@ speed-measure-webpack-plugin@1.4.2: dependencies: chalk "^4.1.0" +speedline-core@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/speedline-core/-/speedline-core-1.4.3.tgz#4d6e7276e2063c2d36a375cb25a523ac73475319" + integrity sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog== + dependencies: + "@types/node" "*" + image-ssim "^0.2.0" + jpeg-js "^0.4.1" + split-on-first@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz" @@ -13225,6 +13883,11 @@ split@^1.0.1: dependencies: through "2" +sprintf-js@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" + integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" @@ -13631,7 +14294,7 @@ superstruct@^2.0.2: resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-2.0.2.tgz#3f6d32fbdc11c357deff127d591a39b996300c54" integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== -supports-color@^5.5.0: +supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -13730,7 +14393,7 @@ tapable@^2.0.0: resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tar-fs@2.1.3, tar-fs@^2.0.0, tar-fs@^3.0.4: +tar-fs@2.1.3, tar-fs@^2.0.0, tar-fs@^3.0.4, tar-fs@^3.0.8: version "2.1.3" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.3.tgz#fb3b8843a26b6f13a08e606f7922875eb1fbbf92" integrity sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg== @@ -13843,6 +14506,11 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" +third-party-web@^0.26.6, third-party-web@latest: + version "0.26.6" + resolved "https://registry.yarnpkg.com/third-party-web/-/third-party-web-0.26.6.tgz#9c315f1756defb1dca7f1180cb84c721810bff2f" + integrity sha512-GsjP92xycMK8qLTcQCacgzvffYzEqe29wyz3zdKVXlfRD5Kz1NatCTOZEeDaSd6uCZXvGd2CNVtQ89RNIhJWvA== + thread-stream@^0.15.1: version "0.15.2" resolved "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz" @@ -13922,6 +14590,18 @@ tippy.js@^6.3.1: dependencies: "@popperjs/core" "^2.9.0" +tldts-core@^6.1.86: + version "6.1.86" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.86.tgz#a93e6ed9d505cb54c542ce43feb14c73913265d8" + integrity sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA== + +tldts-icann@^6.1.16: + version "6.1.86" + resolved "https://registry.yarnpkg.com/tldts-icann/-/tldts-icann-6.1.86.tgz#7ac14d54bcc134ccf78f63d9b505cbadd24ee52b" + integrity sha512-NFxmRT2lAEMcCOBgeZ0NuM0zsK/xgmNajnY6n4S1mwAKocft2s2ise1O3nQxrH3c+uY6hgHUV9GGNVp7tUE4Sg== + dependencies: + tldts-core "^6.1.86" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz" @@ -14054,7 +14734,12 @@ tslib@2.4.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.6.0, tslib@^2.8.0: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0: + version "2.5.3" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz" + integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== + +tslib@^2.0.1, tslib@^2.6.0, tslib@^2.8.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -14172,6 +14857,11 @@ typed-array-length@^1.0.7: possible-typed-array-names "^1.0.0" reflect.getprototypeof "^1.0.6" +typed-query-selector@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/typed-query-selector/-/typed-query-selector-2.12.0.tgz#92b65dbc0a42655fccf4aeb1a08b1dddce8af5f2" + integrity sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg== + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" @@ -14324,6 +15014,13 @@ unicode-trie@^2.0.0: pako "^0.2.5" tiny-inflate "^1.0.0" +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + universal-user-agent@^6.0.0: version "6.0.1" resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz" @@ -15028,16 +15725,21 @@ ws@8.18.1: resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== -ws@^7.5.1, ws@^7.5.10: +ws@^7.0.0, ws@^7.5.1, ws@^7.5.10: version "7.5.10" resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -ws@^8.13.0, ws@^8.5.0: +ws@^8.13.0, ws@^8.18.2, ws@^8.5.0: version "8.18.2" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a" integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + xmlhttprequest-ssl@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz#e9e8023b3f29ef34b97a859f584c5e6c61418e23" @@ -15076,7 +15778,7 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^21.1.1: +yargs-parser@^21.0.0, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== @@ -15103,7 +15805,7 @@ yargs@^15.0.2, yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^17.0.0: +yargs@^17.0.0, yargs@^17.3.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== @@ -15178,11 +15880,16 @@ zod-to-json-schema@^3.24.1: resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz#d1095440b147fb7c2093812a53c54df8d5df50a3" integrity sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g== -zod@^3.23.8, zod@^3.24.2, zod@^3.24.3: +zod@^3.23.8, zod@^3.24.1, zod@^3.24.2: version "3.24.4" resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.4.tgz#e2e2cca5faaa012d76e527d0d36622e0a90c315f" integrity sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg== +zod@^3.24.3: + version "3.24.3" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.3.tgz#1f40f750a05e477396da64438e0e1c0995dafd87" + integrity sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg== + zustand@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/zustand/-/zustand-5.0.0.tgz#71f8aaecf185592a3ba2743d7516607361899da9" From 6bd16fb9a6ccb1683f0016072db43b4465d4ac51 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 12 May 2025 20:50:32 +0000 Subject: [PATCH 002/103] Fix module import --- packages/arb-token-bridge-ui/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/arb-token-bridge-ui/package.json b/packages/arb-token-bridge-ui/package.json index 734a657473..2597c39733 100644 --- a/packages/arb-token-bridge-ui/package.json +++ b/packages/arb-token-bridge-ui/package.json @@ -3,6 +3,7 @@ "version": "3.3.0", "license": "Apache-2.0", "private": true, + "type": "module", "dependencies": { "@apollo/client": "^3.13.8", "@arbitrum/sdk": "^4.0.3", From fb0beb6340fb258e03afd231c48ad02dc7d5d0ae Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 16:10:56 +0000 Subject: [PATCH 003/103] Run lighthouse during workflow --- .../workflows/generate-lighthouse-diff.yml | 57 ++++++++++++ packages/arb-token-bridge-ui/package.json | 3 +- .../tests/perf/switchNetwork.js | 63 ------------- packages/scripts/package.json | 3 +- .../executeLighthouse.ts | 68 ++++++++++++++ .../src/generateLighthouseReport/index.ts | 49 ++++++++++ .../parseLighthouseReport.ts | 89 +++++++++++++++++++ packages/scripts/src/index.ts | 8 ++ 8 files changed, 274 insertions(+), 66 deletions(-) create mode 100644 .github/workflows/generate-lighthouse-diff.yml delete mode 100644 packages/arb-token-bridge-ui/tests/perf/switchNetwork.js create mode 100644 packages/scripts/src/generateLighthouseReport/executeLighthouse.ts create mode 100644 packages/scripts/src/generateLighthouseReport/index.ts create mode 100644 packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml new file mode 100644 index 0000000000..eefeb43ac4 --- /dev/null +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -0,0 +1,57 @@ +name: Run Lighthouse Diff + +on: + pull_request: + branches: ["master"] + types: + - opened + - reopened + - synchronize + # we skip ci for draft PRs + # https://github.com/reviewdog/action-eslint/issues/29#issuecomment-985939887 + - ready_for_review + workflow_dispatch: + merge_group: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + add_orbit_chain: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ref: ${{ github.ref_name }} + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + cache: 'yarn' + + - name: Install node_modules + uses: OffchainLabs/actions/node-modules/install@main + + - name: Build scripts + run: yarn workspace scripts build + + - name: Run generateLighthouseDiff script + run: yarn workspace scripts generate-lighthouse-diff + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + + # - name: Create comment + # uses: peter-evans/create-or-update-comment@v4 + # with: + # issue-number: ${{ github.event.number }} + # body: | + # This is a multi-line test comment + # - With GitHub **Markdown** :sparkles: + # - Created by [create-or-update-comment][1] + + # [1]: https://github.com/peter-evans/create-or-update-comment \ No newline at end of file diff --git a/packages/arb-token-bridge-ui/package.json b/packages/arb-token-bridge-ui/package.json index 2597c39733..fe6fc48160 100644 --- a/packages/arb-token-bridge-ui/package.json +++ b/packages/arb-token-bridge-ui/package.json @@ -3,7 +3,6 @@ "version": "3.3.0", "license": "Apache-2.0", "private": true, - "type": "module", "dependencies": { "@apollo/client": "^3.13.8", "@arbitrum/sdk": "^4.0.3", @@ -65,7 +64,7 @@ "start": "next start", "test": "vitest --config vitest.config.ts --watch", "test:ci": "vitest --config vitest.config.ts --run", - "test:perf": "ts-node --project ./tests/perf/tsconfig.json ./tests/perf/switchNetwork.ts", + "test:perf": "ts-node ./tests/perf/switchNetwork.mts", "lint": "tsc && eslint", "lint:fix": "tsc && eslint --quiet --fix", "prettier:format": "prettier --config-precedence file-override --write \"src/**/*.{tsx,ts,scss,md,json}\"", diff --git a/packages/arb-token-bridge-ui/tests/perf/switchNetwork.js b/packages/arb-token-bridge-ui/tests/perf/switchNetwork.js deleted file mode 100644 index 9b5ae6ee86..0000000000 --- a/packages/arb-token-bridge-ui/tests/perf/switchNetwork.js +++ /dev/null @@ -1,63 +0,0 @@ -import puppeteer from 'puppeteer' -import { writeFileSync } from 'fs' -import { startFlow, desktopConfig } from 'lighthouse' - -// Setup the browser and Lighthouse. -const browser = await puppeteer.launch({ headless: false }) -const page = await browser.newPage() - -const flow = await startFlow(page, { - config: desktopConfig -}) - -await flow.navigate( - 'http://localhost:3000/?destinationChain=arbitrum-one&sourceChain=ethereum' -) - -await flow.startTimespan() - -// Accept ToS -await page.click('[aria-label="Agree to Terms and Continue"]') - -// Type amount -const input = await page.waitForSelector('[aria-label="Amount input"]') -await input?.type('2') -await page.waitForSelector('[aria-label="Route arbitrum"]') - -// Switch network -await page.click('[aria-label="Switch Networks"]') -await page.waitForSelector("[aria-label='From Arbitrum One']") - -// Open token selection -await page.click("[aria-label='Select Token']") -const tokenInput = await page.waitForSelector( - "[placeholder='Search by token name, symbol, or address']" -) -await tokenInput?.type('USDC') -await page.click('[aria-label="Select USDC.e"]') -await page.waitForSelector("xpath///button[contains(., 'USDC.e')]") - -// Open chain selection -await page.click("[aria-label='From Arbitrum One']") -const chainInput = await page.waitForSelector( - '[placeholder="Search a network name"]' -) -await chainInput?.type('Xai') - -const xaiRow = await page.waitForSelector('[aria-label="Switch to Xai"]') -await xaiRow?.click() -await page.waitForSelector("[aria-label='From Xai']") - -await flow.endTimespan() -await flow.snapshot() - -// Get the comprehensive flow report. -writeFileSync('report.html', await flow.generateReport()) -// Save results as JSON. -writeFileSync( - 'flow-result.json', - JSON.stringify(await flow.createFlowResult(), null, 2) -) - -// Cleanup. -await browser.close() diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 2564914c93..ae9ca99910 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -9,7 +9,8 @@ "test": "vitest", "coverage": "vitest run --coverage", "start": "node dist/index.js", - "add-orbit-chain": "node dist/scripts.cjs.js add-orbit-chain" + "add-orbit-chain": "node dist/scripts.cjs.js add-orbit-chain", + "generate-lighthouse-diff": "node dist/scripts.cjs.js generate-lighthouse-report" }, "author": "", "license": "ISC", diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts new file mode 100644 index 0000000000..1e5945edd0 --- /dev/null +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -0,0 +1,68 @@ +import puppeteer from "puppeteer"; +import * as core from "@actions/core"; +import { startFlow, desktopConfig } from "lighthouse"; + +export async function executeLighthouseFlow() { + try { + core.startGroup("Lighthouse execution"); + // Setup the browser and Lighthouse. + const browser = await puppeteer.launch({ headless: false }); + const page = await browser.newPage(); + + const flow = await startFlow(page, { + config: desktopConfig, + }); + + // Exact URL, we don't want redirection that would change the result + await flow.navigate( + "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" + ); + + await flow.startTimespan(); + + // Accept ToS + await page.click('[aria-label="Agree to Terms and Continue"]'); + + // Type amount + const input = await page.waitForSelector('[aria-label="Amount input"]'); + await input?.type("2"); + await page.waitForSelector('[aria-label="Route arbitrum"]'); + + // Switch network + await page.click('[aria-label="Switch Networks"]'); + await page.waitForSelector("[aria-label='From Arbitrum One']"); + + // Open token selection + await page.click("[aria-label='Select Token']"); + const tokenInput = await page.waitForSelector( + "[placeholder='Search by token name, symbol, or address']" + ); + await tokenInput?.type("USDC"); + await page.click('[aria-label="Select USDC.e"]'); + await page.waitForSelector("xpath///button[contains(., 'USDC.e')]"); + + // Open chain selection + await page.click("[aria-label='From Arbitrum One']"); + const chainInput = await page.waitForSelector( + '[placeholder="Search a network name"]' + ); + await chainInput?.type("Xai"); + + const xaiRow = await page.waitForSelector('[aria-label="Switch to Xai"]'); + await xaiRow?.click(); + await page.waitForSelector("[aria-label='From Xai']"); + + await flow.endTimespan(); + await flow.snapshot(); + + // Get the comprehensive flow report. + // writeFileSync("report.html", await flow.generateReport()); + // Save results as JSON. + // const file = JSON.stringify(await flow.createFlowResult(), null, 2); + const file = await flow.createFlowResult(); + // Cleanup. + await browser.close(); + core.endGroup(); + return file; + } catch (error) {} +} diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts new file mode 100644 index 0000000000..ea4eef2a4d --- /dev/null +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -0,0 +1,49 @@ +import * as core from "@actions/core"; +import * as github from "@actions/github"; +import { executeLighthouseFlow } from "./executeLighthouse"; +import { parseLighthouseReport } from "./parseLighthouseReport"; + +export async function generateLighthouseReport() { + try { + const report = await executeLighthouseFlow(); + + if (!report) { + core.setFailed("Report wasn't generated"); + return; + } + + core.startGroup("Parse lighthouse report"); + const parsedReport = parseLighthouseReport(report); + core.endGroup(); + + core.startGroup("Post comment"); + const octokit = github.getOctokit(core.getInput("token")); + + const { data: comment } = await octokit.rest.issues.createComment({ + ...github.context.repo, + issue_number: github.context.issue.number, + body: `
+🗼 Click to expand performance result + +
+ +| Name | Result | +|------------|---------| +| Performance | ${parsedReport[0].performance} | +| Accessibility | ${parsedReport[0].accessibility} | +| Best Practices | ${parsedReport[0]["best_practices"]} | +| SEO | ${parsedReport[0].seo} | +| First Contentful Paint | ${parsedReport[0].fcp.displayValue} | +| Largest Contentful Paint | ${parsedReport[0].cls.displayValue} | +| Total Blocking Time | ${parsedReport[0].tbt.displayValue} | +| Cumulative Layout Shift | ${parsedReport[0].cls.displayValue} | +| Speed Index | ${parsedReport[0].speed.displayValue} | + +
`, + }); + core.info( + `Created comment id '${comment.id}' on issue '${github.context.issue.number}'.` + ); + core.endGroup(); + } catch (error) {} +} diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts new file mode 100644 index 0000000000..13e06d6e37 --- /dev/null +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -0,0 +1,89 @@ +import { FlowResult, Result } from "lighthouse"; + +type Metric = { + /** Number from 0 to 1 */ + score: number; + numericValue: string; + displayValue: string; + scoringOptions: { + p10: number; + median: number; + }; +}; +type NavigationResult = { + fcp: Metric; + lcp: Metric; + tbt: Metric; + cls: Metric; + speed: Metric; + performance: number; + accessibility: number; + best_practices: number; + seo: number; +}; +type TimespanResult = { + performance: { + total: number; + tbt: Metric; + cls: Metric; + inp: Metric; + }; + best_practices: number; +}; +type SnapshotResult = { + performance: number; + accessibility: number; + best_practices: number; + seo: Result; +}; + +function parseNavigationResult( + navigationResult: FlowResult.Step +): NavigationResult { + const fcp = navigationResult.lhr.audits["first-contentful-paint"]; + const lcp = navigationResult.lhr.audits["largest-contentful-paint"]; + const tbt = navigationResult.lhr.audits["total-blocking-time"]; + const cls = navigationResult.lhr.audits["first-contentful-paint"]; + const speed = navigationResult.lhr.audits["speed-index"]; + + return { + fcp: { + score: fcp.score!, + displayValue: fcp.displayValue!, + numericValue: fcp.numericUnit!, + scoringOptions: fcp.scoringOptions!, + }, + lcp: { + score: lcp.score!, + displayValue: lcp.displayValue!, + numericValue: lcp.numericUnit!, + scoringOptions: lcp.scoringOptions!, + }, + tbt: { + score: tbt.score!, + displayValue: tbt.displayValue!, + numericValue: tbt.numericUnit!, + scoringOptions: tbt.scoringOptions!, + }, + cls: { + score: cls.score!, + displayValue: cls.displayValue!, + numericValue: cls.numericUnit!, + scoringOptions: cls.scoringOptions!, + }, + speed: { + score: speed.score!, + displayValue: speed.displayValue!, + numericValue: speed.numericUnit!, + scoringOptions: speed.scoringOptions!, + }, + performance: navigationResult.lhr.categories.performance.score!, + accessibility: navigationResult.lhr.categories.accessibility.score!, + best_practices: navigationResult.lhr.categories["best-practices"].score!, + seo: navigationResult.lhr.categories.seo.score!, + }; +} + +export function parseLighthouseReport(report: FlowResult): [NavigationResult] { + return [parseNavigationResult(report.steps[0])]; +} diff --git a/packages/scripts/src/index.ts b/packages/scripts/src/index.ts index 11742ce657..cdb1e87362 100644 --- a/packages/scripts/src/index.ts +++ b/packages/scripts/src/index.ts @@ -1,6 +1,7 @@ #!/usr/bin/env node import { Command } from "commander"; import { addOrbitChain } from "./addOrbitChain"; +import { generateLighthouseReport } from "./generateLighthouseReport"; const program = new Command(); @@ -19,6 +20,13 @@ program }); }); +program + .command("generate-lighthouse-report") + .description("Run lighthouse diff") + .action(() => { + generateLighthouseReport(); + }); + // Add more commands here as needed, for example: // program // .command('some-other-script') From 355c10b8288df8d9942503ae197dfac263a91a9b Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 16:12:48 +0000 Subject: [PATCH 004/103] Update job name --- .github/workflows/generate-lighthouse-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index eefeb43ac4..b96d56d237 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -18,7 +18,7 @@ concurrency: cancel-in-progress: true jobs: - add_orbit_chain: + generate_lighthouse_diff: runs-on: ubuntu-latest steps: - name: Checkout repository From 99d1077c35562798c3abfe270f0dd7a091159e59 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 16:14:07 +0000 Subject: [PATCH 005/103] update input --- .github/workflows/generate-lighthouse-diff.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index b96d56d237..d2fb9f87e5 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -25,7 +25,6 @@ jobs: uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} - ref: ${{ github.ref_name }} - name: Setup Node.js uses: actions/setup-node@v3 From 544ddd6321f5247e45aad19fe87894a7290b4291 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 16:45:28 +0000 Subject: [PATCH 006/103] Fix build --- packages/arb-token-bridge-ui/package.json | 2 -- packages/scripts/package.json | 2 ++ packages/scripts/vite.config.ts | 4 ++- yarn.lock | 43 ++++++++++++++++++----- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/packages/arb-token-bridge-ui/package.json b/packages/arb-token-bridge-ui/package.json index fe6fc48160..b07ca300d8 100644 --- a/packages/arb-token-bridge-ui/package.json +++ b/packages/arb-token-bridge-ui/package.json @@ -119,13 +119,11 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-zustand-rules": "https://github.com/OffchainLabs/eslint-plugin-zustand-rules", "happy-dom": "^17.4.4", - "lighthouse": "^12.6.0", "patch-package": "^8.0.0", "postcss": "^8.5.3", "postinstall-postinstall": "^2.1.0", "prettier": "^2.7.1", "prettier-plugin-tailwindcss": "^0.1.11", - "puppeteer": "^24.8.2", "satori": "^0.12.2", "start-server-and-test": "^2.0.11", "tailwindcss": "^3.4.16", diff --git a/packages/scripts/package.json b/packages/scripts/package.json index ae9ca99910..d4b51eda7b 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -23,7 +23,9 @@ "commander": "^12.1.0", "ethers": "^5.7.2", "file-type": "^19.6.0", + "lighthouse": "^12.6.0", "mime-types": "^2.1.35", + "puppeteer": "^24.9.0", "sharp": "0.32.6", "zod": "^3.23.8" }, diff --git a/packages/scripts/vite.config.ts b/packages/scripts/vite.config.ts index 3a0e811e39..3a8416d51e 100644 --- a/packages/scripts/vite.config.ts +++ b/packages/scripts/vite.config.ts @@ -17,11 +17,13 @@ export default defineConfig({ "commander", "sharp", "path", + "puppeteer", + "lighthouse", ], }, }, optimizeDeps: { - exclude: ["sharp"], + exclude: ["sharp", "puppeteer", "lighthouse"], }, resolve: { alias: { diff --git a/yarn.lock b/yarn.lock index 14008eb5bf..9d1b9fb8f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2991,6 +2991,19 @@ tar-fs "^3.0.8" yargs "^17.7.2" +"@puppeteer/browsers@2.10.5": + version "2.10.5" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.10.5.tgz#dddb8f8716ae6364f6f2d31125e76f311dd4a49d" + integrity sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w== + dependencies: + debug "^4.4.1" + extract-zip "^2.0.1" + progress "^2.0.3" + proxy-agent "^6.5.0" + semver "^7.7.2" + tar-fs "^3.0.8" + yargs "^17.7.2" + "@rainbow-me/rainbowkit@^2.2.4": version "2.2.4" resolved "https://registry.yarnpkg.com/@rainbow-me/rainbowkit/-/rainbowkit-2.2.4.tgz#a02b79b8be3838046cf4ef54d2d014ac9301fe3b" @@ -6959,7 +6972,7 @@ debug@^3.1.0, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0, debug@^4.4.1: version "4.4.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== @@ -12596,7 +12609,19 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== -puppeteer-core@24.8.2, puppeteer-core@^24.6.1: +puppeteer-core@24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-24.9.0.tgz#fc489e83bf65db1dc72e53a78140ee567efd847e" + integrity sha512-HFdCeH/wx6QPz8EncafbCqJBqaCG1ENW75xg3cLFMRUoqZDgByT6HSueiumetT2uClZxwqj0qS4qMVZwLHRHHw== + dependencies: + "@puppeteer/browsers" "2.10.5" + chromium-bidi "5.1.0" + debug "^4.4.1" + devtools-protocol "0.0.1439962" + typed-query-selector "^2.12.0" + ws "^8.18.2" + +puppeteer-core@^24.6.1: version "24.8.2" resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-24.8.2.tgz#f3e939e39e001d9933e79d980371e380d9e535c1" integrity sha512-wNw5cRZOHiFibWc0vdYCYO92QuKTbJ8frXiUfOq/UGJWMqhPoBThTKkV+dJ99YyWfzJ2CfQQ4T1nhhR0h8FlVw== @@ -12608,16 +12633,16 @@ puppeteer-core@24.8.2, puppeteer-core@^24.6.1: typed-query-selector "^2.12.0" ws "^8.18.2" -puppeteer@^24.8.2: - version "24.8.2" - resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-24.8.2.tgz#3ee6cfe74e4cc8dc4dd5cb4b553f4d4416df935f" - integrity sha512-Sn6SBPwJ6ASFvQ7knQkR+yG7pcmr4LfXzmoVp3NR0xXyBbPhJa8a8ybtb6fnw1g/DD/2t34//yirubVczko37w== +puppeteer@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-24.9.0.tgz#1d3f805e0170ca481b637a47c71a09b815594dae" + integrity sha512-L0pOtALIx8rgDt24Y+COm8X52v78gNtBOW6EmUcEPci0TYD72SAuaXKqasRIx4JXxmg2Tkw5ySKcpPOwN8xXnQ== dependencies: - "@puppeteer/browsers" "2.10.4" + "@puppeteer/browsers" "2.10.5" chromium-bidi "5.1.0" cosmiconfig "^9.0.0" devtools-protocol "0.0.1439962" - puppeteer-core "24.8.2" + puppeteer-core "24.9.0" typed-query-selector "^2.12.0" qrcode@1.5.3: @@ -13378,7 +13403,7 @@ semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.7.1: +semver@^7.0.0, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.7.1, semver@^7.7.2: version "7.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== From f7981fab9bd1c2e4b885ce1a615a4235c2dd0c2f Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 16:54:30 +0000 Subject: [PATCH 007/103] Add debug --- .../src/generateLighthouseReport/executeLighthouse.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 1e5945edd0..5ff59fdc15 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -64,5 +64,8 @@ export async function executeLighthouseFlow() { await browser.close(); core.endGroup(); return file; - } catch (error) {} + } catch (error) { + console.log(error); + core.setFailed(error); + } } From a18b7d9cdfbf6aa7d25bab528747d8b4fcb3560d Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 16:56:26 +0000 Subject: [PATCH 008/103] Install chromium --- packages/scripts/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/scripts/package.json b/packages/scripts/package.json index d4b51eda7b..7005c02e51 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -10,7 +10,9 @@ "coverage": "vitest run --coverage", "start": "node dist/index.js", "add-orbit-chain": "node dist/scripts.cjs.js add-orbit-chain", - "generate-lighthouse-diff": "node dist/scripts.cjs.js generate-lighthouse-report" + "generate-lighthouse-diff": "node dist/scripts.cjs.js generate-lighthouse-report", + "postinstall": "yarn install:chromium", + "install:chromium": "npx @puppeteer/browsers install chrome@$npm_package_config_chromeVersion --path $npm_package_config_chromePath" }, "author": "", "license": "ISC", From 0e99be8bbb6ad07225b29d78acf9c656f2b98889 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 17:07:38 +0000 Subject: [PATCH 009/103] Update package.json config --- packages/scripts/package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 7005c02e51..beb727956c 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -42,5 +42,9 @@ "typescript": "^5.0.0", "vite": "^5.4.18", "vitest": "^0.34.0" + }, + "config": { + "chromeVersion": "128.0.6613.137", + "chromePath": "node_modules/.cache/synpress" } } From 8cfa7f494280cdd369829e75b369fd49b78f9ffe Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 17:12:54 +0000 Subject: [PATCH 010/103] Update args --- .github/workflows/generate-lighthouse-diff.yml | 1 + .../src/generateLighthouseReport/executeLighthouse.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index d2fb9f87e5..4308ff2297 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -19,6 +19,7 @@ concurrency: jobs: generate_lighthouse_diff: + name: "Generate lighthouse diff" runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 5ff59fdc15..4d170869f7 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -6,7 +6,10 @@ export async function executeLighthouseFlow() { try { core.startGroup("Lighthouse execution"); // Setup the browser and Lighthouse. - const browser = await puppeteer.launch({ headless: false }); + const browser = await puppeteer.launch({ + headless: false, + args: ["--no-sandbox"], + }); const page = await browser.newPage(); const flow = await startFlow(page, { From 60e1fd07e3985e864338e1aade29c6b087b6a933 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 17:23:52 +0000 Subject: [PATCH 011/103] Update chromium version --- packages/scripts/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/scripts/package.json b/packages/scripts/package.json index beb727956c..05bd5ef5d8 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -44,7 +44,7 @@ "vitest": "^0.34.0" }, "config": { - "chromeVersion": "128.0.6613.137", - "chromePath": "node_modules/.cache/synpress" + "chromeVersion": "136.0.7103.94", + "chromePath": "node_modules/.cache/puppeteer" } } From 16e08722817aeaeb8a9e420ae7bacaffb0a9e5d9 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 17:28:09 +0000 Subject: [PATCH 012/103] Install dependencies --- .github/workflows/generate-lighthouse-diff.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 4308ff2297..10ad497570 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -39,6 +39,20 @@ jobs: - name: Build scripts run: yarn workspace scripts build + - name: Install linux dependencies + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends -y \ + fluxbox \ + xvfb + + - name: Run xvfb and fluxbox + run: | + Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & + fluxbox & + env: + DISPLAY: :0.0 + - name: Run generateLighthouseDiff script run: yarn workspace scripts generate-lighthouse-diff env: From 87f7f0f8bc251506cc48cd23860239330ec344c9 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 17:31:42 +0000 Subject: [PATCH 013/103] WIP --- packages/scripts/package.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 05bd5ef5d8..6d26b703c3 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -11,8 +11,7 @@ "start": "node dist/index.js", "add-orbit-chain": "node dist/scripts.cjs.js add-orbit-chain", "generate-lighthouse-diff": "node dist/scripts.cjs.js generate-lighthouse-report", - "postinstall": "yarn install:chromium", - "install:chromium": "npx @puppeteer/browsers install chrome@$npm_package_config_chromeVersion --path $npm_package_config_chromePath" + "postinstall": "npx puppeteer browsers install chrome" }, "author": "", "license": "ISC", @@ -42,9 +41,5 @@ "typescript": "^5.0.0", "vite": "^5.4.18", "vitest": "^0.34.0" - }, - "config": { - "chromeVersion": "136.0.7103.94", - "chromePath": "node_modules/.cache/puppeteer" } } From 5a25b16a59ee855d82d8c201f1f5b9a54292dbc2 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 17:41:38 +0000 Subject: [PATCH 014/103] Debug --- packages/scripts/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 6d26b703c3..944ca77fda 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -10,7 +10,7 @@ "coverage": "vitest run --coverage", "start": "node dist/index.js", "add-orbit-chain": "node dist/scripts.cjs.js add-orbit-chain", - "generate-lighthouse-diff": "node dist/scripts.cjs.js generate-lighthouse-report", + "generate-lighthouse-diff": "DEBUG=puppeteer:browsers:launcher node dist/scripts.cjs.js generate-lighthouse-report", "postinstall": "npx puppeteer browsers install chrome" }, "author": "", From b75153d11e662e2426fabebfb0ea3a09ff2b2498 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 17:45:25 +0000 Subject: [PATCH 015/103] Cleanup --- .github/workflows/generate-lighthouse-diff.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 10ad497570..ef42b075d1 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -22,6 +22,22 @@ jobs: name: "Generate lighthouse diff" runs-on: ubuntu-latest steps: + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be + with: + # this might remove tools that are actually needed, + # if set to "true" but frees about 6 GB + tool-cache: false + + # all of these default to true, but feel free to set to + # "false" if necessary for your workflow + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: false + swap-storage: true + - name: Checkout repository uses: actions/checkout@v4 with: From 8a32e7f4d13442e89a22dd6254d5b6b5aea18438 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 17:57:19 +0000 Subject: [PATCH 016/103] WIP --- packages/scripts/package.json | 3 +-- .../src/generateLighthouseReport/executeLighthouse.ts | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 944ca77fda..d4b51eda7b 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -10,8 +10,7 @@ "coverage": "vitest run --coverage", "start": "node dist/index.js", "add-orbit-chain": "node dist/scripts.cjs.js add-orbit-chain", - "generate-lighthouse-diff": "DEBUG=puppeteer:browsers:launcher node dist/scripts.cjs.js generate-lighthouse-report", - "postinstall": "npx puppeteer browsers install chrome" + "generate-lighthouse-diff": "node dist/scripts.cjs.js generate-lighthouse-report" }, "author": "", "license": "ISC", diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 4d170869f7..05114a7a88 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -1,7 +1,9 @@ import puppeteer from "puppeteer"; import * as core from "@actions/core"; import { startFlow, desktopConfig } from "lighthouse"; +import { join, resolve } from "path"; +const workspaceRoot = resolve(process.cwd(), "../.."); export async function executeLighthouseFlow() { try { core.startGroup("Lighthouse execution"); @@ -9,6 +11,10 @@ export async function executeLighthouseFlow() { const browser = await puppeteer.launch({ headless: false, args: ["--no-sandbox"], + executablePath: join( + workspaceRoot, + "node_modules/.cache/synpress/chrome/linux-128.0.6613.137/chrome-linux64/chrome" + ), }); const page = await browser.newPage(); From b691f72489b3f5036602d17cb10d5d3c67c1e3f0 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 18:28:10 +0000 Subject: [PATCH 017/103] Debug --- .github/workflows/generate-lighthouse-diff.yml | 14 +++++++------- .../generateLighthouseReport/executeLighthouse.ts | 7 ++++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index ef42b075d1..5243984b62 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -62,15 +62,15 @@ jobs: fluxbox \ xvfb - - name: Run xvfb and fluxbox - run: | - Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & - fluxbox & - env: - DISPLAY: :0.0 + # - name: Run xvfb and fluxbox + # run: | + # Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & + # fluxbox & + # env: + # DISPLAY: :0.0 - name: Run generateLighthouseDiff script - run: yarn workspace scripts generate-lighthouse-diff + run: xvfb-run --auto-servernum --server-args='-screen 0 1366x768x24' yarn workspace scripts generate-lighthouse-diff env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 05114a7a88..a7c44d32cf 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -2,6 +2,7 @@ import puppeteer from "puppeteer"; import * as core from "@actions/core"; import { startFlow, desktopConfig } from "lighthouse"; import { join, resolve } from "path"; +import { config } from "../../../../package.json"; const workspaceRoot = resolve(process.cwd(), "../.."); export async function executeLighthouseFlow() { @@ -11,9 +12,13 @@ export async function executeLighthouseFlow() { const browser = await puppeteer.launch({ headless: false, args: ["--no-sandbox"], + // "node_modules/.cache/synpress/chrome/linux-128.0.6613.137/chrome-linux64/chrome" executablePath: join( workspaceRoot, - "node_modules/.cache/synpress/chrome/linux-128.0.6613.137/chrome-linux64/chrome" + config.chromePath, + "/chrome/linux-", + config.chromeVersion, + "/chrome-linux64/chrome" ), }); const page = await browser.newPage(); From dd3295dc929b9115e133c10c290f96a16802c371 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 18:32:34 +0000 Subject: [PATCH 018/103] Update path --- .../src/generateLighthouseReport/executeLighthouse.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index a7c44d32cf..fc7c56ef78 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -16,9 +16,8 @@ export async function executeLighthouseFlow() { executablePath: join( workspaceRoot, config.chromePath, - "/chrome/linux-", - config.chromeVersion, - "/chrome-linux64/chrome" + `/chrome/linux-${config.chromeVersion}`, + "chrome-linux64/chrome" ), }); const page = await browser.newPage(); From 67e0e029655640372d9bb9934d9b4dd3741c24f3 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 18:43:14 +0000 Subject: [PATCH 019/103] Add build and start --- .github/workflows/generate-lighthouse-diff.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 5243984b62..533be5edea 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -55,6 +55,9 @@ jobs: - name: Build scripts run: yarn workspace scripts build + - name: Build bridge + run: yarn build + - name: Install linux dependencies run: | sudo apt-get update @@ -62,12 +65,8 @@ jobs: fluxbox \ xvfb - # - name: Run xvfb and fluxbox - # run: | - # Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & - # fluxbox & - # env: - # DISPLAY: :0.0 + - name: Start server + run: yarn start - name: Run generateLighthouseDiff script run: xvfb-run --auto-servernum --server-args='-screen 0 1366x768x24' yarn workspace scripts generate-lighthouse-diff From dff139c401c511bb6eaf322d2366955add8868fb Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 18:50:28 +0000 Subject: [PATCH 020/103] Update environment variables --- .../workflows/generate-lighthouse-diff.yml | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 533be5edea..4a1966995b 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -55,9 +55,6 @@ jobs: - name: Build scripts run: yarn workspace scripts build - - name: Build bridge - run: yarn build - - name: Install linux dependencies run: | sudo apt-get update @@ -65,14 +62,26 @@ jobs: fluxbox \ xvfb - - name: Start server - run: yarn start + - name: Run xvfb and fluxbox + run: | + Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & + fluxbox & + env: + DISPLAY: :0.0 - name: Run generateLighthouseDiff script - run: xvfb-run --auto-servernum --server-args='-screen 0 1366x768x24' yarn workspace scripts generate-lighthouse-diff + run: yarn workspace scripts generate-lighthouse-diff env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + DISPLAY: :0.0 + TEST_FILE: ${{ matrix.test.file }} + SKIP_METAMASK_SETUP: true + CYPRESS_RECORD_VIDEO: ${{ matrix.test.recordVideo }} + PRIVATE_KEY_CUSTOM: ${{ secrets.E2E_PRIVATE_KEY }} + PRIVATE_KEY_USER: ${{ secrets.E2E_PRIVATE_KEY_USER }} + PRIVATE_KEY_CCTP: ${{ secrets.E2E_PRIVATE_KEY_CCTP }} + NEXT_PUBLIC_IS_E2E_TEST: true # - name: Create comment # uses: peter-evans/create-or-update-comment@v4 From 945d7f6b962f9ad4e04ef030165b5079bc9493a8 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 18:56:40 +0000 Subject: [PATCH 021/103] Update env --- .../workflows/generate-lighthouse-diff.yml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 4a1966995b..97ea3d47d8 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -55,6 +55,18 @@ jobs: - name: Build scripts run: yarn workspace scripts build + - name: Build and start bridge + run: yarn build && yarn start + env: + NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + + - name: Install linux dependencies run: | sudo apt-get update @@ -75,13 +87,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} DISPLAY: :0.0 - TEST_FILE: ${{ matrix.test.file }} - SKIP_METAMASK_SETUP: true - CYPRESS_RECORD_VIDEO: ${{ matrix.test.recordVideo }} - PRIVATE_KEY_CUSTOM: ${{ secrets.E2E_PRIVATE_KEY }} - PRIVATE_KEY_USER: ${{ secrets.E2E_PRIVATE_KEY_USER }} - PRIVATE_KEY_CCTP: ${{ secrets.E2E_PRIVATE_KEY_CCTP }} - NEXT_PUBLIC_IS_E2E_TEST: true # - name: Create comment # uses: peter-evans/create-or-update-comment@v4 From 0649c8242ff9ecb9da4e88b46ad20a5216c64836 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 19:14:50 +0000 Subject: [PATCH 022/103] Start server in the background --- .github/workflows/generate-lighthouse-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 97ea3d47d8..56b73fc41b 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -56,7 +56,7 @@ jobs: run: yarn workspace scripts build - name: Build and start bridge - run: yarn build && yarn start + run: yarn build && yarn start & env: NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} From f8fcfef1d53b1f42822bf036d21e3a3b677b38ec Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 19:23:44 +0000 Subject: [PATCH 023/103] Add poll --- .../workflows/generate-lighthouse-diff.yml | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 56b73fc41b..03228b3562 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -55,8 +55,8 @@ jobs: - name: Build scripts run: yarn workspace scripts build - - name: Build and start bridge - run: yarn build && yarn start & + - name: Build the bridge + run: yarn build env: NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} @@ -66,7 +66,31 @@ jobs: NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - + - name: Start the bridge + run: yarn start & + env: + NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + + - name: Wait for server to be ready + run: | + for i in {1..20}; do + if curl -s http://localhost:3000 > /dev/null; then + echo "Server is up!" + break + fi + echo "Waiting for server..." + sleep 1 + done + + echo "Server did not start in time." + exit 1 + - name: Install linux dependencies run: | sudo apt-get update From 0bb44265f518bba1900024db26697470cc363e8b Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 19:38:03 +0000 Subject: [PATCH 024/103] Update script --- .github/workflows/generate-lighthouse-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 03228b3562..12fa872d43 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -82,7 +82,7 @@ jobs: for i in {1..20}; do if curl -s http://localhost:3000 > /dev/null; then echo "Server is up!" - break + exit 0 fi echo "Waiting for server..." sleep 1 From da20eea88f8744705713e9de586cab04e0e4a228 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 26 May 2025 19:49:24 +0000 Subject: [PATCH 025/103] WIP --- .github/workflows/generate-lighthouse-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 12fa872d43..95ac6a9af2 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -80,7 +80,7 @@ jobs: - name: Wait for server to be ready run: | for i in {1..20}; do - if curl -s http://localhost:3000 > /dev/null; then + if curl -s http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge > /dev/null; then echo "Server is up!" exit 0 fi From af5cadfb081f8f397ec84817fe5575c9db008f2a Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 12:31:56 +0200 Subject: [PATCH 026/103] WIP --- .../scripts/src/generateLighthouseReport/executeLighthouse.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index fc7c56ef78..0d526fd18f 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -31,6 +31,9 @@ export async function executeLighthouseFlow() { "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" ); + const screenshot = page.screenshot(); + core.setOutput("image", JSON.stringify(screenshot, null, 2)); + await flow.startTimespan(); // Accept ToS From 8a3ba4320b569ab1c70585fb2f4f9c49779899d7 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 12:45:10 +0200 Subject: [PATCH 027/103] WIP --- .../workflows/generate-lighthouse-diff.yml | 30 ++++---- .../executeLighthouse.ts | 76 +++++++++---------- .../src/generateLighthouseReport/index.ts | 76 +++++++++---------- 3 files changed, 91 insertions(+), 91 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 95ac6a9af2..08beb1fca5 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -22,21 +22,21 @@ jobs: name: "Generate lighthouse diff" runs-on: ubuntu-latest steps: - - name: Free Disk Space (Ubuntu) - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be - with: - # this might remove tools that are actually needed, - # if set to "true" but frees about 6 GB - tool-cache: false - - # all of these default to true, but feel free to set to - # "false" if necessary for your workflow - android: true - dotnet: true - haskell: true - large-packages: true - docker-images: false - swap-storage: true + # - name: Free Disk Space (Ubuntu) + # uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be + # with: + # # this might remove tools that are actually needed, + # # if set to "true" but frees about 6 GB + # tool-cache: false + + # # all of these default to true, but feel free to set to + # # "false" if necessary for your workflow + # android: true + # dotnet: true + # haskell: true + # large-packages: true + # docker-images: false + # swap-storage: true - name: Checkout repository uses: actions/checkout@v4 diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 0d526fd18f..98f9cb5615 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -34,52 +34,52 @@ export async function executeLighthouseFlow() { const screenshot = page.screenshot(); core.setOutput("image", JSON.stringify(screenshot, null, 2)); - await flow.startTimespan(); + // await flow.startTimespan(); - // Accept ToS - await page.click('[aria-label="Agree to Terms and Continue"]'); + // // Accept ToS + // await page.click('[aria-label="Agree to Terms and Continue"]'); - // Type amount - const input = await page.waitForSelector('[aria-label="Amount input"]'); - await input?.type("2"); - await page.waitForSelector('[aria-label="Route arbitrum"]'); + // // Type amount + // const input = await page.waitForSelector('[aria-label="Amount input"]'); + // await input?.type("2"); + // await page.waitForSelector('[aria-label="Route arbitrum"]'); - // Switch network - await page.click('[aria-label="Switch Networks"]'); - await page.waitForSelector("[aria-label='From Arbitrum One']"); + // // Switch network + // await page.click('[aria-label="Switch Networks"]'); + // await page.waitForSelector("[aria-label='From Arbitrum One']"); - // Open token selection - await page.click("[aria-label='Select Token']"); - const tokenInput = await page.waitForSelector( - "[placeholder='Search by token name, symbol, or address']" - ); - await tokenInput?.type("USDC"); - await page.click('[aria-label="Select USDC.e"]'); - await page.waitForSelector("xpath///button[contains(., 'USDC.e')]"); + // // Open token selection + // await page.click("[aria-label='Select Token']"); + // const tokenInput = await page.waitForSelector( + // "[placeholder='Search by token name, symbol, or address']" + // ); + // await tokenInput?.type("USDC"); + // await page.click('[aria-label="Select USDC.e"]'); + // await page.waitForSelector("xpath///button[contains(., 'USDC.e')]"); - // Open chain selection - await page.click("[aria-label='From Arbitrum One']"); - const chainInput = await page.waitForSelector( - '[placeholder="Search a network name"]' - ); - await chainInput?.type("Xai"); + // // Open chain selection + // await page.click("[aria-label='From Arbitrum One']"); + // const chainInput = await page.waitForSelector( + // '[placeholder="Search a network name"]' + // ); + // await chainInput?.type("Xai"); - const xaiRow = await page.waitForSelector('[aria-label="Switch to Xai"]'); - await xaiRow?.click(); - await page.waitForSelector("[aria-label='From Xai']"); + // const xaiRow = await page.waitForSelector('[aria-label="Switch to Xai"]'); + // await xaiRow?.click(); + // await page.waitForSelector("[aria-label='From Xai']"); - await flow.endTimespan(); - await flow.snapshot(); + // await flow.endTimespan(); + // await flow.snapshot(); - // Get the comprehensive flow report. - // writeFileSync("report.html", await flow.generateReport()); - // Save results as JSON. - // const file = JSON.stringify(await flow.createFlowResult(), null, 2); - const file = await flow.createFlowResult(); - // Cleanup. - await browser.close(); - core.endGroup(); - return file; + // // Get the comprehensive flow report. + // // writeFileSync("report.html", await flow.generateReport()); + // // Save results as JSON. + // // const file = JSON.stringify(await flow.createFlowResult(), null, 2); + // const file = await flow.createFlowResult(); + // // Cleanup. + // await browser.close(); + // core.endGroup(); + // return file; } catch (error) { console.log(error); core.setFailed(error); diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index ea4eef2a4d..0043203178 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -7,43 +7,43 @@ export async function generateLighthouseReport() { try { const report = await executeLighthouseFlow(); - if (!report) { - core.setFailed("Report wasn't generated"); - return; - } - - core.startGroup("Parse lighthouse report"); - const parsedReport = parseLighthouseReport(report); - core.endGroup(); - - core.startGroup("Post comment"); - const octokit = github.getOctokit(core.getInput("token")); - - const { data: comment } = await octokit.rest.issues.createComment({ - ...github.context.repo, - issue_number: github.context.issue.number, - body: `
-🗼 Click to expand performance result - -
- -| Name | Result | -|------------|---------| -| Performance | ${parsedReport[0].performance} | -| Accessibility | ${parsedReport[0].accessibility} | -| Best Practices | ${parsedReport[0]["best_practices"]} | -| SEO | ${parsedReport[0].seo} | -| First Contentful Paint | ${parsedReport[0].fcp.displayValue} | -| Largest Contentful Paint | ${parsedReport[0].cls.displayValue} | -| Total Blocking Time | ${parsedReport[0].tbt.displayValue} | -| Cumulative Layout Shift | ${parsedReport[0].cls.displayValue} | -| Speed Index | ${parsedReport[0].speed.displayValue} | - -
`, - }); - core.info( - `Created comment id '${comment.id}' on issue '${github.context.issue.number}'.` - ); - core.endGroup(); + // if (!report) { + // core.setFailed("Report wasn't generated"); + // throw new Error("Report wasn't generated"); + // } + + // core.startGroup("Parse lighthouse report"); + // const parsedReport = parseLighthouseReport(report); + // core.endGroup(); + + // core.startGroup("Post comment"); + // const octokit = github.getOctokit(core.getInput("token")); + + // const { data: comment } = await octokit.rest.issues.createComment({ + // ...github.context.repo, + // issue_number: github.context.issue.number, + // body: `
+ // 🗼 Click to expand performance result + + //
+ + // | Name | Result | + // |------------|---------| + // | Performance | ${parsedReport[0].performance} | + // | Accessibility | ${parsedReport[0].accessibility} | + // | Best Practices | ${parsedReport[0]["best_practices"]} | + // | SEO | ${parsedReport[0].seo} | + // | First Contentful Paint | ${parsedReport[0].fcp.displayValue} | + // | Largest Contentful Paint | ${parsedReport[0].cls.displayValue} | + // | Total Blocking Time | ${parsedReport[0].tbt.displayValue} | + // | Cumulative Layout Shift | ${parsedReport[0].cls.displayValue} | + // | Speed Index | ${parsedReport[0].speed.displayValue} | + + //
`, + // }); + // core.info( + // `Created comment id '${comment.id}' on issue '${github.context.issue.number}'.` + // ); + // core.endGroup(); } catch (error) {} } From ce12781e4f967c3ebf64a45907585c0828c536bf Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 12:50:30 +0200 Subject: [PATCH 028/103] WIP --- .../src/generateLighthouseReport/executeLighthouse.ts | 5 +++-- packages/scripts/src/generateLighthouseReport/index.ts | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 98f9cb5615..105d72441c 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -31,8 +31,9 @@ export async function executeLighthouseFlow() { "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" ); - const screenshot = page.screenshot(); - core.setOutput("image", JSON.stringify(screenshot, null, 2)); + const screenshot = await page.screenshot({ encoding: "base64" }); + return screenshot; + // core.setOutput("image", JSON.stringify(screenshot, null, 2)); // await flow.startTimespan(); diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 0043203178..6d04182c38 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -7,6 +7,8 @@ export async function generateLighthouseReport() { try { const report = await executeLighthouseFlow(); + console.log(report); + core.setOutput("img", report); // if (!report) { // core.setFailed("Report wasn't generated"); // throw new Error("Report wasn't generated"); From abf65f1016598e082c4904b1e2b7a7e073caea82 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 13:01:50 +0200 Subject: [PATCH 029/103] WIP --- .../src/generateLighthouseReport/executeLighthouse.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 105d72441c..12bbe928ed 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -12,6 +12,7 @@ export async function executeLighthouseFlow() { const browser = await puppeteer.launch({ headless: false, args: ["--no-sandbox"], + dumpio: true, // "node_modules/.cache/synpress/chrome/linux-128.0.6613.137/chrome-linux64/chrome" executablePath: join( workspaceRoot, @@ -31,6 +32,10 @@ export async function executeLighthouseFlow() { "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" ); + await new Promise((resolve) => { + setTimeout(() => resolve(void 0), 5_000); + }); + const screenshot = await page.screenshot({ encoding: "base64" }); return screenshot; // core.setOutput("image", JSON.stringify(screenshot, null, 2)); From f732c6907a6794089209c151226fa1b301f8580c Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 13:07:32 +0200 Subject: [PATCH 030/103] WIP --- .../src/generateLighthouseReport/executeLighthouse.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 12bbe928ed..6783002c5f 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -1,4 +1,4 @@ -import puppeteer from "puppeteer"; +import puppeteer, { BoundingBox } from "puppeteer"; import * as core from "@actions/core"; import { startFlow, desktopConfig } from "lighthouse"; import { join, resolve } from "path"; @@ -36,7 +36,11 @@ export async function executeLighthouseFlow() { setTimeout(() => resolve(void 0), 5_000); }); - const screenshot = await page.screenshot({ encoding: "base64" }); + const body = await page.$("body"); + const screenshot = await page.screenshot({ + encoding: "base64", + clip: (await body!.boundingBox()) as BoundingBox, + }); return screenshot; // core.setOutput("image", JSON.stringify(screenshot, null, 2)); From ea811480fc430ff0a792727a0b9add66b79d5e91 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 13:13:20 +0200 Subject: [PATCH 031/103] WIP --- .../executeLighthouse.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 6783002c5f..122bb96575 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -22,24 +22,28 @@ export async function executeLighthouseFlow() { ), }); const page = await browser.newPage(); + await page.goto( + "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" + ); const flow = await startFlow(page, { config: desktopConfig, }); // Exact URL, we don't want redirection that would change the result - await flow.navigate( - "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" - ); + // await flow.navigate( + // "https://www.google.com" + // // "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" + // ); + // await page.setViewport({ width: 810, height: 415 }); + // await page.goto("https://www.google.com"); await new Promise((resolve) => { setTimeout(() => resolve(void 0), 5_000); - }); + // }); - const body = await page.$("body"); const screenshot = await page.screenshot({ encoding: "base64", - clip: (await body!.boundingBox()) as BoundingBox, }); return screenshot; // core.setOutput("image", JSON.stringify(screenshot, null, 2)); From 35479212227af73fc3cc75ac598afda29d58f354 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 13:16:55 +0200 Subject: [PATCH 032/103] WIP --- .../src/generateLighthouseReport/executeLighthouse.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 122bb96575..3d40538e75 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -30,17 +30,9 @@ export async function executeLighthouseFlow() { config: desktopConfig, }); - // Exact URL, we don't want redirection that would change the result - // await flow.navigate( - // "https://www.google.com" - // // "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" - // ); - // await page.setViewport({ width: 810, height: 415 }); - // await page.goto("https://www.google.com"); - await new Promise((resolve) => { setTimeout(() => resolve(void 0), 5_000); - // }); + }); const screenshot = await page.screenshot({ encoding: "base64", From f4ee77166e89649ebdf8c72325094b676d94fe3b Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 14:27:16 +0200 Subject: [PATCH 033/103] Debug --- .../src/generateLighthouseReport/executeLighthouse.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 3d40538e75..47d50dff46 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -23,12 +23,13 @@ export async function executeLighthouseFlow() { }); const page = await browser.newPage(); await page.goto( - "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" + // "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" + "https://www.google.com/" ); - const flow = await startFlow(page, { - config: desktopConfig, - }); + // const flow = await startFlow(page, { + // config: desktopConfig, + // }); await new Promise((resolve) => { setTimeout(() => resolve(void 0), 5_000); From 4c171a1378f319cb01c0a4a90cffc965b539566a Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 14:50:41 +0200 Subject: [PATCH 034/103] Debug --- .../executeLighthouse.ts | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 47d50dff46..2be2b7ee84 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -5,6 +5,14 @@ import { join, resolve } from "path"; import { config } from "../../../../package.json"; const workspaceRoot = resolve(process.cwd(), "../.."); +// "node_modules/.cache/synpress/chrome/linux-128.0.6613.137/chrome-linux64/chrome" +const chromePath = join( + workspaceRoot, + config.chromePath, + `/chrome/linux-${config.chromeVersion}`, + "chrome-linux64/chrome" +); + export async function executeLighthouseFlow() { try { core.startGroup("Lighthouse execution"); @@ -13,28 +21,19 @@ export async function executeLighthouseFlow() { headless: false, args: ["--no-sandbox"], dumpio: true, - // "node_modules/.cache/synpress/chrome/linux-128.0.6613.137/chrome-linux64/chrome" - executablePath: join( - workspaceRoot, - config.chromePath, - `/chrome/linux-${config.chromeVersion}`, - "chrome-linux64/chrome" - ), + executablePath: chromePath, }); const page = await browser.newPage(); + await page.goto( - // "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" - "https://www.google.com/" + "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge", + { waitUntil: "networkidle0", timeout: 60_000 } ); // const flow = await startFlow(page, { // config: desktopConfig, // }); - await new Promise((resolve) => { - setTimeout(() => resolve(void 0), 5_000); - }); - const screenshot = await page.screenshot({ encoding: "base64", }); From 64a00a70457ef35c5792c87791137628e1d62614 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 15:11:22 +0200 Subject: [PATCH 035/103] Debug --- packages/scripts/package.json | 2 +- .../executeLighthouse.ts | 121 +++++++++--------- .../src/generateLighthouseReport/index.ts | 14 +- 3 files changed, 75 insertions(+), 62 deletions(-) diff --git a/packages/scripts/package.json b/packages/scripts/package.json index d4b51eda7b..52ce9f79a4 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "Collection of utility scripts", "main": "dist/index.js", - "type": "commonjs", + "type": "module", "scripts": { "build": "vite build", "test": "vitest", diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 2be2b7ee84..633eb223de 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -1,19 +1,8 @@ import puppeteer, { BoundingBox } from "puppeteer"; import * as core from "@actions/core"; import { startFlow, desktopConfig } from "lighthouse"; -import { join, resolve } from "path"; -import { config } from "../../../../package.json"; -const workspaceRoot = resolve(process.cwd(), "../.."); -// "node_modules/.cache/synpress/chrome/linux-128.0.6613.137/chrome-linux64/chrome" -const chromePath = join( - workspaceRoot, - config.chromePath, - `/chrome/linux-${config.chromeVersion}`, - "chrome-linux64/chrome" -); - -export async function executeLighthouseFlow() { +export async function executeLighthouseFlow(chromePath?: string) { try { core.startGroup("Lighthouse execution"); // Setup the browser and Lighthouse. @@ -21,73 +10,87 @@ export async function executeLighthouseFlow() { headless: false, args: ["--no-sandbox"], dumpio: true, - executablePath: chromePath, + ...(chromePath ? { executablePath: chromePath } : {}), }); const page = await browser.newPage(); + await page.setViewport({ width: 1366, height: 768 }); + + // await page.goto( + // "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge", + // { waitUntil: "networkidle0", timeout: 60_000 } + // ); - await page.goto( - "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge", - { waitUntil: "networkidle0", timeout: 60_000 } + const flow = await startFlow(page, { + config: desktopConfig, + }); + + await flow.navigate( + "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" ); - // const flow = await startFlow(page, { - // config: desktopConfig, + // const screenshot = await page.screenshot({ + // encoding: "base64", + // fullPage: true, // }); - - const screenshot = await page.screenshot({ - encoding: "base64", - }); - return screenshot; + // return screenshot; // core.setOutput("image", JSON.stringify(screenshot, null, 2)); - // await flow.startTimespan(); + await flow.startTimespan(); - // // Accept ToS - // await page.click('[aria-label="Agree to Terms and Continue"]'); + // Accept ToS + const tosButton = await page.waitForSelector( + '[aria-label="Agree to Terms and Continue"]' + ); + await tosButton?.click(); - // // Type amount - // const input = await page.waitForSelector('[aria-label="Amount input"]'); - // await input?.type("2"); - // await page.waitForSelector('[aria-label="Route arbitrum"]'); + // Type amount + const input = await page.waitForSelector('[aria-label="Amount input"]'); + await input?.type("2"); + await page.waitForSelector('[aria-label="Route arbitrum"]'); - // // Switch network - // await page.click('[aria-label="Switch Networks"]'); - // await page.waitForSelector("[aria-label='From Arbitrum One']"); + // Switch network + await page.click('[aria-label="Switch Networks"]'); + await page.waitForSelector("[aria-label='From Arbitrum One']"); - // // Open token selection - // await page.click("[aria-label='Select Token']"); - // const tokenInput = await page.waitForSelector( - // "[placeholder='Search by token name, symbol, or address']" - // ); - // await tokenInput?.type("USDC"); - // await page.click('[aria-label="Select USDC.e"]'); - // await page.waitForSelector("xpath///button[contains(., 'USDC.e')]"); + // Open token selection + await page.click("[aria-label='Select Token']"); + const tokenInput = await page.waitForSelector( + "[placeholder='Search by token name, symbol, or address']" + ); + await tokenInput?.type("USDC"); + const usdcButton = await page.waitForSelector( + '[aria-label="Select USDC.e"]' + ); + await usdcButton?.click(); + await page.waitForSelector("xpath///button[contains(., 'USDC.e')]"); - // // Open chain selection - // await page.click("[aria-label='From Arbitrum One']"); - // const chainInput = await page.waitForSelector( - // '[placeholder="Search a network name"]' - // ); - // await chainInput?.type("Xai"); + // Open chain selection + await page.click("[aria-label='From Arbitrum One']"); + const chainInput = await page.waitForSelector( + '[placeholder="Search a network name"]' + ); + await chainInput?.type("Xai"); - // const xaiRow = await page.waitForSelector('[aria-label="Switch to Xai"]'); - // await xaiRow?.click(); - // await page.waitForSelector("[aria-label='From Xai']"); + const xaiRow = await page.waitForSelector('[aria-label="Switch to Xai"]'); + await xaiRow?.click(); + await page.waitForSelector("[aria-label='From Xai']"); - // await flow.endTimespan(); - // await flow.snapshot(); + await flow.endTimespan(); + await flow.snapshot(); - // // Get the comprehensive flow report. - // // writeFileSync("report.html", await flow.generateReport()); - // // Save results as JSON. - // // const file = JSON.stringify(await flow.createFlowResult(), null, 2); + // Get the comprehensive flow report. + // writeFileSync("report.html", await flow.generateReport()); + // Save results as JSON. + const file = JSON.stringify(await flow.createFlowResult(), null, 2); // const file = await flow.createFlowResult(); - // // Cleanup. - // await browser.close(); - // core.endGroup(); + // Cleanup. + await browser.close(); + core.endGroup(); // return file; } catch (error) { console.log(error); core.setFailed(error); } } + +executeLighthouseFlow(); diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 6d04182c38..537bad5e78 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -2,10 +2,20 @@ import * as core from "@actions/core"; import * as github from "@actions/github"; import { executeLighthouseFlow } from "./executeLighthouse"; import { parseLighthouseReport } from "./parseLighthouseReport"; - +import { join, resolve } from "path"; +import { config } from "../../../../package.json"; + +const workspaceRoot = resolve(process.cwd(), "../.."); +// "node_modules/.cache/synpress/chrome/linux-128.0.6613.137/chrome-linux64/chrome" +const chromePath = join( + workspaceRoot, + config.chromePath, + `/chrome/linux-${config.chromeVersion}`, + "chrome-linux64/chrome" +); export async function generateLighthouseReport() { try { - const report = await executeLighthouseFlow(); + const report = await executeLighthouseFlow(chromePath); console.log(report); core.setOutput("img", report); From 5cf104dfb8c632c3fa03fda917bb8eb8ea3072a4 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 15:16:56 +0200 Subject: [PATCH 036/103] Debug --- packages/scripts/package.json | 2 +- .../executeLighthouse.ts | 147 ++++++++---------- 2 files changed, 70 insertions(+), 79 deletions(-) diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 52ce9f79a4..d4b51eda7b 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "Collection of utility scripts", "main": "dist/index.js", - "type": "module", + "type": "commonjs", "scripts": { "build": "vite build", "test": "vitest", diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 633eb223de..768e14f0f3 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -1,96 +1,87 @@ -import puppeteer, { BoundingBox } from "puppeteer"; +import puppeteer from "puppeteer"; import * as core from "@actions/core"; import { startFlow, desktopConfig } from "lighthouse"; export async function executeLighthouseFlow(chromePath?: string) { - try { - core.startGroup("Lighthouse execution"); - // Setup the browser and Lighthouse. - const browser = await puppeteer.launch({ - headless: false, - args: ["--no-sandbox"], - dumpio: true, - ...(chromePath ? { executablePath: chromePath } : {}), - }); - const page = await browser.newPage(); - await page.setViewport({ width: 1366, height: 768 }); + core.startGroup("Lighthouse execution"); + // Setup the browser and Lighthouse. + const browser = await puppeteer.launch({ + headless: false, + args: ["--no-sandbox"], + dumpio: true, + ...(chromePath ? { executablePath: chromePath } : {}), + }); + const page = await browser.newPage(); + await page.setViewport({ width: 1366, height: 768 }); - // await page.goto( - // "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge", - // { waitUntil: "networkidle0", timeout: 60_000 } - // ); + // await page.goto( + // "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge", + // { waitUntil: "networkidle0", timeout: 60_000 } + // ); - const flow = await startFlow(page, { - config: desktopConfig, - }); + const flow = await startFlow(page, { + config: desktopConfig, + }); - await flow.navigate( - "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" - ); + await flow.navigate( + "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" + ); - // const screenshot = await page.screenshot({ - // encoding: "base64", - // fullPage: true, - // }); - // return screenshot; - // core.setOutput("image", JSON.stringify(screenshot, null, 2)); + // const screenshot = await page.screenshot({ + // encoding: "base64", + // fullPage: true, + // }); + // return screenshot; + // core.setOutput("image", JSON.stringify(screenshot, null, 2)); - await flow.startTimespan(); + await flow.startTimespan(); - // Accept ToS - const tosButton = await page.waitForSelector( - '[aria-label="Agree to Terms and Continue"]' - ); - await tosButton?.click(); + // Accept ToS + const tosButton = await page.waitForSelector( + '[aria-label="Agree to Terms and Continue"]' + ); + await tosButton?.click(); - // Type amount - const input = await page.waitForSelector('[aria-label="Amount input"]'); - await input?.type("2"); - await page.waitForSelector('[aria-label="Route arbitrum"]'); + // Type amount + const input = await page.waitForSelector('[aria-label="Amount input"]'); + await input?.type("2"); + await page.waitForSelector('[aria-label="Route arbitrum"]'); - // Switch network - await page.click('[aria-label="Switch Networks"]'); - await page.waitForSelector("[aria-label='From Arbitrum One']"); + // Switch network + await page.click('[aria-label="Switch Networks"]'); + await page.waitForSelector("[aria-label='From Arbitrum One']"); - // Open token selection - await page.click("[aria-label='Select Token']"); - const tokenInput = await page.waitForSelector( - "[placeholder='Search by token name, symbol, or address']" - ); - await tokenInput?.type("USDC"); - const usdcButton = await page.waitForSelector( - '[aria-label="Select USDC.e"]' - ); - await usdcButton?.click(); - await page.waitForSelector("xpath///button[contains(., 'USDC.e')]"); + // Open token selection + await page.click("[aria-label='Select Token']"); + const tokenInput = await page.waitForSelector( + "[placeholder='Search by token name, symbol, or address']" + ); + await tokenInput?.type("USDC"); + const usdcButton = await page.waitForSelector('[aria-label="Select USDC.e"]'); + await usdcButton?.click(); + await page.waitForSelector("xpath///button[contains(., 'USDC.e')]"); - // Open chain selection - await page.click("[aria-label='From Arbitrum One']"); - const chainInput = await page.waitForSelector( - '[placeholder="Search a network name"]' - ); - await chainInput?.type("Xai"); + // Open chain selection + await page.click("[aria-label='From Arbitrum One']"); + const chainInput = await page.waitForSelector( + '[placeholder="Search a network name"]' + ); + await chainInput?.type("Xai"); - const xaiRow = await page.waitForSelector('[aria-label="Switch to Xai"]'); - await xaiRow?.click(); - await page.waitForSelector("[aria-label='From Xai']"); + const xaiRow = await page.waitForSelector('[aria-label="Switch to Xai"]'); + await xaiRow?.click(); + await page.waitForSelector("[aria-label='From Xai']"); - await flow.endTimespan(); - await flow.snapshot(); + await flow.endTimespan(); + await flow.snapshot(); - // Get the comprehensive flow report. - // writeFileSync("report.html", await flow.generateReport()); - // Save results as JSON. - const file = JSON.stringify(await flow.createFlowResult(), null, 2); - // const file = await flow.createFlowResult(); - // Cleanup. - await browser.close(); - core.endGroup(); - // return file; - } catch (error) { - console.log(error); - core.setFailed(error); - } + // Get the comprehensive flow report. + // writeFileSync("report.html", await flow.generateReport()); + // Save results as JSON. + const file = JSON.stringify(await flow.createFlowResult(), null, 2); + // const file = await flow.createFlowResult(); + // Cleanup. + await browser.close(); + core.endGroup(); + // return file; } - -executeLighthouseFlow(); From 51c21c9d6fc0bed9c1ebdb553ed8fa228f5f64d5 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 16:46:17 +0200 Subject: [PATCH 037/103] Test --- .../executeLighthouse.ts | 5 -- .../src/generateLighthouseReport/index.ts | 64 +++++++++---------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 768e14f0f3..d9615ae16b 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -14,11 +14,6 @@ export async function executeLighthouseFlow(chromePath?: string) { const page = await browser.newPage(); await page.setViewport({ width: 1366, height: 768 }); - // await page.goto( - // "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge", - // { waitUntil: "networkidle0", timeout: 60_000 } - // ); - const flow = await startFlow(page, { config: desktopConfig, }); diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 537bad5e78..00c70cfeb8 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -15,10 +15,10 @@ const chromePath = join( ); export async function generateLighthouseReport() { try { - const report = await executeLighthouseFlow(chromePath); + // const report = await executeLighthouseFlow(chromePath); - console.log(report); - core.setOutput("img", report); + // console.log(report); + // core.setOutput("img", report); // if (!report) { // core.setFailed("Report wasn't generated"); // throw new Error("Report wasn't generated"); @@ -28,34 +28,34 @@ export async function generateLighthouseReport() { // const parsedReport = parseLighthouseReport(report); // core.endGroup(); - // core.startGroup("Post comment"); - // const octokit = github.getOctokit(core.getInput("token")); - - // const { data: comment } = await octokit.rest.issues.createComment({ - // ...github.context.repo, - // issue_number: github.context.issue.number, - // body: `
- // 🗼 Click to expand performance result - - //
- - // | Name | Result | - // |------------|---------| - // | Performance | ${parsedReport[0].performance} | - // | Accessibility | ${parsedReport[0].accessibility} | - // | Best Practices | ${parsedReport[0]["best_practices"]} | - // | SEO | ${parsedReport[0].seo} | - // | First Contentful Paint | ${parsedReport[0].fcp.displayValue} | - // | Largest Contentful Paint | ${parsedReport[0].cls.displayValue} | - // | Total Blocking Time | ${parsedReport[0].tbt.displayValue} | - // | Cumulative Layout Shift | ${parsedReport[0].cls.displayValue} | - // | Speed Index | ${parsedReport[0].speed.displayValue} | - - //
`, - // }); - // core.info( - // `Created comment id '${comment.id}' on issue '${github.context.issue.number}'.` - // ); - // core.endGroup(); + core.startGroup("Post comment"); + const octokit = github.getOctokit(core.getInput("token")); + + const { data: comment } = await octokit.rest.issues.createComment({ + ...github.context.repo, + issue_number: github.context.issue.number, + body: `
+ 🗼 Click to expand performance result + +
+ + | Name | Result | + |------------|---------| + | Performance | 30 | + | Accessibility | 90 | + | Best Practices | 90 | + | SEO | 90 | + | First Contentful Paint | 1.1s | + | Largest Contentful Paint | 2s | + | Total Blocking Time | 2s | + | Cumulative Layout Shift | 0.0015s | + | Speed Index | 25 | + +
`, + }); + core.info( + `Created comment id '${comment.id}' on issue '${github.context.issue.number}'.` + ); + core.endGroup(); } catch (error) {} } From f24df20544c6517dc1d03b9d9516ca952e07d93e Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 16:52:37 +0200 Subject: [PATCH 038/103] Test --- .../src/generateLighthouseReport/index.ts | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 00c70cfeb8..48b89269b5 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -31,28 +31,32 @@ export async function generateLighthouseReport() { core.startGroup("Post comment"); const octokit = github.getOctokit(core.getInput("token")); + console.log(github.context.issue.number, github.context.repo); const { data: comment } = await octokit.rest.issues.createComment({ ...github.context.repo, issue_number: github.context.issue.number, - body: `
- 🗼 Click to expand performance result - -
- - | Name | Result | - |------------|---------| - | Performance | 30 | - | Accessibility | 90 | - | Best Practices | 90 | - | SEO | 90 | - | First Contentful Paint | 1.1s | - | Largest Contentful Paint | 2s | - | Total Blocking Time | 2s | - | Cumulative Layout Shift | 0.0015s | - | Speed Index | 25 | - -
`, + body: "test", }); + console.log(comment); + // body: `
+ // 🗼 Click to expand performance result + + //
+ + // | Name | Result | + // |------------|---------| + // | Performance | 30 | + // | Accessibility | 90 | + // | Best Practices | 90 | + // | SEO | 90 | + // | First Contentful Paint | 1.1s | + // | Largest Contentful Paint | 2s | + // | Total Blocking Time | 2s | + // | Cumulative Layout Shift | 0.0015s | + // | Speed Index | 25 | + + //
`, + // }); core.info( `Created comment id '${comment.id}' on issue '${github.context.issue.number}'.` ); From 5b2f4f1d1df1643a047b07ae46eb6531943eec8b Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 16:52:56 +0200 Subject: [PATCH 039/103] Test --- packages/scripts/src/generateLighthouseReport/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 48b89269b5..0008d901cc 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -61,5 +61,7 @@ export async function generateLighthouseReport() { `Created comment id '${comment.id}' on issue '${github.context.issue.number}'.` ); core.endGroup(); - } catch (error) {} + } catch (error) { + console.log(error); + } } From e9a4b565d3be971b0470251325ce6dcf072f7101 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 17:05:28 +0200 Subject: [PATCH 040/103] Test --- .../workflows/generate-lighthouse-diff.yml | 100 +++++++++--------- .../src/generateLighthouseReport/index.ts | 13 +-- 2 files changed, 57 insertions(+), 56 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 08beb1fca5..880c3680e6 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -55,62 +55,62 @@ jobs: - name: Build scripts run: yarn workspace scripts build - - name: Build the bridge - run: yarn build - env: - NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - - - name: Start the bridge - run: yarn start & - env: - NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - - - name: Wait for server to be ready - run: | - for i in {1..20}; do - if curl -s http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge > /dev/null; then - echo "Server is up!" - exit 0 - fi - echo "Waiting for server..." - sleep 1 - done - - echo "Server did not start in time." - exit 1 - - - name: Install linux dependencies - run: | - sudo apt-get update - sudo apt-get install --no-install-recommends -y \ - fluxbox \ - xvfb - - - name: Run xvfb and fluxbox - run: | - Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & - fluxbox & - env: - DISPLAY: :0.0 + # - name: Build the bridge + # run: yarn build + # env: + # NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + + # - name: Start the bridge + # run: yarn start & + # env: + # NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + # NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + + # - name: Wait for server to be ready + # run: | + # for i in {1..20}; do + # if curl -s http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge > /dev/null; then + # echo "Server is up!" + # exit 0 + # fi + # echo "Waiting for server..." + # sleep 1 + # done + + # echo "Server did not start in time." + # exit 1 + + # - name: Install linux dependencies + # run: | + # sudo apt-get update + # sudo apt-get install --no-install-recommends -y \ + # fluxbox \ + # xvfb + + # - name: Run xvfb and fluxbox + # run: | + # Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & + # fluxbox & + # env: + # DISPLAY: :0.0 - name: Run generateLighthouseDiff script run: yarn workspace scripts generate-lighthouse-diff env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - DISPLAY: :0.0 + # DISPLAY: :0.0 # - name: Create comment # uses: peter-evans/create-or-update-comment@v4 diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 0008d901cc..a14549fdf5 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -1,5 +1,5 @@ import * as core from "@actions/core"; -import * as github from "@actions/github"; +import { getOctokit, context } from "@actions/github"; import { executeLighthouseFlow } from "./executeLighthouse"; import { parseLighthouseReport } from "./parseLighthouseReport"; import { join, resolve } from "path"; @@ -29,12 +29,13 @@ export async function generateLighthouseReport() { // core.endGroup(); core.startGroup("Post comment"); - const octokit = github.getOctokit(core.getInput("token")); + const github = getOctokit(process.env.GITHUB_TOKEN || ""); + // const octokit = getOctokit(core.getInput("token")); - console.log(github.context.issue.number, github.context.repo); - const { data: comment } = await octokit.rest.issues.createComment({ - ...github.context.repo, - issue_number: github.context.issue.number, + console.log(context.issue.number, context.repo); + const { data: comment } = await github.rest.issues.createComment({ + ...context.repo, + issue_number: context.issue.number, body: "test", }); console.log(comment); From 0c8604ef1f2712bb4ad2a159d5b680a33a2c8c8f Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 17:07:57 +0200 Subject: [PATCH 041/103] Test --- .../src/generateLighthouseReport/index.ts | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index a14549fdf5..66f86d0cb6 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -32,34 +32,31 @@ export async function generateLighthouseReport() { const github = getOctokit(process.env.GITHUB_TOKEN || ""); // const octokit = getOctokit(core.getInput("token")); - console.log(context.issue.number, context.repo); const { data: comment } = await github.rest.issues.createComment({ ...context.repo, issue_number: context.issue.number, - body: "test", - }); - console.log(comment); - // body: `
- // 🗼 Click to expand performance result + body: `
+ 🗼 Click to expand performance result + +
- //
+ | Name | Result | + |------------|---------| + | Performance | 30 | + | Accessibility | 90 | + | Best Practices | 90 | + | SEO | 90 | + | First Contentful Paint | 1.1s | + | Largest Contentful Paint | 2s | + | Total Blocking Time | 2s | + | Cumulative Layout Shift | 0.0015s | + | Speed Index | 25 | - // | Name | Result | - // |------------|---------| - // | Performance | 30 | - // | Accessibility | 90 | - // | Best Practices | 90 | - // | SEO | 90 | - // | First Contentful Paint | 1.1s | - // | Largest Contentful Paint | 2s | - // | Total Blocking Time | 2s | - // | Cumulative Layout Shift | 0.0015s | - // | Speed Index | 25 | +
`, + }); - //
`, - // }); core.info( - `Created comment id '${comment.id}' on issue '${github.context.issue.number}'.` + `Created comment id '${comment.id}' on issue '${context.issue.number}'.` ); core.endGroup(); } catch (error) { From 148b46b77cd1e5c44d7bc8468a8e1d0ac90ad41f Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 17:13:44 +0200 Subject: [PATCH 042/103] Test --- .../src/generateLighthouseReport/index.ts | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 66f86d0cb6..4a0db9aece 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -36,23 +36,25 @@ export async function generateLighthouseReport() { ...context.repo, issue_number: context.issue.number, body: `
- 🗼 Click to expand performance result + 🗼 Click to expand performance result -
+
- | Name | Result | - |------------|---------| - | Performance | 30 | - | Accessibility | 90 | - | Best Practices | 90 | - | SEO | 90 | - | First Contentful Paint | 1.1s | - | Largest Contentful Paint | 2s | - | Total Blocking Time | 2s | - | Cumulative Layout Shift | 0.0015s | - | Speed Index | 25 | + -
`, +| Name | Result | +|--------------------------|--------| +| Performance | 30 | +| Accessibility | 90 | +| Best Practices | 90 | +| SEO | 90 | +| First Contentful Paint | 1.1s | +| Largest Contentful Paint | 2s | +| Total Blocking Time | 2s | +| Cumulative Layout Shift | 0.0015s| +| Speed Index | 25 | + +`, }); core.info( From 402270f3a7192d696fdaee7d2144cd0ff354952d Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 17:21:13 +0200 Subject: [PATCH 043/103] WIP --- .../workflows/generate-lighthouse-diff.yml | 111 ++++++++---------- .../src/generateLighthouseReport/index.ts | 24 ++-- 2 files changed, 62 insertions(+), 73 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 880c3680e6..f343611367 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -55,70 +55,59 @@ jobs: - name: Build scripts run: yarn workspace scripts build - # - name: Build the bridge - # run: yarn build - # env: - # NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - - # - name: Start the bridge - # run: yarn start & - # env: - # NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - - # - name: Wait for server to be ready - # run: | - # for i in {1..20}; do - # if curl -s http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge > /dev/null; then - # echo "Server is up!" - # exit 0 - # fi - # echo "Waiting for server..." - # sleep 1 - # done - - # echo "Server did not start in time." - # exit 1 - - # - name: Install linux dependencies - # run: | - # sudo apt-get update - # sudo apt-get install --no-install-recommends -y \ - # fluxbox \ - # xvfb - - # - name: Run xvfb and fluxbox - # run: | - # Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & - # fluxbox & - # env: - # DISPLAY: :0.0 + - name: Build the bridge + run: yarn build + env: + NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + + - name: Start the bridge + run: yarn start & + env: + NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + + - name: Wait for server to be ready + run: | + for i in {1..20}; do + if curl -s http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge > /dev/null; then + echo "Server is up!" + exit 0 + fi + echo "Waiting for server..." + sleep 1 + done + + echo "Server did not start in time." + exit 1 + + - name: Install linux dependencies + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends -y \ + fluxbox \ + xvfb + + - name: Run xvfb and fluxbox + run: | + Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & + fluxbox & + env: + DISPLAY: :0.0 - name: Run generateLighthouseDiff script run: yarn workspace scripts generate-lighthouse-diff env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - # DISPLAY: :0.0 - - # - name: Create comment - # uses: peter-evans/create-or-update-comment@v4 - # with: - # issue-number: ${{ github.event.number }} - # body: | - # This is a multi-line test comment - # - With GitHub **Markdown** :sparkles: - # - Created by [create-or-update-comment][1] - - # [1]: https://github.com/peter-evans/create-or-update-comment \ No newline at end of file + DISPLAY: :0.0 diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 4a0db9aece..a2ee233bcc 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -36,23 +36,23 @@ export async function generateLighthouseReport() { ...context.repo, issue_number: context.issue.number, body: `
- 🗼 Click to expand performance result + ❌ Lighthouse: Regression found
-| Name | Result | -|--------------------------|--------| -| Performance | 30 | -| Accessibility | 90 | -| Best Practices | 90 | -| SEO | 90 | -| First Contentful Paint | 1.1s | -| Largest Contentful Paint | 2s | -| Total Blocking Time | 2s | -| Cumulative Layout Shift | 0.0015s| -| Speed Index | 25 | +| Name | Result | Regression | +|--------------------------|--------|------------| +| Performance | 30 | yes ❌ | +| Accessibility | 90 | no ✅ | +| Best Practices | 90 | no ✅ | +| SEO | 90 | no ✅ | +| First Contentful Paint | 1.1s | no ✅ | +| Largest Contentful Paint | 2s | yes ❌ | +| Total Blocking Time | 2s | yes ❌ | +| Cumulative Layout Shift | 0.0015s| yes ✅ | +| Speed Index | 25 | yes ❌ |
`, }); From 7feb4ac99300a29ca55796a51ef15ad650667f9c Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 17:43:57 +0200 Subject: [PATCH 044/103] Minimize diff --- .../src/generateLighthouseReport/index.ts | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index a2ee233bcc..da301bb8ca 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -15,10 +15,9 @@ const chromePath = join( ); export async function generateLighthouseReport() { try { - // const report = await executeLighthouseFlow(chromePath); + const report = await executeLighthouseFlow(chromePath); - // console.log(report); - // core.setOutput("img", report); + // core.setOutput("img", report); // if (!report) { // core.setFailed("Report wasn't generated"); // throw new Error("Report wasn't generated"); @@ -28,38 +27,38 @@ export async function generateLighthouseReport() { // const parsedReport = parseLighthouseReport(report); // core.endGroup(); - core.startGroup("Post comment"); - const github = getOctokit(process.env.GITHUB_TOKEN || ""); - // const octokit = getOctokit(core.getInput("token")); + // core.startGroup("Post comment"); + // const github = getOctokit(process.env.GITHUB_TOKEN || ""); + // // const octokit = getOctokit(core.getInput("token")); - const { data: comment } = await github.rest.issues.createComment({ - ...context.repo, - issue_number: context.issue.number, - body: `
- ❌ Lighthouse: Regression found + // const { data: comment } = await github.rest.issues.createComment({ + // ...context.repo, + // issue_number: context.issue.number, + // body: `
+ // ❌ Lighthouse: Regression found -
+ //
- + // -| Name | Result | Regression | -|--------------------------|--------|------------| -| Performance | 30 | yes ❌ | -| Accessibility | 90 | no ✅ | -| Best Practices | 90 | no ✅ | -| SEO | 90 | no ✅ | -| First Contentful Paint | 1.1s | no ✅ | -| Largest Contentful Paint | 2s | yes ❌ | -| Total Blocking Time | 2s | yes ❌ | -| Cumulative Layout Shift | 0.0015s| yes ✅ | -| Speed Index | 25 | yes ❌ | + // | Name | Result | Regression | + // |--------------------------|--------|------------| + // | Performance | 30 | yes ❌ | + // | Accessibility | 90 | no ✅ | + // | Best Practices | 90 | no ✅ | + // | SEO | 90 | no ✅ | + // | First Contentful Paint | 1.1s | no ✅ | + // | Largest Contentful Paint | 2s | yes ❌ | + // | Total Blocking Time | 2s | yes ❌ | + // | Cumulative Layout Shift | 0.0015s| yes ✅ | + // | Speed Index | 25 | yes ❌ | -
`, - }); + //
`, + // }); - core.info( - `Created comment id '${comment.id}' on issue '${context.issue.number}'.` - ); + // core.info( + // `Created comment id '${comment.id}' on issue '${context.issue.number}'.` + // ); core.endGroup(); } catch (error) { console.log(error); From 22c0dc85e572dc9aeb4cf8dabf4bb9e95bb46621 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 17:57:31 +0200 Subject: [PATCH 045/103] WIP --- .../src/generateLighthouseReport/executeLighthouse.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index d9615ae16b..ca9e192a56 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -22,12 +22,13 @@ export async function executeLighthouseFlow(chromePath?: string) { "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" ); - // const screenshot = await page.screenshot({ - // encoding: "base64", - // fullPage: true, - // }); + const screenshot = await page.screenshot({ + encoding: "base64", + fullPage: true, + }); // return screenshot; - // core.setOutput("image", JSON.stringify(screenshot, null, 2)); + core.info(JSON.stringify(screenshot, null, 2)); + core.setOutput("image", JSON.stringify(screenshot, null, 2)); await flow.startTimespan(); From 87c579e1d72523b7194a827c956bdff52905a021 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 18:08:07 +0200 Subject: [PATCH 046/103] WIP --- .../src/generateLighthouseReport/executeLighthouse.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index ca9e192a56..6338877843 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -26,7 +26,6 @@ export async function executeLighthouseFlow(chromePath?: string) { encoding: "base64", fullPage: true, }); - // return screenshot; core.info(JSON.stringify(screenshot, null, 2)); core.setOutput("image", JSON.stringify(screenshot, null, 2)); @@ -34,7 +33,10 @@ export async function executeLighthouseFlow(chromePath?: string) { // Accept ToS const tosButton = await page.waitForSelector( - '[aria-label="Agree to Terms and Continue"]' + '[aria-label="Agree to Terms and Continue"]', + { + timeout: 80_000, + } ); await tosButton?.click(); From 41d45e172988a1f9daa163bd4ad4a271b5ab589f Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 18:40:52 +0200 Subject: [PATCH 047/103] WIP --- .../generateLighthouseReport/executeLighthouse.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 6338877843..67affc489d 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -19,9 +19,13 @@ export async function executeLighthouseFlow(chromePath?: string) { }); await flow.navigate( - "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge" + "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0" ); + await page.waitForNetworkIdle({ timeout: 50_000 }); + + await flow.startTimespan(); + const screenshot = await page.screenshot({ encoding: "base64", fullPage: true, @@ -29,14 +33,9 @@ export async function executeLighthouseFlow(chromePath?: string) { core.info(JSON.stringify(screenshot, null, 2)); core.setOutput("image", JSON.stringify(screenshot, null, 2)); - await flow.startTimespan(); - // Accept ToS const tosButton = await page.waitForSelector( - '[aria-label="Agree to Terms and Continue"]', - { - timeout: 80_000, - } + '[aria-label="Agree to Terms and Continue"]' ); await tosButton?.click(); From e10c638ca0da6318c7aa8770f367fdaa6f476f31 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 18:59:40 +0200 Subject: [PATCH 048/103] WIP --- .../executeLighthouse.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 67affc489d..d58134dc05 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -22,20 +22,19 @@ export async function executeLighthouseFlow(chromePath?: string) { "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0" ); - await page.waitForNetworkIdle({ timeout: 50_000 }); - await flow.startTimespan(); - const screenshot = await page.screenshot({ - encoding: "base64", - fullPage: true, - }); - core.info(JSON.stringify(screenshot, null, 2)); - core.setOutput("image", JSON.stringify(screenshot, null, 2)); + // const screenshot = await page.screenshot({ + // encoding: "base64", + // fullPage: true, + // }); + // core.info(JSON.stringify(screenshot, null, 2)); + // core.setOutput("image", JSON.stringify(screenshot, null, 2)); // Accept ToS const tosButton = await page.waitForSelector( - '[aria-label="Agree to Terms and Continue"]' + '[aria-label="Agree to Terms and Continue"]', + { timeout: 120_000 } ); await tosButton?.click(); From 6a689a86a091dea65efa0c218c0560a7ffb29fdf Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 19:05:22 +0200 Subject: [PATCH 049/103] WIP --- .../scripts/src/generateLighthouseReport/executeLighthouse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index d58134dc05..507bae654e 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -34,7 +34,7 @@ export async function executeLighthouseFlow(chromePath?: string) { // Accept ToS const tosButton = await page.waitForSelector( '[aria-label="Agree to Terms and Continue"]', - { timeout: 120_000 } + { timeout: 300_000 } ); await tosButton?.click(); From 48454b9562da7d1aed9eb3358509c2ceed6302ff Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 19:15:50 +0200 Subject: [PATCH 050/103] WIP --- .../workflows/generate-lighthouse-diff.yml | 26 +++++++++++-------- .../executeLighthouse.ts | 14 ++++++++-- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index f343611367..b94ef0c736 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -77,19 +77,23 @@ jobs: NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - - name: Wait for server to be ready + - name: Start server and wait run: | - for i in {1..20}; do - if curl -s http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge > /dev/null; then - echo "Server is up!" - exit 0 - fi - echo "Waiting for server..." - sleep 1 - done + yarn start & npx wait-on http://localhost:3000 - echo "Server did not start in time." - exit 1 + # - name: Wait for server to be ready + # run: | + # for i in {1..20}; do + # if curl -s http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge > /dev/null; then + # echo "Server is up!" + # exit 0 + # fi + # echo "Waiting for server..." + # sleep 1 + # done + + # echo "Server did not start in time." + # exit 1 - name: Install linux dependencies run: | diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 507bae654e..695fd37a04 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -13,11 +13,22 @@ export async function executeLighthouseFlow(chromePath?: string) { }); const page = await browser.newPage(); await page.setViewport({ width: 1366, height: 768 }); + await page.setUserAgent( + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" + ); const flow = await startFlow(page, { config: desktopConfig, }); + page.on("console", (log) => { + core.info(`[log] ${log.text}`); + }); + + page.on("pageError", (err) => { + core.error(`[err] ${err}`); + }); + await flow.navigate( "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0" ); @@ -33,8 +44,7 @@ export async function executeLighthouseFlow(chromePath?: string) { // Accept ToS const tosButton = await page.waitForSelector( - '[aria-label="Agree to Terms and Continue"]', - { timeout: 300_000 } + '[aria-label="Agree to Terms and Continue"]' ); await tosButton?.click(); From 118cebf4d00f6b32f150c380351a54979020a36e Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 19:20:05 +0200 Subject: [PATCH 051/103] WIP --- .github/workflows/generate-lighthouse-diff.yml | 10 +++++----- .../src/generateLighthouseReport/executeLighthouse.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index b94ef0c736..affd8cee3a 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -66,8 +66,11 @@ jobs: NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - - name: Start the bridge - run: yarn start & + # - name: Start the bridge + # run: yarn start & + + - name: Start server and wait + run: yarn start & npx wait-on http://localhost:3000 env: NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} @@ -77,9 +80,6 @@ jobs: NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - - name: Start server and wait - run: | - yarn start & npx wait-on http://localhost:3000 # - name: Wait for server to be ready # run: | diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 695fd37a04..1546057d16 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -22,7 +22,7 @@ export async function executeLighthouseFlow(chromePath?: string) { }); page.on("console", (log) => { - core.info(`[log] ${log.text}`); + core.info(`[log] ${log.text()}`); }); page.on("pageError", (err) => { From a7f463d26461f6fecca950d53b28b5b6af005094 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 19:30:45 +0200 Subject: [PATCH 052/103] Add Env variables --- .github/workflows/generate-lighthouse-diff.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index affd8cee3a..09581110ce 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -79,7 +79,8 @@ jobs: NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - + NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID }} + THE_GRAPH_NETWORK_API_KEY: ${{ secrets.THE_GRAPH_NETWORK_API_KEY }} # - name: Wait for server to be ready # run: | From 0fc4d7c73fb2c911ff49c85597f1b2d88e1fb7ee Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 19:35:32 +0200 Subject: [PATCH 053/103] Add env variables to build --- .github/workflows/generate-lighthouse-diff.yml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/generate-lighthouse-diff.yml b/.github/workflows/generate-lighthouse-diff.yml index 09581110ce..db9365bd9f 100644 --- a/.github/workflows/generate-lighthouse-diff.yml +++ b/.github/workflows/generate-lighthouse-diff.yml @@ -65,22 +65,14 @@ jobs: NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID }} + THE_GRAPH_NETWORK_API_KEY: ${{ secrets.THE_GRAPH_NETWORK_API_KEY }} # - name: Start the bridge # run: yarn start & - name: Start server and wait run: yarn start & npx wait-on http://localhost:3000 - env: - NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_ETHEREUM: https://mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_SEPOLIA: https://sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE: https://arbitrum-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_BASE: https://base-mainnet.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA: https://arbitrum-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA: https://base-sepolia.infura.io/v3/${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID }} - THE_GRAPH_NETWORK_API_KEY: ${{ secrets.THE_GRAPH_NETWORK_API_KEY }} # - name: Wait for server to be ready # run: | From 41b41346b332ffb3c1ef4c626312086f4f57392b Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 19:41:28 +0200 Subject: [PATCH 054/103] WIP --- .../executeLighthouse.ts | 13 +--- .../src/generateLighthouseReport/index.ts | 76 +++++++++---------- 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 1546057d16..83e7acf6ac 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -35,13 +35,6 @@ export async function executeLighthouseFlow(chromePath?: string) { await flow.startTimespan(); - // const screenshot = await page.screenshot({ - // encoding: "base64", - // fullPage: true, - // }); - // core.info(JSON.stringify(screenshot, null, 2)); - // core.setOutput("image", JSON.stringify(screenshot, null, 2)); - // Accept ToS const tosButton = await page.waitForSelector( '[aria-label="Agree to Terms and Continue"]' @@ -84,10 +77,10 @@ export async function executeLighthouseFlow(chromePath?: string) { // Get the comprehensive flow report. // writeFileSync("report.html", await flow.generateReport()); // Save results as JSON. - const file = JSON.stringify(await flow.createFlowResult(), null, 2); - // const file = await flow.createFlowResult(); + // const file = JSON.stringify(await flow.createFlowResult(), null, 2); + const file = await flow.createFlowResult(); // Cleanup. await browser.close(); core.endGroup(); - // return file; + return file; } diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index da301bb8ca..61bdd9040a 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -17,48 +17,42 @@ export async function generateLighthouseReport() { try { const report = await executeLighthouseFlow(chromePath); - // core.setOutput("img", report); - // if (!report) { - // core.setFailed("Report wasn't generated"); - // throw new Error("Report wasn't generated"); - // } - - // core.startGroup("Parse lighthouse report"); - // const parsedReport = parseLighthouseReport(report); - // core.endGroup(); - - // core.startGroup("Post comment"); - // const github = getOctokit(process.env.GITHUB_TOKEN || ""); - // // const octokit = getOctokit(core.getInput("token")); - - // const { data: comment } = await github.rest.issues.createComment({ - // ...context.repo, - // issue_number: context.issue.number, - // body: `
- // ❌ Lighthouse: Regression found - - //
- - // - - // | Name | Result | Regression | - // |--------------------------|--------|------------| - // | Performance | 30 | yes ❌ | - // | Accessibility | 90 | no ✅ | - // | Best Practices | 90 | no ✅ | - // | SEO | 90 | no ✅ | - // | First Contentful Paint | 1.1s | no ✅ | - // | Largest Contentful Paint | 2s | yes ❌ | - // | Total Blocking Time | 2s | yes ❌ | - // | Cumulative Layout Shift | 0.0015s| yes ✅ | - // | Speed Index | 25 | yes ❌ | - - //
`, - // }); + core.startGroup("Parse lighthouse report"); + const parsedReport = parseLighthouseReport(report); + core.endGroup(); - // core.info( - // `Created comment id '${comment.id}' on issue '${context.issue.number}'.` - // ); + core.startGroup("Post comment"); + const github = getOctokit(process.env.GITHUB_TOKEN || ""); + + core.info(`perfscore: ${parsedReport[0].performance.toString()}`); + const { data: comment } = await github.rest.issues.createComment({ + ...context.repo, + issue_number: context.issue.number, + body: `
+ ❌ Lighthouse: Regression found + +
+ + + + | Name | Result | + |--------------------------|--------| + | Performance | ${parsedReport[0].performance} | + | Accessibility | ${parsedReport[0].accessibility} | + | Best Practices | ${parsedReport[0]["best_practices"]} | + | SEO | ${parsedReport[0].seo} | + | First Contentful Paint | ${parsedReport[0].fcp.displayValue} | + | Largest Contentful Paint | ${parsedReport[0].cls.displayValue} | + | Total Blocking Time | ${parsedReport[0].tbt.displayValue} | + | Cumulative Layout Shift | ${parsedReport[0].cls.displayValue} | + | Speed Index | ${parsedReport[0].speed.displayValue} | + +
`, + }); + + core.info( + `Created comment id '${comment.id}' on issue '${context.issue.number}'.` + ); core.endGroup(); } catch (error) { console.log(error); From 14c331bb3ee28cd42411323b05b1b5e4b9930c82 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 20:18:51 +0200 Subject: [PATCH 055/103] Cleanup, add long tasks --- .../executeLighthouse.ts | 28 +++++++---- .../src/generateLighthouseReport/index.ts | 48 ++++++++++--------- 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 83e7acf6ac..5f200c5601 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -1,6 +1,7 @@ import puppeteer from "puppeteer"; import * as core from "@actions/core"; import { startFlow, desktopConfig } from "lighthouse"; +import { PerformanceEntry } from "perf_hooks"; export async function executeLighthouseFlow(chromePath?: string) { core.startGroup("Lighthouse execution"); @@ -13,9 +14,6 @@ export async function executeLighthouseFlow(chromePath?: string) { }); const page = await browser.newPage(); await page.setViewport({ width: 1366, height: 768 }); - await page.setUserAgent( - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" - ); const flow = await startFlow(page, { config: desktopConfig, @@ -29,6 +27,19 @@ export async function executeLighthouseFlow(chromePath?: string) { core.error(`[err] ${err}`); }); + const longTasks: PerformanceEntry[] = []; + const observer = new PerformanceObserver((list) => { + list.getEntries().forEach((entry) => { + longTasks.push(entry); + }); + }); + + /** + * longtask is supported as a type + * see https://developer.mozilla.org/en-US/docs/Web/API/PerformanceLongTaskTiming + */ + observer.observe({ type: "longtask", buffered: true }); + await flow.navigate( "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0" ); @@ -75,12 +86,13 @@ export async function executeLighthouseFlow(chromePath?: string) { await flow.snapshot(); // Get the comprehensive flow report. - // writeFileSync("report.html", await flow.generateReport()); - // Save results as JSON. - // const file = JSON.stringify(await flow.createFlowResult(), null, 2); - const file = await flow.createFlowResult(); + const report = await flow.createFlowResult(); // Cleanup. await browser.close(); core.endGroup(); - return file; + + return { + report, + longTasks, + }; } diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 61bdd9040a..5f4807edd0 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -15,8 +15,11 @@ const chromePath = join( ); export async function generateLighthouseReport() { try { - const report = await executeLighthouseFlow(chromePath); + const { report, longTasks } = await executeLighthouseFlow(chromePath); + const longTasksTotal = longTasks.reduce((sum, longTask) => { + return sum + longTask.duration; + }, 0); core.startGroup("Parse lighthouse report"); const parsedReport = parseLighthouseReport(report); core.endGroup(); @@ -24,30 +27,31 @@ export async function generateLighthouseReport() { core.startGroup("Post comment"); const github = getOctokit(process.env.GITHUB_TOKEN || ""); - core.info(`perfscore: ${parsedReport[0].performance.toString()}`); const { data: comment } = await github.rest.issues.createComment({ ...context.repo, issue_number: context.issue.number, - body: `
- ❌ Lighthouse: Regression found - -
- - - - | Name | Result | - |--------------------------|--------| - | Performance | ${parsedReport[0].performance} | - | Accessibility | ${parsedReport[0].accessibility} | - | Best Practices | ${parsedReport[0]["best_practices"]} | - | SEO | ${parsedReport[0].seo} | - | First Contentful Paint | ${parsedReport[0].fcp.displayValue} | - | Largest Contentful Paint | ${parsedReport[0].cls.displayValue} | - | Total Blocking Time | ${parsedReport[0].tbt.displayValue} | - | Cumulative Layout Shift | ${parsedReport[0].cls.displayValue} | - | Speed Index | ${parsedReport[0].speed.displayValue} | - -
`, + // Identation needs to be on the same level, otherwise github doesn't format it properly + body: ` +
+❌ Lighthouse: Regression found + + + +| Name | Result | +|----------------------------|---------------------------------| +| Performance | ${parsedReport[0].performance * 100} | +| Accessibility | ${parsedReport[0].accessibility * 100} | +| Best Practices | ${parsedReport[0]["best_practices"] * 100} | +| SEO | ${parsedReport[0].seo * 100} | +| First Contentful Paint | ${parsedReport[0].fcp.displayValue} | +| Largest Contentful Paint | ${parsedReport[0].lcp.displayValue} | +| Total Blocking Time | ${parsedReport[0].tbt.displayValue} | +| Cumulative Layout Shift | ${parsedReport[0].cls.displayValue} | +| Speed Index | ${parsedReport[0].speed.displayValue} | +| Long tasks | ${longTasks.length} (${longTasksTotal}ms) + +
+ `, }); core.info( From 5cc87ca4694d32bbf5c0f6c3181a0bac8c5bf167 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 21:47:36 +0200 Subject: [PATCH 056/103] Parsing --- .../executeLighthouse.ts | 19 +--- .../src/generateLighthouseReport/index.ts | 39 +++++--- .../parseLighthouseReport.ts | 94 +++++++++++++++---- 3 files changed, 103 insertions(+), 49 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts index 5f200c5601..29c51726d6 100644 --- a/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts +++ b/packages/scripts/src/generateLighthouseReport/executeLighthouse.ts @@ -1,7 +1,6 @@ import puppeteer from "puppeteer"; import * as core from "@actions/core"; import { startFlow, desktopConfig } from "lighthouse"; -import { PerformanceEntry } from "perf_hooks"; export async function executeLighthouseFlow(chromePath?: string) { core.startGroup("Lighthouse execution"); @@ -27,19 +26,6 @@ export async function executeLighthouseFlow(chromePath?: string) { core.error(`[err] ${err}`); }); - const longTasks: PerformanceEntry[] = []; - const observer = new PerformanceObserver((list) => { - list.getEntries().forEach((entry) => { - longTasks.push(entry); - }); - }); - - /** - * longtask is supported as a type - * see https://developer.mozilla.org/en-US/docs/Web/API/PerformanceLongTaskTiming - */ - observer.observe({ type: "longtask", buffered: true }); - await flow.navigate( "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0" ); @@ -91,8 +77,5 @@ export async function executeLighthouseFlow(chromePath?: string) { await browser.close(); core.endGroup(); - return { - report, - longTasks, - }; + return report; } diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 5f4807edd0..90db17c6d0 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -15,13 +15,11 @@ const chromePath = join( ); export async function generateLighthouseReport() { try { - const { report, longTasks } = await executeLighthouseFlow(chromePath); + const report = await executeLighthouseFlow(chromePath); - const longTasksTotal = longTasks.reduce((sum, longTask) => { - return sum + longTask.duration; - }, 0); core.startGroup("Parse lighthouse report"); - const parsedReport = parseLighthouseReport(report); + const [parsedNavigationReport, parsedTimespanReport] = + parseLighthouseReport(report); core.endGroup(); core.startGroup("Post comment"); @@ -31,24 +29,35 @@ export async function generateLighthouseReport() { ...context.repo, issue_number: context.issue.number, // Identation needs to be on the same level, otherwise github doesn't format it properly + // prettier-ignore body: `
❌ Lighthouse: Regression found +Navigation: | Name | Result | |----------------------------|---------------------------------| -| Performance | ${parsedReport[0].performance * 100} | -| Accessibility | ${parsedReport[0].accessibility * 100} | -| Best Practices | ${parsedReport[0]["best_practices"] * 100} | -| SEO | ${parsedReport[0].seo * 100} | -| First Contentful Paint | ${parsedReport[0].fcp.displayValue} | -| Largest Contentful Paint | ${parsedReport[0].lcp.displayValue} | -| Total Blocking Time | ${parsedReport[0].tbt.displayValue} | -| Cumulative Layout Shift | ${parsedReport[0].cls.displayValue} | -| Speed Index | ${parsedReport[0].speed.displayValue} | -| Long tasks | ${longTasks.length} (${longTasksTotal}ms) +| Performance | ${parsedNavigationReport.performance * 100} | +| Accessibility | ${parsedNavigationReport.accessibility * 100} | +| Best Practices | ${parsedNavigationReport["best_practices"] * 100} | +| SEO | ${parsedNavigationReport.seo * 100} | +| First Contentful Paint | ${parsedNavigationReport.fcp.score * 100} (${parsedNavigationReport.fcp.displayValue}) | +| Largest Contentful Paint | ${parsedNavigationReport.lcp.score * 100} (${parsedNavigationReport.lcp.displayValue}) | +| Total Blocking Time | ${parsedNavigationReport.tbt.score * 100} (${parsedNavigationReport.tbt.displayValue}) | +| Cumulative Layout Shift | ${parsedNavigationReport.cls.score * 100} (${parsedNavigationReport.cls.displayValue}) | +| Speed Index | ${parsedNavigationReport.speed.score * 100} (${parsedNavigationReport.speed.displayValue}) | + +Timespan: +| Name | Result | +|----------------------------|---------------------------------| +| Performance | ${parsedTimespanReport.performance.total * 100} | +| Total Blocking Time | ${parsedTimespanReport.performance.tbt.score * 100} (${parsedTimespanReport.performance.tbt.displayValue}) | +| Cumulative Layout Shift | ${parsedTimespanReport.performance.cls.score * 100} (${parsedTimespanReport.performance.cls.displayValue}) | +| Interaction to Next Paint | ${parsedTimespanReport.performance.inp.score * 100} (${parsedTimespanReport.performance.inp.displayValue}) | +| Best practices | ${parsedTimespanReport.best_practices} | +| Long tasks | ${parsedTimespanReport.longTasks.total} (${parsedTimespanReport.longTasks.durationMs}ms) |
`, diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts index 13e06d6e37..99aa5b54c5 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -26,9 +26,17 @@ type TimespanResult = { total: number; tbt: Metric; cls: Metric; - inp: Metric; + inp: { + score: number; + numericValue: number; + displayValue: string; + }; }; best_practices: number; + longTasks: { + total: number; + durationMs: number; + }; }; type SnapshotResult = { performance: number; @@ -37,46 +45,63 @@ type SnapshotResult = { seo: Result; }; -function parseNavigationResult( - navigationResult: FlowResult.Step -): NavigationResult { - const fcp = navigationResult.lhr.audits["first-contentful-paint"]; - const lcp = navigationResult.lhr.audits["largest-contentful-paint"]; - const tbt = navigationResult.lhr.audits["total-blocking-time"]; - const cls = navigationResult.lhr.audits["first-contentful-paint"]; - const speed = navigationResult.lhr.audits["speed-index"]; +function commonParse(result: FlowResult.Step): { + fcp: Metric; + lcp: Metric; + tbt: Metric; + cls: Metric; + speed: Metric; +} { + const fcp = result.lhr.audits["first-contentful-paint"]; + const lcp = result.lhr.audits["largest-contentful-paint"]; + const tbt = result.lhr.audits["total-blocking-time"]; + const cls = result.lhr.audits["first-contentful-paint"]; + const speed = result.lhr.audits["speed-index"]; return { fcp: { score: fcp.score!, displayValue: fcp.displayValue!, - numericValue: fcp.numericUnit!, + // numericValue: fcp.numericUnit!, scoringOptions: fcp.scoringOptions!, }, lcp: { score: lcp.score!, displayValue: lcp.displayValue!, - numericValue: lcp.numericUnit!, + // numericValue: lcp.numericUnit!, scoringOptions: lcp.scoringOptions!, }, tbt: { score: tbt.score!, displayValue: tbt.displayValue!, - numericValue: tbt.numericUnit!, + // numericValue: tbt.numericUnit!, scoringOptions: tbt.scoringOptions!, }, cls: { score: cls.score!, displayValue: cls.displayValue!, - numericValue: cls.numericUnit!, + // numericValue: cls.numericUnit!, scoringOptions: cls.scoringOptions!, }, speed: { score: speed.score!, displayValue: speed.displayValue!, - numericValue: speed.numericUnit!, + // numericValue: speed.numericUnit!, scoringOptions: speed.scoringOptions!, }, + }; +} + +function parseNavigationResult( + navigationResult: FlowResult.Step +): NavigationResult { + const { fcp, lcp, tbt, cls, speed } = commonParse(navigationResult); + return { + fcp, + lcp, + tbt, + cls, + speed, performance: navigationResult.lhr.categories.performance.score!, accessibility: navigationResult.lhr.categories.accessibility.score!, best_practices: navigationResult.lhr.categories["best-practices"].score!, @@ -84,6 +109,43 @@ function parseNavigationResult( }; } -export function parseLighthouseReport(report: FlowResult): [NavigationResult] { - return [parseNavigationResult(report.steps[0])]; +function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { + const { tbt, cls } = commonParse(timespanResult); + const longTasks = ( + timespanResult.lhr.audits["long-tasks"].details! as unknown as { + items: { + url: string; + duration: number; + startTime: number; + }[]; + } + ).items; + + const inp = timespanResult.lhr.audits["interaction-to-next-paint"]; + return { + performance: { + total: timespanResult.lhr.categories.performance.score!, + tbt, + cls, + inp: { + score: inp.score!, + numericValue: inp.numericValue!, + displayValue: inp.displayValue!, + }, + }, + best_practices: timespanResult.lhr.categories.best_practices.score!, + longTasks: { + total: longTasks.length, + durationMs: longTasks.reduce((sum, task) => sum + task.duration, 0), + }, + }; +} + +export function parseLighthouseReport( + report: FlowResult +): [NavigationResult, TimespanResult] { + return [ + parseNavigationResult(report.steps[0]), + parseTimespanResult(report.steps[1]), + ] as const; } From 5fece249c32e4ea0dbcf2f11a6adbdbb64e907af Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 21:56:08 +0200 Subject: [PATCH 057/103] Parsing --- .../src/generateLighthouseReport/index.ts | 12 ++---------- .../parseLighthouseReport.ts | 16 +++++++++++----- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 90db17c6d0..e27e105023 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -25,6 +25,8 @@ export async function generateLighthouseReport() { core.startGroup("Post comment"); const github = getOctokit(process.env.GITHUB_TOKEN || ""); + core.info(JSON.stringify(parsedNavigationReport)); + // core.info(JSON.stringify(parsedTimespanReport)); const { data: comment } = await github.rest.issues.createComment({ ...context.repo, issue_number: context.issue.number, @@ -49,16 +51,6 @@ Navigation: | Cumulative Layout Shift | ${parsedNavigationReport.cls.score * 100} (${parsedNavigationReport.cls.displayValue}) | | Speed Index | ${parsedNavigationReport.speed.score * 100} (${parsedNavigationReport.speed.displayValue}) | -Timespan: -| Name | Result | -|----------------------------|---------------------------------| -| Performance | ${parsedTimespanReport.performance.total * 100} | -| Total Blocking Time | ${parsedTimespanReport.performance.tbt.score * 100} (${parsedTimespanReport.performance.tbt.displayValue}) | -| Cumulative Layout Shift | ${parsedTimespanReport.performance.cls.score * 100} (${parsedTimespanReport.performance.cls.displayValue}) | -| Interaction to Next Paint | ${parsedTimespanReport.performance.inp.score * 100} (${parsedTimespanReport.performance.inp.displayValue}) | -| Best practices | ${parsedTimespanReport.best_practices} | -| Long tasks | ${parsedTimespanReport.longTasks.total} (${parsedTimespanReport.longTasks.durationMs}ms) | - `, }); diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts index 99aa5b54c5..45da6f14ff 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -1,4 +1,5 @@ import { FlowResult, Result } from "lighthouse"; +import * as core from "@actions/core"; type Metric = { /** Number from 0 to 1 */ @@ -62,31 +63,31 @@ function commonParse(result: FlowResult.Step): { fcp: { score: fcp.score!, displayValue: fcp.displayValue!, - // numericValue: fcp.numericUnit!, + numericValue: fcp.numericUnit!, scoringOptions: fcp.scoringOptions!, }, lcp: { score: lcp.score!, displayValue: lcp.displayValue!, - // numericValue: lcp.numericUnit!, + numericValue: lcp.numericUnit!, scoringOptions: lcp.scoringOptions!, }, tbt: { score: tbt.score!, displayValue: tbt.displayValue!, - // numericValue: tbt.numericUnit!, + numericValue: tbt.numericUnit!, scoringOptions: tbt.scoringOptions!, }, cls: { score: cls.score!, displayValue: cls.displayValue!, - // numericValue: cls.numericUnit!, + numericValue: cls.numericUnit!, scoringOptions: cls.scoringOptions!, }, speed: { score: speed.score!, displayValue: speed.displayValue!, - // numericValue: speed.numericUnit!, + numericValue: speed.numericUnit!, scoringOptions: speed.scoringOptions!, }, }; @@ -144,6 +145,11 @@ function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { export function parseLighthouseReport( report: FlowResult ): [NavigationResult, TimespanResult] { + core.info("Parsing navigation result"); + const navigationResult = parseNavigationResult(report.steps[0]); + core.info("Parsing timespan result"); + const timespanResult = parseNavigationResult(report.steps[0]); + core.info("Parsing executed"); return [ parseNavigationResult(report.steps[0]), parseTimespanResult(report.steps[1]), From 8df385f42648faf3923ac8c29f643143fa0c0443 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 22:01:18 +0200 Subject: [PATCH 058/103] Parsing --- packages/scripts/src/generateLighthouseReport/index.ts | 2 ++ .../src/generateLighthouseReport/parseLighthouseReport.ts | 6 ------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index e27e105023..b7096d3c5b 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -18,8 +18,10 @@ export async function generateLighthouseReport() { const report = await executeLighthouseFlow(chromePath); core.startGroup("Parse lighthouse report"); + core.info("befoer parsing"); const [parsedNavigationReport, parsedTimespanReport] = parseLighthouseReport(report); + core.info("after parsing"); core.endGroup(); core.startGroup("Post comment"); diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts index 45da6f14ff..6d589d45b8 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -1,5 +1,4 @@ import { FlowResult, Result } from "lighthouse"; -import * as core from "@actions/core"; type Metric = { /** Number from 0 to 1 */ @@ -145,11 +144,6 @@ function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { export function parseLighthouseReport( report: FlowResult ): [NavigationResult, TimespanResult] { - core.info("Parsing navigation result"); - const navigationResult = parseNavigationResult(report.steps[0]); - core.info("Parsing timespan result"); - const timespanResult = parseNavigationResult(report.steps[0]); - core.info("Parsing executed"); return [ parseNavigationResult(report.steps[0]), parseTimespanResult(report.steps[1]), From 003be0649dcb209a99258b4d3275d787d37771bc Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 22:08:52 +0200 Subject: [PATCH 059/103] Parsing --- .../src/generateLighthouseReport/index.ts | 15 +++++++++++---- .../parseLighthouseReport.ts | 19 +++++++++---------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index b7096d3c5b..26da968099 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -18,17 +18,13 @@ export async function generateLighthouseReport() { const report = await executeLighthouseFlow(chromePath); core.startGroup("Parse lighthouse report"); - core.info("befoer parsing"); const [parsedNavigationReport, parsedTimespanReport] = parseLighthouseReport(report); - core.info("after parsing"); core.endGroup(); core.startGroup("Post comment"); const github = getOctokit(process.env.GITHUB_TOKEN || ""); - core.info(JSON.stringify(parsedNavigationReport)); - // core.info(JSON.stringify(parsedTimespanReport)); const { data: comment } = await github.rest.issues.createComment({ ...context.repo, issue_number: context.issue.number, @@ -53,6 +49,17 @@ Navigation: | Cumulative Layout Shift | ${parsedNavigationReport.cls.score * 100} (${parsedNavigationReport.cls.displayValue}) | | Speed Index | ${parsedNavigationReport.speed.score * 100} (${parsedNavigationReport.speed.displayValue}) | +Timespan: +| Name | Result | +|----------------------------|---------------------------------| +| Performance | ${parsedTimespanReport.performance.total * 100} | +| Total Blocking Time | ${parsedTimespanReport.performance.tbt.score * 100} (${parsedTimespanReport.performance.tbt.displayValue}) | +| Cumulative Layout Shift | ${parsedTimespanReport.performance.cls.score * 100} (${parsedTimespanReport.performance.cls.displayValue}) | +| Interaction to Next Paint | ${parsedTimespanReport.performance.inp.score * 100} (${parsedTimespanReport.performance.inp.displayValue}) | +| Best practices | ${parsedTimespanReport.best_practices} | +| Long tasks | ${parsedTimespanReport.longTasks.total} (${parsedTimespanReport.longTasks.durationMs}ms) | + + `, }); diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts index 6d589d45b8..f0034d442f 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -50,13 +50,11 @@ function commonParse(result: FlowResult.Step): { lcp: Metric; tbt: Metric; cls: Metric; - speed: Metric; } { const fcp = result.lhr.audits["first-contentful-paint"]; const lcp = result.lhr.audits["largest-contentful-paint"]; const tbt = result.lhr.audits["total-blocking-time"]; const cls = result.lhr.audits["first-contentful-paint"]; - const speed = result.lhr.audits["speed-index"]; return { fcp: { @@ -83,25 +81,26 @@ function commonParse(result: FlowResult.Step): { numericValue: cls.numericUnit!, scoringOptions: cls.scoringOptions!, }, - speed: { - score: speed.score!, - displayValue: speed.displayValue!, - numericValue: speed.numericUnit!, - scoringOptions: speed.scoringOptions!, - }, }; } function parseNavigationResult( navigationResult: FlowResult.Step ): NavigationResult { - const { fcp, lcp, tbt, cls, speed } = commonParse(navigationResult); + core; + const { fcp, lcp, tbt, cls } = commonParse(navigationResult); + const speed = navigationResult.lhr.audits["speed-index"]; return { fcp, lcp, tbt, cls, - speed, + speed: { + score: speed.score!, + displayValue: speed.displayValue!, + numericValue: speed.numericUnit!, + scoringOptions: speed.scoringOptions!, + }, performance: navigationResult.lhr.categories.performance.score!, accessibility: navigationResult.lhr.categories.accessibility.score!, best_practices: navigationResult.lhr.categories["best-practices"].score!, From ce5d0b36947b4b0aefb64ad1abe4b41e5fa26eba Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 22:13:36 +0200 Subject: [PATCH 060/103] Parsing --- .../src/generateLighthouseReport/parseLighthouseReport.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts index f0034d442f..dc5ae9cd8d 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -87,7 +87,6 @@ function commonParse(result: FlowResult.Step): { function parseNavigationResult( navigationResult: FlowResult.Step ): NavigationResult { - core; const { fcp, lcp, tbt, cls } = commonParse(navigationResult); const speed = navigationResult.lhr.audits["speed-index"]; return { From b036ecaa623185c3f3a80811d6c36ed25cc4e756 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 22:17:38 +0200 Subject: [PATCH 061/103] Parsing --- .../scripts/src/generateLighthouseReport/index.ts | 13 +------------ .../parseLighthouseReport.ts | 6 ++---- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 26da968099..5f2beae766 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -18,8 +18,7 @@ export async function generateLighthouseReport() { const report = await executeLighthouseFlow(chromePath); core.startGroup("Parse lighthouse report"); - const [parsedNavigationReport, parsedTimespanReport] = - parseLighthouseReport(report); + const [parsedNavigationReport] = parseLighthouseReport(report); core.endGroup(); core.startGroup("Post comment"); @@ -49,16 +48,6 @@ Navigation: | Cumulative Layout Shift | ${parsedNavigationReport.cls.score * 100} (${parsedNavigationReport.cls.displayValue}) | | Speed Index | ${parsedNavigationReport.speed.score * 100} (${parsedNavigationReport.speed.displayValue}) | -Timespan: -| Name | Result | -|----------------------------|---------------------------------| -| Performance | ${parsedTimespanReport.performance.total * 100} | -| Total Blocking Time | ${parsedTimespanReport.performance.tbt.score * 100} (${parsedTimespanReport.performance.tbt.displayValue}) | -| Cumulative Layout Shift | ${parsedTimespanReport.performance.cls.score * 100} (${parsedTimespanReport.performance.cls.displayValue}) | -| Interaction to Next Paint | ${parsedTimespanReport.performance.inp.score * 100} (${parsedTimespanReport.performance.inp.displayValue}) | -| Best practices | ${parsedTimespanReport.best_practices} | -| Long tasks | ${parsedTimespanReport.longTasks.total} (${parsedTimespanReport.longTasks.durationMs}ms) | - `, diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts index dc5ae9cd8d..a1c70572ef 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -139,11 +139,9 @@ function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { }; } -export function parseLighthouseReport( - report: FlowResult -): [NavigationResult, TimespanResult] { +export function parseLighthouseReport(report: FlowResult): [NavigationResult] { return [ parseNavigationResult(report.steps[0]), - parseTimespanResult(report.steps[1]), + // parseTimespanResult(report.steps[1]), ] as const; } From 2c33625bf9901b8ea02ad24a5b92984b452498f6 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 22:27:01 +0200 Subject: [PATCH 062/103] Parsing --- .../parseLighthouseReport.ts | 54 ++++++------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts index a1c70572ef..a059385df6 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -45,49 +45,24 @@ type SnapshotResult = { seo: Result; }; -function commonParse(result: FlowResult.Step): { - fcp: Metric; - lcp: Metric; - tbt: Metric; - cls: Metric; -} { - const fcp = result.lhr.audits["first-contentful-paint"]; - const lcp = result.lhr.audits["largest-contentful-paint"]; - const tbt = result.lhr.audits["total-blocking-time"]; - const cls = result.lhr.audits["first-contentful-paint"]; +function parse(result: FlowResult.Step, metricName: string): Metric { + const metric = result.lhr.audits[metricName]; return { - fcp: { - score: fcp.score!, - displayValue: fcp.displayValue!, - numericValue: fcp.numericUnit!, - scoringOptions: fcp.scoringOptions!, - }, - lcp: { - score: lcp.score!, - displayValue: lcp.displayValue!, - numericValue: lcp.numericUnit!, - scoringOptions: lcp.scoringOptions!, - }, - tbt: { - score: tbt.score!, - displayValue: tbt.displayValue!, - numericValue: tbt.numericUnit!, - scoringOptions: tbt.scoringOptions!, - }, - cls: { - score: cls.score!, - displayValue: cls.displayValue!, - numericValue: cls.numericUnit!, - scoringOptions: cls.scoringOptions!, - }, + score: metric.score!, + displayValue: metric.displayValue!, + numericValue: metric.numericUnit!, + scoringOptions: metric.scoringOptions!, }; } function parseNavigationResult( navigationResult: FlowResult.Step ): NavigationResult { - const { fcp, lcp, tbt, cls } = commonParse(navigationResult); + const fcp = parse(navigationResult, "fcp"); + const lcp = parse(navigationResult, "fcp"); + const tbt = parse(navigationResult, "fcp"); + const cls = parse(navigationResult, "fcp"); const speed = navigationResult.lhr.audits["speed-index"]; return { fcp, @@ -108,7 +83,8 @@ function parseNavigationResult( } function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { - const { tbt, cls } = commonParse(timespanResult); + const tbt = parse(timespanResult, "fcp"); + const cls = parse(timespanResult, "fcp"); const longTasks = ( timespanResult.lhr.audits["long-tasks"].details! as unknown as { items: { @@ -139,9 +115,11 @@ function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { }; } -export function parseLighthouseReport(report: FlowResult): [NavigationResult] { +export function parseLighthouseReport( + report: FlowResult +): [NavigationResult, TimespanResult] { return [ parseNavigationResult(report.steps[0]), - // parseTimespanResult(report.steps[1]), + parseTimespanResult(report.steps[1]), ] as const; } From 9823b1def56b8402c8f4665673450599590395c6 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 22:33:08 +0200 Subject: [PATCH 063/103] Parsing --- .../scripts/src/generateLighthouseReport/index.ts | 14 +++++++++++++- .../parseLighthouseReport.ts | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 5f2beae766..e7eca042f3 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -18,7 +18,8 @@ export async function generateLighthouseReport() { const report = await executeLighthouseFlow(chromePath); core.startGroup("Parse lighthouse report"); - const [parsedNavigationReport] = parseLighthouseReport(report); + const [parsedNavigationReport, parsedTimespanReport] = + parseLighthouseReport(report); core.endGroup(); core.startGroup("Post comment"); @@ -49,6 +50,17 @@ Navigation: | Speed Index | ${parsedNavigationReport.speed.score * 100} (${parsedNavigationReport.speed.displayValue}) | +Timespan: +| Name | Result | +|----------------------------|---------------------------------| +| Performance | ${parsedTimespanReport.performance.total * 100} | +| Total Blocking Time | ${parsedTimespanReport.performance.tbt.score * 100} (${parsedTimespanReport.performance.tbt.displayValue}) | +| Cumulative Layout Shift | ${parsedTimespanReport.performance.cls.score * 100} (${parsedTimespanReport.performance.cls.displayValue}) | +| Interaction to Next Paint | ${parsedTimespanReport.performance.inp.score * 100} (${parsedTimespanReport.performance.inp.displayValue}) | +| Best practices | ${parsedTimespanReport.best_practices} | +| Long tasks | ${parsedTimespanReport.longTasks.total} (${parsedTimespanReport.longTasks.durationMs}ms) | + + `, }); diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts index a059385df6..dda0486f89 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -94,8 +94,8 @@ function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { }[]; } ).items; - const inp = timespanResult.lhr.audits["interaction-to-next-paint"]; + return { performance: { total: timespanResult.lhr.categories.performance.score!, @@ -107,7 +107,7 @@ function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { displayValue: inp.displayValue!, }, }, - best_practices: timespanResult.lhr.categories.best_practices.score!, + best_practices: timespanResult.lhr.categories["best-practices"].score!, longTasks: { total: longTasks.length, durationMs: longTasks.reduce((sum, task) => sum + task.duration, 0), From 4bcbfb323d7ea7e2de52befdd607cc609b05bdf5 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 22:48:00 +0200 Subject: [PATCH 064/103] Parsing --- .../parseLighthouseReport.ts | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts index dda0486f89..5cc228b97a 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -1,4 +1,5 @@ import { FlowResult, Result } from "lighthouse"; +import * as core from "@actions/core"; type Metric = { /** Number from 0 to 1 */ @@ -59,11 +60,12 @@ function parse(result: FlowResult.Step, metricName: string): Metric { function parseNavigationResult( navigationResult: FlowResult.Step ): NavigationResult { - const fcp = parse(navigationResult, "fcp"); - const lcp = parse(navigationResult, "fcp"); - const tbt = parse(navigationResult, "fcp"); - const cls = parse(navigationResult, "fcp"); + const fcp = parse(navigationResult, "first-contentful-paint"); + const lcp = parse(navigationResult, "largest-contentful-paint"); + const tbt = parse(navigationResult, "total-blocking-time"); + const cls = parse(navigationResult, "cumulative-layout-shift"); const speed = navigationResult.lhr.audits["speed-index"]; + return { fcp, lcp, @@ -83,8 +85,12 @@ function parseNavigationResult( } function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { - const tbt = parse(timespanResult, "fcp"); - const cls = parse(timespanResult, "fcp"); + core.info("parsetimespan"); + const tbt = parse(timespanResult, "total-blocking-time"); + core.info("tbt"); + core.info(JSON.stringify(tbt)); + const cls = parse(timespanResult, "cumulative-layout-shift"); + core.info("cls"); const longTasks = ( timespanResult.lhr.audits["long-tasks"].details! as unknown as { items: { @@ -96,6 +102,12 @@ function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { ).items; const inp = timespanResult.lhr.audits["interaction-to-next-paint"]; + core.info("timespanResult.lhr.categories.performance"); + core.info(JSON.stringify(timespanResult.lhr.categories.performance)); + + core.info("timespanResult.lhr.categories['best-practices']"); + core.info(JSON.stringify(timespanResult.lhr.categories["best-practices"])); + return { performance: { total: timespanResult.lhr.categories.performance.score!, From e02eececeac553c892ece820749f842606e4925a Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 27 May 2025 22:52:57 +0200 Subject: [PATCH 065/103] Cleanup --- .../scripts/src/generateLighthouseReport/index.ts | 2 +- .../generateLighthouseReport/parseLighthouseReport.ts | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index e7eca042f3..6e1a4add93 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -57,7 +57,7 @@ Timespan: | Total Blocking Time | ${parsedTimespanReport.performance.tbt.score * 100} (${parsedTimespanReport.performance.tbt.displayValue}) | | Cumulative Layout Shift | ${parsedTimespanReport.performance.cls.score * 100} (${parsedTimespanReport.performance.cls.displayValue}) | | Interaction to Next Paint | ${parsedTimespanReport.performance.inp.score * 100} (${parsedTimespanReport.performance.inp.displayValue}) | -| Best practices | ${parsedTimespanReport.best_practices} | +| Best practices | ${parsedTimespanReport.best_practices * 100} | | Long tasks | ${parsedTimespanReport.longTasks.total} (${parsedTimespanReport.longTasks.durationMs}ms) | diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts index 5cc228b97a..a907aff0f2 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts @@ -1,5 +1,4 @@ import { FlowResult, Result } from "lighthouse"; -import * as core from "@actions/core"; type Metric = { /** Number from 0 to 1 */ @@ -85,12 +84,8 @@ function parseNavigationResult( } function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { - core.info("parsetimespan"); const tbt = parse(timespanResult, "total-blocking-time"); - core.info("tbt"); - core.info(JSON.stringify(tbt)); const cls = parse(timespanResult, "cumulative-layout-shift"); - core.info("cls"); const longTasks = ( timespanResult.lhr.audits["long-tasks"].details! as unknown as { items: { @@ -102,12 +97,6 @@ function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { ).items; const inp = timespanResult.lhr.audits["interaction-to-next-paint"]; - core.info("timespanResult.lhr.categories.performance"); - core.info(JSON.stringify(timespanResult.lhr.categories.performance)); - - core.info("timespanResult.lhr.categories['best-practices']"); - core.info(JSON.stringify(timespanResult.lhr.categories["best-practices"])); - return { performance: { total: timespanResult.lhr.categories.performance.score!, From 57aceef90b5204069bf97c21c48ee4c5621b70ae Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 28 May 2025 11:34:09 +0200 Subject: [PATCH 066/103] Run multiple tests --- packages/scripts/src/generateLighthouseReport/index.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index 6e1a4add93..d76db3d1c7 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -15,8 +15,15 @@ const chromePath = join( ); export async function generateLighthouseReport() { try { - const report = await executeLighthouseFlow(chromePath); + const reports = await Promise.all([ + executeLighthouseFlow(chromePath), + executeLighthouseFlow(chromePath), + executeLighthouseFlow(chromePath), + executeLighthouseFlow(chromePath), + executeLighthouseFlow(chromePath), + ]); + const report = reports[0]; core.startGroup("Parse lighthouse report"); const [parsedNavigationReport, parsedTimespanReport] = parseLighthouseReport(report); From 340d827a99445825b55132d35553474d23c3f533 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 28 May 2025 12:06:40 +0200 Subject: [PATCH 067/103] Run multiple tests --- .../scripts/src/generateLighthouseReport/index.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index d76db3d1c7..e5718d8804 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -15,15 +15,10 @@ const chromePath = join( ); export async function generateLighthouseReport() { try { - const reports = await Promise.all([ - executeLighthouseFlow(chromePath), - executeLighthouseFlow(chromePath), - executeLighthouseFlow(chromePath), - executeLighthouseFlow(chromePath), - executeLighthouseFlow(chromePath), - ]); + const report = await executeLighthouseFlow(chromePath); + const report1 = await executeLighthouseFlow(chromePath); + const report2 = await executeLighthouseFlow(chromePath); - const report = reports[0]; core.startGroup("Parse lighthouse report"); const [parsedNavigationReport, parsedTimespanReport] = parseLighthouseReport(report); From ca85f573c4bf81a8c6654d24ce67393d21dde32c Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 30 May 2025 15:55:03 +0000 Subject: [PATCH 068/103] Run multiple lighthouse --- .../src/generateLighthouseReport/index.ts | 57 +------- .../parseLighthouseReport.ts | 126 ------------------ .../generateLighthouseReport/postComment.ts | 59 ++++++++ .../postComment.ts.ts | 59 ++++++++ 4 files changed, 124 insertions(+), 177 deletions(-) delete mode 100644 packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts create mode 100644 packages/scripts/src/generateLighthouseReport/postComment.ts create mode 100644 packages/scripts/src/generateLighthouseReport/postComment.ts.ts diff --git a/packages/scripts/src/generateLighthouseReport/index.ts b/packages/scripts/src/generateLighthouseReport/index.ts index e5718d8804..34815ecf7a 100644 --- a/packages/scripts/src/generateLighthouseReport/index.ts +++ b/packages/scripts/src/generateLighthouseReport/index.ts @@ -1,9 +1,9 @@ import * as core from "@actions/core"; -import { getOctokit, context } from "@actions/github"; import { executeLighthouseFlow } from "./executeLighthouse"; -import { parseLighthouseReport } from "./parseLighthouseReport"; +import { parseLighthouseReports } from "./parseLighthouseReports"; import { join, resolve } from "path"; import { config } from "../../../../package.json"; +import { postComment } from "./postComment"; const workspaceRoot = resolve(process.cwd(), "../.."); // "node_modules/.cache/synpress/chrome/linux-128.0.6613.137/chrome-linux64/chrome" @@ -15,62 +15,17 @@ const chromePath = join( ); export async function generateLighthouseReport() { try { - const report = await executeLighthouseFlow(chromePath); + // Reports need to be run sequentially const report1 = await executeLighthouseFlow(chromePath); const report2 = await executeLighthouseFlow(chromePath); + const report3 = await executeLighthouseFlow(chromePath); core.startGroup("Parse lighthouse report"); const [parsedNavigationReport, parsedTimespanReport] = - parseLighthouseReport(report); + parseLighthouseReports([report1, report2, report3]); core.endGroup(); - core.startGroup("Post comment"); - const github = getOctokit(process.env.GITHUB_TOKEN || ""); - - const { data: comment } = await github.rest.issues.createComment({ - ...context.repo, - issue_number: context.issue.number, - // Identation needs to be on the same level, otherwise github doesn't format it properly - // prettier-ignore - body: ` -
-❌ Lighthouse: Regression found - - - -Navigation: -| Name | Result | -|----------------------------|---------------------------------| -| Performance | ${parsedNavigationReport.performance * 100} | -| Accessibility | ${parsedNavigationReport.accessibility * 100} | -| Best Practices | ${parsedNavigationReport["best_practices"] * 100} | -| SEO | ${parsedNavigationReport.seo * 100} | -| First Contentful Paint | ${parsedNavigationReport.fcp.score * 100} (${parsedNavigationReport.fcp.displayValue}) | -| Largest Contentful Paint | ${parsedNavigationReport.lcp.score * 100} (${parsedNavigationReport.lcp.displayValue}) | -| Total Blocking Time | ${parsedNavigationReport.tbt.score * 100} (${parsedNavigationReport.tbt.displayValue}) | -| Cumulative Layout Shift | ${parsedNavigationReport.cls.score * 100} (${parsedNavigationReport.cls.displayValue}) | -| Speed Index | ${parsedNavigationReport.speed.score * 100} (${parsedNavigationReport.speed.displayValue}) | - - -Timespan: -| Name | Result | -|----------------------------|---------------------------------| -| Performance | ${parsedTimespanReport.performance.total * 100} | -| Total Blocking Time | ${parsedTimespanReport.performance.tbt.score * 100} (${parsedTimespanReport.performance.tbt.displayValue}) | -| Cumulative Layout Shift | ${parsedTimespanReport.performance.cls.score * 100} (${parsedTimespanReport.performance.cls.displayValue}) | -| Interaction to Next Paint | ${parsedTimespanReport.performance.inp.score * 100} (${parsedTimespanReport.performance.inp.displayValue}) | -| Best practices | ${parsedTimespanReport.best_practices * 100} | -| Long tasks | ${parsedTimespanReport.longTasks.total} (${parsedTimespanReport.longTasks.durationMs}ms) | - - -
- `, - }); - - core.info( - `Created comment id '${comment.id}' on issue '${context.issue.number}'.` - ); - core.endGroup(); + await postComment({ parsedNavigationReport, parsedTimespanReport }); } catch (error) { console.log(error); } diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts deleted file mode 100644 index a907aff0f2..0000000000 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReport.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { FlowResult, Result } from "lighthouse"; - -type Metric = { - /** Number from 0 to 1 */ - score: number; - numericValue: string; - displayValue: string; - scoringOptions: { - p10: number; - median: number; - }; -}; -type NavigationResult = { - fcp: Metric; - lcp: Metric; - tbt: Metric; - cls: Metric; - speed: Metric; - performance: number; - accessibility: number; - best_practices: number; - seo: number; -}; -type TimespanResult = { - performance: { - total: number; - tbt: Metric; - cls: Metric; - inp: { - score: number; - numericValue: number; - displayValue: string; - }; - }; - best_practices: number; - longTasks: { - total: number; - durationMs: number; - }; -}; -type SnapshotResult = { - performance: number; - accessibility: number; - best_practices: number; - seo: Result; -}; - -function parse(result: FlowResult.Step, metricName: string): Metric { - const metric = result.lhr.audits[metricName]; - - return { - score: metric.score!, - displayValue: metric.displayValue!, - numericValue: metric.numericUnit!, - scoringOptions: metric.scoringOptions!, - }; -} - -function parseNavigationResult( - navigationResult: FlowResult.Step -): NavigationResult { - const fcp = parse(navigationResult, "first-contentful-paint"); - const lcp = parse(navigationResult, "largest-contentful-paint"); - const tbt = parse(navigationResult, "total-blocking-time"); - const cls = parse(navigationResult, "cumulative-layout-shift"); - const speed = navigationResult.lhr.audits["speed-index"]; - - return { - fcp, - lcp, - tbt, - cls, - speed: { - score: speed.score!, - displayValue: speed.displayValue!, - numericValue: speed.numericUnit!, - scoringOptions: speed.scoringOptions!, - }, - performance: navigationResult.lhr.categories.performance.score!, - accessibility: navigationResult.lhr.categories.accessibility.score!, - best_practices: navigationResult.lhr.categories["best-practices"].score!, - seo: navigationResult.lhr.categories.seo.score!, - }; -} - -function parseTimespanResult(timespanResult: FlowResult.Step): TimespanResult { - const tbt = parse(timespanResult, "total-blocking-time"); - const cls = parse(timespanResult, "cumulative-layout-shift"); - const longTasks = ( - timespanResult.lhr.audits["long-tasks"].details! as unknown as { - items: { - url: string; - duration: number; - startTime: number; - }[]; - } - ).items; - const inp = timespanResult.lhr.audits["interaction-to-next-paint"]; - - return { - performance: { - total: timespanResult.lhr.categories.performance.score!, - tbt, - cls, - inp: { - score: inp.score!, - numericValue: inp.numericValue!, - displayValue: inp.displayValue!, - }, - }, - best_practices: timespanResult.lhr.categories["best-practices"].score!, - longTasks: { - total: longTasks.length, - durationMs: longTasks.reduce((sum, task) => sum + task.duration, 0), - }, - }; -} - -export function parseLighthouseReport( - report: FlowResult -): [NavigationResult, TimespanResult] { - return [ - parseNavigationResult(report.steps[0]), - parseTimespanResult(report.steps[1]), - ] as const; -} diff --git a/packages/scripts/src/generateLighthouseReport/postComment.ts b/packages/scripts/src/generateLighthouseReport/postComment.ts new file mode 100644 index 0000000000..41be5a4e97 --- /dev/null +++ b/packages/scripts/src/generateLighthouseReport/postComment.ts @@ -0,0 +1,59 @@ +import * as core from "@actions/core"; +import { getOctokit, context } from "@actions/github"; +import { NavigationResult, TimespanResult } from "./parseLighthouseReports"; + +export async function postComment({ + parsedNavigationReport, + parsedTimespanReport, +}: { + parsedNavigationReport: NavigationResult; + parsedTimespanReport: TimespanResult; +}) { + core.startGroup("Post comment"); + const github = getOctokit(process.env.GITHUB_TOKEN || ""); + + const { data: comment } = await github.rest.issues.createComment({ + ...context.repo, + issue_number: context.issue.number, + // Identation needs to be on the same level, otherwise github doesn't format it properly + // prettier-ignore + body: ` +
+❌ Lighthouse: Regression found + + + +Navigation: +| Name | Result | +|----------------------------|---------------------------------| +| Performance | ${(parsedNavigationReport.performance * 100).toFixed(0)} | +| Accessibility | ${(parsedNavigationReport.accessibility * 100).toFixed(0)} | +| Best Practices | ${(parsedNavigationReport["best_practices"] * 100).toFixed(0)} | +| SEO | ${(parsedNavigationReport.seo * 100).toFixed(0)} | +| First Contentful Paint | ${(parsedNavigationReport.fcp.score * 100).toFixed(0)} ((${parsedNavigationReport.fcp.numericValue.toFixed(3)})s) | +| Largest Contentful Paint | ${(parsedNavigationReport.lcp.score * 100).toFixed(0)} (${parsedNavigationReport.lcp.numericValue.toFixed(3)}s) | +| Total Blocking Time | ${(parsedNavigationReport.tbt.score * 100).toFixed(0)} (${parsedNavigationReport.tbt.numericValue.toFixed(3)}ms) | +| Cumulative Layout Shift | ${(parsedNavigationReport.cls.score * 100).toFixed(0)} (${parsedNavigationReport.cls.numericValue.toFixed(3)}) | +| Speed Index | ${(parsedNavigationReport.speed.score * 100).toFixed(0)} (${parsedNavigationReport.speed.numericValue.toFixed(3)}s) | + + +Timespan: +| Name | Result | +|----------------------------|---------------------------------| +| Performance | ${(parsedTimespanReport.performance.total * 100).toFixed(0)} | +| Total Blocking Time | ${(parsedTimespanReport.performance.tbt.score * 100).toFixed(0)} (${parsedTimespanReport.performance.tbt.numericValue}ms) | +| Cumulative Layout Shift | ${(parsedTimespanReport.performance.cls.score * 100).toFixed(0)} (${parsedTimespanReport.performance.cls.numericValue}) | +| Interaction to Next Paint | ${(parsedTimespanReport.performance.inp.score * 100).toFixed(0)} (${parsedTimespanReport.performance.inp.numericValue}ms) | +| Best practices | ${(parsedTimespanReport.best_practices * 100).toFixed(0)} | +| Long tasks | ${(parsedTimespanReport.longTasks.total).toFixed(0)} (${(parsedTimespanReport.longTasks.durationMs).toFixed(2)}ms) | + + +
+ `, + }); + + core.info( + `Created comment id '${comment.id}' on issue '${context.issue.number}'.` + ); + core.endGroup(); +} diff --git a/packages/scripts/src/generateLighthouseReport/postComment.ts.ts b/packages/scripts/src/generateLighthouseReport/postComment.ts.ts new file mode 100644 index 0000000000..3af2ef985c --- /dev/null +++ b/packages/scripts/src/generateLighthouseReport/postComment.ts.ts @@ -0,0 +1,59 @@ +import * as core from "@actions/core"; +import { getOctokit, context } from "@actions/github"; +import { NavigationResult, TimespanResult } from "./parseLighthouseReport"; + +export async function postComment({ + parsedNavigationReport, + parsedTimespanReport, +}: { + parsedNavigationReport: NavigationResult; + parsedTimespanReport: TimespanResult; +}) { + core.startGroup("Post comment"); + const github = getOctokit(process.env.GITHUB_TOKEN || ""); + + const { data: comment } = await github.rest.issues.createComment({ + ...context.repo, + issue_number: context.issue.number, + // Identation needs to be on the same level, otherwise github doesn't format it properly + // prettier-ignore + body: ` +
+❌ Lighthouse: Regression found + + + +Navigation: +| Name | Result | +|----------------------------|---------------------------------| +| Performance | ${parsedNavigationReport.performance * 100} | +| Accessibility | ${parsedNavigationReport.accessibility * 100} | +| Best Practices | ${parsedNavigationReport["best_practices"] * 100} | +| SEO | ${parsedNavigationReport.seo * 100} | +| First Contentful Paint | ${parsedNavigationReport.fcp.score * 100} (${parsedNavigationReport.fcp.displayValue}) | +| Largest Contentful Paint | ${parsedNavigationReport.lcp.score * 100} (${parsedNavigationReport.lcp.displayValue}) | +| Total Blocking Time | ${parsedNavigationReport.tbt.score * 100} (${parsedNavigationReport.tbt.displayValue}) | +| Cumulative Layout Shift | ${parsedNavigationReport.cls.score * 100} (${parsedNavigationReport.cls.displayValue}) | +| Speed Index | ${parsedNavigationReport.speed.score * 100} (${parsedNavigationReport.speed.displayValue}) | + + +Timespan: +| Name | Result | +|----------------------------|---------------------------------| +| Performance | ${parsedTimespanReport.performance.total * 100} | +| Total Blocking Time | ${parsedTimespanReport.performance.tbt.score * 100} (${parsedTimespanReport.performance.tbt.displayValue}) | +| Cumulative Layout Shift | ${parsedTimespanReport.performance.cls.score * 100} (${parsedTimespanReport.performance.cls.displayValue}) | +| Interaction to Next Paint | ${parsedTimespanReport.performance.inp.score * 100} (${parsedTimespanReport.performance.inp.displayValue}) | +| Best practices | ${parsedTimespanReport.best_practices * 100} | +| Long tasks | ${parsedTimespanReport.longTasks.total} (${parsedTimespanReport.longTasks.durationMs}ms) | + + +
+ `, + }); + + core.info( + `Created comment id '${comment.id}' on issue '${context.issue.number}'.` + ); + core.endGroup(); +} From cf526ccbafd36d2617d287c5fdfdfc124c17ebea Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 30 May 2025 16:01:40 +0000 Subject: [PATCH 069/103] Missing file --- .../parseLighthouseReports.ts | 248 ++++++++++++++++++ .../postComment.ts.ts | 59 ----- 2 files changed, 248 insertions(+), 59 deletions(-) create mode 100644 packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts delete mode 100644 packages/scripts/src/generateLighthouseReport/postComment.ts.ts diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts new file mode 100644 index 0000000000..bfd81e129e --- /dev/null +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts @@ -0,0 +1,248 @@ +import { FlowResult, Result } from "lighthouse"; + +type Metric = { + /** Number from 0 to 1 */ + score: number; + numericValue: number; +}; +export type NavigationResult = { + fcp: Metric; + lcp: Metric; + tbt: Metric; + cls: Metric; + speed: Metric; + performance: number; + accessibility: number; + best_practices: number; + seo: number; +}; +export type TimespanResult = { + performance: { + total: number; + tbt: Metric; + cls: Metric; + inp: Metric; + }; + best_practices: number; + longTasks: { + total: number; + durationMs: number; + }; +}; +export type SnapshotResult = { + performance: number; + accessibility: number; + best_practices: number; + seo: Result; +}; + +function parse(result: FlowResult.Step, metricName: string): Metric { + const metric = result.lhr.audits[metricName]; + + return { + score: metric.score!, + numericValue: Number(metric.numericUnit)!, + }; +} + +function parseNavigationResults( + navigationReports: FlowResult.Step[] +): NavigationResult { + const mergedReports = navigationReports.reduce( + (acc, report) => { + const fcp = parse(report, "first-contentful-paint"); + const lcp = parse(report, "largest-contentful-paint"); + const tbt = parse(report, "total-blocking-time"); + const cls = parse(report, "cumulative-layout-shift"); + const speed = report.lhr.audits["speed-index"]; + + return { + fcp: { + numericValue: acc.fcp.numericValue + fcp.numericValue, + score: acc.fcp.score + fcp.score, + }, + lcp: { + numericValue: acc.lcp.numericValue + lcp.numericValue, + score: acc.lcp.score + lcp.score, + }, + tbt: { + numericValue: acc.tbt.numericValue + tbt.numericValue, + score: acc.tbt.score + tbt.score, + }, + cls: { + numericValue: acc.cls.numericValue + cls.numericValue, + score: acc.cls.score + cls.score, + }, + speed: { + numericValue: acc.speed.numericValue + (speed.numericValue || 0), + score: acc.speed.score + (speed.score || 0), + }, + performance: acc.performance + report.lhr.categories.performance.score!, + accessibility: + acc.accessibility + report.lhr.categories.accessibility.score!, + best_practices: + acc.best_practices + report.lhr.categories["best-practices"].score!, + seo: acc.seo + report.lhr.categories.seo.score!, + }; + }, + { + fcp: { + numericValue: 0, + score: 0, + }, + lcp: { + numericValue: 0, + score: 0, + }, + tbt: { + numericValue: 0, + score: 0, + }, + cls: { + numericValue: 0, + score: 0, + }, + speed: { + numericValue: 0, + score: 0, + }, + performance: 0, + accessibility: 0, + best_practices: 0, + seo: 0, + } satisfies NavigationResult + ); + + const length = navigationReports.length; + return { + fcp: { + numericValue: mergedReports.fcp.numericValue / length, + score: mergedReports.fcp.score / length, + }, + lcp: { + numericValue: mergedReports.lcp.numericValue / length, + score: mergedReports.lcp.score / length, + }, + tbt: { + numericValue: mergedReports.tbt.numericValue / length, + score: mergedReports.tbt.score / length, + }, + cls: { + numericValue: mergedReports.cls.numericValue / length, + score: mergedReports.cls.score / length, + }, + speed: { + numericValue: mergedReports.speed.numericValue / length, + score: mergedReports.speed.score / length, + }, + performance: mergedReports.performance / length, + accessibility: mergedReports.accessibility / length, + best_practices: mergedReports.best_practices / length, + seo: mergedReports.seo / length, + }; +} + +function parseTimespanResults( + timespanReports: FlowResult.Step[] +): TimespanResult { + const mergedReports = timespanReports.reduce( + (acc, report) => { + const tbt = parse(report, "total-blocking-time"); + const cls = parse(report, "cumulative-layout-shift"); + const inp = parse(report, "interaction-to-next-paint"); + const longTasks = ( + report.lhr.audits["long-tasks"].details! as unknown as { + items: { + url: string; + duration: number; + startTime: number; + }[]; + } + ).items; + return { + performance: { + total: + acc.performance.total + + (report.lhr.categories.performance.score || 0), + tbt: { + numericValue: acc.performance.tbt.numericValue + tbt.numericValue, + score: acc.performance.tbt.score + tbt.score, + }, + cls: { + numericValue: acc.performance.cls.numericValue + cls.numericValue, + score: acc.performance.cls.score + cls.score, + }, + inp: { + numericValue: acc.performance.inp.numericValue + inp.numericValue, + score: acc.performance.inp.score + inp.score, + }, + }, + best_practices: + acc.best_practices + + (report.lhr.categories["best-practices"].score || 0), + longTasks: { + total: acc.longTasks.total + longTasks.length, + durationMs: longTasks.reduce( + (sum, task) => sum + task.duration, + acc.longTasks.durationMs + ), + }, + }; + }, + { + performance: { + total: 0, + tbt: { + numericValue: 0, + score: 0, + }, + cls: { + numericValue: 0, + score: 0, + }, + inp: { numericValue: 0, score: 0 }, + }, + best_practices: 0, + longTasks: { + total: 0, + durationMs: 0, + }, + } satisfies TimespanResult + ); + + const length = timespanReports.length; + return { + performance: { + total: mergedReports.performance.total / length, + tbt: { + numericValue: mergedReports.performance.tbt.numericValue, + score: mergedReports.performance.tbt.numericValue, + }, + cls: { + numericValue: mergedReports.performance.cls.numericValue, + score: mergedReports.performance.cls.numericValue, + }, + inp: { + numericValue: mergedReports.performance.inp.numericValue, + score: mergedReports.performance.inp.numericValue, + }, + }, + best_practices: mergedReports.best_practices / length, + longTasks: { + total: mergedReports.longTasks.total / length, + durationMs: mergedReports.longTasks.durationMs / length, + }, + }; +} + +export function parseLighthouseReports( + reports: FlowResult[] +): [NavigationResult, TimespanResult] { + const navigationReports = reports.map((report) => report.steps[0]); + const timespanReports = reports.map((report) => report.steps[0]); + + return [ + parseNavigationResults(navigationReports), + parseTimespanResults(timespanReports), + ] as const; +} diff --git a/packages/scripts/src/generateLighthouseReport/postComment.ts.ts b/packages/scripts/src/generateLighthouseReport/postComment.ts.ts deleted file mode 100644 index 3af2ef985c..0000000000 --- a/packages/scripts/src/generateLighthouseReport/postComment.ts.ts +++ /dev/null @@ -1,59 +0,0 @@ -import * as core from "@actions/core"; -import { getOctokit, context } from "@actions/github"; -import { NavigationResult, TimespanResult } from "./parseLighthouseReport"; - -export async function postComment({ - parsedNavigationReport, - parsedTimespanReport, -}: { - parsedNavigationReport: NavigationResult; - parsedTimespanReport: TimespanResult; -}) { - core.startGroup("Post comment"); - const github = getOctokit(process.env.GITHUB_TOKEN || ""); - - const { data: comment } = await github.rest.issues.createComment({ - ...context.repo, - issue_number: context.issue.number, - // Identation needs to be on the same level, otherwise github doesn't format it properly - // prettier-ignore - body: ` -
-❌ Lighthouse: Regression found - - - -Navigation: -| Name | Result | -|----------------------------|---------------------------------| -| Performance | ${parsedNavigationReport.performance * 100} | -| Accessibility | ${parsedNavigationReport.accessibility * 100} | -| Best Practices | ${parsedNavigationReport["best_practices"] * 100} | -| SEO | ${parsedNavigationReport.seo * 100} | -| First Contentful Paint | ${parsedNavigationReport.fcp.score * 100} (${parsedNavigationReport.fcp.displayValue}) | -| Largest Contentful Paint | ${parsedNavigationReport.lcp.score * 100} (${parsedNavigationReport.lcp.displayValue}) | -| Total Blocking Time | ${parsedNavigationReport.tbt.score * 100} (${parsedNavigationReport.tbt.displayValue}) | -| Cumulative Layout Shift | ${parsedNavigationReport.cls.score * 100} (${parsedNavigationReport.cls.displayValue}) | -| Speed Index | ${parsedNavigationReport.speed.score * 100} (${parsedNavigationReport.speed.displayValue}) | - - -Timespan: -| Name | Result | -|----------------------------|---------------------------------| -| Performance | ${parsedTimespanReport.performance.total * 100} | -| Total Blocking Time | ${parsedTimespanReport.performance.tbt.score * 100} (${parsedTimespanReport.performance.tbt.displayValue}) | -| Cumulative Layout Shift | ${parsedTimespanReport.performance.cls.score * 100} (${parsedTimespanReport.performance.cls.displayValue}) | -| Interaction to Next Paint | ${parsedTimespanReport.performance.inp.score * 100} (${parsedTimespanReport.performance.inp.displayValue}) | -| Best practices | ${parsedTimespanReport.best_practices * 100} | -| Long tasks | ${parsedTimespanReport.longTasks.total} (${parsedTimespanReport.longTasks.durationMs}ms) | - - -
- `, - }); - - core.info( - `Created comment id '${comment.id}' on issue '${context.issue.number}'.` - ); - core.endGroup(); -} From 77e8bd0ff4cdb3997ccb77374231f4c6aaaa07de Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 30 May 2025 18:04:46 +0000 Subject: [PATCH 070/103] WIP --- .../src/generateLighthouseReport/parseLighthouseReports.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts index bfd81e129e..663e2927bc 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts @@ -49,7 +49,7 @@ function parseNavigationResults( navigationReports: FlowResult.Step[] ): NavigationResult { const mergedReports = navigationReports.reduce( - (acc, report) => { + function parseNavigationResultsReduce(acc, report) { const fcp = parse(report, "first-contentful-paint"); const lcp = parse(report, "largest-contentful-paint"); const tbt = parse(report, "total-blocking-time"); @@ -146,7 +146,7 @@ function parseTimespanResults( timespanReports: FlowResult.Step[] ): TimespanResult { const mergedReports = timespanReports.reduce( - (acc, report) => { + function parseTimespanResultsReduce(acc, report) { const tbt = parse(report, "total-blocking-time"); const cls = parse(report, "cumulative-layout-shift"); const inp = parse(report, "interaction-to-next-paint"); @@ -159,6 +159,7 @@ function parseTimespanResults( }[]; } ).items; + return { performance: { total: From a8e8f6d23b3306f1ff3b31e2bbd10a9fbf08b188 Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 30 May 2025 20:11:09 +0000 Subject: [PATCH 071/103] Add tests --- .../parseLighthouseReports.ts | 177 +- .../generateLighthouseReport/postComment.ts | 30 +- .../tests/__mocks__/output.json | 26898 ++++++++++++++++ .../parseLighthouseReports.test.ts.snap | 53 + .../tests/parseLighthouseReports.test.ts | 38 + .../generateLighthouseReport/tests/setup.ts | 8 + 6 files changed, 27106 insertions(+), 98 deletions(-) create mode 100644 packages/scripts/src/generateLighthouseReport/tests/__mocks__/output.json create mode 100644 packages/scripts/src/generateLighthouseReport/tests/__snapshots__/parseLighthouseReports.test.ts.snap create mode 100644 packages/scripts/src/generateLighthouseReport/tests/parseLighthouseReports.test.ts create mode 100644 packages/scripts/src/generateLighthouseReport/tests/setup.ts diff --git a/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts b/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts index 663e2927bc..ccea949de2 100644 --- a/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts +++ b/packages/scripts/src/generateLighthouseReport/parseLighthouseReports.ts @@ -17,12 +17,10 @@ export type NavigationResult = { seo: number; }; export type TimespanResult = { - performance: { - total: number; - tbt: Metric; - cls: Metric; - inp: Metric; - }; + performance: number; + tbt: Metric; + cls: Metric; + inp: Metric; best_practices: number; longTasks: { total: number; @@ -40,12 +38,36 @@ function parse(result: FlowResult.Step, metricName: string): Metric { const metric = result.lhr.audits[metricName]; return { - score: metric.score!, - numericValue: Number(metric.numericUnit)!, + score: metric.score || 0, + numericValue: metric.numericValue || 0, + }; +} + +function parseToFixedNumber(num: number, fractionDigits: number) { + return Number(num.toFixed(fractionDigits)); +} + +function generateMetric({ + key, + length, + report, +}: { + key: TKey; + length: number; + report: { + [key in TKey]: { + numericValue: number; + score: number; + }; + }; +}) { + return { + numericValue: parseToFixedNumber(report[key].numericValue / length, 3), + score: parseToFixedNumber((report[key].score / length) * 100, 2), }; } -function parseNavigationResults( +export function parseNavigationResults( navigationReports: FlowResult.Step[] ): NavigationResult { const mergedReports = navigationReports.reduce( @@ -77,12 +99,14 @@ function parseNavigationResults( numericValue: acc.speed.numericValue + (speed.numericValue || 0), score: acc.speed.score + (speed.score || 0), }, - performance: acc.performance + report.lhr.categories.performance.score!, + performance: + acc.performance + (report.lhr.categories.performance.score || 0), accessibility: - acc.accessibility + report.lhr.categories.accessibility.score!, + acc.accessibility + (report.lhr.categories.accessibility.score || 0), best_practices: - acc.best_practices + report.lhr.categories["best-practices"].score!, - seo: acc.seo + report.lhr.categories.seo.score!, + acc.best_practices + + (report.lhr.categories["best-practices"].score || 0), + seo: acc.seo + (report.lhr.categories.seo.score || 0), }; }, { @@ -115,34 +139,28 @@ function parseNavigationResults( const length = navigationReports.length; return { - fcp: { - numericValue: mergedReports.fcp.numericValue / length, - score: mergedReports.fcp.score / length, - }, - lcp: { - numericValue: mergedReports.lcp.numericValue / length, - score: mergedReports.lcp.score / length, - }, - tbt: { - numericValue: mergedReports.tbt.numericValue / length, - score: mergedReports.tbt.score / length, - }, - cls: { - numericValue: mergedReports.cls.numericValue / length, - score: mergedReports.cls.score / length, - }, - speed: { - numericValue: mergedReports.speed.numericValue / length, - score: mergedReports.speed.score / length, - }, - performance: mergedReports.performance / length, - accessibility: mergedReports.accessibility / length, - best_practices: mergedReports.best_practices / length, - seo: mergedReports.seo / length, + fcp: generateMetric({ key: "fcp", length, report: mergedReports }), + lcp: generateMetric({ key: "lcp", length, report: mergedReports }), + tbt: generateMetric({ key: "tbt", length, report: mergedReports }), + cls: generateMetric({ key: "cls", length, report: mergedReports }), + speed: generateMetric({ key: "speed", length, report: mergedReports }), + performance: parseToFixedNumber( + (mergedReports.performance / length) * 100, + 2 + ), + accessibility: parseToFixedNumber( + (mergedReports.accessibility / length) * 100, + 2 + ), + best_practices: parseToFixedNumber( + (mergedReports.best_practices / length) * 100, + 2 + ), + seo: parseToFixedNumber((mergedReports.seo / length) * 100, 2), }; } -function parseTimespanResults( +export function parseTimespanResults( timespanReports: FlowResult.Step[] ): TimespanResult { const mergedReports = timespanReports.reduce( @@ -161,22 +179,19 @@ function parseTimespanResults( ).items; return { - performance: { - total: - acc.performance.total + - (report.lhr.categories.performance.score || 0), - tbt: { - numericValue: acc.performance.tbt.numericValue + tbt.numericValue, - score: acc.performance.tbt.score + tbt.score, - }, - cls: { - numericValue: acc.performance.cls.numericValue + cls.numericValue, - score: acc.performance.cls.score + cls.score, - }, - inp: { - numericValue: acc.performance.inp.numericValue + inp.numericValue, - score: acc.performance.inp.score + inp.score, - }, + performance: + acc.performance + (report.lhr.categories.performance.score || 0), + tbt: { + numericValue: acc.tbt.numericValue + tbt.numericValue, + score: acc.tbt.score + tbt.score, + }, + cls: { + numericValue: acc.cls.numericValue + cls.numericValue, + score: acc.cls.score + cls.score, + }, + inp: { + numericValue: acc.inp.numericValue + inp.numericValue, + score: acc.inp.score + inp.score, }, best_practices: acc.best_practices + @@ -191,18 +206,16 @@ function parseTimespanResults( }; }, { - performance: { - total: 0, - tbt: { - numericValue: 0, - score: 0, - }, - cls: { - numericValue: 0, - score: 0, - }, - inp: { numericValue: 0, score: 0 }, + performance: 0, + tbt: { + numericValue: 0, + score: 0, + }, + cls: { + numericValue: 0, + score: 0, }, + inp: { numericValue: 0, score: 0 }, best_practices: 0, longTasks: { total: 0, @@ -213,25 +226,23 @@ function parseTimespanResults( const length = timespanReports.length; return { - performance: { - total: mergedReports.performance.total / length, - tbt: { - numericValue: mergedReports.performance.tbt.numericValue, - score: mergedReports.performance.tbt.numericValue, - }, - cls: { - numericValue: mergedReports.performance.cls.numericValue, - score: mergedReports.performance.cls.numericValue, - }, - inp: { - numericValue: mergedReports.performance.inp.numericValue, - score: mergedReports.performance.inp.numericValue, - }, - }, - best_practices: mergedReports.best_practices / length, + performance: parseToFixedNumber( + (mergedReports.performance / length) * 100, + 2 + ), + tbt: generateMetric({ key: "tbt", length, report: mergedReports }), + cls: generateMetric({ key: "cls", length, report: mergedReports }), + inp: generateMetric({ key: "inp", length, report: mergedReports }), + best_practices: parseToFixedNumber( + (mergedReports.best_practices / length) * 100, + 2 + ), longTasks: { - total: mergedReports.longTasks.total / length, - durationMs: mergedReports.longTasks.durationMs / length, + total: parseToFixedNumber(mergedReports.longTasks.total / length, 0), + durationMs: parseToFixedNumber( + mergedReports.longTasks.durationMs / length, + 3 + ), }, }; } diff --git a/packages/scripts/src/generateLighthouseReport/postComment.ts b/packages/scripts/src/generateLighthouseReport/postComment.ts index 41be5a4e97..a9ff4d2b25 100644 --- a/packages/scripts/src/generateLighthouseReport/postComment.ts +++ b/packages/scripts/src/generateLighthouseReport/postComment.ts @@ -26,26 +26,26 @@ export async function postComment({ Navigation: | Name | Result | |----------------------------|---------------------------------| -| Performance | ${(parsedNavigationReport.performance * 100).toFixed(0)} | -| Accessibility | ${(parsedNavigationReport.accessibility * 100).toFixed(0)} | -| Best Practices | ${(parsedNavigationReport["best_practices"] * 100).toFixed(0)} | -| SEO | ${(parsedNavigationReport.seo * 100).toFixed(0)} | -| First Contentful Paint | ${(parsedNavigationReport.fcp.score * 100).toFixed(0)} ((${parsedNavigationReport.fcp.numericValue.toFixed(3)})s) | -| Largest Contentful Paint | ${(parsedNavigationReport.lcp.score * 100).toFixed(0)} (${parsedNavigationReport.lcp.numericValue.toFixed(3)}s) | -| Total Blocking Time | ${(parsedNavigationReport.tbt.score * 100).toFixed(0)} (${parsedNavigationReport.tbt.numericValue.toFixed(3)}ms) | -| Cumulative Layout Shift | ${(parsedNavigationReport.cls.score * 100).toFixed(0)} (${parsedNavigationReport.cls.numericValue.toFixed(3)}) | -| Speed Index | ${(parsedNavigationReport.speed.score * 100).toFixed(0)} (${parsedNavigationReport.speed.numericValue.toFixed(3)}s) | +| Performance | ${parsedNavigationReport.performance} | +| Accessibility | ${parsedNavigationReport.accessibility} | +| Best Practices | ${parsedNavigationReport["best_practices"]} | +| SEO | ${parsedNavigationReport.seo} | +| First Contentful Paint | ${parsedNavigationReport.fcp.score} (${parsedNavigationReport.fcp.numericValue})s) | +| Largest Contentful Paint | ${parsedNavigationReport.lcp.score} (${parsedNavigationReport.lcp.numericValue}s) | +| Total Blocking Time | ${parsedNavigationReport.tbt.score} (${parsedNavigationReport.tbt.numericValue}ms) | +| Cumulative Layout Shift | ${parsedNavigationReport.cls.score} (${parsedNavigationReport.cls.numericValue}) | +| Speed Index | ${parsedNavigationReport.speed.score} (${parsedNavigationReport.speed.numericValue}s) | Timespan: | Name | Result | |----------------------------|---------------------------------| -| Performance | ${(parsedTimespanReport.performance.total * 100).toFixed(0)} | -| Total Blocking Time | ${(parsedTimespanReport.performance.tbt.score * 100).toFixed(0)} (${parsedTimespanReport.performance.tbt.numericValue}ms) | -| Cumulative Layout Shift | ${(parsedTimespanReport.performance.cls.score * 100).toFixed(0)} (${parsedTimespanReport.performance.cls.numericValue}) | -| Interaction to Next Paint | ${(parsedTimespanReport.performance.inp.score * 100).toFixed(0)} (${parsedTimespanReport.performance.inp.numericValue}ms) | -| Best practices | ${(parsedTimespanReport.best_practices * 100).toFixed(0)} | -| Long tasks | ${(parsedTimespanReport.longTasks.total).toFixed(0)} (${(parsedTimespanReport.longTasks.durationMs).toFixed(2)}ms) | +| Performance | ${parsedTimespanReport.performance} | +| Total Blocking Time | ${parsedTimespanReport.tbt.score} (${parsedTimespanReport.tbt.numericValue}ms) | +| Cumulative Layout Shift | ${parsedTimespanReport.cls.score} (${parsedTimespanReport.cls.numericValue}) | +| Interaction to Next Paint | ${parsedTimespanReport.inp.score} (${parsedTimespanReport.inp.numericValue}ms) | +| Best practices | ${parsedTimespanReport.best_practices} | +| Long tasks | ${parsedTimespanReport.longTasks.total} (${parsedTimespanReport.longTasks.durationMs}ms) | diff --git a/packages/scripts/src/generateLighthouseReport/tests/__mocks__/output.json b/packages/scripts/src/generateLighthouseReport/tests/__mocks__/output.json new file mode 100644 index 0000000000..aae824832d --- /dev/null +++ b/packages/scripts/src/generateLighthouseReport/tests/__mocks__/output.json @@ -0,0 +1,26898 @@ +{ + "steps": [ + { + "lhr": { + "lighthouseVersion": "12.6.0", + "requestedUrl": "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0", + "mainDocumentUrl": "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0", + "finalDisplayedUrl": "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0", + "finalUrl": "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0", + "fetchTime": "2025-05-30T19:04:56.257Z", + "gatherMode": "navigation", + "runWarnings": [], + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36", + "environment": { + "networkUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "hostUserAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36", + "benchmarkIndex": 3387.5, + "credits": { + "axe-core": "4.10.3" + } + }, + "audits": { + "is-on-https": { + "id": "is-on-https", + "title": "Uses HTTPS", + "description": "All sites should be protected with HTTPS, even ones that don't handle sensitive data. This includes avoiding [mixed content](https://developers.google.com/web/fundamentals/security/prevent-mixed-content/what-is-mixed-content), where some resources are loaded over HTTP despite the initial request being served over HTTPS. HTTPS prevents intruders from tampering with or passively listening in on the communications between your app and your users, and is a prerequisite for HTTP/2 and many new web platform APIs. [Learn more about HTTPS](https://developer.chrome.com/docs/lighthouse/pwa/is-on-https/).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "redirects-http": { + "id": "redirects-http", + "title": "Redirects HTTP traffic to HTTPS", + "description": "Make sure that you redirect all HTTP traffic to HTTPS in order to enable secure web features for all your users. [Learn more](https://developer.chrome.com/docs/lighthouse/pwa/redirects-http/).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "viewport": { + "id": "viewport", + "title": "Has a `` tag with `width` or `initial-scale`", + "description": "A `` not only optimizes your app for mobile screen sizes, but also prevents [a 300 millisecond delay to user input](https://developer.chrome.com/blog/300ms-tap-delay-gone-away/). [Learn more about using the viewport meta tag](https://developer.chrome.com/docs/lighthouse/pwa/viewport/).", + "score": 1, + "scoreDisplayMode": "metricSavings", + "warnings": [], + "metricSavings": { + "INP": 0 + }, + "details": { + "type": "debugdata", + "viewportContent": "width=device-width, initial-scale=1" + }, + "guidanceLevel": 3 + }, + "first-contentful-paint": { + "id": "first-contentful-paint", + "title": "First Contentful Paint", + "description": "First Contentful Paint marks the time at which the first text or image is painted. [Learn more about the First Contentful Paint metric](https://developer.chrome.com/docs/lighthouse/performance/first-contentful-paint/).", + "score": 1, + "scoreDisplayMode": "numeric", + "numericValue": 442.24474999999995, + "numericUnit": "millisecond", + "displayValue": "0.4 s", + "scoringOptions": { + "p10": 934, + "median": 1600 + } + }, + "largest-contentful-paint": { + "id": "largest-contentful-paint", + "title": "Largest Contentful Paint", + "description": "Largest Contentful Paint marks the time at which the largest text or image is painted. [Learn more about the Largest Contentful Paint metric](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-largest-contentful-paint/)", + "score": 0.03, + "scoreDisplayMode": "numeric", + "numericValue": 6386.565749999998, + "numericUnit": "millisecond", + "displayValue": "6.4 s", + "scoringOptions": { + "p10": 1200, + "median": 2400 + } + }, + "first-meaningful-paint": { + "id": "first-meaningful-paint", + "title": "First Meaningful Paint", + "description": "First Meaningful Paint measures when the primary content of a page is visible. [Learn more about the First Meaningful Paint metric](https://developer.chrome.com/docs/lighthouse/performance/first-meaningful-paint/).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "speed-index": { + "id": "speed-index", + "title": "Speed Index", + "description": "Speed Index shows how quickly the contents of a page are visibly populated. [Learn more about the Speed Index metric](https://developer.chrome.com/docs/lighthouse/performance/speed-index/).", + "score": 0.01, + "scoreDisplayMode": "numeric", + "numericValue": 5786.937630172584, + "numericUnit": "millisecond", + "displayValue": "5.8 s", + "scoringOptions": { + "p10": 1311, + "median": 2300 + } + }, + "screenshot-thumbnails": { + "id": "screenshot-thumbnails", + "title": "Screenshot Thumbnails", + "description": "This is what the load of your site looked like.", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "filmstrip", + "scale": 5187, + "items": [ + { + "timing": 648, + "timestamp": 31363305945, + "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2MBERISGBUYLxoaL2NCOEJjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY//AABEIAVwB9AMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/APQKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//9k=" + }, + { + "timing": 1297, + "timestamp": 31363954320, + "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2MBERISGBUYLxoaL2NCOEJjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY//AABEIAVwB9AMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/APQKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//9k=" + }, + { + "timing": 1945, + "timestamp": 31364602695, + "data": "data:image/jpeg;base64,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" + }, + { + "timing": 2594, + "timestamp": 31365251070, + "data": "data:image/jpeg;base64,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" + }, + { + "timing": 3242, + "timestamp": 31365899445, + "data": "data:image/jpeg;base64,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" + }, + { + "timing": 3890, + "timestamp": 31366547820, + "data": "data:image/jpeg;base64,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" + }, + { + "timing": 4539, + "timestamp": 31367196195, + "data": "data:image/jpeg;base64,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" + }, + { + "timing": 5187, + "timestamp": 31367844570, + "data": "data:image/jpeg;base64,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" + } + ] + } + }, + "final-screenshot": { + "id": "final-screenshot", + "title": "Final Screenshot", + "description": "The last screenshot captured of the pageload.", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "screenshot", + "timing": 5188, + "timestamp": 31367845236, + "data": "data:image/jpeg;base64,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" + } + }, + "total-blocking-time": { + "id": "total-blocking-time", + "title": "Total Blocking Time", + "description": "Sum of all time periods between FCP and Time to Interactive, when task length exceeded 50ms, expressed in milliseconds. [Learn more about the Total Blocking Time metric](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-total-blocking-time/).", + "score": 0, + "scoreDisplayMode": "numeric", + "numericValue": 2630, + "numericUnit": "millisecond", + "displayValue": "2,630 ms", + "scoringOptions": { + "p10": 150, + "median": 350 + } + }, + "max-potential-fid": { + "id": "max-potential-fid", + "title": "Max Potential First Input Delay", + "description": "The maximum potential First Input Delay that your users could experience is the duration of the longest task. [Learn more about the Maximum Potential First Input Delay metric](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-max-potential-fid/).", + "score": 0, + "scoreDisplayMode": "numeric", + "numericValue": 1196, + "numericUnit": "millisecond", + "displayValue": "1,200 ms" + }, + "cumulative-layout-shift": { + "id": "cumulative-layout-shift", + "title": "Cumulative Layout Shift", + "description": "Cumulative Layout Shift measures the movement of visible elements within the viewport. [Learn more about the Cumulative Layout Shift metric](https://web.dev/articles/cls).", + "score": 1, + "scoreDisplayMode": "numeric", + "numericValue": 0, + "numericUnit": "unitless", + "displayValue": "0", + "scoringOptions": { + "p10": 0.1, + "median": 0.25 + }, + "details": { + "type": "debugdata", + "items": [ + { + "cumulativeLayoutShiftMainFrame": 0, + "newEngineResult": { + "cumulativeLayoutShift": 0, + "cumulativeLayoutShiftMainFrame": 0 + }, + "newEngineResultDiffered": false + } + ] + } + }, + "errors-in-console": { + "id": "errors-in-console", + "title": "Browser errors were logged to the console", + "description": "Errors logged to the console indicate unresolved problems. They can come from network request failures and other browser concerns. [Learn more about this errors in console diagnostic audit](https://developer.chrome.com/docs/lighthouse/best-practices/errors-in-console/)", + "score": 0, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "sourceLocation", + "valueType": "source-location", + "label": "Source" + }, + { + "key": "description", + "valueType": "code", + "label": "Description" + } + ], + "items": [ + { + "source": "console.error", + "description": "[PostHog.js] PostHog was initialized without a token. This likely indicates a misconfiguration. Please check the first argument passed to posthog.init()", + "sourceLocation": { + "type": "source-location", + "url": "webpack-internal:///../../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/hydration-error-info.js", + "urlProvider": "network", + "line": 70, + "column": 13 + } + }, + { + "source": "network", + "description": "Failed to load resource: net::ERR_CONNECTION_REFUSED", + "sourceLocation": { + "type": "source-location", + "url": "http://127.0.0.1:8547/", + "urlProvider": "network", + "line": 0, + "column": 0 + } + }, + { + "source": "network", + "description": "Failed to load resource: net::ERR_CONNECTION_REFUSED", + "sourceLocation": { + "type": "source-location", + "url": "http://127.0.0.1:8547/", + "urlProvider": "network", + "line": 0, + "column": 0 + } + }, + { + "source": "network", + "description": "Failed to load resource: net::ERR_CONNECTION_REFUSED", + "sourceLocation": { + "type": "source-location", + "url": "http://127.0.0.1:8547/", + "urlProvider": "network", + "line": 0, + "column": 0 + } + }, + { + "source": "network", + "description": "Failed to load resource: net::ERR_CONNECTION_REFUSED", + "sourceLocation": { + "type": "source-location", + "url": "http://127.0.0.1:8547/", + "urlProvider": "network", + "line": 0, + "column": 0 + } + }, + { + "source": "console.error", + "description": "OVERMIND DEVTOOLS: Not able to connect. You are trying to connect to \"localhost:3031\", but there was no devtool there. Try the following:\n \n - Make sure you are running the latest version of the devtools, using \"npx overmind-devtools@latest\" or install latest extension for VSCode\n - Close the current tab and open a new one\n - Make sure the correct port is configured in the devtools\n ", + "sourceLocation": { + "type": "source-location", + "url": "webpack-internal:///../../node_modules/next/dist/client/components/react-dev-overlay/internal/helpers/hydration-error-info.js", + "urlProvider": "network", + "line": 70, + "column": 13 + } + }, + { + "source": "network", + "description": "WebSocket connection to 'ws://localhost:3031/?name=Bridge%20to%20Arbitrum%20One' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED", + "sourceLocation": { + "type": "source-location", + "url": "webpack-internal:///../../node_modules/overmind/es/Devtools.js", + "urlProvider": "network", + "line": 20, + "column": 22 + } + } + ] + } + }, + "server-response-time": { + "id": "server-response-time", + "title": "Initial server response time was short", + "description": "Keep the server response time for the main document short because all other requests depend on it. [Learn more about the Time to First Byte metric](https://developer.chrome.com/docs/lighthouse/performance/time-to-first-byte/).", + "score": 1, + "scoreDisplayMode": "metricSavings", + "numericValue": 24.311, + "numericUnit": "millisecond", + "displayValue": "Root document took 20 ms", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, + "details": { + "type": "opportunity", + "headings": [ + { + "key": "url", + "valueType": "url", + "label": "URL" + }, + { + "key": "responseTime", + "valueType": "timespanMs", + "label": "Time Spent" + } + ], + "items": [ + { + "url": "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0", + "responseTime": 24.311 + } + ], + "overallSavingsMs": 0 + }, + "guidanceLevel": 1 + }, + "interactive": { + "id": "interactive", + "title": "Time to Interactive", + "description": "Time to Interactive is the amount of time it takes for the page to become fully interactive. [Learn more about the Time to Interactive metric](https://developer.chrome.com/docs/lighthouse/performance/interactive/).", + "score": 0, + "scoreDisplayMode": "numeric", + "numericValue": 15824.922262500015, + "numericUnit": "millisecond", + "displayValue": "15.8 s" + }, + "user-timings": { + "id": "user-timings", + "title": "User Timing marks and measures", + "description": "Consider instrumenting your app with the User Timing API to measure your app's real-world performance during key user experiences. [Learn more about User Timing marks](https://developer.chrome.com/docs/lighthouse/performance/user-timings/).", + "score": 1, + "scoreDisplayMode": "informative", + "displayValue": "4 user timings", + "details": { + "type": "table", + "headings": [ + { + "key": "name", + "valueType": "text", + "label": "Name" + }, + { + "key": "timingType", + "valueType": "text", + "label": "Type" + }, + { + "key": "startTime", + "valueType": "ms", + "granularity": 0.01, + "label": "Start Time" + }, + { + "key": "duration", + "valueType": "ms", + "granularity": 0.01, + "label": "Duration" + } + ], + "items": [ + { + "name": "Next.js-before-hydration", + "startTime": 0, + "duration": 1768.372, + "timingType": "Measure" + }, + { + "name": "Next.js-hydration", + "startTime": 1768.372, + "duration": 32.067, + "timingType": "Measure" + }, + { + "name": "beforeRender", + "startTime": 1768.372, + "timingType": "Mark" + }, + { + "name": "afterHydrate", + "startTime": 1800.439, + "timingType": "Mark" + } + ] + }, + "guidanceLevel": 2 + }, + "critical-request-chains": { + "id": "critical-request-chains", + "title": "Avoid chaining critical requests", + "description": "The Critical Request Chains below show you what resources are loaded with a high priority. Consider reducing the length of chains, reducing the download size of resources, or deferring the download of unnecessary resources to improve page load. [Learn how to avoid chaining critical requests](https://developer.chrome.com/docs/lighthouse/performance/critical-request-chains/).", + "score": 1, + "scoreDisplayMode": "informative", + "displayValue": "1 chain found", + "details": { + "type": "criticalrequestchain", + "chains": { + "D7DAA8A36A4A8B8F6DA92B5D47DDD0D3": { + "request": { + "url": "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0", + "startTime": 31362.659238, + "endTime": 31362.684541, + "responseReceivedTime": 31362.683994000003, + "transferSize": 1685 + }, + "children": { + "27474.11": { + "request": { + "url": "http://localhost:3000/_next/static/chunks/react-refresh.js", + "startTime": 31362.690642, + "endTime": 31362.697673, + "responseReceivedTime": 31362.696745999998, + "transferSize": 25433 + } + } + } + } + }, + "longestChain": { + "duration": 38.434999998658895, + "length": 2, + "transferSize": 25433 + } + }, + "guidanceLevel": 1 + }, + "redirects": { + "id": "redirects", + "title": "Avoid multiple page redirects", + "description": "Redirects introduce additional delays before the page can be loaded. [Learn how to avoid page redirects](https://developer.chrome.com/docs/lighthouse/performance/redirects/).", + "score": 1, + "scoreDisplayMode": "metricSavings", + "numericValue": 0, + "numericUnit": "millisecond", + "displayValue": "", + "metricSavings": { + "LCP": 0, + "FCP": 0 + }, + "details": { + "type": "opportunity", + "headings": [], + "items": [], + "overallSavingsMs": 0 + }, + "guidanceLevel": 2 + }, + "image-aspect-ratio": { + "id": "image-aspect-ratio", + "title": "Displays images with correct aspect ratio", + "description": "Image display dimensions should match natural aspect ratio. [Learn more about image aspect ratio](https://developer.chrome.com/docs/lighthouse/best-practices/image-aspect-ratio/).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "image-size-responsive": { + "id": "image-size-responsive", + "title": "Serves images with appropriate resolution", + "description": "Image natural dimensions should be proportional to the display size and the pixel ratio to maximize image clarity. [Learn how to provide responsive images](https://web.dev/articles/serve-responsive-images).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "deprecations": { + "id": "deprecations", + "title": "Avoids deprecated APIs", + "description": "Deprecated APIs will eventually be removed from the browser. [Learn more about deprecated APIs](https://developer.chrome.com/docs/lighthouse/best-practices/deprecations/).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "third-party-cookies": { + "id": "third-party-cookies", + "title": "Avoids third-party cookies", + "description": "Third-party cookies may be blocked in some contexts. [Learn more about preparing for third-party cookie restrictions](https://privacysandbox.google.com/cookies/prepare/overview).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "mainthread-work-breakdown": { + "id": "mainthread-work-breakdown", + "title": "Minimize main-thread work", + "description": "Consider reducing the time spent parsing, compiling and executing JS. You may find delivering smaller JS payloads helps with this. [Learn how to minimize main-thread work](https://developer.chrome.com/docs/lighthouse/performance/mainthread-work-breakdown/)", + "score": 0, + "scoreDisplayMode": "metricSavings", + "numericValue": 4661.641000000063, + "numericUnit": "millisecond", + "displayValue": "4.7 s", + "metricSavings": { + "TBT": 2650 + }, + "details": { + "type": "table", + "headings": [ + { + "key": "groupLabel", + "valueType": "text", + "label": "Category" + }, + { + "key": "duration", + "valueType": "ms", + "granularity": 1, + "label": "Time Spent" + } + ], + "items": [ + { + "group": "scriptParseCompile", + "groupLabel": "Script Parsing & Compilation", + "duration": 3230.0540000001097 + }, + { + "group": "scriptEvaluation", + "groupLabel": "Script Evaluation", + "duration": 1194.2339999999524 + }, + { + "group": "other", + "groupLabel": "Other", + "duration": 161.93500000000057 + }, + { + "group": "garbageCollection", + "groupLabel": "Garbage Collection", + "duration": 42.045000000000016 + }, + { + "group": "styleLayout", + "groupLabel": "Style & Layout", + "duration": 27.511000000000013 + }, + { + "group": "paintCompositeRender", + "groupLabel": "Rendering", + "duration": 2.960999999999995 + }, + { + "group": "parseHTML", + "groupLabel": "Parse HTML & CSS", + "duration": 2.9009999999999994 + } + ], + "sortedBy": [ + "duration" + ] + }, + "guidanceLevel": 1 + }, + "bootup-time": { + "id": "bootup-time", + "title": "Reduce JavaScript execution time", + "description": "Consider reducing the time spent parsing, compiling, and executing JS. You may find delivering smaller JS payloads helps with this. [Learn how to reduce Javascript execution time](https://developer.chrome.com/docs/lighthouse/performance/bootup-time/).", + "score": 0, + "scoreDisplayMode": "metricSavings", + "numericValue": 4345.536000000076, + "numericUnit": "millisecond", + "displayValue": "4.3 s", + "metricSavings": { + "TBT": 2650 + }, + "details": { + "type": "table", + "headings": [ + { + "key": "url", + "valueType": "url", + "label": "URL" + }, + { + "key": "total", + "granularity": 1, + "valueType": "ms", + "label": "Total CPU Time" + }, + { + "key": "scripting", + "granularity": 1, + "valueType": "ms", + "label": "Script Evaluation" + }, + { + "key": "scriptParseCompile", + "granularity": 1, + "valueType": "ms", + "label": "Script Parse" + } + ], + "items": [ + { + "url": "http://localhost:3000/_next/static/chunks/src_components_App_App_tsx.js", + "total": 2392.5660000000803, + "scripting": 181.6330000000002, + "scriptParseCompile": 2188.1670000000795 + }, + { + "url": "http://localhost:3000/_next/static/chunks/pages/_app.js", + "total": 1169.038999999994, + "scripting": 344.98599999999425, + "scriptParseCompile": 818.1769999999999 + }, + { + "url": "http://localhost:3000/_next/static/chunks/main.js", + "total": 341.58799999999957, + "scripting": 221.23599999999956, + "scriptParseCompile": 116.766 + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_ethereum-provider_dist_index_es_js.js", + "total": 145.26000000000204, + "scripting": 99.19300000000203, + "scriptParseCompile": 37.504 + }, + { + "url": "Unattributable", + "total": 140.86500000000157, + "scripting": 9.475999999999994, + "scriptParseCompile": 0 + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_offchainlabs_cobalt_dist_cobalt_es_js.js", + "total": 82.45600000000012, + "scripting": 67.12700000000011, + "scriptParseCompile": 11.775000000000002 + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_modal-ui_dist_index_js.js", + "total": 75.68499999999992, + "scripting": 50.400999999999904, + "scriptParseCompile": 22.612000000000002 + }, + { + "url": "webpack-internal:///../../node_modules/scheduler/cjs/scheduler.development.js", + "total": 70.4140000000001, + "scripting": 69.2150000000001, + "scriptParseCompile": 0 + }, + { + "url": "webpack-internal:///../../node_modules/idb-keyval/dist/index.js", + "total": 60.43000000000005, + "scripting": 55.07600000000005, + "scriptParseCompile": 0 + }, + { + "url": "http://localhost:3000/_next/static/chunks/pages/index.js", + "total": 52.19200000000005, + "scripting": 37.15200000000005, + "scriptParseCompile": 15.04 + } + ], + "summary": { + "wastedMs": 4345.536000000076 + }, + "sortedBy": [ + "total" + ] + }, + "guidanceLevel": 1 + }, + "uses-rel-preconnect": { + "id": "uses-rel-preconnect", + "title": "Preconnect to required origins", + "description": "Consider adding `preconnect` or `dns-prefetch` resource hints to establish early connections to important third-party origins. [Learn how to preconnect to required origins](https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/).", + "score": 0, + "scoreDisplayMode": "metricSavings", + "numericValue": 118.932, + "numericUnit": "millisecond", + "displayValue": "Est savings of 120 ms", + "warnings": [], + "metricSavings": { + "LCP": 100, + "FCP": 100 + }, + "details": { + "type": "opportunity", + "headings": [ + { + "key": "url", + "valueType": "url", + "label": "URL" + }, + { + "key": "wastedMs", + "valueType": "timespanMs", + "label": "Est Savings" + } + ], + "items": [ + { + "url": "https://fonts.googleapis.com", + "wastedMs": 118.932 + } + ], + "overallSavingsMs": 118.932, + "sortedBy": [ + "wastedMs" + ] + }, + "guidanceLevel": 3 + }, + "font-display": { + "id": "font-display", + "title": "Ensure text remains visible during webfont load", + "description": "Leverage the `font-display` CSS feature to ensure text is user-visible while webfonts are loading. [Learn more about `font-display`](https://developer.chrome.com/docs/lighthouse/performance/font-display/).", + "score": 0.5, + "scoreDisplayMode": "metricSavings", + "warnings": [], + "details": { + "type": "table", + "headings": [ + { + "key": "url", + "valueType": "url", + "label": "URL" + }, + { + "key": "wastedMs", + "valueType": "ms", + "label": "Est Savings" + } + ], + "items": [ + { + "url": "https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3yUBHMdazQ.woff2", + "wastedMs": 21.74099999666214 + } + ] + }, + "guidanceLevel": 3 + }, + "diagnostics": { + "id": "diagnostics", + "title": "Diagnostics", + "description": "Collection of useful page vitals.", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "debugdata", + "items": [ + { + "numRequests": 64, + "numScripts": 23, + "numStylesheets": 1, + "numFonts": 4, + "numTasks": 3336, + "numTasksOver10ms": 14, + "numTasksOver25ms": 9, + "numTasksOver50ms": 7, + "numTasksOver100ms": 4, + "numTasksOver500ms": 2, + "rtt": 0, + "throughput": 120020378.17802115, + "maxRtt": 27.57, + "maxServerLatency": 30.154, + "totalByteWeight": 17480764, + "totalTaskTime": 4661.641000000021, + "mainDocumentTransferSize": 1685 + } + ] + } + }, + "network-requests": { + "id": "network-requests", + "title": "Network Requests", + "description": "Lists the network requests that were made during page load.", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "table", + "headings": [ + { + "key": "url", + "valueType": "url", + "label": "URL" + }, + { + "key": "protocol", + "valueType": "text", + "label": "Protocol" + }, + { + "key": "networkRequestTime", + "valueType": "ms", + "granularity": 1, + "label": "Network Request Time" + }, + { + "key": "networkEndTime", + "valueType": "ms", + "granularity": 1, + "label": "Network End Time" + }, + { + "key": "transferSize", + "valueType": "bytes", + "displayUnit": "kb", + "granularity": 1, + "label": "Transfer Size" + }, + { + "key": "resourceSize", + "valueType": "bytes", + "displayUnit": "kb", + "granularity": 1, + "label": "Resource Size" + }, + { + "key": "statusCode", + "valueType": "text", + "label": "Status Code" + }, + { + "key": "mimeType", + "valueType": "text", + "label": "MIME Type" + }, + { + "key": "resourceType", + "valueType": "text", + "label": "Resource Type" + } + ], + "items": [ + { + "url": "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 0, + "networkRequestTime": 0.6770000010728836, + "networkEndTime": 25.979999996721745, + "finished": true, + "transferSize": 1685, + "resourceSize": 4734, + "statusCode": 200, + "mimeType": "text/html", + "resourceType": "Document", + "priority": "VeryHigh", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/media/e1d74c7d0918b0fb-s.p.woff2", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 30.281999997794628, + "networkRequestTime": 30.83500000089407, + "networkEndTime": 39.99100000038743, + "finished": true, + "transferSize": 72022, + "resourceSize": 71721, + "statusCode": 200, + "mimeType": "font/woff2", + "resourceType": "Font", + "priority": "High", + "isLinkPreload": true, + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/media/47bad734875a3c19-s.p.woff2", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 30.534000001847744, + "networkRequestTime": 31.096999999135733, + "networkEndTime": 40.40299999713898, + "finished": true, + "transferSize": 73529, + "resourceSize": 73228, + "statusCode": 200, + "mimeType": "font/woff2", + "resourceType": "Font", + "priority": "High", + "isLinkPreload": true, + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/media/a0dda0300042e3c7-s.p.woff2", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 30.682000000029802, + "networkRequestTime": 31.3260000012815, + "networkEndTime": 40.19200000166893, + "finished": true, + "transferSize": 74635, + "resourceSize": 74334, + "statusCode": 200, + "mimeType": "font/woff2", + "resourceType": "Font", + "priority": "High", + "isLinkPreload": true, + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/webpack.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 30.822999998927116, + "networkRequestTime": 36.493000000715256, + "networkEndTime": 48.94700000062585, + "finished": true, + "transferSize": 10384, + "resourceSize": 53011, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/main.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 30.943999998271465, + "networkRequestTime": 36.82899999991059, + "networkEndTime": 158.5190000012517, + "finished": true, + "transferSize": 1177149, + "resourceSize": 5287954, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/pages/_app.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 31.07599999755621, + "networkRequestTime": 39.418000001460314, + "networkEndTime": 383.3449999988079, + "finished": true, + "transferSize": 3979857, + "resourceSize": 18915423, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/pages/index.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 31.195000000298023, + "networkRequestTime": 40.53700000047684, + "networkEndTime": 71.51000000163913, + "finished": true, + "transferSize": 196454, + "resourceSize": 895933, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/development/_buildManifest.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 31.313999999314547, + "networkRequestTime": 40.64799999818206, + "networkEndTime": 49.53000000119209, + "finished": true, + "transferSize": 633, + "resourceSize": 296, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/development/_ssgManifest.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 31.46900000050664, + "networkRequestTime": 40.76400000229478, + "networkEndTime": 50.05199999734759, + "finished": true, + "transferSize": 411, + "resourceSize": 76, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/react-refresh.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 31.605000000447035, + "networkRequestTime": 32.08100000023842, + "networkEndTime": 39.11199999973178, + "finished": true, + "transferSize": 25433, + "resourceSize": 79107, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700", + "sessionTargetType": "page", + "protocol": "h2", + "rendererStartTime": 983.8819999992847, + "networkRequestTime": 984.3619999997318, + "networkEndTime": 1132.8929999992251, + "finished": true, + "transferSize": 2318, + "resourceSize": 27200, + "statusCode": 200, + "mimeType": "text/css", + "resourceType": "Stylesheet", + "priority": "VeryHigh", + "experimentalFromMainFrame": true, + "entity": "Google Fonts" + }, + { + "url": "http://localhost:3000/_next/static/development/_devMiddlewareManifest.json", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 1744.6009999997914, + "networkRequestTime": 1745.2359999977052, + "networkEndTime": 1747.2919999994338, + "finished": true, + "transferSize": 213, + "resourceSize": 2, + "statusCode": 200, + "mimeType": "application/json", + "resourceType": "Fetch", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/logo.png", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 1761.6409999988973, + "networkRequestTime": 1762.0570000000298, + "networkEndTime": 1764.5969999991357, + "finished": true, + "transferSize": 22781, + "resourceSize": 22500, + "statusCode": 200, + "mimeType": "image/png", + "resourceType": "Other", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Feclipse_bottom.4304bd37.png&w=1920&q=75", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 1772.6860000006855, + "networkRequestTime": 1773.0720000006258, + "networkEndTime": 1779.062000002712, + "finished": true, + "transferSize": 477810, + "resourceSize": 477384, + "statusCode": 200, + "mimeType": "image/webp", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_offchainlabs_cobalt_dist_cobalt_es_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 1793.5509999990463, + "networkRequestTime": 1794.4749999977648, + "networkEndTime": 1809.2509999983013, + "finished": true, + "transferSize": 147417, + "resourceSize": 576083, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/api/status", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 1812.562999997288, + "networkRequestTime": 1813.2269999980927, + "networkEndTime": 1925.8379999995232, + "finished": true, + "transferSize": 1070, + "resourceSize": 3206, + "statusCode": 200, + "mimeType": "application/json", + "resourceType": "Fetch", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/api/status", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 1817.8459999971092, + "networkRequestTime": 1818.5679999999702, + "networkEndTime": 1957.3759999983013, + "finished": true, + "transferSize": 1072, + "resourceSize": 3206, + "statusCode": 200, + "mimeType": "application/json", + "resourceType": "Fetch", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6I…", + "sessionTargetType": "page", + "protocol": "data", + "rendererStartTime": 1912.9109999984503, + "networkRequestTime": 1912.9109999984503, + "networkEndTime": 1913.1499999985099, + "finished": true, + "transferSize": 0, + "resourceSize": 6129, + "statusCode": 200, + "mimeType": "image/svg+xml", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true + }, + { + "url": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6I…", + "sessionTargetType": "page", + "protocol": "data", + "rendererStartTime": 1913.7819999977946, + "networkRequestTime": 1913.7819999977946, + "networkEndTime": 1913.910000000149, + "finished": true, + "transferSize": 0, + "resourceSize": 2056, + "statusCode": 200, + "mimeType": "image/svg+xml", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true + }, + { + "url": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ib…", + "sessionTargetType": "page", + "protocol": "data", + "rendererStartTime": 1914.3499999977648, + "networkRequestTime": 1914.3499999977648, + "networkEndTime": 1914.4659999981523, + "finished": true, + "transferSize": 0, + "resourceSize": 1720, + "statusCode": 200, + "mimeType": "image/svg+xml", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true + }, + { + "url": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ib…", + "sessionTargetType": "page", + "protocol": "data", + "rendererStartTime": 1915.2939999997616, + "networkRequestTime": 1915.2939999997616, + "networkEndTime": 1915.3699999973178, + "finished": true, + "transferSize": 0, + "resourceSize": 1611, + "statusCode": 200, + "mimeType": "image/svg+xml", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true + }, + { + "url": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUiIGhlaWdodD0iMjUiIHZpZXdCb3g9IjAgMCAyNSAyNSIgZmlsbD0ib…", + "sessionTargetType": "page", + "protocol": "data", + "rendererStartTime": 1916.1579999998212, + "networkRequestTime": 1916.1579999998212, + "networkEndTime": 1916.2780000008643, + "finished": true, + "transferSize": 0, + "resourceSize": 2112, + "statusCode": 200, + "mimeType": "image/svg+xml", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true + }, + { + "url": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ib…", + "sessionTargetType": "page", + "protocol": "data", + "rendererStartTime": 1917.0289999991655, + "networkRequestTime": 1917.0289999991655, + "networkEndTime": 1917.1369999982417, + "finished": true, + "transferSize": 0, + "resourceSize": 1166, + "statusCode": 200, + "mimeType": "image/svg+xml", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true + }, + { + "url": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUiIGhlaWdodD0iMjUiIHZpZXdCb3g9IjAgMCAyNSAyNSIgZmlsbD0ib…", + "sessionTargetType": "page", + "protocol": "data", + "rendererStartTime": 1917.8579999990761, + "networkRequestTime": 1917.8579999990761, + "networkEndTime": 1917.9680000022054, + "finished": true, + "transferSize": 0, + "resourceSize": 1790, + "statusCode": 200, + "mimeType": "image/svg+xml", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true + }, + { + "url": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ib…", + "sessionTargetType": "page", + "protocol": "data", + "rendererStartTime": 1918.7769999988377, + "networkRequestTime": 1918.7769999988377, + "networkEndTime": 1918.9079999998212, + "finished": true, + "transferSize": 0, + "resourceSize": 3274, + "statusCode": 200, + "mimeType": "image/svg+xml", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true + }, + { + "url": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ib…", + "sessionTargetType": "page", + "protocol": "data", + "rendererStartTime": 1919.582999996841, + "networkRequestTime": 1919.582999996841, + "networkEndTime": 1919.6530000008643, + "finished": true, + "transferSize": 0, + "resourceSize": 1046, + "statusCode": 200, + "mimeType": "image/svg+xml", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true + }, + { + "url": "https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3yUBHMdazQ.woff2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 1930.684999998659, + "networkRequestTime": 1935.3220000006258, + "networkEndTime": 1957.062999997288, + "finished": true, + "transferSize": 34700, + "resourceSize": 34668, + "statusCode": 200, + "mimeType": "font/woff2", + "resourceType": "Font", + "priority": "VeryHigh", + "experimentalFromMainFrame": true, + "entity": "Google Fonts" + }, + { + "url": "http://127.0.0.1:8547/", + "sessionTargetType": "page", + "protocol": "", + "rendererStartTime": 1942.6429999992251, + "networkRequestTime": 1942.6429999992251, + "networkEndTime": 1946.6990000009537, + "finished": true, + "transferSize": 0, + "resourceSize": 0, + "statusCode": -1, + "mimeType": "", + "resourceType": "Fetch", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "127.0.0.1" + }, + { + "url": "http://127.0.0.1:8547/", + "sessionTargetType": "page", + "protocol": "", + "rendererStartTime": 1945.2060000002384, + "networkRequestTime": 1945.2060000002384, + "networkEndTime": 1945.3269999995828, + "finished": true, + "transferSize": 0, + "resourceSize": 0, + "statusCode": -1, + "mimeType": "", + "resourceType": "Preflight", + "priority": "High", + "entity": "127.0.0.1" + }, + { + "url": "http://127.0.0.1:8547/", + "sessionTargetType": "page", + "protocol": "", + "rendererStartTime": 1947.9059999994934, + "networkRequestTime": 1947.9059999994934, + "networkEndTime": 1950.422999996692, + "finished": true, + "transferSize": 0, + "resourceSize": 0, + "statusCode": -1, + "mimeType": "", + "resourceType": "Fetch", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "127.0.0.1" + }, + { + "url": "http://127.0.0.1:8547/", + "sessionTargetType": "page", + "protocol": "", + "rendererStartTime": 1948.6519999988377, + "networkRequestTime": 1948.6519999988377, + "networkEndTime": 1949.7069999985397, + "finished": true, + "transferSize": 0, + "resourceSize": 0, + "statusCode": -1, + "mimeType": "", + "resourceType": "Preflight", + "priority": "High", + "entity": "127.0.0.1" + }, + { + "url": "http://127.0.0.1:8547/", + "sessionTargetType": "page", + "protocol": "", + "rendererStartTime": 1954.5719999969006, + "networkRequestTime": 1954.5719999969006, + "networkEndTime": 1957.1109999977052, + "finished": true, + "transferSize": 0, + "resourceSize": 0, + "statusCode": -1, + "mimeType": "", + "resourceType": "Fetch", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "127.0.0.1" + }, + { + "url": "http://127.0.0.1:8547/", + "sessionTargetType": "page", + "protocol": "", + "rendererStartTime": 1955.7359999977052, + "networkRequestTime": 1955.7359999977052, + "networkEndTime": 1957.030000001192, + "finished": true, + "transferSize": 0, + "resourceSize": 0, + "statusCode": -1, + "mimeType": "", + "resourceType": "Preflight", + "priority": "High", + "entity": "127.0.0.1" + }, + { + "url": "http://127.0.0.1:8547/", + "sessionTargetType": "page", + "protocol": "", + "rendererStartTime": 1957.8319999985397, + "networkRequestTime": 1957.8319999985397, + "networkEndTime": 1960.0109999999404, + "finished": true, + "transferSize": 0, + "resourceSize": 0, + "statusCode": -1, + "mimeType": "", + "resourceType": "Fetch", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "127.0.0.1" + }, + { + "url": "http://127.0.0.1:8547/", + "sessionTargetType": "page", + "protocol": "", + "rendererStartTime": 1959.605000000447, + "networkRequestTime": 1959.605000000447, + "networkEndTime": 1959.9219999983907, + "finished": true, + "transferSize": 0, + "resourceSize": 0, + "statusCode": -1, + "mimeType": "", + "resourceType": "Preflight", + "priority": "High", + "entity": "127.0.0.1" + }, + { + "url": "http://localhost:3000/_next/static/chunks/src_components_App_App_tsx.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 1960.4829999990761, + "networkRequestTime": 1960.925000000745, + "networkEndTime": 2658.162999998778, + "finished": true, + "transferSize": 9942484, + "resourceSize": 43420453, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_ethereum-provider_dist_index_es_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 4986.796000000089, + "networkRequestTime": 4987.328999999911, + "networkEndTime": 5038.241999998689, + "finished": true, + "transferSize": 639168, + "resourceSize": 2332526, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_safeWallet-VUYZPLY4_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5140.322000000626, + "networkRequestTime": 5140.866000000387, + "networkEndTime": 5144.382999997586, + "finished": true, + "transferSize": 3266, + "resourceSize": 5674, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_rainbowWallet-2SR6TVBF_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5140.985999997705, + "networkRequestTime": 5141.56799999997, + "networkEndTime": 5145.585999999195, + "finished": true, + "transferSize": 4076, + "resourceSize": 11347, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_coinbaseWallet-WWX6LF36_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5141.629999998957, + "networkRequestTime": 5142.051999997348, + "networkEndTime": 5146.741999998689, + "finished": true, + "transferSize": 2301, + "resourceSize": 3751, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_metaMaskWallet-YFHEHW7V_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5142.186999998987, + "networkRequestTime": 5142.592000000179, + "networkEndTime": 5148.065000001341, + "finished": true, + "transferSize": 4980, + "resourceSize": 18353, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_walletConnectWallet-FNSU4KNU_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5142.726999998093, + "networkRequestTime": 5143.187000002712, + "networkEndTime": 5148.48900000006, + "finished": true, + "transferSize": 3315, + "resourceSize": 5968, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_wallets_walletConnectors_okxWallet-GJMKZIND_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5143.3069999963045, + "networkRequestTime": 5143.695999998599, + "networkEndTime": 5149.804000001401, + "finished": true, + "transferSize": 2437, + "resourceSize": 4565, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_wallets_walletConnectors_trustWallet-E2GVGE4U_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5143.853000000119, + "networkRequestTime": 5144.5289999991655, + "networkEndTime": 5150.170000001788, + "finished": true, + "transferSize": 2509, + "resourceSize": 4371, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_wallets_walletConnectors_rabbyWallet-FLVUU35F_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5144.51099999994, + "networkRequestTime": 5145.7289999984205, + "networkEndTime": 5151.063000001013, + "finished": true, + "transferSize": 4330, + "resourceSize": 8269, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_assets-NU2OP443_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5145.228000000119, + "networkRequestTime": 5146.85000000149, + "networkEndTime": 5152.309000000358, + "finished": true, + "transferSize": 12469, + "resourceSize": 45515, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_login-CWDTIDNK_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5145.796000000089, + "networkRequestTime": 5148.248999997973, + "networkEndTime": 5152.491000000387, + "finished": true, + "transferSize": 9697, + "resourceSize": 24218, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIxNiIKICBoZWlnaHQ9IjEyIgogIHZpZXdCb3g9IjAgMCAxNiAxMiIKI…", + "sessionTargetType": "page", + "protocol": "data", + "rendererStartTime": 5166.4310000017285, + "networkRequestTime": 5166.4310000017285, + "networkEndTime": 5166.513000000268, + "finished": true, + "transferSize": 0, + "resourceSize": 280, + "statusCode": 200, + "mimeType": "image/svg+xml", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true + }, + { + "url": "https://verify.walletconnect.com/8702c5ea8d157774a011deb8e1433d01", + "sessionTargetType": "iframe", + "protocol": "h3", + "rendererStartTime": 5554.9439999982715, + "networkRequestTime": 5555.662999998778, + "networkEndTime": 5660.646999999881, + "finished": true, + "transferSize": 278, + "resourceSize": 62, + "statusCode": 200, + "mimeType": "text/html", + "resourceType": "Document", + "priority": "VeryHigh", + "entity": "walletconnect.com" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_coinbase_wallet-sdk_dist_index_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5554.157999999821, + "networkRequestTime": 5554.584000002593, + "networkEndTime": 5567.478000000119, + "finished": true, + "transferSize": 173361, + "resourceSize": 657128, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5601.936999998987, + "networkRequestTime": 5602.295000001788, + "networkEndTime": 5613.890999998897, + "finished": true, + "transferSize": 276, + "resourceSize": 0, + "statusCode": 200, + "mimeType": "text/html", + "resourceType": "Fetch", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_modal_dist_index_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5633.605000000447, + "networkRequestTime": 5634.261999998242, + "networkEndTime": 5637.504999998957, + "finished": true, + "transferSize": 22370, + "resourceSize": 63923, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_modal-ui_dist_index_js.js", + "sessionTargetType": "page", + "protocol": "http/1.1", + "rendererStartTime": 5643.223999999464, + "networkRequestTime": 5643.6819999963045, + "networkEndTime": 5668.773000001907, + "finished": true, + "transferSize": 334017, + "resourceSize": 1321332, + "statusCode": 200, + "mimeType": "application/javascript", + "resourceType": "Script", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "localhost" + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getDesktopListings?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2&page=1&entries=9&version=2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 5745.813000001013, + "networkRequestTime": 5746.335000000894, + "networkEndTime": 6012.017999999225, + "finished": true, + "transferSize": 2226, + "resourceSize": 7613, + "statusCode": 200, + "mimeType": "application/json", + "resourceType": "Fetch", + "priority": "High", + "experimentalFromMainFrame": true, + "entity": "walletconnect.com" + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/3d7eb880-7654-431f-ed84-a25712b45200?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 6013.951999999583, + "networkRequestTime": 6014.236999999732, + "networkEndTime": 6220.143999997526, + "finished": true, + "transferSize": 2572, + "resourceSize": 2176, + "statusCode": 200, + "mimeType": "image/webp", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "walletconnect.com" + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/4e7d6f52-f663-4fc1-4b88-eebe7fc72800?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 6014.06099999696, + "networkRequestTime": 6014.401000000536, + "networkEndTime": 6061.516000002623, + "finished": true, + "transferSize": 2038, + "resourceSize": 1638, + "statusCode": 200, + "mimeType": "image/webp", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "walletconnect.com" + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/d8e930b6-ccde-471e-ecbe-6967b1c0c400?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 6014.12899999693, + "networkRequestTime": 6014.546999998391, + "networkEndTime": 6076.444999996573, + "finished": true, + "transferSize": 1974, + "resourceSize": 1576, + "statusCode": 200, + "mimeType": "image/webp", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "walletconnect.com" + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/77c1d3dd-0213-400a-f9cc-bfd524c47f00?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 6014.242000002414, + "networkRequestTime": 6014.741000000387, + "networkEndTime": 6067.776999998838, + "finished": true, + "transferSize": 1804, + "resourceSize": 1404, + "statusCode": 200, + "mimeType": "image/webp", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "walletconnect.com" + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/c20e1cec-05e8-4ac6-a086-7ce355092400?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 6014.335999999195, + "networkRequestTime": 6014.942000001669, + "networkEndTime": 6070.927999999374, + "finished": true, + "transferSize": 1592, + "resourceSize": 1192, + "statusCode": 200, + "mimeType": "image/webp", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "walletconnect.com" + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/67336675-0daa-489b-6885-cb95234bc400?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 6014.425000000745, + "networkRequestTime": 6015.127999998629, + "networkEndTime": 6071.069999996573, + "finished": true, + "transferSize": 2273, + "resourceSize": 1872, + "statusCode": 200, + "mimeType": "image/webp", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "walletconnect.com" + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/a578bd45-b418-4111-2c56-8ddcd1417c00?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 6014.479000002146, + "networkRequestTime": 6015.288999997079, + "networkEndTime": 6073.75, + "finished": true, + "transferSize": 1972, + "resourceSize": 1572, + "statusCode": 200, + "mimeType": "image/webp", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "walletconnect.com" + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/7e1514ba-932d-415d-1bdb-bccb6c2cbc00?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 6014.559999998659, + "networkRequestTime": 6015.457999996841, + "networkEndTime": 6080.824000000954, + "finished": true, + "transferSize": 1309, + "resourceSize": 910, + "statusCode": 200, + "mimeType": "image/webp", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "walletconnect.com" + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/f5b26eef-c5e8-421a-e379-ae010b4a7400?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "sessionTargetType": "page", + "protocol": "h3", + "rendererStartTime": 6014.614999998361, + "networkRequestTime": 6015.614999998361, + "networkEndTime": 6073.625, + "finished": true, + "transferSize": 2097, + "resourceSize": 1694, + "statusCode": 200, + "mimeType": "image/webp", + "resourceType": "Image", + "priority": "Low", + "experimentalFromMainFrame": true, + "entity": "walletconnect.com" + } + ], + "debugData": { + "type": "debugdata", + "networkStartTimeTs": 31362658561 + } + } + }, + "network-rtt": { + "id": "network-rtt", + "title": "Network Round Trip Times", + "description": "Network round trip times (RTT) have a large impact on performance. If the RTT to an origin is high, it's an indication that servers closer to the user could improve performance. [Learn more about the Round Trip Time](https://hpbn.co/primer-on-latency-and-bandwidth/).", + "score": 1, + "scoreDisplayMode": "informative", + "numericValue": 27.57, + "numericUnit": "millisecond", + "displayValue": "30 ms", + "details": { + "type": "table", + "headings": [ + { + "key": "origin", + "valueType": "text", + "label": "URL" + }, + { + "key": "rtt", + "valueType": "ms", + "granularity": 1, + "label": "Time Spent" + } + ], + "items": [ + { + "origin": "https://verify.walletconnect.com", + "rtt": 27.57 + }, + { + "origin": "https://explorer-api.walletconnect.com", + "rtt": 26.305 + }, + { + "origin": "https://fonts.googleapis.com", + "rtt": 19.466 + }, + { + "origin": "http://localhost:3000", + "rtt": 0.03675 + }, + { + "origin": "https://fonts.gstatic.com", + "rtt": 0 + } + ], + "sortedBy": [ + "rtt" + ] + } + }, + "network-server-latency": { + "id": "network-server-latency", + "title": "Server Backend Latencies", + "description": "Server latencies can impact web performance. If the server latency of an origin is high, it's an indication the server is overloaded or has poor backend performance. [Learn more about server response time](https://hpbn.co/primer-on-web-performance/#analyzing-the-resource-waterfall).", + "score": 1, + "scoreDisplayMode": "informative", + "numericValue": 30.154, + "numericUnit": "millisecond", + "displayValue": "30 ms", + "details": { + "type": "table", + "headings": [ + { + "key": "origin", + "valueType": "text", + "label": "URL" + }, + { + "key": "serverResponseTime", + "valueType": "ms", + "granularity": 1, + "label": "Time Spent" + } + ], + "items": [ + { + "origin": "https://explorer-api.walletconnect.com", + "serverResponseTime": 30.154 + }, + { + "origin": "https://fonts.googleapis.com", + "serverResponseTime": 19.48600000000001 + }, + { + "origin": "https://fonts.gstatic.com", + "serverResponseTime": 18.366 + }, + { + "origin": "https://verify.walletconnect.com", + "serverResponseTime": 13.793 + }, + { + "origin": "http://localhost:3000", + "serverResponseTime": 4.28725 + } + ], + "sortedBy": [ + "serverResponseTime" + ] + } + }, + "main-thread-tasks": { + "id": "main-thread-tasks", + "title": "Tasks", + "description": "Lists the toplevel main thread tasks that executed during page load.", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "table", + "headings": [ + { + "key": "startTime", + "valueType": "ms", + "granularity": 1, + "label": "Start Time" + }, + { + "key": "duration", + "valueType": "ms", + "granularity": 1, + "label": "End Time" + } + ], + "items": [ + { + "duration": 6.119, + "startTime": 29.302 + }, + { + "duration": 6.4, + "startTime": 52.092 + }, + { + "duration": 341.588, + "startTime": 172.552 + }, + { + "duration": 9.503, + "startTime": 515.115 + }, + { + "duration": 1169.039, + "startTime": 524.635 + }, + { + "duration": 52.192, + "startTime": 1693.778 + }, + { + "duration": 6.687, + "startTime": 1767.221 + }, + { + "duration": 27.735, + "startTime": 1773.964 + }, + { + "duration": 17.067, + "startTime": 1810.716 + }, + { + "duration": 9.507, + "startTime": 1831.01 + }, + { + "duration": 82.731, + "startTime": 1840.89 + }, + { + "duration": 12.054, + "startTime": 1923.692 + }, + { + "duration": 5.147, + "startTime": 2692.1 + }, + { + "duration": 24.434, + "startTime": 2751.595 + }, + { + "duration": 2392.075, + "startTime": 2776.096 + }, + { + "duration": 5.452, + "startTime": 5168.969 + }, + { + "duration": 144.056, + "startTime": 5185.436 + }, + { + "duration": 23.188, + "startTime": 5409.964 + }, + { + "duration": 11.402, + "startTime": 5435.098 + }, + { + "duration": 8.081, + "startTime": 5448.236 + }, + { + "duration": 35.519, + "startTime": 5570.688 + }, + { + "duration": 5.66, + "startTime": 5639.285 + }, + { + "duration": 75.716, + "startTime": 5675.205 + }, + { + "duration": 6.075, + "startTime": 5750.934 + } + ] + } + }, + "metrics": { + "id": "metrics", + "title": "Metrics", + "description": "Collects all available metrics.", + "score": 1, + "scoreDisplayMode": "informative", + "numericValue": 15825, + "numericUnit": "millisecond", + "details": { + "type": "debugdata", + "items": [ + { + "firstContentfulPaint": 442, + "largestContentfulPaint": 6387, + "interactive": 15825, + "speedIndex": 5787, + "totalBlockingTime": 2630, + "maxPotentialFID": 1196, + "cumulativeLayoutShift": 0, + "cumulativeLayoutShiftMainFrame": 0, + "lcpLoadStart": 5942, + "lcpLoadEnd": 5962, + "timeToFirstByte": 124, + "observedTimeOrigin": 0, + "observedTimeOriginTs": 31362657570, + "observedNavigationStart": 0, + "observedNavigationStartTs": 31362657570, + "observedFirstPaint": 1879, + "observedFirstPaintTs": 31364536563, + "observedFirstContentfulPaint": 1907, + "observedFirstContentfulPaintTs": 31364564476, + "observedFirstContentfulPaintAllFrames": 1907, + "observedFirstContentfulPaintAllFramesTs": 31364564476, + "observedLargestContentfulPaint": 1907, + "observedLargestContentfulPaintTs": 31364564476, + "observedLargestContentfulPaintAllFrames": 1907, + "observedLargestContentfulPaintAllFramesTs": 31364564476, + "observedTraceEnd": 7051, + "observedTraceEndTs": 31369708833, + "observedLoad": 1759, + "observedLoadTs": 31364416347, + "observedDomContentLoaded": 1751, + "observedDomContentLoadedTs": 31364408638, + "observedCumulativeLayoutShift": 0, + "observedCumulativeLayoutShiftMainFrame": 0, + "observedFirstVisualChange": 1854, + "observedFirstVisualChangeTs": 31364511570, + "observedLastVisualChange": 5187, + "observedLastVisualChangeTs": 31367844570, + "observedSpeedIndex": 2191, + "observedSpeedIndexTs": 31364848523 + }, + { + "lcpInvalidated": false + } + ] + } + }, + "resource-summary": { + "id": "resource-summary", + "title": "Resources Summary", + "description": "Aggregates all network requests and groups them by type", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "table", + "headings": [ + { + "key": "label", + "valueType": "text", + "label": "Resource Type" + }, + { + "key": "requestCount", + "valueType": "numeric", + "label": "Requests" + }, + { + "key": "transferSize", + "valueType": "bytes", + "label": "Transfer Size" + } + ], + "items": [ + { + "resourceType": "total", + "label": "Total", + "requestCount": 54, + "transferSize": 17480764 + }, + { + "resourceType": "script", + "label": "Script", + "requestCount": 23, + "transferSize": 16698518 + }, + { + "resourceType": "image", + "label": "Image", + "requestCount": 10, + "transferSize": 495441 + }, + { + "resourceType": "font", + "label": "Font", + "requestCount": 4, + "transferSize": 254886 + }, + { + "resourceType": "other", + "label": "Other", + "requestCount": 14, + "transferSize": 27638 + }, + { + "resourceType": "stylesheet", + "label": "Stylesheet", + "requestCount": 1, + "transferSize": 2318 + }, + { + "resourceType": "document", + "label": "Document", + "requestCount": 2, + "transferSize": 1963 + }, + { + "resourceType": "media", + "label": "Media", + "requestCount": 0, + "transferSize": 0 + }, + { + "resourceType": "third-party", + "label": "Third-party", + "requestCount": 21, + "transferSize": 57153 + } + ] + } + }, + "third-party-summary": { + "id": "third-party-summary", + "title": "Minimize third-party usage", + "description": "Third-party code can significantly impact load performance. Limit the number of redundant third-party providers and try to load third-party code after your page has primarily finished loading. [Learn how to minimize third-party impact](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript/).", + "score": 1, + "scoreDisplayMode": "informative", + "displayValue": "Third-party code blocked the main thread for 0 ms", + "metricSavings": { + "TBT": 0 + }, + "details": { + "type": "table", + "headings": [ + { + "key": "entity", + "valueType": "text", + "label": "Third-Party", + "subItemsHeading": { + "key": "url", + "valueType": "url" + } + }, + { + "key": "transferSize", + "granularity": 1, + "valueType": "bytes", + "label": "Transfer Size", + "subItemsHeading": { + "key": "transferSize" + } + }, + { + "key": "blockingTime", + "granularity": 1, + "valueType": "ms", + "label": "Main-Thread Blocking Time", + "subItemsHeading": { + "key": "blockingTime" + } + } + ], + "items": [ + { + "mainThreadTime": 1.65, + "blockingTime": 0, + "transferSize": 37018, + "tbtImpact": 0, + "entity": "Google Fonts", + "subItems": { + "type": "subitems", + "items": [ + { + "url": "https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3yUBHMdazQ.woff2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 34700, + "tbtImpact": 0 + }, + { + "url": "https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700", + "mainThreadTime": 1.65, + "blockingTime": 0, + "transferSize": 2318, + "tbtImpact": 0 + } + ] + } + }, + { + "mainThreadTime": 0.052000000000000005, + "blockingTime": 0, + "transferSize": 20135, + "tbtImpact": 0, + "entity": "walletconnect.com", + "subItems": { + "type": "subitems", + "items": [ + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/3d7eb880-7654-431f-ed84-a25712b45200?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 2572, + "tbtImpact": 0 + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/67336675-0daa-489b-6885-cb95234bc400?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 2273, + "tbtImpact": 0 + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getDesktopListings?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2&page=1&entries=9&version=2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 2226, + "tbtImpact": 0 + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/f5b26eef-c5e8-421a-e379-ae010b4a7400?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 2097, + "tbtImpact": 0 + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/4e7d6f52-f663-4fc1-4b88-eebe7fc72800?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 2038, + "tbtImpact": 0 + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/d8e930b6-ccde-471e-ecbe-6967b1c0c400?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 1974, + "tbtImpact": 0 + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/a578bd45-b418-4111-2c56-8ddcd1417c00?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 1972, + "tbtImpact": 0 + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/77c1d3dd-0213-400a-f9cc-bfd524c47f00?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 1804, + "tbtImpact": 0 + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/c20e1cec-05e8-4ac6-a086-7ce355092400?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 1592, + "tbtImpact": 0 + }, + { + "url": "https://explorer-api.walletconnect.com/w3m/v1/getWalletImage/7e1514ba-932d-415d-1bdb-bccb6c2cbc00?projectId=8702c5ea8d157774a011deb8e1433d01&sdkType=wcm&sdkVersion=js-2.6.2", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 1309, + "tbtImpact": 0 + }, + { + "url": "https://verify.walletconnect.com/8702c5ea8d157774a011deb8e1433d01", + "mainThreadTime": 0.052000000000000005, + "blockingTime": 0, + "transferSize": 278, + "tbtImpact": 0 + } + ] + } + }, + { + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 0, + "tbtImpact": 0, + "entity": "127.0.0.1", + "subItems": { + "type": "subitems", + "items": [ + { + "url": "http://127.0.0.1:8547/", + "mainThreadTime": 0, + "blockingTime": 0, + "transferSize": 0, + "tbtImpact": 0 + } + ] + } + } + ], + "summary": { + "wastedBytes": 57153, + "wastedMs": 0 + }, + "isEntityGrouped": true + }, + "guidanceLevel": 1 + }, + "third-party-facades": { + "id": "third-party-facades", + "title": "Lazy load third-party resources with facades", + "description": "Some third-party embeds can be lazy loaded. Consider replacing them with a facade until they are required. [Learn how to defer third-parties with a facade](https://developer.chrome.com/docs/lighthouse/performance/third-party-facades/).", + "score": null, + "scoreDisplayMode": "notApplicable", + "metricSavings": { + "TBT": 0 + }, + "guidanceLevel": 3 + }, + "largest-contentful-paint-element": { + "id": "largest-contentful-paint-element", + "title": "Largest Contentful Paint element", + "description": "This is the largest contentful element painted within the viewport. [Learn more about the Largest Contentful Paint element](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-largest-contentful-paint/)", + "score": 0, + "scoreDisplayMode": "metricSavings", + "displayValue": "6,390 ms", + "metricSavings": { + "LCP": 5200 + }, + "details": { + "type": "list", + "items": [ + { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "label": "Element" + } + ], + "items": [ + { + "node": { + "type": "node", + "lhId": "page-0-IMG", + "path": "1,HTML,1,BODY,0,DIV,0,DIV,1,IMG", + "selector": "body > div#__next > div.relative > img.absolute", + "boundingRect": { + "top": 366, + "bottom": 940, + "left": 0, + "right": 1350, + "width": 1350, + "height": 574 + }, + "snippet": "\"grains\"", + "nodeLabel": "grains" + } + } + ] + }, + { + "type": "table", + "headings": [ + { + "key": "phase", + "valueType": "text", + "label": "Phase" + }, + { + "key": "percent", + "valueType": "text", + "label": "% of LCP" + }, + { + "key": "timing", + "valueType": "ms", + "label": "Timing" + } + ], + "items": [ + { + "phase": "TTFB", + "timing": 124.28725, + "percent": "2%" + }, + { + "phase": "Load Delay", + "timing": 5817.363777449029, + "percent": "91%" + }, + { + "phase": "Load Time", + "timing": 20.061570342651066, + "percent": "0%" + }, + { + "phase": "Render Delay", + "timing": 424.8531522083176, + "percent": "7%" + } + ] + } + ] + }, + "guidanceLevel": 1 + }, + "lcp-lazy-loaded": { + "id": "lcp-lazy-loaded", + "title": "Largest Contentful Paint image was lazily loaded", + "description": "Above-the-fold images that are lazily loaded render later in the page lifecycle, which can delay the largest contentful paint. [Learn more about optimal lazy loading](https://web.dev/articles/lcp-lazy-loading).", + "score": 0, + "scoreDisplayMode": "metricSavings", + "metricSavings": { + "LCP": 950 + }, + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "label": "Element" + } + ], + "items": [ + { + "node": { + "type": "node", + "lhId": "1-32-IMG", + "path": "1,HTML,1,BODY,0,DIV,0,DIV,1,IMG", + "selector": "body > div#__next > div.relative > img.absolute", + "boundingRect": { + "top": 366, + "bottom": 940, + "left": 0, + "right": 1350, + "width": 1350, + "height": 574 + }, + "snippet": "\"grains\"", + "nodeLabel": "grains" + } + } + ] + }, + "guidanceLevel": 3 + }, + "layout-shifts": { + "id": "layout-shifts", + "title": "Avoid large layout shifts", + "description": "These are the largest layout shifts observed on the page. Each table item represents a single layout shift, and shows the element that shifted the most. Below each item are possible root causes that led to the layout shift. Some of these layout shifts may not be included in the CLS metric value due to [windowing](https://web.dev/articles/cls#what_is_cls). [Learn how to improve CLS](https://web.dev/articles/optimize-cls)", + "score": null, + "scoreDisplayMode": "notApplicable", + "metricSavings": { + "CLS": 0 + }, + "details": { + "type": "table", + "headings": [], + "items": [] + }, + "guidanceLevel": 2 + }, + "long-tasks": { + "id": "long-tasks", + "title": "Avoid long main-thread tasks", + "description": "Lists the longest tasks on the main thread, useful for identifying worst contributors to input delay. [Learn how to avoid long main-thread tasks](https://web.dev/articles/optimize-long-tasks)", + "score": 1, + "scoreDisplayMode": "informative", + "displayValue": "5 long tasks found", + "metricSavings": { + "TBT": 2650 + }, + "details": { + "type": "table", + "headings": [ + { + "key": "url", + "valueType": "url", + "label": "URL" + }, + { + "key": "startTime", + "valueType": "ms", + "granularity": 1, + "label": "Start Time" + }, + { + "key": "duration", + "valueType": "ms", + "granularity": 1, + "label": "Duration" + } + ], + "items": [ + { + "url": "http://localhost:3000/_next/static/chunks/src_components_App_App_tsx.js", + "duration": 1196, + "startTime": 14034.225250000014 + }, + { + "url": "http://localhost:3000/_next/static/chunks/pages/_app.js", + "duration": 1169, + "startTime": 9261.277500000007 + }, + { + "url": "http://localhost:3000/_next/static/chunks/main.js", + "duration": 342, + "startTime": 4692.8007499999985 + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_ethereum-provider_dist_index_es_js.js", + "duration": 144, + "startTime": 15915.137250000013 + }, + { + "url": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_modal-ui_dist_index_js.js", + "duration": 76, + "startTime": 15230.225250000014 + } + ], + "sortedBy": [ + "duration" + ], + "skipSumming": [ + "startTime" + ], + "debugData": { + "type": "debugdata", + "urls": [ + "http://localhost:3000/_next/static/chunks/src_components_App_App_tsx.js", + "http://localhost:3000/_next/static/chunks/pages/_app.js", + "http://localhost:3000/_next/static/chunks/main.js", + "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_ethereum-provider_dist_index_es_js.js", + "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_modal-ui_dist_index_js.js" + ], + "tasks": [ + { + "urlIndex": 0, + "startTime": 14034.2, + "duration": 1196, + "other": 1196, + "scriptEvaluation": 0 + }, + { + "urlIndex": 1, + "startTime": 9261.3, + "duration": 1169, + "other": 1169, + "scriptEvaluation": 0 + }, + { + "urlIndex": 2, + "startTime": 4692.8, + "duration": 342, + "other": 342, + "scriptEvaluation": 0 + }, + { + "urlIndex": 3, + "startTime": 15915.1, + "duration": 144, + "other": 144, + "scriptEvaluation": 0 + }, + { + "urlIndex": 4, + "startTime": 15230.2, + "duration": 76, + "other": 76, + "scriptEvaluation": 0 + } + ] + } + }, + "guidanceLevel": 1 + }, + "non-composited-animations": { + "id": "non-composited-animations", + "title": "Avoid non-composited animations", + "description": "Animations which are not composited can be janky and increase CLS. [Learn how to avoid non-composited animations](https://developer.chrome.com/docs/lighthouse/performance/non-composited-animations/)", + "score": 1, + "scoreDisplayMode": "informative", + "displayValue": "4 animated elements found", + "metricSavings": { + "CLS": 0 + }, + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "failureReason", + "valueType": "text" + }, + "label": "Element" + }, + { + "key": null, + "valueType": "text", + "subItemsHeading": { + "key": "animation", + "valueType": "text" + }, + "label": "Name" + } + ], + "items": [ + { + "node": { + "type": "node", + "lhId": "page-1-DIV", + "path": "1,HTML,1,BODY,0,DIV,0,DIV,2,DIV,0,DIV,0,DIV,0,DIV,0,DIV,2,DIV,4,DIV,1,DIV", + "selector": "div.relative > div.z-10 > div.flex > div.flex", + "boundingRect": { + "top": 364, + "bottom": 364, + "left": 50, + "right": 237, + "width": 187, + "height": 0 + }, + "snippet": "
", + "nodeLabel": "div.relative > div.z-10 > div.flex > div.flex" + }, + "subItems": { + "type": "subitems", + "items": [ + { + "failureReason": "Unsupported CSS Property: scrollbar-color", + "animation": "scrollbar-color" + }, + { + "failureReason": "Unsupported CSS Property: scrollbar-color", + "animation": "scrollbar-color" + } + ] + } + }, + { + "node": { + "type": "node", + "lhId": "page-2-DIV", + "path": "1,HTML,1,BODY,0,DIV,0,DIV,2,DIV,0,DIV,0,DIV,0,DIV,0,DIV,2,DIV,1,DIV,1,DIV", + "selector": "div.relative > div.z-10 > div.flex > div.flex", + "boundingRect": { + "top": 199, + "bottom": 199, + "left": 50, + "right": 237, + "width": 187, + "height": 0 + }, + "snippet": "
", + "nodeLabel": "div.relative > div.z-10 > div.flex > div.flex" + }, + "subItems": { + "type": "subitems", + "items": [ + { + "failureReason": "Unsupported CSS Property: scrollbar-color", + "animation": "scrollbar-color" + }, + { + "failureReason": "Unsupported CSS Property: scrollbar-color", + "animation": "scrollbar-color" + } + ] + } + }, + { + "node": { + "type": "node", + "lhId": "page-3-DIV", + "path": "1,HTML,1,BODY,0,DIV,0,DIV,2,DIV,0,DIV,0,DIV,0,DIV,0,DIV,2,DIV,2,DIV,1,DIV", + "selector": "div.relative > div.z-10 > div.flex > div.flex", + "boundingRect": { + "top": 254, + "bottom": 254, + "left": 50, + "right": 237, + "width": 187, + "height": 0 + }, + "snippet": "
", + "nodeLabel": "div.relative > div.z-10 > div.flex > div.flex" + }, + "subItems": { + "type": "subitems", + "items": [ + { + "failureReason": "Unsupported CSS Property: scrollbar-color", + "animation": "scrollbar-color" + }, + { + "failureReason": "Unsupported CSS Property: scrollbar-color", + "animation": "scrollbar-color" + } + ] + } + }, + { + "node": { + "type": "node", + "lhId": "page-4-DIV", + "path": "1,HTML,1,BODY,0,DIV,0,DIV,2,DIV,0,DIV,0,DIV,0,DIV,0,DIV", + "selector": "div.relative > div.sticky > div.sticky > div.relative", + "boundingRect": { + "top": 0, + "bottom": 940, + "left": 0, + "right": 256, + "width": 256, + "height": 940 + }, + "snippet": "
", + "nodeLabel": "Home\nProjects\nChains\nBridge\nDevelopers\nCommunity\nGet Help\nThe Most Decentralize…" + }, + "subItems": { + "type": "subitems", + "items": [ + { + "failureReason": "Unsupported CSS Property: scrollbar-color", + "animation": "scrollbar-color" + } + ] + } + } + ] + }, + "guidanceLevel": 2 + }, + "unsized-images": { + "id": "unsized-images", + "title": "Image elements have explicit `width` and `height`", + "description": "Set an explicit width and height on image elements to reduce layout shifts and improve CLS. [Learn how to set image dimensions](https://web.dev/articles/optimize-cls#images_without_dimensions)", + "score": 1, + "scoreDisplayMode": "metricSavings", + "metricSavings": { + "CLS": 0 + }, + "details": { + "type": "table", + "headings": [], + "items": [] + }, + "guidanceLevel": 4 + }, + "valid-source-maps": { + "id": "valid-source-maps", + "title": "Missing source maps for large first-party JavaScript", + "description": "Source maps translate minified code to the original source code. This helps developers debug in production. In addition, Lighthouse is able to provide further insights. Consider deploying source maps to take advantage of these benefits. [Learn more about source maps](https://developer.chrome.com/docs/devtools/javascript/source-maps/).", + "score": 0, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "scriptUrl", + "valueType": "url", + "subItemsHeading": { + "key": "error" + }, + "label": "URL" + }, + { + "key": "sourceMapUrl", + "valueType": "url", + "label": "Map URL" + } + ], + "items": [ + { + "scriptUrl": "http://localhost:3000/_next/static/chunks/src_components_App_App_tsx.js", + "subItems": { + "type": "subitems", + "items": [ + { + "error": "Large JavaScript file is missing a source map" + } + ] + } + }, + { + "scriptUrl": "http://localhost:3000/_next/static/chunks/pages/index.js", + "subItems": { + "type": "subitems", + "items": [ + { + "error": "Large JavaScript file is missing a source map" + } + ] + } + }, + { + "scriptUrl": "http://localhost:3000/_next/static/chunks/pages/_app.js", + "subItems": { + "type": "subitems", + "items": [ + { + "error": "Large JavaScript file is missing a source map" + } + ] + } + }, + { + "scriptUrl": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_modal-ui_dist_index_js.js", + "subItems": { + "type": "subitems", + "items": [ + { + "error": "Large JavaScript file is missing a source map" + } + ] + } + }, + { + "scriptUrl": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_ethereum-provider_dist_index_es_js.js", + "subItems": { + "type": "subitems", + "items": [ + { + "error": "Large JavaScript file is missing a source map" + } + ] + } + }, + { + "scriptUrl": "http://localhost:3000/_next/static/chunks/node_modules_offchainlabs_cobalt_dist_cobalt_es_js.js", + "subItems": { + "type": "subitems", + "items": [ + { + "error": "Large JavaScript file is missing a source map" + } + ] + } + }, + { + "scriptUrl": "http://localhost:3000/_next/static/chunks/node_modules_coinbase_wallet-sdk_dist_index_js.js", + "subItems": { + "type": "subitems", + "items": [ + { + "error": "Large JavaScript file is missing a source map" + } + ] + } + }, + { + "scriptUrl": "http://localhost:3000/_next/static/chunks/main.js", + "subItems": { + "type": "subitems", + "items": [ + { + "error": "Large JavaScript file is missing a source map" + } + ] + } + } + ] + } + }, + "prioritize-lcp-image": { + "id": "prioritize-lcp-image", + "title": "Preload Largest Contentful Paint image", + "description": "If the LCP element is dynamically added to the page, you should preload the image in order to improve LCP. [Learn more about preloading LCP elements](https://web.dev/articles/optimize-lcp#optimize_when_the_resource_is_discovered).", + "score": 1, + "scoreDisplayMode": "metricSavings", + "numericValue": 0, + "numericUnit": "millisecond", + "displayValue": "", + "metricSavings": { + "LCP": 0 + }, + "details": { + "type": "opportunity", + "headings": [], + "items": [], + "overallSavingsMs": 0, + "sortedBy": [ + "wastedMs" + ], + "debugData": { + "type": "debugdata", + "initiatorPath": [ + { + "url": "http://localhost:3000/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Feclipse_bottom.4304bd37.png&w=1920&q=75", + "initiatorType": "fallbackToMain" + }, + { + "url": "http://localhost:3000/?sourceChain=ethereum&destinationChain=arbitrum-one&tab=bridge&txHistory=0", + "initiatorType": "other" + } + ], + "pathLength": 2 + } + }, + "guidanceLevel": 4 + }, + "csp-xss": { + "id": "csp-xss", + "title": "Ensure CSP is effective against XSS attacks", + "description": "A strong Content Security Policy (CSP) significantly reduces the risk of cross-site scripting (XSS) attacks. [Learn how to use a CSP to prevent XSS](https://developer.chrome.com/docs/lighthouse/best-practices/csp-xss/)", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "table", + "headings": [ + { + "key": "description", + "valueType": "text", + "subItemsHeading": { + "key": "description" + }, + "label": "Description" + }, + { + "key": "directive", + "valueType": "code", + "subItemsHeading": { + "key": "directive" + }, + "label": "Directive" + }, + { + "key": "severity", + "valueType": "text", + "subItemsHeading": { + "key": "severity" + }, + "label": "Severity" + } + ], + "items": [ + { + "severity": "High", + "description": "No CSP found in enforcement mode" + } + ] + } + }, + "has-hsts": { + "id": "has-hsts", + "title": "Use a strong HSTS policy", + "description": "Deployment of the HSTS header significantly reduces the risk of downgrading HTTP connections and eavesdropping attacks. A rollout in stages, starting with a low max-age is recommended. [Learn more about using a strong HSTS policy.](https://developer.chrome.com/docs/lighthouse/best-practices/has-hsts)", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "table", + "headings": [ + { + "key": "description", + "valueType": "text", + "subItemsHeading": { + "key": "description" + }, + "label": "Description" + }, + { + "key": "directive", + "valueType": "code", + "subItemsHeading": { + "key": "directive" + }, + "label": "Directive" + }, + { + "key": "severity", + "valueType": "text", + "subItemsHeading": { + "key": "severity" + }, + "label": "Severity" + } + ], + "items": [ + { + "severity": "High", + "description": "No HSTS header found" + } + ] + } + }, + "origin-isolation": { + "id": "origin-isolation", + "title": "Ensure proper origin isolation with COOP", + "description": "The Cross-Origin-Opener-Policy (COOP) can be used to isolate the top-level window from other documents such as pop-ups. [Learn more about deploying the COOP header.](https://web.dev/articles/why-coop-coep#coop)", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "table", + "headings": [ + { + "key": "description", + "valueType": "text", + "subItemsHeading": { + "key": "description" + }, + "label": "Description" + }, + { + "key": "directive", + "valueType": "code", + "subItemsHeading": { + "key": "directive" + }, + "label": "Directive" + }, + { + "key": "severity", + "valueType": "text", + "subItemsHeading": { + "key": "severity" + }, + "label": "Severity" + } + ], + "items": [ + { + "description": "No COOP header found", + "severity": "High" + } + ] + } + }, + "clickjacking-mitigation": { + "id": "clickjacking-mitigation", + "title": "Mitigate clickjacking with XFO or CSP", + "description": "The `X-Frame-Options` (XFO) header or the `frame-ancestors` directive in the `Content-Security-Policy` (CSP) header control where a page can be embedded. These can mitigate clickjacking attacks by blocking some or all sites from embedding the page. [Learn more about mitigating clickjacking](https://developer.chrome.com/docs/lighthouse/best-practices/clickjacking-mitigation).", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "table", + "headings": [ + { + "key": "description", + "valueType": "text", + "subItemsHeading": { + "key": "description" + }, + "label": "Description" + }, + { + "key": "severity", + "valueType": "text", + "subItemsHeading": { + "key": "severity" + }, + "label": "Severity" + } + ], + "items": [ + { + "severity": "High", + "description": "No frame control policy found" + } + ] + } + }, + "script-treemap-data": { + "id": "script-treemap-data", + "title": "Script Treemap Data", + "description": "Used for treemap app", + "score": 1, + "scoreDisplayMode": "informative", + "details": { + "type": "treemap-data", + "nodes": [ + { + "name": "http://localhost:3000/_next/static/chunks/react-refresh.js", + "resourceBytes": 79107, + "encodedBytes": 25063, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/webpack.js", + "resourceBytes": 53011, + "encodedBytes": 10015, + "unusedBytes": 28078 + }, + { + "name": "http://localhost:3000/_next/static/chunks/main.js", + "resourceBytes": 5287916, + "encodedBytes": 1176778, + "unusedBytes": 23699 + }, + { + "name": "http://localhost:3000/_next/static/chunks/pages/_app.js", + "resourceBytes": 18915166, + "encodedBytes": 3979485, + "unusedBytes": 83488 + }, + { + "name": "http://localhost:3000/_next/static/chunks/pages/index.js", + "resourceBytes": 895933, + "encodedBytes": 196084, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/development/_buildManifest.js", + "resourceBytes": 296, + "encodedBytes": 296, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/development/_ssgManifest.js", + "resourceBytes": 76, + "encodedBytes": 76, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_offchainlabs_cobalt_dist_cobalt_es_js.js", + "resourceBytes": 576077, + "encodedBytes": 147047, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/src_components_App_App_tsx.js", + "resourceBytes": 43336048, + "encodedBytes": 9942112, + "unusedBytes": 574631 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_ethereum-provider_dist_index_es_js.js", + "resourceBytes": 2332522, + "encodedBytes": 638797, + "unusedBytes": 1282 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_safeWallet-VUYZPLY4_js.js", + "resourceBytes": 5674, + "encodedBytes": 2897, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_rainbowWallet-2SR6TVBF_js.js", + "resourceBytes": 11347, + "encodedBytes": 3707, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_coinbaseWallet-WWX6LF36_js.js", + "resourceBytes": 3751, + "encodedBytes": 1933, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_metaMaskWallet-YFHEHW7V_js.js", + "resourceBytes": 18353, + "encodedBytes": 4611, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_walletConnectWallet-FNSU4KNU_js.js", + "resourceBytes": 5968, + "encodedBytes": 2946, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_wallets_walletConnectors_okxWallet-GJMKZIND_js.js", + "resourceBytes": 4565, + "encodedBytes": 2068, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_wallets_walletConnectors_trustWallet-E2GVGE4U_js.js", + "resourceBytes": 4371, + "encodedBytes": 2140, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_wallets_walletConnectors_rabbyWallet-FLVUU35F_js.js", + "resourceBytes": 8269, + "encodedBytes": 3961, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_assets-NU2OP443_js.js", + "resourceBytes": 45515, + "encodedBytes": 12100, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_rainbow-me_rainbowkit_dist_login-CWDTIDNK_js.js", + "resourceBytes": 24218, + "encodedBytes": 9328, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_coinbase_wallet-sdk_dist_index_js.js", + "resourceBytes": 657123, + "encodedBytes": 172991, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_modal_dist_index_js.js", + "resourceBytes": 63923, + "encodedBytes": 22001, + "unusedBytes": 0 + }, + { + "name": "http://localhost:3000/_next/static/chunks/node_modules_walletconnect_modal-ui_dist_index_js.js", + "resourceBytes": 1321329, + "encodedBytes": 333646, + "unusedBytes": 0 + } + ] + } + }, + "accesskeys": { + "id": "accesskeys", + "title": "`[accesskey]` values are unique", + "description": "Access keys let users quickly focus a part of the page. For proper navigation, each access key must be unique. [Learn more about access keys](https://dequeuniversity.com/rules/axe/4.10/accesskeys).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-allowed-attr": { + "id": "aria-allowed-attr", + "title": "`[aria-*]` attributes match their roles", + "description": "Each ARIA `role` supports a specific subset of `aria-*` attributes. Mismatching these invalidates the `aria-*` attributes. [Learn how to match ARIA attributes to their roles](https://dequeuniversity.com/rules/axe/4.10/aria-allowed-attr).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "aria-allowed-role": { + "id": "aria-allowed-role", + "title": "Uses ARIA roles only on compatible elements", + "description": "Many HTML elements can only be assigned certain ARIA roles. Using ARIA roles where they are not allowed can interfere with the accessibility of the web page. [Learn more about ARIA roles](https://dequeuniversity.com/rules/axe/4.10/aria-allowed-role).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "aria-command-name": { + "id": "aria-command-name", + "title": "`button`, `link`, and `menuitem` elements have accessible names", + "description": "When an element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to make command elements more accessible](https://dequeuniversity.com/rules/axe/4.10/aria-command-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-conditional-attr": { + "id": "aria-conditional-attr", + "title": "ARIA attributes are used as specified for the element's role", + "description": "Some ARIA attributes are only allowed on an element under certain conditions. [Learn more about conditional ARIA attributes](https://dequeuniversity.com/rules/axe/4.10/aria-conditional-attr).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "aria-deprecated-role": { + "id": "aria-deprecated-role", + "title": "Deprecated ARIA roles were not used", + "description": "Deprecated ARIA roles may not be processed correctly by assistive technology. [Learn more about deprecated ARIA roles](https://dequeuniversity.com/rules/axe/4.10/aria-deprecated-role).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "aria-dialog-name": { + "id": "aria-dialog-name", + "title": "Elements with `role=\"dialog\"` or `role=\"alertdialog\"` do not have accessible names.", + "description": "ARIA dialog elements without accessible names may prevent screen readers users from discerning the purpose of these elements. [Learn how to make ARIA dialog elements more accessible](https://dequeuniversity.com/rules/axe/4.10/aria-dialog-name).", + "score": 0, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [ + { + "node": { + "type": "node", + "lhId": "1-0-DIV", + "path": "1,HTML,1,BODY,7,WCM-MODAL,a,#document-fragment,3,DIV", + "selector": "div#wcm-modal", + "boundingRect": { + "top": 0, + "bottom": 940, + "left": 0, + "right": 1350, + "width": 1350, + "height": 940 + }, + "snippet": "
", + "nodeLabel": "div#wcm-modal", + "explanation": "Fix any of the following:\n aria-label attribute does not exist or is empty\n aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty\n Element has no title attribute" + } + } + ], + "debugData": { + "type": "debugdata", + "impact": "serious", + "tags": [ + "cat.aria", + "best-practice" + ] + } + } + }, + "aria-hidden-body": { + "id": "aria-hidden-body", + "title": "`[aria-hidden=\"true\"]` is not present on the document ``", + "description": "Assistive technologies, like screen readers, work inconsistently when `aria-hidden=\"true\"` is set on the document ``. [Learn how `aria-hidden` affects the document body](https://dequeuniversity.com/rules/axe/4.10/aria-hidden-body).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "aria-hidden-focus": { + "id": "aria-hidden-focus", + "title": "`[aria-hidden=\"true\"]` elements do not contain focusable descendents", + "description": "Focusable descendents within an `[aria-hidden=\"true\"]` element prevent those interactive elements from being available to users of assistive technologies like screen readers. [Learn how `aria-hidden` affects focusable elements](https://dequeuniversity.com/rules/axe/4.10/aria-hidden-focus).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "aria-input-field-name": { + "id": "aria-input-field-name", + "title": "ARIA input fields have accessible names", + "description": "When an input field doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about input field labels](https://dequeuniversity.com/rules/axe/4.10/aria-input-field-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-meter-name": { + "id": "aria-meter-name", + "title": "ARIA `meter` elements have accessible names", + "description": "When a meter element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to name `meter` elements](https://dequeuniversity.com/rules/axe/4.10/aria-meter-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-progressbar-name": { + "id": "aria-progressbar-name", + "title": "ARIA `progressbar` elements have accessible names", + "description": "When a `progressbar` element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to label `progressbar` elements](https://dequeuniversity.com/rules/axe/4.10/aria-progressbar-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-prohibited-attr": { + "id": "aria-prohibited-attr", + "title": "Elements use only permitted ARIA attributes", + "description": "Using ARIA attributes in roles where they are prohibited can mean that important information is not communicated to users of assistive technologies. [Learn more about prohibited ARIA roles](https://dequeuniversity.com/rules/axe/4.10/aria-prohibited-attr).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "aria-required-attr": { + "id": "aria-required-attr", + "title": "`[role]`s have all required `[aria-*]` attributes", + "description": "Some ARIA roles have required attributes that describe the state of the element to screen readers. [Learn more about roles and required attributes](https://dequeuniversity.com/rules/axe/4.10/aria-required-attr).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "aria-required-children": { + "id": "aria-required-children", + "title": "Elements with an ARIA `[role]` that require children to contain a specific `[role]` have all required children.", + "description": "Some ARIA parent roles must contain specific child roles to perform their intended accessibility functions. [Learn more about roles and required children elements](https://dequeuniversity.com/rules/axe/4.10/aria-required-children).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-required-parent": { + "id": "aria-required-parent", + "title": "`[role]`s are contained by their required parent element", + "description": "Some ARIA child roles must be contained by specific parent roles to properly perform their intended accessibility functions. [Learn more about ARIA roles and required parent element](https://dequeuniversity.com/rules/axe/4.10/aria-required-parent).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-roles": { + "id": "aria-roles", + "title": "`[role]` values are valid", + "description": "ARIA roles must have valid values in order to perform their intended accessibility functions. [Learn more about valid ARIA roles](https://dequeuniversity.com/rules/axe/4.10/aria-roles).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "aria-text": { + "id": "aria-text", + "title": "Elements with the `role=text` attribute do not have focusable descendents.", + "description": "Adding `role=text` around a text node split by markup enables VoiceOver to treat it as one phrase, but the element's focusable descendents will not be announced. [Learn more about the `role=text` attribute](https://dequeuniversity.com/rules/axe/4.10/aria-text).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-toggle-field-name": { + "id": "aria-toggle-field-name", + "title": "ARIA toggle fields have accessible names", + "description": "When a toggle field doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about toggle fields](https://dequeuniversity.com/rules/axe/4.10/aria-toggle-field-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-tooltip-name": { + "id": "aria-tooltip-name", + "title": "ARIA `tooltip` elements have accessible names", + "description": "When a tooltip element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to name `tooltip` elements](https://dequeuniversity.com/rules/axe/4.10/aria-tooltip-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-treeitem-name": { + "id": "aria-treeitem-name", + "title": "ARIA `treeitem` elements have accessible names", + "description": "When a `treeitem` element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about labeling `treeitem` elements](https://dequeuniversity.com/rules/axe/4.10/aria-treeitem-name).", + "score": null, + "scoreDisplayMode": "notApplicable" + }, + "aria-valid-attr-value": { + "id": "aria-valid-attr-value", + "title": "`[aria-*]` attributes have valid values", + "description": "Assistive technologies, like screen readers, can't interpret ARIA attributes with invalid values. [Learn more about valid values for ARIA attributes](https://dequeuniversity.com/rules/axe/4.10/aria-valid-attr-value).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "aria-valid-attr": { + "id": "aria-valid-attr", + "title": "`[aria-*]` attributes are valid and not misspelled", + "description": "Assistive technologies, like screen readers, can't interpret ARIA attributes with invalid names. [Learn more about valid ARIA attributes](https://dequeuniversity.com/rules/axe/4.10/aria-valid-attr).", + "score": 1, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [], + "items": [] + } + }, + "button-name": { + "id": "button-name", + "title": "Buttons do not have an accessible name", + "description": "When a button doesn't have an accessible name, screen readers announce it as \"button\", making it unusable for users who rely on screen readers. [Learn how to make buttons more accessible](https://dequeuniversity.com/rules/axe/4.10/button-name).", + "score": 0, + "scoreDisplayMode": "binary", + "details": { + "type": "table", + "headings": [ + { + "key": "node", + "valueType": "node", + "subItemsHeading": { + "key": "relatedNode", + "valueType": "node" + }, + "label": "Failing Elements" + } + ], + "items": [ + { + "node": { + "type": "node", + "lhId": "1-1-BUTTON", + "path": "1,HTML,1,BODY,0,DIV,0,DIV,2,DIV,0,DIV,0,DIV,0,DIV,0,DIV,0,BUTTON", + "selector": "div.sticky > div.sticky > div.relative > button.absolute", + "boundingRect": { + "top": 60, + "bottom": 92, + "left": 239, + "right": 271, + "width": 32, + "height": 32 + }, + "snippet": "