noibu-react-native 0.1.2 → 0.2.0

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 (52) hide show
  1. package/android/.gitignore +13 -0
  2. package/android/build.gradle +79 -0
  3. package/android/gradle.properties +7 -0
  4. package/android/src/main/AndroidManifest.xml +5 -0
  5. package/android/src/main/java/com/noibu/sessionreplay/reactnative/NoibuSessionReplayModule.kt +107 -0
  6. package/android/src/main/java/com/noibu/sessionreplay/reactnative/NoibuSessionReplayPackage.kt +17 -0
  7. package/dist/api/clientConfig.d.ts +6 -7
  8. package/dist/api/clientConfig.js +14 -16
  9. package/dist/api/helpCode.d.ts +29 -0
  10. package/dist/api/inputManager.d.ts +87 -0
  11. package/dist/api/metroplexSocket.d.ts +156 -0
  12. package/dist/api/metroplexSocket.js +662 -815
  13. package/dist/api/storedMetrics.d.ts +73 -0
  14. package/dist/api/storedPageVisit.d.ts +49 -0
  15. package/dist/const_matchers.d.ts +1 -0
  16. package/dist/constants.d.ts +10 -1
  17. package/dist/constants.js +19 -2
  18. package/dist/entry/index.d.ts +1 -1
  19. package/dist/entry/init.d.ts +1 -1
  20. package/dist/entry/init.js +10 -6
  21. package/dist/monitors/appNavigationMonitor.js +3 -2
  22. package/dist/monitors/clickMonitor.d.ts +44 -0
  23. package/dist/monitors/gqlErrorValidator.d.ts +82 -0
  24. package/dist/monitors/httpDataBundler.d.ts +161 -0
  25. package/dist/monitors/inputMonitor.d.ts +34 -0
  26. package/dist/monitors/inputMonitor.js +5 -0
  27. package/dist/monitors/integrations/react-native-navigation-integration.d.ts +1 -2
  28. package/dist/monitors/keyboardInputMonitor.d.ts +17 -0
  29. package/dist/monitors/pageMonitor.d.ts +22 -0
  30. package/dist/monitors/requestMonitor.d.ts +10 -0
  31. package/dist/pageVisit/pageVisit.d.ts +52 -0
  32. package/dist/pageVisit/pageVisit.js +9 -2
  33. package/dist/pageVisit/pageVisitEventError.d.ts +15 -0
  34. package/dist/pageVisit/pageVisitEventHTTP.d.ts +18 -0
  35. package/dist/pageVisit/userStep.d.ts +5 -0
  36. package/dist/react/ErrorBoundary.js +17 -9
  37. package/dist/sessionRecorder/nativeSessionRecorderSubscription.d.ts +64 -0
  38. package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +58 -0
  39. package/dist/sessionRecorder/sessionRecorder.d.ts +60 -0
  40. package/dist/sessionRecorder/sessionRecorder.js +287 -0
  41. package/dist/sessionRecorder/types.d.ts +91 -0
  42. package/dist/types/NavigationIntegration.d.ts +1 -2
  43. package/dist/types/StoredPageVisit.types.d.ts +54 -0
  44. package/dist/types/globals.d.ts +2 -1
  45. package/dist/utils/date.d.ts +6 -0
  46. package/dist/utils/eventlistener.d.ts +8 -0
  47. package/dist/utils/eventlistener.js +2 -2
  48. package/dist/utils/function.d.ts +6 -3
  49. package/dist/utils/function.js +23 -10
  50. package/dist/utils/log.d.ts +0 -1
  51. package/dist/utils/object.d.ts +2 -2
  52. package/package.json +15 -6
@@ -0,0 +1,73 @@
1
+ /**
2
+ * This class holds the final page visit and video frag metrics. It flushes
3
+ * them to storage and then finally sends them to Metroplex via the post
4
+ * route when the next page is loaded
5
+ */
6
+ export default class StoredMetrics {
7
+ /**
8
+ * gets the singleton instance
9
+ * @returns {StoredMetrics}
10
+ */
11
+ static getInstance(): StoredMetrics;
12
+ expectedVideoLength: number;
13
+ expectedVfSeq: number;
14
+ httpSequenceNumber: number;
15
+ httpOverLimitCount: number;
16
+ httpDroppedPayloadByTypeCount: number;
17
+ httpDroppedPayloadByLengthCount: number;
18
+ httpPayloadCount: number;
19
+ expectedPvPart: number;
20
+ videoClicks: number;
21
+ pvClicks: number;
22
+ errCount: number;
23
+ httpCount: number;
24
+ didCutPv: boolean;
25
+ didCutVideo: boolean;
26
+ writeTimeout: any;
27
+ didStartVideo: boolean;
28
+ /** Add video frag payload data to the stored metrics
29
+ * @param {} expectedVfSeq
30
+ * @param {} expectedVideoLength
31
+ */
32
+ addVideoFragData(expectedVfSeq: any, expectedVideoLength: any): void;
33
+ /** Set the amount of page visit parts
34
+ * @param {} expectedPvPart
35
+ */
36
+ setPvPart(expectedPvPart: any): void;
37
+ /** Increase the amount of video clicks seen in the session */
38
+ addVideoClick(): void;
39
+ /** Increase the amount of page visit clicks */
40
+ addPvClick(): void;
41
+ /** Increments the error count by 1 */
42
+ addError(): void;
43
+ /** Increments the http count by 1 */
44
+ addHttpEvent(): void;
45
+ /** Increments the http data sequence count by 1 */
46
+ addHttpData(): void;
47
+ /** Increments the http data over limit count by 1 */
48
+ addHttpDataOverLimit(): void;
49
+ /** Increments the http data drop count by content type */
50
+ addHttpDataDropByType(): void;
51
+ /** Increments the http data drop count by content length */
52
+ addHttpDataDropByLength(): void;
53
+ /** Increments the http data payload collected count */
54
+ addHttpDataPayloadCount(): void;
55
+ /** Set that the video was cut/blocked due to size constraints */
56
+ setDidCutVideo(): void;
57
+ /** Set that the video was started */
58
+ setDidStartVideo(): void;
59
+ /** Set that the page visit was cut/blocked due to size constraints */
60
+ setDidCutPv(): void;
61
+ /**
62
+ * Sets up all the listeners that noibujs should listen to before storing
63
+ * our metrics to localstorage
64
+ */
65
+ _setupListeners(): void;
66
+ /** posts the metrics to metroplex if client is active
67
+ * @param {} eventName
68
+ */
69
+ _postMetricsIfActive(eventName: any): void;
70
+ /** posts the metrics to metroplex using the beacon API
71
+ */
72
+ postMetrics(): Promise<void>;
73
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * This class holds the final page visit. It flushes it to storage and then
3
+ * finally sends it to Metroplex via the post route when the next page is loaded
4
+ */
5
+ export default class StoredPageVisit {
6
+ /** gets the singleton instance */
7
+ static getInstance(): StoredPageVisit;
8
+ latestPageVisitFrag: any;
9
+ writeTimeout: any;
10
+ flushedStorage: boolean;
11
+ /**
12
+ * Check if the events contain a click or location change. If they do then write the retry
13
+ * queue (which contains the metroplex msg sent above) to storage
14
+ * @param {} retryMessageQueue
15
+ * @param {} pvInfo
16
+ */
17
+ checkAndStoreRetryQueue(retryMessageQueue: any, pvInfo: any): void;
18
+ /** Writes the page visit frags in the retry queue to storage
19
+ * @param {} retryMessageQueue
20
+ * @param {} pvInfo
21
+ */
22
+ writePageVisitsFromRetryQueue(retryMessageQueue: any, pvInfo: any): void;
23
+ /** Write the given page visit frags to storage
24
+ * @param {} pageVisitFrags
25
+ * @param {} pvInfo
26
+ */
27
+ _writePageVisitFrags(pageVisitFrags: any, pvInfo: any): Promise<void>;
28
+ /**
29
+ * Read the stored page visit from storage, create a complete page visit object
30
+ * and then post that to Metroplex
31
+ */
32
+ _getPostData(): Promise<{
33
+ pvi: any;
34
+ pvp: never[];
35
+ pvvf: never[];
36
+ } | null>;
37
+ /**
38
+ * Creates and tries to resolve a promise that posts the previous page visit
39
+ * to Metroplex from storage
40
+ */
41
+ _postPreviousPageVisit(): void;
42
+ /**
43
+ * Remove the storage item and set flushed to true after they have
44
+ * been posted to metroplex
45
+ */
46
+ _updateStorageFlushed(): void;
47
+ /** Returns a promise that resolves to post the page visit in storage to Metroplex */
48
+ _getPostPageVisitPromise(): Promise<any>;
49
+ }
@@ -0,0 +1 @@
1
+ export function WHITELIST_TEXT_REGEX_STRING(): string;
@@ -33,7 +33,6 @@ export declare const SEVERITY: {
33
33
  readonly info: "info";
34
34
  readonly debug: "debug";
35
35
  };
36
- export declare const UNFREEZE_TAG: "unfreeze";
37
36
  export declare const MAX_METROPLEX_SOCKET_INNACTIVE_TIME: number;
38
37
  export declare const MAX_PAGEVISIT_VISITED: 300;
39
38
  export declare const IMG_EXTENSIONS: readonly ["jpg", "jpeg", "bmp", "gif", "png"];
@@ -59,7 +58,10 @@ export declare const BROWSER_ID_ATT_NAME: "br_id";
59
58
  export declare const PV_ID_ATT_NAME: "pv_id";
60
59
  export declare const VER_ATT_NAME: "v";
61
60
  export declare const PV_SEQ_ATT_NAME: "seq";
61
+ export declare const VIDEO_RECORDER_ATT_NAME: "video_recorder";
62
62
  export declare const ON_URL_ATT_NAME: "on_url";
63
+ export declare const PAGE_GROUPS_ATT_NAME = "page_groups";
64
+ export declare const PAGE_TITLE_ATT_NAME = "page_title";
63
65
  export declare const URL_ATT_NAME: "url";
64
66
  export declare const REF_URL_ATT_NAME: "ref_url";
65
67
  export declare const STARTED_AT_ATT_NAME: "start_at";
@@ -225,6 +227,10 @@ export declare function GET_METROPLEX_METRICS_URL(): string;
225
227
  * gets the current env
226
228
  */
227
229
  export declare function JS_ENV(): string;
230
+ /**
231
+ * gets the current env
232
+ */
233
+ export declare function GET_DEVICE_ENV(): string;
228
234
  export declare const METROPLEX_RETRY_FREQUENCY: 30000;
229
235
  export declare const STACK_TRACE_SANITIZE_REGEXP: RegExp;
230
236
  export declare const BLOCKLISTED_DOMAINS: {
@@ -234,3 +240,6 @@ export declare const BLOCKLISTED_DOMAINS: {
234
240
  'vf.staging.noibu.com': boolean;
235
241
  'cdn.noibu.com': boolean;
236
242
  };
243
+ export declare const MAX_RECORDER_EVENT_BUFFER = 10;
244
+ export declare const MAX_TIME_FOR_RECORDER_USER_EVENTS = 2000;
245
+ export declare const POST_METRICS_EVENT_NAME = "noibuPostMetrics";
package/dist/constants.js CHANGED
@@ -159,6 +159,7 @@ const BROWSER_ID_ATT_NAME = 'br_id';
159
159
  const PV_ID_ATT_NAME = 'pv_id';
160
160
  const VER_ATT_NAME = 'v';
161
161
  const PV_SEQ_ATT_NAME = 'seq';
162
+ const VIDEO_RECORDER_ATT_NAME = 'video_recorder';
162
163
  const ON_URL_ATT_NAME = 'on_url';
163
164
  const URL_ATT_NAME = 'url';
164
165
  const REF_URL_ATT_NAME = 'ref_url';
@@ -167,7 +168,10 @@ const PV_EVENTS_ATT_NAME = 'events';
167
168
  const PV_PART_COUNTER_ATT_NAME = 'pc';
168
169
  const CONN_COUNT_ATT_NAME = 'conc';
169
170
  const COLLECT_VER_ATT_NAME = 'cv';
171
+ const VIDEO_FRAG_ATT_NAME = 'vid';
172
+ const CSS_URLS_ATT_NAME = 'css_urls';
170
173
  const END_AT_ATT_NAME = 'end_at';
174
+ const LENGTH_ATT_NAME = 'len';
171
175
  const IS_LAST_ATT_NAME = 'last';
172
176
  const TYPE_ATT_NAME = 'type';
173
177
  const OCCURRED_AT_ATT_NAME = 'occ_at';
@@ -315,7 +319,7 @@ const CONTENT_LENGTH = 'content-length';
315
319
  * Gets the script id from the cookie object, returns default if cannot be found
316
320
  */
317
321
  function GET_SCRIPT_ID() {
318
- return "1.0.104-rn-sdk-0.1.2" ;
322
+ return "1.0.104-rn-sdk-0.2.0" ;
319
323
  }
320
324
  /**
321
325
  *
@@ -421,6 +425,12 @@ function JS_ENV() {
421
425
  return 'test';
422
426
  }
423
427
  }
428
+ /**
429
+ * gets the current env
430
+ */
431
+ function GET_DEVICE_ENV() {
432
+ return "react-native-expo" ;
433
+ }
424
434
  // gets the frequency at which the client resends the message that were not confirmed by metroplex
425
435
  const METROPLEX_RETRY_FREQUENCY = 30000;
426
436
  const STACK_TRACE_SANITIZE_REGEXP = /(nbuGlobalPromiseRejectWrapper|(hermes.*InternalBytecode\/InternalBytecode))/gi;
@@ -431,5 +441,12 @@ const BLOCKLISTED_DOMAINS = {
431
441
  'vf.staging.noibu.com': true,
432
442
  'cdn.noibu.com': true,
433
443
  };
444
+ // Maximum number of events in the RRWEB session recorder buffer
445
+ // before sending to Metroplex
446
+ const MAX_RECORDER_EVENT_BUFFER = 10;
447
+ // the max amount of time to wait for user events until freezing rrweb mutation events
448
+ const MAX_TIME_FOR_RECORDER_USER_EVENTS = 2000;
449
+ // custom event name for posting metrics
450
+ const POST_METRICS_EVENT_NAME = 'noibuPostMetrics';
434
451
 
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 };
452
+ 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, CSS_URLS_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_DEVICE_ENV, 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, LENGTH_ATT_NAME, 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_RECORDER_EVENT_BUFFER, MAX_STRING_LENGTH, MAX_TIME_FOR_RECORDER_USER_EVENTS, 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, POST_METRICS_EVENT_NAME, 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_FRAG_ATT_NAME, VIDEO_METROPLEX_TYPE, VIDEO_PART_COUNT_ATT_NAME, VIDEO_RECORDER_ATT_NAME, WHITELIST_HTML_ID_TEXT_REGEX, WORK_REQUEST_ATT_NAME, WRAPPED_EXCEPTION_ERROR_TYPE, XML_HTTP_REQUEST_ERROR_TYPE };
@@ -6,7 +6,7 @@ import { ErrorBoundary as _ErrorBoundary } from '../react/ErrorBoundary';
6
6
  */
7
7
  export declare const setupNoibu: typeof globalInit;
8
8
  export declare const NoibuJS: {
9
- requestHelpCode: (alert?: boolean | undefined) => Promise<string>;
9
+ requestHelpCode: (alert?: boolean) => Promise<string>;
10
10
  addCustomAttribute: (name: string, value: string) => Promise<string>;
11
11
  addError: (customError: Error) => string;
12
12
  addJsSdkError: (customError: string, errorSource: string) => string;
@@ -2,4 +2,4 @@ import { CustomerConfig } from '../types/Config';
2
2
  /**
3
3
  * initilializes the script to start executing all of NJS features
4
4
  */
5
- export default function globalInit(customerConfig: CustomerConfig): void;
5
+ export default function globalInit(customerConfig: CustomerConfig): Promise<void>;
@@ -14,6 +14,7 @@ import StoredPageVisit from '../api/storedPageVisit.js';
14
14
  import HelpCode from '../api/helpCode.js';
15
15
  import { AppNavigationMonitor } from '../monitors/appNavigationMonitor.js';
16
16
  import { noibuLog } from '../utils/log.js';
17
+ import SessionRecorder from '../sessionRecorder/sessionRecorder.js';
17
18
 
18
19
  /** @module Init */
19
20
  // these are set via rollup
@@ -24,7 +25,7 @@ const urlConfig = {
24
25
  /**
25
26
  * initilializes the script to start executing all of NJS features
26
27
  */
27
- function globalInit(customerConfig) {
28
+ async function globalInit(customerConfig) {
28
29
  noibuLog('global init started');
29
30
  // if the config url is invalid we block collect from executing
30
31
  if (isInvalidURLConfig({ ...urlConfig, domain: customerConfig.domain })) {
@@ -39,7 +40,7 @@ function globalInit(customerConfig) {
39
40
  const noibuErrorURL = `${urlConfig.metroplexHTTPBase}/${METROPLEX_ERROR_ROUTE}`;
40
41
  // catch any errors that happened during initialization and send collect error
41
42
  try {
42
- ClientConfig.configureInstance({
43
+ await ClientConfig.configureInstance({
43
44
  noibuErrorURL,
44
45
  customerConfig,
45
46
  });
@@ -69,10 +70,13 @@ function globalInit(customerConfig) {
69
70
  clickMonitor.monitorClicks();
70
71
  keyboardInputMonitor.monitor();
71
72
  pageMonitor.monitor();
72
- // todo: disable types here until metroplex socket file moves to ts
73
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
74
- // @ts-ignore
75
- metroplexSocket.connectionPromise.catch((e) => ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(`Error during metroplexSocket initial connection: ${e}`, false, SEVERITY.error));
73
+ SessionRecorder.getInstance().recordUserSession();
74
+ if (metroplexSocket.connectionPromise) {
75
+ metroplexSocket.connectionPromise.catch((e) => ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(`Error during metroplexSocket initial connection: ${e}`, false, SEVERITY.error));
76
+ }
77
+ else {
78
+ throw new Error('metroplex socket not ready');
79
+ }
76
80
  noibuLog('global init finished');
77
81
  }
78
82
  catch (err) {
@@ -14,8 +14,9 @@ class AppNavigationMonitor {
14
14
  constructor() {
15
15
  this.onNavigation = this.onNavigation.bind(this);
16
16
  try {
17
- // eslint-disable-next-line global-require,@typescript-eslint/no-var-requires,import/no-extraneous-dependencies
18
- const rnNavigation = require('react-native-navigation')?.Navigation;
17
+ // eslint-disable-next-line global-require,@typescript-eslint/no-var-requires,import/no-extraneous-dependencies,import/no-unresolved
18
+ const Navigation = require('react-native-navigation');
19
+ const rnNavigation = Navigation?.Navigation;
19
20
  if (rnNavigation) {
20
21
  new ReactNativeNavigationIntegration().register(rnNavigation, this.onNavigation);
21
22
  }
@@ -0,0 +1,44 @@
1
+ /** Monitors the clicks which we capture and later process */
2
+ export class ClickMonitor {
3
+ /** gets the singleton instance
4
+ * @returns {ClickMonitor}
5
+ */
6
+ static getInstance(): ClickMonitor;
7
+ /**
8
+ * Gets selectors to prevent those elements from being recorded
9
+ */
10
+ static getBlockedElements(): string[];
11
+ textCapturedWhiteListRegex: RegExp;
12
+ htmlIDAllowListRegex: RegExp;
13
+ /** Starts monitoring clicks on every Press-able component */
14
+ monitorClicks(): void;
15
+ /**
16
+ * Handles a single click event
17
+ * @param {{ _targetInst: RNNode }} event
18
+ */
19
+ _onClickHandle(event: {
20
+ _targetInst: RNNode;
21
+ }): void;
22
+ /** Gets the textual content from an element, if any
23
+ * @param {} element
24
+ */
25
+ _getTextualContentFromEl(element: any): string;
26
+ /** Parse and trim text
27
+ * @param {} text
28
+ */
29
+ _trimText(text: any): any;
30
+ /**
31
+ * Recursively parses element's inner content and masks blocked css classes
32
+ * @param {NReactNative.Node} element
33
+ * @param {String} text
34
+ * @param {Number} textLimit
35
+ * @param {Object} counter
36
+ */
37
+ _parseInnerContent(element: NReactNative.Node, text: string, textLimit: number, counter: Object): string;
38
+ /**
39
+ * normalize value and append to the resulting text if not empty
40
+ * @param {String} text
41
+ * @param {Array.<any>} values
42
+ */
43
+ _parseAndAppendText(text: string, values: Array<any>): string;
44
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Try detecting GraphQL errors from http response
3
+ */
4
+ export default class GqlErrorValidator {
5
+ /**
6
+ * Retrieves GQL error object based on fetch request/response
7
+ * @param {String} url
8
+ * @param {{}} options
9
+ * @param {Request} request
10
+ * @param {Response} response - cloned() from original response
11
+ */
12
+ static fromFetch(url: string, options: {}, request: Request, response: Response): Promise<any>;
13
+ /**
14
+ * Retrieves GQL error object based on XHR object
15
+ * @param {String} url
16
+ * @param {XMLHttpRequest} xhr
17
+ */
18
+ static fromXhr(url: string, xhr: XMLHttpRequest): Promise<any>;
19
+ /**
20
+ * Try safely parse a string and return null if fails
21
+ * @param {String} content
22
+ */
23
+ static _parseJsonSafely(content: string): any;
24
+ /**
25
+ * Try to get content type for fetch arguments
26
+ * @param {{}} options
27
+ * @param {Request} request
28
+ */
29
+ static _getContentTypeFromFetchArguments(options: {}, request: Request): string | null;
30
+ /**
31
+ * Checks if request is aborted
32
+ * If it has been aborder we are not able to consume the response
33
+ * @param {{}} options
34
+ * @param {Request} request
35
+ */
36
+ static _isRequestAborted(options: {}, request: Request): any;
37
+ /**
38
+ * Determines if request should be processed
39
+ * @param {String|URL} url
40
+ * @param {String} contentType
41
+ */
42
+ static _shouldHandleRequest(url: string | URL, contentType: string): boolean;
43
+ /**
44
+ * Sanitizes payload object
45
+ * @param {any} data
46
+ * @param {Array<String>} validationIssues
47
+ */
48
+ static _validate(data: any, validationIssues: Array<string>): any;
49
+ /**
50
+ * Sanitizes message object
51
+ * @param {any} error
52
+ */
53
+ static _validateMessage(error: any): void;
54
+ /**
55
+ * Sanitizes extensions object
56
+ * @param {any} error
57
+ * @param {Array<String>} validationIssues
58
+ */
59
+ static _validateExtensions(error: any): void;
60
+ /**
61
+ * Sanitizes locations object
62
+ * @param {any} error
63
+ * @param {Array<String>} validationIssues
64
+ */
65
+ static _validateLocations(error: any, validationIssues: Array<string>): void;
66
+ /**
67
+ * Sanitizes path object
68
+ * @param {any} error
69
+ * @param {Array<String>} validationIssues
70
+ */
71
+ static _validatePath(error: any, validationIssues: Array<string>): void;
72
+ /**
73
+ * Posts error
74
+ * @param {String} message
75
+ */
76
+ static _postError(message: string): void;
77
+ /**
78
+ * Posts issue found during object sanitization
79
+ * @param {Array<String>} validationIssues
80
+ */
81
+ static _postValidationIssues(validationIssues: Array<string>): void;
82
+ }
@@ -0,0 +1,161 @@
1
+ /** Bundles HTTP payloads and headers */
2
+ export class HTTPDataBundler {
3
+ /** gets http data payload allowed URLs */
4
+ static getHttpPayloadAllowedURLs(): string[];
5
+ /**
6
+ * gets the singleton instance
7
+ * @returns {HTTPDataBundler}
8
+ */
9
+ static getInstance(): HTTPDataBundler;
10
+ /**
11
+ * Builds the HTTP payload allowed regexes for full and relative URLs
12
+ * @param allowedURLs A list of allowed URLs
13
+ * @param {'absolute' | 'relative'} strategy Use only absolute URLs if true, use only relative URL if false
14
+ * @returns a regex of allowed URLs
15
+ */
16
+ static buildAllowedRegex(allowedURLs: any, strategy: "absolute" | "relative"): RegExp | null;
17
+ /**
18
+ * Takes an iterator and returns a map of strings representing headers.
19
+ * @param {object} headersIterable any iterable object
20
+ * @returns a map of strings (as expected by metroplex) representing HTTP
21
+ * request or response headers
22
+ */
23
+ static headersMapFromIterable(headersIterable: object): Map<any, any>;
24
+ /**
25
+ * Takes a string of headers with 'name: value' and returns
26
+ * a map of strings representing headers.
27
+ * @param {string} headersString is all the headers in one string
28
+ * @returns a map of strings (as expected by metroplex) representing HTTP
29
+ * request or response headers
30
+ */
31
+ static headersMapFromString(headersString: string): Map<any, any>;
32
+ /**
33
+ * For an XHR object, checks the responseType property and handles the response or
34
+ * responseText property accordingly to return a string representation of the response.
35
+ * @param {object} xhr an XMLHTTPRequest object
36
+ * @returns a string representation of the response, or null if this fails.
37
+ */
38
+ static responseStringFromXHRResponseType(xhr: object): any;
39
+ /**
40
+ * Determins if the URL is absolute or relative
41
+ * @param {string} url
42
+ * @returns boolean indicating whether the URL passed is either absolute or relative
43
+ */
44
+ static isAbsoluteURL(url: string): boolean;
45
+ contentTypeReadableRegex: RegExp;
46
+ initialURLPartsReversed: any[];
47
+ httpDataCollectionEnabled: boolean;
48
+ httpDataAllowedAbsoluteRegex: RegExp | null;
49
+ httpDataAllowedRelativeRegex: RegExp | null;
50
+ fuzzyFieldsToRedact: string[];
51
+ exactFieldsToRedact: string[];
52
+ /**
53
+ * Takes a URL and returns true if it is determined to be on the same domain as the URL
54
+ * the script is running on. Ignores protocol and path, and allows the URL to be a subdomain.
55
+ * @param {string} requestURL the URL of a request to compare to the script website's URL
56
+ */
57
+ isURLSameDomain(requestURL: string): boolean;
58
+ /**
59
+ * Builds an HTTP Data bundle
60
+ * @param url
61
+ * @param requestHeaders is a map of request headers
62
+ * @param rawRequestPayload
63
+ * @param responseHeaders is a map of response headers
64
+ * @param responsePayload
65
+ * @param method
66
+ * @param shouldCollectPayload
67
+ */
68
+ bundleHTTPData(url: any, requestHeaders: any, rawRequestPayload: any, responseHeaders: any, responsePayload: any, method: any, shouldCollectPayload: any): {
69
+ rqh: any;
70
+ rqp: string | null;
71
+ rsh: any;
72
+ rsp: string | null;
73
+ } | null;
74
+ /**
75
+ * Validates a request based on the URL and method. When enabled, will handle
76
+ * de-duping the requests
77
+ * @param {string} url
78
+ * @param {string} method
79
+ * @returns boolean indicating whether the validation passed
80
+ */
81
+ isValidRequest(url: string, method: string): boolean;
82
+ /**
83
+ * Checks two things: that the URL is either on the same domain (or an address relative to the
84
+ * current domain), and also checks that the config http_data_collection flag is enabled.
85
+ * @param {string} url
86
+ * @returns boolean indicating whether the URL passed is either relative (in which case it is
87
+ * inherently on the current domain) or matches the current domain.
88
+ */
89
+ shouldContinueForURL(url: string): boolean;
90
+ /**
91
+ * Checks whether HTTP payloads can be collected on this URL
92
+ * @param {string} url
93
+ * @returns boolean indicating whether HTTP payloads can be collected on this URL
94
+ */
95
+ shouldCollectPayloadForURL(url: string): boolean;
96
+ /**
97
+ * Double checks content length if we couldn't read the headers, and redacts PII
98
+ * @param {string} payload
99
+ * @param {string} url
100
+ * @returns the restricted payload
101
+ */
102
+ restrictPayload(payload: string, url: string): string | null;
103
+ /**
104
+ * Returns true if the content length is acceptable to collect
105
+ * If the headers are not found, check actual content for length
106
+ * @param {Headers} headers
107
+ * @returns boolean true if acceptable to collect
108
+ */
109
+ contentLengthAcceptable(headers: Headers): boolean;
110
+ /**
111
+ * Returns true if the content type according to the headers is valid for collection.
112
+ * Also returns assumed true if content type is not stated in headers.
113
+ * @param {Map} headersMap
114
+ * @returns boolean true if acceptable to collect
115
+ */
116
+ contentTypeAcceptable(headersMap: Map<any, any>): boolean;
117
+ /**
118
+ * Returns a descriptive string if we have to drop payload based on the length
119
+ * or type listed in the headers passed. Returns an empty string otherwise.
120
+ * @param {Headers} headers a Headers object
121
+ * @returns A string, which is empty if the payload doesn't need to be dropped, or is a
122
+ * descriptive string explaining the circumstances of the drop otherwise.
123
+ */
124
+ dropPayloadIfNecessaryFromHeaders(headers: Headers): string;
125
+ /**
126
+ * Returns content length from the headers, if available
127
+ * If the headers are not found or not a number, return -1
128
+ * @param {} headersObject
129
+ * @returns content length
130
+ */
131
+ contentLength(headersObject: any): number;
132
+ /**
133
+ * Accepts a value that could be any type used as a request payload, and returns a string
134
+ * representation. First attemtps to find a .toString() method, then tries to handle it
135
+ * like an XML or HTML element, then finally falls back to JSON.stringify(). If none of
136
+ * these are successful, returns null.
137
+ * @param {*} value request paylad body, of any type
138
+ * @returns string representation of the value passed, or null if this fails.
139
+ */
140
+ stringFromRequestBody(value: any): any;
141
+ /**
142
+ * Removes possible PII from headers.
143
+ * @param {Map} dirtyHeaders a Map of HTTP response or request headers
144
+ * @returns a map of headers with PII redacted
145
+ */
146
+ removePIIHeaders(dirtyHeaders: Map<any, any>): Map<any, any> | null;
147
+ /**
148
+ * Takes a body payload string and redacts any PII we're able to detect
149
+ *
150
+ * @param {string} dirtyBody the string from which we want to redact PII
151
+ * @returns the string with any PII we're able to detect redacted.
152
+ */
153
+ removePIIBody(dirtyBody: string): string | null;
154
+ /**
155
+ * Try to parse content as a JSON object and
156
+ * iterate it recursively removing PII.
157
+ * Returns original content if nothing was changes or error is thrown.
158
+ * @param {String} content
159
+ */
160
+ tryParseObjectAndRemovePII(content: string): string;
161
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Singleton class to manage the client configuration
3
+ * this class will be responsible for debouncing all events
4
+ * that are registered
5
+ */
6
+ export class InputMonitor {
7
+ /**
8
+ * gets the instance of InputMonitor
9
+ * @returns {InputMonitor}
10
+ */
11
+ static getInstance(): InputMonitor;
12
+ eventsToDebounce: {};
13
+ /** will debounce all events that are of this type by the debounce period
14
+ * @param {} type
15
+ * @param {} debouncePeriod
16
+ * @param {} eventName=type
17
+ */
18
+ registerInputType(type: any, debouncePeriod: any, eventName?: any): void;
19
+ /**
20
+ * Creates an event object with the event and the time it was added then pushes
21
+ * that event object to the queue of events waiting to be debounced.
22
+ * @param {} event
23
+ * @param {} type
24
+ */
25
+ addEvent(event: any, type: any): void;
26
+ /**
27
+ * Adds the events from the object to the page visit and sets up a timer
28
+ * to send the events if no more are received without the timeout
29
+ * @param {} type
30
+ */
31
+ _debouncePvEvents(type: any): void;
32
+ /** Sets up the page hide handler to try to push remaining events in the queues */
33
+ _setupUnloadHandler(): void;
34
+ }
@@ -2,6 +2,7 @@ import { PageVisit } from '../pageVisit/pageVisit.js';
2
2
  import { APP_NAVIGATION_EVENT_TYPE, PAGE_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS, ERROR_EVENT_TYPE, HTTP_EVENT_TYPE, KEYBOARD_EVENT_TYPE, USERSTEP_EVENT_TYPE } from '../constants.js';
3
3
  import { timestampWrapper } from '../utils/date.js';
4
4
  import { addSafeEventListener } from '../utils/eventlistener.js';
5
+ import { noibuLog } from '../utils/log.js';
5
6
 
6
7
  /** @module InputMonitor */
7
8
 
@@ -80,6 +81,10 @@ class InputMonitor {
80
81
  * @param {} type
81
82
  */
82
83
  addEvent(event, type) {
84
+ noibuLog('addEvent', {
85
+ event,
86
+ type,
87
+ });
83
88
  if (!(type in this.eventsToDebounce)) {
84
89
  throw new Error(`Type: ${type} is not in eventsToDebounce`);
85
90
  }
@@ -1,4 +1,3 @@
1
- import type { NavigationDelegate } from 'react-native-navigation/lib/dist/src/NavigationDelegate';
2
1
  import { NavigationIntegration } from '../../types/NavigationIntegration';
3
2
  /**
4
3
  * react-native-navigation adapter
@@ -9,7 +8,7 @@ export declare class ReactNativeNavigationIntegration implements NavigationInteg
9
8
  /**
10
9
  * attaches provided listeners to the integration
11
10
  */
12
- register(navigation: NavigationDelegate, onNavigation: (breadcrumbs: string[]) => void): void;
11
+ register(navigation: any, onNavigation: (breadcrumbs: string[]) => void): void;
13
12
  /**
14
13
  * Listens to ComponentWillAppear events, keeps track of visited screens and
15
14
  * pops them if the same page is visited to prevent cycles