11import type { ExecutionContext } from '@cloudflare/workers-types' ;
22import type { CloudflareOptions } from '@sentry/cloudflare' ;
33import { setAsyncLocalStorageAsyncContextStrategy , wrapRequestHandler } from '@sentry/cloudflare' ;
4+ import { getDefaultIsolationScope , getIsolationScope , logger } from '@sentry/core' ;
45import type { NitroApp , NitroAppPlugin } from 'nitropack' ;
56import type { NuxtRenderHTMLContext } from 'nuxt/app' ;
67import { sentryCaptureErrorHook } from '../hooks/captureErrorHook' ;
@@ -34,14 +35,47 @@ function isEventType(event: unknown): event is CfEventType {
3435 ) ;
3536}
3637
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 =>
3972 ( nitroApp : NitroApp ) : void => {
4073 nitroApp . localFetch = new Proxy ( nitroApp . localFetch , {
4174 async apply ( handlerTarget , handlerThisArg , handlerArgs : [ string , unknown ] ) {
42- // fixme: is this the correct spot?
4375 setAsyncLocalStorageAsyncContextStrategy ( ) ;
4476
77+ const sentryOptions = typeof optionsOrFn === 'function' ? optionsOrFn ( nitroApp ) : optionsOrFn ;
78+
4579 const pathname = handlerArgs [ 0 ] ;
4680 const event = handlerArgs [ 1 ] ;
4781
@@ -52,7 +86,16 @@ export const cloudflareNitroPlugin =
5286 context : event . context . cloudflare . context ,
5387 } ;
5488
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+
5699 return wrapRequestHandler ( requestHandlerOptions , ( ) => handlerTarget . apply ( handlerThisArg , handlerArgs ) ) ;
57100 }
58101
@@ -63,6 +106,7 @@ export const cloudflareNitroPlugin =
63106 // @ts -expect-error - 'render:html' is a valid hook name in the Nuxt context
64107 nitroApp . hooks . hook ( 'render:html' , ( html : NuxtRenderHTMLContext ) => {
65108 // 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
66110 addSentryTracingMetaTags ( html . head ) ;
67111 } ) ;
68112
0 commit comments