noibu-react-native 0.0.4 → 0.0.7
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 +22 -7
- package/dist/api/clientConfig.d.ts +101 -0
- package/dist/api/clientConfig.js +317 -388
- package/dist/api/helpCode.js +2 -2
- package/dist/api/inputManager.js +3 -9
- package/dist/api/metroplexSocket.js +10 -34
- package/dist/api/storedMetrics.js +3 -2
- package/dist/api/storedPageVisit.js +3 -3
- package/dist/constants.d.ts +7 -40
- package/dist/constants.js +8 -65
- package/dist/entry/index.d.ts +2 -3
- package/dist/entry/index.js +1 -9
- package/dist/entry/init.d.ts +5 -0
- package/dist/entry/init.js +60 -75
- package/dist/monitors/AppNavigationMonitor.d.ts +23 -0
- package/dist/monitors/AppNavigationMonitor.js +63 -0
- package/dist/monitors/clickMonitor.js +10 -57
- package/dist/monitors/errorMonitor.js +1 -1
- package/dist/monitors/gqlErrorValidator.js +3 -3
- package/dist/monitors/httpDataBundler.js +13 -12
- package/dist/monitors/integrations/react-native-navigation-integration.d.ts +19 -0
- package/dist/monitors/integrations/react-native-navigation-integration.js +38 -0
- package/dist/monitors/keyboardInputMonitor.js +0 -1
- package/dist/monitors/requestMonitor.js +10 -8
- package/dist/pageVisit/pageVisitEventError/pageVisitEventError.js +10 -8
- package/dist/storage/storage.d.ts +3 -2
- package/dist/storage/storageProvider.d.ts +6 -5
- package/dist/types/Config.d.ts +27 -0
- package/dist/types/NavigationIntegration.d.ts +7 -0
- package/dist/types/PageVisit.d.ts +22 -0
- package/dist/types/ReactNative.d.ts +4 -0
- package/dist/types/Storage.d.ts +14 -0
- package/dist/types/globals.d.ts +34 -0
- package/dist/utils/date.js +2 -2
- package/dist/utils/eventlistener.js +3 -3
- package/dist/utils/function.d.ts +93 -0
- package/dist/utils/function.js +210 -320
- package/dist/utils/stacktrace-parser.d.ts +6 -8
- package/dist/utils/stacktrace-parser.js +5 -5
- package/package.json +5 -1
- package/dist/monitors/elementMonitor.js +0 -177
- package/dist/monitors/locationChangeMonitor.js +0 -18
package/dist/utils/function.js
CHANGED
|
@@ -1,178 +1,120 @@
|
|
|
1
1
|
import DeviceInfo from 'react-native-device-info';
|
|
2
2
|
import { getLocales } from 'react-native-localize';
|
|
3
3
|
import { parseStack } from './stacktrace-parser.js';
|
|
4
|
-
import {
|
|
4
|
+
import { MAX_STRING_LENGTH, MAX_BEACON_PAYLOAD_SIZE, REQUIRED_DATA_PROCESSING_URLS, PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING, PII_DIGIT_PATTERN, DEFAULT_STACK_FRAME_FIELD_VALUE } from '../constants.js';
|
|
5
5
|
import ClientConfig from '../api/clientConfig.js';
|
|
6
|
+
import { AppNavigationMonitor } from '../monitors/AppNavigationMonitor.js';
|
|
6
7
|
|
|
7
8
|
/** @module Functions */
|
|
8
|
-
|
|
9
9
|
/**
|
|
10
10
|
* Returns a stack trace frame with default filed values
|
|
11
11
|
*/
|
|
12
12
|
const getDefaultFrame = () => ({
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
line: DEFAULT_STACK_FRAME_FIELD_VALUE,
|
|
14
|
+
mname: DEFAULT_STACK_FRAME_FIELD_VALUE,
|
|
15
|
+
file: DEFAULT_STACK_FRAME_FIELD_VALUE,
|
|
16
16
|
});
|
|
17
|
-
|
|
18
17
|
/**
|
|
19
|
-
*
|
|
20
18
|
* returns a string that satisfies a max length
|
|
21
19
|
* stringToVerify: string that needs to be verified
|
|
22
20
|
* length :optional, max length that stringToVerify can be
|
|
23
|
-
* @param stringToVerify
|
|
24
|
-
* @param length
|
|
25
|
-
*/
|
|
26
|
-
function getMaxSubstringAllowed(
|
|
27
|
-
stringToVerify,
|
|
28
|
-
length = MAX_STRING_LENGTH,
|
|
29
|
-
) {
|
|
30
|
-
if (!stringToVerify) {
|
|
31
|
-
return stringToVerify;
|
|
32
|
-
}
|
|
33
|
-
if (stringToVerify.length < length) return stringToVerify;
|
|
34
|
-
return stringToVerify.substring(0, length);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
*
|
|
39
|
-
* todo implement navigation
|
|
40
|
-
* getProperGlobalUrl gets the proper global url from the window
|
|
41
|
-
* @returns {string}
|
|
42
21
|
*/
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
22
|
+
function getMaxSubstringAllowed(stringToVerify, length = MAX_STRING_LENGTH) {
|
|
23
|
+
if (!stringToVerify) {
|
|
24
|
+
return stringToVerify;
|
|
25
|
+
}
|
|
26
|
+
if (stringToVerify.length < length)
|
|
27
|
+
return stringToVerify;
|
|
28
|
+
return stringToVerify.substring(0, length);
|
|
47
29
|
}
|
|
48
|
-
|
|
49
30
|
/**
|
|
50
31
|
* Processes the raw stack frames and creates a readable stack in a safe manner
|
|
51
32
|
* @param {StackFrame[]} rawFrames
|
|
52
33
|
*/
|
|
53
34
|
function processFrames(rawFrames) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (
|
|
75
|
-
frame[JS_STACK_FILE_ATT_NAME] &&
|
|
76
|
-
frame[JS_STACK_FILE_ATT_NAME] !== '<unknown>'
|
|
77
|
-
) {
|
|
78
|
-
processedFrame[JS_STACK_FILE_ATT_NAME] = String(
|
|
79
|
-
frame[JS_STACK_FILE_ATT_NAME],
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (frame[JS_STACK_COL_ATT_NAME]) {
|
|
84
|
-
if (Number.isInteger(frame[JS_STACK_COL_ATT_NAME])) {
|
|
85
|
-
processedFrame[JS_STACK_COL_ATT_NAME] = frame[JS_STACK_COL_ATT_NAME];
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return processedFrame;
|
|
90
|
-
});
|
|
35
|
+
return rawFrames.map(frame => {
|
|
36
|
+
const processedFrame = getDefaultFrame();
|
|
37
|
+
if (frame.line) {
|
|
38
|
+
if (Number.isInteger(frame.line)) {
|
|
39
|
+
processedFrame.line = String(frame.line);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (frame.mname && frame.mname !== '<unknown>') {
|
|
43
|
+
processedFrame.mname = String(frame.mname);
|
|
44
|
+
}
|
|
45
|
+
if (frame.file && frame.file !== '<unknown>') {
|
|
46
|
+
processedFrame.file = String(frame.file);
|
|
47
|
+
}
|
|
48
|
+
if (frame.column) {
|
|
49
|
+
if (Number.isInteger(frame.column)) {
|
|
50
|
+
processedFrame.column = frame.column;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return processedFrame;
|
|
54
|
+
});
|
|
91
55
|
}
|
|
92
|
-
|
|
93
56
|
/**
|
|
94
57
|
* Retrieves the javascript stack and message from an error event object
|
|
95
58
|
* @param errObj error to extract stack from
|
|
96
59
|
*/
|
|
97
60
|
function getJSStack(errObj) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// If there is no stack field present then try to read the single file/line/column values
|
|
116
|
-
if (!errObj.stack) {
|
|
117
|
-
if (errObj.fileName && typeof errObj.fileName === 'string') {
|
|
118
|
-
frames[0][JS_STACK_FILE_ATT_NAME] = errObj.fileName;
|
|
119
|
-
}
|
|
120
|
-
if (errObj.lineNumber) {
|
|
121
|
-
frames[0][JS_STACK_LINE_ATT_NAME] = String(errObj.lineNumber);
|
|
122
|
-
}
|
|
123
|
-
if (errObj.columnNumber && Number.isInteger(errObj.columnNumber)) {
|
|
124
|
-
frames[0][JS_STACK_COL_ATT_NAME] = errObj.columnNumber;
|
|
61
|
+
let frames = [
|
|
62
|
+
{
|
|
63
|
+
line: DEFAULT_STACK_FRAME_FIELD_VALUE,
|
|
64
|
+
mname: DEFAULT_STACK_FRAME_FIELD_VALUE,
|
|
65
|
+
file: DEFAULT_STACK_FRAME_FIELD_VALUE,
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
// if the errObj type is not an object or null
|
|
69
|
+
// return a default frame
|
|
70
|
+
if (typeof errObj !== 'object' || !errObj) {
|
|
71
|
+
return {
|
|
72
|
+
frames,
|
|
73
|
+
msg: '',
|
|
74
|
+
};
|
|
125
75
|
}
|
|
126
|
-
} else {
|
|
127
76
|
frames = processFrames(parseStack(errObj.stack));
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const msg = errObj.message ? getMaxSubstringAllowed(errObj.message) : '';
|
|
135
|
-
return {
|
|
136
|
-
[JS_STACK_FRAMES_ATT_NAME]: frames,
|
|
137
|
-
[JS_STACK_MESSAGE_ATT_NAME]: msg,
|
|
138
|
-
};
|
|
77
|
+
const msg = errObj.message ? getMaxSubstringAllowed(errObj.message) : '';
|
|
78
|
+
return {
|
|
79
|
+
frames,
|
|
80
|
+
msg,
|
|
81
|
+
};
|
|
139
82
|
}
|
|
140
|
-
|
|
141
83
|
/**
|
|
142
|
-
*
|
|
143
|
-
* @returns {boolean}
|
|
84
|
+
* Checks if possiblyStacktrace has any stack frames present
|
|
144
85
|
*/
|
|
145
86
|
function isStackTrace(possiblyStacktrace) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
87
|
+
try {
|
|
88
|
+
// todo disable temporary
|
|
89
|
+
// return parseStack(possiblyStacktrace).length > 0;
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
151
95
|
}
|
|
152
|
-
|
|
153
96
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
97
|
+
* Stringify function that is aware of inner circular references and handles them by replacing with {} (empty object)
|
|
98
|
+
* taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value
|
|
156
99
|
*/
|
|
157
100
|
function stringifyJSON(jsonObject) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
101
|
+
const ancestors = [];
|
|
102
|
+
return JSON.stringify(jsonObject, function (k, v) {
|
|
103
|
+
if (typeof v !== 'object' || v === null) {
|
|
104
|
+
return v;
|
|
105
|
+
}
|
|
106
|
+
// `this` is the object that value is contained in,
|
|
107
|
+
// i.e., its direct parent.
|
|
108
|
+
while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) {
|
|
109
|
+
ancestors.pop();
|
|
110
|
+
}
|
|
111
|
+
if (ancestors.includes(v)) {
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
ancestors.push(v);
|
|
115
|
+
return v;
|
|
116
|
+
});
|
|
174
117
|
}
|
|
175
|
-
|
|
176
118
|
/**
|
|
177
119
|
* Wrapper for a request, since we have to do some special handling
|
|
178
120
|
* @param method
|
|
@@ -182,244 +124,192 @@ function stringifyJSON(jsonObject) {
|
|
|
182
124
|
* @param timeout
|
|
183
125
|
* @param sendAndForget
|
|
184
126
|
*/
|
|
185
|
-
async function makeRequest(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
timeout,
|
|
191
|
-
sendAndForget,
|
|
192
|
-
) {
|
|
193
|
-
const ua = Object.keys(headers).findLast(
|
|
194
|
-
k => k.toLowerCase() === 'user-agent',
|
|
195
|
-
);
|
|
196
|
-
const headersWithUa = { ...headers };
|
|
197
|
-
if (!headers[ua]) {
|
|
198
|
-
headersWithUa['User-Agent'] = await getUserAgent();
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// a send-and-forget request is made by using the beacon API (fetch + keepalive)
|
|
202
|
-
if (sendAndForget) {
|
|
203
|
-
const stringData = stringifyJSON(data);
|
|
204
|
-
const currentPayloadSize = new Blob([stringData]).size;
|
|
205
|
-
// if we have a large object or fetch is not available, we skip sending the message
|
|
206
|
-
if (!global.fetch || currentPayloadSize > MAX_BEACON_PAYLOAD_SIZE) {
|
|
207
|
-
return new Promise(resolve => {
|
|
208
|
-
resolve();
|
|
209
|
-
});
|
|
127
|
+
async function makeRequest(method, url, data, headers, timeout, sendAndForget) {
|
|
128
|
+
const ua = Object.keys(headers).findLast(k => k.toLowerCase() === 'user-agent');
|
|
129
|
+
const headersWithUa = { ...headers };
|
|
130
|
+
if (!headers[ua]) {
|
|
131
|
+
headersWithUa['User-Agent'] = await getUserAgent();
|
|
210
132
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
xhr.setRequestHeader(header, headers[header]);
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
xhr.onload = () => {
|
|
230
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
231
|
-
resolve(xhr.response);
|
|
232
|
-
} else {
|
|
233
|
-
reject(new Error(`Custom Request failed: ${xhr.statusText}`));
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
xhr.onerror = () => {
|
|
237
|
-
reject(new Error(`Custom Request failed: ${xhr.statusText}`));
|
|
238
|
-
};
|
|
239
|
-
if (data) {
|
|
240
|
-
xhr.send(stringifyJSON(data));
|
|
241
|
-
} else {
|
|
242
|
-
xhr.send();
|
|
133
|
+
// a send-and-forget request is made by using the beacon API (fetch + keepalive)
|
|
134
|
+
if (sendAndForget) {
|
|
135
|
+
const stringData = stringifyJSON(data);
|
|
136
|
+
const currentPayloadSize = new Blob([stringData]).size;
|
|
137
|
+
// if we have a large object or fetch is not available, we skip sending the message
|
|
138
|
+
if (currentPayloadSize > MAX_BEACON_PAYLOAD_SIZE) {
|
|
139
|
+
return Promise.resolve();
|
|
140
|
+
}
|
|
141
|
+
return fetch(url, {
|
|
142
|
+
method: 'POST',
|
|
143
|
+
headers: headersWithUa,
|
|
144
|
+
body: stringifyJSON(data),
|
|
145
|
+
// keep alive outlives the current page, its the same as beacon
|
|
146
|
+
keepalive: true,
|
|
147
|
+
});
|
|
243
148
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
149
|
+
return new Promise((resolve, reject) => {
|
|
150
|
+
const xhr = new XMLHttpRequest();
|
|
151
|
+
xhr.open(method, url);
|
|
152
|
+
xhr.timeout = timeout;
|
|
153
|
+
Object.keys(headersWithUa).forEach(header => {
|
|
154
|
+
xhr.setRequestHeader(header, headers[header]);
|
|
155
|
+
});
|
|
156
|
+
xhr.onload = () => {
|
|
157
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
158
|
+
resolve(xhr.response);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
reject(new Error(`Custom Request failed: ${xhr.statusText}`));
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
xhr.onerror = () => {
|
|
165
|
+
reject(new Error(`Custom Request failed: ${xhr.statusText}`));
|
|
166
|
+
};
|
|
167
|
+
if (data) {
|
|
168
|
+
xhr.send(stringifyJSON(data));
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
xhr.send();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
254
174
|
}
|
|
255
|
-
|
|
256
175
|
/** checks if http data collection is enabled */
|
|
257
176
|
function checkHttpDataCollectionEnabled() {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/** determines if we have received the http allowed urls */
|
|
264
|
-
function checkHttpPayloadAllowedURLsExistence() {
|
|
265
|
-
const noibuConfig = NOIBUJS_CONFIG();
|
|
266
|
-
return (
|
|
267
|
-
noibuConfig[HTTP_DATA_PAYLOAD_URL_REGEXES_FLAG_NAME] &&
|
|
268
|
-
Array.isArray(noibuConfig[HTTP_DATA_PAYLOAD_URL_REGEXES_FLAG_NAME])
|
|
269
|
-
);
|
|
177
|
+
const noibuConfig = ClientConfig.getInstance();
|
|
178
|
+
// Just a boolean, so safe to return truthiness. If undefined, will return false.
|
|
179
|
+
return !!noibuConfig.enableHttpDataCollection;
|
|
270
180
|
}
|
|
271
|
-
|
|
272
181
|
/** gets http data payload allowed URLs */
|
|
273
182
|
function getHttpPayloadAllowedURLs() {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
183
|
+
const noibuConfig = ClientConfig.getInstance();
|
|
184
|
+
// return the allowed list or an empty list
|
|
185
|
+
if (noibuConfig.listOfUrlsToCollectHttpDataFrom &&
|
|
186
|
+
Array.isArray(noibuConfig.listOfUrlsToCollectHttpDataFrom)) {
|
|
187
|
+
return noibuConfig.listOfUrlsToCollectHttpDataFrom;
|
|
188
|
+
}
|
|
189
|
+
return [];
|
|
280
190
|
}
|
|
281
191
|
/**
|
|
282
|
-
* Gets
|
|
192
|
+
* Gets selectors to prevent those elements from being recorded
|
|
283
193
|
*/
|
|
284
|
-
function
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
// selecting everything after and including the element at index 1
|
|
292
|
-
blockedCSS.push(sel.substring(1));
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
return blockedCSS;
|
|
194
|
+
function getBlockedElements() {
|
|
195
|
+
const selectors = ClientConfig.getInstance().blockedElements;
|
|
196
|
+
const blockedElements = ['noibu-blocked'];
|
|
197
|
+
if (selectors && Array.isArray(selectors)) {
|
|
198
|
+
blockedElements.push(...selectors);
|
|
199
|
+
}
|
|
200
|
+
return blockedElements;
|
|
297
201
|
}
|
|
298
202
|
/**
|
|
299
203
|
* makes sure the url sent is a valid URL
|
|
300
|
-
* @param {} string url to be validated
|
|
301
204
|
*/
|
|
302
|
-
function isValidURL(
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
205
|
+
function isValidURL(str) {
|
|
206
|
+
try {
|
|
207
|
+
return !!new URL(str);
|
|
208
|
+
}
|
|
209
|
+
catch (_) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
309
212
|
}
|
|
310
|
-
|
|
311
213
|
let userAgentCache = '';
|
|
312
|
-
|
|
313
214
|
/**
|
|
314
215
|
* Because of the nature of user agent in react native, we have to make this async.
|
|
315
216
|
* But I promise, this is really fast, since we memoize the result for the whole session :)
|
|
316
217
|
* @returns {Promise<string>}
|
|
317
218
|
*/
|
|
318
219
|
async function getUserAgent() {
|
|
319
|
-
|
|
220
|
+
if (userAgentCache) {
|
|
221
|
+
return userAgentCache;
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
userAgentCache = await DeviceInfo.getUserAgent();
|
|
225
|
+
}
|
|
226
|
+
catch (e) {
|
|
227
|
+
userAgentCache = '';
|
|
228
|
+
}
|
|
320
229
|
return userAgentCache;
|
|
321
|
-
}
|
|
322
|
-
userAgentCache = await DeviceInfo.getUserAgent();
|
|
323
|
-
return userAgentCache;
|
|
324
230
|
}
|
|
325
|
-
|
|
326
231
|
/**
|
|
327
232
|
* isInvalidURLConfig will verify that Collect is being initializes with
|
|
328
233
|
* the correct env vars.
|
|
329
|
-
* @param {Noibu.UrlConfig} urlConfig
|
|
330
234
|
*/
|
|
331
|
-
function isInvalidURLConfig(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
235
|
+
function isInvalidURLConfig(urls) {
|
|
236
|
+
for (let i = 0; i < REQUIRED_DATA_PROCESSING_URLS.length; i += 1) {
|
|
237
|
+
const u = REQUIRED_DATA_PROCESSING_URLS[i];
|
|
238
|
+
if (!urls[u]) {
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
336
241
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
return false;
|
|
242
|
+
return false;
|
|
340
243
|
}
|
|
341
|
-
|
|
342
244
|
/**
|
|
343
245
|
* isNoibuJSAlreadyLoaded will verify if there are already other
|
|
344
246
|
* copies of NoibuJS runnung
|
|
345
247
|
*/
|
|
346
248
|
function isNoibuJSAlreadyLoaded() {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
249
|
+
// check if the global variable exists and its value
|
|
250
|
+
const loaded = window.noibuJSLoaded !== undefined;
|
|
251
|
+
// set the variable so future copies of the script
|
|
252
|
+
// will know this instance is running
|
|
253
|
+
window.noibuJSLoaded = true;
|
|
254
|
+
return loaded;
|
|
353
255
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
* @param {} obj
|
|
256
|
+
/**
|
|
257
|
+
* asString will create a string out of anything passed to it.
|
|
357
258
|
*/
|
|
358
259
|
function asString(obj) {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
return String(obj);
|
|
260
|
+
if (!obj) {
|
|
261
|
+
return '';
|
|
262
|
+
}
|
|
263
|
+
// we've seen the url be an object in some cases
|
|
264
|
+
// we would still like to send those to our backend in the case
|
|
265
|
+
// that this is an issue and needs to be queried
|
|
266
|
+
if (typeof obj === 'object') {
|
|
267
|
+
return stringifyJSON(obj);
|
|
268
|
+
}
|
|
269
|
+
return String(obj);
|
|
370
270
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
* @param {} text
|
|
271
|
+
/**
|
|
272
|
+
* masks textual content if it ressembles something sensitive
|
|
374
273
|
*/
|
|
375
274
|
function maskTextInput(text) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
275
|
+
// if it has an email or digit(s), we mask the text
|
|
276
|
+
return text
|
|
277
|
+
.replace(PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING)
|
|
278
|
+
.replace(PII_DIGIT_PATTERN, '*');
|
|
380
279
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
* @param {} realOnURL
|
|
280
|
+
/**
|
|
281
|
+
* gets the onURL of a string, defaulting to the location of the webpage
|
|
384
282
|
*/
|
|
385
283
|
function getOnURL(realOnURL) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
return onURL;
|
|
284
|
+
if (realOnURL && realOnURL.trim() !== '' && realOnURL !== 'undefined') {
|
|
285
|
+
return asString(getMaxSubstringAllowed(realOnURL));
|
|
286
|
+
}
|
|
287
|
+
return AppNavigationMonitor.getInstance().globalUrl;
|
|
393
288
|
}
|
|
394
|
-
|
|
395
289
|
/** gets the user language from the browser */
|
|
396
290
|
function getUserLanguage() {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
return lang.toLowerCase();
|
|
291
|
+
const locales = getLocales();
|
|
292
|
+
if (!locales.length) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
const lang = locales[0].languageCode;
|
|
296
|
+
if (lang === '' || !lang) {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
return lang.toLowerCase();
|
|
408
300
|
}
|
|
409
|
-
|
|
410
301
|
/**
|
|
411
302
|
* Checks if the provided object is an instance of the specified type.
|
|
412
303
|
* It's safer than `instanceof` operator as it handles cases
|
|
413
304
|
* where type is not actually a type but an object.
|
|
414
|
-
* @param {any} instance
|
|
415
|
-
* @param {any} type
|
|
416
305
|
*/
|
|
417
306
|
function isInstanceOf(instance, type) {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
307
|
+
try {
|
|
308
|
+
return typeof type === 'function' && instance instanceof type;
|
|
309
|
+
}
|
|
310
|
+
catch (e) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
423
313
|
}
|
|
424
314
|
|
|
425
|
-
export { asString, checkHttpDataCollectionEnabled,
|
|
315
|
+
export { asString, checkHttpDataCollectionEnabled, getBlockedElements, getHttpPayloadAllowedURLs, getJSStack, getMaxSubstringAllowed, getOnURL, getUserAgent, getUserLanguage, isInstanceOf, isInvalidURLConfig, isNoibuJSAlreadyLoaded, isStackTrace, isValidURL, makeRequest, maskTextInput, processFrames, stringifyJSON };
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[JS_STACK_METHOD_ATT_NAME]: string;
|
|
1
|
+
export declare interface RawStackFrame {
|
|
2
|
+
file: string;
|
|
3
|
+
line?: number;
|
|
4
|
+
column?: number;
|
|
5
|
+
mname: string;
|
|
7
6
|
}
|
|
8
|
-
export declare function parseStack(stackString: string):
|
|
9
|
-
export {};
|
|
7
|
+
export declare function parseStack(stackString: string): RawStackFrame[];
|