noibu-react-native 0.2.3 → 0.2.5
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/dist/api/clientConfig.js +20 -27
- package/dist/api/helpCode.js +61 -87
- package/dist/api/metroplexSocket.js +72 -65
- package/dist/api/storedPageVisit.js +150 -208
- package/dist/constants.js +3 -7
- package/dist/entry/init.js +13 -15
- package/dist/monitors/{appNavigationMonitor.js → AppNavigationMonitor.js} +10 -19
- package/dist/monitors/BaseMonitor.js +23 -0
- package/dist/monitors/ClickMonitor.js +198 -0
- package/dist/monitors/ErrorMonitor.js +206 -0
- package/dist/monitors/KeyboardInputMonitor.js +60 -0
- package/dist/monitors/PageMonitor.js +98 -0
- package/dist/monitors/RequestMonitor.js +390 -0
- package/dist/monitors/http-tools/GqlErrorValidator.js +259 -0
- package/dist/monitors/{httpDataBundler.js → http-tools/HTTPDataBundler.js} +23 -102
- package/dist/pageVisit/{eventDebouncer.js → EventDebouncer.js} +36 -47
- package/dist/pageVisit/pageVisitEventError.js +3 -3
- package/dist/pageVisit/pageVisitEventHTTP.js +5 -4
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +22 -5
- package/dist/sessionRecorder/sessionRecorder.js +5 -2
- package/dist/src/api/clientConfig.d.ts +8 -13
- package/dist/src/api/clientConfig.test.d.ts +1 -0
- package/dist/src/api/helpCode.d.ts +10 -16
- package/dist/src/api/metroplexSocket.d.ts +52 -71
- package/dist/src/api/storedPageVisit.d.ts +12 -21
- package/dist/src/constants.d.ts +1 -0
- package/dist/src/monitors/AppNavigationMonitor.d.ts +18 -0
- package/dist/src/monitors/BaseMonitor.d.ts +13 -0
- package/dist/src/monitors/BaseMonitor.test.d.ts +1 -0
- package/dist/src/monitors/ClickMonitor.d.ts +31 -0
- package/dist/src/monitors/ErrorMonitor.d.ts +63 -0
- package/dist/src/monitors/{keyboardInputMonitor.d.ts → KeyboardInputMonitor.d.ts} +7 -4
- package/dist/src/monitors/{pageMonitor.d.ts → PageMonitor.d.ts} +6 -8
- package/dist/src/monitors/RequestMonitor.d.ts +94 -0
- package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +59 -0
- package/dist/src/monitors/{httpDataBundler.d.ts → http-tools/HTTPDataBundler.d.ts} +13 -28
- package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +3 -2
- package/dist/src/pageVisit/{eventDebouncer.d.ts → EventDebouncer.d.ts} +3 -10
- package/dist/src/pageVisit/pageVisit.d.ts +1 -1
- package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +3 -3
- package/dist/src/sessionRecorder/nativeSessionRecorderSubscription.d.ts +15 -0
- package/dist/src/storage/rnStorageProvider.d.ts +1 -1
- package/dist/src/storage/storage.d.ts +1 -1
- package/dist/src/storage/storageProvider.d.ts +2 -2
- package/dist/src/utils/function.d.ts +4 -5
- package/dist/src/utils/object.d.ts +3 -5
- package/dist/src/utils/polyfills.d.ts +1 -4
- package/dist/types/Metroplex.types.d.ts +73 -0
- package/dist/types/PageVisit.types.d.ts +2 -145
- package/dist/types/PageVisitErrors.types.d.ts +114 -0
- package/dist/types/PageVisitEvents.types.d.ts +91 -0
- package/dist/types/Storage.d.ts +1 -1
- package/dist/types/StoredPageVisit.types.d.ts +4 -45
- package/dist/utils/function.js +0 -1
- package/dist/utils/object.js +1 -0
- package/package.json +11 -7
- package/dist/monitors/clickMonitor.js +0 -258
- package/dist/monitors/errorMonitor.js +0 -202
- package/dist/monitors/gqlErrorValidator.js +0 -306
- package/dist/monitors/inputMonitor.js +0 -138
- package/dist/monitors/keyboardInputMonitor.js +0 -66
- package/dist/monitors/pageMonitor.js +0 -122
- package/dist/monitors/requestMonitor.js +0 -386
- package/dist/src/monitors/appNavigationMonitor.d.ts +0 -22
- package/dist/src/monitors/clickMonitor.d.ts +0 -44
- package/dist/src/monitors/errorMonitor.d.ts +0 -28
- package/dist/src/monitors/gqlErrorValidator.d.ts +0 -82
- package/dist/src/monitors/inputMonitor.d.ts +0 -34
- package/dist/src/monitors/requestMonitor.d.ts +0 -10
- package/dist/types/RRWeb.d.ts +0 -48
- package/dist/types/ReactNative.d.ts +0 -4
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
|
-
import { HUMAN_READABLE_CONTENT_TYPE_REGEX, DEFAULT_WEBSITE_SUBDOMAIN_PATTERN, SEVERITY, HTTP_BODY_NULL_STRING, HTTP_DATA_REQ_HEADERS_ATT_NAME, HTTP_DATA_PAYLOAD_ATT_NAME, HTTP_DATA_RESP_HEADERS_ATT_NAME, HTTP_DATA_RESP_PAYLOAD_ATT_NAME, HTTP_BODY_DROPPED_LENGTH_MSG, HTTP_BODY_DROPPED_TYPE_MSG, CONTENT_TYPE, CONTENT_LENGTH, BLOCKED_HTTP_HEADER_KEYS, PII_REDACTION_REPLACEMENT_STRING, MAX_HTTP_DATA_PAYLOAD_LENGTH, MAX_SUCCESS_HTTP_DATA_PAYLOAD_LENGTH } from '
|
|
3
|
-
import ClientConfig from '
|
|
4
|
-
import StoredMetrics from '
|
|
5
|
-
import { safeFromEntries, safeEntries } from '
|
|
6
|
-
import { safeTrim, stringifyJSON, isString } from '
|
|
7
|
-
import { removePII } from '
|
|
2
|
+
import { HUMAN_READABLE_CONTENT_TYPE_REGEX, DEFAULT_WEBSITE_SUBDOMAIN_PATTERN, SEVERITY, HTTP_BODY_NULL_STRING, HTTP_DATA_REQ_HEADERS_ATT_NAME, HTTP_DATA_PAYLOAD_ATT_NAME, HTTP_DATA_RESP_HEADERS_ATT_NAME, HTTP_DATA_RESP_PAYLOAD_ATT_NAME, HTTP_BODY_DROPPED_LENGTH_MSG, HTTP_BODY_DROPPED_TYPE_MSG, CONTENT_TYPE, CONTENT_LENGTH, BLOCKED_HTTP_HEADER_KEYS, PII_REDACTION_REPLACEMENT_STRING, MAX_HTTP_DATA_PAYLOAD_LENGTH, MAX_SUCCESS_HTTP_DATA_PAYLOAD_LENGTH } from '../../constants.js';
|
|
3
|
+
import ClientConfig from '../../api/clientConfig.js';
|
|
4
|
+
import StoredMetrics from '../../api/storedMetrics.js';
|
|
5
|
+
import { safeFromEntries, safeEntries } from '../../utils/object.js';
|
|
6
|
+
import { safeTrim, stringifyJSON, isString } from '../../utils/function.js';
|
|
7
|
+
import { removePII } from '../../utils/piiRedactor.js';
|
|
8
|
+
import { Singleton } from '../BaseMonitor.js';
|
|
8
9
|
|
|
9
10
|
/** Bundles HTTP payloads and headers */
|
|
10
|
-
class HTTPDataBundler {
|
|
11
|
+
class HTTPDataBundler extends Singleton {
|
|
11
12
|
/**
|
|
12
13
|
* Creates an instance of the ClickMonitor instance
|
|
13
14
|
*/
|
|
14
15
|
constructor() {
|
|
16
|
+
super();
|
|
15
17
|
// compile regex only once
|
|
16
18
|
this.contentTypeReadableRegex = new RegExp(HUMAN_READABLE_CONTENT_TYPE_REGEX, 'i');
|
|
17
19
|
// pull out the domain hostname
|
|
@@ -43,15 +45,6 @@ class HTTPDataBundler {
|
|
|
43
45
|
// TODO: disabled for beta. NOI-4253
|
|
44
46
|
// this.uniqueRequests = new Set();
|
|
45
47
|
}
|
|
46
|
-
/** gets the singleton instance
|
|
47
|
-
* @returns {HTTPDataBundler}
|
|
48
|
-
* */
|
|
49
|
-
static getInstance() {
|
|
50
|
-
if (!this.instance) {
|
|
51
|
-
this.instance = new HTTPDataBundler();
|
|
52
|
-
}
|
|
53
|
-
return this.instance;
|
|
54
|
-
}
|
|
55
48
|
/**
|
|
56
49
|
* Builds the HTTP payload allowed regexes for full and relative URLs
|
|
57
50
|
* @param allowedURLs A list of allowed URLs
|
|
@@ -77,13 +70,12 @@ class HTTPDataBundler {
|
|
|
77
70
|
}
|
|
78
71
|
/**
|
|
79
72
|
* Takes an iterator and returns a map of strings representing headers.
|
|
80
|
-
*
|
|
81
|
-
*
|
|
73
|
+
* param {object} headersIterable any iterable object
|
|
74
|
+
* returns a map of strings (as expected by metroplex) representing HTTP
|
|
82
75
|
* request or response headers
|
|
83
76
|
*/
|
|
84
77
|
static headersMapFromIterable(headersIterable) {
|
|
85
78
|
const headerMap = new Map();
|
|
86
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
87
79
|
for (const header of headersIterable) {
|
|
88
80
|
// Ensure we're working with strings
|
|
89
81
|
// This will also automatically convert null to "null"
|
|
@@ -153,65 +145,11 @@ class HTTPDataBundler {
|
|
|
153
145
|
return null;
|
|
154
146
|
});
|
|
155
147
|
}
|
|
156
|
-
/**
|
|
157
|
-
* Takes a URL and returns true if it is determined to be on the same domain as the URL
|
|
158
|
-
* the script is running on. Ignores protocol and path, and allows the URL to be a subdomain.
|
|
159
|
-
* @param {string} requestURL the URL of a request to compare to the script website's URL
|
|
160
|
-
* @param {bool} isHostnameCheck the URL is a domain hostname, could be a super or sub domain
|
|
161
|
-
*/
|
|
162
|
-
isURLSameDomain(requestURL, isHostnameCheck = false) {
|
|
163
|
-
if (typeof requestURL !== 'string' ||
|
|
164
|
-
!this.initialURLPartsReversed ||
|
|
165
|
-
this.initialURLPartsReversed.length < 1) {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
let requestHostname = isHostnameCheck ? requestURL : ''; // has to be declared outside of `try`
|
|
169
|
-
// Use URL constructor to extract hostname
|
|
170
|
-
if (!isHostnameCheck) {
|
|
171
|
-
try {
|
|
172
|
-
let requestURLWithProtocol = requestURL;
|
|
173
|
-
if (requestURL.startsWith('//')) {
|
|
174
|
-
// eslint-disable-next-line prefer-template
|
|
175
|
-
requestURLWithProtocol = 'https:' + requestURL;
|
|
176
|
-
}
|
|
177
|
-
requestHostname = new URL(requestURLWithProtocol).hostname;
|
|
178
|
-
}
|
|
179
|
-
catch (e) {
|
|
180
|
-
// Return false if URL() is unable to parse the request URL
|
|
181
|
-
ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(`Unable to determine hostname for request URL: ${e}`, false, SEVERITY.warn);
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
const requestParts = requestHostname.split('.');
|
|
186
|
-
// Remove first subdomain from either URL if it is www., www1., etc.
|
|
187
|
-
if (requestParts.length < 1)
|
|
188
|
-
return false;
|
|
189
|
-
/* eslint-disable no-unused-expressions */
|
|
190
|
-
DEFAULT_WEBSITE_SUBDOMAIN_PATTERN.test(requestParts[0]) &&
|
|
191
|
-
requestParts.shift();
|
|
192
|
-
/* eslint-enable no-unused-expressions */
|
|
193
|
-
// Reverse order array
|
|
194
|
-
requestParts.reverse();
|
|
195
|
-
if (!isHostnameCheck &&
|
|
196
|
-
requestParts.length < this.initialURLPartsReversed.length)
|
|
197
|
-
return false;
|
|
198
|
-
// Return true if for every part in the website part, the same part exists
|
|
199
|
-
// in the request part, or if alsoCheckSuperDomain is true.
|
|
200
|
-
if (isHostnameCheck) {
|
|
201
|
-
const isSubDomain = requestParts.length >= this.initialURLPartsReversed.length &&
|
|
202
|
-
this.initialURLPartsReversed.every((part, i) => part === requestParts[i]);
|
|
203
|
-
const isSuperDomain = requestParts.length <= this.initialURLPartsReversed.length &&
|
|
204
|
-
requestParts.every((part, i) => part === this.initialURLPartsReversed[i]);
|
|
205
|
-
return isSubDomain || isSuperDomain;
|
|
206
|
-
}
|
|
207
|
-
// Default return false if alsoCheckSuperDomain is not true
|
|
208
|
-
return this.initialURLPartsReversed.every((part, i) => part === requestParts[i]);
|
|
209
|
-
}
|
|
210
148
|
/**
|
|
211
149
|
* Builds an HTTP Data bundle
|
|
212
150
|
*/
|
|
213
151
|
bundleHTTPData(url, requestHeaders, rawRequestPayload, responseHeaders, rawResponsePayload, method, isError) {
|
|
214
|
-
if (!this.isValidRequest(
|
|
152
|
+
if (!this.isValidRequest(method)) {
|
|
215
153
|
return null;
|
|
216
154
|
}
|
|
217
155
|
// stringify payload if correct type and not too large
|
|
@@ -253,24 +191,9 @@ class HTTPDataBundler {
|
|
|
253
191
|
/**
|
|
254
192
|
* Validates a request based on the URL and method. When enabled, will handle
|
|
255
193
|
* de-duping the requests
|
|
256
|
-
* @param {string} url
|
|
257
|
-
* @param {string} method
|
|
258
|
-
* @returns boolean indicating whether the validation passed
|
|
259
194
|
*/
|
|
260
|
-
isValidRequest(
|
|
261
|
-
|
|
262
|
-
return false;
|
|
263
|
-
if (!method || typeof method !== 'string') {
|
|
264
|
-
return false;
|
|
265
|
-
}
|
|
266
|
-
// TODO: Check below disabled for beta. NOI-4253
|
|
267
|
-
// only bundle and send once per request/method/response code combination
|
|
268
|
-
// const urlWithoutParams = url.split('?')[0];
|
|
269
|
-
// const requestSignature = `${urlWithoutParams}-${method}-${responseCode}`;
|
|
270
|
-
// if (this.uniqueRequests.has(requestSignature)) {
|
|
271
|
-
// return false;
|
|
272
|
-
// }
|
|
273
|
-
return true;
|
|
195
|
+
isValidRequest(method) {
|
|
196
|
+
return (this.httpDataCollectionEnabled && method && typeof method === 'string');
|
|
274
197
|
}
|
|
275
198
|
/**
|
|
276
199
|
* Checks two things: that the URL is either on the same domain (or an address relative to the
|
|
@@ -288,15 +211,15 @@ class HTTPDataBundler {
|
|
|
288
211
|
// URL is absolute; either "http://example.com" or "//example.com"
|
|
289
212
|
if (HTTPDataBundler.isAbsoluteURL(url)) {
|
|
290
213
|
// Only capture requests on the same domain or in the allowed list
|
|
291
|
-
if (!this.
|
|
214
|
+
if (!this.shouldCollectPayloadForURL(url)) {
|
|
292
215
|
return false;
|
|
216
|
+
}
|
|
293
217
|
} // end `if` (if URL is relative, it is on the same domain.)
|
|
294
218
|
return true;
|
|
295
219
|
}
|
|
296
220
|
/**
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
* @returns boolean indicating whether the URL passed is either absolute or relative
|
|
221
|
+
* Determines if the URL is absolute or relative
|
|
222
|
+
* returns boolean indicating whether the URL passed is either absolute or relative
|
|
300
223
|
*/
|
|
301
224
|
static isAbsoluteURL(url) {
|
|
302
225
|
if (!url || typeof url !== 'string') {
|
|
@@ -306,22 +229,20 @@ class HTTPDataBundler {
|
|
|
306
229
|
}
|
|
307
230
|
/**
|
|
308
231
|
* Checks whether HTTP payloads can be collected on this URL
|
|
309
|
-
*
|
|
232
|
+
* returns boolean indicating whether HTTP payloads can be collected on this URL
|
|
310
233
|
*/
|
|
311
234
|
shouldCollectPayloadForURL(url) {
|
|
235
|
+
var _a, _b;
|
|
312
236
|
if (!url || typeof url !== 'string') {
|
|
313
237
|
return false;
|
|
314
238
|
}
|
|
315
239
|
// check if in the full URL allowed list
|
|
316
|
-
const isAllowedAsAbsolute =
|
|
317
|
-
|
|
318
|
-
const isRelative = !HTTPDataBundler.isAbsoluteURL(url) || this.isURLSameDomain(url);
|
|
240
|
+
const isAllowedAsAbsolute = (_a = this.httpDataAllowedAbsoluteRegex) === null || _a === void 0 ? void 0 : _a.test(url.toLowerCase());
|
|
241
|
+
const isRelative = !HTTPDataBundler.isAbsoluteURL(url);
|
|
319
242
|
// check if in the relative URL allowed list or if it is on the same domain
|
|
320
243
|
const isAllowedAsRelative =
|
|
321
244
|
// if this is a relative URL (isURLSameDomain will fail) OR a full URL on domain
|
|
322
|
-
isRelative &&
|
|
323
|
-
!!this.httpDataAllowedRelativeRegex &&
|
|
324
|
-
this.httpDataAllowedRelativeRegex.test(url.toLowerCase());
|
|
245
|
+
isRelative && ((_b = this.httpDataAllowedRelativeRegex) === null || _b === void 0 ? void 0 : _b.test(url.toLowerCase()));
|
|
325
246
|
return isAllowedAsAbsolute || isAllowedAsRelative;
|
|
326
247
|
}
|
|
327
248
|
/**
|
|
@@ -1,65 +1,54 @@
|
|
|
1
1
|
import { PageVisit } from './pageVisit.js';
|
|
2
|
-
import {
|
|
2
|
+
import { APP_NAVIGATION_EVENT_TYPE, PAGE_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS, ERROR_EVENT_TYPE, HTTP_EVENT_TYPE, KEYBOARD_EVENT_TYPE, SEVERITY } from '../constants.js';
|
|
3
3
|
import { timestampWrapper } from '../utils/date.js';
|
|
4
4
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
5
5
|
import ClientConfig from '../api/clientConfig.js';
|
|
6
|
+
import { Singleton } from '../monitors/BaseMonitor.js';
|
|
6
7
|
|
|
7
8
|
/** @module EventDebouncer */
|
|
8
9
|
/**
|
|
9
10
|
* Singleton class responsible for debouncing all events
|
|
10
11
|
* that are registered
|
|
11
12
|
*/
|
|
12
|
-
class EventDebouncer {
|
|
13
|
+
class EventDebouncer extends Singleton {
|
|
13
14
|
/**
|
|
14
15
|
* Creates an instance of EventDebouncer
|
|
15
16
|
*/
|
|
16
17
|
constructor() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
/** will debounce all events that are of this type by the debounce period
|
|
51
|
-
*/
|
|
52
|
-
registerInputType(type, debouncePeriod, eventName = type) {
|
|
53
|
-
if (type in this.eventsToDebounce) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
// registering this event type as a debouncable
|
|
57
|
-
this.eventsToDebounce[type] = {
|
|
58
|
-
timeout: null,
|
|
59
|
-
events: [],
|
|
60
|
-
debouncePeriod,
|
|
61
|
-
eventName,
|
|
18
|
+
super();
|
|
19
|
+
this.eventsToDebounce = {
|
|
20
|
+
[APP_NAVIGATION_EVENT_TYPE]: {
|
|
21
|
+
timeout: null,
|
|
22
|
+
events: [],
|
|
23
|
+
debouncePeriod: 0,
|
|
24
|
+
eventName: APP_NAVIGATION_EVENT_TYPE,
|
|
25
|
+
},
|
|
26
|
+
[PAGE_EVENT_TYPE]: {
|
|
27
|
+
timeout: null,
|
|
28
|
+
events: [],
|
|
29
|
+
debouncePeriod: MAX_TIME_FOR_UNSENT_DATA_MILLIS,
|
|
30
|
+
eventName: PAGE_EVENT_TYPE,
|
|
31
|
+
},
|
|
32
|
+
[ERROR_EVENT_TYPE]: {
|
|
33
|
+
timeout: null,
|
|
34
|
+
events: [],
|
|
35
|
+
debouncePeriod: MAX_TIME_FOR_UNSENT_DATA_MILLIS,
|
|
36
|
+
eventName: ERROR_EVENT_TYPE,
|
|
37
|
+
},
|
|
38
|
+
[HTTP_EVENT_TYPE]: {
|
|
39
|
+
timeout: null,
|
|
40
|
+
events: [],
|
|
41
|
+
debouncePeriod: MAX_TIME_FOR_UNSENT_DATA_MILLIS,
|
|
42
|
+
eventName: HTTP_EVENT_TYPE,
|
|
43
|
+
},
|
|
44
|
+
[KEYBOARD_EVENT_TYPE]: {
|
|
45
|
+
timeout: null,
|
|
46
|
+
events: [],
|
|
47
|
+
debouncePeriod: MAX_TIME_FOR_UNSENT_DATA_MILLIS,
|
|
48
|
+
eventName: KEYBOARD_EVENT_TYPE,
|
|
49
|
+
},
|
|
62
50
|
};
|
|
51
|
+
this._setupUnloadHandler();
|
|
63
52
|
}
|
|
64
53
|
/**
|
|
65
54
|
* Creates an event object with the event and the time it was added then pushes
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { isValidURL, getJSStack, stringifyJSON, getMaxSubstringAllowed, asString } from '../utils/function.js';
|
|
2
|
-
import { EVENT_ERROR_TYPE, URL_ATT_NAME, BLOCKLISTED_DOMAINS, ERROR_EVENT_TYPE, ERROR_EVENT_ERROR_TYPE, CUSTOM_ERROR_EVENT_TYPE, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, ERROR_LOG_EVENT_ERROR_TYPE, FETCH_EXCEPTION_ERROR_TYPE, WRAPPED_EXCEPTION_ERROR_TYPE, GQL_ERROR_TYPE, RESPONSE_ERROR_TYPE, XML_HTTP_REQUEST_ERROR_TYPE, ERROR_SOURCE_ATT_NAME, TYPE_ATT_NAME, JS_EVENT_TYPE, JS_ERROR_ATT_NAME, JS_STACK_FRAMES_ATT_NAME, JS_STACK_FILE_ATT_NAME, JS_STACK_METHOD_ATT_NAME, SEVERITY, JS_STACK_MESSAGE_ATT_NAME, HTTP_EVENT_TYPE, NOIBU_INPUT_URLS, HTTP_CODE_ATT_NAME, GQL_EVENT_TYPE, GQL_ERROR_ATT_NAME
|
|
2
|
+
import { EVENT_ERROR_TYPE, URL_ATT_NAME, BLOCKLISTED_DOMAINS, ERROR_EVENT_TYPE, ERROR_EVENT_ERROR_TYPE, CUSTOM_ERROR_EVENT_TYPE, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, ERROR_LOG_EVENT_ERROR_TYPE, FETCH_EXCEPTION_ERROR_TYPE, WRAPPED_EXCEPTION_ERROR_TYPE, GQL_ERROR_TYPE, RESPONSE_ERROR_TYPE, XML_HTTP_REQUEST_ERROR_TYPE, ERROR_SOURCE_ATT_NAME, TYPE_ATT_NAME, JS_EVENT_TYPE, JS_ERROR_ATT_NAME, JS_STACK_FRAMES_ATT_NAME, JS_STACK_FILE_ATT_NAME, JS_STACK_METHOD_ATT_NAME, SEVERITY, JS_STACK_MESSAGE_ATT_NAME, HTTP_EVENT_TYPE, NOIBU_INPUT_URLS, HTTP_CODE_ATT_NAME, PV_SEQ_ATT_NAME, GQL_EVENT_TYPE, GQL_ERROR_ATT_NAME } from '../constants.js';
|
|
3
3
|
import ClientConfig from '../api/clientConfig.js';
|
|
4
|
-
import { InputMonitor } from '../monitors/inputMonitor.js';
|
|
5
4
|
import StoredMetrics from '../api/storedMetrics.js';
|
|
5
|
+
import { EventDebouncer } from './EventDebouncer.js';
|
|
6
6
|
|
|
7
7
|
/** @module PageVisitEventError */
|
|
8
8
|
|
|
@@ -314,7 +314,7 @@ function saveErrorToPagevisit(type, payload, httpDataSeqNum) {
|
|
|
314
314
|
// we register an error event
|
|
315
315
|
StoredMetrics.getInstance().addError();
|
|
316
316
|
// debounce event
|
|
317
|
-
|
|
317
|
+
EventDebouncer.getInstance().addEvent(pvError, ERROR_EVENT_TYPE);
|
|
318
318
|
}
|
|
319
319
|
|
|
320
320
|
export { getOnURL, isErrorCollectedByNoibu, saveErrorToPagevisit };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { timestampWrapper } from '../utils/date.js';
|
|
2
|
-
import { HTTP_RESP_CODE_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HTTP_METHOD_ATT_NAME, URL_ATT_NAME, PV_SEQ_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_EVENT_TYPE, MAX_HTTP_DATA_EVENT_COUNT, MAX_HTTP_DATA_IF_ERROR_EVENT_COUNT
|
|
2
|
+
import { HTTP_RESP_CODE_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HTTP_METHOD_ATT_NAME, URL_ATT_NAME, PV_SEQ_ATT_NAME, PAGE_VISIT_HTTP_DATA_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_EVENT_TYPE, MAX_HTTP_DATA_EVENT_COUNT, MAX_HTTP_DATA_IF_ERROR_EVENT_COUNT } from '../constants.js';
|
|
3
3
|
import { PageVisit } from './pageVisit.js';
|
|
4
4
|
import StoredMetrics from '../api/storedMetrics.js';
|
|
5
5
|
import MetroplexSocket from '../api/metroplexSocket.js';
|
|
6
6
|
import { getMaxSubstringAllowed, asString, safeTrim } from '../utils/function.js';
|
|
7
|
-
import { EventDebouncer } from './
|
|
7
|
+
import { EventDebouncer } from './EventDebouncer.js';
|
|
8
8
|
|
|
9
9
|
/** @module PageVisitEventHTTP */
|
|
10
10
|
/**
|
|
@@ -54,8 +54,9 @@ class PageVisitEventHTTP {
|
|
|
54
54
|
this.httpEvent[PV_SEQ_ATT_NAME] = sequenceNumber;
|
|
55
55
|
// increment the count
|
|
56
56
|
StoredMetrics.getInstance().addHttpData();
|
|
57
|
-
const metroplexMsg = {
|
|
58
|
-
|
|
57
|
+
const metroplexMsg = {
|
|
58
|
+
[PAGE_VISIT_HTTP_DATA_ATT_NAME]: this.httpData,
|
|
59
|
+
};
|
|
59
60
|
MetroplexSocket.getInstance().sendMessage(HTTP_DATA_METROPLEX_TYPE, metroplexMsg);
|
|
60
61
|
}
|
|
61
62
|
else {
|
|
@@ -46,13 +46,30 @@ function initialize(projectId, config) {
|
|
|
46
46
|
const refinedMaximumDailyNetworkUsageInMB = maximumDailyNetworkUsageInMB !== null && maximumDailyNetworkUsageInMB !== void 0 ? maximumDailyNetworkUsageInMB : 0;
|
|
47
47
|
NativeSessionRecorder.initialize(projectId, userId, logLevel, allowMeteredNetworkUsage, enableWebViewCapture, allowedDomains, disableOnLowEndDevices, enableDailyNetworkUsageLimit, refinedMaximumDailyNetworkUsageInMB);
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Subscribes to a native event emitted by the Noibu Session Recorder.
|
|
51
|
+
*
|
|
52
|
+
* This function listens for the `noibuRecordingEvent` emitted from the native layer (only on Android)
|
|
53
|
+
* and invokes the provided callback whenever the event occurs. If the platform is not Android,
|
|
54
|
+
* the function will do nothing and return a no-op unsubscribe function.
|
|
55
|
+
*
|
|
56
|
+
* @param {function(RecorderEvent): void} callback - A callback function that will be invoked with
|
|
57
|
+
* the event data whenever the `noibuRecordingEvent` is emitted.
|
|
58
|
+
*
|
|
59
|
+
* @returns {UnsubscribeFn} A function to unsubscribe from the event. On Android, this will remove
|
|
60
|
+
* the event listener. On other platforms, it will be a no-op.
|
|
61
|
+
*
|
|
62
|
+
* @throws {Error} If the Noibu Session Recorder is not initialized before calling this function.
|
|
63
|
+
*/
|
|
49
64
|
function subscribeToNativeEvent(callback) {
|
|
50
|
-
if (
|
|
51
|
-
|
|
65
|
+
if (Platform.OS === 'android') {
|
|
66
|
+
if (!nativeModuleEmitter) {
|
|
67
|
+
throw new Error('You have to initialize Noibu Session Recorder first');
|
|
68
|
+
}
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
70
|
+
nativeModuleEmitter.addListener('noibuRecordingEvent', callback);
|
|
71
|
+
// return () => subscription.remove();
|
|
52
72
|
}
|
|
53
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
54
|
-
nativeModuleEmitter.addListener('noibuRecordingEvent', callback);
|
|
55
|
-
// return () => subscription.remove();
|
|
56
73
|
return () => { };
|
|
57
74
|
}
|
|
58
75
|
|
|
@@ -4,10 +4,11 @@ import { LogLevel, initialize, subscribeToNativeEvent } from './nativeSessionRec
|
|
|
4
4
|
import StoredMetrics from '../api/storedMetrics.js';
|
|
5
5
|
import ClientConfig from '../api/clientConfig.js';
|
|
6
6
|
import { stringifyJSON } from '../utils/function.js';
|
|
7
|
-
import {
|
|
7
|
+
import { MAX_TIME_FOR_RECORDER_USER_EVENTS, SEVERITY, MAX_RECORDER_EVENT_BUFFER, MAX_TIME_FOR_UNSENT_DATA_MILLIS, VIDEO_FRAG_ATT_NAME, PV_SEQ_ATT_NAME, LENGTH_ATT_NAME, CSS_URLS_ATT_NAME, VIDEO_METROPLEX_TYPE, PAGE_VISIT_VID_FRAG_ATT_NAME, POST_METRICS_EVENT_NAME } from '../constants.js';
|
|
8
8
|
import MetroplexSocket from '../api/metroplexSocket.js';
|
|
9
9
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
10
10
|
import { noibuLog } from '../utils/log.js';
|
|
11
|
+
import { Platform } from 'react-native';
|
|
11
12
|
|
|
12
13
|
/** Singleton class to record user sessions */
|
|
13
14
|
class SessionRecorder {
|
|
@@ -36,7 +37,9 @@ class SessionRecorder {
|
|
|
36
37
|
const nativeSessionRecorderConfig = {
|
|
37
38
|
logLevel: LogLevel.Verbose,
|
|
38
39
|
};
|
|
39
|
-
|
|
40
|
+
if (Platform.OS === 'android') {
|
|
41
|
+
initialize('abc1234', nativeSessionRecorderConfig);
|
|
42
|
+
}
|
|
40
43
|
this.instance = new SessionRecorder();
|
|
41
44
|
// todo handle RN clicks
|
|
42
45
|
addSafeEventListener(window, 'click', () => {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { SEVERITY } from '../constants';
|
|
2
2
|
import { CustomerConfig, StoredConfig } from '../../types/Config';
|
|
3
|
+
import { Singleton } from '../monitors/BaseMonitor';
|
|
3
4
|
/**
|
|
4
5
|
* Singleton class to manage the client configuration
|
|
5
6
|
* this class will be responsible for controlling the disabled
|
|
6
7
|
* status of the client script as well as managing all storage
|
|
7
8
|
* storing and retrieval.
|
|
8
9
|
*/
|
|
9
|
-
export default class ClientConfig {
|
|
10
|
+
export default class ClientConfig extends Singleton {
|
|
10
11
|
readonly pageVisitId: string;
|
|
11
12
|
browserId: StoredConfig['BrowserId'];
|
|
12
13
|
private pageVisitSeq;
|
|
@@ -15,26 +16,20 @@ export default class ClientConfig {
|
|
|
15
16
|
private cltErrorPostCounter;
|
|
16
17
|
private readonly maxSocketInactiveTime;
|
|
17
18
|
private locationBreadcrumbs;
|
|
18
|
-
private static instance;
|
|
19
|
-
static noibuErrorURL: string;
|
|
20
19
|
customerDomain: string;
|
|
21
20
|
isClientDisabled: boolean;
|
|
21
|
+
configurationPromise: Promise<void>;
|
|
22
22
|
readonly listOfUrlsToCollectHttpDataFrom: CustomerConfig['listOfUrlsToCollectHttpDataFrom'];
|
|
23
23
|
readonly enableHttpDataCollection: CustomerConfig['enableHttpDataCollection'];
|
|
24
24
|
readonly blockedElements: CustomerConfig['blockedElements'];
|
|
25
25
|
/**
|
|
26
26
|
* Creates a ClientConfig singleton instance
|
|
27
27
|
*/
|
|
28
|
-
constructor(noibuErrorURL
|
|
29
|
-
/** Configures the singleton instance */
|
|
30
|
-
static configureInstance({ noibuErrorURL, customerConfig, }: {
|
|
31
|
-
noibuErrorURL: string;
|
|
32
|
-
customerConfig: CustomerConfig;
|
|
33
|
-
}): Promise<void>;
|
|
28
|
+
constructor(noibuErrorURL?: string, customerConfig?: CustomerConfig);
|
|
34
29
|
/**
|
|
35
|
-
*
|
|
30
|
+
* Convenience method to check correct setup
|
|
36
31
|
*/
|
|
37
|
-
|
|
32
|
+
private hasAllNecessaryArgs;
|
|
38
33
|
/** lockClient will disable the client script for a single pagevisit for
|
|
39
34
|
* duration given in minuntes */
|
|
40
35
|
lockClient(duration: number, msg: string): Promise<void>;
|
|
@@ -43,7 +38,7 @@ export default class ClientConfig {
|
|
|
43
38
|
/** Updates the config object to store the given last active time */
|
|
44
39
|
updateLastActiveTime(lastActiveTime: Date): Promise<void>;
|
|
45
40
|
/** Gets the current page visit sequence number that should be used */
|
|
46
|
-
getPageVisitSeq(): Promise<number
|
|
41
|
+
getPageVisitSeq(): Promise<number>;
|
|
47
42
|
/**
|
|
48
43
|
* Returns the client config object from storage or generates a new one
|
|
49
44
|
* What is stored in storage will look like this
|
|
@@ -97,7 +92,7 @@ export default class ClientConfig {
|
|
|
97
92
|
* and disable the client if required
|
|
98
93
|
* severity expects one of the SEVERITY_x level constants, or else error will be used
|
|
99
94
|
*/
|
|
100
|
-
postNoibuErrorAndOptionallyDisableClient(errorMsg: any, disableClient
|
|
95
|
+
postNoibuErrorAndOptionallyDisableClient(errorMsg: any, disableClient?: boolean, severity?: (typeof SEVERITY)[keyof typeof SEVERITY], keepAlive?: boolean): Promise<void>;
|
|
101
96
|
/**
|
|
102
97
|
* Returns true if the page visit is considered to be inactive
|
|
103
98
|
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,23 +1,13 @@
|
|
|
1
|
+
import { Singleton } from '../monitors/BaseMonitor';
|
|
1
2
|
/**
|
|
2
3
|
* HelpCode class is responsible for help code feature related functionality
|
|
3
4
|
*/
|
|
4
|
-
export default class HelpCode {
|
|
5
|
+
export default class HelpCode extends Singleton {
|
|
6
|
+
private requestContext;
|
|
5
7
|
/**
|
|
6
|
-
*
|
|
7
|
-
* @returns {HelpCode}
|
|
8
|
+
* Constructs instance and sets up event listeners
|
|
8
9
|
*/
|
|
9
|
-
|
|
10
|
-
requestContext: {
|
|
11
|
-
resolve: null;
|
|
12
|
-
reject: null;
|
|
13
|
-
promise: null;
|
|
14
|
-
} | null;
|
|
15
|
-
/**
|
|
16
|
-
* Handles the received help code event.
|
|
17
|
-
* @param {CustomEvent<string>} event - The event object with string detail property.
|
|
18
|
-
* @returns {void}
|
|
19
|
-
*/
|
|
20
|
-
receiveHelpCode(event: CustomEvent<string>): void;
|
|
10
|
+
constructor();
|
|
21
11
|
/**
|
|
22
12
|
* Requests a help code and returns a Promise that resolves when the help code is obtained
|
|
23
13
|
* or rejects if the noibu connection is unavailable.
|
|
@@ -25,5 +15,9 @@ export default class HelpCode {
|
|
|
25
15
|
* @returns {Promise<string>} Promise object representing the help code request.
|
|
26
16
|
* @throws {string} Throws an error if the noibu connection is unavailable.
|
|
27
17
|
*/
|
|
28
|
-
requestHelpCode(): Promise<
|
|
18
|
+
requestHelpCode(): Promise<unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* Handles the received help code event.
|
|
21
|
+
*/
|
|
22
|
+
receiveHelpCode(event: CustomEvent<string>): void;
|
|
29
23
|
}
|