withServerActionInstrumentation.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. var {
  2. _nullishCoalesce,
  3. _optionalChain
  4. } = require('@sentry/utils');
  5. Object.defineProperty(exports, '__esModule', { value: true });
  6. const core = require('@sentry/core');
  7. const utils = require('@sentry/utils');
  8. const debugBuild = require('./debug-build.js');
  9. const nextNavigationErrorUtils = require('./nextNavigationErrorUtils.js');
  10. const platformSupportsStreaming = require('./utils/platformSupportsStreaming.js');
  11. const responseEnd = require('./utils/responseEnd.js');
  12. /**
  13. * Wraps a Next.js Server Action implementation with Sentry Error and Performance instrumentation.
  14. */
  15. function withServerActionInstrumentation(
  16. ...args
  17. ) {
  18. if (typeof args[1] === 'function') {
  19. const [serverActionName, callback] = args;
  20. return withServerActionInstrumentationImplementation(serverActionName, {}, callback);
  21. } else {
  22. const [serverActionName, options, callback] = args;
  23. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  24. return withServerActionInstrumentationImplementation(serverActionName, options, callback);
  25. }
  26. }
  27. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  28. async function withServerActionInstrumentationImplementation(
  29. serverActionName,
  30. options,
  31. callback,
  32. ) {
  33. core.addTracingExtensions();
  34. return core.withIsolationScope(isolationScope => {
  35. const sendDefaultPii = _optionalChain([core.getClient, 'call', _ => _(), 'optionalAccess', _2 => _2.getOptions, 'call', _3 => _3(), 'access', _4 => _4.sendDefaultPii]);
  36. let sentryTraceHeader;
  37. let baggageHeader;
  38. const fullHeadersObject = {};
  39. try {
  40. sentryTraceHeader = _nullishCoalesce(_optionalChain([options, 'access', _5 => _5.headers, 'optionalAccess', _6 => _6.get, 'call', _7 => _7('sentry-trace')]), () => ( undefined));
  41. baggageHeader = _optionalChain([options, 'access', _8 => _8.headers, 'optionalAccess', _9 => _9.get, 'call', _10 => _10('baggage')]);
  42. _optionalChain([options, 'access', _11 => _11.headers, 'optionalAccess', _12 => _12.forEach, 'call', _13 => _13((value, key) => {
  43. fullHeadersObject[key] = value;
  44. })]);
  45. } catch (e) {
  46. debugBuild.DEBUG_BUILD &&
  47. utils.logger.warn(
  48. "Sentry wasn't able to extract the tracing headers for a server action. Will not trace this request.",
  49. );
  50. }
  51. isolationScope.setSDKProcessingMetadata({
  52. request: {
  53. headers: fullHeadersObject,
  54. },
  55. });
  56. return core.continueTrace(
  57. {
  58. sentryTrace: sentryTraceHeader,
  59. baggage: baggageHeader,
  60. },
  61. async () => {
  62. try {
  63. return await core.startSpan(
  64. {
  65. op: 'function.server_action',
  66. name: `serverAction/${serverActionName}`,
  67. metadata: {
  68. source: 'route',
  69. },
  70. },
  71. async span => {
  72. const result = await core.handleCallbackErrors(callback, error => {
  73. if (nextNavigationErrorUtils.isNotFoundNavigationError(error)) {
  74. // We don't want to report "not-found"s
  75. _optionalChain([span, 'optionalAccess', _14 => _14.setStatus, 'call', _15 => _15('not_found')]);
  76. } else if (nextNavigationErrorUtils.isRedirectNavigationError(error)) {
  77. // Don't do anything for redirects
  78. } else {
  79. _optionalChain([span, 'optionalAccess', _16 => _16.setStatus, 'call', _17 => _17('internal_error')]);
  80. core.captureException(error, {
  81. mechanism: {
  82. handled: false,
  83. },
  84. });
  85. }
  86. });
  87. if (options.recordResponse !== undefined ? options.recordResponse : sendDefaultPii) {
  88. core.getIsolationScope().setExtra('server_action_result', result);
  89. }
  90. if (options.formData) {
  91. options.formData.forEach((value, key) => {
  92. core.getIsolationScope().setExtra(
  93. `server_action_form_data.${key}`,
  94. typeof value === 'string' ? value : '[non-string value]',
  95. );
  96. });
  97. }
  98. return result;
  99. },
  100. );
  101. } finally {
  102. if (!platformSupportsStreaming.platformSupportsStreaming()) {
  103. // Lambdas require manual flushing to prevent execution freeze before the event is sent
  104. await responseEnd.flushQueue();
  105. }
  106. if (process.env.NEXT_RUNTIME === 'edge') {
  107. // flushQueue should not throw
  108. // eslint-disable-next-line @typescript-eslint/no-floating-promises
  109. responseEnd.flushQueue();
  110. }
  111. }
  112. },
  113. );
  114. });
  115. }
  116. exports.withServerActionInstrumentation = withServerActionInstrumentation;
  117. //# sourceMappingURL=withServerActionInstrumentation.js.map