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
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import ClientConfig from '../api/clientConfig.js';
|
|
1
|
+
import { ReactNativeNavigationIntegration } from './integrations/ReactNativeNavigationIntegration.js';
|
|
2
|
+
import ClientConfig from '../api/ClientConfig.js';
|
|
4
3
|
import { EventDebouncer } from '../pageVisit/EventDebouncer.js';
|
|
5
4
|
import { Singleton } from './BaseMonitor.js';
|
|
5
|
+
import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
|
|
6
|
+
import { Severity } from '../node_modules/@noibu/metroplex-ts-bindings/dist/Severity.js';
|
|
7
|
+
import { EventType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/EventType.js';
|
|
6
8
|
|
|
7
|
-
/**
|
|
8
|
-
* Attaches corresponding listener to the passed navigation integration
|
|
9
|
-
*/
|
|
9
|
+
/** Attaches corresponding listener to the passed navigation integration */
|
|
10
10
|
class AppNavigationMonitor extends Singleton {
|
|
11
|
-
/**
|
|
12
|
-
* Main method for starting the monitoring
|
|
13
|
-
*/
|
|
11
|
+
/** Main method for starting the monitoring */
|
|
14
12
|
monitor() {
|
|
15
13
|
try {
|
|
16
14
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
17
15
|
const Navigation = require('react-native-navigation');
|
|
18
16
|
const rnNavigation = Navigation === null || Navigation === void 0 ? void 0 : Navigation.Navigation;
|
|
19
17
|
if (rnNavigation) {
|
|
20
|
-
|
|
18
|
+
ReactNativeNavigationIntegration.getInstance().register(rnNavigation, AppNavigationMonitor.onNavigation);
|
|
21
19
|
}
|
|
22
20
|
}
|
|
23
21
|
catch (e) {
|
|
24
|
-
ClientConfig.getInstance().
|
|
22
|
+
ClientConfig.getInstance().postInternalError({
|
|
23
|
+
msg: `Error while trying to attach to navigation events`,
|
|
24
|
+
error: e,
|
|
25
|
+
}, false, Severity.ERROR);
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
|
-
/**
|
|
28
|
-
* handler for updating navigation breadcrumbs and notifying metro of location change
|
|
29
|
-
*/
|
|
28
|
+
/** handler for updating navigation breadcrumbs and notifying metro of location change */
|
|
30
29
|
static onNavigation(breadcrumbs) {
|
|
31
30
|
ClientConfig.getInstance().currentLocationBreadcrumbs = breadcrumbs;
|
|
32
31
|
AppNavigationMonitor.reportLocationChange(breadcrumbs.pop());
|
|
33
32
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Called when the event needs to be emitted
|
|
36
|
-
*/
|
|
33
|
+
/** Called when the event needs to be emitted */
|
|
37
34
|
static reportLocationChange(currentLocation) {
|
|
38
|
-
const
|
|
39
|
-
|
|
35
|
+
const event = {
|
|
36
|
+
app_nav: { location: currentLocation || '' },
|
|
37
|
+
type: EventType.ApplicationNavigation,
|
|
38
|
+
};
|
|
39
|
+
EventDebouncer.getInstance().debounce(event);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export interface Monitor {
|
|
2
2
|
monitor(): void;
|
|
3
3
|
}
|
|
4
|
-
/**
|
|
5
|
-
* Singleton pattern with our flavor
|
|
6
|
-
*/
|
|
4
|
+
/** Singleton pattern with our flavor */
|
|
7
5
|
export declare abstract class Singleton {
|
|
8
6
|
private static instances;
|
|
9
7
|
/** returns singleton instance */
|
|
10
|
-
static getInstance<T extends Singleton, A extends any[]>(this: new (...args: A) => T, ...args: A): T;
|
|
8
|
+
static getInstance<T extends Singleton, A extends any[]>(this: new (...args: A) => T, ...args: ConstructorParameters<new (...args: A) => T>): T;
|
|
9
|
+
/** Destructor */
|
|
10
|
+
protected destroy(): void;
|
|
11
11
|
/** used for testing only */
|
|
12
|
-
|
|
12
|
+
private static resetInstances;
|
|
13
13
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { noibuLog } from '../utils/log.js';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Singleton pattern with our flavor
|
|
5
|
-
*/
|
|
3
|
+
/** Singleton pattern with our flavor */
|
|
6
4
|
class Singleton {
|
|
7
5
|
/** returns singleton instance */
|
|
8
6
|
static getInstance(...args) {
|
|
@@ -13,8 +11,15 @@ class Singleton {
|
|
|
13
11
|
}
|
|
14
12
|
return Singleton.instances.get(this);
|
|
15
13
|
}
|
|
14
|
+
/** Destructor */
|
|
15
|
+
destroy() {
|
|
16
|
+
// implement in subclasses if needed
|
|
17
|
+
}
|
|
16
18
|
/** used for testing only */
|
|
17
|
-
resetInstances() {
|
|
19
|
+
static resetInstances() {
|
|
20
|
+
Singleton.instances.forEach(instance => {
|
|
21
|
+
instance.destroy();
|
|
22
|
+
});
|
|
18
23
|
Singleton.instances.clear();
|
|
19
24
|
}
|
|
20
25
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -4,28 +4,25 @@ import { Monitor, Singleton } from './BaseMonitor';
|
|
|
4
4
|
export declare class ClickMonitor extends Singleton implements Monitor {
|
|
5
5
|
private static textCapturedWhiteListRegex;
|
|
6
6
|
private static htmlIDAllowListRegex;
|
|
7
|
-
private static originalCreateEventHandlers;
|
|
8
7
|
/** Starts monitoring clicks on every Press-able component */
|
|
9
8
|
monitor(): void;
|
|
10
|
-
/**
|
|
11
|
-
* Handles a single click event
|
|
12
|
-
*/
|
|
9
|
+
/** Handles a single click event */
|
|
13
10
|
private static onClickHandle;
|
|
14
11
|
/** Gets the textual content from an element, if any
|
|
15
12
|
*/
|
|
16
13
|
private static getTextualContentFromEl;
|
|
17
14
|
/** Parse and trim text */
|
|
18
15
|
private static trimText;
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
/** gets id */
|
|
17
|
+
private static getHid;
|
|
18
|
+
/** gets tag name */
|
|
19
|
+
private static getTagName;
|
|
20
|
+
/** Recursively parses element's inner content and masks blocked css classes */
|
|
22
21
|
private static parseInnerContent;
|
|
23
|
-
/**
|
|
24
|
-
* Gets selectors to prevent those elements from being recorded
|
|
25
|
-
*/
|
|
22
|
+
/** Gets selectors to prevent those elements from being recorded */
|
|
26
23
|
private static getBlockedElements;
|
|
27
|
-
/**
|
|
28
|
-
* normalize value and append to the resulting text if not empty
|
|
29
|
-
*/
|
|
24
|
+
/** normalize value and append to the resulting text if not empty */
|
|
30
25
|
private static parseAndAppendText;
|
|
26
|
+
/** Destructs instance */
|
|
27
|
+
destroy(this: Singleton): void;
|
|
31
28
|
}
|
|
@@ -1,95 +1,85 @@
|
|
|
1
1
|
import Pressability from 'react-native/Libraries/Pressability/Pressability';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { updatePayload } from '../pageVisit/userStep.js';
|
|
5
|
-
import StoredMetrics from '../api/storedMetrics.js';
|
|
2
|
+
import { PageVisitManager } from '../pageVisit/PageVisitManager.js';
|
|
3
|
+
import StoredMetrics from '../api/StoredMetrics.js';
|
|
6
4
|
import { WHITELIST_TEXT_REGEX_STRING } from '../const_matchers.js';
|
|
7
5
|
import { maskTextInput } from '../utils/function.js';
|
|
8
|
-
import
|
|
9
|
-
import ClientConfig from '../api/clientConfig.js';
|
|
6
|
+
import ClientConfig from '../api/ClientConfig.js';
|
|
10
7
|
import { Singleton } from './BaseMonitor.js';
|
|
8
|
+
import { isNoibuWrapped, replace, unwrapNoibuWrapped } from '../utils/object.js';
|
|
9
|
+
import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
|
|
10
|
+
import { UserStepType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/UserStepType.js';
|
|
11
|
+
import { EventType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/EventType.js';
|
|
11
12
|
|
|
12
13
|
/** @module ClickMonitor */
|
|
14
|
+
/**
|
|
15
|
+
* will return a regex that will match
|
|
16
|
+
* any keywords that may indicate that users are moving
|
|
17
|
+
* forward in the sales funnel. It will match add to cart, checkout,
|
|
18
|
+
* and any other relevant text.
|
|
19
|
+
* INFO: WHEN ARCEE CHANGES THE REGEX PATTERN, THIS NEEDS TO CHANGE TOO
|
|
20
|
+
* will return a regex that will match
|
|
21
|
+
* any keywords that may indicate that users are moving
|
|
22
|
+
* forward in the sales funnel. It will match add to cart, checkout,
|
|
23
|
+
* and any other relevant text.
|
|
24
|
+
* INFO: WHEN ARCEE CHANGES THE REGEX PATERN, THIS NEEDS TO CHANGE TOO
|
|
25
|
+
* text that have this id will not be masked, change arcee/src/models/websessions/pv_event.rs
|
|
26
|
+
*/
|
|
27
|
+
const WHITELIST_HTML_ID_TEXT_REGEX = 'method|finance|sagepay|cart|bag|coupon|affirm|karna|sezzle|button';
|
|
13
28
|
/** Monitors the clicks which we capture and later process */
|
|
14
29
|
class ClickMonitor extends Singleton {
|
|
15
30
|
/** Starts monitoring clicks on every Press-able component */
|
|
16
31
|
monitor() {
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
Pressability.prototype.getEventHandlers;
|
|
20
|
-
/**
|
|
21
|
-
* Proxies prototype method
|
|
22
|
-
*/
|
|
23
|
-
Pressability.prototype.getEventHandlers = function () {
|
|
24
|
-
const ehs = ClickMonitor.originalCreateEventHandlers.call(this);
|
|
25
|
-
return Object.fromEntries(Object.entries(ehs).map(([key, handler]) => [
|
|
26
|
-
key,
|
|
27
|
-
(event) => {
|
|
28
|
-
if (key === 'onResponderRelease') {
|
|
29
|
-
ClickMonitor.onClickHandle(event);
|
|
30
|
-
}
|
|
31
|
-
return handler(event);
|
|
32
|
-
},
|
|
33
|
-
]));
|
|
34
|
-
};
|
|
32
|
+
if (isNoibuWrapped(Pressability.prototype.getEventHandlers)) {
|
|
33
|
+
return;
|
|
35
34
|
}
|
|
35
|
+
replace(Pressability.prototype, 'getEventHandlers', function (original) {
|
|
36
|
+
return function nbuWrapper() {
|
|
37
|
+
const ehs = original.call(this);
|
|
38
|
+
return Object.assign(Object.assign({}, ehs), { onResponderRelease: function nbuWrapper(event) {
|
|
39
|
+
ClientConfig.getInstance().wrapInternal('ClickMonitor.onClickHandle', () => ClickMonitor.onClickHandle(event));
|
|
40
|
+
return ehs.onResponderRelease(event);
|
|
41
|
+
} });
|
|
42
|
+
};
|
|
43
|
+
});
|
|
36
44
|
}
|
|
37
|
-
/**
|
|
38
|
-
* Handles a single click event
|
|
39
|
-
*/
|
|
45
|
+
/** Handles a single click event */
|
|
40
46
|
static onClickHandle(event) {
|
|
41
47
|
if (event) {
|
|
42
48
|
const { _targetInst: target } = event;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// to process the image name, else we need to get the textual content
|
|
46
|
-
// todo process images
|
|
47
|
-
const text = ClickMonitor.getTextualContentFromEl(target);
|
|
48
|
-
let textFromElement = ClickMonitor.trimText(text);
|
|
49
|
-
let tagName = '';
|
|
50
|
-
if (typeof targetClassName === 'string') {
|
|
51
|
-
tagName = targetClassName.toLowerCase();
|
|
52
|
-
}
|
|
53
|
-
// id of element
|
|
54
|
-
let hid = target.memoizedProps.testID || '';
|
|
55
|
-
// in some bizarre cases, the html id of an element gets overriden
|
|
56
|
-
// to contain jquery objects. If the hid is an object, it's of no
|
|
57
|
-
// use to us.
|
|
58
|
-
if (typeof hid !== 'string') {
|
|
59
|
-
hid = '';
|
|
49
|
+
if (!target) {
|
|
50
|
+
return;
|
|
60
51
|
}
|
|
52
|
+
const tag = this.getTagName(target);
|
|
53
|
+
const hid = this.getHid(target);
|
|
54
|
+
let textFromElement = ClickMonitor.trimText(ClickMonitor.getTextualContentFromEl(target));
|
|
61
55
|
// if we find that the text matches analytic data used
|
|
62
56
|
// to find checkout starts, add to cart clicks, etc.
|
|
63
57
|
// we do not mask it.
|
|
64
58
|
if (!ClickMonitor.textCapturedWhiteListRegex.test(textFromElement) &&
|
|
65
59
|
!ClickMonitor.htmlIDAllowListRegex.test(hid)) {
|
|
66
|
-
if (
|
|
67
|
-
if (event.type &&
|
|
68
|
-
(event.type === 'button' || event.type === 'submit')) ;
|
|
60
|
+
if (tag === 'input') {
|
|
61
|
+
if (event.type && (event.type === 'button' || event.type === 'submit')) ;
|
|
69
62
|
else {
|
|
70
63
|
textFromElement = '*';
|
|
71
64
|
}
|
|
72
65
|
}
|
|
73
|
-
else if (
|
|
66
|
+
else if (tag === 'textarea') {
|
|
74
67
|
textFromElement = '*';
|
|
75
68
|
}
|
|
76
69
|
}
|
|
77
|
-
textFromElement = maskTextInput(textFromElement);
|
|
78
70
|
const tPayload = {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
71
|
+
src: '',
|
|
72
|
+
txt: maskTextInput(textFromElement),
|
|
73
|
+
tag,
|
|
74
|
+
hid,
|
|
75
|
+
type: UserStepType.Click,
|
|
76
|
+
class: '',
|
|
85
77
|
};
|
|
86
78
|
StoredMetrics.getInstance().addPvClick();
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
},
|
|
92
|
-
], USERSTEP_EVENT_TYPE);
|
|
79
|
+
PageVisitManager.getInstance().addPageVisitEvent({
|
|
80
|
+
type: EventType.UserStep,
|
|
81
|
+
userstep: tPayload,
|
|
82
|
+
});
|
|
93
83
|
}
|
|
94
84
|
}
|
|
95
85
|
/** Gets the textual content from an element, if any
|
|
@@ -122,12 +112,18 @@ class ClickMonitor extends Singleton {
|
|
|
122
112
|
}
|
|
123
113
|
return parsedText;
|
|
124
114
|
}
|
|
125
|
-
/**
|
|
126
|
-
|
|
127
|
-
|
|
115
|
+
/** gets id */
|
|
116
|
+
static getHid(element) {
|
|
117
|
+
var _a;
|
|
118
|
+
const hid = (_a = element.memoizedProps) === null || _a === void 0 ? void 0 : _a.testID;
|
|
119
|
+
return typeof hid === 'string' ? hid : '';
|
|
120
|
+
}
|
|
121
|
+
/** gets tag name */
|
|
122
|
+
static getTagName(element) {
|
|
123
|
+
return typeof element.elementType === 'string' ? element.elementType.toLowerCase() : '';
|
|
124
|
+
}
|
|
125
|
+
/** Recursively parses element's inner content and masks blocked css classes */
|
|
128
126
|
static parseInnerContent(element, text, textLimit, counter) {
|
|
129
|
-
/* eslint-disable no-restricted-syntax */
|
|
130
|
-
/* eslint-disable no-param-reassign */
|
|
131
127
|
if (text.length >= textLimit) {
|
|
132
128
|
return text;
|
|
133
129
|
}
|
|
@@ -135,7 +131,7 @@ class ClickMonitor extends Singleton {
|
|
|
135
131
|
return text;
|
|
136
132
|
}
|
|
137
133
|
counter.value += 1;
|
|
138
|
-
if (ClickMonitor.getBlockedElements().includes(element
|
|
134
|
+
if (ClickMonitor.getBlockedElements().includes(this.getHid(element))) {
|
|
139
135
|
return `${text}${text ? ' ' : ''}*`;
|
|
140
136
|
}
|
|
141
137
|
// eslint-disable-next-line require-jsdoc
|
|
@@ -146,9 +142,7 @@ class ClickMonitor extends Singleton {
|
|
|
146
142
|
((_a = node.elementType) === null || _a === void 0 ? void 0 : _a.displayName) === 'Text' &&
|
|
147
143
|
node.memoizedProps &&
|
|
148
144
|
typeof node.memoizedProps.children === 'string') {
|
|
149
|
-
text = ClickMonitor.parseAndAppendText(text, [
|
|
150
|
-
node.memoizedProps.children,
|
|
151
|
-
]);
|
|
145
|
+
text = ClickMonitor.parseAndAppendText(text, [node.memoizedProps.children]);
|
|
152
146
|
if (text.length >= textLimit)
|
|
153
147
|
return;
|
|
154
148
|
}
|
|
@@ -162,9 +156,7 @@ class ClickMonitor extends Singleton {
|
|
|
162
156
|
walk(element);
|
|
163
157
|
return text;
|
|
164
158
|
}
|
|
165
|
-
/**
|
|
166
|
-
* Gets selectors to prevent those elements from being recorded
|
|
167
|
-
*/
|
|
159
|
+
/** Gets selectors to prevent those elements from being recorded */
|
|
168
160
|
static getBlockedElements() {
|
|
169
161
|
const selectors = ClientConfig.getInstance().blockedElements;
|
|
170
162
|
const blockedElements = ['noibu-blocked'];
|
|
@@ -173,9 +165,7 @@ class ClickMonitor extends Singleton {
|
|
|
173
165
|
}
|
|
174
166
|
return blockedElements;
|
|
175
167
|
}
|
|
176
|
-
/**
|
|
177
|
-
* normalize value and append to the resulting text if not empty
|
|
178
|
-
*/
|
|
168
|
+
/** normalize value and append to the resulting text if not empty */
|
|
179
169
|
static parseAndAppendText(text, values) {
|
|
180
170
|
const goodValues = [];
|
|
181
171
|
for (const v of values) {
|
|
@@ -191,6 +181,12 @@ class ClickMonitor extends Singleton {
|
|
|
191
181
|
}
|
|
192
182
|
return text;
|
|
193
183
|
}
|
|
184
|
+
/** Destructs instance */
|
|
185
|
+
destroy() {
|
|
186
|
+
if (isNoibuWrapped(Pressability.prototype.getEventHandlers)) {
|
|
187
|
+
Pressability.prototype.getEventHandlers = unwrapNoibuWrapped(Pressability.prototype.getEventHandlers);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
194
190
|
}
|
|
195
191
|
ClickMonitor.textCapturedWhiteListRegex = new RegExp(WHITELIST_TEXT_REGEX_STRING(), 'i');
|
|
196
192
|
ClickMonitor.htmlIDAllowListRegex = new RegExp(WHITELIST_HTML_ID_TEXT_REGEX, 'i');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,32 +1,16 @@
|
|
|
1
1
|
import { Monitor, Singleton } from './BaseMonitor';
|
|
2
|
-
|
|
3
|
-
__noibu__: boolean;
|
|
4
|
-
__noibu_wrapped__: T;
|
|
5
|
-
}>;
|
|
6
|
-
/**
|
|
7
|
-
* wraps a provided function into a function that try and catches
|
|
8
|
-
* the original function, doing so allows us to catch errors
|
|
9
|
-
* functionToWrap: function to be wrapped
|
|
10
|
-
* @param {} functionToWrap
|
|
11
|
-
*/
|
|
12
|
-
export declare function wrap(functionToWrap: WrappedFunction): Function;
|
|
13
|
-
/**
|
|
14
|
-
* Monitors the errors happening on the window
|
|
15
|
-
*/
|
|
2
|
+
/** Monitors the errors happening on the window */
|
|
16
3
|
export declare class ErrorMonitor extends Singleton implements Monitor {
|
|
4
|
+
static preventInfiniteLoopFlag: boolean;
|
|
17
5
|
/** base method */
|
|
18
6
|
monitor(): void;
|
|
19
7
|
/** proxy error utils */
|
|
20
8
|
private static configureErrorUtilsHandler;
|
|
21
|
-
/**
|
|
22
|
-
* Handles a single error event
|
|
23
|
-
*/
|
|
9
|
+
/** Handles a single error event */
|
|
24
10
|
private static onErrorHandler;
|
|
25
11
|
/** proxy hermes engine */
|
|
26
12
|
private static configureHermesHooks;
|
|
27
|
-
/**
|
|
28
|
-
* handler for promise rejection failures
|
|
29
|
-
*/
|
|
13
|
+
/** handler for promise rejection failures */
|
|
30
14
|
private static onPromiseRejectionHandler;
|
|
31
15
|
/**
|
|
32
16
|
* wraps and replaces the addEventListener property
|
|
@@ -45,19 +29,11 @@ export declare class ErrorMonitor extends Singleton implements Monitor {
|
|
|
45
29
|
* it maps the stack traces to objects with their respective first lines as messages.
|
|
46
30
|
* Otherwise, if there is exactly one stack trace and one error message,
|
|
47
31
|
* it constructs an array with a single object containing the first stack trace and the first error message.
|
|
48
|
-
* @param {Array<string>} args
|
|
49
32
|
*/
|
|
50
33
|
private static constructErrors;
|
|
51
|
-
/**
|
|
52
|
-
* returns boolean that indicates wether we should
|
|
53
|
-
* ignore the next error event caught by the error event
|
|
54
|
-
* listener.
|
|
55
|
-
*/
|
|
56
|
-
private static shouldIgnoreError;
|
|
57
34
|
/**
|
|
58
35
|
* transform a log into an error since React hides component errors
|
|
59
36
|
* https://reactjs.org/docs/error-boundaries.html
|
|
60
37
|
*/
|
|
61
38
|
private static processErrorLog;
|
|
62
39
|
}
|
|
63
|
-
export {};
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { asString, isStackTrace } from '../utils/function.js';
|
|
2
|
-
import { ERROR_EVENT_ERROR_TYPE, STACK_TRACE_SANITIZE_REGEXP, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, CONSOLE_FUNCTION_OVERRIDES, ERROR_LOG_EVENT_ERROR_TYPE } from '../constants.js';
|
|
3
2
|
import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError.js';
|
|
4
3
|
import { replace } from '../utils/object.js';
|
|
5
4
|
import { Singleton } from './BaseMonitor.js';
|
|
5
|
+
import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
|
|
6
|
+
import ClientConfig from '../api/ClientConfig.js';
|
|
7
|
+
import { PageVisitErrorSource } from '../node_modules/@noibu/metroplex-ts-bindings/dist/PageVisitErrorSource.js';
|
|
6
8
|
|
|
7
9
|
/* eslint-disable @typescript-eslint/ban-types,prefer-arrow-callback */
|
|
8
10
|
/** @module ErrorMonitor */
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*/
|
|
11
|
+
// console functions that we override to capture errors
|
|
12
|
+
const CONSOLE_FUNCTION_OVERRIDES = ['error', 'warn', 'log'];
|
|
13
|
+
/** Monitors the errors happening on the window */
|
|
13
14
|
class ErrorMonitor extends Singleton {
|
|
14
15
|
/** base method */
|
|
15
16
|
monitor() {
|
|
@@ -30,16 +31,14 @@ class ErrorMonitor extends Singleton {
|
|
|
30
31
|
}
|
|
31
32
|
});
|
|
32
33
|
}
|
|
33
|
-
/**
|
|
34
|
-
* Handles a single error event
|
|
35
|
-
*/
|
|
34
|
+
/** Handles a single error event */
|
|
36
35
|
static onErrorHandler(error) {
|
|
37
|
-
if (!error || ErrorMonitor.
|
|
36
|
+
if (!error || ErrorMonitor.preventInfiniteLoopFlag) {
|
|
38
37
|
return;
|
|
39
38
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
ErrorMonitor.preventInfiniteLoopFlag = true;
|
|
40
|
+
saveErrorToPagevisit({ error, type: PageVisitErrorSource.ErrorEvent });
|
|
41
|
+
ErrorMonitor.preventInfiniteLoopFlag = false;
|
|
43
42
|
}
|
|
44
43
|
/** proxy hermes engine */
|
|
45
44
|
static configureHermesHooks() {
|
|
@@ -48,42 +47,42 @@ class ErrorMonitor extends Singleton {
|
|
|
48
47
|
(_a = HermesInternal.enablePromiseRejectionTracker) === null || _a === void 0 ? void 0 : _a.call(HermesInternal, {
|
|
49
48
|
allRejections: true,
|
|
50
49
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* This internal promise implementation method is populated only after enabling the promise tracker.
|
|
53
|
+
* It represents an improvement over the previous approach,
|
|
54
|
+
* which would lose stack context regarding the rejection because it ran asynchronously through setTimeout.
|
|
55
|
+
*
|
|
56
|
+
* This updated method ensures synchronous error capturing and retrieves the correct stack frames.
|
|
57
|
+
*/
|
|
58
|
+
replace(Promise, '_m', (originalFunction) => function nbuGlobalPromiseRejectWrapper(promise, error) {
|
|
59
|
+
ClientConfig.getInstance().wrapInternal('ErrorMonitor.configureHermesHooks', () => {
|
|
60
|
+
switch (true) {
|
|
61
|
+
case !!(error.message && error.stack): {
|
|
62
|
+
ErrorMonitor.onPromiseRejectionHandler(error);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
default: {
|
|
66
|
+
ErrorMonitor.onPromiseRejectionHandler(new Error(asString(error)));
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
64
69
|
}
|
|
65
|
-
return originalFunction === null || originalFunction === void 0 ? void 0 : originalFunction(promise, error);
|
|
66
70
|
});
|
|
67
|
-
|
|
71
|
+
return originalFunction === null || originalFunction === void 0 ? void 0 : originalFunction(promise, error);
|
|
72
|
+
});
|
|
68
73
|
}
|
|
69
|
-
/**
|
|
70
|
-
* handler for promise rejection failures
|
|
71
|
-
*/
|
|
74
|
+
/** handler for promise rejection failures */
|
|
72
75
|
static onPromiseRejectionHandler(error) {
|
|
73
|
-
if (!error || !error.
|
|
76
|
+
if (!error || !error.stack || ErrorMonitor.preventInfiniteLoopFlag) {
|
|
74
77
|
return;
|
|
75
78
|
}
|
|
76
|
-
|
|
77
|
-
.split('\n')
|
|
78
|
-
.filter(line => !line.match(STACK_TRACE_SANITIZE_REGEXP))
|
|
79
|
-
.join('\n');
|
|
79
|
+
ErrorMonitor.preventInfiniteLoopFlag = true;
|
|
80
80
|
const payload = {
|
|
81
|
-
error
|
|
82
|
-
|
|
83
|
-
stack: sanitizedStack,
|
|
84
|
-
},
|
|
81
|
+
error,
|
|
82
|
+
type: PageVisitErrorSource.UnhandledRejectionError,
|
|
85
83
|
};
|
|
86
|
-
saveErrorToPagevisit(
|
|
84
|
+
saveErrorToPagevisit(payload);
|
|
85
|
+
ErrorMonitor.preventInfiniteLoopFlag = false;
|
|
87
86
|
}
|
|
88
87
|
/**
|
|
89
88
|
* wraps and replaces the addEventListener property
|
|
@@ -101,13 +100,12 @@ class ErrorMonitor extends Singleton {
|
|
|
101
100
|
// the trace message will start with nbuWrapper which would allow us to
|
|
102
101
|
// detect that this is a wrapped function and not a NoibuJS error
|
|
103
102
|
return function nbuWrapper() {
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
ClientConfig.getInstance().wrapInternal('ErrorMonitor.configureEventListeners', () => {
|
|
104
|
+
// eslint-disable-next-line prefer-rest-params
|
|
105
|
+
ErrorMonitor.processErrorLogArguments(Array.from(arguments));
|
|
106
|
+
});
|
|
106
107
|
// eslint-disable-next-line prefer-rest-params
|
|
107
108
|
originalFunction.call(window.console, ...arguments);
|
|
108
|
-
// converting the arguments to an array so that we do not nest argument objects
|
|
109
|
-
// eslint-disable-next-line prefer-rest-params
|
|
110
|
-
ErrorMonitor.processErrorLogArguments(Array.from(arguments));
|
|
111
109
|
};
|
|
112
110
|
});
|
|
113
111
|
});
|
|
@@ -144,7 +142,6 @@ class ErrorMonitor extends Singleton {
|
|
|
144
142
|
* it maps the stack traces to objects with their respective first lines as messages.
|
|
145
143
|
* Otherwise, if there is exactly one stack trace and one error message,
|
|
146
144
|
* it constructs an array with a single object containing the first stack trace and the first error message.
|
|
147
|
-
* @param {Array<string>} args
|
|
148
145
|
*/
|
|
149
146
|
static constructErrors(args) {
|
|
150
147
|
if (args.length === 0) {
|
|
@@ -176,14 +173,6 @@ class ErrorMonitor extends Singleton {
|
|
|
176
173
|
});
|
|
177
174
|
return stacks.map((stack, i) => ({ stack, message: messages[i] }));
|
|
178
175
|
}
|
|
179
|
-
/**
|
|
180
|
-
* returns boolean that indicates wether we should
|
|
181
|
-
* ignore the next error event caught by the error event
|
|
182
|
-
* listener.
|
|
183
|
-
*/
|
|
184
|
-
static shouldIgnoreError() {
|
|
185
|
-
return ignoreError > 0;
|
|
186
|
-
}
|
|
187
176
|
/**
|
|
188
177
|
* transform a log into an error since React hides component errors
|
|
189
178
|
* https://reactjs.org/docs/error-boundaries.html
|
|
@@ -198,9 +187,10 @@ class ErrorMonitor extends Singleton {
|
|
|
198
187
|
if (!stack || !message) {
|
|
199
188
|
return false;
|
|
200
189
|
}
|
|
201
|
-
saveErrorToPagevisit(
|
|
190
|
+
saveErrorToPagevisit({ message, stack, type: PageVisitErrorSource.ErrorLogEvent });
|
|
202
191
|
return true;
|
|
203
192
|
}
|
|
204
193
|
}
|
|
194
|
+
ErrorMonitor.preventInfiniteLoopFlag = false;
|
|
205
195
|
|
|
206
196
|
export { ErrorMonitor };
|
|
@@ -10,9 +10,7 @@ export declare class KeyboardInputMonitor extends Singleton implements Monitor {
|
|
|
10
10
|
* we currently only monitor two input locations: textarea and input
|
|
11
11
|
*/
|
|
12
12
|
monitor(): void;
|
|
13
|
-
/**
|
|
14
|
-
* Validates an event
|
|
15
|
-
*/
|
|
13
|
+
/** Validates an event */
|
|
16
14
|
static handle(uiViewClassName: string, props: {
|
|
17
15
|
placeholder?: string;
|
|
18
16
|
testID?: string;
|