@grafana/faro-react-native 1.1.0 → 1.2.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/README.md +72 -0
- package/android/build.gradle +145 -0
- package/dist/cjs/config/getRNInstrumentations.js +3 -1
- package/dist/cjs/config/getRNInstrumentations.js.map +1 -1
- package/dist/cjs/config/makeRNConfig.js +7 -4
- package/dist/cjs/config/makeRNConfig.js.map +1 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/generated/faroRNPackageMeta.js +1 -1
- package/dist/cjs/generated/faroRNPackageMeta.js.map +1 -1
- package/dist/cjs/instrumentations/errors/index.js +3 -2
- package/dist/cjs/instrumentations/errors/index.js.map +1 -1
- package/dist/cjs/instrumentations/errors/stackTraceParser.js +98 -37
- package/dist/cjs/instrumentations/errors/stackTraceParser.js.map +1 -1
- package/dist/esm/config/getRNInstrumentations.js +3 -1
- package/dist/esm/config/getRNInstrumentations.js.map +1 -1
- package/dist/esm/config/makeRNConfig.js +7 -4
- package/dist/esm/config/makeRNConfig.js.map +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/generated/faroRNPackageMeta.js +1 -1
- package/dist/esm/generated/faroRNPackageMeta.js.map +1 -1
- package/dist/esm/instrumentations/errors/index.js +3 -2
- package/dist/esm/instrumentations/errors/index.js.map +1 -1
- package/dist/esm/instrumentations/errors/stackTraceParser.js +97 -37
- package/dist/esm/instrumentations/errors/stackTraceParser.js.map +1 -1
- package/dist/types/config/types.d.ts +5 -0
- package/dist/types/generated/faroRNPackageMeta.d.ts +1 -1
- package/dist/types/instrumentations/errors/index.d.ts +5 -0
- package/dist/types/instrumentations/errors/stackTraceParser.d.ts +19 -3
- package/ios/faro-upload-composed-source-map.sh +93 -0
- package/package.json +7 -10
- package/react-native.config.js +9 -1
- package/src/config/getRNInstrumentations.ts +5 -1
- package/src/config/makeRNConfig.test.ts +11 -0
- package/src/config/makeRNConfig.ts +7 -4
- package/src/config/types.ts +5 -0
- package/src/generated/faroRNPackageMeta.ts +1 -1
- package/src/initialize.test.ts +25 -0
- package/src/instrumentations/errors/index.ts +25 -8
- package/src/instrumentations/errors/stackTraceParser.test.ts +65 -0
- package/src/instrumentations/errors/stackTraceParser.ts +121 -37
|
@@ -40,6 +40,12 @@ export interface ErrorsInstrumentationOptions {
|
|
|
40
40
|
* Older errors are removed when this limit is reached
|
|
41
41
|
*/
|
|
42
42
|
maxDeduplicationEntries?: number;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Bundle filename for Hermes/minified release lines (`func@line:col`).
|
|
46
|
+
* Must match the Metro plugin source map `file` field (default `bundle.js`).
|
|
47
|
+
*/
|
|
48
|
+
releaseBundleFilename?: string;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
interface ErrorFingerprint {
|
|
@@ -80,7 +86,9 @@ export class ErrorsInstrumentation extends BaseInstrumentation {
|
|
|
80
86
|
|
|
81
87
|
private originalErrorHandler?: ErrorHandlerCallback;
|
|
82
88
|
private unhandledRejectionListener?: (event: PromiseRejectionEvent) => void;
|
|
83
|
-
private options: Required<ErrorsInstrumentationOptions
|
|
89
|
+
private options: Required<Omit<ErrorsInstrumentationOptions, 'releaseBundleFilename'>> & {
|
|
90
|
+
releaseBundleFilename?: string;
|
|
91
|
+
};
|
|
84
92
|
private errorFingerprints: ErrorFingerprint[] = [];
|
|
85
93
|
|
|
86
94
|
constructor(options: ErrorsInstrumentationOptions = {}) {
|
|
@@ -90,6 +98,7 @@ export class ErrorsInstrumentation extends BaseInstrumentation {
|
|
|
90
98
|
enableDeduplication: options.enableDeduplication ?? true,
|
|
91
99
|
deduplicationWindow: options.deduplicationWindow ?? 5000,
|
|
92
100
|
maxDeduplicationEntries: options.maxDeduplicationEntries ?? 50,
|
|
101
|
+
releaseBundleFilename: options.releaseBundleFilename,
|
|
93
102
|
};
|
|
94
103
|
}
|
|
95
104
|
|
|
@@ -123,10 +132,14 @@ export class ErrorsInstrumentation extends BaseInstrumentation {
|
|
|
123
132
|
error: enhancedError,
|
|
124
133
|
stackFrames,
|
|
125
134
|
context,
|
|
126
|
-
} = enhanceErrorWithContext(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
135
|
+
} = enhanceErrorWithContext(
|
|
136
|
+
error,
|
|
137
|
+
{
|
|
138
|
+
mechanism: ErrorMechanism.UNCAUGHT,
|
|
139
|
+
isFatal: String(isFatal ?? false),
|
|
140
|
+
},
|
|
141
|
+
{ releaseBundleFilename: this.options.releaseBundleFilename }
|
|
142
|
+
);
|
|
130
143
|
|
|
131
144
|
// Push error to Faro with enhanced data (type from error.name, matches Web SDK)
|
|
132
145
|
this.api.pushError(enhancedError, {
|
|
@@ -182,9 +195,13 @@ export class ErrorsInstrumentation extends BaseInstrumentation {
|
|
|
182
195
|
error: enhancedError,
|
|
183
196
|
stackFrames,
|
|
184
197
|
context,
|
|
185
|
-
} = enhanceErrorWithContext(
|
|
186
|
-
|
|
187
|
-
|
|
198
|
+
} = enhanceErrorWithContext(
|
|
199
|
+
error,
|
|
200
|
+
{
|
|
201
|
+
mechanism: ErrorMechanism.UNHANDLED_REJECTION,
|
|
202
|
+
},
|
|
203
|
+
{ releaseBundleFilename: this.options.releaseBundleFilename }
|
|
204
|
+
);
|
|
188
205
|
|
|
189
206
|
// Type: use actual error type for Error objects; 'UnhandledRejection' for primitives (Web SDK)
|
|
190
207
|
const errorType = isPrimitiveRejection ? primitiveUnhandledType : enhancedError.name || 'Error';
|
|
@@ -65,6 +65,29 @@ describe('Stack Trace Parser', () => {
|
|
|
65
65
|
filename: '<unknown>',
|
|
66
66
|
lineno: 123,
|
|
67
67
|
colno: 456,
|
|
68
|
+
releaseLine: true,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should normalize Hermes Android "address at index.android.bundle" file segment', () => {
|
|
73
|
+
const line = ' at someFunction (address at index.android.bundle:42:15)';
|
|
74
|
+
const frame = parseStackTraceLine(line);
|
|
75
|
+
|
|
76
|
+
expect(frame).toEqual({
|
|
77
|
+
function: 'someFunction',
|
|
78
|
+
filename: 'index.android.bundle',
|
|
79
|
+
lineno: 42,
|
|
80
|
+
colno: 15,
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should parse Hermes-style parenthesis frame with bundle filename', () => {
|
|
85
|
+
const line = ' at reportError (index.android.bundle:1:849989)';
|
|
86
|
+
expect(parseStackTraceLine(line)).toEqual({
|
|
87
|
+
function: 'reportError',
|
|
88
|
+
filename: 'index.android.bundle',
|
|
89
|
+
lineno: 1,
|
|
90
|
+
colno: 849989,
|
|
68
91
|
});
|
|
69
92
|
});
|
|
70
93
|
|
|
@@ -165,6 +188,39 @@ describe('Stack Trace Parser', () => {
|
|
|
165
188
|
const faroFrames = toFaroStackFrames([]);
|
|
166
189
|
expect(faroFrames).toEqual([]);
|
|
167
190
|
});
|
|
191
|
+
|
|
192
|
+
it('maps release placeholders to bundle.js in Faro frames', () => {
|
|
193
|
+
const parsed = parseStackTraceLine('a@123:456');
|
|
194
|
+
expect(parsed).not.toBeNull();
|
|
195
|
+
const faroFrames = toFaroStackFrames([parsed!]);
|
|
196
|
+
expect(faroFrames[0]?.filename).toBe('bundle.js');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('maps release placeholders to a custom bundle filename', () => {
|
|
200
|
+
const parsed = parseStackTraceLine('a@123:456');
|
|
201
|
+
expect(parsed).not.toBeNull();
|
|
202
|
+
const faroFrames = toFaroStackFrames([parsed!], { releaseBundleFilename: 'index.android.bundle' });
|
|
203
|
+
expect(faroFrames[0]?.filename).toBe('index.android.bundle');
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('collapses Hermes absolute .app bundle path to basename so uploads match ingest keys', () => {
|
|
207
|
+
const iosPath =
|
|
208
|
+
'/Users/ci/Library/Developer/CoreSimulator/Devices/ABC/Data/Containers/Bundle/Application/62A2/QuickPizza.app/main.jsbundle';
|
|
209
|
+
const parsed = parseStackTraceLine(` at reportHandledException (${iosPath}:1:1249030)`);
|
|
210
|
+
expect(parsed).not.toBeNull();
|
|
211
|
+
const faroFrames = toFaroStackFrames([parsed!], { releaseBundleFilename: 'main.jsbundle' });
|
|
212
|
+
expect(faroFrames[0]?.filename).toBe('main.jsbundle');
|
|
213
|
+
expect(faroFrames[0]?.lineno).toBe(1);
|
|
214
|
+
expect(faroFrames[0]?.colno).toBe(1249030);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('collapses absolute Android artifact path ending in index.android.bundle', () => {
|
|
218
|
+
const apkPath = '/data/app/org.example.cp/base.apk/assets/index.android.bundle';
|
|
219
|
+
const parsed = parseStackTraceLine(` at reportError (${apkPath}:1:849989)`);
|
|
220
|
+
expect(parsed).not.toBeNull();
|
|
221
|
+
const faroFrames = toFaroStackFrames([parsed!], { releaseBundleFilename: 'index.android.bundle' });
|
|
222
|
+
expect(faroFrames[0]?.filename).toBe('index.android.bundle');
|
|
223
|
+
});
|
|
168
224
|
});
|
|
169
225
|
|
|
170
226
|
describe('getStackFramesFromError', () => {
|
|
@@ -243,5 +299,14 @@ describe('Stack Trace Parser', () => {
|
|
|
243
299
|
expect(result.context).toHaveProperty('customField', 'customValue');
|
|
244
300
|
expect(result.context).toHaveProperty('platform');
|
|
245
301
|
});
|
|
302
|
+
|
|
303
|
+
it('applies stack parse options for release frames', () => {
|
|
304
|
+
const error = new Error('Test');
|
|
305
|
+
error.stack = 'global@10:20';
|
|
306
|
+
|
|
307
|
+
const result = enhanceErrorWithContext(error, undefined, { releaseBundleFilename: 'main.jsbundle' });
|
|
308
|
+
|
|
309
|
+
expect(result.stackFrames[0]?.filename).toBe('main.jsbundle');
|
|
310
|
+
});
|
|
246
311
|
});
|
|
247
312
|
});
|
|
@@ -28,35 +28,85 @@ const REACT_NATIVE_RELEASE_REGEX = /^(.+?)@(\d+):(\d+)$/;
|
|
|
28
28
|
const REACT_NATIVE_ANONYMOUS_REGEX = /^\s*at\s+anonymous\s+\((.+?):(\d+):(\d+)\)$/;
|
|
29
29
|
const METRO_BUNDLER_REGEX = /^\s*at\s+(?:Object\.)?(.+?)\s+\((.+?):(\d+):(\d+)\)$/;
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Hermes (Android release) often reports the bundle segment as `address at index.android.bundle`
|
|
33
|
+
* inside parentheses. The collector hashes `frame.filename` for uploaded maps; it must match the
|
|
34
|
+
* source map `file` field (e.g. `index.android.bundle`), not the verbose Hermes label.
|
|
35
|
+
*/
|
|
36
|
+
export function normalizeHermesStackFilename(filename: string): string {
|
|
37
|
+
const trimmed = filename.trim();
|
|
38
|
+
const m = /^address\s+at\s+(.+)$/i.exec(trimmed);
|
|
39
|
+
return m?.[1]?.trim() ?? filename;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* iOS Simulator (and Android) stacks often carry full filesystem paths such as
|
|
44
|
+
* `…/Foo.app/main.jsbundle` while uploaded maps are keyed by the bundle basename (`main.jsbundle`)
|
|
45
|
+
* that matches Metro’s source map `file` field — same as ingest’s bundle lookup hashes.
|
|
46
|
+
*/
|
|
47
|
+
function collapseBundledArtifactPath(filename: string, releaseBasename: string): string {
|
|
48
|
+
const key = releaseBasename.trim();
|
|
49
|
+
if (!key || filename === key) {
|
|
50
|
+
return filename;
|
|
51
|
+
}
|
|
52
|
+
const suffix = `/${key}`;
|
|
53
|
+
return filename.endsWith(suffix) ? key : filename;
|
|
54
|
+
}
|
|
55
|
+
|
|
31
56
|
export interface ParsedStackFrame {
|
|
32
57
|
function?: string;
|
|
33
58
|
filename?: string;
|
|
34
59
|
lineno?: number;
|
|
35
60
|
colno?: number;
|
|
36
61
|
isNative?: boolean;
|
|
62
|
+
/** Set when the line matched Hermes/minified `func@line:col` (no path). */
|
|
63
|
+
releaseLine?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Which parser branch handled a stack line (internal). */
|
|
67
|
+
type ParsedStackLineKind =
|
|
68
|
+
| 'react_native_paren'
|
|
69
|
+
| 'metro_paren'
|
|
70
|
+
| 'anonymous_paren'
|
|
71
|
+
| 'native'
|
|
72
|
+
| 'release_func_at'
|
|
73
|
+
| 'unparsed';
|
|
74
|
+
|
|
75
|
+
const UNKNOWN_RELEASE_FILENAME = '<unknown>';
|
|
76
|
+
|
|
77
|
+
export interface StackFrameParseOptions {
|
|
78
|
+
/**
|
|
79
|
+
* Hermes / minified RN release lines use `func@line:col` with no file path. Those frames are tagged
|
|
80
|
+
* with `releaseLine` and use this as `filename` (default `bundle.js`). Match the Metro plugin’s
|
|
81
|
+
* source map `file` field (or `sourceMapFile` option there).
|
|
82
|
+
*/
|
|
83
|
+
releaseBundleFilename?: string;
|
|
37
84
|
}
|
|
38
85
|
|
|
39
86
|
/**
|
|
40
|
-
* Parse a single stack trace line into a structured frame
|
|
87
|
+
* Parse a single stack trace line into a structured frame and record how it was parsed.
|
|
41
88
|
*/
|
|
42
|
-
|
|
89
|
+
function parseStackTraceLineDetailed(line: string): { frame: ParsedStackFrame | null; kind: ParsedStackLineKind } {
|
|
43
90
|
if (!line || typeof line !== 'string') {
|
|
44
|
-
return null;
|
|
91
|
+
return { frame: null, kind: 'unparsed' };
|
|
45
92
|
}
|
|
46
93
|
|
|
47
94
|
const trimmedLine = line.trim();
|
|
48
95
|
if (!trimmedLine) {
|
|
49
|
-
return null;
|
|
96
|
+
return { frame: null, kind: 'unparsed' };
|
|
50
97
|
}
|
|
51
98
|
|
|
52
99
|
// Try standard React Native format: at functionName (file.js:123:45)
|
|
53
100
|
let match = trimmedLine.match(REACT_NATIVE_STACK_REGEX);
|
|
54
101
|
if (match && match[2] && match[3] && match[4]) {
|
|
55
102
|
return {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
103
|
+
kind: 'react_native_paren',
|
|
104
|
+
frame: {
|
|
105
|
+
function: match[1] || '<anonymous>',
|
|
106
|
+
filename: normalizeHermesStackFilename(match[2]),
|
|
107
|
+
lineno: parseInt(match[3], 10),
|
|
108
|
+
colno: parseInt(match[4], 10),
|
|
109
|
+
},
|
|
60
110
|
};
|
|
61
111
|
}
|
|
62
112
|
|
|
@@ -64,10 +114,13 @@ export function parseStackTraceLine(line: string): ParsedStackFrame | null {
|
|
|
64
114
|
match = trimmedLine.match(METRO_BUNDLER_REGEX);
|
|
65
115
|
if (match && match[2] && match[3] && match[4]) {
|
|
66
116
|
return {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
117
|
+
kind: 'metro_paren',
|
|
118
|
+
frame: {
|
|
119
|
+
function: match[1] || '<anonymous>',
|
|
120
|
+
filename: normalizeHermesStackFilename(match[2]),
|
|
121
|
+
lineno: parseInt(match[3], 10),
|
|
122
|
+
colno: parseInt(match[4], 10),
|
|
123
|
+
},
|
|
71
124
|
};
|
|
72
125
|
}
|
|
73
126
|
|
|
@@ -75,10 +128,13 @@ export function parseStackTraceLine(line: string): ParsedStackFrame | null {
|
|
|
75
128
|
match = trimmedLine.match(REACT_NATIVE_ANONYMOUS_REGEX);
|
|
76
129
|
if (match && match[1] && match[2] && match[3]) {
|
|
77
130
|
return {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
131
|
+
kind: 'anonymous_paren',
|
|
132
|
+
frame: {
|
|
133
|
+
function: '<anonymous>',
|
|
134
|
+
filename: normalizeHermesStackFilename(match[1]),
|
|
135
|
+
lineno: parseInt(match[2], 10),
|
|
136
|
+
colno: parseInt(match[3], 10),
|
|
137
|
+
},
|
|
82
138
|
};
|
|
83
139
|
}
|
|
84
140
|
|
|
@@ -86,9 +142,12 @@ export function parseStackTraceLine(line: string): ParsedStackFrame | null {
|
|
|
86
142
|
match = trimmedLine.match(REACT_NATIVE_NATIVE_REGEX);
|
|
87
143
|
if (match) {
|
|
88
144
|
return {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
145
|
+
kind: 'native',
|
|
146
|
+
frame: {
|
|
147
|
+
function: match[1] || '<native>',
|
|
148
|
+
filename: '<native>',
|
|
149
|
+
isNative: true,
|
|
150
|
+
},
|
|
92
151
|
};
|
|
93
152
|
}
|
|
94
153
|
|
|
@@ -96,15 +155,25 @@ export function parseStackTraceLine(line: string): ParsedStackFrame | null {
|
|
|
96
155
|
match = trimmedLine.match(REACT_NATIVE_RELEASE_REGEX);
|
|
97
156
|
if (match && match[2] && match[3]) {
|
|
98
157
|
return {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
158
|
+
kind: 'release_func_at',
|
|
159
|
+
frame: {
|
|
160
|
+
function: match[1] || '<anonymous>',
|
|
161
|
+
filename: UNKNOWN_RELEASE_FILENAME,
|
|
162
|
+
lineno: parseInt(match[2], 10),
|
|
163
|
+
colno: parseInt(match[3], 10),
|
|
164
|
+
releaseLine: true,
|
|
165
|
+
},
|
|
103
166
|
};
|
|
104
167
|
}
|
|
105
168
|
|
|
106
|
-
|
|
107
|
-
|
|
169
|
+
return { frame: null, kind: 'unparsed' };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Parse a single stack trace line into a structured frame
|
|
174
|
+
*/
|
|
175
|
+
export function parseStackTraceLine(line: string): ParsedStackFrame | null {
|
|
176
|
+
return parseStackTraceLineDetailed(line).frame;
|
|
108
177
|
}
|
|
109
178
|
|
|
110
179
|
/**
|
|
@@ -119,7 +188,7 @@ export function parseStackTrace(stackTrace: string): ParsedStackFrame[] {
|
|
|
119
188
|
const frames: ParsedStackFrame[] = [];
|
|
120
189
|
|
|
121
190
|
for (const line of lines) {
|
|
122
|
-
const frame =
|
|
191
|
+
const { frame } = parseStackTraceLineDetailed(line);
|
|
123
192
|
if (frame) {
|
|
124
193
|
frames.push(frame);
|
|
125
194
|
}
|
|
@@ -131,26 +200,40 @@ export function parseStackTrace(stackTrace: string): ParsedStackFrame[] {
|
|
|
131
200
|
/**
|
|
132
201
|
* Convert parsed stack frames to Faro's StackFrame format
|
|
133
202
|
*/
|
|
134
|
-
export function toFaroStackFrames(parsedFrames: ParsedStackFrame[]): StackFrame[] {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
203
|
+
export function toFaroStackFrames(parsedFrames: ParsedStackFrame[], options?: StackFrameParseOptions): StackFrame[] {
|
|
204
|
+
const releaseName = options?.releaseBundleFilename ?? 'bundle.js';
|
|
205
|
+
const keyedBasename =
|
|
206
|
+
typeof options?.releaseBundleFilename === 'string' && options.releaseBundleFilename.trim() !== ''
|
|
207
|
+
? options.releaseBundleFilename.trim()
|
|
208
|
+
: null;
|
|
209
|
+
|
|
210
|
+
return parsedFrames.map((frame, _index) => {
|
|
211
|
+
let filename = normalizeHermesStackFilename(frame.filename || '<unknown>');
|
|
212
|
+
if (frame.releaseLine) {
|
|
213
|
+
filename = releaseName;
|
|
214
|
+
} else if (keyedBasename) {
|
|
215
|
+
filename = collapseBundledArtifactPath(filename, keyedBasename);
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
filename,
|
|
219
|
+
function: frame.function || '<anonymous>',
|
|
220
|
+
lineno: frame.lineno,
|
|
221
|
+
colno: frame.colno,
|
|
222
|
+
};
|
|
223
|
+
});
|
|
141
224
|
}
|
|
142
225
|
|
|
143
226
|
/**
|
|
144
227
|
* Extract and parse stack frames from an Error object
|
|
145
228
|
*/
|
|
146
|
-
export function getStackFramesFromError(error: Error): StackFrame[] {
|
|
229
|
+
export function getStackFramesFromError(error: Error, options?: StackFrameParseOptions): StackFrame[] {
|
|
147
230
|
if (!error || !error.stack) {
|
|
148
231
|
return [];
|
|
149
232
|
}
|
|
150
233
|
|
|
151
234
|
try {
|
|
152
235
|
const parsedFrames = parseStackTrace(error.stack);
|
|
153
|
-
return toFaroStackFrames(parsedFrames);
|
|
236
|
+
return toFaroStackFrames(parsedFrames, options);
|
|
154
237
|
} catch (_e) {
|
|
155
238
|
// If parsing fails, return empty array
|
|
156
239
|
return [];
|
|
@@ -173,13 +256,14 @@ export function getPlatformErrorContext(): Record<string, string> {
|
|
|
173
256
|
*/
|
|
174
257
|
export function enhanceErrorWithContext(
|
|
175
258
|
error: Error,
|
|
176
|
-
additionalContext?: Record<string, string
|
|
259
|
+
additionalContext?: Record<string, string>,
|
|
260
|
+
stackParseOptions?: StackFrameParseOptions
|
|
177
261
|
): {
|
|
178
262
|
error: Error;
|
|
179
263
|
stackFrames: StackFrame[];
|
|
180
264
|
context: Record<string, string>;
|
|
181
265
|
} {
|
|
182
|
-
const stackFrames = getStackFramesFromError(error);
|
|
266
|
+
const stackFrames = getStackFramesFromError(error, stackParseOptions);
|
|
183
267
|
const platformContext = getPlatformErrorContext();
|
|
184
268
|
|
|
185
269
|
return {
|