From dafe06b9d59730a5f70d304f8c2bd04dda1dc1e3 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 3 Oct 2025 11:09:59 +0200 Subject: [PATCH 1/4] feat: collect lighthouse data Adds some logic to collect Lighthouse data for the eval run. --- package.json | 1 + pnpm-lock.yaml | 812 ++++++++++++++++++- runner/eval-cli.ts | 7 + runner/index.ts | 5 + runner/orchestration/build-serve-loop.ts | 3 + runner/orchestration/generate.ts | 4 + runner/orchestration/serve-testing-worker.ts | 2 + runner/workers/serve-testing/lighthouse.ts | 70 ++ runner/workers/serve-testing/puppeteer.ts | 27 +- runner/workers/serve-testing/worker-types.ts | 26 +- runner/workers/serve-testing/worker.ts | 9 +- 11 files changed, 928 insertions(+), 38 deletions(-) create mode 100644 runner/workers/serve-testing/lighthouse.ts diff --git a/package.json b/package.json index 7227adc..1b64e93 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "genkit": "^1.19.1", "genkitx-anthropic": "0.25.0", "handlebars": "^4.7.8", + "lighthouse": "^12.8.2", "limiter": "^3.0.0", "marked": "^16.1.1", "node-fetch": "^3.3.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8cc3aed..9e48d21 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,6 +68,9 @@ importers: handlebars: specifier: ^4.7.8 version: 4.7.8 + lighthouse: + specifier: ^12.8.2 + version: 12.8.2 limiter: specifier: ^3.0.0 version: 3.0.0 @@ -859,6 +862,21 @@ packages: resolution: {integrity: sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ==} engines: {node: '>=20.0.0'} + '@formatjs/ecma402-abstract@2.3.4': + resolution: {integrity: sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA==} + + '@formatjs/fast-memoize@2.2.7': + resolution: {integrity: sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==} + + '@formatjs/icu-messageformat-parser@2.11.2': + resolution: {integrity: sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA==} + + '@formatjs/icu-skeleton-parser@1.8.14': + resolution: {integrity: sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ==} + + '@formatjs/intl-localematcher@0.6.1': + resolution: {integrity: sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==} + '@genkit-ai/ai@1.20.0': resolution: {integrity: sha512-mT8rS5Qc3pLKM4nLIRo2PWP7PgNln/4/z3hC96DxIXJ6MGE33nbEqU2X4bHvB33bKxiDgMOahTbOu0APNj8BtA==} @@ -1602,6 +1620,10 @@ packages: resolution: {integrity: sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==} engines: {node: '>=14'} + '@opentelemetry/api-logs@0.57.2': + resolution: {integrity: sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==} + engines: {node: '>=14'} + '@opentelemetry/api@1.9.0': resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} @@ -1618,6 +1640,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/context-async-hooks@1.30.1': + resolution: {integrity: sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/context-async-hooks@2.0.1': resolution: {integrity: sha512-XuY23lSI3d4PEqKA+7SLtAgwqIfc6E/E9eAQWLN1vlpC53ybO3o6jW4BsXo1xvz9lYyyWItfQDDLzezER01mCw==} engines: {node: ^18.19.0 || >=20.6.0} @@ -1744,6 +1772,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-amqplib@0.46.1': + resolution: {integrity: sha512-AyXVnlCf/xV3K/rNumzKxZqsULyITJH6OVLiW6730JPRqWA7Zc9bvYoVNpN6iOpTU8CasH34SU/ksVJmObFibQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-aws-lambda@0.43.0': resolution: {integrity: sha512-pSxcWlsE/pCWQRIw92sV2C+LmKXelYkjkA7C5s39iPUi4pZ2lA1nIiw+1R/y2pDEhUHcaKkNyljQr3cx9ZpVlQ==} engines: {node: '>=14'} @@ -1774,6 +1808,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-connect@0.43.1': + resolution: {integrity: sha512-ht7YGWQuV5BopMcw5Q2hXn3I8eG8TH0J/kc/GMcW4CuNTgiP6wCu44BOnucJWL3CmFWaRHI//vWyAhaC8BwePw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-cucumber@0.8.0': resolution: {integrity: sha512-ieTm4RBIlZt2brPwtX5aEZYtYnkyqhAVXJI9RIohiBVMe5DxiwCwt+2Exep/nDVqGPX8zRBZUl4AEw423OxJig==} engines: {node: '>=14'} @@ -1786,6 +1826,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-dataloader@0.16.1': + resolution: {integrity: sha512-K/qU4CjnzOpNkkKO4DfCLSQshejRNAJtd4esgigo/50nxCB6XCyi1dhAblUHM9jG5dRm8eu0FB+t87nIo99LYQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-dns@0.38.0': resolution: {integrity: sha512-Um07I0TQXDWa+ZbEAKDFUxFH40dLtejtExDOMLNJ1CL8VmOmA71qx93Qi/QG4tGkiI1XWqr7gF/oiMCJ4m8buQ==} engines: {node: '>=14'} @@ -1798,6 +1844,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-express@0.47.1': + resolution: {integrity: sha512-QNXPTWteDclR2B4pDFpz0TNghgB33UMjUt14B+BZPmtH1MwUFAfLHBaP5If0Z5NZC+jaH8oF2glgYjrmhZWmSw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-fastify@0.38.0': resolution: {integrity: sha512-HBVLpTSYpkQZ87/Df3N0gAw7VzYZV3n28THIBrJWfuqw3Or7UqdhnjeuMIPQ04BKk3aZc0cWn2naSQObbh5vXw==} engines: {node: '>=14'} @@ -1810,18 +1862,36 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-fs@0.19.1': + resolution: {integrity: sha512-6g0FhB3B9UobAR60BGTcXg4IHZ6aaYJzp0Ki5FhnxyAPt8Ns+9SSvgcrnsN2eGmk3RWG5vYycUGOEApycQL24A==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-generic-pool@0.38.1': resolution: {integrity: sha512-WvssuKCuavu/hlq661u82UWkc248cyI/sT+c2dEIj6yCk0BUkErY1D+9XOO+PmHdJNE+76i2NdcvQX5rJrOe/w==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-generic-pool@0.43.1': + resolution: {integrity: sha512-M6qGYsp1cURtvVLGDrPPZemMFEbuMmCXgQYTReC/IbimV5sGrLBjB+/hANUpRZjX67nGLdKSVLZuQQAiNz+sww==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-graphql@0.42.0': resolution: {integrity: sha512-N8SOwoKL9KQSX7z3gOaw5UaTeVQcfDO1c21csVHnmnmGUoqsXbArK2B8VuwPWcv6/BC/i3io+xTo7QGRZ/z28Q==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-graphql@0.47.1': + resolution: {integrity: sha512-EGQRWMGqwiuVma8ZLAZnExQ7sBvbOx0N/AE/nlafISPs8S+QtXX+Viy6dcQwVWwYHQPAcuY3bFt3xgoAwb4ZNQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-grpc@0.52.1': resolution: {integrity: sha512-EdSDiDSAO+XRXk/ZN128qQpBo1I51+Uay/LUPcPQhSRGf7fBPIEUBeOLQiItguGsug5MGOYjql2w/1wCQF3fdQ==} engines: {node: '>=14'} @@ -1834,6 +1904,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-hapi@0.45.2': + resolution: {integrity: sha512-7Ehow/7Wp3aoyCrZwQpU7a2CnoMq0XhIcioFuKjBb0PLYfBfmTsFTUyatlHu0fRxhwcRsSQRTvEhmZu8CppBpQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-http@0.203.0': resolution: {integrity: sha512-y3uQAcCOAwnO6vEuNVocmpVzG3PER6/YZqbPbbffDdJ9te5NkHEkfSMNzlC3+v7KlE+WinPGc3N7MR30G1HY2g==} engines: {node: ^18.19.0 || >=20.6.0} @@ -1846,36 +1922,72 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-http@0.57.2': + resolution: {integrity: sha512-1Uz5iJ9ZAlFOiPuwYg29Bf7bJJc/GeoeJIFKJYQf67nTVKFe8RHbEtxgkOmK4UGZNHKXcpW4P8cWBYzBn1USpg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-ioredis@0.42.0': resolution: {integrity: sha512-P11H168EKvBB9TUSasNDOGJCSkpT44XgoM6d3gRIWAa9ghLpYhl0uRkS8//MqPzcJVHr3h3RmfXIpiYLjyIZTw==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-ioredis@0.47.1': + resolution: {integrity: sha512-OtFGSN+kgk/aoKgdkKQnBsQFDiG8WdCxu+UrHr0bXScdAmtSzLSraLo7wFIb25RVHfRWvzI5kZomqJYEg/l1iA==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-kafkajs@0.2.0': resolution: {integrity: sha512-uKKmhEFd0zR280tJovuiBG7cfnNZT4kvVTvqtHPxQP7nOmRbJstCYHFH13YzjVcKjkmoArmxiSulmZmF7SLIlg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-kafkajs@0.7.1': + resolution: {integrity: sha512-OtjaKs8H7oysfErajdYr1yuWSjMAectT7Dwr+axIoZqT9lmEOkD/H/3rgAs8h/NIuEi2imSXD+vL4MZtOuJfqQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-knex@0.39.0': resolution: {integrity: sha512-lRwTqIKQecPWDkH1KEcAUcFhCaNssbKSpxf4sxRTAROCwrCEnYkjOuqJHV+q1/CApjMTaKu0Er4LBv/6bDpoxA==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-knex@0.44.1': + resolution: {integrity: sha512-U4dQxkNhvPexffjEmGwCq68FuftFK15JgUF05y/HlK3M6W/G2iEaACIfXdSnwVNe9Qh0sPfw8LbOPxrWzGWGMQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-koa@0.42.0': resolution: {integrity: sha512-H1BEmnMhho8o8HuNRq5zEI4+SIHDIglNB7BPKohZyWG4fWNuR7yM4GTlR01Syq21vODAS7z5omblScJD/eZdKw==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-koa@0.47.1': + resolution: {integrity: sha512-l/c+Z9F86cOiPJUllUCt09v+kICKvT+Vg1vOAJHtHPsJIzurGayucfCMq2acd/A/yxeNWunl9d9eqZ0G+XiI6A==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-lru-memoizer@0.39.0': resolution: {integrity: sha512-eU1Wx1RRTR/2wYXFzH9gcpB8EPmhYlNDIUHzUXjyUE0CAXEJhBLkYNlzdaVCoQDw2neDqS+Woshiia6+emWK9A==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-lru-memoizer@0.44.1': + resolution: {integrity: sha512-5MPkYCvG2yw7WONEjYj5lr5JFehTobW7wX+ZUFy81oF2lr9IPfZk9qO+FTaM0bGEiymwfLwKe6jE15nHn1nmHg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-memcached@0.38.0': resolution: {integrity: sha512-tPmyqQEZNyrvg6G+iItdlguQEcGzfE+bJkpQifmBXmWBnoS5oU3UxqtyYuXGL2zI9qQM5yMBHH4nRXWALzy7WA==} engines: {node: '>=14'} @@ -1888,24 +2000,48 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-mongodb@0.52.0': + resolution: {integrity: sha512-1xmAqOtRUQGR7QfJFfGV/M2kC7wmI2WgZdpru8hJl3S0r4hW0n3OQpEHlSGXJAaNFyvT+ilnwkT+g5L4ljHR6g==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-mongoose@0.41.0': resolution: {integrity: sha512-ivJg4QnnabFxxoI7K8D+in7hfikjte38sYzJB9v1641xJk9Esa7jM3hmbPB7lxwcgWJLVEDvfPwobt1if0tXxA==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-mongoose@0.46.1': + resolution: {integrity: sha512-3kINtW1LUTPkiXFRSSBmva1SXzS/72we/jL22N+BnF3DFcoewkdkHPYOIdAAk9gSicJ4d5Ojtt1/HeibEc5OQg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-mysql2@0.40.0': resolution: {integrity: sha512-0xfS1xcqUmY7WE1uWjlmI67Xg3QsSUlNT+AcXHeA4BDUPwZtWqF4ezIwLgpVZfHOnkAEheqGfNSWd1PIu3Wnfg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-mysql2@0.45.2': + resolution: {integrity: sha512-h6Ad60FjCYdJZ5DTz1Lk2VmQsShiViKe0G7sYikb0GHI0NVvApp2XQNRHNjEMz87roFttGPLHOYVPlfy+yVIhQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-mysql@0.40.0': resolution: {integrity: sha512-d7ja8yizsOCNMYIJt5PH/fKZXjb/mS48zLROO4BzZTtDfhNCl2UM/9VIomP2qkGIFVouSJrGr/T00EzY7bPtKA==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-mysql@0.45.1': + resolution: {integrity: sha512-TKp4hQ8iKQsY7vnp/j0yJJ4ZsP109Ht6l4RHTj0lNEG1TfgTrIH5vJMbgmoYXWzNHAqBH2e7fncN12p3BP8LFg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-nestjs-core@0.39.0': resolution: {integrity: sha512-mewVhEXdikyvIZoMIUry8eb8l3HUjuQjSjVbmLVTt4NQi35tkpnHQrG9bTRBrl3403LoWZ2njMPJyg4l6HfKvA==} engines: {node: '>=14'} @@ -1924,6 +2060,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-pg@0.51.1': + resolution: {integrity: sha512-QxgjSrxyWZc7Vk+qGSfsejPVFL1AgAJdSBMYZdDUbwg730D09ub3PXScB9d04vIqPriZ+0dqzjmQx0yWKiCi2Q==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-pino@0.41.0': resolution: {integrity: sha512-Kpv0fJRk/8iMzMk5Ue5BsUJfHkBJ2wQoIi/qduU1a1Wjx9GLj6J2G17PHjPK5mnZjPNzkFOXFADZMfgDioliQw==} engines: {node: '>=14'} @@ -1936,6 +2078,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-redis-4@0.46.1': + resolution: {integrity: sha512-UMqleEoabYMsWoTkqyt9WAzXwZ4BlFZHO40wr3d5ZvtjKCHlD4YXLm+6OLCeIi/HkX7EXvQaz8gtAwkwwSEvcQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-redis@0.41.0': resolution: {integrity: sha512-RJ1pwI3btykp67ts+5qZbaFSAAzacucwBet5/5EsKYtWBpHbWwV/qbGN/kIBzXg5WEZBhXLrR/RUq0EpEUpL3A==} engines: {node: '>=14'} @@ -1966,6 +2114,18 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation-tedious@0.18.1': + resolution: {integrity: sha512-5Cuy/nj0HBaH+ZJ4leuD7RjgvA844aY2WW+B5uLcWtxGjRZl3MNLuxnNg5DYWZNPO+NafSSnra0q49KWAHsKBg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-undici@0.10.1': + resolution: {integrity: sha512-rkOGikPEyRpMCmNu9AQuV5dtRlDmJp2dK5sw8roVshAGoB6hH/3QjDtRhdwd75SsJwgynWUNRUYe0wAkTo16tQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.7.0 + '@opentelemetry/instrumentation-undici@0.5.0': resolution: {integrity: sha512-aNTeSrFAVcM9qco5DfZ9DNXu6hpMRe8Kt8nCDHfMWDB3pwgGVUE76jTdohc+H/7eLRqh4L7jqs5NSQoHw7S6ww==} engines: {node: '>=14'} @@ -1990,6 +2150,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation@0.57.2': + resolution: {integrity: sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/otlp-exporter-base@0.203.0': resolution: {integrity: sha512-Wbxf7k+87KyvxFr5D7uOiSq/vHXWommvdnNE7vECO3tAhsA2GfOlpWINCMWUEPdHZ7tCXxw6Epp3vgx3jU7llQ==} engines: {node: ^18.19.0 || >=20.6.0} @@ -2295,6 +2461,9 @@ packages: resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} engines: {node: '>= 10.0.0'} + '@paulirish/trace_engine@0.0.59': + resolution: {integrity: sha512-439NUzQGmH+9Y017/xCchBP9571J4bzhpcNhrxorf7r37wcyJZkgUfrUsRL3xl+JDcZ6ORhoFCzCw98c6S3YHw==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2311,6 +2480,11 @@ packages: resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} engines: {node: '>=12'} + '@prisma/instrumentation@6.11.1': + resolution: {integrity: sha512-mrZOev24EDhnefmnZX7WVVT7v+r9LttPRqf54ONvj6re4XMF7wFTpK2tLJi4XHB7fFp/6xhYbgRel8YV7gQiyA==} + peerDependencies: + '@opentelemetry/api': ^1.8 + '@protobuf-ts/plugin@2.11.1': resolution: {integrity: sha512-HyuprDcw0bEEJqkOWe1rnXUP0gwYLij8YhPuZyZk6cJbIgc/Q0IFgoHQxOXNIXAcXM4Sbehh6kjVnCzasElw1A==} hasBin: true @@ -2603,6 +2777,36 @@ packages: '@selderee/plugin-htmlparser2@0.11.0': resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} + '@sentry/core@9.46.0': + resolution: {integrity: sha512-it7JMFqxVproAgEtbLgCVBYtQ9fIb+Bu0JD+cEplTN/Ukpe6GaolyYib5geZqslVxhp2sQgT+58aGvfd/k0N8Q==} + engines: {node: '>=18'} + + '@sentry/node-core@9.46.0': + resolution: {integrity: sha512-XRVu5pqoklZeh4wqhxCLZkz/ipoKhitctgEFXX9Yh1e1BoHM2pIxT52wf+W6hHM676TFmFXW3uKBjsmRM3AjgA==} + engines: {node: '>=18'} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/context-async-hooks': ^1.30.1 || ^2.0.0 + '@opentelemetry/core': ^1.30.1 || ^2.0.0 + '@opentelemetry/instrumentation': '>=0.57.1 <1' + '@opentelemetry/resources': ^1.30.1 || ^2.0.0 + '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.0.0 + '@opentelemetry/semantic-conventions': ^1.34.0 + + '@sentry/node@9.46.0': + resolution: {integrity: sha512-pRLqAcd7GTGvN8gex5FtkQR5Mcol8gOy1WlyZZFq4rBbVtMbqKOQRhohwqnb+YrnmtFpj7IZ7KNDo077MvNeOQ==} + engines: {node: '>=18'} + + '@sentry/opentelemetry@9.46.0': + resolution: {integrity: sha512-w2zTxqrdmwRok0cXBoh+ksXdGRUHUZhlpfL/H2kfTodOL+Mk8rW72qUmfqQceXoqgbz8UyK8YgJbyt+XS5H4Qg==} + engines: {node: '>=18'} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/context-async-hooks': ^1.30.1 || ^2.0.0 + '@opentelemetry/core': ^1.30.1 || ^2.0.0 + '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.0.0 + '@opentelemetry/semantic-conventions': ^1.34.0 + '@shikijs/core@3.13.0': resolution: {integrity: sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA==} @@ -2784,6 +2988,9 @@ packages: '@types/mysql@2.15.22': resolution: {integrity: sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ==} + '@types/mysql@2.15.26': + resolution: {integrity: sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==} + '@types/node-fetch@2.6.13': resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} @@ -2805,6 +3012,9 @@ packages: '@types/pg-pool@2.0.4': resolution: {integrity: sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ==} + '@types/pg-pool@2.0.6': + resolution: {integrity: sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==} + '@types/pg@8.6.1': resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==} @@ -2999,6 +3209,10 @@ packages: ansi-color@0.2.1: resolution: {integrity: sha512-bF6xLaZBLpOQzgYUtYEhJx090nPSZk1BQ/q2oyBK9aMMcJHzx9uXGCjI2Y+LebsN4Jwoykr0V9whbPiogdyHoQ==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + ansi-escapes@7.1.1: resolution: {integrity: sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==} engines: {node: '>=18'} @@ -3284,6 +3498,11 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} + chrome-launcher@1.2.1: + resolution: {integrity: sha512-qmFR5PLMzHyuNJHwOloHPAHhbaNglkfeV/xDtt5b7xiFFyU1I+AZZX0PYseMuhenJSSirgxELYIbswcoc+5H4A==} + engines: {node: '>=12.13.0'} + hasBin: true + chromium-bidi@9.1.0: resolution: {integrity: sha512-rlUzQ4WzIAWdIbY/viPShhZU2n21CxDUgazXVbw4Hu1MwaeUSEksSeM6DqPgpRjCLXRk702AVRxJxoOz0dw4OA==} peerDependencies: @@ -3457,6 +3676,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + csp_evaluator@1.1.5: + resolution: {integrity: sha512-EL/iN9etCTzw/fBnp0/uj0f5BOOGvZut2mzsiiBZ/FdT6gFQCKRO/tmcKOxn5drWZ2Ndm/xBb1SI4zwWbGtmIw==} + css-functions-list@3.2.3: resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==} engines: {node: '>=12 || >=16'} @@ -3525,6 +3747,9 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -3552,6 +3777,10 @@ packages: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} engines: {node: '>=10'} + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + define-lazy-prop@3.0.0: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} @@ -3591,6 +3820,9 @@ packages: devtools-protocol@0.0.1495869: resolution: {integrity: sha512-i+bkd9UYFis40RcnkW7XrOprCujXRAHg62IVh/Ah3G8MmNXpCGt1m0dTFhSdx/AVs8XEMbdOGRwdkR1Bcta8AA==} + devtools-protocol@0.0.1507524: + resolution: {integrity: sha512-OjaNE7qpk6GRTXtqQjAE5bGx6+c4F1zZH0YXtpZQLM92HNXx4zMAaqlKhP4T52DosG6hDW8gPMNhGOF8xbwk/w==} + di@0.0.1: resolution: {integrity: sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==} @@ -3689,6 +3921,10 @@ packages: resolution: {integrity: sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==} engines: {node: '>=10.2.0'} + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + ent@2.2.2: resolution: {integrity: sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==} engines: {node: '>= 0.4'} @@ -4291,6 +4527,10 @@ packages: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} + http-link-header@1.1.3: + resolution: {integrity: sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ==} + engines: {node: '>=6.0.0'} + http-parser-js@0.5.10: resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} @@ -4352,6 +4592,9 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + image-ssim@0.2.0: + resolution: {integrity: sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg==} + immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} @@ -4421,6 +4664,9 @@ packages: react-devtools-core: optional: true + intl-messageformat@10.7.16: + resolution: {integrity: sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug==} + ip-address@10.0.1: resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} engines: {node: '>= 12'} @@ -4440,6 +4686,11 @@ packages: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -4531,6 +4782,10 @@ packages: resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} engines: {node: '>=18'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + is-wsl@3.1.0: resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} engines: {node: '>=16'} @@ -4593,6 +4848,13 @@ packages: jose@4.15.9: resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} + jpeg-js@0.4.4: + resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} + + js-library-detector@6.7.0: + resolution: {integrity: sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA==} + engines: {node: '>=12'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4730,6 +4992,9 @@ packages: leac@0.6.0: resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} + legacy-javascript@0.0.1: + resolution: {integrity: sha512-lPyntS4/aS7jpuvOlitZDFifBCb4W8L/3QU0PLbUTUj+zYah8rfVjYic88yG7ZKTxhS5h9iz7duT8oUXKszLhg==} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -4737,6 +5002,17 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lighthouse-logger@2.0.2: + resolution: {integrity: sha512-vWl2+u5jgOQuZR55Z1WM0XDdrJT6mzMP8zHUct7xTlWhuQs+eV0g+QL0RQdFjT54zVmbhLCP8vIVpy1wGn/gCg==} + + lighthouse-stack-packs@1.12.2: + resolution: {integrity: sha512-Ug8feS/A+92TMTCK6yHYLwaFMuelK/hAKRMdldYkMNwv+d9PtWxjXEg6rwKtsUXTADajhdrhXyuNCJ5/sfmPFw==} + + lighthouse@12.8.2: + resolution: {integrity: sha512-+5SKYzVaTFj22MgoYDPNrP9tlD2/Ay7j3SxPSFD9FpPyVxGr4UtOQGKyrdZ7wCmcnBaFk0mCkPfARU3CsE0nvA==} + engines: {node: '>=18.16'} + hasBin: true + limiter@1.1.5: resolution: {integrity: sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==} @@ -4758,6 +5034,9 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} @@ -4820,6 +5099,9 @@ packages: long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + lookup-closest-locale@6.2.0: + resolution: {integrity: sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -4877,6 +5159,9 @@ packages: engines: {node: '>= 20'} hasBin: true + marky@1.3.0: + resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -4916,6 +5201,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + metaviewport-parser@0.3.0: + resolution: {integrity: sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ==} + methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} @@ -5245,6 +5533,10 @@ packages: resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} engines: {node: '>=18'} + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + openai@4.104.0: resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} hasBin: true @@ -5323,6 +5615,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-cache-control@1.0.1: + resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -5736,6 +6031,10 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + robots-parser@3.0.1: + resolution: {integrity: sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ==} + engines: {node: '>=10.0.0'} + rolldown@1.0.0-beta.39: resolution: {integrity: sha512-05bTT0CJU9dvCRC0Uc4zwB79W5N9MV9OG/Inyx8KNE2pSrrApJoWxEEArW6rmjx113HIx5IreCoTjzLfgvXTdg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5941,6 +6240,10 @@ packages: spdx-license-ids@3.0.22: resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} + speedline-core@1.4.3: + resolution: {integrity: sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog==} + engines: {node: '>=8.0'} + ssri@12.0.0: resolution: {integrity: sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==} engines: {node: ^18.17.0 || >=20.5.0} @@ -6111,6 +6414,9 @@ packages: text-hex@1.0.0: resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + third-party-web@0.27.0: + resolution: {integrity: sha512-h0JYX+dO2Zr3abCQpS6/uFjujaOjA1DyDzGQ41+oFn9VW/ARiq9g5ln7qEP9+BTzDpOMyIfsfj4OvfgXAsMUSA==} + thriftrw@3.11.4: resolution: {integrity: sha512-UcuBd3eanB3T10nXWRRMwfwoaC6VMk7qe3/5YIWP2Jtw+EbHqJ0p1/K3x8ixiR5dozKSSfcg1W+0e33G1Di3XA==} engines: {node: '>= 0.10.x'} @@ -6129,6 +6435,12 @@ packages: tinygradient@1.1.5: resolution: {integrity: sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw==} + tldts-core@7.0.16: + resolution: {integrity: sha512-XHhPmHxphLi+LGbH0G/O7dmUH9V65OY20R7vH8gETHsp5AZCjBk9l8sqmRKLaGOxnETU7XNSDUPtewAy/K6jbA==} + + tldts-icann@7.0.16: + resolution: {integrity: sha512-WS/pPasPs2cx6orcxCcIz01SlG3dwYlgjLAnQt7vLAusTuTLqdI8zmkqbM8TWYEf3Z0o1S4BzM3oSRFPk/6WnA==} + tmp@0.2.5: resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} engines: {node: '>=14.14'} @@ -6509,6 +6821,18 @@ packages: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.17.1: resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} engines: {node: '>=10.0.0'} @@ -7314,6 +7638,32 @@ snapshots: tslib: 2.8.1 optional: true + '@formatjs/ecma402-abstract@2.3.4': + dependencies: + '@formatjs/fast-memoize': 2.2.7 + '@formatjs/intl-localematcher': 0.6.1 + decimal.js: 10.6.0 + tslib: 2.8.1 + + '@formatjs/fast-memoize@2.2.7': + dependencies: + tslib: 2.8.1 + + '@formatjs/icu-messageformat-parser@2.11.2': + dependencies: + '@formatjs/ecma402-abstract': 2.3.4 + '@formatjs/icu-skeleton-parser': 1.8.14 + tslib: 2.8.1 + + '@formatjs/icu-skeleton-parser@1.8.14': + dependencies: + '@formatjs/ecma402-abstract': 2.3.4 + tslib: 2.8.1 + + '@formatjs/intl-localematcher@0.6.1': + dependencies: + tslib: 2.8.1 + '@genkit-ai/ai@1.20.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(genkit@1.20.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13)))': dependencies: '@genkit-ai/core': 1.20.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(genkit@1.20.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))) @@ -8298,6 +8648,10 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs@0.57.2': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api@1.9.0': {} '@opentelemetry/auto-instrumentations-node@0.49.2(@opentelemetry/api@1.9.0)(encoding@0.1.13)': @@ -8359,6 +8713,10 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks@2.0.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8550,6 +8908,15 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-amqplib@0.46.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-aws-lambda@0.43.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8603,6 +8970,16 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-connect@0.43.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + '@types/connect': 3.4.38 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-cucumber@0.8.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8620,6 +8997,13 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-dataloader@0.16.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-dns@0.38.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8639,6 +9023,15 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-express@0.47.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-fastify@0.38.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8658,6 +9051,14 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-fs@0.19.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-generic-pool@0.38.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8666,6 +9067,13 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-generic-pool@0.43.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-graphql@0.42.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8674,6 +9082,13 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-graphql@0.47.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-grpc@0.52.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8693,6 +9108,15 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-hapi@0.45.2(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-http@0.203.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8715,6 +9139,17 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-http@0.57.2(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.28.0 + forwarded-parse: 2.1.2 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-ioredis@0.42.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8725,6 +9160,15 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-ioredis@0.47.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/redis-common': 0.36.2 + '@opentelemetry/semantic-conventions': 1.37.0 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-kafkajs@0.2.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8734,6 +9178,14 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-kafkajs@0.7.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-knex@0.39.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8743,6 +9195,14 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-knex@0.44.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-koa@0.42.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8753,6 +9213,15 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-koa@0.47.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-lru-memoizer@0.39.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8761,6 +9230,13 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-lru-memoizer@0.44.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-memcached@0.38.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8781,6 +9257,14 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-mongodb@0.52.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-mongoose@0.41.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8791,6 +9275,15 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-mongoose@0.46.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-mysql2@0.40.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8801,6 +9294,15 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-mysql2@0.45.2(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.0) + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-mysql@0.40.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8811,6 +9313,15 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-mysql@0.45.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + '@types/mysql': 2.15.26 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-nestjs-core@0.39.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8841,6 +9352,18 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-pg@0.51.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.0) + '@types/pg': 8.6.1 + '@types/pg-pool': 2.0.6 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-pino@0.41.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8861,6 +9384,15 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-redis-4@0.46.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/redis-common': 0.36.2 + '@opentelemetry/semantic-conventions': 1.37.0 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-redis@0.41.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8909,6 +9441,23 @@ snapshots: - supports-color optional: true + '@opentelemetry/instrumentation-tedious@0.18.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + '@types/tedious': 4.0.14 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-undici@0.10.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation-undici@0.5.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -8949,6 +9498,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.57.2 + '@types/shimmer': 1.2.0 + import-in-the-middle: 1.14.4 + require-in-the-middle: 7.5.2 + semver: 7.7.2 + shimmer: 1.2.1 + transitivePeerDependencies: + - supports-color + '@opentelemetry/otlp-exporter-base@0.203.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -9034,8 +9595,7 @@ snapshots: '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) optional: true - '@opentelemetry/redis-common@0.36.2': - optional: true + '@opentelemetry/redis-common@0.36.2': {} '@opentelemetry/resource-detector-alibaba-cloud@0.29.7(@opentelemetry/api@1.9.0)': dependencies: @@ -9232,14 +9792,12 @@ snapshots: '@opentelemetry/semantic-conventions@1.28.0': {} - '@opentelemetry/semantic-conventions@1.37.0': - optional: true + '@opentelemetry/semantic-conventions@1.37.0': {} '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - optional: true '@oxc-project/types@0.90.0': {} @@ -9304,6 +9862,11 @@ snapshots: '@parcel/watcher-win32-x64': 2.5.1 optional: true + '@paulirish/trace_engine@0.0.59': + dependencies: + legacy-javascript: 0.0.1 + third-party-web: 0.27.0 + '@pkgjs/parseargs@0.11.0': optional: true @@ -9322,6 +9885,13 @@ snapshots: config-chain: 1.1.13 optional: true + '@prisma/instrumentation@6.11.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + transitivePeerDependencies: + - supports-color + '@protobuf-ts/plugin@2.11.1': dependencies: '@bufbuild/protobuf': 2.9.0 @@ -9555,6 +10125,70 @@ snapshots: selderee: 0.11.0 optional: true + '@sentry/core@9.46.0': {} + + '@sentry/node-core@9.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + '@sentry/core': 9.46.0 + '@sentry/opentelemetry': 9.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0) + import-in-the-middle: 1.14.4 + + '@sentry/node@9.46.0': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-amqplib': 0.46.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-connect': 0.43.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-dataloader': 0.16.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-express': 0.47.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-fs': 0.19.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-generic-pool': 0.43.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-graphql': 0.47.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-hapi': 0.45.2(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-http': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-ioredis': 0.47.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-kafkajs': 0.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-knex': 0.44.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-koa': 0.47.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-lru-memoizer': 0.44.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mongodb': 0.52.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mongoose': 0.46.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mysql': 0.45.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mysql2': 0.45.2(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-pg': 0.51.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-redis-4': 0.46.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-tedious': 0.18.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-undici': 0.10.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + '@prisma/instrumentation': 6.11.1(@opentelemetry/api@1.9.0) + '@sentry/core': 9.46.0 + '@sentry/node-core': 9.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0) + '@sentry/opentelemetry': 9.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0) + import-in-the-middle: 1.14.4 + minimatch: 9.0.5 + transitivePeerDependencies: + - supports-color + + '@sentry/opentelemetry@9.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.37.0 + '@sentry/core': 9.46.0 + '@shikijs/core@3.13.0': dependencies: '@shikijs/types': 3.13.0 @@ -9783,6 +10417,10 @@ snapshots: '@types/node': 24.6.1 optional: true + '@types/mysql@2.15.26': + dependencies: + '@types/node': 24.6.1 + '@types/node-fetch@2.6.13': dependencies: '@types/node': 24.6.1 @@ -9813,12 +10451,15 @@ snapshots: '@types/pg': 8.6.1 optional: true + '@types/pg-pool@2.0.6': + dependencies: + '@types/pg': 8.6.1 + '@types/pg@8.6.1': dependencies: '@types/node': 24.6.1 pg-protocol: 1.10.3 pg-types: 2.2.0 - optional: true '@types/qs@6.14.0': {} @@ -9848,7 +10489,6 @@ snapshots: '@types/tedious@4.0.14': dependencies: '@types/node': 24.6.1 - optional: true '@types/tinycolor2@1.4.6': optional: true @@ -10068,6 +10708,8 @@ snapshots: ansi-color@0.2.1: {} + ansi-colors@4.1.3: {} + ansi-escapes@7.1.1: dependencies: environment: 1.1.0 @@ -10124,7 +10766,6 @@ snapshots: dependencies: stubborn-fs: 1.2.5 when-exit: 2.1.4 - optional: true auto-bind@5.0.1: optional: true @@ -10418,6 +11059,15 @@ snapshots: chownr@3.0.0: {} + chrome-launcher@1.2.1: + dependencies: + '@types/node': 24.6.1 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 2.0.2 + transitivePeerDependencies: + - supports-color + chromium-bidi@9.1.0(devtools-protocol@0.0.1495869): dependencies: devtools-protocol: 0.0.1495869 @@ -10537,7 +11187,6 @@ snapshots: dot-prop: 9.0.0 graceful-fs: 4.2.11 xdg-basedir: 5.1.0 - optional: true connect@3.7.0: dependencies: @@ -10595,6 +11244,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + csp_evaluator@1.1.5: {} + css-functions-list@3.2.3: {} css-select@5.2.2: @@ -10644,6 +11295,8 @@ snapshots: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -10669,6 +11322,8 @@ snapshots: defer-to-connect@2.0.1: optional: true + define-lazy-prop@2.0.0: {} + define-lazy-prop@3.0.0: optional: true @@ -10698,6 +11353,8 @@ snapshots: devtools-protocol@0.0.1495869: {} + devtools-protocol@0.0.1507524: {} + di@0.0.1: {} diff@7.0.0: @@ -10740,7 +11397,6 @@ snapshots: dot-prop@9.0.0: dependencies: type-fest: 4.41.0 - optional: true dotenv@17.2.3: optional: true @@ -10818,6 +11474,11 @@ snapshots: - supports-color - utf-8-validate + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + ent@2.2.2: dependencies: call-bound: 1.0.4 @@ -11303,8 +11964,7 @@ snapshots: dependencies: fetch-blob: 3.2.0 - forwarded-parse@2.1.2: - optional: true + forwarded-parse@2.1.2: {} forwarded@0.2.0: {} @@ -11690,6 +12350,8 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 + http-link-header@1.1.3: {} + http-parser-js@0.5.10: optional: true @@ -11767,6 +12429,8 @@ snapshots: ignore@7.0.5: {} + image-ssim@0.2.0: {} + immediate@3.0.6: {} immutable@5.1.3: {} @@ -11852,6 +12516,13 @@ snapshots: - utf-8-validate optional: true + intl-messageformat@10.7.16: + dependencies: + '@formatjs/ecma402-abstract': 2.3.4 + '@formatjs/fast-memoize': 2.2.7 + '@formatjs/icu-messageformat-parser': 2.11.2 + tslib: 2.8.1 + ip-address@10.0.1: {} ipaddr.js@1.9.1: {} @@ -11866,6 +12537,8 @@ snapshots: dependencies: hasown: 2.0.2 + is-docker@2.2.1: {} + is-docker@3.0.0: optional: true @@ -11935,6 +12608,10 @@ snapshots: is-unicode-supported@2.1.0: {} + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + is-wsl@3.1.0: dependencies: is-inside-container: 1.0.0 @@ -12014,6 +12691,10 @@ snapshots: jose@4.15.9: optional: true + jpeg-js@0.4.4: {} + + js-library-detector@6.7.0: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -12204,6 +12885,8 @@ snapshots: leac@0.6.0: optional: true + legacy-javascript@0.0.1: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -12213,6 +12896,51 @@ snapshots: dependencies: immediate: 3.0.6 + lighthouse-logger@2.0.2: + dependencies: + debug: 4.4.3 + marky: 1.3.0 + transitivePeerDependencies: + - supports-color + + lighthouse-stack-packs@1.12.2: {} + + lighthouse@12.8.2: + dependencies: + '@paulirish/trace_engine': 0.0.59 + '@sentry/node': 9.46.0 + axe-core: 4.10.3 + chrome-launcher: 1.2.1 + configstore: 7.1.0 + csp_evaluator: 1.1.5 + devtools-protocol: 0.0.1507524 + enquirer: 2.4.1 + http-link-header: 1.1.3 + intl-messageformat: 10.7.16 + jpeg-js: 0.4.4 + js-library-detector: 6.7.0 + lighthouse-logger: 2.0.2 + 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.2 + parse-cache-control: 1.0.1 + puppeteer-core: 24.22.3 + robots-parser: 3.0.1 + speedline-core: 1.4.3 + third-party-web: 0.27.0 + tldts-icann: 7.0.16 + ws: 7.5.10 + yargs: 17.7.2 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - bare-buffer + - bufferutil + - react-native-b4a + - supports-color + - utf-8-validate + limiter@1.1.5: optional: true @@ -12250,6 +12978,8 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash-es@4.17.21: {} + lodash.camelcase@4.3.0: {} lodash.clonedeep@4.5.0: @@ -12321,6 +13051,8 @@ snapshots: long@5.3.2: {} + lookup-closest-locale@6.2.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -12402,6 +13134,8 @@ snapshots: marked@16.3.0: {} + marky@1.3.0: {} + math-intrinsics@1.1.0: {} mathml-tag-names@2.1.3: {} @@ -12434,6 +13168,8 @@ snapshots: merge2@1.4.1: {} + metaviewport-parser@0.3.0: {} + methods@1.1.2: {} micromark-util-character@2.1.1: @@ -12767,6 +13503,12 @@ snapshots: wsl-utils: 0.1.0 optional: true + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.76): dependencies: '@types/node': 18.19.129 @@ -12884,6 +13626,8 @@ snapshots: dependencies: callsites: 3.1.0 + parse-cache-control@1.0.1: {} + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.27.1 @@ -12976,11 +13720,9 @@ snapshots: pend@1.2.0: {} - pg-int8@1.0.1: - optional: true + pg-int8@1.0.1: {} - pg-protocol@1.10.3: - optional: true + pg-protocol@1.10.3: {} pg-types@2.2.0: dependencies: @@ -12989,7 +13731,6 @@ snapshots: postgres-bytea: 1.0.0 postgres-date: 1.0.7 postgres-interval: 1.2.0 - optional: true picocolors@1.1.1: {} @@ -13028,19 +13769,15 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postgres-array@2.0.0: - optional: true + postgres-array@2.0.0: {} - postgres-bytea@1.0.0: - optional: true + postgres-bytea@1.0.0: {} - postgres-date@1.0.7: - optional: true + postgres-date@1.0.7: {} postgres-interval@1.2.0: dependencies: xtend: 4.0.2 - optional: true prelude-ls@1.2.1: {} @@ -13348,6 +14085,8 @@ snapshots: dependencies: glob: 7.2.3 + robots-parser@3.0.1: {} + rolldown@1.0.0-beta.39: dependencies: '@oxc-project/types': 0.90.0 @@ -13682,6 +14421,12 @@ snapshots: spdx-license-ids@3.0.22: {} + speedline-core@1.4.3: + dependencies: + '@types/node': 24.6.1 + image-ssim: 0.2.0 + jpeg-js: 0.4.4 + ssri@12.0.0: dependencies: minipass: 7.1.2 @@ -13791,8 +14536,7 @@ snapshots: dependencies: '@tokenizer/token': 0.3.0 - stubborn-fs@1.2.5: - optional: true + stubborn-fs@1.2.5: {} stubs@3.0.0: optional: true @@ -13934,6 +14678,8 @@ snapshots: text-hex@1.0.0: {} + third-party-web@0.27.0: {} + thriftrw@3.11.4: dependencies: bufrw: 1.4.0 @@ -13956,6 +14702,12 @@ snapshots: tinycolor2: 1.6.0 optional: true + tldts-core@7.0.16: {} + + tldts-icann@7.0.16: + dependencies: + tldts-core: 7.0.16 + tmp@0.2.5: {} to-regex-range@5.0.1: @@ -14221,8 +14973,7 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 - when-exit@2.1.4: - optional: true + when-exit@2.1.4: {} which@1.3.1: dependencies: @@ -14300,6 +15051,8 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 + ws@7.5.10: {} + ws@8.17.1: {} ws@8.18.3: {} @@ -14309,8 +15062,7 @@ snapshots: is-wsl: 3.1.0 optional: true - xdg-basedir@5.1.0: - optional: true + xdg-basedir@5.1.0: {} xhr2@0.2.1: {} diff --git a/runner/eval-cli.ts b/runner/eval-cli.ts index 8734583..b6fdd19 100644 --- a/runner/eval-cli.ts +++ b/runner/eval-cli.ts @@ -38,6 +38,7 @@ interface Options { autoraterModel?: string; a11yRepairAttempts?: number; logging?: 'text-only' | 'dynamic'; + skipLighthouse?: boolean; } function builder(argv: Argv): Argv { @@ -153,6 +154,11 @@ function builder(argv: Argv): Argv { default: 0, description: 'Number of repair attempts for discovered a11y violations', }) + .option('skip-lighthouse', { + type: 'boolean', + default: false, + description: 'Whether to skip collecting Lighthouse data', + }) .strict() .version(false) .help() @@ -197,6 +203,7 @@ async function handler(cliArgs: Arguments): Promise { autoraterModel: cliArgs.autoraterModel, skipAiSummary: cliArgs.skipAiSummary, a11yRepairAttempts: cliArgs.a11yRepairAttempts, + skipLighthouse: cliArgs.skipLighthouse, }); logReportToConsole(runInfo); diff --git a/runner/index.ts b/runner/index.ts index ca747c2..b3c35f8 100644 --- a/runner/index.ts +++ b/runner/index.ts @@ -17,6 +17,11 @@ export { BuildResultStatus, type BuildResult, } from './workers/builder/builder-types.js'; +export { + type LighthouseResult, + type LighthouseCategory, + type LighthouseAudit, +} from './workers/serve-testing/worker-types.js'; export {type UserJourneysResult} from './orchestration/user-journeys.js'; export {type AutoRateResult} from './ratings/autoraters/auto-rate-shared.js'; export {DEFAULT_MODEL_NAME, REPORT_VERSION} from './configuration/constants.js'; diff --git a/runner/orchestration/build-serve-loop.ts b/runner/orchestration/build-serve-loop.ts index 9bbd849..665d8a0 100644 --- a/runner/orchestration/build-serve-loop.ts +++ b/runner/orchestration/build-serve-loop.ts @@ -46,6 +46,7 @@ export async function attemptBuild( skipScreenshots: boolean, skipAxeTesting: boolean, enableAutoCsp: boolean, + skipLighthouse: boolean, userJourneyAgentTaskInput: BrowserAgentTaskInput | undefined, maxAxeRepairAttempts: number, ) { @@ -125,6 +126,7 @@ export async function attemptBuild( skipScreenshots, skipAxeTesting, enableAutoCsp, + skipLighthouse, userJourneyAgentTaskInput, ); } @@ -194,6 +196,7 @@ export async function attemptBuild( skipScreenshots, skipAxeTesting, enableAutoCsp, + skipLighthouse, userJourneyAgentTaskInput, ); diff --git a/runner/orchestration/generate.ts b/runner/orchestration/generate.ts index 16bcfd2..891e27e 100644 --- a/runner/orchestration/generate.ts +++ b/runner/orchestration/generate.ts @@ -85,6 +85,7 @@ export async function generateCodeAndAssess(options: { logging?: 'text-only' | 'dynamic'; autoraterModel?: string; a11yRepairAttempts?: number; + skipLighthouse?: boolean; }): Promise { const env = await getEnvironmentByPath(options.environmentConfigPath, options.runner); const ratingLlm = await getRunnerByName('genkit'); @@ -179,6 +180,7 @@ export async function generateCodeAndAssess(options: { progress, options.autoraterModel || DEFAULT_AUTORATER_MODEL_NAME, options.a11yRepairAttempts ?? 0, + !!options.skipLighthouse, ), // 10min max per app evaluation. We just want to make sure it never gets stuck. 10, @@ -307,6 +309,7 @@ async function startEvaluationTask( progress: ProgressLogger, autoraterModel: string, a11yRepairAttempts: number, + skipLighthouse: boolean, ): Promise { // Set up the project structure once for the root project. const {directory, cleanup} = await setupProjectStructure( @@ -430,6 +433,7 @@ async function startEvaluationTask( skipScreenshots, skipAxeTesting, enableAutoCsp, + skipLighthouse, userJourneyAgentTaskInput, a11yRepairAttempts, ); diff --git a/runner/orchestration/serve-testing-worker.ts b/runner/orchestration/serve-testing-worker.ts index 83835e6..88e8390 100644 --- a/runner/orchestration/serve-testing-worker.ts +++ b/runner/orchestration/serve-testing-worker.ts @@ -26,6 +26,7 @@ export async function serveAndTestApp( skipScreenshots: boolean, skipAxeTesting: boolean, enableAutoCsp: boolean, + skipLighthouse: boolean, userJourneyAgentTaskInput?: BrowserAgentTaskInput, ): Promise { progress.log(rootPromptDef, 'serve-testing', `Testing the app`); @@ -43,6 +44,7 @@ export async function serveAndTestApp( enableAutoCsp, includeAxeTesting: skipAxeTesting === false, takeScreenshots: skipScreenshots === false, + includeLighthouseData: skipLighthouse === false, userJourneyAgentTaskInput, }; diff --git a/runner/workers/serve-testing/lighthouse.ts b/runner/workers/serve-testing/lighthouse.ts new file mode 100644 index 0000000..be9a8cb --- /dev/null +++ b/runner/workers/serve-testing/lighthouse.ts @@ -0,0 +1,70 @@ +import lighthouse from 'lighthouse'; +import {Page} from 'puppeteer'; +import {LighthouseAudit, LighthouseResult} from './worker-types.js'; + +export async function getLighthouseData( + hostUrl: string, + page: Page, +): Promise { + const data = await lighthouse( + hostUrl, + undefined, + { + extends: 'lighthouse:default', + settings: { + // Exclude accessibility since it's already covered by Axe above. + onlyCategories: ['performance', 'best-practices'], + }, + }, + page, + ); + + if (!data) { + return undefined; + } + + const availableAudits = new Map(); + const result: LighthouseResult = {categories: [], uncategorized: []}; + + for (const audit of Object.values(data.lhr.audits)) { + const type = audit.details?.type; + const displayMode = audit.scoreDisplayMode; + const isAllowedType = + !type || + type === 'list' || + type === 'opportunity' || + (type === 'checklist' && Object.keys(audit.details?.items || {}).length > 0) || + (type === 'table' && audit.details?.items.length); + const isAllowedDisplayMode = displayMode === 'binary' || displayMode === 'numeric'; + + if (audit.score != null && isAllowedType && isAllowedDisplayMode) { + availableAudits.set(audit.id, audit); + } + } + + for (const category of Object.values(data.lhr.categories)) { + const auditsForCategory: LighthouseAudit[] = []; + + for (const ref of category.auditRefs) { + const audit = availableAudits.get(ref.id); + + if (audit) { + auditsForCategory.push(audit); + availableAudits.delete(ref.id); + } + } + + result.categories.push({ + id: category.id, + displayName: category.title, + description: category.description || '', + score: category.score || 0, + audits: auditsForCategory, + }); + } + + // Track all remaining audits as uncategorized. + result.uncategorized.push(...availableAudits.values()); + + return result.categories.length === 0 && result.uncategorized.length === 0 ? undefined : result; +} diff --git a/runner/workers/serve-testing/puppeteer.ts b/runner/workers/serve-testing/puppeteer.ts index 1e1e8c3..b4e028a 100644 --- a/runner/workers/serve-testing/puppeteer.ts +++ b/runner/workers/serve-testing/puppeteer.ts @@ -1,10 +1,11 @@ import {AxePuppeteer} from '@axe-core/puppeteer'; -import {Result} from 'axe-core'; +import {Result as AxeResult} from 'axe-core'; import puppeteer from 'puppeteer'; import {callWithTimeout} from '../../utils/timeout.js'; import {AutoCsp} from './auto-csp.js'; import {CspViolation} from './auto-csp-types.js'; -import {ServeTestingProgressLogFn} from './worker-types.js'; +import {LighthouseResult, ServeTestingProgressLogFn} from './worker-types.js'; +import {getLighthouseData} from './lighthouse.js'; /** * Uses Puppeteer to take a screenshot of the main page, perform Axe testing, @@ -18,13 +19,15 @@ export async function runAppInPuppeteer( includeAxeTesting: boolean, progressLog: ServeTestingProgressLogFn, enableAutoCsp: boolean, + includeLighthouseData: boolean, ) { const runtimeErrors: string[] = []; // Undefined by default so it gets flagged correctly as `skipped` if there's no data. let cspViolations: CspViolation[] | undefined; let screenshotBase64Data: string | undefined; - let axeViolations: Result[] | undefined; + let axeViolations: AxeResult[] | undefined; + let lighthouseResult: LighthouseResult | undefined; try { const browser = await puppeteer.launch({ @@ -139,6 +142,22 @@ export async function runAppInPuppeteer( ); progressLog('success', 'Screenshot captured and encoded'); } + + if (includeLighthouseData) { + try { + progressLog('eval', `Gathering Lighthouse data from ${hostUrl}`); + lighthouseResult = await getLighthouseData(hostUrl, page); + + if (lighthouseResult) { + progressLog('success', 'Lighthouse data has been collected'); + } else { + progressLog('error', 'Lighthouse did not produce usable data'); + } + } catch (lighthouseError: any) { + progressLog('error', 'Could not gather Lighthouse data', lighthouseError.message); + } + } + await browser.close(); } catch (screenshotError: any) { let details: string = screenshotError.message; @@ -150,5 +169,5 @@ export async function runAppInPuppeteer( progressLog('error', 'Could not take screenshot', details); } - return {screenshotBase64Data, runtimeErrors, axeViolations, cspViolations}; + return {screenshotBase64Data, runtimeErrors, axeViolations, cspViolations, lighthouseResult}; } diff --git a/runner/workers/serve-testing/worker-types.ts b/runner/workers/serve-testing/worker-types.ts index 748727e..b030c0b 100644 --- a/runner/workers/serve-testing/worker-types.ts +++ b/runner/workers/serve-testing/worker-types.ts @@ -1,6 +1,7 @@ +import {Result as AxeResult} from 'axe-core'; +import {RunnerResult as LighthouseRunnerResult} from 'lighthouse'; import {ProgressType} from '../../progress/progress-logger.js'; import {AgentOutput, BrowserAgentTaskInput} from '../../testing/browser-agent/models.js'; -import {Result} from 'axe-core'; import {CspViolation} from './auto-csp-types.js'; /** @@ -24,8 +25,11 @@ export interface ServeTestingWorkerMessage { /** Whether to enable the auto CSP checks. */ enableAutoCsp: boolean; - /** User journey browser agent task input */ + /** User journey browser agent task input. */ userJourneyAgentTaskInput: BrowserAgentTaskInput | undefined; + + /** Whether to capture Lighthouse data for the run. */ + includeLighthouseData: boolean; } export interface ServeTestingResult { @@ -34,7 +38,8 @@ export interface ServeTestingResult { runtimeErrors?: string; userJourneyAgentOutput: AgentOutput | null; cspViolations?: CspViolation[]; - axeViolations?: Result[]; + axeViolations?: AxeResult[]; + lighthouseResult?: LighthouseResult; } export interface ServeTestingResultMessage { @@ -60,3 +65,18 @@ export type ServeTestingProgressLogFn = ( export type ServeTestingWorkerResponseMessage = | ServeTestingProgressLogMessage | ServeTestingResultMessage; + +export type LighthouseAudit = LighthouseRunnerResult['lhr']['audits']['x']; // Lighthouse doesn't export this so we need to dig for it. + +export interface LighthouseCategory { + id: string; + displayName: string; + description: string; + score: number; + audits: LighthouseAudit[]; +} + +export interface LighthouseResult { + categories: LighthouseCategory[]; + uncategorized: LighthouseAudit[]; +} diff --git a/runner/workers/serve-testing/worker.ts b/runner/workers/serve-testing/worker.ts index eb5c5f5..86b7f99 100644 --- a/runner/workers/serve-testing/worker.ts +++ b/runner/workers/serve-testing/worker.ts @@ -5,6 +5,7 @@ import {CspViolation} from '../serve-testing/auto-csp-types.js'; import {runBrowserAgentUserJourneyTests} from '../serve-testing/browser-agent.js'; import {runAppInPuppeteer} from '../serve-testing/puppeteer.js'; import { + LighthouseResult, ServeTestingProgressLogMessage, ServeTestingResult, ServeTestingWorkerMessage, @@ -19,6 +20,7 @@ process.on('message', async (message: ServeTestingWorkerMessage) => { includeAxeTesting, takeScreenshots, userJourneyAgentTaskInput, + includeLighthouseData, } = message; const runtimeErrors: string[] = []; const progressLog = (state: ProgressType, message: string, details?: string) => { @@ -29,10 +31,11 @@ process.on('message', async (message: ServeTestingWorkerMessage) => { }; let result: ServeTestingResult; - let screenshotBase64Data: string | undefined = undefined; + let screenshotBase64Data: string | undefined; let axeViolations: any[] | undefined = []; let userJourneyAgentOutput: AgentOutput | null = null; let cspViolations: CspViolation[] | undefined = []; + let lighthouseResult: LighthouseResult | undefined; try { const puppeteerResult = await callWithTimeout( @@ -45,6 +48,7 @@ process.on('message', async (message: ServeTestingWorkerMessage) => { !!includeAxeTesting, progressLog, !!enableAutoCsp, + includeLighthouseData, ), 4, // 4min ); @@ -52,6 +56,7 @@ process.on('message', async (message: ServeTestingWorkerMessage) => { screenshotBase64Data = puppeteerResult.screenshotBase64Data; axeViolations = puppeteerResult.axeViolations; cspViolations = puppeteerResult.cspViolations; + lighthouseResult = puppeteerResult.lighthouseResult; runtimeErrors.push(...puppeteerResult.runtimeErrors); @@ -72,6 +77,7 @@ process.on('message', async (message: ServeTestingWorkerMessage) => { axeViolations, userJourneyAgentOutput: userJourneyAgentOutput, cspViolations, + lighthouseResult, }; } catch (error: any) { const cleanErrorMessage = cleanupBuildMessage(error.message); @@ -80,6 +86,7 @@ process.on('message', async (message: ServeTestingWorkerMessage) => { runtimeErrors: runtimeErrors.join('\n'), userJourneyAgentOutput: userJourneyAgentOutput, cspViolations, + lighthouseResult, }; } From 7d9dc413e5d3e8717543473d6a15a527f01e39be Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 3 Oct 2025 12:44:44 +0200 Subject: [PATCH 2/4] refactor: reuse tooltip styles Moves out the tooltip styles to make them easier to reuse. --- report-app/src/app/shared/styles/tooltip.scss | 39 +++++++++++++++++++ .../stacked-bar-chart/stacked-bar-chart.html | 4 +- .../stacked-bar-chart/stacked-bar-chart.scss | 25 ------------ report-app/src/styles.scss | 2 + 4 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 report-app/src/app/shared/styles/tooltip.scss diff --git a/report-app/src/app/shared/styles/tooltip.scss b/report-app/src/app/shared/styles/tooltip.scss new file mode 100644 index 0000000..7b634c3 --- /dev/null +++ b/report-app/src/app/shared/styles/tooltip.scss @@ -0,0 +1,39 @@ +@mixin tooltip-styles { + .has-tooltip { + position: relative; + + &::before { + font-family: var(--font-family); + content: attr(data-tooltip); + position: absolute; + bottom: 110%; + left: 50%; + transform: translateX(-50%); + background-color: var(--tooltip-background-color); + color: var(--tooltip-text-color); + padding: 6px 12px; + border-radius: 6px; + font-size: 13px; + line-height: 1.5; + opacity: 0; + visibility: hidden; + overflow: hidden; + white-space: nowrap; + transition: + opacity 0.2s ease-in-out, + visibility 0.2s ease-in-out; + z-index: 10; + display: block; + } + + &.multiline-tooltip::before { + white-space: normal; + max-width: 400px; + } + + &:hover::before { + opacity: 1; + visibility: visible; + } + } +} diff --git a/report-app/src/app/shared/visualization/stacked-bar-chart/stacked-bar-chart.html b/report-app/src/app/shared/visualization/stacked-bar-chart/stacked-bar-chart.html index 5f769a0..4be49ab 100644 --- a/report-app/src/app/shared/visualization/stacked-bar-chart/stacked-bar-chart.html +++ b/report-app/src/app/shared/visualization/stacked-bar-chart/stacked-bar-chart.html @@ -8,8 +8,8 @@ [style.width.%]="asPercent(item.value)" [style.background-color]="item.color" (click)="toggleDisplayMode()" - [attr.data-tooltip]="showLegend() ? null : item.label" - > + [class.has-tooltip]="!showLegend()" + [attr.data-tooltip]="item.label"> {{ getItemDisplayValue(item) }} } diff --git a/report-app/src/app/shared/visualization/stacked-bar-chart/stacked-bar-chart.scss b/report-app/src/app/shared/visualization/stacked-bar-chart/stacked-bar-chart.scss index 8670813..d3f6a38 100644 --- a/report-app/src/app/shared/visualization/stacked-bar-chart/stacked-bar-chart.scss +++ b/report-app/src/app/shared/visualization/stacked-bar-chart/stacked-bar-chart.scss @@ -51,31 +51,6 @@ &:hover { filter: brightness(1.1); } - - &[data-tooltip]::before { - content: attr(data-tooltip); // Use a data attribute for the text - position: absolute; - bottom: 110%; // Position it above the segment - left: 50%; - transform: translateX(-50%); - background-color: var(--tooltip-background-color); - color: var(--tooltip-text-color); - padding: 6px 12px; - border-radius: 6px; - font-size: 13px; - white-space: nowrap; - opacity: 0; - visibility: hidden; - transition: - opacity 0.2s ease-in-out, - visibility 0.2s ease-in-out; - z-index: 10; - } - - &[data-tooltip]:hover::before { - opacity: 1; - visibility: visible; - } } .legend { diff --git a/report-app/src/styles.scss b/report-app/src/styles.scss index 016c12f..3d0bcb2 100644 --- a/report-app/src/styles.scss +++ b/report-app/src/styles.scss @@ -3,6 +3,7 @@ @use './app/shared/styles/callouts'; @use './app/shared/styles/cards'; @use './app/shared/styles/statuses'; +@use './app/shared/styles/tooltip'; @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); @@ -80,6 +81,7 @@ hr { @include callouts.callout-styles; @include cards.card-styles; @include statuses.status-styles; +@include tooltip.tooltip-styles; ::view-transition-old(count), ::view-transition-new(count) { From 0475c251bf314f2a8b61c1515a547a7104b5bfac Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 3 Oct 2025 12:45:06 +0200 Subject: [PATCH 3/4] refactor: add tiny variant for score Adds an even smaller variant of the score component. --- report-app/src/app/shared/score/score.scss | 12 ++++++++++++ report-app/src/app/shared/score/score.ts | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/report-app/src/app/shared/score/score.scss b/report-app/src/app/shared/score/score.scss index a28f232..4acd597 100644 --- a/report-app/src/app/shared/score/score.scss +++ b/report-app/src/app/shared/score/score.scss @@ -4,6 +4,7 @@ align-items: center; justify-content: center; color: var(--text-on-status); + flex-shrink: 0; } :host(.excellent-score) { @@ -55,3 +56,14 @@ font-size: 0.4rem; } } + +:host(.tiny) { + width: 26px; + height: 26px; + font-size: 0.7rem; + border-radius: 6px; + + .label { + font-size: 0.4rem; + } +} diff --git a/report-app/src/app/shared/score/score.ts b/report-app/src/app/shared/score/score.ts index e2b6bfe..a854ef2 100644 --- a/report-app/src/app/shared/score/score.ts +++ b/report-app/src/app/shared/score/score.ts @@ -17,7 +17,7 @@ import {formatScore} from '../scoring'; export class Score { readonly total = input.required(); readonly max = input.required(); - readonly size = input<'small' | 'medium' | 'large'>('medium'); + readonly size = input<'tiny' | 'small' | 'medium' | 'large'>('medium'); readonly label = input(''); protected formattedScore = computed(() => formatScore(this.total(), this.max())); From 43ca4d05af56cabb032d0ef307bf0062cf9c4817 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 3 Oct 2025 13:00:15 +0200 Subject: [PATCH 4/4] feat: show lighthouse data in report app Updates the report app to render out the Lighthouse data. --- .../report-viewer/lighthouse-category.ts | 78 +++++++++++++++++++ .../pages/report-viewer/report-viewer.html | 23 ++++++ .../pages/report-viewer/report-viewer.scss | 4 + .../app/pages/report-viewer/report-viewer.ts | 9 +-- 4 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 report-app/src/app/pages/report-viewer/lighthouse-category.ts diff --git a/report-app/src/app/pages/report-viewer/lighthouse-category.ts b/report-app/src/app/pages/report-viewer/lighthouse-category.ts new file mode 100644 index 0000000..6e0791a --- /dev/null +++ b/report-app/src/app/pages/report-viewer/lighthouse-category.ts @@ -0,0 +1,78 @@ +import {Component, input} from '@angular/core'; +import {LighthouseAudit} from '../../../../../runner/workers/serve-testing/worker-types'; +import {Score} from '../../shared/score/score'; + +@Component({ + selector: 'lighthouse-category', + imports: [Score], + template: ` + @let audits = this.audits(); + @let score = this.score(); + +

+ @if (score != null) { + + } + {{displayName()}} +

+ + @if (description()) { +

{{description()}}

+ } + +
    + @for (audit of audits; track audit.id) { +
  • + @if (audit.score != null) { + + } + {{audit.title}}{{audit.displayValue ? ': ' + audit.displayValue : ''}} + + @if (audit.description) { + info + } +
  • + } +
+ `, + styles: ` + :host { + display: block; + } + + h4 { + display: flex; + width: 100%; + align-items: center; + gap: 0.5rem; + margin: 1rem 0 0.5rem 0; + } + + ul { + display: flex; + flex-direction: column; + list-style: none; + padding: 0 0 0 4px; + gap: 0.5rem; + margin: 0; + } + + li { + display: flex; + align-items: center; + gap: 0.5rem; + } + `, +}) +export class LighthouseCategory { + readonly audits = input.required(); + readonly displayName = input.required(); + readonly score = input.required(); + readonly description = input(); + + protected toPercent(value: number) { + return Math.round(value * 100) + '%'; + } +} diff --git a/report-app/src/app/pages/report-viewer/report-viewer.html b/report-app/src/app/pages/report-viewer/report-viewer.html index ba45ffb..6e7e895 100644 --- a/report-app/src/app/pages/report-viewer/report-viewer.html +++ b/report-app/src/app/pages/report-viewer/report-viewer.html @@ -439,6 +439,29 @@

Generated Code

} + @let lighthouse = result.finalAttempt.serveTestingResult?.lighthouseResult; + + @if (lighthouse) { + + Lighthouse + + @for (category of lighthouse.categories; track category.id) { + + } + + @if (lighthouse.uncategorized.length > 0) { + + } + + } + @if (result.userJourneys && result.userJourneys.result.length > 0) { User Journeys diff --git a/report-app/src/app/pages/report-viewer/report-viewer.scss b/report-app/src/app/pages/report-viewer/report-viewer.scss index 46b1413..44b05fb 100644 --- a/report-app/src/app/pages/report-viewer/report-viewer.scss +++ b/report-app/src/app/pages/report-viewer/report-viewer.scss @@ -48,6 +48,10 @@ expansion-panel { margin-top: 1rem; } +lighthouse-category + lighthouse-category { + margin-top: 2rem; +} + .summary-meta { display: flex; align-items: center; diff --git a/report-app/src/app/pages/report-viewer/report-viewer.ts b/report-app/src/app/pages/report-viewer/report-viewer.ts index 8e02168..3175df1 100644 --- a/report-app/src/app/pages/report-viewer/report-viewer.ts +++ b/report-app/src/app/pages/report-viewer/report-viewer.ts @@ -13,12 +13,8 @@ import { viewChild, } from '@angular/core'; import {NgxJsonViewerModule} from 'ngx-json-viewer'; +import {BuildErrorType} from '../../../../../runner/workers/builder/builder-types'; import { - BuildErrorType, - BuildResultStatus, -} from '../../../../../runner/workers/builder/builder-types'; -import { - AiChatResponse, AssessmentResult, IndividualAssessment, IndividualAssessmentState, @@ -44,8 +40,8 @@ import {bucketToScoreVariable, formatScore, ScoreCssVariable} from '../../shared import {ExpansionPanel} from '../../shared/expansion-panel/expansion-panel'; import {ExpansionPanelHeader} from '../../shared/expansion-panel/expansion-panel-header'; import {ProviderLabel} from '../../shared/provider-label'; -import {firstValueFrom} from 'rxjs'; import {AiAssistant} from '../../shared/ai-assistant/ai-assistant'; +import {LighthouseCategory} from './lighthouse-category'; const localReportRegex = /-l\d+$/; @@ -63,6 +59,7 @@ const localReportRegex = /-l\d+$/; ProviderLabel, NgxJsonViewerModule, AiAssistant, + LighthouseCategory, ], templateUrl: './report-viewer.html', styleUrls: ['./report-viewer.scss'],