@sentry/nitro 10.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +129 -0
  3. package/build/esm/config.js +32 -0
  4. package/build/esm/config.js.map +1 -0
  5. package/build/esm/index.js +4 -0
  6. package/build/esm/index.js.map +1 -0
  7. package/build/esm/instruments/instrumentServer.js +14 -0
  8. package/build/esm/instruments/instrumentServer.js.map +1 -0
  9. package/build/esm/module.js +18 -0
  10. package/build/esm/module.js.map +1 -0
  11. package/build/esm/package.json +1 -0
  12. package/build/esm/runtime/hooks/captureErrorHook.js +69 -0
  13. package/build/esm/runtime/hooks/captureErrorHook.js.map +1 -0
  14. package/build/esm/runtime/hooks/captureTracingEvents.js +264 -0
  15. package/build/esm/runtime/hooks/captureTracingEvents.js.map +1 -0
  16. package/build/esm/runtime/hooks/setServerTimingHeaders.js +29 -0
  17. package/build/esm/runtime/hooks/setServerTimingHeaders.js.map +1 -0
  18. package/build/esm/runtime/plugins/server.js +12 -0
  19. package/build/esm/runtime/plugins/server.js.map +1 -0
  20. package/build/esm/sdk.js +33 -0
  21. package/build/esm/sdk.js.map +1 -0
  22. package/build/esm/sourceMaps.js +192 -0
  23. package/build/esm/sourceMaps.js.map +1 -0
  24. package/build/esm/utils/plugin.js +10 -0
  25. package/build/esm/utils/plugin.js.map +1 -0
  26. package/build/esm/utils/resolver.js +24 -0
  27. package/build/esm/utils/resolver.js.map +1 -0
  28. package/build/types/common/debug-build.d.ts +7 -0
  29. package/build/types/common/debug-build.d.ts.map +1 -0
  30. package/build/types/config.d.ts +12 -0
  31. package/build/types/config.d.ts.map +1 -0
  32. package/build/types/index.d.ts +4 -0
  33. package/build/types/index.d.ts.map +1 -0
  34. package/build/types/instruments/instrumentServer.d.ts +7 -0
  35. package/build/types/instruments/instrumentServer.d.ts.map +1 -0
  36. package/build/types/module.d.ts +7 -0
  37. package/build/types/module.d.ts.map +1 -0
  38. package/build/types/runtime/hooks/captureErrorHook.d.ts +6 -0
  39. package/build/types/runtime/hooks/captureErrorHook.d.ts.map +1 -0
  40. package/build/types/runtime/hooks/captureTracingEvents.d.ts +5 -0
  41. package/build/types/runtime/hooks/captureTracingEvents.d.ts.map +1 -0
  42. package/build/types/runtime/hooks/setServerTimingHeaders.d.ts +7 -0
  43. package/build/types/runtime/hooks/setServerTimingHeaders.d.ts.map +1 -0
  44. package/build/types/runtime/plugins/server.d.ts +3 -0
  45. package/build/types/runtime/plugins/server.d.ts.map +1 -0
  46. package/build/types/sdk.d.ts +13 -0
  47. package/build/types/sdk.d.ts.map +1 -0
  48. package/build/types/sourceMaps.d.ts +17 -0
  49. package/build/types/sourceMaps.d.ts.map +1 -0
  50. package/build/types/utils/plugin.d.ts +6 -0
  51. package/build/types/utils/plugin.d.ts.map +1 -0
  52. package/build/types/utils/resolver.d.ts +13 -0
  53. package/build/types/utils/resolver.d.ts.map +1 -0
  54. package/package.json +84 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Functional Software, Inc. dba Sentry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,129 @@
1
+ <p align="center">
2
+ <a href="https://sentry.io/?utm_source=github&utm_medium=logo" target="_blank">
3
+ <img src="https://sentry-brand.storage.googleapis.com/sentry-wordmark-dark-280x84.png" alt="Sentry" width="280" height="84">
4
+ </a>
5
+ </p>
6
+
7
+ > NOTICE: This package is in beta state and may be subject to breaking changes.
8
+
9
+ # Official Sentry SDK for Nitro
10
+
11
+ [![npm version](https://img.shields.io/npm/v/@sentry/nitro.svg)](https://www.npmjs.com/package/@sentry/nitro)
12
+ [![npm dm](https://img.shields.io/npm/dm/@sentry/nitro.svg)](https://www.npmjs.com/package/@sentry/nitro)
13
+ [![npm dt](https://img.shields.io/npm/dt/@sentry/nitro.svg)](https://www.npmjs.com/package/@sentry/nitro)
14
+
15
+ ## Links
16
+
17
+ - [Official Nitro SDK Docs](https://docs.sentry.io/platforms/javascript/guides/nitro/)
18
+ - [Example Nitro app](https://github.com/getsentry/sentry-javascript/tree/develop/dev-packages/e2e-tests/test-applications/nitro-3)
19
+
20
+ ## Compatibility
21
+
22
+ The minimum supported version of Nitro is `3.0.260415-beta`.
23
+
24
+ ## General
25
+
26
+ This package is a wrapper around `@sentry/node` with added instrumentation for Nitro's features like:
27
+
28
+ - HTTP handlers and error capturing.
29
+ - [Middleware instrumentation](https://nitro.build/guide/routing#middleware).
30
+ <!-- - [Database instrumentation](https://nitro.build/guide/database). -->
31
+ <!-- - [KV Storage](https://nitro.build/guide/storage) and [Cache](https://nitro.build/guide/cache) instrumentation. -->
32
+
33
+ ## Manual Setup
34
+
35
+ ### 1. Prerequisites & Installation
36
+
37
+ 1. Install the Sentry Nitro SDK:
38
+
39
+ ```bash
40
+ # Using npm
41
+ npm install @sentry/nitro
42
+
43
+ # Using yarn
44
+ yarn add @sentry/nitro
45
+
46
+ # Using pnpm
47
+ pnpm add @sentry/nitro
48
+ ```
49
+
50
+ ### 2. Build-Time Nitro Config Setup
51
+
52
+ 1. Import `withSentryConfig` from `@sentry/nitro` and call it with your Nitro config.
53
+
54
+ #### In `nitro.config.ts`
55
+
56
+ If you are using a dedicated `nitro.config.ts` file, you can import `withSentryConfig` from `@sentry/nitro` and call it with your Nitro config.
57
+
58
+ ```javascript
59
+ import { defineNitroConfig } from 'nitro/config';
60
+ import { withSentryConfig } from '@sentry/nitro';
61
+
62
+ const config = defineNitroConfig({
63
+ // ...
64
+ });
65
+
66
+ export default withSentryConfig(config, {
67
+ // Sentry Build Options
68
+ });
69
+ ```
70
+
71
+ #### In `vite.config.ts`
72
+
73
+ If you are using Nitro as a Vite plugin, you can import `withSentryConfig` from `@sentry/nitro` and call it with your Nitro config.
74
+
75
+ ```ts
76
+ import { defineConfig } from 'vite';
77
+ import { nitro } from 'nitro/vite';
78
+ import { withSentryConfig } from '@sentry/nitro';
79
+
80
+ export default defineConfig({
81
+ plugins: [nitro()],
82
+ nitro: withSentryConfig(
83
+ {
84
+ // Nitro options
85
+ },
86
+ {
87
+ // Sentry Build Options
88
+ },
89
+ ),
90
+ });
91
+ ```
92
+
93
+ ### 3. Sentry Config Setup
94
+
95
+ Create an `instrument.mjs` file in your project root to initialize the Sentry SDK:
96
+
97
+ ```javascript
98
+ import * as Sentry from '@sentry/nitro';
99
+
100
+ Sentry.init({
101
+ dsn: '__YOUR_DSN__',
102
+ tracesSampleRate: 1.0,
103
+ });
104
+ ```
105
+
106
+ Then use `--import` in `NODE_OPTIONS` to load the instrumentation before your app code:
107
+
108
+ ```bash
109
+ NODE_OPTIONS='--import ./instrument.mjs' npx nitro dev
110
+ ```
111
+
112
+ This works with any Nitro command (`nitro dev`, `nitro preview`, or a production start script).
113
+
114
+ ## Uploading Source Maps
115
+
116
+ The `withSentryConfig` function automatically configures source map uploading when the `authToken`, `org`, and `project`
117
+ options are provided:
118
+
119
+ ```javascript
120
+ export default withSentryConfig(config, {
121
+ org: 'your-sentry-org',
122
+ project: 'your-sentry-project',
123
+ authToken: process.env.SENTRY_AUTH_TOKEN,
124
+ });
125
+ ```
126
+
127
+ ## Troubleshoot
128
+
129
+ If you encounter any issues with error tracking or integrations, refer to the official [Sentry Nitro SDK documentation](https://docs.sentry.io/platforms/javascript/guides/nitro/). If the documentation does not provide the necessary information, consider opening an issue on GitHub.
@@ -0,0 +1,32 @@
1
+ import { createNitroModule } from './module.js';
2
+ import { configureSourcemapSettings } from './sourceMaps.js';
3
+
4
+ /**
5
+ * Modifies the passed in Nitro configuration with automatic build-time instrumentation.
6
+ */
7
+ function withSentryConfig(config, sentryOptions) {
8
+ return setupSentryNitroModule(config, sentryOptions);
9
+ }
10
+
11
+ /**
12
+ * Sets up the Sentry Nitro module, useful for meta framework integrations.
13
+ */
14
+ function setupSentryNitroModule(
15
+ config,
16
+ moduleOptions,
17
+ _serverConfigFile,
18
+ ) {
19
+ if (!config.tracingChannel) {
20
+ config.tracingChannel = true;
21
+ }
22
+
23
+ const { sentryEnabledSourcemaps } = configureSourcemapSettings(config, moduleOptions);
24
+
25
+ config.modules = config.modules || [];
26
+ config.modules.push(createNitroModule(moduleOptions, sentryEnabledSourcemaps));
27
+
28
+ return config;
29
+ }
30
+
31
+ export { setupSentryNitroModule, withSentryConfig };
32
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sources":["../../src/config.ts"],"sourcesContent":["import type { BuildTimeOptionsBase } from '@sentry/core';\nimport type { NitroConfig } from 'nitro/types';\nimport { createNitroModule } from './module';\nimport { configureSourcemapSettings } from './sourceMaps';\n\nexport type SentryNitroOptions = BuildTimeOptionsBase;\n\n/**\n * Modifies the passed in Nitro configuration with automatic build-time instrumentation.\n */\nexport function withSentryConfig(config: NitroConfig, sentryOptions?: SentryNitroOptions): NitroConfig {\n return setupSentryNitroModule(config, sentryOptions);\n}\n\n/**\n * Sets up the Sentry Nitro module, useful for meta framework integrations.\n */\nexport function setupSentryNitroModule(\n config: NitroConfig,\n moduleOptions?: SentryNitroOptions,\n _serverConfigFile?: string,\n): NitroConfig {\n if (!config.tracingChannel) {\n config.tracingChannel = true;\n }\n\n const { sentryEnabledSourcemaps } = configureSourcemapSettings(config, moduleOptions);\n\n config.modules = config.modules || [];\n config.modules.push(createNitroModule(moduleOptions, sentryEnabledSourcemaps));\n\n return config;\n}\n"],"names":[],"mappings":";;;AAOA;AACA;AACA;AACO,SAAS,gBAAgB,CAAC,MAAM,EAAe,aAAa,EAAoC;AACvG,EAAE,OAAO,sBAAsB,CAAC,MAAM,EAAE,aAAa,CAAC;AACtD;;AAEA;AACA;AACA;AACO,SAAS,sBAAsB;AACtC,EAAE,MAAM;AACR,EAAE,aAAa;AACf,EAAE,iBAAiB;AACnB,EAAe;AACf,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;AAC9B,IAAI,MAAM,CAAC,cAAA,GAAiB,IAAI;AAChC,EAAE;;AAEF,EAAE,MAAM,EAAE,uBAAA,EAAwB,GAAI,0BAA0B,CAAC,MAAM,EAAE,aAAa,CAAC;;AAEvF,EAAE,MAAM,CAAC,OAAA,GAAU,MAAM,CAAC,OAAA,IAAW,EAAE;AACvC,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE,uBAAuB,CAAC,CAAC;;AAEhF,EAAE,OAAO,MAAM;AACf;;;;"}
@@ -0,0 +1,4 @@
1
+ export { setupSentryNitroModule, withSentryConfig } from './config.js';
2
+ export * from '@sentry/node';
3
+ export { init } from './sdk.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,14 @@
1
+ import { addPlugin } from '../utils/plugin.js';
2
+ import { createResolver } from '../utils/resolver.js';
3
+
4
+ /**
5
+ * Sets up the Nitro server instrumentation plugin
6
+ * @param nitro - The Nitro instance.
7
+ */
8
+ function instrumentServer(nitro) {
9
+ const moduleResolver = createResolver(import.meta.url);
10
+ addPlugin(nitro, moduleResolver.resolve('../runtime/plugins/server'));
11
+ }
12
+
13
+ export { instrumentServer };
14
+ //# sourceMappingURL=instrumentServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrumentServer.js","sources":["../../../src/instruments/instrumentServer.ts"],"sourcesContent":["import type { Nitro } from 'nitro/types';\nimport { addPlugin } from '../utils/plugin';\nimport { createResolver } from '../utils/resolver';\n\n/**\n * Sets up the Nitro server instrumentation plugin\n * @param nitro - The Nitro instance.\n */\nexport function instrumentServer(nitro: Nitro): void {\n const moduleResolver = createResolver(import.meta.url);\n addPlugin(nitro, moduleResolver.resolve('../runtime/plugins/server'));\n}\n"],"names":[],"mappings":";;;AAIA;AACA;AACA;AACA;AACO,SAAS,gBAAgB,CAAC,KAAK,EAAe;AACrD,EAAE,MAAM,cAAA,GAAiB,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;AACxD,EAAE,SAAS,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;AACvE;;;;"}
@@ -0,0 +1,18 @@
1
+ import { instrumentServer } from './instruments/instrumentServer.js';
2
+ import { setupSourceMaps } from './sourceMaps.js';
3
+
4
+ /**
5
+ * Creates a Nitro module to setup the Sentry SDK.
6
+ */
7
+ function createNitroModule(sentryOptions, sentryEnabledSourcemaps) {
8
+ return {
9
+ name: 'sentry',
10
+ setup: nitro => {
11
+ instrumentServer(nitro);
12
+ setupSourceMaps(nitro, sentryOptions, sentryEnabledSourcemaps);
13
+ },
14
+ };
15
+ }
16
+
17
+ export { createNitroModule };
18
+ //# sourceMappingURL=module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.js","sources":["../../src/module.ts"],"sourcesContent":["import type { NitroModule } from 'nitro/types';\nimport type { SentryNitroOptions } from './config';\nimport { instrumentServer } from './instruments/instrumentServer';\nimport { setupSourceMaps } from './sourceMaps';\n\n/**\n * Creates a Nitro module to setup the Sentry SDK.\n */\nexport function createNitroModule(sentryOptions?: SentryNitroOptions, sentryEnabledSourcemaps?: boolean): NitroModule {\n return {\n name: 'sentry',\n setup: nitro => {\n instrumentServer(nitro);\n setupSourceMaps(nitro, sentryOptions, sentryEnabledSourcemaps);\n },\n };\n}\n"],"names":[],"mappings":";;;AAKA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,aAAa,EAAuB,uBAAuB,EAAyB;AACtH,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,QAAQ;AAClB,IAAI,KAAK,EAAE,KAAA,IAAS;AACpB,MAAM,gBAAgB,CAAC,KAAK,CAAC;AAC7B,MAAM,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,uBAAuB,CAAC;AACpE,IAAI,CAAC;AACL,GAAG;AACH;;;;"}
@@ -0,0 +1 @@
1
+ {"type":"module","version":"10.51.0","sideEffects":false}
@@ -0,0 +1,69 @@
1
+ import { getClient, parseUrl, getCurrentScope, getActiveSpan, getRootSpan, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, captureException, flushIfServerless } from '@sentry/core';
2
+ import { HTTPError } from 'h3';
3
+
4
+ /**
5
+ * Extracts the relevant context information from the error context (HTTPEvent in Nitro Error)
6
+ * and creates a structured context object.
7
+ */
8
+ function extractErrorContext(errorContext) {
9
+ const ctx = {};
10
+
11
+ if (!errorContext) {
12
+ return ctx;
13
+ }
14
+
15
+ if (errorContext.event) {
16
+ ctx.method = errorContext.event.req.method;
17
+ ctx.path = parseUrl(errorContext.event.req.url).path;
18
+ }
19
+
20
+ if (Array.isArray(errorContext.tags)) {
21
+ ctx.tags = errorContext.tags;
22
+ }
23
+
24
+ return ctx;
25
+ }
26
+
27
+ /**
28
+ * Hook that can be added in a Nitro plugin. It captures an error and sends it to Sentry.
29
+ */
30
+ async function captureErrorHook(error, errorContext) {
31
+ const sentryClient = getClient();
32
+ const sentryClientOptions = sentryClient?.getOptions();
33
+
34
+ if (
35
+ sentryClientOptions &&
36
+ 'enableNitroErrorHandler' in sentryClientOptions &&
37
+ sentryClientOptions.enableNitroErrorHandler === false
38
+ ) {
39
+ return;
40
+ }
41
+
42
+ // Do not report HTTPErrors with 3xx or 4xx status codes
43
+ if (HTTPError.isError(error) && error.status >= 300 && error.status < 500) {
44
+ return;
45
+ }
46
+
47
+ const method = errorContext.event?.req.method ?? '';
48
+ const path = errorContext.event?.req.url ? parseUrl(errorContext.event.req.url).path : null;
49
+
50
+ if (path) {
51
+ getCurrentScope().setTransactionName(`${method} ${path}`);
52
+ const activeSpan = getActiveSpan();
53
+ const activeRootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;
54
+ activeRootSpan?.updateName(`${method} ${path}`);
55
+ activeRootSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
56
+ }
57
+
58
+ const structuredContext = extractErrorContext(errorContext);
59
+
60
+ captureException(error, {
61
+ captureContext: { contexts: { nitro: structuredContext } },
62
+ mechanism: { handled: false, type: 'auto.function.nitro.captureErrorHook' },
63
+ });
64
+
65
+ await flushIfServerless();
66
+ }
67
+
68
+ export { captureErrorHook };
69
+ //# sourceMappingURL=captureErrorHook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captureErrorHook.js","sources":["../../../../src/runtime/hooks/captureErrorHook.ts"],"sourcesContent":["import {\n captureException,\n flushIfServerless,\n getActiveSpan,\n getClient,\n getCurrentScope,\n getRootSpan,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n} from '@sentry/core';\nimport { HTTPError } from 'h3';\nimport type { CapturedErrorContext } from 'nitro/types';\n\n/**\n * Extracts the relevant context information from the error context (HTTPEvent in Nitro Error)\n * and creates a structured context object.\n */\nfunction extractErrorContext(errorContext: CapturedErrorContext | undefined): Record<string, unknown> {\n const ctx: Record<string, unknown> = {};\n\n if (!errorContext) {\n return ctx;\n }\n\n if (errorContext.event) {\n ctx.method = errorContext.event.req.method;\n ctx.path = parseUrl(errorContext.event.req.url).path;\n }\n\n if (Array.isArray(errorContext.tags)) {\n ctx.tags = errorContext.tags;\n }\n\n return ctx;\n}\n\n/**\n * Hook that can be added in a Nitro plugin. It captures an error and sends it to Sentry.\n */\nexport async function captureErrorHook(error: Error, errorContext: CapturedErrorContext): Promise<void> {\n const sentryClient = getClient();\n const sentryClientOptions = sentryClient?.getOptions();\n\n if (\n sentryClientOptions &&\n 'enableNitroErrorHandler' in sentryClientOptions &&\n sentryClientOptions.enableNitroErrorHandler === false\n ) {\n return;\n }\n\n // Do not report HTTPErrors with 3xx or 4xx status codes\n if (HTTPError.isError(error) && error.status >= 300 && error.status < 500) {\n return;\n }\n\n const method = errorContext.event?.req.method ?? '';\n const path = errorContext.event?.req.url ? parseUrl(errorContext.event.req.url).path : null;\n\n if (path) {\n getCurrentScope().setTransactionName(`${method} ${path}`);\n const activeSpan = getActiveSpan();\n const activeRootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n activeRootSpan?.updateName(`${method} ${path}`);\n activeRootSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n }\n\n const structuredContext = extractErrorContext(errorContext);\n\n captureException(error, {\n captureContext: { contexts: { nitro: structuredContext } },\n mechanism: { handled: false, type: 'auto.function.nitro.captureErrorHook' },\n });\n\n await flushIfServerless();\n}\n"],"names":[],"mappings":";;;AAaA;AACA;AACA;AACA;AACA,SAAS,mBAAmB,CAAC,YAAY,EAA6D;AACtG,EAAE,MAAM,GAAG,GAA4B,EAAE;;AAEzC,EAAE,IAAI,CAAC,YAAY,EAAE;AACrB,IAAI,OAAO,GAAG;AACd,EAAE;;AAEF,EAAE,IAAI,YAAY,CAAC,KAAK,EAAE;AAC1B,IAAI,GAAG,CAAC,MAAA,GAAS,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM;AAC9C,IAAI,GAAG,CAAC,IAAA,GAAO,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI;AACxD,EAAE;;AAEF,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE;AACxC,IAAI,GAAG,CAAC,IAAA,GAAO,YAAY,CAAC,IAAI;AAChC,EAAE;;AAEF,EAAE,OAAO,GAAG;AACZ;;AAEA;AACA;AACA;AACO,eAAe,gBAAgB,CAAC,KAAK,EAAS,YAAY,EAAuC;AACxG,EAAE,MAAM,YAAA,GAAe,SAAS,EAAE;AAClC,EAAE,MAAM,mBAAA,GAAsB,YAAY,EAAE,UAAU,EAAE;;AAExD,EAAE;AACF,IAAI,mBAAA;AACJ,IAAI,yBAAA,IAA6B,mBAAA;AACjC,IAAI,mBAAmB,CAAC,uBAAA,KAA4B;AACpD,IAAI;AACJ,IAAI;AACJ,EAAE;;AAEF;AACA,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,MAAA,IAAU,OAAO,KAAK,CAAC,MAAA,GAAS,GAAG,EAAE;AAC7E,IAAI;AACJ,EAAE;;AAEF,EAAE,MAAM,MAAA,GAAS,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,MAAA,IAAU,EAAE;AACrD,EAAE,MAAM,IAAA,GAAO,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,GAAA,GAAM,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAA,GAAO,IAAI;;AAE7F,EAAE,IAAI,IAAI,EAAE;AACZ,IAAI,eAAe,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAA,MAAA,CAAA,CAAA,EAAA,IAAA,CAAA,CAAA,CAAA;AACA,IAAA,MAAA,UAAA,GAAA,aAAA,EAAA;AACA,IAAA,MAAA,cAAA,GAAA,UAAA,GAAA,WAAA,CAAA,UAAA,CAAA,GAAA,SAAA;AACA,IAAA,cAAA,EAAA,UAAA,CAAA,CAAA,EAAA,MAAA,CAAA,CAAA,EAAA,IAAA,CAAA,CAAA,CAAA;AACA,IAAA,cAAA,EAAA,YAAA,CAAA,gCAAA,EAAA,OAAA,CAAA;AACA,EAAA;;AAEA,EAAA,MAAA,iBAAA,GAAA,mBAAA,CAAA,YAAA,CAAA;;AAEA,EAAA,gBAAA,CAAA,KAAA,EAAA;AACA,IAAA,cAAA,EAAA,EAAA,QAAA,EAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,EAAA;AACA,IAAA,SAAA,EAAA,EAAA,OAAA,EAAA,KAAA,EAAA,IAAA,EAAA,sCAAA,EAAA;AACA,GAAA,CAAA;;AAEA,EAAA,MAAA,iBAAA,EAAA;AACA;;;;"}
@@ -0,0 +1,264 @@
1
+ import { GLOBAL_OBJ, parseStringToURLObject, getHttpSpanDetailsFromUrlObject, startSpanManual, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getRootSpan, updateSpanName, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getClient, httpHeadersToSpanAttributes, getActiveSpan, captureException, SPAN_STATUS_ERROR, setHttpStatus } from '@sentry/core';
2
+ import { tracingChannel } from '@sentry/opentelemetry/tracing-channel';
3
+ import { setServerTimingHeaders } from './setServerTimingHeaders.js';
4
+
5
+ /**
6
+ * Global object with the trace channels
7
+ */
8
+ const globalWithTraceChannels = GLOBAL_OBJ
9
+
10
+ ;
11
+
12
+ /**
13
+ * Captures tracing events emitted by Nitro tracing channels.
14
+ */
15
+ function captureTracingEvents() {
16
+ if (globalWithTraceChannels.__SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__) {
17
+ return;
18
+ }
19
+
20
+ setupH3TracingChannels();
21
+ setupSrvxTracingChannels();
22
+ globalWithTraceChannels.__SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__ = true;
23
+ }
24
+
25
+ /**
26
+ * No-op function to satisfy the tracing channel subscribe callbacks
27
+ */
28
+ const NOOP = () => {};
29
+
30
+ /**
31
+ * Extracts the HTTP status code from a tracing channel result.
32
+ * The result is the return value of the traced handler, which is a Response for srvx
33
+ * and may or may not be a Response for h3.
34
+ */
35
+ function getResponseStatusCode(result) {
36
+ if (result && typeof result === 'object' && 'status' in result && typeof result.status === 'number') {
37
+ return result.status;
38
+ }
39
+ return undefined;
40
+ }
41
+
42
+ function onTraceEnd(data) {
43
+ const statusCode = getResponseStatusCode(data.result);
44
+ if (data._sentrySpan && statusCode !== undefined) {
45
+ setHttpStatus(data._sentrySpan, statusCode);
46
+ }
47
+
48
+ data._sentrySpan?.end();
49
+ }
50
+
51
+ function onTraceError(data) {
52
+ captureException(data.error, { mechanism: { type: 'auto.http.nitro.onTraceError', handled: false } });
53
+ data._sentrySpan?.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
54
+ data._sentrySpan?.end();
55
+ }
56
+
57
+ /**
58
+ * Extracts the parameterized route pattern from the h3 event context.
59
+ */
60
+ function getParameterizedRoute(event) {
61
+ const matchedRoute = event.context?.matchedRoute;
62
+ if (!matchedRoute) {
63
+ return undefined;
64
+ }
65
+
66
+ const routePath = matchedRoute.route;
67
+
68
+ // Skip catch-all routes as they're not useful for transaction grouping
69
+ if (!routePath || routePath === '/**') {
70
+ return undefined;
71
+ }
72
+
73
+ return routePath;
74
+ }
75
+
76
+ function setupH3TracingChannels() {
77
+ const h3Channel = tracingChannel('h3.request', data => {
78
+ const parsedUrl = parseStringToURLObject(data.event.url.href);
79
+ const routePattern = getParameterizedRoute(data.event);
80
+
81
+ const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(
82
+ parsedUrl,
83
+ 'server',
84
+ 'auto.http.nitro.h3',
85
+ { method: data.event.req.method },
86
+ routePattern,
87
+ );
88
+
89
+ return startSpanManual(
90
+ {
91
+ name: spanName,
92
+ attributes: {
93
+ ...urlAttributes,
94
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.h3',
95
+ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: data?.type === 'middleware' ? 'middleware.nitro' : 'http.server',
96
+ },
97
+ },
98
+ span => {
99
+ setParameterizedRouteAttributes(span, data.event);
100
+
101
+ return span;
102
+ },
103
+ );
104
+ });
105
+
106
+ h3Channel.subscribe({
107
+ start: (data) => {
108
+ setServerTimingHeaders(data.event);
109
+ },
110
+ asyncStart: NOOP,
111
+ end: NOOP,
112
+ asyncEnd: (data) => {
113
+ onTraceEnd(data);
114
+
115
+ if (!data._sentrySpan) {
116
+ return;
117
+ }
118
+
119
+ // Update the root span (srvx transaction) with the parameterized route name.
120
+ // The srvx span is created before h3 resolves the route, so it initially has the raw URL.
121
+ // Note: data.type is always 'middleware' in asyncEnd regardless of handler type,
122
+ // so we rely on getParameterizedRoute() to filter out catch-all routes instead.
123
+ const rootSpan = getRootSpan(data._sentrySpan);
124
+ if (rootSpan && rootSpan !== data._sentrySpan) {
125
+ const routePattern = getParameterizedRoute(data.event);
126
+ if (routePattern) {
127
+ const method = data.event.req.method || 'GET';
128
+ updateSpanName(rootSpan, `${method} ${routePattern}`);
129
+ rootSpan.setAttributes({
130
+ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
131
+ 'http.route': routePattern,
132
+ });
133
+ }
134
+ }
135
+ },
136
+ error: onTraceError,
137
+ });
138
+ }
139
+
140
+ function setupSrvxTracingChannels() {
141
+ // Store the parent span per-request so middleware and fetch share the same parent.
142
+ // WeakMap ensures per-request isolation in concurrent environments and automatic cleanup.
143
+ const requestParentSpans = new WeakMap();
144
+
145
+ const fetchChannel = tracingChannel('srvx.request', data => {
146
+ const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : undefined;
147
+ const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, 'server', 'auto.http.nitro.srvx', {
148
+ method: data.request.method,
149
+ });
150
+
151
+ const sendDefaultPii = getClient()?.getOptions().sendDefaultPii ?? false;
152
+ const headerAttributes = httpHeadersToSpanAttributes(
153
+ Object.fromEntries(data.request.headers.entries()),
154
+ sendDefaultPii,
155
+ );
156
+
157
+ return startSpanManual(
158
+ {
159
+ name: spanName,
160
+ attributes: {
161
+ ...urlAttributes,
162
+ ...headerAttributes,
163
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.srvx',
164
+ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: data.middleware ? 'middleware.nitro' : 'http.server',
165
+ 'server.port': data.server.options.port,
166
+ },
167
+ // Use the same parent span as middleware to make them siblings
168
+ parentSpan: requestParentSpans.get(data.request) || undefined,
169
+ },
170
+ span => span,
171
+ );
172
+ });
173
+
174
+ // Subscribe to events (span already created in bindStore)
175
+ fetchChannel.subscribe({
176
+ start: () => {},
177
+ asyncStart: () => {},
178
+ end: () => {},
179
+ asyncEnd: data => {
180
+ onTraceEnd(data);
181
+
182
+ // Clean up parent span reference after the fetch handler completes.
183
+ requestParentSpans.delete(data.request);
184
+ },
185
+ error: data => {
186
+ onTraceError(data);
187
+ // Clean up parent span reference on error too
188
+ requestParentSpans.delete(data.request);
189
+ },
190
+ });
191
+
192
+ const middlewareChannel = tracingChannel('srvx.middleware', data => {
193
+ // For the first middleware, capture the current parent span per-request
194
+ if (data.middleware?.index === 0) {
195
+ const activeSpan = getActiveSpan();
196
+ if (activeSpan) {
197
+ requestParentSpans.set(data.request, activeSpan);
198
+ }
199
+ }
200
+
201
+ const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : undefined;
202
+ const [, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, 'server', 'auto.http.nitro.srvx', {
203
+ method: data.request.method,
204
+ });
205
+
206
+ // Create span as a child of the original parent, not the previous middleware
207
+ return startSpanManual(
208
+ {
209
+ name: `${data.middleware?.handler.name ?? 'unknown'} - ${data.request.method} ${data.request._url?.pathname}`,
210
+ attributes: {
211
+ ...urlAttributes,
212
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.srvx',
213
+ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'middleware.nitro',
214
+ },
215
+ parentSpan: requestParentSpans.get(data.request) || undefined,
216
+ },
217
+ span => span,
218
+ );
219
+ });
220
+
221
+ // Subscribe to events (span already created in bindStore)
222
+ middlewareChannel.subscribe({
223
+ start: () => {},
224
+ asyncStart: () => {},
225
+ end: () => {},
226
+ asyncEnd: onTraceEnd,
227
+ error: onTraceError,
228
+ });
229
+ }
230
+
231
+ /**
232
+ * Sets the parameterized route attributes on the span.
233
+ */
234
+ function setParameterizedRouteAttributes(span, event) {
235
+ const rootSpan = getRootSpan(span);
236
+ if (!rootSpan) {
237
+ return;
238
+ }
239
+
240
+ const matchedRoutePath = getParameterizedRoute(event);
241
+ if (!matchedRoutePath) {
242
+ return;
243
+ }
244
+
245
+ rootSpan.setAttributes({
246
+ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
247
+ 'http.route': matchedRoutePath,
248
+ });
249
+
250
+ const params = event.context?.params;
251
+
252
+ if (params && typeof params === 'object') {
253
+ Object.entries(params).forEach(([key, value]) => {
254
+ // Based on this convention: https://getsentry.github.io/sentry-conventions/generated/attributes/url.html#urlpathparameterkey
255
+ rootSpan.setAttributes({
256
+ [`url.path.parameter.${key}`]: String(value),
257
+ [`params.${key}`]: String(value),
258
+ });
259
+ });
260
+ }
261
+ }
262
+
263
+ export { captureTracingEvents };
264
+ //# sourceMappingURL=captureTracingEvents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captureTracingEvents.js","sources":["../../../../src/runtime/hooks/captureTracingEvents.ts"],"sourcesContent":["import {\n captureException,\n getActiveSpan,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n getRootSpan,\n GLOBAL_OBJ,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n setHttpStatus,\n type Span,\n SPAN_STATUS_ERROR,\n startSpanManual,\n updateSpanName,\n} from '@sentry/core';\nimport { tracingChannel, type TracingChannelContextWithSpan } from '@sentry/opentelemetry/tracing-channel';\nimport type { TracingRequestEvent as H3TracingRequestEvent } from 'h3/tracing';\nimport type { RequestEvent as SrvxRequestEvent } from 'srvx/tracing';\nimport { setServerTimingHeaders } from './setServerTimingHeaders';\n\n/**\n * Global object with the trace channels\n */\nconst globalWithTraceChannels = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__: boolean;\n};\n\n/**\n * Captures tracing events emitted by Nitro tracing channels.\n */\nexport function captureTracingEvents(): void {\n if (globalWithTraceChannels.__SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__) {\n return;\n }\n\n setupH3TracingChannels();\n setupSrvxTracingChannels();\n globalWithTraceChannels.__SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__ = true;\n}\n\n/**\n * No-op function to satisfy the tracing channel subscribe callbacks\n */\nconst NOOP = (): void => {};\n\n/**\n * Extracts the HTTP status code from a tracing channel result.\n * The result is the return value of the traced handler, which is a Response for srvx\n * and may or may not be a Response for h3.\n */\nfunction getResponseStatusCode(result: unknown): number | undefined {\n if (result && typeof result === 'object' && 'status' in result && typeof result.status === 'number') {\n return result.status;\n }\n return undefined;\n}\n\nfunction onTraceEnd(data: TracingChannelContextWithSpan<{ result?: unknown }>): void {\n const statusCode = getResponseStatusCode(data.result);\n if (data._sentrySpan && statusCode !== undefined) {\n setHttpStatus(data._sentrySpan, statusCode);\n }\n\n data._sentrySpan?.end();\n}\n\nfunction onTraceError(data: TracingChannelContextWithSpan<{ error: unknown }>): void {\n captureException(data.error, { mechanism: { type: 'auto.http.nitro.onTraceError', handled: false } });\n data._sentrySpan?.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n data._sentrySpan?.end();\n}\n\n/**\n * Extracts the parameterized route pattern from the h3 event context.\n */\nfunction getParameterizedRoute(event: H3TracingRequestEvent['event']): string | undefined {\n const matchedRoute = event.context?.matchedRoute;\n if (!matchedRoute) {\n return undefined;\n }\n\n const routePath = matchedRoute.route;\n\n // Skip catch-all routes as they're not useful for transaction grouping\n if (!routePath || routePath === '/**') {\n return undefined;\n }\n\n return routePath;\n}\n\nfunction setupH3TracingChannels(): void {\n const h3Channel = tracingChannel<H3TracingRequestEvent>('h3.request', data => {\n const parsedUrl = parseStringToURLObject(data.event.url.href);\n const routePattern = getParameterizedRoute(data.event);\n\n const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(\n parsedUrl,\n 'server',\n 'auto.http.nitro.h3',\n { method: data.event.req.method },\n routePattern,\n );\n\n return startSpanManual(\n {\n name: spanName,\n attributes: {\n ...urlAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.h3',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: data?.type === 'middleware' ? 'middleware.nitro' : 'http.server',\n },\n },\n span => {\n setParameterizedRouteAttributes(span, data.event);\n\n return span;\n },\n );\n });\n\n h3Channel.subscribe({\n start: (data: H3TracingRequestEvent) => {\n setServerTimingHeaders(data.event);\n },\n asyncStart: NOOP,\n end: NOOP,\n asyncEnd: (data: TracingChannelContextWithSpan<H3TracingRequestEvent>) => {\n onTraceEnd(data);\n\n if (!data._sentrySpan) {\n return;\n }\n\n // Update the root span (srvx transaction) with the parameterized route name.\n // The srvx span is created before h3 resolves the route, so it initially has the raw URL.\n // Note: data.type is always 'middleware' in asyncEnd regardless of handler type,\n // so we rely on getParameterizedRoute() to filter out catch-all routes instead.\n const rootSpan = getRootSpan(data._sentrySpan);\n if (rootSpan && rootSpan !== data._sentrySpan) {\n const routePattern = getParameterizedRoute(data.event);\n if (routePattern) {\n const method = data.event.req.method || 'GET';\n updateSpanName(rootSpan, `${method} ${routePattern}`);\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n 'http.route': routePattern,\n });\n }\n }\n },\n error: onTraceError,\n });\n}\n\nfunction setupSrvxTracingChannels(): void {\n // Store the parent span per-request so middleware and fetch share the same parent.\n // WeakMap ensures per-request isolation in concurrent environments and automatic cleanup.\n const requestParentSpans = new WeakMap<Request, Span>();\n\n const fetchChannel = tracingChannel<SrvxRequestEvent>('srvx.request', data => {\n const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : undefined;\n const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, 'server', 'auto.http.nitro.srvx', {\n method: data.request.method,\n });\n\n const sendDefaultPii = getClient()?.getOptions().sendDefaultPii ?? false;\n const headerAttributes = httpHeadersToSpanAttributes(\n Object.fromEntries(data.request.headers.entries()),\n sendDefaultPii,\n );\n\n return startSpanManual(\n {\n name: spanName,\n attributes: {\n ...urlAttributes,\n ...headerAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.srvx',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: data.middleware ? 'middleware.nitro' : 'http.server',\n 'server.port': data.server.options.port,\n },\n // Use the same parent span as middleware to make them siblings\n parentSpan: requestParentSpans.get(data.request) || undefined,\n },\n span => span,\n );\n });\n\n // Subscribe to events (span already created in bindStore)\n fetchChannel.subscribe({\n start: () => {},\n asyncStart: () => {},\n end: () => {},\n asyncEnd: data => {\n onTraceEnd(data);\n\n // Clean up parent span reference after the fetch handler completes.\n requestParentSpans.delete(data.request);\n },\n error: data => {\n onTraceError(data);\n // Clean up parent span reference on error too\n requestParentSpans.delete(data.request);\n },\n });\n\n const middlewareChannel = tracingChannel<SrvxRequestEvent>('srvx.middleware', data => {\n // For the first middleware, capture the current parent span per-request\n if (data.middleware?.index === 0) {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n requestParentSpans.set(data.request, activeSpan);\n }\n }\n\n const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : undefined;\n const [, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, 'server', 'auto.http.nitro.srvx', {\n method: data.request.method,\n });\n\n // Create span as a child of the original parent, not the previous middleware\n return startSpanManual(\n {\n name: `${data.middleware?.handler.name ?? 'unknown'} - ${data.request.method} ${data.request._url?.pathname}`,\n attributes: {\n ...urlAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.srvx',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'middleware.nitro',\n },\n parentSpan: requestParentSpans.get(data.request) || undefined,\n },\n span => span,\n );\n });\n\n // Subscribe to events (span already created in bindStore)\n middlewareChannel.subscribe({\n start: () => {},\n asyncStart: () => {},\n end: () => {},\n asyncEnd: onTraceEnd,\n error: onTraceError,\n });\n}\n\n/**\n * Sets the parameterized route attributes on the span.\n */\nfunction setParameterizedRouteAttributes(span: Span, event: H3TracingRequestEvent['event']): void {\n const rootSpan = getRootSpan(span);\n if (!rootSpan) {\n return;\n }\n\n const matchedRoutePath = getParameterizedRoute(event);\n if (!matchedRoutePath) {\n return;\n }\n\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n 'http.route': matchedRoutePath,\n });\n\n const params = event.context?.params;\n\n if (params && typeof params === 'object') {\n Object.entries(params).forEach(([key, value]) => {\n // Based on this convention: https://getsentry.github.io/sentry-conventions/generated/attributes/url.html#urlpathparameterkey\n rootSpan.setAttributes({\n [`url.path.parameter.${key}`]: String(value),\n [`params.${key}`]: String(value),\n });\n });\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { getTraceData } from '@sentry/core';
2
+
3
+ /**
4
+ * Sets Server-Timing response headers for trace propagation to the client.
5
+ * The browser SDK reads these via the Performance API to connect pageload traces.
6
+ */
7
+ function setServerTimingHeaders(event) {
8
+ if (event.context._sentryServerTimingSet) {
9
+ return;
10
+ }
11
+
12
+ const headers = event.res?.headers;
13
+ if (!headers) {
14
+ return;
15
+ }
16
+
17
+ const traceData = getTraceData();
18
+ if (traceData['sentry-trace']) {
19
+ headers.append('Server-Timing', `sentry-trace;desc="${traceData['sentry-trace']}"`);
20
+ }
21
+ if (traceData.baggage) {
22
+ headers.append('Server-Timing', `baggage;desc="${traceData.baggage}"`);
23
+ }
24
+
25
+ event.context._sentryServerTimingSet = true;
26
+ }
27
+
28
+ export { setServerTimingHeaders };
29
+ //# sourceMappingURL=setServerTimingHeaders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setServerTimingHeaders.js","sources":["../../../../src/runtime/hooks/setServerTimingHeaders.ts"],"sourcesContent":["import { getTraceData } from '@sentry/core';\nimport type { TracingRequestEvent as H3TracingRequestEvent } from 'h3/tracing';\n\n/**\n * Sets Server-Timing response headers for trace propagation to the client.\n * The browser SDK reads these via the Performance API to connect pageload traces.\n */\nexport function setServerTimingHeaders(event: H3TracingRequestEvent['event']): void {\n if (event.context._sentryServerTimingSet) {\n return;\n }\n\n const headers = event.res?.headers;\n if (!headers) {\n return;\n }\n\n const traceData = getTraceData();\n if (traceData['sentry-trace']) {\n headers.append('Server-Timing', `sentry-trace;desc=\"${traceData['sentry-trace']}\"`);\n }\n if (traceData.baggage) {\n headers.append('Server-Timing', `baggage;desc=\"${traceData.baggage}\"`);\n }\n\n event.context._sentryServerTimingSet = true;\n}\n"],"names":[],"mappings":";;AAGA;AACA;AACA;AACA;AACO,SAAS,sBAAsB,CAAC,KAAK,EAAwC;AACpF,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,sBAAsB,EAAE;AAC5C,IAAI;AACJ,EAAE;;AAEF,EAAE,MAAM,OAAA,GAAU,KAAK,CAAC,GAAG,EAAE,OAAO;AACpC,EAAE,IAAI,CAAC,OAAO,EAAE;AAChB,IAAI;AACJ,EAAE;;AAEF,EAAE,MAAM,SAAA,GAAY,YAAY,EAAE;AAClC,EAAE,IAAI,SAAS,CAAC,cAAc,CAAC,EAAE;AACjC,IAAI,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,mBAAmB,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AACvF,EAAE;AACF,EAAE,IAAI,SAAS,CAAC,OAAO,EAAE;AACzB,IAAI,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,cAAc,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC1E,EAAE;;AAEF,EAAE,KAAK,CAAC,OAAO,CAAC,sBAAA,GAAyB,IAAI;AAC7C;;;;"}