withSentryConfig.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. var {
  2. _optionalChain
  3. } = require('@sentry/utils');
  4. Object.defineProperty(exports, '__esModule', { value: true });
  5. const utils = require('@sentry/utils');
  6. const webpack = require('./webpack.js');
  7. let showedExportModeTunnelWarning = false;
  8. /**
  9. * Add Sentry options to the config to be exported from the user's `next.config.js` file.
  10. *
  11. * @param exportedUserNextConfig The existing config to be exported prior to adding Sentry
  12. * @param userSentryWebpackPluginOptions Configuration for SentryWebpackPlugin
  13. * @param sentryOptions Optional additional options to add as alternative to `sentry` property of config
  14. * @returns The modified config to be exported
  15. */
  16. function withSentryConfig(
  17. exportedUserNextConfig = {},
  18. userSentryWebpackPluginOptions = {},
  19. sentryOptions,
  20. ) {
  21. if (typeof exportedUserNextConfig === 'function') {
  22. return function ( ...webpackConfigFunctionArgs) {
  23. const maybeUserNextConfigObject = exportedUserNextConfig.apply(
  24. this,
  25. webpackConfigFunctionArgs,
  26. );
  27. if (utils.isThenable(maybeUserNextConfigObject)) {
  28. return maybeUserNextConfigObject.then(function (userNextConfigObject) {
  29. const userSentryOptions = { ...userNextConfigObject.sentry, ...sentryOptions };
  30. return getFinalConfigObject(userNextConfigObject, userSentryOptions, userSentryWebpackPluginOptions);
  31. });
  32. }
  33. // Reassign for naming-consistency sake.
  34. const userNextConfigObject = maybeUserNextConfigObject;
  35. const userSentryOptions = { ...userNextConfigObject.sentry, ...sentryOptions };
  36. return getFinalConfigObject(userNextConfigObject, userSentryOptions, userSentryWebpackPluginOptions);
  37. };
  38. } else {
  39. const userSentryOptions = { ...exportedUserNextConfig.sentry, ...sentryOptions };
  40. return getFinalConfigObject(exportedUserNextConfig, userSentryOptions, userSentryWebpackPluginOptions);
  41. }
  42. }
  43. // Modify the materialized object form of the user's next config by deleting the `sentry` property and wrapping the
  44. // `webpack` property
  45. function getFinalConfigObject(
  46. incomingUserNextConfigObject,
  47. userSentryOptions,
  48. userSentryWebpackPluginOptions,
  49. ) {
  50. // Next 12.2.3+ warns about non-canonical properties on `userNextConfig`.
  51. delete incomingUserNextConfigObject.sentry;
  52. if (_optionalChain([userSentryOptions, 'optionalAccess', _ => _.tunnelRoute])) {
  53. if (incomingUserNextConfigObject.output === 'export') {
  54. if (!showedExportModeTunnelWarning) {
  55. showedExportModeTunnelWarning = true;
  56. // eslint-disable-next-line no-console
  57. console.warn(
  58. '[@sentry/nextjs] The Sentry Next.js SDK `tunnelRoute` option will not work in combination with Next.js static exports. The `tunnelRoute` option uses serverside features that cannot be accessed in export mode. If you still want to tunnel Sentry events, set up your own tunnel: https://docs.sentry.io/platforms/javascript/troubleshooting/#using-the-tunnel-option',
  59. );
  60. }
  61. } else {
  62. setUpTunnelRewriteRules(incomingUserNextConfigObject, userSentryOptions.tunnelRoute);
  63. }
  64. }
  65. return {
  66. ...incomingUserNextConfigObject,
  67. webpack: webpack.constructWebpackConfigFunction(
  68. incomingUserNextConfigObject,
  69. userSentryWebpackPluginOptions,
  70. userSentryOptions,
  71. ),
  72. };
  73. }
  74. /**
  75. * Injects rewrite rules into the Next.js config provided by the user to tunnel
  76. * requests from the `tunnelPath` to Sentry.
  77. *
  78. * See https://nextjs.org/docs/api-reference/next.config.js/rewrites.
  79. */
  80. function setUpTunnelRewriteRules(userNextConfig, tunnelPath) {
  81. const originalRewrites = userNextConfig.rewrites;
  82. // This function doesn't take any arguments at the time of writing but we future-proof
  83. // here in case Next.js ever decides to pass some
  84. userNextConfig.rewrites = async (...args) => {
  85. const injectedRewrite = {
  86. // Matched rewrite routes will look like the following: `[tunnelPath]?o=[orgid]&p=[projectid]`
  87. // Nextjs will automatically convert `source` into a regex for us
  88. source: `${tunnelPath}(/?)`,
  89. has: [
  90. {
  91. type: 'query',
  92. key: 'o', // short for orgId - we keep it short so matching is harder for ad-blockers
  93. value: '(?<orgid>\\d*)',
  94. },
  95. {
  96. type: 'query',
  97. key: 'p', // short for projectId - we keep it short so matching is harder for ad-blockers
  98. value: '(?<projectid>\\d*)',
  99. },
  100. ],
  101. destination: 'https://o:orgid.ingest.sentry.io/api/:projectid/envelope/?hsts=0',
  102. };
  103. if (typeof originalRewrites !== 'function') {
  104. return [injectedRewrite];
  105. }
  106. // @ts-expect-error Expected 0 arguments but got 1 - this is from the future-proofing mentioned above, so we don't care about it
  107. const originalRewritesResult = await originalRewrites(...args);
  108. if (Array.isArray(originalRewritesResult)) {
  109. return [injectedRewrite, ...originalRewritesResult];
  110. } else {
  111. return {
  112. ...originalRewritesResult,
  113. beforeFiles: [injectedRewrite, ...(originalRewritesResult.beforeFiles || [])],
  114. };
  115. }
  116. };
  117. }
  118. exports.withSentryConfig = withSentryConfig;
  119. //# sourceMappingURL=withSentryConfig.js.map