From d67fc63722ad8e3237e3d6f6c7878032f7591729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ra=C4=8D=C3=A1k?= Date: Wed, 8 Jan 2025 16:39:15 +0100 Subject: [PATCH] Switch error tracking to Sentry --- .bundlewatch.config.json | 2 +- .github/workflows/sentry.yml | 21 + .gitignore | 3 + README.md | 2 - adminSiteClient/admin.entry.ts | 4 + adminSiteClient/instrument.ts | 7 + adminSiteServer/apiRoutes/datasets.ts | 6 +- adminSiteServer/app.ts | 3 + adminSiteServer/appClass.tsx | 32 +- adminSiteServer/authentication.ts | 4 +- adminSiteServer/chartConfigR2Helpers.ts | 3 - baker/DatapageHelpers.ts | 8 +- baker/DeployUtils.ts | 22 +- baker/GrapherBaker.tsx | 7 +- baker/GrapherBakingUtils.ts | 9 +- baker/MultiDimBaker.tsx | 7 +- baker/SiteBaker.tsx | 96 +- baker/algolia/indexChartsToAlgolia.ts | 16 +- .../indexExplorerViewsAndChartsToAlgolia.ts | 69 +- baker/algolia/indexExplorerViewsToAlgolia.ts | 46 +- baker/algolia/utils/explorerViews.ts | 10 +- baker/algolia/utils/pages.ts | 4 +- baker/pageOverrides.tsx | 10 +- baker/redirects.ts | 12 +- baker/siteRenderers.tsx | 21 +- baker/startDeployQueueServer.ts | 17 +- explorerAdminClient/ExplorerCreatePage.tsx | 2 +- gitCms/GitCmsServer.ts | 10 +- package.json | 9 +- .../@ourworldindata/explorer/package.json | 3 - .../@ourworldindata/explorer/src/Explorer.tsx | 2 - packages/@ourworldindata/grapher/package.json | 4 +- .../grapher/src/core/Grapher.tsx | 64 +- serverUtils/errorLog.ts | 20 +- serverUtils/instrument.ts | 19 + settings/clientSettings.ts | 8 +- settings/serverSettings.ts | 7 +- site/DataCatalog/DataCatalog.tsx | 5 +- site/DonateForm.tsx | 6 +- site/hacks.ts | 18 +- site/instrument.ts | 35 + site/multiembedder/MultiEmbedder.tsx | 2 - site/owid.entry.ts | 88 +- site/viteUtils.tsx | 2 +- vite.config-common.mts | 9 +- yarn.lock | 1495 ++++++++++++++--- 46 files changed, 1571 insertions(+), 678 deletions(-) create mode 100644 .github/workflows/sentry.yml create mode 100644 adminSiteClient/instrument.ts create mode 100644 serverUtils/instrument.ts create mode 100644 site/instrument.ts diff --git a/.bundlewatch.config.json b/.bundlewatch.config.json index 86a2fb354ac..3c9b1e8a0ec 100644 --- a/.bundlewatch.config.json +++ b/.bundlewatch.config.json @@ -2,7 +2,7 @@ "files": [ { "path": "./dist/assets/owid.mjs", - "maxSize": "2.6MB" + "maxSize": "2.8MB" }, { "path": "./dist/assets/owid.css", diff --git a/.github/workflows/sentry.yml b/.github/workflows/sentry.yml new file mode 100644 index 00000000000..f145fc6512e --- /dev/null +++ b/.github/workflows/sentry.yml @@ -0,0 +1,21 @@ +name: Sentry Release +on: push + +jobs: + create-release: + runs-on: ubuntu-latest + + steps: + - name: Clone repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Create Sentry release + uses: getsentry/action-release@v1 + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_ORG: ${{ secrets.SENTRY_ORG }} + with: + environment: ${{ github.ref_name == 'master' && 'production' || 'staging' }} + projects: admin website diff --git a/.gitignore b/.gitignore index 0c56cb718ec..80358aaa443 100755 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ dist/ **/tsup.config.bundled*.mjs cfstorage/ vite.*.mjs + +# Sentry Config File +.env.sentry-build-plugin diff --git a/README.md b/README.md index 0c5ef29c04c..5cdc623ec68 100644 --- a/README.md +++ b/README.md @@ -84,5 +84,3 @@ The following is an excerpt explaining the origin of this repo and what the alte --- Cross-browser testing provided by BrowserStack - -Client-side bug tracking provided by diff --git a/adminSiteClient/admin.entry.ts b/adminSiteClient/admin.entry.ts index 3f095208022..d69caddf6d6 100644 --- a/adminSiteClient/admin.entry.ts +++ b/adminSiteClient/admin.entry.ts @@ -1,3 +1,7 @@ +// This should be imported as early as possible so the global error handler is +// set up before any errors are thrown. +import "./instrument.js" + import "./admin.scss" import "@ourworldindata/grapher/src/core/grapher.scss" import "../explorerAdminClient/ExplorerCreatePage.scss" diff --git a/adminSiteClient/instrument.ts b/adminSiteClient/instrument.ts new file mode 100644 index 00000000000..03a37296771 --- /dev/null +++ b/adminSiteClient/instrument.ts @@ -0,0 +1,7 @@ +import * as Sentry from "@sentry/react" + +Sentry.init({ + dsn: process.env.SENTRY_ADMIN_DSN, + environment: process.env.ENV, + release: process.env.COMMIT_SHA, +}) diff --git a/adminSiteServer/apiRoutes/datasets.ts b/adminSiteServer/apiRoutes/datasets.ts index fb490bc42ee..caa4f29f763 100644 --- a/adminSiteServer/apiRoutes/datasets.ts +++ b/adminSiteServer/apiRoutes/datasets.ts @@ -12,7 +12,7 @@ import { assignTagsForCharts, } from "../../db/model/Chart.js" import { getDatasetById, setTagsForDataset } from "../../db/model/Dataset.js" -import { logErrorAndMaybeSendToBugsnag } from "../../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../../serverUtils/errorLog.js" import { expectInt } from "../../serverUtils/serverUtil.js" import { syncDatasetToGitRepo, @@ -299,7 +299,7 @@ export async function updateDataset( commitEmail: _res.locals.user.email, }) } catch (err) { - await logErrorAndMaybeSendToBugsnag(err, req) + await logErrorAndMaybeCaptureInSentry(err) // Continue } @@ -363,7 +363,7 @@ export async function deleteDataset( commitEmail: _res.locals.user.email, }) } catch (err: any) { - await logErrorAndMaybeSendToBugsnag(err, req) + await logErrorAndMaybeCaptureInSentry(err) // Continue } diff --git a/adminSiteServer/app.ts b/adminSiteServer/app.ts index b45978b2367..922a62439e0 100644 --- a/adminSiteServer/app.ts +++ b/adminSiteServer/app.ts @@ -1,3 +1,6 @@ +// This must be imported first for Sentry instrumentation to work. +import "../serverUtils/instrument.js" + import { GIT_CMS_DIR } from "../gitCms/GitCmsConstants.js" import { ADMIN_SERVER_HOST, diff --git a/adminSiteServer/appClass.tsx b/adminSiteServer/appClass.tsx index 1ef3cc0546b..45eab13cae9 100644 --- a/adminSiteServer/appClass.tsx +++ b/adminSiteServer/appClass.tsx @@ -1,16 +1,11 @@ import { simpleGit } from "simple-git" import express, { NextFunction } from "express" +import * as Sentry from "@sentry/node" // eslint-disable-next-line @typescript-eslint/no-require-imports require("express-async-errors") // todo: why the require? import cookieParser from "cookie-parser" import http from "http" -import Bugsnag from "@bugsnag/js" -import BugsnagPluginExpress from "@bugsnag/plugin-express" -import { - BAKED_BASE_URL, - BUGSNAG_NODE_API_KEY, - ENV_IS_STAGING, -} from "../settings/serverSettings.js" +import { BAKED_BASE_URL, ENV_IS_STAGING } from "../settings/serverSettings.js" import * as db from "../db/db.js" import { IndexPage } from "./IndexPage.js" import { @@ -66,23 +61,9 @@ export class OwidAdminApp { async startListening(adminServerPort: number, adminServerHost: string) { this.gitCmsBranchName = await this.getGitCmsBranchName() - let bugsnagMiddleware const { app } = this - if (BUGSNAG_NODE_API_KEY) { - Bugsnag.start({ - apiKey: BUGSNAG_NODE_API_KEY, - context: "admin-server", - plugins: [BugsnagPluginExpress], - autoTrackSessions: false, - }) - bugsnagMiddleware = Bugsnag.getPlugin("express") - // From the docs: "this must be the first piece of middleware in the - // stack. It can only capture errors in downstream middleware" - if (bugsnagMiddleware) app.use(bugsnagMiddleware.requestHandler) - } - // since the server is running behind a reverse proxy (nginx), we need to "trust" // the X-Forwarded-For header in order to get the real request IP // https://expressjs.com/en/guide/behind-proxies.html @@ -157,11 +138,6 @@ export class OwidAdminApp { } }) - // From the docs: "this handles any errors that Express catches. This - // needs to go before other error handlers. BugSnag will call the `next` - // error handler if it exists. - if (bugsnagMiddleware) app.use(bugsnagMiddleware.errorHandler) - if (this.options.isDev) { if (!this.options.isTest) { // https://vitejs.dev/guide/ssr @@ -179,6 +155,10 @@ export class OwidAdminApp { app.use("/", mockSiteRouter) } + // Add this after all routes, + // but before any and other error-handling middlewares are defined + Sentry.setupExpressErrorHandler(app) + // Give full error messages, including in production app.use(this.errorHandler) diff --git a/adminSiteServer/authentication.ts b/adminSiteServer/authentication.ts index 605fb4c6747..47033fcdfb6 100644 --- a/adminSiteServer/authentication.ts +++ b/adminSiteServer/authentication.ts @@ -100,7 +100,7 @@ export async function authCloudflareSSOMiddleware( res.cookie("sessionid", sessionId, { httpOnly: true, sameSite: "lax", - secure: ENV === "production", + secure: ENV !== "development", }) // Prevents redirect to external URLs @@ -327,7 +327,7 @@ export async function tailscaleAuthMiddleware( res.cookie("sessionid", sessionId, { httpOnly: true, sameSite: "lax", - secure: ENV === "production", + secure: ENV !== "development", }) // Save the sessionid in cookies for `authMiddleware` to log us in diff --git a/adminSiteServer/chartConfigR2Helpers.ts b/adminSiteServer/chartConfigR2Helpers.ts index 3c7122da7c4..bae0969eb59 100644 --- a/adminSiteServer/chartConfigR2Helpers.ts +++ b/adminSiteServer/chartConfigR2Helpers.ts @@ -15,7 +15,6 @@ import { } from "@aws-sdk/client-s3" import { JsonError, lazy } from "@ourworldindata/utils" import { Base64String, R2GrapherConfigDirectory } from "@ourworldindata/types" -import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js" const getS3Client: () => S3Client = lazy( () => @@ -116,7 +115,6 @@ async function saveConfigToR2( `Successfully uploaded object: ${params.Bucket}/${params.Key}` ) } catch (err) { - await logErrorAndMaybeSendToBugsnag(err) throw new JsonError( `Failed to save the config to R2. Inner error: ${err}` ) @@ -162,7 +160,6 @@ export async function deleteGrapherConfigFromR2( `Successfully deleted object: ${params.Bucket}/${params.Key}` ) } catch (err) { - await logErrorAndMaybeSendToBugsnag(err) throw new JsonError( `Failed to delete the grapher config to R2 at ${directory}/${filename}. Inner error: ${err}` ) diff --git a/baker/DatapageHelpers.ts b/baker/DatapageHelpers.ts index 469a26b5d75..4c3d057931e 100644 --- a/baker/DatapageHelpers.ts +++ b/baker/DatapageHelpers.ts @@ -25,7 +25,7 @@ import { } from "@ourworldindata/types" import { KnexReadonlyTransaction } from "../db/db.js" import { parseFaqs } from "../db/model/Gdoc/rawToEnriched.js" -import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../serverUtils/errorLog.js" import { getSlugForTopicTag } from "./GrapherBakingUtils.js" import { getShortPageCitation } from "../site/gdocs/utils.js" @@ -197,8 +197,10 @@ export const getPrimaryTopic = async ( try { topicSlug = await getSlugForTopicTag(knex, firstTopicTag) } catch { - await logErrorAndMaybeSendToBugsnag( - `Data page is using "${firstTopicTag}" as its primary tag, which we are unable to resolve to a tag in the grapher DB` + await logErrorAndMaybeCaptureInSentry( + new Error( + `Data page is using "${firstTopicTag}" as its primary tag, which we are unable to resolve to a tag in the grapher DB` + ) ) return undefined } diff --git a/baker/DeployUtils.ts b/baker/DeployUtils.ts index 3e961be1d70..863a4a236ae 100644 --- a/baker/DeployUtils.ts +++ b/baker/DeployUtils.ts @@ -1,6 +1,5 @@ import fs from "fs-extra" import { BuildkiteTrigger } from "../baker/BuildkiteTrigger.js" -import { logErrorAndMaybeSendToBugsnag, warn } from "../serverUtils/errorLog.js" import { DeployQueueServer } from "./DeployQueueServer.js" import { BAKED_SITE_DIR, @@ -24,7 +23,7 @@ export const defaultCommitMessage = async (): Promise => { const sha = await fs.readFile("public/head.txt", "utf8") message += `\nowid/owid-grapher@${sha}` } catch (err) { - warn(err) + console.warn(err) } return message @@ -43,16 +42,12 @@ const triggerBakeAndDeploy = async ( if (BUILDKITE_API_ACCESS_TOKEN) { const buildkite = new BuildkiteTrigger() if (lightningQueue?.length) { - await buildkite - .runLightningBuild( - lightningQueue.map((change) => change.slug!), - deployMetadata - ) - .catch(logErrorAndMaybeSendToBugsnag) + await buildkite.runLightningBuild( + lightningQueue.map((change) => change.slug!), + deployMetadata + ) } else { - await buildkite - .runFullBuild(deployMetadata) - .catch(logErrorAndMaybeSendToBugsnag) + await buildkite.runFullBuild(deployMetadata) } } else { // otherwise, bake locally. This is used for local development or staging servers @@ -143,11 +138,8 @@ const getSlackMentionByEmail = async ( const response = await slackClient.users.lookupByEmail({ email }) return response.user?.id ? `<@${response.user.id}>` : undefined } catch (error) { - await logErrorAndMaybeSendToBugsnag( - `Error looking up email "${email}" in slack: ${error}` - ) + throw new Error(`Error looking up email "${email}" in slack: ${error}`) } - return } const MAX_SUCCESSIVE_FAILURES = 2 diff --git a/baker/GrapherBaker.tsx b/baker/GrapherBaker.tsx index 2f65b46899d..2efc3a6c52a 100644 --- a/baker/GrapherBaker.tsx +++ b/baker/GrapherBaker.tsx @@ -29,7 +29,6 @@ import { getRelatedResearchAndWritingForVariable, } from "../db/model/Post.js" import { - JsonError, GrapherInterface, OwidVariableDataMetadataDimensions, DimensionProperty, @@ -54,7 +53,7 @@ import { resolveFaqsForVariable, } from "./DatapageHelpers.js" import { getAllImages } from "../db/model/Image.js" -import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../serverUtils/errorLog.js" import { getTagToSlugMap } from "./GrapherBakingUtils.js" import { knexRaw } from "../db/db.js" @@ -156,8 +155,8 @@ export async function renderDataPageV2( if (faqResolveErrors.length > 0) { for (const error of faqResolveErrors) { - await logErrorAndMaybeSendToBugsnag( - new JsonError( + await logErrorAndMaybeCaptureInSentry( + new Error( `Data page error in finding FAQs for variable ${variableId}: ${error.error}` ) ) diff --git a/baker/GrapherBakingUtils.ts b/baker/GrapherBakingUtils.ts index b7f80eee83c..6b62bf76828 100644 --- a/baker/GrapherBakingUtils.ts +++ b/baker/GrapherBakingUtils.ts @@ -9,7 +9,6 @@ import { BAKED_SITE_EXPORTS_BASE_URL } from "../settings/clientSettings.js" import * as db from "../db/db.js" import { bakeGraphersToSvgs } from "../baker/GrapherImageBaker.js" -import { warn } from "../serverUtils/errorLog.js" import { mapSlugsToIds } from "../db/model/Chart.js" import md5 from "md5" import { DbPlainTag, Url } from "@ourworldindata/utils" @@ -70,13 +69,13 @@ export const bakeGrapherUrls = async ( const slug = lodash.last(Url.fromURL(url).pathname?.split("/")) if (!slug) { - warn(`Invalid chart url ${url}`) + console.warn(`Invalid chart url ${url}`) continue } const chartId = slugToId[slug] if (chartId === undefined) { - warn(`Couldn't find chart with slug ${slug}`) + console.warn(`Couldn't find chart with slug ${slug}`) continue } @@ -91,7 +90,7 @@ export const bakeGrapherUrls = async ( [chartId] ) if (!rows.length) { - warn(`Mysteriously missing chart by id ${chartId}`) + console.warn(`Mysteriously missing chart by id ${chartId}`) continue } @@ -167,7 +166,7 @@ export async function getTagToSlugMap( /** * Given a topic tag's name or ID, return its slug - * Throws an error if no slug is found so we can log it in Bugsnag + * Throws an error if no slug is found so we can log it in Sentry */ export async function getSlugForTopicTag( knex: db.KnexReadonlyTransaction, diff --git a/baker/MultiDimBaker.tsx b/baker/MultiDimBaker.tsx index db04ecdb3c7..ff80d40d3a0 100644 --- a/baker/MultiDimBaker.tsx +++ b/baker/MultiDimBaker.tsx @@ -8,7 +8,6 @@ import { } from "@ourworldindata/types" import { MultiDimDataPageConfig, - JsonError, keyBy, OwidVariableWithSource, pick, @@ -28,7 +27,7 @@ import { getPrimaryTopic, resolveFaqsForVariable, } from "./DatapageHelpers.js" -import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../serverUtils/errorLog.js" import { getAllMultiDimDataPages, getMultiDimDataPageBySlug, @@ -83,8 +82,8 @@ const getFaqEntries = async ( if (faqResolveErrors.length > 0) { for (const error of faqResolveErrors) { - void logErrorAndMaybeSendToBugsnag( - new JsonError( + void logErrorAndMaybeCaptureInSentry( + new Error( `MDD baking error for page "${config.title}" in finding FAQs for variable ${metadata.id}: ${error.error}` ) ) diff --git a/baker/SiteBaker.tsx b/baker/SiteBaker.tsx index c422adcaa4e..8ae644ffa33 100644 --- a/baker/SiteBaker.tsx +++ b/baker/SiteBaker.tsx @@ -1,3 +1,6 @@ +// This must be imported first for Sentry instrumentation to work. +import "../serverUtils/instrument.js" + import fs from "fs-extra" import path from "path" import { glob } from "glob" @@ -81,7 +84,7 @@ import { import { GdocPost } from "../db/model/Gdoc/GdocPost.js" import { getAllImages } from "../db/model/Image.js" import { generateEmbedSnippet } from "../site/viteUtils.js" -import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../serverUtils/errorLog.js" import { getChartEmbedUrlsInPublishedWordpressPosts, mapSlugsToConfigs, @@ -205,9 +208,6 @@ export class SiteBaker { } ) this.explorerAdminServer = new ExplorerAdminServer(GIT_CMS_DIR) - // As of 10-10-2024, baking sends too many events to Bugsnag which causes us to hit the rate limit. - // We'll have to find a way to be more selective about how we log baking errors/warnings. - // (Only sending errors probably isn't sufficient, because there are some warnings that we want to know about.) // if (BUGSNAG_NODE_API_KEY) { // Bugsnag.start({ // apiKey: BUGSNAG_NODE_API_KEY, @@ -636,22 +636,13 @@ export class SiteBaker { } await publishedGdoc.validate(knex) - for (const errorOrWarning of publishedGdoc.errors) { - const announcement = - errorOrWarning.type === OwidGdocErrorMessageType.Error - ? `Error baking "${publishedGdoc.slug}"` - : `Warning baking "${publishedGdoc.slug}"` - await logErrorAndMaybeSendToBugsnag( - `${announcement}: ${errorOrWarning.message}`, - undefined, - errorOrWarning.message - ) - } try { await this.bakeOwidGdoc(publishedGdoc) } catch (e) { - await logErrorAndMaybeSendToBugsnag( - `Error baking gdoc post with id "${publishedGdoc.id}" and slug "${publishedGdoc.slug}": ${e}` + await logErrorAndMaybeCaptureInSentry( + new Error( + `Error baking gdoc post with id "${publishedGdoc.id}" and slug "${publishedGdoc.slug}": ${e}` + ) ) } } @@ -670,16 +661,20 @@ export class SiteBaker { if (linkedGdocId) { const linkedDocument = attachments.linkedDocuments[linkedGdocId] if (!linkedDocument) { - await logErrorAndMaybeSendToBugsnag( - `Tombstone with id "${tombstone.id}" references a gdoc with id "${linkedGdocId}" which was not found` + await logErrorAndMaybeCaptureInSentry( + new Error( + `Tombstone with id "${tombstone.id}" references a gdoc with id "${linkedGdocId}" which was not found` + ) ) } } try { await this.bakeOwidGdocTombstone(tombstone, attachments) } catch (e) { - await logErrorAndMaybeSendToBugsnag( - `Error baking gdoc tombstone with id "${tombstone.id}" and slug "${tombstone.slug}": ${e}` + await logErrorAndMaybeCaptureInSentry( + new Error( + `Error baking gdoc tombstone with id "${tombstone.id}" and slug "${tombstone.slug}": ${e}` + ) ) } } @@ -806,8 +801,10 @@ export class SiteBaker { ) for (const detailId of detailIds) { if (!details[detailId]) { - await logErrorAndMaybeSendToBugsnag( - `Grapher with slug ${chart.slug} references dod "${detailId}" which does not exist` + await logErrorAndMaybeCaptureInSentry( + new Error( + `Grapher with slug ${chart.slug} references dod "${detailId}" which does not exist` + ) ) } } @@ -842,10 +839,12 @@ export class SiteBaker { const { details, parseErrors } = await GdocPost.getDetailsOnDemandGdoc(knex) if (parseErrors.length) { - await logErrorAndMaybeSendToBugsnag( - `Error(s) baking details: ${parseErrors - .map((e) => e.message) - .join(", ")}` + await logErrorAndMaybeCaptureInSentry( + new Error( + `Error(s) baking details: ${parseErrors + .map((e) => e.message) + .join(", ")}` + ) ) } @@ -889,22 +888,13 @@ export class SiteBaker { dataInsight.latestDataInsights = latestDataInsights await dataInsight.validate(knex) - for (const errorOrWarning of dataInsight.errors) { - const announcement = - errorOrWarning.type === OwidGdocErrorMessageType.Error - ? `Error baking "data-insight/${dataInsight.slug}"` - : `Warning baking "data-insight/${dataInsight.slug}"` - await logErrorAndMaybeSendToBugsnag( - `${announcement}: ${errorOrWarning.message}`, - undefined, - errorOrWarning.message - ) - } try { await this.bakeOwidGdoc(dataInsight) } catch (e) { - await logErrorAndMaybeSendToBugsnag( - `Error baking gdoc post with id "${dataInsight.id}" and slug "${dataInsight.slug}": ${e}` + await logErrorAndMaybeCaptureInSentry( + new Error( + `Error baking gdoc post with id "${dataInsight.id}" and slug "${dataInsight.slug}": ${e}` + ) ) } // We don't need the latest data insights nor their images in the @@ -975,19 +965,23 @@ export class SiteBaker { (e) => e.type === OwidGdocErrorMessageType.Error ).length ) { - await logErrorAndMaybeSendToBugsnag( - `Error(s) baking "${ - publishedAuthor.slug - }" :\n ${publishedAuthor.errors - .map((error) => error.message) - .join("\n ")}` + await logErrorAndMaybeCaptureInSentry( + new Error( + `Error(s) baking "${ + publishedAuthor.slug + }" :\n ${publishedAuthor.errors + .map((error) => error.message) + .join("\n ")}` + ) ) } try { await this.bakeOwidGdoc(publishedAuthor) } catch (e) { - await logErrorAndMaybeSendToBugsnag( - `Error baking author with id "${publishedAuthor.id}" and slug "${publishedAuthor.slug}": ${e}` + await logErrorAndMaybeCaptureInSentry( + new Error( + `Error baking author with id "${publishedAuthor.id}" and slug "${publishedAuthor.slug}": ${e}` + ) ) } } @@ -1040,8 +1034,10 @@ export class SiteBaker { for (const icon of tagIcons) { const iconName = icon.split(".")[0] if (!tagNames.has(iconName)) { - await logErrorAndMaybeSendToBugsnag( - `Tag icon "${icon}" does not have a corresponding tag in the database.` + await logErrorAndMaybeCaptureInSentry( + new Error( + `Tag icon "${icon}" does not have a corresponding tag in the database.` + ) ) } } diff --git a/baker/algolia/indexChartsToAlgolia.ts b/baker/algolia/indexChartsToAlgolia.ts index 30086cdca04..68ed552be10 100644 --- a/baker/algolia/indexChartsToAlgolia.ts +++ b/baker/algolia/indexChartsToAlgolia.ts @@ -1,23 +1,15 @@ +// This must be imported first for Sentry instrumentation to work. +import "../../serverUtils/instrument.js" + import * as db from "../../db/db.js" -import { - ALGOLIA_INDEXING, - BUGSNAG_NODE_API_KEY, -} from "../../settings/serverSettings.js" +import { ALGOLIA_INDEXING } from "../../settings/serverSettings.js" import { getAlgoliaClient } from "./configureAlgolia.js" import { SearchIndexName } from "../../site/search/searchTypes.js" import { getIndexName } from "../../site/search/searchClient.js" import { getChartsRecords } from "./utils/charts.js" -import Bugsnag from "@bugsnag/js" const indexChartsToAlgolia = async () => { if (!ALGOLIA_INDEXING) return - if (BUGSNAG_NODE_API_KEY) { - Bugsnag.start({ - apiKey: BUGSNAG_NODE_API_KEY, - context: "index-explorer-views-to-algolia", - autoTrackSessions: false, - }) - } const client = getAlgoliaClient() if (!client) { diff --git a/baker/algolia/indexExplorerViewsAndChartsToAlgolia.ts b/baker/algolia/indexExplorerViewsAndChartsToAlgolia.ts index 1614d199d29..65e6beca798 100644 --- a/baker/algolia/indexExplorerViewsAndChartsToAlgolia.ts +++ b/baker/algolia/indexExplorerViewsAndChartsToAlgolia.ts @@ -1,10 +1,8 @@ -import Bugsnag from "@bugsnag/js" +// This must be imported first for Sentry instrumentation to work. +import "../../serverUtils/instrument.js" + import * as db from "../../db/db.js" -import { logErrorAndMaybeSendToBugsnag } from "../../serverUtils/errorLog.js" -import { - ALGOLIA_INDEXING, - BUGSNAG_NODE_API_KEY, -} from "../../settings/serverSettings.js" +import { ALGOLIA_INDEXING } from "../../settings/serverSettings.js" import { getAlgoliaClient } from "./configureAlgolia.js" import { getExplorerViewRecords, @@ -20,57 +18,40 @@ import { SearchIndexName } from "../../site/search/searchTypes.js" // to use in /search. const indexExplorerViewsAndChartsToAlgolia = async () => { if (!ALGOLIA_INDEXING) return - if (BUGSNAG_NODE_API_KEY) { - Bugsnag.start({ - apiKey: BUGSNAG_NODE_API_KEY, - context: "index-explorer-views-to-algolia", - autoTrackSessions: false, - }) - } const indexName = getIndexName(SearchIndexName.ExplorerViewsAndCharts) console.log( `Indexing explorer views and charts to the "${indexName}" index on Algolia` ) const client = getAlgoliaClient() if (!client) { - await logErrorAndMaybeSendToBugsnag( + throw new Error( `Failed indexing explorer views (Algolia client not initialized)` ) - return } - try { - const { explorerViews, grapherViews } = - await db.knexReadonlyTransaction(async (trx) => { - return { - explorerViews: await getExplorerViewRecords(trx, true), - grapherViews: await getChartsRecords(trx), - } - }, db.TransactionCloseMode.Close) + const { explorerViews, grapherViews } = await db.knexReadonlyTransaction( + async (trx) => { + return { + explorerViews: await getExplorerViewRecords(trx, true), + grapherViews: await getChartsRecords(trx), + } + }, + db.TransactionCloseMode.Close + ) - // Scale grapher records and the default explorer views between 1000 and 10000, - // Scale the remaining explorer views between 0 and 1000. - // This is because Graphers are generally higher quality than Explorers and we don't want - // the data catalog to smother Grapher results with hundreds of low-quality Explorer results. - const scaledGrapherViews = scaleRecordScores( - grapherViews, - [1000, 10000] - ) - const scaledExplorerViews = adaptExplorerViews(explorerViews) + // Scale grapher records and the default explorer views between 1000 and 10000, + // Scale the remaining explorer views between 0 and 1000. + // This is because Graphers are generally higher quality than Explorers and we don't want + // the data catalog to smother Grapher results with hundreds of low-quality Explorer results. + const scaledGrapherViews = scaleRecordScores(grapherViews, [1000, 10000]) + const scaledExplorerViews = adaptExplorerViews(explorerViews) - const records = [...scaledGrapherViews, ...scaledExplorerViews] + const records = [...scaledGrapherViews, ...scaledExplorerViews] - const index = client.initIndex(indexName) - console.log(`Indexing ${records.length} records`) - await index.replaceAllObjects(records) - console.log(`Indexing complete`) - } catch (error) { - console.log("Error: ", error) - await logErrorAndMaybeSendToBugsnag({ - name: `IndexExplorerViewsToAlgoliaError`, - message: error, - }) - } + const index = client.initIndex(indexName) + console.log(`Indexing ${records.length} records`) + await index.replaceAllObjects(records) + console.log(`Indexing complete`) } process.on("unhandledRejection", (e) => { diff --git a/baker/algolia/indexExplorerViewsToAlgolia.ts b/baker/algolia/indexExplorerViewsToAlgolia.ts index 4c8568e4a2a..c65a6e6462a 100644 --- a/baker/algolia/indexExplorerViewsToAlgolia.ts +++ b/baker/algolia/indexExplorerViewsToAlgolia.ts @@ -1,52 +1,32 @@ +// This must be imported first for Sentry instrumentation to work. +import "../../serverUtils/instrument.js" + import * as db from "../../db/db.js" -import { - ALGOLIA_INDEXING, - BUGSNAG_NODE_API_KEY, -} from "../../settings/serverSettings.js" +import { ALGOLIA_INDEXING } from "../../settings/serverSettings.js" import { getAlgoliaClient } from "./configureAlgolia.js" import { getIndexName } from "../../site/search/searchClient.js" import { SearchIndexName } from "../../site/search/searchTypes.js" -import Bugsnag from "@bugsnag/js" -import { logErrorAndMaybeSendToBugsnag } from "../../serverUtils/errorLog.js" import { getExplorerViewRecords } from "./utils/explorerViews.js" const indexExplorerViewsToAlgolia = async () => { if (!ALGOLIA_INDEXING) return - if (BUGSNAG_NODE_API_KEY) { - Bugsnag.start({ - apiKey: BUGSNAG_NODE_API_KEY, - context: "index-explorer-views-to-algolia", - autoTrackSessions: false, - }) - } const client = getAlgoliaClient() if (!client) { - await logErrorAndMaybeSendToBugsnag( + throw new Error( `Failed indexing explorer views (Algolia client not initialized)` ) - return } - try { - const index = client.initIndex( - getIndexName(SearchIndexName.ExplorerViews) - ) + const index = client.initIndex(getIndexName(SearchIndexName.ExplorerViews)) - const records = await db.knexReadonlyTransaction( - getExplorerViewRecords, - db.TransactionCloseMode.Close - ) - console.log(`Indexing ${records.length} explorer views to Algolia`) - await index.replaceAllObjects(records) - console.log(`Indexing complete`) - } catch (e) { - console.error(e) - await logErrorAndMaybeSendToBugsnag({ - name: `IndexExplorerViewsToAlgoliaError`, - message: `${e}`, - }) - } + const records = await db.knexReadonlyTransaction( + getExplorerViewRecords, + db.TransactionCloseMode.Close + ) + console.log(`Indexing ${records.length} explorer views to Algolia`) + await index.replaceAllObjects(records) + console.log(`Indexing complete`) } process.on("unhandledRejection", (e) => { diff --git a/baker/algolia/utils/explorerViews.ts b/baker/algolia/utils/explorerViews.ts index 84c2037fd4f..f85241bea83 100644 --- a/baker/algolia/utils/explorerViews.ts +++ b/baker/algolia/utils/explorerViews.ts @@ -7,7 +7,7 @@ import { } from "@ourworldindata/explorer" import { at, get, groupBy, mapValues, orderBy, partition, uniq } from "lodash" import { MarkdownTextWrap } from "@ourworldindata/components" -import { logErrorAndMaybeSendToBugsnag } from "../../../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../../../serverUtils/errorLog.js" import { obtainAvailableEntitiesForGraphers } from "../../updateChartEntities.js" import { fetchS3MetadataByPath } from "../../../db/model/Variable.js" import { getVariableMetadataRoute } from "@ourworldindata/grapher" @@ -379,7 +379,7 @@ async function enrichRecordWithGrapherInfo( ): Promise { const grapher = grapherInfo[record.viewGrapherId] if (!grapher) { - await logErrorAndMaybeSendToBugsnag({ + await logErrorAndMaybeCaptureInSentry({ name: "ExplorerViewGrapherMissing", message: `Explorer with slug "${explorerInfo.slug}" has a view with a missing grapher: ${record.viewQueryParams}.`, }) @@ -433,7 +433,7 @@ async function enrichRecordWithTableData( ): Promise { const { tableSlug, ySlugs, viewTitle } = record if (!tableSlug || !ySlugs?.length || !viewTitle) { - await logErrorAndMaybeSendToBugsnag({ + await logErrorAndMaybeCaptureInSentry({ name: "ExplorerViewMissingData", message: `Explorer with slug "${record.explorerSlug}" has a view with missing data: ${record.viewQueryParams}.`, }) @@ -543,7 +543,7 @@ async function processAvailableEntities( record.availableEntities ) if (!availableEntities) { - await logErrorAndMaybeSendToBugsnag({ + await logErrorAndMaybeCaptureInSentry({ name: "ExplorerViewMissingData", message: `Explorer with slug "${record.explorerSlug}" has a view with missing entities: ${record.viewQueryParams}.`, }) @@ -703,7 +703,7 @@ async function getExplorersWithInheritedTags(trx: db.KnexReadonlyTransaction) { for (const explorer of Object.values(explorersBySlug)) { if (!explorer.tags.length) { - await logErrorAndMaybeSendToBugsnag({ + await logErrorAndMaybeCaptureInSentry({ name: "ExplorerTagMissing", message: `Explorer "${explorer.slug}" has no tags.`, }) diff --git a/baker/algolia/utils/pages.ts b/baker/algolia/utils/pages.ts index f9b16b1ce6b..8a68ee9d9a6 100644 --- a/baker/algolia/utils/pages.ts +++ b/baker/algolia/utils/pages.ts @@ -44,7 +44,7 @@ import { BAKED_BASE_URL, CLOUDFLARE_IMAGES_URL, } from "../../../settings/clientSettings.js" -import { logErrorAndMaybeSendToBugsnag } from "../../../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../../../serverUtils/errorLog.js" const computePageScore = (record: Omit): number => { const { importance, views_7d } = record @@ -176,7 +176,7 @@ const getThumbnailUrl = ( const cloudflareId = cloudflareImages[thumbnailFilename]?.cloudflareId if (!cloudflareId) { - void logErrorAndMaybeSendToBugsnag( + void logErrorAndMaybeCaptureInSentry( new Error( `Gdoc ${gdoc.id} has no cloudflare image with filename ${thumbnailFilename}` ) diff --git a/baker/pageOverrides.tsx b/baker/pageOverrides.tsx index 168a84766e4..5e8b2083ff2 100644 --- a/baker/pageOverrides.tsx +++ b/baker/pageOverrides.tsx @@ -1,9 +1,9 @@ import { PageOverrides } from "../site/LongFormPage.js" import { BAKED_BASE_URL } from "../settings/serverSettings.js" -import { urlToSlug, FullPost, JsonError } from "@ourworldindata/utils" +import { urlToSlug, FullPost } from "@ourworldindata/utils" import { FormattingOptions } from "@ourworldindata/types" import { getTopSubnavigationParentItem } from "../site/gdocs/utils.js" -import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../serverUtils/errorLog.js" import { getFullPostBySlugFromSnapshot, isPostSlugCitable, @@ -17,7 +17,7 @@ export const getPostBySlugLogToSlackNoThrow = async ( try { return await getFullPostBySlugFromSnapshot(knex, slug) } catch (err) { - void logErrorAndMaybeSendToBugsnag(err) + void logErrorAndMaybeCaptureInSentry(err) return undefined } } @@ -45,8 +45,8 @@ export const getLandingOnlyIfParent = async ( // todo: the concept of "citation overrides" does not belong to that // generic function. Logging this message should be the responsibility // of the caller function. - await logErrorAndMaybeSendToBugsnag( - new JsonError( + await logErrorAndMaybeCaptureInSentry( + new Error( // This error often shows up intermittently as a false-positive (DB unavailable when calling getPostBySlug()?) // If it happens systematically, please check // the href of the "subnavs[${formattingOptions.subnavId}]" diff --git a/baker/redirects.ts b/baker/redirects.ts index 3a897b2b15b..74e1cadba56 100644 --- a/baker/redirects.ts +++ b/baker/redirects.ts @@ -1,8 +1,8 @@ import * as db from "../db/db.js" -import { memoize, JsonError, Url } from "@ourworldindata/utils" +import { memoize, Url } from "@ourworldindata/utils" import { isCanonicalInternalUrl } from "./formatting.js" import { resolveExplorerRedirect } from "./replaceExplorerRedirects.js" -import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../serverUtils/errorLog.js" import { // deleteExpiredRedirects, getRedirectsFromDb, @@ -148,8 +148,8 @@ export const resolveRedirectFromMap = async ( const _resolveRedirectFromMap = async (url: Url): Promise => { ++recursionDepth if (recursionDepth > MAX_RECURSION_DEPTH) { - void logErrorAndMaybeSendToBugsnag( - new JsonError( + void logErrorAndMaybeCaptureInSentry( + new Error( `A circular redirect (/a -> /b -> /a) has been detected for ${originalUrl.pathname} and is ignored.` ) ) @@ -164,8 +164,8 @@ export const resolveRedirectFromMap = async ( const targetUrl = Url.fromURL(target) if (targetUrl.pathname === url.pathname) { - void logErrorAndMaybeSendToBugsnag( - new JsonError( + void logErrorAndMaybeCaptureInSentry( + new Error( `A self redirect (/a -> /a) has been detected for ${originalUrl.pathname} and is ignored.` ) ) diff --git a/baker/siteRenderers.tsx b/baker/siteRenderers.tsx index e53a9e3e521..811ce2f1964 100644 --- a/baker/siteRenderers.tsx +++ b/baker/siteRenderers.tsx @@ -92,7 +92,7 @@ import { isPostSlugCitable, } from "../db/model/Post.js" import { GdocPost } from "../db/model/Gdoc/GdocPost.js" -import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../serverUtils/errorLog.js" import { getAndLoadGdocBySlug, getAndLoadGdocById, @@ -250,12 +250,9 @@ export const renderFrontPage = async (knex: KnexReadonlyTransaction) => { await gdocHomepage.loadState(knex) return renderGdoc(gdocHomepage) } else { - await logErrorAndMaybeSendToBugsnag( - new JsonError( - `Failed to find homepage Gdoc with type "${OwidGdocType.Homepage}"` - ) + throw new Error( + `Failed to find homepage Gdoc with type "${OwidGdocType.Homepage}"` ) - return "" } } @@ -618,8 +615,8 @@ export const renderProminentLinks = async ( ).title) } finally { if (!title) { - void logErrorAndMaybeSendToBugsnag( - new JsonError( + void logErrorAndMaybeCaptureInSentry( + new Error( `No fallback title found for prominent link ${resolvedUrlString} in wordpress post with id ${containerPostId}. Block removed.` ) ) @@ -703,11 +700,11 @@ export const renderExplorerPage = async ( const { program: transformedProgram, unresolvedCatalogPaths } = transformResult if (unresolvedCatalogPaths?.size) { - const errMessage = new JsonError( + const errMessage = new Error( `${unresolvedCatalogPaths.size} catalog paths cannot be found for explorer ${transformedProgram.slug}: ${[...unresolvedCatalogPaths].join(", ")}.` ) if (opts?.isPreviewing) console.error(errMessage) - else void logErrorAndMaybeSendToBugsnag(errMessage) + else void logErrorAndMaybeCaptureInSentry(errMessage) } // This needs to run after transformExplorerProgramToResolveCatalogPaths, so that the catalog paths @@ -757,8 +754,8 @@ export const renderExplorerPage = async ( (id) => !partialGrapherConfigRows.find((row) => row.id === id) ) if (missingIds.length > 0) { - void logErrorAndMaybeSendToBugsnag( - new JsonError( + void logErrorAndMaybeCaptureInSentry( + new Error( `Referenced variable IDs do not exist in the database for explorer ${transformedProgram.slug}: ${missingIds.join(", ")}.` ) ) diff --git a/baker/startDeployQueueServer.ts b/baker/startDeployQueueServer.ts index 9ac3ebe606d..3d896c1eac4 100644 --- a/baker/startDeployQueueServer.ts +++ b/baker/startDeployQueueServer.ts @@ -1,9 +1,8 @@ +// This must be imported first for Sentry instrumentation to work. +import "../serverUtils/instrument.js" + import fs from "fs-extra" -import Bugsnag from "@bugsnag/js" -import { - DEPLOY_QUEUE_FILE_PATH, - BUGSNAG_NODE_API_KEY, -} from "../settings/serverSettings.js" +import { DEPLOY_QUEUE_FILE_PATH } from "../settings/serverSettings.js" import { deployIfQueueIsNotEmpty } from "./DeployUtils.js" import * as db from "../db/db.js" // Ensure db is cleaned up on PM2 stop / restart / reload and cmd/ctrl + c @@ -25,14 +24,6 @@ const main = async () => { process.exit(1) } - if (BUGSNAG_NODE_API_KEY) { - Bugsnag.start({ - apiKey: BUGSNAG_NODE_API_KEY, - context: "deploy-queue", - autoTrackSessions: false, - }) - } - // Listen for file changes fs.watchFile(DEPLOY_QUEUE_FILE_PATH, () => { // Start deploy after 10 seconds in order to avoid the quick successive diff --git a/explorerAdminClient/ExplorerCreatePage.tsx b/explorerAdminClient/ExplorerCreatePage.tsx index 73fb57da875..940b0d7d460 100644 --- a/explorerAdminClient/ExplorerCreatePage.tsx +++ b/explorerAdminClient/ExplorerCreatePage.tsx @@ -184,7 +184,7 @@ export class ExplorerCreatePage extends Component<{ @action.bound private async save() { let commitMessage - if (ENV === "production") { + if (ENV !== "development") { commitMessage = prompt( `Enter a message describing this change. Your change will be pushed to the '${this.props.gitCmsBranchName}' on GitHub.`, `Updated ${this.program.slug}` diff --git a/gitCms/GitCmsServer.ts b/gitCms/GitCmsServer.ts index 23b5253cd9d..7faf0444486 100644 --- a/gitCms/GitCmsServer.ts +++ b/gitCms/GitCmsServer.ts @@ -22,7 +22,7 @@ import { GIT_CMS_PULL_ROUTE, } from "./GitCmsConstants.js" import { sync } from "glob" -import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js" +import { logErrorAndMaybeCaptureInSentry } from "../serverUtils/errorLog.js" import _ from "lodash" // todo: cleanup typings @@ -188,8 +188,6 @@ export class GitCmsServer { // eslint-disable-next-line no-console console.log(`Deleted ${filepath}`) - // do not push in dev - // XXX: we should not push in staging either! if (ENV === "production") { await this.commitFile( filepath, @@ -203,7 +201,7 @@ export class GitCmsServer { return { success: true } } catch (error) { const err = error as Error - void logErrorAndMaybeSendToBugsnag(err) + void logErrorAndMaybeCaptureInSentry(err) return { success: false, error: err.toString() } } } @@ -227,8 +225,6 @@ export class GitCmsServer { const pull = await this.autopull() if (!pull.success) throw pull.error - // do not push in dev - // XXX: we should not push in staging either! if (ENV === "production") { const commitMsg = commitMessage ? commitMessage @@ -247,7 +243,7 @@ export class GitCmsServer { return { success: true } } catch (error) { const err = error as Error - void logErrorAndMaybeSendToBugsnag(err) + void logErrorAndMaybeCaptureInSentry(err) return { success: false, error: err.toString() } } } diff --git a/package.json b/package.json index 56208e9e7e3..fb6d3a9a820 100644 --- a/package.json +++ b/package.json @@ -50,10 +50,6 @@ "@algolia/autocomplete-plugin-recent-searches": "^1.17.2", "@algolia/autocomplete-theme-classic": "^1.17.2", "@aws-sdk/client-s3": "^3.626.0", - "@bugsnag/core": "^8.0.0", - "@bugsnag/js": "^8.0.0", - "@bugsnag/plugin-express": "^8.0.0", - "@bugsnag/plugin-react": "^8.0.0", "@dnd-kit/core": "^6.1.0", "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-brands-svg-icons": "^6.5.2", @@ -67,7 +63,10 @@ "@ourworldindata/types": "workspace:^", "@ourworldindata/utils": "workspace:^", "@react-awesome-query-builder/antd": "^6.6.0", - "@sentry/react": "^8.36.0", + "@sentry/node": "^8.48.0", + "@sentry/profiling-node": "^8.48.0", + "@sentry/react": "^8.48.0", + "@sentry/vite-plugin": "^2.23.0", "@sinclair/typebox": "^0.28.5", "@slack/web-api": "^7.1.0", "@tippyjs/react": "^4.2.6", diff --git a/packages/@ourworldindata/explorer/package.json b/packages/@ourworldindata/explorer/package.json index 524449cd8ac..9bffccdc235 100644 --- a/packages/@ourworldindata/explorer/package.json +++ b/packages/@ourworldindata/explorer/package.json @@ -19,9 +19,6 @@ "keywords": [], "author": "", "dependencies": { - "@bugsnag/core": "^8.0.0", - "@bugsnag/js": "^8.0.0", - "@bugsnag/plugin-react": "^8.0.0", "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-brands-svg-icons": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", diff --git a/packages/@ourworldindata/explorer/src/Explorer.tsx b/packages/@ourworldindata/explorer/src/Explorer.tsx index 8a9b232f4ba..8a86d8aa098 100644 --- a/packages/@ourworldindata/explorer/src/Explorer.tsx +++ b/packages/@ourworldindata/explorer/src/Explorer.tsx @@ -76,7 +76,6 @@ import { explorerUrlMigrationsById, migrateExplorerUrl, } from "./urlMigrations/ExplorerUrlMigrations.js" -import Bugsnag from "@bugsnag/js" export interface ExplorerProps extends SerializedGridProgram { grapherConfigs?: GrapherInterface[] @@ -385,7 +384,6 @@ export class Explorer console.warn( "ResizeObserver not available; the explorer will not be responsive to window resizes" ) - Bugsnag?.notify("ResizeObserver not available") this.onResize() // fire once to initialize, at least } diff --git a/packages/@ourworldindata/grapher/package.json b/packages/@ourworldindata/grapher/package.json index 93122fac45b..6316de83513 100644 --- a/packages/@ourworldindata/grapher/package.json +++ b/packages/@ourworldindata/grapher/package.json @@ -19,9 +19,6 @@ "keywords": [], "author": "", "dependencies": { - "@bugsnag/core": "^8.0.0", - "@bugsnag/js": "^8.0.0", - "@bugsnag/plugin-react": "^8.0.0", "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-brands-svg-icons": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", @@ -30,6 +27,7 @@ "@ourworldindata/core-table": "workspace:^", "@ourworldindata/types": "workspace:^", "@ourworldindata/utils": "workspace:^", + "@sentry/react": "^8.48.0", "@tippyjs/react": "^4.2.6", "classnames": "^2.5.1", "colorbrewer": "^1.3.0", diff --git a/packages/@ourworldindata/grapher/src/core/Grapher.tsx b/packages/@ourworldindata/grapher/src/core/Grapher.tsx index 94407af5a90..630a3de7af2 100644 --- a/packages/@ourworldindata/grapher/src/core/Grapher.tsx +++ b/packages/@ourworldindata/grapher/src/core/Grapher.tsx @@ -1,5 +1,6 @@ import React from "react" import ReactDOMServer from "react-dom/server.js" +import * as Sentry from "@sentry/react" import { observable, computed, @@ -205,7 +206,6 @@ import { GrapherAnalytics } from "./GrapherAnalytics" import { legacyToCurrentGrapherQueryParams } from "./GrapherUrlMigrations" import { ChartInterface, ChartTableTransformer } from "../chart/ChartInterface" import { MarimekkoChartManager } from "../stackedCharts/MarimekkoChartConstants" -import Bugsnag from "@bugsnag/js" import { FacetChartManager } from "../facetChart/FacetChartConstants" import { StaticChartRasterizer, @@ -1095,41 +1095,27 @@ export class Grapher // No data to download return - try { - let variablesDataMap: MultipleOwidVariableDataDimensionsMap - - const startMark = performance.now() - if (this.useAdminAPI) { - // TODO grapher model: switch this to downloading multiple data and metadata files - variablesDataMap = await loadVariablesDataAdmin( - this.dataApiUrlForAdmin, - this.variableIds - ) - } else { - variablesDataMap = await loadVariablesDataSite( - this.variableIds, - this.dataApiUrl - ) - } - this.createPerformanceMeasurement( - "downloadVariablesData", - startMark - ) + let variablesDataMap: MultipleOwidVariableDataDimensionsMap - this._receiveOwidDataAndApplySelection( - variablesDataMap, - inputTableTransformer + const startMark = performance.now() + if (this.useAdminAPI) { + // TODO grapher model: switch this to downloading multiple data and metadata files + variablesDataMap = await loadVariablesDataAdmin( + this.dataApiUrlForAdmin, + this.variableIds + ) + } else { + variablesDataMap = await loadVariablesDataSite( + this.variableIds, + this.dataApiUrl ) - } catch (err) { - // eslint-disable-next-line no-console - console.log(`Error fetching '${err}'`) - console.error(err) - Bugsnag?.notify(`Error fetching variables: ${err}`, (event) => { - event.addMetadata("context", { - variableIds: this.variableIds, - }) - }) } + this.createPerformanceMeasurement("downloadVariablesData", startMark) + + this._receiveOwidDataAndApplySelection( + variablesDataMap, + inputTableTransformer + ) } @action.bound receiveOwidData( @@ -2339,13 +2325,6 @@ export class Grapher ): React.RefObject { const grapherInstanceRef = React.createRef() - let ErrorBoundary = React.Fragment as React.ComponentType // use React.Fragment as a sort of default error boundary if Bugsnag is not available - if (Bugsnag && (Bugsnag as any)._client) { - ErrorBoundary = - Bugsnag.getPlugin("react")?.createErrorBoundary(React) ?? - React.Fragment - } - const setBoundsFromContainerAndRender = ( entries: ResizeObserverEntry[] ): void => { @@ -2364,9 +2343,9 @@ export class Grapher bounds: Bounds.fromRect(entry.contentRect), } ReactDOM.render( - + - , + , containerNode ) } @@ -2388,7 +2367,6 @@ export class Grapher console.warn( "ResizeObserver not available; grapher will not be able to render" ) - Bugsnag?.notify("ResizeObserver not available") } return grapherInstanceRef diff --git a/serverUtils/errorLog.ts b/serverUtils/errorLog.ts index 09d94d612cc..c1bbd49e296 100644 --- a/serverUtils/errorLog.ts +++ b/serverUtils/errorLog.ts @@ -1,20 +1,6 @@ -import Bugsnag from "@bugsnag/js" +import * as Sentry from "@sentry/react" -export const logErrorAndMaybeSendToBugsnag = async ( - err: any, - req?: any, - // Sometimes Bugsnag's default grouping algorithm gets it wrong (e.g. all SiteBaker errors get grouped together). - // Set a hash here to ensure that errors with the same hash will be grouped together / excluded from group they would otherwise be in. - groupingHash?: string -) => { +export async function logErrorAndMaybeCaptureInSentry(err: any) { console.error(err) - if (req) { - req.bugsnag.notify(err) - } else { - Bugsnag.notify(err, (event) => { - if (groupingHash) event.groupingHash = groupingHash - }) - } + Sentry.captureException(err) } - -export const warn = (err: any) => console.warn(err) diff --git a/serverUtils/instrument.ts b/serverUtils/instrument.ts new file mode 100644 index 00000000000..88db481e140 --- /dev/null +++ b/serverUtils/instrument.ts @@ -0,0 +1,19 @@ +import dotenv from "dotenv" +import * as Sentry from "@sentry/node" +import { nodeProfilingIntegration } from "@sentry/profiling-node" +import findBaseDir from "../settings/findBaseDir.js" + +const baseDir = findBaseDir(__dirname) +if (baseDir === undefined) throw new Error("could not locate base package.json") + +dotenv.config({ path: `${baseDir}/.env` }) + +// Ensure to call this before importing any other modules! +Sentry.init({ + dsn: process.env.SENTRY_ADMIN_DSN, + integrations: [nodeProfilingIntegration()], + tracesSampleRate: 0.1, + profilesSampleRate: 1.0, // This is relative to tracesSampleRate + environment: process.env.ENV, + release: process.env.COMMIT_SHA, +}) diff --git a/settings/clientSettings.ts b/settings/clientSettings.ts index 318caa166ee..94082fce24a 100644 --- a/settings/clientSettings.ts +++ b/settings/clientSettings.ts @@ -15,11 +15,13 @@ if (typeof __dirname !== "undefined") { import { parseIntOrUndefined } from "@ourworldindata/utils" -export const ENV: "development" | "production" = - process.env.ENV === "production" ? "production" : "development" +type Environment = "development" | "staging" | "production" +export const ENV: Environment = + (process.env.ENV as Environment) || "development" +export const COMMIT_SHA = process.env.COMMIT_SHA -export const BUGSNAG_API_KEY: string | undefined = process.env.BUGSNAG_API_KEY export const SENTRY_DSN: string | undefined = process.env.SENTRY_DSN +export const SENTRY_ADMIN_DSN: string | undefined = process.env.SENTRY_ADMIN_DSN export const ADMIN_SERVER_PORT: number = parseIntOrUndefined(process.env.ADMIN_SERVER_PORT) ?? 3030 export const ADMIN_SERVER_HOST: string = diff --git a/settings/serverSettings.ts b/settings/serverSettings.ts index 1b84d363d2e..bd61898dddd 100644 --- a/settings/serverSettings.ts +++ b/settings/serverSettings.ts @@ -19,7 +19,7 @@ import { parseIntOrUndefined } from "@ourworldindata/utils" const serverSettings = process.env ?? {} export const BASE_DIR: string = baseDir -export const ENV: "development" | "production" = clientSettings.ENV +export const ENV = clientSettings.ENV export const ADMIN_SERVER_PORT: number = clientSettings.ADMIN_SERVER_PORT export const ADMIN_SERVER_HOST: string = clientSettings.ADMIN_SERVER_HOST @@ -44,11 +44,6 @@ export const GIT_DEFAULT_USERNAME: string = export const GIT_DEFAULT_EMAIL: string = serverSettings.GIT_DEFAULT_EMAIL ?? "info@ourworldindata.org" -export const BUGSNAG_API_KEY: string | undefined = - serverSettings.BUGSNAG_API_KEY -export const BUGSNAG_NODE_API_KEY: string | undefined = - serverSettings.BUGSNAG_NODE_API_KEY - export const BLOG_POSTS_PER_PAGE: number = parseIntOrUndefined(serverSettings.BLOG_POSTS_PER_PAGE) ?? 21 export const BLOG_SLUG: string = serverSettings.BLOG_SLUG ?? "latest" diff --git a/site/DataCatalog/DataCatalog.tsx b/site/DataCatalog/DataCatalog.tsx index a2b5738a1c4..5e7e2889849 100644 --- a/site/DataCatalog/DataCatalog.tsx +++ b/site/DataCatalog/DataCatalog.tsx @@ -63,7 +63,6 @@ import { TOUCH_DEVICE_MEDIA_QUERY, } from "../SiteConstants.js" import { SiteAnalytics } from "../SiteAnalytics.js" -import Bugsnag from "@bugsnag/js" const analytics = new SiteAnalytics() @@ -871,9 +870,7 @@ export const DataCatalog = ({ if (cache[cacheKey].has(stateAsUrl)) return setIsLoading(true) - fetchData() - .catch(Bugsnag.notify) - .finally(() => setIsLoading(false)) + void fetchData().then(() => setIsLoading(false)) return () => setIsLoading(false) }, [ state, diff --git a/site/DonateForm.tsx b/site/DonateForm.tsx index a914fee14e8..5f05d1eaf85 100644 --- a/site/DonateForm.tsx +++ b/site/DonateForm.tsx @@ -1,5 +1,6 @@ import * as React from "react" import ReactDOM from "react-dom" +import * as Sentry from "@sentry/react" import cx from "classnames" import { observable, action, computed } from "mobx" import { observer } from "mobx-react" @@ -26,7 +27,6 @@ import { import { Checkbox } from "@ourworldindata/components" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome/index.js" import { faArrowRight, faInfoCircle } from "@fortawesome/free-solid-svg-icons" -import Bugsnag from "@bugsnag/js" import { SiteAnalytics } from "./SiteAnalytics.js" const ONETIME_DONATION_AMOUNTS = [20, 50, 100, 500, 1000] @@ -203,14 +203,14 @@ export class DonateForm extends React.Component { this.setIsSubmitting(false) const prefixedErrorMessage = stringifyUnknownError(error) - // Send all errors to Bugsnag. This will help surface issues + // Send all errors to Sentry. This will help surface issues // with our aging reCAPTCHA setup, and pull the trigger on a // (hook-based?) rewrite if it starts failing. This reporting // also includes form validation errors, which are useful to // identify possible UX improvements or validate UX experiments // (such as the combination of the name field and the "include // my name on the list" checkbox). - Bugsnag.notify( + Sentry.captureException( error instanceof Error ? error : new Error(prefixedErrorMessage) ) diff --git a/site/hacks.ts b/site/hacks.ts index 873bf1ba886..3b63c75c8f9 100644 --- a/site/hacks.ts +++ b/site/hacks.ts @@ -1,4 +1,4 @@ -import Bugsnag from "@bugsnag/js" +import * as Sentry from "@sentry/react" /** * React and the browser-integrated Google Translate don't love each other: @@ -30,13 +30,13 @@ export const runMonkeyPatchForGoogleTranslate = (): void => { child, this ) - Bugsnag?.notify( + Sentry.captureMessage( "removeChild: Cannot remove a child from a different parent", - (event) => { - event.addMetadata("context", { + { + extra: { child: nodeToString(child), this: nodeToString(this), - }) + }, } ) return child @@ -55,13 +55,13 @@ export const runMonkeyPatchForGoogleTranslate = (): void => { referenceNode, this ) - Bugsnag?.notify( + Sentry.captureMessage( "insertBefore: Cannot insert before a reference node from a different parent", - (event) => { - event.addMetadata("context", { + { + extra: { child: nodeToString(referenceNode), this: nodeToString(this as Element), - }) + }, } ) return newNode diff --git a/site/instrument.ts b/site/instrument.ts new file mode 100644 index 00000000000..b8a7f57709d --- /dev/null +++ b/site/instrument.ts @@ -0,0 +1,35 @@ +import * as Sentry from "@sentry/react" +import { isInIFrame } from "@ourworldindata/utils" +import { getPreferenceValue, PreferenceType } from "./cookiePreferences.js" + +const analyticsConsent = getPreferenceValue(PreferenceType.Analytics) +const environment = process.env.ENV || "development" + +let sentryOpts: Sentry.BrowserOptions +if (analyticsConsent && !isInIFrame()) { + // only collect session replays from: users that have consented to analytics + // AND where page isn't embedded in an iframe + sentryOpts = { + integrations: [ + Sentry.replayIntegration({ + maskAllText: false, + maskAllInputs: false, + blockAllMedia: false, + mask: [".sentry-mask"], + }), + ], + replaysSessionSampleRate: environment === "development" ? 1 : 0.1, + replaysOnErrorSampleRate: 0, + } +} else { + sentryOpts = { + replaysSessionSampleRate: 0, + replaysOnErrorSampleRate: 0, + } +} +Sentry.init({ + dsn: process.env.SENTRY_DSN, + environment, + release: process.env.COMMIT_SHA, + ...sentryOpts, +}) diff --git a/site/multiembedder/MultiEmbedder.tsx b/site/multiembedder/MultiEmbedder.tsx index 45a41a03948..92b61fb7de3 100644 --- a/site/multiembedder/MultiEmbedder.tsx +++ b/site/multiembedder/MultiEmbedder.tsx @@ -39,7 +39,6 @@ import { GRAPHER_DYNAMIC_CONFIG_URL, MULTI_DIM_DYNAMIC_CONFIG_URL, } from "../../settings/clientSettings.js" -import Bugsnag from "@bugsnag/js" import { embedDynamicCollectionGrapher } from "../collections/DynamicCollection.js" const figuresFromDOM = ( @@ -86,7 +85,6 @@ class MultiEmbedder { console.warn( "IntersectionObserver not available; interactive embeds won't load on this page" ) - Bugsnag?.notify("IntersectionObserver not available") } } diff --git a/site/owid.entry.ts b/site/owid.entry.ts index babcee3dd45..bd2798e0ef9 100644 --- a/site/owid.entry.ts +++ b/site/owid.entry.ts @@ -1,3 +1,7 @@ +// This should be imported as early as possible so the global error handler is +// set up before any errors are thrown. +import "./instrument.js" + import "@ourworldindata/grapher/src/core/grapher.scss" import "./owid.scss" // From https://fontawesome.com/how-to-use/on-the-web/other-topics/server-side-rendering: @@ -12,23 +16,13 @@ import { runDonateForm } from "./DonateForm.js" import { runCountryProfilePage } from "./runCountryProfilePage.js" import { runTableOfContents } from "./runTableOfContents.js" import { Explorer } from "@ourworldindata/explorer" -import { - ENV, - BUGSNAG_API_KEY, - ADMIN_BASE_URL, - SENTRY_DSN, -} from "../settings/clientSettings.js" +import { ENV, ADMIN_BASE_URL } from "../settings/clientSettings.js" import { Grapher, CookieKey } from "@ourworldindata/grapher" import { MultiEmbedderSingleton } from "../site/multiembedder/MultiEmbedder.js" import { CoreTable } from "@ourworldindata/core-table" -import { isInIFrame } from "@ourworldindata/utils" import { SiteAnalytics } from "./SiteAnalytics.js" -import Bugsnag, { BrowserConfig } from "@bugsnag/js" -import BugsnagPluginReact from "@bugsnag/plugin-react" -import * as Sentry from "@sentry/react" import { runMonkeyPatchForGoogleTranslate } from "./hacks.js" import { runSiteFooterScripts } from "./runSiteFooterScripts.js" -import { PreferenceType, getPreferenceValue } from "./cookiePreferences.js" declare let window: any window.Grapher = Grapher @@ -47,78 +41,6 @@ window.runSiteFooterScripts = runSiteFooterScripts runMonkeyPatchForGoogleTranslate() -if (BUGSNAG_API_KEY) { - try { - const analyticsConsent = getPreferenceValue(PreferenceType.Analytics) - - let bugsnagUserInformation: Pick< - BrowserConfig, - "generateAnonymousId" | "user" - > - if (analyticsConsent) { - bugsnagUserInformation = { - generateAnonymousId: true, // gets saved to localStorage, which we only want if the user has consented to analytics - } - } else { - bugsnagUserInformation = { - generateAnonymousId: false, - user: { - // generates a random 10-character string - // we use it so we can at least identify multiple errors from the same user on a single page, albeit not across pages - id: Math.random().toString(36).substring(2, 12), - }, - } - } - - Bugsnag.start({ - apiKey: BUGSNAG_API_KEY, - plugins: [new BugsnagPluginReact()], - autoTrackSessions: false, - collectUserIp: false, - ...bugsnagUserInformation, - }) - } catch { - console.error("Failed to initialize Bugsnag") - } -} - -if (SENTRY_DSN) { - try { - const analyticsConsent = getPreferenceValue(PreferenceType.Analytics) - - let sentryOpts: Sentry.BrowserOptions - if (analyticsConsent && !isInIFrame()) { - // only collect session replays from: users that have consented to analytics - // AND where page isn't embedded in an iframe - sentryOpts = { - integrations: [ - Sentry.replayIntegration({ - maskAllText: false, - maskAllInputs: false, - blockAllMedia: false, - mask: [".sentry-mask"], - }), - ], - replaysSessionSampleRate: ENV === "development" ? 1 : 0.1, - replaysOnErrorSampleRate: 0, - } - } else { - sentryOpts = { - replaysSessionSampleRate: 0, - replaysOnErrorSampleRate: 0, - } - } - Sentry.init({ - dsn: SENTRY_DSN, - debug: ENV === "development", - environment: ENV, - ...sentryOpts, - }) - } catch { - console.error("Failed to initialize Sentry") - } -} - const analytics = new SiteAnalytics(ENV) document.documentElement?.classList.add("js-loaded") diff --git a/site/viteUtils.tsx b/site/viteUtils.tsx index 5cb4c259247..0f04377d295 100644 --- a/site/viteUtils.tsx +++ b/site/viteUtils.tsx @@ -194,7 +194,7 @@ const prodAssets = (entrypoint: ViteEntryPoint, baseUrl: string): Assets => { } } -const useProductionAssets = ENV === "production" || VITE_PREVIEW +const useProductionAssets = ENV !== "development" || VITE_PREVIEW const viteAssets = (entrypoint: ViteEntryPoint, prodBaseUrl?: string) => useProductionAssets diff --git a/vite.config-common.mts b/vite.config-common.mts index 2e51f842202..6f7b1cf93d9 100644 --- a/vite.config-common.mts +++ b/vite.config-common.mts @@ -1,6 +1,7 @@ import { defineConfig } from "vite" import pluginReact from "@vitejs/plugin-react" import pluginChecker from "vite-plugin-checker" +import { sentryVitePlugin } from "@sentry/vite-plugin" import * as clientSettings from "./settings/clientSettings.js" import { VITE_ASSET_SITE_ENTRY, @@ -34,7 +35,7 @@ export const defineViteConfigForEntrypoint = (entrypoint: ViteEntryPoint) => { devSourcemap: true, }, define: { - // Replace all clientSettings with their respective values, i.e. assign e.g. BUGSNAG_API_KEY to process.env.BUGSNAG_API_KEY + // Replace all clientSettings with their respective values, i.e. assign e.g. EXAMPLE_ENV_VAR to process.env.EXAMPLE_ENV_VAR // it's important to note that we only expose values that are present in the clientSettings file - not any other things that are stored in .env ...Object.fromEntries( Object.entries(clientSettings).map(([key, value]) => [ @@ -73,6 +74,12 @@ export const defineViteConfigForEntrypoint = (entrypoint: ViteEntryPoint) => { tsconfigPath: "tsconfig.vite-checker.json", }, }), + // Put the Sentry vite plugin after all other plugins. + sentryVitePlugin({ + authToken: process.env.SENTRY_AUTH_TOKEN, + org: process.env.SENTRY_ORG, + project: entrypoint === "admin" ? "admin" : "website", + }), ], server: { port: 8090, diff --git a/yarn.lock b/yarn.lock index 754e95b69dc..93aa7a45125 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1019,6 +1019,17 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0, @babel/code-frame@npm:^7.26.2": + version: 7.26.2 + resolution: "@babel/code-frame@npm:7.26.2" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.25.9" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10/db2c2122af79d31ca916755331bb4bac96feb2b334cdaca5097a6b467fdd41963b89b14b6836a14f083de7ff887fc78fa1b3c10b14e743d33e12dbfe5ee3d223 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.24.8": version: 7.24.9 resolution: "@babel/compat-data@npm:7.24.9" @@ -1026,6 +1037,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/compat-data@npm:7.26.5" + checksum: 10/afe35751f27bda80390fa221d5e37be55b7fc42cec80de9896086e20394f2306936c4296fcb4d62b683e3b49ba2934661ea7e06196ca2dacdc2e779fbea4a1a9 + languageName: node + linkType: hard + "@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.24.5": version: 7.24.9 resolution: "@babel/core@npm:7.24.9" @@ -1049,6 +1067,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.18.5": + version: 7.26.0 + resolution: "@babel/core@npm:7.26.0" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.26.0" + "@babel/generator": "npm:^7.26.0" + "@babel/helper-compilation-targets": "npm:^7.25.9" + "@babel/helper-module-transforms": "npm:^7.26.0" + "@babel/helpers": "npm:^7.26.0" + "@babel/parser": "npm:^7.26.0" + "@babel/template": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.26.0" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10/65767bfdb1f02e80d3af4f138066670ef8fdd12293de85ef151758a901c191c797e86d2e99b11c4cdfca33c72385ecaf38bbd7fa692791ec44c77763496b9b93 + languageName: node + linkType: hard + "@babel/generator@npm:^7.24.8, @babel/generator@npm:^7.24.9, @babel/generator@npm:^7.7.2": version: 7.24.10 resolution: "@babel/generator@npm:7.24.10" @@ -1061,6 +1102,19 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.26.0, @babel/generator@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/generator@npm:7.26.5" + dependencies: + "@babel/parser": "npm:^7.26.5" + "@babel/types": "npm:^7.26.5" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^3.0.2" + checksum: 10/aa5f176155431d1fb541ca11a7deddec0fc021f20992ced17dc2f688a0a9584e4ff4280f92e8a39302627345cd325762f70f032764806c579c6fd69432542bcb + languageName: node + linkType: hard + "@babel/helper-compilation-targets@npm:^7.24.8": version: 7.24.8 resolution: "@babel/helper-compilation-targets@npm:7.24.8" @@ -1074,6 +1128,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.25.9": + version: 7.26.5 + resolution: "@babel/helper-compilation-targets@npm:7.26.5" + dependencies: + "@babel/compat-data": "npm:^7.26.5" + "@babel/helper-validator-option": "npm:^7.25.9" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10/f3b5f0bfcd7b6adf03be1a494b269782531c6e415afab2b958c077d570371cf1bfe001c442508092c50ed3711475f244c05b8f04457d8dea9c34df2b741522bf + languageName: node + linkType: hard + "@babel/helper-environment-visitor@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-environment-visitor@npm:7.24.7" @@ -1112,6 +1179,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-module-imports@npm:7.25.9" + dependencies: + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10/e090be5dee94dda6cd769972231b21ddfae988acd76b703a480ac0c96f3334557d70a965bf41245d6ee43891e7571a8b400ccf2b2be5803351375d0f4e5bcf08 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.24.9": version: 7.24.9 resolution: "@babel/helper-module-transforms@npm:7.24.9" @@ -1127,6 +1204,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helper-module-transforms@npm:7.26.0" + dependencies: + "@babel/helper-module-imports": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/9841d2a62f61ad52b66a72d08264f23052d533afc4ce07aec2a6202adac0bfe43014c312f94feacb3291f4c5aafe681955610041ece2c276271adce3f570f2f5 + languageName: node + linkType: hard + "@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.17.12, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.8.0": version: 7.24.8 resolution: "@babel/helper-plugin-utils@npm:7.24.8" @@ -1160,6 +1250,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-string-parser@npm:7.25.9" + checksum: 10/c28656c52bd48e8c1d9f3e8e68ecafd09d949c57755b0d353739eb4eae7ba4f7e67e92e4036f1cd43378cc1397a2c943ed7bcaf5949b04ab48607def0258b775 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-validator-identifier@npm:7.24.7" @@ -1167,6 +1264,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-identifier@npm:7.25.9" + checksum: 10/3f9b649be0c2fd457fa1957b694b4e69532a668866b8a0d81eabfa34ba16dbf3107b39e0e7144c55c3c652bf773ec816af8df4a61273a2bb4eb3145ca9cf478e + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.24.8": version: 7.24.8 resolution: "@babel/helper-validator-option@npm:7.24.8" @@ -1174,6 +1278,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-option@npm:7.25.9" + checksum: 10/9491b2755948ebbdd68f87da907283698e663b5af2d2b1b02a2765761974b1120d5d8d49e9175b167f16f72748ffceec8c9cf62acfbee73f4904507b246e2b3d + languageName: node + linkType: hard + "@babel/helpers@npm:^7.24.8": version: 7.24.8 resolution: "@babel/helpers@npm:7.24.8" @@ -1184,6 +1295,16 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helpers@npm:7.26.0" + dependencies: + "@babel/template": "npm:^7.25.9" + "@babel/types": "npm:^7.26.0" + checksum: 10/fd4757f65d10b64cfdbf4b3adb7ea6ffff9497c53e0786452f495d1f7794da7e0898261b4db65e1c62bbb9a360d7d78a1085635c23dfc3af2ab6dcba06585f86 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.24.7": version: 7.24.7 resolution: "@babel/highlight@npm:7.24.7" @@ -1205,6 +1326,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/parser@npm:7.26.5" + dependencies: + "@babel/types": "npm:^7.26.5" + bin: + parser: ./bin/babel-parser.js + checksum: 10/d92097066e3e26625a485149f54c27899e4d94d7ef2f76d8fc9de2019212e7951940a31c0003f26ccad22e664f89ff51e5d5fe80a11eafaaec2420655010533c + languageName: node + linkType: hard + "@babel/plugin-syntax-async-generators@npm:^7.8.4": version: 7.8.4 resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" @@ -1401,6 +1533,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/template@npm:7.25.9" + dependencies: + "@babel/code-frame": "npm:^7.25.9" + "@babel/parser": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10/e861180881507210150c1335ad94aff80fd9e9be6202e1efa752059c93224e2d5310186ddcdd4c0f0b0fc658ce48cb47823f15142b5c00c8456dde54f5de80b2 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8": version: 7.24.8 resolution: "@babel/traverse@npm:7.24.8" @@ -1419,6 +1562,21 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.25.9": + version: 7.26.5 + resolution: "@babel/traverse@npm:7.26.5" + dependencies: + "@babel/code-frame": "npm:^7.26.2" + "@babel/generator": "npm:^7.26.5" + "@babel/parser": "npm:^7.26.5" + "@babel/template": "npm:^7.25.9" + "@babel/types": "npm:^7.26.5" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10/b0131159450e3cd4208354cdea57e832e1a344fcc284b6ac84d1e13567a10501c4747bfd0ce637d2bd02277526b49372cfca71edd5c825cea74dcc9f52bb9225 + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.24.9, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": version: 7.24.9 resolution: "@babel/types@npm:7.24.9" @@ -1430,91 +1588,20 @@ __metadata: languageName: node linkType: hard -"@bcoe/v8-coverage@npm:^0.2.3": - version: 0.2.3 - resolution: "@bcoe/v8-coverage@npm:0.2.3" - checksum: 10/1a1f0e356a3bb30b5f1ced6f79c413e6ebacf130421f15fac5fcd8be5ddf98aedb4404d7f5624e3285b700e041f9ef938321f3ca4d359d5b716f96afa120d88d - languageName: node - linkType: hard - -"@bugsnag/browser@npm:^8.0.0": - version: 8.0.0 - resolution: "@bugsnag/browser@npm:8.0.0" - dependencies: - "@bugsnag/core": "npm:^8.0.0" - checksum: 10/f8ae2c41d0892b1a3b53dc34c65d43e4936f9770a19810d9b290cb2754ccf690a88e65b2882cbb7dba6d41b59d513321c516b005b3523955ffec8228cff00016 - languageName: node - linkType: hard - -"@bugsnag/core@npm:^8.0.0": - version: 8.0.0 - resolution: "@bugsnag/core@npm:8.0.0" +"@babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/types@npm:7.26.5" dependencies: - "@bugsnag/cuid": "npm:^3.0.0" - "@bugsnag/safe-json-stringify": "npm:^6.0.0" - error-stack-parser: "npm:^2.0.3" - iserror: "npm:0.0.2" - stack-generator: "npm:^2.0.3" - checksum: 10/69c0ad04156fa87dcb73ee53c38e0cb58e452d94764000ce4dc92cb4c5ed8fd1009795951950a85657b8271d723d2fc681040d20667a98991b007d06aa9226d9 + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10/148f6bead7bc39371176ba681873c930087503a8bfd2b0dab5090de32752241806c95f4e87cee8b2976bb0277c6cbc150f16c333fc90269634b711d3711c0f18 languageName: node linkType: hard -"@bugsnag/cuid@npm:^3.0.0": - version: 3.0.2 - resolution: "@bugsnag/cuid@npm:3.0.2" - checksum: 10/b0b45edd8c9c3d98c010ff38ccaba06466821bbda8467e1eb4dd30cd7733afbbf40c95264bd7086de60ed11953ef67dc24cda339a3d3d4f83f2643a0c1e8382e - languageName: node - linkType: hard - -"@bugsnag/js@npm:^8.0.0": - version: 8.0.0 - resolution: "@bugsnag/js@npm:8.0.0" - dependencies: - "@bugsnag/browser": "npm:^8.0.0" - "@bugsnag/node": "npm:^8.0.0" - checksum: 10/b6b9b98f5c7a05ebde081e95f8fce98a4f08773313d94d40907390c282cfbfa10c7dac7e7b47c84022a3dd670cf139f0c0e77df44bf72d029b747d1ca8b37a56 - languageName: node - linkType: hard - -"@bugsnag/node@npm:^8.0.0": - version: 8.0.0 - resolution: "@bugsnag/node@npm:8.0.0" - dependencies: - "@bugsnag/core": "npm:^8.0.0" - byline: "npm:^5.0.0" - error-stack-parser: "npm:^2.0.2" - iserror: "npm:^0.0.2" - pump: "npm:^3.0.0" - stack-generator: "npm:^2.0.3" - checksum: 10/c260414807b0231a90e07941bc718f3026f366d5130ba713f447bf8b08682e6c2edfaaa09d197662b7fb834add58064ef26cdf2fc4bec2e9bff80b598fe051f6 - languageName: node - linkType: hard - -"@bugsnag/plugin-express@npm:^8.0.0": - version: 8.0.0 - resolution: "@bugsnag/plugin-express@npm:8.0.0" - peerDependencies: - "@bugsnag/core": ^8.0.0-alpha.1 - checksum: 10/7aff1cb28f8afe77ee1d80f3024086d2a3bff08a9ead6b1998d032d98f85ac61622b5da52276dc83c8ff2f926d09aa9aa5af0c469b403782c7fb468de597f2bb - languageName: node - linkType: hard - -"@bugsnag/plugin-react@npm:^8.0.0": - version: 8.0.0 - resolution: "@bugsnag/plugin-react@npm:8.0.0" - peerDependencies: - "@bugsnag/core": ^8.0.0-alpha.1 - peerDependenciesMeta: - "@bugsnag/core": - optional: true - checksum: 10/908f6dcdbacdb6677d3a22fb6e7546aa95a51e876e2a8c7239f540f734417e1654e8a2bcfd7bed9d9eeb15023e69b49427ed38746608fc8de7d9121cc371fefb - languageName: node - linkType: hard - -"@bugsnag/safe-json-stringify@npm:^6.0.0": - version: 6.0.0 - resolution: "@bugsnag/safe-json-stringify@npm:6.0.0" - checksum: 10/74f5d96af5f2f14be038ff939093329cdc6b3cc94eca6ce5ecd9e66a6d30819bcfd22f99c0ff229de56c0ef601cbca292f86ef5c9940ed2692bc9e005ac1f261 +"@bcoe/v8-coverage@npm:^0.2.3": + version: 0.2.3 + resolution: "@bcoe/v8-coverage@npm:0.2.3" + checksum: 10/1a1f0e356a3bb30b5f1ced6f79c413e6ebacf130421f15fac5fcd8be5ddf98aedb4404d7f5624e3285b700e041f9ef938321f3ca4d359d5b716f96afa120d88d languageName: node linkType: hard @@ -2861,6 +2948,13 @@ __metadata: languageName: node linkType: hard +"@jridgewell/sourcemap-codec@npm:^1.4.15": + version: 1.5.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" + checksum: 10/4ed6123217569a1484419ac53f6ea0d9f3b57e5b57ab30d7c267bdb27792a27eb0e4b08e84a2680aa55cc2f2b411ffd6ec3db01c44fdc6dc43aca4b55f8374fd + languageName: node + linkType: hard + "@jridgewell/trace-mapping@npm:0.3.9": version: 0.3.9 resolution: "@jridgewell/trace-mapping@npm:0.3.9" @@ -3505,6 +3599,455 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/api-logs@npm:0.53.0": + version: 0.53.0 + resolution: "@opentelemetry/api-logs@npm:0.53.0" + dependencies: + "@opentelemetry/api": "npm:^1.0.0" + checksum: 10/347b4554d6ee01afb29bd39e8f9cbbccd80abb0883fe6a84e3bcce8ab4dbfe357a2729246d2f66de0de6272846fd1bb2d71e286e18ad2690d9e7f46f02f00f73 + languageName: node + linkType: hard + +"@opentelemetry/api-logs@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/api-logs@npm:0.56.0" + dependencies: + "@opentelemetry/api": "npm:^1.3.0" + checksum: 10/5a6e25015acada7449d11124e9adbbe6670e1e9f7e8b46c60360ac89bb1537f2be326bcf18c66dcbcdee9f34e3a18bd4807c5a40faa0a4ac0135cb3675efb2a9 + languageName: node + linkType: hard + +"@opentelemetry/api@npm:^1.0.0, @opentelemetry/api@npm:^1.3.0, @opentelemetry/api@npm:^1.8, @opentelemetry/api@npm:^1.9.0": + version: 1.9.0 + resolution: "@opentelemetry/api@npm:1.9.0" + checksum: 10/a607f0eef971893c4f2ee2a4c2069aade6ec3e84e2a1f5c2aac19f65c5d9eeea41aa72db917c1029faafdd71789a1a040bdc18f40d63690e22ccae5d7070f194 + languageName: node + linkType: hard + +"@opentelemetry/context-async-hooks@npm:^1.29.0": + version: 1.30.0 + resolution: "@opentelemetry/context-async-hooks@npm:1.30.0" + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: 10/0d9a4c2eeeceff55b8267123fa3d36f7659afb71e41a09f4d9980c66178d0dbbfb12a3f995d04a7eae80e8a381a9436801b4f9be845aaca0b44e7ea2eff43478 + languageName: node + linkType: hard + +"@opentelemetry/core@npm:1.29.0": + version: 1.29.0 + resolution: "@opentelemetry/core@npm:1.29.0" + dependencies: + "@opentelemetry/semantic-conventions": "npm:1.28.0" + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: 10/eb62dce11cb0cb637acfb3582ad25e48766d9fb37b6b70e57f3c60521c7680a85431a0853c50d98cc8e807e5e3c2fddda314623d879e932bf1a5f629344b39ce + languageName: node + linkType: hard + +"@opentelemetry/core@npm:1.30.0, @opentelemetry/core@npm:^1.1.0, @opentelemetry/core@npm:^1.26.0, @opentelemetry/core@npm:^1.29.0, @opentelemetry/core@npm:^1.8.0": + version: 1.30.0 + resolution: "@opentelemetry/core@npm:1.30.0" + dependencies: + "@opentelemetry/semantic-conventions": "npm:1.28.0" + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: 10/6984b7a2ce32a7de0c29fa9a3b03eed0bae730ba61706668939cad6331b168614f6102b5088f71daf4b41686ea31b3082349a850d3da4ff7e48934882be2c0df + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-amqplib@npm:^0.45.0": + version: 0.45.0 + resolution: "@opentelemetry/instrumentation-amqplib@npm:0.45.0" + dependencies: + "@opentelemetry/core": "npm:^1.8.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/7a0be9861a12a7baf1a63fecd4eb221eecb9cb422223d1b62f183b14c1999e9ba039450a60bbaad139abab040d48dc843d4c93e8247b39215e31066e4ff9aa17 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-connect@npm:0.42.0": + version: 0.42.0 + resolution: "@opentelemetry/instrumentation-connect@npm:0.42.0" + dependencies: + "@opentelemetry/core": "npm:^1.8.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@types/connect": "npm:3.4.36" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/f03090f36028d654fcbb649d52ec57613b407aceb7e3d61978ab4f737c3617f4dd7061612139e0cb856a9df566d1ff0202f2c426ee3dacaf2a68c1ea5a34be63 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-dataloader@npm:0.15.0": + version: 0.15.0 + resolution: "@opentelemetry/instrumentation-dataloader@npm:0.15.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/2a13e5159f5977f8d14955d6ce6994a6c6249ae25da10975aca782d0a74d74355143cdc4c47c99f36abd71d6097b610aa34611bb64a5d042948bbb788c26dd77 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-express@npm:0.46.0": + version: 0.46.0 + resolution: "@opentelemetry/instrumentation-express@npm:0.46.0" + dependencies: + "@opentelemetry/core": "npm:^1.8.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/757b074aece5ad34ac082c54f3c4a6aadcbdf6cfb55510de5d77acc3e75e28a3c7f8b80ba5727b5d47ffa70790d0fdc672fc67d5f3854ba2acbb011424ce914c + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-fastify@npm:0.43.0": + version: 0.43.0 + resolution: "@opentelemetry/instrumentation-fastify@npm:0.43.0" + dependencies: + "@opentelemetry/core": "npm:^1.8.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/aee85c357ad0f0a88935919aa5bd09547e0b81fd11fc83aabc298fa84e4b3f7d6e64aa03f6273849ce93d11cad591a743a2b73f7838ddf26f54a48b53906259c + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-fs@npm:0.18.0": + version: 0.18.0 + resolution: "@opentelemetry/instrumentation-fs@npm:0.18.0" + dependencies: + "@opentelemetry/core": "npm:^1.8.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/634c23bac8aee7325be2cf2d64f0856d11a9de746f942fec52ebd96a6a7159c63913758c78295c9cb909d950f72c73e1e2685f4d9ed5f9754254ff0ce678dcc6 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-generic-pool@npm:0.42.0": + version: 0.42.0 + resolution: "@opentelemetry/instrumentation-generic-pool@npm:0.42.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/09c2cf4b64798ce92ddc0214c6c0443bb7800f94a2a8578f2276f3d8a5dd7018b4f5ec9d82d771b4cedd29b949760ca333c1a4fec0d43244ba338af36ad150b2 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-graphql@npm:0.46.0": + version: 0.46.0 + resolution: "@opentelemetry/instrumentation-graphql@npm:0.46.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/f7850db04df91a8d213396bbaaf7762535295ac2c572d1338a9798cebfb149ccf3a8b98d9255cdcdbbd42f17228440f2a75f064d2f2010da336174a55b644ec6 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-hapi@npm:0.44.0": + version: 0.44.0 + resolution: "@opentelemetry/instrumentation-hapi@npm:0.44.0" + dependencies: + "@opentelemetry/core": "npm:^1.8.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/d8eafb0213ea8c6971b7a21dd3a3f7ea988954cdf23e708c5fc8bd132267709fd449823d496ac2bb8cf93cf164fa452edb16089c307cefcabb54bc99f20b203e + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-http@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/instrumentation-http@npm:0.56.0" + dependencies: + "@opentelemetry/core": "npm:1.29.0" + "@opentelemetry/instrumentation": "npm:0.56.0" + "@opentelemetry/semantic-conventions": "npm:1.28.0" + forwarded-parse: "npm:2.1.2" + semver: "npm:^7.5.2" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/3fb73d5f0df152f7ff9744a32a521a71656075df1ea6418005a991c912f16fd1b16c468bc9dcc48d4d19621be5b0b4aedc377cf6d00f828e0d2d1f8d4822e6ca + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-ioredis@npm:0.46.0": + version: 0.46.0 + resolution: "@opentelemetry/instrumentation-ioredis@npm:0.46.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/redis-common": "npm:^0.36.2" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/579296b0fe06c0d727d9866845110b109160579654bb442f4e4ce05df0d47e2ad3912df1ace2bca84423b1d62584524a79d2c3f82943ae7429801e96440c3db5 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-kafkajs@npm:0.6.0": + version: 0.6.0 + resolution: "@opentelemetry/instrumentation-kafkajs@npm:0.6.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/85723b216fea262d65b6aad9a24242842b0716e06424c6a94a1b9299470c3756dc9d128816f7053bf68eb46bde41d545385e47ac680e2aeff609b3fbc7c6b135 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-knex@npm:0.43.0": + version: 0.43.0 + resolution: "@opentelemetry/instrumentation-knex@npm:0.43.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/bb801ba2198b33e0b4feba84313ad54d502969d5fddea9de26ebbeb1a59ade61f03eed2aea983f43682b53102de837916f6dd44eede3a55237980dc99527bf6c + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-koa@npm:0.46.0": + version: 0.46.0 + resolution: "@opentelemetry/instrumentation-koa@npm:0.46.0" + dependencies: + "@opentelemetry/core": "npm:^1.8.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/63d2209e7acb53d7183cd1926656d388a60cca34f3517a26af101acdb4e5612c123071076828a49e18f288a5d694a2f7994f95ee48dab8312f6c2904321d2e4a + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-lru-memoizer@npm:0.43.0": + version: 0.43.0 + resolution: "@opentelemetry/instrumentation-lru-memoizer@npm:0.43.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/5c1ea5e1f453dea989285199fe8385f31f17982fbc14eb504dc801f5e3a97f8e3fdc4d0f23212ec3cc522e84c1b5750073192b4a33b8a8302cdd18f4935280cb + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-mongodb@npm:0.50.0": + version: 0.50.0 + resolution: "@opentelemetry/instrumentation-mongodb@npm:0.50.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/beee37f0be94c614c620ea431ea7315c9293ea14f3b8f751075a5b4d663ed3daa4fe73ef9f58af812ab38d6b59d511da6252386d1fc7aab4d60b4384a8c2065c + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-mongoose@npm:0.45.0": + version: 0.45.0 + resolution: "@opentelemetry/instrumentation-mongoose@npm:0.45.0" + dependencies: + "@opentelemetry/core": "npm:^1.8.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/a4872b8c7783ace3510f954957aaf6880dee89c00f44a55153e463b5ffeacfdb896ca285cb8b816a746e7dec7f69901d0625c959cbdb09f4dfcba123dfa82213 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-mysql2@npm:0.44.0": + version: 0.44.0 + resolution: "@opentelemetry/instrumentation-mysql2@npm:0.44.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@opentelemetry/sql-common": "npm:^0.40.1" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/8ba5e66d3f994a3473df480bfd417b3e870b2fa25ae77b74ed1e516afb4ad38d1625d36c3947b02d9e52298edda1ea5f2df008a7c5bc8543455d760deb9fe3e1 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-mysql@npm:0.44.0": + version: 0.44.0 + resolution: "@opentelemetry/instrumentation-mysql@npm:0.44.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@types/mysql": "npm:2.15.26" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/7043e7446280be01ff12c88cbe843d131543c48ee73894b2862e9970cf380b43538f82a31fe32569d1fc2627acf0ccd1635e7ba3858ae93d7163a15b293036a8 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-nestjs-core@npm:0.43.0": + version: 0.43.0 + resolution: "@opentelemetry/instrumentation-nestjs-core@npm:0.43.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/8d7170dfb574c77a8f11081aa205c83fb8d8ec7e9935005b1d6ca418b917bc359c55ed955747d330b8d3bdfbc599cc7eac38c0b1c5a092771847f9fd9bf49b3f + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-pg@npm:0.49.0": + version: 0.49.0 + resolution: "@opentelemetry/instrumentation-pg@npm:0.49.0" + dependencies: + "@opentelemetry/core": "npm:^1.26.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:1.27.0" + "@opentelemetry/sql-common": "npm:^0.40.1" + "@types/pg": "npm:8.6.1" + "@types/pg-pool": "npm:2.0.6" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/04457e441872a0afecfa471f04bbecdf4b62782d110cd1a75423f9ff12c34396896056dda99923690f4a26c572fccc0c28d25fbd26e71f07ca2778e61fc3a7d1 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-redis-4@npm:0.45.0": + version: 0.45.0 + resolution: "@opentelemetry/instrumentation-redis-4@npm:0.45.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/redis-common": "npm:^0.36.2" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/8e2cd153936681b9a1e13a1e059df18d31a8d2a85c0db11e3d3b00c496f360efe3c864acac9e87de80cc13318f17ce35ecfe0aea22d502b42109cd1164e39619 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-tedious@npm:0.17.0": + version: 0.17.0 + resolution: "@opentelemetry/instrumentation-tedious@npm:0.17.0" + dependencies: + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/semantic-conventions": "npm:^1.27.0" + "@types/tedious": "npm:^4.0.14" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/62594f42fddc7af06aa14575e70d821551842671d2f2013e583d58d508d6ca8e6749faf89453e8254e6257483390cf8fd9ca0076327850d54e088d436f13ac51 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-undici@npm:0.9.0": + version: 0.9.0 + resolution: "@opentelemetry/instrumentation-undici@npm:0.9.0" + dependencies: + "@opentelemetry/core": "npm:^1.8.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + peerDependencies: + "@opentelemetry/api": ^1.7.0 + checksum: 10/e7300fb0353cc0648cc8a1779287e6780b6aaf3b4f13698a203367cfb9d571677e8f5897b3e79cfede196e72007ac2a1f4fbb8128a61ceb2b85517ebb30effd4 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation@npm:0.56.0, @opentelemetry/instrumentation@npm:^0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/instrumentation@npm:0.56.0" + dependencies: + "@opentelemetry/api-logs": "npm:0.56.0" + "@types/shimmer": "npm:^1.2.0" + import-in-the-middle: "npm:^1.8.1" + require-in-the-middle: "npm:^7.1.1" + semver: "npm:^7.5.2" + shimmer: "npm:^1.2.1" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/7c3802eb6b55b39b6904526d052b918619c9cde0f71a35bc2f23ac6c3a10ea66b08a65adf6862cdbaac7b231fb5119204b4d5531be25b96933a9d8b91a9ce062 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation@npm:^0.49 || ^0.50 || ^0.51 || ^0.52.0 || ^0.53.0": + version: 0.53.0 + resolution: "@opentelemetry/instrumentation@npm:0.53.0" + dependencies: + "@opentelemetry/api-logs": "npm:0.53.0" + "@types/shimmer": "npm:^1.2.0" + import-in-the-middle: "npm:^1.8.1" + require-in-the-middle: "npm:^7.1.1" + semver: "npm:^7.5.2" + shimmer: "npm:^1.2.1" + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 10/4b994c8568a503a15655cba249b1dbdef3f67dfda37938abba6267ba75b6d72a9aa276be4b0c8874e86f98ab89d92877e1874e0565a7e67f062c43dfcbbb16a5 + languageName: node + linkType: hard + +"@opentelemetry/redis-common@npm:^0.36.2": + version: 0.36.2 + resolution: "@opentelemetry/redis-common@npm:0.36.2" + checksum: 10/e7f610f79c95bab9156a9831162c7b55b94ab43c5e47ecb9efcc10c08a236395fdd54b6bb018da981e6641bac9da6fda1b50636fb49db584e87d988750d255e1 + languageName: node + linkType: hard + +"@opentelemetry/resources@npm:1.30.0, @opentelemetry/resources@npm:^1.29.0": + version: 1.30.0 + resolution: "@opentelemetry/resources@npm:1.30.0" + dependencies: + "@opentelemetry/core": "npm:1.30.0" + "@opentelemetry/semantic-conventions": "npm:1.28.0" + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: 10/c9f9bac18b09ff6ad5bcb127de11a8dbd46a39154ac2659ab1c9f94781a9e4fd41d7989d44fc09627f489c903ad9476e8b1d2d958eb9293e05f3a00840760b17 + languageName: node + linkType: hard + +"@opentelemetry/sdk-trace-base@npm:^1.22, @opentelemetry/sdk-trace-base@npm:^1.29.0": + version: 1.30.0 + resolution: "@opentelemetry/sdk-trace-base@npm:1.30.0" + dependencies: + "@opentelemetry/core": "npm:1.30.0" + "@opentelemetry/resources": "npm:1.30.0" + "@opentelemetry/semantic-conventions": "npm:1.28.0" + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: 10/2e926c0cf29b6319a263fd7a1dbf157170e75b7ab329b11b1990130dd1591cea4590d67c6208ef7d63bf5742e4ab5811d64672804568438f2e751dbe1ac98958 + languageName: node + linkType: hard + +"@opentelemetry/semantic-conventions@npm:1.27.0": + version: 1.27.0 + resolution: "@opentelemetry/semantic-conventions@npm:1.27.0" + checksum: 10/98166522f299e2fe3d43376adbdeb92679b75ebb172e2a3c4c71f2942bd91585e9537618efbbae6dc08177699e5719368edf66d7e69e8636f360b85217bbdbe1 + languageName: node + linkType: hard + +"@opentelemetry/semantic-conventions@npm:1.28.0, @opentelemetry/semantic-conventions@npm:^1.27.0, @opentelemetry/semantic-conventions@npm:^1.28.0": + version: 1.28.0 + resolution: "@opentelemetry/semantic-conventions@npm:1.28.0" + checksum: 10/c182a3206769b5d5a8ab89a5c674d046fd789421cef27ea55af179990e314732433c98e5017aa23e99f15fd2b0e13cb129bb6c2282da6860ce9419adf32b2e87 + languageName: node + linkType: hard + +"@opentelemetry/sql-common@npm:^0.40.1": + version: 0.40.1 + resolution: "@opentelemetry/sql-common@npm:0.40.1" + dependencies: + "@opentelemetry/core": "npm:^1.1.0" + peerDependencies: + "@opentelemetry/api": ^1.1.0 + checksum: 10/f887b4135be56c9ef6e29f040c9f75f34709e38c11897d59d284d7e73175a2dd2c6267c18061144e81a0045fc461b7813769db2e49c42a8d6becc58b1456d55c + languageName: node + linkType: hard + "@ourworldindata/components@workspace:^, @ourworldindata/components@workspace:packages/@ourworldindata/components": version: 0.0.0-use.local resolution: "@ourworldindata/components@workspace:packages/@ourworldindata/components" @@ -3550,9 +4093,6 @@ __metadata: version: 0.0.0-use.local resolution: "@ourworldindata/explorer@workspace:packages/@ourworldindata/explorer" dependencies: - "@bugsnag/core": "npm:^8.0.0" - "@bugsnag/js": "npm:^8.0.0" - "@bugsnag/plugin-react": "npm:^8.0.0" "@fortawesome/fontawesome-svg-core": "npm:^6.5.2" "@fortawesome/free-brands-svg-icons": "npm:^6.5.2" "@fortawesome/free-solid-svg-icons": "npm:^6.5.2" @@ -3611,9 +4151,6 @@ __metadata: version: 0.0.0-use.local resolution: "@ourworldindata/grapher@workspace:packages/@ourworldindata/grapher" dependencies: - "@bugsnag/core": "npm:^8.0.0" - "@bugsnag/js": "npm:^8.0.0" - "@bugsnag/plugin-react": "npm:^8.0.0" "@fortawesome/fontawesome-svg-core": "npm:^6.5.2" "@fortawesome/free-brands-svg-icons": "npm:^6.5.2" "@fortawesome/free-solid-svg-icons": "npm:^6.5.2" @@ -3622,6 +4159,7 @@ __metadata: "@ourworldindata/core-table": "workspace:^" "@ourworldindata/types": "workspace:^" "@ourworldindata/utils": "workspace:^" + "@sentry/react": "npm:^8.48.0" "@tippyjs/react": "npm:^4.2.6" "@types/colorbrewer": "npm:^1.0.29" "@types/d3": "npm:^6" @@ -3729,6 +4267,17 @@ __metadata: languageName: node linkType: hard +"@prisma/instrumentation@npm:5.22.0": + version: 5.22.0 + resolution: "@prisma/instrumentation@npm:5.22.0" + dependencies: + "@opentelemetry/api": "npm:^1.8" + "@opentelemetry/instrumentation": "npm:^0.49 || ^0.50 || ^0.51 || ^0.52.0 || ^0.53.0" + "@opentelemetry/sdk-trace-base": "npm:^1.22" + checksum: 10/f48fc6b56e17538013033b5cab651d5d8df8bd0a0695ac3bc0d0cc6619a262a280ffe55aab0acade146928c6c2dfdf5532155a792818c5aea15efced67cc19c1 + languageName: node + linkType: hard + "@rc-component/async-validator@npm:^5.0.3": version: 5.0.4 resolution: "@rc-component/async-validator@npm:5.0.4" @@ -4021,136 +4570,297 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.22.4": - version: 4.22.4 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.22.4" - conditions: os=win32 & cpu=ia32 +"@rollup/rollup-win32-ia32-msvc@npm:4.22.4": + version: 4.22.4 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.22.4" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.22.4": + version: 4.22.4 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.22.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rtsao/scc@npm:^1.1.0": + version: 1.1.0 + resolution: "@rtsao/scc@npm:1.1.0" + checksum: 10/17d04adf404e04c1e61391ed97bca5117d4c2767a76ae3e879390d6dec7b317fcae68afbf9e98badee075d0b64fa60f287729c4942021b4d19cd01db77385c01 + languageName: node + linkType: hard + +"@selderee/plugin-htmlparser2@npm:^0.11.0": + version: 0.11.0 + resolution: "@selderee/plugin-htmlparser2@npm:0.11.0" + dependencies: + domhandler: "npm:^5.0.3" + selderee: "npm:^0.11.0" + checksum: 10/7550108d270e6ea2be4850d55cbf4d58d5a90c109a15b874c3c7c622a1399bd8015359ef3672983a86118432ca8325a6aca1fe79d961b01278fdaeaea8895c5f + languageName: node + linkType: hard + +"@sentry-internal/browser-utils@npm:8.48.0": + version: 8.48.0 + resolution: "@sentry-internal/browser-utils@npm:8.48.0" + dependencies: + "@sentry/core": "npm:8.48.0" + checksum: 10/49feb55a2ba2ed8317b35b8ed7440a9bec6800270387c990d98db35ef0958f6b46640378a9384e5cb657fbef093b7de7b6633c4cd96078f5b820102811fe7c8e + languageName: node + linkType: hard + +"@sentry-internal/feedback@npm:8.48.0": + version: 8.48.0 + resolution: "@sentry-internal/feedback@npm:8.48.0" + dependencies: + "@sentry/core": "npm:8.48.0" + checksum: 10/50dbe4c6a1eff4c961be0a63966d874c8194e00652fdf7a544dfd1a46a27e2780ce7f21bc27f4a47f05985624fa2a43f676f67db06ae6dc7405775459efd46e2 + languageName: node + linkType: hard + +"@sentry-internal/replay-canvas@npm:8.48.0": + version: 8.48.0 + resolution: "@sentry-internal/replay-canvas@npm:8.48.0" + dependencies: + "@sentry-internal/replay": "npm:8.48.0" + "@sentry/core": "npm:8.48.0" + checksum: 10/c7965bb5a66eada623872e0fef896a3267f344819d155a5f0c3d24057eaacf2c22c582c62de7cec1b67517837e6c4e352d67f96493527cd7844491d31c831437 + languageName: node + linkType: hard + +"@sentry-internal/replay@npm:8.48.0": + version: 8.48.0 + resolution: "@sentry-internal/replay@npm:8.48.0" + dependencies: + "@sentry-internal/browser-utils": "npm:8.48.0" + "@sentry/core": "npm:8.48.0" + checksum: 10/be7560dc7d82ab716a310ed47076009ba53a3b6ce9a4d0bfdd987da9256edef56afda9f4c2833a808cad935a47b2e3b8e2f97e2bd36975bf82eb2b4be17c00f6 + languageName: node + linkType: hard + +"@sentry/babel-plugin-component-annotate@npm:2.23.0": + version: 2.23.0 + resolution: "@sentry/babel-plugin-component-annotate@npm:2.23.0" + checksum: 10/2c64d06fd20c641a1d80b53f5dfaca5467fbf7d6108f85517a5555fe1cad7bdd731abd58ab3ed14cedaf6698f323945cfd7c63471a0392e61e4f6c6e62aee13b + languageName: node + linkType: hard + +"@sentry/browser@npm:8.48.0": + version: 8.48.0 + resolution: "@sentry/browser@npm:8.48.0" + dependencies: + "@sentry-internal/browser-utils": "npm:8.48.0" + "@sentry-internal/feedback": "npm:8.48.0" + "@sentry-internal/replay": "npm:8.48.0" + "@sentry-internal/replay-canvas": "npm:8.48.0" + "@sentry/core": "npm:8.48.0" + checksum: 10/5dd74755df73d766be792b2a0b8534f529bb1ebfab7d4111c9ce343a97d9f2015b7bcf9868618e0696d190fb73a9e17bc592252bf3d06121f3cc1472d9921b93 + languageName: node + linkType: hard + +"@sentry/bundler-plugin-core@npm:2.23.0": + version: 2.23.0 + resolution: "@sentry/bundler-plugin-core@npm:2.23.0" + dependencies: + "@babel/core": "npm:^7.18.5" + "@sentry/babel-plugin-component-annotate": "npm:2.23.0" + "@sentry/cli": "npm:2.39.1" + dotenv: "npm:^16.3.1" + find-up: "npm:^5.0.0" + glob: "npm:^9.3.2" + magic-string: "npm:0.30.8" + unplugin: "npm:1.0.1" + checksum: 10/de369d98cea0a7586ea63ef6c912988529eaed82337add3f41a44d862f97db969f84bccc68fb45f3a2c5ee0e8a1ccb115a4f99838e0095d31358823330e942f3 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.22.4": - version: 4.22.4 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.22.4" - conditions: os=win32 & cpu=x64 +"@sentry/cli-darwin@npm:2.39.1": + version: 2.39.1 + resolution: "@sentry/cli-darwin@npm:2.39.1" + conditions: os=darwin languageName: node linkType: hard -"@rtsao/scc@npm:^1.1.0": - version: 1.1.0 - resolution: "@rtsao/scc@npm:1.1.0" - checksum: 10/17d04adf404e04c1e61391ed97bca5117d4c2767a76ae3e879390d6dec7b317fcae68afbf9e98badee075d0b64fa60f287729c4942021b4d19cd01db77385c01 +"@sentry/cli-linux-arm64@npm:2.39.1": + version: 2.39.1 + resolution: "@sentry/cli-linux-arm64@npm:2.39.1" + conditions: (os=linux | os=freebsd) & cpu=arm64 languageName: node linkType: hard -"@selderee/plugin-htmlparser2@npm:^0.11.0": - version: 0.11.0 - resolution: "@selderee/plugin-htmlparser2@npm:0.11.0" - dependencies: - domhandler: "npm:^5.0.3" - selderee: "npm:^0.11.0" - checksum: 10/7550108d270e6ea2be4850d55cbf4d58d5a90c109a15b874c3c7c622a1399bd8015359ef3672983a86118432ca8325a6aca1fe79d961b01278fdaeaea8895c5f +"@sentry/cli-linux-arm@npm:2.39.1": + version: 2.39.1 + resolution: "@sentry/cli-linux-arm@npm:2.39.1" + conditions: (os=linux | os=freebsd) & cpu=arm languageName: node linkType: hard -"@sentry-internal/browser-utils@npm:8.36.0": - version: 8.36.0 - resolution: "@sentry-internal/browser-utils@npm:8.36.0" - dependencies: - "@sentry/core": "npm:8.36.0" - "@sentry/types": "npm:8.36.0" - "@sentry/utils": "npm:8.36.0" - checksum: 10/f886260292e22dd936fbd7d2f4bb1325e3197a418a88b352f064517286677b68e26a993a9cac908faac344f4ea460074578b73fff91746a9f65e18b7c44e0dc6 +"@sentry/cli-linux-i686@npm:2.39.1": + version: 2.39.1 + resolution: "@sentry/cli-linux-i686@npm:2.39.1" + conditions: (os=linux | os=freebsd) & (cpu=x86 | cpu=ia32) languageName: node linkType: hard -"@sentry-internal/feedback@npm:8.36.0": - version: 8.36.0 - resolution: "@sentry-internal/feedback@npm:8.36.0" - dependencies: - "@sentry/core": "npm:8.36.0" - "@sentry/types": "npm:8.36.0" - "@sentry/utils": "npm:8.36.0" - checksum: 10/72cb38adae9939ce90963044cfc39051de0f2c8e037efb6c416299afd7ce66d63374f63c549ed054c245bb93ff337bb2a3eaba532dbad2a712b5a9910af3e4a5 +"@sentry/cli-linux-x64@npm:2.39.1": + version: 2.39.1 + resolution: "@sentry/cli-linux-x64@npm:2.39.1" + conditions: (os=linux | os=freebsd) & cpu=x64 languageName: node linkType: hard -"@sentry-internal/replay-canvas@npm:8.36.0": - version: 8.36.0 - resolution: "@sentry-internal/replay-canvas@npm:8.36.0" - dependencies: - "@sentry-internal/replay": "npm:8.36.0" - "@sentry/core": "npm:8.36.0" - "@sentry/types": "npm:8.36.0" - "@sentry/utils": "npm:8.36.0" - checksum: 10/f7725523339dfadadd55a2c025de82d73b2035b65b1bf34395997204bbd69e4665fcf94e90fb53b279c2bb1c005729f0ef9fb4d9946a20fa542b6cd9d2d2e9ea +"@sentry/cli-win32-i686@npm:2.39.1": + version: 2.39.1 + resolution: "@sentry/cli-win32-i686@npm:2.39.1" + conditions: os=win32 & (cpu=x86 | cpu=ia32) languageName: node linkType: hard -"@sentry-internal/replay@npm:8.36.0": - version: 8.36.0 - resolution: "@sentry-internal/replay@npm:8.36.0" - dependencies: - "@sentry-internal/browser-utils": "npm:8.36.0" - "@sentry/core": "npm:8.36.0" - "@sentry/types": "npm:8.36.0" - "@sentry/utils": "npm:8.36.0" - checksum: 10/558f9f277aef5232c43ce0711d85aa8ca8ed584435c9bbe7e08e59c3af2ed1da137d104b47e6f5c32b69b5b78ed516e627ec096ee4a950f2492c43fcf4a78170 +"@sentry/cli-win32-x64@npm:2.39.1": + version: 2.39.1 + resolution: "@sentry/cli-win32-x64@npm:2.39.1" + conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@sentry/browser@npm:8.36.0": - version: 8.36.0 - resolution: "@sentry/browser@npm:8.36.0" +"@sentry/cli@npm:2.39.1": + version: 2.39.1 + resolution: "@sentry/cli@npm:2.39.1" dependencies: - "@sentry-internal/browser-utils": "npm:8.36.0" - "@sentry-internal/feedback": "npm:8.36.0" - "@sentry-internal/replay": "npm:8.36.0" - "@sentry-internal/replay-canvas": "npm:8.36.0" - "@sentry/core": "npm:8.36.0" - "@sentry/types": "npm:8.36.0" - "@sentry/utils": "npm:8.36.0" - checksum: 10/46af4ade98628d93dd184b42deb5bec267407ebdd4a42c5803ca97cbb25f96c03db06c1c724438238fe0ae89d84ea64b686cae63b156d5aefe7e6c07b7c6ebaa + "@sentry/cli-darwin": "npm:2.39.1" + "@sentry/cli-linux-arm": "npm:2.39.1" + "@sentry/cli-linux-arm64": "npm:2.39.1" + "@sentry/cli-linux-i686": "npm:2.39.1" + "@sentry/cli-linux-x64": "npm:2.39.1" + "@sentry/cli-win32-i686": "npm:2.39.1" + "@sentry/cli-win32-x64": "npm:2.39.1" + https-proxy-agent: "npm:^5.0.0" + node-fetch: "npm:^2.6.7" + progress: "npm:^2.0.3" + proxy-from-env: "npm:^1.1.0" + which: "npm:^2.0.2" + dependenciesMeta: + "@sentry/cli-darwin": + optional: true + "@sentry/cli-linux-arm": + optional: true + "@sentry/cli-linux-arm64": + optional: true + "@sentry/cli-linux-i686": + optional: true + "@sentry/cli-linux-x64": + optional: true + "@sentry/cli-win32-i686": + optional: true + "@sentry/cli-win32-x64": + optional: true + bin: + sentry-cli: bin/sentry-cli + checksum: 10/b3d85acfbe6814df5d660ead9415558901eb005bbad3c42c74c9b444114a4fd7757d30d88b41e1e8546de4b76761dab56628328eec5ea5176caef4305381c74a + languageName: node + linkType: hard + +"@sentry/core@npm:8.48.0": + version: 8.48.0 + resolution: "@sentry/core@npm:8.48.0" + checksum: 10/1fff8fc1e0681459240ceda5a3b2a7402f7ac73da9fa72e3d6e57e8f994ac246b240739ee0f224d48646bf410980aac4213c3e334e1dcbbd806ed5f496c7bb3c + languageName: node + linkType: hard + +"@sentry/node@npm:8.48.0, @sentry/node@npm:^8.48.0": + version: 8.48.0 + resolution: "@sentry/node@npm:8.48.0" + dependencies: + "@opentelemetry/api": "npm:^1.9.0" + "@opentelemetry/context-async-hooks": "npm:^1.29.0" + "@opentelemetry/core": "npm:^1.29.0" + "@opentelemetry/instrumentation": "npm:^0.56.0" + "@opentelemetry/instrumentation-amqplib": "npm:^0.45.0" + "@opentelemetry/instrumentation-connect": "npm:0.42.0" + "@opentelemetry/instrumentation-dataloader": "npm:0.15.0" + "@opentelemetry/instrumentation-express": "npm:0.46.0" + "@opentelemetry/instrumentation-fastify": "npm:0.43.0" + "@opentelemetry/instrumentation-fs": "npm:0.18.0" + "@opentelemetry/instrumentation-generic-pool": "npm:0.42.0" + "@opentelemetry/instrumentation-graphql": "npm:0.46.0" + "@opentelemetry/instrumentation-hapi": "npm:0.44.0" + "@opentelemetry/instrumentation-http": "npm:0.56.0" + "@opentelemetry/instrumentation-ioredis": "npm:0.46.0" + "@opentelemetry/instrumentation-kafkajs": "npm:0.6.0" + "@opentelemetry/instrumentation-knex": "npm:0.43.0" + "@opentelemetry/instrumentation-koa": "npm:0.46.0" + "@opentelemetry/instrumentation-lru-memoizer": "npm:0.43.0" + "@opentelemetry/instrumentation-mongodb": "npm:0.50.0" + "@opentelemetry/instrumentation-mongoose": "npm:0.45.0" + "@opentelemetry/instrumentation-mysql": "npm:0.44.0" + "@opentelemetry/instrumentation-mysql2": "npm:0.44.0" + "@opentelemetry/instrumentation-nestjs-core": "npm:0.43.0" + "@opentelemetry/instrumentation-pg": "npm:0.49.0" + "@opentelemetry/instrumentation-redis-4": "npm:0.45.0" + "@opentelemetry/instrumentation-tedious": "npm:0.17.0" + "@opentelemetry/instrumentation-undici": "npm:0.9.0" + "@opentelemetry/resources": "npm:^1.29.0" + "@opentelemetry/sdk-trace-base": "npm:^1.29.0" + "@opentelemetry/semantic-conventions": "npm:^1.28.0" + "@prisma/instrumentation": "npm:5.22.0" + "@sentry/core": "npm:8.48.0" + "@sentry/opentelemetry": "npm:8.48.0" + import-in-the-middle: "npm:^1.11.2" + checksum: 10/6faa5ec46937ec3c72d3ec487bae21964ee26dfe3103d5509ab6603d31340f6a37deb0829f04d4bf5aa927b37e58aa29f6687383b03149649053477604981ba8 + languageName: node + linkType: hard + +"@sentry/opentelemetry@npm:8.48.0": + version: 8.48.0 + resolution: "@sentry/opentelemetry@npm:8.48.0" + dependencies: + "@sentry/core": "npm:8.48.0" + peerDependencies: + "@opentelemetry/api": ^1.9.0 + "@opentelemetry/core": ^1.29.0 + "@opentelemetry/instrumentation": ^0.56.0 + "@opentelemetry/sdk-trace-base": ^1.29.0 + "@opentelemetry/semantic-conventions": ^1.28.0 + checksum: 10/ada5bee2e709f48b7f788a8488ccd739cb3a193e45c261c8082d8517f3ae31be75596d10a9ebe71cf9d09c596f6f191a77f133696ca86c56f59393dafb3de493 languageName: node linkType: hard -"@sentry/core@npm:8.36.0": - version: 8.36.0 - resolution: "@sentry/core@npm:8.36.0" +"@sentry/profiling-node@npm:^8.48.0": + version: 8.48.0 + resolution: "@sentry/profiling-node@npm:8.48.0" dependencies: - "@sentry/types": "npm:8.36.0" - "@sentry/utils": "npm:8.36.0" - checksum: 10/26d9a926c6a76526cc3ed895370604c88a7fb9f152866362cb0eef348fcada9ae78706a678f081ed26b0bb29fd0293627d458dbc598b630962550ce4924c584d + "@sentry/core": "npm:8.48.0" + "@sentry/node": "npm:8.48.0" + detect-libc: "npm:^2.0.2" + node-abi: "npm:^3.61.0" + node-gyp: "npm:latest" + bin: + sentry-prune-profiler-binaries: scripts/prune-profiler-binaries.js + checksum: 10/b1650af42052063a054620057ad5a31558fdb17c2fa6e79083f1789efea21d6a58d888aed22b17ed172e229ac8b58e8ead3e903118e3d9768015d349c58e14da languageName: node linkType: hard -"@sentry/react@npm:^8.36.0": - version: 8.36.0 - resolution: "@sentry/react@npm:8.36.0" +"@sentry/react@npm:^8.48.0": + version: 8.48.0 + resolution: "@sentry/react@npm:8.48.0" dependencies: - "@sentry/browser": "npm:8.36.0" - "@sentry/core": "npm:8.36.0" - "@sentry/types": "npm:8.36.0" - "@sentry/utils": "npm:8.36.0" + "@sentry/browser": "npm:8.48.0" + "@sentry/core": "npm:8.48.0" hoist-non-react-statics: "npm:^3.3.2" peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - checksum: 10/c5edf3f4cb53e7fcecd3aa11512e125b90531ae41f04c2ade26f052e3138f217b3e254433eb28776d5b845f98fe7678e7961dc7770c063e62f8eda61868bc191 + checksum: 10/d0fe2252171106025d82c4eca2331de3942f83f81aaee7716286de4a424ece92e52b220bc38496c0f900286e47e4be7a44ea307743696ac61bb160a86a4eb696 languageName: node linkType: hard -"@sentry/types@npm:8.36.0": - version: 8.36.0 - resolution: "@sentry/types@npm:8.36.0" - checksum: 10/6c91218f5355e5d9396cf863d66c21edd305075ea5408e31ca52dbc0eae5e39a1247882d515856f9ad05fb7c5f0509c184c048a26086f23dfd41ef4a4eeeb38b - languageName: node - linkType: hard - -"@sentry/utils@npm:8.36.0": - version: 8.36.0 - resolution: "@sentry/utils@npm:8.36.0" +"@sentry/vite-plugin@npm:^2.23.0": + version: 2.23.0 + resolution: "@sentry/vite-plugin@npm:2.23.0" dependencies: - "@sentry/types": "npm:8.36.0" - checksum: 10/5b58bb34ed4e13b71f322a4455702ae5dab7b597410ac7774abce0dd67dcc84ee088be05e1c8d694ec795b8a84baad0467e31afd0c8026aaacac93f8b5a3701f + "@sentry/bundler-plugin-core": "npm:2.23.0" + unplugin: "npm:1.0.1" + checksum: 10/34b3b93a5e20e4e629602eb137bfda98d22deb0f170d9ae538f1f2687feb7533199b71cecc08ac7df6c1e5bcea2889d12aac8690577cd5fcc3ac5dd01a9e047f languageName: node linkType: hard @@ -5083,12 +5793,12 @@ __metadata: languageName: node linkType: hard -"@types/connect@npm:*": - version: 3.4.32 - resolution: "@types/connect@npm:3.4.32" +"@types/connect@npm:*, @types/connect@npm:3.4.36": + version: 3.4.36 + resolution: "@types/connect@npm:3.4.36" dependencies: "@types/node": "npm:*" - checksum: 10/e8ceccbe325cea2ce90f365c721d13c960da241bc6c726e779e5ed3d02e826e1fb5a172569af805aa7836f930b75e869cd0a6b3fbc7b1715fe751c2b78f91217 + checksum: 10/4dee3d966fb527b98f0cbbdcf6977c9193fc3204ed539b7522fe5e64dfa45f9017bdda4ffb1f760062262fce7701a0ee1c2f6ce2e50af36c74d4e37052303172 languageName: node linkType: hard @@ -5660,6 +6370,15 @@ __metadata: languageName: node linkType: hard +"@types/mysql@npm:2.15.26": + version: 2.15.26 + resolution: "@types/mysql@npm:2.15.26" + dependencies: + "@types/node": "npm:*" + checksum: 10/8f205eeaca8f94e998ce4707354bfd02b6ca0da5b7c22289f8f6ff864d549bfb95ca7ddc2f2ebe69eb8f7e3d1f5d8a5b9a2f98aee13824dbc48051bf53a1664d + languageName: node + linkType: hard + "@types/node-fetch@npm:^2.6.4": version: 2.6.4 resolution: "@types/node-fetch@npm:2.6.4" @@ -5709,6 +6428,37 @@ __metadata: languageName: node linkType: hard +"@types/pg-pool@npm:2.0.6": + version: 2.0.6 + resolution: "@types/pg-pool@npm:2.0.6" + dependencies: + "@types/pg": "npm:*" + checksum: 10/cc54ce97115effc982bd052f79901a78215e76554aca0ecc92e78eb907e4fb2962924039369cd9aaf48075f1637593ce14647c62d3a2eb03789ce5d1c6df750b + languageName: node + linkType: hard + +"@types/pg@npm:*": + version: 8.11.10 + resolution: "@types/pg@npm:8.11.10" + dependencies: + "@types/node": "npm:*" + pg-protocol: "npm:*" + pg-types: "npm:^4.0.1" + checksum: 10/65b7d7ca9c90b7cb94aa94ad94bb1883356845e1f64688bc824ecd499da25f63a2400f0a58500554637048a7cc8b91055bbfe14301c082ce9669afd0c18e414c + languageName: node + linkType: hard + +"@types/pg@npm:8.6.1": + version: 8.6.1 + resolution: "@types/pg@npm:8.6.1" + dependencies: + "@types/node": "npm:*" + pg-protocol: "npm:*" + pg-types: "npm:^2.2.0" + checksum: 10/bf1134ea194ad9cb8bfe0aab7a532713c63bae1d95909fa45e8dc1945e44ede74f2d4c5b2cd2f9712c6b970896929e0d82480f9c9da79addf405c089b590e562 + languageName: node + linkType: hard + "@types/pikaday@npm:1.7.4": version: 1.7.4 resolution: "@types/pikaday@npm:1.7.4" @@ -5911,6 +6661,13 @@ __metadata: languageName: node linkType: hard +"@types/shimmer@npm:^1.2.0": + version: 1.2.0 + resolution: "@types/shimmer@npm:1.2.0" + checksum: 10/f081a31d826ce7bfe8cc7ba8129d2b1dffae44fd580eba4fcf741237646c4c2494ae6de2cada4b7713d138f35f4bc512dbf01311d813dee82020f97d7d8c491c + languageName: node + linkType: hard + "@types/sinonjs__fake-timers@npm:8.1.1": version: 8.1.1 resolution: "@types/sinonjs__fake-timers@npm:8.1.1" @@ -5939,6 +6696,15 @@ __metadata: languageName: node linkType: hard +"@types/tedious@npm:^4.0.14": + version: 4.0.14 + resolution: "@types/tedious@npm:4.0.14" + dependencies: + "@types/node": "npm:*" + checksum: 10/c8f6480cf68d95b5e9f64fa6210f50915e8ff124638965a2c5a4c87641cc7f762155b9a8e01e3e517d48f8931e2d3920a40c4e677398e8b93c9cf1c8a36d2fbb + languageName: node + linkType: hard + "@types/tern@npm:*": version: 0.23.4 resolution: "@types/tern@npm:0.23.4" @@ -6311,6 +7077,15 @@ __metadata: languageName: node linkType: hard +"acorn-import-attributes@npm:^1.9.5": + version: 1.9.5 + resolution: "acorn-import-attributes@npm:1.9.5" + peerDependencies: + acorn: ^8 + checksum: 10/8bfbfbb6e2467b9b47abb4d095df717ab64fce2525da65eabee073e85e7975fb3a176b6c8bba17c99a7d8ede283a10a590272304eb54a93c4aa1af9790d47a8b + languageName: node + linkType: hard + "acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" @@ -6327,7 +7102,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.1.0, acorn@npm:^8.14.0, acorn@npm:^8.8.0, acorn@npm:^8.8.1": +"acorn@npm:^8.1.0, acorn@npm:^8.14.0, acorn@npm:^8.8.0, acorn@npm:^8.8.1, acorn@npm:^8.8.2": version: 8.14.0 resolution: "acorn@npm:8.14.0" bin: @@ -7201,6 +7976,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.24.0": + version: 4.24.4 + resolution: "browserslist@npm:4.24.4" + dependencies: + caniuse-lite: "npm:^1.0.30001688" + electron-to-chromium: "npm:^1.5.73" + node-releases: "npm:^2.0.19" + update-browserslist-db: "npm:^1.1.1" + bin: + browserslist: cli.js + checksum: 10/11fda105e803d891311a21a1f962d83599319165faf471c2d70e045dff82a12128f5b50b1fcba665a2352ad66147aaa248a9d2355a80aadc3f53375eb3de2e48 + languageName: node + linkType: hard + "bser@npm:^2.0.0": version: 2.0.0 resolution: "bser@npm:2.0.0" @@ -7282,13 +8071,6 @@ __metadata: languageName: node linkType: hard -"byline@npm:^5.0.0": - version: 5.0.0 - resolution: "byline@npm:5.0.0" - checksum: 10/737ca83e8eda2976728dae62e68bc733aea095fab08db4c6f12d3cee3cf45b6f97dce45d1f6b6ff9c2c947736d10074985b4425b31ce04afa1985a4ef3d334a7 - languageName: node - linkType: hard - "byte-size@npm:8.1.1": version: 8.1.1 resolution: "byte-size@npm:8.1.1" @@ -7408,6 +8190,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001688": + version: 1.0.30001692 + resolution: "caniuse-lite@npm:1.0.30001692" + checksum: 10/92449ec9e9ac6cd8ce7ecc18a8759ae34e4b3ef412acd998714ee9d70dc286bc8d0d6e4917fa454798da9b37667eb5b3b41386bc9d25e4274d0b9c7af8339b0e + languageName: node + linkType: hard + "capnp-ts@npm:^0.7.0": version: 0.7.0 resolution: "capnp-ts@npm:0.7.0" @@ -7626,10 +8415,10 @@ __metadata: languageName: node linkType: hard -"cjs-module-lexer@npm:^1.0.0": - version: 1.2.1 - resolution: "cjs-module-lexer@npm:1.2.1" - checksum: 10/52e82bd7be07d37a04a175c9cbd730890bcf5dd1262043d88f38e9885b388fdd29ede830b04346045e03fb987c1096e38487497eeab5128edce9f43e2ce3ced6 +"cjs-module-lexer@npm:^1.0.0, cjs-module-lexer@npm:^1.2.2": + version: 1.4.1 + resolution: "cjs-module-lexer@npm:1.4.1" + checksum: 10/6e830a1e00a34d416949bbc1924f3e8da65cef4a6a09e2b7fa35722e2d1c34bf378d3baca987b698d1cbc3eb83e44b044039b4e82755c96f30e0f03d1d227637 languageName: node linkType: hard @@ -8846,7 +9635,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.7, debug@npm:~4.4.0": +"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.7, debug@npm:~4.4.0": version: 4.4.0 resolution: "debug@npm:4.4.0" dependencies: @@ -9037,7 +9826,7 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.3": +"detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.2, detect-libc@npm:^2.0.3": version: 2.0.3 resolution: "detect-libc@npm:2.0.3" checksum: 10/b4ea018d623e077bd395f168a9e81db77370dde36a5b01d067f2ad7989924a81d31cb547ff764acb2aa25d50bb7fdde0b0a93bec02212b0cb430621623246d39 @@ -9186,6 +9975,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.3.1": + version: 16.4.7 + resolution: "dotenv@npm:16.4.7" + checksum: 10/f13bfe97db88f0df4ec505eeffb8925ec51f2d56a3d0b6d916964d8b4af494e6fb1633ba5d09089b552e77ab2a25de58d70259b2c5ed45ec148221835fc99a0c + languageName: node + linkType: hard + "dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1": version: 1.0.1 resolution: "dunder-proto@npm:1.0.1" @@ -9255,6 +10051,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.73": + version: 1.5.80 + resolution: "electron-to-chromium@npm:1.5.80" + checksum: 10/fa77236f05d1544d29ed71e3a787ad7d6da250fe0b5fc40aac0fcf46de9cb074d8a90a2b176f2245d2c4f2823b7ec2e95aafb0e29f612895b891d7ccfe43889a + languageName: node + linkType: hard + "embla-carousel-class-names@npm:^8.1.7": version: 8.1.7 resolution: "embla-carousel-class-names@npm:8.1.7" @@ -9457,15 +10260,6 @@ __metadata: languageName: node linkType: hard -"error-stack-parser@npm:^2.0.2, error-stack-parser@npm:^2.0.3": - version: 2.0.6 - resolution: "error-stack-parser@npm:2.0.6" - dependencies: - stackframe: "npm:^1.1.1" - checksum: 10/c83a0f425b73ed8bae4b05535f76477fdd4421e2cca398a2051719ac7eb5f918622d6313ef24f6ab6f64cbd38ebd1119bcb15cd792befbf2dd472d02062ff6d8 - languageName: node - linkType: hard - "es-abstract@npm:^1.17.5, es-abstract@npm:^1.19.0, es-abstract@npm:^1.22.1, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.6": version: 1.23.7 resolution: "es-abstract@npm:1.23.7" @@ -9784,6 +10578,13 @@ __metadata: languageName: node linkType: hard +"escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10/9d7169e3965b2f9ae46971afa392f6e5a25545ea30f2e2dd99c9b0a95a3f52b5653681a84f5b2911a413ddad2d7a93d3514165072f349b5ffc59c75a899970d6 + languageName: node + linkType: hard + "escape-html@npm:~1.0.3": version: 1.0.3 resolution: "escape-html@npm:1.0.3" @@ -10664,6 +11465,13 @@ __metadata: languageName: node linkType: hard +"forwarded-parse@npm:2.1.2": + version: 2.1.2 + resolution: "forwarded-parse@npm:2.1.2" + checksum: 10/fca4df8898248d123d9d29a9fdf48005dd757366c2c17c1e195e8311a9aa89caf9f5e592f58f7d3d635087675ff39e85c32c6205838510f6f1fa4109de519930 + languageName: node + linkType: hard + "forwarded@npm:0.2.0": version: 0.2.0 resolution: "forwarded@npm:0.2.0" @@ -11127,7 +11935,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^9.2.0": +"glob@npm:^9.2.0, glob@npm:^9.3.2": version: 9.3.5 resolution: "glob@npm:9.3.5" dependencies: @@ -11267,10 +12075,6 @@ __metadata: "@algolia/autocomplete-plugin-recent-searches": "npm:^1.17.2" "@algolia/autocomplete-theme-classic": "npm:^1.17.2" "@aws-sdk/client-s3": "npm:^3.626.0" - "@bugsnag/core": "npm:^8.0.0" - "@bugsnag/js": "npm:^8.0.0" - "@bugsnag/plugin-express": "npm:^8.0.0" - "@bugsnag/plugin-react": "npm:^8.0.0" "@dnd-kit/core": "npm:^6.1.0" "@eslint/js": "npm:^9.17.0" "@fortawesome/fontawesome-svg-core": "npm:^6.5.2" @@ -11286,7 +12090,10 @@ __metadata: "@ourworldindata/utils": "workspace:^" "@react-awesome-query-builder/antd": "npm:^6.6.0" "@rmp135/sql-ts": "npm:^2.1.0" - "@sentry/react": "npm:^8.36.0" + "@sentry/node": "npm:^8.48.0" + "@sentry/profiling-node": "npm:^8.48.0" + "@sentry/react": "npm:^8.48.0" + "@sentry/vite-plugin": "npm:^2.23.0" "@sinclair/typebox": "npm:^0.28.5" "@slack/web-api": "npm:^7.1.0" "@testing-library/jest-dom": "npm:^6.1.3" @@ -11978,6 +12785,18 @@ __metadata: languageName: node linkType: hard +"import-in-the-middle@npm:^1.11.2, import-in-the-middle@npm:^1.8.1": + version: 1.12.0 + resolution: "import-in-the-middle@npm:1.12.0" + dependencies: + acorn: "npm:^8.8.2" + acorn-import-attributes: "npm:^1.9.5" + cjs-module-lexer: "npm:^1.2.2" + module-details-from-path: "npm:^1.0.3" + checksum: 10/73f3f0ad8c3fceb90bcf308e84609290fe912af32a4be12fce2bf1fde28a0cb12d7219e15e8fe9e8d7ceafcb115a49a66566c2fd973d0a08e33437b00dfce3f9 + languageName: node + linkType: hard + "import-local@npm:3.1.0, import-local@npm:^3.0.2": version: 3.1.0 resolution: "import-local@npm:3.1.0" @@ -12691,13 +13510,6 @@ __metadata: languageName: node linkType: hard -"iserror@npm:0.0.2, iserror@npm:^0.0.2": - version: 0.0.2 - resolution: "iserror@npm:0.0.2" - checksum: 10/6ca5e50d779471dbb69455ce6853a8284a2a077ff9b7130133a1d09f071830653274884a1e5271b55a422a33e128790a3a7c3e73b2648cf5398d3cbdeb5ca889 - languageName: node - linkType: hard - "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -13412,6 +14224,15 @@ __metadata: languageName: node linkType: hard +"jsesc@npm:^3.0.2": + version: 3.1.0 + resolution: "jsesc@npm:3.1.0" + bin: + jsesc: bin/jsesc + checksum: 10/20bd37a142eca5d1794f354db8f1c9aeb54d85e1f5c247b371de05d23a9751ecd7bd3a9c4fc5298ea6fa09a100dafb4190fa5c98c6610b75952c3487f3ce7967 + languageName: node + linkType: hard + "json-bigint@npm:^1.0.0": version: 1.0.0 resolution: "json-bigint@npm:1.0.0" @@ -14189,6 +15010,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:0.30.8": + version: 0.30.8 + resolution: "magic-string@npm:0.30.8" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.4.15" + checksum: 10/72ab63817af600e92c19dc8489c1aa4a9599da00cfd59b2319709bd48fb0cf533fdf354bf140ac86e598dbd63e6b2cc83647fe8448f864a3eb6061c62c94e784 + languageName: node + linkType: hard + "magic-string@npm:^0.25.3": version: 0.25.9 resolution: "magic-string@npm:0.25.9" @@ -14791,6 +15621,13 @@ __metadata: languageName: node linkType: hard +"module-details-from-path@npm:^1.0.3": + version: 1.0.3 + resolution: "module-details-from-path@npm:1.0.3" + checksum: 10/f93226e9154fc8cb91f4609b639167ec7ad9155b30be4924d9717656648a3ae5f181d4e2338434d4c5afc7b5f4c10dd3b64109e5b89a4be70b20a25ba3573d54 + languageName: node + linkType: hard + "moment@npm:2.30.1, moment@npm:>=2.14.0, moment@npm:^2.30.1": version: 2.30.1 resolution: "moment@npm:2.30.1" @@ -14952,6 +15789,15 @@ __metadata: languageName: node linkType: hard +"node-abi@npm:^3.61.0": + version: 3.71.0 + resolution: "node-abi@npm:3.71.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10/0a1cef5106c43d67f9f8a911b0c9d5ee08971eda002ba466606c8e6164964456f5211f37966717efc3d5d49bae32f0cf9290254b1286bf71f0ba158a4f8a9846 + languageName: node + linkType: hard + "node-addon-api@npm:^5.0.0": version: 5.1.0 resolution: "node-addon-api@npm:5.1.0" @@ -15044,6 +15890,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.19": + version: 2.0.19 + resolution: "node-releases@npm:2.0.19" + checksum: 10/c2b33b4f0c40445aee56141f13ca692fa6805db88510e5bbb3baadb2da13e1293b738e638e15e4a8eb668bb9e97debb08e7a35409b477b5cc18f171d35a83045 + languageName: node + linkType: hard + "nodejs-polars-darwin-arm64@npm:0.7.2": version: 0.7.2 resolution: "nodejs-polars-darwin-arm64@npm:0.7.2" @@ -15498,6 +16351,13 @@ __metadata: languageName: node linkType: hard +"obuf@npm:~1.1.2": + version: 1.1.2 + resolution: "obuf@npm:1.1.2" + checksum: 10/53ff4ab3a13cc33ba6c856cf281f2965c0aec9720967af450e8fd06cfd50aceeefc791986a16bcefa14e7898b3ca9acdfcf15b9d9a1b9c7e1366581a8ad6e65e + languageName: node + linkType: hard + "ohash@npm:^1.1.4": version: 1.1.4 resolution: "ohash@npm:1.1.4" @@ -16100,6 +16960,55 @@ __metadata: languageName: node linkType: hard +"pg-int8@npm:1.0.1": + version: 1.0.1 + resolution: "pg-int8@npm:1.0.1" + checksum: 10/a1e3a05a69005ddb73e5f324b6b4e689868a447c5fa280b44cd4d04e6916a344ac289e0b8d2695d66e8e89a7fba023affb9e0e94778770ada5df43f003d664c9 + languageName: node + linkType: hard + +"pg-numeric@npm:1.0.2": + version: 1.0.2 + resolution: "pg-numeric@npm:1.0.2" + checksum: 10/8899f8200caa1744439a8778a9eb3ceefb599d893e40a09eef84ee0d4c151319fd416634a6c0fc7b7db4ac268710042da5be700b80ef0de716fe089b8652c84f + languageName: node + linkType: hard + +"pg-protocol@npm:*": + version: 1.7.0 + resolution: "pg-protocol@npm:1.7.0" + checksum: 10/ffffdf74426c9357b57050f1c191e84447c0e8b2a701b3ab302ac7dd0eb27b862d92e5e3b2d38876a1051de83547eb9165d6a58b3a8e90bb050dae97f9993d54 + languageName: node + linkType: hard + +"pg-types@npm:^2.2.0": + version: 2.2.0 + resolution: "pg-types@npm:2.2.0" + dependencies: + pg-int8: "npm:1.0.1" + postgres-array: "npm:~2.0.0" + postgres-bytea: "npm:~1.0.0" + postgres-date: "npm:~1.0.4" + postgres-interval: "npm:^1.1.0" + checksum: 10/87a84d4baa91378d3a3da6076c69685eb905d1087bf73525ae1ba84b291b9dd8738c6716b333d8eac6cec91bf087237adc3e9281727365e9cbab0d9d072778b1 + languageName: node + linkType: hard + +"pg-types@npm:^4.0.1": + version: 4.0.2 + resolution: "pg-types@npm:4.0.2" + dependencies: + pg-int8: "npm:1.0.1" + pg-numeric: "npm:1.0.2" + postgres-array: "npm:~3.0.1" + postgres-bytea: "npm:~3.0.0" + postgres-date: "npm:~2.1.0" + postgres-interval: "npm:^3.0.0" + postgres-range: "npm:^1.1.1" + checksum: 10/f4d529da864d4169afab300eb8629a84a6a06aa70c471160a7e46c34b6d4dd0e61cbd57d10d98c3a36e98f474e2ff85d41e4b1c953a321146b4bae09372c58d3 + languageName: node + linkType: hard + "picocolors@npm:^1.0.0, picocolors@npm:^1.0.1, picocolors@npm:^1.1.0": version: 1.1.0 resolution: "picocolors@npm:1.1.0" @@ -16107,6 +17016,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 + languageName: node + linkType: hard + "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" @@ -16238,6 +17154,73 @@ __metadata: languageName: node linkType: hard +"postgres-array@npm:~2.0.0": + version: 2.0.0 + resolution: "postgres-array@npm:2.0.0" + checksum: 10/aff99e79714d1271fe942fec4ffa2007b755e7e7dc3d2feecae3f1ceecb86fd3637c8138037fc3d9e7ec369231eeb136843c0b25927bf1ce295245a40ef849b4 + languageName: node + linkType: hard + +"postgres-array@npm:~3.0.1": + version: 3.0.2 + resolution: "postgres-array@npm:3.0.2" + checksum: 10/0159517e4e5f263bf9e324f0c4d3c10244a294021f2b5980abc8c23afdb965370a7fc0c82012fce4d28e83186ad089b6476b05fcef6c88f8e43e37a3a2fa0ad5 + languageName: node + linkType: hard + +"postgres-bytea@npm:~1.0.0": + version: 1.0.0 + resolution: "postgres-bytea@npm:1.0.0" + checksum: 10/d844ae4ca7a941b70e45cac1261a73ee8ed39d72d3d74ab1d645248185a1b7f0ac91a3c63d6159441020f4e1f7fe64689ac56536a307b31cef361e5187335090 + languageName: node + linkType: hard + +"postgres-bytea@npm:~3.0.0": + version: 3.0.0 + resolution: "postgres-bytea@npm:3.0.0" + dependencies: + obuf: "npm:~1.1.2" + checksum: 10/f5c01758fd2fa807afbd34e1ba2146f683818ebc2d23f4a62f0fd627c0b1126fc543cab1b63925f97ce6c7d8f5f316043218619c447445210ea82f10411efb1b + languageName: node + linkType: hard + +"postgres-date@npm:~1.0.4": + version: 1.0.7 + resolution: "postgres-date@npm:1.0.7" + checksum: 10/571ef45bec4551bb5d608c31b79987d7a895141f7d6c7b82e936a52d23d97474c770c6143e5cf8936c1cdc8b0dfd95e79f8136bf56a90164182a60f242c19f2b + languageName: node + linkType: hard + +"postgres-date@npm:~2.1.0": + version: 2.1.0 + resolution: "postgres-date@npm:2.1.0" + checksum: 10/faa1c70dfad0e35bd4aa7cb6088fcd4e4f039aa25dc42150129178fc2a0baa7e37eca0bf18e4142a40dea18d1955459b08783f78ec487ef27b4b93ab5e854597 + languageName: node + linkType: hard + +"postgres-interval@npm:^1.1.0": + version: 1.2.0 + resolution: "postgres-interval@npm:1.2.0" + dependencies: + xtend: "npm:^4.0.0" + checksum: 10/746b71f93805ae33b03528e429dc624706d1f9b20ee81bf743263efb6a0cd79ae02a642a8a480dbc0f09547b4315ab7df6ce5ec0be77ed700bac42730f5c76b2 + languageName: node + linkType: hard + +"postgres-interval@npm:^3.0.0": + version: 3.0.0 + resolution: "postgres-interval@npm:3.0.0" + checksum: 10/c7a1cf006de97de663b6b8c4d2b167aa9909a238c4866a94b15d303762f5ac884ff4796cd6e2111b7f0a91302b83c570453aa8506fd005b5a5d5dfa87441bebc + languageName: node + linkType: hard + +"postgres-range@npm:^1.1.1": + version: 1.1.4 + resolution: "postgres-range@npm:1.1.4" + checksum: 10/035759f17b44bf9ba7e71a30402ed2ca1e2b7fabb3ad794b08169a5b453d38d06905a6dfb51fe41a3f6d9fac4e183dac9e769b95053053db933be16785edce1f + languageName: node + linkType: hard + "preact@npm:^10.10.0, preact@npm:^10.13.2": version: 10.17.0 resolution: "preact@npm:10.17.0" @@ -17808,6 +18791,17 @@ __metadata: languageName: node linkType: hard +"require-in-the-middle@npm:^7.1.1": + version: 7.4.0 + resolution: "require-in-the-middle@npm:7.4.0" + dependencies: + debug: "npm:^4.3.5" + module-details-from-path: "npm:^1.0.3" + resolve: "npm:^1.22.8" + checksum: 10/0ca30ad6a6183423f38599709fc8a670682db85b581a66cb31ea31342e8ba2ce7dca44ee29e8cfe4fb59ffcb0c2b0f9b77d44a10cdc7535c7c2907028e53afbf + languageName: node + linkType: hard + "requires-port@npm:^1.0.0": version: 1.0.0 resolution: "requires-port@npm:1.0.0" @@ -18312,7 +19306,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3": +"semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3": version: 7.6.3 resolution: "semver@npm:7.6.3" bin: @@ -18527,6 +19521,13 @@ __metadata: languageName: node linkType: hard +"shimmer@npm:^1.2.1": + version: 1.2.1 + resolution: "shimmer@npm:1.2.1" + checksum: 10/aa0d6252ad1c682a4fdfda69e541be987f7a265ac7b00b1208e5e48cc68dc55f293955346ea4c71a169b7324b82c70f8400b3d3d2d60b2a7519f0a3522423250 + languageName: node + linkType: hard + "side-channel-list@npm:^1.0.0": version: 1.0.0 resolution: "side-channel-list@npm:1.0.0" @@ -18903,15 +19904,6 @@ __metadata: languageName: node linkType: hard -"stack-generator@npm:^2.0.3": - version: 2.0.5 - resolution: "stack-generator@npm:2.0.5" - dependencies: - stackframe: "npm:^1.1.1" - checksum: 10/3c7b925c34b93f1528e334f1ed5fe4d7a5d4874589cb63ce539f569e9c76649037b7848be953b24f3c46865584425281fc51925e42c87b7fec128ad646ccae97 - languageName: node - linkType: hard - "stack-utils@npm:^2.0.3": version: 2.0.3 resolution: "stack-utils@npm:2.0.3" @@ -18921,13 +19913,6 @@ __metadata: languageName: node linkType: hard -"stackframe@npm:^1.1.1": - version: 1.2.0 - resolution: "stackframe@npm:1.2.0" - checksum: 10/159c520470aeba7c9b889adcd1615d708fbceae64f6afabba9d1ecdf4ff2ee248bd5d612f778ffd15502a50d237c8a6638690f834d596499462d0c29970cac5e - languageName: node - linkType: hard - "stacktracey@npm:^2.1.8": version: 2.1.8 resolution: "stacktracey@npm:2.1.8" @@ -20201,6 +21186,18 @@ __metadata: languageName: node linkType: hard +"unplugin@npm:1.0.1": + version: 1.0.1 + resolution: "unplugin@npm:1.0.1" + dependencies: + acorn: "npm:^8.8.1" + chokidar: "npm:^3.5.3" + webpack-sources: "npm:^3.2.3" + webpack-virtual-modules: "npm:^0.5.0" + checksum: 10/59f0d29c634adbc56e7e770f9753bff9ec52c479ff837b798354ec5d1b2e8cb971412645df43eb14a698db5bff4db23634c1506657e24d1ba86f4a8f27c1bf87 + languageName: node + linkType: hard + "untildify@npm:^4.0.0": version: 4.0.0 resolution: "untildify@npm:4.0.0" @@ -20229,6 +21226,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.1.1": + version: 1.1.2 + resolution: "update-browserslist-db@npm:1.1.2" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10/e7bf8221dfb21eba4a770cd803df94625bb04f65a706aa94c567de9600fe4eb6133fda016ec471dad43b9e7959c1bffb6580b5e20a87808d2e8a13e3892699a9 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -20669,6 +21680,20 @@ __metadata: languageName: node linkType: hard +"webpack-sources@npm:^3.2.3": + version: 3.2.3 + resolution: "webpack-sources@npm:3.2.3" + checksum: 10/a661f41795d678b7526ae8a88cd1b3d8ce71a7d19b6503da8149b2e667fc7a12f9b899041c1665d39e38245ed3a59ab68de648ea31040c3829aa695a5a45211d + languageName: node + linkType: hard + +"webpack-virtual-modules@npm:^0.5.0": + version: 0.5.0 + resolution: "webpack-virtual-modules@npm:0.5.0" + checksum: 10/65a8f90c7e6609ba1c4ad2697bb83ae662485893fb545f6aa9a74e3a5d7485bbc50ef057c5bc3feca25d3153ebf9c097c233cbe4d67b52418bc84348dfb20c1a + languageName: node + linkType: hard + "whatwg-encoding@npm:^2.0.0": version: 2.0.0 resolution: "whatwg-encoding@npm:2.0.0" @@ -20755,7 +21780,7 @@ __metadata: languageName: node linkType: hard -"which@npm:^2.0.1": +"which@npm:^2.0.1, which@npm:^2.0.2": version: 2.0.2 resolution: "which@npm:2.0.2" dependencies: