noibu-react-native 0.2.6 → 0.2.8

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 (114) hide show
  1. package/README.md +15 -15
  2. package/android/build.gradle +1 -1
  3. package/dist/{src/api/clientConfig.d.ts → api/ClientConfig.d.ts} +19 -20
  4. package/dist/api/{clientConfig.js → ClientConfig.js} +82 -63
  5. package/dist/{src/api/helpCode.d.ts → api/HelpCode.d.ts} +3 -10
  6. package/dist/api/{helpCode.js → HelpCode.js} +8 -14
  7. package/dist/api/InputManager.d.ts +39 -0
  8. package/dist/api/InputManager.js +156 -0
  9. package/dist/{src/api/metroplexSocket.d.ts → api/MetroplexSocket.d.ts} +33 -38
  10. package/dist/api/{metroplexSocket.js → MetroplexSocket.js} +190 -178
  11. package/dist/{src/api/storedMetrics.d.ts → api/StoredMetrics.d.ts} +10 -20
  12. package/dist/api/StoredMetrics.js +158 -0
  13. package/dist/{src/api/storedPageVisit.d.ts → api/StoredPageVisit.d.ts} +11 -8
  14. package/dist/api/{storedPageVisit.js → StoredPageVisit.js} +62 -48
  15. package/dist/const_matchers.js +1 -5
  16. package/dist/constants.d.ts +48 -0
  17. package/dist/constants.js +15 -397
  18. package/dist/{src/entry → entry}/index.d.ts +5 -6
  19. package/dist/entry/index.js +3 -4
  20. package/dist/entry/init.d.ts +8 -0
  21. package/dist/entry/init.js +34 -19
  22. package/dist/monitors/AppNavigationMonitor.d.ts +10 -0
  23. package/dist/monitors/AppNavigationMonitor.js +19 -19
  24. package/dist/monitors/AppNavigationMonitor.test.d.ts +1 -0
  25. package/dist/{src/monitors → monitors}/BaseMonitor.d.ts +5 -5
  26. package/dist/monitors/BaseMonitor.js +9 -4
  27. package/dist/monitors/BaseMonitor.test.d.ts +1 -0
  28. package/dist/{src/monitors → monitors}/ClickMonitor.d.ts +10 -13
  29. package/dist/monitors/ClickMonitor.js +72 -76
  30. package/dist/monitors/ClickMonitor.test.d.ts +1 -0
  31. package/dist/{src/monitors → monitors}/ErrorMonitor.d.ts +4 -28
  32. package/dist/monitors/ErrorMonitor.js +45 -55
  33. package/dist/{src/monitors → monitors}/KeyboardInputMonitor.d.ts +1 -3
  34. package/dist/monitors/KeyboardInputMonitor.js +13 -11
  35. package/dist/{src/monitors → monitors}/PageMonitor.d.ts +1 -1
  36. package/dist/monitors/PageMonitor.js +25 -2
  37. package/dist/{src/monitors → monitors}/RequestMonitor.d.ts +9 -29
  38. package/dist/monitors/RequestMonitor.js +46 -57
  39. package/dist/monitors/http-tools/GqlErrorValidator.d.ts +35 -0
  40. package/dist/monitors/http-tools/GqlErrorValidator.js +42 -70
  41. package/dist/{src/monitors → monitors}/http-tools/HTTPDataBundler.d.ts +9 -15
  42. package/dist/monitors/http-tools/HTTPDataBundler.js +74 -67
  43. package/dist/monitors/integrations/ReactNativeNavigationIntegration.d.ts +17 -0
  44. package/dist/monitors/integrations/{react-native-navigation-integration.js → ReactNativeNavigationIntegration.js} +15 -12
  45. package/dist/{src/pageVisit → pageVisit}/EventDebouncer.d.ts +9 -10
  46. package/dist/pageVisit/EventDebouncer.js +43 -74
  47. package/dist/pageVisit/HttpEventManager.d.ts +14 -0
  48. package/dist/pageVisit/HttpEventManager.js +88 -0
  49. package/dist/pageVisit/PageVisitManager.d.ts +31 -0
  50. package/dist/pageVisit/PageVisitManager.js +99 -0
  51. package/dist/pageVisit/pageVisitEventError.d.ts +12 -0
  52. package/dist/pageVisit/pageVisitEventError.js +170 -280
  53. package/dist/{src/react → react}/ErrorBoundary.d.ts +4 -9
  54. package/dist/react/ErrorBoundary.js +3 -6
  55. package/dist/{src/sessionRecorder/sessionRecorder.d.ts → sessionRecorder/SessionRecorder.d.ts} +7 -17
  56. package/dist/sessionRecorder/{sessionRecorder.js → SessionRecorder.js} +60 -71
  57. package/dist/{src/sessionRecorder → sessionRecorder}/nativeSessionRecorderSubscription.d.ts +4 -6
  58. package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -5
  59. package/dist/{src/storage/rnStorageProvider.d.ts → storage/RNStorageProvider.d.ts} +4 -8
  60. package/dist/storage/{rnStorageProvider.js → RNStorageProvider.js} +3 -7
  61. package/dist/{src/storage/storage.d.ts → storage/Storage.d.ts} +8 -18
  62. package/dist/storage/{storage.js → Storage.js} +17 -30
  63. package/dist/{src/storage/storageProvider.d.ts → storage/StorageProvider.d.ts} +5 -8
  64. package/dist/storage/{storageProvider.js → StorageProvider.js} +7 -8
  65. package/dist/types/NavigationIntegration.d.ts +1 -1
  66. package/dist/utils/date.d.ts +7 -0
  67. package/dist/utils/date.js +41 -51
  68. package/dist/utils/eventlistener.js +6 -14
  69. package/dist/{src/utils → utils}/function.d.ts +13 -43
  70. package/dist/utils/function.js +42 -113
  71. package/dist/utils/log.d.ts +4 -0
  72. package/dist/utils/log.js +2 -4
  73. package/dist/{src/utils → utils}/object.d.ts +10 -8
  74. package/dist/utils/object.js +12 -12
  75. package/dist/{src/utils → utils}/performance.d.ts +1 -1
  76. package/dist/utils/piiRedactor.js +31 -3
  77. package/dist/utils/stacktrace-parser.d.ts +8 -0
  78. package/dist/utils/stacktrace-parser.js +29 -21
  79. package/dist/utils/stacktrace-parser.test.d.ts +1 -0
  80. package/package.json +14 -14
  81. package/dist/api/inputManager.js +0 -227
  82. package/dist/api/storedMetrics.js +0 -198
  83. package/dist/pageVisit/pageVisit.js +0 -181
  84. package/dist/pageVisit/pageVisitEventHTTP.js +0 -98
  85. package/dist/pageVisit/userStep.js +0 -20
  86. package/dist/src/api/inputManager.d.ts +0 -87
  87. package/dist/src/constants.d.ts +0 -290
  88. package/dist/src/entry/init.d.ts +0 -5
  89. package/dist/src/monitors/AppNavigationMonitor.d.ts +0 -18
  90. package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +0 -59
  91. package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +0 -20
  92. package/dist/src/pageVisit/pageVisit.d.ts +0 -52
  93. package/dist/src/pageVisit/pageVisitEventError.d.ts +0 -15
  94. package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +0 -25
  95. package/dist/src/pageVisit/userStep.d.ts +0 -5
  96. package/dist/src/utils/date.d.ts +0 -6
  97. package/dist/src/utils/log.d.ts +0 -4
  98. package/dist/src/utils/stacktrace-parser.d.ts +0 -7
  99. package/dist/types/Config.d.ts +0 -31
  100. package/dist/types/Metroplex.types.d.ts +0 -73
  101. package/dist/types/PageVisit.types.d.ts +0 -8
  102. package/dist/types/PageVisitErrors.types.d.ts +0 -114
  103. package/dist/types/PageVisitEvents.types.d.ts +0 -91
  104. package/dist/types/PageVisitMetrics.types.d.ts +0 -27
  105. package/dist/types/Storage.d.ts +0 -14
  106. package/dist/types/StoredPageVisit.types.d.ts +0 -11
  107. package/dist/types/WrappedObjects.d.ts +0 -6
  108. /package/dist/{src/api/clientConfig.test.d.ts → api/ClientConfig.test.d.ts} +0 -0
  109. /package/dist/{src/monitors/BaseMonitor.test.d.ts → api/MetroplexSocket.test.d.ts} +0 -0
  110. /package/dist/{src/const_matchers.d.ts → const_matchers.d.ts} +0 -0
  111. /package/dist/{src/sessionRecorder → sessionRecorder}/types.d.ts +0 -0
  112. /package/dist/{src/utils → utils}/eventlistener.d.ts +0 -0
  113. /package/dist/{src/utils → utils}/piiRedactor.d.ts +0 -0
  114. /package/dist/{src/utils → utils}/polyfills.d.ts +0 -0
@@ -1,62 +1,52 @@
1
- import ClientConfig from '../api/clientConfig.js';
2
- import { SEVERITY } from '../constants.js';
1
+ import ClientConfig from '../api/ClientConfig.js';
2
+ import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
3
+ import { Severity } from '../node_modules/@noibu/metroplex-ts-bindings/dist/Severity.js';
3
4
 
4
5
  /** @module Date */
5
-
6
6
  /** Checks to see if the necessary Date functions that we use have been overwritten */
7
7
  function isDateOverwritten() {
8
- // Check to see if Date.now() exists
9
- if (!('now' in Date)) {
10
- return true;
11
- }
12
-
13
- // Check to ensure that Date.now() returns a number
14
- if (typeof Date.now() !== 'number') {
15
- return true;
16
- }
17
-
18
- // Check to see if new Date().toISOString() exists
19
- if (!('toISOString' in new Date())) {
20
- return true;
21
- }
22
-
23
- // Check to ensure new Date().toISOString() returns a string
24
- if (typeof new Date().toISOString() !== 'string') {
25
- return true;
26
- }
27
-
28
- // If none of the above checks return true, we assume that the Date function
29
- // has not been overwritten
30
- return false;
8
+ // Check to see if Date.now() exists
9
+ if (!('now' in Date)) {
10
+ return true;
11
+ }
12
+ // Check to ensure that Date.now() returns a number
13
+ if (typeof Date.now() !== 'number') {
14
+ return true;
15
+ }
16
+ // Check to see if new Date().toISOString() exists
17
+ if (!('toISOString' in new Date())) {
18
+ return true;
19
+ }
20
+ // Check to ensure new Date().toISOString() returns a string
21
+ if (typeof new Date().toISOString() !== 'string') {
22
+ return true;
23
+ }
24
+ // If none of the above checks return true, we assume that the Date function
25
+ // has not been overwritten
26
+ return false;
31
27
  }
32
-
33
28
  /** Timestamp wrapper to properly handle timestamps
34
- * @param {} timestamp
35
29
  */
36
30
  function timestampWrapper(timestamp) {
37
- // If the Date object has been overwritten and the timestamp is not a number,
38
- // we use the valueOf property to try to retrieve the actual timestamp.
39
- // If valueOf is not available, we disable client and log the error.
40
- if (typeof timestamp !== 'number' && isDateOverwritten()) {
41
- if (
42
- // eslint-disable-next-line no-prototype-builtins
43
- Date.prototype.hasOwnProperty('valueOf') &&
44
- typeof timestamp.valueOf === 'function' &&
45
- typeof timestamp.valueOf() === 'number'
46
- ) {
47
- return timestamp.valueOf();
48
- }
49
-
50
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
51
- `The date object has been overwritten and can't be processed properly.
31
+ var _a;
32
+ // If the Date object has been overwritten and the timestamp is not a number,
33
+ // we use the valueOf property to try to retrieve the actual timestamp.
34
+ // If valueOf is not available, we disable client and log the error.
35
+ if (typeof timestamp === 'object' && isDateOverwritten()) {
36
+ const value = (_a = timestamp === null || timestamp === void 0 ? void 0 : timestamp.valueOf) === null || _a === void 0 ? void 0 : _a.call(timestamp);
37
+ if (typeof value === 'number') {
38
+ return value;
39
+ }
40
+ ClientConfig.getInstance().postInternalError({
41
+ msg: `The date object has been overwritten and can't be processed properly.
52
42
  Client has been disabled.`,
53
- true,
54
- SEVERITY.error,
55
- true,
56
- );
57
- }
58
-
59
- return timestamp;
43
+ }, true, Severity.ERROR, true);
44
+ }
45
+ return timestamp;
46
+ }
47
+ /** Get the current time in ISO format */
48
+ function getOccurredNow() {
49
+ return new Date(timestampWrapper(Date.now())).toISOString();
60
50
  }
61
51
 
62
- export { isDateOverwritten, timestampWrapper };
52
+ export { getOccurredNow, isDateOverwritten, timestampWrapper };
@@ -1,5 +1,4 @@
1
- import { SEVERITY } from '../constants.js';
2
- import ClientConfig from '../api/clientConfig.js';
1
+ import ClientConfig from '../api/ClientConfig.js';
3
2
 
4
3
  /** addSafeEventListener will add an event listener for the specified event
5
4
  * but will catch and log any errors encountered
@@ -21,25 +20,22 @@ function addSafeEventListener(object, event, callback, capture = false) {
21
20
  try {
22
21
  callback(eventReceived);
23
22
  } catch (e) {
24
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
23
+ ClientConfig.getInstance().postInternalError(
25
24
  `addEventListener callback error: ${e.message}`,
26
25
  false,
27
- SEVERITY.error,
26
+ Severity.ERROR,
28
27
  );
29
28
  }
30
29
  };
31
30
 
32
- /**
33
- * tries to add an event listener to a Proxy object
34
- */
31
+ /** tries to add an event listener to a Proxy object */
35
32
  const tryAddEventListenerForProxy = () => {
36
33
  if (!Reflect) {
37
34
  return false;
38
35
  }
39
36
 
40
37
  try {
41
- const addEventListener =
42
- Reflect.get(object, 'addEventListener') || (() => {});
38
+ const addEventListener = Reflect.get(object, 'addEventListener') || (() => {});
43
39
  addEventListener(event, safeCallback, capture);
44
40
  } catch (e) {
45
41
  return false;
@@ -56,11 +52,7 @@ function addSafeEventListener(object, event, callback, capture = false) {
56
52
  return;
57
53
  }
58
54
  }
59
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
60
- `addEventListener error: ${e.message}`,
61
- false,
62
- SEVERITY.error,
63
- );
55
+ ClientConfig.getInstance().postInternalError(`addEventListener error: ${e.message}`, false, Severity.ERROR);
64
56
  }
65
57
  }
66
58
 
@@ -1,6 +1,5 @@
1
+ import { JSError } from '@noibu/metroplex-ts-bindings';
1
2
  import { RawStackFrame } from './stacktrace-parser';
2
- import { REQUIRED_DATA_PROCESSING_URLS } from '../constants';
3
- import { JSErrorOutputMessage } from '../../types/PageVisitErrors.types';
4
3
  /**
5
4
  * returns a string that satisfies a max length
6
5
  * stringToVerify: string that needs to be verified
@@ -10,20 +9,12 @@ export declare function getMaxSubstringAllowed(stringToVerify: string, length?:
10
9
  /**
11
10
  * Processes the raw stack frames and creates a readable stack in a safe manner
12
11
  */
13
- export declare function processFrames(rawFrames: RawStackFrame[]): {
14
- file: string;
15
- line: string;
16
- mname: string;
17
- column?: number;
18
- }[];
19
- /**
20
- * Retrieves the javascript stack and message from an error event object
21
- * @param errObj error to extract stack from
22
- */
23
- export declare function getJSStack(errObj: {
24
- stack: string;
25
- message: string;
26
- }): JSErrorOutputMessage;
12
+ export declare function processFrames(rawFrames: RawStackFrame[]): import("@noibu/metroplex-ts-bindings").JSStackFrame[];
13
+ /** Retrieves the javascript stack and message from an error event object */
14
+ export declare function getJSStack(errObj?: {
15
+ stack?: string | NativeStackAndroid;
16
+ message?: string;
17
+ }): JSError;
27
18
  /**
28
19
  * Checks if possiblyStacktrace has any stack frames present
29
20
  */
@@ -38,15 +29,10 @@ export declare function byteCount(s: string): number;
38
29
  */
39
30
  export declare function stringifyJSON(jsonObject: unknown): string;
40
31
  /**
41
- * Wrapper for a request, since we have to do some special handling
42
- * @param method
43
- * @param url
44
- * @param data
45
- * @param headers
46
- * @param timeout
47
- * @param sendAndForget
32
+ * Wrapper for a request with an ability to send-and-forget
33
+ * a send-and-forget request can outlive the page
48
34
  */
49
- export declare function makeRequest(method: string, url: string, data: unknown, headers: Record<string, string>, timeout: number, sendAndForget: boolean): Promise<unknown>;
35
+ export declare function postRequest(url: string | URL, data: unknown, headers: Record<string, string>, sendAndForget?: boolean, timeout?: number): Promise<void>;
50
36
  /**
51
37
  * makes sure the url sent is a valid URL
52
38
  */
@@ -56,11 +42,6 @@ export declare function isValidURL(str: string): boolean;
56
42
  * caches the result for the session
57
43
  */
58
44
  export declare function getUserAgent(): Promise<string>;
59
- /**
60
- * isInvalidURLConfig will verify that Collect is being initializes with
61
- * the correct env vars.
62
- */
63
- export declare function isInvalidURLConfig(urls: Record<(typeof REQUIRED_DATA_PROCESSING_URLS)[number], string>): boolean;
64
45
  /**
65
46
  * isNoibuJSAlreadyLoaded will verify if there are already other
66
47
  * copies of NoibuJS runnung
@@ -80,23 +61,12 @@ export declare function maskTextInput(text: string): string;
80
61
  * where type is not actually a type but an object.
81
62
  */
82
63
  export declare function isInstanceOf<T>(instance: unknown, type: T): instance is T;
83
- /**
84
- * To grab the video recorder type based on the device we run the app on.
85
- */
86
- export declare function getVideoRecorderType(): Promise<string>;
87
64
  /** String.trim, but safe */
88
65
  export declare function safeTrim(text: unknown): string;
89
66
  /**
90
67
  * Tries to get the stack trace from the given error object and returns it.
91
68
  * If the error object does not have a stack trace, an empty string is returned.
92
- *
93
- * @param {Error} error - The error object from which to retrieve the stack trace.
94
- * @returns {string} The stack trace of the error, if available. Otherwise, an empty string is returned.
95
- */
96
- export declare function tryGetStackTrace(error: any): string;
97
- /**
98
- * Checks whether the given value is a string or an instance of String.
99
- * @param {*} value - The value to be checked.
100
- * @returns {boolean} Returns true if the value is a string or an instance of String, otherwise returns false.
101
69
  */
102
- export declare function isString(value: any): value is string | String;
70
+ export declare function tryGetStackTrace(error: {
71
+ stack?: string;
72
+ }): string;
@@ -1,17 +1,21 @@
1
1
  import { __awaiter } from 'tslib';
2
2
  import { Platform } from 'react-native';
3
3
  import { parseStack } from './stacktrace-parser.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
+ import { MAX_STRING_LENGTH, MAX_BEACON_PAYLOAD_SIZE, PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING } from '../constants.js';
5
5
  import { noibuLog } from './log.js';
6
6
  import { unwrapNoibuWrapped } from './object.js';
7
7
 
8
+ // default string for stack frame fields
9
+ const DEFAULT_STACK_FRAME_FIELD_VALUE = '_';
10
+ const PII_DIGIT_PATTERN = /[0-9]+/g;
11
+ const STACK_TRACE_SANITIZE_REGEXP = /(nbuGlobalPromiseRejectWrapper|InternalBytecode)/gi;
8
12
  /**
9
13
  * Returns a stack trace frame with default filed values
10
14
  */
11
15
  const getDefaultFrame = () => ({
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,
16
+ line: DEFAULT_STACK_FRAME_FIELD_VALUE,
17
+ mname: DEFAULT_STACK_FRAME_FIELD_VALUE,
18
+ file: DEFAULT_STACK_FRAME_FIELD_VALUE,
15
19
  });
16
20
  /**
17
21
  * returns a string that satisfies a max length
@@ -55,22 +59,15 @@ function processFrames(rawFrames) {
55
59
  return processedFrame;
56
60
  });
57
61
  }
58
- /**
59
- * Retrieves the javascript stack and message from an error event object
60
- * @param errObj error to extract stack from
61
- */
62
+ /** Retrieves the javascript stack and message from an error event object */
62
63
  function getJSStack(errObj) {
63
- let frames = [getDefaultFrame()];
64
64
  // if the errObj type is not an object or null
65
65
  // return a default frame
66
66
  if (typeof errObj !== 'object' || !errObj || !errObj.stack) {
67
- return {
68
- frames,
69
- msg: '',
70
- };
67
+ return { frames: [getDefaultFrame()], msg: '' };
71
68
  }
72
- frames = processFrames(parseStack(errObj.stack));
73
69
  const msg = errObj.message ? getMaxSubstringAllowed(errObj.message) : '';
70
+ const frames = processFrames(parseStack(errObj.stack)).filter(line => !`${line.file}|${line.mname}`.match(STACK_TRACE_SANITIZE_REGEXP));
74
71
  return {
75
72
  frames,
76
73
  msg,
@@ -111,63 +108,36 @@ function stringifyJSON(jsonObject) {
111
108
  });
112
109
  }
113
110
  /**
114
- * Wrapper for a request, since we have to do some special handling
115
- * @param method
116
- * @param url
117
- * @param data
118
- * @param headers
119
- * @param timeout
120
- * @param sendAndForget
111
+ * Wrapper for a request with an ability to send-and-forget
112
+ * a send-and-forget request can outlive the page
121
113
  */
122
- function makeRequest(method, url, data, headers, timeout, sendAndForget) {
123
- return __awaiter(this, void 0, void 0, function* () {
124
- const ua = Object.keys(headers).findLast(k => k.toLowerCase() === 'user-agent');
125
- const headersWithUa = Object.assign({}, headers);
126
- if (!headers[ua]) {
127
- headersWithUa['User-Agent'] = yield getUserAgent();
128
- }
129
- // a send-and-forget request is made by using the beacon API (fetch + keepalive)
130
- if (sendAndForget) {
131
- const stringData = stringifyJSON(data);
132
- const currentPayloadSize = new Blob([stringData]).size;
133
- // if we have a large object or fetch is not available, we skip sending the message
134
- if (currentPayloadSize > MAX_BEACON_PAYLOAD_SIZE) {
135
- return Promise.resolve();
136
- }
137
- return unwrapNoibuWrapped(fetch)(url, {
138
- method: 'POST',
139
- headers: headersWithUa,
140
- body: stringifyJSON(data),
141
- // keep alive outlives the current page, its the same as beacon
142
- keepalive: true,
143
- });
144
- }
145
- return new Promise((resolve, reject) => {
146
- const xhr = new XMLHttpRequest();
147
- xhr.open(method, url);
148
- xhr.timeout = timeout;
149
- Object.keys(headersWithUa).forEach(header => {
150
- xhr.setRequestHeader(header, headers[header]);
151
- });
152
- xhr.onload = () => {
153
- if (xhr.status >= 200 && xhr.status < 300) {
154
- resolve(xhr.response);
155
- }
156
- else {
157
- reject(new Error(`Custom Request failed: ${xhr.statusText}`));
158
- }
159
- };
160
- xhr.onerror = () => {
161
- reject(new Error(`Custom Request failed: ${xhr.statusText}`));
162
- };
163
- if (data) {
164
- xhr.send(stringifyJSON(data));
165
- }
166
- else {
167
- xhr.send();
168
- }
169
- });
170
- });
114
+ function postRequest(url, data, headers, sendAndForget = false, timeout = 2000) {
115
+ if (typeof fetch !== 'function') {
116
+ return Promise.resolve();
117
+ }
118
+ const body = asString(data);
119
+ const currentPayloadSize = new Blob([body]).size;
120
+ if (sendAndForget && currentPayloadSize > MAX_BEACON_PAYLOAD_SIZE) {
121
+ return Promise.reject("Can't queue data for transfer due to it's size.");
122
+ }
123
+ const init = {
124
+ method: 'POST',
125
+ headers,
126
+ body,
127
+ keepalive: sendAndForget,
128
+ };
129
+ let timer;
130
+ if (typeof AbortController !== 'undefined') {
131
+ const controller = new AbortController();
132
+ init.signal = controller.signal;
133
+ timer = setTimeout(() => controller.abort('Timeout exceeded'), timeout);
134
+ }
135
+ const originalFetch = unwrapNoibuWrapped(fetch);
136
+ const promise = originalFetch(url, init).then(() => { });
137
+ if (typeof AbortController !== 'undefined') {
138
+ promise.finally(() => clearTimeout(timer));
139
+ }
140
+ return promise;
171
141
  }
172
142
  /**
173
143
  * makes sure the url sent is a valid URL
@@ -202,20 +172,6 @@ function getUserAgent() {
202
172
  return userAgentCache;
203
173
  });
204
174
  }
205
- /**
206
- * isInvalidURLConfig will verify that Collect is being initializes with
207
- * the correct env vars.
208
- */
209
- function isInvalidURLConfig(urls) {
210
- for (let i = 0; i < REQUIRED_DATA_PROCESSING_URLS.length; i += 1) {
211
- const u = REQUIRED_DATA_PROCESSING_URLS[i];
212
- if (!urls[u]) {
213
- noibuLog('urlConfig invalid, reason', u);
214
- return true;
215
- }
216
- }
217
- return false;
218
- }
219
175
  /**
220
176
  * isNoibuJSAlreadyLoaded will verify if there are already other
221
177
  * copies of NoibuJS runnung
@@ -249,9 +205,7 @@ function asString(obj) {
249
205
  */
250
206
  function maskTextInput(text) {
251
207
  // if it has an email or digit(s), we mask the text
252
- return text
253
- .replace(PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING)
254
- .replace(PII_DIGIT_PATTERN, '*');
208
+ return text.replace(PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING).replace(PII_DIGIT_PATTERN, '*');
255
209
  }
256
210
  /**
257
211
  * Checks if the provided object is an instance of the specified type.
@@ -266,20 +220,6 @@ function isInstanceOf(instance, type) {
266
220
  return false;
267
221
  }
268
222
  }
269
- /**
270
- * To grab the video recorder type based on the device we run the app on.
271
- */
272
- function getVideoRecorderType() {
273
- return __awaiter(this, void 0, void 0, function* () {
274
- if (Platform.OS === 'android') {
275
- return 'AndroidNative';
276
- }
277
- if (Platform.OS === 'ios') {
278
- return 'IOSNative';
279
- }
280
- return '';
281
- });
282
- }
283
223
  /** String.trim, but safe */
284
224
  function safeTrim(text) {
285
225
  if (typeof text !== 'string') {
@@ -290,9 +230,6 @@ function safeTrim(text) {
290
230
  /**
291
231
  * Tries to get the stack trace from the given error object and returns it.
292
232
  * If the error object does not have a stack trace, an empty string is returned.
293
- *
294
- * @param {Error} error - The error object from which to retrieve the stack trace.
295
- * @returns {string} The stack trace of the error, if available. Otherwise, an empty string is returned.
296
233
  */
297
234
  function tryGetStackTrace(error) {
298
235
  let result = '';
@@ -306,13 +243,5 @@ function tryGetStackTrace(error) {
306
243
  }
307
244
  return result;
308
245
  }
309
- /**
310
- * Checks whether the given value is a string or an instance of String.
311
- * @param {*} value - The value to be checked.
312
- * @returns {boolean} Returns true if the value is a string or an instance of String, otherwise returns false.
313
- */
314
- function isString(value) {
315
- return typeof value === 'string' || value instanceof String;
316
- }
317
246
 
318
- export { asString, getJSStack, getMaxSubstringAllowed, getUserAgent, getVideoRecorderType, isInstanceOf, isInvalidURLConfig, isNoibuJSAlreadyLoaded, isStackTrace, isString, isValidURL, makeRequest, maskTextInput, processFrames, safeTrim, stringifyJSON, tryGetStackTrace };
247
+ export { asString, getJSStack, getMaxSubstringAllowed, getUserAgent, isInstanceOf, isNoibuJSAlreadyLoaded, isStackTrace, isValidURL, maskTextInput, postRequest, processFrames, safeTrim, stringifyJSON, tryGetStackTrace };
@@ -0,0 +1,4 @@
1
+ /**log with level = info */
2
+ export declare const noibuLog: Console['log'];
3
+ /**log with level = error */
4
+ export declare const noibuErr: Console['error'];
package/dist/utils/log.js CHANGED
@@ -4,12 +4,10 @@
4
4
  * checks if was overridden and calls original console function
5
5
  */
6
6
  const getConsoleMethod = (ogProp) => {
7
- // @ts-ignore
7
+ // @ts-expect-error __noibu_original__ is not a standard property
8
8
  return console[ogProp].__noibu_original__ || console[ogProp];
9
9
  };
10
- /**
11
- * log with level = info
12
- */
10
+ /**log with level = info */
13
11
  const noibuLog = (...msgs) => getConsoleMethod('log')('Noibu', ...msgs);
14
12
 
15
13
  export { noibuLog };
@@ -5,18 +5,20 @@
5
5
  * attributeName: the attribute key whose value will be replace
6
6
  * processingFunction: function that accepts the original value
7
7
  * and returns the newValue
8
- * @param {} sourceObject
9
- * @param {} attributeName
10
- * @param {} processingFunction
11
8
  */
12
- export declare const replace: <A extends { [k in K]: Function; }, K extends keyof A>(sourceObject: A, attributeName: K, processingFunction: (arg: A[K]) => A[K]) => void;
9
+ export declare function replace<Target extends object, Prop extends keyof Target>(sourceObject: Target, attributeName: Prop, processingFunction: (arg: Target[Prop]) => Target[Prop]): void;
13
10
  /**
14
11
  * unwraps wrapped property, so we can use it without side effects
15
- * @param anything
16
12
  */
17
13
  export declare function unwrapNoibuWrapped<T>(anything: {
18
14
  __noibu_original__?: T;
19
- } & T): T;
15
+ } & T): NonNullable<T>;
16
+ /**
17
+ * Checks if the given object is wrapped
18
+ */
19
+ export declare function isNoibuWrapped<T extends object>(anything: T): anything is {
20
+ __noibu_original__?: T;
21
+ } & T;
20
22
  /**
21
23
  * Checks whether the prototype's property is writeable. If it is not,
22
24
  * checks whether the property can be made writeable. If it can, it is
@@ -28,14 +30,14 @@ export declare const propWriteableOrMadeWriteable: <T>(proto: T, property: keyof
28
30
  * Iterates object recursively and calls visit function
29
31
  * for each property allowing to override its value
30
32
  * @param {Object} instance An object to iterate through
31
- * @param {Function} visit A callback function that is called for each property
33
+ * @param {Function} visit Target callback function that is called for each property
32
34
  * There are 3 arguments: current object, current property and its value
33
35
  * @param {{depth: number}} limit Use limit config object to set depth of the recursion
34
36
  */
35
37
  export declare const iterateObjectRecursively: (instance: Record<any, any>, visit: (i: typeof instance, p: keyof typeof i, v: (typeof i)[typeof p]) => typeof v, limit?: {
36
38
  depth: number;
37
39
  }) => void;
38
- export declare const safeEntries: (obj: unknown | Record<string, string | null> | Headers) => [string, string][];
40
+ export declare const safeEntries: (obj: unknown | Record<string, string | null> | Headers) => [string, string | null][];
39
41
  /**
40
42
  * Replaces the behaviour of Object.fromEntries() as it is not supported on all browsers
41
43
  * @param {Iterable} entries The iterable to parse into an object
@@ -6,16 +6,13 @@
6
6
  * attributeName: the attribute key whose value will be replace
7
7
  * processingFunction: function that accepts the original value
8
8
  * and returns the newValue
9
- * @param {} sourceObject
10
- * @param {} attributeName
11
- * @param {} processingFunction
12
9
  */
13
- const replace = (sourceObject, attributeName, processingFunction) => {
10
+ function replace(sourceObject, attributeName, processingFunction) {
14
11
  if (!(attributeName in sourceObject)) {
15
12
  return;
16
13
  }
17
14
  const originalAttribute = sourceObject[attributeName];
18
- const newValue = processingFunction(originalAttribute);
15
+ const newValue = processingFunction.call(sourceObject, originalAttribute);
19
16
  if (typeof newValue === 'function') {
20
17
  try {
21
18
  newValue.prototype = newValue.prototype || {};
@@ -40,14 +37,19 @@ const replace = (sourceObject, attributeName, processingFunction) => {
40
37
  }
41
38
  // eslint-disable-next-line no-param-reassign
42
39
  sourceObject[attributeName] = newValue;
43
- };
40
+ }
44
41
  /**
45
42
  * unwraps wrapped property, so we can use it without side effects
46
- * @param anything
47
43
  */
48
44
  function unwrapNoibuWrapped(anything) {
49
45
  return anything.__noibu_original__ || anything;
50
46
  }
47
+ /**
48
+ * Checks if the given object is wrapped
49
+ */
50
+ function isNoibuWrapped(anything) {
51
+ return '__noibu_original__' in anything;
52
+ }
51
53
  /**
52
54
  * Checks whether the prototype's property is writeable. If it is not,
53
55
  * checks whether the property can be made writeable. If it can, it is
@@ -55,9 +57,7 @@ function unwrapNoibuWrapped(anything) {
55
57
  * returns Whether the property on the prototype is (or is now) writeable
56
58
  */
57
59
  const propWriteableOrMadeWriteable = (proto, property) => {
58
- if (!proto ||
59
- !proto.hasOwnProperty ||
60
- !Object.prototype.hasOwnProperty.call(proto, property)) {
60
+ if (!proto || !proto.hasOwnProperty || !Object.prototype.hasOwnProperty.call(proto, property)) {
61
61
  return false;
62
62
  }
63
63
  // Getting the properties that this the prototype
@@ -82,7 +82,7 @@ const propWriteableOrMadeWriteable = (proto, property) => {
82
82
  * Iterates object recursively and calls visit function
83
83
  * for each property allowing to override its value
84
84
  * @param {Object} instance An object to iterate through
85
- * @param {Function} visit A callback function that is called for each property
85
+ * @param {Function} visit Target callback function that is called for each property
86
86
  * There are 3 arguments: current object, current property and its value
87
87
  * @param {{depth: number}} limit Use limit config object to set depth of the recursion
88
88
  */
@@ -171,4 +171,4 @@ const safeFromEntries = (entries) => {
171
171
  return obj;
172
172
  };
173
173
 
174
- export { iterateObjectRecursively, propWriteableOrMadeWriteable, replace, safeEntries, safeFromEntries, unwrapNoibuWrapped };
174
+ export { isNoibuWrapped, iterateObjectRecursively, propWriteableOrMadeWriteable, replace, safeEntries, safeFromEntries, unwrapNoibuWrapped };
@@ -3,4 +3,4 @@
3
3
  * it's available before calling it. If it's not available,
4
4
  * we return Date.now() instead.
5
5
  */
6
- export declare function safePerformanceNow(): any;
6
+ export declare function safePerformanceNow(): number;
@@ -1,7 +1,36 @@
1
1
  import { iterateObjectRecursively } from './object.js';
2
- import { HTTP_PII_BLOCKING_PATTERNS, PII_REDACTION_REPLACEMENT_STRING } from '../constants.js';
2
+ import { PII_REDACTION_REPLACEMENT_STRING, PII_EMAIL_PATTERN } from '../constants.js';
3
3
  import { stringifyJSON } from './function.js';
4
4
 
5
+ // Regex patterns for a best-effort attempt at blocking PII in HTTP requests
6
+ const HTTP_PII_BLOCKING_PATTERNS = [
7
+ // Match credit cards [https://www.regular-expressions.info/creditcard.html]
8
+ // Visa
9
+ /\b4\d{12}(?:\d{3})?\b/g,
10
+ // MasterCard
11
+ /\b(?:5[1-5]\d{2}|222[1-9]|22[3-9]\d|2[3-6]\d{2}|27[01]\d|2720)\d{12}\b/g,
12
+ // Amex
13
+ /\b3[47]\d{13}\b/g,
14
+ // Diners Club
15
+ /\b3(?:0[0-5]|[68]\d)\d{11}\b/g,
16
+ // Discover
17
+ /\b6(?:011|5\d{2})\d{12}\b/g,
18
+ // JCB
19
+ /\b(?:2131|1800|35\d{3})\d{11}\b/g,
20
+ // Emails [https://www.regular-expressions.info/email.html]
21
+ PII_EMAIL_PATTERN,
22
+ // US SSN with or without dashes
23
+ // [https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s12.html]
24
+ /\b(?!000|666)[0-8]\d{2}[-.● ]?(?!00)\d{2}[-.● ]?(?!0000)\d{4}\b/g,
25
+ // Canadian SIN with or without dashes [https://regexpattern.com/social-insurance-number-ca]
26
+ /\b(\d{3}[-.● ]?\d{3}[-.● ]?\d{3})\b/g,
27
+ // International phone numbers
28
+ // [https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s03.html]
29
+ /\+(?:\d●?){6,14}\d\b/g,
30
+ // US/Canada phone numbers
31
+ // [https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s02.html]
32
+ /(\b|\+)?(1[-.● ]?)?\(?(\d{3})\)?[-.● ]?(\d{3})[-.● ]?(\d{4})\b/g,
33
+ ];
5
34
  const fuzzyFieldsToRedact = [
6
35
  'password',
7
36
  'address',
@@ -35,8 +64,7 @@ const exactFieldsToRedact = [
35
64
  */
36
65
  function shouldRedact(field) {
37
66
  // check for exact and fuzzy matches
38
- return (exactFieldsToRedact.some(v => field === v) ||
39
- fuzzyFieldsToRedact.some(v => field.indexOf(v) >= 0));
67
+ return exactFieldsToRedact.some(v => field === v) || fuzzyFieldsToRedact.some(v => field.indexOf(v) >= 0);
40
68
  }
41
69
  /**
42
70
  * Try to parse content as a JSON object and