✨(collaboration) report yhub errors to sentry

Sentry can be used to report errors in yhub-server service
This commit is contained in:
Manuel Raynaud
2026-09-23 12:06:05 +02:00
parent 4906c73e39
commit ea553fccd0
9 changed files with 530 additions and 5 deletions
+2
View File
@@ -15,6 +15,8 @@ and this project adheres to
- ✨(backend) expose the attachment max size in the config endpoint #2577
- ✨(frontend) warn before uploading an attachment over the size limit #2577
- ✨(frontend) add keyboard shortcut to open presentation mode #2697
- ✨(collaboration) report yhub errors to sentry, configured through
`SENTRY_*`
- ✨(backend) add opt-in prometheus metrics on `/metrics`, protected by a
bearer token
- ✨(helm) add a dedicated ingress for the prometheus metrics
+5
View File
@@ -194,6 +194,11 @@ documents what each of them changes.
| YHUB_TASK_CONCURRENCY | Tasks one worker process claims at once | 5 |
| YHUB_TASK_DEBOUNCE_MS | How long an update waits on the redis stream before a worker persists it | 10000 |
| YHUB_MIN_MESSAGE_LIFETIME_MS | How long persisted updates stay replayable from redis rather than read back from postgres | 60000 |
| SENTRY_DSN | Sentry DSN, unset disables it: the SDK is then not even loaded. Can be read from a file with SENTRY_DSN_FILE | |
| SENTRY_ENVIRONMENT | Environment the events are reported under | production |
| SENTRY_RELEASE | Release the events are reported under. Detected by the SDK when unset | |
| SENTRY_TRACES_SAMPLE_RATE | Share of the traces sent to Sentry, between `0` and `1` | 0 |
| SENTRY_PROFILES_SAMPLE_RATE | Share of the sampled traces that are also profiled, between `0` and `1`. The native profiler is only loaded above `0` | 0 |
| SOFT_MIGRATION | Set to "true" to seed a room from the legacy Django/S3 document store the first time it is opened | false |
| LEGACY_S3_ENDPOINT_URL | Required by SOFT_MIGRATION, endpoint of the legacy media bucket, without a path | |
| LEGACY_S3_ACCESS_KEY_ID | Required by SOFT_MIGRATION, read access to that bucket (or LEGACY_S3_ACCESS_KEY_ID_FILE) | |
+3 -1
View File
@@ -70,4 +70,6 @@ USER ${DOCKER_USER}
ENTRYPOINT [ "/usr/local/bin/entrypoint" ]
CMD ["node", "dist/server.js"]
# sentry.js is preloaded so that error reporting is in place before anything else
# is imported; it does nothing without a SENTRY_DSN
CMD ["node", "--import", "./dist/sentry.js", "dist/server.js"]
+37
View File
@@ -391,6 +391,43 @@ made *versioned*, so what is exercised is what a deployment runs rather than a
simpler case. Watch it with `mc ls --versions --recursive impress/yhub-storage`
from an `mc` container on the stack's network.
## Error reporting (Sentry)
`src/sentry.ts` is preloaded by the start command
(`node --import ./dist/sentry.js dist/server.js`), the way y-provider does it:
the SDK hooks the modules it instruments as they are loaded, so it has to be
there before `server.ts` imports anything. A deployment that overrides the
command of the container has to keep the `--import`.
| Variable | Default | What it changes |
| -------- | ------- | --------------- |
| `SENTRY_DSN` | — | Where to report. Unset: nothing is reported and the SDK is not loaded (or `…_FILE`) |
| `SENTRY_ENVIRONMENT` | `production` | Environment the events are reported under |
| `SENTRY_RELEASE` | detected | Release the events are reported under |
| `SENTRY_TRACES_SAMPLE_RATE` | `0` | Share of the traces that are sent, `0` to `1` |
| `SENTRY_PROFILES_SAMPLE_RATE` | `0` | Share of the sampled traces that are profiled, `0` to `1` |
A rate that is not a number between 0 and 1 is a startup error.
What is reported:
- uncaught exceptions and unhandled rejections. The process still ends on an
unhandled rejection, as it does without Sentry: the SDK's default would
report it and carry on;
- every `error` and `fatal` line of the logger, with its fields as context.
yhub and this wrapper share one pino logger, and that is where a failed
upgrade, compaction or migration ends up — none of them is thrown to anything
that could report it. `warn` lines (a backend that did not answer, a lost
`content-updated` notification) are not sent.
Every event carries the tags `application: yhub-server` and `role` (the
`YHUB_ROLE` of the process), the server and the worker being one image.
Traces are of limited use here: the websocket server is uWebSockets.js, which
the SDK does not instrument, so there is no span for an upgrade or a message.
What is traced is the outgoing side — the calls to the backend, postgres,
redis — when something starts a trace around them.
## Tests
`yarn test` runs the **vitest** suite under `__tests__/*.spec.ts`
+163
View File
@@ -0,0 +1,163 @@
// sentry.ts — the module preloaded with `node --import`. Tested with both SDK
// packages mocked: the environment goes in, and what is handed to `Sentry.init`
// (or the fact that the SDK was never touched) comes out.
import { beforeEach, describe, expect, it, vi } from 'vitest';
const sentry = vi.hoisted(() => ({
loaded: vi.fn(),
init: vi.fn(),
setTag: vi.fn(),
pinoIntegration: vi.fn((options: unknown) => ({ name: 'Pino', options })),
onUnhandledRejectionIntegration: vi.fn((options: unknown) => ({
name: 'OnUnhandledRejection',
options,
})),
}));
const profiling = vi.hoisted(() => ({
loaded: vi.fn(),
nodeProfilingIntegration: vi.fn(() => ({ name: 'ProfilingIntegration' })),
}));
vi.mock('@sentry/node', () => {
sentry.loaded();
return sentry;
});
vi.mock('@sentry/profiling-node', () => {
profiling.loaded();
return profiling;
});
const load = () => import('../src/sentry.js');
beforeEach(() => {
vi.unstubAllEnvs();
vi.resetModules();
vi.clearAllMocks();
for (const key of [
'SENTRY_DSN',
'SENTRY_DSN_FILE',
'SENTRY_ENVIRONMENT',
'SENTRY_RELEASE',
'SENTRY_TRACES_SAMPLE_RATE',
'SENTRY_PROFILES_SAMPLE_RATE',
'YHUB_ROLE',
]) {
vi.stubEnv(key, '');
}
});
describe('without a SENTRY_DSN', () => {
it('does not even import the SDK', async () => {
await load();
expect(sentry.loaded).not.toHaveBeenCalled();
expect(profiling.loaded).not.toHaveBeenCalled();
expect(sentry.init).not.toHaveBeenCalled();
});
it('ignores the other settings', async () => {
vi.stubEnv('SENTRY_TRACES_SAMPLE_RATE', '1');
vi.stubEnv('SENTRY_PROFILES_SAMPLE_RATE', '1');
await load();
expect(sentry.loaded).not.toHaveBeenCalled();
expect(profiling.loaded).not.toHaveBeenCalled();
});
});
describe('with a SENTRY_DSN', () => {
beforeEach(() => {
vi.stubEnv('SENTRY_DSN', 'https://key@sentry.example.com/1');
});
it('reports errors only, by default', async () => {
await load();
expect(sentry.init).toHaveBeenCalledTimes(1);
expect(sentry.init).toHaveBeenCalledWith(
expect.objectContaining({
dsn: 'https://key@sentry.example.com/1',
environment: undefined,
release: undefined,
tracesSampleRate: 0,
profilesSampleRate: 0,
}),
);
// the native profiler is not loaded by a deployment that does not profile
expect(profiling.loaded).not.toHaveBeenCalled();
});
it('reports the error lines of the logger and keeps node crashing on unhandled rejections', async () => {
await load();
expect(sentry.pinoIntegration).toHaveBeenCalledWith({
error: { levels: ['error', 'fatal'] },
});
expect(sentry.onUnhandledRejectionIntegration).toHaveBeenCalledWith({
mode: 'strict',
});
const { integrations } = sentry.init.mock.calls[0][0] as {
integrations: Array<{ name: string }>;
};
expect(integrations.map(({ name }) => name)).toEqual([
'Pino',
'OnUnhandledRejection',
]);
});
it('takes the environment, the release and the sampling rates from the environment', async () => {
vi.stubEnv('SENTRY_ENVIRONMENT', 'preprod');
vi.stubEnv('SENTRY_RELEASE', 'docs@5.0.0');
vi.stubEnv('SENTRY_TRACES_SAMPLE_RATE', '0.25');
vi.stubEnv('SENTRY_PROFILES_SAMPLE_RATE', '0.5');
await load();
expect(sentry.init).toHaveBeenCalledWith(
expect.objectContaining({
environment: 'preprod',
release: 'docs@5.0.0',
tracesSampleRate: 0.25,
profilesSampleRate: 0.5,
}),
);
});
it('loads the profiler only when profiles are sampled', async () => {
vi.stubEnv('SENTRY_PROFILES_SAMPLE_RATE', '0.5');
await load();
expect(profiling.nodeProfilingIntegration).toHaveBeenCalledTimes(1);
const { integrations } = sentry.init.mock.calls[0][0] as {
integrations: Array<{ name: string }>;
};
expect(integrations.map(({ name }) => name)).toContain(
'ProfilingIntegration',
);
});
it('tags the events with the application and the role of the process', async () => {
vi.stubEnv('YHUB_ROLE', 'worker');
await load();
expect(sentry.setTag).toHaveBeenCalledWith('application', 'yhub-server');
expect(sentry.setTag).toHaveBeenCalledWith('role', 'worker');
});
it.each([
['SENTRY_TRACES_SAMPLE_RATE', 'abc'],
['SENTRY_TRACES_SAMPLE_RATE', '1.5'],
['SENTRY_PROFILES_SAMPLE_RATE', '-0.1'],
])('refuses to start when %s is "%s"', async (name, value) => {
vi.stubEnv(name, value);
await expect(load()).rejects.toThrow(
`${name} must be a number between 0 and 1 (got "${value}")`,
);
expect(sentry.init).not.toHaveBeenCalled();
});
});
+3 -1
View File
@@ -5,7 +5,7 @@
"scripts": {
"build": "tsc -p tsconfig.build.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"start": "node dist/server.js",
"start": "node --import ./dist/sentry.js dist/server.js",
"dev": "nodemon --config nodemon.json",
"init-db": "node node_modules/@y/hub/bin/init-db.js",
"lint": "eslint",
@@ -14,6 +14,8 @@
},
"dependencies": {
"@aws-sdk/client-s3": "3.1110.0",
"@sentry/node": "10.70.0",
"@sentry/profiling-node": "10.70.0",
"@y/hub": "0.9.0",
"@y/y": "14.0.0-rc.25",
"jose": "6.2.8"
+28
View File
@@ -24,6 +24,17 @@ const intEnv = (name: string, dflt: number, min = 1): number => {
return value;
};
// A sampling rate, refused rather than guessed when it is not a number between
// 0 and 1: Sentry reads anything else as "drop everything" and says so nowhere.
const rateEnv = (name: string, dflt: number): number => {
const raw = process.env[name];
const value = raw == null || raw === '' ? dflt : Number(raw);
if (!Number.isFinite(value) || value < 0 || value > 1) {
throw new Error(`${name} must be a number between 0 and 1 (got "${raw}")`);
}
return value;
};
export const PORT = Number(process.env.PORT || 3002);
export const REDIS = process.env.REDIS;
export const POSTGRES = process.env.POSTGRES;
@@ -155,3 +166,20 @@ export const BACKEND_TOKEN_MARGIN_MS = 10000;
// signs to call us: no long-lived shared secret, only our private key here and
// its public half published on the JWKS endpoint.
export const YHUB_JWT_PRIVATE_KEY = secret('YHUB_JWT_PRIVATE_KEY', '');
// Error reporting, set up by `sentry.ts` before anything else is loaded. No DSN,
// no Sentry: the SDK is not even imported.
export const SENTRY_DSN = secret('SENTRY_DSN', '');
// Left to the SDK when unset: it reports "production", and reads the release
// from what the platform exposes.
export const SENTRY_ENVIRONMENT = process.env.SENTRY_ENVIRONMENT || undefined;
export const SENTRY_RELEASE = process.env.SENTRY_RELEASE || undefined;
// Both off by default, like the backend. The websocket server is not an http
// server the SDK knows how to trace, so a trace here is the outgoing calls (the
// backend, postgres, redis) rather than a request from end to end.
export const SENTRY_TRACES_SAMPLE_RATE = rateEnv('SENTRY_TRACES_SAMPLE_RATE', 0);
// Relative to the traces: the share of sampled traces that are also profiled.
export const SENTRY_PROFILES_SAMPLE_RATE = rateEnv(
'SENTRY_PROFILES_SAMPLE_RATE',
0,
);
+53
View File
@@ -0,0 +1,53 @@
/**
* Error reporting. Preloaded with `node --import ./dist/sentry.js`, the way
* y-provider does it: the SDK hooks the modules it instruments as they are
* loaded, so it has to be initialised before `server.ts` imports any of them.
*
* Everything is read from the environment (`config.ts`), and without a
* `SENTRY_DSN` nothing happens at all — the SDK is imported on demand, so a
* deployment that does not use Sentry does not pay for it.
*
* What reaches Sentry:
* - uncaught exceptions and unhandled rejections;
* - every `error` and `fatal` line of the pino logger, ours and yhub's — it is
* one logger, and it is where a failed upgrade, compaction or migration ends
* up, none of them being thrown to anything that could report it;
* - traces and profiles, when their sampling rates ask for them.
*/
import {
ROLE,
SENTRY_DSN,
SENTRY_ENVIRONMENT,
SENTRY_PROFILES_SAMPLE_RATE,
SENTRY_RELEASE,
SENTRY_TRACES_SAMPLE_RATE,
} from './config.js';
if (SENTRY_DSN) {
const Sentry = await import('@sentry/node');
const integrations = [
Sentry.pinoIntegration({ error: { levels: ['error', 'fatal'] } }),
// Node ends the process on an unhandled rejection. The SDK's default would
// report it and carry on, which makes a server behave differently with and
// without error reporting: report it, then end as Node would have.
Sentry.onUnhandledRejectionIntegration({ mode: 'strict' }),
];
if (SENTRY_PROFILES_SAMPLE_RATE > 0) {
// a native module: only loaded by the deployments that profile
const { nodeProfilingIntegration } = await import('@sentry/profiling-node');
integrations.push(nodeProfilingIntegration());
}
Sentry.init({
dsn: SENTRY_DSN,
environment: SENTRY_ENVIRONMENT,
release: SENTRY_RELEASE,
integrations,
tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE,
profilesSampleRate: SENTRY_PROFILES_SAMPLE_RATE,
});
Sentry.setTag('application', 'yhub-server');
// the server and the worker are the same image: tell them apart
Sentry.setTag('role', ROLE);
}
+236 -3
View File
@@ -2,6 +2,37 @@
# yarn lockfile v1
"@apm-js-collab/code-transformer-bundler-plugins@^0.7.3":
version "0.7.4"
resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer-bundler-plugins/-/code-transformer-bundler-plugins-0.7.4.tgz#f323d5f723565e34f1409aa96e445ad489020f76"
integrity sha512-nAfOeZPSUAQvJa1iFT/5oCrTm5YQhMMrfCNthNnaXHZiOQhu1KGuLoIx7HtbAi3wfwaBYLaICPIeenIaEwcXIg==
dependencies:
"@apm-js-collab/code-transformer" "^0.18.1"
es-module-lexer "^2.1.0"
magic-string "^0.30.21"
module-details-from-path "^1.0.4"
"@apm-js-collab/code-transformer@^0.18.0", "@apm-js-collab/code-transformer@^0.18.1":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer/-/code-transformer-0.18.1.tgz#66ce01cfe9607779b4abebb4f54c49a46e8b48ca"
integrity sha512-u1Hb6bHjWtkSpiprwVP6YaHC1DTN4RAU3zYkUDUe7WMnJwdyU1pwTL9dFKiSJB9IiLue/EQovmyx6xhU7FFtAQ==
dependencies:
"@types/estree" "^1.0.8"
astring "^1.9.0"
esquery "^1.7.0"
meriyah "^6.1.4"
semifies "^1.0.0"
source-map "^0.6.0"
"@apm-js-collab/tracing-hooks@^0.13.0":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@apm-js-collab/tracing-hooks/-/tracing-hooks-0.13.2.tgz#c219d04bf115bf7828a8887e437c0d6c888159f0"
integrity sha512-jk3acBAJecK8ctMGlkappcX5CtymTxmd0GGnUqh4ZX3Pk1RbXei/vzGEDTeOHcXJ6wsRkm8PhHsfOba0jxB67A==
dependencies:
"@apm-js-collab/code-transformer" "^0.18.0"
debug "^4.4.1"
module-details-from-path "^1.0.4"
"@aws-sdk/checksums@^3.1000.27":
version "3.1000.29"
resolved "https://registry.yarnpkg.com/@aws-sdk/checksums/-/checksums-3.1000.29.tgz#f12a6926eb3789057f5f16582fc226fe533c87fa"
@@ -450,6 +481,66 @@
resolved "https://registry.yarnpkg.com/@nodable/entities/-/entities-3.0.0.tgz#694703bc864d30eaed55c2e3def00dbd61493670"
integrity sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==
"@opentelemetry/api-logs@0.220.0":
version "0.220.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz#b2ed235de4b5f3c1769adfa5f3bc247d82cdfbc9"
integrity sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==
dependencies:
"@opentelemetry/api" "^1.3.0"
"@opentelemetry/api@^1.3.0", "@opentelemetry/api@^1.9.1":
version "1.9.1"
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.1.tgz#c1b0346de336ba55af2d5a7970882037baedec05"
integrity sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==
"@opentelemetry/core@2.11.0":
version "2.11.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-2.11.0.tgz#97849d3808bba652568b7d53e20c9fc38bcb7c49"
integrity sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA==
dependencies:
"@opentelemetry/semantic-conventions" "^1.29.0"
"@opentelemetry/instrumentation@^0.220.0":
version "0.220.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.220.0.tgz#542b36bf4871dd83dc84e1373ac4bbcd35a8bfb8"
integrity sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw==
dependencies:
"@opentelemetry/api-logs" "0.220.0"
import-in-the-middle "^3.0.0"
require-in-the-middle "^8.0.0"
"@opentelemetry/resources@2.11.0":
version "2.11.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-2.11.0.tgz#b4e60ba92a4f122dc979f3402aea9713a98eac5b"
integrity sha512-Ie7+8q8MDF4FAEQCKVMTx3ReUvxiIAgIiiW3c9JdmP8+HMcDy20puT+AHjexnExgnbvBxjQ9fjkFDWrikJ2jQA==
dependencies:
"@opentelemetry/core" "2.11.0"
"@opentelemetry/semantic-conventions" "^1.29.0"
"@opentelemetry/sdk-trace-base@^2.9.0":
version "2.11.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.11.0.tgz#3f725401fcfb16e5b2335c103cdc9488829632d1"
integrity sha512-H19x/TX/LZdqiYOjM7fqtSxwlplC5pgelavqbQdHbhdq0q/AI/TGkM2dfGuuynTXmJPeF2HoZVoPDu+TGoW78A==
dependencies:
"@opentelemetry/core" "2.11.0"
"@opentelemetry/resources" "2.11.0"
"@opentelemetry/sdk-trace" "2.11.0"
"@opentelemetry/semantic-conventions" "^1.29.0"
"@opentelemetry/sdk-trace@2.11.0":
version "2.11.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace/-/sdk-trace-2.11.0.tgz#46bbba9d366755df7d6faded0f7cd25af7f265c2"
integrity sha512-fFnTqGm8/G73GQVnxYi7LXa1ZVYEUvgL6XI1LpvV0bPC7WQ/ZGgKxCSl8FnlZBKto9JHHEFTO6s6CUpvvtwFrA==
dependencies:
"@opentelemetry/core" "2.11.0"
"@opentelemetry/resources" "2.11.0"
"@opentelemetry/semantic-conventions" "^1.29.0"
"@opentelemetry/semantic-conventions@^1.29.0":
version "1.43.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz#f3f467e36c27332f0e735ec86cdcd78dd6f27865"
integrity sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==
"@pinojs/redact@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@pinojs/redact/-/redact-0.4.0.tgz#c3de060dd12640dcc838516aa2a6803cc7b2e9d6"
@@ -607,6 +698,79 @@
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.1.tgz#cd19d691330cbd52ebb13620acb6cf7140b95e80"
integrity sha512-at8QVep6S3h5Y6gSbdGU06bRY5WJkf6WUduM9YtvYMbYhB1MOFfUgc6kehitQXzOtMSaT70q7f9ydPhpqu821w==
"@sentry/conventions@^0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@sentry/conventions/-/conventions-0.16.0.tgz#3b58d15714cf44dca1518496c00749eec5525009"
integrity sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ==
"@sentry/core@10.70.0":
version "10.70.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-10.70.0.tgz#96eb9f2beab7d4b3b10c1b59ec7833e4dfe5fb73"
integrity sha512-ozhCTDqg89oB4XmWfAwuHshABpvT7AkRpaPnogopPfMAaI61G1t8EKCJ4W7aum8JSBonlfyjPCyW5oYZFm0KvA==
dependencies:
"@sentry/conventions" "^0.16.0"
"@sentry/node-core@10.70.0":
version "10.70.0"
resolved "https://registry.yarnpkg.com/@sentry/node-core/-/node-core-10.70.0.tgz#d7998eaf9d0efa06d05ba6d9c001afcb8e68dcb5"
integrity sha512-oPOEVVNxv5WHtckx2i06Wi9FLWyvOg/1DUeX732jZ4iqT2nupINaMH4nF4f4kSvUThFnxkFSRQxwqOxgzMKhKA==
dependencies:
"@sentry/conventions" "^0.16.0"
"@sentry/core" "10.70.0"
"@sentry/opentelemetry" "10.70.0"
import-in-the-middle "^3.0.0"
"@sentry/node-cpu-profiler@^2.4.3":
version "2.4.4"
resolved "https://registry.yarnpkg.com/@sentry/node-cpu-profiler/-/node-cpu-profiler-2.4.4.tgz#b275d249bd6e0c98c1e4f2ebc87acf702e6ae04d"
integrity sha512-FaYbFWxEyTTVqXLJccokJCkwx2cTuvTiRaM9kA+O4HbZVT49xYXqSV9cNLI5UqJhgdHiZDhelBd5LB4wj7IIRA==
dependencies:
detect-libc "^2.0.3"
node-abi "^3.73.0"
"@sentry/node@10.70.0":
version "10.70.0"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-10.70.0.tgz#99fa23d90147c92e8291b8da9d706d3759468bc1"
integrity sha512-SPOOVxmKTVIEtqvOKkQT163e/pOwucjS7OPsCHyRs8sFR4nfBNu0EThplyqnvqd5BWBMTPH6WTBQfo+QWHV+HA==
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.70.0"
"@sentry/node-core" "10.70.0"
"@sentry/opentelemetry" "10.70.0"
"@sentry/server-utils" "10.70.0"
import-in-the-middle "^3.0.0"
"@sentry/opentelemetry@10.70.0":
version "10.70.0"
resolved "https://registry.yarnpkg.com/@sentry/opentelemetry/-/opentelemetry-10.70.0.tgz#40823a9d16b5d271a52de65244a3e2faeba43fbb"
integrity sha512-UNV/2tqypcUK6FDzerAsFJn1Km/c4VZCYkUZDNbnV5S0cwAq2BYKMo4M5vovaLDBQlxA+Wk9ovbxi5wYjjl9fw==
dependencies:
"@sentry/conventions" "^0.16.0"
"@sentry/core" "10.70.0"
"@sentry/profiling-node@10.70.0":
version "10.70.0"
resolved "https://registry.yarnpkg.com/@sentry/profiling-node/-/profiling-node-10.70.0.tgz#ca7b288d4db741923b5920c78a64a38e5d8cfdc1"
integrity sha512-bOL1nd+t6H4dHM2BB768Thm26UXBxIqBORIMr7nM+QLID+6DjHRcknRZbyklGNUVzAggsprzQ3f61i2xdRmTEA==
dependencies:
"@sentry/core" "10.70.0"
"@sentry/node" "10.70.0"
"@sentry/node-cpu-profiler" "^2.4.3"
"@sentry/server-utils@10.70.0":
version "10.70.0"
resolved "https://registry.yarnpkg.com/@sentry/server-utils/-/server-utils-10.70.0.tgz#df7ab00caae3f7398338062ba91d7a355ca27489"
integrity sha512-rzegZjMFFgCp3o+N8+XU13rfSvz4B+f8rU0ijBGrQcHdMNyfsFDTu1UTm262JofmrV2u+s+D0u0vFTnqtOGkbA==
dependencies:
"@apm-js-collab/code-transformer-bundler-plugins" "^0.7.3"
"@apm-js-collab/tracing-hooks" "^0.13.0"
"@sentry/conventions" "^0.16.0"
"@sentry/core" "10.70.0"
meriyah "^6.1.4"
"@smithy/core@^3.31.1", "@smithy/core@^3.33.2", "@smithy/core@^3.33.3":
version "3.33.3"
resolved "https://registry.yarnpkg.com/@smithy/core/-/core-3.33.3.tgz#c1e801fe17160bcbf6c714cf16e832057e6bf79e"
@@ -922,6 +1086,11 @@ assertion-error@^2.0.1:
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7"
integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==
astring@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/astring/-/astring-1.9.0.tgz#cc73e6062a7eb03e7d19c22d8b0b3451fd9bfeef"
integrity sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==
async@^3.2.4:
version "3.2.6"
resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce"
@@ -1014,6 +1183,11 @@ chokidar@^3.5.2:
optionalDependencies:
fsevents "~2.3.2"
cjs-module-lexer@^2.2.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-2.2.1.tgz#ab35b03c56ade05fe170c70e67ae89f60666847c"
integrity sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==
cluster-key-slot@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"
@@ -1028,7 +1202,7 @@ cross-spawn@^7.0.6:
shebang-command "^2.0.0"
which "^2.0.1"
debug@^4, debug@^4.3.1, debug@^4.3.2, debug@^4.4.1, debug@^4.4.3:
debug@^4, debug@^4.3.1, debug@^4.3.2, debug@^4.3.5, debug@^4.4.1, debug@^4.4.3:
version "4.4.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
@@ -1050,11 +1224,26 @@ deep-is@^0.1.3:
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
detect-libc@^2.0.3:
version "2.1.2"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad"
integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==
es-module-lexer@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a"
integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==
es-module-lexer@^2.1.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-2.3.2.tgz#311fa4f40168c1975c505477c51b23234d41ad55"
integrity sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==
es-module-lexer@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-3.0.2.tgz#8cc09097dd80a9cbb79437fd405b935cac76cda3"
integrity sha512-BuIB67FngDSyQ/dpQNOZybwdEBDUGJQvOqwWr4ha/ufYiqzuEwPkKO2zLhRAgay28tStRIHUeWmszZAJo3GCOg==
"esbuild@^0.27.0 || ^0.28.0":
version "0.28.2"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.28.2.tgz#0f43bd1bad955b72d24e2261e3abe5957ccf0816"
@@ -1322,6 +1511,15 @@ ignore@^7.0.5:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.8.tgz#84d8466899958458ee30b4190c839ee1446cc88d"
integrity sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==
import-in-the-middle@^3.0.0:
version "3.5.1"
resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-3.5.1.tgz#74fc490851751005dc2f776a87bc8a075904b474"
integrity sha512-mPKuL8bPQzecui2KK6Gb+M8JvJoHnhS1FeYGa22QopBmlevF5F0FE6ued/B5EgHDeIoMTONIpDWWFKUPOG0DBQ==
dependencies:
cjs-module-lexer "^2.2.0"
es-module-lexer "^3.0.2"
module-details-from-path "^1.0.4"
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
@@ -1433,13 +1631,18 @@ loupe@^3.1.0, loupe@^3.1.4:
resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76"
integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==
magic-string@^0.30.17:
magic-string@^0.30.17, magic-string@^0.30.21:
version "0.30.21"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91"
integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==
dependencies:
"@jridgewell/sourcemap-codec" "^1.5.5"
meriyah@^6.1.4:
version "6.1.4"
resolved "https://registry.yarnpkg.com/meriyah/-/meriyah-6.1.4.tgz#2d49a8934fbcd9205c20564579c3560d9b1e077b"
integrity sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
@@ -1478,6 +1681,11 @@ minio@^8.0.6:
through2 "^4.0.2"
xml2js "^0.5.0 || ^0.6.2"
module-details-from-path@^1.0.3, module-details-from-path@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.4.tgz#b662fdcd93f6c83d3f25289da0ce81c8d9685b94"
integrity sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==
ms@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
@@ -1493,6 +1701,13 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
node-abi@^3.73.0:
version "3.96.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.96.0.tgz#8b038bc6cca97d6cec2e9aafdb81b900da1ff80d"
integrity sha512-rebQ/lz7i0EkoLzUVSrKRzA69zMkwLp95kKMWoMDkkM00Suxz0D7zEQPwRml5fQum24mj7bPvmlgLAmu2JCiYg==
dependencies:
semver "^7.3.5"
nodemon@3.1.14:
version "3.1.14"
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.1.14.tgz#8487ca379c515301d221ec007f27f24ecafa2b51"
@@ -1700,6 +1915,14 @@ redis@^5.10.0:
"@redis/search" "5.12.1"
"@redis/time-series" "5.12.1"
require-in-the-middle@^8.0.0:
version "8.0.1"
resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz#dbde2587f669398626d56b20c868ab87bf01cce4"
integrity sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==
dependencies:
debug "^4.3.5"
module-details-from-path "^1.0.3"
rollup@^4.43.0:
version "4.63.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.63.1.tgz#a9b96d5b2558d034babb12ad8b67a043bc870ac4"
@@ -1750,7 +1973,12 @@ sax@>=0.6.0:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.6.1.tgz#4c23cf608c0b693ab54b4b5888e92cfe977b9843"
integrity sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==
semver@^7.5.3, semver@^7.7.3:
semifies@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/semifies/-/semifies-1.0.0.tgz#b69569f32c2ba2ac04f705ea82831364289b2ae2"
integrity sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw==
semver@^7.3.5, semver@^7.5.3, semver@^7.7.3:
version "7.8.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69"
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
@@ -1791,6 +2019,11 @@ source-map-js@^1.2.1:
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
source-map@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
split-on-first@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"