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.
Files changed (42) hide show
  1. package/README.md +22 -7
  2. package/dist/api/clientConfig.d.ts +101 -0
  3. package/dist/api/clientConfig.js +317 -388
  4. package/dist/api/helpCode.js +2 -2
  5. package/dist/api/inputManager.js +3 -9
  6. package/dist/api/metroplexSocket.js +10 -34
  7. package/dist/api/storedMetrics.js +3 -2
  8. package/dist/api/storedPageVisit.js +3 -3
  9. package/dist/constants.d.ts +7 -40
  10. package/dist/constants.js +8 -65
  11. package/dist/entry/index.d.ts +2 -3
  12. package/dist/entry/index.js +1 -9
  13. package/dist/entry/init.d.ts +5 -0
  14. package/dist/entry/init.js +60 -75
  15. package/dist/monitors/AppNavigationMonitor.d.ts +23 -0
  16. package/dist/monitors/AppNavigationMonitor.js +63 -0
  17. package/dist/monitors/clickMonitor.js +10 -57
  18. package/dist/monitors/errorMonitor.js +1 -1
  19. package/dist/monitors/gqlErrorValidator.js +3 -3
  20. package/dist/monitors/httpDataBundler.js +13 -12
  21. package/dist/monitors/integrations/react-native-navigation-integration.d.ts +19 -0
  22. package/dist/monitors/integrations/react-native-navigation-integration.js +38 -0
  23. package/dist/monitors/keyboardInputMonitor.js +0 -1
  24. package/dist/monitors/requestMonitor.js +10 -8
  25. package/dist/pageVisit/pageVisitEventError/pageVisitEventError.js +10 -8
  26. package/dist/storage/storage.d.ts +3 -2
  27. package/dist/storage/storageProvider.d.ts +6 -5
  28. package/dist/types/Config.d.ts +27 -0
  29. package/dist/types/NavigationIntegration.d.ts +7 -0
  30. package/dist/types/PageVisit.d.ts +22 -0
  31. package/dist/types/ReactNative.d.ts +4 -0
  32. package/dist/types/Storage.d.ts +14 -0
  33. package/dist/types/globals.d.ts +34 -0
  34. package/dist/utils/date.js +2 -2
  35. package/dist/utils/eventlistener.js +3 -3
  36. package/dist/utils/function.d.ts +93 -0
  37. package/dist/utils/function.js +210 -320
  38. package/dist/utils/stacktrace-parser.d.ts +6 -8
  39. package/dist/utils/stacktrace-parser.js +5 -5
  40. package/package.json +5 -1
  41. package/dist/monitors/elementMonitor.js +0 -177
  42. package/dist/monitors/locationChangeMonitor.js +0 -18
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Attaches corresponding listener to the passed navigation integration
3
+ */
4
+ export declare class AppNavigationMonitor {
5
+ private static instance;
6
+ private breadcrumbs;
7
+ /**
8
+ * guesses which navigation is used in app, and registers a listener if found
9
+ */
10
+ constructor();
11
+ /**
12
+ * Gets the singleton instance
13
+ */
14
+ static getInstance(): AppNavigationMonitor;
15
+ /**
16
+ * gets current global url
17
+ */
18
+ get globalUrl(): string;
19
+ /**
20
+ * Called when the event needs to be emitted
21
+ */
22
+ private reportLocationChange;
23
+ }
@@ -0,0 +1,63 @@
1
+ import { SEVERITY, URL_ATT_NAME, LOCATION_EVENT_TYPE } from '../constants.js';
2
+ import { getMaxSubstringAllowed } from '../utils/function.js';
3
+ import { InputMonitor } from './inputMonitor.js';
4
+ import { ReactNativeNavigationIntegration } from './integrations/react-native-navigation-integration.js';
5
+ import ClientConfig from '../api/clientConfig.js';
6
+
7
+ /**
8
+ * Attaches corresponding listener to the passed navigation integration
9
+ */
10
+ class AppNavigationMonitor {
11
+ static instance;
12
+ breadcrumbs = [];
13
+ /**
14
+ * guesses which navigation is used in app, and registers a listener if found
15
+ */
16
+ constructor() {
17
+ try {
18
+ // eslint-disable-next-line global-require,@typescript-eslint/no-var-requires,import/no-extraneous-dependencies
19
+ const rnNavigation = require('react-native-navigation')?.Navigation;
20
+ if (rnNavigation) {
21
+ new ReactNativeNavigationIntegration().register(rnNavigation, breadcrumbs => {
22
+ this.breadcrumbs = breadcrumbs;
23
+ this.reportLocationChange();
24
+ });
25
+ }
26
+ }
27
+ catch (e) {
28
+ ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(`AppNavigationMonitor: ${e}`, false, SEVERITY.error);
29
+ }
30
+ }
31
+ /**
32
+ * Gets the singleton instance
33
+ */
34
+ static getInstance() {
35
+ if (!AppNavigationMonitor.instance) {
36
+ AppNavigationMonitor.instance = new AppNavigationMonitor();
37
+ }
38
+ return AppNavigationMonitor.instance;
39
+ }
40
+ /**
41
+ * gets current global url
42
+ */
43
+ get globalUrl() {
44
+ const globalUrl = new URL('https://localhost');
45
+ globalUrl.hostname = ClientConfig.getInstance().customerDomain;
46
+ if (this.breadcrumbs.length) {
47
+ globalUrl.pathname = this.breadcrumbs.join('/');
48
+ }
49
+ return getMaxSubstringAllowed(globalUrl.toString());
50
+ }
51
+ /**
52
+ * Called when the event needs to be emitted
53
+ */
54
+ reportLocationChange() {
55
+ const payload = {
56
+ [URL_ATT_NAME]: this.globalUrl,
57
+ };
58
+ // storing the location change in the page visit queue
59
+ InputMonitor.getInstance().addEvent(payload, LOCATION_EVENT_TYPE);
60
+ }
61
+ }
62
+
63
+ export { AppNavigationMonitor };
@@ -4,14 +4,12 @@ import { PageVisit } from '../pageVisit/pageVisit.js';
4
4
  import { updatePayload } from '../pageVisit/userStep/userStep.js';
5
5
  import StoredMetrics from '../api/storedMetrics.js';
6
6
  import { WHITELIST_TEXT_REGEX_STRING } from '../const_matchers.js';
7
- import { getBlockedCSSForCurrentDomain, maskTextInput } from '../utils/function.js';
7
+ import { maskTextInput, getBlockedElements } from '../utils/function.js';
8
8
  import { timestampWrapper } from '../utils/date.js';
9
9
 
10
10
  /** @module ClickMonitor */
11
11
 
12
12
 
13
- const maxParentIteration = 5;
14
-
15
13
  /** Monitors the clicks which we capture and later process */
16
14
  class ClickMonitor {
17
15
  /**
@@ -67,10 +65,9 @@ class ClickMonitor {
67
65
 
68
66
  /**
69
67
  * Handles a single click event
70
- * @param {} event
68
+ * @param {{ _targetInst: RNNode }} event
71
69
  */
72
70
  _onClickHandle(event) {
73
- const blockedCSS = getBlockedCSSForCurrentDomain();
74
71
  if (event) {
75
72
  const { _targetInst: target } = event;
76
73
  const targetClassName = target.elementType;
@@ -80,7 +77,7 @@ class ClickMonitor {
80
77
  // to process the image name, else we need to get the textual content
81
78
  // todo process images
82
79
 
83
- text = this._getTextualContentFromEl(target, false, blockedCSS);
80
+ text = this._getTextualContentFromEl(target);
84
81
 
85
82
  let textFromElement = this._trimText(text);
86
83
 
@@ -140,54 +137,11 @@ class ClickMonitor {
140
137
  }
141
138
  }
142
139
 
143
- /**
144
- * parseTextFromParentElement will parse the parents of an element to try
145
- * and find textual content if no text can be extracted from the clicked element
146
- * @param {} element
147
- * @param {Array.<String>} blockedCSS
148
- */
149
- _parseTextFromParentElement(element, blockedCSS) {
150
- let iteratableElement = element;
151
- const parentElements = [];
152
- let parentIterations = 0;
153
- while (iteratableElement) {
154
- if (
155
- parentIterations >= maxParentIteration ||
156
- !iteratableElement.parentNode
157
- ) {
158
- break;
159
- }
160
- iteratableElement = iteratableElement.parentNode;
161
- parentElements.push(iteratableElement);
162
- parentIterations += 1;
163
- }
164
-
165
- for (let i = 0; i < parentElements.length; i += 1) {
166
- const el = parentElements[i];
167
- // we only get the text content if the clicked element has a button parent
168
- if (el && el.tagName === 'BUTTON') {
169
- // we disable the linter because we use 1 level recursion.
170
- // eslint-disable-next-line no-use-before-define
171
- return this._getTextualContentFromEl(el, false, blockedCSS);
172
- }
173
- }
174
-
175
- return '';
176
- }
177
-
178
140
  /** Gets the textual content from an element, if any
179
141
  * @param {} element
180
- * @param {} parseParent
181
- * @param {Array.<String>} blockedCSS
182
142
  */
183
- _getTextualContentFromEl(element, parseParent, blockedCSS) {
184
- return this._parseInnerContent(
185
- element,
186
- '',
187
- 100,
188
- { value: 0, limit: 100 },
189
- blockedCSS,
190
- );
143
+ _getTextualContentFromEl(element) {
144
+ return this._parseInnerContent(element, '', 100, { value: 0, limit: 100 });
191
145
  }
192
146
 
193
147
  /** Parse and trim text
@@ -207,7 +161,7 @@ class ClickMonitor {
207
161
  if (index > 0) {
208
162
  parsedText = `${parsedText.substring(0, index)}...`;
209
163
  } else {
210
- // If the are no ' ' characters then the text is likely not valid so just
164
+ // If there are no ' ' characters then the text is likely not valid so just
211
165
  // return '...'.
212
166
  parsedText = '...';
213
167
  }
@@ -217,13 +171,12 @@ class ClickMonitor {
217
171
 
218
172
  /**
219
173
  * Recursively parses element's inner content and masks blocked css classes
220
- * @param {HTMLElement} element
174
+ * @param {NReactNative.Node} element
221
175
  * @param {String} text
222
176
  * @param {Number} textLimit
223
177
  * @param {Object} counter
224
- * @param {Array.<String>} blockedCSS
225
178
  */
226
- _parseInnerContent(element, text, textLimit, counter, blockedCSS) {
179
+ _parseInnerContent(element, text, textLimit, counter) {
227
180
  /* eslint-disable no-restricted-syntax */
228
181
  /* eslint-disable no-param-reassign */
229
182
 
@@ -237,7 +190,7 @@ class ClickMonitor {
237
190
 
238
191
  counter.value += 1;
239
192
 
240
- if (blockedCSS.includes(element.memoizedProps.testID)) {
193
+ if (getBlockedElements().includes(element.memoizedProps.testID)) {
241
194
  return `${text}${text ? ' ' : ''}*`;
242
195
  }
243
196
 
@@ -260,7 +213,7 @@ class ClickMonitor {
260
213
  /**
261
214
  * normalize value and append to the resulting text if not empty
262
215
  * @param {String} text
263
- * @param {Array.<String>} values
216
+ * @param {Array.<any>} values
264
217
  */
265
218
  _parseAndAppendText(text, values) {
266
219
  const goodValues = [];
@@ -50,7 +50,7 @@ function constructErrors(args) {
50
50
  const stacks = [];
51
51
  const messages = [];
52
52
  args.forEach(sm => {
53
- if (isStackTrace(sm)) {
53
+ if (isStackTrace()) {
54
54
  stacks.push(sm);
55
55
  const lines = sm.split('\n');
56
56
  if (isStackTrace(lines[0])) {
@@ -1,4 +1,4 @@
1
- import { CONTENT_TYPE, SEVERITY_ERROR } from '../constants.js';
1
+ import { CONTENT_TYPE, SEVERITY } from '../constants.js';
2
2
  import { isInstanceOf, getMaxSubstringAllowed } from '../utils/function.js';
3
3
  import ClientConfig from '../api/clientConfig.js';
4
4
 
@@ -285,7 +285,7 @@ class GqlErrorValidator {
285
285
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
286
286
  `GQL parse error: ${message}`,
287
287
  false,
288
- SEVERITY_ERROR,
288
+ SEVERITY.error,
289
289
  );
290
290
  }
291
291
 
@@ -298,7 +298,7 @@ class GqlErrorValidator {
298
298
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
299
299
  `GQL error validation warning: ${message}`,
300
300
  false,
301
- SEVERITY_ERROR,
301
+ SEVERITY.error,
302
302
  );
303
303
  }
304
304
  }
@@ -1,8 +1,9 @@
1
- import { HUMAN_READABLE_CONTENT_TYPE_REGEX, DEFAULT_WEBSITE_SUBDOMAIN_PATTERN, SEVERITY_WARN, 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, MAX_HTTP_DATA_PAYLOAD_LENGTH, CONTENT_TYPE, CONTENT_LENGTH, BLOCKED_HTTP_HEADER_KEYS, PII_REDACTION_REPLACEMENT_STRING, HTTP_PII_BLOCKING_PATTERNS } from '../constants.js';
2
- import { getProperGlobalUrl, checkHttpDataCollectionEnabled, getHttpPayloadAllowedURLs } from '../utils/function.js';
1
+ 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, MAX_HTTP_DATA_PAYLOAD_LENGTH, CONTENT_TYPE, CONTENT_LENGTH, BLOCKED_HTTP_HEADER_KEYS, PII_REDACTION_REPLACEMENT_STRING, HTTP_PII_BLOCKING_PATTERNS } from '../constants.js';
3
2
  import ClientConfig from '../api/clientConfig.js';
4
3
  import StoredMetrics from '../api/storedMetrics.js';
5
4
  import { safeFromEntries, iterateObjectRecursively } from '../utils/object.js';
5
+ import { checkHttpDataCollectionEnabled, getHttpPayloadAllowedURLs } from '../utils/function.js';
6
+ import { AppNavigationMonitor } from './AppNavigationMonitor.js';
6
7
 
7
8
  /** @module HTTPDataBundler */
8
9
 
@@ -19,7 +20,7 @@ class HTTPDataBundler {
19
20
  );
20
21
 
21
22
  // pull out the domain hostname
22
- const initialURL = getProperGlobalUrl();
23
+ const initialURL = AppNavigationMonitor.getInstance().globalUrl;
23
24
  this.initialURLPartsReversed = [];
24
25
  if (initialURL && initialURL.length > 0) {
25
26
  try {
@@ -39,7 +40,7 @@ class HTTPDataBundler {
39
40
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
40
41
  `Unable to determine hostname for initial URL: ${e}`,
41
42
  false,
42
- SEVERITY_WARN,
43
+ SEVERITY.warn,
43
44
  );
44
45
  }
45
46
  }
@@ -50,11 +51,11 @@ class HTTPDataBundler {
50
51
  const allowedURLs = getHttpPayloadAllowedURLs();
51
52
  this.httpDataAllowedAbsoluteRegex = HTTPDataBundler.buildAllowedRegex(
52
53
  allowedURLs,
53
- true,
54
+ 'absolute',
54
55
  );
55
56
  this.httpDataAllowedRelativeRegex = HTTPDataBundler.buildAllowedRegex(
56
57
  allowedURLs,
57
- false,
58
+ 'relative',
58
59
  );
59
60
  // track unique requests and only capture each once
60
61
  // TODO: disabled for beta. NOI-4253
@@ -100,14 +101,14 @@ class HTTPDataBundler {
100
101
  /**
101
102
  * Builds the HTTP payload allowed regexes for full and relative URLs
102
103
  * @param allowedURLs A list of allowed URLs
103
- * @param absolute Use only absolute URLs if true, use only relative URL if false
104
+ * @param {'absolute' | 'relative'} strategy Use only absolute URLs if true, use only relative URL if false
104
105
  * @returns a regex of allowed URLs
105
106
  */
106
- static buildAllowedRegex(allowedURLs, absolute) {
107
+ static buildAllowedRegex(allowedURLs, strategy) {
107
108
  if (!allowedURLs) return null;
108
109
  const allowedURLsFiltered = allowedURLs.filter(url => {
109
110
  const isAbsolute = HTTPDataBundler.isAbsoluteURL(url);
110
- return absolute ? isAbsolute : !isAbsolute;
111
+ return strategy === 'absolute' ? isAbsolute : !isAbsolute;
111
112
  });
112
113
  if (allowedURLsFiltered.length > 0) {
113
114
  const lowerCasedURLs = allowedURLsFiltered.map(url =>
@@ -189,7 +190,7 @@ class HTTPDataBundler {
189
190
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
190
191
  `Unable to stringify JSON response: ${e}`,
191
192
  false,
192
- SEVERITY_WARN,
193
+ SEVERITY.warn,
193
194
  );
194
195
  return null;
195
196
  }
@@ -221,7 +222,7 @@ class HTTPDataBundler {
221
222
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
222
223
  `Unable to determine hostname for request URL: ${e}`,
223
224
  false,
224
- SEVERITY_WARN,
225
+ SEVERITY.warn,
225
226
  );
226
227
 
227
228
  return false;
@@ -568,7 +569,7 @@ ${HTTPDataBundler.getInstance().contentLength(headers)}`;
568
569
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
569
570
  `Unable to stringify request body: ${e}`,
570
571
  false,
571
- SEVERITY_WARN,
572
+ SEVERITY.warn,
572
573
  );
573
574
  }
574
575
  return null;
@@ -0,0 +1,19 @@
1
+ import type { NavigationDelegate } from 'react-native-navigation/lib/dist/src/NavigationDelegate';
2
+ import { NavigationIntegration } from '../../types/NavigationIntegration';
3
+ /**
4
+ * react-native-navigation adapter
5
+ */
6
+ export declare class ReactNativeNavigationIntegration implements NavigationIntegration {
7
+ private stack;
8
+ private stackPointers;
9
+ /**
10
+ * attaches provided listeners to the integration
11
+ */
12
+ register(navigation: NavigationDelegate, onNavigation: (breadcrumbs: string[]) => void): void;
13
+ /**
14
+ * Listens to ComponentWillAppear events
15
+ * @param onNavigation
16
+ * @private
17
+ */
18
+ private getListener;
19
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * react-native-navigation adapter
3
+ */
4
+ class ReactNativeNavigationIntegration {
5
+ stack = [];
6
+ stackPointers = {};
7
+ /**
8
+ * attaches provided listeners to the integration
9
+ */
10
+ register(navigation, onNavigation) {
11
+ navigation
12
+ .events()
13
+ .registerComponentWillAppearListener(this.getListener(onNavigation));
14
+ }
15
+ /**
16
+ * Listens to ComponentWillAppear events
17
+ * @param onNavigation
18
+ * @private
19
+ */
20
+ getListener(onNavigation) {
21
+ return (event) => {
22
+ if (this.stackPointers[event.componentName] === undefined) {
23
+ this.stackPointers[event.componentName] = this.stack.push(event.componentName);
24
+ }
25
+ else {
26
+ this.stack.forEach((id, i) => {
27
+ if (i >= this.stackPointers[event.componentName]) {
28
+ delete this.stackPointers[id];
29
+ }
30
+ });
31
+ this.stack.length = this.stackPointers[event.componentName];
32
+ }
33
+ onNavigation(this.stack.slice(1)); // slice 1 to skip root component
34
+ };
35
+ }
36
+ }
37
+
38
+ export { ReactNativeNavigationIntegration };
@@ -16,7 +16,6 @@ class KeyboardInputMonitor {
16
16
  */
17
17
  monitor() {
18
18
  const handler = this._handle.bind(this);
19
- // addSafeEventListener(window, 'input', handler);
20
19
 
21
20
  if (!TextInput.originalRender) {
22
21
  TextInput.originalRender = TextInput.render;
@@ -4,9 +4,11 @@ import { PageVisitEventHTTP, isHttpCodeFailure } from '../pageVisit/pageVisitEve
4
4
  import { propWriteableOrMadeWriteable, replace } from '../utils/object.js';
5
5
  import 'react-native-device-info';
6
6
  import 'react-native-localize';
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';
7
+ import { PV_SEQ_ATT_NAME, XML_HTTP_REQUEST_ERROR_TYPE, GQL_ERROR_TYPE, SEVERITY, 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
8
  import ClientConfig from '../api/clientConfig.js';
9
+ import 'react-native-uuid';
9
10
  import { addSafeEventListener } from '../utils/eventlistener.js';
11
+ import '@react-native-async-storage/async-storage';
10
12
  import { HTTPDataBundler } from './httpDataBundler.js';
11
13
  import GqlErrorValidator from './gqlErrorValidator.js';
12
14
 
@@ -180,7 +182,7 @@ async function _buildHttpEventDataObjectsForFetch(
180
182
  };
181
183
 
182
184
  let httpData = null;
183
- // Only get the bodies of the request and response on error and if the URL is one we care about.
185
+ // Only get the bodies of the request and response if the URL is one we care about.
184
186
  if (HTTPDataBundler.getInstance().shouldContinueForURL(url)) {
185
187
  // add response payload length, if any
186
188
  if (response && response.headers) {
@@ -307,7 +309,7 @@ function wrapXMLHTTPSend(proto) {
307
309
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
308
310
  `Error in XHR.send() wrapper: ${e}`,
309
311
  false,
310
- SEVERITY_ERROR,
312
+ SEVERITY.error,
311
313
  );
312
314
  }
313
315
  return originalFunction.call(this, data);
@@ -349,7 +351,7 @@ function wrapXMLHTTPOpen(proto, shouldHandleLoadend) {
349
351
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
350
352
  `Unable to set custom properties on XHR object: ${error}`,
351
353
  false,
352
- SEVERITY_WARN,
354
+ SEVERITY.warn,
353
355
  );
354
356
  }
355
357
 
@@ -398,7 +400,7 @@ function wrapXMLHTTPOpen(proto, shouldHandleLoadend) {
398
400
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
399
401
  `Error in XHR.open() wrapper: ${e}`,
400
402
  false,
401
- SEVERITY_ERROR,
403
+ SEVERITY.error,
402
404
  );
403
405
  }
404
406
  return originalFunction.call(this, method, url, async, user, password);
@@ -433,7 +435,7 @@ function wrapXMLHTTPSetRequestHeader(proto) {
433
435
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
434
436
  `Error in XHR.setRequestHeader() wrapper: ${error}`,
435
437
  false,
436
- SEVERITY_ERROR,
438
+ SEVERITY.error,
437
439
  );
438
440
  }
439
441
  return originalFunction.call(this, header, value);
@@ -536,7 +538,7 @@ function setupGlobalFetchWrapper() {
536
538
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
537
539
  `Error in fetch() wrapper: ${e}`,
538
540
  false,
539
- SEVERITY_ERROR,
541
+ SEVERITY.error,
540
542
  );
541
543
  }
542
544
 
@@ -611,7 +613,7 @@ function setupGlobalFetchWrapper() {
611
613
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
612
614
  `Error in custom fetch() callback: ${e}`,
613
615
  false,
614
- SEVERITY_ERROR,
616
+ SEVERITY.error,
615
617
  );
616
618
  }
617
619
  })
@@ -1,9 +1,10 @@
1
- import { isValidURL, getOnURL, getProperGlobalUrl, getJSStack, stringifyJSON, getMaxSubstringAllowed } from '../../utils/function.js';
2
- import { EVENT_ERROR_TYPE, URL_ATT_NAME, 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_ERROR, 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';
1
+ import { isValidURL, getOnURL, getJSStack, stringifyJSON, getMaxSubstringAllowed } from '../../utils/function.js';
2
+ import { EVENT_ERROR_TYPE, URL_ATT_NAME, 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 blacklisedDomains from './blacklistedDomains.js';
4
4
  import ClientConfig from '../../api/clientConfig.js';
5
5
  import { InputMonitor } from '../../monitors/inputMonitor.js';
6
6
  import StoredMetrics from '../../api/storedMetrics.js';
7
+ import { AppNavigationMonitor } from '../../monitors/AppNavigationMonitor.js';
7
8
 
8
9
  /** @module PageVisitEventError */
9
10
 
@@ -69,7 +70,9 @@ function getPVErrorFromXMLHttpRequest(errPayload, httpDataSeqNum) {
69
70
  */
70
71
  function getPVErrorFromErrorEvent(errPayload) {
71
72
  return {
72
- [URL_ATT_NAME]: getOnURL(errPayload.filename || getProperGlobalUrl()), // todo implement navigation
73
+ [URL_ATT_NAME]: getOnURL(
74
+ errPayload.filename || AppNavigationMonitor.getInstance().globalUrl,
75
+ ),
73
76
  [TYPE_ATT_NAME]: JS_EVENT_TYPE,
74
77
  [JS_ERROR_ATT_NAME]: getJSStack(errPayload.error),
75
78
  };
@@ -80,8 +83,7 @@ function getPVErrorFromErrorEvent(errPayload) {
80
83
  */
81
84
  function getPVErrorFromErrorLog(errPayload) {
82
85
  return {
83
- // default to window url
84
- [URL_ATT_NAME]: getOnURL(getProperGlobalUrl()), // todo should be current navigation
86
+ [URL_ATT_NAME]: getOnURL(AppNavigationMonitor.getInstance().globalUrl),
85
87
  [TYPE_ATT_NAME]: JS_EVENT_TYPE,
86
88
  [JS_ERROR_ATT_NAME]: getJSStack(errPayload),
87
89
  };
@@ -218,7 +220,7 @@ function isCollectError(pvError) {
218
220
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
219
221
  pvError,
220
222
  false,
221
- SEVERITY_ERROR,
223
+ SEVERITY.error,
222
224
  );
223
225
  return true;
224
226
  }
@@ -236,7 +238,7 @@ function isCollectError(pvError) {
236
238
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
237
239
  pvError,
238
240
  false,
239
- SEVERITY_ERROR,
241
+ SEVERITY.error,
240
242
  );
241
243
  return true;
242
244
  }
@@ -255,7 +257,7 @@ function isCollectError(pvError) {
255
257
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
256
258
  pvError,
257
259
  false,
258
- SEVERITY_ERROR,
260
+ SEVERITY.error,
259
261
  );
260
262
  return true;
261
263
  }
@@ -1,7 +1,8 @@
1
+ import { IStorage, StorageValue } from '../types/Storage';
1
2
  /**
2
3
  * Encapsulates storage api
3
4
  */
4
- export default class Storage implements Noibu.Storage {
5
+ export default class Storage implements IStorage {
5
6
  private readonly _isRNStorageAvailable;
6
7
  private readonly _rnStorageError;
7
8
  private static _instance;
@@ -21,7 +22,7 @@ export default class Storage implements Noibu.Storage {
21
22
  /** Loads value from storage */
22
23
  load<R = unknown>(key: string): Promise<R | null>;
23
24
  /** Saves value to storage */
24
- save(key: string, value: Noibu.StorageValue): Promise<void>;
25
+ save(key: string, value: StorageValue): Promise<void>;
25
26
  /**
26
27
  * Removes value from storage
27
28
  * @param {String} key
@@ -1,21 +1,22 @@
1
+ import { Provider, StorageValue } from '../types/Storage';
1
2
  /**
2
3
  * Base implementation for LocalStorage and SessionStorage
3
4
  */
4
5
  export default abstract class StorageProvider {
5
- _provider: Noibu.Provider;
6
+ _provider: Provider;
6
7
  /** Creates new instance based on provided provider type */
7
- constructor(provider: Noibu.Provider);
8
+ constructor(provider: Provider);
8
9
  /** Checks if provider is available */
9
- static isAvailable(resolver: () => Noibu.Provider): Promise<{
10
+ static isAvailable(resolver: () => Provider): Promise<{
10
11
  result: boolean;
11
12
  error: unknown;
12
13
  }>;
13
14
  /**
14
15
  * Loads value from storage
15
16
  */
16
- load<R = Noibu.StorageValue>(key: string): Promise<R | null>;
17
+ load<R = StorageValue>(key: string): Promise<R | null>;
17
18
  /** Saves value to storage */
18
- save(key: string, value: Noibu.StorageValue): Promise<void>;
19
+ save(key: string, value: StorageValue): Promise<void>;
19
20
  /**
20
21
  * Removes value from storage
21
22
  * @param {String} key
@@ -0,0 +1,27 @@
1
+ export interface Config {
2
+ sel: string[];
3
+ scriptID: string;
4
+ njs_version: string;
5
+ nid_cookie: boolean;
6
+ http_data_collection: boolean;
7
+ http_re: string[];
8
+ }
9
+ export interface CustomerConfig {
10
+ blockedElements?: Config['sel'];
11
+ listOfUrlsToCollectHttpDataFrom?: Config['http_re'];
12
+ enableHttpDataCollection?: Config['http_data_collection'];
13
+ domain: UrlConfig['domain'];
14
+ }
15
+ export interface StoredConfig {
16
+ BrowserId: string;
17
+ LastActive?: Date;
18
+ pvId?: string;
19
+ CurrentPageVisitCount: number;
20
+ ClientUnlockTime?: Date;
21
+ DisabledStatus: boolean;
22
+ }
23
+ export type UrlConfig = {
24
+ metroplexSocketBase: string;
25
+ metroplexHTTPBase: string;
26
+ domain: string;
27
+ };
@@ -0,0 +1,7 @@
1
+ import type { NavigationDelegate } from 'react-native-navigation/lib/dist/src/NavigationDelegate';
2
+ /**
3
+ * interface enforces constructor signature
4
+ */
5
+ export interface NavigationIntegration {
6
+ register(navigation: NavigationDelegate, onNavigation: (breadcrumbs: string[]) => void): void;
7
+ }
@@ -0,0 +1,22 @@
1
+ export type Event = {
2
+ type: string;
3
+ };
4
+ export type EventPayload = Partial<{
5
+ txt: string;
6
+ src: string;
7
+ hid: string;
8
+ tag: string;
9
+ type: string;
10
+ class: string;
11
+ pvp: string;
12
+ }>;
13
+ export interface JError {
14
+ frames: JStackFrame[];
15
+ msg: string;
16
+ }
17
+ export interface JStackFrame {
18
+ column?: number;
19
+ line: string;
20
+ mname: string;
21
+ file: string;
22
+ }
@@ -0,0 +1,4 @@
1
+ export interface RNNode {
2
+ memoizedProps: any;
3
+ elementType: string;
4
+ }