|
1 |
| -import type { Span } from '@sentry/core'; |
2 |
| -import { |
3 |
| - SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, |
4 |
| - SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, |
5 |
| - continueTrace, |
6 |
| - getCurrentScope, |
7 |
| - getDefaultIsolationScope, |
8 |
| - getIsolationScope, |
9 |
| - getTraceMetaTags, |
10 |
| - logger, |
11 |
| - setHttpStatus, |
12 |
| - startSpan, |
13 |
| - winterCGRequestToRequestData, |
14 |
| - withIsolationScope, |
15 |
| -} from '@sentry/core'; |
16 |
| -import type { Handle, ResolveOptions } from '@sveltejs/kit'; |
17 |
| - |
18 |
| -import type { SentryHandleOptions } from '../server-common/handle'; |
19 |
| -import { sentryHandleGeneric } from '../server-common/handle'; |
20 |
| - |
21 |
| -/** |
22 |
| - * A SvelteKit handle function that wraps the request for Sentry error and |
23 |
| - * performance monitoring. |
24 |
| - * |
25 |
| - * Usage: |
26 |
| - * ``` |
27 |
| - * // src/hooks.server.ts |
28 |
| - * import { sentryHandle } from '@sentry/sveltekit'; |
29 |
| - * |
30 |
| - * export const handle = sentryHandle(); |
31 |
| - * |
32 |
| - * // Optionally use the `sequence` function to add additional handlers. |
33 |
| - * // export const handle = sequence(sentryHandle(), yourCustomHandler); |
34 |
| - * ``` |
35 |
| - */ |
36 |
| -export function sentryHandle(handlerOptions?: SentryHandleOptions): Handle { |
37 |
| - const { handleUnknownRoutes, ...rest } = handlerOptions ?? {}; |
38 |
| - const options = { |
39 |
| - handleUnknownRoutes: handleUnknownRoutes ?? false, |
40 |
| - ...rest, |
41 |
| - }; |
42 |
| - |
43 |
| - const sentryRequestHandler: Handle = input => { |
44 |
| - // In case of a same-origin `fetch` call within a server`load` function, |
45 |
| - // SvelteKit will actually just re-enter the `handle` function and set `isSubRequest` |
46 |
| - // to `true` so that no additional network call is made. |
47 |
| - // We want the `http.server` span of that nested call to be a child span of the |
48 |
| - // currently active span instead of a new root span to correctly reflect this |
49 |
| - // behavior. |
50 |
| - if (input.event.isSubRequest) { |
51 |
| - return instrumentHandle(input, options); |
52 |
| - } |
53 |
| - |
54 |
| - return withIsolationScope(isolationScope => { |
55 |
| - // We only call continueTrace in the initial top level request to avoid |
56 |
| - // creating a new root span for the sub request. |
57 |
| - isolationScope.setSDKProcessingMetadata({ |
58 |
| - // We specifically avoid cloning the request here to avoid double read errors. |
59 |
| - // We only read request headers so we're not consuming the body anyway. |
60 |
| - // Note to future readers: This sounds counter-intuitive but please read |
61 |
| - // https://github.com/getsentry/sentry-javascript/issues/14583 |
62 |
| - normalizedRequest: winterCGRequestToRequestData(input.event.request), |
63 |
| - }); |
64 |
| - return continueTrace(getTracePropagationData(input.event), () => instrumentHandle(input, options)); |
65 |
| - }); |
66 |
| - }; |
67 |
| - |
68 |
| - return sentryRequestHandler; |
69 |
| -} |
70 |
| - |
71 |
| -async function instrumentHandle( |
72 |
| - { event, resolve }: Parameters<Handle>[0], |
73 |
| - options: SentryHandleOptions, |
74 |
| -): Promise<Response> { |
75 |
| - if (!event.route?.id && !options.handleUnknownRoutes) { |
76 |
| - return resolve(event); |
77 |
| - } |
78 |
| - |
79 |
| - // caching the result of the version check in `options.injectFetchProxyScript` |
80 |
| - // to avoid doing the dynamic import on every request |
81 |
| - if (options.injectFetchProxyScript == null) { |
82 |
| - try { |
83 |
| - // @ts-expect-error - the dynamic import is fine here |
84 |
| - const { VERSION } = await import('@sveltejs/kit'); |
85 |
| - options.injectFetchProxyScript = isFetchProxyRequired(VERSION); |
86 |
| - } catch { |
87 |
| - options.injectFetchProxyScript = true; |
88 |
| - } |
89 |
| - } |
90 |
| - |
91 |
| - const routeName = `${event.request.method} ${event.route?.id || event.url.pathname}`; |
92 |
| - |
93 |
| - if (getIsolationScope() !== getDefaultIsolationScope()) { |
94 |
| - getIsolationScope().setTransactionName(routeName); |
95 |
| - } else { |
96 |
| - DEBUG_BUILD && logger.warn('Isolation scope is default isolation scope - skipping setting transactionName'); |
97 |
| - } |
98 |
| - |
99 |
| - try { |
100 |
| - const resolveResult = await startSpan( |
101 |
| - { |
102 |
| - op: 'http.server', |
103 |
| - attributes: { |
104 |
| - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit', |
105 |
| - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: event.route?.id ? 'route' : 'url', |
106 |
| - 'http.method': event.request.method, |
107 |
| - }, |
108 |
| - name: routeName, |
109 |
| - }, |
110 |
| - async (span?: Span) => { |
111 |
| - getCurrentScope().setSDKProcessingMetadata({ |
112 |
| - // We specifically avoid cloning the request here to avoid double read errors. |
113 |
| - // We only read request headers so we're not consuming the body anyway. |
114 |
| - // Note to future readers: This sounds counter-intuitive but please read |
115 |
| - // https://github.com/getsentry/sentry-javascript/issues/14583 |
116 |
| - normalizedRequest: winterCGRequestToRequestData(event.request), |
117 |
| - }); |
118 |
| - const res = await resolve(event, { |
119 |
| - transformPageChunk: addSentryCodeToPage({ injectFetchProxyScript: options.injectFetchProxyScript ?? true }), |
120 |
| - }); |
121 |
| - if (span) { |
122 |
| - setHttpStatus(span, res.status); |
123 |
| - } |
124 |
| - return res; |
125 |
| - }, |
126 |
| - ); |
127 |
| - return resolveResult; |
128 |
| - } catch (e: unknown) { |
129 |
| - sendErrorToSentry(e, 'handle'); |
130 |
| - throw e; |
131 |
| - } finally { |
132 |
| - await flushIfServerless(); |
133 |
| - } |
134 |
| -} |
135 |
| - |
136 |
| -/** |
137 |
| - * We only need to inject the fetch proxy script for SvelteKit versions < 2.16.0. |
138 |
| - * Exported only for testing. |
139 |
| - */ |
140 |
| -export function isFetchProxyRequired(version: string): boolean { |
141 |
| - try { |
142 |
| - const [major, minor] = version.trim().replace(/-.*/, '').split('.').map(Number); |
143 |
| - if (major != null && minor != null && (major > 2 || (major === 2 && minor >= 16))) { |
144 |
| - return false; |
145 |
| - } |
146 |
| - } catch { |
147 |
| - // ignore |
148 |
| - } |
149 |
| - return true; |
150 |
| -} |
| 1 | +import type { CloudflareOptions } from '@sentry/cloudflare'; |
| 2 | +import type { Handle } from '@sveltejs/kit'; |
| 3 | +import { init } from './sdk'; |
151 | 4 |
|
152 | 5 | /**
|
153 | 6 | * Actual implementation in ../worker/handle.ts
|
|
0 commit comments