noibu-react-native 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/android/src/main/java/com/noibu/sessionreplay/reactnative/NoibuSessionReplayModule.kt +10 -0
- package/dist/api/clientConfig.js +225 -217
- package/dist/api/metroplexSocket.js +406 -416
- package/dist/constants.js +14 -2
- package/dist/entry/init.js +58 -56
- package/dist/monitors/appNavigationMonitor.js +2 -3
- package/dist/monitors/clickMonitor.js +16 -9
- package/dist/monitors/errorMonitor.js +30 -8
- package/dist/monitors/gqlErrorValidator.js +4 -4
- package/dist/monitors/httpDataBundler.js +525 -713
- package/dist/monitors/integrations/react-native-navigation-integration.js +4 -2
- package/dist/monitors/requestMonitor.js +350 -365
- package/dist/pageVisit/eventDebouncer.js +110 -0
- package/dist/pageVisit/pageVisitEventError.js +1 -1
- package/dist/pageVisit/pageVisitEventHTTP.js +78 -93
- package/dist/react/ErrorBoundary.js +18 -15
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -2
- package/dist/sessionRecorder/sessionRecorder.js +151 -150
- package/dist/{api → src/api}/clientConfig.d.ts +1 -1
- package/dist/{api → src/api}/metroplexSocket.d.ts +25 -25
- package/dist/{constants.d.ts → src/constants.d.ts} +44 -0
- package/dist/{entry → src/entry}/init.d.ts +1 -1
- package/dist/{monitors → src/monitors}/clickMonitor.d.ts +1 -1
- package/dist/{monitors → src/monitors}/gqlErrorValidator.d.ts +6 -6
- package/dist/src/monitors/httpDataBundler.d.ts +127 -0
- package/dist/src/monitors/requestMonitor.d.ts +10 -0
- package/dist/src/pageVisit/eventDebouncer.d.ts +31 -0
- package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +25 -0
- package/dist/{sessionRecorder → src/sessionRecorder}/types.d.ts +1 -1
- package/dist/{storage → src/storage}/rnStorageProvider.d.ts +1 -1
- package/dist/{storage → src/storage}/storage.d.ts +1 -1
- package/dist/{storage → src/storage}/storageProvider.d.ts +3 -3
- package/dist/{utils → src/utils}/function.d.ts +25 -4
- package/dist/{utils → src/utils}/object.d.ts +9 -4
- package/dist/src/utils/piiRedactor.d.ts +11 -0
- package/dist/src/utils/polyfills.d.ts +7 -0
- package/dist/storage/rnStorageProvider.js +7 -5
- package/dist/storage/storage.js +43 -35
- package/dist/storage/storageProvider.js +23 -19
- package/dist/types/Config.d.ts +24 -20
- package/dist/types/PageVisit.types.d.ts +151 -0
- package/dist/types/PageVisitMetrics.types.d.ts +27 -0
- package/dist/types/RRWeb.d.ts +48 -0
- package/dist/types/StoredPageVisit.types.d.ts +2 -4
- package/dist/types/WrappedObjects.d.ts +6 -0
- package/dist/utils/function.js +110 -76
- package/dist/utils/object.js +58 -6
- package/dist/utils/piiRedactor.js +98 -0
- package/dist/utils/polyfills.js +24 -0
- package/package.json +24 -9
- package/dist/monitors/httpDataBundler.d.ts +0 -161
- package/dist/monitors/requestMonitor.d.ts +0 -10
- package/dist/pageVisit/pageVisitEventHTTP.d.ts +0 -18
- package/dist/types/PageVisit.d.ts +0 -22
- package/dist/types/globals.d.ts +0 -45
- /package/dist/{api → src/api}/helpCode.d.ts +0 -0
- /package/dist/{api → src/api}/inputManager.d.ts +0 -0
- /package/dist/{api → src/api}/storedMetrics.d.ts +0 -0
- /package/dist/{api → src/api}/storedPageVisit.d.ts +0 -0
- /package/dist/{const_matchers.d.ts → src/const_matchers.d.ts} +0 -0
- /package/dist/{entry → src/entry}/index.d.ts +0 -0
- /package/dist/{monitors → src/monitors}/appNavigationMonitor.d.ts +0 -0
- /package/dist/{monitors → src/monitors}/errorMonitor.d.ts +0 -0
- /package/dist/{monitors → src/monitors}/inputMonitor.d.ts +0 -0
- /package/dist/{monitors → src/monitors}/integrations/react-native-navigation-integration.d.ts +0 -0
- /package/dist/{monitors → src/monitors}/keyboardInputMonitor.d.ts +0 -0
- /package/dist/{monitors → src/monitors}/pageMonitor.d.ts +0 -0
- /package/dist/{pageVisit → src/pageVisit}/pageVisit.d.ts +0 -0
- /package/dist/{pageVisit → src/pageVisit}/pageVisitEventError.d.ts +0 -0
- /package/dist/{pageVisit → src/pageVisit}/userStep.d.ts +0 -0
- /package/dist/{react → src/react}/ErrorBoundary.d.ts +0 -0
- /package/dist/{sessionRecorder → src/sessionRecorder}/nativeSessionRecorderSubscription.d.ts +0 -0
- /package/dist/{sessionRecorder → src/sessionRecorder}/sessionRecorder.d.ts +0 -0
- /package/dist/{utils → src/utils}/date.d.ts +0 -0
- /package/dist/{utils → src/utils}/eventlistener.d.ts +0 -0
- /package/dist/{utils → src/utils}/log.d.ts +0 -0
- /package/dist/{utils → src/utils}/performance.d.ts +0 -0
- /package/dist/{utils → src/utils}/stacktrace-parser.d.ts +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { PageVisit } from './pageVisit.js';
|
|
2
|
+
import { LOCATION_EVENT_TYPE, TITLE_EVENT_TYPE, PAGE_TYPE_EVENT_TYPE, PAGE_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS, ERROR_EVENT_TYPE, HTTP_EVENT_TYPE, NETWORK_STATS_EVENT_TYPE, KEYBOARD_EVENT_TYPE, USERSTEP_EVENT_TYPE, ECOMMERCE_EVENT_TYPE, SEVERITY } from '../constants.js';
|
|
3
|
+
import { timestampWrapper } from '../utils/date.js';
|
|
4
|
+
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
5
|
+
import ClientConfig from '../api/clientConfig.js';
|
|
6
|
+
|
|
7
|
+
/** @module EventDebouncer */
|
|
8
|
+
/**
|
|
9
|
+
* Singleton class responsible for debouncing all events
|
|
10
|
+
* that are registered
|
|
11
|
+
*/
|
|
12
|
+
class EventDebouncer {
|
|
13
|
+
/**
|
|
14
|
+
* Creates an instance of EventDebouncer
|
|
15
|
+
*/
|
|
16
|
+
constructor() {
|
|
17
|
+
// events are stored in queues that are debounced seperatly
|
|
18
|
+
// each object in this map is
|
|
19
|
+
// type: {
|
|
20
|
+
// timeout: timeout,
|
|
21
|
+
// events: [...],
|
|
22
|
+
// debouncePeriod: period at which we debounce events,
|
|
23
|
+
// eventName: name of the event, could be different than type
|
|
24
|
+
// (clicks and keyboards are usersteps)
|
|
25
|
+
// }
|
|
26
|
+
this.eventsToDebounce = {};
|
|
27
|
+
// setting up debouncers for all events
|
|
28
|
+
// we send clicks directly to the socket so they aren't registered here
|
|
29
|
+
// we dont wait to send location changes, they happen at most once per second.
|
|
30
|
+
this.registerInputType(LOCATION_EVENT_TYPE, 0);
|
|
31
|
+
this.registerInputType(TITLE_EVENT_TYPE, 0);
|
|
32
|
+
this.registerInputType(PAGE_TYPE_EVENT_TYPE, 0);
|
|
33
|
+
this.registerInputType(PAGE_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS);
|
|
34
|
+
this.registerInputType(ERROR_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS);
|
|
35
|
+
this.registerInputType(HTTP_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS);
|
|
36
|
+
this.registerInputType(NETWORK_STATS_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS);
|
|
37
|
+
this.registerInputType(KEYBOARD_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS, USERSTEP_EVENT_TYPE);
|
|
38
|
+
this.registerInputType(ECOMMERCE_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS);
|
|
39
|
+
this._setupUnloadHandler();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* gets the instance of EventDebouncer
|
|
43
|
+
*/
|
|
44
|
+
static getInstance() {
|
|
45
|
+
if (!this.instance) {
|
|
46
|
+
this.instance = new EventDebouncer();
|
|
47
|
+
}
|
|
48
|
+
return this.instance;
|
|
49
|
+
}
|
|
50
|
+
/** will debounce all events that are of this type by the debounce period
|
|
51
|
+
*/
|
|
52
|
+
registerInputType(type, debouncePeriod, eventName = type) {
|
|
53
|
+
if (type in this.eventsToDebounce) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// registering this event type as a debouncable
|
|
57
|
+
this.eventsToDebounce[type] = {
|
|
58
|
+
timeout: null,
|
|
59
|
+
events: [],
|
|
60
|
+
debouncePeriod,
|
|
61
|
+
eventName,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Creates an event object with the event and the time it was added then pushes
|
|
66
|
+
* that event object to the queue of events waiting to be debounced.
|
|
67
|
+
*/
|
|
68
|
+
addEvent(event, type, occurredAt) {
|
|
69
|
+
if (!(type in this.eventsToDebounce)) {
|
|
70
|
+
ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(new Error(`Type: ${type} is not in eventsToDebounce`), false, SEVERITY.error);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (!occurredAt) {
|
|
74
|
+
occurredAt = Date.now();
|
|
75
|
+
}
|
|
76
|
+
this.eventsToDebounce[type].events.push({
|
|
77
|
+
event,
|
|
78
|
+
occurredAt: new Date(timestampWrapper(occurredAt)).toISOString(),
|
|
79
|
+
});
|
|
80
|
+
this._debouncePvEvents(type);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Adds the events from the object to the page visit and sets up a timer
|
|
84
|
+
* to send the events if no more are received without the timeout
|
|
85
|
+
*/
|
|
86
|
+
_debouncePvEvents(type) {
|
|
87
|
+
/**
|
|
88
|
+
* Debounce function to be executed once the debounce period is completed
|
|
89
|
+
*/
|
|
90
|
+
const later = () => {
|
|
91
|
+
this.eventsToDebounce[type].timeout = null;
|
|
92
|
+
PageVisit.getInstance().addPageVisitEvents(this.eventsToDebounce[type].events, this.eventsToDebounce[type].eventName);
|
|
93
|
+
this.eventsToDebounce[type].events = [];
|
|
94
|
+
};
|
|
95
|
+
if (this.eventsToDebounce[type].timeout !== null) {
|
|
96
|
+
clearTimeout(this.eventsToDebounce[type].timeout);
|
|
97
|
+
}
|
|
98
|
+
this.eventsToDebounce[type].timeout = setTimeout(later, this.eventsToDebounce[type].debouncePeriod);
|
|
99
|
+
}
|
|
100
|
+
/** Sets up the page hide handler to try to push remaining events in the queues */
|
|
101
|
+
_setupUnloadHandler() {
|
|
102
|
+
addSafeEventListener(window, 'pagehide', () => {
|
|
103
|
+
Object.values(this.eventsToDebounce).forEach(eventObject => {
|
|
104
|
+
PageVisit.getInstance().addPageVisitEvents(eventObject.events, eventObject.eventName);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { EventDebouncer };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isValidURL, getJSStack, stringifyJSON, getMaxSubstringAllowed, asString } from '../utils/function.js';
|
|
2
|
-
import { EVENT_ERROR_TYPE, URL_ATT_NAME, BLOCKLISTED_DOMAINS, ERROR_EVENT_TYPE, ERROR_EVENT_ERROR_TYPE, CUSTOM_ERROR_EVENT_TYPE, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, ERROR_LOG_EVENT_ERROR_TYPE, FETCH_EXCEPTION_ERROR_TYPE, WRAPPED_EXCEPTION_ERROR_TYPE, GQL_ERROR_TYPE, RESPONSE_ERROR_TYPE, XML_HTTP_REQUEST_ERROR_TYPE, ERROR_SOURCE_ATT_NAME, TYPE_ATT_NAME, JS_EVENT_TYPE, JS_ERROR_ATT_NAME, JS_STACK_FRAMES_ATT_NAME, JS_STACK_FILE_ATT_NAME, JS_STACK_METHOD_ATT_NAME, SEVERITY, JS_STACK_MESSAGE_ATT_NAME, HTTP_EVENT_TYPE, NOIBU_INPUT_URLS, HTTP_CODE_ATT_NAME,
|
|
2
|
+
import { EVENT_ERROR_TYPE, URL_ATT_NAME, BLOCKLISTED_DOMAINS, ERROR_EVENT_TYPE, ERROR_EVENT_ERROR_TYPE, CUSTOM_ERROR_EVENT_TYPE, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, ERROR_LOG_EVENT_ERROR_TYPE, FETCH_EXCEPTION_ERROR_TYPE, WRAPPED_EXCEPTION_ERROR_TYPE, GQL_ERROR_TYPE, RESPONSE_ERROR_TYPE, XML_HTTP_REQUEST_ERROR_TYPE, ERROR_SOURCE_ATT_NAME, TYPE_ATT_NAME, JS_EVENT_TYPE, JS_ERROR_ATT_NAME, JS_STACK_FRAMES_ATT_NAME, JS_STACK_FILE_ATT_NAME, JS_STACK_METHOD_ATT_NAME, SEVERITY, JS_STACK_MESSAGE_ATT_NAME, HTTP_EVENT_TYPE, NOIBU_INPUT_URLS, HTTP_CODE_ATT_NAME, GQL_EVENT_TYPE, GQL_ERROR_ATT_NAME, PV_SEQ_ATT_NAME } from '../constants.js';
|
|
3
3
|
import ClientConfig from '../api/clientConfig.js';
|
|
4
4
|
import { InputMonitor } from '../monitors/inputMonitor.js';
|
|
5
5
|
import StoredMetrics from '../api/storedMetrics.js';
|
|
@@ -1,112 +1,97 @@
|
|
|
1
|
-
import { getMaxSubstringAllowed, asString } from '../utils/function.js';
|
|
2
1
|
import { timestampWrapper } from '../utils/date.js';
|
|
3
|
-
import {
|
|
4
|
-
import { HTTP_METHOD_ATT_NAME, MAX_HTTP_DATA_EVENT_COUNT, PV_SEQ_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_EVENT_TYPE, PAGE_VISIT_HTTP_DATA_ATT_NAME } from '../constants.js';
|
|
2
|
+
import { HTTP_RESP_CODE_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HTTP_METHOD_ATT_NAME, URL_ATT_NAME, PV_SEQ_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_EVENT_TYPE, MAX_HTTP_DATA_EVENT_COUNT, MAX_HTTP_DATA_IF_ERROR_EVENT_COUNT, PAGE_VISIT_HTTP_DATA_ATT_NAME } from '../constants.js';
|
|
5
3
|
import { PageVisit } from './pageVisit.js';
|
|
6
4
|
import StoredMetrics from '../api/storedMetrics.js';
|
|
7
5
|
import MetroplexSocket from '../api/metroplexSocket.js';
|
|
8
|
-
import {
|
|
6
|
+
import { getMaxSubstringAllowed, asString, safeTrim } from '../utils/function.js';
|
|
7
|
+
import { EventDebouncer } from './eventDebouncer.js';
|
|
9
8
|
|
|
10
9
|
/** @module PageVisitEventHTTP */
|
|
11
|
-
|
|
12
10
|
/**
|
|
13
11
|
* Determines if a response is a failure
|
|
14
|
-
* @param {number} code
|
|
15
12
|
*/
|
|
16
13
|
function isHttpCodeFailure(code) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return code >= 400 || code <= 0;
|
|
14
|
+
if (typeof code !== 'number') {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return code >= 400 || code <= 0;
|
|
22
18
|
}
|
|
23
|
-
|
|
24
19
|
/** Class representing a PageVisitEventHTTP */
|
|
25
20
|
class PageVisitEventHTTP {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
mutatedHttpEvent[HTTP_METHOD_ATT_NAME] =
|
|
41
|
-
httpEvent[HTTP_METHOD_ATT_NAME].toUpperCase();
|
|
42
|
-
|
|
43
|
-
mutatedHttpEvent.url = getMaxSubstringAllowed(
|
|
44
|
-
asString(mutatedHttpEvent.url),
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
this.httpEvent = mutatedHttpEvent;
|
|
48
|
-
this.httpData = httpData;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Saves the HTTP event to the pageVisit Queue */
|
|
52
|
-
saveHTTPEvent() {
|
|
53
|
-
noibuLog('saveHTTPEvent');
|
|
54
|
-
// we do not store http events that have empty urls
|
|
55
|
-
if (
|
|
56
|
-
!this.httpEvent ||
|
|
57
|
-
!this.httpEvent.url ||
|
|
58
|
-
this.httpEvent.url.trim() === ''
|
|
59
|
-
) {
|
|
60
|
-
noibuLog('saveHTTPEvent dropped due to empty url');
|
|
61
|
-
return;
|
|
21
|
+
/**
|
|
22
|
+
* Creates an instance of the http event for the pv
|
|
23
|
+
*/
|
|
24
|
+
constructor(httpEvent, httpData, isGqlError = false) {
|
|
25
|
+
/** if no value or it's less than 0, fallback to 0 */
|
|
26
|
+
const validate = (value) => (!value || value < 0 ? 0 : value);
|
|
27
|
+
this.httpEvent = {
|
|
28
|
+
[HTTP_RESP_CODE_ATT_NAME]: validate(httpEvent[HTTP_RESP_CODE_ATT_NAME]),
|
|
29
|
+
[HTTP_RESP_TIME_ATT_NAME]: validate(httpEvent[HTTP_RESP_TIME_ATT_NAME]),
|
|
30
|
+
[HTTP_METHOD_ATT_NAME]: (httpEvent[HTTP_METHOD_ATT_NAME] || 'get').toUpperCase(),
|
|
31
|
+
[URL_ATT_NAME]: getMaxSubstringAllowed(asString(httpEvent[URL_ATT_NAME])),
|
|
32
|
+
};
|
|
33
|
+
this.httpData = httpData;
|
|
34
|
+
this.isGqlError = isGqlError;
|
|
62
35
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
36
|
+
/** Saves the HTTP event to the pageVisit Queue */
|
|
37
|
+
saveHTTPEvent() {
|
|
38
|
+
// we do not store http events that have empty urls
|
|
39
|
+
if (!this.httpEvent || !safeTrim(this.httpEvent[URL_ATT_NAME])) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// we register an http event
|
|
43
|
+
StoredMetrics.getInstance().addHttpEvent();
|
|
44
|
+
const status = this.httpEvent[HTTP_RESP_CODE_ATT_NAME];
|
|
45
|
+
// send http data down to metroplex
|
|
46
|
+
if (this.httpData) {
|
|
47
|
+
// add the sequence number to both events
|
|
48
|
+
const sequenceNumber = StoredMetrics.getInstance().httpSequenceNumber;
|
|
49
|
+
const isSendAllowed = PageVisitEventHTTP.isSendAllowed(status, sequenceNumber, this.isGqlError);
|
|
50
|
+
// restrict total number of events collected per page visit to ensure we don't
|
|
51
|
+
// blow up memory and storage usage
|
|
52
|
+
if (isSendAllowed) {
|
|
53
|
+
this.httpData[PV_SEQ_ATT_NAME] = sequenceNumber;
|
|
54
|
+
this.httpEvent[PV_SEQ_ATT_NAME] = sequenceNumber;
|
|
55
|
+
// increment the count
|
|
56
|
+
StoredMetrics.getInstance().addHttpData();
|
|
57
|
+
const metroplexMsg = {};
|
|
58
|
+
metroplexMsg[PAGE_VISIT_HTTP_DATA_ATT_NAME] = this.httpData;
|
|
59
|
+
MetroplexSocket.getInstance().sendMessage(HTTP_DATA_METROPLEX_TYPE, metroplexMsg);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// have collected more than the max number of http requests for this
|
|
63
|
+
// page visit, so increment the over request limit count
|
|
64
|
+
StoredMetrics.getInstance().addHttpDataOverLimit();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// if this was an error, send immediately so we don't lose it
|
|
68
|
+
if (isHttpCodeFailure(status)) {
|
|
69
|
+
PageVisit.getInstance().addPageVisitEvent({
|
|
70
|
+
event: this.httpEvent,
|
|
71
|
+
occurredAt: new Date(timestampWrapper(Date.now())).toISOString(),
|
|
72
|
+
}, HTTP_EVENT_TYPE);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// debounce event
|
|
76
|
+
EventDebouncer.getInstance().addEvent(this.httpEvent, HTTP_EVENT_TYPE);
|
|
93
77
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Checks if sending data is allowed based on the HTTP status code and count.
|
|
80
|
+
* status - The HTTP status code to evaluate.
|
|
81
|
+
* count - The count of events to consider.
|
|
82
|
+
* isGqlError - Whether the context is considered as a GQL error.
|
|
83
|
+
* Returns `true` if sending data is allowed, `false` otherwise.
|
|
84
|
+
*/
|
|
85
|
+
static isSendAllowed(status, count, isGqlError = false) {
|
|
86
|
+
const isFailure = isHttpCodeFailure(status) || isGqlError;
|
|
87
|
+
const isSuccess = !isFailure;
|
|
88
|
+
if (isSuccess) {
|
|
89
|
+
if (count < MAX_HTTP_DATA_EVENT_COUNT) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return isFailure && count < MAX_HTTP_DATA_IF_ERROR_EVENT_COUNT;
|
|
105
94
|
}
|
|
106
|
-
|
|
107
|
-
// debounce event
|
|
108
|
-
InputMonitor.getInstance().addEvent(this.httpEvent, HTTP_EVENT_TYPE);
|
|
109
|
-
}
|
|
110
95
|
}
|
|
111
96
|
|
|
112
97
|
export { PageVisitEventHTTP, isHttpCodeFailure };
|
|
@@ -13,7 +13,24 @@ const INITIAL_STATE = {
|
|
|
13
13
|
* @extends {Component<ErrorBoundaryProps, ErrorBoundaryState>}
|
|
14
14
|
*/
|
|
15
15
|
class ErrorBoundary extends React.Component {
|
|
16
|
-
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.state = INITIAL_STATE;
|
|
19
|
+
/**
|
|
20
|
+
* Callback from fallback to reset the error boundary
|
|
21
|
+
* @param {} =>void=(
|
|
22
|
+
*/
|
|
23
|
+
this.resetErrorBoundary = () => {
|
|
24
|
+
const { onReset } = this.props;
|
|
25
|
+
const { error, componentStack, eventId } = this.state;
|
|
26
|
+
if (onReset) {
|
|
27
|
+
if (typeof componentStack === 'string') {
|
|
28
|
+
onReset(error, componentStack, eventId);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
this.setState(INITIAL_STATE);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
17
34
|
/**
|
|
18
35
|
* Lifecycle hook on mount
|
|
19
36
|
* @returns void
|
|
@@ -57,20 +74,6 @@ class ErrorBoundary extends React.Component {
|
|
|
57
74
|
}
|
|
58
75
|
}
|
|
59
76
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Callback from fallback to reset the error boundary
|
|
62
|
-
* @param {} =>void=(
|
|
63
|
-
*/
|
|
64
|
-
resetErrorBoundary = () => {
|
|
65
|
-
const { onReset } = this.props;
|
|
66
|
-
const { error, componentStack, eventId } = this.state;
|
|
67
|
-
if (onReset) {
|
|
68
|
-
if (typeof componentStack === 'string') {
|
|
69
|
-
onReset(error, componentStack, eventId);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
this.setState(INITIAL_STATE);
|
|
73
|
-
};
|
|
74
77
|
/**
|
|
75
78
|
*
|
|
76
79
|
* Renders the fallback ui
|
|
@@ -32,7 +32,7 @@ function initialize(projectId, config) {
|
|
|
32
32
|
}
|
|
33
33
|
nativeModuleEmitter = new NativeEventEmitter(NativeSessionRecorder);
|
|
34
34
|
// applying default values
|
|
35
|
-
const { userId = null, logLevel = LogLevel.None, allowMeteredNetworkUsage = false, enableWebViewCapture = true, allowedDomains = ['*'], disableOnLowEndDevices = false, maximumDailyNetworkUsageInMB = null, } = config
|
|
35
|
+
const { userId = null, logLevel = LogLevel.None, allowMeteredNetworkUsage = false, enableWebViewCapture = true, allowedDomains = ['*'], disableOnLowEndDevices = false, maximumDailyNetworkUsageInMB = null, } = config !== null && config !== void 0 ? config : {};
|
|
36
36
|
if (!SupportedPlatforms.includes(Platform.OS)) {
|
|
37
37
|
noibuLog(`Noibu - Session recording supports ${SupportedPlatforms.join(', ')} only for now.`);
|
|
38
38
|
return;
|
|
@@ -43,13 +43,14 @@ function initialize(projectId, config) {
|
|
|
43
43
|
}
|
|
44
44
|
// We use two parameters because the react method parameters do not accept nullable primitive types.
|
|
45
45
|
const enableDailyNetworkUsageLimit = maximumDailyNetworkUsageInMB != null;
|
|
46
|
-
const refinedMaximumDailyNetworkUsageInMB = maximumDailyNetworkUsageInMB
|
|
46
|
+
const refinedMaximumDailyNetworkUsageInMB = maximumDailyNetworkUsageInMB !== null && maximumDailyNetworkUsageInMB !== void 0 ? maximumDailyNetworkUsageInMB : 0;
|
|
47
47
|
NativeSessionRecorder.initialize(projectId, userId, logLevel, allowMeteredNetworkUsage, enableWebViewCapture, allowedDomains, disableOnLowEndDevices, enableDailyNetworkUsageLimit, refinedMaximumDailyNetworkUsageInMB);
|
|
48
48
|
}
|
|
49
49
|
function subscribeToNativeEvent(callback) {
|
|
50
50
|
if (!nativeModuleEmitter) {
|
|
51
51
|
throw new Error('You have to initialize Noibu Session Recorder first');
|
|
52
52
|
}
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
53
54
|
nativeModuleEmitter.addListener('noibuRecordingEvent', callback);
|
|
54
55
|
// return () => subscription.remove();
|
|
55
56
|
return () => { };
|