Skip to content

meta(changelog): Update changelog for 9.1.0 #15400

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ env:
nx-Linux-${{ github.ref }}
nx-Linux

# https://bsky.app/profile/joyeecheung.bsky.social/post/3lhy6o54fo22h
# Apparently some of our CI failures are attributable to a corrupt v8 cache, causing v8 failures with: "Check failed: current == end_slot_index.".
# This option both controls the `v8-compile-cache-lib` and `v8-compile-cache` packages.
DISABLE_V8_COMPILE_CACHE: '1'

jobs:
job_get_metadata:
name: Get Metadata
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@

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

## 9.1.0

- feat(browser): Add `graphqlClientIntegration` ([#13783](https://github.com/getsentry/sentry-javascript/pull/13783))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to mention this person in the contributions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, added :)

- feat(core): Allow for nested trpc context ([#15379](https://github.com/getsentry/sentry-javascript/pull/15379))
- feat(core): Create types and utilities for span links ([#15375](https://github.com/getsentry/sentry-javascript/pull/15375))
- feat(deps): bump @opentelemetry/instrumentation-pg from 0.50.0 to 0.51.0 ([#15273](https://github.com/getsentry/sentry-javascript/pull/15273))
- feat(node): Extract Sentry-specific node-fetch instrumentation ([#15231](https://github.com/getsentry/sentry-javascript/pull/15231))
- feat(vue): Support Pinia v3 ([#15383](https://github.com/getsentry/sentry-javascript/pull/15383))
- fix(sveltekit): Avoid request body double read errors ([#15368](https://github.com/getsentry/sentry-javascript/pull/15368))
- fix(sveltekit): Avoid top-level `vite` import ([#15371](https://github.com/getsentry/sentry-javascript/pull/15371))

Work in this release was contributed by @Zen-cronic and @filips-alpe. Thank you for your contribution!

## 9.0.1

- ref(flags): rename unleash integration param ([#15343](https://github.com/getsentry/sentry-javascript/pull/15343))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const query = `query Test{
people {
name
pet
}
}`;

const requestBody = JSON.stringify({ query });

fetch('http://sentry-test.io/foo', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: requestBody,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { expect } from '@playwright/test';
import type { Event } from '@sentry/core';

import { sentryTest } from '../../../../utils/fixtures';
import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers';

// Duplicate from subject.js
const query = `query Test{
people {
name
pet
}
}`;
const queryPayload = JSON.stringify({ query });

sentryTest('should update spans for GraphQL fetch requests', async ({ getLocalTestUrl, page }) => {
if (shouldSkipTracingTest()) {
return;
}

const url = await getLocalTestUrl({ testDir: __dirname });

await page.route('**/foo', route => {
return route.fulfill({
status: 200,
body: JSON.stringify({
people: [
{ name: 'Amy', pet: 'dog' },
{ name: 'Jay', pet: 'cat' },
],
}),
headers: {
'Content-Type': 'application/json',
},
});
});

const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);
const requestSpans = eventData.spans?.filter(({ op }) => op === 'http.client');

expect(requestSpans).toHaveLength(1);

expect(requestSpans![0]).toMatchObject({
description: 'POST http://sentry-test.io/foo (query Test)',
parent_span_id: eventData.contexts?.trace?.span_id,
span_id: expect.any(String),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
trace_id: eventData.contexts?.trace?.trace_id,
status: 'ok',
data: expect.objectContaining({
type: 'fetch',
'http.method': 'POST',
'http.url': 'http://sentry-test.io/foo',
url: 'http://sentry-test.io/foo',
'server.address': 'sentry-test.io',
'sentry.op': 'http.client',
'sentry.origin': 'auto.http.browser',
'graphql.document': queryPayload,
}),
});
});

sentryTest('should update breadcrumbs for GraphQL fetch requests', async ({ getLocalTestUrl, page }) => {
if (shouldSkipTracingTest()) {
return;
}

const url = await getLocalTestUrl({ testDir: __dirname });

await page.route('**/foo', route => {
return route.fulfill({
status: 200,
body: JSON.stringify({
people: [
{ name: 'Amy', pet: 'dog' },
{ name: 'Jay', pet: 'cat' },
],
}),
headers: {
'Content-Type': 'application/json',
},
});
});

const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);

expect(eventData?.breadcrumbs?.length).toBe(1);

expect(eventData!.breadcrumbs![0]).toEqual({
timestamp: expect.any(Number),
category: 'fetch',
type: 'http',
data: {
method: 'POST',
status_code: 200,
url: 'http://sentry-test.io/foo',
__span: expect.any(String),
'graphql.document': query,
'graphql.operation': 'query Test',
},
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as Sentry from '@sentry/browser';
// Must import this like this to ensure the test transformation for CDN bundles works
import { graphqlClientIntegration } from '@sentry/browser';

window.Sentry = Sentry;

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
integrations: [
Sentry.browserTracingIntegration(),
graphqlClientIntegration({
endpoints: ['http://sentry-test.io/foo'],
}),
],
tracesSampleRate: 1,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const xhr = new XMLHttpRequest();

xhr.open('POST', 'http://sentry-test.io/foo');
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json');

const query = `query Test{
people {
name
pet
}
}`;

const requestBody = JSON.stringify({ query });
xhr.send(requestBody);
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { expect } from '@playwright/test';
import type { Event } from '@sentry/core';

import { sentryTest } from '../../../../utils/fixtures';
import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers';

// Duplicate from subject.js
const query = `query Test{
people {
name
pet
}
}`;
const queryPayload = JSON.stringify({ query });

sentryTest('should update spans for GraphQL XHR requests', async ({ getLocalTestUrl, page }) => {
if (shouldSkipTracingTest()) {
return;
}

const url = await getLocalTestUrl({ testDir: __dirname });

await page.route('**/foo', route => {
return route.fulfill({
status: 200,
body: JSON.stringify({
people: [
{ name: 'Amy', pet: 'dog' },
{ name: 'Jay', pet: 'cat' },
],
}),
headers: {
'Content-Type': 'application/json',
},
});
});

const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);
const requestSpans = eventData.spans?.filter(({ op }) => op === 'http.client');

expect(requestSpans).toHaveLength(1);

expect(requestSpans![0]).toMatchObject({
description: 'POST http://sentry-test.io/foo (query Test)',
parent_span_id: eventData.contexts?.trace?.span_id,
span_id: expect.any(String),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
trace_id: eventData.contexts?.trace?.trace_id,
status: 'ok',
data: {
type: 'xhr',
'http.method': 'POST',
'http.url': 'http://sentry-test.io/foo',
url: 'http://sentry-test.io/foo',
'server.address': 'sentry-test.io',
'sentry.op': 'http.client',
'sentry.origin': 'auto.http.browser',
'graphql.document': queryPayload,
},
});
});

sentryTest('should update breadcrumbs for GraphQL XHR requests', async ({ getLocalTestUrl, page }) => {
if (shouldSkipTracingTest()) {
return;
}

const url = await getLocalTestUrl({ testDir: __dirname });

await page.route('**/foo', route => {
return route.fulfill({
status: 200,
body: JSON.stringify({
people: [
{ name: 'Amy', pet: 'dog' },
{ name: 'Jay', pet: 'cat' },
],
}),
headers: {
'Content-Type': 'application/json',
},
});
});

const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);

expect(eventData?.breadcrumbs?.length).toBe(1);

expect(eventData!.breadcrumbs![0]).toEqual({
timestamp: expect.any(Number),
category: 'xhr',
type: 'http',
data: {
method: 'POST',
status_code: 200,
url: 'http://sentry-test.io/foo',
'graphql.document': query,
'graphql.operation': 'query Test',
},
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const IMPORTED_INTEGRATION_CDN_BUNDLE_PATHS: Record<string, string> = {
reportingObserverIntegration: 'reportingobserver',
feedbackIntegration: 'feedback',
moduleMetadataIntegration: 'modulemetadata',
graphqlClientIntegration: 'graphqlclient',
// technically, this is not an integration, but let's add it anyway for simplicity
makeMultiplexedTransport: 'multiplexedtransport',
};
Expand Down
2 changes: 1 addition & 1 deletion dev-packages/e2e-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"clean": "rimraf tmp node_modules && yarn clean:test-applications && yarn clean:pnpm",
"ci:build-matrix": "ts-node ./lib/getTestMatrix.ts",
"ci:build-matrix-optional": "ts-node ./lib/getTestMatrix.ts --optional=true",
"clean:test-applications": "rimraf --glob test-applications/**/{node_modules,dist,build,.next,.nuxt,.sveltekit,pnpm-lock.yaml,.last-run.json,test-results}",
"clean:test-applications": "rimraf --glob test-applications/**/{node_modules,dist,build,.next,.nuxt,.sveltekit,.react-router,pnpm-lock.yaml,.last-run.json,test-results}",
"clean:pnpm": "pnpm store prune"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,11 @@ export const appRouter = t.router({
await new Promise(resolve => setTimeout(resolve, 400));
return { success: true };
}),
crashSomething: procedure.mutation(() => {
throw new Error('I crashed in a trpc handler');
}),
crashSomething: procedure
.input(z.object({ nested: z.object({ nested: z.object({ nested: z.string() }) }) }))
.mutation(() => {
throw new Error('I crashed in a trpc handler');
}),
dontFindSomething: procedure.mutation(() => {
throw new TRPCError({ code: 'NOT_FOUND', cause: new Error('Page not found') });
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,22 @@ test('Should record transaction and error for a crashing trpc handler', async ({
],
});

await expect(trpcClient.crashSomething.mutate()).rejects.toBeDefined();
await expect(trpcClient.crashSomething.mutate({ nested: { nested: { nested: 'foobar' } } })).rejects.toBeDefined();

await expect(transactionEventPromise).resolves.toBeDefined();
await expect(errorEventPromise).resolves.toBeDefined();

expect((await errorEventPromise).contexts?.trpc?.['procedure_type']).toBe('mutation');
expect((await errorEventPromise).contexts?.trpc?.['procedure_path']).toBe('crashSomething');

// Should record nested context
expect((await errorEventPromise).contexts?.trpc?.['input']).toEqual({
nested: {
nested: {
nested: 'foobar',
},
},
});
});

test('Should record transaction and error for a trpc handler that returns a status code', async ({ baseURL }) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

/test-results/
/playwright-report/
/playwright/.cache/

!*.d.ts

# react router
.react-router
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
html,
body {
@media (prefers-color-scheme: dark) {
color-scheme: dark;
}
}
Loading
Loading