From 27325140985e49b7001c1657c0524e63282d0d91 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Fri, 14 Feb 2025 14:39:27 +0000 Subject: [PATCH 01/15] feat(nextjs): Do not strip origin information from different origin stack frames --- .../client/clientNormalizationIntegration.ts | 22 +++++++++++++------ packages/nextjs/src/client/index.ts | 13 +++++------ packages/nextjs/src/config/webpack.ts | 8 +------ .../nextjs/src/config/withSentryConfig.ts | 10 ++++----- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index e4bbb4881bc3..010d1f250914 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -1,16 +1,24 @@ -import { rewriteFramesIntegration } from '@sentry/browser'; +import { WINDOW, rewriteFramesIntegration } from '@sentry/browser'; import { defineIntegration } from '@sentry/core'; +const windowOrigin = WINDOW.location.origin; + export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( - ({ assetPrefixPath }: { assetPrefixPath: string }) => { + ({ assetPrefix, basePath }: { assetPrefix?: string; basePath?: string }) => { const rewriteFramesInstance = rewriteFramesIntegration({ // Turn `//_next/static/...` into `app:///_next/static/...` iteratee: frame => { - try { - const { origin } = new URL(frame.filename as string); - frame.filename = frame.filename?.replace(origin, 'app://').replace(assetPrefixPath, ''); - } catch (err) { - // Filename wasn't a properly formed URL, so there's nothing we can do + if (assetPrefix) { + frame.filename = frame.filename?.replace(assetPrefix, 'app://'); + } else if (basePath) { + try { + const { origin: frameOrigin } = new URL(frame.filename as string); + if (frameOrigin === windowOrigin) { + frame.filename = frame.filename?.replace(frameOrigin, 'app://').replace(basePath, ''); + } + } catch (err) { + // Filename wasn't a properly formed URL, so there's nothing we can do + } } // We need to URI-decode the filename because Next.js has wildcard routes like "/users/[id].js" which show up as "/users/%5id%5.js" in Error stacktraces. diff --git a/packages/nextjs/src/client/index.ts b/packages/nextjs/src/client/index.ts index 163e29f0b9a7..bdf66b9ab7a8 100644 --- a/packages/nextjs/src/client/index.ts +++ b/packages/nextjs/src/client/index.ts @@ -16,7 +16,8 @@ export { captureUnderscoreErrorException } from '../common/pages-router-instrume export { browserTracingIntegration } from './browserTracingIntegration'; const globalWithInjectedValues = GLOBAL_OBJ as typeof GLOBAL_OBJ & { - _sentryRewriteFramesAssetPrefixPath: string; + _sentryAssetPrefix?: string; + _sentryBasePath?: string; }; // Treeshakable guard to remove all code related to tracing @@ -67,13 +68,11 @@ function getDefaultIntegrations(options: BrowserOptions): Integration[] { customDefaultIntegrations.push(browserTracingIntegration()); } - // This value is injected at build time, based on the output directory specified in the build config. Though a default + // These values are injected at build time, based on the output directory specified in the build config. Though a default // is set there, we set it here as well, just in case something has gone wrong with the injection. - const assetPrefixPath = - process.env._sentryRewriteFramesAssetPrefixPath || - globalWithInjectedValues._sentryRewriteFramesAssetPrefixPath || - ''; - customDefaultIntegrations.push(nextjsClientStackFrameNormalizationIntegration({ assetPrefixPath })); + const assetPrefix = process.env._sentryAssetPrefix || globalWithInjectedValues._sentryAssetPrefix; + const basePath = process.env._sentryBasePath || globalWithInjectedValues._sentryBasePath; + customDefaultIntegrations.push(nextjsClientStackFrameNormalizationIntegration({ assetPrefix, basePath })); return customDefaultIntegrations; } diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index f82bb4a0476e..a98da76a12c8 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -595,8 +595,6 @@ function addValueInjectionLoader( buildContext: BuildContext, releaseName: string | undefined, ): void { - const assetPrefix = userNextConfig.assetPrefix || userNextConfig.basePath || ''; - const isomorphicValues = { // `rewritesTunnel` set by the user in Next.js config _sentryRewritesTunnelPath: @@ -619,11 +617,7 @@ function addValueInjectionLoader( const clientValues = { ...isomorphicValues, - // Get the path part of `assetPrefix`, minus any trailing slash. (We use a placeholder for the origin if - // `assetPrefix` doesn't include one. Since we only care about the path, it doesn't matter what it is.) - _sentryRewriteFramesAssetPrefixPath: assetPrefix - ? new URL(assetPrefix, 'http://dogs.are.great').pathname.replace(/\/$/, '') - : '', + _sentryAssetPrefix: userNextConfig.assetPrefix, }; if (buildContext.isServer) { diff --git a/packages/nextjs/src/config/withSentryConfig.ts b/packages/nextjs/src/config/withSentryConfig.ts index 8f57f51a8c58..1d2e7c26511a 100644 --- a/packages/nextjs/src/config/withSentryConfig.ts +++ b/packages/nextjs/src/config/withSentryConfig.ts @@ -250,7 +250,6 @@ function setUpTunnelRewriteRules(userNextConfig: NextConfigObject, tunnelPath: s // TODO: For Turbopack we need to pass the release name here and pick it up in the SDK function setUpBuildTimeVariables(userNextConfig: NextConfigObject, userSentryOptions: SentryBuildOptions): void { - const assetPrefix = userNextConfig.assetPrefix || userNextConfig.basePath || ''; const basePath = userNextConfig.basePath ?? ''; const rewritesTunnelPath = userSentryOptions.tunnelRoute !== undefined && userNextConfig.output !== 'export' @@ -261,11 +260,6 @@ function setUpBuildTimeVariables(userNextConfig: NextConfigObject, userSentryOpt // Make sure that if we have a windows path, the backslashes are interpreted as such (rather than as escape // characters) _sentryRewriteFramesDistDir: userNextConfig.distDir?.replace(/\\/g, '\\\\') || '.next', - // Get the path part of `assetPrefix`, minus any trailing slash. (We use a placeholder for the origin if - // `assetPrefix` doesn't include one. Since we only care about the path, it doesn't matter what it is.) - _sentryRewriteFramesAssetPrefixPath: assetPrefix - ? new URL(assetPrefix, 'http://dogs.are.great').pathname.replace(/\/$/, '') - : '', }; if (rewritesTunnelPath) { @@ -276,6 +270,10 @@ function setUpBuildTimeVariables(userNextConfig: NextConfigObject, userSentryOpt buildTimeVariables._sentryBasePath = basePath; } + if (userNextConfig.assetPrefix) { + buildTimeVariables._sentryAssetPrefix = userNextConfig.assetPrefix; + } + if (typeof userNextConfig.env === 'object') { userNextConfig.env = { ...buildTimeVariables, ...userNextConfig.env }; } else if (userNextConfig.env === undefined) { From b6a681858f96575ee4d710df587738e4407e0ea9 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Fri, 14 Feb 2025 14:49:55 +0000 Subject: [PATCH 02/15] fix tests? --- .../nextjs/src/client/clientNormalizationIntegration.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index 010d1f250914..9351fa7e6f1f 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -1,15 +1,17 @@ import { WINDOW, rewriteFramesIntegration } from '@sentry/browser'; import { defineIntegration } from '@sentry/core'; -const windowOrigin = WINDOW.location.origin; - export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( ({ assetPrefix, basePath }: { assetPrefix?: string; basePath?: string }) => { + const windowOrigin = WINDOW.location.origin; + const rewriteFramesInstance = rewriteFramesIntegration({ // Turn `//_next/static/...` into `app:///_next/static/...` iteratee: frame => { if (assetPrefix) { - frame.filename = frame.filename?.replace(assetPrefix, 'app://'); + if (frame.filename?.startsWith(assetPrefix)) { + frame.filename = frame.filename.replace(assetPrefix, 'app://'); + } } else if (basePath) { try { const { origin: frameOrigin } = new URL(frame.filename as string); From f0496d9e88b580a095d2d813a62eda41eb7c426b Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Fri, 14 Feb 2025 15:01:48 +0000 Subject: [PATCH 03/15] . --- .../nextjs/src/client/clientNormalizationIntegration.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index 9351fa7e6f1f..4970c0415b9d 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -8,6 +8,11 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( const rewriteFramesInstance = rewriteFramesIntegration({ // Turn `//_next/static/...` into `app:///_next/static/...` iteratee: frame => { + // A filename starting with the local origin and not ending with JS is most likely JS in HTML which we do not want to rewrite + if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { + return frame; + } + if (assetPrefix) { if (frame.filename?.startsWith(assetPrefix)) { frame.filename = frame.filename.replace(assetPrefix, 'app://'); @@ -25,13 +30,13 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( // We need to URI-decode the filename because Next.js has wildcard routes like "/users/[id].js" which show up as "/users/%5id%5.js" in Error stacktraces. // The corresponding sources that Next.js generates have proper brackets so we also need proper brackets in the frame so that source map resolving works. - if (frame.filename?.startsWith('app:///_next')) { + if (frame.filename?.includes('/_next')) { frame.filename = decodeURI(frame.filename); } if ( frame.filename?.match( - /^app:\/\/\/_next\/static\/chunks\/(main-|main-app-|polyfills-|webpack-|framework-|framework\.)[0-9a-f]+\.js$/, + /\/_next\/static\/chunks\/(main-|main-app-|polyfills-|webpack-|framework-|framework\.)[0-9a-f]+\.js$/, ) ) { // We don't care about these frames. It's Next.js internal code. From e47084a3d0be644fe5982dab6a20540e8ef8e4da Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Fri, 14 Feb 2025 15:04:38 +0000 Subject: [PATCH 04/15] comments and stuff --- packages/nextjs/src/client/clientNormalizationIntegration.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index 4970c0415b9d..257496cb51c0 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -14,10 +14,14 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( } if (assetPrefix) { + // If the user defined an asset prefix, we need to strip it so that we can match it with uploaded sourcemaps. + // assetPrefix always takes priority over basePath. if (frame.filename?.startsWith(assetPrefix)) { frame.filename = frame.filename.replace(assetPrefix, 'app://'); } } else if (basePath) { + // If the user defined a base path, we need to strip it to match with uploaded sourcemaps. + // We should only do this for same-origin filenames though, so that third party assets are not rewritten. try { const { origin: frameOrigin } = new URL(frame.filename as string); if (frameOrigin === windowOrigin) { From c38281ae91eb000a59b6c8b777c52f72723c55f1 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 19 Feb 2025 13:02:12 +0100 Subject: [PATCH 05/15] add experimental flag --- .../client/clientNormalizationIntegration.ts | 91 +++++++++++++------ packages/nextjs/src/client/index.ts | 18 +++- packages/nextjs/src/config/types.ts | 10 ++ packages/nextjs/src/config/webpack.ts | 10 ++ .../nextjs/src/config/withSentryConfig.ts | 18 ++++ 5 files changed, 117 insertions(+), 30 deletions(-) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index 257496cb51c0..f27d8dd18c5a 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -2,31 +2,49 @@ import { WINDOW, rewriteFramesIntegration } from '@sentry/browser'; import { defineIntegration } from '@sentry/core'; export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( - ({ assetPrefix, basePath }: { assetPrefix?: string; basePath?: string }) => { - const windowOrigin = WINDOW.location.origin; - + ({ + assetPrefix, + basePath, + rewriteFramesAssetPrefixPath, + experimentalThirdPartyOriginStackFrames, + }: { + assetPrefix?: string; + basePath?: string; + rewriteFramesAssetPrefixPath: string; + experimentalThirdPartyOriginStackFrames: boolean; + }) => { const rewriteFramesInstance = rewriteFramesIntegration({ // Turn `//_next/static/...` into `app:///_next/static/...` iteratee: frame => { - // A filename starting with the local origin and not ending with JS is most likely JS in HTML which we do not want to rewrite - if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { - return frame; - } + if (experimentalThirdPartyOriginStackFrames) { + const windowOrigin = WINDOW.location.origin; + // A filename starting with the local origin and not ending with JS is most likely JS in HTML which we do not want to rewrite + if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { + return frame; + } - if (assetPrefix) { - // If the user defined an asset prefix, we need to strip it so that we can match it with uploaded sourcemaps. - // assetPrefix always takes priority over basePath. - if (frame.filename?.startsWith(assetPrefix)) { - frame.filename = frame.filename.replace(assetPrefix, 'app://'); + if (assetPrefix) { + // If the user defined an asset prefix, we need to strip it so that we can match it with uploaded sourcemaps. + // assetPrefix always takes priority over basePath. + if (frame.filename?.startsWith(assetPrefix)) { + frame.filename = frame.filename.replace(assetPrefix, 'app://'); + } + } else if (basePath) { + // If the user defined a base path, we need to strip it to match with uploaded sourcemaps. + // We should only do this for same-origin filenames though, so that third party assets are not rewritten. + try { + const { origin: frameOrigin } = new URL(frame.filename as string); + if (frameOrigin === windowOrigin) { + frame.filename = frame.filename?.replace(frameOrigin, 'app://').replace(basePath, ''); + } + } catch (err) { + // Filename wasn't a properly formed URL, so there's nothing we can do + } } - } else if (basePath) { - // If the user defined a base path, we need to strip it to match with uploaded sourcemaps. - // We should only do this for same-origin filenames though, so that third party assets are not rewritten. + } else { try { - const { origin: frameOrigin } = new URL(frame.filename as string); - if (frameOrigin === windowOrigin) { - frame.filename = frame.filename?.replace(frameOrigin, 'app://').replace(basePath, ''); - } + const { origin } = new URL(frame.filename as string); + frame.filename = frame.filename?.replace(origin, 'app://').replace(rewriteFramesAssetPrefixPath, ''); } catch (err) { // Filename wasn't a properly formed URL, so there's nothing we can do } @@ -34,17 +52,32 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( // We need to URI-decode the filename because Next.js has wildcard routes like "/users/[id].js" which show up as "/users/%5id%5.js" in Error stacktraces. // The corresponding sources that Next.js generates have proper brackets so we also need proper brackets in the frame so that source map resolving works. - if (frame.filename?.includes('/_next')) { - frame.filename = decodeURI(frame.filename); - } + if (experimentalThirdPartyOriginStackFrames) { + if (frame.filename?.includes('/_next')) { + frame.filename = decodeURI(frame.filename); + } + + if ( + frame.filename?.match( + /\/_next\/static\/chunks\/(main-|main-app-|polyfills-|webpack-|framework-|framework\.)[0-9a-f]+\.js$/, + ) + ) { + // We don't care about these frames. It's Next.js internal code. + frame.in_app = false; + } + } else { + if (frame.filename?.startsWith('app:///_next')) { + frame.filename = decodeURI(frame.filename); + } - if ( - frame.filename?.match( - /\/_next\/static\/chunks\/(main-|main-app-|polyfills-|webpack-|framework-|framework\.)[0-9a-f]+\.js$/, - ) - ) { - // We don't care about these frames. It's Next.js internal code. - frame.in_app = false; + if ( + frame.filename?.match( + /^app:\/\/\/_next\/static\/chunks\/(main-|main-app-|polyfills-|webpack-|framework-|framework\.)[0-9a-f]+\.js$/, + ) + ) { + // We don't care about these frames. It's Next.js internal code. + frame.in_app = false; + } } return frame; diff --git a/packages/nextjs/src/client/index.ts b/packages/nextjs/src/client/index.ts index bdf66b9ab7a8..c8e6d21837fd 100644 --- a/packages/nextjs/src/client/index.ts +++ b/packages/nextjs/src/client/index.ts @@ -16,8 +16,10 @@ export { captureUnderscoreErrorException } from '../common/pages-router-instrume export { browserTracingIntegration } from './browserTracingIntegration'; const globalWithInjectedValues = GLOBAL_OBJ as typeof GLOBAL_OBJ & { + _sentryRewriteFramesAssetPrefixPath: string; _sentryAssetPrefix?: string; _sentryBasePath?: string; + _experimentalThirdPartyOriginStackFrames?: string; }; // Treeshakable guard to remove all code related to tracing @@ -70,9 +72,23 @@ function getDefaultIntegrations(options: BrowserOptions): Integration[] { // These values are injected at build time, based on the output directory specified in the build config. Though a default // is set there, we set it here as well, just in case something has gone wrong with the injection. + const rewriteFramesAssetPrefixPath = + process.env._sentryRewriteFramesAssetPrefixPath || + globalWithInjectedValues._sentryRewriteFramesAssetPrefixPath || + ''; const assetPrefix = process.env._sentryAssetPrefix || globalWithInjectedValues._sentryAssetPrefix; const basePath = process.env._sentryBasePath || globalWithInjectedValues._sentryBasePath; - customDefaultIntegrations.push(nextjsClientStackFrameNormalizationIntegration({ assetPrefix, basePath })); + const experimentalThirdPartyOriginStackFrames = + process.env._experimentalThirdPartyOriginStackFrames === 'true' || + globalWithInjectedValues._experimentalThirdPartyOriginStackFrames === 'true'; + customDefaultIntegrations.push( + nextjsClientStackFrameNormalizationIntegration({ + assetPrefix, + basePath, + rewriteFramesAssetPrefixPath, + experimentalThirdPartyOriginStackFrames, + }), + ); return customDefaultIntegrations; } diff --git a/packages/nextjs/src/config/types.ts b/packages/nextjs/src/config/types.ts index a747684cc753..4d7122d1bf65 100644 --- a/packages/nextjs/src/config/types.ts +++ b/packages/nextjs/src/config/types.ts @@ -439,6 +439,16 @@ export type SentryBuildOptions = { * Defaults to `false`. */ automaticVercelMonitors?: boolean; + + /** + * Contains a set of experimental flags that might change in future releases. These flags enable + * features that are still in development and may be modified, renamed, or removed without notice. + * Use with caution in production environments. + * + */ + _experimental?: Partial<{ + thirdPartyOriginStackFrames: boolean; + }>; }; export type NextConfigFunction = ( diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index a98da76a12c8..5ff02da355a1 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -595,6 +595,8 @@ function addValueInjectionLoader( buildContext: BuildContext, releaseName: string | undefined, ): void { + const assetPrefix = userNextConfig.assetPrefix || userNextConfig.basePath || ''; + const isomorphicValues = { // `rewritesTunnel` set by the user in Next.js config _sentryRewritesTunnelPath: @@ -617,7 +619,15 @@ function addValueInjectionLoader( const clientValues = { ...isomorphicValues, + // Get the path part of `assetPrefix`, minus any trailing slash. (We use a placeholder for the origin if + // `assetPrefix` doesn't include one. Since we only care about the path, it doesn't matter what it is.) + _sentryRewriteFramesAssetPrefixPath: assetPrefix + ? new URL(assetPrefix, 'http://dogs.are.great').pathname.replace(/\/$/, '') + : '', _sentryAssetPrefix: userNextConfig.assetPrefix, + _sentryExperimentalThirdPartyOriginStackFrames: userSentryOptions._experimental?.thirdPartyOriginStackFrames + ? 'true' + : undefined, }; if (buildContext.isServer) { diff --git a/packages/nextjs/src/config/withSentryConfig.ts b/packages/nextjs/src/config/withSentryConfig.ts index 1d2e7c26511a..ab15d1c86c0d 100644 --- a/packages/nextjs/src/config/withSentryConfig.ts +++ b/packages/nextjs/src/config/withSentryConfig.ts @@ -250,6 +250,7 @@ function setUpTunnelRewriteRules(userNextConfig: NextConfigObject, tunnelPath: s // TODO: For Turbopack we need to pass the release name here and pick it up in the SDK function setUpBuildTimeVariables(userNextConfig: NextConfigObject, userSentryOptions: SentryBuildOptions): void { + const assetPrefix = userNextConfig.assetPrefix || userNextConfig.basePath || ''; const basePath = userNextConfig.basePath ?? ''; const rewritesTunnelPath = userSentryOptions.tunnelRoute !== undefined && userNextConfig.output !== 'export' @@ -260,8 +261,21 @@ function setUpBuildTimeVariables(userNextConfig: NextConfigObject, userSentryOpt // Make sure that if we have a windows path, the backslashes are interpreted as such (rather than as escape // characters) _sentryRewriteFramesDistDir: userNextConfig.distDir?.replace(/\\/g, '\\\\') || '.next', + // Get the path part of `assetPrefix`, minus any trailing slash. (We use a placeholder for the origin if + // `assetPrefix` doesn't include one. Since we only care about the path, it doesn't matter what it is.) + _sentryRewriteFramesAssetPrefixPath: assetPrefix + ? new URL(assetPrefix, 'http://dogs.are.great').pathname.replace(/\/$/, '') + : '', }; + if (userNextConfig.assetPrefix) { + buildTimeVariables._assetsPrefix = userNextConfig.assetPrefix; + } + + if (userSentryOptions._experimental?.thirdPartyOriginStackFrames) { + buildTimeVariables._experimentalThirdPartyOriginStackFrames = 'true'; + } + if (rewritesTunnelPath) { buildTimeVariables._sentryRewritesTunnelPath = rewritesTunnelPath; } @@ -274,6 +288,10 @@ function setUpBuildTimeVariables(userNextConfig: NextConfigObject, userSentryOpt buildTimeVariables._sentryAssetPrefix = userNextConfig.assetPrefix; } + if (userSentryOptions._experimental?.thirdPartyOriginStackFrames) { + buildTimeVariables._experimentalThirdPartyOriginStackFrames = 'true'; + } + if (typeof userNextConfig.env === 'object') { userNextConfig.env = { ...buildTimeVariables, ...userNextConfig.env }; } else if (userNextConfig.env === undefined) { From ad052c3a80ca0dd185da447f6c23cf9dc206edd7 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 19 Feb 2025 15:55:25 +0100 Subject: [PATCH 06/15] trigger ci --- packages/nextjs/src/config/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/nextjs/src/config/types.ts b/packages/nextjs/src/config/types.ts index 4d7122d1bf65..965233d08b76 100644 --- a/packages/nextjs/src/config/types.ts +++ b/packages/nextjs/src/config/types.ts @@ -444,7 +444,6 @@ export type SentryBuildOptions = { * Contains a set of experimental flags that might change in future releases. These flags enable * features that are still in development and may be modified, renamed, or removed without notice. * Use with caution in production environments. - * */ _experimental?: Partial<{ thirdPartyOriginStackFrames: boolean; From e7e7428d5ed416fcb8fc70eea89e1e33b0c48fa3 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 19 Feb 2025 16:34:14 +0100 Subject: [PATCH 07/15] debug: remove nextjs from size limit --- .size-limit.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.size-limit.js b/.size-limit.js index 157c1243021e..381734ed301b 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -204,14 +204,14 @@ module.exports = [ limit: '264 KB', }, // Next.js SDK (ESM) - { - name: '@sentry/nextjs (client)', - path: 'packages/nextjs/build/esm/client/index.js', - import: createImport('init'), - ignore: ['next/router', 'next/constants'], - gzip: true, - limit: '40 KB', - }, + // { + // name: '@sentry/nextjs (client)', + // path: 'packages/nextjs/build/esm/client/index.js', + // import: createImport('init'), + // ignore: ['next/router', 'next/constants'], + // gzip: true, + // limit: '40 KB', + // }, // SvelteKit SDK (ESM) { name: '@sentry/sveltekit (client)', From 7dfc195a9536ec93472f15f61e7d038f0d4c9e01 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 19 Feb 2025 16:50:42 +0100 Subject: [PATCH 08/15] add next to size check --- .size-limit.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.size-limit.js b/.size-limit.js index 381734ed301b..157c1243021e 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -204,14 +204,14 @@ module.exports = [ limit: '264 KB', }, // Next.js SDK (ESM) - // { - // name: '@sentry/nextjs (client)', - // path: 'packages/nextjs/build/esm/client/index.js', - // import: createImport('init'), - // ignore: ['next/router', 'next/constants'], - // gzip: true, - // limit: '40 KB', - // }, + { + name: '@sentry/nextjs (client)', + path: 'packages/nextjs/build/esm/client/index.js', + import: createImport('init'), + ignore: ['next/router', 'next/constants'], + gzip: true, + limit: '40 KB', + }, // SvelteKit SDK (ESM) { name: '@sentry/sveltekit (client)', From 9b9f8848ba7d30ae9626a86887b6315370988432 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 21 Feb 2025 15:30:31 +0100 Subject: [PATCH 09/15] debug: check if window causes ci failure --- .../client/clientNormalizationIntegration.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index f27d8dd18c5a..75805b0000b4 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -1,4 +1,5 @@ -import { WINDOW, rewriteFramesIntegration } from '@sentry/browser'; +// import { WINDOW, rewriteFramesIntegration } from '@sentry/browser'; +import { rewriteFramesIntegration } from '@sentry/browser'; import { defineIntegration } from '@sentry/core'; export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( @@ -17,11 +18,11 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( // Turn `//_next/static/...` into `app:///_next/static/...` iteratee: frame => { if (experimentalThirdPartyOriginStackFrames) { - const windowOrigin = WINDOW.location.origin; + // const windowOrigin = WINDOW.location.origin; // A filename starting with the local origin and not ending with JS is most likely JS in HTML which we do not want to rewrite - if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { - return frame; - } + // if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { + // return frame; + // } if (assetPrefix) { // If the user defined an asset prefix, we need to strip it so that we can match it with uploaded sourcemaps. @@ -33,10 +34,10 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( // If the user defined a base path, we need to strip it to match with uploaded sourcemaps. // We should only do this for same-origin filenames though, so that third party assets are not rewritten. try { - const { origin: frameOrigin } = new URL(frame.filename as string); - if (frameOrigin === windowOrigin) { - frame.filename = frame.filename?.replace(frameOrigin, 'app://').replace(basePath, ''); - } + // const { origin: frameOrigin } = new URL(frame.filename as string); + // if (frameOrigin === windowOrigin) { + // frame.filename = frame.filename?.replace(frameOrigin, 'app://').replace(basePath, ''); + // } } catch (err) { // Filename wasn't a properly formed URL, so there's nothing we can do } From 9941dabde2839dcb5f962a4a9876a6b77db2d83b Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 21 Feb 2025 15:59:33 +0100 Subject: [PATCH 10/15] guard window access --- .../client/clientNormalizationIntegration.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index 75805b0000b4..1955844339eb 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -1,5 +1,4 @@ -// import { WINDOW, rewriteFramesIntegration } from '@sentry/browser'; -import { rewriteFramesIntegration } from '@sentry/browser'; +import { WINDOW, rewriteFramesIntegration } from '@sentry/browser'; import { defineIntegration } from '@sentry/core'; export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( @@ -18,11 +17,12 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( // Turn `//_next/static/...` into `app:///_next/static/...` iteratee: frame => { if (experimentalThirdPartyOriginStackFrames) { - // const windowOrigin = WINDOW.location.origin; + // Unguarded access to window causes hideous ci errors + const windowOrigin = typeof WINDOW !== 'undefined' ? WINDOW.location.origin : ''; // A filename starting with the local origin and not ending with JS is most likely JS in HTML which we do not want to rewrite - // if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { - // return frame; - // } + if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { + return frame; + } if (assetPrefix) { // If the user defined an asset prefix, we need to strip it so that we can match it with uploaded sourcemaps. @@ -34,10 +34,10 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( // If the user defined a base path, we need to strip it to match with uploaded sourcemaps. // We should only do this for same-origin filenames though, so that third party assets are not rewritten. try { - // const { origin: frameOrigin } = new URL(frame.filename as string); - // if (frameOrigin === windowOrigin) { - // frame.filename = frame.filename?.replace(frameOrigin, 'app://').replace(basePath, ''); - // } + const { origin: frameOrigin } = new URL(frame.filename as string); + if (frameOrigin === windowOrigin) { + frame.filename = frame.filename?.replace(frameOrigin, 'app://').replace(basePath, ''); + } } catch (err) { // Filename wasn't a properly formed URL, so there's nothing we can do } From 497b0195907b6aff6c10e265cde3467e063e0881 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 21 Feb 2025 16:09:52 +0100 Subject: [PATCH 11/15] sorry for all the notifications luca --- packages/nextjs/src/client/clientNormalizationIntegration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index 1955844339eb..6790fd326c22 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -18,7 +18,7 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( iteratee: frame => { if (experimentalThirdPartyOriginStackFrames) { // Unguarded access to window causes hideous ci errors - const windowOrigin = typeof WINDOW !== 'undefined' ? WINDOW.location.origin : ''; + const windowOrigin = typeof WINDOW !== 'undefined' && WINDOW.location ? WINDOW.location.origin : ''; // A filename starting with the local origin and not ending with JS is most likely JS in HTML which we do not want to rewrite if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { return frame; From 15497db50529e281135e8dc15450443ac0fdf209 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 21 Feb 2025 16:21:01 +0100 Subject: [PATCH 12/15] try without global obj --- packages/nextjs/src/client/clientNormalizationIntegration.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index 6790fd326c22..22e21379f685 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -1,4 +1,4 @@ -import { WINDOW, rewriteFramesIntegration } from '@sentry/browser'; +import { rewriteFramesIntegration } from '@sentry/browser'; import { defineIntegration } from '@sentry/core'; export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( @@ -18,7 +18,8 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( iteratee: frame => { if (experimentalThirdPartyOriginStackFrames) { // Unguarded access to window causes hideous ci errors - const windowOrigin = typeof WINDOW !== 'undefined' && WINDOW.location ? WINDOW.location.origin : ''; + // eslint-disable-next-line no-restricted-globals + const windowOrigin = typeof window !== 'undefined' && window.location ? window.location.origin : ''; // A filename starting with the local origin and not ending with JS is most likely JS in HTML which we do not want to rewrite if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { return frame; From 27f8c9cb2667b0b853a7f774e29ab42b9f1ad3c3 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 21 Feb 2025 17:13:14 +0100 Subject: [PATCH 13/15] ... --- .size-limit.js | 2 +- packages/nextjs/src/client/clientNormalizationIntegration.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.size-limit.js b/.size-limit.js index 157c1243021e..08adf5a80c29 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -210,7 +210,7 @@ module.exports = [ import: createImport('init'), ignore: ['next/router', 'next/constants'], gzip: true, - limit: '40 KB', + limit: '41 KB', }, // SvelteKit SDK (ESM) { diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index 22e21379f685..c1d83ef9e33e 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -1,4 +1,4 @@ -import { rewriteFramesIntegration } from '@sentry/browser'; +import { rewriteFramesIntegration, WINDOW } from '@sentry/browser'; import { defineIntegration } from '@sentry/core'; export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( @@ -18,8 +18,7 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( iteratee: frame => { if (experimentalThirdPartyOriginStackFrames) { // Unguarded access to window causes hideous ci errors - // eslint-disable-next-line no-restricted-globals - const windowOrigin = typeof window !== 'undefined' && window.location ? window.location.origin : ''; + const windowOrigin = typeof WINDOW !== 'undefined' && WINDOW.location ? WINDOW.location.origin : ''; // A filename starting with the local origin and not ending with JS is most likely JS in HTML which we do not want to rewrite if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { return frame; From 87c3f9c712d0454e026ad3b297d2737a1a386214 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 21 Feb 2025 17:16:04 +0100 Subject: [PATCH 14/15] madonna mia --- packages/nextjs/src/client/clientNormalizationIntegration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index c1d83ef9e33e..6790fd326c22 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -1,4 +1,4 @@ -import { rewriteFramesIntegration, WINDOW } from '@sentry/browser'; +import { WINDOW, rewriteFramesIntegration } from '@sentry/browser'; import { defineIntegration } from '@sentry/core'; export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( From 818cf7830d9390701e96f33f4e0746ad4cc1c13d Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 21 Feb 2025 17:24:35 +0100 Subject: [PATCH 15/15] triste --- .../nextjs/src/client/clientNormalizationIntegration.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index 6790fd326c22..a7cd2c356f4e 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -1,4 +1,4 @@ -import { WINDOW, rewriteFramesIntegration } from '@sentry/browser'; +import { rewriteFramesIntegration } from '@sentry/browser'; import { defineIntegration } from '@sentry/core'; export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( @@ -17,8 +17,9 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( // Turn `//_next/static/...` into `app:///_next/static/...` iteratee: frame => { if (experimentalThirdPartyOriginStackFrames) { - // Unguarded access to window causes hideous ci errors - const windowOrigin = typeof WINDOW !== 'undefined' && WINDOW.location ? WINDOW.location.origin : ''; + // Not sure why but access to global WINDOW from @sentry/Browser causes hideous ci errors + // eslint-disable-next-line no-restricted-globals + const windowOrigin = typeof window !== 'undefined' && window.location ? window.location.origin : ''; // A filename starting with the local origin and not ending with JS is most likely JS in HTML which we do not want to rewrite if (frame.filename?.startsWith(windowOrigin) && !frame.filename.endsWith('.js')) { return frame;