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/adminSiteServer/apiRouter.ts b/adminSiteServer/apiRouter.ts
index 5cf0e042bc3..534d3cd5881 100644
--- a/adminSiteServer/apiRouter.ts
+++ b/adminSiteServer/apiRouter.ts
@@ -155,7 +155,7 @@ import {
getPublishingAction,
} from "../adminSiteClient/gdocsDeploy.js"
import { createGdocAndInsertOwidGdocPostContent } from "../db/model/Gdoc/archieToGdoc.js"
-import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js"
+import { logErrorAndMaybeCaptureInSentry } from "../serverUtils/errorLog.js"
import {
getRouteWithROTransaction,
deleteRouteWithRWTransaction,
@@ -2158,7 +2158,7 @@ putRouteWithRWTransaction(
await db.knexRaw(trx, `DELETE FROM dataset_tags WHERE datasetId=?`, [
datasetId,
])
- if (tagRows.length)
+ if (tagRows.length) {
for (const tagRow of tagRows) {
await db.knexRaw(
trx,
@@ -2166,6 +2166,7 @@ putRouteWithRWTransaction(
tagRow
)
}
+ }
try {
await syncDatasetToGitRepo(trx, datasetId, {
@@ -2174,7 +2175,7 @@ putRouteWithRWTransaction(
commitEmail: res.locals.user.email,
})
} catch (err) {
- await logErrorAndMaybeSendToBugsnag(err, req)
+ await logErrorAndMaybeCaptureInSentry(err)
// Continue
}
@@ -2240,7 +2241,7 @@ deleteRouteWithRWTransaction(
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/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..6ff1356f22e 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,
@@ -641,17 +641,17 @@ export class SiteBaker {
errorOrWarning.type === OwidGdocErrorMessageType.Error
? `Error baking "${publishedGdoc.slug}"`
: `Warning baking "${publishedGdoc.slug}"`
- await logErrorAndMaybeSendToBugsnag(
- `${announcement}: ${errorOrWarning.message}`,
- undefined,
- errorOrWarning.message
+ await logErrorAndMaybeCaptureInSentry(
+ new Error(`${announcement}: ${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 +670,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 +810,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 +848,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(", ")}`
+ )
)
}
@@ -894,17 +902,17 @@ export class SiteBaker {
errorOrWarning.type === OwidGdocErrorMessageType.Error
? `Error baking "data-insight/${dataInsight.slug}"`
: `Warning baking "data-insight/${dataInsight.slug}"`
- await logErrorAndMaybeSendToBugsnag(
- `${announcement}: ${errorOrWarning.message}`,
- undefined,
- errorOrWarning.message
+ await logErrorAndMaybeCaptureInSentry(
+ new Error(`${announcement}: ${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 +983,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 +1052,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/gitCms/GitCmsServer.ts b/gitCms/GitCmsServer.ts
index 23b5253cd9d..5adbf457ef5 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
@@ -203,7 +203,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() }
}
}
@@ -247,7 +247,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..572d12b7a64 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,9 @@
"@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",
"@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..6f46a05be92
--- /dev/null
+++ b/serverUtils/instrument.ts
@@ -0,0 +1,11 @@
+import * as Sentry from "@sentry/node"
+import { nodeProfilingIntegration } from "@sentry/profiling-node"
+
+// 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,
+})
diff --git a/settings/clientSettings.ts b/settings/clientSettings.ts
index 318caa166ee..76e6e0b9b9b 100644
--- a/settings/clientSettings.ts
+++ b/settings/clientSettings.ts
@@ -18,8 +18,6 @@ import { parseIntOrUndefined } from "@ourworldindata/utils"
export const ENV: "development" | "production" =
process.env.ENV === "production" ? "production" : "development"
-export const BUGSNAG_API_KEY: string | undefined = process.env.BUGSNAG_API_KEY
-export const SENTRY_DSN: string | undefined = process.env.SENTRY_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 51959210ada..0e443bdfb31 100644
--- a/settings/serverSettings.ts
+++ b/settings/serverSettings.ts
@@ -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 e68f8d47a27..f30a3577010 100644
--- a/site/DataCatalog/DataCatalog.tsx
+++ b/site/DataCatalog/DataCatalog.tsx
@@ -62,7 +62,6 @@ import {
TOUCH_DEVICE_MEDIA_QUERY,
} from "../SiteConstants.js"
import { SiteAnalytics } from "../SiteAnalytics.js"
-import Bugsnag from "@bugsnag/js"
const analytics = new SiteAnalytics()
@@ -869,9 +868,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..91bd0211d74
--- /dev/null
+++ b/site/instrument.ts
@@ -0,0 +1,34 @@
+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: environment,
+ ...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/vite.config-common.mts b/vite.config-common.mts
index 2e51f842202..dca9ef7938f 100644
--- a/vite.config-common.mts
+++ b/vite.config-common.mts
@@ -34,7 +34,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]) => [
diff --git a/yarn.lock b/yarn.lock
index 754e95b69dc..c558f9a6385 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1437,87 +1437,6 @@ __metadata:
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"
- 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
- 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
- languageName: node
- linkType: hard
-
"@cloudflare/kv-asset-handler@npm:0.3.4":
version: 0.3.4
resolution: "@cloudflare/kv-asset-handler@npm:0.3.4"
@@ -3505,6 +3424,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 +3918,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 +3976,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 +3984,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 +4092,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"
@@ -4052,105 +4426,147 @@ __metadata:
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"
+"@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.36.0"
- "@sentry/types": "npm:8.36.0"
- "@sentry/utils": "npm:8.36.0"
- checksum: 10/f886260292e22dd936fbd7d2f4bb1325e3197a418a88b352f064517286677b68e26a993a9cac908faac344f4ea460074578b73fff91746a9f65e18b7c44e0dc6
+ "@sentry/core": "npm:8.48.0"
+ checksum: 10/49feb55a2ba2ed8317b35b8ed7440a9bec6800270387c990d98db35ef0958f6b46640378a9384e5cb657fbef093b7de7b6633c4cd96078f5b820102811fe7c8e
languageName: node
linkType: hard
-"@sentry-internal/feedback@npm:8.36.0":
- version: 8.36.0
- resolution: "@sentry-internal/feedback@npm:8.36.0"
+"@sentry-internal/feedback@npm:8.48.0":
+ version: 8.48.0
+ resolution: "@sentry-internal/feedback@npm:8.48.0"
dependencies:
- "@sentry/core": "npm:8.36.0"
- "@sentry/types": "npm:8.36.0"
- "@sentry/utils": "npm:8.36.0"
- checksum: 10/72cb38adae9939ce90963044cfc39051de0f2c8e037efb6c416299afd7ce66d63374f63c549ed054c245bb93ff337bb2a3eaba532dbad2a712b5a9910af3e4a5
+ "@sentry/core": "npm:8.48.0"
+ checksum: 10/50dbe4c6a1eff4c961be0a63966d874c8194e00652fdf7a544dfd1a46a27e2780ce7f21bc27f4a47f05985624fa2a43f676f67db06ae6dc7405775459efd46e2
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"
+"@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.36.0"
- "@sentry/core": "npm:8.36.0"
- "@sentry/types": "npm:8.36.0"
- "@sentry/utils": "npm:8.36.0"
- checksum: 10/f7725523339dfadadd55a2c025de82d73b2035b65b1bf34395997204bbd69e4665fcf94e90fb53b279c2bb1c005729f0ef9fb4d9946a20fa542b6cd9d2d2e9ea
+ "@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.36.0":
- version: 8.36.0
- resolution: "@sentry-internal/replay@npm:8.36.0"
+"@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.36.0"
- "@sentry/core": "npm:8.36.0"
- "@sentry/types": "npm:8.36.0"
- "@sentry/utils": "npm:8.36.0"
- checksum: 10/558f9f277aef5232c43ce0711d85aa8ca8ed584435c9bbe7e08e59c3af2ed1da137d104b47e6f5c32b69b5b78ed516e627ec096ee4a950f2492c43fcf4a78170
+ "@sentry-internal/browser-utils": "npm:8.48.0"
+ "@sentry/core": "npm:8.48.0"
+ checksum: 10/be7560dc7d82ab716a310ed47076009ba53a3b6ce9a4d0bfdd987da9256edef56afda9f4c2833a808cad935a47b2e3b8e2f97e2bd36975bf82eb2b4be17c00f6
languageName: node
linkType: hard
-"@sentry/browser@npm:8.36.0":
- version: 8.36.0
- resolution: "@sentry/browser@npm:8.36.0"
+"@sentry/browser@npm:8.48.0":
+ version: 8.48.0
+ resolution: "@sentry/browser@npm:8.48.0"
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-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/core@npm:8.48.0":
+ version: 8.48.0
+ resolution: "@sentry/core@npm:8.48.0"
+ checksum: 10/1fff8fc1e0681459240ceda5a3b2a7402f7ac73da9fa72e3d6e57e8f994ac246b240739ee0f224d48646bf410980aac4213c3e334e1dcbbd806ed5f496c7bb3c
languageName: node
linkType: hard
-"@sentry/core@npm:8.36.0":
- version: 8.36.0
- resolution: "@sentry/core@npm:8.36.0"
+"@sentry/node@npm:8.48.0, @sentry/node@npm:^8.48.0":
+ version: 8.48.0
+ resolution: "@sentry/node@npm:8.48.0"
dependencies:
- "@sentry/types": "npm:8.36.0"
- "@sentry/utils": "npm:8.36.0"
- checksum: 10/26d9a926c6a76526cc3ed895370604c88a7fb9f152866362cb0eef348fcada9ae78706a678f081ed26b0bb29fd0293627d458dbc598b630962550ce4924c584d
+ "@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/react@npm:^8.36.0":
- version: 8.36.0
- resolution: "@sentry/react@npm:8.36.0"
+"@sentry/opentelemetry@npm:8.48.0":
+ version: 8.48.0
+ resolution: "@sentry/opentelemetry@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"
- hoist-non-react-statics: "npm:^3.3.2"
+ "@sentry/core": "npm:8.48.0"
peerDependencies:
- react: ^16.14.0 || 17.x || 18.x || 19.x
- checksum: 10/c5edf3f4cb53e7fcecd3aa11512e125b90531ae41f04c2ade26f052e3138f217b3e254433eb28776d5b845f98fe7678e7961dc7770c063e62f8eda61868bc191
+ "@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/types@npm:8.36.0":
- version: 8.36.0
- resolution: "@sentry/types@npm:8.36.0"
- checksum: 10/6c91218f5355e5d9396cf863d66c21edd305075ea5408e31ca52dbc0eae5e39a1247882d515856f9ad05fb7c5f0509c184c048a26086f23dfd41ef4a4eeeb38b
+"@sentry/profiling-node@npm:^8.48.0":
+ version: 8.48.0
+ resolution: "@sentry/profiling-node@npm:8.48.0"
+ dependencies:
+ "@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/utils@npm:8.36.0":
- version: 8.36.0
- resolution: "@sentry/utils@npm:8.36.0"
+"@sentry/react@npm:^8.48.0":
+ version: 8.48.0
+ resolution: "@sentry/react@npm:8.48.0"
dependencies:
- "@sentry/types": "npm:8.36.0"
- checksum: 10/5b58bb34ed4e13b71f322a4455702ae5dab7b597410ac7774abce0dd67dcc84ee088be05e1c8d694ec795b8a84baad0467e31afd0c8026aaacac93f8b5a3701f
+ "@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/d0fe2252171106025d82c4eca2331de3942f83f81aaee7716286de4a424ece92e52b220bc38496c0f900286e47e4be7a44ea307743696ac61bb160a86a4eb696
languageName: node
linkType: hard
@@ -5083,12 +5499,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 +6076,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 +6134,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 +6367,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 +6402,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 +6783,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 +6808,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:
@@ -7282,13 +7763,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"
@@ -7626,10 +8100,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 +9320,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 +9511,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
@@ -9457,15 +9931,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"
@@ -10664,6 +11129,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"
@@ -11267,10 +11739,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 +11754,9 @@ __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"
"@sinclair/typebox": "npm:^0.28.5"
"@slack/web-api": "npm:^7.1.0"
"@testing-library/jest-dom": "npm:^6.1.3"
@@ -11978,6 +12448,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 +13173,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"
@@ -14791,6 +15266,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 +15434,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"
@@ -15498,6 +15989,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 +16598,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"
@@ -16238,6 +16785,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 +18422,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 +18937,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 +19152,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 +19535,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 +19544,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"