@flareapp/react 2.2.1 → 2.4.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 +35 -2
- package/dist/index.cjs +53 -20
- package/dist/index.d.cts +8 -1
- package/dist/index.d.mts +8 -1
- package/dist/index.mjs +54 -21
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @flareapp/react
|
|
2
2
|
|
|
3
|
-
React integration for [Flare](https://flareapp.io) error tracking. Provides an error boundary component and
|
|
4
|
-
error handler for catching and reporting React component errors to Flare.
|
|
3
|
+
React integration for [Flare](https://flareapp.io) error tracking and logging. Provides an error boundary component and
|
|
4
|
+
a React 19+ error handler for catching and reporting React component errors to Flare.
|
|
5
5
|
|
|
6
6
|
## Installation
|
|
7
7
|
|
|
@@ -28,6 +28,39 @@ function App() {
|
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
## Logging
|
|
32
|
+
|
|
33
|
+
Beyond errors, the client can send structured logs. Logs are opt-in: enable them with `enableLogs`, then call any of the
|
|
34
|
+
eight syslog levels (`debug`, `info`, `notice`, `warning`, `error`, `critical`, `alert`, `emergency`).
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { flare } from '@flareapp/js';
|
|
38
|
+
|
|
39
|
+
flare.configure({ enableLogs: true });
|
|
40
|
+
|
|
41
|
+
flare.logger.info('Checkout started', { cartId: cart.id, total: cart.total });
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Minified production errors
|
|
45
|
+
|
|
46
|
+
In production, React throws minified errors like `Minified React error #418; visit https://react.dev/errors/418?args[]=Foo`.
|
|
47
|
+
The client parses these into structured fields and attaches them, along with the running React version, to the report
|
|
48
|
+
context:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
react: {
|
|
52
|
+
version: '19.0.0',
|
|
53
|
+
minifiedError: {
|
|
54
|
+
number: 418,
|
|
55
|
+
args: ['Foo', 'Bar'],
|
|
56
|
+
url: 'https://react.dev/errors/418?args[]=Foo&args[]=Bar',
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Flare uses `react.minifiedError` and `react.version` on the backend to look up React's error-code map and surface the
|
|
62
|
+
full, human-readable message. No error-code map is bundled into the client. Non-minified errors are reported unchanged.
|
|
63
|
+
|
|
31
64
|
## Documentation
|
|
32
65
|
|
|
33
66
|
Full documentation on the error boundary, the React 19+ error handler, lifecycle callbacks, and more is available
|
package/dist/index.cjs
CHANGED
|
@@ -33,7 +33,7 @@ react = __toESM(react);
|
|
|
33
33
|
//#region src/constants.ts
|
|
34
34
|
const CHROMIUM_STACK_REGEX = /^at\s+(\S+)(?:\s+\((.+):(\d+):(\d+)\))?$/;
|
|
35
35
|
const FIREFOX_SAFARI_STACK_REGEX = /^(\S+?)@(.+):(\d+):(\d+)$/;
|
|
36
|
-
const PACKAGE_VERSION = typeof process !== "undefined" && true ? "2.
|
|
36
|
+
const PACKAGE_VERSION = typeof process !== "undefined" && true ? "2.4.0" : "?";
|
|
37
37
|
|
|
38
38
|
//#endregion
|
|
39
39
|
//#region src/identify.ts
|
|
@@ -51,15 +51,6 @@ function registerReactSdkIdentity() {
|
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
//#endregion
|
|
55
|
-
//#region src/contextToAttributes.ts
|
|
56
|
-
function contextToAttributes(context) {
|
|
57
|
-
return { "context.custom": { react: {
|
|
58
|
-
componentStack: context.react.componentStack,
|
|
59
|
-
componentStackFrames: context.react.componentStackFrames
|
|
60
|
-
} } };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
54
|
//#endregion
|
|
64
55
|
//#region src/formatComponentStack.ts
|
|
65
56
|
function formatComponentStack(stack) {
|
|
@@ -93,6 +84,56 @@ function parseComponentStack(stack) {
|
|
|
93
84
|
});
|
|
94
85
|
}
|
|
95
86
|
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/parseMinifiedReactError.ts
|
|
89
|
+
const NUMBER_PATTERN = /Minified React error #(\d+)/;
|
|
90
|
+
const ARG_PATTERN = /args\[\]=([^&\s]*)/g;
|
|
91
|
+
const URL_PATTERN = /(https?:\/\/\S+)/;
|
|
92
|
+
function safeDecode(value) {
|
|
93
|
+
try {
|
|
94
|
+
return decodeURIComponent(value);
|
|
95
|
+
} catch {
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function parseMinifiedReactError(error) {
|
|
100
|
+
const message = error?.message;
|
|
101
|
+
if (!message) return null;
|
|
102
|
+
const numberMatch = message.match(NUMBER_PATTERN);
|
|
103
|
+
if (!numberMatch) return null;
|
|
104
|
+
const args = [];
|
|
105
|
+
for (const match of message.matchAll(ARG_PATTERN)) args.push(safeDecode(match[1]));
|
|
106
|
+
const urlMatch = message.match(URL_PATTERN);
|
|
107
|
+
return {
|
|
108
|
+
number: Number(numberMatch[1]),
|
|
109
|
+
args,
|
|
110
|
+
url: urlMatch ? urlMatch[1] : null
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/buildReactContext.ts
|
|
116
|
+
function buildReactContext(rawStack, error) {
|
|
117
|
+
const minifiedError = parseMinifiedReactError(error);
|
|
118
|
+
return { react: {
|
|
119
|
+
componentStack: formatComponentStack(rawStack),
|
|
120
|
+
componentStackFrames: parseComponentStack(rawStack),
|
|
121
|
+
version: react.version,
|
|
122
|
+
...minifiedError ? { minifiedError } : {}
|
|
123
|
+
} };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region src/contextToAttributes.ts
|
|
128
|
+
function contextToAttributes(context) {
|
|
129
|
+
return { "context.custom": { react: {
|
|
130
|
+
componentStack: context.react.componentStack,
|
|
131
|
+
componentStackFrames: context.react.componentStackFrames,
|
|
132
|
+
...context.react.version ? { version: context.react.version } : {},
|
|
133
|
+
...context.react.minifiedError ? { minifiedError: context.react.minifiedError } : {}
|
|
134
|
+
} } };
|
|
135
|
+
}
|
|
136
|
+
|
|
96
137
|
//#endregion
|
|
97
138
|
//#region src/FlareErrorBoundary.ts
|
|
98
139
|
var FlareErrorBoundary = class extends react.Component {
|
|
@@ -108,11 +149,7 @@ var FlareErrorBoundary = class extends react.Component {
|
|
|
108
149
|
error,
|
|
109
150
|
errorInfo
|
|
110
151
|
});
|
|
111
|
-
const
|
|
112
|
-
const context = { react: {
|
|
113
|
-
componentStack: formatComponentStack(rawStack),
|
|
114
|
-
componentStackFrames: parseComponentStack(rawStack)
|
|
115
|
-
} };
|
|
152
|
+
const context = buildReactContext(errorInfo.componentStack ?? "", error);
|
|
116
153
|
const finalContext = this.props.beforeSubmit?.({
|
|
117
154
|
error,
|
|
118
155
|
errorInfo,
|
|
@@ -166,11 +203,7 @@ function flareReactErrorHandler(options) {
|
|
|
166
203
|
error: errorObject,
|
|
167
204
|
errorInfo
|
|
168
205
|
});
|
|
169
|
-
const
|
|
170
|
-
const context = { react: {
|
|
171
|
-
componentStack: formatComponentStack(rawStack),
|
|
172
|
-
componentStackFrames: parseComponentStack(rawStack)
|
|
173
|
-
} };
|
|
206
|
+
const context = buildReactContext(errorInfo.componentStack ?? "", errorObject);
|
|
174
207
|
const finalContext = options?.beforeSubmit?.({
|
|
175
208
|
error: errorObject,
|
|
176
209
|
errorInfo,
|
package/dist/index.d.cts
CHANGED
|
@@ -7,10 +7,17 @@ type ComponentStackFrame = {
|
|
|
7
7
|
line: number | null;
|
|
8
8
|
column: number | null;
|
|
9
9
|
};
|
|
10
|
+
type MinifiedReactError = {
|
|
11
|
+
number: number;
|
|
12
|
+
args: string[];
|
|
13
|
+
url: string | null;
|
|
14
|
+
};
|
|
10
15
|
type FlareReactContext = {
|
|
11
16
|
react: {
|
|
12
17
|
componentStack: string[];
|
|
13
18
|
componentStackFrames: ComponentStackFrame[];
|
|
19
|
+
version?: string;
|
|
20
|
+
minifiedError?: MinifiedReactError;
|
|
14
21
|
};
|
|
15
22
|
};
|
|
16
23
|
//#endregion
|
|
@@ -80,4 +87,4 @@ type FlareReactErrorHandlerOptions = {
|
|
|
80
87
|
};
|
|
81
88
|
declare function flareReactErrorHandler(options?: FlareReactErrorHandlerOptions): FlareReactErrorHandlerCallback;
|
|
82
89
|
//#endregion
|
|
83
|
-
export { type ComponentStackFrame, FlareErrorBoundary, type FlareErrorBoundaryFallbackProps, type FlareErrorBoundaryProps, type FlareReactContext, type FlareReactErrorHandlerCallback, type FlareReactErrorHandlerOptions, flareReactErrorHandler };
|
|
90
|
+
export { type ComponentStackFrame, FlareErrorBoundary, type FlareErrorBoundaryFallbackProps, type FlareErrorBoundaryProps, type FlareReactContext, type FlareReactErrorHandlerCallback, type FlareReactErrorHandlerOptions, type MinifiedReactError, flareReactErrorHandler };
|
package/dist/index.d.mts
CHANGED
|
@@ -7,10 +7,17 @@ type ComponentStackFrame = {
|
|
|
7
7
|
line: number | null;
|
|
8
8
|
column: number | null;
|
|
9
9
|
};
|
|
10
|
+
type MinifiedReactError = {
|
|
11
|
+
number: number;
|
|
12
|
+
args: string[];
|
|
13
|
+
url: string | null;
|
|
14
|
+
};
|
|
10
15
|
type FlareReactContext = {
|
|
11
16
|
react: {
|
|
12
17
|
componentStack: string[];
|
|
13
18
|
componentStackFrames: ComponentStackFrame[];
|
|
19
|
+
version?: string;
|
|
20
|
+
minifiedError?: MinifiedReactError;
|
|
14
21
|
};
|
|
15
22
|
};
|
|
16
23
|
//#endregion
|
|
@@ -80,4 +87,4 @@ type FlareReactErrorHandlerOptions = {
|
|
|
80
87
|
};
|
|
81
88
|
declare function flareReactErrorHandler(options?: FlareReactErrorHandlerOptions): FlareReactErrorHandlerCallback;
|
|
82
89
|
//#endregion
|
|
83
|
-
export { type ComponentStackFrame, FlareErrorBoundary, type FlareErrorBoundaryFallbackProps, type FlareErrorBoundaryProps, type FlareReactContext, type FlareReactErrorHandlerCallback, type FlareReactErrorHandlerOptions, flareReactErrorHandler };
|
|
90
|
+
export { type ComponentStackFrame, FlareErrorBoundary, type FlareErrorBoundaryFallbackProps, type FlareErrorBoundaryProps, type FlareReactContext, type FlareReactErrorHandlerCallback, type FlareReactErrorHandlerOptions, type MinifiedReactError, flareReactErrorHandler };
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { convertToError, flare } from "@flareapp/js";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import { Component } from "react";
|
|
3
|
+
import { Component, version } from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/constants.ts
|
|
6
6
|
const CHROMIUM_STACK_REGEX = /^at\s+(\S+)(?:\s+\((.+):(\d+):(\d+)\))?$/;
|
|
7
7
|
const FIREFOX_SAFARI_STACK_REGEX = /^(\S+?)@(.+):(\d+):(\d+)$/;
|
|
8
|
-
const PACKAGE_VERSION = typeof process !== "undefined" && true ? "2.
|
|
8
|
+
const PACKAGE_VERSION = typeof process !== "undefined" && true ? "2.4.0" : "?";
|
|
9
9
|
|
|
10
10
|
//#endregion
|
|
11
11
|
//#region src/identify.ts
|
|
@@ -23,15 +23,6 @@ function registerReactSdkIdentity() {
|
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
//#endregion
|
|
27
|
-
//#region src/contextToAttributes.ts
|
|
28
|
-
function contextToAttributes(context) {
|
|
29
|
-
return { "context.custom": { react: {
|
|
30
|
-
componentStack: context.react.componentStack,
|
|
31
|
-
componentStackFrames: context.react.componentStackFrames
|
|
32
|
-
} } };
|
|
33
|
-
}
|
|
34
|
-
|
|
35
26
|
//#endregion
|
|
36
27
|
//#region src/formatComponentStack.ts
|
|
37
28
|
function formatComponentStack(stack) {
|
|
@@ -65,6 +56,56 @@ function parseComponentStack(stack) {
|
|
|
65
56
|
});
|
|
66
57
|
}
|
|
67
58
|
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/parseMinifiedReactError.ts
|
|
61
|
+
const NUMBER_PATTERN = /Minified React error #(\d+)/;
|
|
62
|
+
const ARG_PATTERN = /args\[\]=([^&\s]*)/g;
|
|
63
|
+
const URL_PATTERN = /(https?:\/\/\S+)/;
|
|
64
|
+
function safeDecode(value) {
|
|
65
|
+
try {
|
|
66
|
+
return decodeURIComponent(value);
|
|
67
|
+
} catch {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function parseMinifiedReactError(error) {
|
|
72
|
+
const message = error?.message;
|
|
73
|
+
if (!message) return null;
|
|
74
|
+
const numberMatch = message.match(NUMBER_PATTERN);
|
|
75
|
+
if (!numberMatch) return null;
|
|
76
|
+
const args = [];
|
|
77
|
+
for (const match of message.matchAll(ARG_PATTERN)) args.push(safeDecode(match[1]));
|
|
78
|
+
const urlMatch = message.match(URL_PATTERN);
|
|
79
|
+
return {
|
|
80
|
+
number: Number(numberMatch[1]),
|
|
81
|
+
args,
|
|
82
|
+
url: urlMatch ? urlMatch[1] : null
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/buildReactContext.ts
|
|
88
|
+
function buildReactContext(rawStack, error) {
|
|
89
|
+
const minifiedError = parseMinifiedReactError(error);
|
|
90
|
+
return { react: {
|
|
91
|
+
componentStack: formatComponentStack(rawStack),
|
|
92
|
+
componentStackFrames: parseComponentStack(rawStack),
|
|
93
|
+
version,
|
|
94
|
+
...minifiedError ? { minifiedError } : {}
|
|
95
|
+
} };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region src/contextToAttributes.ts
|
|
100
|
+
function contextToAttributes(context) {
|
|
101
|
+
return { "context.custom": { react: {
|
|
102
|
+
componentStack: context.react.componentStack,
|
|
103
|
+
componentStackFrames: context.react.componentStackFrames,
|
|
104
|
+
...context.react.version ? { version: context.react.version } : {},
|
|
105
|
+
...context.react.minifiedError ? { minifiedError: context.react.minifiedError } : {}
|
|
106
|
+
} } };
|
|
107
|
+
}
|
|
108
|
+
|
|
68
109
|
//#endregion
|
|
69
110
|
//#region src/FlareErrorBoundary.ts
|
|
70
111
|
var FlareErrorBoundary = class extends Component {
|
|
@@ -80,11 +121,7 @@ var FlareErrorBoundary = class extends Component {
|
|
|
80
121
|
error,
|
|
81
122
|
errorInfo
|
|
82
123
|
});
|
|
83
|
-
const
|
|
84
|
-
const context = { react: {
|
|
85
|
-
componentStack: formatComponentStack(rawStack),
|
|
86
|
-
componentStackFrames: parseComponentStack(rawStack)
|
|
87
|
-
} };
|
|
124
|
+
const context = buildReactContext(errorInfo.componentStack ?? "", error);
|
|
88
125
|
const finalContext = this.props.beforeSubmit?.({
|
|
89
126
|
error,
|
|
90
127
|
errorInfo,
|
|
@@ -138,11 +175,7 @@ function flareReactErrorHandler(options) {
|
|
|
138
175
|
error: errorObject,
|
|
139
176
|
errorInfo
|
|
140
177
|
});
|
|
141
|
-
const
|
|
142
|
-
const context = { react: {
|
|
143
|
-
componentStack: formatComponentStack(rawStack),
|
|
144
|
-
componentStackFrames: parseComponentStack(rawStack)
|
|
145
|
-
} };
|
|
178
|
+
const context = buildReactContext(errorInfo.componentStack ?? "", errorObject);
|
|
146
179
|
const finalContext = options?.beforeSubmit?.({
|
|
147
180
|
error: errorObject,
|
|
148
181
|
errorInfo,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flareapp/react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "React client for flareapp.io",
|
|
5
5
|
"homepage": "https://flareapp.io",
|
|
6
6
|
"bugs": "https://github.com/spatie/flare-client-js/issues",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"vitest": "^4.0.0"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@flareapp/js": "^2.
|
|
63
|
+
"@flareapp/js": "^2.4.0",
|
|
64
64
|
"react": "^16.0.0||^17.0.0||^18.0.0||^19.0.0"
|
|
65
65
|
},
|
|
66
66
|
"publishConfig": {
|