noibu-react-native 0.0.1
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 +155 -0
- package/dist/api/clientConfig.js +416 -0
- package/dist/api/helpCode.js +106 -0
- package/dist/api/inputManager.js +233 -0
- package/dist/api/metroplexSocket.js +882 -0
- package/dist/api/storedMetrics.js +201 -0
- package/dist/api/storedPageVisit.js +235 -0
- package/dist/const_matchers.js +260 -0
- package/dist/constants.d.ts +264 -0
- package/dist/constants.js +528 -0
- package/dist/entry/index.d.ts +8 -0
- package/dist/entry/index.js +15 -0
- package/dist/entry/init.js +91 -0
- package/dist/monitors/clickMonitor.js +284 -0
- package/dist/monitors/elementMonitor.js +174 -0
- package/dist/monitors/errorMonitor.js +295 -0
- package/dist/monitors/gqlErrorValidator.js +306 -0
- package/dist/monitors/httpDataBundler.js +665 -0
- package/dist/monitors/inputMonitor.js +130 -0
- package/dist/monitors/keyboardInputMonitor.js +67 -0
- package/dist/monitors/locationChangeMonitor.js +30 -0
- package/dist/monitors/pageMonitor.js +119 -0
- package/dist/monitors/requestMonitor.js +679 -0
- package/dist/pageVisit/pageVisit.js +172 -0
- package/dist/pageVisit/pageVisitEventError/pageVisitEventError.js +313 -0
- package/dist/pageVisit/pageVisitEventHTTP/pageVisitEventHTTP.js +115 -0
- package/dist/pageVisit/userStep/userStep.js +20 -0
- package/dist/react/ErrorBoundary.d.ts +72 -0
- package/dist/react/ErrorBoundary.js +102 -0
- package/dist/storage/localStorageProvider.js +23 -0
- package/dist/storage/rnStorageProvider.js +62 -0
- package/dist/storage/sessionStorageProvider.js +23 -0
- package/dist/storage/storage.js +119 -0
- package/dist/storage/storageProvider.js +83 -0
- package/dist/utils/date.js +62 -0
- package/dist/utils/eventlistener.js +67 -0
- package/dist/utils/function.js +398 -0
- package/dist/utils/object.js +144 -0
- package/dist/utils/performance.js +21 -0
- package/package.json +57 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import uuid from 'react-native-uuid';
|
|
3
|
+
import InputManager from '../api/inputManager.js';
|
|
4
|
+
|
|
5
|
+
// initial state variables
|
|
6
|
+
const INITIAL_STATE = {
|
|
7
|
+
componentStack: null,
|
|
8
|
+
error: null,
|
|
9
|
+
eventId: null,
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* @description A ErrorBoundary component that logs errors to Noibu. Requires React >= 16.
|
|
13
|
+
* @extends {Component<ErrorBoundaryProps, ErrorBoundaryState>}
|
|
14
|
+
*/
|
|
15
|
+
class ErrorBoundary extends React.Component {
|
|
16
|
+
state = INITIAL_STATE;
|
|
17
|
+
/**
|
|
18
|
+
* Lifecycle hook on mount
|
|
19
|
+
* @returns void
|
|
20
|
+
*/
|
|
21
|
+
componentDidMount() {
|
|
22
|
+
const { onMount } = this.props;
|
|
23
|
+
if (onMount) {
|
|
24
|
+
onMount();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* Handler for all errors that happen in a wrapped component
|
|
30
|
+
* @param {Error&{cause?:Error}} error
|
|
31
|
+
* @param {React.ErrorInfo} {componentStack}
|
|
32
|
+
* @returns void
|
|
33
|
+
*/
|
|
34
|
+
componentDidCatch(error, { componentStack }) {
|
|
35
|
+
const { onError } = this.props;
|
|
36
|
+
InputManager.getInstance()._addErrorFromJSSdk(error, 'ReactError');
|
|
37
|
+
const eventId = uuid.v4();
|
|
38
|
+
if (onError) {
|
|
39
|
+
onError(error, componentStack, eventId);
|
|
40
|
+
}
|
|
41
|
+
// componentDidCatch is used over getDerivedStateFromError
|
|
42
|
+
// so that componentStack is accessible through state.
|
|
43
|
+
this.setState({ error, componentStack, eventId });
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* * Lifecycle hook on unmount
|
|
47
|
+
* @returns void
|
|
48
|
+
*/
|
|
49
|
+
componentWillUnmount() {
|
|
50
|
+
const { error, componentStack, eventId } = this.state;
|
|
51
|
+
const { onUnmount } = this.props;
|
|
52
|
+
if (onUnmount) {
|
|
53
|
+
onUnmount(error, componentStack, eventId);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Callback from fallback to reset the error boundary
|
|
58
|
+
* @param {} =>void=(
|
|
59
|
+
*/
|
|
60
|
+
resetErrorBoundary = () => {
|
|
61
|
+
const { onReset } = this.props;
|
|
62
|
+
const { error, componentStack, eventId } = this.state;
|
|
63
|
+
if (onReset) {
|
|
64
|
+
onReset(error, componentStack, eventId);
|
|
65
|
+
}
|
|
66
|
+
this.setState(INITIAL_STATE);
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
*
|
|
70
|
+
* Renders the fallback ui
|
|
71
|
+
* @returns {React.ReactNode}
|
|
72
|
+
*/
|
|
73
|
+
render() {
|
|
74
|
+
const { fallback, children } = this.props;
|
|
75
|
+
const { error, componentStack, eventId } = this.state;
|
|
76
|
+
if (error) {
|
|
77
|
+
let element;
|
|
78
|
+
if (typeof fallback === 'function') {
|
|
79
|
+
element = fallback({
|
|
80
|
+
error,
|
|
81
|
+
componentStack,
|
|
82
|
+
resetError: this.resetErrorBoundary,
|
|
83
|
+
eventId,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
element = fallback;
|
|
88
|
+
}
|
|
89
|
+
if (React.isValidElement(element)) {
|
|
90
|
+
return element;
|
|
91
|
+
}
|
|
92
|
+
// Fail gracefully if no fallback provided or is not valid
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
if (typeof children === 'function') {
|
|
96
|
+
return children();
|
|
97
|
+
}
|
|
98
|
+
return children;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { ErrorBoundary };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import StorageProvider from './storageProvider.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Local storage provider implementation
|
|
5
|
+
*/
|
|
6
|
+
class LocalStorageProvider extends StorageProvider {
|
|
7
|
+
/**
|
|
8
|
+
* Creates new instance
|
|
9
|
+
*/
|
|
10
|
+
constructor() {
|
|
11
|
+
super(window.localStorage);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Checks if storage is available
|
|
16
|
+
* @returns {Object}
|
|
17
|
+
*/
|
|
18
|
+
static isAvailable() {
|
|
19
|
+
return StorageProvider.isAvailable(() => window.localStorage);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { LocalStorageProvider as default };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import StorageProvider from './storageProvider.js';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line max-classes-per-file
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* React native storage implementation: temporary
|
|
7
|
+
*/
|
|
8
|
+
class RNStorageTmp {
|
|
9
|
+
/** */
|
|
10
|
+
constructor() {
|
|
11
|
+
this._map = new Map();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param key
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
getItem(key) {
|
|
19
|
+
return this._map.get(key);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param key
|
|
24
|
+
* @param value
|
|
25
|
+
* @returns {Map<string, string>}
|
|
26
|
+
*/
|
|
27
|
+
setItem(key, value) {
|
|
28
|
+
return this._map.set(key, value);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param key
|
|
33
|
+
* @returns {boolean}
|
|
34
|
+
*/
|
|
35
|
+
removeItem(key) {
|
|
36
|
+
return this._map.delete(key);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* React native storage provider implementation
|
|
42
|
+
*/
|
|
43
|
+
class RNStorageProvider extends StorageProvider {
|
|
44
|
+
static storage = new RNStorageTmp();
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Creates new instance
|
|
48
|
+
*/
|
|
49
|
+
constructor() {
|
|
50
|
+
super(RNStorageProvider.storage);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Checks if storage is available
|
|
55
|
+
* @returns {Object}
|
|
56
|
+
*/
|
|
57
|
+
static isAvailable() {
|
|
58
|
+
return StorageProvider.isAvailable(() => RNStorageProvider.storage);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { RNStorageProvider as default };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import StorageProvider from './storageProvider.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Session storage provider implementation
|
|
5
|
+
*/
|
|
6
|
+
class SessionStorageProvider extends StorageProvider {
|
|
7
|
+
/**
|
|
8
|
+
* Creates new instance
|
|
9
|
+
*/
|
|
10
|
+
constructor() {
|
|
11
|
+
super(window.sessionStorage);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Checks if storage is available
|
|
16
|
+
* @returns {Object}
|
|
17
|
+
*/
|
|
18
|
+
static isAvailable() {
|
|
19
|
+
return StorageProvider.isAvailable(() => window.sessionStorage);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { SessionStorageProvider as default };
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import LocalStorageProvider from './localStorageProvider.js';
|
|
2
|
+
import SessionStorageProvider from './sessionStorageProvider.js';
|
|
3
|
+
import RNStorageProvider from './rnStorageProvider.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Encapsulates storage api
|
|
7
|
+
*/
|
|
8
|
+
class Storage {
|
|
9
|
+
/**
|
|
10
|
+
* Creates new instance assessing available options
|
|
11
|
+
*/
|
|
12
|
+
constructor() {
|
|
13
|
+
const localStorageAvailability = LocalStorageProvider.isAvailable();
|
|
14
|
+
const sessionStorageAvailability = SessionStorageProvider.isAvailable();
|
|
15
|
+
const rnStorageAvailability = RNStorageProvider.isAvailable();
|
|
16
|
+
this._isLocalStorageAvailable = localStorageAvailability.result;
|
|
17
|
+
this._isSessionStorageAvailable = sessionStorageAvailability.result;
|
|
18
|
+
this._isRNStorageAvailable = rnStorageAvailability.result;
|
|
19
|
+
this._localStorageError = localStorageAvailability.error;
|
|
20
|
+
this._sessionStorageError = sessionStorageAvailability.error;
|
|
21
|
+
this._rnStorageError = rnStorageAvailability.error;
|
|
22
|
+
this._provider = null;
|
|
23
|
+
this._type = 'unavailable';
|
|
24
|
+
|
|
25
|
+
if (this._isLocalStorageAvailable) {
|
|
26
|
+
this._provider = new LocalStorageProvider();
|
|
27
|
+
this._type = 'LocalStorage';
|
|
28
|
+
} else if (this._isSessionStorageAvailable) {
|
|
29
|
+
this._provider = new SessionStorageProvider();
|
|
30
|
+
this._type = 'SessionStorage';
|
|
31
|
+
} else if (this._isRNStorageAvailable) {
|
|
32
|
+
console.log('_isRNStorageAvailable');
|
|
33
|
+
this._provider = new RNStorageProvider();
|
|
34
|
+
this._type = 'RNStorage';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Singleton
|
|
40
|
+
* @returns {Storage}
|
|
41
|
+
*/
|
|
42
|
+
static getInstance() {
|
|
43
|
+
if (!this._instance) {
|
|
44
|
+
this._instance = new Storage();
|
|
45
|
+
}
|
|
46
|
+
return this._instance;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Checks if storage is available
|
|
51
|
+
* @returns {Boolean}
|
|
52
|
+
*/
|
|
53
|
+
isAvailable() {
|
|
54
|
+
return this._provider != null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Loads value from storage
|
|
59
|
+
* @param {String} key
|
|
60
|
+
* @returns {String}
|
|
61
|
+
*/
|
|
62
|
+
load(key) {
|
|
63
|
+
if (this.isAvailable()) {
|
|
64
|
+
return this._provider.load(key);
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Saves value to storage
|
|
71
|
+
* @param {String} key
|
|
72
|
+
* @param {String} value
|
|
73
|
+
*/
|
|
74
|
+
save(key, value) {
|
|
75
|
+
if (this.isAvailable()) {
|
|
76
|
+
this._provider.save(key, value);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Removes value from storage
|
|
82
|
+
* @param {String} key
|
|
83
|
+
*/
|
|
84
|
+
remove(key) {
|
|
85
|
+
if (this.isAvailable()) {
|
|
86
|
+
this._provider.remove(key);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Calculates used scape
|
|
92
|
+
* @returns {Number}
|
|
93
|
+
*/
|
|
94
|
+
calculateUsedSize() {
|
|
95
|
+
if (this.isAvailable()) {
|
|
96
|
+
return this._provider.calculateUsedSize();
|
|
97
|
+
}
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Returns string indicating current provider type
|
|
103
|
+
* and availability for other storage types
|
|
104
|
+
* @returns {String}
|
|
105
|
+
*/
|
|
106
|
+
getDiagnoseInfo() {
|
|
107
|
+
return (
|
|
108
|
+
`storage provider: ${this._type} ` +
|
|
109
|
+
`(localStorage available: ${this._isLocalStorageAvailable}, ` +
|
|
110
|
+
`error: ${this._localStorageError}) ` +
|
|
111
|
+
`(sessionStorage available: ${this._isSessionStorageAvailable}, ` +
|
|
112
|
+
`error: ${this._sessionStorageError})` +
|
|
113
|
+
`(rnStorage available: ${this._isRNStorageAvailable}, ` +
|
|
114
|
+
`error: ${this._rnStorageError})`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export { Storage as default };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { NOIBU_LOCAL_STORAGE_TEST_KEY } from '../constants.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base implementation for LocalStorage and SessionStorage
|
|
5
|
+
*/
|
|
6
|
+
class StorageProvider {
|
|
7
|
+
/**
|
|
8
|
+
* Creates new instance based on provided provider type
|
|
9
|
+
* @param {WindowLocalStorage|WindowSessionStorage|RNStorageTmp} provider
|
|
10
|
+
*/
|
|
11
|
+
constructor(provider) {
|
|
12
|
+
this._provider = provider;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks if provider is available
|
|
17
|
+
* @param {Function} function that returns storage instance
|
|
18
|
+
* @return {Object} { result: true|false, error: null|Error }
|
|
19
|
+
*/
|
|
20
|
+
static isAvailable(resolver) {
|
|
21
|
+
let result = true;
|
|
22
|
+
let error = null;
|
|
23
|
+
try {
|
|
24
|
+
// access to localStorage/sessionStorage may throw an error
|
|
25
|
+
// so use function to resolve it wrapped with try/catch
|
|
26
|
+
const provider = resolver();
|
|
27
|
+
console.log({ provider, providerset: provider.setItem });
|
|
28
|
+
provider.setItem(NOIBU_LOCAL_STORAGE_TEST_KEY, 0);
|
|
29
|
+
provider.removeItem(NOIBU_LOCAL_STORAGE_TEST_KEY);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
result = false;
|
|
32
|
+
error = e;
|
|
33
|
+
}
|
|
34
|
+
return { result, error };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Loads value from storage
|
|
39
|
+
* @param {String} key
|
|
40
|
+
* @returns {String}
|
|
41
|
+
*/
|
|
42
|
+
load(key) {
|
|
43
|
+
return this._provider.getItem(key);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Saves value to storage
|
|
48
|
+
* @param {String} key
|
|
49
|
+
* @param {String} value
|
|
50
|
+
*/
|
|
51
|
+
save(key, value) {
|
|
52
|
+
this._provider.setItem(key, value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Removes value from storage
|
|
57
|
+
* @param {String} key
|
|
58
|
+
*/
|
|
59
|
+
remove(key) {
|
|
60
|
+
this._provider.removeItem(key);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Calculates used scape
|
|
65
|
+
* @returns {Number}
|
|
66
|
+
*/
|
|
67
|
+
calculateUsedSize() {
|
|
68
|
+
let size = 0;
|
|
69
|
+
for (let i = 0; i < this._provider.length; i++) {
|
|
70
|
+
const key = this._provider.key(i);
|
|
71
|
+
if (key) {
|
|
72
|
+
size += key.length;
|
|
73
|
+
const value = this._provider.getItem(key);
|
|
74
|
+
if (value) {
|
|
75
|
+
size += value.length;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return size;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { StorageProvider as default };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import ClientConfig from '../api/clientConfig.js';
|
|
2
|
+
import { SEVERITY_ERROR } from '../constants.js';
|
|
3
|
+
|
|
4
|
+
/** @module Date */
|
|
5
|
+
|
|
6
|
+
/** Checks to see if the necessary Date functions that we use have been overwritten */
|
|
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;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Timestamp wrapper to properly handle timestamps
|
|
34
|
+
* @param {} timestamp
|
|
35
|
+
*/
|
|
36
|
+
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.
|
|
52
|
+
Client has been disabled.`,
|
|
53
|
+
true,
|
|
54
|
+
SEVERITY_ERROR,
|
|
55
|
+
true,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return timestamp;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { isDateOverwritten, timestampWrapper };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { SEVERITY_ERROR } from '../constants.js';
|
|
2
|
+
import ClientConfig from '../api/clientConfig.js';
|
|
3
|
+
|
|
4
|
+
/** addSafeEventListener will add an event listener for the specified event
|
|
5
|
+
* but will catch and log any errors encountered
|
|
6
|
+
* @param {} object to attach the listener to
|
|
7
|
+
* @param {} event to listen to
|
|
8
|
+
* @param {} callback function to call
|
|
9
|
+
* @param {} capture additional arguments
|
|
10
|
+
*/
|
|
11
|
+
function addSafeEventListener(object, event, callback, capture) {
|
|
12
|
+
if (!object || !event || !callback) {
|
|
13
|
+
// nothing to do if these don't exist
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** safeCallback will catch and log any errors encountered on the callback
|
|
18
|
+
* @param {} eventReceived for the callback
|
|
19
|
+
*/
|
|
20
|
+
const safeCallback = eventReceived => {
|
|
21
|
+
try {
|
|
22
|
+
callback(eventReceived);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
|
|
25
|
+
`addEventListener callback error: ${e.message}`,
|
|
26
|
+
false,
|
|
27
|
+
SEVERITY_ERROR,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* tries to add an event listener to a Proxy object
|
|
34
|
+
*/
|
|
35
|
+
const tryAddEventListenerForProxy = () => {
|
|
36
|
+
if (!Reflect) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const addEventListener =
|
|
42
|
+
Reflect.get(object, 'addEventListener') || (() => {});
|
|
43
|
+
addEventListener(event, safeCallback, capture);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return true;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
object.addEventListener(event, safeCallback, capture);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
if (e instanceof TypeError) {
|
|
55
|
+
if (tryAddEventListenerForProxy()) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
|
|
60
|
+
`addEventListener error: ${e.message}`,
|
|
61
|
+
false,
|
|
62
|
+
SEVERITY_ERROR,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { addSafeEventListener };
|