noibu-react-native 0.2.2 → 0.2.3

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 (78) hide show
  1. package/README.md +1 -1
  2. package/dist/api/clientConfig.js +225 -217
  3. package/dist/api/metroplexSocket.js +406 -416
  4. package/dist/constants.js +14 -2
  5. package/dist/entry/init.js +58 -56
  6. package/dist/monitors/appNavigationMonitor.js +2 -3
  7. package/dist/monitors/clickMonitor.js +16 -9
  8. package/dist/monitors/errorMonitor.js +30 -8
  9. package/dist/monitors/gqlErrorValidator.js +4 -4
  10. package/dist/monitors/httpDataBundler.js +525 -713
  11. package/dist/monitors/integrations/react-native-navigation-integration.js +4 -2
  12. package/dist/monitors/requestMonitor.js +350 -365
  13. package/dist/pageVisit/eventDebouncer.js +110 -0
  14. package/dist/pageVisit/pageVisitEventError.js +1 -1
  15. package/dist/pageVisit/pageVisitEventHTTP.js +78 -93
  16. package/dist/react/ErrorBoundary.js +18 -15
  17. package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -2
  18. package/dist/sessionRecorder/sessionRecorder.js +151 -150
  19. package/dist/{api → src/api}/clientConfig.d.ts +1 -1
  20. package/dist/{api → src/api}/metroplexSocket.d.ts +25 -25
  21. package/dist/{constants.d.ts → src/constants.d.ts} +44 -0
  22. package/dist/{entry → src/entry}/init.d.ts +1 -1
  23. package/dist/{monitors → src/monitors}/clickMonitor.d.ts +1 -1
  24. package/dist/{monitors → src/monitors}/gqlErrorValidator.d.ts +6 -6
  25. package/dist/src/monitors/httpDataBundler.d.ts +127 -0
  26. package/dist/src/monitors/requestMonitor.d.ts +10 -0
  27. package/dist/src/pageVisit/eventDebouncer.d.ts +31 -0
  28. package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +25 -0
  29. package/dist/{sessionRecorder → src/sessionRecorder}/types.d.ts +1 -1
  30. package/dist/{storage → src/storage}/storage.d.ts +1 -1
  31. package/dist/{storage → src/storage}/storageProvider.d.ts +1 -1
  32. package/dist/{utils → src/utils}/function.d.ts +25 -4
  33. package/dist/{utils → src/utils}/object.d.ts +9 -4
  34. package/dist/src/utils/piiRedactor.d.ts +11 -0
  35. package/dist/src/utils/polyfills.d.ts +7 -0
  36. package/dist/storage/rnStorageProvider.js +7 -4
  37. package/dist/storage/storage.js +43 -35
  38. package/dist/storage/storageProvider.js +23 -19
  39. package/dist/types/Config.d.ts +24 -20
  40. package/dist/types/PageVisit.types.d.ts +151 -0
  41. package/dist/types/PageVisitMetrics.types.d.ts +27 -0
  42. package/dist/types/RRWeb.d.ts +48 -0
  43. package/dist/types/StoredPageVisit.types.d.ts +2 -4
  44. package/dist/types/WrappedObjects.d.ts +6 -0
  45. package/dist/utils/function.js +110 -76
  46. package/dist/utils/object.js +58 -6
  47. package/dist/utils/piiRedactor.js +98 -0
  48. package/dist/utils/polyfills.js +24 -0
  49. package/package.json +5 -6
  50. package/dist/monitors/httpDataBundler.d.ts +0 -161
  51. package/dist/monitors/requestMonitor.d.ts +0 -10
  52. package/dist/pageVisit/pageVisitEventHTTP.d.ts +0 -18
  53. package/dist/types/PageVisit.d.ts +0 -22
  54. package/dist/types/globals.d.ts +0 -45
  55. /package/dist/{api → src/api}/helpCode.d.ts +0 -0
  56. /package/dist/{api → src/api}/inputManager.d.ts +0 -0
  57. /package/dist/{api → src/api}/storedMetrics.d.ts +0 -0
  58. /package/dist/{api → src/api}/storedPageVisit.d.ts +0 -0
  59. /package/dist/{const_matchers.d.ts → src/const_matchers.d.ts} +0 -0
  60. /package/dist/{entry → src/entry}/index.d.ts +0 -0
  61. /package/dist/{monitors → src/monitors}/appNavigationMonitor.d.ts +0 -0
  62. /package/dist/{monitors → src/monitors}/errorMonitor.d.ts +0 -0
  63. /package/dist/{monitors → src/monitors}/inputMonitor.d.ts +0 -0
  64. /package/dist/{monitors → src/monitors}/integrations/react-native-navigation-integration.d.ts +0 -0
  65. /package/dist/{monitors → src/monitors}/keyboardInputMonitor.d.ts +0 -0
  66. /package/dist/{monitors → src/monitors}/pageMonitor.d.ts +0 -0
  67. /package/dist/{pageVisit → src/pageVisit}/pageVisit.d.ts +0 -0
  68. /package/dist/{pageVisit → src/pageVisit}/pageVisitEventError.d.ts +0 -0
  69. /package/dist/{pageVisit → src/pageVisit}/userStep.d.ts +0 -0
  70. /package/dist/{react → src/react}/ErrorBoundary.d.ts +0 -0
  71. /package/dist/{sessionRecorder → src/sessionRecorder}/nativeSessionRecorderSubscription.d.ts +0 -0
  72. /package/dist/{sessionRecorder → src/sessionRecorder}/sessionRecorder.d.ts +0 -0
  73. /package/dist/{storage → src/storage}/rnStorageProvider.d.ts +0 -0
  74. /package/dist/{utils → src/utils}/date.d.ts +0 -0
  75. /package/dist/{utils → src/utils}/eventlistener.d.ts +0 -0
  76. /package/dist/{utils → src/utils}/log.d.ts +0 -0
  77. /package/dist/{utils → src/utils}/performance.d.ts +0 -0
  78. /package/dist/{utils → src/utils}/stacktrace-parser.d.ts +0 -0
@@ -0,0 +1,151 @@
1
+ import { CLICK_EVENT_TYPE, CSS_CLASS_ATT_NAME, CUSTOM_ERROR_EVENT_TYPE, ERROR_EVENT_ERROR_TYPE, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, ERROR_LOG_EVENT_ERROR_TYPE, ERROR_SOURCE_ATT_NAME, FETCH_EXCEPTION_ERROR_TYPE, GLOBAL_REASSIGN_ERROR_TYPE, GQL_COLUMN_ATT_NAME, GQL_ERROR_ATT_NAME, GQL_ERROR_TYPE, GQL_EXTENSIONS_ATT_NAME, GQL_LINE_ATT_NAME, GQL_LOCATIONS_ATT_NAME, GQL_MESSAGE_ATT_NAME, GQL_PATH_ATT_NAME, GQL_SRC_ATT_NAME, HTMLID_ATT_NAME, HTTP_CODE_ATT_NAME, HTTP_DATA_PAYLOAD_ATT_NAME, HTTP_DATA_REQ_HEADERS_ATT_NAME, HTTP_DATA_RESP_HEADERS_ATT_NAME, HTTP_DATA_RESP_PAYLOAD_ATT_NAME, HTTP_METHOD_ATT_NAME, HTTP_RESP_CODE_ATT_NAME, HTTP_RESP_LENGTH_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, IMAGE_ERROR_TYPE, JS_ERROR_ATT_NAME, JS_STACK_CAUSE_ATT_NAME, JS_STACK_COL_ATT_NAME, JS_STACK_FILE_ATT_NAME, JS_STACK_FRAMES_ATT_NAME, JS_STACK_LINE_ATT_NAME, JS_STACK_MESSAGE_ATT_NAME, JS_STACK_METHOD_ATT_NAME, KEYBOARD_EVENT_TYPE, PAGE_CHECK_ERROR_ATT_NAME, PAGE_CHECK_ERROR_TYPE, PV_SEQ_ATT_NAME, RESOURCE_ERROR_ATT_NAME, RESPONSE_ERROR_TYPE, SOURCE_ATT_NAME, TAGNAME_ATT_NAME, TEXT_ATT_NAME, TYPE_ATT_NAME, URL_ATT_NAME, WRAPPED_EXCEPTION_ERROR_TYPE } from '../src/constants';
2
+ export type PVEventHTTP = {
3
+ [HTTP_METHOD_ATT_NAME]: string;
4
+ [HTTP_RESP_CODE_ATT_NAME]: number;
5
+ [URL_ATT_NAME]: string;
6
+ [HTTP_RESP_TIME_ATT_NAME]: number;
7
+ [HTTP_RESP_LENGTH_ATT_NAME]?: number;
8
+ [PV_SEQ_ATT_NAME]?: number;
9
+ };
10
+ export type HTTPDataBundle = {
11
+ [HTTP_DATA_REQ_HEADERS_ATT_NAME]: Record<string, string>;
12
+ [HTTP_DATA_PAYLOAD_ATT_NAME]: string;
13
+ [HTTP_DATA_RESP_HEADERS_ATT_NAME]: Record<string, string>;
14
+ [HTTP_DATA_RESP_PAYLOAD_ATT_NAME]: string;
15
+ };
16
+ export interface UserInputMonitorPayload {
17
+ [SOURCE_ATT_NAME]: string;
18
+ [TEXT_ATT_NAME]: string;
19
+ [TAGNAME_ATT_NAME]: string;
20
+ [HTMLID_ATT_NAME]: string;
21
+ [TYPE_ATT_NAME]: string;
22
+ [CSS_CLASS_ATT_NAME]: string;
23
+ }
24
+ export interface ClickMonitorPayload extends UserInputMonitorPayload {
25
+ [SOURCE_ATT_NAME]: string;
26
+ [TEXT_ATT_NAME]: string;
27
+ [TAGNAME_ATT_NAME]: string;
28
+ [HTMLID_ATT_NAME]: string;
29
+ [TYPE_ATT_NAME]: typeof CLICK_EVENT_TYPE;
30
+ [CSS_CLASS_ATT_NAME]: string;
31
+ }
32
+ export interface KeyboardMonitorPayload extends UserInputMonitorPayload {
33
+ [SOURCE_ATT_NAME]: string;
34
+ [TEXT_ATT_NAME]: string;
35
+ [TAGNAME_ATT_NAME]: string;
36
+ [HTMLID_ATT_NAME]: string;
37
+ [TYPE_ATT_NAME]: typeof KEYBOARD_EVENT_TYPE;
38
+ [CSS_CLASS_ATT_NAME]: string;
39
+ }
40
+ export type JSErrorOutputMessage = {
41
+ [JS_STACK_MESSAGE_ATT_NAME]: string;
42
+ [JS_STACK_FRAMES_ATT_NAME]: {
43
+ [JS_STACK_FILE_ATT_NAME]: string;
44
+ [JS_STACK_LINE_ATT_NAME]: string;
45
+ [JS_STACK_METHOD_ATT_NAME]: string;
46
+ [JS_STACK_COL_ATT_NAME]?: number;
47
+ }[];
48
+ [JS_STACK_CAUSE_ATT_NAME]?: UserInputMonitorPayload[];
49
+ };
50
+ /**
51
+ * Helper class to improve typing in methods that use anonymous classes: Keyboard and Click monitors
52
+ */
53
+ export interface UserInputEventMonitor {
54
+ isValid(event: Event): boolean;
55
+ getPayload(event: Event): UserInputMonitorPayload;
56
+ }
57
+ export declare namespace PVError {
58
+ export interface Input {
59
+ [ERROR_EVENT_ERROR_TYPE]: EventInput;
60
+ [ERROR_EVENT_UNHANDLED_REJECTION_TYPE]: EventInput;
61
+ [RESPONSE_ERROR_TYPE]: ResponseInput;
62
+ [GQL_ERROR_TYPE]: GqlInput;
63
+ [IMAGE_ERROR_TYPE]: ResourceInput;
64
+ [PAGE_CHECK_ERROR_TYPE]: PageCheckInput;
65
+ [WRAPPED_EXCEPTION_ERROR_TYPE]: EventInput;
66
+ [FETCH_EXCEPTION_ERROR_TYPE]: EventInput;
67
+ [ERROR_LOG_EVENT_ERROR_TYPE]: JErrorObject;
68
+ [CUSTOM_ERROR_EVENT_TYPE]: EventInput;
69
+ [GLOBAL_REASSIGN_ERROR_TYPE]: GlobalReassignInput;
70
+ }
71
+ export interface Output {
72
+ [ERROR_EVENT_ERROR_TYPE]: Event;
73
+ [ERROR_EVENT_UNHANDLED_REJECTION_TYPE]: Event;
74
+ [RESPONSE_ERROR_TYPE]: Http;
75
+ [GQL_ERROR_TYPE]: Gql;
76
+ [IMAGE_ERROR_TYPE]: Image;
77
+ [PAGE_CHECK_ERROR_TYPE]: PageCheck;
78
+ [WRAPPED_EXCEPTION_ERROR_TYPE]: Event;
79
+ [FETCH_EXCEPTION_ERROR_TYPE]: Event;
80
+ [ERROR_LOG_EVENT_ERROR_TYPE]: Log;
81
+ [CUSTOM_ERROR_EVENT_TYPE]: Event;
82
+ [GLOBAL_REASSIGN_ERROR_TYPE]: Event;
83
+ }
84
+ export type ResourceInput = {
85
+ tag_name: string;
86
+ id?: string;
87
+ src: string;
88
+ detail: string;
89
+ };
90
+ export type PageCheckInput = {
91
+ checkId: string;
92
+ version?: string;
93
+ triggerId?: string;
94
+ assertionId?: string;
95
+ log: string[];
96
+ };
97
+ export type GqlInput = {
98
+ [GQL_SRC_ATT_NAME]?: string;
99
+ [GQL_MESSAGE_ATT_NAME]: string;
100
+ [GQL_LOCATIONS_ATT_NAME]?: {
101
+ [GQL_LINE_ATT_NAME]: number;
102
+ [GQL_COLUMN_ATT_NAME]: number;
103
+ }[];
104
+ [GQL_PATH_ATT_NAME]?: string[];
105
+ [GQL_EXTENSIONS_ATT_NAME]?: string;
106
+ };
107
+ export type ResponseInput = Pick<Response, 'status' | 'url'>;
108
+ export type JErrWithCause = Partial<{
109
+ cause: UserInputMonitorPayload[];
110
+ }>;
111
+ export type JErrWithStack = Error & JErrWithCause;
112
+ export type JErrWithFilename = {
113
+ fileName: string;
114
+ lineNumber: string;
115
+ columnNumber: number;
116
+ } & JErrWithCause;
117
+ export type JErrorObject = JErrWithFilename | JErrWithStack;
118
+ export type EventInput = {
119
+ filename?: string;
120
+ error: JErrorObject;
121
+ };
122
+ export type GlobalReassignInput = {
123
+ error: Error;
124
+ };
125
+ interface Base {
126
+ [TYPE_ATT_NAME]: string;
127
+ [URL_ATT_NAME]: string;
128
+ [ERROR_SOURCE_ATT_NAME]?: keyof Input;
129
+ }
130
+ export interface Http extends Base {
131
+ [HTTP_CODE_ATT_NAME]: number;
132
+ [PV_SEQ_ATT_NAME]?: number;
133
+ }
134
+ export interface Event extends Base {
135
+ [JS_ERROR_ATT_NAME]: JSErrorOutputMessage;
136
+ }
137
+ export interface Gql extends Base {
138
+ [GQL_ERROR_ATT_NAME]: GqlInput;
139
+ [PV_SEQ_ATT_NAME]?: number;
140
+ }
141
+ export interface Log extends Base {
142
+ [JS_ERROR_ATT_NAME]: JSErrorOutputMessage;
143
+ }
144
+ export interface PageCheck extends Base {
145
+ [PAGE_CHECK_ERROR_ATT_NAME]: PageCheckInput;
146
+ }
147
+ export interface Image extends Base {
148
+ [RESOURCE_ERROR_ATT_NAME]: ResourceInput;
149
+ }
150
+ export {};
151
+ }
@@ -0,0 +1,27 @@
1
+ import { BROWSER_ID_ATT_NAME, COLLECT_VER_ATT_NAME, CURRENT_METRICS_VERSION, CURRENT_NOIBUJS_VERSION, CUSTOM_ATTRIBUTE_FAIL_COUNT_ATT_NAME, CUSTOM_ATTRIBUTE_KEY_COUNT_ATT_NAME, CUSTOM_ATTRIBUTE_TOTAL_COUNT_ATT_NAME, DID_CUT_PV_ATT_NAME, DID_CUT_VID_ATT_NAME, DID_START_VID_ATT_NAME, ERR_COUNT_EXPECTED_ATT_NAME, OTHER_METRICS_ATT_NAME, EXP_VIDEO_LENGTH_ATT_NAME, HTTP_COUNT_EXPECTED_ATT_NAME, ON_URL_ATT_NAME, PV_CLICKS_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, VER_ATT_NAME, VIDEO_CLICKS_ATT_NAME, OTHER_METRICS_KEYS } from '../src/constants';
2
+ export interface PageVisitMetrics {
3
+ [BROWSER_ID_ATT_NAME]: null | string;
4
+ [PV_ID_ATT_NAME]: string;
5
+ [COLLECT_VER_ATT_NAME]: typeof CURRENT_NOIBUJS_VERSION;
6
+ [VER_ATT_NAME]: typeof CURRENT_METRICS_VERSION;
7
+ [EXP_VIDEO_LENGTH_ATT_NAME]: number;
8
+ [PV_EXP_VF_SEQ_ATT_NAME]: number;
9
+ [PV_EXP_PART_COUNTER_ATT_NAME]: number;
10
+ [PV_EXP_HTTP_DATA_SEQ_ATT_NAME]: number;
11
+ [PV_HTTP_PAYLOADS_COLLECTED_ATT_NAME]: number;
12
+ [PV_HTTP_PAYLOADS_DROPPED_OVERSIZE_ATT_NAME]: number;
13
+ [PV_HTTP_PAYLOADS_DROPPED_TYPE_ATT_NAME]: number;
14
+ [PV_HTTP_REQUESTS_DROPPED_OVER_LIMIT]: number;
15
+ [VIDEO_CLICKS_ATT_NAME]: number;
16
+ [PV_CLICKS_ATT_NAME]: number;
17
+ [DID_CUT_PV_ATT_NAME]: boolean;
18
+ [DID_CUT_VID_ATT_NAME]: boolean;
19
+ [DID_START_VID_ATT_NAME]: boolean;
20
+ [HTTP_COUNT_EXPECTED_ATT_NAME]: number;
21
+ [ERR_COUNT_EXPECTED_ATT_NAME]: number;
22
+ [ON_URL_ATT_NAME]: string;
23
+ [CUSTOM_ATTRIBUTE_TOTAL_COUNT_ATT_NAME]: number;
24
+ [CUSTOM_ATTRIBUTE_FAIL_COUNT_ATT_NAME]: number;
25
+ [CUSTOM_ATTRIBUTE_KEY_COUNT_ATT_NAME]: number;
26
+ [OTHER_METRICS_ATT_NAME]?: Partial<Record<ValueOf<typeof OTHER_METRICS_KEYS>, number>>;
27
+ }
@@ -0,0 +1,48 @@
1
+ export declare const enum EventType {
2
+ DomContentLoaded = 0,
3
+ Load = 1,
4
+ FullSnapshot = 2,
5
+ IncrementalSnapshot = 3,
6
+ Meta = 4,
7
+ Custom = 5,
8
+ Plugin = 6
9
+ }
10
+ export declare const enum NodeType {
11
+ Document = 0,
12
+ DocumentType = 1,
13
+ Element = 2,
14
+ Text = 3,
15
+ CDATA = 4,
16
+ Comment = 5
17
+ }
18
+ export declare const enum IncrementalSource {
19
+ Mutation = 0,
20
+ MouseMove = 1,
21
+ MouseInteraction = 2,
22
+ Scroll = 3,
23
+ ViewportResize = 4,
24
+ Input = 5,
25
+ TouchMove = 6,
26
+ MediaInteraction = 7,
27
+ StyleSheetRule = 8,
28
+ CanvasMutation = 9,
29
+ Font = 10,
30
+ Log = 11,
31
+ Drag = 12,
32
+ StyleDeclaration = 13,
33
+ Selection = 14,
34
+ AdoptedStyleSheet = 15
35
+ }
36
+ export declare const enum MouseInteractions {
37
+ MouseUp = 0,
38
+ MouseDown = 1,
39
+ Click = 2,
40
+ ContextMenu = 3,
41
+ DblClick = 4,
42
+ Focus = 5,
43
+ Blur = 6,
44
+ TouchStart = 7,
45
+ TouchMove_Departed = 8,
46
+ TouchEnd = 9,
47
+ TouchCancel = 10
48
+ }
@@ -1,4 +1,4 @@
1
- import { BROWSER_ID_ATT_NAME, COLLECT_VER_ATT_NAME, CONN_COUNT_ATT_NAME, CSS_URLS_ATT_NAME, END_AT_ATT_NAME, IS_LAST_ATT_NAME, LANG_ATT_NAME, LENGTH_ATT_NAME, METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME, ON_URL_ATT_NAME, PAGE_GROUPS_ATT_NAME, PAGE_TITLE_ATT_NAME, PAGE_VISIT_INFORMATION_ATT_NAME, PAGE_VISIT_PART_ATT_NAME, PAGE_VISIT_VID_FRAG_ATT_NAME, PV_EVENTS_ATT_NAME, PV_EXP_PART_COUNTER_ATT_NAME, PV_EXP_VF_SEQ_ATT_NAME, PV_ID_ATT_NAME, PV_PART_COUNTER_ATT_NAME, PV_SEQ_ATT_NAME, REF_URL_ATT_NAME, SCRIPT_ID_ATT_NAME, SCRIPT_INSTANCE_ID_ATT_NAME, SEQ_NUM_ATT_NAME, SOCKET_INSTANCE_ID_ATT_NAME, STARTED_AT_ATT_NAME, VIDEO_FRAG_ATT_NAME, VIDEO_METROPLEX_TYPE } from '../constants';
1
+ import { BROWSER_ID_ATT_NAME, COLLECT_VER_ATT_NAME, CONN_COUNT_ATT_NAME, CSS_URLS_ATT_NAME, END_AT_ATT_NAME, IS_LAST_ATT_NAME, LANG_ATT_NAME, LENGTH_ATT_NAME, METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME, ON_URL_ATT_NAME, PAGE_GROUPS_ATT_NAME, PAGE_TITLE_ATT_NAME, PAGE_VISIT_INFORMATION_ATT_NAME, PAGE_VISIT_PART_ATT_NAME, PAGE_VISIT_VID_FRAG_ATT_NAME, PV_EVENTS_ATT_NAME, PV_EXP_PART_COUNTER_ATT_NAME, PV_EXP_VF_SEQ_ATT_NAME, PV_ID_ATT_NAME, PV_PART_COUNTER_ATT_NAME, PV_SEQ_ATT_NAME, REF_URL_ATT_NAME, SCRIPT_ID_ATT_NAME, SCRIPT_INSTANCE_ID_ATT_NAME, SEQ_NUM_ATT_NAME, SOCKET_INSTANCE_ID_ATT_NAME, STARTED_AT_ATT_NAME, VIDEO_FRAG_ATT_NAME, VIDEO_METROPLEX_TYPE, VIDEO_RECORDER_ATT_NAME } from '../src/constants';
2
2
  export interface PageVisitPart {
3
3
  [PV_PART_COUNTER_ATT_NAME]: number;
4
4
  [END_AT_ATT_NAME]: number;
@@ -25,6 +25,7 @@ export interface PageVisitInfo {
25
25
  [STARTED_AT_ATT_NAME]: string;
26
26
  [COLLECT_VER_ATT_NAME]: number;
27
27
  [LANG_ATT_NAME]?: string;
28
+ [VIDEO_RECORDER_ATT_NAME]: string;
28
29
  }
29
30
  export interface PageVisitPartsBase {
30
31
  pageVisitInfo: PageVisitInfo;
@@ -44,9 +45,6 @@ export interface VideoFrag {
44
45
  [SEQ_NUM_ATT_NAME]: number;
45
46
  [CSS_URLS_ATT_NAME]: string[];
46
47
  }
47
- export interface VideoMetroplexMessage {
48
- [PAGE_VISIT_VID_FRAG_ATT_NAME]: VideoFrag;
49
- }
50
48
  export interface CompletePageVisitParts {
51
49
  [PAGE_VISIT_VID_FRAG_ATT_NAME]: Array<VideoFrag>;
52
50
  [PAGE_VISIT_INFORMATION_ATT_NAME]: PageVisitInfo;
@@ -0,0 +1,6 @@
1
+ export interface WrappedXMLHttpRequest extends XMLHttpRequest, Partial<{
2
+ noibuRequestHeaders: Map<string, string>;
3
+ noibuHttpMethod: string;
4
+ noibuHttpUrl: string;
5
+ }> {
6
+ }
@@ -1,6 +1,7 @@
1
+ import { __awaiter } from 'tslib';
1
2
  import { Platform } from 'react-native';
2
3
  import { parseStack } from './stacktrace-parser.js';
3
- import { MAX_STRING_LENGTH, MAX_BEACON_PAYLOAD_SIZE, REQUIRED_DATA_PROCESSING_URLS, PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING, PII_DIGIT_PATTERN, DEFAULT_STACK_FRAME_FIELD_VALUE } from '../constants.js';
4
+ import { MAX_STRING_LENGTH, MAX_BEACON_PAYLOAD_SIZE, REQUIRED_DATA_PROCESSING_URLS, PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING, PII_DIGIT_PATTERN, JS_STACK_LINE_ATT_NAME, DEFAULT_STACK_FRAME_FIELD_VALUE, JS_STACK_METHOD_ATT_NAME, JS_STACK_FILE_ATT_NAME } from '../constants.js';
4
5
  import { noibuLog } from './log.js';
5
6
  import { unwrapNoibuWrapped } from './object.js';
6
7
 
@@ -8,9 +9,9 @@ import { unwrapNoibuWrapped } from './object.js';
8
9
  * Returns a stack trace frame with default filed values
9
10
  */
10
11
  const getDefaultFrame = () => ({
11
- line: DEFAULT_STACK_FRAME_FIELD_VALUE,
12
- mname: DEFAULT_STACK_FRAME_FIELD_VALUE,
13
- file: DEFAULT_STACK_FRAME_FIELD_VALUE,
12
+ [JS_STACK_LINE_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
13
+ [JS_STACK_METHOD_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
14
+ [JS_STACK_FILE_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
14
15
  });
15
16
  /**
16
17
  * returns a string that satisfies a max length
@@ -60,13 +61,7 @@ function processFrames(rawFrames) {
60
61
  * @param errObj error to extract stack from
61
62
  */
62
63
  function getJSStack(errObj) {
63
- let frames = [
64
- {
65
- line: DEFAULT_STACK_FRAME_FIELD_VALUE,
66
- mname: DEFAULT_STACK_FRAME_FIELD_VALUE,
67
- file: DEFAULT_STACK_FRAME_FIELD_VALUE,
68
- },
69
- ];
64
+ let frames = [getDefaultFrame()];
70
65
  // if the errObj type is not an object or null
71
66
  // return a default frame
72
67
  if (typeof errObj !== 'object' || !errObj || !errObj.stack) {
@@ -85,10 +80,9 @@ function getJSStack(errObj) {
85
80
  /**
86
81
  * Checks if possiblyStacktrace has any stack frames present
87
82
  */
88
- function isStackTrace(possiblyStacktrace) {
83
+ function isStackTrace(_possiblyStacktrace) {
89
84
  try {
90
- // todo disable temporary
91
- // return parseStack(possiblyStacktrace).length > 0;
85
+ // todo implement for react native
92
86
  return false;
93
87
  }
94
88
  catch (e) {
@@ -126,52 +120,54 @@ function stringifyJSON(jsonObject) {
126
120
  * @param timeout
127
121
  * @param sendAndForget
128
122
  */
129
- async function makeRequest(method, url, data, headers, timeout, sendAndForget) {
130
- const ua = Object.keys(headers).findLast(k => k.toLowerCase() === 'user-agent');
131
- const headersWithUa = { ...headers };
132
- if (!headers[ua]) {
133
- headersWithUa['User-Agent'] = await getUserAgent();
134
- }
135
- // a send-and-forget request is made by using the beacon API (fetch + keepalive)
136
- if (sendAndForget) {
137
- const stringData = stringifyJSON(data);
138
- const currentPayloadSize = new Blob([stringData]).size;
139
- // if we have a large object or fetch is not available, we skip sending the message
140
- if (currentPayloadSize > MAX_BEACON_PAYLOAD_SIZE) {
141
- return Promise.resolve();
123
+ function makeRequest(method, url, data, headers, timeout, sendAndForget) {
124
+ return __awaiter(this, void 0, void 0, function* () {
125
+ const ua = Object.keys(headers).findLast(k => k.toLowerCase() === 'user-agent');
126
+ const headersWithUa = Object.assign({}, headers);
127
+ if (!headers[ua]) {
128
+ headersWithUa['User-Agent'] = yield getUserAgent();
142
129
  }
143
- return unwrapNoibuWrapped(fetch)(url, {
144
- method: 'POST',
145
- headers: headersWithUa,
146
- body: stringifyJSON(data),
147
- // keep alive outlives the current page, its the same as beacon
148
- keepalive: true,
149
- });
150
- }
151
- return new Promise((resolve, reject) => {
152
- const xhr = new XMLHttpRequest();
153
- xhr.open(method, url);
154
- xhr.timeout = timeout;
155
- Object.keys(headersWithUa).forEach(header => {
156
- xhr.setRequestHeader(header, headers[header]);
157
- });
158
- xhr.onload = () => {
159
- if (xhr.status >= 200 && xhr.status < 300) {
160
- resolve(xhr.response);
130
+ // a send-and-forget request is made by using the beacon API (fetch + keepalive)
131
+ if (sendAndForget) {
132
+ const stringData = stringifyJSON(data);
133
+ const currentPayloadSize = new Blob([stringData]).size;
134
+ // if we have a large object or fetch is not available, we skip sending the message
135
+ if (currentPayloadSize > MAX_BEACON_PAYLOAD_SIZE) {
136
+ return Promise.resolve();
161
137
  }
162
- else {
138
+ return unwrapNoibuWrapped(fetch)(url, {
139
+ method: 'POST',
140
+ headers: headersWithUa,
141
+ body: stringifyJSON(data),
142
+ // keep alive outlives the current page, its the same as beacon
143
+ keepalive: true,
144
+ });
145
+ }
146
+ return new Promise((resolve, reject) => {
147
+ const xhr = new XMLHttpRequest();
148
+ xhr.open(method, url);
149
+ xhr.timeout = timeout;
150
+ Object.keys(headersWithUa).forEach(header => {
151
+ xhr.setRequestHeader(header, headers[header]);
152
+ });
153
+ xhr.onload = () => {
154
+ if (xhr.status >= 200 && xhr.status < 300) {
155
+ resolve(xhr.response);
156
+ }
157
+ else {
158
+ reject(new Error(`Custom Request failed: ${xhr.statusText}`));
159
+ }
160
+ };
161
+ xhr.onerror = () => {
163
162
  reject(new Error(`Custom Request failed: ${xhr.statusText}`));
163
+ };
164
+ if (data) {
165
+ xhr.send(stringifyJSON(data));
164
166
  }
165
- };
166
- xhr.onerror = () => {
167
- reject(new Error(`Custom Request failed: ${xhr.statusText}`));
168
- };
169
- if (data) {
170
- xhr.send(stringifyJSON(data));
171
- }
172
- else {
173
- xhr.send();
174
- }
167
+ else {
168
+ xhr.send();
169
+ }
170
+ });
175
171
  });
176
172
  }
177
173
  /**
@@ -190,20 +186,22 @@ let userAgentCache = '';
190
186
  * Fakes the user agent retrieval, since there are no good libraries that support both expo and plain RN
191
187
  * caches the result for the session
192
188
  */
193
- async function getUserAgent() {
194
- if (userAgentCache) {
189
+ function getUserAgent() {
190
+ return __awaiter(this, void 0, void 0, function* () {
191
+ if (userAgentCache) {
192
+ return userAgentCache;
193
+ }
194
+ noibuLog('getUserAgent start');
195
+ if (Platform.OS === 'android') {
196
+ const { Brand, Model, Release } = Platform.constants;
197
+ userAgentCache = `Mozilla/5.0 (Linux; Android ${Release}; ${Brand} ${Model}; React Native ${Platform.Version}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36`;
198
+ }
199
+ else if (Platform.OS === 'ios') {
200
+ userAgentCache = `Mozilla/5.0 (iPhone; CPU iPhone OS ${Platform.constants.osVersion} like Mac OS X; React Native ${Platform.Version}) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1`;
201
+ }
202
+ noibuLog('getUserAgent end', { userAgentCache });
195
203
  return userAgentCache;
196
- }
197
- noibuLog('getUserAgent start');
198
- if (Platform.OS === 'android') {
199
- const { Brand, Model, Release } = Platform.constants;
200
- userAgentCache = `Mozilla/5.0 (Linux; Android ${Release}; ${Brand} ${Model}; React Native ${Platform.Version}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36`;
201
- }
202
- else if (Platform.OS === 'ios') {
203
- userAgentCache = `Mozilla/5.0 (iPhone; CPU iPhone OS ${Platform.constants.osVersion} like Mac OS X; React Native ${Platform.Version}) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1`;
204
- }
205
- noibuLog('getUserAgent end', { userAgentCache });
206
- return userAgentCache;
204
+ });
207
205
  }
208
206
  /**
209
207
  * isInvalidURLConfig will verify that Collect is being initializes with
@@ -272,14 +270,50 @@ function isInstanceOf(instance, type) {
272
270
  /**
273
271
  * To grab the video recorder type based on the device we run the app on.
274
272
  */
275
- async function getVideoRecorderType() {
276
- if (Platform.OS === 'android') {
277
- return 'AndroidNative';
273
+ function getVideoRecorderType() {
274
+ return __awaiter(this, void 0, void 0, function* () {
275
+ if (Platform.OS === 'android') {
276
+ return 'AndroidNative';
277
+ }
278
+ if (Platform.OS === 'ios') {
279
+ return 'IOSNative';
280
+ }
281
+ return '';
282
+ });
283
+ }
284
+ /** String.trim, but safe */
285
+ function safeTrim(text) {
286
+ if (typeof text !== 'string') {
287
+ return '';
278
288
  }
279
- if (Platform.OS === 'ios') {
280
- return 'IOSNative';
289
+ return text.trim();
290
+ }
291
+ /**
292
+ * Tries to get the stack trace from the given error object and returns it.
293
+ * If the error object does not have a stack trace, an empty string is returned.
294
+ *
295
+ * @param {Error} error - The error object from which to retrieve the stack trace.
296
+ * @returns {string} The stack trace of the error, if available. Otherwise, an empty string is returned.
297
+ */
298
+ function tryGetStackTrace(error) {
299
+ let result = '';
300
+ try {
301
+ if (error && error.stack) {
302
+ result = `(stack: ${error.stack})`;
303
+ }
281
304
  }
282
- return '';
305
+ catch (_a) {
306
+ // non-standard property - that's fine
307
+ }
308
+ return result;
309
+ }
310
+ /**
311
+ * Checks whether the given value is a string or an instance of String.
312
+ * @param {*} value - The value to be checked.
313
+ * @returns {boolean} Returns true if the value is a string or an instance of String, otherwise returns false.
314
+ */
315
+ function isString(value) {
316
+ return typeof value === 'string' || value instanceof String;
283
317
  }
284
318
 
285
- export { asString, getJSStack, getMaxSubstringAllowed, getUserAgent, getVideoRecorderType, isInstanceOf, isInvalidURLConfig, isNoibuJSAlreadyLoaded, isStackTrace, isValidURL, makeRequest, maskTextInput, processFrames, stringifyJSON };
319
+ export { asString, getJSStack, getMaxSubstringAllowed, getUserAgent, getVideoRecorderType, isInstanceOf, isInvalidURLConfig, isNoibuJSAlreadyLoaded, isStackTrace, isString, isValidURL, makeRequest, maskTextInput, processFrames, safeTrim, stringifyJSON, tryGetStackTrace };
@@ -51,9 +51,7 @@ function unwrapNoibuWrapped(anything) {
51
51
  * Checks whether the prototype's property is writeable. If it is not,
52
52
  * checks whether the property can be made writeable. If it can, it is
53
53
  * set to writeable.
54
- * @param {object} proto
55
- * @param {string} property
56
- * @returns {boolean} Whether the property on the prototype is (or is now) writeable
54
+ * returns Whether the property on the prototype is (or is now) writeable
57
55
  */
58
56
  const propWriteableOrMadeWriteable = (proto, property) => {
59
57
  if (!proto ||
@@ -65,9 +63,9 @@ const propWriteableOrMadeWriteable = (proto, property) => {
65
63
  // has under the open property
66
64
  const propDescriptor = Object.getOwnPropertyDescriptor(proto, property);
67
65
  // Checking if the open property is read-only
68
- if (!propDescriptor?.writable) {
66
+ if (!(propDescriptor === null || propDescriptor === void 0 ? void 0 : propDescriptor.writable)) {
69
67
  // Checking if we can write to it
70
- if (propDescriptor?.configurable) {
68
+ if (propDescriptor === null || propDescriptor === void 0 ? void 0 : propDescriptor.configurable) {
71
69
  // Making it writable to wrap it
72
70
  Object.defineProperty(proto, property, {
73
71
  writable: true,
@@ -117,5 +115,59 @@ const iterateObjectRecursively = (instance, visit, limit = { depth: 5 }) => {
117
115
  };
118
116
  iterate(instance, 1);
119
117
  };
118
+ const safeEntries = (obj) => {
119
+ const collection = [];
120
+ if (!obj) {
121
+ return collection;
122
+ }
123
+ if (obj instanceof Headers) {
124
+ obj.forEach((value, key) => {
125
+ collection.push([key, value]);
126
+ });
127
+ }
128
+ else if (typeof obj === 'object') {
129
+ collection.push(...Object.entries(obj));
130
+ }
131
+ return collection;
132
+ };
133
+ /**
134
+ * Determines if the given instance is iterable.
135
+ * An object is considered iterable if it has a method whose key is `Symbol.iterator`.
136
+ * This method checks if `instance[Symbol.iterator]` is a function, and if so, returns `true`.
137
+ * If `instance` is `null` or `undefined`, or if accessing `instance[Symbol.iterator]` throws an error,
138
+ * this method returns `false`.
139
+ */
140
+ function isIterable(instance) {
141
+ if (!instance) {
142
+ return false;
143
+ }
144
+ try {
145
+ return typeof instance[Symbol.iterator] === 'function';
146
+ }
147
+ catch (e) {
148
+ return false;
149
+ }
150
+ }
151
+ /**
152
+ * Replaces the behaviour of Object.fromEntries() as it is not supported on all browsers
153
+ * @param {Iterable} entries The iterable to parse into an object
154
+ * @returns An object containing the same key/values as the iterable passed
155
+ */
156
+ const safeFromEntries = (entries) => {
157
+ if (!isIterable(entries)) {
158
+ return {};
159
+ }
160
+ const obj = {};
161
+ try {
162
+ // eslint-disable-next-line no-restricted-syntax
163
+ for (const [key, value] of entries) {
164
+ obj[key] = value;
165
+ }
166
+ }
167
+ catch (e) {
168
+ // noting we can do - give up
169
+ }
170
+ return obj;
171
+ };
120
172
 
121
- export { iterateObjectRecursively, propWriteableOrMadeWriteable, replace, unwrapNoibuWrapped };
173
+ export { iterateObjectRecursively, propWriteableOrMadeWriteable, replace, safeEntries, safeFromEntries, unwrapNoibuWrapped };
@@ -0,0 +1,98 @@
1
+ import { iterateObjectRecursively } from './object.js';
2
+ import { HTTP_PII_BLOCKING_PATTERNS, PII_REDACTION_REPLACEMENT_STRING } from '../constants.js';
3
+ import { stringifyJSON } from './function.js';
4
+
5
+ const fuzzyFieldsToRedact = [
6
+ 'password',
7
+ 'address',
8
+ 'credit',
9
+ 'postal',
10
+ 'token',
11
+ 'phone',
12
+ 'mobile',
13
+ 'expiry',
14
+ 'account',
15
+ 'email',
16
+ ];
17
+ const exactFieldsToRedact = [
18
+ 'firstname',
19
+ 'lastname',
20
+ 'street',
21
+ 'fullname',
22
+ 'creditcard',
23
+ 'postcode',
24
+ 'zipcode',
25
+ 'city',
26
+ 'town',
27
+ 'county',
28
+ 'cc',
29
+ 'cardtype',
30
+ 'cardnumber',
31
+ 'email',
32
+ ];
33
+ /**
34
+ * Redacts one string, returns redacted value or false if nothing to redact
35
+ */
36
+ function shouldRedact(field) {
37
+ // check for exact and fuzzy matches
38
+ return (exactFieldsToRedact.some(v => field === v) ||
39
+ fuzzyFieldsToRedact.some(v => field.indexOf(v) >= 0));
40
+ }
41
+ /**
42
+ * Try to parse content as a JSON object and
43
+ * iterate it recursively removing PII.
44
+ * Returns original content if nothing was changes or error is thrown.
45
+ * @param {String} content
46
+ */
47
+ function tryParseObjectAndRemovePII(content) {
48
+ const first = content[0];
49
+ const isParsable = first === '{' || first === '[';
50
+ if (!isParsable) {
51
+ return content;
52
+ }
53
+ let redacted = false;
54
+ try {
55
+ const instance = JSON.parse(content);
56
+ iterateObjectRecursively(instance, (current, property) => {
57
+ if (typeof property !== 'string') {
58
+ return undefined;
59
+ }
60
+ const propertyLowerCase = property.toLowerCase();
61
+ const shouldRedactField = shouldRedact(propertyLowerCase);
62
+ if (shouldRedactField) {
63
+ redacted = true;
64
+ return PII_REDACTION_REPLACEMENT_STRING;
65
+ }
66
+ return undefined;
67
+ });
68
+ return redacted ? stringifyJSON(instance) : content;
69
+ }
70
+ catch (e) {
71
+ return content;
72
+ }
73
+ }
74
+ /**
75
+ * Takes a string and redacts any PII we're able to detect
76
+ *
77
+ * content - the string from which we want to redact PII
78
+ * returns the string with any PII we're able to detect redacted.
79
+ */
80
+ function removePII(content) {
81
+ /* eslint-disable no-param-reassign */
82
+ // In order to be fail-safe, let's return null if we won't be able to remove PII.
83
+ if (typeof content !== 'string') {
84
+ return '';
85
+ }
86
+ if (!content.length) {
87
+ return content;
88
+ }
89
+ content = tryParseObjectAndRemovePII(content);
90
+ // Go through each of the PII matching patterns
91
+ HTTP_PII_BLOCKING_PATTERNS.forEach(pattern => {
92
+ // Replace all matches with the appropriate number of asterisks
93
+ content = content.replace(pattern, PII_REDACTION_REPLACEMENT_STRING);
94
+ });
95
+ return content;
96
+ }
97
+
98
+ export { removePII, shouldRedact };