diff --git a/.size-limit.js b/.size-limit.js
index 207fd6a2b85b..e8124a622962 100644
--- a/.size-limit.js
+++ b/.size-limit.js
@@ -38,7 +38,7 @@ module.exports = [
path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'browserTracingIntegration'),
gzip: true,
- limit: '42 KB',
+ limit: '43 KB',
},
{
name: '@sentry/browser (incl. Tracing, Profiling)',
@@ -287,7 +287,7 @@ module.exports = [
import: createImport('init'),
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
gzip: true,
- limit: '163 KB',
+ limit: '166 KB',
},
{
name: '@sentry/node - without tracing',
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2d67c0238bb2..e32b01c44a72 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,22 @@
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
+## 10.36.0
+
+- feat(node): Add Prisma v7 support ([#18908](https://github.com/getsentry/sentry-javascript/pull/18908))
+- feat(opentelemetry): Support `db.system.name` attribute for database spans ([#18902](https://github.com/getsentry/sentry-javascript/pull/18902))
+- feat(deps): Bump OpenTelemetry dependencies ([#18878](https://github.com/getsentry/sentry-javascript/pull/18878))
+- fix(core): Sanitize data URLs in `http.client` spans ([#18896](https://github.com/getsentry/sentry-javascript/pull/18896))
+- fix(nextjs): Add ALS runner fallbacks for serverless environments ([#18889](https://github.com/getsentry/sentry-javascript/pull/18889))
+- fix(node): Profiling debug ID matching
+
+
+ Internal Changes
+
+- chore(deps-dev): bump @remix-run/server-runtime from 2.15.2 to 2.17.3 in /packages/remix ([#18750](https://github.com/getsentry/sentry-javascript/pull/18750))
+
+
+
## 10.35.0
### Important Changes
diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-data-url/init.js b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-data-url/init.js
new file mode 100644
index 000000000000..5ab240338c8c
--- /dev/null
+++ b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-data-url/init.js
@@ -0,0 +1,10 @@
+import * as Sentry from '@sentry/browser';
+
+window.Sentry = Sentry;
+
+Sentry.init({
+ dsn: 'https://public@dsn.ingest.sentry.io/1337',
+ integrations: [Sentry.browserTracingIntegration()],
+ tracesSampleRate: 1,
+ autoSessionTracking: false,
+});
diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-data-url/subject.js b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-data-url/subject.js
new file mode 100644
index 000000000000..63d2d14fbd43
--- /dev/null
+++ b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-data-url/subject.js
@@ -0,0 +1,6 @@
+// Fetch a data URL to verify that the span name and attributes are sanitized
+// Data URLs are used for inline resources, e.g., Web Workers with inline scripts
+const dataUrl = 'data:text/plain;base64,SGVsbG8gV29ybGQh';
+fetch(dataUrl).catch(() => {
+ // Data URL fetch might fail in some browsers, but the span should still be created
+});
diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-data-url/test.ts b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-data-url/test.ts
new file mode 100644
index 000000000000..46995dd6c152
--- /dev/null
+++ b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-data-url/test.ts
@@ -0,0 +1,35 @@
+import { expect } from '@playwright/test';
+import { sentryTest } from '../../../../utils/fixtures';
+import {
+ envelopeRequestParser,
+ shouldSkipTracingTest,
+ waitForTransactionRequestOnUrl,
+} from '../../../../utils/helpers';
+
+sentryTest('sanitizes data URLs in fetch span name and attributes', async ({ getLocalTestUrl, page }) => {
+ if (shouldSkipTracingTest()) {
+ sentryTest.skip();
+ }
+
+ const url = await getLocalTestUrl({ testDir: __dirname });
+
+ const req = await waitForTransactionRequestOnUrl(page, url);
+ const transactionEvent = envelopeRequestParser(req);
+
+ const requestSpans = transactionEvent.spans?.filter(({ op }) => op === 'http.client');
+
+ expect(requestSpans).toHaveLength(1);
+
+ const span = requestSpans?.[0];
+
+ const sanitizedUrl = 'data:text/plain,base64,SGVsbG8gV2... [truncated]';
+ expect(span?.description).toBe(`GET ${sanitizedUrl}`);
+
+ expect(span?.data).toMatchObject({
+ 'http.method': 'GET',
+ url: sanitizedUrl,
+ type: 'fetch',
+ });
+
+ expect(span?.data?.['http.url']).toBe(sanitizedUrl);
+});
diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/xhr-data-url/init.js b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-data-url/init.js
new file mode 100644
index 000000000000..5ab240338c8c
--- /dev/null
+++ b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-data-url/init.js
@@ -0,0 +1,10 @@
+import * as Sentry from '@sentry/browser';
+
+window.Sentry = Sentry;
+
+Sentry.init({
+ dsn: 'https://public@dsn.ingest.sentry.io/1337',
+ integrations: [Sentry.browserTracingIntegration()],
+ tracesSampleRate: 1,
+ autoSessionTracking: false,
+});
diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/xhr-data-url/subject.js b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-data-url/subject.js
new file mode 100644
index 000000000000..76656f862519
--- /dev/null
+++ b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-data-url/subject.js
@@ -0,0 +1,5 @@
+// XHR request to a data URL to verify that the span name and attributes are sanitized
+const dataUrl = 'data:text/plain;base64,SGVsbG8gV29ybGQh';
+const xhr = new XMLHttpRequest();
+xhr.open('GET', dataUrl);
+xhr.send();
diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/xhr-data-url/test.ts b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-data-url/test.ts
new file mode 100644
index 000000000000..88bce31e1753
--- /dev/null
+++ b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-data-url/test.ts
@@ -0,0 +1,30 @@
+import { expect } from '@playwright/test';
+import type { Event } from '@sentry/core';
+import { sentryTest } from '../../../../utils/fixtures';
+import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers';
+
+sentryTest('sanitizes data URLs in XHR span name and attributes', async ({ getLocalTestUrl, page }) => {
+ if (shouldSkipTracingTest()) {
+ sentryTest.skip();
+ }
+
+ const url = await getLocalTestUrl({ testDir: __dirname });
+
+ const eventData = await getFirstSentryEnvelopeRequest(page, url);
+ const requestSpans = eventData.spans?.filter(({ op }) => op === 'http.client');
+
+ expect(requestSpans).toHaveLength(1);
+
+ const span = requestSpans?.[0];
+
+ const sanitizedUrl = 'data:text/plain,base64,SGVsbG8gV2... [truncated]';
+ expect(span?.description).toBe(`GET ${sanitizedUrl}`);
+
+ expect(span?.data).toMatchObject({
+ 'http.method': 'GET',
+ url: sanitizedUrl,
+ type: 'xhr',
+ });
+
+ expect(span?.data?.['http.url']).toBe(sanitizedUrl);
+});
diff --git a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-custom-sampler/package.json b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-custom-sampler/package.json
index d7c83c773514..62d5bc10cd1a 100644
--- a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-custom-sampler/package.json
+++ b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-custom-sampler/package.json
@@ -12,12 +12,12 @@
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/context-async-hooks": "^2.2.0",
- "@opentelemetry/core": "^2.2.0",
- "@opentelemetry/instrumentation": "^0.208.0",
- "@opentelemetry/instrumentation-http": "^0.208.0",
- "@opentelemetry/resources": "^2.2.0",
- "@opentelemetry/sdk-trace-node": "^2.2.0",
+ "@opentelemetry/context-async-hooks": "^2.4.0",
+ "@opentelemetry/core": "^2.4.0",
+ "@opentelemetry/instrumentation": "^0.210.0",
+ "@opentelemetry/instrumentation-http": "^0.210.0",
+ "@opentelemetry/resources": "^2.4.0",
+ "@opentelemetry/sdk-trace-node": "^2.4.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
"@sentry/node-core": "latest || *",
"@sentry/opentelemetry": "latest || *",
diff --git a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-sdk-node/package.json b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-sdk-node/package.json
index c8987cd84f39..49e9bfe01dc8 100644
--- a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-sdk-node/package.json
+++ b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2-sdk-node/package.json
@@ -12,15 +12,15 @@
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/context-async-hooks": "^2.2.0",
- "@opentelemetry/core": "^2.2.0",
- "@opentelemetry/instrumentation": "^0.208.0",
- "@opentelemetry/instrumentation-http": "^0.208.0",
- "@opentelemetry/resources": "^2.2.0",
- "@opentelemetry/sdk-trace-node": "^2.2.0",
+ "@opentelemetry/context-async-hooks": "^2.4.0",
+ "@opentelemetry/core": "^2.4.0",
+ "@opentelemetry/instrumentation": "^0.210.0",
+ "@opentelemetry/instrumentation-http": "^0.210.0",
+ "@opentelemetry/resources": "^2.4.0",
+ "@opentelemetry/sdk-trace-node": "^2.4.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
- "@opentelemetry/sdk-node": "^0.208.0",
- "@opentelemetry/exporter-trace-otlp-http": "^0.208.0",
+ "@opentelemetry/sdk-node": "^0.210.0",
+ "@opentelemetry/exporter-trace-otlp-http": "^0.210.0",
"@sentry/node-core": "latest || *",
"@sentry/opentelemetry": "latest || *",
"@types/express": "4.17.17",
diff --git a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2/package.json b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2/package.json
index c532f50e5ef9..bda2295cc692 100644
--- a/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2/package.json
+++ b/dev-packages/e2e-tests/test-applications/node-core-express-otel-v2/package.json
@@ -14,12 +14,12 @@
"@sentry/node-core": "latest || *",
"@sentry/opentelemetry": "latest || *",
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/context-async-hooks": "^2.2.0",
- "@opentelemetry/core": "^2.2.0",
- "@opentelemetry/instrumentation": "^0.208.0",
- "@opentelemetry/instrumentation-http": "^0.208.0",
- "@opentelemetry/resources": "^2.2.0",
- "@opentelemetry/sdk-trace-node": "^2.2.0",
+ "@opentelemetry/context-async-hooks": "^2.4.0",
+ "@opentelemetry/core": "^2.4.0",
+ "@opentelemetry/instrumentation": "^0.210.0",
+ "@opentelemetry/instrumentation-http": "^0.210.0",
+ "@opentelemetry/resources": "^2.4.0",
+ "@opentelemetry/sdk-trace-node": "^2.4.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
"@types/express": "^4.17.21",
"@types/node": "^18.19.1",
diff --git a/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json b/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json
index 85fc9b85de85..681a10ccc39d 100644
--- a/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json
+++ b/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/sdk-trace-node": "^2.1.0",
+ "@opentelemetry/sdk-trace-node": "^2.4.0",
"@sentry/node": "latest || *",
"@sentry/opentelemetry": "latest || *",
"@types/express": "4.17.17",
diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json
index 709d597b19af..cadd3c29470c 100644
--- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json
+++ b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json
@@ -11,8 +11,8 @@
"test:assert": "pnpm test"
},
"dependencies": {
- "@opentelemetry/sdk-node": "0.208.0",
- "@opentelemetry/exporter-trace-otlp-http": "0.208.0",
+ "@opentelemetry/sdk-node": "0.210.0",
+ "@opentelemetry/exporter-trace-otlp-http": "0.210.0",
"@sentry/node": "latest || *",
"@types/express": "4.17.17",
"@types/node": "^18.19.1",
diff --git a/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json b/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json
index a66c60146c65..a445a9ef4aac 100644
--- a/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json
+++ b/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json
@@ -12,11 +12,11 @@
},
"dependencies": {
"@opentelemetry/api": "1.9.0",
- "@opentelemetry/sdk-trace-node": "2.2.0",
- "@opentelemetry/exporter-trace-otlp-http": "0.208.0",
- "@opentelemetry/instrumentation-undici": "0.13.2",
- "@opentelemetry/instrumentation-http": "0.208.0",
- "@opentelemetry/instrumentation": "0.208.0",
+ "@opentelemetry/sdk-trace-node": "2.4.0",
+ "@opentelemetry/exporter-trace-otlp-http": "0.210.0",
+ "@opentelemetry/instrumentation-undici": "0.20.0",
+ "@opentelemetry/instrumentation-http": "0.210.0",
+ "@opentelemetry/instrumentation": "0.210.0",
"@sentry/node": "latest || *",
"@types/express": "4.17.17",
"@types/node": "^18.19.1",
diff --git a/dev-packages/e2e-tests/test-applications/node-otel/package.json b/dev-packages/e2e-tests/test-applications/node-otel/package.json
index 0b202bd80556..f13c0cdb896e 100644
--- a/dev-packages/e2e-tests/test-applications/node-otel/package.json
+++ b/dev-packages/e2e-tests/test-applications/node-otel/package.json
@@ -11,8 +11,8 @@
"test:assert": "pnpm test"
},
"dependencies": {
- "@opentelemetry/sdk-node": "0.208.0",
- "@opentelemetry/exporter-trace-otlp-http": "0.208.0",
+ "@opentelemetry/sdk-node": "0.210.0",
+ "@opentelemetry/exporter-trace-otlp-http": "0.210.0",
"@sentry/node": "latest || *",
"@types/express": "4.17.17",
"@types/node": "^18.19.1",
diff --git a/dev-packages/node-core-integration-tests/package.json b/dev-packages/node-core-integration-tests/package.json
index 6157ec378d4f..a6448dd06030 100644
--- a/dev-packages/node-core-integration-tests/package.json
+++ b/dev-packages/node-core-integration-tests/package.json
@@ -27,12 +27,12 @@
"@nestjs/core": "^11",
"@nestjs/platform-express": "^11",
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/context-async-hooks": "^2.2.0",
- "@opentelemetry/core": "^2.2.0",
- "@opentelemetry/instrumentation": "^0.208.0",
- "@opentelemetry/instrumentation-http": "0.208.0",
- "@opentelemetry/resources": "^2.2.0",
- "@opentelemetry/sdk-trace-base": "^2.2.0",
+ "@opentelemetry/context-async-hooks": "^2.4.0",
+ "@opentelemetry/core": "^2.4.0",
+ "@opentelemetry/instrumentation": "^0.210.0",
+ "@opentelemetry/instrumentation-http": "0.210.0",
+ "@opentelemetry/resources": "^2.4.0",
+ "@opentelemetry/sdk-trace-base": "^2.4.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
"@sentry/core": "10.35.0",
"@sentry/node-core": "10.35.0",
diff --git a/dev-packages/node-integration-tests/package.json b/dev-packages/node-integration-tests/package.json
index 0305a70e0029..b503e11b5c51 100644
--- a/dev-packages/node-integration-tests/package.json
+++ b/dev-packages/node-integration-tests/package.json
@@ -35,6 +35,7 @@
"@nestjs/common": "^11",
"@nestjs/core": "^11",
"@nestjs/platform-express": "^11",
+ "@prisma/adapter-pg": "7.2.0",
"@prisma/client": "6.15.0",
"@sentry/aws-serverless": "10.35.0",
"@sentry/core": "10.35.0",
diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/docker-compose.yml b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/docker-compose.yml
new file mode 100644
index 000000000000..a56fd51cf7d9
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/docker-compose.yml
@@ -0,0 +1,13 @@
+version: '3.9'
+
+services:
+ db:
+ image: postgres:13
+ restart: always
+ container_name: integration-tests-prisma-v7
+ ports:
+ - '5435:5432'
+ environment:
+ POSTGRES_USER: prisma
+ POSTGRES_PASSWORD: prisma
+ POSTGRES_DB: tests
diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/instrument.mjs
new file mode 100644
index 000000000000..46a27dd03b74
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/instrument.mjs
@@ -0,0 +1,9 @@
+import * as Sentry from '@sentry/node';
+import { loggingTransport } from '@sentry-internal/node-integration-tests';
+
+Sentry.init({
+ dsn: 'https://public@dsn.ingest.sentry.io/1337',
+ release: '1.0',
+ tracesSampleRate: 1.0,
+ transport: loggingTransport,
+});
diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma.config.ts b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma.config.ts
new file mode 100644
index 000000000000..cb67c05a6f37
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma.config.ts
@@ -0,0 +1,9 @@
+import { defineConfig } from 'prisma/config';
+
+export default defineConfig({
+ schema: './prisma/schema.prisma',
+ migrations: './prisma/migrations',
+ datasource: {
+ url: 'postgresql://prisma:prisma@localhost:5435/tests',
+ },
+});
diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/migrations/migration_lock.toml b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/migrations/migration_lock.toml
new file mode 100644
index 000000000000..99e4f2009079
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/migrations/migration_lock.toml
@@ -0,0 +1,3 @@
+# Please do not edit this file manually
+# It should be added in your version-control system (i.e. Git)
+provider = "postgresql"
diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/migrations/sentry_test/migration.sql b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/migrations/sentry_test/migration.sql
new file mode 100644
index 000000000000..8619aaceb2b0
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/migrations/sentry_test/migration.sql
@@ -0,0 +1,12 @@
+-- CreateTable
+CREATE TABLE "User" (
+ "id" SERIAL NOT NULL,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "email" TEXT NOT NULL,
+ "name" TEXT,
+
+ CONSTRAINT "User_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/schema.prisma b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/schema.prisma
new file mode 100644
index 000000000000..6aa93e968540
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/schema.prisma
@@ -0,0 +1,15 @@
+datasource db {
+ provider = "postgresql"
+}
+
+generator client {
+ provider = "prisma-client"
+ output = "./generated/prisma"
+}
+
+model User {
+ id Int @id @default(autoincrement())
+ createdAt DateTime @default(now())
+ email String @unique
+ name String?
+}
diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/tsconfig.json b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/tsconfig.json
new file mode 100644
index 000000000000..f95f8e88df1b
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/prisma/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "target": "ES2023",
+ "declaration": false,
+ "rewriteRelativeImportExtensions": true,
+ "skipLibCheck": true
+ },
+ "include": ["./generated/prisma/**/*.ts"]
+}
diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/scenario.mjs b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/scenario.mjs
new file mode 100644
index 000000000000..61a7d3c43984
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/scenario.mjs
@@ -0,0 +1,46 @@
+import { PrismaPg } from '@prisma/adapter-pg';
+import * as Sentry from '@sentry/node';
+import { randomBytes } from 'crypto';
+import { PrismaClient } from './prisma/generated/prisma/client.js';
+
+// Stop the process from exiting before the transaction is sent
+setInterval(() => {}, 1000);
+
+const connectionString = 'postgresql://prisma:prisma@localhost:5435/tests';
+
+async function run() {
+ await Sentry.startSpan(
+ {
+ name: 'Test Transaction',
+ op: 'transaction',
+ },
+ async span => {
+ const adapter = new PrismaPg({ connectionString });
+ const client = new PrismaClient({ adapter });
+
+ await client.user.create({
+ data: {
+ name: 'Tilda',
+ email: `tilda_${randomBytes(4).toString('hex')}@sentry.io`,
+ },
+ });
+
+ await client.user.findMany();
+
+ await client.user.deleteMany({
+ where: {
+ email: {
+ contains: 'sentry.io',
+ },
+ },
+ });
+
+ setTimeout(async () => {
+ span.end();
+ await client.$disconnect();
+ }, 500);
+ },
+ );
+}
+
+run();
diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/test.ts b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/test.ts
new file mode 100644
index 000000000000..9ae4efd136e7
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm-v7/test.ts
@@ -0,0 +1,74 @@
+import { afterAll, expect } from 'vitest';
+import { conditionalTest } from '../../../utils';
+import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner';
+
+afterAll(() => {
+ cleanupChildProcesses();
+});
+
+// Prisma 7 requires Node.js 20.19+
+conditionalTest({ min: 20 })('Prisma ORM v7 Tests', () => {
+ createEsmAndCjsTests(
+ __dirname,
+ 'scenario.mjs',
+ 'instrument.mjs',
+ (createRunner, test, _mode, cwd) => {
+ test('should instrument PostgreSQL queries from Prisma ORM', { timeout: 75_000 }, async () => {
+ await createRunner()
+ .withDockerCompose({
+ workingDirectory: [cwd],
+ readyMatches: ['port 5432'],
+ setupCommand: `prisma generate --schema ${cwd}/prisma/schema.prisma && tsc -p ${cwd}/prisma/tsconfig.json && prisma migrate dev -n sentry-test --schema ${cwd}/prisma/schema.prisma`,
+ })
+ .expect({
+ transaction: transaction => {
+ expect(transaction.transaction).toBe('Test Transaction');
+
+ const spans = transaction.spans || [];
+ expect(spans.length).toBeGreaterThanOrEqual(5);
+
+ // Verify Prisma spans have the correct origin
+ const prismaSpans = spans.filter(
+ span => span.data && span.data['sentry.origin'] === 'auto.db.otel.prisma',
+ );
+ expect(prismaSpans.length).toBeGreaterThanOrEqual(5);
+
+ // Check for key Prisma span descriptions
+ const spanDescriptions = prismaSpans.map(span => span.description);
+ expect(spanDescriptions).toContain('prisma:client:operation');
+ expect(spanDescriptions).toContain('prisma:client:serialize');
+ expect(spanDescriptions).toContain('prisma:client:connect');
+ expect(spanDescriptions).toContain('prisma:client:db_query');
+
+ // Verify the create operation has correct metadata
+ const createSpan = prismaSpans.find(
+ span =>
+ span.description === 'prisma:client:operation' &&
+ span.data?.['method'] === 'create' &&
+ span.data?.['model'] === 'User',
+ );
+ expect(createSpan).toBeDefined();
+
+ // Verify db_query span has system info and correct op (v7 uses db.system.name)
+ const dbQuerySpan = prismaSpans.find(span => span.description === 'prisma:client:db_query');
+ expect(dbQuerySpan?.data?.['db.system.name']).toBe('postgresql');
+ expect(dbQuerySpan?.data?.['sentry.op']).toBe('db');
+ expect(dbQuerySpan?.op).toBe('db');
+ },
+ })
+ .start()
+ .completed();
+ });
+ },
+ {
+ additionalDependencies: {
+ '@prisma/adapter-pg': '7.2.0',
+ '@prisma/client': '7.2.0',
+ pg: '^8.11.0',
+ prisma: '7.2.0',
+ typescript: '^5.9.0',
+ },
+ copyPaths: ['prisma', 'prisma.config.ts', 'docker-compose.yml'],
+ },
+ );
+});
diff --git a/dev-packages/node-integration-tests/utils/runner.ts b/dev-packages/node-integration-tests/utils/runner.ts
index 985db0a80e6c..ee2fae0bc06b 100644
--- a/dev-packages/node-integration-tests/utils/runner.ts
+++ b/dev-packages/node-integration-tests/utils/runner.ts
@@ -110,7 +110,9 @@ async function runDockerCompose(options: DockerOptions): Promise {
clearTimeout(timeout);
if (options.setupCommand) {
try {
- execSync(options.setupCommand, { cwd, stdio: 'inherit' });
+ // Prepend local node_modules/.bin to PATH so additionalDependencies binaries take precedence
+ const env = { ...process.env, PATH: `${cwd}/node_modules/.bin:${process.env.PATH}` };
+ execSync(options.setupCommand, { cwd, stdio: 'inherit', env });
} catch (e) {
log('Error running docker setup command', e);
}
diff --git a/packages/aws-serverless/package.json b/packages/aws-serverless/package.json
index aa93a915f338..56174588929c 100644
--- a/packages/aws-serverless/package.json
+++ b/packages/aws-serverless/package.json
@@ -66,8 +66,8 @@
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/instrumentation": "^0.208.0",
- "@opentelemetry/instrumentation-aws-sdk": "0.64.0",
+ "@opentelemetry/instrumentation": "^0.210.0",
+ "@opentelemetry/instrumentation-aws-sdk": "0.65.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
"@sentry/core": "10.35.0",
"@sentry/node": "10.35.0",
diff --git a/packages/browser/src/integrations/globalhandlers.ts b/packages/browser/src/integrations/globalhandlers.ts
index 6bada802b98e..c8cd806d0062 100644
--- a/packages/browser/src/integrations/globalhandlers.ts
+++ b/packages/browser/src/integrations/globalhandlers.ts
@@ -9,6 +9,7 @@ import {
getLocationHref,
isPrimitive,
isString,
+ stripDataUrlContent,
UNKNOWN_FUNCTION,
} from '@sentry/core';
import type { BrowserClient } from '../client';
@@ -208,14 +209,13 @@ function getFilenameFromUrl(url: string | undefined): string | undefined {
return undefined;
}
- // stack frame urls can be data urls, for example when initializing a Worker with a base64 encoded script
- // in this case we just show the data prefix and mime type to avoid too long raw data urls
+ // Strip data URL content to avoid long base64 strings in stack frames
+ // (e.g. when initializing a Worker with a base64 encoded script)
+ // Don't include data prefix for filenames as it's not useful for stack traces
+ // Wrap with < > to indicate it's a placeholder
if (url.startsWith('data:')) {
- const match = url.match(/^data:([^;]+)/);
- const mimeType = match ? match[1] : 'text/javascript';
- const isBase64 = url.includes('base64,');
- return ``;
+ return `<${stripDataUrlContent(url, false)}>`;
}
- return url; // it's fine to not truncate it as it's not put in a regex (https://codeql.github.com/codeql-query-help/javascript/js-polynomial-redos)
+ return url;
}
diff --git a/packages/browser/src/tracing/request.ts b/packages/browser/src/tracing/request.ts
index 025b08b12168..0c0e30629436 100644
--- a/packages/browser/src/tracing/request.ts
+++ b/packages/browser/src/tracing/request.ts
@@ -23,6 +23,7 @@ import {
spanToJSON,
startInactiveSpan,
stringMatchesSomePattern,
+ stripDataUrlContent,
stripUrlQueryAndFragment,
} from '@sentry/core';
import type { XhrHint } from '@sentry-internal/browser-utils';
@@ -199,7 +200,7 @@ export function instrumentOutgoingRequests(client: Client, _options?: Partial
@@ -317,9 +322,22 @@ function getSpanStartOptions(
method: string,
spanOrigin: SpanOrigin,
): Parameters[0] {
+ // Data URLs need special handling because parseStringToURLObject treats them as "relative"
+ // (no "://"), causing getSanitizedUrlStringFromUrlObject to return just the pathname
+ // without the "data:" prefix, making later stripDataUrlContent calls ineffective.
+ // So for data URLs, we strip the content first and use that directly.
+ if (url.startsWith('data:')) {
+ const sanitizedUrl = stripDataUrlContent(url);
+ return {
+ name: `${method} ${sanitizedUrl}`,
+ attributes: getFetchSpanAttributes(url, undefined, method, spanOrigin),
+ };
+ }
+
const parsedUrl = parseStringToURLObject(url);
+ const sanitizedUrl = parsedUrl ? getSanitizedUrlStringFromUrlObject(parsedUrl) : url;
return {
- name: parsedUrl ? `${method} ${getSanitizedUrlStringFromUrlObject(parsedUrl)}` : method,
+ name: `${method} ${sanitizedUrl}`,
attributes: getFetchSpanAttributes(url, parsedUrl, method, spanOrigin),
};
}
@@ -331,7 +349,7 @@ function getFetchSpanAttributes(
spanOrigin: SpanOrigin,
): SpanAttributes {
const attributes: SpanAttributes = {
- url,
+ url: stripDataUrlContent(url),
type: 'fetch',
'http.method': method,
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanOrigin,
@@ -339,7 +357,7 @@ function getFetchSpanAttributes(
};
if (parsedUrl) {
if (!isURLObjectRelative(parsedUrl)) {
- attributes['http.url'] = parsedUrl.href;
+ attributes['http.url'] = stripDataUrlContent(parsedUrl.href);
attributes['server.address'] = parsedUrl.host;
}
if (parsedUrl.search) {
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 0fdd328a42d2..19a83d230155 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -313,6 +313,7 @@ export {
getHttpSpanDetailsFromUrlObject,
isURLObjectRelative,
getSanitizedUrlStringFromUrlObject,
+ stripDataUrlContent,
} from './utils/url';
export {
eventFromMessage,
diff --git a/packages/core/src/utils/debug-ids.ts b/packages/core/src/utils/debug-ids.ts
index fd31009ae32d..ea45a8fb2e6c 100644
--- a/packages/core/src/utils/debug-ids.ts
+++ b/packages/core/src/utils/debug-ids.ts
@@ -1,5 +1,6 @@
import type { DebugImage } from '../types-hoist/debugMeta';
import type { StackParser } from '../types-hoist/stacktrace';
+import { normalizeStackTracePath } from './stacktrace';
import { GLOBAL_OBJ } from './worldwide';
type StackString = string;
@@ -10,6 +11,17 @@ let lastSentryKeysCount: number | undefined;
let lastNativeKeysCount: number | undefined;
let cachedFilenameDebugIds: Record | undefined;
+/**
+ * Clears the cached debug ID mappings.
+ * Useful for testing or when the global debug ID state changes.
+ */
+export function clearDebugIdCache(): void {
+ parsedStackResults = undefined;
+ lastSentryKeysCount = undefined;
+ lastNativeKeysCount = undefined;
+ cachedFilenameDebugIds = undefined;
+}
+
/**
* Returns a map of filenames to debug identifiers.
* Supports both proprietary _sentryDebugIds and native _debugIds (e.g., from Vercel) formats.
@@ -101,11 +113,12 @@ export function getDebugImagesForResources(
const images: DebugImage[] = [];
for (const path of resource_paths) {
- if (path && filenameDebugIdMap[path]) {
+ const normalizedPath = normalizeStackTracePath(path);
+ if (normalizedPath && filenameDebugIdMap[normalizedPath]) {
images.push({
type: 'sourcemap',
code_file: path,
- debug_id: filenameDebugIdMap[path],
+ debug_id: filenameDebugIdMap[normalizedPath],
});
}
}
diff --git a/packages/core/src/utils/node-stack-trace.ts b/packages/core/src/utils/node-stack-trace.ts
index 0cecd3dbf1e9..1132471b0e8f 100644
--- a/packages/core/src/utils/node-stack-trace.ts
+++ b/packages/core/src/utils/node-stack-trace.ts
@@ -22,7 +22,7 @@
// THE SOFTWARE.
import type { StackLineParser, StackLineParserFn } from '../types-hoist/stacktrace';
-import { UNKNOWN_FUNCTION } from './stacktrace';
+import { normalizeStackTracePath, UNKNOWN_FUNCTION } from './stacktrace';
export type GetModuleFn = (filename: string | undefined) => string | undefined;
@@ -55,7 +55,6 @@ export function node(getModule?: GetModuleFn): StackLineParserFn {
const FULL_MATCH = /at (?:async )?(?:(.+?)\s+\()?(?:(.+):(\d+):(\d+)?|([^)]+))\)?/;
const DATA_URI_MATCH = /at (?:async )?(.+?) \(data:(.*?),/;
- // eslint-disable-next-line complexity
return (line: string) => {
const dataUriMatch = line.match(DATA_URI_MATCH);
if (dataUriMatch) {
@@ -109,14 +108,9 @@ export function node(getModule?: GetModuleFn): StackLineParserFn {
functionName = typeName ? `${typeName}.${methodName}` : methodName;
}
- let filename = lineMatch[2]?.startsWith('file://') ? lineMatch[2].slice(7) : lineMatch[2];
+ let filename = normalizeStackTracePath(lineMatch[2]);
const isNative = lineMatch[5] === 'native';
- // If it's a Windows path, trim the leading slash so that `/C:/foo` becomes `C:/foo`
- if (filename?.match(/\/[A-Z]:/)) {
- filename = filename.slice(1);
- }
-
if (!filename && lineMatch[5] && !isNative) {
filename = lineMatch[5];
}
diff --git a/packages/core/src/utils/stacktrace.ts b/packages/core/src/utils/stacktrace.ts
index 6b50caf48b30..16a32ede4e58 100644
--- a/packages/core/src/utils/stacktrace.ts
+++ b/packages/core/src/utils/stacktrace.ts
@@ -177,3 +177,15 @@ export function getVueInternalName(value: VueViewModel | VNode): string {
return isVNode ? '[VueVNode]' : '[VueViewModel]';
}
+
+/**
+ * Normalizes stack line paths by removing file:// prefix and leading slashes for Windows paths
+ */
+export function normalizeStackTracePath(path: string | undefined): string | undefined {
+ let filename = path?.startsWith('file://') ? path.slice(7) : path;
+ // If it's a Windows path, trim the leading slash so that `/C:/foo` becomes `C:/foo`
+ if (filename?.match(/\/[A-Z]:/)) {
+ filename = filename.slice(1);
+ }
+ return filename;
+}
diff --git a/packages/core/src/utils/url.ts b/packages/core/src/utils/url.ts
index ca09e6e8b5e7..bf0c17dbc278 100644
--- a/packages/core/src/utils/url.ts
+++ b/packages/core/src/utils/url.ts
@@ -263,3 +263,39 @@ export function getSanitizedUrlString(url: PartialURL): string {
return `${protocol ? `${protocol}://` : ''}${filteredHost}${path}`;
}
+
+/**
+ * Strips the content from a data URL, returning a placeholder with the MIME type.
+ *
+ * Data URLs can be very long (e.g. base64 encoded scripts for Web Workers),
+ * with little valuable information, often leading to envelopes getting dropped due
+ * to size limit violations. Therefore, we strip data URLs and replace them with a
+ * placeholder.
+ *
+ * @param url - The URL to process
+ * @param includeDataPrefix - If true, includes the first 10 characters of the data stream
+ * for debugging (e.g., to identify magic bytes like WASM's AGFzbQ).
+ * Defaults to true.
+ * @returns For data URLs, returns a short format like `data:text/javascript;base64,SGVsbG8gV2... [truncated]`.
+ * For non-data URLs, returns the original URL unchanged.
+ */
+export function stripDataUrlContent(url: string, includeDataPrefix: boolean = true): string {
+ if (url.startsWith('data:')) {
+ // Match the MIME type (everything after 'data:' until the first ';' or ',')
+ const match = url.match(/^data:([^;,]+)/);
+ const mimeType = match ? match[1] : 'text/plain';
+ const isBase64 = url.includes(';base64,');
+
+ // Find where the actual data starts (after the comma)
+ const dataStart = url.indexOf(',');
+ let dataPrefix = '';
+ if (includeDataPrefix && dataStart !== -1) {
+ const data = url.slice(dataStart + 1);
+ // Include first 10 chars of data to help identify content (e.g., magic bytes)
+ dataPrefix = data.length > 10 ? `${data.slice(0, 10)}... [truncated]` : data;
+ }
+
+ return `data:${mimeType}${isBase64 ? ',base64' : ''}${dataPrefix ? `,${dataPrefix}` : ''}`;
+ }
+ return url;
+}
diff --git a/packages/core/test/lib/utils/debug-ids.test.ts b/packages/core/test/lib/utils/debug-ids.test.ts
new file mode 100644
index 000000000000..45ff58c82565
--- /dev/null
+++ b/packages/core/test/lib/utils/debug-ids.test.ts
@@ -0,0 +1,187 @@
+import { beforeEach, describe, expect, it } from 'vitest';
+import { nodeStackLineParser } from '../../../src';
+import { clearDebugIdCache, getDebugImagesForResources, getFilenameToDebugIdMap } from '../../../src/utils/debug-ids';
+import { createStackParser } from '../../../src/utils/stacktrace';
+
+const nodeStackParser = createStackParser(nodeStackLineParser());
+
+describe('getDebugImagesForResources', () => {
+ beforeEach(() => {
+ // Clear any existing debug ID maps
+ delete (globalThis as any)._sentryDebugIds;
+ delete (globalThis as any)._debugIds;
+ clearDebugIdCache();
+ });
+
+ it('should return debug images for resources without file:// prefix', () => {
+ // Setup debug IDs
+ (globalThis as any)._sentryDebugIds = {
+ 'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
+ };
+
+ const resources = ['/var/task/index.js'];
+ const images = getDebugImagesForResources(nodeStackParser, resources);
+
+ expect(images).toHaveLength(1);
+ expect(images[0]).toEqual({
+ type: 'sourcemap',
+ code_file: '/var/task/index.js',
+ debug_id: 'debug-id-123',
+ });
+ });
+
+ it('should return debug images for resources with file:// prefix', () => {
+ // Setup debug IDs - the stack parser strips file:// when parsing
+ (globalThis as any)._sentryDebugIds = {
+ 'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
+ };
+
+ // V8 profiler returns resources WITH file:// prefix
+ const resources = ['file:///var/task/index.js'];
+ const images = getDebugImagesForResources(nodeStackParser, resources);
+
+ expect(images).toHaveLength(1);
+ expect(images[0]).toEqual({
+ type: 'sourcemap',
+ code_file: 'file:///var/task/index.js',
+ debug_id: 'debug-id-123',
+ });
+ });
+
+ it('should handle mixed resources with and without file:// prefix', () => {
+ (globalThis as any)._sentryDebugIds = {
+ 'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
+ 'at anotherFunction (/var/task/utils.js:10:5)': 'debug-id-456',
+ };
+
+ const resources = ['file:///var/task/index.js', '/var/task/utils.js'];
+ const images = getDebugImagesForResources(nodeStackParser, resources);
+
+ expect(images).toHaveLength(2);
+ expect(images[0]).toEqual({
+ type: 'sourcemap',
+ code_file: 'file:///var/task/index.js',
+ debug_id: 'debug-id-123',
+ });
+ expect(images[1]).toEqual({
+ type: 'sourcemap',
+ code_file: '/var/task/utils.js',
+ debug_id: 'debug-id-456',
+ });
+ });
+
+ it('should return empty array when no debug IDs match', () => {
+ (globalThis as any)._sentryDebugIds = {
+ 'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
+ };
+
+ const resources = ['file:///var/task/other.js'];
+ const images = getDebugImagesForResources(nodeStackParser, resources);
+
+ expect(images).toHaveLength(0);
+ });
+
+ it('should return empty array when no debug IDs are registered', () => {
+ const resources = ['file:///var/task/index.js'];
+ const images = getDebugImagesForResources(nodeStackParser, resources);
+
+ expect(images).toHaveLength(0);
+ });
+
+ it('should handle empty resource paths array', () => {
+ (globalThis as any)._sentryDebugIds = {
+ 'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
+ };
+
+ const resources: string[] = [];
+ const images = getDebugImagesForResources(nodeStackParser, resources);
+
+ expect(images).toHaveLength(0);
+ });
+
+ it('should handle Windows paths with file:// prefix', () => {
+ // Stack parser normalizes Windows paths: file:///C:/foo.js -> C:/foo.js
+ (globalThis as any)._sentryDebugIds = {
+ 'at mockFunction (C:/Users/dev/project/index.js:1:1)': 'debug-id-win-123',
+ };
+
+ // V8 profiler returns Windows paths with file:// prefix
+ const resources = ['file:///C:/Users/dev/project/index.js'];
+ const images = getDebugImagesForResources(nodeStackParser, resources);
+
+ expect(images).toHaveLength(1);
+ expect(images[0]).toEqual({
+ type: 'sourcemap',
+ code_file: 'file:///C:/Users/dev/project/index.js',
+ debug_id: 'debug-id-win-123',
+ });
+ });
+
+ it('should handle Windows paths without file:// prefix', () => {
+ (globalThis as any)._sentryDebugIds = {
+ 'at mockFunction (C:/Users/dev/project/index.js:1:1)': 'debug-id-win-123',
+ };
+
+ const resources = ['C:/Users/dev/project/index.js'];
+ const images = getDebugImagesForResources(nodeStackParser, resources);
+
+ expect(images).toHaveLength(1);
+ expect(images[0]).toEqual({
+ type: 'sourcemap',
+ code_file: 'C:/Users/dev/project/index.js',
+ debug_id: 'debug-id-win-123',
+ });
+ });
+});
+
+describe('getFilenameToDebugIdMap', () => {
+ beforeEach(() => {
+ delete (globalThis as any)._sentryDebugIds;
+ delete (globalThis as any)._debugIds;
+ clearDebugIdCache();
+ });
+
+ it('should return empty object when no debug IDs are registered', () => {
+ const map = getFilenameToDebugIdMap(nodeStackParser);
+ expect(map).toEqual({});
+ });
+
+ it('should build map from _sentryDebugIds', () => {
+ (globalThis as any)._sentryDebugIds = {
+ 'at mockFunction (/var/task/index.js:1:1)': 'debug-id-123',
+ 'at anotherFunction (/var/task/utils.js:10:5)': 'debug-id-456',
+ };
+
+ const map = getFilenameToDebugIdMap(nodeStackParser);
+
+ expect(map).toEqual({
+ '/var/task/index.js': 'debug-id-123',
+ '/var/task/utils.js': 'debug-id-456',
+ });
+ });
+
+ it('should build map from native _debugIds', () => {
+ (globalThis as any)._debugIds = {
+ 'at mockFunction (/var/task/index.js:1:1)': 'native-debug-id-123',
+ };
+
+ const map = getFilenameToDebugIdMap(nodeStackParser);
+
+ expect(map).toEqual({
+ '/var/task/index.js': 'native-debug-id-123',
+ });
+ });
+
+ it('should prioritize native _debugIds over _sentryDebugIds', () => {
+ (globalThis as any)._sentryDebugIds = {
+ 'at mockFunction (/var/task/index.js:1:1)': 'sentry-debug-id',
+ };
+ (globalThis as any)._debugIds = {
+ 'at mockFunction (/var/task/index.js:1:1)': 'native-debug-id',
+ };
+
+ const map = getFilenameToDebugIdMap(nodeStackParser);
+
+ expect(map['/var/task/index.js']).toBe('native-debug-id');
+ });
+});
diff --git a/packages/core/test/lib/utils/url.test.ts b/packages/core/test/lib/utils/url.test.ts
index 33364d66daa5..7bdfcfd63804 100644
--- a/packages/core/test/lib/utils/url.test.ts
+++ b/packages/core/test/lib/utils/url.test.ts
@@ -6,6 +6,7 @@ import {
isURLObjectRelative,
parseStringToURLObject,
parseUrl,
+ stripDataUrlContent,
stripUrlQueryAndFragment,
} from '../../../src/utils/url';
@@ -638,3 +639,119 @@ describe('getHttpSpanDetailsFromUrlObject', () => {
});
});
});
+
+describe('stripDataUrlContent', () => {
+ it('returns regular URLs unchanged', () => {
+ expect(stripDataUrlContent('https://example.com/api')).toBe('https://example.com/api');
+ expect(stripDataUrlContent('http://localhost:3000/test')).toBe('http://localhost:3000/test');
+ expect(stripDataUrlContent('/relative/path')).toBe('/relative/path');
+ });
+
+ it('should be applied BEFORE parseStringToURLObject for data URLs', () => {
+ // This test documents an important behavior:
+ // Data URLs are treated as "relative" by parseStringToURLObject because they don't contain "://".
+ // This means getSanitizedUrlStringFromUrlObject returns just the pathname (without "data:" prefix),
+ // and stripDataUrlContent won't match since it checks url.startsWith('data:').
+ // Therefore, stripDataUrlContent MUST be applied to the original URL before parsing.
+ const dataUrl = 'data:text/javascript;base64,SGVsbG8gV29ybGQ=';
+
+ // Verify data URLs are treated as relative
+ const parsedUrl = parseStringToURLObject(dataUrl);
+ expect(parsedUrl).toBeDefined();
+ expect(isURLObjectRelative(parsedUrl!)).toBe(true);
+
+ // getSanitizedUrlStringFromUrlObject returns just the pathname for relative URLs
+ const sanitizedWithoutStripping = getSanitizedUrlStringFromUrlObject(parsedUrl!);
+ // The pathname doesn't start with 'data:', so stripDataUrlContent wouldn't work on it
+ expect(sanitizedWithoutStripping.startsWith('data:')).toBe(false);
+ // Applying stripDataUrlContent AFTER parsing is ineffective
+ expect(stripDataUrlContent(sanitizedWithoutStripping)).toBe(sanitizedWithoutStripping);
+
+ // CORRECT approach: strip data URL content FIRST, before any URL parsing
+ const strippedUrl = stripDataUrlContent(dataUrl);
+ // Default behavior includes first 10 chars of data for debugging (e.g., magic bytes)
+ expect(strippedUrl).toBe('data:text/javascript,base64,SGVsbG8gV2... [truncated]');
+ // The stripped URL is already sanitized and can be used directly as the span name
+ });
+
+ describe('with includeDataPrefix=true (default)', () => {
+ it('includes first 10 chars of data for base64 data URLs', () => {
+ // SGVsbG8gV29ybGQ= is "Hello World" in base64
+ expect(stripDataUrlContent('data:text/javascript;base64,SGVsbG8gV29ybGQ=')).toBe(
+ 'data:text/javascript,base64,SGVsbG8gV2... [truncated]',
+ );
+ expect(stripDataUrlContent('data:application/json;base64,eyJrZXkiOiJ2YWx1ZSJ9')).toBe(
+ 'data:application/json,base64,eyJrZXkiOi... [truncated]',
+ );
+ });
+
+ it('includes first 10 chars of data for non-base64 data URLs', () => {
+ expect(stripDataUrlContent('data:text/plain,Hello%20World')).toBe('data:text/plain,Hello%20Wo... [truncated]');
+ expect(stripDataUrlContent('data:text/html,Hello
')).toBe('data:text/html,Hello<... [truncated]');
+ });
+
+ it('includes all data if less than 10 chars', () => {
+ expect(stripDataUrlContent('data:text/plain,Hi')).toBe('data:text/plain,Hi');
+ expect(stripDataUrlContent('data:text/plain;base64,SGk=')).toBe('data:text/plain,base64,SGk=');
+ });
+
+ it('helps identify WASM by magic bytes (AGFzbQ)', () => {
+ // WASM magic bytes: \0asm -> base64: AGFzbQ
+ const wasmDataUrl = 'data:application/wasm;base64,AGFzbQEAAAA=';
+ expect(stripDataUrlContent(wasmDataUrl)).toBe('data:application/wasm,base64,AGFzbQEAAA... [truncated]');
+ });
+
+ it('handles various MIME types', () => {
+ expect(stripDataUrlContent('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA')).toBe(
+ 'data:image/png,base64,iVBORw0KGg... [truncated]',
+ );
+ expect(stripDataUrlContent('data:image/svg+xml;base64,PHN2Zz4=')).toBe('data:image/svg+xml,base64,PHN2Zz4=');
+ });
+
+ it('defaults to text/plain for data URLs without MIME type', () => {
+ expect(stripDataUrlContent('data:,Hello')).toBe('data:text/plain,Hello');
+ expect(stripDataUrlContent('data:;base64,SGVsbG8=')).toBe('data:text/plain,base64,SGVsbG8=');
+ });
+
+ it('handles empty data URLs', () => {
+ expect(stripDataUrlContent('data:')).toBe('data:text/plain');
+ });
+
+ it('handles very long base64 encoded data URLs', () => {
+ const longBase64 = 'A'.repeat(10000);
+ expect(stripDataUrlContent(`data:text/javascript;base64,${longBase64}`)).toBe(
+ 'data:text/javascript,base64,AAAAAAAAAA... [truncated]',
+ );
+ });
+ });
+
+ describe('with includeDataPrefix=false', () => {
+ it('strips all content from base64 data URLs', () => {
+ expect(stripDataUrlContent('data:text/javascript;base64,SGVsbG8gV29ybGQ=', false)).toBe(
+ 'data:text/javascript,base64',
+ );
+ expect(stripDataUrlContent('data:application/json;base64,eyJrZXkiOiJ2YWx1ZSJ9', false)).toBe(
+ 'data:application/json,base64',
+ );
+ });
+
+ it('strips all content from non-base64 data URLs', () => {
+ expect(stripDataUrlContent('data:text/plain,Hello%20World', false)).toBe('data:text/plain');
+ expect(stripDataUrlContent('data:text/html,Hello
', false)).toBe('data:text/html');
+ });
+
+ it('handles various MIME types', () => {
+ expect(stripDataUrlContent('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA', false)).toBe(
+ 'data:image/png,base64',
+ );
+ expect(stripDataUrlContent('data:application/wasm;base64,AGFzbQEAAAA=', false)).toBe(
+ 'data:application/wasm,base64',
+ );
+ });
+
+ it('defaults to text/plain for data URLs without MIME type', () => {
+ expect(stripDataUrlContent('data:,Hello', false)).toBe('data:text/plain');
+ expect(stripDataUrlContent('data:;base64,SGVsbG8=', false)).toBe('data:text/plain,base64');
+ });
+ });
+});
diff --git a/packages/nestjs/package.json b/packages/nestjs/package.json
index 38838303b35c..67a0afa84c2e 100644
--- a/packages/nestjs/package.json
+++ b/packages/nestjs/package.json
@@ -45,9 +45,9 @@
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/core": "^2.2.0",
- "@opentelemetry/instrumentation": "^0.208.0",
- "@opentelemetry/instrumentation-nestjs-core": "0.55.0",
+ "@opentelemetry/core": "^2.4.0",
+ "@opentelemetry/instrumentation": "^0.210.0",
+ "@opentelemetry/instrumentation-nestjs-core": "0.56.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
"@sentry/core": "10.35.0",
"@sentry/node": "10.35.0"
diff --git a/packages/nextjs/src/server/prepareSafeIdGeneratorContext.ts b/packages/nextjs/src/server/prepareSafeIdGeneratorContext.ts
index bd262eb736e1..b060ae040cfe 100644
--- a/packages/nextjs/src/server/prepareSafeIdGeneratorContext.ts
+++ b/packages/nextjs/src/server/prepareSafeIdGeneratorContext.ts
@@ -1,8 +1,4 @@
-import {
- type _INTERNAL_RandomSafeContextRunner as _INTERNAL_RandomSafeContextRunner,
- debug,
- GLOBAL_OBJ,
-} from '@sentry/core';
+import { type _INTERNAL_RandomSafeContextRunner as RandomSafeContextRunner, debug, GLOBAL_OBJ } from '@sentry/core';
import { DEBUG_BUILD } from '../common/debug-build';
// Inline AsyncLocalStorage interface from current types
@@ -15,17 +11,53 @@ type OriginalAsyncLocalStorage = typeof AsyncLocalStorage;
*/
export function prepareSafeIdGeneratorContext(): void {
const sym = Symbol.for('__SENTRY_SAFE_RANDOM_ID_WRAPPER__');
- const globalWithSymbol: typeof GLOBAL_OBJ & { [sym]?: _INTERNAL_RandomSafeContextRunner } = GLOBAL_OBJ;
- const als = getAsyncLocalStorage();
- if (!als || typeof als.snapshot !== 'function') {
- DEBUG_BUILD &&
- debug.warn(
- '[@sentry/nextjs] No AsyncLocalStorage found in the runtime or AsyncLocalStorage.snapshot() is not available, skipping safe random ID generator context preparation, you may see some errors with cache components.',
- );
+ const globalWithSymbol: typeof GLOBAL_OBJ & { [sym]?: RandomSafeContextRunner } = GLOBAL_OBJ;
+
+ // Get initial snapshot - if unavailable, don't set up the wrapper at all
+ const initialSnapshot = getAsyncLocalStorageSnapshot();
+ if (!initialSnapshot) {
return;
}
- globalWithSymbol[sym] = als.snapshot();
+ // We store a wrapper function instead of the raw snapshot because in serverless
+ // environments (e.g., Cloudflare Workers), the snapshot is bound to the request
+ // context it was created in. Once that request ends, the snapshot becomes invalid.
+ // The wrapper catches this and creates a fresh snapshot for the current request context.
+ let cachedSnapshot: RandomSafeContextRunner = initialSnapshot;
+
+ globalWithSymbol[sym] = (callback: () => T): T => {
+ try {
+ return cachedSnapshot(callback);
+ } catch (error) {
+ // Only handle AsyncLocalStorage-related errors, rethrow others
+ if (!isAsyncLocalStorageError(error)) {
+ throw error;
+ }
+
+ // Snapshot likely stale, try to get a fresh one and retry
+ const freshSnapshot = getAsyncLocalStorageSnapshot();
+ // No snapshot available, fall back to direct execution
+ if (!freshSnapshot) {
+ return callback();
+ }
+
+ // Update the cached snapshot
+ cachedSnapshot = freshSnapshot;
+
+ // Retry the callback with the fresh snapshot
+ try {
+ return cachedSnapshot(callback);
+ } catch (retryError) {
+ // Only fall back for AsyncLocalStorage errors, rethrow others
+ if (!isAsyncLocalStorageError(retryError)) {
+ throw retryError;
+ }
+ // If fresh snapshot also fails with ALS error, fall back to direct execution
+ return callback();
+ }
+ }
+ };
+
DEBUG_BUILD && debug.log('[@sentry/nextjs] Prepared safe random ID generator context');
}
@@ -47,3 +79,21 @@ function getAsyncLocalStorage(): OriginalAsyncLocalStorage | undefined {
return undefined;
}
+
+function getAsyncLocalStorageSnapshot(): RandomSafeContextRunner | undefined {
+ const als = getAsyncLocalStorage();
+
+ if (!als || typeof als.snapshot !== 'function') {
+ DEBUG_BUILD &&
+ debug.warn(
+ '[@sentry/nextjs] No AsyncLocalStorage found in the runtime or AsyncLocalStorage.snapshot() is not available, skipping safe random ID generator context preparation, you may see some errors with cache components.',
+ );
+ return undefined;
+ }
+
+ return als.snapshot();
+}
+
+function isAsyncLocalStorageError(error: unknown): boolean {
+ return error instanceof Error && error.message.includes('AsyncLocalStorage');
+}
diff --git a/packages/node-core/package.json b/packages/node-core/package.json
index de16a80e79d7..bc6b4eed4b5e 100644
--- a/packages/node-core/package.json
+++ b/packages/node-core/package.json
@@ -58,11 +58,11 @@
},
"peerDependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0 || ^2.2.0",
- "@opentelemetry/core": "^1.30.1 || ^2.1.0 || ^2.2.0",
+ "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0",
+ "@opentelemetry/core": "^1.30.1 || ^2.1.0",
"@opentelemetry/instrumentation": ">=0.57.1 <1",
- "@opentelemetry/resources": "^1.30.1 || ^2.1.0 || ^2.2.0",
- "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0 || ^2.2.0",
+ "@opentelemetry/resources": "^1.30.1 || ^2.1.0",
+ "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0",
"@opentelemetry/semantic-conventions": "^1.37.0"
},
"dependencies": {
@@ -74,11 +74,11 @@
"devDependencies": {
"@apm-js-collab/code-transformer": "^0.8.2",
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/context-async-hooks": "^2.2.0",
- "@opentelemetry/core": "^2.2.0",
- "@opentelemetry/instrumentation": "^0.208.0",
- "@opentelemetry/resources": "^2.2.0",
- "@opentelemetry/sdk-trace-base": "^2.2.0",
+ "@opentelemetry/context-async-hooks": "^2.4.0",
+ "@opentelemetry/core": "^2.4.0",
+ "@opentelemetry/instrumentation": "^0.210.0",
+ "@opentelemetry/resources": "^2.4.0",
+ "@opentelemetry/sdk-trace-base": "^2.4.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
"@types/node": "^18.19.1"
},
diff --git a/packages/node/package.json b/packages/node/package.json
index c54ee3edc9f9..a17ab657b6e8 100644
--- a/packages/node/package.json
+++ b/packages/node/package.json
@@ -66,35 +66,35 @@
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/context-async-hooks": "^2.2.0",
- "@opentelemetry/core": "^2.2.0",
- "@opentelemetry/instrumentation": "^0.208.0",
- "@opentelemetry/instrumentation-amqplib": "0.55.0",
- "@opentelemetry/instrumentation-connect": "0.52.0",
- "@opentelemetry/instrumentation-dataloader": "0.26.0",
- "@opentelemetry/instrumentation-express": "0.57.0",
- "@opentelemetry/instrumentation-fs": "0.28.0",
- "@opentelemetry/instrumentation-generic-pool": "0.52.0",
- "@opentelemetry/instrumentation-graphql": "0.56.0",
- "@opentelemetry/instrumentation-hapi": "0.55.0",
- "@opentelemetry/instrumentation-http": "0.208.0",
- "@opentelemetry/instrumentation-ioredis": "0.56.0",
- "@opentelemetry/instrumentation-kafkajs": "0.18.0",
- "@opentelemetry/instrumentation-knex": "0.53.0",
- "@opentelemetry/instrumentation-koa": "0.57.0",
- "@opentelemetry/instrumentation-lru-memoizer": "0.53.0",
- "@opentelemetry/instrumentation-mongodb": "0.61.0",
- "@opentelemetry/instrumentation-mongoose": "0.55.0",
- "@opentelemetry/instrumentation-mysql": "0.54.0",
- "@opentelemetry/instrumentation-mysql2": "0.55.0",
- "@opentelemetry/instrumentation-pg": "0.61.0",
- "@opentelemetry/instrumentation-redis": "0.57.0",
- "@opentelemetry/instrumentation-tedious": "0.27.0",
- "@opentelemetry/instrumentation-undici": "0.19.0",
- "@opentelemetry/resources": "^2.2.0",
- "@opentelemetry/sdk-trace-base": "^2.2.0",
+ "@opentelemetry/context-async-hooks": "^2.4.0",
+ "@opentelemetry/core": "^2.4.0",
+ "@opentelemetry/instrumentation": "^0.210.0",
+ "@opentelemetry/instrumentation-amqplib": "0.57.0",
+ "@opentelemetry/instrumentation-connect": "0.53.0",
+ "@opentelemetry/instrumentation-dataloader": "0.27.0",
+ "@opentelemetry/instrumentation-express": "0.58.0",
+ "@opentelemetry/instrumentation-fs": "0.29.0",
+ "@opentelemetry/instrumentation-generic-pool": "0.53.0",
+ "@opentelemetry/instrumentation-graphql": "0.57.0",
+ "@opentelemetry/instrumentation-hapi": "0.56.0",
+ "@opentelemetry/instrumentation-http": "0.210.0",
+ "@opentelemetry/instrumentation-ioredis": "0.58.0",
+ "@opentelemetry/instrumentation-kafkajs": "0.19.0",
+ "@opentelemetry/instrumentation-knex": "0.54.0",
+ "@opentelemetry/instrumentation-koa": "0.58.0",
+ "@opentelemetry/instrumentation-lru-memoizer": "0.54.0",
+ "@opentelemetry/instrumentation-mongodb": "0.63.0",
+ "@opentelemetry/instrumentation-mongoose": "0.56.0",
+ "@opentelemetry/instrumentation-mysql": "0.56.0",
+ "@opentelemetry/instrumentation-mysql2": "0.56.0",
+ "@opentelemetry/instrumentation-pg": "0.62.0",
+ "@opentelemetry/instrumentation-redis": "0.58.0",
+ "@opentelemetry/instrumentation-tedious": "0.29.0",
+ "@opentelemetry/instrumentation-undici": "0.20.0",
+ "@opentelemetry/resources": "^2.4.0",
+ "@opentelemetry/sdk-trace-base": "^2.4.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
- "@prisma/instrumentation": "6.19.0",
+ "@prisma/instrumentation": "7.2.0",
"@sentry/core": "10.35.0",
"@sentry/node-core": "10.35.0",
"@sentry/opentelemetry": "10.35.0",
diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts
index e6c48a6bd550..7c2cadf9eb43 100644
--- a/packages/node/src/integrations/http.ts
+++ b/packages/node/src/integrations/http.ts
@@ -3,7 +3,13 @@ import { diag } from '@opentelemetry/api';
import type { HttpInstrumentationConfig } from '@opentelemetry/instrumentation-http';
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
import type { Span } from '@sentry/core';
-import { defineIntegration, getClient, hasSpansEnabled } from '@sentry/core';
+import {
+ defineIntegration,
+ getClient,
+ hasSpansEnabled,
+ SEMANTIC_ATTRIBUTE_URL_FULL,
+ stripDataUrlContent,
+} from '@sentry/core';
import type { HTTPModuleRequestIncomingMessage, NodeClient, SentryHttpInstrumentationOptions } from '@sentry/node-core';
import {
addOriginToSpan,
@@ -282,6 +288,15 @@ function getConfigWithDefaults(options: Partial = {}): HttpInstrume
requestHook: (span, req) => {
addOriginToSpan(span, 'auto.http.otel.http');
+ // Sanitize data URLs to prevent long base64 strings in span attributes
+ const url = getRequestUrl(req as ClientRequest);
+ if (url.startsWith('data:')) {
+ const sanitizedUrl = stripDataUrlContent(url);
+ span.setAttribute('http.url', sanitizedUrl);
+ span.setAttribute(SEMANTIC_ATTRIBUTE_URL_FULL, sanitizedUrl);
+ span.updateName(`${(req as ClientRequest).method || 'GET'} ${sanitizedUrl}`);
+ }
+
options.instrumentation?.requestHook?.(span, req);
},
responseHook: (span, res) => {
diff --git a/packages/node/src/integrations/node-fetch.ts b/packages/node/src/integrations/node-fetch.ts
index 6da9fd628bac..b07c1cce8628 100644
--- a/packages/node/src/integrations/node-fetch.ts
+++ b/packages/node/src/integrations/node-fetch.ts
@@ -1,7 +1,15 @@
import type { UndiciInstrumentationConfig } from '@opentelemetry/instrumentation-undici';
import { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici';
import type { IntegrationFn } from '@sentry/core';
-import { defineIntegration, getClient, hasSpansEnabled, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
+import {
+ defineIntegration,
+ getClient,
+ hasSpansEnabled,
+ SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME,
+ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
+ SEMANTIC_ATTRIBUTE_URL_FULL,
+ stripDataUrlContent,
+} from '@sentry/core';
import type { NodeClient } from '@sentry/node-core';
import { generateInstrumentOnce, SentryNodeFetchInstrumentation } from '@sentry/node-core';
import type { NodeClientOptions } from '../types';
@@ -101,7 +109,20 @@ function getConfigWithDefaults(options: Partial = {}): UndiciI
return !!shouldIgnore;
},
- startSpanHook: () => {
+ startSpanHook: request => {
+ const url = getAbsoluteUrl(request.origin, request.path);
+
+ // Sanitize data URLs to prevent long base64 strings in span attributes
+ if (url.startsWith('data:')) {
+ const sanitizedUrl = stripDataUrlContent(url);
+ return {
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.node_fetch',
+ 'http.url': sanitizedUrl,
+ [SEMANTIC_ATTRIBUTE_URL_FULL]: sanitizedUrl,
+ [SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME]: `${request.method || 'GET'} ${sanitizedUrl}`,
+ };
+ }
+
return {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.node_fetch',
};
diff --git a/packages/opentelemetry/package.json b/packages/opentelemetry/package.json
index 28a12de398c6..f8a5e3a391f4 100644
--- a/packages/opentelemetry/package.json
+++ b/packages/opentelemetry/package.json
@@ -43,16 +43,16 @@
},
"peerDependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0 || ^2.2.0",
- "@opentelemetry/core": "^1.30.1 || ^2.1.0 || ^2.2.0",
- "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0 || ^2.2.0",
+ "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0",
+ "@opentelemetry/core": "^1.30.1 || ^2.1.0",
+ "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0",
"@opentelemetry/semantic-conventions": "^1.37.0"
},
"devDependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/context-async-hooks": "^2.2.0",
- "@opentelemetry/core": "^2.2.0",
- "@opentelemetry/sdk-trace-base": "^2.2.0",
+ "@opentelemetry/context-async-hooks": "^2.4.0",
+ "@opentelemetry/core": "^2.4.0",
+ "@opentelemetry/sdk-trace-base": "^2.4.0",
"@opentelemetry/semantic-conventions": "^1.37.0"
},
"scripts": {
diff --git a/packages/opentelemetry/src/utils/parseSpanDescription.ts b/packages/opentelemetry/src/utils/parseSpanDescription.ts
index 9328320e404f..bb9c5f59acf7 100644
--- a/packages/opentelemetry/src/utils/parseSpanDescription.ts
+++ b/packages/opentelemetry/src/utils/parseSpanDescription.ts
@@ -1,6 +1,7 @@
import type { Attributes, AttributeValue } from '@opentelemetry/api';
import { SpanKind } from '@opentelemetry/api';
import {
+ ATTR_DB_SYSTEM_NAME,
ATTR_HTTP_REQUEST_METHOD,
ATTR_HTTP_ROUTE,
ATTR_URL_FULL,
@@ -47,7 +48,7 @@ export function inferSpanData(spanName: string, attributes: SpanAttributes, kind
}
// eslint-disable-next-line deprecation/deprecation
- const dbSystem = attributes[SEMATTRS_DB_SYSTEM];
+ const dbSystem = attributes[ATTR_DB_SYSTEM_NAME] || attributes[SEMATTRS_DB_SYSTEM];
const opIsCache =
typeof attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] === 'string' &&
attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP].startsWith('cache.');
diff --git a/packages/opentelemetry/test/utils/parseSpanDescription.test.ts b/packages/opentelemetry/test/utils/parseSpanDescription.test.ts
index 1d717b1d7488..529866b8a2ac 100644
--- a/packages/opentelemetry/test/utils/parseSpanDescription.test.ts
+++ b/packages/opentelemetry/test/utils/parseSpanDescription.test.ts
@@ -2,6 +2,7 @@
import type { Span } from '@opentelemetry/api';
import { SpanKind } from '@opentelemetry/api';
import {
+ ATTR_DB_SYSTEM_NAME,
ATTR_HTTP_ROUTE,
SEMATTRS_DB_STATEMENT,
SEMATTRS_DB_SYSTEM,
@@ -147,6 +148,48 @@ describe('parseSpanDescription', () => {
source: 'task',
},
],
+ [
+ 'works with db.system.name (stable attribute)',
+ {
+ [ATTR_DB_SYSTEM_NAME]: 'postgresql',
+ [SEMATTRS_DB_STATEMENT]: 'SELECT * from users',
+ },
+ 'test name',
+ SpanKind.CLIENT,
+ {
+ description: 'SELECT * from users',
+ op: 'db',
+ source: 'task',
+ },
+ ],
+ [
+ 'works with db.system.name without statement',
+ {
+ [ATTR_DB_SYSTEM_NAME]: 'postgresql',
+ },
+ 'test name',
+ SpanKind.CLIENT,
+ {
+ description: 'test name',
+ op: 'db',
+ source: 'task',
+ },
+ ],
+ [
+ 'prefers db.system.name over deprecated db.system',
+ {
+ [ATTR_DB_SYSTEM_NAME]: 'postgresql',
+ [SEMATTRS_DB_SYSTEM]: 'mysql',
+ [SEMATTRS_DB_STATEMENT]: 'SELECT * from users',
+ },
+ 'test name',
+ SpanKind.CLIENT,
+ {
+ description: 'SELECT * from users',
+ op: 'db',
+ source: 'task',
+ },
+ ],
[
'works with rpc service',
{
diff --git a/packages/react-router/package.json b/packages/react-router/package.json
index 307ea8dd48f6..9f8ec57975ea 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -46,8 +46,8 @@
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/core": "^2.2.0",
- "@opentelemetry/instrumentation": "^0.208.0",
+ "@opentelemetry/core": "^2.4.0",
+ "@opentelemetry/instrumentation": "^0.210.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
"@sentry/browser": "10.35.0",
"@sentry/cli": "^2.58.4",
diff --git a/packages/remix/package.json b/packages/remix/package.json
index 923ef935e18c..4cf7f1e83e1f 100644
--- a/packages/remix/package.json
+++ b/packages/remix/package.json
@@ -65,7 +65,7 @@
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/instrumentation": "^0.208.0",
+ "@opentelemetry/instrumentation": "^0.210.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
"@remix-run/router": "1.x",
"@sentry/cli": "^2.58.2",
@@ -76,9 +76,9 @@
"yargs": "^17.6.0"
},
"devDependencies": {
- "@remix-run/node": "^2.15.2",
- "@remix-run/react": "^2.15.2",
- "@remix-run/server-runtime": "2.15.2",
+ "@remix-run/node": "^2.17.4",
+ "@remix-run/react": "^2.17.4",
+ "@remix-run/server-runtime": "^2.17.4",
"@types/express": "^4.17.14",
"react": "^18.3.1",
"react-dom": "^18.3.1",
diff --git a/packages/vercel-edge/package.json b/packages/vercel-edge/package.json
index 22d49718de4d..af20da5dec82 100644
--- a/packages/vercel-edge/package.json
+++ b/packages/vercel-edge/package.json
@@ -40,13 +40,13 @@
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
- "@opentelemetry/resources": "^2.2.0",
+ "@opentelemetry/resources": "^2.4.0",
"@sentry/core": "10.35.0"
},
"devDependencies": {
"@edge-runtime/types": "3.0.1",
- "@opentelemetry/core": "^2.2.0",
- "@opentelemetry/sdk-trace-base": "^2.2.0",
+ "@opentelemetry/core": "^2.4.0",
+ "@opentelemetry/sdk-trace-base": "^2.4.0",
"@opentelemetry/semantic-conventions": "^1.37.0",
"@sentry/opentelemetry": "10.35.0"
},
diff --git a/packages/vercel-edge/rollup.npm.config.mjs b/packages/vercel-edge/rollup.npm.config.mjs
index d8f1704e2f8a..d19ef3a09e2f 100644
--- a/packages/vercel-edge/rollup.npm.config.mjs
+++ b/packages/vercel-edge/rollup.npm.config.mjs
@@ -43,6 +43,9 @@ const baseConfig = makeBaseNPMConfig({
plugins.makeJsonPlugin(), // Needed because `require-in-the-middle` imports json via require
replace({
preventAssignment: true,
+ // Use negative lookahead/lookbehind instead of word boundaries so `process.argv0` is also replaced in
+ // `process.argv0.length` (where `.` follows). Default `\b` delimiters don't match before `.`.
+ delimiters: ['(?=0.52.0 <1", "@opentelemetry/instrumentation@^0.208.0":
- version "0.208.0"
- resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.208.0.tgz#d764f8e4329dad50804e2e98f010170c14c4ce8f"
- integrity sha512-Eju0L4qWcQS+oXxi6pgh7zvE2byogAkcsVv0OjHF/97iOz1N/aKE6etSGowYkie+YA1uo6DNwdSxaaNnLvcRlA==
+"@opentelemetry/instrumentation@0.210.0", "@opentelemetry/instrumentation@^0.210.0":
+ version "0.210.0"
+ resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.210.0.tgz#3c9cf77072b7c7796fffcb04e19cad2976a4afbf"
+ integrity sha512-sLMhyHmW9katVaLUOKpfCnxSGhZq2t1ReWgwsu2cSgxmDVMB690H9TanuexanpFI94PJaokrqbp8u9KYZDUT5g==
+ dependencies:
+ "@opentelemetry/api-logs" "0.210.0"
+ import-in-the-middle "^2.0.0"
+ require-in-the-middle "^8.0.0"
+
+"@opentelemetry/instrumentation@^0.207.0":
+ version "0.207.0"
+ resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.207.0.tgz#1a5a921c04f171ff28096fa320af713f3c87ec14"
+ integrity sha512-y6eeli9+TLKnznrR8AZlQMSJT7wILpXH+6EYq5Vf/4Ao+huI7EedxQHwRgVUOMLFbe7VFDvHJrX9/f4lcwnJsA==
dependencies:
- "@opentelemetry/api-logs" "0.208.0"
+ "@opentelemetry/api-logs" "0.207.0"
import-in-the-middle "^2.0.0"
require-in-the-middle "^8.0.0"
@@ -6203,21 +6225,21 @@
resolved "https://registry.yarnpkg.com/@opentelemetry/redis-common/-/redis-common-0.38.2.tgz#cefa4f3e79db1cd54f19e233b7dfb56621143955"
integrity sha512-1BCcU93iwSRZvDAgwUxC/DV4T/406SkMfxGqu5ojc3AvNI+I9GhV7v0J1HljsczuuhcnFLYqD5VmwVXfCGHzxA==
-"@opentelemetry/resources@2.2.0", "@opentelemetry/resources@^2.2.0":
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-2.2.0.tgz#b90a950ad98551295b76ea8a0e7efe45a179badf"
- integrity sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==
+"@opentelemetry/resources@2.4.0", "@opentelemetry/resources@^2.4.0":
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-2.4.0.tgz#51188708204ba888685de019286a3969508c444d"
+ integrity sha512-RWvGLj2lMDZd7M/5tjkI/2VHMpXebLgPKvBUd9LRasEWR2xAynDwEYZuLvY9P2NGG73HF07jbbgWX2C9oavcQg==
dependencies:
- "@opentelemetry/core" "2.2.0"
+ "@opentelemetry/core" "2.4.0"
"@opentelemetry/semantic-conventions" "^1.29.0"
-"@opentelemetry/sdk-trace-base@^2.2.0":
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz#ddef9a0afd01a623d8625a3529f2137b05e67d0b"
- integrity sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==
+"@opentelemetry/sdk-trace-base@^2.4.0":
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.4.0.tgz#0ab37a996cb574e7efc94e58fc759cb4a8df8401"
+ integrity sha512-WH0xXkz/OHORDLKqaxcUZS0X+t1s7gGlumr2ebiEgNZQl2b0upK2cdoD0tatf7l8iP74woGJ/Kmxe82jdvcWRw==
dependencies:
- "@opentelemetry/core" "2.2.0"
- "@opentelemetry/resources" "2.2.0"
+ "@opentelemetry/core" "2.4.0"
+ "@opentelemetry/resources" "2.4.0"
"@opentelemetry/semantic-conventions" "^1.29.0"
"@opentelemetry/semantic-conventions@^1.24.0", "@opentelemetry/semantic-conventions@^1.27.0", "@opentelemetry/semantic-conventions@^1.29.0", "@opentelemetry/semantic-conventions@^1.30.0", "@opentelemetry/semantic-conventions@^1.33.0", "@opentelemetry/semantic-conventions@^1.33.1", "@opentelemetry/semantic-conventions@^1.34.0", "@opentelemetry/semantic-conventions@^1.36.0", "@opentelemetry/semantic-conventions@^1.37.0":
@@ -6385,6 +6407,15 @@
resolved "https://registry.yarnpkg.com/@poppinss/exception/-/exception-1.2.2.tgz#8d30d42e126c54fe84e997433e4dcac610090743"
integrity sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==
+"@prisma/adapter-pg@7.2.0":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@prisma/adapter-pg/-/adapter-pg-7.2.0.tgz#a956ae4b6b168ed2e1c687a0b45e0d1633959bf0"
+ integrity sha512-euIdQ13cRB2wZ3jPsnDnFhINquo1PYFPCg6yVL8b2rp3EdinQHsX9EDdCtRr489D5uhphcRk463OdQAFlsCr0w==
+ dependencies:
+ "@prisma/driver-adapter-utils" "7.2.0"
+ pg "^8.16.3"
+ postgres-array "3.0.4"
+
"@prisma/client@6.15.0":
version "6.15.0"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-6.15.0.tgz#c4166aa8492878c842e63c515853d7a4125e6168"
@@ -6405,6 +6436,18 @@
resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-6.15.0.tgz#8595f8ae91eadd20d926398449b8602c74e36bbf"
integrity sha512-y7cSeLuQmyt+A3hstAs6tsuAiVXSnw9T55ra77z0nbNkA8Lcq9rNcQg6PI00by/+WnE/aMRJ/W7sZWn2cgIy1g==
+"@prisma/debug@7.2.0":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-7.2.0.tgz#569b1cbc10eb3e8cae798b40075fd11d21f6b533"
+ integrity sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==
+
+"@prisma/driver-adapter-utils@7.2.0":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.2.0.tgz#53d6686cdbb695338826e1c8ab5ac97c92efb676"
+ integrity sha512-gzrUcbI9VmHS24Uf+0+7DNzdIw7keglJsD5m/MHxQOU68OhGVzlphQRobLiDMn8CHNA2XN8uugwKjudVtnfMVQ==
+ dependencies:
+ "@prisma/debug" "7.2.0"
+
"@prisma/engines-version@6.15.0-5.85179d7826409ee107a6ba334b5e305ae3fba9fb":
version "6.15.0-5.85179d7826409ee107a6ba334b5e305ae3fba9fb"
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-6.15.0-5.85179d7826409ee107a6ba334b5e305ae3fba9fb.tgz#718b17890287447360107bef3675487d8cb0ae15"
@@ -6436,12 +6479,12 @@
dependencies:
"@prisma/debug" "6.15.0"
-"@prisma/instrumentation@6.19.0":
- version "6.19.0"
- resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-6.19.0.tgz#46d15adc8bc4a5a3167032eea6d0a7aa64fb7d93"
- integrity sha512-QcuYy25pkXM8BJ37wVFBO7Zh34nyRV1GOb2n3lPkkbRYfl4hWl3PTcImP41P0KrzVXfa/45p6eVCos27x3exIg==
+"@prisma/instrumentation@7.2.0":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-7.2.0.tgz#9409a436d8f98e8950c8659aeeba045c4a07e891"
+ integrity sha512-Rh9Z4x5kEj1OdARd7U18AtVrnL6rmLSI0qYShaB4W7Wx5BKbgzndWF+QnuzMb7GLfVdlT5aYCXoPQVYuYtVu0g==
dependencies:
- "@opentelemetry/instrumentation" ">=0.52.0 <1"
+ "@opentelemetry/instrumentation" "^0.207.0"
"@protobuf-ts/plugin-framework@^2.0.7", "@protobuf-ts/plugin-framework@^2.9.4":
version "2.9.4"
@@ -6609,47 +6652,52 @@
resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.5.tgz#a6d70ef7a0e71e083ea09b967df0a0ed742bc6ad"
integrity sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==
-"@remix-run/node@^2.15.2":
- version "2.15.2"
- resolved "https://registry.yarnpkg.com/@remix-run/node/-/node-2.15.2.tgz#7ea460335b66a06d22e554a84edf09e2b8879a8a"
- integrity sha512-NS/h5uxje7DYCNgcKqKAiUhf0r2HVnoYUBWLyIIMmCUP1ddWurBP6xTPcWzGhEvV/EvguniYi1wJZ5+X8sonWw==
+"@remix-run/node@^2.17.4":
+ version "2.17.4"
+ resolved "https://registry.yarnpkg.com/@remix-run/node/-/node-2.17.4.tgz#dfcc43106fc631c1bd6644d215d5698eb4958962"
+ integrity sha512-9A29JaYiGHDEmaiQuD1IlO/TrQxnnkj98GpytihU+Nz6yTt6RwzzyMMqTAoasRd1dPD4OeSaSqbwkcim/eE76Q==
dependencies:
- "@remix-run/server-runtime" "2.15.2"
+ "@remix-run/server-runtime" "2.17.4"
"@remix-run/web-fetch" "^4.4.2"
"@web3-storage/multipart-parser" "^1.0.0"
cookie-signature "^1.1.0"
source-map-support "^0.5.21"
stream-slice "^0.1.2"
- undici "^6.11.1"
+ undici "^6.21.2"
-"@remix-run/react@^2.15.2":
- version "2.15.2"
- resolved "https://registry.yarnpkg.com/@remix-run/react/-/react-2.15.2.tgz#4f57434c120e0b7885d8b737c417b67f72a3a042"
- integrity sha512-NAAMsSgoC/sdOgovUewwRCE/RUm3F+MBxxZKfwu3POCNeHaplY5qGkH/y8PUXvdN1EBG7Z0Ko43dyzCfcEy5PA==
+"@remix-run/react@^2.17.4":
+ version "2.17.4"
+ resolved "https://registry.yarnpkg.com/@remix-run/react/-/react-2.17.4.tgz#128b6505c118e4bf67d919ee7d3991c0f6c65028"
+ integrity sha512-MeXHacIBoohr9jzec5j/Rmk57xk34korkPDDb0OPHgkdvh20lO5fJoSAcnZfjTIOH+Vsq1ZRQlmvG5PRQ/64Sw==
dependencies:
- "@remix-run/router" "1.21.0"
- "@remix-run/server-runtime" "2.15.2"
- react-router "6.28.1"
- react-router-dom "6.28.1"
- turbo-stream "2.4.0"
+ "@remix-run/router" "1.23.2"
+ "@remix-run/server-runtime" "2.17.4"
+ react-router "6.30.3"
+ react-router-dom "6.30.3"
+ turbo-stream "2.4.1"
-"@remix-run/router@1.21.0", "@remix-run/router@1.x":
+"@remix-run/router@1.21.0":
version "1.21.0"
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.21.0.tgz#c65ae4262bdcfe415dbd4f64ec87676e4a56e2b5"
integrity sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==
-"@remix-run/server-runtime@2.15.2":
- version "2.15.2"
- resolved "https://registry.yarnpkg.com/@remix-run/server-runtime/-/server-runtime-2.15.2.tgz#5be945027612c0891748d1788d39fea1ef0ba33c"
- integrity sha512-OqiPcvEnnU88B8b1LIWHHkQ3Tz2GDAmQ1RihFNQsbrFKpDsQLkw0lJlnfgKA/uHd0CEEacpfV7C9qqJT3V6Z2g==
+"@remix-run/router@1.23.2", "@remix-run/router@1.x":
+ version "1.23.2"
+ resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.23.2.tgz#156c4b481c0bee22a19f7924728a67120de06971"
+ integrity sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==
+
+"@remix-run/server-runtime@2.17.4", "@remix-run/server-runtime@^2.17.4":
+ version "2.17.4"
+ resolved "https://registry.yarnpkg.com/@remix-run/server-runtime/-/server-runtime-2.17.4.tgz#00d52eb69e684b13c152ab9ace70b6c00aaeee5f"
+ integrity sha512-oCsFbPuISgh8KpPKsfBChzjcntvTz5L+ggq9VNYWX8RX3yA7OgQpKspRHOSxb05bw7m0Hx+L1KRHXjf3juKX8w==
dependencies:
- "@remix-run/router" "1.21.0"
+ "@remix-run/router" "1.23.2"
"@types/cookie" "^0.6.0"
"@web3-storage/multipart-parser" "^1.0.0"
- cookie "^0.6.0"
+ cookie "^0.7.2"
set-cookie-parser "^2.4.8"
source-map "^0.7.3"
- turbo-stream "2.4.0"
+ turbo-stream "2.4.1"
"@remix-run/web-blob@^3.1.0":
version "3.1.0"
@@ -8982,10 +9030,10 @@
resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb"
integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==
-"@types/pg-pool@2.0.6":
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/@types/pg-pool/-/pg-pool-2.0.6.tgz#1376d9dc5aec4bb2ec67ce28d7e9858227403c77"
- integrity sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==
+"@types/pg-pool@2.0.7":
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/@types/pg-pool/-/pg-pool-2.0.7.tgz#c17945a74472d9a3beaf8e66d5aa6fc938328734"
+ integrity sha512-U4CwmGVQcbEuqpyju8/ptOKg6gEC+Tqsvj2xS9o1g71bUh8twxnC6ZL5rZKCsGN0iyH0CwgUyc9VR5owNQF9Ng==
dependencies:
"@types/pg" "*"
@@ -13582,7 +13630,7 @@ cookie@^0.6.0:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
-cookie@^0.7.1, cookie@~0.7.2:
+cookie@^0.7.1, cookie@^0.7.2, cookie@~0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7"
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
@@ -24887,35 +24935,35 @@ periscopic@^3.1.0:
estree-walker "^3.0.0"
is-reference "^3.0.0"
-pg-cloudflare@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.2.5.tgz#2e3649c38a7a9c74a7e5327c8098a2fd9af595bd"
- integrity sha512-OOX22Vt0vOSRrdoUPKJ8Wi2OpE/o/h9T8X1s4qSkCedbNah9ei2W2765be8iMVxQUsvgT7zIAT2eIa9fs5+vtg==
+pg-cloudflare@^1.2.5, pg-cloudflare@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz#386035d4bfcf1a7045b026f8b21acf5353f14d65"
+ integrity sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==
pg-connection-string@2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.1.tgz#78c23c21a35dd116f48e12e23c0965e8d9e2cbfb"
integrity sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==
-pg-connection-string@^2.9.0:
- version "2.9.0"
- resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.9.0.tgz#f75e06591fdd42ec7636fe2c6a03febeedbec9bf"
- integrity sha512-P2DEBKuvh5RClafLngkAuGe9OUlFV7ebu8w1kmaaOgPcpJd1RIFh7otETfI6hAR8YupOLFTY7nuvvIn7PLciUQ==
+pg-connection-string@^2.10.0, pg-connection-string@^2.9.0:
+ version "2.10.0"
+ resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.10.0.tgz#5570fd4837bd813a2b3938cd1744586c7df4a5f1"
+ integrity sha512-ur/eoPKzDx2IjPaYyXS6Y8NSblxM7X64deV2ObV57vhjsWiwLvUD6meukAzogiOsu60GO8m/3Cb6FdJsWNjwXg==
pg-int8@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c"
integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==
-pg-pool@^3.10.0:
- version "3.10.0"
- resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.10.0.tgz#134b0213755c5e7135152976488aa7cd7ee1268d"
- integrity sha512-DzZ26On4sQ0KmqnO34muPcmKbhrjmyiO4lCCR0VwEd7MjmiKf5NTg/6+apUEu0NF7ESa37CGzFxH513CoUmWnA==
+pg-pool@^3.10.0, pg-pool@^3.11.0:
+ version "3.11.0"
+ resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.11.0.tgz#adf9a6651a30c839f565a3cc400110949c473d69"
+ integrity sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==
-pg-protocol@*, pg-protocol@^1.10.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.10.0.tgz#a473afcbb1c6e5dc3ac24869ba3dd563f8a1ae1b"
- integrity sha512-IpdytjudNuLv8nhlHs/UrVBhU0e78J0oIS/0AVdTbWxSOkFUVdsHC/NrorO6nXsQNDTT1kzDSOMJubBQviX18Q==
+pg-protocol@*, pg-protocol@^1.10.0, pg-protocol@^1.11.0:
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.11.0.tgz#2502908893edaa1e8c0feeba262dd7b40b317b53"
+ integrity sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==
pg-types@2.2.0, pg-types@^2.2.0:
version "2.2.0"
@@ -24941,6 +24989,19 @@ pg@8.16.0:
optionalDependencies:
pg-cloudflare "^1.2.5"
+pg@^8.16.3:
+ version "8.17.1"
+ resolved "https://registry.yarnpkg.com/pg/-/pg-8.17.1.tgz#cecf0c96d3f5004951ccbafaaa230779ebc89d35"
+ integrity sha512-EIR+jXdYNSMOrpRp7g6WgQr7SaZNZfS7IzZIO0oTNEeibq956JxeD15t3Jk3zZH0KH8DmOIx38qJfQenoE8bXQ==
+ dependencies:
+ pg-connection-string "^2.10.0"
+ pg-pool "^3.11.0"
+ pg-protocol "^1.11.0"
+ pg-types "2.2.0"
+ pgpass "1.0.5"
+ optionalDependencies:
+ pg-cloudflare "^1.3.0"
+
pgpass@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d"
@@ -25739,6 +25800,11 @@ postcss@^8.1.10, postcss@^8.2.14, postcss@^8.2.15, postcss@^8.3.7, postcss@^8.4.
picocolors "^1.1.1"
source-map-js "^1.2.1"
+postgres-array@3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-3.0.4.tgz#4efcaf4d2c688d8bcaa8620ed13f35f299f7528c"
+ integrity sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==
+
postgres-array@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e"
@@ -26340,20 +26406,20 @@ react-refresh@^0.14.0:
dependencies:
"@remix-run/router" "1.21.0"
-react-router-dom@6.28.1:
- version "6.28.1"
- resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.28.1.tgz#b78fe452d2cd31919b80e57047a896bfa1509f8c"
- integrity sha512-YraE27C/RdjcZwl5UCqF/ffXnZDxpJdk9Q6jw38SZHjXs7NNdpViq2l2c7fO7+4uWaEfcwfGCv3RSg4e1By/fQ==
+react-router-dom@6.30.3:
+ version "6.30.3"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.30.3.tgz#42ae6dc4c7158bfb0b935f162b9621b29dddf740"
+ integrity sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==
dependencies:
- "@remix-run/router" "1.21.0"
- react-router "6.28.1"
+ "@remix-run/router" "1.23.2"
+ react-router "6.30.3"
-react-router@6.28.1:
- version "6.28.1"
- resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.28.1.tgz#f82317ab24eee67d7beb7b304c0378b2b48fa178"
- integrity sha512-2omQTA3rkMljmrvvo6WtewGdVh45SpL9hGiCI9uUrwGGfNFDIvGK4gYJsKlJoNVi6AQZcopSCballL+QGOm7fA==
+react-router@6.30.3:
+ version "6.30.3"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.30.3.tgz#994b3ccdbe0e81fe84d4f998100f62584dfbf1cf"
+ integrity sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==
dependencies:
- "@remix-run/router" "1.21.0"
+ "@remix-run/router" "1.23.2"
react-router@^7.9.2:
version "7.9.2"
@@ -29958,10 +30024,10 @@ tunnel@^0.0.6:
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
-turbo-stream@2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/turbo-stream/-/turbo-stream-2.4.0.tgz#1e4fca6725e90fa14ac4adb782f2d3759a5695f0"
- integrity sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==
+turbo-stream@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/turbo-stream/-/turbo-stream-2.4.1.tgz#c1a64397724084c09b0f6ea4a2c528d3f67931f9"
+ integrity sha512-v8kOJXpG3WoTN/+at8vK7erSzo6nW6CIaeOvNOkHQVDajfz1ZVeSxCbc6tOH4hrGZW7VUCV0TOXd8CPzYnYkrw==
twirp-ts@^2.5.0:
version "2.5.0"
@@ -30288,10 +30354,10 @@ undici@^5.25.4, undici@^5.28.5:
dependencies:
"@fastify/busboy" "^2.0.0"
-undici@^6.11.1, undici@^6.19.2:
- version "6.21.3"
- resolved "https://registry.yarnpkg.com/undici/-/undici-6.21.3.tgz#185752ad92c3d0efe7a7d1f6854a50f83b552d7a"
- integrity sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==
+undici@^6.19.2, undici@^6.21.2:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/undici/-/undici-6.23.0.tgz#7953087744d9095a96f115de3140ca3828aff3a4"
+ integrity sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==
unenv@2.0.0-rc.17:
version "2.0.0-rc.17"