Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c8df5ab
test(react): Add gql tests for react router (#19844)
chargome Mar 17, 2026
8d364d6
fix(deps): bump undici 6.23.0 to 6.24.1 to fix multiple CVEs (#19841)
chargome Mar 17, 2026
f01fcc9
chore(deps): bump next from 16.1.5 to 16.1.7 in /dev-packages/e2e-tes…
dependabot[bot] Mar 17, 2026
5c47722
fix(deps): bump hono 4.12.5 to 4.12.7 in cloudflare-hono E2E test app…
chargome Mar 17, 2026
3a3bb51
fix(deps): bump tar 7.5.10 to 7.5.11 to fix CVE-2026-31802 (#19846)
chargome Mar 17, 2026
41fc707
Merge pull request #19857 from getsentry/master
github-actions[bot] Mar 17, 2026
406ce22
fix(deno): Clear pre-existing OTel global before registering TracerPr…
sergical Mar 17, 2026
d1ea777
fix(deps): bump flatted 3.3.1 to 3.4.2 to fix CVE-2026-32141 (#19842)
chargome Mar 18, 2026
f95e4de
fix(deps): bump unhead 2.1.4 to 2.1.12 to fix CVE-2026-31860 and CVE-…
chargome Mar 18, 2026
6a6fa99
fix(deps): bump file-type to 21.3.2 and @nestjs/common to 11.1.17 (#1…
chargome Mar 18, 2026
76e038b
fix(deps): bump devalue 5.6.3 to 5.6.4 to fix CVE-2026-30226 (#19849)
chargome Mar 18, 2026
2b62357
ci(release): Switch from action-prepare-release to Craft (#18763)
BYK Mar 18, 2026
de7f71e
fix(node-core): Recycle propagationContext for each request (#19835)
Lms24 Mar 18, 2026
ae7206f
feat(remix): Server Timing Headers Trace Propagation (#18653)
onurtemizkan Mar 18, 2026
b4b9e71
test(nextjs): Skip broken ISR tests (#19871)
chargome Mar 19, 2026
6f17b8a
fix(cloudflare): Use correct env types for withSentry (#19836)
JPeer264 Mar 19, 2026
3e5499a
fix(deps): bump next to 15.5.13/16.1.7 to fix CVE-2026-1525, CVE-202-…
chargome Mar 19, 2026
3bb4325
fix(core): Align error span status message with core `SpanStatusType`…
nicohrubec Mar 19, 2026
938ab2d
ref(core): Simplify core utility functions for smaller bundle (#19854)
HazAT Mar 19, 2026
79241b0
fix(nextjs): Skip tracing for tunnel requests (#19861)
chargome Mar 19, 2026
2e2fd35
meta(changelog): Update changelog for 10.45.0
Lms24 Mar 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .craft.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
minVersion: '0.23.1'
changelogPolicy: simple
changelog:
policy: simple
preReleaseCommand: bash scripts/craft-pre-release.sh
targets:
# NPM Targets
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/auto-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ on:
branches:
- master

# This workflow tirggers a release when merging a branch with the pattern `prepare-release/VERSION` into master.
# This workflow triggers a release when merging a branch with the pattern `prepare-release/VERSION` into master.
permissions:
contents: write
pull-requests: write

jobs:
release:
runs-on: ubuntu-24.04
Expand Down Expand Up @@ -47,7 +51,7 @@ jobs:
node-version-file: 'package.json'

- name: Prepare release
uses: getsentry/action-prepare-release@v1
uses: getsentry/craft@013a7b2113c2cac0ff32d5180cfeaefc7c9ce5b6 # v2.24.1
if:
github.event.pull_request.merged == true && steps.version-regex.outputs.match != '' &&
steps.get_version.outputs.version != ''
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,11 @@ jobs:
with:
use-installer: true
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Deno
if: matrix.test-application == 'deno'
uses: denoland/setup-deno@v2.0.3
with:
deno-version: v2.1.5
- name: Restore caches
uses: ./.github/actions/restore-cache
with:
Expand Down
19 changes: 19 additions & 0 deletions .github/workflows/changelog-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Changelog Preview
on:
pull_request_target:
types:
- opened
- synchronize
- reopened
- edited
- labeled
- unlabeled
permissions:
contents: write
pull-requests: write
statuses: write

jobs:
changelog-preview:
uses: getsentry/craft/.github/workflows/changelog-preview.yml@2.24.1
secrets: inherit
10 changes: 7 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@ on:
workflow_dispatch:
inputs:
version:
description: Version to release
required: true
description: Version to release (or "auto")
required: false
force:
description: Force a release even when there are release-blockers (optional)
required: false
merge_target:
description: Target branch to merge into. Uses the default branch as a fallback (optional)
required: false
default: master
permissions:
contents: write
pull-requests: write

jobs:
release:
runs-on: ubuntu-24.04
Expand All @@ -32,7 +36,7 @@ jobs:
with:
node-version-file: 'package.json'
- name: Prepare release
uses: getsentry/action-prepare-release@v1
uses: getsentry/craft@013a7b2113c2cac0ff32d5180cfeaefc7c9ce5b6 # v2.24.1
env:
GITHUB_TOKEN: ${{ steps.token.outputs.token }}
with:
Expand Down
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,43 @@

- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott

## 10.45.0

### Important Changes

- **feat(remix): Server Timing Headers Trace Propagation ([#18653](https://github.com/getsentry/sentry-javascript/pull/18653))**

The Remix SDK now supports automatic trace propagation via `Server-Timing` response headers to continue pageload traces on the client side.
This means, you no longer have to define a custom `meta` function to add Sentry `<meta>` tags to your page as previously.
We'll update out Remix tracing docs after this release.

### Other Changes

- fix(cloudflare): Use correct env types for `withSentry` ([#19836](https://github.com/getsentry/sentry-javascript/pull/19836))
- fix(core): Align error span status message with core `SpanStatusType` for langchain/google-genai ([#19863](https://github.com/getsentry/sentry-javascript/pull/19863))
- fix(deno): Clear pre-existing OTel global before registering TracerProvider ([#19723](https://github.com/getsentry/sentry-javascript/pull/19723))
- fix(nextjs): Skip tracing for tunnel requests ([#19861](https://github.com/getsentry/sentry-javascript/pull/19861))
- fix(node-core): Recycle propagationContext for each request ([#19835](https://github.com/getsentry/sentry-javascript/pull/19835))
- ref(core): Simplify core utility functions for smaller bundle ([#19854](https://github.com/getsentry/sentry-javascript/pull/19854))

<details>
<summary> <strong>Internal Changes</strong> </summary>

- chore(deps): bump next from 16.1.5 to 16.1.7 in /dev-packages/e2e-tests/test-applications/nextjs-16 ([#19851](https://github.com/getsentry/sentry-javascript/pull/19851))
- ci(release): Switch from action-prepare-release to Craft ([#18763](https://github.com/getsentry/sentry-javascript/pull/18763))
- fix(deps): bump devalue 5.6.3 to 5.6.4 to fix CVE-2026-30226 ([#19849](https://github.com/getsentry/sentry-javascript/pull/19849))
- fix(deps): bump file-type to 21.3.2 and @nestjs/common to 11.1.17 ([#19847](https://github.com/getsentry/sentry-javascript/pull/19847))
- fix(deps): bump flatted 3.3.1 to 3.4.2 to fix CVE-2026-32141 ([#19842](https://github.com/getsentry/sentry-javascript/pull/19842))
- fix(deps): bump hono 4.12.5 to 4.12.7 in cloudflare-hono E2E test app ([#19850](https://github.com/getsentry/sentry-javascript/pull/19850))
- fix(deps): bump next to 15.5.13/16.1.7 to fix CVE-2026-1525, CVE-202-33036 and related ([#19870](https://github.com/getsentry/sentry-javascript/pull/19870))
- fix(deps): bump tar 7.5.10 to 7.5.11 to fix CVE-2026-31802 ([#19846](https://github.com/getsentry/sentry-javascript/pull/19846))
- fix(deps): bump undici 6.23.0 to 6.24.1 to fix multiple CVEs ([#19841](https://github.com/getsentry/sentry-javascript/pull/19841))
- fix(deps): bump unhead 2.1.4 to 2.1.12 to fix CVE-2026-31860 and CVE-2026-31873 ([#19848](https://github.com/getsentry/sentry-javascript/pull/19848))
- test(nextjs): Skip broken ISR tests ([#19871](https://github.com/getsentry/sentry-javascript/pull/19871))
- test(react): Add gql tests for react router ([#19844](https://github.com/getsentry/sentry-javascript/pull/19844))

</details>

## 10.44.0

### Important Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"dependencies": {
"@sentry/cloudflare": "latest || *",
"hono": "4.12.5"
"hono": "4.12.7"
},
"devDependencies": {
"@cloudflare/vitest-pool-workers": "^0.8.31",
Expand Down
2 changes: 2 additions & 0 deletions dev-packages/e2e-tests/test-applications/deno/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@sentry:registry=http://127.0.0.1:4873
@sentry-internal:registry=http://127.0.0.1:4873
8 changes: 8 additions & 0 deletions dev-packages/e2e-tests/test-applications/deno/deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"imports": {
"@sentry/deno": "npm:@sentry/deno",
"@sentry/core": "npm:@sentry/core",
"@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0"
},
"nodeModulesDir": "manual"
}
23 changes: 23 additions & 0 deletions dev-packages/e2e-tests/test-applications/deno/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "deno-app",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "deno run --allow-net --allow-env --allow-read src/app.ts",
"test": "playwright test",
"clean": "npx rimraf node_modules pnpm-lock.yaml",
"test:build": "pnpm install",
"test:assert": "pnpm test"
},
"dependencies": {
"@sentry/deno": "latest || *",
"@opentelemetry/api": "^1.9.0"
},
"devDependencies": {
"@playwright/test": "~1.56.0",
"@sentry-internal/test-utils": "link:../../../test-utils"
},
"volta": {
"extends": "../../package.json"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { getPlaywrightConfig } from '@sentry-internal/test-utils';

const config = getPlaywrightConfig({
startCommand: `pnpm start`,
port: 3030,
});

export default config;
90 changes: 90 additions & 0 deletions dev-packages/e2e-tests/test-applications/deno/src/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { trace } from '@opentelemetry/api';

// Simulate a pre-existing OTel provider (like Supabase Edge Runtime registers
// before user code runs). Without trace.disable() in Sentry's setup, this would
// cause setGlobalTracerProvider to be a no-op, silently dropping all OTel spans.
const fakeProvider = {
getTracer: () => ({
startSpan: () => ({ end: () => {}, setAttributes: () => {} }),
startActiveSpan: (_name: string, fn: Function) => fn({ end: () => {}, setAttributes: () => {} }),
}),
};
trace.setGlobalTracerProvider(fakeProvider as any);

// Sentry.init() must call trace.disable() to clear the fake provider above
import * as Sentry from '@sentry/deno';

Sentry.init({
environment: 'qa',
dsn: Deno.env.get('E2E_TEST_DSN'),
debug: !!Deno.env.get('DEBUG'),
tunnel: 'http://localhost:3031/',
tracesSampleRate: 1,
});

const port = 3030;

Deno.serve({ port }, (req: Request) => {
const url = new URL(req.url);

if (url.pathname === '/test-success') {
return new Response(JSON.stringify({ version: 'v1' }), {
headers: { 'Content-Type': 'application/json' },
});
}

if (url.pathname === '/test-error') {
const exceptionId = Sentry.captureException(new Error('This is an error'));
return new Response(JSON.stringify({ exceptionId }), {
headers: { 'Content-Type': 'application/json' },
});
}

// Test Sentry.startSpan — uses Sentry's internal pipeline
if (url.pathname === '/test-sentry-span') {
Sentry.startSpan({ name: 'test-sentry-span' }, () => {
// noop
});
return new Response(JSON.stringify({ status: 'ok' }), {
headers: { 'Content-Type': 'application/json' },
});
}

// Test OTel tracer.startSpan — goes through the global TracerProvider
if (url.pathname === '/test-otel-span') {
const tracer = trace.getTracer('test-tracer');
const span = tracer.startSpan('test-otel-span');
span.end();
return new Response(JSON.stringify({ status: 'ok' }), {
headers: { 'Content-Type': 'application/json' },
});
}

// Test OTel tracer.startActiveSpan — what AI SDK and most instrumentations use
if (url.pathname === '/test-otel-active-span') {
const tracer = trace.getTracer('test-tracer');
tracer.startActiveSpan('test-otel-active-span', span => {
span.setAttributes({ 'test.active': true });
span.end();
});
return new Response(JSON.stringify({ status: 'ok' }), {
headers: { 'Content-Type': 'application/json' },
});
}

// Test interop: OTel span inside a Sentry span
if (url.pathname === '/test-interop') {
Sentry.startSpan({ name: 'sentry-parent' }, () => {
const tracer = trace.getTracer('test-tracer');
const span = tracer.startSpan('otel-child');
span.end();
});
return new Response(JSON.stringify({ status: 'ok' }), {
headers: { 'Content-Type': 'application/json' },
});
}

return new Response('Not found', { status: 404 });
});

console.log(`Deno test app listening on port ${port}`);
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { startEventProxyServer } from '@sentry-internal/test-utils';

startEventProxyServer({
port: 3031,
proxyServerName: 'deno',
});
15 changes: 15 additions & 0 deletions dev-packages/e2e-tests/test-applications/deno/tests/errors.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { expect, test } from '@playwright/test';
import { waitForError } from '@sentry-internal/test-utils';

test('Sends error event', async ({ baseURL }) => {
const errorEventPromise = waitForError('deno', event => {
return !event.type && event.exception?.values?.[0]?.value === 'This is an error';
});

await fetch(`${baseURL}/test-error`);

const errorEvent = await errorEventPromise;

expect(errorEvent.exception?.values).toHaveLength(1);
expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an error');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { expect, test } from '@playwright/test';
import { waitForTransaction } from '@sentry-internal/test-utils';

test('Sends transaction with Sentry.startSpan', async ({ baseURL }) => {
const transactionPromise = waitForTransaction('deno', event => {
return event?.spans?.some(span => span.description === 'test-sentry-span') ?? false;
});

await fetch(`${baseURL}/test-sentry-span`);

const transaction = await transactionPromise;

expect(transaction.spans).toEqual(
expect.arrayContaining([
expect.objectContaining({
description: 'test-sentry-span',
origin: 'manual',
}),
]),
);
});

test('Sends transaction with OTel tracer.startSpan despite pre-existing provider', async ({ baseURL }) => {
const transactionPromise = waitForTransaction('deno', event => {
return event?.spans?.some(span => span.description === 'test-otel-span') ?? false;
});

await fetch(`${baseURL}/test-otel-span`);

const transaction = await transactionPromise;

expect(transaction.spans).toEqual(
expect.arrayContaining([
expect.objectContaining({
description: 'test-otel-span',
op: 'otel.span',
origin: 'manual',
}),
]),
);
});

test('Sends transaction with OTel tracer.startActiveSpan', async ({ baseURL }) => {
const transactionPromise = waitForTransaction('deno', event => {
return event?.spans?.some(span => span.description === 'test-otel-active-span') ?? false;
});

await fetch(`${baseURL}/test-otel-active-span`);

const transaction = await transactionPromise;

expect(transaction.spans).toEqual(
expect.arrayContaining([
expect.objectContaining({
description: 'test-otel-active-span',
op: 'otel.span',
origin: 'manual',
}),
]),
);
});

test('OTel span appears as child of Sentry span (interop)', async ({ baseURL }) => {
const transactionPromise = waitForTransaction('deno', event => {
return event?.spans?.some(span => span.description === 'sentry-parent') ?? false;
});

await fetch(`${baseURL}/test-interop`);

const transaction = await transactionPromise;

expect(transaction.spans).toEqual(
expect.arrayContaining([
expect.objectContaining({
description: 'sentry-parent',
origin: 'manual',
}),
expect.objectContaining({
description: 'otel-child',
op: 'otel.span',
origin: 'manual',
}),
]),
);

// Verify the OTel span is a child of the Sentry span
const sentrySpan = transaction.spans!.find((s: any) => s.description === 'sentry-parent');
const otelSpan = transaction.spans!.find((s: any) => s.description === 'otel-child');
expect(otelSpan!.parent_span_id).toBe(sentrySpan!.span_id);
});
Loading
Loading