sdk.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. Object.defineProperty(exports, '__esModule', { value: true });
  2. const core = require('@sentry/core');
  3. const utils = require('@sentry/utils');
  4. const client = require('./client.js');
  5. const debugBuild = require('./debug-build.js');
  6. const helpers = require('./helpers.js');
  7. const breadcrumbs = require('./integrations/breadcrumbs.js');
  8. const dedupe = require('./integrations/dedupe.js');
  9. const globalhandlers = require('./integrations/globalhandlers.js');
  10. const httpcontext = require('./integrations/httpcontext.js');
  11. const linkederrors = require('./integrations/linkederrors.js');
  12. const trycatch = require('./integrations/trycatch.js');
  13. const stackParsers = require('./stack-parsers.js');
  14. const fetch = require('./transports/fetch.js');
  15. const xhr = require('./transports/xhr.js');
  16. /** @deprecated Use `getDefaultIntegrations(options)` instead. */
  17. const defaultIntegrations = [
  18. core.inboundFiltersIntegration(),
  19. core.functionToStringIntegration(),
  20. trycatch.browserApiErrorsIntegration(),
  21. breadcrumbs.breadcrumbsIntegration(),
  22. globalhandlers.globalHandlersIntegration(),
  23. linkederrors.linkedErrorsIntegration(),
  24. dedupe.dedupeIntegration(),
  25. httpcontext.httpContextIntegration(),
  26. ];
  27. /** Get the default integrations for the browser SDK. */
  28. function getDefaultIntegrations(_options) {
  29. // We return a copy of the defaultIntegrations here to avoid mutating this
  30. return [
  31. // eslint-disable-next-line deprecation/deprecation
  32. ...defaultIntegrations,
  33. ];
  34. }
  35. /**
  36. * A magic string that build tooling can leverage in order to inject a release value into the SDK.
  37. */
  38. /**
  39. * The Sentry Browser SDK Client.
  40. *
  41. * To use this SDK, call the {@link init} function as early as possible when
  42. * loading the web page. To set context information or send manual events, use
  43. * the provided methods.
  44. *
  45. * @example
  46. *
  47. * ```
  48. *
  49. * import { init } from '@sentry/browser';
  50. *
  51. * init({
  52. * dsn: '__DSN__',
  53. * // ...
  54. * });
  55. * ```
  56. *
  57. * @example
  58. * ```
  59. *
  60. * import { configureScope } from '@sentry/browser';
  61. * configureScope((scope: Scope) => {
  62. * scope.setExtra({ battery: 0.7 });
  63. * scope.setTag({ user_mode: 'admin' });
  64. * scope.setUser({ id: '4711' });
  65. * });
  66. * ```
  67. *
  68. * @example
  69. * ```
  70. *
  71. * import { addBreadcrumb } from '@sentry/browser';
  72. * addBreadcrumb({
  73. * message: 'My Breadcrumb',
  74. * // ...
  75. * });
  76. * ```
  77. *
  78. * @example
  79. *
  80. * ```
  81. *
  82. * import * as Sentry from '@sentry/browser';
  83. * Sentry.captureMessage('Hello, world!');
  84. * Sentry.captureException(new Error('Good bye'));
  85. * Sentry.captureEvent({
  86. * message: 'Manual',
  87. * stacktrace: [
  88. * // ...
  89. * ],
  90. * });
  91. * ```
  92. *
  93. * @see {@link BrowserOptions} for documentation on configuration options.
  94. */
  95. function init(options = {}) {
  96. if (options.defaultIntegrations === undefined) {
  97. options.defaultIntegrations = getDefaultIntegrations();
  98. }
  99. if (options.release === undefined) {
  100. // This allows build tooling to find-and-replace __SENTRY_RELEASE__ to inject a release value
  101. if (typeof __SENTRY_RELEASE__ === 'string') {
  102. options.release = __SENTRY_RELEASE__;
  103. }
  104. // This supports the variable that sentry-webpack-plugin injects
  105. if (helpers.WINDOW.SENTRY_RELEASE && helpers.WINDOW.SENTRY_RELEASE.id) {
  106. options.release = helpers.WINDOW.SENTRY_RELEASE.id;
  107. }
  108. }
  109. if (options.autoSessionTracking === undefined) {
  110. options.autoSessionTracking = true;
  111. }
  112. if (options.sendClientReports === undefined) {
  113. options.sendClientReports = true;
  114. }
  115. const clientOptions = {
  116. ...options,
  117. stackParser: utils.stackParserFromStackParserOptions(options.stackParser || stackParsers.defaultStackParser),
  118. integrations: core.getIntegrationsToSetup(options),
  119. transport: options.transport || (utils.supportsFetch() ? fetch.makeFetchTransport : xhr.makeXHRTransport),
  120. };
  121. core.initAndBind(client.BrowserClient, clientOptions);
  122. if (options.autoSessionTracking) {
  123. startSessionTracking();
  124. }
  125. }
  126. const showReportDialog = (
  127. // eslint-disable-next-line deprecation/deprecation
  128. options = {},
  129. // eslint-disable-next-line deprecation/deprecation
  130. hub = core.getCurrentHub(),
  131. ) => {
  132. // doesn't work without a document (React Native)
  133. if (!helpers.WINDOW.document) {
  134. debugBuild.DEBUG_BUILD && utils.logger.error('Global document not defined in showReportDialog call');
  135. return;
  136. }
  137. // eslint-disable-next-line deprecation/deprecation
  138. const { client, scope } = hub.getStackTop();
  139. const dsn = options.dsn || (client && client.getDsn());
  140. if (!dsn) {
  141. debugBuild.DEBUG_BUILD && utils.logger.error('DSN not configured for showReportDialog call');
  142. return;
  143. }
  144. if (scope) {
  145. options.user = {
  146. ...scope.getUser(),
  147. ...options.user,
  148. };
  149. }
  150. // TODO(v8): Remove this entire if statement. `eventId` will be a required option.
  151. // eslint-disable-next-line deprecation/deprecation
  152. if (!options.eventId) {
  153. // eslint-disable-next-line deprecation/deprecation
  154. options.eventId = hub.lastEventId();
  155. }
  156. const script = helpers.WINDOW.document.createElement('script');
  157. script.async = true;
  158. script.crossOrigin = 'anonymous';
  159. script.src = core.getReportDialogEndpoint(dsn, options);
  160. if (options.onLoad) {
  161. script.onload = options.onLoad;
  162. }
  163. const { onClose } = options;
  164. if (onClose) {
  165. const reportDialogClosedMessageHandler = (event) => {
  166. if (event.data === '__sentry_reportdialog_closed__') {
  167. try {
  168. onClose();
  169. } finally {
  170. helpers.WINDOW.removeEventListener('message', reportDialogClosedMessageHandler);
  171. }
  172. }
  173. };
  174. helpers.WINDOW.addEventListener('message', reportDialogClosedMessageHandler);
  175. }
  176. const injectionPoint = helpers.WINDOW.document.head || helpers.WINDOW.document.body;
  177. if (injectionPoint) {
  178. injectionPoint.appendChild(script);
  179. } else {
  180. debugBuild.DEBUG_BUILD && utils.logger.error('Not injecting report dialog. No injection point found in HTML');
  181. }
  182. };
  183. /**
  184. * This function is here to be API compatible with the loader.
  185. * @hidden
  186. */
  187. function forceLoad() {
  188. // Noop
  189. }
  190. /**
  191. * This function is here to be API compatible with the loader.
  192. * @hidden
  193. */
  194. function onLoad(callback) {
  195. callback();
  196. }
  197. /**
  198. * Wrap code within a try/catch block so the SDK is able to capture errors.
  199. *
  200. * @deprecated This function will be removed in v8.
  201. * It is not part of Sentry's official API and it's easily replaceable by using a try/catch block
  202. * and calling Sentry.captureException.
  203. *
  204. * @param fn A function to wrap.
  205. *
  206. * @returns The result of wrapped function call.
  207. */
  208. // TODO(v8): Remove this function
  209. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  210. function wrap(fn) {
  211. return helpers.wrap(fn)();
  212. }
  213. /**
  214. * Enable automatic Session Tracking for the initial page load.
  215. */
  216. function startSessionTracking() {
  217. if (typeof helpers.WINDOW.document === 'undefined') {
  218. debugBuild.DEBUG_BUILD && utils.logger.warn('Session tracking in non-browser environment with @sentry/browser is not supported.');
  219. return;
  220. }
  221. // The session duration for browser sessions does not track a meaningful
  222. // concept that can be used as a metric.
  223. // Automatically captured sessions are akin to page views, and thus we
  224. // discard their duration.
  225. core.startSession({ ignoreDuration: true });
  226. core.captureSession();
  227. // We want to create a session for every navigation as well
  228. utils.addHistoryInstrumentationHandler(({ from, to }) => {
  229. // Don't create an additional session for the initial route or if the location did not change
  230. if (from !== undefined && from !== to) {
  231. core.startSession({ ignoreDuration: true });
  232. core.captureSession();
  233. }
  234. });
  235. }
  236. /**
  237. * Captures user feedback and sends it to Sentry.
  238. */
  239. function captureUserFeedback(feedback) {
  240. const client = core.getClient();
  241. if (client) {
  242. client.captureUserFeedback(feedback);
  243. }
  244. }
  245. exports.captureUserFeedback = captureUserFeedback;
  246. exports.defaultIntegrations = defaultIntegrations;
  247. exports.forceLoad = forceLoad;
  248. exports.getDefaultIntegrations = getDefaultIntegrations;
  249. exports.init = init;
  250. exports.onLoad = onLoad;
  251. exports.showReportDialog = showReportDialog;
  252. exports.wrap = wrap;
  253. //# sourceMappingURL=sdk.js.map