noibu-react-native 0.0.1 → 0.0.2
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 +5 -3
- package/dist/api/clientConfig.js +19 -15
- package/dist/api/metroplexSocket.js +15 -25
- package/dist/api/storedMetrics.js +18 -22
- package/dist/constants.d.ts +2 -1
- package/dist/constants.js +2 -34
- package/dist/entry/index.d.ts +7 -0
- package/dist/entry/index.js +8 -2
- package/dist/entry/init.js +6 -5
- package/dist/monitors/clickMonitor.js +1 -2
- package/dist/monitors/elementMonitor.js +4 -1
- package/dist/monitors/errorMonitor.d.ts +25 -0
- package/dist/monitors/errorMonitor.js +110 -263
- package/dist/monitors/httpDataBundler.js +11 -12
- package/dist/monitors/inputMonitor.js +4 -1
- package/dist/monitors/locationChangeMonitor.js +3 -16
- package/dist/monitors/pageMonitor.js +4 -1
- package/dist/monitors/requestMonitor.js +5 -19
- package/dist/pageVisit/pageVisit.js +3 -1
- package/dist/pageVisit/pageVisitEventError/blacklistedDomains.js +9 -0
- package/dist/pageVisit/pageVisitEventError/pageVisitEventError.js +9 -14
- package/dist/pageVisit/pageVisitEventHTTP/pageVisitEventHTTP.js +3 -14
- package/dist/storage/storage.js +0 -1
- package/dist/storage/storageProvider.js +0 -1
- package/dist/utils/function.js +80 -53
- package/dist/utils/performance.js +0 -7
- package/dist/utils/stacktrace-parser.d.ts +9 -0
- package/dist/utils/stacktrace-parser.js +156 -0
- package/package.json +3 -4
|
@@ -1,295 +1,142 @@
|
|
|
1
1
|
import { replace } from '../utils/object.js';
|
|
2
|
-
import '
|
|
3
|
-
import '
|
|
4
|
-
import { ERROR_EVENT_ERROR_TYPE, EVENT_TARGETS, CONSOLE_FUNCTION_OVERRIDES, WRAPPED_EXCEPTION_ERROR_TYPE, ERROR_LOG_EVENT_ERROR_TYPE } from '../constants.js';
|
|
2
|
+
import { isStackTrace } from '../utils/function.js';
|
|
3
|
+
import { ERROR_EVENT_ERROR_TYPE, CONSOLE_FUNCTION_OVERRIDES, ERROR_LOG_EVENT_ERROR_TYPE } from '../constants.js';
|
|
5
4
|
import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError/pageVisitEventError.js';
|
|
6
|
-
import 'react-native-uuid';
|
|
7
5
|
|
|
6
|
+
/* eslint-disable @typescript-eslint/ban-types,prefer-arrow-callback */
|
|
8
7
|
/** @module ErrorMonitor */
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* will make sure that we ignore the next error caught by the error event listener
|
|
12
|
-
* ignoreError is used to not store errors that were generated by noibu wrapped
|
|
13
|
-
* code twice (once by wrapped code, once by error event listener).
|
|
14
|
-
*/
|
|
15
|
-
function ignoreNextError() {
|
|
16
|
-
|
|
17
|
-
// this works because setTimeout without a delay fires
|
|
18
|
-
// as the immidiate next event in the event loop. Which should
|
|
19
|
-
// be right after the error that we throw before callign this error
|
|
20
|
-
setTimeout(() => {
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
8
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* @
|
|
9
|
+
* transform a log into an error since React hides component errors
|
|
10
|
+
* tps://reactjs.org/docs/error-boundaries.html
|
|
11
|
+
* @param {Error|any} errorLog
|
|
12
|
+
* @returns {boolean} true on success
|
|
29
13
|
*/
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
// the function was wrapped already
|
|
37
|
-
if (functionToWrap.__noibu__) {
|
|
38
|
-
return functionToWrap;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// trying to wrap a function that was already wrapped in the past,
|
|
42
|
-
// return the wrapped value
|
|
43
|
-
if (functionToWrap.__noibu_wrapped__) {
|
|
44
|
-
return functionToWrap.__noibu_wrapped__;
|
|
45
|
-
}
|
|
46
|
-
} catch (err) {
|
|
47
|
-
// silently failling
|
|
48
|
-
return functionToWrap;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* wrapper for most prototypes we know can generate errors
|
|
52
|
-
* @param {} ...args
|
|
53
|
-
*/
|
|
54
|
-
const nbuWrapper = function (...args) {
|
|
55
|
-
// Trying to call the function in a wrapped try and catch
|
|
56
|
-
// this will generate an error in the console if there is one.
|
|
57
|
-
try {
|
|
58
|
-
// Recursively wrap arguments in case that some are
|
|
59
|
-
// functions
|
|
60
|
-
const wrappedArguments = Array.prototype.slice
|
|
61
|
-
.call(args)
|
|
62
|
-
.map(arg => wrap(arg));
|
|
63
|
-
|
|
64
|
-
// checking if the function is served through the handleEvent property
|
|
65
|
-
// for compatibility reasons
|
|
66
|
-
if (functionToWrap.handleEvent) {
|
|
67
|
-
return functionToWrap.handleEvent.apply(this, wrappedArguments);
|
|
68
|
-
}
|
|
69
|
-
return functionToWrap.apply(this, wrappedArguments);
|
|
70
|
-
// user land
|
|
71
|
-
} catch (exception) {
|
|
72
|
-
// we need to ignore this error during the onerror otherwise
|
|
73
|
-
// we catch it 2x
|
|
74
|
-
saveErrorToPagevisit(WRAPPED_EXCEPTION_ERROR_TYPE, {
|
|
75
|
-
error: exception,
|
|
76
|
-
});
|
|
77
|
-
ignoreNextError();
|
|
78
|
-
throw exception;
|
|
14
|
+
function processErrorLog(errorLog) {
|
|
15
|
+
// handle empty arguments
|
|
16
|
+
if (!errorLog) {
|
|
17
|
+
return false;
|
|
79
18
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
for (const property in functionToWrap) {
|
|
85
|
-
if (Object.prototype.hasOwnProperty.call(functionToWrap, property)) {
|
|
86
|
-
nbuWrapper[property] = functionToWrap[property];
|
|
87
|
-
}
|
|
19
|
+
const { message, stack } = errorLog;
|
|
20
|
+
// for now, we only process error logs if they are a way to describe an error
|
|
21
|
+
if (!stack || !message) {
|
|
22
|
+
return false;
|
|
88
23
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
nbuWrapper.prototype = functionToWrap.prototype || {};
|
|
94
|
-
|
|
95
|
-
Object.defineProperty(functionToWrap, '__noibu_wrapped__', {
|
|
96
|
-
enumerable: false,
|
|
97
|
-
value: nbuWrapper,
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Signal that this function has been wrapped/filled already
|
|
101
|
-
// for both debugging and to prevent it to being wrapped/filled twice
|
|
102
|
-
Object.defineProperties(nbuWrapper, {
|
|
103
|
-
__noibu__: {
|
|
104
|
-
enumerable: false,
|
|
105
|
-
value: true,
|
|
106
|
-
},
|
|
107
|
-
__noibu_original__: {
|
|
108
|
-
enumerable: false,
|
|
109
|
-
value: functionToWrap,
|
|
110
|
-
},
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// Restore original function name (not all browsers allow that)
|
|
114
|
-
try {
|
|
115
|
-
const descriptor = Object.getOwnPropertyDescriptor(nbuWrapper, 'name');
|
|
116
|
-
if (descriptor.configurable) {
|
|
117
|
-
Object.defineProperty(nbuWrapper, 'name', {
|
|
118
|
-
// eslint-disable-next-line require-jsdoc
|
|
119
|
-
get() {
|
|
120
|
-
return functionToWrap.name;
|
|
121
|
-
},
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
} catch (err) {
|
|
125
|
-
return functionToWrap;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return nbuWrapper;
|
|
24
|
+
saveErrorToPagevisit(ERROR_LOG_EVENT_ERROR_TYPE, { message, stack });
|
|
25
|
+
return true;
|
|
129
26
|
}
|
|
130
|
-
|
|
131
27
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
28
|
+
* Constructs error objects based on console args.
|
|
29
|
+
* Relies on isStackTrace() to determine if arg is a stack trace, otherwise the arg must be a message.
|
|
30
|
+
*
|
|
31
|
+
* If there are multiple stack traces or the number of error messages is not equal to one,
|
|
32
|
+
* it maps the stack traces to objects with their respective first lines as messages.
|
|
33
|
+
* Otherwise, if there is exactly one stack trace and one error message,
|
|
34
|
+
* it constructs an array with a single object containing the first stack trace and the first error message.
|
|
35
|
+
* @param {Array<string>} args
|
|
135
36
|
*/
|
|
136
|
-
function
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
37
|
+
function constructErrors(args) {
|
|
38
|
+
if (args.length === 0) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
if (args.length === 2) {
|
|
42
|
+
if (isStackTrace(args[0])) {
|
|
43
|
+
return [{ stack: args[0], message: args[1] }];
|
|
44
|
+
}
|
|
45
|
+
if (isStackTrace(args[1])) {
|
|
46
|
+
return [{ stack: args[1], message: args[0] }];
|
|
47
|
+
}
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
const stacks = [];
|
|
51
|
+
const messages = [];
|
|
52
|
+
args.forEach(sm => {
|
|
53
|
+
if (isStackTrace(sm)) {
|
|
54
|
+
stacks.push(sm);
|
|
55
|
+
const lines = sm.split('\n');
|
|
56
|
+
if (isStackTrace(lines[0])) {
|
|
57
|
+
messages.push('_');
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// we can use 1st line of stack trace as a message
|
|
61
|
+
messages.push(lines[0]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return stacks.map((stack, i) => ({ stack, message: messages[i] }));
|
|
148
66
|
}
|
|
149
|
-
|
|
150
67
|
/** iterates arguments to try to extract errors from them
|
|
151
|
-
* @param {} argsFromErrorLog
|
|
68
|
+
* @param {Array<string | Error>} argsFromErrorLog
|
|
152
69
|
*/
|
|
153
70
|
function processErrorLogArguments(argsFromErrorLog) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
71
|
+
// tracks if arguments were processed at least once successfully, and if not, tries to reconstruct an Error
|
|
72
|
+
const collectedArgs = [];
|
|
73
|
+
// we may receive multiple arguments
|
|
74
|
+
argsFromErrorLog.forEach(arg => {
|
|
75
|
+
// ensure arg exists before attempting processing
|
|
76
|
+
if (!arg) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// if we pass an array of elements in the console, we want to go through that
|
|
80
|
+
// away and make sure we are extracting the error object. We don't do nested arrays.
|
|
81
|
+
if (Array.isArray(arg)) {
|
|
82
|
+
collectedArgs.push(...arg);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
collectedArgs.push(arg);
|
|
86
|
+
});
|
|
87
|
+
const argsToBeReconstructedIntoErrors = collectedArgs.filter(arg => !processErrorLog(arg));
|
|
88
|
+
// if previous process calls return nothing,
|
|
89
|
+
// try to reconstruct error from the args
|
|
90
|
+
constructErrors(argsToBeReconstructedIntoErrors).forEach(processErrorLog);
|
|
170
91
|
}
|
|
171
|
-
|
|
172
92
|
/**
|
|
173
93
|
* wraps and replaces the addEventListener property
|
|
174
94
|
* of event targets to try and catch errors
|
|
175
95
|
* eventTargetString: event target name
|
|
176
96
|
*/
|
|
177
97
|
function configureEventListeners() {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
function nbuWrapper(eventName, handler, capture) {
|
|
199
|
-
// testPassive is done by passing a null handler, so we code
|
|
200
|
-
// against that
|
|
201
|
-
if (!handler) {
|
|
202
|
-
return originalFunction.call(this, eventName, handler, capture);
|
|
203
|
-
}
|
|
204
|
-
let wrappedHandler;
|
|
205
|
-
// Checking if handleEvent is explicitely
|
|
206
|
-
// passed for compatibility reason
|
|
207
|
-
if (handler.handleEvent) {
|
|
208
|
-
const wrappedHandleEvent = wrap(handler.handleEvent.bind(handler));
|
|
209
|
-
// in some case the handler is an object that contains much more than just the
|
|
210
|
-
// the single handle event property, in such cases we need to make sure we are not
|
|
211
|
-
// overwritting any other critical functionality by wrapping the event handler
|
|
212
|
-
wrappedHandler = handler;
|
|
213
|
-
wrappedHandler.handleEvent = wrappedHandleEvent;
|
|
214
|
-
} else {
|
|
215
|
-
wrappedHandler = wrap(handler);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return originalFunction.call(
|
|
219
|
-
this,
|
|
220
|
-
eventName,
|
|
221
|
-
wrappedHandler,
|
|
222
|
-
capture,
|
|
223
|
-
);
|
|
224
|
-
},
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
// replacing the removeEventListener function as well to wrap the listener
|
|
228
|
-
replace(
|
|
229
|
-
proto,
|
|
230
|
-
'removeEventListener',
|
|
231
|
-
originalFunction =>
|
|
232
|
-
// We set nbuWrapper to the handler function so if this returns an error
|
|
233
|
-
// the trace message will start with nbuWrapper which would allow us to
|
|
234
|
-
// detect that this is a wrapped function and not a NoibuJS error
|
|
235
|
-
function nbuWrapper(eventName, handler, options) {
|
|
236
|
-
let callback = handler;
|
|
237
|
-
try {
|
|
238
|
-
callback = callback && (callback.__noibu_wrapped__ || callback);
|
|
239
|
-
} catch (e) {
|
|
240
|
-
// fail silently
|
|
241
|
-
}
|
|
242
|
-
return originalFunction.call(this, eventName, callback, options);
|
|
243
|
-
},
|
|
244
|
-
);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
// we wrap all logging to catch any potential errors passed in logs
|
|
248
|
-
CONSOLE_FUNCTION_OVERRIDES.forEach(consoleFunction => {
|
|
249
|
-
if (!window.console || !window.console[consoleFunction]) {
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
replace(
|
|
253
|
-
window.console,
|
|
254
|
-
consoleFunction,
|
|
255
|
-
originalFunction =>
|
|
256
|
-
// We set nbuWrapper to the handler function so if this returns an error
|
|
257
|
-
// the trace message will start with nbuWrapper which would allow us to
|
|
258
|
-
// detect that this is a wrapped function and not a NoibuJS error
|
|
259
|
-
function nbuWrapper() {
|
|
260
|
-
// ignoring this linting error since we don't want
|
|
261
|
-
// potentially overide the actual functioning of console.error
|
|
262
|
-
// eslint-disable-next-line prefer-rest-params
|
|
263
|
-
originalFunction.call(window.console, ...arguments);
|
|
264
|
-
// converting the arguments to an array so that we do not nest argument objects
|
|
265
|
-
// eslint-disable-next-line prefer-rest-params
|
|
266
|
-
processErrorLogArguments(Array.from(arguments));
|
|
267
|
-
},
|
|
268
|
-
);
|
|
269
|
-
});
|
|
98
|
+
// we wrap all logging to catch any potential errors passed in logs
|
|
99
|
+
CONSOLE_FUNCTION_OVERRIDES.forEach(consoleFunction => {
|
|
100
|
+
if (!window.console || !window.console[consoleFunction]) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
replace(window.console, consoleFunction, function (originalFunction) {
|
|
104
|
+
// We set nbuWrapper to the handler function so if this returns an error
|
|
105
|
+
// the trace message will start with nbuWrapper which would allow us to
|
|
106
|
+
// detect that this is a wrapped function and not a NoibuJS error
|
|
107
|
+
return function nbuWrapper() {
|
|
108
|
+
// ignoring this linting error since we don't want
|
|
109
|
+
// potentially overide the actual functioning of console.error
|
|
110
|
+
// eslint-disable-next-line prefer-rest-params
|
|
111
|
+
originalFunction.call(window.console, ...arguments);
|
|
112
|
+
// converting the arguments to an array so that we do not nest argument objects
|
|
113
|
+
// eslint-disable-next-line prefer-rest-params
|
|
114
|
+
processErrorLogArguments(Array.from(arguments));
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
});
|
|
270
118
|
}
|
|
271
|
-
|
|
272
119
|
/**
|
|
273
120
|
* Monitors the errors happening on the window
|
|
274
121
|
*/
|
|
275
122
|
function monitorErrors() {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
saveErrorToPagevisit(ERROR_EVENT_ERROR_TYPE, {
|
|
280
|
-
error,
|
|
281
|
-
});
|
|
282
|
-
}, true);
|
|
283
|
-
if (global.HermesInternal) {
|
|
284
|
-
global.HermesInternal.enablePromiseRejectionTracker({
|
|
285
|
-
allRejections: true,
|
|
286
|
-
onUnhandled: (id, rejection = {}) => {
|
|
123
|
+
// wrapping all listeners as soon as possible after we set the above listener
|
|
124
|
+
configureEventListeners();
|
|
125
|
+
global.ErrorUtils.setGlobalHandler((error) => {
|
|
287
126
|
saveErrorToPagevisit(ERROR_EVENT_ERROR_TYPE, {
|
|
288
|
-
|
|
127
|
+
error,
|
|
289
128
|
});
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
129
|
+
}, true);
|
|
130
|
+
if (global.HermesInternal) {
|
|
131
|
+
global.HermesInternal.enablePromiseRejectionTracker({
|
|
132
|
+
allRejections: true,
|
|
133
|
+
onUnhandled: (id, rejection = {}) => {
|
|
134
|
+
saveErrorToPagevisit(ERROR_EVENT_ERROR_TYPE, {
|
|
135
|
+
error: rejection,
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
293
140
|
}
|
|
294
141
|
|
|
295
142
|
export { monitorErrors, processErrorLogArguments };
|
|
@@ -85,7 +85,10 @@ class HTTPDataBundler {
|
|
|
85
85
|
];
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* gets the singleton instance
|
|
90
|
+
* @returns {HTTPDataBundler}
|
|
91
|
+
*/
|
|
89
92
|
static getInstance() {
|
|
90
93
|
if (!this.instance) {
|
|
91
94
|
this.instance = new HTTPDataBundler();
|
|
@@ -208,7 +211,7 @@ class HTTPDataBundler {
|
|
|
208
211
|
return false;
|
|
209
212
|
}
|
|
210
213
|
|
|
211
|
-
let requestHostname; // has to be declared outside
|
|
214
|
+
let requestHostname; // has to be declared outside `try`
|
|
212
215
|
|
|
213
216
|
// Use URL constructor to extract hostname
|
|
214
217
|
try {
|
|
@@ -251,11 +254,10 @@ class HTTPDataBundler {
|
|
|
251
254
|
* Builds an HTTP Data bundle
|
|
252
255
|
* @param {} url
|
|
253
256
|
* @param {} requestHeaders is a map of request headers
|
|
254
|
-
* @param {}
|
|
257
|
+
* @param {} rawRequestPayload
|
|
255
258
|
* @param {} responseHeaders is a map of response headers
|
|
256
259
|
* @param {} responsePayload
|
|
257
260
|
* @param {} method
|
|
258
|
-
* @param {} isError Response code is an error
|
|
259
261
|
*/
|
|
260
262
|
bundleHTTPData(
|
|
261
263
|
url,
|
|
@@ -264,9 +266,8 @@ class HTTPDataBundler {
|
|
|
264
266
|
responseHeaders,
|
|
265
267
|
responsePayload,
|
|
266
268
|
method,
|
|
267
|
-
isError,
|
|
268
269
|
) {
|
|
269
|
-
if (!this.isValidRequest(url, method
|
|
270
|
+
if (!this.isValidRequest(url, method)) return null;
|
|
270
271
|
|
|
271
272
|
// stringify payload if correct type and not too large
|
|
272
273
|
let requestPayload = '';
|
|
@@ -320,15 +321,13 @@ class HTTPDataBundler {
|
|
|
320
321
|
* de-duping the requests
|
|
321
322
|
* @param {string} url
|
|
322
323
|
* @param {string} method
|
|
323
|
-
* @param {} isError Response code is an error
|
|
324
324
|
* @returns boolean indicating whether the validation passed
|
|
325
325
|
*/
|
|
326
|
-
isValidRequest(url, method
|
|
326
|
+
isValidRequest(url, method) {
|
|
327
327
|
if (!this.httpDataCollectionEnabled) return false;
|
|
328
328
|
if (!method || typeof method !== 'string') {
|
|
329
329
|
return false;
|
|
330
330
|
}
|
|
331
|
-
if (!isError) return false;
|
|
332
331
|
// TODO: Check below disabled for beta. NOI-4253
|
|
333
332
|
// only bundle and send once per request/method/response code combination
|
|
334
333
|
// const urlWithoutParams = url.split('?')[0];
|
|
@@ -408,7 +407,7 @@ class HTTPDataBundler {
|
|
|
408
407
|
* @returns the restricted payload
|
|
409
408
|
*/
|
|
410
409
|
restrictPayload(payload, url) {
|
|
411
|
-
// if no payload, too large, payload already dropped,
|
|
410
|
+
// if no payload, or too large, payload already dropped,
|
|
412
411
|
// or payloads not allowed for this URL: nothing to do
|
|
413
412
|
if (!payload || !this.shouldCollectPayloadForURL(url)) {
|
|
414
413
|
return HTTP_BODY_NULL_STRING;
|
|
@@ -611,7 +610,7 @@ ${HTTPDataBundler.getInstance().contentLength(headers)}`;
|
|
|
611
610
|
if (typeof dirtyBody !== 'string') return null;
|
|
612
611
|
if (dirtyBody.length < 1) return dirtyBody;
|
|
613
612
|
|
|
614
|
-
let cleanString = this.
|
|
613
|
+
let cleanString = this.tryParseObjectAndRemovePII(dirtyBody);
|
|
615
614
|
// Go through each of the PII matching patterns
|
|
616
615
|
HTTP_PII_BLOCKING_PATTERNS.forEach(pattern => {
|
|
617
616
|
// Replace all matches with the appropriate number of asterisks
|
|
@@ -630,7 +629,7 @@ ${HTTPDataBundler.getInstance().contentLength(headers)}`;
|
|
|
630
629
|
* Returns original content if nothing was changes or error is thrown.
|
|
631
630
|
* @param {String} content
|
|
632
631
|
*/
|
|
633
|
-
|
|
632
|
+
tryParseObjectAndRemovePII(content) {
|
|
634
633
|
const first = content[0];
|
|
635
634
|
const isParsable = first === '{' || first === '[';
|
|
636
635
|
if (!isParsable) {
|
|
@@ -42,7 +42,10 @@ class InputMonitor {
|
|
|
42
42
|
this._setupUnloadHandler();
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* gets the instance of InputMonitor
|
|
47
|
+
* @returns {InputMonitor}
|
|
48
|
+
*/
|
|
46
49
|
static getInstance() {
|
|
47
50
|
if (!this.instance) {
|
|
48
51
|
this.instance = new InputMonitor();
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import 'react-native-device-info';
|
|
2
|
+
import 'react-native-localize';
|
|
3
|
+
import 'react-native-uuid';
|
|
4
4
|
|
|
5
5
|
/** @module LocationMonitor */
|
|
6
6
|
|
|
7
|
-
let currentLocation = (window.location && window.location.href) || '';
|
|
8
|
-
|
|
9
7
|
/**
|
|
10
8
|
* will poll the url on a 1 second basis to see if it has changed
|
|
11
9
|
* there is currently no alternative to getting an accurate url
|
|
@@ -13,17 +11,6 @@ let currentLocation = (window.location && window.location.href) || '';
|
|
|
13
11
|
*/
|
|
14
12
|
function monitorLocation() {
|
|
15
13
|
setInterval(() => {
|
|
16
|
-
if (currentLocation !== ((window.location && window.location.href) || '')) {
|
|
17
|
-
// updating the current url to be the new one
|
|
18
|
-
currentLocation = (window.location && window.location.href) || '';
|
|
19
|
-
|
|
20
|
-
const payload = {
|
|
21
|
-
[URL_ATT_NAME]: getProperGlobalUrl(),
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// storing the location change in the page visit queue
|
|
25
|
-
InputMonitor.getInstance().addEvent(payload, LOCATION_EVENT_TYPE);
|
|
26
|
-
}
|
|
27
14
|
}, 1000);
|
|
28
15
|
}
|
|
29
16
|
|
|
@@ -6,7 +6,10 @@ import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
|
6
6
|
|
|
7
7
|
/** Monitors the page events which we capture and later process */
|
|
8
8
|
class PageMonitor {
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* gets the singleton instance
|
|
11
|
+
* @returns {PageMonitor}
|
|
12
|
+
*/
|
|
10
13
|
static getInstance() {
|
|
11
14
|
if (!this.instance) {
|
|
12
15
|
this.instance = new PageMonitor();
|
|
@@ -2,12 +2,12 @@ import 'react-native/Libraries/Network/fetch';
|
|
|
2
2
|
import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError/pageVisitEventError.js';
|
|
3
3
|
import { PageVisitEventHTTP, isHttpCodeFailure } from '../pageVisit/pageVisitEventHTTP/pageVisitEventHTTP.js';
|
|
4
4
|
import { propWriteableOrMadeWriteable, replace } from '../utils/object.js';
|
|
5
|
-
import 'stacktrace-parser';
|
|
6
5
|
import 'react-native-device-info';
|
|
6
|
+
import 'react-native-localize';
|
|
7
7
|
import { PV_SEQ_ATT_NAME, XML_HTTP_REQUEST_ERROR_TYPE, GQL_ERROR_TYPE, SEVERITY_ERROR, SEVERITY_WARN, RESPONSE_ERROR_TYPE, HTTP_METHOD_ATT_NAME, HTTP_RESP_CODE_ATT_NAME, URL_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HTTP_RESP_LENGTH_ATT_NAME, FETCH_EXCEPTION_ERROR_TYPE } from '../constants.js';
|
|
8
|
+
import ClientConfig from '../api/clientConfig.js';
|
|
8
9
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
9
10
|
import { HTTPDataBundler } from './httpDataBundler.js';
|
|
10
|
-
import ClientConfig from '../api/clientConfig.js';
|
|
11
11
|
import GqlErrorValidator from './gqlErrorValidator.js';
|
|
12
12
|
|
|
13
13
|
/** @module RequestMonitor */
|
|
@@ -20,7 +20,6 @@ import GqlErrorValidator from './gqlErrorValidator.js';
|
|
|
20
20
|
* @param {string} method
|
|
21
21
|
* @param {string} url
|
|
22
22
|
* @param {number} respTime
|
|
23
|
-
* @param {object} gqlError
|
|
24
23
|
* @param {*} rawPayload
|
|
25
24
|
* @returns HTTP event and data
|
|
26
25
|
*/
|
|
@@ -29,7 +28,6 @@ function _buildHttpEventDataObjectsForXHR(
|
|
|
29
28
|
method,
|
|
30
29
|
url,
|
|
31
30
|
respTime,
|
|
32
|
-
gqlError,
|
|
33
31
|
rawPayload = null,
|
|
34
32
|
) {
|
|
35
33
|
const httpEvent = {
|
|
@@ -39,9 +37,8 @@ function _buildHttpEventDataObjectsForXHR(
|
|
|
39
37
|
[HTTP_RESP_TIME_ATT_NAME]: respTime,
|
|
40
38
|
};
|
|
41
39
|
let httpData = null;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (isError && HTTPDataBundler.getInstance().shouldContinueForURL(url)) {
|
|
40
|
+
|
|
41
|
+
if (HTTPDataBundler.getInstance().shouldContinueForURL(url)) {
|
|
45
42
|
const responseHeaders = HTTPDataBundler.headersMapFromString(
|
|
46
43
|
xhrObj.getAllResponseHeaders(),
|
|
47
44
|
);
|
|
@@ -72,7 +69,6 @@ function _buildHttpEventDataObjectsForXHR(
|
|
|
72
69
|
responseHeaders,
|
|
73
70
|
responseBody,
|
|
74
71
|
method,
|
|
75
|
-
isError,
|
|
76
72
|
);
|
|
77
73
|
}
|
|
78
74
|
return [httpEvent, httpData];
|
|
@@ -88,7 +84,6 @@ function _buildHttpEventDataObjectsForXHR(
|
|
|
88
84
|
* [0] is the response body, [1] is an optional response body.
|
|
89
85
|
* @param {string} url the URL of the request
|
|
90
86
|
* @param {string} method the method used in the fetch call
|
|
91
|
-
* @param {boolean} isError is an error
|
|
92
87
|
* @returns the return from the bundleHTTPData() call
|
|
93
88
|
*/
|
|
94
89
|
function _handleFetchOnPromiseCompletion(
|
|
@@ -98,7 +93,6 @@ function _handleFetchOnPromiseCompletion(
|
|
|
98
93
|
bodyStrings,
|
|
99
94
|
url,
|
|
100
95
|
method,
|
|
101
|
-
isError,
|
|
102
96
|
) {
|
|
103
97
|
let reqBody; //
|
|
104
98
|
let reqHeaders = new Map();
|
|
@@ -154,7 +148,6 @@ function _handleFetchOnPromiseCompletion(
|
|
|
154
148
|
respHeaders,
|
|
155
149
|
bodyStrings[0],
|
|
156
150
|
method,
|
|
157
|
-
isError,
|
|
158
151
|
);
|
|
159
152
|
}
|
|
160
153
|
|
|
@@ -167,7 +160,6 @@ function _handleFetchOnPromiseCompletion(
|
|
|
167
160
|
* @param {object} options the options parameter from the original fetch() call
|
|
168
161
|
* @param {number} respTime the time between the fetch() call and the the resolution of the
|
|
169
162
|
* original implementation's return
|
|
170
|
-
* @param {object} gqlError a GraphQL error object
|
|
171
163
|
* @param {Promise<string>} requestTextPromise
|
|
172
164
|
* @returns an array in the form [httpEvent, httpData]
|
|
173
165
|
*/
|
|
@@ -179,7 +171,6 @@ async function _buildHttpEventDataObjectsForFetch(
|
|
|
179
171
|
options,
|
|
180
172
|
respTime,
|
|
181
173
|
requestTextPromise,
|
|
182
|
-
gqlError,
|
|
183
174
|
) {
|
|
184
175
|
const httpEvent = {
|
|
185
176
|
[HTTP_METHOD_ATT_NAME]: method,
|
|
@@ -189,10 +180,8 @@ async function _buildHttpEventDataObjectsForFetch(
|
|
|
189
180
|
};
|
|
190
181
|
|
|
191
182
|
let httpData = null;
|
|
192
|
-
const isGqlError = gqlError != null;
|
|
193
|
-
const isError = isHttpCodeFailure(response.status) || isGqlError;
|
|
194
183
|
// Only get the bodies of the request and response on error and if the URL is one we care about.
|
|
195
|
-
if (
|
|
184
|
+
if (HTTPDataBundler.getInstance().shouldContinueForURL(url)) {
|
|
196
185
|
// add response payload length, if any
|
|
197
186
|
if (response && response.headers) {
|
|
198
187
|
const contentLength = HTTPDataBundler.getInstance().contentLength(
|
|
@@ -206,7 +195,6 @@ async function _buildHttpEventDataObjectsForFetch(
|
|
|
206
195
|
let responseText = '';
|
|
207
196
|
if (
|
|
208
197
|
HTTPDataBundler.getInstance().shouldCollectPayloadForURL(url) &&
|
|
209
|
-
!!response &&
|
|
210
198
|
response instanceof Response
|
|
211
199
|
) {
|
|
212
200
|
const droppedResponseText =
|
|
@@ -235,7 +223,6 @@ async function _buildHttpEventDataObjectsForFetch(
|
|
|
235
223
|
data,
|
|
236
224
|
url,
|
|
237
225
|
method,
|
|
238
|
-
isError,
|
|
239
226
|
),
|
|
240
227
|
)
|
|
241
228
|
.then(httpDataReturn => {
|
|
@@ -591,7 +578,6 @@ function setupGlobalFetchWrapper() {
|
|
|
591
578
|
options,
|
|
592
579
|
respTime,
|
|
593
580
|
requestTextPromise,
|
|
594
|
-
gqlError,
|
|
595
581
|
);
|
|
596
582
|
|
|
597
583
|
let pageVisitEventHTTP = new PageVisitEventHTTP(
|