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.
- package/README.md +15 -15
- package/android/build.gradle +1 -1
- package/dist/{src/api/clientConfig.d.ts → api/ClientConfig.d.ts} +19 -20
- package/dist/api/{clientConfig.js → ClientConfig.js} +82 -63
- package/dist/{src/api/helpCode.d.ts → api/HelpCode.d.ts} +3 -10
- package/dist/api/{helpCode.js → HelpCode.js} +8 -14
- package/dist/api/InputManager.d.ts +39 -0
- package/dist/api/InputManager.js +156 -0
- package/dist/{src/api/metroplexSocket.d.ts → api/MetroplexSocket.d.ts} +33 -38
- package/dist/api/{metroplexSocket.js → MetroplexSocket.js} +190 -178
- package/dist/{src/api/storedMetrics.d.ts → api/StoredMetrics.d.ts} +10 -20
- package/dist/api/StoredMetrics.js +158 -0
- package/dist/{src/api/storedPageVisit.d.ts → api/StoredPageVisit.d.ts} +11 -8
- package/dist/api/{storedPageVisit.js → StoredPageVisit.js} +62 -48
- package/dist/const_matchers.js +1 -5
- package/dist/constants.d.ts +48 -0
- package/dist/constants.js +15 -397
- package/dist/{src/entry → entry}/index.d.ts +5 -6
- package/dist/entry/index.js +3 -4
- package/dist/entry/init.d.ts +8 -0
- package/dist/entry/init.js +34 -19
- package/dist/monitors/AppNavigationMonitor.d.ts +10 -0
- package/dist/monitors/AppNavigationMonitor.js +19 -19
- package/dist/monitors/AppNavigationMonitor.test.d.ts +1 -0
- package/dist/{src/monitors → monitors}/BaseMonitor.d.ts +5 -5
- package/dist/monitors/BaseMonitor.js +9 -4
- package/dist/monitors/BaseMonitor.test.d.ts +1 -0
- package/dist/{src/monitors → monitors}/ClickMonitor.d.ts +10 -13
- package/dist/monitors/ClickMonitor.js +72 -76
- package/dist/monitors/ClickMonitor.test.d.ts +1 -0
- package/dist/{src/monitors → monitors}/ErrorMonitor.d.ts +4 -28
- package/dist/monitors/ErrorMonitor.js +45 -55
- package/dist/{src/monitors → monitors}/KeyboardInputMonitor.d.ts +1 -3
- package/dist/monitors/KeyboardInputMonitor.js +13 -11
- package/dist/{src/monitors → monitors}/PageMonitor.d.ts +1 -1
- package/dist/monitors/PageMonitor.js +25 -2
- package/dist/{src/monitors → monitors}/RequestMonitor.d.ts +9 -29
- package/dist/monitors/RequestMonitor.js +46 -57
- package/dist/monitors/http-tools/GqlErrorValidator.d.ts +35 -0
- package/dist/monitors/http-tools/GqlErrorValidator.js +42 -70
- package/dist/{src/monitors → monitors}/http-tools/HTTPDataBundler.d.ts +9 -15
- package/dist/monitors/http-tools/HTTPDataBundler.js +74 -67
- package/dist/monitors/integrations/ReactNativeNavigationIntegration.d.ts +17 -0
- package/dist/monitors/integrations/{react-native-navigation-integration.js → ReactNativeNavigationIntegration.js} +15 -12
- package/dist/{src/pageVisit → pageVisit}/EventDebouncer.d.ts +9 -10
- package/dist/pageVisit/EventDebouncer.js +43 -74
- package/dist/pageVisit/HttpEventManager.d.ts +14 -0
- package/dist/pageVisit/HttpEventManager.js +88 -0
- package/dist/pageVisit/PageVisitManager.d.ts +31 -0
- package/dist/pageVisit/PageVisitManager.js +99 -0
- package/dist/pageVisit/pageVisitEventError.d.ts +12 -0
- package/dist/pageVisit/pageVisitEventError.js +170 -280
- package/dist/{src/react → react}/ErrorBoundary.d.ts +4 -9
- package/dist/react/ErrorBoundary.js +3 -6
- package/dist/{src/sessionRecorder/sessionRecorder.d.ts → sessionRecorder/SessionRecorder.d.ts} +7 -17
- package/dist/sessionRecorder/{sessionRecorder.js → SessionRecorder.js} +60 -71
- package/dist/{src/sessionRecorder → sessionRecorder}/nativeSessionRecorderSubscription.d.ts +4 -6
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -5
- package/dist/{src/storage/rnStorageProvider.d.ts → storage/RNStorageProvider.d.ts} +4 -8
- package/dist/storage/{rnStorageProvider.js → RNStorageProvider.js} +3 -7
- package/dist/{src/storage/storage.d.ts → storage/Storage.d.ts} +8 -18
- package/dist/storage/{storage.js → Storage.js} +17 -30
- package/dist/{src/storage/storageProvider.d.ts → storage/StorageProvider.d.ts} +5 -8
- package/dist/storage/{storageProvider.js → StorageProvider.js} +7 -8
- package/dist/types/NavigationIntegration.d.ts +1 -1
- package/dist/utils/date.d.ts +7 -0
- package/dist/utils/date.js +41 -51
- package/dist/utils/eventlistener.js +6 -14
- package/dist/{src/utils → utils}/function.d.ts +13 -43
- package/dist/utils/function.js +42 -113
- package/dist/utils/log.d.ts +4 -0
- package/dist/utils/log.js +2 -4
- package/dist/{src/utils → utils}/object.d.ts +10 -8
- package/dist/utils/object.js +12 -12
- package/dist/{src/utils → utils}/performance.d.ts +1 -1
- package/dist/utils/piiRedactor.js +31 -3
- package/dist/utils/stacktrace-parser.d.ts +8 -0
- package/dist/utils/stacktrace-parser.js +29 -21
- package/dist/utils/stacktrace-parser.test.d.ts +1 -0
- package/package.json +14 -14
- package/dist/api/inputManager.js +0 -227
- package/dist/api/storedMetrics.js +0 -198
- package/dist/pageVisit/pageVisit.js +0 -181
- package/dist/pageVisit/pageVisitEventHTTP.js +0 -98
- package/dist/pageVisit/userStep.js +0 -20
- package/dist/src/api/inputManager.d.ts +0 -87
- package/dist/src/constants.d.ts +0 -290
- package/dist/src/entry/init.d.ts +0 -5
- package/dist/src/monitors/AppNavigationMonitor.d.ts +0 -18
- package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +0 -59
- package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +0 -20
- package/dist/src/pageVisit/pageVisit.d.ts +0 -52
- package/dist/src/pageVisit/pageVisitEventError.d.ts +0 -15
- package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +0 -25
- package/dist/src/pageVisit/userStep.d.ts +0 -5
- package/dist/src/utils/date.d.ts +0 -6
- package/dist/src/utils/log.d.ts +0 -4
- package/dist/src/utils/stacktrace-parser.d.ts +0 -7
- package/dist/types/Config.d.ts +0 -31
- package/dist/types/Metroplex.types.d.ts +0 -73
- package/dist/types/PageVisit.types.d.ts +0 -8
- package/dist/types/PageVisitErrors.types.d.ts +0 -114
- package/dist/types/PageVisitEvents.types.d.ts +0 -91
- package/dist/types/PageVisitMetrics.types.d.ts +0 -27
- package/dist/types/Storage.d.ts +0 -14
- package/dist/types/StoredPageVisit.types.d.ts +0 -11
- package/dist/types/WrappedObjects.d.ts +0 -6
- /package/dist/{src/api/clientConfig.test.d.ts → api/ClientConfig.test.d.ts} +0 -0
- /package/dist/{src/monitors/BaseMonitor.test.d.ts → api/MetroplexSocket.test.d.ts} +0 -0
- /package/dist/{src/const_matchers.d.ts → const_matchers.d.ts} +0 -0
- /package/dist/{src/sessionRecorder → sessionRecorder}/types.d.ts +0 -0
- /package/dist/{src/utils → utils}/eventlistener.d.ts +0 -0
- /package/dist/{src/utils → utils}/piiRedactor.d.ts +0 -0
- /package/dist/{src/utils → utils}/polyfills.d.ts +0 -0
package/dist/utils/date.js
CHANGED
|
@@ -1,62 +1,52 @@
|
|
|
1
|
-
import ClientConfig from '../api/
|
|
2
|
-
import
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
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().
|
|
23
|
+
ClientConfig.getInstance().postInternalError(
|
|
25
24
|
`addEventListener callback error: ${e.message}`,
|
|
26
25
|
false,
|
|
27
|
-
|
|
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().
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
42
|
-
*
|
|
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
|
|
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
|
|
70
|
+
export declare function tryGetStackTrace(error: {
|
|
71
|
+
stack?: string;
|
|
72
|
+
}): string;
|
package/dist/utils/function.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
|
115
|
-
*
|
|
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
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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,
|
|
247
|
+
export { asString, getJSStack, getMaxSubstringAllowed, getUserAgent, isInstanceOf, isNoibuJSAlreadyLoaded, isStackTrace, isValidURL, maskTextInput, postRequest, processFrames, safeTrim, stringifyJSON, tryGetStackTrace };
|
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-
|
|
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
|
|
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
|
|
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
|
package/dist/utils/object.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 };
|
|
@@ -1,7 +1,36 @@
|
|
|
1
1
|
import { iterateObjectRecursively } from './object.js';
|
|
2
|
-
import {
|
|
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
|
|
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
|