Skip to content

Commit 616a37f

Browse files
committed
Merge remote-tracking branch 'origin' into feat/prioritize-component-name
2 parents 2259dae + 04e7be9 commit 616a37f

File tree

113 files changed

+1265
-409
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+1265
-409
lines changed

CHANGELOG.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44

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

7+
## 7.80.0
8+
9+
- feat(astro): Add distributed tracing via `<meta>` tags (#9483)
10+
- feat(node): Capture internal server errors in trpc middleware (#9482)
11+
- feat(remix): Export a type to use for `MetaFunction` parameters (#9493)
12+
- fix(astro): Mark SDK package as Astro-external (#9509)
13+
- ref(nextjs): Don't initialize Server SDK during build (#9503)
14+
715
## 7.79.0
816

917
- feat(tracing): Add span `origin` to trace context (#9472)
@@ -24,7 +32,7 @@ This was possible by extensive use of tree shaking and a host of small changes t
2432

2533
By using [tree shaking](https://docs.sentry.io/platforms/javascript/configuration/tree-shaking/) it is possible to shave up to 10 additional KB off the bundle.
2634

27-
#### Other Changes
35+
### Other Changes
2836

2937
- feat(astro): Add Sentry middleware (#9445)
3038
- feat(feedback): Add "outline focus" and "foreground hover" vars (#9462)
@@ -44,13 +52,18 @@ By using [tree shaking](https://docs.sentry.io/platforms/javascript/configuratio
4452

4553
## 7.77.0
4654

55+
### Security Fixes
56+
57+
- fix(nextjs): Match only numbers as orgid in tunnelRoute (#9416) (CVE-2023-46729)
58+
- fix(nextjs): Strictly validate tunnel target parameters (#9415) (CVE-2023-46729)
59+
60+
### Other Changes
61+
4762
- feat: Move LinkedErrors integration to @sentry/core (#9404)
4863
- feat(remix): Update sentry-cli version to ^2.21.2 (#9401)
4964
- feat(replay): Allow to treeshake & configure compression worker URL (#9409)
5065
- fix(angular-ivy): Adjust package entry points to support Angular 17 with SSR config (#9412)
5166
- fix(feedback): Fixing feedback import (#9403)
52-
- fix(nextjs): Match only numbers as orgid in tunnelRoute (#9416)
53-
- fix(nextjs): Strictly validate tunnel target parameters (#9415)
5467
- fix(utils): Avoid keeping a reference of last used event (#9387)
5568

5669
## 7.76.0

lerna.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
3-
"version": "7.79.0",
3+
"version": "7.80.0",
44
"npmClient": "yarn"
55
}

packages/angular-ivy/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sentry/angular-ivy",
3-
"version": "7.79.0",
3+
"version": "7.80.0",
44
"description": "Official Sentry SDK for Angular with full Ivy Support",
55
"repository": "git://github.com/getsentry/sentry-javascript.git",
66
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/angular-ivy",
@@ -21,9 +21,9 @@
2121
"rxjs": "^6.5.5 || ^7.x"
2222
},
2323
"dependencies": {
24-
"@sentry/browser": "7.79.0",
25-
"@sentry/types": "7.79.0",
26-
"@sentry/utils": "7.79.0",
24+
"@sentry/browser": "7.80.0",
25+
"@sentry/types": "7.80.0",
26+
"@sentry/utils": "7.80.0",
2727
"tslib": "^2.4.1"
2828
},
2929
"devDependencies": {

packages/angular/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sentry/angular",
3-
"version": "7.79.0",
3+
"version": "7.80.0",
44
"description": "Official Sentry SDK for Angular",
55
"repository": "git://github.com/getsentry/sentry-javascript.git",
66
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/angular",
@@ -21,9 +21,9 @@
2121
"rxjs": "^6.5.5 || ^7.x"
2222
},
2323
"dependencies": {
24-
"@sentry/browser": "7.79.0",
25-
"@sentry/types": "7.79.0",
26-
"@sentry/utils": "7.79.0",
24+
"@sentry/browser": "7.80.0",
25+
"@sentry/types": "7.80.0",
26+
"@sentry/utils": "7.80.0",
2727
"tslib": "^2.4.1"
2828
},
2929
"devDependencies": {

packages/astro/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ import { sequence } from "astro:middleware";
6464
import * as Sentry from "@sentry/astro";
6565

6666
export const onRequest = sequence(
67-
Sentry.sentryMiddleware(),
68-
// Add your other handlers after sentryMiddleware
67+
Sentry.handleRequest(),
68+
// Add your other handlers after Sentry.handleRequest()
6969
);
7070
```
7171

packages/astro/package.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sentry/astro",
3-
"version": "7.79.0",
3+
"version": "7.80.0",
44
"description": "Official Sentry SDK for Astro",
55
"repository": "git://github.com/getsentry/sentry-javascript.git",
66
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/astro",
@@ -37,11 +37,11 @@
3737
"astro": "3.x"
3838
},
3939
"dependencies": {
40-
"@sentry/browser": "7.79.0",
41-
"@sentry/core": "7.79.0",
42-
"@sentry/node": "7.79.0",
43-
"@sentry/types": "7.79.0",
44-
"@sentry/utils": "7.79.0",
40+
"@sentry/browser": "7.80.0",
41+
"@sentry/core": "7.80.0",
42+
"@sentry/node": "7.80.0",
43+
"@sentry/types": "7.80.0",
44+
"@sentry/utils": "7.80.0",
4545
"@sentry/vite-plugin": "^2.8.0"
4646
},
4747
"devDependencies": {
@@ -74,5 +74,8 @@
7474
},
7575
"volta": {
7676
"extends": "../../package.json"
77+
},
78+
"astro": {
79+
"external": true
7780
}
7881
}

packages/astro/src/server/meta.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { getDynamicSamplingContextFromClient } from '@sentry/core';
2+
import type { Hub, Span } from '@sentry/types';
3+
import {
4+
dynamicSamplingContextToSentryBaggageHeader,
5+
generateSentryTraceHeader,
6+
logger,
7+
TRACEPARENT_REGEXP,
8+
} from '@sentry/utils';
9+
10+
/**
11+
* Extracts the tracing data from the current span or from the client's scope
12+
* (via transaction or propagation context) and renders the data to <meta> tags.
13+
*
14+
* This function creates two serialized <meta> tags:
15+
* - `<meta name="sentry-trace" content="..."/>`
16+
* - `<meta name="baggage" content="..."/>`
17+
*
18+
* TODO: Extract this later on and export it from the Core or Node SDK
19+
*
20+
* @param span the currently active span
21+
* @param client the SDK's client
22+
*
23+
* @returns an object with the two serialized <meta> tags
24+
*/
25+
export function getTracingMetaTags(span: Span | undefined, hub: Hub): { sentryTrace: string; baggage?: string } {
26+
const scope = hub.getScope();
27+
const client = hub.getClient();
28+
const { dsc, sampled, traceId } = scope.getPropagationContext();
29+
const transaction = span?.transaction;
30+
31+
const sentryTrace = span ? span.toTraceparent() : generateSentryTraceHeader(traceId, undefined, sampled);
32+
33+
const dynamicSamplingContext = transaction
34+
? transaction.getDynamicSamplingContext()
35+
: dsc
36+
? dsc
37+
: client
38+
? getDynamicSamplingContextFromClient(traceId, client, scope)
39+
: undefined;
40+
41+
const baggage = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
42+
43+
const isValidSentryTraceHeader = TRACEPARENT_REGEXP.test(sentryTrace);
44+
if (!isValidSentryTraceHeader) {
45+
logger.warn('Invalid sentry-trace data. Returning empty <meta name="sentry-trace"/> tag');
46+
}
47+
48+
const validBaggage = isValidBaggageString(baggage);
49+
if (!validBaggage) {
50+
logger.warn('Invalid baggage data. Returning empty <meta name="baggage"/> tag');
51+
}
52+
53+
return {
54+
sentryTrace: `<meta name="sentry-trace" content="${isValidSentryTraceHeader ? sentryTrace : ''}"/>`,
55+
baggage: baggage && `<meta name="baggage" content="${validBaggage ? baggage : ''}"/>`,
56+
};
57+
}
58+
59+
/**
60+
* Tests string against baggage spec as defined in:
61+
*
62+
* - W3C Baggage grammar: https://www.w3.org/TR/baggage/#definition
63+
* - RFC7230 token definition: https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
64+
*
65+
* exported for testing
66+
*/
67+
export function isValidBaggageString(baggage?: string): boolean {
68+
if (!baggage || !baggage.length) {
69+
return false;
70+
}
71+
const keyRegex = "[-!#$%&'*+.^_`|~A-Za-z0-9]+";
72+
const valueRegex = '[!#-+-./0-9:<=>?@A-Z\\[\\]a-z{-}]+';
73+
const spaces = '\\s*';
74+
const baggageRegex = new RegExp(
75+
`^${keyRegex}${spaces}=${spaces}${valueRegex}(${spaces},${spaces}${keyRegex}${spaces}=${spaces}${valueRegex})*$`,
76+
);
77+
return baggageRegex.test(baggage);
78+
}

packages/astro/src/server/middleware.ts

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
1-
import { captureException, configureScope, startSpan } from '@sentry/node';
1+
import { captureException, configureScope, getCurrentHub, startSpan } from '@sentry/node';
2+
import type { Hub, Span } from '@sentry/types';
23
import { addExceptionMechanism, objectify, stripUrlQueryAndFragment, tracingContextFromHeaders } from '@sentry/utils';
34
import type { APIContext, MiddlewareResponseHandler } from 'astro';
45

6+
import { getTracingMetaTags } from './meta';
7+
58
type MiddlewareOptions = {
69
/**
710
* If true, the client IP will be attached to the event by calling `setUser`.
8-
* Only set this to `true` if you're fine with collecting potentially personally identifiable information (PII).
911
*
10-
* This will only work if your app is configured for SSR
12+
* Important: Only enable this option if your Astro app is configured for (hybrid) SSR
13+
* via the `output: 'server' | 'hybrid'` option in your `astro.config.mjs` file.
14+
* Otherwise, Astro will throw an error when starting the server.
15+
*
16+
* Only set this to `true` if you're fine with collecting potentially personally identifiable information (PII).
1117
*
1218
* @default false (recommended)
1319
*/
1420
trackClientIp?: boolean;
1521

1622
/**
1723
* If true, the headers from the request will be attached to the event by calling `setExtra`.
24+
*
1825
* Only set this to `true` if you're fine with collecting potentially personally identifiable information (PII).
1926
*
2027
* @default false (recommended)
@@ -93,11 +100,42 @@ export const handleRequest: (options?: MiddlewareOptions) => MiddlewareResponseH
93100
},
94101
},
95102
async span => {
96-
const res = await next();
97-
if (span && res.status) {
98-
span.setHttpStatus(res.status);
103+
const originalResponse = await next();
104+
105+
if (span && originalResponse.status) {
106+
span.setHttpStatus(originalResponse.status);
107+
}
108+
109+
const hub = getCurrentHub();
110+
const client = hub.getClient();
111+
const contentType = originalResponse.headers.get('content-type');
112+
113+
const isPageloadRequest = contentType && contentType.startsWith('text/html');
114+
if (!isPageloadRequest || !client) {
115+
return originalResponse;
99116
}
100-
return res;
117+
118+
// Type case necessary b/c the body's ReadableStream type doesn't include
119+
// the async iterator that is actually available in Node
120+
// We later on use the async iterator to read the body chunks
121+
// see https://github.com/microsoft/TypeScript/issues/39051
122+
const originalBody = originalResponse.body as NodeJS.ReadableStream | null;
123+
if (!originalBody) {
124+
return originalResponse;
125+
}
126+
127+
const newResponseStream = new ReadableStream({
128+
start: async controller => {
129+
for await (const chunk of originalBody) {
130+
const html = typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk);
131+
const modifiedHtml = addMetaTagToHead(html, hub, span);
132+
controller.enqueue(new TextEncoder().encode(modifiedHtml));
133+
}
134+
controller.close();
135+
},
136+
});
137+
138+
return new Response(newResponseStream, originalResponse);
101139
},
102140
);
103141
return res;
@@ -109,6 +147,20 @@ export const handleRequest: (options?: MiddlewareOptions) => MiddlewareResponseH
109147
};
110148
};
111149

150+
/**
151+
* This function optimistically assumes that the HTML coming in chunks will not be split
152+
* within the <head> tag. If this still happens, we simply won't replace anything.
153+
*/
154+
function addMetaTagToHead(htmlChunk: string, hub: Hub, span?: Span): string {
155+
if (typeof htmlChunk !== 'string') {
156+
return htmlChunk;
157+
}
158+
159+
const { sentryTrace, baggage } = getTracingMetaTags(span, hub);
160+
const content = `<head>\n${sentryTrace}\n${baggage}\n`;
161+
return htmlChunk.replace('<head>', content);
162+
}
163+
112164
/**
113165
* Interpolates the route from the URL and the passed params.
114166
* Best we can do to get a route name instead of a raw URL.

0 commit comments

Comments
 (0)