diff --git a/.env.example b/.env.example index 6b91583db1..70580001c8 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,4 @@ -NEXT_PUBLIC_SENTRY_DSN=https://sentry.io -SENTRY_CSP_REPORT_URI=https://sentry.io +NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN=xxx NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=xxx NEXT_PUBLIC_RE_CAPTCHA_V3_APP_SITE_KEY=xxx NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID=UA-XXXXXX-X diff --git a/.github/workflows/upload-source-maps.yml b/.github/workflows/upload-source-maps.yml index 4814ed6d8e..6c0ec2fa04 100644 --- a/.github/workflows/upload-source-maps.yml +++ b/.github/workflows/upload-source-maps.yml @@ -1,3 +1,4 @@ +# TODO @tom2drum setup source maps for Rollbar name: Upload source maps to Sentry on: workflow_call: diff --git a/.gitignore b/.gitignore index 24bd046ba4..74d489ae6b 100644 --- a/.gitignore +++ b/.gitignore @@ -43,9 +43,6 @@ yarn-error.log* .eslintcache -# Sentry -.sentryclirc - **.decrypted~** /test-results/ /playwright-report/ diff --git a/configs/app/features/index.ts b/configs/app/features/index.ts index b85a55d546..39b7919614 100644 --- a/configs/app/features/index.ts +++ b/configs/app/features/index.ts @@ -25,10 +25,10 @@ export { default as nameService } from './nameService'; export { default as publicTagsSubmission } from './publicTagsSubmission'; export { default as restApiDocs } from './restApiDocs'; export { default as rewards } from './rewards'; +export { default as rollbar } from './rollbar'; export { default as rollup } from './rollup'; export { default as safe } from './safe'; export { default as saveOnGas } from './saveOnGas'; -export { default as sentry } from './sentry'; export { default as sol2uml } from './sol2uml'; export { default as stats } from './stats'; export { default as suave } from './suave'; diff --git a/configs/app/features/sentry.ts b/configs/app/features/rollbar.ts similarity index 56% rename from configs/app/features/sentry.ts rename to configs/app/features/rollbar.ts index fb840ca9e5..276f782e4e 100644 --- a/configs/app/features/sentry.ts +++ b/configs/app/features/rollbar.ts @@ -3,35 +3,34 @@ import type { Feature } from './types'; import app from '../app'; import { getEnvValue } from '../utils'; -const dsn = getEnvValue('NEXT_PUBLIC_SENTRY_DSN'); +const clientToken = getEnvValue('NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN'); const instance = (() => { const envValue = getEnvValue('NEXT_PUBLIC_APP_INSTANCE'); if (envValue) { return envValue; } - return app.host?.replace('.blockscout.com', '').replaceAll('-', '_'); + return app.host?.replace('.blockscout.com', '').replace('.k8s-dev', '').replaceAll('-', '_'); })(); const environment = getEnvValue('NEXT_PUBLIC_APP_ENV') || 'production'; -const release = getEnvValue('NEXT_PUBLIC_GIT_TAG'); -const title = 'Sentry error monitoring'; +const codeVersion = getEnvValue('NEXT_PUBLIC_GIT_TAG') || getEnvValue('NEXT_PUBLIC_GIT_COMMIT_SHA'); + +const title = 'Rollbar error monitoring'; const config: Feature<{ - dsn: string; - instance: string; - release: string | undefined; + clientToken: string; environment: string; - enableTracing: boolean; + instance: string | undefined; + codeVersion: string | undefined; }> = (() => { - if (dsn && instance && environment) { + if (clientToken) { return Object.freeze({ title, isEnabled: true, - dsn, - instance, - release, + clientToken, environment, - enableTracing: getEnvValue('NEXT_PUBLIC_SENTRY_ENABLE_TRACING') === 'true', + instance, + codeVersion, }); } diff --git a/configs/envs/.env.eth b/configs/envs/.env.eth index 293263ce7d..ebb31e36ea 100644 --- a/configs/envs/.env.eth +++ b/configs/envs/.env.eth @@ -61,7 +61,6 @@ NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://eth.drpc.org?ref=559183','text':'Public NEXT_PUBLIC_REWARDS_SERVICE_API_HOST=https://merits.blockscout.com NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-mainnet.safe.global NEXT_PUBLIC_SAVE_ON_GAS_ENABLED=true -NEXT_PUBLIC_SENTRY_ENABLE_TRACING=true NEXT_PUBLIC_SEO_ENHANCED_DATA_ENABLED=true NEXT_PUBLIC_STATS_API_HOST=https://stats-eth-main.k8s-prod-1.blockscout.com NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout diff --git a/configs/envs/.env.eth_sepolia b/configs/envs/.env.eth_sepolia index 2b54a8faea..06c2094b85 100644 --- a/configs/envs/.env.eth_sepolia +++ b/configs/envs/.env.eth_sepolia @@ -64,7 +64,6 @@ NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-c NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://sepolia.drpc.org?ref=559183','text':'Public RPC'}] NEXT_PUBLIC_REWARDS_SERVICE_API_HOST=https://merits.blockscout.com NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-sepolia.safe.global -NEXT_PUBLIC_SENTRY_ENABLE_TRACING=true NEXT_PUBLIC_STATS_API_HOST=https://stats-sepolia.k8s.blockscout.com NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=noves NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true diff --git a/configs/envs/.env.main b/configs/envs/.env.main index 0568827c78..a5bcd4c351 100644 --- a/configs/envs/.env.main +++ b/configs/envs/.env.main @@ -7,6 +7,7 @@ NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_PORT=3000 NEXT_PUBLIC_APP_ENV=development +NEXT_PUBLIC_APP_INSTANCE=rubber_duck NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws # Instance ENVs @@ -60,7 +61,6 @@ NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/sepolia-testnet.png NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://sepolia.drpc.org?ref=559183','text':'Public RPC'}] NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-sepolia.safe.global -NEXT_PUBLIC_SENTRY_ENABLE_TRACING=true NEXT_PUBLIC_SEO_ENHANCED_DATA_ENABLED=true NEXT_PUBLIC_STATS_API_HOST=https://stats-sepolia.k8s-dev.blockscout.com NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout diff --git a/deploy/tools/envs-validator/index.ts b/deploy/tools/envs-validator/index.ts index fe7354f7a7..c085ea2800 100644 --- a/deploy/tools/envs-validator/index.ts +++ b/deploy/tools/envs-validator/index.ts @@ -147,6 +147,16 @@ function printDeprecationWarning(envsMap: Record) { console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n'); } + if ( + (envsMap.NEXT_PUBLIC_SENTRY_DSN || envsMap.SENTRY_CSP_REPORT_URI || envsMap.NEXT_PUBLIC_SENTRY_ENABLE_TRACING) && + envsMap.NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN + ) { + console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗'); + // eslint-disable-next-line max-len + console.warn('The Sentry monitoring is now deprecated and will be removed in the next release. Please migrate to the Rollbar error monitoring.'); + console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n'); + } + if ( envsMap.NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR || envsMap.NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND @@ -178,5 +188,14 @@ function checkDeprecatedEnvs(envsMap: Record) { throw new Error(); } + if ( + (envsMap.NEXT_PUBLIC_SENTRY_DSN || envsMap.SENTRY_CSP_REPORT_URI || envsMap.NEXT_PUBLIC_SENTRY_ENABLE_TRACING) && + !envsMap.NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN + ) { + // eslint-disable-next-line max-len + console.log('🚨 The Sentry error monitoring is no longer supported. Please migrate to the Rollbar error monitoring.'); + throw new Error(); + } + !silent && console.log('👍 All good!\n'); } diff --git a/deploy/tools/envs-validator/schema.ts b/deploy/tools/envs-validator/schema.ts index ff896cf413..c5752cc308 100644 --- a/deploy/tools/envs-validator/schema.ts +++ b/deploy/tools/envs-validator/schema.ts @@ -372,6 +372,7 @@ const adsBannerSchema = yup NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE: adButlerConfigSchema, }); +// DEPRECATED const sentrySchema = yup .object() .shape({ @@ -389,20 +390,6 @@ const sentrySchema = yup is: (value: string) => Boolean(value), then: (schema) => schema, }), - NEXT_PUBLIC_APP_INSTANCE: yup - .string() - .when('NEXT_PUBLIC_SENTRY_DSN', { - is: (value: string) => Boolean(value), - then: (schema) => schema, - otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_APP_INSTANCE cannot not be used without NEXT_PUBLIC_SENTRY_DSN'), - }), - NEXT_PUBLIC_APP_ENV: yup - .string() - .when('NEXT_PUBLIC_SENTRY_DSN', { - is: (value: string) => Boolean(value), - then: (schema) => schema, - otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_APP_ENV cannot not be used without NEXT_PUBLIC_SENTRY_DSN'), - }), }); const accountSchema = yup @@ -592,6 +579,8 @@ const schema = yup NEXT_PUBLIC_APP_HOST: yup.string().required(), NEXT_PUBLIC_APP_PROTOCOL: yup.string().oneOf(protocols), NEXT_PUBLIC_APP_PORT: yup.number().positive().integer(), + NEXT_PUBLIC_APP_ENV: yup.string(), + NEXT_PUBLIC_APP_INSTANCE: yup.string(), // 2. Blockchain parameters NEXT_PUBLIC_NETWORK_NAME: yup.string().required(), @@ -898,6 +887,7 @@ const schema = yup NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: yup.string(), NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN: yup.string(), NEXT_PUBLIC_GROWTH_BOOK_CLIENT_KEY: yup.string(), + NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN: yup.string(), // Misc NEXT_PUBLIC_USE_NEXT_JS_PROXY: yup.boolean(), diff --git a/deploy/tools/envs-validator/test/.env.base b/deploy/tools/envs-validator/test/.env.base index a80650f4bc..1024b67be1 100644 --- a/deploy/tools/envs-validator/test/.env.base +++ b/deploy/tools/envs-validator/test/.env.base @@ -1,4 +1,4 @@ -NEXT_PUBLIC_SENTRY_DSN=https://sentry.io +NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN=https://rollbar.com NEXT_PUBLIC_AUTH_URL=https://example.com NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_LOGOUT_URL=https://example.com diff --git a/deploy/tools/envs-validator/test/.env.sentry b/deploy/tools/envs-validator/test/.env.sentry deleted file mode 100644 index c34c4d4f26..0000000000 --- a/deploy/tools/envs-validator/test/.env.sentry +++ /dev/null @@ -1,5 +0,0 @@ -NEXT_PUBLIC_SENTRY_DSN=https://sentry.io -SENTRY_CSP_REPORT_URI=https://sentry.io -NEXT_PUBLIC_SENTRY_ENABLE_TRACING=true -NEXT_PUBLIC_APP_ENV=production -NEXT_PUBLIC_APP_INSTANCE=duck \ No newline at end of file diff --git a/deploy/values/review-l2/values.yaml.gotmpl b/deploy/values/review-l2/values.yaml.gotmpl index 782072ff59..492ba76c9c 100644 --- a/deploy/values/review-l2/values.yaml.gotmpl +++ b/deploy/values/review-l2/values.yaml.gotmpl @@ -47,8 +47,7 @@ frontend: memory: 384Mi cpu: 250m env: - NEXT_PUBLIC_APP_ENV: development - NEXT_PUBLIC_APP_INSTANCE: review_L2 + NEXT_PUBLIC_APP_ENV: review NEXT_PUBLIC_NETWORK_LOGO: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/base.svg NEXT_PUBLIC_NETWORK_ICON: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/base.svg NEXT_PUBLIC_FEATURED_NETWORKS: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/base-mainnet.json @@ -73,8 +72,6 @@ frontend: NEXT_PUBLIC_NAVIGATION_LAYOUT: horizontal NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES: "['/blocks','/name-domains']" envFromSecret: - NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN - SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI NEXT_PUBLIC_AUTH0_CLIENT_ID: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_AUTH0_CLIENT_ID NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID diff --git a/deploy/values/review/values.yaml.gotmpl b/deploy/values/review/values.yaml.gotmpl index b0d34ffa99..30eda36084 100644 --- a/deploy/values/review/values.yaml.gotmpl +++ b/deploy/values/review/values.yaml.gotmpl @@ -47,8 +47,7 @@ frontend: memory: 384Mi cpu: 250m env: - NEXT_PUBLIC_APP_ENV: development - NEXT_PUBLIC_APP_INSTANCE: review + NEXT_PUBLIC_APP_ENV: review NEXT_PUBLIC_FEATURED_NETWORKS: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-sepolia.json NEXT_PUBLIC_NETWORK_LOGO: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/sepolia.svg NEXT_PUBLIC_NETWORK_ICON: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/sepolia.png @@ -79,11 +78,10 @@ frontend: NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES: "['/apps']" PROMETHEUS_METRICS_ENABLED: true envFromSecret: - NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN - SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI NEXT_PUBLIC_AUTH0_CLIENT_ID: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_AUTH0_CLIENT_ID NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID NEXT_PUBLIC_GROWTH_BOOK_CLIENT_KEY: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GROWTH_BOOK_CLIENT_KEY NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN NEXT_PUBLIC_RE_CAPTCHA_V3_APP_SITE_KEY: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_V3_APP_SITE_KEY + NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN diff --git a/docs/ENVS.md b/docs/ENVS.md index f0eccde5f9..08614deae3 100644 --- a/docs/ENVS.md +++ b/docs/ENVS.md @@ -60,6 +60,7 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will - [MetaSuites extension](ENVS.md#metasuites-extension) - [Validators list](ENVS.md#validators-list) - [Sentry error monitoring](ENVS.md#sentry-error-monitoring) + - [Rollbar error monitoring](ENVS.md#rollbar-error-monitoring) - [OpenTelemetry](ENVS.md#opentelemetry) - [DeFi dropdown](ENVS.md#defi-dropdown) - [Multichain balance button](ENVS.md#multichain-balance-button) @@ -77,6 +78,8 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will | NEXT_PUBLIC_APP_PROTOCOL | `http \| https` | App url schema | - | `https` | `http` | v1.0.x+ | | NEXT_PUBLIC_APP_HOST | `string` | App host | Required | - | `blockscout.com` | v1.0.x+ | | NEXT_PUBLIC_APP_PORT | `number` | Port where app is running | - | `3000` | `3001` | v1.0.x+ | +| NEXT_PUBLIC_APP_ENV | `string` | App env (e.g development, staging, production, etc.). | - | `production` | `staging` | v1.0.x+ | +| NEXT_PUBLIC_APP_INSTANCE | `string` | Name of app instance. Used for app monitoring purposes. If not provided, it will be constructed from `NEXT_PUBLIC_APP_HOST` | - | - | `wonderful_kepler` | v1.0.x+ | | NEXT_PUBLIC_USE_NEXT_JS_PROXY | `boolean` | Tells the app to proxy all APIs request through the NextJS app. **We strongly advise not to use it in the production environment**, since it can lead to performance issues of the NodeJS server | - | `false` | `true` | v1.8.0+ |   @@ -738,13 +741,21 @@ The feature enables the Validators page which provides detailed information abou ### Sentry error monitoring +_Note_ This feature is **deprecated**. All ENV variables will be removed in the future releases. + | Variable | Type| Description | Compulsoriness | Default value | Example value | Version | | --- | --- | --- | --- | --- | --- | --- | | NEXT_PUBLIC_SENTRY_DSN | `string` | Client key for your Sentry.io app | Required | - | `` | v1.0.x+ | | SENTRY_CSP_REPORT_URI | `string` | URL for sending CSP-reports to your Sentry.io app | - | - | `` | v1.0.x+ | | NEXT_PUBLIC_SENTRY_ENABLE_TRACING | `boolean` | Enables tracing and performance monitoring in Sentry.io | - | `false` | `true` | v1.17.0+ | -| NEXT_PUBLIC_APP_ENV | `string` | App env (e.g development, review or production). Passed as `environment` property to Sentry config | - | `production` | `production` | v1.0.x+ | -| NEXT_PUBLIC_APP_INSTANCE | `string` | Name of app instance. Used as custom tag `app_instance` value in the main Sentry scope. If not provided, it will be constructed from `NEXT_PUBLIC_APP_HOST` | - | - | `wonderful_kepler` | v1.0.x+ | + +  + +### Rollbar error monitoring + +| Variable | Type| Description | Compulsoriness | Default value | Example value | Version | +| --- | --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN | `string` | Client token for your Rollbar project | Required | - | `` | v1.37.x+ |   diff --git a/lib/api/useApiFetch.tsx b/lib/api/useApiFetch.tsx index 86e5fa9ea9..cda519c1c1 100644 --- a/lib/api/useApiFetch.tsx +++ b/lib/api/useApiFetch.tsx @@ -21,6 +21,7 @@ export interface Params { pathParams?: ResourcePathParams; queryParams?: Record | number | boolean | undefined | null>; fetchParams?: Pick; + logError?: boolean; } export default function useApiFetch() { @@ -30,7 +31,7 @@ export default function useApiFetch() { return React.useCallback(( resourceName: R, - { pathParams, queryParams, fetchParams }: Params = {}, + { pathParams, queryParams, fetchParams, logError }: Params = {}, ) => { const apiToken = cookies.get(cookies.NAMES.API_TOKEN); @@ -58,7 +59,7 @@ export default function useApiFetch() { }, { resource: resource.path, - omitSentryErrorLog: true, // disable logging of API errors to Sentry + logError, }, ); }, [ fetch, csrfToken ]); diff --git a/lib/api/useApiQuery.tsx b/lib/api/useApiQuery.tsx index 8dfa918b8c..6cd58c024e 100644 --- a/lib/api/useApiQuery.tsx +++ b/lib/api/useApiQuery.tsx @@ -11,6 +11,7 @@ export interface Params | number | boolean | undefined>; fetchParams?: Pick; queryOptions?: Partial, ResourceError, D>, 'queryFn'>>; + logError?: boolean; } export function getResourceKey(resource: R, { pathParams, queryParams }: Params = {}) { @@ -23,7 +24,7 @@ export function getResourceKey(resource: R, { pathParams export default function useApiQuery>( resource: R, - { queryOptions, pathParams, queryParams, fetchParams }: Params = {}, + { queryOptions, pathParams, queryParams, fetchParams, logError }: Params = {}, ) { const apiFetch = useApiFetch(); @@ -33,7 +34,7 @@ export default function useApiQuery>" - return apiFetch(resource, { pathParams, queryParams, fetchParams: { ...fetchParams, signal } }) as Promise>; + return apiFetch(resource, { pathParams, queryParams, logError, fetchParams: { ...fetchParams, signal } }) as Promise>; }, ...queryOptions, }); diff --git a/lib/hooks/useAddressProfileApiQuery.tsx b/lib/hooks/useAddressProfileApiQuery.tsx index 26298637fc..ef39555d43 100644 --- a/lib/hooks/useAddressProfileApiQuery.tsx +++ b/lib/hooks/useAddressProfileApiQuery.tsx @@ -27,7 +27,7 @@ export default function useAddressProfileApiQuery(hash: string | undefined, isEn return Promise.reject(); } - return fetch(feature.apiUrlTemplate.replace('{address}', hash), undefined, { omitSentryErrorLog: true }); + return fetch(feature.apiUrlTemplate.replace('{address}', hash)); }, enabled: isEnabled && Boolean(hash), refetchOnMount: false, diff --git a/lib/hooks/useFetch.tsx b/lib/hooks/useFetch.tsx index 06eea3fcae..4b50945f97 100644 --- a/lib/hooks/useFetch.tsx +++ b/lib/hooks/useFetch.tsx @@ -1,8 +1,8 @@ -import * as Sentry from '@sentry/react'; import React from 'react'; import isBodyAllowed from 'lib/api/isBodyAllowed'; import type { ResourceError, ResourcePath } from 'lib/api/resources'; +import { useRollbar } from 'lib/rollbar'; export interface Params { method?: RequestInit['method']; @@ -14,10 +14,12 @@ export interface Params { interface Meta { resource?: ResourcePath; - omitSentryErrorLog?: boolean; + logError?: boolean; } export default function useFetch() { + const rollbar = useRollbar(); + return React.useCallback((path: string, params?: Params, meta?: Meta): Promise> => { const _body = params?.body; const isFormData = _body instanceof FormData; @@ -51,13 +53,12 @@ export default function useFetch() { statusText: response.statusText, }; - if (!meta?.omitSentryErrorLog) { - Sentry.captureException(new Error('Client fetch failed'), { tags: { - source: 'fetch', - 'source.resource': meta?.resource, - 'status.code': error.status, - 'status.text': error.statusText, - } }); + if (meta?.logError && rollbar) { + rollbar.warn('Client fetch failed', { + resource: meta?.resource, + status_code: error.status, + status_text: error.statusText, + }); } return response.json().then( @@ -75,5 +76,5 @@ export default function useFetch() { return response.json() as Promise; } }); - }, [ ]); + }, [ rollbar ]); } diff --git a/lib/hooks/useGetCsrfToken.tsx b/lib/hooks/useGetCsrfToken.tsx index a301b25594..e1db1e595f 100644 --- a/lib/hooks/useGetCsrfToken.tsx +++ b/lib/hooks/useGetCsrfToken.tsx @@ -1,4 +1,3 @@ -import * as Sentry from '@sentry/react'; import { useQuery } from '@tanstack/react-query'; import buildUrl from 'lib/api/buildUrl'; @@ -6,9 +5,11 @@ import isNeedProxy from 'lib/api/isNeedProxy'; import { getResourceKey } from 'lib/api/useApiQuery'; import * as cookies from 'lib/cookies'; import useFetch from 'lib/hooks/useFetch'; +import { useRollbar } from 'lib/rollbar'; export default function useGetCsrfToken() { const nodeApiFetch = useFetch(); + const rollbar = useRollbar(); return useQuery({ queryKey: getResourceKey('csrf'), @@ -19,12 +20,11 @@ export default function useGetCsrfToken() { const csrfFromHeader = apiResponse.headers.get('x-bs-account-csrf'); if (!csrfFromHeader) { - Sentry.captureException(new Error('Client fetch failed'), { tags: { - source: 'fetch', - 'source.resource': 'csrf', - 'status.code': 500, - 'status.text': 'Unable to obtain csrf token from header', - } }); + rollbar?.warn('Client fetch failed', { + resource: 'csrf', + status_code: 500, + status_text: 'Unable to obtain csrf token from header', + }); return; } diff --git a/lib/hooks/useIsSafeAddress.tsx b/lib/hooks/useIsSafeAddress.tsx index 49062f7cc2..7888050a6c 100644 --- a/lib/hooks/useIsSafeAddress.tsx +++ b/lib/hooks/useIsSafeAddress.tsx @@ -15,7 +15,7 @@ export default function useIsSafeAddress(hash: string | undefined): boolean { return Promise.reject(); } - return fetch(`${ feature.apiUrl }/${ hash }`, undefined, { omitSentryErrorLog: true }); + return fetch(`${ feature.apiUrl }/${ hash }`); }, enabled: feature.isEnabled && Boolean(hash), refetchOnMount: false, diff --git a/lib/rollbar/index.tsx b/lib/rollbar/index.tsx new file mode 100644 index 0000000000..9dfbb887a0 --- /dev/null +++ b/lib/rollbar/index.tsx @@ -0,0 +1,23 @@ +import { Provider as DefaultProvider, useRollbar as useRollbarDefault } from '@rollbar/react'; +import type React from 'react'; +import type { Configuration } from 'rollbar'; + +import config from 'configs/app'; + +const feature = config.features.rollbar; + +const FallbackProvider = ({ children }: { children: React.ReactNode }) => children; + +const useRollbarFallback = (): undefined => {}; + +export const Provider = feature.isEnabled ? DefaultProvider : FallbackProvider; +export const useRollbar = feature.isEnabled ? useRollbarDefault : useRollbarFallback; + +export const clientConfig: Configuration | undefined = feature.isEnabled ? { + accessToken: feature.clientToken, + environment: feature.environment, + payload: { + code_version: feature.codeVersion, + app_instance: feature.instance, + }, +} : undefined; diff --git a/lib/sentry/config.ts b/lib/sentry/config.ts deleted file mode 100644 index f619c9346c..0000000000 --- a/lib/sentry/config.ts +++ /dev/null @@ -1,108 +0,0 @@ -import * as Sentry from '@sentry/react'; -import { BrowserTracing } from '@sentry/tracing'; - -import appConfig from 'configs/app'; -import { RESOURCE_LOAD_ERROR_MESSAGE } from 'lib/errors/throwOnResourceLoadError'; - -const feature = appConfig.features.sentry; - -export const config: Sentry.BrowserOptions | undefined = (() => { - if (!feature.isEnabled) { - return; - } - - const tracesSampleRate: number | undefined = (() => { - switch (feature.environment) { - case 'development': - return 1; - case 'staging': - return 0.75; - case 'production': - return 0.2; - } - })(); - - return { - environment: feature.environment, - dsn: feature.dsn, - release: feature.release, - enableTracing: feature.enableTracing, - tracesSampleRate, - integrations: feature.enableTracing ? [ new BrowserTracing() ] : undefined, - - // error filtering settings - // were taken from here - https://docs.sentry.io/platforms/node/guides/azure-functions/configuration/filtering/#decluttering-sentry - ignoreErrors: [ - // Random plugins/extensions - 'top.GLOBALS', - // See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html - 'originalCreateNotification', - 'canvas.contentDocument', - 'MyApp_RemoveAllHighlights', - 'http://tt.epicplay.com', - 'Can\'t find variable: ZiteReader', - 'jigsaw is not defined', - 'ComboSearch is not defined', - 'http://loading.retry.widdit.com/', - 'atomicFindClose', - // Facebook borked - 'fb_xd_fragment', - // ISP "optimizing" proxy - `Cache-Control: no-transform` seems to reduce this. (thanks @acdha) - // See http://stackoverflow.com/questions/4113268/how-to-stop-javascript-injection-from-vodafone-proxy - 'bmi_SafeAddOnload', - 'EBCallBackMessageReceived', - // See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx - 'conduitPage', - // Generic error code from errors outside the security sandbox - 'Script error.', - - // Relay and WalletConnect errors - 'The quota has been exceeded', - 'Attempt to connect to relay via', - 'WebSocket connection failed for URL: wss://relay.walletconnect.com', - - // API errors - RESOURCE_LOAD_ERROR_MESSAGE, - ], - denyUrls: [ - // Facebook flakiness - /graph\.facebook\.com/i, - // Facebook blocked - /connect\.facebook\.net\/en_US\/all\.js/i, - // Woopra flakiness - /eatdifferent\.com\.woopra-ns\.com/i, - /static\.woopra\.com\/js\/woopra\.js/i, - // Chrome and other extensions - /extensions\//i, - /^chrome:\/\//i, - /^chrome-extension:\/\//i, - /^moz-extension:\/\//i, - // Other plugins - /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb - /webappstoolbarba\.texthelp\.com\//i, - /metrics\.itunes\.apple\.com\.edgesuite\.net\//i, - - // AD fetch failed errors - /czilladx\.com/i, - /coinzilla\.com/i, - /coinzilla\.io/i, - /slise\.xyz/i, - ], - }; -})(); - -export function configureScope(scope: Sentry.Scope) { - if (!feature.isEnabled) { - return; - } - scope.setTag('app_instance', feature.instance); -} - -export function init() { - if (!config) { - return; - } - - Sentry.init(config); - Sentry.configureScope(configureScope); -} diff --git a/next.config.js b/next.config.js index e78614249b..1ac9991d07 100644 --- a/next.config.js +++ b/next.config.js @@ -18,13 +18,7 @@ const moduleExports = { 'swagger-ui-react', ], reactStrictMode: true, - webpack(config, { webpack }) { - config.plugins.push( - new webpack.DefinePlugin({ - __SENTRY_DEBUG__: false, - __SENTRY_TRACING__: false, - }), - ); + webpack(config) { config.module.rules.push( { test: /\.svg$/, diff --git a/nextjs/PageNextJs.tsx b/nextjs/PageNextJs.tsx index 89e066ca6d..9993410d8b 100644 --- a/nextjs/PageNextJs.tsx +++ b/nextjs/PageNextJs.tsx @@ -9,7 +9,6 @@ import useAdblockDetect from 'lib/hooks/useAdblockDetect'; import useGetCsrfToken from 'lib/hooks/useGetCsrfToken'; import * as metadata from 'lib/metadata'; import * as mixpanel from 'lib/mixpanel'; -import { init as initSentry } from 'lib/sentry/config'; interface Props { pathname: Pathname; @@ -18,8 +17,6 @@ interface Props { apiData?: PageProps['apiData']; } -initSentry(); - const PageNextJs = (props: Props) => { const { title, description, opengraph, canonical } = metadata.generate(props, props.apiData); diff --git a/nextjs/csp/generateCspPolicy.ts b/nextjs/csp/generateCspPolicy.ts index 64badf9ac1..891a03af5d 100644 --- a/nextjs/csp/generateCspPolicy.ts +++ b/nextjs/csp/generateCspPolicy.ts @@ -15,8 +15,8 @@ function generateCspPolicy() { descriptors.marketplace(), descriptors.mixpanel(), descriptors.monaco(), + descriptors.rollbar(), descriptors.safe(), - descriptors.sentry(), descriptors.usernameApi(), descriptors.walletConnect(), ); diff --git a/nextjs/csp/policies/app.ts b/nextjs/csp/policies/app.ts index 60b4cbb697..0b2d79512b 100644 --- a/nextjs/csp/policies/app.ts +++ b/nextjs/csp/policies/app.ts @@ -11,25 +11,6 @@ const MAIN_DOMAINS = [ config.app.host, ].filter(Boolean); -const getCspReportUrl = () => { - try { - const sentryFeature = config.features.sentry; - if (!sentryFeature.isEnabled || !process.env.SENTRY_CSP_REPORT_URI) { - return; - } - - const url = new URL(process.env.SENTRY_CSP_REPORT_URI); - - // https://docs.sentry.io/product/security-policy-reporting/#additional-configuration - url.searchParams.set('sentry_environment', sentryFeature.environment); - sentryFeature.release && url.searchParams.set('sentry_release', sentryFeature.release); - - return url.toString(); - } catch (error) { - return; - } -}; - const externalFontsDomains = (() => { try { return [ @@ -152,17 +133,5 @@ export function app(): CspDev.DirectiveDescriptor { // allow remix.ethereum.org to embed our contract page in iframe 'remix.ethereum.org', ], - - ...((() => { - if (!config.features.sentry.isEnabled) { - return {}; - } - - return { - 'report-uri': [ - getCspReportUrl(), - ].filter(Boolean), - }; - })()), }; } diff --git a/nextjs/csp/policies/index.ts b/nextjs/csp/policies/index.ts index ebf3db4238..387a58b2d0 100644 --- a/nextjs/csp/policies/index.ts +++ b/nextjs/csp/policies/index.ts @@ -10,7 +10,7 @@ export { helia } from './helia'; export { marketplace } from './marketplace'; export { mixpanel } from './mixpanel'; export { monaco } from './monaco'; +export { rollbar } from './rollbar'; export { safe } from './safe'; -export { sentry } from './sentry'; export { usernameApi } from './usernameApi'; export { walletConnect } from './walletConnect'; diff --git a/nextjs/csp/policies/rollbar.ts b/nextjs/csp/policies/rollbar.ts new file mode 100644 index 0000000000..87470735f7 --- /dev/null +++ b/nextjs/csp/policies/rollbar.ts @@ -0,0 +1,15 @@ +import type CspDev from 'csp-dev'; + +import config from 'configs/app'; + +export function rollbar(): CspDev.DirectiveDescriptor { + if (!config.features.rollbar.isEnabled) { + return {}; + } + + return { + 'connect-src': [ + 'api.rollbar.com', + ], + }; +} diff --git a/nextjs/csp/policies/sentry.ts b/nextjs/csp/policies/sentry.ts deleted file mode 100644 index 298c17a63e..0000000000 --- a/nextjs/csp/policies/sentry.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type CspDev from 'csp-dev'; - -export function sentry(): CspDev.DirectiveDescriptor { - return { - 'connect-src': [ - 'sentry.io', - '*.sentry.io', - ], - }; -} diff --git a/package.json b/package.json index d57d2e84a4..125441b70d 100644 --- a/package.json +++ b/package.json @@ -59,10 +59,8 @@ "@opentelemetry/sdk-node": "0.49.1", "@opentelemetry/sdk-trace-node": "1.22.0", "@opentelemetry/semantic-conventions": "1.22.0", + "@rollbar/react": "0.12.0-beta", "@scure/base": "1.1.9", - "@sentry/cli": "^2.21.2", - "@sentry/react": "7.24.0", - "@sentry/tracing": "7.24.0", "@slise/embed-react": "^2.2.0", "@tanstack/react-query": "5.55.4", "@tanstack/react-query-devtools": "5.55.4", @@ -110,6 +108,7 @@ "react-jazzicon": "^1.0.4", "react-number-format": "^5.3.1", "react-scroll": "^1.8.7", + "rollbar": "2.26.4", "swagger-ui-react": "^5.9.0", "use-font-face-observer": "^1.2.1", "valibot": "0.38.0", diff --git a/pages/404.tsx b/pages/404.tsx index 0e747ae875..bd4e020c0d 100644 --- a/pages/404.tsx +++ b/pages/404.tsx @@ -1,19 +1,21 @@ -import * as Sentry from '@sentry/react'; import React from 'react'; import type { NextPageWithLayout } from 'nextjs/types'; import PageNextJs from 'nextjs/PageNextJs'; +import { useRollbar } from 'lib/rollbar'; import AppError from 'ui/shared/AppError/AppError'; import LayoutError from 'ui/shared/layout/LayoutError'; const error = new Error('Not found', { cause: { status: 404 } }); const Page: NextPageWithLayout = () => { + const rollbar = useRollbar(); + React.useEffect(() => { - Sentry.captureException(new Error('Page not found'), { tags: { source: '404' } }); - }, []); + rollbar?.error('Page not found'); + }, [ rollbar ]); return ( diff --git a/pages/_app.tsx b/pages/_app.tsx index 3c412226f3..bc583e44e8 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,6 +1,5 @@ import { type ChakraProps } from '@chakra-ui/react'; import { GrowthBookProvider } from '@growthbook/growthbook-react'; -import * as Sentry from '@sentry/react'; import { QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import type { AppProps } from 'next/app'; @@ -19,6 +18,7 @@ import { SettingsContextProvider } from 'lib/contexts/settings'; import { growthBook } from 'lib/growthbook/init'; import useLoadFeatures from 'lib/growthbook/useLoadFeatures'; import useNotifyOnNavigation from 'lib/hooks/useNotifyOnNavigation'; +import { clientConfig as rollbarConfig, Provider as RollbarProvider } from 'lib/rollbar'; import { SocketProvider } from 'lib/socket/context'; import RewardsLoginModal from 'ui/rewards/login/RewardsLoginModal'; import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary'; @@ -53,42 +53,39 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { const queryClient = useQueryClientConfig(); - const handleError = React.useCallback((error: Error) => { - Sentry.captureException(error); - }, []); - const getLayout = Component.getLayout ?? ((page) => { page }); return ( - - - - - - - - - - - { getLayout() } - { config.features.rewards.isEnabled && } - - - - - - - - - - - - + + + + + + + + + + + + { getLayout() } + { config.features.rewards.isEnabled && } + + + + + + + + + + + + + ); } diff --git a/ui/address/details/AddressQrCode.tsx b/ui/address/details/AddressQrCode.tsx index f3f58e546c..4a3f3970a0 100644 --- a/ui/address/details/AddressQrCode.tsx +++ b/ui/address/details/AddressQrCode.tsx @@ -14,7 +14,6 @@ import { IconButton, Skeleton, } from '@chakra-ui/react'; -import * as Sentry from '@sentry/react'; import { useRouter } from 'next/router'; import QRCode from 'qrcode'; import React from 'react'; @@ -23,6 +22,7 @@ import type { Address as AddressType } from 'types/api/address'; import getPageType from 'lib/mixpanel/getPageType'; import * as mixpanel from 'lib/mixpanel/index'; +import { useRollbar } from 'lib/rollbar'; import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import IconSvg from 'ui/shared/IconSvg'; @@ -40,6 +40,7 @@ const AddressQrCode = ({ address, className, isLoading }: Props) => { const { isOpen, onOpen, onClose } = useDisclosure(); const router = useRouter(); + const rollbar = useRollbar(); const [ qr, setQr ] = React.useState(''); const [ error, setError ] = React.useState(''); @@ -51,7 +52,7 @@ const AddressQrCode = ({ address, className, isLoading }: Props) => { QRCode.toString(address.hash, SVG_OPTIONS, (error: Error | null | undefined, svg: string) => { if (error) { setError('We were unable to generate QR code.'); - Sentry.captureException(error, { tags: { source: 'qr_code' } }); + rollbar?.warn('QR code generation failed'); return; } @@ -60,7 +61,7 @@ const AddressQrCode = ({ address, className, isLoading }: Props) => { mixpanel.logEvent(mixpanel.EventTypes.QR_CODE, { 'Page type': pageType }); }); } - }, [ address.hash, isOpen, onClose, pageType ]); + }, [ address.hash, isOpen, onClose, pageType, rollbar ]); if (isLoading) { return ; diff --git a/ui/pages/Login.tsx b/ui/pages/Login.tsx index 438f13fd4b..7bc96b70a6 100644 --- a/ui/pages/Login.tsx +++ b/ui/pages/Login.tsx @@ -1,5 +1,4 @@ import { VStack, Textarea, Button, Alert, AlertTitle, AlertDescription, Code, Flex, Box } from '@chakra-ui/react'; -import * as Sentry from '@sentry/react'; import mixpanel from 'mixpanel-browser'; import type { ChangeEvent } from 'react'; import React from 'react'; @@ -9,12 +8,13 @@ import * as cookies from 'lib/cookies'; import useFeatureValue from 'lib/growthbook/useFeatureValue'; import useGradualIncrement from 'lib/hooks/useGradualIncrement'; import useToast from 'lib/hooks/useToast'; +import { useRollbar } from 'lib/rollbar'; import PageTitle from 'ui/shared/Page/PageTitle'; const Login = () => { + const rollbar = useRollbar(); const toast = useToast(); const [ num, setNum ] = useGradualIncrement(0); - const testFeature = useFeatureValue('test_value', 'fallback'); const [ isFormVisible, setFormVisibility ] = React.useState(false); @@ -23,12 +23,12 @@ const Login = () => { React.useEffect(() => { const token = cookies.get(cookies.NAMES.API_TOKEN); setFormVisibility(Boolean(!token && config.features.account.isEnabled)); - // throw new Error('Test error'); + // throw new Error('Render error'); }, []); - const checkSentry = React.useCallback(() => { - Sentry.captureException(new Error('Test error'), { tags: { source: 'test' } }); - }, []); + const checkRollbar = React.useCallback(() => { + rollbar?.error('Test error', { payload: 'foo' }); + }, [ rollbar ]); const checkMixpanel = React.useCallback(() => { mixpanel.track('Test event', { my_prop: 'foo bar' }); @@ -80,7 +80,7 @@ const Login = () => { ) } - + diff --git a/ui/shared/AppError/AppErrorBoundary.tsx b/ui/shared/AppError/AppErrorBoundary.tsx index 8129ac17c7..4c666967be 100644 --- a/ui/shared/AppError/AppErrorBoundary.tsx +++ b/ui/shared/AppError/AppErrorBoundary.tsx @@ -1,6 +1,8 @@ import { chakra } from '@chakra-ui/react'; import React from 'react'; +import getErrorCauseStatusCode from 'lib/errors/getErrorCauseStatusCode'; +import { useRollbar } from 'lib/rollbar'; import ErrorBoundary from 'ui/shared/ErrorBoundary'; import AppError from './AppError'; @@ -8,11 +10,12 @@ import AppError from './AppError'; interface Props { className?: string; children: React.ReactNode; - onError?: (error: Error) => void; Container?: React.FC<{ children: React.ReactNode }>; } -const AppErrorBoundary = ({ className, children, onError, Container }: Props) => { +const AppErrorBoundary = ({ className, children, Container }: Props) => { + + const rollbar = useRollbar(); const renderErrorScreen = React.useCallback((error?: Error) => { const content = ; @@ -22,8 +25,21 @@ const AppErrorBoundary = ({ className, children, onError, Container }: Props) => return content; }, [ className, Container ]); + const handleError = React.useCallback((error: Error) => { + const statusCode = getErrorCauseStatusCode(error); + if (statusCode || !rollbar) { + // For now, we are not interested in logging errors from the API. + // If an error from a resource should be logged, please consider passing "logError: true" to the useApiQuery or useApiFetch hook. + return; + } + + // To this point, there can only be errors that lead to a page crash. + // Therefore, we set the error level to "critical." + rollbar.critical(error); + }, [ rollbar ]); + return ( - + { children } ); diff --git a/ui/snippets/auth/useRedirectForInvalidAuthToken.ts b/ui/snippets/auth/useRedirectForInvalidAuthToken.ts index afbb6a5d61..96634a138b 100644 --- a/ui/snippets/auth/useRedirectForInvalidAuthToken.ts +++ b/ui/snippets/auth/useRedirectForInvalidAuthToken.ts @@ -1,10 +1,11 @@ -import * as Sentry from '@sentry/react'; import React from 'react'; import * as cookies from 'lib/cookies'; +import { useRollbar } from 'lib/rollbar'; import useProfileQuery from 'ui/snippets/auth/useProfileQuery'; export default function useRedirectForInvalidAuthToken() { + const rollbar = useRollbar(); const profileQuery = useProfileQuery(); const errorStatus = profileQuery.error?.status; @@ -13,10 +14,9 @@ export default function useRedirectForInvalidAuthToken() { const apiToken = cookies.get(cookies.NAMES.API_TOKEN); if (apiToken) { - Sentry.captureException(new Error('Invalid API token'), { tags: { source: 'invalid_api_token' } }); cookies.remove(cookies.NAMES.API_TOKEN); window.location.assign('/'); } } - }, [ errorStatus ]); + }, [ errorStatus, rollbar ]); } diff --git a/yarn.lock b/yarn.lock index 75241caafc..af839888d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5415,6 +5415,13 @@ prop-types "^15.7.2" tslib "^2.3.0" +"@rollbar/react@0.12.0-beta": + version "0.12.0-beta" + resolved "https://registry.yarnpkg.com/@rollbar/react/-/react-0.12.0-beta.tgz#b80dfab1535ece358a0e98a4f26aadee8b54edda" + integrity sha512-8udBX0lJwdBBq+O/jqDXpg/giHt8bo/Us1IlTkHEdCBO18Cjj7sxWJ80OPFxiPRNwZgZnhf2HbxQxvLN+4FeJA== + dependencies: + tiny-invariant "^1.1.0" + "@rollup/pluginutils@^5.0.0": version "5.0.2" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33" @@ -5600,70 +5607,6 @@ "@noble/hashes" "~1.5.0" "@scure/base" "~1.1.8" -"@sentry/browser@7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.24.0.tgz#3e657f8032322d07f98486f44e048fcdbc3aaff7" - integrity sha512-G2eeYWF7rIz1Dm8PCQiuuTzctrrJSWqD5MCWOICqHr8FrxOPVsVO3Qa/B7/+BSpHd+V7sSUU17oFu41SAWZCOg== - dependencies: - "@sentry/core" "7.24.0" - "@sentry/types" "7.24.0" - "@sentry/utils" "7.24.0" - tslib "^1.9.3" - -"@sentry/cli@^2.21.2": - version "2.21.2" - resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.21.2.tgz#89e5633ff48a83d078c76c6997fffd4b68b2da1c" - integrity sha512-X1nye89zl+QV3FSuQDGItfM51tW9PQ7ce0TtV/12DgGgTVEgnVp5uvO3wX5XauHvulQzRPzwUL3ZK+yS5bAwCw== - dependencies: - https-proxy-agent "^5.0.0" - node-fetch "^2.6.7" - progress "^2.0.3" - proxy-from-env "^1.1.0" - which "^2.0.2" - -"@sentry/core@7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.24.0.tgz#e856a071c702279854d6e5221957d61cd48036cc" - integrity sha512-QVRtmnaWEI0/MHIfBozgsMfh+7WU6OfpvUd72x1Dpk3Zk6Zs7Hqq0YfxfeBd7ApjNjGogPl1beaHcHAHlr3IyA== - dependencies: - "@sentry/types" "7.24.0" - "@sentry/utils" "7.24.0" - tslib "^1.9.3" - -"@sentry/react@7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.24.0.tgz#aa51b09bad8c5d7af163a28a4718abb1e68ea232" - integrity sha512-uW6j7wrPxg7UillUVdsjrsIPqqPEAN/PdotR2O75Qh7s0aR7+Le8i29C4VeW/iubXhlxF/qFvnXwqG5Ji4GwBg== - dependencies: - "@sentry/browser" "7.24.0" - "@sentry/types" "7.24.0" - "@sentry/utils" "7.24.0" - hoist-non-react-statics "^3.3.2" - tslib "^1.9.3" - -"@sentry/tracing@7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.24.0.tgz#d9477a2da9c902ca9663cd4cd87ba279f73f212c" - integrity sha512-O/4hE/lYM6+hM4K5O06pWNuHzZb2ex5f2497bxkwxq17wpJhVp1oDuz8hbWNL7BUNeIbeDpqunBHQzzmVRbL1Q== - dependencies: - "@sentry/core" "7.24.0" - "@sentry/types" "7.24.0" - "@sentry/utils" "7.24.0" - tslib "^1.9.3" - -"@sentry/types@7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.24.0.tgz#1acc841efe7bd56fc3eb647a613dba92631e8413" - integrity sha512-Xs4r9esBPieJUA6cGmMqfSQiinILdlhScjM+NqDSzxOo8+LRCJzckTLhUttBGVlaAoa4hjCEsfkHA1tVV1DycA== - -"@sentry/utils@7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.24.0.tgz#73f100dc8942e73353473eaf3168e5052e2f45be" - integrity sha512-baaRDhHWHTyhmR6V8YKSo0NvN+D17pIKRDmb2vpWHVpTjobKCivNBLRoy3VhnIMS/24XyZnL028QLwkUNLg1Ug== - dependencies: - "@sentry/types" "7.24.0" - tslib "^1.9.3" - "@sideway/address@^4.1.3": version "4.1.4" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" @@ -8270,6 +8213,11 @@ async-mutex@^0.2.6: dependencies: tslib "^2.0.0" +async@~3.2.3: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -9015,6 +8963,11 @@ consola@^3.2.3: resolved "https://registry.yarnpkg.com/consola/-/consola-3.2.3.tgz#0741857aa88cfa0d6fd53f1cff0375136e98502f" integrity sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ== +console-polyfill@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/console-polyfill/-/console-polyfill-0.3.0.tgz#84900902a18c47a5eba932be75fa44d23e8af861" + integrity sha512-w+JSDZS7XML43Xnwo2x5O5vxB0ID7T5BdqDtyqT6uiCAX2kZAgcWxNaGqT97tZfSHzfOcvrfsDAodKcJ3UvnXQ== + convert-hrtime@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/convert-hrtime/-/convert-hrtime-5.0.0.tgz#f2131236d4598b95de856926a67100a0a97e9fa3" @@ -9610,6 +9563,13 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +decache@^3.0.5: + version "3.1.0" + resolved "https://registry.yarnpkg.com/decache/-/decache-3.1.0.tgz#4f5036fbd6581fcc97237ac3954a244b9536c2da" + integrity sha512-p7D6wJ5EJFFq1CcF2lu1XeqKFLBob8jRQGNAvFLTsV3CbSKBl3VtliAVlUIGz2i9H6kEFnI2Amaft5ZopIG2Fw== + dependencies: + find "^0.2.4" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -10052,6 +10012,13 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +error-stack-parser@^2.0.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" + integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== + dependencies: + stackframe "^1.3.4" + error@7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" @@ -10959,6 +10926,13 @@ find-yarn-workspace-root@^2.0.0: dependencies: micromatch "^4.0.2" +find@^0.2.4: + version "0.2.9" + resolved "https://registry.yarnpkg.com/find/-/find-0.2.9.tgz#4b73f1ff9e56ad91b76e716407fe5ffe6554bb8c" + integrity sha512-7a4/LCiInB9xYMnAUEjLilL9FKclwbwK7VlXw+h5jMvT2TDFeYFCHM24O1XdnC/on/hx8mxVO3FTQkyHZnOghQ== + dependencies: + traverse-chain "~0.1.0" + flat-cache@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" @@ -11658,7 +11632,7 @@ http-shutdown@^1.2.2: resolved "https://registry.yarnpkg.com/http-shutdown/-/http-shutdown-1.2.2.tgz#41bc78fc767637c4c95179bc492f312c0ae64c5f" integrity sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw== -https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: +https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -13158,6 +13132,11 @@ json-stable-stringify@^1.0.2: dependencies: jsonify "^0.0.1" +json-stringify-safe@~5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + json5@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" @@ -13536,6 +13515,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@~2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d" + integrity sha512-Q5pAgXs+WEAfoEdw2qKQhNFFhMoFMTYqRVKKUMnzuiR7oKFHS7fWo848cPcTKw+4j/IdN17NyzdhVKgabFV0EA== + lz-string@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" @@ -14920,11 +14904,6 @@ progress-events@^1.0.0, progress-events@^1.0.1: resolved "https://registry.yarnpkg.com/progress-events/-/progress-events-1.0.1.tgz#693b6d4153f08c1418ae3cd5fcad8596c91db7e8" integrity sha512-MOzLIwhpt64KIVN64h1MwdKWiyKFNc/S6BoYKPIVUHFg0/eIEyBulhWCgn678v/4c0ri3FdGuzXymNCv02MUIw== -progress@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - prom-client@15.1.1: version "15.1.1" resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-15.1.1.tgz#71ba84371241acd173181b04a436782c246f3652" @@ -15658,6 +15637,11 @@ repeat-string@^1.5.2: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== +request-ip@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-3.3.0.tgz#863451e8fec03847d44f223e30a5d63e369fa611" + integrity sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA== + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -15780,6 +15764,21 @@ robust-predicates@^3.0.0: resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a" integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g== +rollbar@2.26.4: + version "2.26.4" + resolved "https://registry.yarnpkg.com/rollbar/-/rollbar-2.26.4.tgz#05e47d3b1f52ab6da9f88710ec66371a76cdc3c9" + integrity sha512-JKmrj6riYm9ZPJisgxljgH4uCsvjMHDHXrinDF7aAFaP+eoF51HomVPtLcDTYLsrJ568aKVNLUhedFajONBwSg== + dependencies: + async "~3.2.3" + console-polyfill "0.3.0" + error-stack-parser "^2.0.4" + json-stringify-safe "~5.0.0" + lru-cache "~2.2.1" + request-ip "~3.3.0" + source-map "^0.5.7" + optionalDependencies: + decache "^3.0.5" + rollup-plugin-visualizer@^5.9.2: version "5.12.0" resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.12.0.tgz#661542191ce78ee4f378995297260d0c1efb1302" @@ -16249,6 +16248,11 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" +stackframe@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" + integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== + stampit@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/stampit/-/stampit-4.3.2.tgz#cfd3f607dd628a161ce6305621597994b4d56573" @@ -16823,6 +16827,11 @@ tiny-invariant@^1.0.6: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== +tiny-invariant@^1.1.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== + tiny-parse-argv@^2.2.0: version "2.4.0" resolved "https://registry.yarnpkg.com/tiny-parse-argv/-/tiny-parse-argv-2.4.0.tgz#8612163a88104a5af9a64e4775cd1e091d4fa265" @@ -16889,6 +16898,11 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +traverse-chain@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1" + integrity sha512-up6Yvai4PYKhpNp5PkYtx50m3KbwQrqDwbuZP/ItyL64YEWHAvH6Md83LFLV/GRSk/BoUVwwgUzX6SOQSbsfAg== + traverse@~0.6.6: version "0.6.7" resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.7.tgz#46961cd2d57dd8706c36664acde06a248f1173fe" @@ -16974,7 +16988,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@1.14.1, tslib@^1.8.1, tslib@^1.9.3: +tslib@1.14.1, tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -17682,7 +17696,7 @@ which-typed-array@^1.1.2, which-typed-array@^1.1.8, which-typed-array@^1.1.9: has-tostringtag "^1.0.0" is-typed-array "^1.1.10" -which@^2.0.1, which@^2.0.2: +which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==