noibu-react-native 0.0.9 → 0.1.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 CHANGED
@@ -164,10 +164,6 @@ import { NoibuJS } from 'noibu-react-native';
164
164
  NoibuJS.addJsSdkError(new Error('My Error'), 'myModule.js');
165
165
  ```
166
166
 
167
- ## Contributing
168
-
169
- You can contribute by checking out the project page and open issues. https://linear.app/noibu/project/react-native-sdk-5ccd19a3343a
170
-
171
167
  ## License
172
168
 
173
169
  Copyright 2023 Noibu.com
@@ -2,6 +2,8 @@ import uuid from 'react-native-uuid';
2
2
  import { MAX_METROPLEX_SOCKET_INNACTIVE_TIME, SEVERITY, NOIBU_BROWSER_ID_KYWRD, PV_SEQ_NUM_RESET_TIME_MINUTES, JS_ENV, MAX_PAGEVISIT_VISITED, CLIENT_LOCK_TIME_MINUTES, GET_SCRIPT_ID, MAX_COLLECT_ERROR_LOG } from '../constants.js';
3
3
  import { stringifyJSON, getMaxSubstringAllowed, getUserAgent, makeRequest } from '../utils/function.js';
4
4
  import Storage from '../storage/storage.js';
5
+ import { noibuLog } from '../utils/log.js';
6
+ import { unwrapNoibuWrapped } from '../utils/object.js';
5
7
 
6
8
  /** @module ClientConfig */
7
9
  /**
@@ -292,6 +294,12 @@ class ClientConfig {
292
294
  * severity expects one of the SEVERITY_x level constants, or else error will be used
293
295
  */
294
296
  async postNoibuErrorAndOptionallyDisableClient(errorMsg, disableClient, severity, keepAlive = false) {
297
+ noibuLog('postNoibuErrorAndOptionallyDisableClient', {
298
+ errorMsg,
299
+ disableClient,
300
+ severity,
301
+ keepAlive,
302
+ });
295
303
  if (this.isClientDisabled) {
296
304
  return;
297
305
  }
@@ -339,7 +347,7 @@ class ClientConfig {
339
347
  });
340
348
  }
341
349
  else {
342
- fetch(this.noibuErrorURL, {
350
+ unwrapNoibuWrapped(fetch)(this.noibuErrorURL, {
343
351
  method: 'POST',
344
352
  headers,
345
353
  body: stringifyJSON(errorContent),
@@ -1,6 +1,6 @@
1
1
  import { NOIBUJS_SDK_REQUEST_HELP_CODE, NOIBUJS_SDK_ADD_ID_FUNCTION, NOIBUJS_SDK_ADD_ERROR_FUNCTION, NOIBUJS_SDK_ADD_ERROR_FROM_JS_FMW_FUNCTION, MAX_CUSTOM_ERRORS_PER_PAGEVISIT, MAX_CUSTOM_IDS_PER_PAGEVISIT, META_DATA_METROPLEX_TYPE, PAGE_VISIT_META_DATA_ATT_NAME, CUSTOM_ID_NAME_TYPE, CUSTOM_ID_VALUE_TYPE, CUSTOM_ERROR_EVENT_TYPE } from '../constants.js';
2
2
  import MetroplexSocket from './metroplexSocket.js';
3
- import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError/pageVisitEventError.js';
3
+ import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError.js';
4
4
  import HelpCode from './helpCode.js';
5
5
 
6
6
  /** @module InputManager */
@@ -7,6 +7,8 @@ import StoredMetrics from './storedMetrics.js';
7
7
  import StoredPageVisit from './storedPageVisit.js';
8
8
  import { safePerformanceNow } from '../utils/performance.js';
9
9
  import { isDateOverwritten } from '../utils/date.js';
10
+ import { unwrapNoibuWrapped } from '../utils/object.js';
11
+ import { noibuLog } from '../utils/log.js';
10
12
 
11
13
  /** @module MetroplexSocket */
12
14
 
@@ -174,11 +176,16 @@ class MetroplexSocket {
174
176
  * @returns {Promise<boolean>} true if message was sent succefully, false otherwise
175
177
  */
176
178
  async sendMessage(type, payload) {
179
+ noibuLog('sendMessage start', { type });
177
180
  // if we have a lock on this specific type, we dont send it
178
181
  if (
179
182
  type in this.metroplexTypeLock ||
180
183
  ClientConfig.getInstance().isClientDisabled
181
184
  ) {
185
+ noibuLog('sendMessage quitting due to', {
186
+ typeInLock: type in this.metroplexTypeLock,
187
+ isClientDisabled: ClientConfig.getInstance().isClientDisabled,
188
+ });
182
189
  return false;
183
190
  }
184
191
 
@@ -749,7 +756,7 @@ class MetroplexSocket {
749
756
  updatedMsg[VIDEO_PART_COUNT_ATT_NAME] += 1;
750
757
 
751
758
  // we send the remainder elements
752
- global.fetch(this.postURL, {
759
+ unwrapNoibuWrapped(fetch)(this.postURL, {
753
760
  method: 'POST',
754
761
  headers: {
755
762
  'content-type': 'application/json',
@@ -768,10 +775,15 @@ class MetroplexSocket {
768
775
  * @param {} payload
769
776
  */
770
777
  _sendSocketMessage(payload) {
771
- if (this.closeIfInactive()) {
778
+ noibuLog('_sendSocketMessage');
779
+ const closeIfInactive = this.closeIfInactive();
780
+ if (closeIfInactive) {
781
+ noibuLog('_sendSocketMessage dropped due to', { closeIfInactive });
772
782
  return false;
773
783
  }
774
- this.socket.send(stringifyJSON(payload));
784
+ const payloadJson = stringifyJSON(payload);
785
+ noibuLog(`_sendSocketMessage sending: ${payloadJson}`);
786
+ this.socket.send(payloadJson);
775
787
  return true;
776
788
  }
777
789
 
@@ -2,6 +2,7 @@ import { BROWSER_ID_ATT_NAME, PV_ID_ATT_NAME, COLLECT_VER_ATT_NAME, CURRENT_NOIB
2
2
  import ClientConfig from './clientConfig.js';
3
3
  import { getUserAgent, stringifyJSON } from '../utils/function.js';
4
4
  import { addSafeEventListener } from '../utils/eventlistener.js';
5
+ import { unwrapNoibuWrapped } from '../utils/object.js';
5
6
 
6
7
  /** @module StoredMetrics */
7
8
 
@@ -181,7 +182,7 @@ class StoredMetrics {
181
182
  [ERR_COUNT_EXPECTED_ATT_NAME]: this.errCount,
182
183
  [ON_URL_ATT_NAME]: ClientConfig.getInstance().globalUrl,
183
184
  };
184
- global.fetch(GET_METROPLEX_METRICS_URL(), {
185
+ unwrapNoibuWrapped(fetch)(GET_METROPLEX_METRICS_URL(), {
185
186
  method: 'POST',
186
187
  headers: {
187
188
  'content-type': 'application/json',
@@ -226,3 +226,11 @@ export declare function GET_METROPLEX_METRICS_URL(): string;
226
226
  */
227
227
  export declare function JS_ENV(): string;
228
228
  export declare const METROPLEX_RETRY_FREQUENCY: 30000;
229
+ export declare const STACK_TRACE_SANITIZE_REGEXP: RegExp;
230
+ export declare const BLOCKLISTED_DOMAINS: {
231
+ 'input.noibu.com': boolean;
232
+ 'input.staging.noibu.com': boolean;
233
+ 'vf.noibu.com': boolean;
234
+ 'vf.staging.noibu.com': boolean;
235
+ 'cdn.noibu.com': boolean;
236
+ };
package/dist/constants.js CHANGED
@@ -315,7 +315,7 @@ const CONTENT_LENGTH = 'content-length';
315
315
  * Gets the script id from the cookie object, returns default if cannot be found
316
316
  */
317
317
  function GET_SCRIPT_ID() {
318
- return "1.0.104-rn-sdk-0.0.9" ;
318
+ return "1.0.104-rn-sdk-0.1.2" ;
319
319
  }
320
320
  /**
321
321
  *
@@ -423,5 +423,13 @@ function JS_ENV() {
423
423
  }
424
424
  // gets the frequency at which the client resends the message that were not confirmed by metroplex
425
425
  const METROPLEX_RETRY_FREQUENCY = 30000;
426
+ const STACK_TRACE_SANITIZE_REGEXP = /(nbuGlobalPromiseRejectWrapper|(hermes.*InternalBytecode\/InternalBytecode))/gi;
427
+ const BLOCKLISTED_DOMAINS = {
428
+ 'input.noibu.com': true,
429
+ 'input.staging.noibu.com': true,
430
+ 'vf.noibu.com': true,
431
+ 'vf.staging.noibu.com': true,
432
+ 'cdn.noibu.com': true,
433
+ };
426
434
 
427
- export { APP_NAVIGATION_EVENT_TYPE, BLOCKED_HTTP_HEADER_KEYS, BLOCK_SOCKET_MESSAGE, BROWSER_ID_ATT_NAME, CLICK_EVENT_TYPE, CLIENT_LOCK_TIME_MINUTES, CLOSE_CONNECTION_FORCEFULLY, COLLECT_VER_ATT_NAME, CONN_COUNT_ATT_NAME, CONSOLE_FUNCTION_OVERRIDES, CONTENT_LENGTH, CONTENT_TYPE, CSS_CLASS_ATT_NAME, CURRENT_METRICS_VERSION, CURRENT_NOIBUJS_VERSION, CURRENT_PV_VERSION, CUSTOM_ERROR_EVENT_TYPE, CUSTOM_ID_NAME_TYPE, CUSTOM_ID_VALUE_TYPE, DEFAULT_STACK_FRAME_FIELD_VALUE, DEFAULT_WEBSITE_SUBDOMAIN_PATTERN, DID_CUT_PV_ATT_NAME, DID_CUT_VID_ATT_NAME, DID_START_VID_ATT_NAME, END_AT_ATT_NAME, ERROR_EVENT_ERROR_TYPE, ERROR_EVENT_TYPE, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, ERROR_LOG_EVENT_ERROR_TYPE, ERROR_SOURCE_ATT_NAME, ERR_COUNT_EXPECTED_ATT_NAME, EVENT_ERROR_TYPE, EXP_VIDEO_LENGTH_ATT_NAME, FETCH_EXCEPTION_ERROR_TYPE, GET_MAX_METROPLEX_RECONNECTION_NUMBER, GET_METROPLEX_BASE_HTTP_URL, GET_METROPLEX_BASE_SOCKET_URL, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, GET_METROPLEX_METRICS_URL, GET_METROPLEX_POST_URL, GET_SCRIPT_ID, GQL_ERROR_ATT_NAME, GQL_ERROR_TYPE, GQL_EVENT_TYPE, HELP_CODE_ATT_NAME, HTMLID_ATT_NAME, HTTP_BODY_DROPPED_LENGTH_MSG, HTTP_BODY_DROPPED_TYPE_MSG, HTTP_BODY_NULL_STRING, HTTP_CODE_ATT_NAME, HTTP_COUNT_EXPECTED_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_DATA_PAYLOAD_ATT_NAME, HTTP_DATA_REQ_HEADERS_ATT_NAME, HTTP_DATA_RESP_HEADERS_ATT_NAME, HTTP_DATA_RESP_PAYLOAD_ATT_NAME, HTTP_EVENT_TYPE, HTTP_METHOD_ATT_NAME, HTTP_PII_BLOCKING_PATTERNS, HTTP_RESP_CODE_ATT_NAME, HTTP_RESP_LENGTH_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HUMAN_READABLE_CONTENT_TYPE_REGEX, IS_LAST_ATT_NAME, IS_NJS_VERSION_BETA, JS_ENV, JS_ERROR_ATT_NAME, JS_EVENT_TYPE, JS_STACK_FILE_ATT_NAME, JS_STACK_FRAMES_ATT_NAME, JS_STACK_MESSAGE_ATT_NAME, JS_STACK_METHOD_ATT_NAME, KEYBOARD_EVENT_TYPE, MAX_BEACON_PAYLOAD_SIZE, MAX_COLLECT_ERROR_LOG, MAX_CUSTOM_ERRORS_PER_PAGEVISIT, MAX_CUSTOM_IDS_PER_PAGEVISIT, MAX_FRAMES_IN_ARRAY, MAX_HTTP_DATA_EVENT_COUNT, MAX_HTTP_DATA_PAYLOAD_LENGTH, MAX_METROPLEX_CONNECTION_COUNT, MAX_METROPLEX_SOCKET_INNACTIVE_TIME, MAX_PAGEVISIT_EVENTS, MAX_PAGEVISIT_PARTS, MAX_PAGEVISIT_VISITED, MAX_STRING_LENGTH, MAX_TIME_FOR_UNSENT_DATA_MILLIS, META_DATA_METROPLEX_TYPE, METROPLEX_ERROR_ROUTE, METROPLEX_FRAG_ROUTE, METROPLEX_FULL_PV_ROUTE, METROPLEX_METRICS_ROUTE, METROPLEX_RETRY_FREQUENCY, METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME, NOIBUJS_SDK_ADD_ERROR_FROM_JS_FMW_FUNCTION, NOIBUJS_SDK_ADD_ERROR_FUNCTION, NOIBUJS_SDK_ADD_ID_FUNCTION, NOIBUJS_SDK_REQUEST_HELP_CODE, NOIBU_BROWSER_ID_KYWRD, NOIBU_INPUT_URLS, NOIBU_LOCAL_STORAGE_TEST_KEY, NOIBU_STORED_PAGE_VISIT, OCCURRED_AT_ATT_NAME, OK_SOCKET_MESSAGE, ON_URL_ATT_NAME, PAGE_EVENTS_DOCUMENT, PAGE_EVENTS_WINDOW, PAGE_EVENT_TYPE, PAGE_VISIT_HTTP_DATA_ATT_NAME, PAGE_VISIT_INFORMATION_ATT_NAME, PAGE_VISIT_META_DATA_ATT_NAME, PAGE_VISIT_PART_ATT_NAME, PAGE_VISIT_VID_FRAG_ATT_NAME, PII_DIGIT_PATTERN, PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING, PV_CLICKS_ATT_NAME, PV_EVENTS_ATT_NAME, PV_EXP_HTTP_DATA_SEQ_ATT_NAME, PV_EXP_PART_COUNTER_ATT_NAME, PV_EXP_VF_SEQ_ATT_NAME, PV_HTTP_PAYLOADS_COLLECTED_ATT_NAME, PV_HTTP_PAYLOADS_DROPPED_OVERSIZE_ATT_NAME, PV_HTTP_PAYLOADS_DROPPED_TYPE_ATT_NAME, PV_HTTP_REQUESTS_DROPPED_OVER_LIMIT, PV_ID_ATT_NAME, PV_METROPLEX_TYPE, PV_PART_COUNTER_ATT_NAME, PV_SEQ_ATT_NAME, PV_SEQ_NUM_RESET_TIME_MINUTES, REF_URL_ATT_NAME, REQUIRED_DATA_PROCESSING_URLS, RESPONSE_ERROR_TYPE, SCRIPT_ID_ATT_NAME, SCRIPT_INSTANCE_ID_ATT_NAME, SEQ_NUM_ATT_NAME, SEVERITY, SOCKET_INSTANCE_ID_ATT_NAME, SOURCE_ATT_NAME, STARTED_AT_ATT_NAME, STOP_STORING_PV_SOCKET_MESSAGE, STOP_STORING_VID_SOCKET_MESSAGE, TAGNAME_ATT_NAME, TEXT_ATT_NAME, TYPE_ATT_NAME, URL_ATT_NAME, USERSTEP_EVENT_TYPE, VER_ATT_NAME, VIDEO_CLICKS_ATT_NAME, VIDEO_METROPLEX_TYPE, VIDEO_PART_COUNT_ATT_NAME, WHITELIST_HTML_ID_TEXT_REGEX, WORK_REQUEST_ATT_NAME, WRAPPED_EXCEPTION_ERROR_TYPE, XML_HTTP_REQUEST_ERROR_TYPE };
435
+ export { APP_NAVIGATION_EVENT_TYPE, BLOCKED_HTTP_HEADER_KEYS, BLOCKLISTED_DOMAINS, BLOCK_SOCKET_MESSAGE, BROWSER_ID_ATT_NAME, CLICK_EVENT_TYPE, CLIENT_LOCK_TIME_MINUTES, CLOSE_CONNECTION_FORCEFULLY, COLLECT_VER_ATT_NAME, CONN_COUNT_ATT_NAME, CONSOLE_FUNCTION_OVERRIDES, CONTENT_LENGTH, CONTENT_TYPE, CSS_CLASS_ATT_NAME, CURRENT_METRICS_VERSION, CURRENT_NOIBUJS_VERSION, CURRENT_PV_VERSION, CUSTOM_ERROR_EVENT_TYPE, CUSTOM_ID_NAME_TYPE, CUSTOM_ID_VALUE_TYPE, DEFAULT_STACK_FRAME_FIELD_VALUE, DEFAULT_WEBSITE_SUBDOMAIN_PATTERN, DID_CUT_PV_ATT_NAME, DID_CUT_VID_ATT_NAME, DID_START_VID_ATT_NAME, END_AT_ATT_NAME, ERROR_EVENT_ERROR_TYPE, ERROR_EVENT_TYPE, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, ERROR_LOG_EVENT_ERROR_TYPE, ERROR_SOURCE_ATT_NAME, ERR_COUNT_EXPECTED_ATT_NAME, EVENT_ERROR_TYPE, EXP_VIDEO_LENGTH_ATT_NAME, FETCH_EXCEPTION_ERROR_TYPE, GET_MAX_METROPLEX_RECONNECTION_NUMBER, GET_METROPLEX_BASE_HTTP_URL, GET_METROPLEX_BASE_SOCKET_URL, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, GET_METROPLEX_METRICS_URL, GET_METROPLEX_POST_URL, GET_SCRIPT_ID, GQL_ERROR_ATT_NAME, GQL_ERROR_TYPE, GQL_EVENT_TYPE, HELP_CODE_ATT_NAME, HTMLID_ATT_NAME, HTTP_BODY_DROPPED_LENGTH_MSG, HTTP_BODY_DROPPED_TYPE_MSG, HTTP_BODY_NULL_STRING, HTTP_CODE_ATT_NAME, HTTP_COUNT_EXPECTED_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_DATA_PAYLOAD_ATT_NAME, HTTP_DATA_REQ_HEADERS_ATT_NAME, HTTP_DATA_RESP_HEADERS_ATT_NAME, HTTP_DATA_RESP_PAYLOAD_ATT_NAME, HTTP_EVENT_TYPE, HTTP_METHOD_ATT_NAME, HTTP_PII_BLOCKING_PATTERNS, HTTP_RESP_CODE_ATT_NAME, HTTP_RESP_LENGTH_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HUMAN_READABLE_CONTENT_TYPE_REGEX, IS_LAST_ATT_NAME, IS_NJS_VERSION_BETA, JS_ENV, JS_ERROR_ATT_NAME, JS_EVENT_TYPE, JS_STACK_FILE_ATT_NAME, JS_STACK_FRAMES_ATT_NAME, JS_STACK_MESSAGE_ATT_NAME, JS_STACK_METHOD_ATT_NAME, KEYBOARD_EVENT_TYPE, MAX_BEACON_PAYLOAD_SIZE, MAX_COLLECT_ERROR_LOG, MAX_CUSTOM_ERRORS_PER_PAGEVISIT, MAX_CUSTOM_IDS_PER_PAGEVISIT, MAX_FRAMES_IN_ARRAY, MAX_HTTP_DATA_EVENT_COUNT, MAX_HTTP_DATA_PAYLOAD_LENGTH, MAX_METROPLEX_CONNECTION_COUNT, MAX_METROPLEX_SOCKET_INNACTIVE_TIME, MAX_PAGEVISIT_EVENTS, MAX_PAGEVISIT_PARTS, MAX_PAGEVISIT_VISITED, MAX_STRING_LENGTH, MAX_TIME_FOR_UNSENT_DATA_MILLIS, META_DATA_METROPLEX_TYPE, METROPLEX_ERROR_ROUTE, METROPLEX_FRAG_ROUTE, METROPLEX_FULL_PV_ROUTE, METROPLEX_METRICS_ROUTE, METROPLEX_RETRY_FREQUENCY, METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME, NOIBUJS_SDK_ADD_ERROR_FROM_JS_FMW_FUNCTION, NOIBUJS_SDK_ADD_ERROR_FUNCTION, NOIBUJS_SDK_ADD_ID_FUNCTION, NOIBUJS_SDK_REQUEST_HELP_CODE, NOIBU_BROWSER_ID_KYWRD, NOIBU_INPUT_URLS, NOIBU_LOCAL_STORAGE_TEST_KEY, NOIBU_STORED_PAGE_VISIT, OCCURRED_AT_ATT_NAME, OK_SOCKET_MESSAGE, ON_URL_ATT_NAME, PAGE_EVENTS_DOCUMENT, PAGE_EVENTS_WINDOW, PAGE_EVENT_TYPE, PAGE_VISIT_HTTP_DATA_ATT_NAME, PAGE_VISIT_INFORMATION_ATT_NAME, PAGE_VISIT_META_DATA_ATT_NAME, PAGE_VISIT_PART_ATT_NAME, PAGE_VISIT_VID_FRAG_ATT_NAME, PII_DIGIT_PATTERN, PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING, PV_CLICKS_ATT_NAME, PV_EVENTS_ATT_NAME, PV_EXP_HTTP_DATA_SEQ_ATT_NAME, PV_EXP_PART_COUNTER_ATT_NAME, PV_EXP_VF_SEQ_ATT_NAME, PV_HTTP_PAYLOADS_COLLECTED_ATT_NAME, PV_HTTP_PAYLOADS_DROPPED_OVERSIZE_ATT_NAME, PV_HTTP_PAYLOADS_DROPPED_TYPE_ATT_NAME, PV_HTTP_REQUESTS_DROPPED_OVER_LIMIT, PV_ID_ATT_NAME, PV_METROPLEX_TYPE, PV_PART_COUNTER_ATT_NAME, PV_SEQ_ATT_NAME, PV_SEQ_NUM_RESET_TIME_MINUTES, REF_URL_ATT_NAME, REQUIRED_DATA_PROCESSING_URLS, RESPONSE_ERROR_TYPE, SCRIPT_ID_ATT_NAME, SCRIPT_INSTANCE_ID_ATT_NAME, SEQ_NUM_ATT_NAME, SEVERITY, SOCKET_INSTANCE_ID_ATT_NAME, SOURCE_ATT_NAME, STACK_TRACE_SANITIZE_REGEXP, STARTED_AT_ATT_NAME, STOP_STORING_PV_SOCKET_MESSAGE, STOP_STORING_VID_SOCKET_MESSAGE, TAGNAME_ATT_NAME, TEXT_ATT_NAME, TYPE_ATT_NAME, URL_ATT_NAME, USERSTEP_EVENT_TYPE, VER_ATT_NAME, VIDEO_CLICKS_ATT_NAME, VIDEO_METROPLEX_TYPE, VIDEO_PART_COUNT_ATT_NAME, WHITELIST_HTML_ID_TEXT_REGEX, WORK_REQUEST_ATT_NAME, WRAPPED_EXCEPTION_ERROR_TYPE, XML_HTTP_REQUEST_ERROR_TYPE };
@@ -2,7 +2,9 @@ import 'react-native-url-polyfill/auto';
2
2
  import globalInit from './init.js';
3
3
  import { ErrorBoundary as ErrorBoundary$1 } from '../react/ErrorBoundary.js';
4
4
  import InputManager from '../api/inputManager.js';
5
+ import { noibuLog } from '../utils/log.js';
5
6
 
7
+ noibuLog('imported');
6
8
  /**
7
9
  * @param config
8
10
  */
@@ -13,6 +13,7 @@ import MetroplexSocket from '../api/metroplexSocket.js';
13
13
  import StoredPageVisit from '../api/storedPageVisit.js';
14
14
  import HelpCode from '../api/helpCode.js';
15
15
  import { AppNavigationMonitor } from '../monitors/appNavigationMonitor.js';
16
+ import { noibuLog } from '../utils/log.js';
16
17
 
17
18
  /** @module Init */
18
19
  // these are set via rollup
@@ -24,12 +25,15 @@ const urlConfig = {
24
25
  * initilializes the script to start executing all of NJS features
25
26
  */
26
27
  function globalInit(customerConfig) {
28
+ noibuLog('global init started');
27
29
  // if the config url is invalid we block collect from executing
28
30
  if (isInvalidURLConfig({ ...urlConfig, domain: customerConfig.domain })) {
31
+ noibuLog('exiting');
29
32
  return;
30
33
  }
31
34
  // ensure only one copy of NoibuJS is running at a time
32
35
  if (isNoibuJSAlreadyLoaded()) {
36
+ noibuLog('exiting');
33
37
  return;
34
38
  }
35
39
  const noibuErrorURL = `${urlConfig.metroplexHTTPBase}/${METROPLEX_ERROR_ROUTE}`;
@@ -43,6 +47,7 @@ function globalInit(customerConfig) {
43
47
  const instanceId = uuid.v4();
44
48
  // verifying if collect was disabled by other microservices
45
49
  if (ClientConfig.getInstance().isClientDisabled) {
50
+ noibuLog('client disabled, exiting');
46
51
  return;
47
52
  }
48
53
  HelpCode.getInstance();
@@ -68,9 +73,11 @@ function globalInit(customerConfig) {
68
73
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
69
74
  // @ts-ignore
70
75
  metroplexSocket.connectionPromise.catch((e) => ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(`Error during metroplexSocket initial connection: ${e}`, false, SEVERITY.error));
76
+ noibuLog('global init finished');
71
77
  }
72
78
  catch (err) {
73
79
  ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(`Error during globalInit: ${err}`, true, SEVERITY.error);
80
+ noibuLog('exiting');
74
81
  }
75
82
  }
76
83
 
@@ -1,7 +1,7 @@
1
1
  import Pressability from 'react-native/Libraries/Pressability/Pressability';
2
2
  import { WHITELIST_HTML_ID_TEXT_REGEX, USERSTEP_EVENT_TYPE, SOURCE_ATT_NAME, TEXT_ATT_NAME, TAGNAME_ATT_NAME, HTMLID_ATT_NAME, TYPE_ATT_NAME, CLICK_EVENT_TYPE, CSS_CLASS_ATT_NAME } from '../constants.js';
3
3
  import { PageVisit } from '../pageVisit/pageVisit.js';
4
- import { updatePayload } from '../pageVisit/userStep/userStep.js';
4
+ import { updatePayload } from '../pageVisit/userStep.js';
5
5
  import StoredMetrics from '../api/storedMetrics.js';
6
6
  import { WHITELIST_TEXT_REGEX_STRING } from '../const_matchers.js';
7
7
  import { maskTextInput } from '../utils/function.js';
@@ -15,9 +15,12 @@ export declare function wrap(functionToWrap: WrappedFunction): Function;
15
15
  export declare function processErrorLogArguments(argsFromErrorLog: any[]): void;
16
16
  /**
17
17
  * handler for promise rejection failures
18
- * @param {} event
18
+ * @param error
19
19
  */
20
- export declare function onPromiseRejectionHandler(event: PromiseRejectedResult): void;
20
+ export declare function onPromiseRejectionHandler(error: {
21
+ message: string;
22
+ stack?: string;
23
+ }): void;
21
24
  /**
22
25
  * Monitors the errors happening on the window
23
26
  */
@@ -1,7 +1,7 @@
1
+ import { asString, isStackTrace } from '../utils/function.js';
2
+ import { CONSOLE_FUNCTION_OVERRIDES, ERROR_EVENT_ERROR_TYPE, STACK_TRACE_SANITIZE_REGEXP, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, ERROR_LOG_EVENT_ERROR_TYPE } from '../constants.js';
3
+ import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError.js';
1
4
  import { replace } from '../utils/object.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';
4
- import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError/pageVisitEventError.js';
5
5
 
6
6
  /* eslint-disable @typescript-eslint/ban-types,prefer-arrow-callback */
7
7
  /** @module ErrorMonitor */
@@ -117,11 +117,49 @@ function configureEventListeners() {
117
117
  });
118
118
  }
119
119
  /**
120
- * Monitors the errors happening on the window
120
+ * handler for promise rejection failures
121
+ * @param error
121
122
  */
122
- function monitorErrors() {
123
- // wrapping all listeners as soon as possible after we set the above listener
124
- configureEventListeners();
123
+ function onPromiseRejectionHandler(error) {
124
+ if (!error || !error.message || !error.stack) {
125
+ return;
126
+ }
127
+ const sanitizedStack = error.stack
128
+ .split('\n')
129
+ .filter(line => !line.match(STACK_TRACE_SANITIZE_REGEXP))
130
+ .join('\n');
131
+ const payload = {
132
+ error: {
133
+ message: error.message,
134
+ stack: sanitizedStack,
135
+ },
136
+ };
137
+ saveErrorToPagevisit(ERROR_EVENT_UNHANDLED_REJECTION_TYPE, payload);
138
+ }
139
+ function configureHermesHooks() {
140
+ if (global.HermesInternal) {
141
+ global.HermesInternal.enablePromiseRejectionTracker?.({
142
+ allRejections: true,
143
+ });
144
+ /**
145
+ * This internal promise implementation method is populated only after enabling the promise tracker.
146
+ * It represents an improvement over the previous approach,
147
+ * which would lose stack context regarding the rejection because it ran asynchronously through setTimeout.
148
+ *
149
+ * This updated method ensures synchronous error capturing and retrieves the correct stack frames.
150
+ */
151
+ replace(Promise, '_m', (originalFunction) => function nbuGlobalPromiseRejectWrapper(promise, error) {
152
+ if (error.message && error.stack) {
153
+ onPromiseRejectionHandler(error);
154
+ }
155
+ else {
156
+ onPromiseRejectionHandler(new Error(asString(error)));
157
+ }
158
+ return originalFunction?.(promise, error);
159
+ });
160
+ }
161
+ }
162
+ function configureErrorUtilsHandler() {
125
163
  const existingHandler = global.ErrorUtils.getGlobalHandler() || (() => { });
126
164
  global.ErrorUtils.setGlobalHandler((error, ...rest) => {
127
165
  saveErrorToPagevisit(ERROR_EVENT_ERROR_TYPE, {
@@ -129,16 +167,14 @@ function monitorErrors() {
129
167
  });
130
168
  return existingHandler(error, ...rest);
131
169
  });
132
- if (global.HermesInternal) {
133
- global.HermesInternal.enablePromiseRejectionTracker({
134
- allRejections: true,
135
- onUnhandled: (id, rejection = {}) => {
136
- saveErrorToPagevisit(ERROR_EVENT_ERROR_TYPE, {
137
- error: rejection,
138
- });
139
- },
140
- });
141
- }
170
+ }
171
+ /**
172
+ * Monitors the errors happening on the window
173
+ */
174
+ function monitorErrors() {
175
+ configureEventListeners();
176
+ configureHermesHooks();
177
+ configureErrorUtilsHandler();
142
178
  }
143
179
 
144
- export { monitorErrors, processErrorLogArguments };
180
+ export { monitorErrors, onPromiseRejectionHandler, processErrorLogArguments };
@@ -1,8 +1,8 @@
1
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';
2
2
  import ClientConfig from '../api/clientConfig.js';
3
3
  import StoredMetrics from '../api/storedMetrics.js';
4
- import { safeFromEntries, iterateObjectRecursively } from '../utils/object.js';
5
- import 'react-native-device-info';
4
+ import { iterateObjectRecursively } from '../utils/object.js';
5
+ import { noibuLog } from '../utils/log.js';
6
6
 
7
7
  /** @module HTTPDataBundler */
8
8
 
@@ -183,6 +183,7 @@ class HTTPDataBundler {
183
183
  if (xhr === undefined || xhr === null) return null;
184
184
 
185
185
  // If the XHR object exists but the response is null, return null as a string.
186
+ // noinspection PointlessBooleanExpressionJS
186
187
  if (xhr.response && xhr.response === null) return HTTP_BODY_NULL_STRING;
187
188
 
188
189
  if (xhr.responseType === '' || xhr.responseType === 'text') {
@@ -266,12 +267,13 @@ class HTTPDataBundler {
266
267
 
267
268
  /**
268
269
  * Builds an HTTP Data bundle
269
- * @param {} url
270
- * @param {} requestHeaders is a map of request headers
271
- * @param {} rawRequestPayload
272
- * @param {} responseHeaders is a map of response headers
273
- * @param {} responsePayload
274
- * @param {} method
270
+ * @param url
271
+ * @param requestHeaders is a map of request headers
272
+ * @param rawRequestPayload
273
+ * @param responseHeaders is a map of response headers
274
+ * @param responsePayload
275
+ * @param method
276
+ * @param shouldCollectPayload
275
277
  */
276
278
  bundleHTTPData(
277
279
  url,
@@ -280,15 +282,23 @@ class HTTPDataBundler {
280
282
  responseHeaders,
281
283
  responsePayload,
282
284
  method,
285
+ shouldCollectPayload,
283
286
  ) {
284
- if (!this.isValidRequest(url, method)) return null;
287
+ noibuLog('bundleHTTPData started for', method, url);
288
+ if (!this.isValidRequest(url, method)) {
289
+ noibuLog('quitting');
290
+ return null;
291
+ }
285
292
 
286
293
  // stringify payload if correct type and not too large
287
294
  let requestPayload = '';
288
- if (this.shouldCollectPayloadForURL(url)) {
295
+ if (shouldCollectPayload) {
296
+ noibuLog('bundleHTTPData collecting payload');
289
297
  requestPayload =
290
298
  this.dropPayloadIfNecessaryFromHeaders(requestHeaders) ||
291
299
  this.stringFromRequestBody(rawRequestPayload);
300
+ } else {
301
+ noibuLog('bundleHTTPData not collecting payload');
292
302
  }
293
303
 
294
304
  // don't bundle if there is no data
@@ -302,6 +312,7 @@ class HTTPDataBundler {
302
312
  safeResponseHeaders.size === 0 &&
303
313
  safeResponsePayload.length === 0
304
314
  ) {
315
+ noibuLog('bundleHTTPData payload is empty, quitting');
305
316
  return null;
306
317
  }
307
318
 
@@ -320,11 +331,11 @@ class HTTPDataBundler {
320
331
  // build the http bundle
321
332
  return {
322
333
  [HTTP_DATA_REQ_HEADERS_ATT_NAME]: cleanRequestHeaders
323
- ? safeFromEntries(cleanRequestHeaders)
334
+ ? Object.fromEntries(cleanRequestHeaders)
324
335
  : {},
325
336
  [HTTP_DATA_PAYLOAD_ATT_NAME]: requestPayloadUpdated,
326
337
  [HTTP_DATA_RESP_HEADERS_ATT_NAME]: cleanResponseHeaders
327
- ? safeFromEntries(cleanResponseHeaders)
338
+ ? Object.fromEntries(cleanResponseHeaders)
328
339
  : {},
329
340
  [HTTP_DATA_RESP_PAYLOAD_ATT_NAME]: responsePayloadUpdated,
330
341
  };
@@ -338,8 +349,13 @@ class HTTPDataBundler {
338
349
  * @returns boolean indicating whether the validation passed
339
350
  */
340
351
  isValidRequest(url, method) {
341
- if (!this.httpDataCollectionEnabled) return false;
352
+ noibuLog('isValidRequest');
353
+ if (!this.httpDataCollectionEnabled) {
354
+ noibuLog('isValidRequest httpDataCollectionEnabled is off, quitting');
355
+ return false;
356
+ }
342
357
  if (!method || typeof method !== 'string') {
358
+ noibuLog('isValidRequest method is invalid, quitting');
343
359
  return false;
344
360
  }
345
361
  // TODO: Check below disabled for beta. NOI-4253
@@ -361,16 +377,32 @@ class HTTPDataBundler {
361
377
  * inherently on the current domain) or matches the current domain.
362
378
  */
363
379
  shouldContinueForURL(url) {
364
- if (!this.httpDataCollectionEnabled) return false;
380
+ noibuLog('shouldContinueForURL started for', url);
381
+ if (!this.httpDataCollectionEnabled) {
382
+ noibuLog('shouldContinueForURL httpDataCollection turned off, quitting');
383
+ return false;
384
+ }
365
385
  if (!url || typeof url !== 'string' || !this.initialURLPartsReversed) {
386
+ noibuLog('shouldContinueForURL url is not valid, quitting', {
387
+ initialUrlPartsReversed: this.initialURLPartsReversed,
388
+ });
366
389
  return false;
367
390
  }
368
391
  // URL is absolute; either "http://example.com" or "//example.com"
369
392
  if (HTTPDataBundler.isAbsoluteURL(url)) {
370
393
  // Only capture requests on the same domain or in the allowed list
371
- if (!this.isURLSameDomain(url) && !this.shouldCollectPayloadForURL(url))
394
+ if (!this.isURLSameDomain(url) && !this.shouldCollectPayloadForURL(url)) {
395
+ noibuLog(
396
+ 'shouldContinueForURL url is not same domain or is not in allow list, quitting',
397
+ {
398
+ shouldCollectPayloadForURL: this.shouldCollectPayloadForURL(url),
399
+ },
400
+ );
372
401
  return false;
402
+ }
373
403
  } // end `if` (if URL is relative, it is on the same domain.)
404
+
405
+ noibuLog('shouldContinueForURL - yes');
374
406
  return true;
375
407
  }
376
408
 
@@ -392,7 +424,9 @@ class HTTPDataBundler {
392
424
  * @returns boolean indicating whether HTTP payloads can be collected on this URL
393
425
  */
394
426
  shouldCollectPayloadForURL(url) {
427
+ noibuLog('shouldCollectPayloadForURL', url);
395
428
  if (!url || typeof url !== 'string') {
429
+ noibuLog('shouldCollectPayloadForURL url is invalid, quitting');
396
430
  return false;
397
431
  }
398
432
  // check if in the full URL allowed list
@@ -400,6 +434,7 @@ class HTTPDataBundler {
400
434
  this.httpDataAllowedAbsoluteRegex &&
401
435
  this.httpDataAllowedAbsoluteRegex.test(url.toLowerCase())
402
436
  ) {
437
+ noibuLog('shouldCollectPayloadForURL yes, absolute');
403
438
  return true;
404
439
  }
405
440
  // check if in the relative URL allowed list, if on domain
@@ -409,8 +444,20 @@ class HTTPDataBundler {
409
444
  (!HTTPDataBundler.isAbsoluteURL(url) || this.isURLSameDomain(url)) &&
410
445
  this.httpDataAllowedRelativeRegex.test(url.toLowerCase())
411
446
  ) {
447
+ noibuLog('shouldCollectPayloadForURL yes, relative');
412
448
  return true;
413
449
  }
450
+
451
+ noibuLog('shouldCollectPayloadForURL answer is no, reason', {
452
+ httpDataAllowedAbsoluteRegexTest:
453
+ this.httpDataAllowedAbsoluteRegex &&
454
+ this.httpDataAllowedAbsoluteRegex.test(url.toLowerCase()),
455
+ httpDataAllowedRelativeRegexTest:
456
+ this.httpDataAllowedRelativeRegex &&
457
+ this.httpDataAllowedRelativeRegex.test(url.toLowerCase()),
458
+ isAbsoluteURL: HTTPDataBundler.isAbsoluteURL(url),
459
+ isURLSameDomain: this.isURLSameDomain(url),
460
+ });
414
461
  return false;
415
462
  }
416
463
 
@@ -1,5 +1,5 @@
1
1
  import { TextInput } from 'react-native';
2
- import { updatePayload } from '../pageVisit/userStep/userStep.js';
2
+ import { updatePayload } from '../pageVisit/userStep.js';
3
3
  import { InputMonitor } from './inputMonitor.js';
4
4
  import { SOURCE_ATT_NAME, TEXT_ATT_NAME, TAGNAME_ATT_NAME, TYPE_ATT_NAME, KEYBOARD_EVENT_TYPE } from '../constants.js';
5
5