@sentry/react 6.13.0-beta.1
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/LICENSE +29 -0
- package/README.md +92 -0
- package/dist/errorboundary.d.ts +59 -0
- package/dist/errorboundary.d.ts.map +1 -0
- package/dist/errorboundary.js +138 -0
- package/dist/errorboundary.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/profiler.d.ts +55 -0
- package/dist/profiler.d.ts.map +1 -0
- package/dist/profiler.js +239 -0
- package/dist/profiler.js.map +1 -0
- package/dist/reactrouter.d.ts +25 -0
- package/dist/reactrouter.d.ts.map +1 -0
- package/dist/reactrouter.js +119 -0
- package/dist/reactrouter.js.map +1 -0
- package/dist/reactrouterv3.d.ts +26 -0
- package/dist/reactrouterv3.d.ts.map +1 -0
- package/dist/reactrouterv3.js +105 -0
- package/dist/reactrouterv3.js.map +1 -0
- package/dist/redux.d.ts +33 -0
- package/dist/redux.d.ts.map +1 -0
- package/dist/redux.js +54 -0
- package/dist/redux.js.map +1 -0
- package/dist/sdk.d.ts +6 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +21 -0
- package/dist/sdk.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/esm/errorboundary.d.ts +59 -0
- package/esm/errorboundary.d.ts.map +1 -0
- package/esm/errorboundary.js +136 -0
- package/esm/errorboundary.js.map +1 -0
- package/esm/index.d.ts +8 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +8 -0
- package/esm/index.js.map +1 -0
- package/esm/profiler.d.ts +55 -0
- package/esm/profiler.d.ts.map +1 -0
- package/esm/profiler.js +235 -0
- package/esm/profiler.js.map +1 -0
- package/esm/reactrouter.d.ts +25 -0
- package/esm/reactrouter.d.ts.map +1 -0
- package/esm/reactrouter.js +115 -0
- package/esm/reactrouter.js.map +1 -0
- package/esm/reactrouterv3.d.ts +26 -0
- package/esm/reactrouterv3.d.ts.map +1 -0
- package/esm/reactrouterv3.js +103 -0
- package/esm/reactrouterv3.js.map +1 -0
- package/esm/redux.d.ts +33 -0
- package/esm/redux.d.ts.map +1 -0
- package/esm/redux.js +53 -0
- package/esm/redux.js.map +1 -0
- package/esm/sdk.d.ts +6 -0
- package/esm/sdk.d.ts.map +1 -0
- package/esm/sdk.js +19 -0
- package/esm/sdk.js.map +1 -0
- package/esm/types.d.ts +8 -0
- package/esm/types.d.ts.map +1 -0
- package/esm/types.js +1 -0
- package/esm/types.js.map +1 -0
- package/package.json +107 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019, Sentry
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://sentry.io" target="_blank" align="center">
|
|
3
|
+
<img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
|
|
4
|
+
</a>
|
|
5
|
+
<br />
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
# Official Sentry SDK for ReactJS
|
|
9
|
+
|
|
10
|
+
## Links
|
|
11
|
+
|
|
12
|
+
- [Official SDK Docs](https://docs.sentry.io/platforms/javascript/guides/react/)
|
|
13
|
+
- [TypeDoc](http://getsentry.github.io/sentry-javascript/)
|
|
14
|
+
|
|
15
|
+
## General
|
|
16
|
+
|
|
17
|
+
This package is a wrapper around `@sentry/browser`, with added functionality related to React. All methods available in
|
|
18
|
+
`@sentry/browser` can be imported from `@sentry/react`.
|
|
19
|
+
|
|
20
|
+
To use this SDK, call `Sentry.init(options)` before you mount your React component.
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
import React from 'react';
|
|
24
|
+
import ReactDOM from "react-dom";
|
|
25
|
+
import * as Sentry from '@sentry/react';
|
|
26
|
+
|
|
27
|
+
Sentry.init({
|
|
28
|
+
dsn: '__DSN__',
|
|
29
|
+
// ...
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// ...
|
|
33
|
+
|
|
34
|
+
ReactDOM.render(<App />, rootNode);
|
|
35
|
+
|
|
36
|
+
// Can also use with React Concurrent Mode
|
|
37
|
+
// ReactDOM.createRoot(rootNode).render(<App />);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### ErrorBoundary
|
|
41
|
+
|
|
42
|
+
`@sentry/react` exports an ErrorBoundary component that will automatically send Javascript errors from inside a
|
|
43
|
+
component tree to Sentry, and set a fallback UI. Requires React version >= 16.
|
|
44
|
+
|
|
45
|
+
> app.js
|
|
46
|
+
```javascript
|
|
47
|
+
import React from 'react';
|
|
48
|
+
import * as Sentry from '@sentry/react';
|
|
49
|
+
|
|
50
|
+
function FallbackComponent() {
|
|
51
|
+
return (
|
|
52
|
+
<div>An error has occured</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class App extends React.Component {
|
|
57
|
+
render() {
|
|
58
|
+
return (
|
|
59
|
+
<Sentry.ErrorBoundary fallback={FallbackComponent} showDialog>
|
|
60
|
+
<OtherComponents />
|
|
61
|
+
</Sentry.ErrorBoundary>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export default App;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Profiler
|
|
70
|
+
|
|
71
|
+
`@sentry/react` exports a Profiler component that leverages the `@sentry/tracing` Tracing integration to add React related
|
|
72
|
+
spans to transactions. If the Tracing integration is not enabled, the Profiler component will not work. The Profiler
|
|
73
|
+
tracks component mount, render duration and updates. Requires React version >= 15.
|
|
74
|
+
|
|
75
|
+
> app.js
|
|
76
|
+
```javascript
|
|
77
|
+
import React from 'react';
|
|
78
|
+
import * as Sentry from '@sentry/react';
|
|
79
|
+
|
|
80
|
+
class App extends React.Component {
|
|
81
|
+
render() {
|
|
82
|
+
return (
|
|
83
|
+
<FancyComponent>
|
|
84
|
+
<InsideComponent someProp={2} />
|
|
85
|
+
<AnotherComponent />
|
|
86
|
+
</FancyComponent>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default Sentry.withProfiler(App);
|
|
92
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ReportDialogOptions, Scope } from '@sentry/browser';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
export declare const UNKNOWN_COMPONENT = "unknown";
|
|
4
|
+
export declare type FallbackRender = (errorData: {
|
|
5
|
+
error: Error;
|
|
6
|
+
componentStack: string | null;
|
|
7
|
+
eventId: string | null;
|
|
8
|
+
resetError(): void;
|
|
9
|
+
}) => React.ReactElement;
|
|
10
|
+
export declare type ErrorBoundaryProps = {
|
|
11
|
+
/** If a Sentry report dialog should be rendered on error */
|
|
12
|
+
showDialog?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Options to be passed into the Sentry report dialog.
|
|
15
|
+
* No-op if {@link showDialog} is false.
|
|
16
|
+
*/
|
|
17
|
+
dialogOptions?: ReportDialogOptions;
|
|
18
|
+
/**
|
|
19
|
+
* A fallback component that gets rendered when the error boundary encounters an error.
|
|
20
|
+
*
|
|
21
|
+
* Can either provide a React Component, or a function that returns React Component as
|
|
22
|
+
* a valid fallback prop. If a function is provided, the function will be called with
|
|
23
|
+
* the error, the component stack, and an function that resets the error boundary on error.
|
|
24
|
+
*
|
|
25
|
+
*/
|
|
26
|
+
fallback?: React.ReactElement | FallbackRender;
|
|
27
|
+
/** Called when the error boundary encounters an error */
|
|
28
|
+
onError?(error: Error, componentStack: string, eventId: string): void;
|
|
29
|
+
/** Called on componentDidMount() */
|
|
30
|
+
onMount?(): void;
|
|
31
|
+
/** Called if resetError() is called from the fallback render props function */
|
|
32
|
+
onReset?(error: Error | null, componentStack: string | null, eventId: string | null): void;
|
|
33
|
+
/** Called on componentWillUnmount() */
|
|
34
|
+
onUnmount?(error: Error | null, componentStack: string | null, eventId: string | null): void;
|
|
35
|
+
/** Called before the error is captured by Sentry, allows for you to add tags or context using the scope */
|
|
36
|
+
beforeCapture?(scope: Scope, error: Error | null, componentStack: string | null): void;
|
|
37
|
+
};
|
|
38
|
+
declare type ErrorBoundaryState = {
|
|
39
|
+
componentStack: string | null;
|
|
40
|
+
error: Error | null;
|
|
41
|
+
eventId: string | null;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* A ErrorBoundary component that logs errors to Sentry. Requires React >= 16.
|
|
45
|
+
* NOTE: If you are a Sentry user, and you are seeing this stack frame, it means the
|
|
46
|
+
* Sentry React SDK ErrorBoundary caught an error invoking your application code. This
|
|
47
|
+
* is expected behavior and NOT indicative of a bug with the Sentry React SDK.
|
|
48
|
+
*/
|
|
49
|
+
declare class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
50
|
+
state: ErrorBoundaryState;
|
|
51
|
+
componentDidCatch(error: Error, { componentStack }: React.ErrorInfo): void;
|
|
52
|
+
componentDidMount(): void;
|
|
53
|
+
componentWillUnmount(): void;
|
|
54
|
+
resetErrorBoundary: () => void;
|
|
55
|
+
render(): React.ReactNode;
|
|
56
|
+
}
|
|
57
|
+
declare function withErrorBoundary<P extends Record<string, any>>(WrappedComponent: React.ComponentType<P>, errorBoundaryOptions: ErrorBoundaryProps): React.FC<P>;
|
|
58
|
+
export { ErrorBoundary, withErrorBoundary };
|
|
59
|
+
//# sourceMappingURL=errorboundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorboundary.d.ts","sourceRoot":"","sources":["../src/errorboundary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,mBAAmB,EACnB,KAAK,EAGN,MAAM,iBAAiB,CAAC;AAIzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAE3C,oBAAY,cAAc,GAAG,CAAC,SAAS,EAAE;IACvC,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,IAAI,IAAI,CAAC;CACpB,KAAK,KAAK,CAAC,YAAY,CAAC;AAEzB,oBAAY,kBAAkB,GAAG;IAC/B,4DAA4D;IAC5D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,cAAc,CAAC;IAC/C,yDAAyD;IACzD,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACtE,oCAAoC;IACpC,OAAO,CAAC,IAAI,IAAI,CAAC;IACjB,gFAAgF;IAChF,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IAC3F,uCAAuC;IACvC,SAAS,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IAC7F,2GAA2G;IAC3G,aAAa,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;CACxF,CAAC;AAEF,aAAK,kBAAkB,GAAG;IACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAAC;AA6CF;;;;;GAKG;AACH,cAAM,aAAc,SAAQ,KAAK,CAAC,SAAS,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;IAC1E,KAAK,EAAE,kBAAkB,CAAiB;IAE1C,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,cAAc,EAAE,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI;IAqB1E,iBAAiB,IAAI,IAAI;IAOzB,oBAAoB,IAAI,IAAI;IAQ5B,kBAAkB,EAAE,MAAM,IAAI,CAOnC;IAEK,MAAM,IAAI,KAAK,CAAC,SAAS;CA6BjC;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,CAeb;AAED,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
|
+
var tslib_1 = require("tslib");
|
|
3
|
+
var browser_1 = require("@sentry/browser");
|
|
4
|
+
var utils_1 = require("@sentry/utils");
|
|
5
|
+
var hoist_non_react_statics_1 = tslib_1.__importDefault(require("hoist-non-react-statics"));
|
|
6
|
+
var React = tslib_1.__importStar(require("react"));
|
|
7
|
+
var reactVersion = utils_1.parseSemver(React.version);
|
|
8
|
+
exports.UNKNOWN_COMPONENT = 'unknown';
|
|
9
|
+
var INITIAL_STATE = {
|
|
10
|
+
componentStack: null,
|
|
11
|
+
error: null,
|
|
12
|
+
eventId: null,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Logs react error boundary errors to Sentry. If on React version >= 17, creates stack trace
|
|
16
|
+
* from componentStack param, otherwise relies on error param for stacktrace.
|
|
17
|
+
*
|
|
18
|
+
* @param error An error captured by React Error Boundary
|
|
19
|
+
* @param componentStack The component stacktrace
|
|
20
|
+
*/
|
|
21
|
+
function captureReactErrorBoundaryError(error, componentStack) {
|
|
22
|
+
var errorBoundaryError = new Error(error.message);
|
|
23
|
+
errorBoundaryError.name = "React ErrorBoundary " + errorBoundaryError.name;
|
|
24
|
+
errorBoundaryError.stack = componentStack;
|
|
25
|
+
var errorBoundaryEvent = {};
|
|
26
|
+
void browser_1.eventFromException({}, errorBoundaryError).then(function (e) {
|
|
27
|
+
errorBoundaryEvent = e;
|
|
28
|
+
});
|
|
29
|
+
if (errorBoundaryEvent.exception &&
|
|
30
|
+
Array.isArray(errorBoundaryEvent.exception.values) &&
|
|
31
|
+
reactVersion.major &&
|
|
32
|
+
reactVersion.major >= 17) {
|
|
33
|
+
var originalEvent_1 = {};
|
|
34
|
+
void browser_1.eventFromException({}, error).then(function (e) {
|
|
35
|
+
originalEvent_1 = e;
|
|
36
|
+
});
|
|
37
|
+
if (originalEvent_1.exception && Array.isArray(originalEvent_1.exception.values)) {
|
|
38
|
+
originalEvent_1.exception.values = tslib_1.__spread(errorBoundaryEvent.exception.values, originalEvent_1.exception.values);
|
|
39
|
+
}
|
|
40
|
+
return browser_1.captureEvent(originalEvent_1);
|
|
41
|
+
}
|
|
42
|
+
return browser_1.captureException(error, { contexts: { react: { componentStack: componentStack } } });
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A ErrorBoundary component that logs errors to Sentry. Requires React >= 16.
|
|
46
|
+
* NOTE: If you are a Sentry user, and you are seeing this stack frame, it means the
|
|
47
|
+
* Sentry React SDK ErrorBoundary caught an error invoking your application code. This
|
|
48
|
+
* is expected behavior and NOT indicative of a bug with the Sentry React SDK.
|
|
49
|
+
*/
|
|
50
|
+
var ErrorBoundary = /** @class */ (function (_super) {
|
|
51
|
+
tslib_1.__extends(ErrorBoundary, _super);
|
|
52
|
+
function ErrorBoundary() {
|
|
53
|
+
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
54
|
+
_this.state = INITIAL_STATE;
|
|
55
|
+
_this.resetErrorBoundary = function () {
|
|
56
|
+
var onReset = _this.props.onReset;
|
|
57
|
+
var _a = _this.state, error = _a.error, componentStack = _a.componentStack, eventId = _a.eventId;
|
|
58
|
+
if (onReset) {
|
|
59
|
+
onReset(error, componentStack, eventId);
|
|
60
|
+
}
|
|
61
|
+
_this.setState(INITIAL_STATE);
|
|
62
|
+
};
|
|
63
|
+
return _this;
|
|
64
|
+
}
|
|
65
|
+
ErrorBoundary.prototype.componentDidCatch = function (error, _a) {
|
|
66
|
+
var _this = this;
|
|
67
|
+
var componentStack = _a.componentStack;
|
|
68
|
+
var _b = this.props, beforeCapture = _b.beforeCapture, onError = _b.onError, showDialog = _b.showDialog, dialogOptions = _b.dialogOptions;
|
|
69
|
+
browser_1.withScope(function (scope) {
|
|
70
|
+
if (beforeCapture) {
|
|
71
|
+
beforeCapture(scope, error, componentStack);
|
|
72
|
+
}
|
|
73
|
+
var eventId = captureReactErrorBoundaryError(error, componentStack);
|
|
74
|
+
if (onError) {
|
|
75
|
+
onError(error, componentStack, eventId);
|
|
76
|
+
}
|
|
77
|
+
if (showDialog) {
|
|
78
|
+
browser_1.showReportDialog(tslib_1.__assign(tslib_1.__assign({}, dialogOptions), { eventId: eventId }));
|
|
79
|
+
}
|
|
80
|
+
// componentDidCatch is used over getDerivedStateFromError
|
|
81
|
+
// so that componentStack is accessible through state.
|
|
82
|
+
_this.setState({ error: error, componentStack: componentStack, eventId: eventId });
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
ErrorBoundary.prototype.componentDidMount = function () {
|
|
86
|
+
var onMount = this.props.onMount;
|
|
87
|
+
if (onMount) {
|
|
88
|
+
onMount();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
ErrorBoundary.prototype.componentWillUnmount = function () {
|
|
92
|
+
var _a = this.state, error = _a.error, componentStack = _a.componentStack, eventId = _a.eventId;
|
|
93
|
+
var onUnmount = this.props.onUnmount;
|
|
94
|
+
if (onUnmount) {
|
|
95
|
+
onUnmount(error, componentStack, eventId);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
ErrorBoundary.prototype.render = function () {
|
|
99
|
+
var _a = this.props, fallback = _a.fallback, children = _a.children;
|
|
100
|
+
var _b = this.state, error = _b.error, componentStack = _b.componentStack, eventId = _b.eventId;
|
|
101
|
+
if (error) {
|
|
102
|
+
var element = undefined;
|
|
103
|
+
if (typeof fallback === 'function') {
|
|
104
|
+
element = fallback({ error: error, componentStack: componentStack, resetError: this.resetErrorBoundary, eventId: eventId });
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
element = fallback;
|
|
108
|
+
}
|
|
109
|
+
if (React.isValidElement(element)) {
|
|
110
|
+
return element;
|
|
111
|
+
}
|
|
112
|
+
if (fallback) {
|
|
113
|
+
utils_1.logger.warn('fallback did not produce a valid ReactElement');
|
|
114
|
+
}
|
|
115
|
+
// Fail gracefully if no fallback provided or is not valid
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
if (typeof children === 'function') {
|
|
119
|
+
return children();
|
|
120
|
+
}
|
|
121
|
+
return children;
|
|
122
|
+
};
|
|
123
|
+
return ErrorBoundary;
|
|
124
|
+
}(React.Component));
|
|
125
|
+
exports.ErrorBoundary = ErrorBoundary;
|
|
126
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
127
|
+
function withErrorBoundary(WrappedComponent, errorBoundaryOptions) {
|
|
128
|
+
var componentDisplayName = WrappedComponent.displayName || WrappedComponent.name || exports.UNKNOWN_COMPONENT;
|
|
129
|
+
var Wrapped = function (props) { return (React.createElement(ErrorBoundary, tslib_1.__assign({}, errorBoundaryOptions),
|
|
130
|
+
React.createElement(WrappedComponent, tslib_1.__assign({}, props)))); };
|
|
131
|
+
Wrapped.displayName = "errorBoundary(" + componentDisplayName + ")";
|
|
132
|
+
// Copy over static methods from Wrapped component to Profiler HOC
|
|
133
|
+
// See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over
|
|
134
|
+
hoist_non_react_statics_1.default(Wrapped, WrappedComponent);
|
|
135
|
+
return Wrapped;
|
|
136
|
+
}
|
|
137
|
+
exports.withErrorBoundary = withErrorBoundary;
|
|
138
|
+
//# sourceMappingURL=errorboundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorboundary.js","sourceRoot":"","sources":["../src/errorboundary.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n captureEvent,\n captureException,\n eventFromException,\n ReportDialogOptions,\n Scope,\n showReportDialog,\n withScope,\n} from '@sentry/browser';\nimport { Event } from '@sentry/types';\nimport { logger, parseSemver } from '@sentry/utils';\nimport hoistNonReactStatics from 'hoist-non-react-statics';\nimport * as React from 'react';\n\nconst reactVersion = parseSemver(React.version);\n\nexport const UNKNOWN_COMPONENT = 'unknown';\n\nexport type FallbackRender = (errorData: {\n error: Error;\n componentStack: string | null;\n eventId: string | null;\n resetError(): void;\n}) => React.ReactElement;\n\nexport type ErrorBoundaryProps = {\n /** If a Sentry report dialog should be rendered on error */\n showDialog?: boolean;\n /**\n * Options to be passed into the Sentry report dialog.\n * No-op if {@link showDialog} is false.\n */\n dialogOptions?: ReportDialogOptions;\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;\n /** Called when the error boundary encounters an error */\n onError?(error: Error, componentStack: string, eventId: string): void;\n /** Called on componentDidMount() */\n onMount?(): void;\n /** Called if resetError() is called from the fallback render props function */\n onReset?(error: Error | null, componentStack: string | null, eventId: string | null): void;\n /** Called on componentWillUnmount() */\n onUnmount?(error: Error | null, componentStack: string | null, eventId: string | null): void;\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: Error | null, componentStack: string | null): void;\n};\n\ntype ErrorBoundaryState = {\n componentStack: string | null;\n error: Error | null;\n eventId: string | null;\n};\n\nconst INITIAL_STATE = {\n componentStack: null,\n error: null,\n eventId: null,\n};\n\n/**\n * Logs react error boundary errors to Sentry. If on React version >= 17, creates stack trace\n * from componentStack param, otherwise relies on error param for stacktrace.\n *\n * @param error An error captured by React Error Boundary\n * @param componentStack The component stacktrace\n */\nfunction captureReactErrorBoundaryError(error: Error, componentStack: string): string {\n const errorBoundaryError = new Error(error.message);\n errorBoundaryError.name = `React ErrorBoundary ${errorBoundaryError.name}`;\n errorBoundaryError.stack = componentStack;\n\n let errorBoundaryEvent: Event = {};\n void eventFromException({}, errorBoundaryError).then(e => {\n errorBoundaryEvent = e;\n });\n\n if (\n errorBoundaryEvent.exception &&\n Array.isArray(errorBoundaryEvent.exception.values) &&\n reactVersion.major &&\n reactVersion.major >= 17\n ) {\n let originalEvent: Event = {};\n void eventFromException({}, error).then(e => {\n originalEvent = e;\n });\n if (originalEvent.exception && Array.isArray(originalEvent.exception.values)) {\n originalEvent.exception.values = [...errorBoundaryEvent.exception.values, ...originalEvent.exception.values];\n }\n\n return captureEvent(originalEvent);\n }\n\n return captureException(error, { contexts: { react: { componentStack } } });\n}\n\n/**\n * A ErrorBoundary component that logs errors to Sentry. Requires React >= 16.\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 = INITIAL_STATE;\n\n public componentDidCatch(error: Error, { componentStack }: React.ErrorInfo): void {\n const { beforeCapture, onError, showDialog, dialogOptions } = this.props;\n\n withScope(scope => {\n if (beforeCapture) {\n beforeCapture(scope, error, componentStack);\n }\n const eventId = captureReactErrorBoundaryError(error, componentStack);\n if (onError) {\n onError(error, componentStack, eventId);\n }\n if (showDialog) {\n showReportDialog({ ...dialogOptions, eventId });\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 { error, componentStack, eventId } = this.state;\n\n if (error) {\n let element: React.ReactElement | undefined = undefined;\n if (typeof fallback === 'function') {\n element = fallback({ error, componentStack, resetError: this.resetErrorBoundary, eventId });\n } else {\n element = fallback;\n }\n\n if (React.isValidElement(element)) {\n return element;\n }\n\n if (fallback) {\n 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();\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"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from '@sentry/browser';
|
|
2
|
+
export { init } from './sdk';
|
|
3
|
+
export { Profiler, withProfiler, useProfiler } from './profiler';
|
|
4
|
+
export { ErrorBoundary, withErrorBoundary } from './errorboundary';
|
|
5
|
+
export { createReduxEnhancer } from './redux';
|
|
6
|
+
export { reactRouterV3Instrumentation } from './reactrouterv3';
|
|
7
|
+
export { reactRouterV4Instrumentation, reactRouterV5Instrumentation, withSentryRouting } from './reactrouter';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,4BAA4B,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
|
+
var tslib_1 = require("tslib");
|
|
3
|
+
tslib_1.__exportStar(require("@sentry/browser"), exports);
|
|
4
|
+
var sdk_1 = require("./sdk");
|
|
5
|
+
exports.init = sdk_1.init;
|
|
6
|
+
var profiler_1 = require("./profiler");
|
|
7
|
+
exports.Profiler = profiler_1.Profiler;
|
|
8
|
+
exports.withProfiler = profiler_1.withProfiler;
|
|
9
|
+
exports.useProfiler = profiler_1.useProfiler;
|
|
10
|
+
var errorboundary_1 = require("./errorboundary");
|
|
11
|
+
exports.ErrorBoundary = errorboundary_1.ErrorBoundary;
|
|
12
|
+
exports.withErrorBoundary = errorboundary_1.withErrorBoundary;
|
|
13
|
+
var redux_1 = require("./redux");
|
|
14
|
+
exports.createReduxEnhancer = redux_1.createReduxEnhancer;
|
|
15
|
+
var reactrouterv3_1 = require("./reactrouterv3");
|
|
16
|
+
exports.reactRouterV3Instrumentation = reactrouterv3_1.reactRouterV3Instrumentation;
|
|
17
|
+
var reactrouter_1 = require("./reactrouter");
|
|
18
|
+
exports.reactRouterV4Instrumentation = reactrouter_1.reactRouterV4Instrumentation;
|
|
19
|
+
exports.reactRouterV5Instrumentation = reactrouter_1.reactRouterV5Instrumentation;
|
|
20
|
+
exports.withSentryRouting = reactrouter_1.withSentryRouting;
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,0DAAgC;AAEhC,6BAA6B;AAApB,qBAAA,IAAI,CAAA;AACb,uCAAiE;AAAxD,8BAAA,QAAQ,CAAA;AAAE,kCAAA,YAAY,CAAA;AAAE,iCAAA,WAAW,CAAA;AAC5C,iDAAmE;AAA1D,wCAAA,aAAa,CAAA;AAAE,4CAAA,iBAAiB,CAAA;AACzC,iCAA8C;AAArC,sCAAA,mBAAmB,CAAA;AAC5B,iDAA+D;AAAtD,uDAAA,4BAA4B,CAAA;AACrC,6CAA8G;AAArG,qDAAA,4BAA4B,CAAA;AAAE,qDAAA,4BAA4B,CAAA;AAAE,0CAAA,iBAAiB,CAAA","sourcesContent":["export * from '@sentry/browser';\n\nexport { init } from './sdk';\nexport { Profiler, withProfiler, useProfiler } from './profiler';\nexport { ErrorBoundary, withErrorBoundary } from './errorboundary';\nexport { createReduxEnhancer } from './redux';\nexport { reactRouterV3Instrumentation } from './reactrouterv3';\nexport { reactRouterV4Instrumentation, reactRouterV5Instrumentation, withSentryRouting } from './reactrouter';\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Hub } from '@sentry/browser';
|
|
2
|
+
import { Span, Transaction } from '@sentry/types';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
export declare const UNKNOWN_COMPONENT = "unknown";
|
|
5
|
+
export declare type ProfilerProps = {
|
|
6
|
+
name: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
includeRender?: boolean;
|
|
9
|
+
includeUpdates?: boolean;
|
|
10
|
+
updateProps: {
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The Profiler component leverages Sentry's Tracing integration to generate
|
|
16
|
+
* spans based on component lifecycles.
|
|
17
|
+
*/
|
|
18
|
+
declare class Profiler extends React.Component<ProfilerProps> {
|
|
19
|
+
/**
|
|
20
|
+
* The span of the mount activity
|
|
21
|
+
* Made protected for the React Native SDK to access
|
|
22
|
+
*/
|
|
23
|
+
protected _mountSpan: Span | undefined;
|
|
24
|
+
private _mountActivity;
|
|
25
|
+
static defaultProps: Partial<ProfilerProps>;
|
|
26
|
+
constructor(props: ProfilerProps);
|
|
27
|
+
componentDidMount(): void;
|
|
28
|
+
componentDidUpdate({ updateProps, includeUpdates }: ProfilerProps): void;
|
|
29
|
+
componentWillUnmount(): void;
|
|
30
|
+
render(): React.ReactNode;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* withProfiler is a higher order component that wraps a
|
|
34
|
+
* component in a {@link Profiler} component. It is recommended that
|
|
35
|
+
* the higher order component be used over the regular {@link Profiler} component.
|
|
36
|
+
*
|
|
37
|
+
* @param WrappedComponent component that is wrapped by Profiler
|
|
38
|
+
* @param options the {@link ProfilerProps} you can pass into the Profiler
|
|
39
|
+
*/
|
|
40
|
+
declare function withProfiler<P extends Record<string, any>>(WrappedComponent: React.ComponentType<P>, options?: Pick<Partial<ProfilerProps>, Exclude<keyof ProfilerProps, 'updateProps'>>): React.FC<P>;
|
|
41
|
+
/**
|
|
42
|
+
*
|
|
43
|
+
* `useProfiler` is a React hook that profiles a React component.
|
|
44
|
+
*
|
|
45
|
+
* Requires React 16.8 or above.
|
|
46
|
+
* @param name displayName of component being profiled
|
|
47
|
+
*/
|
|
48
|
+
declare function useProfiler(name: string, options?: {
|
|
49
|
+
disabled?: boolean;
|
|
50
|
+
hasRenderSpan?: boolean;
|
|
51
|
+
}): void;
|
|
52
|
+
export { withProfiler, Profiler, useProfiler };
|
|
53
|
+
/** Grabs active transaction off scope */
|
|
54
|
+
export declare function getActiveTransaction<T extends Transaction>(hub?: Hub): T | undefined;
|
|
55
|
+
//# sourceMappingURL=profiler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../src/profiler.tsx"],"names":[],"mappings":"AACA,OAAO,EAAiB,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAiC,IAAI,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjF,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,eAAO,MAAM,iBAAiB,YAAY,CAAC;AA8D3C,oBAAY,aAAa,GAAG;IAE1B,IAAI,EAAE,MAAM,CAAC;IAGb,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,WAAW,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,cAAM,QAAS,SAAQ,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC;IACnD;;;OAGG;IACH,SAAS,CAAC,UAAU,EAAE,IAAI,GAAG,SAAS,CAAa;IAGnD,OAAO,CAAC,cAAc,CAAuB;IAG7C,OAAc,YAAY,EAAE,OAAO,CAAC,aAAa,CAAC,CAIhD;gBAEiB,KAAK,EAAE,aAAa;IAyBhC,iBAAiB,IAAI,IAAI;IAYzB,kBAAkB,CAAC,EAAE,WAAW,EAAE,cAAqB,EAAE,EAAE,aAAa,GAAG,IAAI;IA2B/E,oBAAoB,IAAI,IAAI;IAe5B,MAAM,IAAI,KAAK,CAAC,SAAS;CAGjC;AAED;;;;;;;GAOG;AACH,iBAAS,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjD,gBAAgB,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAExC,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC,MAAM,aAAa,EAAE,aAAa,CAAC,CAAC,GAClF,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAgBb;AAED;;;;;;GAMG;AACH,iBAAS,WAAW,CAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAGrD,GACA,IAAI,CAmCN;AAED,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AAE/C,yCAAyC;AACzC,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,WAAW,EAAE,GAAG,GAAE,GAAqB,GAAG,CAAC,GAAG,SAAS,CASrG"}
|
package/dist/profiler.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
|
+
var tslib_1 = require("tslib");
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
var browser_1 = require("@sentry/browser");
|
|
5
|
+
var utils_1 = require("@sentry/utils");
|
|
6
|
+
var hoist_non_react_statics_1 = tslib_1.__importDefault(require("hoist-non-react-statics"));
|
|
7
|
+
var React = tslib_1.__importStar(require("react"));
|
|
8
|
+
exports.UNKNOWN_COMPONENT = 'unknown';
|
|
9
|
+
var TRACING_GETTER = {
|
|
10
|
+
id: 'Tracing',
|
|
11
|
+
};
|
|
12
|
+
var globalTracingIntegration = null;
|
|
13
|
+
/** @deprecated remove when @sentry/apm no longer used */
|
|
14
|
+
var getTracingIntegration = function () {
|
|
15
|
+
if (globalTracingIntegration) {
|
|
16
|
+
return globalTracingIntegration;
|
|
17
|
+
}
|
|
18
|
+
globalTracingIntegration = browser_1.getCurrentHub().getIntegration(TRACING_GETTER);
|
|
19
|
+
return globalTracingIntegration;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* pushActivity creates an new react activity.
|
|
23
|
+
* Is a no-op if Tracing integration is not valid
|
|
24
|
+
* @param name displayName of component that started activity
|
|
25
|
+
* @deprecated remove when @sentry/apm no longer used
|
|
26
|
+
*/
|
|
27
|
+
function pushActivity(name, op) {
|
|
28
|
+
if (globalTracingIntegration === null) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return globalTracingIntegration.constructor.pushActivity(name, {
|
|
32
|
+
description: "<" + name + ">",
|
|
33
|
+
op: "react." + op,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* popActivity removes a React activity.
|
|
38
|
+
* Is a no-op if Tracing integration is not valid.
|
|
39
|
+
* @param activity id of activity that is being popped
|
|
40
|
+
* @deprecated remove when @sentry/apm no longer used
|
|
41
|
+
*/
|
|
42
|
+
function popActivity(activity) {
|
|
43
|
+
if (activity === null || globalTracingIntegration === null) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
globalTracingIntegration.constructor.popActivity(activity);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Obtain a span given an activity id.
|
|
50
|
+
* Is a no-op if Tracing integration is not valid.
|
|
51
|
+
* @param activity activity id associated with obtained span
|
|
52
|
+
* @deprecated remove when @sentry/apm no longer used
|
|
53
|
+
*/
|
|
54
|
+
function getActivitySpan(activity) {
|
|
55
|
+
if (activity === null || globalTracingIntegration === null) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
return globalTracingIntegration.constructor.getActivitySpan(activity);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The Profiler component leverages Sentry's Tracing integration to generate
|
|
62
|
+
* spans based on component lifecycles.
|
|
63
|
+
*/
|
|
64
|
+
var Profiler = /** @class */ (function (_super) {
|
|
65
|
+
tslib_1.__extends(Profiler, _super);
|
|
66
|
+
function Profiler(props) {
|
|
67
|
+
var _this = _super.call(this, props) || this;
|
|
68
|
+
/**
|
|
69
|
+
* The span of the mount activity
|
|
70
|
+
* Made protected for the React Native SDK to access
|
|
71
|
+
*/
|
|
72
|
+
_this._mountSpan = undefined;
|
|
73
|
+
// The activity representing how long it takes to mount a component.
|
|
74
|
+
_this._mountActivity = null;
|
|
75
|
+
var _a = _this.props, name = _a.name, _b = _a.disabled, disabled = _b === void 0 ? false : _b;
|
|
76
|
+
if (disabled) {
|
|
77
|
+
return _this;
|
|
78
|
+
}
|
|
79
|
+
// If they are using @sentry/apm, we need to push/pop activities
|
|
80
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
81
|
+
if (getTracingIntegration()) {
|
|
82
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
83
|
+
_this._mountActivity = pushActivity(name, 'mount');
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
var activeTransaction = getActiveTransaction();
|
|
87
|
+
if (activeTransaction) {
|
|
88
|
+
_this._mountSpan = activeTransaction.startChild({
|
|
89
|
+
description: "<" + name + ">",
|
|
90
|
+
op: 'react.mount',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return _this;
|
|
95
|
+
}
|
|
96
|
+
// If a component mounted, we can finish the mount activity.
|
|
97
|
+
Profiler.prototype.componentDidMount = function () {
|
|
98
|
+
if (this._mountSpan) {
|
|
99
|
+
this._mountSpan.finish();
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
103
|
+
this._mountSpan = getActivitySpan(this._mountActivity);
|
|
104
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
105
|
+
popActivity(this._mountActivity);
|
|
106
|
+
this._mountActivity = null;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
Profiler.prototype.componentDidUpdate = function (_a) {
|
|
110
|
+
var _this = this;
|
|
111
|
+
var updateProps = _a.updateProps, _b = _a.includeUpdates, includeUpdates = _b === void 0 ? true : _b;
|
|
112
|
+
// Only generate an update span if hasUpdateSpan is true, if there is a valid mountSpan,
|
|
113
|
+
// and if the updateProps have changed. It is ok to not do a deep equality check here as it is expensive.
|
|
114
|
+
// We are just trying to give baseline clues for further investigation.
|
|
115
|
+
if (includeUpdates && this._mountSpan && updateProps !== this.props.updateProps) {
|
|
116
|
+
// See what props haved changed between the previous props, and the current props. This is
|
|
117
|
+
// set as data on the span. We just store the prop keys as the values could be potenially very large.
|
|
118
|
+
var changedProps = Object.keys(updateProps).filter(function (k) { return updateProps[k] !== _this.props.updateProps[k]; });
|
|
119
|
+
if (changedProps.length > 0) {
|
|
120
|
+
// The update span is a point in time span with 0 duration, just signifying that the component
|
|
121
|
+
// has been updated.
|
|
122
|
+
var now = utils_1.timestampWithMs();
|
|
123
|
+
this._mountSpan.startChild({
|
|
124
|
+
data: {
|
|
125
|
+
changedProps: changedProps,
|
|
126
|
+
},
|
|
127
|
+
description: "<" + this.props.name + ">",
|
|
128
|
+
endTimestamp: now,
|
|
129
|
+
op: "react.update",
|
|
130
|
+
startTimestamp: now,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
// If a component is unmounted, we can say it is no longer on the screen.
|
|
136
|
+
// This means we can finish the span representing the component render.
|
|
137
|
+
Profiler.prototype.componentWillUnmount = function () {
|
|
138
|
+
var _a = this.props, name = _a.name, _b = _a.includeRender, includeRender = _b === void 0 ? true : _b;
|
|
139
|
+
if (this._mountSpan && includeRender) {
|
|
140
|
+
// If we were able to obtain the spanId of the mount activity, we should set the
|
|
141
|
+
// next activity as a child to the component mount activity.
|
|
142
|
+
this._mountSpan.startChild({
|
|
143
|
+
description: "<" + name + ">",
|
|
144
|
+
endTimestamp: utils_1.timestampWithMs(),
|
|
145
|
+
op: "react.render",
|
|
146
|
+
startTimestamp: this._mountSpan.endTimestamp,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
Profiler.prototype.render = function () {
|
|
151
|
+
return this.props.children;
|
|
152
|
+
};
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/member-ordering
|
|
154
|
+
Profiler.defaultProps = {
|
|
155
|
+
disabled: false,
|
|
156
|
+
includeRender: true,
|
|
157
|
+
includeUpdates: true,
|
|
158
|
+
};
|
|
159
|
+
return Profiler;
|
|
160
|
+
}(React.Component));
|
|
161
|
+
exports.Profiler = Profiler;
|
|
162
|
+
/**
|
|
163
|
+
* withProfiler is a higher order component that wraps a
|
|
164
|
+
* component in a {@link Profiler} component. It is recommended that
|
|
165
|
+
* the higher order component be used over the regular {@link Profiler} component.
|
|
166
|
+
*
|
|
167
|
+
* @param WrappedComponent component that is wrapped by Profiler
|
|
168
|
+
* @param options the {@link ProfilerProps} you can pass into the Profiler
|
|
169
|
+
*/
|
|
170
|
+
function withProfiler(WrappedComponent,
|
|
171
|
+
// We do not want to have `updateProps` given in options, it is instead filled through the HOC.
|
|
172
|
+
options) {
|
|
173
|
+
var componentDisplayName = (options && options.name) || WrappedComponent.displayName || WrappedComponent.name || exports.UNKNOWN_COMPONENT;
|
|
174
|
+
var Wrapped = function (props) { return (React.createElement(Profiler, tslib_1.__assign({}, options, { name: componentDisplayName, updateProps: props }),
|
|
175
|
+
React.createElement(WrappedComponent, tslib_1.__assign({}, props)))); };
|
|
176
|
+
Wrapped.displayName = "profiler(" + componentDisplayName + ")";
|
|
177
|
+
// Copy over static methods from Wrapped component to Profiler HOC
|
|
178
|
+
// See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over
|
|
179
|
+
hoist_non_react_statics_1.default(Wrapped, WrappedComponent);
|
|
180
|
+
return Wrapped;
|
|
181
|
+
}
|
|
182
|
+
exports.withProfiler = withProfiler;
|
|
183
|
+
/**
|
|
184
|
+
*
|
|
185
|
+
* `useProfiler` is a React hook that profiles a React component.
|
|
186
|
+
*
|
|
187
|
+
* Requires React 16.8 or above.
|
|
188
|
+
* @param name displayName of component being profiled
|
|
189
|
+
*/
|
|
190
|
+
function useProfiler(name, options) {
|
|
191
|
+
if (options === void 0) { options = {
|
|
192
|
+
disabled: false,
|
|
193
|
+
hasRenderSpan: true,
|
|
194
|
+
}; }
|
|
195
|
+
var _a = tslib_1.__read(React.useState(function () {
|
|
196
|
+
if (options && options.disabled) {
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
var activeTransaction = getActiveTransaction();
|
|
200
|
+
if (activeTransaction) {
|
|
201
|
+
return activeTransaction.startChild({
|
|
202
|
+
description: "<" + name + ">",
|
|
203
|
+
op: 'react.mount',
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return undefined;
|
|
207
|
+
}), 1), mountSpan = _a[0];
|
|
208
|
+
React.useEffect(function () {
|
|
209
|
+
if (mountSpan) {
|
|
210
|
+
mountSpan.finish();
|
|
211
|
+
}
|
|
212
|
+
return function () {
|
|
213
|
+
if (mountSpan && options.hasRenderSpan) {
|
|
214
|
+
mountSpan.startChild({
|
|
215
|
+
description: "<" + name + ">",
|
|
216
|
+
endTimestamp: utils_1.timestampWithMs(),
|
|
217
|
+
op: "react.render",
|
|
218
|
+
startTimestamp: mountSpan.endTimestamp,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
// We only want this to run once.
|
|
223
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
224
|
+
}, []);
|
|
225
|
+
}
|
|
226
|
+
exports.useProfiler = useProfiler;
|
|
227
|
+
/** Grabs active transaction off scope */
|
|
228
|
+
function getActiveTransaction(hub) {
|
|
229
|
+
if (hub === void 0) { hub = browser_1.getCurrentHub(); }
|
|
230
|
+
if (hub) {
|
|
231
|
+
var scope = hub.getScope();
|
|
232
|
+
if (scope) {
|
|
233
|
+
return scope.getTransaction();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
exports.getActiveTransaction = getActiveTransaction;
|
|
239
|
+
//# sourceMappingURL=profiler.js.map
|