From 41dcff1709ac33440e2844bb9e9ec6245b027464 Mon Sep 17 00:00:00 2001 From: Matt Isenhower Date: Sat, 5 Sep 2026 10:23:35 -0700 Subject: [PATCH] Report updater errors through @sentry/core The updaters run in the container today and in a Worker next, and @sentry/node cannot be bundled into a Worker. Both @sentry/node and @sentry/cloudflare are built on @sentry/core, where captureException lives, so the updater base class imports from core and lands on whichever client the entry point initialized. The Node entry point keeps initializing @sentry/node; the Worker will use @sentry/cloudflare. The two packages must stay on the same version: Sentry keys its global carrier by version, and a split silently drops events. A test pins the routing. Co-Authored-By: Claude Fable 5.1 --- package-lock.json | 91 +++++++++++++++-------------- package.json | 3 +- src/app/updater/updaters/Updater.js | 2 +- test/sentry.test.js | 20 +++++++ 4 files changed, 69 insertions(+), 47 deletions(-) create mode 100644 test/sentry.test.js diff --git a/package-lock.json b/package-lock.json index 5a48586..cf9c200 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,8 @@ "dependencies": { "@atproto/api": "^0.20.42", "@aws-sdk/client-s3": "^3.1121.0", - "@sentry/node": "^10.72.0", + "@sentry/core": "^10.73.0", + "@sentry/node": "^10.73.0", "bulma": "^0.9.4", "bulma-tooltip": "^3.0.2", "console-stamp": "^3.1.2", @@ -3961,9 +3962,9 @@ } }, "node_modules/@opentelemetry/core": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.10.0.tgz", - "integrity": "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.11.0.tgz", + "integrity": "sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" @@ -3993,12 +3994,12 @@ } }, "node_modules/@opentelemetry/resources": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.10.0.tgz", - "integrity": "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.11.0.tgz", + "integrity": "sha512-Ie7+8q8MDF4FAEQCKVMTx3ReUvxiIAgIiiW3c9JdmP8+HMcDy20puT+AHjexnExgnbvBxjQ9fjkFDWrikJ2jQA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.10.0", + "@opentelemetry/core": "2.11.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -4009,13 +4010,13 @@ } }, "node_modules/@opentelemetry/sdk-trace": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace/-/sdk-trace-2.10.0.tgz", - "integrity": "sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace/-/sdk-trace-2.11.0.tgz", + "integrity": "sha512-fFnTqGm8/G73GQVnxYi7LXa1ZVYEUvgL6XI1LpvV0bPC7WQ/ZGgKxCSl8FnlZBKto9JHHEFTO6s6CUpvvtwFrA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.10.0", - "@opentelemetry/resources": "2.10.0", + "@opentelemetry/core": "2.11.0", + "@opentelemetry/resources": "2.11.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -4026,14 +4027,14 @@ } }, "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.10.0.tgz", - "integrity": "sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.11.0.tgz", + "integrity": "sha512-H19x/TX/LZdqiYOjM7fqtSxwlplC5pgelavqbQdHbhdq0q/AI/TGkM2dfGuuynTXmJPeF2HoZVoPDu+TGoW78A==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.10.0", - "@opentelemetry/resources": "2.10.0", - "@opentelemetry/sdk-trace": "2.10.0", + "@opentelemetry/core": "2.11.0", + "@opentelemetry/resources": "2.11.0", + "@opentelemetry/sdk-trace": "2.11.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -4865,9 +4866,9 @@ } }, "node_modules/@sentry/core": { - "version": "10.72.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.72.0.tgz", - "integrity": "sha512-UJMHZfbjP4qk+g4AQhZmzosMdICC2D9p0/hLrm1LofPsp+WBfcSnv9jsY1a9TfmpS4WCAmTx8nANYTIXifcBjA==", + "version": "10.73.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.73.0.tgz", + "integrity": "sha512-FLO1UgH19RyasVpofu612WCOgb2nEH0dZy+R72d7p65XU9i0wxlMKm3+sgfwKmiSJp1Qhilaaxs4Jg6BbiM5HA==", "license": "MIT", "dependencies": { "@sentry/conventions": "^0.16.0" @@ -4877,19 +4878,19 @@ } }, "node_modules/@sentry/node": { - "version": "10.72.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.72.0.tgz", - "integrity": "sha512-eQHQFxSX26MhG/nB+tAY4QRslnPvJse7pww/hd3zXAqNULRa5lFtjSLALcHx/KUVDCZdTPdUVZEj4nGidcHrow==", + "version": "10.73.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.73.0.tgz", + "integrity": "sha512-jiMJ6GgXDw6UMGzJY+o0c8OoeA9OfHqZ/xEpHfDqy75hn+9CEkRkbNGCIdMvsc7wW/Se1Os394hHfTpU+YEskg==", "license": "MIT", "dependencies": { "@opentelemetry/api": "^1.9.1", "@opentelemetry/instrumentation": "^0.220.0", "@opentelemetry/sdk-trace-base": "^2.9.0", "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.72.0", - "@sentry/node-core": "10.72.0", - "@sentry/opentelemetry": "10.72.0", - "@sentry/server-utils": "10.72.0", + "@sentry/core": "10.73.0", + "@sentry/node-core": "10.73.0", + "@sentry/opentelemetry": "10.73.0", + "@sentry/server-utils": "10.73.0", "import-in-the-middle": "^3.0.0" }, "engines": { @@ -4897,14 +4898,14 @@ } }, "node_modules/@sentry/node-core": { - "version": "10.72.0", - "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.72.0.tgz", - "integrity": "sha512-xYuYWmWEWnN8h3YHa7mds212ANFgrxfrbmLvVg0p0wf9m6MFjLowOTmjaiK0XW20sM/veSelicre650bx8UFtQ==", + "version": "10.73.0", + "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.73.0.tgz", + "integrity": "sha512-GHAGUmZPmm6FKfxfv2maVVJ/A99YAmd7oFOuKMDmITI6O/Msl6JB3vPTEpopVAHLW0LYJQBOjddL9C7o+Jt44g==", "license": "MIT", "dependencies": { "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.72.0", - "@sentry/opentelemetry": "10.72.0", + "@sentry/core": "10.73.0", + "@sentry/opentelemetry": "10.73.0", "import-in-the-middle": "^3.0.0" }, "engines": { @@ -4936,13 +4937,13 @@ } }, "node_modules/@sentry/opentelemetry": { - "version": "10.72.0", - "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.72.0.tgz", - "integrity": "sha512-ZVbAM1rGU/awN7cH/jvC87WpQw0NOJx5id6dKnnefStXpP/kUnZXYhtX9gfBnofYvJWa5I5VUSeuKCLUcKL75w==", + "version": "10.73.0", + "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.73.0.tgz", + "integrity": "sha512-fQouPQKsH0CQrw6oAn1k0Z2I+tgyochCovifr5qNS69i0OzjknLa03WJyiZ/IuzXc4AVa5jAKfOeE9slABz8Qw==", "license": "MIT", "dependencies": { "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.72.0" + "@sentry/core": "10.73.0" }, "engines": { "node": ">=18" @@ -4954,13 +4955,13 @@ } }, "node_modules/@sentry/server-utils": { - "version": "10.72.0", - "resolved": "https://registry.npmjs.org/@sentry/server-utils/-/server-utils-10.72.0.tgz", - "integrity": "sha512-CWpHMYW81RDBSVBdnxulGUvvBhkBb/OpSr72ubSe1UkKTcgT0NDMCWxE3dLFXqSxzT4DaF5UlUVv9ii5Sse53w==", + "version": "10.73.0", + "resolved": "https://registry.npmjs.org/@sentry/server-utils/-/server-utils-10.73.0.tgz", + "integrity": "sha512-QskripdKFbM/+gipC6mpa2crLwL7+VbkX84IpHg2z9UlYQ1kNKd3aMT+Qk9NLRSw/zu1rSIAvlbWfx4D3rgNAA==", "license": "MIT", "dependencies": { "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.72.0" + "@sentry/core": "10.73.0" }, "engines": { "node": ">=18" @@ -10225,9 +10226,9 @@ } }, "node_modules/import-in-the-middle": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.3.3.tgz", - "integrity": "sha512-AiohS3H80sXO6owEltjGX+glb7qXaDhBoJb9XcQVH4UI207xu/bDLUcadVKp7Qe576reg9yr/PXZjV5qx8gfbA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.4.0.tgz", + "integrity": "sha512-Xfjwfarhe+LGmoaof+sexeNo3sGRysb5x56WrZLwHtmqT0OilSKtVWkv0lrCcMgSKyKP9oBogBAisHZvtJH0aw==", "license": "Apache-2.0", "dependencies": { "cjs-module-lexer": "^2.2.0", diff --git a/package.json b/package.json index b989fa4..15dcaef 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "dependencies": { "@atproto/api": "^0.20.42", "@aws-sdk/client-s3": "^3.1121.0", - "@sentry/node": "^10.72.0", + "@sentry/core": "^10.73.0", + "@sentry/node": "^10.73.0", "bulma": "^0.9.4", "bulma-tooltip": "^3.0.2", "console-stamp": "^3.1.2", diff --git a/src/app/updater/updaters/Updater.js b/src/app/updater/updaters/Updater.js index fe4a15c..d4a55b5 100644 --- a/src/app/updater/updaters/Updater.js +++ b/src/app/updater/updaters/Updater.js @@ -2,7 +2,7 @@ import _ from 'lodash'; import jsonpath from '../../../common/jsonpath.js'; import SplatNet from '../../../common/splatnet.js'; import { createEvents } from 'ics'; -import * as Sentry from '@sentry/node'; +import * as Sentry from '@sentry/core'; // not @sentry/node: this file also runs in a Worker (see test/sentry.test.js) import { languages } from '../../../common/regions.js'; import LocalizationProcessor from '../LocalizationProcessor.js'; import { DATA_CACHE_CONTROL } from '../../../common/storage/index.js'; diff --git a/test/sentry.test.js b/test/sentry.test.js new file mode 100644 index 0000000..5c03cd9 --- /dev/null +++ b/test/sentry.test.js @@ -0,0 +1,20 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import * as SentryNode from '@sentry/node'; +import { captureException } from '@sentry/core'; + +// Shared code (the updaters) reports through @sentry/core so it runs unchanged under +// @sentry/node and @sentry/cloudflare. That only works while both resolve to one copy of +// core: Sentry keys its global carrier by version, so a version split silently drops events. +test('captureException from @sentry/core reaches the client @sentry/node initialized', async () => { + const seen = []; + SentryNode.init({ + dsn: 'https://public@example.ingest.sentry.io/1', + beforeSend: event => { seen.push(event.exception.values[0].value); return null; }, + }); + + captureException(new Error('routed through core')); + await SentryNode.flush(1000); + + assert.deepEqual(seen, ['routed through core']); +});