1
1
import type { ExecutionContext } from '@cloudflare/workers-types' ;
2
2
import type { CloudflareOptions } from '@sentry/cloudflare' ;
3
3
import { setAsyncLocalStorageAsyncContextStrategy , wrapRequestHandler } from '@sentry/cloudflare' ;
4
+ import { getDefaultIsolationScope , getIsolationScope , logger } from '@sentry/core' ;
4
5
import type { NitroApp , NitroAppPlugin } from 'nitropack' ;
5
6
import type { NuxtRenderHTMLContext } from 'nuxt/app' ;
6
7
import { sentryCaptureErrorHook } from '../hooks/captureErrorHook' ;
@@ -34,14 +35,47 @@ function isEventType(event: unknown): event is CfEventType {
34
35
) ;
35
36
}
36
37
37
- export const cloudflareNitroPlugin =
38
- ( sentryOptions : CloudflareOptions ) : NitroAppPlugin =>
38
+ /**
39
+ * Sentry Cloudflare Nitro plugin for when using the "cloudflare-pages" preset in Nuxt.
40
+ * This plugin automatically sets up Sentry error monitoring and performance tracking for Cloudflare Pages projects.
41
+ *
42
+ * Instead of adding a `sentry.server.config.ts` file, export this plugin in the `server/plugins` directory
43
+ * with the necessary Sentry options to enable Sentry for your Cloudflare Pages project.
44
+ *
45
+ *
46
+ * @example Basic usage
47
+ * ```ts
48
+ * // nitro/plugins/sentry.ts
49
+ * import { defineNitroPlugin } from '#imports'
50
+ * import { sentryCloudflareNitroPlugin } from '@sentry/nuxt/module/plugins'
51
+ *
52
+ * export default defineNitroPlugin(sentryCloudflareNitroPlugin({
53
+ * dsn: 'https://examplePublicKey@o 0.ingest.sentry.io/0',
54
+ * tracesSampleRate: 1.0,
55
+ * }));
56
+ * ```
57
+ *
58
+ * @example Dynamic configuration with nitroApp
59
+ * ```ts
60
+ * // nitro/plugins/sentry.ts
61
+ * import { defineNitroPlugin } from '#imports'
62
+ * import { sentryCloudflareNitroPlugin } from '@sentry/nuxt/module/plugins'
63
+ *
64
+ * export default defineNitroPlugin(sentryCloudflareNitroPlugin(nitroApp => ({
65
+ * dsn: 'https://examplePublicKey@o 0.ingest.sentry.io/0',
66
+ * debug: nitroApp.h3App.options.debug
67
+ * })));
68
+ * ```
69
+ */
70
+ export const sentryCloudflareNitroPlugin =
71
+ ( optionsOrFn : CloudflareOptions | ( ( nitroApp : NitroApp ) => CloudflareOptions ) ) : NitroAppPlugin =>
39
72
( nitroApp : NitroApp ) : void => {
40
73
nitroApp . localFetch = new Proxy ( nitroApp . localFetch , {
41
74
async apply ( handlerTarget , handlerThisArg , handlerArgs : [ string , unknown ] ) {
42
- // fixme: is this the correct spot?
43
75
setAsyncLocalStorageAsyncContextStrategy ( ) ;
44
76
77
+ const sentryOptions = typeof optionsOrFn === 'function' ? optionsOrFn ( nitroApp ) : optionsOrFn ;
78
+
45
79
const pathname = handlerArgs [ 0 ] ;
46
80
const event = handlerArgs [ 1 ] ;
47
81
@@ -52,7 +86,16 @@ export const cloudflareNitroPlugin =
52
86
context : event . context . cloudflare . context ,
53
87
} ;
54
88
55
- // todo: wrap in isolation scope (like regular handler)
89
+ const isolationScope = getIsolationScope ( ) ;
90
+ const newIsolationScope =
91
+ isolationScope === getDefaultIsolationScope ( ) ? isolationScope . clone ( ) : isolationScope ;
92
+
93
+ logger . log (
94
+ `Patched Cloudflare handler (\`nitroApp.localFetch\`). ${
95
+ isolationScope === newIsolationScope ? 'Using existing' : 'Created new'
96
+ } isolation scope.`,
97
+ ) ;
98
+
56
99
return wrapRequestHandler ( requestHandlerOptions , ( ) => handlerTarget . apply ( handlerThisArg , handlerArgs ) ) ;
57
100
}
58
101
@@ -63,6 +106,7 @@ export const cloudflareNitroPlugin =
63
106
// @ts -expect-error - 'render:html' is a valid hook name in the Nuxt context
64
107
nitroApp . hooks . hook ( 'render:html' , ( html : NuxtRenderHTMLContext ) => {
65
108
// fixme: it's attaching the html meta tag but it's not connecting the trace
109
+ // fixme: its' actually connecting the trace but the meta tags are cached
66
110
addSentryTracingMetaTags ( html . head ) ;
67
111
} ) ;
68
112
0 commit comments