@sentry/react 8.5.0 → 8.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@ To use this SDK, call `Sentry.init(options)` before you mount your React compone
20
20
 
21
21
  ```javascript
22
22
  import React from 'react';
23
- import ReactDOM from 'react-dom';
23
+ import { createRoot } from 'react-dom/client';
24
24
  import * as Sentry from '@sentry/react';
25
25
 
26
26
  Sentry.init({
@@ -30,12 +30,39 @@ Sentry.init({
30
30
 
31
31
  // ...
32
32
 
33
- ReactDOM.render(<App />, rootNode);
33
+ const container = document.getElementById(“app”);
34
+ const root = createRoot(container);
35
+ root.render(<App />);
34
36
 
35
- // Can also use with React Concurrent Mode
36
- // ReactDOM.createRoot(rootNode).render(<App />);
37
+ // also works with hydrateRoot
38
+ // const domNode = document.getElementById('root');
39
+ // const root = hydrateRoot(domNode, reactNode);
40
+ // root.render(<App />);
37
41
  ```
38
42
 
43
+ ### React 19
44
+
45
+ Starting with React 19, the `createRoot` and `hydrateRoot` methods expose error hooks that can be used to capture errors
46
+ automatically. Use the `Sentry.reactErrorHandler` function to capture errors in the error hooks you are interested in.
47
+
48
+ ```js
49
+ const container = document.getElementById(“app”);
50
+ const root = createRoot(container, {
51
+ // Callback called when an error is thrown and not caught by an Error Boundary.
52
+ onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
53
+ console.warn('Uncaught error', error, errorInfo.componentStack);
54
+ }),
55
+ // Callback called when React catches an error in an Error Boundary.
56
+ onCaughtError: Sentry.reactErrorHandler(),
57
+ // Callback called when React automatically recovers from errors.
58
+ onRecoverableError: Sentry.reactErrorHandler(),
59
+ });
60
+ root.render(<App />);
61
+ ```
62
+
63
+ If you want more finely grained control over error handling, we recommend only adding the `onUncaughtError` and
64
+ `onRecoverableError` hooks and using an `ErrorBoundary` component instead of the `onCaughtError` hook.
65
+
39
66
  ### ErrorBoundary
40
67
 
41
68
  `@sentry/react` exports an ErrorBoundary component that will automatically send Javascript errors from inside a
package/cjs/error.js ADDED
@@ -0,0 +1,112 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+
3
+ const browser = require('@sentry/browser');
4
+ const utils = require('@sentry/utils');
5
+ const React = require('react');
6
+
7
+ /**
8
+ * See if React major version is 17+ by parsing version string.
9
+ */
10
+ function isAtLeastReact17(reactVersion) {
11
+ const reactMajor = reactVersion.match(/^([^.]+)/);
12
+ return reactMajor !== null && parseInt(reactMajor[0]) >= 17;
13
+ }
14
+
15
+ /**
16
+ * Recurse through `error.cause` chain to set cause on an error.
17
+ */
18
+ function setCause(error, cause) {
19
+ const seenErrors = new WeakSet();
20
+
21
+ function recurse(error, cause) {
22
+ // If we've already seen the error, there is a recursive loop somewhere in the error's
23
+ // cause chain. Let's just bail out then to prevent a stack overflow.
24
+ if (seenErrors.has(error)) {
25
+ return;
26
+ }
27
+ if (error.cause) {
28
+ seenErrors.add(error);
29
+ return recurse(error.cause, cause);
30
+ }
31
+ error.cause = cause;
32
+ }
33
+
34
+ recurse(error, cause);
35
+ }
36
+
37
+ /**
38
+ * Captures an error that was thrown by a React ErrorBoundary or React root.
39
+ *
40
+ * @param error The error to capture.
41
+ * @param errorInfo The errorInfo provided by React.
42
+ * @param hint Optional additional data to attach to the Sentry event.
43
+ * @returns the id of the captured Sentry event.
44
+ */
45
+ function captureReactException(
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ error,
48
+ { componentStack },
49
+ hint,
50
+ ) {
51
+ // If on React version >= 17, create stack trace from componentStack param and links
52
+ // to to the original error using `error.cause` otherwise relies on error param for stacktrace.
53
+ // Linking errors requires the `LinkedErrors` integration be enabled.
54
+ // See: https://reactjs.org/blog/2020/08/10/react-v17-rc.html#native-component-stacks
55
+ //
56
+ // Although `componentDidCatch` is typed to accept an `Error` object, it can also be invoked
57
+ // with non-error objects. This is why we need to check if the error is an error-like object.
58
+ // See: https://github.com/getsentry/sentry-javascript/issues/6167
59
+ if (isAtLeastReact17(React.version) && utils.isError(error) && componentStack) {
60
+ const errorBoundaryError = new Error(error.message);
61
+ errorBoundaryError.name = `React ErrorBoundary ${error.name}`;
62
+ errorBoundaryError.stack = componentStack;
63
+
64
+ // Using the `LinkedErrors` integration to link the errors together.
65
+ setCause(error, errorBoundaryError);
66
+ }
67
+
68
+ return browser.captureException(error, {
69
+ ...hint,
70
+ captureContext: {
71
+ contexts: { react: { componentStack } },
72
+ },
73
+ });
74
+ }
75
+
76
+ /**
77
+ * Creates an error handler that can be used with the `onCaughtError`, `onUncaughtError`,
78
+ * and `onRecoverableError` options in `createRoot` and `hydrateRoot` React DOM methods.
79
+ *
80
+ * @param callback An optional callback that will be called after the error is captured.
81
+ * Use this to add custom handling for errors.
82
+ *
83
+ * @example
84
+ *
85
+ * ```JavaScript
86
+ * const root = createRoot(container, {
87
+ * onCaughtError: Sentry.reactErrorHandler(),
88
+ * onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
89
+ * console.warn('Caught error', error, errorInfo.componentStack);
90
+ * });
91
+ * });
92
+ * ```
93
+ */
94
+ function reactErrorHandler(
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ callback,
97
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
+ ) {
99
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
+ return (error, errorInfo) => {
101
+ const eventId = captureReactException(error, errorInfo);
102
+ if (callback) {
103
+ callback(error, errorInfo, eventId);
104
+ }
105
+ };
106
+ }
107
+
108
+ exports.captureReactException = captureReactException;
109
+ exports.isAtLeastReact17 = isAtLeastReact17;
110
+ exports.reactErrorHandler = reactErrorHandler;
111
+ exports.setCause = setCause;
112
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.js","sources":["../../src/error.ts"],"sourcesContent":["import { captureException } from '@sentry/browser';\nimport type { EventHint } from '@sentry/types';\nimport { isError } from '@sentry/utils';\nimport { version } from 'react';\nimport type { ErrorInfo } from 'react';\n\n/**\n * See if React major version is 17+ by parsing version string.\n */\nexport function isAtLeastReact17(reactVersion: string): boolean {\n const reactMajor = reactVersion.match(/^([^.]+)/);\n return reactMajor !== null && parseInt(reactMajor[0]) >= 17;\n}\n\n/**\n * Recurse through `error.cause` chain to set cause on an error.\n */\nexport function setCause(error: Error & { cause?: Error }, cause: Error): void {\n const seenErrors = new WeakSet();\n\n function recurse(error: Error & { cause?: Error }, cause: Error): void {\n // If we've already seen the error, there is a recursive loop somewhere in the error's\n // cause chain. Let's just bail out then to prevent a stack overflow.\n if (seenErrors.has(error)) {\n return;\n }\n if (error.cause) {\n seenErrors.add(error);\n return recurse(error.cause, cause);\n }\n error.cause = cause;\n }\n\n recurse(error, cause);\n}\n\n/**\n * Captures an error that was thrown by a React ErrorBoundary or React root.\n *\n * @param error The error to capture.\n * @param errorInfo The errorInfo provided by React.\n * @param hint Optional additional data to attach to the Sentry event.\n * @returns the id of the captured Sentry event.\n */\nexport function captureReactException(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error: any,\n { componentStack }: ErrorInfo,\n hint?: EventHint,\n): string {\n // If on React version >= 17, create stack trace from componentStack param and links\n // to to the original error using `error.cause` otherwise relies on error param for stacktrace.\n // Linking errors requires the `LinkedErrors` integration be enabled.\n // See: https://reactjs.org/blog/2020/08/10/react-v17-rc.html#native-component-stacks\n //\n // Although `componentDidCatch` is typed to accept an `Error` object, it can also be invoked\n // with non-error objects. This is why we need to check if the error is an error-like object.\n // See: https://github.com/getsentry/sentry-javascript/issues/6167\n if (isAtLeastReact17(version) && isError(error) && componentStack) {\n const errorBoundaryError = new Error(error.message);\n errorBoundaryError.name = `React ErrorBoundary ${error.name}`;\n errorBoundaryError.stack = componentStack;\n\n // Using the `LinkedErrors` integration to link the errors together.\n setCause(error, errorBoundaryError);\n }\n\n return captureException(error, {\n ...hint,\n captureContext: {\n contexts: { react: { componentStack } },\n },\n });\n}\n\n/**\n * Creates an error handler that can be used with the `onCaughtError`, `onUncaughtError`,\n * and `onRecoverableError` options in `createRoot` and `hydrateRoot` React DOM methods.\n *\n * @param callback An optional callback that will be called after the error is captured.\n * Use this to add custom handling for errors.\n *\n * @example\n *\n * ```JavaScript\n * const root = createRoot(container, {\n * onCaughtError: Sentry.reactErrorHandler(),\n * onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {\n * console.warn('Caught error', error, errorInfo.componentStack);\n * });\n * });\n * ```\n */\nexport function reactErrorHandler(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n callback?: (error: any, errorInfo: ErrorInfo, eventId: string) => void,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): (error: any, errorInfo: ErrorInfo) => void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (error: any, errorInfo: ErrorInfo) => {\n const eventId = captureReactException(error, errorInfo);\n if (callback) {\n callback(error, errorInfo, eventId);\n }\n };\n}\n"],"names":["version","isError","captureException"],"mappings":";;;;;;AAMA;AACA;AACA;AACO,SAAS,gBAAgB,CAAC,YAAY,EAAmB;AAChE,EAAE,MAAM,aAAa,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;AACnD,EAAE,OAAO,UAAA,KAAe,IAAA,IAAQ,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA,IAAK,EAAE,CAAA;AAC7D,CAAA;AACA;AACA;AACA;AACA;AACO,SAAS,QAAQ,CAAC,KAAK,EAA6B,KAAK,EAAe;AAC/E,EAAE,MAAM,UAAW,GAAE,IAAI,OAAO,EAAE,CAAA;AAClC;AACA,EAAE,SAAS,OAAO,CAAC,KAAK,EAA6B,KAAK,EAAe;AACzE;AACA;AACA,IAAI,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC/B,MAAM,OAAM;AACZ,KAAI;AACJ,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE;AACrB,MAAM,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AAC3B,MAAM,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AACxC,KAAI;AACJ,IAAI,KAAK,CAAC,KAAM,GAAE,KAAK,CAAA;AACvB,GAAE;AACF;AACA,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AACvB,CAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB;AACrC;AACA,EAAE,KAAK;AACP,EAAE,EAAE,gBAAgB;AACpB,EAAE,IAAI;AACN,EAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,IAAI,gBAAgB,CAACA,aAAO,CAAA,IAAKC,aAAO,CAAC,KAAK,CAAE,IAAG,cAAc,EAAE;AACrE,IAAI,MAAM,qBAAqB,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;AACvD,IAAI,kBAAkB,CAAC,IAAA,GAAO,CAAC,oBAAoB,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA,CAAA;AACA,IAAA,kBAAA,CAAA,KAAA,GAAA,cAAA,CAAA;AACA;AACA;AACA,IAAA,QAAA,CAAA,KAAA,EAAA,kBAAA,CAAA,CAAA;AACA,GAAA;AACA;AACA,EAAA,OAAAC,wBAAA,CAAA,KAAA,EAAA;AACA,IAAA,GAAA,IAAA;AACA,IAAA,cAAA,EAAA;AACA,MAAA,QAAA,EAAA,EAAA,KAAA,EAAA,EAAA,cAAA,EAAA,EAAA;AACA,KAAA;AACA,GAAA,CAAA,CAAA;AACA,CAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAA,iBAAA;AACA;AACA,EAAA,QAAA;AACA;AACA,EAAA;AACA;AACA,EAAA,OAAA,CAAA,KAAA,EAAA,SAAA,KAAA;AACA,IAAA,MAAA,OAAA,GAAA,qBAAA,CAAA,KAAA,EAAA,SAAA,CAAA,CAAA;AACA,IAAA,IAAA,QAAA,EAAA;AACA,MAAA,QAAA,CAAA,KAAA,EAAA,SAAA,EAAA,OAAA,CAAA,CAAA;AACA,KAAA;AACA,GAAA,CAAA;AACA;;;;;;;"}
@@ -6,6 +6,7 @@ const utils = require('@sentry/utils');
6
6
  const hoistNonReactStatics = require('hoist-non-react-statics');
7
7
  const React = require('react');
8
8
  const debugBuild = require('./debug-build.js');
9
+ const error = require('./error.js');
9
10
 
10
11
  const _interopDefault = e => e && e.__esModule ? e.default : e;
11
12
 
@@ -24,11 +25,6 @@ function _interopNamespace(e) {
24
25
  const hoistNonReactStatics__default = /*#__PURE__*/_interopDefault(hoistNonReactStatics);
25
26
  const React__namespace = /*#__PURE__*/_interopNamespace(React);
26
27
 
27
- function isAtLeastReact17(version) {
28
- const major = version.match(/^([^.]+)/);
29
- return major !== null && parseInt(major[0]) >= 17;
30
- }
31
-
32
28
  const UNKNOWN_COMPONENT = 'unknown';
33
29
 
34
30
  const INITIAL_STATE = {
@@ -37,25 +33,6 @@ const INITIAL_STATE = {
37
33
  eventId: null,
38
34
  };
39
35
 
40
- function setCause(error, cause) {
41
- const seenErrors = new WeakMap();
42
-
43
- function recurse(error, cause) {
44
- // If we've already seen the error, there is a recursive loop somewhere in the error's
45
- // cause chain. Let's just bail out then to prevent a stack overflow.
46
- if (seenErrors.has(error)) {
47
- return;
48
- }
49
- if (error.cause) {
50
- seenErrors.set(error, true);
51
- return recurse(error.cause, cause);
52
- }
53
- error.cause = cause;
54
- }
55
-
56
- recurse(error, cause);
57
- }
58
-
59
36
  /**
60
37
  * A ErrorBoundary component that logs errors to Sentry.
61
38
  * NOTE: If you are a Sentry user, and you are seeing this stack frame, it means the
@@ -80,41 +57,21 @@ class ErrorBoundary extends React__namespace.Component {
80
57
  }
81
58
  }
82
59
 
83
- componentDidCatch(error, { componentStack }) {
60
+ componentDidCatch(error$1, errorInfo) {
61
+ const { componentStack } = errorInfo;
62
+ // TODO(v9): Remove this check and type `componentStack` to be React.ErrorInfo['componentStack'].
63
+ const passedInComponentStack = componentStack == null ? undefined : componentStack;
64
+
84
65
  const { beforeCapture, onError, showDialog, dialogOptions } = this.props;
85
66
  browser.withScope(scope => {
86
- // If on React version >= 17, create stack trace from componentStack param and links
87
- // to to the original error using `error.cause` otherwise relies on error param for stacktrace.
88
- // Linking errors requires the `LinkedErrors` integration be enabled.
89
- // See: https://reactjs.org/blog/2020/08/10/react-v17-rc.html#native-component-stacks
90
- //
91
- // Although `componentDidCatch` is typed to accept an `Error` object, it can also be invoked
92
- // with non-error objects. This is why we need to check if the error is an error-like object.
93
- // See: https://github.com/getsentry/sentry-javascript/issues/6167
94
- if (isAtLeastReact17(React__namespace.version) && utils.isError(error)) {
95
- const errorBoundaryError = new Error(error.message);
96
- errorBoundaryError.name = `React ErrorBoundary ${error.name}`;
97
- errorBoundaryError.stack = componentStack;
98
-
99
- // Using the `LinkedErrors` integration to link the errors together.
100
- setCause(error, errorBoundaryError);
101
- }
102
-
103
67
  if (beforeCapture) {
104
- beforeCapture(scope, error, componentStack);
68
+ beforeCapture(scope, error$1, passedInComponentStack);
105
69
  }
106
70
 
107
- const eventId = browser.captureException(error, {
108
- captureContext: {
109
- contexts: { react: { componentStack } },
110
- },
111
- // If users provide a fallback component we can assume they are handling the error.
112
- // Therefore, we set the mechanism depending on the presence of the fallback prop.
113
- mechanism: { handled: !!this.props.fallback },
114
- });
71
+ const eventId = error.captureReactException(error$1, errorInfo, { mechanism: { handled: !!this.props.fallback } });
115
72
 
116
73
  if (onError) {
117
- onError(error, componentStack, eventId);
74
+ onError(error$1, passedInComponentStack, eventId);
118
75
  }
119
76
  if (showDialog) {
120
77
  this._lastEventId = eventId;
@@ -125,7 +82,7 @@ class ErrorBoundary extends React__namespace.Component {
125
82
 
126
83
  // componentDidCatch is used over getDerivedStateFromError
127
84
  // so that componentStack is accessible through state.
128
- this.setState({ error, componentStack, eventId });
85
+ this.setState({ error: error$1, componentStack, eventId });
129
86
  });
130
87
  }
131
88
 
@@ -194,7 +151,6 @@ function withErrorBoundary(
194
151
  WrappedComponent,
195
152
  errorBoundaryOptions,
196
153
  ) {
197
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
198
154
  const componentDisplayName = WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;
199
155
 
200
156
  const Wrapped = (props) => (
@@ -203,7 +159,6 @@ function withErrorBoundary(
203
159
  })
204
160
  );
205
161
 
206
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
207
162
  Wrapped.displayName = `errorBoundary(${componentDisplayName})`;
208
163
 
209
164
  // Copy over static methods from Wrapped component to Profiler HOC
@@ -214,6 +169,5 @@ function withErrorBoundary(
214
169
 
215
170
  exports.ErrorBoundary = ErrorBoundary;
216
171
  exports.UNKNOWN_COMPONENT = UNKNOWN_COMPONENT;
217
- exports.isAtLeastReact17 = isAtLeastReact17;
218
172
  exports.withErrorBoundary = withErrorBoundary;
219
173
  //# sourceMappingURL=errorboundary.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorboundary.js","sources":["../../src/errorboundary.tsx"],"sourcesContent":["import type { ReportDialogOptions } from '@sentry/browser';\nimport { captureException, getClient, showReportDialog, withScope } from '@sentry/browser';\nimport type { Scope } from '@sentry/types';\nimport { isError, logger } from '@sentry/utils';\nimport hoistNonReactStatics from 'hoist-non-react-statics';\nimport * as React from 'react';\n\nimport { DEBUG_BUILD } from './debug-build';\n\nexport function isAtLeastReact17(version: string): boolean {\n const major = version.match(/^([^.]+)/);\n return major !== null && parseInt(major[0]) >= 17;\n}\n\nexport const UNKNOWN_COMPONENT = 'unknown';\n\nexport type FallbackRender = (errorData: {\n error: unknown;\n componentStack: string;\n eventId: string;\n resetError(): void;\n}) => React.ReactElement;\n\nexport type ErrorBoundaryProps = {\n children?: React.ReactNode | (() => React.ReactNode);\n /** If a Sentry report dialog should be rendered on error */\n showDialog?: boolean | undefined;\n /**\n * Options to be passed into the Sentry report dialog.\n * No-op if {@link showDialog} is false.\n */\n dialogOptions?: ReportDialogOptions | undefined;\n /**\n * A fallback component that gets rendered when the error boundary encounters an error.\n *\n * Can either provide a React Component, or a function that returns React Component as\n * a valid fallback prop. If a function is provided, the function will be called with\n * the error, the component stack, and an function that resets the error boundary on error.\n *\n */\n fallback?: React.ReactElement | FallbackRender | undefined;\n /** Called when the error boundary encounters an error */\n onError?: ((error: unknown, componentStack: string, eventId: string) => void) | undefined;\n /** Called on componentDidMount() */\n onMount?: (() => void) | undefined;\n /** Called if resetError() is called from the fallback render props function */\n onReset?: ((error: unknown, componentStack: string | null, eventId: string | null) => void) | undefined;\n /** Called on componentWillUnmount() */\n onUnmount?: ((error: unknown, componentStack: string | null, eventId: string | null) => void) | undefined;\n /** Called before the error is captured by Sentry, allows for you to add tags or context using the scope */\n beforeCapture?: ((scope: Scope, error: unknown, componentStack: string | undefined) => void) | undefined;\n};\n\ntype ErrorBoundaryState =\n | {\n componentStack: null;\n error: null;\n eventId: null;\n }\n | {\n componentStack: React.ErrorInfo['componentStack'];\n error: unknown;\n eventId: string;\n };\n\nconst INITIAL_STATE = {\n componentStack: null,\n error: null,\n eventId: null,\n};\n\nfunction setCause(error: Error & { cause?: Error }, cause: Error): void {\n const seenErrors = new WeakMap<Error, boolean>();\n\n function recurse(error: Error & { cause?: Error }, cause: Error): void {\n // If we've already seen the error, there is a recursive loop somewhere in the error's\n // cause chain. Let's just bail out then to prevent a stack overflow.\n if (seenErrors.has(error)) {\n return;\n }\n if (error.cause) {\n seenErrors.set(error, true);\n return recurse(error.cause, cause);\n }\n error.cause = cause;\n }\n\n recurse(error, cause);\n}\n\n/**\n * A ErrorBoundary component that logs errors to Sentry.\n * NOTE: If you are a Sentry user, and you are seeing this stack frame, it means the\n * Sentry React SDK ErrorBoundary caught an error invoking your application code. This\n * is expected behavior and NOT indicative of a bug with the Sentry React SDK.\n */\nclass ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n public state: ErrorBoundaryState;\n\n private readonly _openFallbackReportDialog: boolean;\n\n private _lastEventId?: string;\n\n public constructor(props: ErrorBoundaryProps) {\n super(props);\n\n this.state = INITIAL_STATE;\n this._openFallbackReportDialog = true;\n\n const client = getClient();\n if (client && props.showDialog) {\n this._openFallbackReportDialog = false;\n client.on('afterSendEvent', event => {\n if (!event.type && this._lastEventId && event.event_id === this._lastEventId) {\n showReportDialog({ ...props.dialogOptions, eventId: this._lastEventId });\n }\n });\n }\n }\n\n public componentDidCatch(error: unknown, { componentStack }: React.ErrorInfo): void {\n const { beforeCapture, onError, showDialog, dialogOptions } = this.props;\n withScope(scope => {\n // If on React version >= 17, create stack trace from componentStack param and links\n // to to the original error using `error.cause` otherwise relies on error param for stacktrace.\n // Linking errors requires the `LinkedErrors` integration be enabled.\n // See: https://reactjs.org/blog/2020/08/10/react-v17-rc.html#native-component-stacks\n //\n // Although `componentDidCatch` is typed to accept an `Error` object, it can also be invoked\n // with non-error objects. This is why we need to check if the error is an error-like object.\n // See: https://github.com/getsentry/sentry-javascript/issues/6167\n if (isAtLeastReact17(React.version) && isError(error)) {\n const errorBoundaryError = new Error(error.message);\n errorBoundaryError.name = `React ErrorBoundary ${error.name}`;\n errorBoundaryError.stack = componentStack;\n\n // Using the `LinkedErrors` integration to link the errors together.\n setCause(error, errorBoundaryError);\n }\n\n if (beforeCapture) {\n beforeCapture(scope, error, componentStack);\n }\n\n const eventId = captureException(error, {\n captureContext: {\n contexts: { react: { componentStack } },\n },\n // If users provide a fallback component we can assume they are handling the error.\n // Therefore, we set the mechanism depending on the presence of the fallback prop.\n mechanism: { handled: !!this.props.fallback },\n });\n\n if (onError) {\n onError(error, componentStack, eventId);\n }\n if (showDialog) {\n this._lastEventId = eventId;\n if (this._openFallbackReportDialog) {\n showReportDialog({ ...dialogOptions, eventId });\n }\n }\n\n // componentDidCatch is used over getDerivedStateFromError\n // so that componentStack is accessible through state.\n this.setState({ error, componentStack, eventId });\n });\n }\n\n public componentDidMount(): void {\n const { onMount } = this.props;\n if (onMount) {\n onMount();\n }\n }\n\n public componentWillUnmount(): void {\n const { error, componentStack, eventId } = this.state;\n const { onUnmount } = this.props;\n if (onUnmount) {\n onUnmount(error, componentStack, eventId);\n }\n }\n\n public resetErrorBoundary: () => void = () => {\n const { onReset } = this.props;\n const { error, componentStack, eventId } = this.state;\n if (onReset) {\n onReset(error, componentStack, eventId);\n }\n this.setState(INITIAL_STATE);\n };\n\n public render(): React.ReactNode {\n const { fallback, children } = this.props;\n const state = this.state;\n\n if (state.error) {\n let element: React.ReactElement | undefined = undefined;\n if (typeof fallback === 'function') {\n element = React.createElement(fallback, {\n error: state.error,\n componentStack: state.componentStack as string,\n resetError: this.resetErrorBoundary,\n eventId: state.eventId as string,\n });\n } else {\n element = fallback;\n }\n\n if (React.isValidElement(element)) {\n return element;\n }\n\n if (fallback) {\n DEBUG_BUILD && logger.warn('fallback did not produce a valid ReactElement');\n }\n\n // Fail gracefully if no fallback provided or is not valid\n return null;\n }\n\n if (typeof children === 'function') {\n return (children as () => React.ReactNode)();\n }\n return children;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction withErrorBoundary<P extends Record<string, any>>(\n WrappedComponent: React.ComponentType<P>,\n errorBoundaryOptions: ErrorBoundaryProps,\n): React.FC<P> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const componentDisplayName = WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;\n\n const Wrapped: React.FC<P> = (props: P) => (\n <ErrorBoundary {...errorBoundaryOptions}>\n <WrappedComponent {...props} />\n </ErrorBoundary>\n );\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n Wrapped.displayName = `errorBoundary(${componentDisplayName})`;\n\n // Copy over static methods from Wrapped component to Profiler HOC\n // See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over\n hoistNonReactStatics(Wrapped, WrappedComponent);\n return Wrapped;\n}\n\nexport { ErrorBoundary, withErrorBoundary };\n"],"names":["React","getClient","showReportDialog","withScope","isError","captureException","DEBUG_BUILD","logger","_jsx","hoistNonReactStatics"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AASO,SAAS,gBAAgB,CAAC,OAAO,EAAmB;AAC3D,EAAE,MAAM,QAAQ,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;AACzC,EAAE,OAAO,KAAA,KAAU,IAAA,IAAQ,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA,IAAK,EAAE,CAAA;AACnD,CAAA;AACA;AACO,MAAM,iBAAkB,GAAE,UAAS;;AAmD1C,MAAM,gBAAgB;AACtB,EAAE,cAAc,EAAE,IAAI;AACtB,EAAE,KAAK,EAAE,IAAI;AACb,EAAE,OAAO,EAAE,IAAI;AACf,CAAC,CAAA;AACD;AACA,SAAS,QAAQ,CAAC,KAAK,EAA6B,KAAK,EAAe;AACxE,EAAE,MAAM,UAAW,GAAE,IAAI,OAAO,EAAkB,CAAA;AAClD;AACA,EAAE,SAAS,OAAO,CAAC,KAAK,EAA6B,KAAK,EAAe;AACzE;AACA;AACA,IAAI,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC/B,MAAM,OAAM;AACZ,KAAI;AACJ,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE;AACrB,MAAM,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;AACjC,MAAM,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AACxC,KAAI;AACJ,IAAI,KAAK,CAAC,KAAM,GAAE,KAAK,CAAA;AACvB,GAAE;AACF;AACA,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AACvB,CAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,aAAc,SAAQA,gBAAK,CAAC,SAAS,CAAyC;;AAOpF,GAAS,WAAW,CAAC,KAAK,EAAsB;AAChD,IAAI,KAAK,CAAC,KAAK,CAAC,CAAA,aAAA,CAAA,SAAA,CAAA,MAAA,CAAA,IAAA,CAAA,IAAA,CAAA,CAChB;AACA,IAAI,IAAI,CAAC,KAAM,GAAE,aAAa,CAAA;AAC9B,IAAI,IAAI,CAAC,yBAA0B,GAAE,IAAI,CAAA;AACzC;AACA,IAAI,MAAM,MAAA,GAASC,iBAAS,EAAE,CAAA;AAC9B,IAAI,IAAI,MAAA,IAAU,KAAK,CAAC,UAAU,EAAE;AACpC,MAAM,IAAI,CAAC,yBAA0B,GAAE,KAAK,CAAA;AAC5C,MAAM,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,SAAS;AAC3C,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAA,IAAQ,IAAI,CAAC,YAAa,IAAG,KAAK,CAAC,QAAA,KAAa,IAAI,CAAC,YAAY,EAAE;AACtF,UAAUC,wBAAgB,CAAC,EAAE,GAAG,KAAK,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,YAAA,EAAc,CAAC,CAAA;AAClF,SAAQ;AACR,OAAO,CAAC,CAAA;AACR,KAAI;AACJ,GAAE;AACF;AACA,GAAS,iBAAiB,CAAC,KAAK,EAAW,EAAE,cAAA,EAAgB,EAAyB;AACtF,IAAI,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,aAAc,EAAA,GAAI,IAAI,CAAC,KAAK,CAAA;AAC5E,IAAIC,iBAAS,CAAC,KAAA,IAAS;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,IAAI,gBAAgB,CAACH,gBAAK,CAAC,OAAO,CAAA,IAAKI,aAAO,CAAC,KAAK,CAAC,EAAE;AAC7D,QAAQ,MAAM,qBAAqB,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;AAC3D,QAAQ,kBAAkB,CAAC,IAAA,GAAO,CAAC,oBAAoB,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA,CAAA;AACA,QAAA,kBAAA,CAAA,KAAA,GAAA,cAAA,CAAA;AACA;AACA;AACA,QAAA,QAAA,CAAA,KAAA,EAAA,kBAAA,CAAA,CAAA;AACA,OAAA;AACA;AACA,MAAA,IAAA,aAAA,EAAA;AACA,QAAA,aAAA,CAAA,KAAA,EAAA,KAAA,EAAA,cAAA,CAAA,CAAA;AACA,OAAA;AACA;AACA,MAAA,MAAA,OAAA,GAAAC,wBAAA,CAAA,KAAA,EAAA;AACA,QAAA,cAAA,EAAA;AACA,UAAA,QAAA,EAAA,EAAA,KAAA,EAAA,EAAA,cAAA,EAAA,EAAA;AACA,SAAA;AACA;AACA;AACA,QAAA,SAAA,EAAA,EAAA,OAAA,EAAA,CAAA,CAAA,IAAA,CAAA,KAAA,CAAA,QAAA,EAAA;AACA,OAAA,CAAA,CAAA;AACA;AACA,MAAA,IAAA,OAAA,EAAA;AACA,QAAA,OAAA,CAAA,KAAA,EAAA,cAAA,EAAA,OAAA,CAAA,CAAA;AACA,OAAA;AACA,MAAA,IAAA,UAAA,EAAA;AACA,QAAA,IAAA,CAAA,YAAA,GAAA,OAAA,CAAA;AACA,QAAA,IAAA,IAAA,CAAA,yBAAA,EAAA;AACA,UAAAH,wBAAA,CAAA,EAAA,GAAA,aAAA,EAAA,OAAA,EAAA,CAAA,CAAA;AACA,SAAA;AACA,OAAA;AACA;AACA;AACA;AACA,MAAA,IAAA,CAAA,QAAA,CAAA,EAAA,KAAA,EAAA,cAAA,EAAA,OAAA,EAAA,CAAA,CAAA;AACA,KAAA,CAAA,CAAA;AACA,GAAA;AACA;AACA,GAAA,iBAAA,GAAA;AACA,IAAA,MAAA,EAAA,OAAA,EAAA,GAAA,IAAA,CAAA,KAAA,CAAA;AACA,IAAA,IAAA,OAAA,EAAA;AACA,MAAA,OAAA,EAAA,CAAA;AACA,KAAA;AACA,GAAA;AACA;AACA,GAAA,oBAAA,GAAA;AACA,IAAA,MAAA,EAAA,KAAA,EAAA,cAAA,EAAA,OAAA,EAAA,GAAA,IAAA,CAAA,KAAA,CAAA;AACA,IAAA,MAAA,EAAA,SAAA,EAAA,GAAA,IAAA,CAAA,KAAA,CAAA;AACA,IAAA,IAAA,SAAA,EAAA;AACA,MAAA,SAAA,CAAA,KAAA,EAAA,cAAA,EAAA,OAAA,CAAA,CAAA;AACA,KAAA;AACA,GAAA;AACA;AACA,GAAA,MAAA,GAAA,CAAA,IAAA,CAAA,kBAAA,GAAA,MAAA;AACA,IAAA,MAAA,EAAA,OAAA,EAAA,GAAA,IAAA,CAAA,KAAA,CAAA;AACA,IAAA,MAAA,EAAA,KAAA,EAAA,cAAA,EAAA,OAAA,EAAA,GAAA,IAAA,CAAA,KAAA,CAAA;AACA,IAAA,IAAA,OAAA,EAAA;AACA,MAAA,OAAA,CAAA,KAAA,EAAA,cAAA,EAAA,OAAA,CAAA,CAAA;AACA,KAAA;AACA,IAAA,IAAA,CAAA,QAAA,CAAA,aAAA,CAAA,CAAA;AACA,IAAA,CAAA;AACA;AACA,GAAA,MAAA,GAAA;AACA,IAAA,MAAA,EAAA,QAAA,EAAA,QAAA,EAAA,GAAA,IAAA,CAAA,KAAA,CAAA;AACA,IAAA,MAAA,KAAA,GAAA,IAAA,CAAA,KAAA,CAAA;AACA;AACA,IAAA,IAAA,KAAA,CAAA,KAAA,EAAA;AACA,MAAA,IAAA,OAAA,GAAA,SAAA,CAAA;AACA,MAAA,IAAA,OAAA,QAAA,KAAA,UAAA,EAAA;AACA,QAAA,OAAA,GAAAF,gBAAA,CAAA,aAAA,CAAA,QAAA,EAAA;AACA,UAAA,KAAA,EAAA,KAAA,CAAA,KAAA;AACA,UAAA,cAAA,EAAA,KAAA,CAAA,cAAA;AACA,UAAA,UAAA,EAAA,IAAA,CAAA,kBAAA;AACA,UAAA,OAAA,EAAA,KAAA,CAAA,OAAA;AACA,SAAA,CAAA,CAAA;AACA,OAAA,MAAA;AACA,QAAA,OAAA,GAAA,QAAA,CAAA;AACA,OAAA;AACA;AACA,MAAA,IAAAA,gBAAA,CAAA,cAAA,CAAA,OAAA,CAAA,EAAA;AACA,QAAA,OAAA,OAAA,CAAA;AACA,OAAA;AACA;AACA,MAAA,IAAA,QAAA,EAAA;AACA,QAAAM,sBAAA,IAAAC,YAAA,CAAA,IAAA,CAAA,+CAAA,CAAA,CAAA;AACA,OAAA;AACA;AACA;AACA,MAAA,OAAA,IAAA,CAAA;AACA,KAAA;AACA;AACA,IAAA,IAAA,OAAA,QAAA,KAAA,UAAA,EAAA;AACA,MAAA,OAAA,CAAA,QAAA,IAAA,CAAA;AACA,KAAA;AACA,IAAA,OAAA,QAAA,CAAA;AACA,GAAA;AACA,CAAA;AACA;AACA;AACA,SAAA,iBAAA;AACA,EAAA,gBAAA;AACA,EAAA,oBAAA;AACA,EAAA;AACA;AACA,EAAA,MAAA,oBAAA,GAAA,gBAAA,CAAA,WAAA,IAAA,gBAAA,CAAA,IAAA,IAAA,iBAAA,CAAA;AACA;AACA,EAAA,MAAA,OAAA,GAAA,CAAA,KAAA;AACA,IAAAC,cAAA,CAAA,aAAA,EAAA,EAAA,GAAA,oBAAA,EAAA,QAAA;AACA,MAAAA,cAAA,CAAA,gBAAA,EAAA,EAAA,GAAA,KAAA,EAAA,EAAA;AACA,KAAA,CAAA;AACA,GAAA,CAAA;AACA;AACA;AACA,EAAA,OAAA,CAAA,WAAA,GAAA,CAAA,cAAA,EAAA,oBAAA,CAAA,CAAA,CAAA,CAAA;AACA;AACA;AACA;AACA,EAAAC,6BAAA,CAAA,OAAA,EAAA,gBAAA,CAAA,CAAA;AACA,EAAA,OAAA,OAAA,CAAA;AACA;;;;;;;"}
1
+ {"version":3,"file":"errorboundary.js","sources":["../../src/errorboundary.tsx"],"sourcesContent":["import type { ReportDialogOptions } from '@sentry/browser';\nimport { getClient, showReportDialog, withScope } from '@sentry/browser';\nimport type { Scope } from '@sentry/types';\nimport { logger } from '@sentry/utils';\nimport hoistNonReactStatics from 'hoist-non-react-statics';\nimport * as React from 'react';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport { captureReactException } from './error';\n\nexport const UNKNOWN_COMPONENT = 'unknown';\n\nexport type FallbackRender = (errorData: {\n error: unknown;\n componentStack: string;\n eventId: string;\n resetError(): void;\n}) => React.ReactElement;\n\nexport type ErrorBoundaryProps = {\n children?: React.ReactNode | (() => React.ReactNode);\n /** If a Sentry report dialog should be rendered on error */\n showDialog?: boolean | undefined;\n /**\n * Options to be passed into the Sentry report dialog.\n * No-op if {@link showDialog} is false.\n */\n dialogOptions?: ReportDialogOptions | undefined;\n /**\n * A fallback component that gets rendered when the error boundary encounters an error.\n *\n * Can either provide a React Component, or a function that returns React Component as\n * a valid fallback prop. If a function is provided, the function will be called with\n * the error, the component stack, and an function that resets the error boundary on error.\n *\n */\n fallback?: React.ReactElement | FallbackRender | undefined;\n /** Called when the error boundary encounters an error */\n onError?: ((error: unknown, componentStack: string | undefined, eventId: string) => void) | undefined;\n /** Called on componentDidMount() */\n onMount?: (() => void) | undefined;\n /** Called if resetError() is called from the fallback render props function */\n onReset?: ((error: unknown, componentStack: string | null | undefined, eventId: string | null) => void) | undefined;\n /** Called on componentWillUnmount() */\n onUnmount?: ((error: unknown, componentStack: string | null | undefined, eventId: string | null) => void) | undefined;\n /** Called before the error is captured by Sentry, allows for you to add tags or context using the scope */\n beforeCapture?: ((scope: Scope, error: unknown, componentStack: string | undefined) => void) | undefined;\n};\n\ntype ErrorBoundaryState =\n | {\n componentStack: null;\n error: null;\n eventId: null;\n }\n | {\n componentStack: React.ErrorInfo['componentStack'];\n error: unknown;\n eventId: string;\n };\n\nconst INITIAL_STATE = {\n componentStack: null,\n error: null,\n eventId: null,\n};\n\n/**\n * A ErrorBoundary component that logs errors to Sentry.\n * NOTE: If you are a Sentry user, and you are seeing this stack frame, it means the\n * Sentry React SDK ErrorBoundary caught an error invoking your application code. This\n * is expected behavior and NOT indicative of a bug with the Sentry React SDK.\n */\nclass ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n public state: ErrorBoundaryState;\n\n private readonly _openFallbackReportDialog: boolean;\n\n private _lastEventId?: string;\n\n public constructor(props: ErrorBoundaryProps) {\n super(props);\n\n this.state = INITIAL_STATE;\n this._openFallbackReportDialog = true;\n\n const client = getClient();\n if (client && props.showDialog) {\n this._openFallbackReportDialog = false;\n client.on('afterSendEvent', event => {\n if (!event.type && this._lastEventId && event.event_id === this._lastEventId) {\n showReportDialog({ ...props.dialogOptions, eventId: this._lastEventId });\n }\n });\n }\n }\n\n public componentDidCatch(error: unknown, errorInfo: React.ErrorInfo): void {\n const { componentStack } = errorInfo;\n // TODO(v9): Remove this check and type `componentStack` to be React.ErrorInfo['componentStack'].\n const passedInComponentStack: string | undefined = componentStack == null ? undefined : componentStack;\n\n const { beforeCapture, onError, showDialog, dialogOptions } = this.props;\n withScope(scope => {\n if (beforeCapture) {\n beforeCapture(scope, error, passedInComponentStack);\n }\n\n const eventId = captureReactException(error, errorInfo, { mechanism: { handled: !!this.props.fallback } });\n\n if (onError) {\n onError(error, passedInComponentStack, eventId);\n }\n if (showDialog) {\n this._lastEventId = eventId;\n if (this._openFallbackReportDialog) {\n showReportDialog({ ...dialogOptions, eventId });\n }\n }\n\n // componentDidCatch is used over getDerivedStateFromError\n // so that componentStack is accessible through state.\n this.setState({ error, componentStack, eventId });\n });\n }\n\n public componentDidMount(): void {\n const { onMount } = this.props;\n if (onMount) {\n onMount();\n }\n }\n\n public componentWillUnmount(): void {\n const { error, componentStack, eventId } = this.state;\n const { onUnmount } = this.props;\n if (onUnmount) {\n onUnmount(error, componentStack, eventId);\n }\n }\n\n public resetErrorBoundary: () => void = () => {\n const { onReset } = this.props;\n const { error, componentStack, eventId } = this.state;\n if (onReset) {\n onReset(error, componentStack, eventId);\n }\n this.setState(INITIAL_STATE);\n };\n\n public render(): React.ReactNode {\n const { fallback, children } = this.props;\n const state = this.state;\n\n if (state.error) {\n let element: React.ReactElement | undefined = undefined;\n if (typeof fallback === 'function') {\n element = React.createElement(fallback, {\n error: state.error,\n componentStack: state.componentStack as string,\n resetError: this.resetErrorBoundary,\n eventId: state.eventId as string,\n });\n } else {\n element = fallback;\n }\n\n if (React.isValidElement(element)) {\n return element;\n }\n\n if (fallback) {\n DEBUG_BUILD && logger.warn('fallback did not produce a valid ReactElement');\n }\n\n // Fail gracefully if no fallback provided or is not valid\n return null;\n }\n\n if (typeof children === 'function') {\n return (children as () => React.ReactNode)();\n }\n return children;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction withErrorBoundary<P extends Record<string, any>>(\n WrappedComponent: React.ComponentType<P>,\n errorBoundaryOptions: ErrorBoundaryProps,\n): React.FC<P> {\n const componentDisplayName = WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;\n\n const Wrapped: React.FC<P> = (props: P) => (\n <ErrorBoundary {...errorBoundaryOptions}>\n <WrappedComponent {...props} />\n </ErrorBoundary>\n );\n\n Wrapped.displayName = `errorBoundary(${componentDisplayName})`;\n\n // Copy over static methods from Wrapped component to Profiler HOC\n // See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over\n hoistNonReactStatics(Wrapped, WrappedComponent);\n return Wrapped;\n}\n\nexport { ErrorBoundary, withErrorBoundary };\n"],"names":["React","getClient","showReportDialog","error","withScope","captureReactException","DEBUG_BUILD","logger","_jsx","hoistNonReactStatics"],"mappings":"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"}
package/cjs/index.js CHANGED
@@ -2,6 +2,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
2
2
 
3
3
  const browser = require('@sentry/browser');
4
4
  const sdk = require('./sdk.js');
5
+ const error = require('./error.js');
5
6
  const profiler = require('./profiler.js');
6
7
  const errorboundary = require('./errorboundary.js');
7
8
  const redux = require('./redux.js');
@@ -12,6 +13,7 @@ const reactrouterv6 = require('./reactrouterv6.js');
12
13
 
13
14
 
14
15
  exports.init = sdk.init;
16
+ exports.reactErrorHandler = error.reactErrorHandler;
15
17
  exports.Profiler = profiler.Profiler;
16
18
  exports.useProfiler = profiler.useProfiler;
17
19
  exports.withProfiler = profiler.withProfiler;
package/cjs/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/esm/error.js ADDED
@@ -0,0 +1,107 @@
1
+ import { captureException } from '@sentry/browser';
2
+ import { isError } from '@sentry/utils';
3
+ import { version } from 'react';
4
+
5
+ /**
6
+ * See if React major version is 17+ by parsing version string.
7
+ */
8
+ function isAtLeastReact17(reactVersion) {
9
+ const reactMajor = reactVersion.match(/^([^.]+)/);
10
+ return reactMajor !== null && parseInt(reactMajor[0]) >= 17;
11
+ }
12
+
13
+ /**
14
+ * Recurse through `error.cause` chain to set cause on an error.
15
+ */
16
+ function setCause(error, cause) {
17
+ const seenErrors = new WeakSet();
18
+
19
+ function recurse(error, cause) {
20
+ // If we've already seen the error, there is a recursive loop somewhere in the error's
21
+ // cause chain. Let's just bail out then to prevent a stack overflow.
22
+ if (seenErrors.has(error)) {
23
+ return;
24
+ }
25
+ if (error.cause) {
26
+ seenErrors.add(error);
27
+ return recurse(error.cause, cause);
28
+ }
29
+ error.cause = cause;
30
+ }
31
+
32
+ recurse(error, cause);
33
+ }
34
+
35
+ /**
36
+ * Captures an error that was thrown by a React ErrorBoundary or React root.
37
+ *
38
+ * @param error The error to capture.
39
+ * @param errorInfo The errorInfo provided by React.
40
+ * @param hint Optional additional data to attach to the Sentry event.
41
+ * @returns the id of the captured Sentry event.
42
+ */
43
+ function captureReactException(
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ error,
46
+ { componentStack },
47
+ hint,
48
+ ) {
49
+ // If on React version >= 17, create stack trace from componentStack param and links
50
+ // to to the original error using `error.cause` otherwise relies on error param for stacktrace.
51
+ // Linking errors requires the `LinkedErrors` integration be enabled.
52
+ // See: https://reactjs.org/blog/2020/08/10/react-v17-rc.html#native-component-stacks
53
+ //
54
+ // Although `componentDidCatch` is typed to accept an `Error` object, it can also be invoked
55
+ // with non-error objects. This is why we need to check if the error is an error-like object.
56
+ // See: https://github.com/getsentry/sentry-javascript/issues/6167
57
+ if (isAtLeastReact17(version) && isError(error) && componentStack) {
58
+ const errorBoundaryError = new Error(error.message);
59
+ errorBoundaryError.name = `React ErrorBoundary ${error.name}`;
60
+ errorBoundaryError.stack = componentStack;
61
+
62
+ // Using the `LinkedErrors` integration to link the errors together.
63
+ setCause(error, errorBoundaryError);
64
+ }
65
+
66
+ return captureException(error, {
67
+ ...hint,
68
+ captureContext: {
69
+ contexts: { react: { componentStack } },
70
+ },
71
+ });
72
+ }
73
+
74
+ /**
75
+ * Creates an error handler that can be used with the `onCaughtError`, `onUncaughtError`,
76
+ * and `onRecoverableError` options in `createRoot` and `hydrateRoot` React DOM methods.
77
+ *
78
+ * @param callback An optional callback that will be called after the error is captured.
79
+ * Use this to add custom handling for errors.
80
+ *
81
+ * @example
82
+ *
83
+ * ```JavaScript
84
+ * const root = createRoot(container, {
85
+ * onCaughtError: Sentry.reactErrorHandler(),
86
+ * onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
87
+ * console.warn('Caught error', error, errorInfo.componentStack);
88
+ * });
89
+ * });
90
+ * ```
91
+ */
92
+ function reactErrorHandler(
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ callback,
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ ) {
97
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
+ return (error, errorInfo) => {
99
+ const eventId = captureReactException(error, errorInfo);
100
+ if (callback) {
101
+ callback(error, errorInfo, eventId);
102
+ }
103
+ };
104
+ }
105
+
106
+ export { captureReactException, isAtLeastReact17, reactErrorHandler, setCause };
107
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.js","sources":["../../src/error.ts"],"sourcesContent":["import { captureException } from '@sentry/browser';\nimport type { EventHint } from '@sentry/types';\nimport { isError } from '@sentry/utils';\nimport { version } from 'react';\nimport type { ErrorInfo } from 'react';\n\n/**\n * See if React major version is 17+ by parsing version string.\n */\nexport function isAtLeastReact17(reactVersion: string): boolean {\n const reactMajor = reactVersion.match(/^([^.]+)/);\n return reactMajor !== null && parseInt(reactMajor[0]) >= 17;\n}\n\n/**\n * Recurse through `error.cause` chain to set cause on an error.\n */\nexport function setCause(error: Error & { cause?: Error }, cause: Error): void {\n const seenErrors = new WeakSet();\n\n function recurse(error: Error & { cause?: Error }, cause: Error): void {\n // If we've already seen the error, there is a recursive loop somewhere in the error's\n // cause chain. Let's just bail out then to prevent a stack overflow.\n if (seenErrors.has(error)) {\n return;\n }\n if (error.cause) {\n seenErrors.add(error);\n return recurse(error.cause, cause);\n }\n error.cause = cause;\n }\n\n recurse(error, cause);\n}\n\n/**\n * Captures an error that was thrown by a React ErrorBoundary or React root.\n *\n * @param error The error to capture.\n * @param errorInfo The errorInfo provided by React.\n * @param hint Optional additional data to attach to the Sentry event.\n * @returns the id of the captured Sentry event.\n */\nexport function captureReactException(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error: any,\n { componentStack }: ErrorInfo,\n hint?: EventHint,\n): string {\n // If on React version >= 17, create stack trace from componentStack param and links\n // to to the original error using `error.cause` otherwise relies on error param for stacktrace.\n // Linking errors requires the `LinkedErrors` integration be enabled.\n // See: https://reactjs.org/blog/2020/08/10/react-v17-rc.html#native-component-stacks\n //\n // Although `componentDidCatch` is typed to accept an `Error` object, it can also be invoked\n // with non-error objects. This is why we need to check if the error is an error-like object.\n // See: https://github.com/getsentry/sentry-javascript/issues/6167\n if (isAtLeastReact17(version) && isError(error) && componentStack) {\n const errorBoundaryError = new Error(error.message);\n errorBoundaryError.name = `React ErrorBoundary ${error.name}`;\n errorBoundaryError.stack = componentStack;\n\n // Using the `LinkedErrors` integration to link the errors together.\n setCause(error, errorBoundaryError);\n }\n\n return captureException(error, {\n ...hint,\n captureContext: {\n contexts: { react: { componentStack } },\n },\n });\n}\n\n/**\n * Creates an error handler that can be used with the `onCaughtError`, `onUncaughtError`,\n * and `onRecoverableError` options in `createRoot` and `hydrateRoot` React DOM methods.\n *\n * @param callback An optional callback that will be called after the error is captured.\n * Use this to add custom handling for errors.\n *\n * @example\n *\n * ```JavaScript\n * const root = createRoot(container, {\n * onCaughtError: Sentry.reactErrorHandler(),\n * onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {\n * console.warn('Caught error', error, errorInfo.componentStack);\n * });\n * });\n * ```\n */\nexport function reactErrorHandler(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n callback?: (error: any, errorInfo: ErrorInfo, eventId: string) => void,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): (error: any, errorInfo: ErrorInfo) => void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (error: any, errorInfo: ErrorInfo) => {\n const eventId = captureReactException(error, errorInfo);\n if (callback) {\n callback(error, errorInfo, eventId);\n }\n };\n}\n"],"names":[],"mappings":";;;;AAMA;AACA;AACA;AACO,SAAS,gBAAgB,CAAC,YAAY,EAAmB;AAChE,EAAE,MAAM,aAAa,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;AACnD,EAAE,OAAO,UAAA,KAAe,IAAA,IAAQ,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA,IAAK,EAAE,CAAA;AAC7D,CAAA;AACA;AACA;AACA;AACA;AACO,SAAS,QAAQ,CAAC,KAAK,EAA6B,KAAK,EAAe;AAC/E,EAAE,MAAM,UAAW,GAAE,IAAI,OAAO,EAAE,CAAA;AAClC;AACA,EAAE,SAAS,OAAO,CAAC,KAAK,EAA6B,KAAK,EAAe;AACzE;AACA;AACA,IAAI,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC/B,MAAM,OAAM;AACZ,KAAI;AACJ,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE;AACrB,MAAM,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AAC3B,MAAM,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AACxC,KAAI;AACJ,IAAI,KAAK,CAAC,KAAM,GAAE,KAAK,CAAA;AACvB,GAAE;AACF;AACA,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AACvB,CAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB;AACrC;AACA,EAAE,KAAK;AACP,EAAE,EAAE,gBAAgB;AACpB,EAAE,IAAI;AACN,EAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,IAAI,gBAAgB,CAAC,OAAO,CAAA,IAAK,OAAO,CAAC,KAAK,CAAE,IAAG,cAAc,EAAE;AACrE,IAAI,MAAM,qBAAqB,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;AACvD,IAAI,kBAAkB,CAAC,IAAA,GAAO,CAAC,oBAAoB,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA,CAAA;AACA,IAAA,kBAAA,CAAA,KAAA,GAAA,cAAA,CAAA;AACA;AACA;AACA,IAAA,QAAA,CAAA,KAAA,EAAA,kBAAA,CAAA,CAAA;AACA,GAAA;AACA;AACA,EAAA,OAAA,gBAAA,CAAA,KAAA,EAAA;AACA,IAAA,GAAA,IAAA;AACA,IAAA,cAAA,EAAA;AACA,MAAA,QAAA,EAAA,EAAA,KAAA,EAAA,EAAA,cAAA,EAAA,EAAA;AACA,KAAA;AACA,GAAA,CAAA,CAAA;AACA,CAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAA,iBAAA;AACA;AACA,EAAA,QAAA;AACA;AACA,EAAA;AACA;AACA,EAAA,OAAA,CAAA,KAAA,EAAA,SAAA,KAAA;AACA,IAAA,MAAA,OAAA,GAAA,qBAAA,CAAA,KAAA,EAAA,SAAA,CAAA,CAAA;AACA,IAAA,IAAA,QAAA,EAAA;AACA,MAAA,QAAA,CAAA,KAAA,EAAA,SAAA,EAAA,OAAA,CAAA,CAAA;AACA,KAAA;AACA,GAAA,CAAA;AACA;;;;"}
@@ -1,14 +1,10 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { getClient, showReportDialog, withScope, captureException } from '@sentry/browser';
3
- import { isError, logger } from '@sentry/utils';
2
+ import { getClient, showReportDialog, withScope } from '@sentry/browser';
3
+ import { logger } from '@sentry/utils';
4
4
  import hoistNonReactStatics from 'hoist-non-react-statics';
5
5
  import * as React from 'react';
6
6
  import { DEBUG_BUILD } from './debug-build.js';
7
-
8
- function isAtLeastReact17(version) {
9
- const major = version.match(/^([^.]+)/);
10
- return major !== null && parseInt(major[0]) >= 17;
11
- }
7
+ import { captureReactException } from './error.js';
12
8
 
13
9
  const UNKNOWN_COMPONENT = 'unknown';
14
10
 
@@ -18,25 +14,6 @@ const INITIAL_STATE = {
18
14
  eventId: null,
19
15
  };
20
16
 
21
- function setCause(error, cause) {
22
- const seenErrors = new WeakMap();
23
-
24
- function recurse(error, cause) {
25
- // If we've already seen the error, there is a recursive loop somewhere in the error's
26
- // cause chain. Let's just bail out then to prevent a stack overflow.
27
- if (seenErrors.has(error)) {
28
- return;
29
- }
30
- if (error.cause) {
31
- seenErrors.set(error, true);
32
- return recurse(error.cause, cause);
33
- }
34
- error.cause = cause;
35
- }
36
-
37
- recurse(error, cause);
38
- }
39
-
40
17
  /**
41
18
  * A ErrorBoundary component that logs errors to Sentry.
42
19
  * NOTE: If you are a Sentry user, and you are seeing this stack frame, it means the
@@ -61,41 +38,21 @@ class ErrorBoundary extends React.Component {
61
38
  }
62
39
  }
63
40
 
64
- componentDidCatch(error, { componentStack }) {
41
+ componentDidCatch(error, errorInfo) {
42
+ const { componentStack } = errorInfo;
43
+ // TODO(v9): Remove this check and type `componentStack` to be React.ErrorInfo['componentStack'].
44
+ const passedInComponentStack = componentStack == null ? undefined : componentStack;
45
+
65
46
  const { beforeCapture, onError, showDialog, dialogOptions } = this.props;
66
47
  withScope(scope => {
67
- // If on React version >= 17, create stack trace from componentStack param and links
68
- // to to the original error using `error.cause` otherwise relies on error param for stacktrace.
69
- // Linking errors requires the `LinkedErrors` integration be enabled.
70
- // See: https://reactjs.org/blog/2020/08/10/react-v17-rc.html#native-component-stacks
71
- //
72
- // Although `componentDidCatch` is typed to accept an `Error` object, it can also be invoked
73
- // with non-error objects. This is why we need to check if the error is an error-like object.
74
- // See: https://github.com/getsentry/sentry-javascript/issues/6167
75
- if (isAtLeastReact17(React.version) && isError(error)) {
76
- const errorBoundaryError = new Error(error.message);
77
- errorBoundaryError.name = `React ErrorBoundary ${error.name}`;
78
- errorBoundaryError.stack = componentStack;
79
-
80
- // Using the `LinkedErrors` integration to link the errors together.
81
- setCause(error, errorBoundaryError);
82
- }
83
-
84
48
  if (beforeCapture) {
85
- beforeCapture(scope, error, componentStack);
49
+ beforeCapture(scope, error, passedInComponentStack);
86
50
  }
87
51
 
88
- const eventId = captureException(error, {
89
- captureContext: {
90
- contexts: { react: { componentStack } },
91
- },
92
- // If users provide a fallback component we can assume they are handling the error.
93
- // Therefore, we set the mechanism depending on the presence of the fallback prop.
94
- mechanism: { handled: !!this.props.fallback },
95
- });
52
+ const eventId = captureReactException(error, errorInfo, { mechanism: { handled: !!this.props.fallback } });
96
53
 
97
54
  if (onError) {
98
- onError(error, componentStack, eventId);
55
+ onError(error, passedInComponentStack, eventId);
99
56
  }
100
57
  if (showDialog) {
101
58
  this._lastEventId = eventId;
@@ -175,7 +132,6 @@ function withErrorBoundary(
175
132
  WrappedComponent,
176
133
  errorBoundaryOptions,
177
134
  ) {
178
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
179
135
  const componentDisplayName = WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;
180
136
 
181
137
  const Wrapped = (props) => (
@@ -184,7 +140,6 @@ function withErrorBoundary(
184
140
  })
185
141
  );
186
142
 
187
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
188
143
  Wrapped.displayName = `errorBoundary(${componentDisplayName})`;
189
144
 
190
145
  // Copy over static methods from Wrapped component to Profiler HOC
@@ -193,5 +148,5 @@ function withErrorBoundary(
193
148
  return Wrapped;
194
149
  }
195
150
 
196
- export { ErrorBoundary, UNKNOWN_COMPONENT, isAtLeastReact17, withErrorBoundary };
151
+ export { ErrorBoundary, UNKNOWN_COMPONENT, withErrorBoundary };
197
152
  //# sourceMappingURL=errorboundary.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorboundary.js","sources":["../../src/errorboundary.tsx"],"sourcesContent":["import type { ReportDialogOptions } from '@sentry/browser';\nimport { captureException, getClient, showReportDialog, withScope } from '@sentry/browser';\nimport type { Scope } from '@sentry/types';\nimport { isError, logger } from '@sentry/utils';\nimport hoistNonReactStatics from 'hoist-non-react-statics';\nimport * as React from 'react';\n\nimport { DEBUG_BUILD } from './debug-build';\n\nexport function isAtLeastReact17(version: string): boolean {\n const major = version.match(/^([^.]+)/);\n return major !== null && parseInt(major[0]) >= 17;\n}\n\nexport const UNKNOWN_COMPONENT = 'unknown';\n\nexport type FallbackRender = (errorData: {\n error: unknown;\n componentStack: string;\n eventId: string;\n resetError(): void;\n}) => React.ReactElement;\n\nexport type ErrorBoundaryProps = {\n children?: React.ReactNode | (() => React.ReactNode);\n /** If a Sentry report dialog should be rendered on error */\n showDialog?: boolean | undefined;\n /**\n * Options to be passed into the Sentry report dialog.\n * No-op if {@link showDialog} is false.\n */\n dialogOptions?: ReportDialogOptions | undefined;\n /**\n * A fallback component that gets rendered when the error boundary encounters an error.\n *\n * Can either provide a React Component, or a function that returns React Component as\n * a valid fallback prop. If a function is provided, the function will be called with\n * the error, the component stack, and an function that resets the error boundary on error.\n *\n */\n fallback?: React.ReactElement | FallbackRender | undefined;\n /** Called when the error boundary encounters an error */\n onError?: ((error: unknown, componentStack: string, eventId: string) => void) | undefined;\n /** Called on componentDidMount() */\n onMount?: (() => void) | undefined;\n /** Called if resetError() is called from the fallback render props function */\n onReset?: ((error: unknown, componentStack: string | null, eventId: string | null) => void) | undefined;\n /** Called on componentWillUnmount() */\n onUnmount?: ((error: unknown, componentStack: string | null, eventId: string | null) => void) | undefined;\n /** Called before the error is captured by Sentry, allows for you to add tags or context using the scope */\n beforeCapture?: ((scope: Scope, error: unknown, componentStack: string | undefined) => void) | undefined;\n};\n\ntype ErrorBoundaryState =\n | {\n componentStack: null;\n error: null;\n eventId: null;\n }\n | {\n componentStack: React.ErrorInfo['componentStack'];\n error: unknown;\n eventId: string;\n };\n\nconst INITIAL_STATE = {\n componentStack: null,\n error: null,\n eventId: null,\n};\n\nfunction setCause(error: Error & { cause?: Error }, cause: Error): void {\n const seenErrors = new WeakMap<Error, boolean>();\n\n function recurse(error: Error & { cause?: Error }, cause: Error): void {\n // If we've already seen the error, there is a recursive loop somewhere in the error's\n // cause chain. Let's just bail out then to prevent a stack overflow.\n if (seenErrors.has(error)) {\n return;\n }\n if (error.cause) {\n seenErrors.set(error, true);\n return recurse(error.cause, cause);\n }\n error.cause = cause;\n }\n\n recurse(error, cause);\n}\n\n/**\n * A ErrorBoundary component that logs errors to Sentry.\n * NOTE: If you are a Sentry user, and you are seeing this stack frame, it means the\n * Sentry React SDK ErrorBoundary caught an error invoking your application code. This\n * is expected behavior and NOT indicative of a bug with the Sentry React SDK.\n */\nclass ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n public state: ErrorBoundaryState;\n\n private readonly _openFallbackReportDialog: boolean;\n\n private _lastEventId?: string;\n\n public constructor(props: ErrorBoundaryProps) {\n super(props);\n\n this.state = INITIAL_STATE;\n this._openFallbackReportDialog = true;\n\n const client = getClient();\n if (client && props.showDialog) {\n this._openFallbackReportDialog = false;\n client.on('afterSendEvent', event => {\n if (!event.type && this._lastEventId && event.event_id === this._lastEventId) {\n showReportDialog({ ...props.dialogOptions, eventId: this._lastEventId });\n }\n });\n }\n }\n\n public componentDidCatch(error: unknown, { componentStack }: React.ErrorInfo): void {\n const { beforeCapture, onError, showDialog, dialogOptions } = this.props;\n withScope(scope => {\n // If on React version >= 17, create stack trace from componentStack param and links\n // to to the original error using `error.cause` otherwise relies on error param for stacktrace.\n // Linking errors requires the `LinkedErrors` integration be enabled.\n // See: https://reactjs.org/blog/2020/08/10/react-v17-rc.html#native-component-stacks\n //\n // Although `componentDidCatch` is typed to accept an `Error` object, it can also be invoked\n // with non-error objects. This is why we need to check if the error is an error-like object.\n // See: https://github.com/getsentry/sentry-javascript/issues/6167\n if (isAtLeastReact17(React.version) && isError(error)) {\n const errorBoundaryError = new Error(error.message);\n errorBoundaryError.name = `React ErrorBoundary ${error.name}`;\n errorBoundaryError.stack = componentStack;\n\n // Using the `LinkedErrors` integration to link the errors together.\n setCause(error, errorBoundaryError);\n }\n\n if (beforeCapture) {\n beforeCapture(scope, error, componentStack);\n }\n\n const eventId = captureException(error, {\n captureContext: {\n contexts: { react: { componentStack } },\n },\n // If users provide a fallback component we can assume they are handling the error.\n // Therefore, we set the mechanism depending on the presence of the fallback prop.\n mechanism: { handled: !!this.props.fallback },\n });\n\n if (onError) {\n onError(error, componentStack, eventId);\n }\n if (showDialog) {\n this._lastEventId = eventId;\n if (this._openFallbackReportDialog) {\n showReportDialog({ ...dialogOptions, eventId });\n }\n }\n\n // componentDidCatch is used over getDerivedStateFromError\n // so that componentStack is accessible through state.\n this.setState({ error, componentStack, eventId });\n });\n }\n\n public componentDidMount(): void {\n const { onMount } = this.props;\n if (onMount) {\n onMount();\n }\n }\n\n public componentWillUnmount(): void {\n const { error, componentStack, eventId } = this.state;\n const { onUnmount } = this.props;\n if (onUnmount) {\n onUnmount(error, componentStack, eventId);\n }\n }\n\n public resetErrorBoundary: () => void = () => {\n const { onReset } = this.props;\n const { error, componentStack, eventId } = this.state;\n if (onReset) {\n onReset(error, componentStack, eventId);\n }\n this.setState(INITIAL_STATE);\n };\n\n public render(): React.ReactNode {\n const { fallback, children } = this.props;\n const state = this.state;\n\n if (state.error) {\n let element: React.ReactElement | undefined = undefined;\n if (typeof fallback === 'function') {\n element = React.createElement(fallback, {\n error: state.error,\n componentStack: state.componentStack as string,\n resetError: this.resetErrorBoundary,\n eventId: state.eventId as string,\n });\n } else {\n element = fallback;\n }\n\n if (React.isValidElement(element)) {\n return element;\n }\n\n if (fallback) {\n DEBUG_BUILD && logger.warn('fallback did not produce a valid ReactElement');\n }\n\n // Fail gracefully if no fallback provided or is not valid\n return null;\n }\n\n if (typeof children === 'function') {\n return (children as () => React.ReactNode)();\n }\n return children;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction withErrorBoundary<P extends Record<string, any>>(\n WrappedComponent: React.ComponentType<P>,\n errorBoundaryOptions: ErrorBoundaryProps,\n): React.FC<P> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const componentDisplayName = WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;\n\n const Wrapped: React.FC<P> = (props: P) => (\n <ErrorBoundary {...errorBoundaryOptions}>\n <WrappedComponent {...props} />\n </ErrorBoundary>\n );\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n Wrapped.displayName = `errorBoundary(${componentDisplayName})`;\n\n // Copy over static methods from Wrapped component to Profiler HOC\n // See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over\n hoistNonReactStatics(Wrapped, WrappedComponent);\n return Wrapped;\n}\n\nexport { ErrorBoundary, withErrorBoundary };\n"],"names":["_jsx"],"mappings":"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"}
1
+ {"version":3,"file":"errorboundary.js","sources":["../../src/errorboundary.tsx"],"sourcesContent":["import type { ReportDialogOptions } from '@sentry/browser';\nimport { getClient, showReportDialog, withScope } from '@sentry/browser';\nimport type { Scope } from '@sentry/types';\nimport { logger } from '@sentry/utils';\nimport hoistNonReactStatics from 'hoist-non-react-statics';\nimport * as React from 'react';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport { captureReactException } from './error';\n\nexport const UNKNOWN_COMPONENT = 'unknown';\n\nexport type FallbackRender = (errorData: {\n error: unknown;\n componentStack: string;\n eventId: string;\n resetError(): void;\n}) => React.ReactElement;\n\nexport type ErrorBoundaryProps = {\n children?: React.ReactNode | (() => React.ReactNode);\n /** If a Sentry report dialog should be rendered on error */\n showDialog?: boolean | undefined;\n /**\n * Options to be passed into the Sentry report dialog.\n * No-op if {@link showDialog} is false.\n */\n dialogOptions?: ReportDialogOptions | undefined;\n /**\n * A fallback component that gets rendered when the error boundary encounters an error.\n *\n * Can either provide a React Component, or a function that returns React Component as\n * a valid fallback prop. If a function is provided, the function will be called with\n * the error, the component stack, and an function that resets the error boundary on error.\n *\n */\n fallback?: React.ReactElement | FallbackRender | undefined;\n /** Called when the error boundary encounters an error */\n onError?: ((error: unknown, componentStack: string | undefined, eventId: string) => void) | undefined;\n /** Called on componentDidMount() */\n onMount?: (() => void) | undefined;\n /** Called if resetError() is called from the fallback render props function */\n onReset?: ((error: unknown, componentStack: string | null | undefined, eventId: string | null) => void) | undefined;\n /** Called on componentWillUnmount() */\n onUnmount?: ((error: unknown, componentStack: string | null | undefined, eventId: string | null) => void) | undefined;\n /** Called before the error is captured by Sentry, allows for you to add tags or context using the scope */\n beforeCapture?: ((scope: Scope, error: unknown, componentStack: string | undefined) => void) | undefined;\n};\n\ntype ErrorBoundaryState =\n | {\n componentStack: null;\n error: null;\n eventId: null;\n }\n | {\n componentStack: React.ErrorInfo['componentStack'];\n error: unknown;\n eventId: string;\n };\n\nconst INITIAL_STATE = {\n componentStack: null,\n error: null,\n eventId: null,\n};\n\n/**\n * A ErrorBoundary component that logs errors to Sentry.\n * NOTE: If you are a Sentry user, and you are seeing this stack frame, it means the\n * Sentry React SDK ErrorBoundary caught an error invoking your application code. This\n * is expected behavior and NOT indicative of a bug with the Sentry React SDK.\n */\nclass ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n public state: ErrorBoundaryState;\n\n private readonly _openFallbackReportDialog: boolean;\n\n private _lastEventId?: string;\n\n public constructor(props: ErrorBoundaryProps) {\n super(props);\n\n this.state = INITIAL_STATE;\n this._openFallbackReportDialog = true;\n\n const client = getClient();\n if (client && props.showDialog) {\n this._openFallbackReportDialog = false;\n client.on('afterSendEvent', event => {\n if (!event.type && this._lastEventId && event.event_id === this._lastEventId) {\n showReportDialog({ ...props.dialogOptions, eventId: this._lastEventId });\n }\n });\n }\n }\n\n public componentDidCatch(error: unknown, errorInfo: React.ErrorInfo): void {\n const { componentStack } = errorInfo;\n // TODO(v9): Remove this check and type `componentStack` to be React.ErrorInfo['componentStack'].\n const passedInComponentStack: string | undefined = componentStack == null ? undefined : componentStack;\n\n const { beforeCapture, onError, showDialog, dialogOptions } = this.props;\n withScope(scope => {\n if (beforeCapture) {\n beforeCapture(scope, error, passedInComponentStack);\n }\n\n const eventId = captureReactException(error, errorInfo, { mechanism: { handled: !!this.props.fallback } });\n\n if (onError) {\n onError(error, passedInComponentStack, eventId);\n }\n if (showDialog) {\n this._lastEventId = eventId;\n if (this._openFallbackReportDialog) {\n showReportDialog({ ...dialogOptions, eventId });\n }\n }\n\n // componentDidCatch is used over getDerivedStateFromError\n // so that componentStack is accessible through state.\n this.setState({ error, componentStack, eventId });\n });\n }\n\n public componentDidMount(): void {\n const { onMount } = this.props;\n if (onMount) {\n onMount();\n }\n }\n\n public componentWillUnmount(): void {\n const { error, componentStack, eventId } = this.state;\n const { onUnmount } = this.props;\n if (onUnmount) {\n onUnmount(error, componentStack, eventId);\n }\n }\n\n public resetErrorBoundary: () => void = () => {\n const { onReset } = this.props;\n const { error, componentStack, eventId } = this.state;\n if (onReset) {\n onReset(error, componentStack, eventId);\n }\n this.setState(INITIAL_STATE);\n };\n\n public render(): React.ReactNode {\n const { fallback, children } = this.props;\n const state = this.state;\n\n if (state.error) {\n let element: React.ReactElement | undefined = undefined;\n if (typeof fallback === 'function') {\n element = React.createElement(fallback, {\n error: state.error,\n componentStack: state.componentStack as string,\n resetError: this.resetErrorBoundary,\n eventId: state.eventId as string,\n });\n } else {\n element = fallback;\n }\n\n if (React.isValidElement(element)) {\n return element;\n }\n\n if (fallback) {\n DEBUG_BUILD && logger.warn('fallback did not produce a valid ReactElement');\n }\n\n // Fail gracefully if no fallback provided or is not valid\n return null;\n }\n\n if (typeof children === 'function') {\n return (children as () => React.ReactNode)();\n }\n return children;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction withErrorBoundary<P extends Record<string, any>>(\n WrappedComponent: React.ComponentType<P>,\n errorBoundaryOptions: ErrorBoundaryProps,\n): React.FC<P> {\n const componentDisplayName = WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;\n\n const Wrapped: React.FC<P> = (props: P) => (\n <ErrorBoundary {...errorBoundaryOptions}>\n <WrappedComponent {...props} />\n </ErrorBoundary>\n );\n\n Wrapped.displayName = `errorBoundary(${componentDisplayName})`;\n\n // Copy over static methods from Wrapped component to Profiler HOC\n // See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over\n hoistNonReactStatics(Wrapped, WrappedComponent);\n return Wrapped;\n}\n\nexport { ErrorBoundary, withErrorBoundary };\n"],"names":["_jsx"],"mappings":"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"}
package/esm/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from '@sentry/browser';
2
2
  export { init } from './sdk.js';
3
+ export { reactErrorHandler } from './error.js';
3
4
  export { Profiler, useProfiler, withProfiler } from './profiler.js';
4
5
  export { ErrorBoundary, withErrorBoundary } from './errorboundary.js';
5
6
  export { createReduxEnhancer } from './redux.js';
package/esm/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/react",
3
- "version": "8.5.0",
3
+ "version": "8.6.0",
4
4
  "description": "Official Sentry SDK for React.js",
5
5
  "repository": "git://github.com/getsentry/sentry-javascript.git",
6
6
  "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/react",
@@ -42,10 +42,10 @@
42
42
  "access": "public"
43
43
  },
44
44
  "dependencies": {
45
- "@sentry/browser": "8.5.0",
46
- "@sentry/core": "8.5.0",
47
- "@sentry/types": "8.5.0",
48
- "@sentry/utils": "8.5.0",
45
+ "@sentry/browser": "8.6.0",
46
+ "@sentry/core": "8.6.0",
47
+ "@sentry/types": "8.6.0",
48
+ "@sentry/utils": "8.6.0",
49
49
  "hoist-non-react-statics": "^3.3.2"
50
50
  },
51
51
  "peerDependencies": {
@@ -56,9 +56,9 @@
56
56
  "@testing-library/react-hooks": "^7.0.2",
57
57
  "@types/history-4": "npm:@types/history@4.7.8",
58
58
  "@types/history-5": "npm:@types/history@4.7.8",
59
- "@types/hoist-non-react-statics": "^3.3.1",
59
+ "@types/hoist-non-react-statics": "^3.3.5",
60
60
  "@types/node-fetch": "^2.6.0",
61
- "@types/react": "^17.0.3",
61
+ "@types/react": "17.0.3",
62
62
  "@types/react-router-3": "npm:@types/react-router@3.0.24",
63
63
  "@types/react-router-4": "npm:@types/react-router@5.1.14",
64
64
  "@types/react-router-5": "npm:@types/react-router@5.1.14",
@@ -0,0 +1,41 @@
1
+ import type { EventHint } from '@sentry/types';
2
+ import type { ErrorInfo } from 'react';
3
+ /**
4
+ * See if React major version is 17+ by parsing version string.
5
+ */
6
+ export declare function isAtLeastReact17(reactVersion: string): boolean;
7
+ /**
8
+ * Recurse through `error.cause` chain to set cause on an error.
9
+ */
10
+ export declare function setCause(error: Error & {
11
+ cause?: Error;
12
+ }, cause: Error): void;
13
+ /**
14
+ * Captures an error that was thrown by a React ErrorBoundary or React root.
15
+ *
16
+ * @param error The error to capture.
17
+ * @param errorInfo The errorInfo provided by React.
18
+ * @param hint Optional additional data to attach to the Sentry event.
19
+ * @returns the id of the captured Sentry event.
20
+ */
21
+ export declare function captureReactException(error: any, { componentStack }: ErrorInfo, hint?: EventHint): string;
22
+ /**
23
+ * Creates an error handler that can be used with the `onCaughtError`, `onUncaughtError`,
24
+ * and `onRecoverableError` options in `createRoot` and `hydrateRoot` React DOM methods.
25
+ *
26
+ * @param callback An optional callback that will be called after the error is captured.
27
+ * Use this to add custom handling for errors.
28
+ *
29
+ * @example
30
+ *
31
+ * ```JavaScript
32
+ * const root = createRoot(container, {
33
+ * onCaughtError: Sentry.reactErrorHandler(),
34
+ * onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
35
+ * console.warn('Caught error', error, errorInfo.componentStack);
36
+ * });
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function reactErrorHandler(callback?: (error: any, errorInfo: ErrorInfo, eventId: string) => void): (error: any, errorInfo: ErrorInfo) => void;
41
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/error.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAG9D;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAiB7E;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAEnC,KAAK,EAAE,GAAG,EACV,EAAE,cAAc,EAAE,EAAE,SAAS,EAC7B,IAAI,CAAC,EAAE,SAAS,GACf,MAAM,CAwBR;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAE/B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAErE,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,KAAK,IAAI,CAQ5C"}
@@ -1,7 +1,6 @@
1
1
  import type { ReportDialogOptions } from '@sentry/browser';
2
2
  import type { Scope } from '@sentry/types';
3
3
  import * as React from 'react';
4
- export declare function isAtLeastReact17(version: string): boolean;
5
4
  export declare const UNKNOWN_COMPONENT = "unknown";
6
5
  export type FallbackRender = (errorData: {
7
6
  error: unknown;
@@ -28,13 +27,13 @@ export type ErrorBoundaryProps = {
28
27
  */
29
28
  fallback?: React.ReactElement | FallbackRender | undefined;
30
29
  /** Called when the error boundary encounters an error */
31
- onError?: ((error: unknown, componentStack: string, eventId: string) => void) | undefined;
30
+ onError?: ((error: unknown, componentStack: string | undefined, eventId: string) => void) | undefined;
32
31
  /** Called on componentDidMount() */
33
32
  onMount?: (() => void) | undefined;
34
33
  /** Called if resetError() is called from the fallback render props function */
35
- onReset?: ((error: unknown, componentStack: string | null, eventId: string | null) => void) | undefined;
34
+ onReset?: ((error: unknown, componentStack: string | null | undefined, eventId: string | null) => void) | undefined;
36
35
  /** Called on componentWillUnmount() */
37
- onUnmount?: ((error: unknown, componentStack: string | null, eventId: string | null) => void) | undefined;
36
+ onUnmount?: ((error: unknown, componentStack: string | null | undefined, eventId: string | null) => void) | undefined;
38
37
  /** Called before the error is captured by Sentry, allows for you to add tags or context using the scope */
39
38
  beforeCapture?: ((scope: Scope, error: unknown, componentStack: string | undefined) => void) | undefined;
40
39
  };
@@ -58,7 +57,7 @@ declare class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBou
58
57
  private readonly _openFallbackReportDialog;
59
58
  private _lastEventId?;
60
59
  constructor(props: ErrorBoundaryProps);
61
- componentDidCatch(error: unknown, { componentStack }: React.ErrorInfo): void;
60
+ componentDidCatch(error: unknown, errorInfo: React.ErrorInfo): void;
62
61
  componentDidMount(): void;
63
62
  componentWillUnmount(): void;
64
63
  resetErrorBoundary: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"errorboundary.d.ts","sourceRoot":"","sources":["../../src/errorboundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAG3C,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAE3C,MAAM,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,IAAI,IAAI,CAAC;CACpB,KAAK,KAAK,CAAC,YAAY,CAAC;AAEzB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,CAAC,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;IACrD,4DAA4D;IAC5D,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC;;;OAGG;IACH,aAAa,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAChD;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,cAAc,GAAG,SAAS,CAAC;IAC3D,yDAAyD;IACzD,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1F,oCAAoC;IACpC,OAAO,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACnC,gFAAgF;IAChF,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACxG,uCAAuC;IACvC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1G,2GAA2G;IAC3G,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC1G,CAAC;AAEF,KAAK,kBAAkB,GACnB;IACE,cAAc,EAAE,IAAI,CAAC;IACrB,KAAK,EAAE,IAAI,CAAC;IACZ,OAAO,EAAE,IAAI,CAAC;CACf,GACD;IACE,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAClD,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AA2BN;;;;;GAKG;AACH,cAAM,aAAc,SAAQ,KAAK,CAAC,SAAS,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;IAC1E,KAAK,EAAE,kBAAkB,CAAC;IAEjC,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAU;IAEpD,OAAO,CAAC,YAAY,CAAC,CAAS;gBAEX,KAAK,EAAE,kBAAkB;IAiBrC,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI;IAiD5E,iBAAiB,IAAI,IAAI;IAOzB,oBAAoB,IAAI,IAAI;IAQ5B,kBAAkB,EAAE,MAAM,IAAI,CAOnC;IAEK,MAAM,IAAI,KAAK,CAAC,SAAS;CAkCjC;AAGD,iBAAS,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACtD,gBAAgB,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EACxC,oBAAoB,EAAE,kBAAkB,GACvC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAiBb;AAED,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"errorboundary.d.ts","sourceRoot":"","sources":["../../src/errorboundary.tsx"],"names":[],"mappings":"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"}
package/types/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from '@sentry/browser';
2
2
  export { init } from './sdk';
3
+ export { reactErrorHandler } from './error';
3
4
  export { Profiler, withProfiler, useProfiler } from './profiler';
4
5
  export type { ErrorBoundaryProps, FallbackRender } from './errorboundary';
5
6
  export { ErrorBoundary, withErrorBoundary } from './errorboundary';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAEhC,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACjE,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,sCAAsC,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EACL,iBAAiB,EACjB,sCAAsC,EACtC,sCAAsC,GACvC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sCAAsC,EACtC,8BAA8B,EAC9B,aAAa,EACb,uBAAuB,GACxB,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAEhC,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACjE,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,sCAAsC,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EACL,iBAAiB,EACjB,sCAAsC,EACtC,sCAAsC,GACvC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sCAAsC,EACtC,8BAA8B,EAC9B,aAAa,EACb,uBAAuB,GACxB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { EventHint } from '@sentry/types';
2
+ import { ErrorInfo } from 'react';
3
+ /**
4
+ * See if React major version is 17+ by parsing version string.
5
+ */
6
+ export declare function isAtLeastReact17(reactVersion: string): boolean;
7
+ /**
8
+ * Recurse through `error.cause` chain to set cause on an error.
9
+ */
10
+ export declare function setCause(error: Error & {
11
+ cause?: Error;
12
+ }, cause: Error): void;
13
+ /**
14
+ * Captures an error that was thrown by a React ErrorBoundary or React root.
15
+ *
16
+ * @param error The error to capture.
17
+ * @param errorInfo The errorInfo provided by React.
18
+ * @param hint Optional additional data to attach to the Sentry event.
19
+ * @returns the id of the captured Sentry event.
20
+ */
21
+ export declare function captureReactException(error: any, { componentStack }: ErrorInfo, hint?: EventHint): string;
22
+ /**
23
+ * Creates an error handler that can be used with the `onCaughtError`, `onUncaughtError`,
24
+ * and `onRecoverableError` options in `createRoot` and `hydrateRoot` React DOM methods.
25
+ *
26
+ * @param callback An optional callback that will be called after the error is captured.
27
+ * Use this to add custom handling for errors.
28
+ *
29
+ * @example
30
+ *
31
+ * ```JavaScript
32
+ * const root = createRoot(container, {
33
+ * onCaughtError: Sentry.reactErrorHandler(),
34
+ * onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
35
+ * console.warn('Caught error', error, errorInfo.componentStack);
36
+ * });
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function reactErrorHandler(callback?: (error: any, errorInfo: ErrorInfo, eventId: string) => void): (error: any, errorInfo: ErrorInfo) => void;
41
+ //# sourceMappingURL=error.d.ts.map
@@ -1,7 +1,6 @@
1
1
  import { ReportDialogOptions } from '@sentry/browser';
2
2
  import { Scope } from '@sentry/types';
3
3
  import * as React from 'react';
4
- export declare function isAtLeastReact17(version: string): boolean;
5
4
  export declare const UNKNOWN_COMPONENT = "unknown";
6
5
  export type FallbackRender = (errorData: {
7
6
  error: unknown;
@@ -28,13 +27,13 @@ export type ErrorBoundaryProps = {
28
27
  */
29
28
  fallback?: React.ReactElement | FallbackRender | undefined;
30
29
  /** Called when the error boundary encounters an error */
31
- onError?: ((error: unknown, componentStack: string, eventId: string) => void) | undefined;
30
+ onError?: ((error: unknown, componentStack: string | undefined, eventId: string) => void) | undefined;
32
31
  /** Called on componentDidMount() */
33
32
  onMount?: (() => void) | undefined;
34
33
  /** Called if resetError() is called from the fallback render props function */
35
- onReset?: ((error: unknown, componentStack: string | null, eventId: string | null) => void) | undefined;
34
+ onReset?: ((error: unknown, componentStack: string | null | undefined, eventId: string | null) => void) | undefined;
36
35
  /** Called on componentWillUnmount() */
37
- onUnmount?: ((error: unknown, componentStack: string | null, eventId: string | null) => void) | undefined;
36
+ onUnmount?: ((error: unknown, componentStack: string | null | undefined, eventId: string | null) => void) | undefined;
38
37
  /** Called before the error is captured by Sentry, allows for you to add tags or context using the scope */
39
38
  beforeCapture?: ((scope: Scope, error: unknown, componentStack: string | undefined) => void) | undefined;
40
39
  };
@@ -58,7 +57,7 @@ declare class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBou
58
57
  private readonly _openFallbackReportDialog;
59
58
  private _lastEventId?;
60
59
  constructor(props: ErrorBoundaryProps);
61
- componentDidCatch(error: unknown, { componentStack }: React.ErrorInfo): void;
60
+ componentDidCatch(error: unknown, errorInfo: React.ErrorInfo): void;
62
61
  componentDidMount(): void;
63
62
  componentWillUnmount(): void;
64
63
  resetErrorBoundary: () => void;
@@ -1,5 +1,6 @@
1
1
  export * from '@sentry/browser';
2
2
  export { init } from './sdk';
3
+ export { reactErrorHandler } from './error';
3
4
  export { Profiler, withProfiler, useProfiler } from './profiler';
4
5
  export { ErrorBoundaryProps, FallbackRender } from './errorboundary';
5
6
  export { ErrorBoundary, withErrorBoundary } from './errorboundary';