noibu-react-native 0.2.5 → 0.2.7
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/api/{clientConfig.js → ClientConfig.js} +69 -52
- package/dist/api/{helpCode.js → HelpCode.js} +6 -13
- package/dist/api/InputManager.js +156 -0
- package/dist/api/{metroplexSocket.js → MetroplexSocket.js} +189 -178
- package/dist/api/StoredMetrics.js +158 -0
- package/dist/api/{storedPageVisit.js → StoredPageVisit.js} +61 -48
- package/dist/const_matchers.js +1 -5
- package/dist/constants.js +15 -390
- package/dist/entry/index.js +3 -4
- package/dist/entry/init.js +33 -19
- package/dist/monitors/AppNavigationMonitor.js +19 -19
- package/dist/monitors/BaseMonitor.js +9 -4
- package/dist/monitors/ClickMonitor.js +72 -76
- package/dist/monitors/ErrorMonitor.js +45 -55
- package/dist/monitors/KeyboardInputMonitor.js +13 -11
- package/dist/monitors/PageMonitor.js +25 -2
- package/dist/monitors/RequestMonitor.js +46 -57
- package/dist/monitors/http-tools/GqlErrorValidator.js +39 -69
- package/dist/monitors/http-tools/HTTPDataBundler.js +71 -66
- package/dist/monitors/integrations/{react-native-navigation-integration.js → ReactNativeNavigationIntegration.js} +15 -12
- package/dist/pageVisit/EventDebouncer.js +43 -74
- package/dist/pageVisit/HttpEventManager.js +88 -0
- package/dist/pageVisit/PageVisitManager.js +99 -0
- package/dist/pageVisit/pageVisitEventError.js +170 -280
- package/dist/react/ErrorBoundary.js +3 -6
- package/dist/sessionRecorder/{sessionRecorder.js → SessionRecorder.js} +58 -70
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -5
- package/dist/storage/{rnStorageProvider.js → RNStorageProvider.js} +3 -7
- package/dist/storage/{storage.js → Storage.js} +17 -30
- package/dist/storage/{storageProvider.js → StorageProvider.js} +7 -8
- package/dist/utils/date.js +39 -50
- package/dist/utils/eventlistener.js +5 -12
- package/dist/utils/function.js +42 -113
- package/dist/utils/log.js +5 -5
- package/dist/utils/object.js +12 -12
- package/dist/utils/piiRedactor.js +31 -3
- package/dist/utils/stacktrace-parser.js +29 -21
- 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/clientConfig.d.ts +0 -100
- package/dist/src/api/clientConfig.test.d.ts +0 -1
- package/dist/src/api/helpCode.d.ts +0 -23
- package/dist/src/api/inputManager.d.ts +0 -87
- package/dist/src/api/metroplexSocket.d.ts +0 -137
- package/dist/src/api/storedMetrics.d.ts +0 -73
- package/dist/src/api/storedPageVisit.d.ts +0 -40
- package/dist/src/const_matchers.d.ts +0 -1
- package/dist/src/constants.d.ts +0 -290
- package/dist/src/entry/index.d.ts +0 -14
- package/dist/src/entry/init.d.ts +0 -5
- package/dist/src/monitors/AppNavigationMonitor.d.ts +0 -18
- package/dist/src/monitors/BaseMonitor.d.ts +0 -13
- package/dist/src/monitors/BaseMonitor.test.d.ts +0 -1
- package/dist/src/monitors/ClickMonitor.d.ts +0 -31
- package/dist/src/monitors/ErrorMonitor.d.ts +0 -63
- package/dist/src/monitors/KeyboardInputMonitor.d.ts +0 -20
- package/dist/src/monitors/PageMonitor.d.ts +0 -20
- package/dist/src/monitors/RequestMonitor.d.ts +0 -94
- package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +0 -59
- package/dist/src/monitors/http-tools/HTTPDataBundler.d.ts +0 -112
- package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +0 -20
- package/dist/src/pageVisit/EventDebouncer.d.ts +0 -24
- 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/react/ErrorBoundary.d.ts +0 -72
- package/dist/src/sessionRecorder/nativeSessionRecorderSubscription.d.ts +0 -79
- package/dist/src/sessionRecorder/sessionRecorder.d.ts +0 -60
- package/dist/src/sessionRecorder/types.d.ts +0 -91
- package/dist/src/storage/rnStorageProvider.d.ts +0 -23
- package/dist/src/storage/storage.d.ts +0 -39
- package/dist/src/storage/storageProvider.d.ts +0 -26
- package/dist/src/utils/date.d.ts +0 -6
- package/dist/src/utils/eventlistener.d.ts +0 -8
- package/dist/src/utils/function.d.ts +0 -102
- package/dist/src/utils/log.d.ts +0 -4
- package/dist/src/utils/object.d.ts +0 -44
- package/dist/src/utils/performance.d.ts +0 -6
- package/dist/src/utils/piiRedactor.d.ts +0 -11
- package/dist/src/utils/polyfills.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/NavigationIntegration.d.ts +0 -6
- 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/api/inputManager.js
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import { NOIBUJS_SDK_REQUEST_HELP_CODE, NOIBUJS_SDK_ADD_ID_FUNCTION, NOIBUJS_SDK_ADD_ERROR_FUNCTION, NOIBUJS_SDK_ADD_ERROR_FROM_JS_FMW_FUNCTION, MAX_CUSTOM_ERRORS_PER_PAGEVISIT, MAX_CUSTOM_IDS_PER_PAGEVISIT, META_DATA_METROPLEX_TYPE, PAGE_VISIT_META_DATA_ATT_NAME, CUSTOM_ID_NAME_TYPE, CUSTOM_ID_VALUE_TYPE, CUSTOM_ERROR_EVENT_TYPE } from '../constants.js';
|
|
2
|
-
import MetroplexSocket from './metroplexSocket.js';
|
|
3
|
-
import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError.js';
|
|
4
|
-
import HelpCode from './helpCode.js';
|
|
5
|
-
|
|
6
|
-
/** @module InputManager */
|
|
7
|
-
|
|
8
|
-
/** this class controls the input that customers can inject into
|
|
9
|
-
* our script via the NoibuJS SDK
|
|
10
|
-
*/
|
|
11
|
-
class InputManager {
|
|
12
|
-
/**
|
|
13
|
-
* Creates a new InputManager
|
|
14
|
-
*/
|
|
15
|
-
constructor() {
|
|
16
|
-
this.customIDs = {};
|
|
17
|
-
this.customErrorsCount = 0;
|
|
18
|
-
|
|
19
|
-
this.TOO_MANY_IDS_ADDED_MSG = 'TOO_MANY_IDS_ADDED';
|
|
20
|
-
this.ID_NAME_ALREADY_ADDED_MSG = 'ID_NAME_ALREADY_ADDED';
|
|
21
|
-
this.NAME_TOO_LONG_MSG = 'NAME_TOO_LONG';
|
|
22
|
-
this.VALUE_TOO_LONG_MSG = 'VALUE_TOO_LONG';
|
|
23
|
-
this.INVALID_NAME_TYPE_MSG = 'INVALID_NAME_TYPE';
|
|
24
|
-
this.INVALID_VALUE_TYPE_MSG = 'INVALID_VALUE_TYPE';
|
|
25
|
-
this.NAME_HAS_NO_LENGTH_MSG = 'NAME_HAS_NO_LENGTH';
|
|
26
|
-
this.VALUE_HAS_NO_LENGTH_MSG = 'VALUE_HAS_NO_LENGTH';
|
|
27
|
-
this.SUCCESS_MSG = 'SUCCESS';
|
|
28
|
-
this.ERROR_HAS_NO_MSG_MSG = 'ERROR_HAS_NO_MSG';
|
|
29
|
-
this.ERROR_HAS_NO_STACK_MSG = 'ERROR_HAS_NO_STACK';
|
|
30
|
-
this.NULL_CUSTOM_ERR_MSG = 'NULL_CUSTOM_ERROR';
|
|
31
|
-
this.ERROR_ALREADY_RECEIVED_MSG = 'ERROR_ALREADY_RECEIVED';
|
|
32
|
-
this.INVALID_ERROR_SOURCE_MSG = 'INVALID_ERROR_SOURCE_MSG';
|
|
33
|
-
this.TOO_MANY_ERRORS_RECEIVED_PER_PAGEVISIT_MSG =
|
|
34
|
-
'TOO_MANY_ERRORS_RECEIVED_PER_PAGEVISIT';
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** gets the singleton instance */
|
|
38
|
-
static getInstance() {
|
|
39
|
-
if (!this.instance) {
|
|
40
|
-
this.instance = new InputManager();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return this.instance;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** exposes functions to the window of the browser for the clients
|
|
47
|
-
* to interact with on their end
|
|
48
|
-
*/
|
|
49
|
-
exposeFunctions() {
|
|
50
|
-
return this._getSDKWindowObject();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* gets the sdk object that will be assigned to a window variable
|
|
55
|
-
* @returns {{
|
|
56
|
-
* requestHelpCode: (alert?: boolean) => Promise<string>,
|
|
57
|
-
* addCustomAttribute: (name: string, value: string) => Promise<string>,
|
|
58
|
-
* addError: (customError: Error) => string,
|
|
59
|
-
* addJsSdkError: (customError: string, errorSource: string) => string
|
|
60
|
-
* }}
|
|
61
|
-
*/
|
|
62
|
-
_getSDKWindowObject() {
|
|
63
|
-
return {
|
|
64
|
-
// adding all the functions and binding the current context
|
|
65
|
-
// so that we can use the exposed function as if they are running`
|
|
66
|
-
// in the noibujs script
|
|
67
|
-
[NOIBUJS_SDK_REQUEST_HELP_CODE]: this._requestHelpCode.bind(this),
|
|
68
|
-
[NOIBUJS_SDK_ADD_ID_FUNCTION]: this._addCustomAttribute.bind(this),
|
|
69
|
-
[NOIBUJS_SDK_ADD_ERROR_FUNCTION]: this._addCustomError.bind(this),
|
|
70
|
-
[NOIBUJS_SDK_ADD_ERROR_FROM_JS_FMW_FUNCTION]:
|
|
71
|
-
this._addErrorFromJSSdk.bind(this),
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* validates the custom error that was passed
|
|
77
|
-
* @param {} customError
|
|
78
|
-
*/
|
|
79
|
-
_validateCustomError(customError) {
|
|
80
|
-
// customError cannot be null
|
|
81
|
-
if (!customError) {
|
|
82
|
-
return this.NULL_CUSTOM_ERR_MSG;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// making sure we have the message and stack to create an error signature
|
|
86
|
-
if (!customError.message) {
|
|
87
|
-
return this.ERROR_HAS_NO_MSG_MSG;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (!customError.stack) {
|
|
91
|
-
return this.ERROR_HAS_NO_STACK_MSG;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return this.SUCCESS_MSG;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Validates and sets the custom error to our internal trackers
|
|
99
|
-
* @param {} customError
|
|
100
|
-
*/
|
|
101
|
-
_validateAndSetCustomError(customError) {
|
|
102
|
-
// we cap the number of errors allowed to be sent
|
|
103
|
-
if (this.customErrorsCount >= MAX_CUSTOM_ERRORS_PER_PAGEVISIT) {
|
|
104
|
-
return this.TOO_MANY_ERRORS_RECEIVED_PER_PAGEVISIT_MSG;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// need to validate first before we start operating with the received
|
|
108
|
-
// data
|
|
109
|
-
const validationResult = this._validateCustomError(customError);
|
|
110
|
-
if (validationResult !== this.SUCCESS_MSG) {
|
|
111
|
-
return validationResult;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
this.customErrorsCount += 1;
|
|
115
|
-
return this.SUCCESS_MSG;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* adds an error from a JS Sdk to the session
|
|
120
|
-
* @param {} customError
|
|
121
|
-
* @param {string} errorSource
|
|
122
|
-
*/
|
|
123
|
-
_addErrorFromJSSdk(customError, errorSource) {
|
|
124
|
-
const validationAndSettingResult =
|
|
125
|
-
this._validateAndSetCustomError(customError);
|
|
126
|
-
|
|
127
|
-
if (validationAndSettingResult !== this.SUCCESS_MSG) {
|
|
128
|
-
return validationAndSettingResult;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
saveErrorToPagevisit(errorSource, { error: customError });
|
|
132
|
-
return validationAndSettingResult;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* adds a custom Error to the session
|
|
137
|
-
* @param {} customError
|
|
138
|
-
*/
|
|
139
|
-
_addCustomError(customError) {
|
|
140
|
-
const validationAndSettingResult =
|
|
141
|
-
this._validateAndSetCustomError(customError);
|
|
142
|
-
if (validationAndSettingResult !== this.SUCCESS_MSG) {
|
|
143
|
-
return validationAndSettingResult;
|
|
144
|
-
}
|
|
145
|
-
saveErrorToPagevisit(CUSTOM_ERROR_EVENT_TYPE, { error: customError });
|
|
146
|
-
return validationAndSettingResult;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* adds a custom id to the session
|
|
151
|
-
* @param {} name
|
|
152
|
-
* @param {} value
|
|
153
|
-
*/
|
|
154
|
-
async _addCustomAttribute(name, value) {
|
|
155
|
-
// we return if we are over the limit of ids
|
|
156
|
-
if (Object.keys(this.customIDs).length >= MAX_CUSTOM_IDS_PER_PAGEVISIT) {
|
|
157
|
-
return this.TOO_MANY_IDS_ADDED_MSG;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// need to validate first before we start operating with the received
|
|
161
|
-
// data
|
|
162
|
-
const validationResult = this._validateCustomIDInput(name, value);
|
|
163
|
-
if (validationResult !== this.SUCCESS_MSG) {
|
|
164
|
-
return validationResult;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// we do not want to keep sending something that was already sent
|
|
168
|
-
if (name in this.customIDs) {
|
|
169
|
-
return this.ID_NAME_ALREADY_ADDED_MSG;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
this.customIDs[name] = value;
|
|
173
|
-
await MetroplexSocket.getInstance().sendMessage(META_DATA_METROPLEX_TYPE, {
|
|
174
|
-
[PAGE_VISIT_META_DATA_ATT_NAME]: {
|
|
175
|
-
[CUSTOM_ID_NAME_TYPE]: name,
|
|
176
|
-
[CUSTOM_ID_VALUE_TYPE]: value,
|
|
177
|
-
},
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
return this.SUCCESS_MSG;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* validation function for customer input
|
|
185
|
-
* @param {} name
|
|
186
|
-
* @param {} value
|
|
187
|
-
*/
|
|
188
|
-
_validateCustomIDInput(name, value) {
|
|
189
|
-
// all ids need to be strings and less than 50 chars and more than 0 chars
|
|
190
|
-
if (typeof name !== 'string') {
|
|
191
|
-
return this.INVALID_NAME_TYPE_MSG;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (typeof value !== 'string') {
|
|
195
|
-
return this.INVALID_VALUE_TYPE_MSG;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (value.length > 50) {
|
|
199
|
-
return this.VALUE_TOO_LONG_MSG;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (name.length > 50) {
|
|
203
|
-
return this.NAME_TOO_LONG_MSG;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (value.length === 0) {
|
|
207
|
-
return this.VALUE_HAS_NO_LENGTH_MSG;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (name.length === 0) {
|
|
211
|
-
return this.NAME_HAS_NO_LENGTH_MSG;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return this.SUCCESS_MSG;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Requests a help code from the HelpCode instance.
|
|
219
|
-
* @param {boolean} [alertUser=true] - Whether to alert the user about the help code request.
|
|
220
|
-
* @returns {Promise<string>} A promise that resolves with the requested help code.
|
|
221
|
-
*/
|
|
222
|
-
_requestHelpCode() {
|
|
223
|
-
return HelpCode.getInstance().requestHelpCode();
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export { InputManager as default };
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { BROWSER_ID_ATT_NAME, PV_ID_ATT_NAME, COLLECT_VER_ATT_NAME, CURRENT_NOIBUJS_VERSION, VER_ATT_NAME, CURRENT_METRICS_VERSION, EXP_VIDEO_LENGTH_ATT_NAME, PV_EXP_VF_SEQ_ATT_NAME, PV_EXP_PART_COUNTER_ATT_NAME, PV_EXP_HTTP_DATA_SEQ_ATT_NAME, PV_HTTP_PAYLOADS_COLLECTED_ATT_NAME, PV_HTTP_PAYLOADS_DROPPED_OVERSIZE_ATT_NAME, PV_HTTP_PAYLOADS_DROPPED_TYPE_ATT_NAME, PV_HTTP_REQUESTS_DROPPED_OVER_LIMIT, VIDEO_CLICKS_ATT_NAME, PV_CLICKS_ATT_NAME, DID_CUT_PV_ATT_NAME, DID_CUT_VID_ATT_NAME, DID_START_VID_ATT_NAME, HTTP_COUNT_EXPECTED_ATT_NAME, ERR_COUNT_EXPECTED_ATT_NAME, ON_URL_ATT_NAME, GET_METROPLEX_METRICS_URL } from '../constants.js';
|
|
2
|
-
import ClientConfig from './clientConfig.js';
|
|
3
|
-
import { getUserAgent, stringifyJSON } from '../utils/function.js';
|
|
4
|
-
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
5
|
-
import { unwrapNoibuWrapped } from '../utils/object.js';
|
|
6
|
-
|
|
7
|
-
/** @module StoredMetrics */
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* This class holds the final page visit and video frag metrics. It flushes
|
|
11
|
-
* them to storage and then finally sends them to Metroplex via the post
|
|
12
|
-
* route when the next page is loaded
|
|
13
|
-
*/
|
|
14
|
-
class StoredMetrics {
|
|
15
|
-
/**
|
|
16
|
-
* Creates a new StoredMetrics instance
|
|
17
|
-
*/
|
|
18
|
-
constructor() {
|
|
19
|
-
this.expectedVideoLength = 0;
|
|
20
|
-
this.expectedVfSeq = 0;
|
|
21
|
-
this.httpSequenceNumber = 0;
|
|
22
|
-
this.httpOverLimitCount = 0;
|
|
23
|
-
this.httpDroppedPayloadByTypeCount = 0;
|
|
24
|
-
this.httpDroppedPayloadByLengthCount = 0;
|
|
25
|
-
this.httpPayloadCount = 0;
|
|
26
|
-
this.expectedPvPart = 0;
|
|
27
|
-
this.videoClicks = 0;
|
|
28
|
-
this.pvClicks = 0;
|
|
29
|
-
this.errCount = 0;
|
|
30
|
-
this.httpCount = 0;
|
|
31
|
-
this.didCutPv = false;
|
|
32
|
-
this.didCutVideo = false;
|
|
33
|
-
this.writeTimeout = null;
|
|
34
|
-
this.didStartVideo = false;
|
|
35
|
-
|
|
36
|
-
this._setupListeners();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* gets the singleton instance
|
|
41
|
-
* @returns {StoredMetrics}
|
|
42
|
-
*/
|
|
43
|
-
static getInstance() {
|
|
44
|
-
if (!this.instance) {
|
|
45
|
-
this.instance = new StoredMetrics();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return this.instance;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Add video frag payload data to the stored metrics
|
|
52
|
-
* @param {} expectedVfSeq
|
|
53
|
-
* @param {} expectedVideoLength
|
|
54
|
-
*/
|
|
55
|
-
addVideoFragData(expectedVfSeq, expectedVideoLength) {
|
|
56
|
-
this.expectedVfSeq = expectedVfSeq;
|
|
57
|
-
this.expectedVideoLength = expectedVideoLength;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** Set the amount of page visit parts
|
|
61
|
-
* @param {} expectedPvPart
|
|
62
|
-
*/
|
|
63
|
-
setPvPart(expectedPvPart) {
|
|
64
|
-
this.expectedPvPart = expectedPvPart;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Increase the amount of video clicks seen in the session */
|
|
68
|
-
addVideoClick() {
|
|
69
|
-
this.videoClicks += 1;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Increase the amount of page visit clicks */
|
|
73
|
-
addPvClick() {
|
|
74
|
-
this.pvClicks += 1;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Increments the error count by 1 */
|
|
78
|
-
addError() {
|
|
79
|
-
this.errCount += 1;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Increments the http count by 1 */
|
|
83
|
-
addHttpEvent() {
|
|
84
|
-
this.httpCount += 1;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** Increments the http data sequence count by 1 */
|
|
88
|
-
addHttpData() {
|
|
89
|
-
this.httpSequenceNumber += 1;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** Increments the http data over limit count by 1 */
|
|
93
|
-
addHttpDataOverLimit() {
|
|
94
|
-
this.httpOverLimitCount += 1;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** Increments the http data drop count by content type */
|
|
98
|
-
addHttpDataDropByType() {
|
|
99
|
-
this.httpDroppedPayloadByTypeCount += 1;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/** Increments the http data drop count by content length */
|
|
103
|
-
addHttpDataDropByLength() {
|
|
104
|
-
this.httpDroppedPayloadByLengthCount += 1;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** Increments the http data payload collected count */
|
|
108
|
-
addHttpDataPayloadCount() {
|
|
109
|
-
this.httpPayloadCount += 1;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/** Set that the video was cut/blocked due to size constraints */
|
|
113
|
-
setDidCutVideo() {
|
|
114
|
-
this.didCutVideo = true;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** Set that the video was started */
|
|
118
|
-
setDidStartVideo() {
|
|
119
|
-
this.didStartVideo = true;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** Set that the page visit was cut/blocked due to size constraints */
|
|
123
|
-
setDidCutPv() {
|
|
124
|
-
this.didCutPv = true;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Sets up all the listeners that noibujs should listen to before storing
|
|
129
|
-
* our metrics to localstorage
|
|
130
|
-
*/
|
|
131
|
-
_setupListeners() {
|
|
132
|
-
// Add the window event handlers to post the data to the metrics endpoint
|
|
133
|
-
const evt = 'pagehide';
|
|
134
|
-
addSafeEventListener(window, evt, () => {
|
|
135
|
-
this._postMetricsIfActive(evt);
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** posts the metrics to metroplex if client is active
|
|
140
|
-
* @param {} eventName
|
|
141
|
-
*/
|
|
142
|
-
_postMetricsIfActive(eventName) {
|
|
143
|
-
if (ClientConfig.getInstance().isClientDisabled) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
// Don't send the metrics if the session has become inactive
|
|
147
|
-
// already sent when went inactive
|
|
148
|
-
if (ClientConfig.getInstance().isInactive()) {
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
this.postMetrics(eventName);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/** posts the metrics to metroplex using the beacon API
|
|
155
|
-
*/
|
|
156
|
-
async postMetrics() {
|
|
157
|
-
// Create a new object to write to local storage that doesnt have the timeout and flush members.
|
|
158
|
-
const lsMetrics = {
|
|
159
|
-
// metadata
|
|
160
|
-
[BROWSER_ID_ATT_NAME]: ClientConfig.getInstance().browserId,
|
|
161
|
-
[PV_ID_ATT_NAME]: ClientConfig.getInstance().pageVisitId,
|
|
162
|
-
[COLLECT_VER_ATT_NAME]: CURRENT_NOIBUJS_VERSION,
|
|
163
|
-
[VER_ATT_NAME]: CURRENT_METRICS_VERSION,
|
|
164
|
-
|
|
165
|
-
// metrics
|
|
166
|
-
[EXP_VIDEO_LENGTH_ATT_NAME]: this.expectedVideoLength,
|
|
167
|
-
[PV_EXP_VF_SEQ_ATT_NAME]: this.expectedVfSeq,
|
|
168
|
-
[PV_EXP_PART_COUNTER_ATT_NAME]: this.expectedPvPart,
|
|
169
|
-
[PV_EXP_HTTP_DATA_SEQ_ATT_NAME]: this.httpSequenceNumber,
|
|
170
|
-
[PV_HTTP_PAYLOADS_COLLECTED_ATT_NAME]: this.httpPayloadCount,
|
|
171
|
-
[PV_HTTP_PAYLOADS_DROPPED_OVERSIZE_ATT_NAME]:
|
|
172
|
-
this.httpDroppedPayloadByLengthCount,
|
|
173
|
-
[PV_HTTP_PAYLOADS_DROPPED_TYPE_ATT_NAME]:
|
|
174
|
-
this.httpDroppedPayloadByTypeCount,
|
|
175
|
-
[PV_HTTP_REQUESTS_DROPPED_OVER_LIMIT]: this.httpOverLimitCount,
|
|
176
|
-
[VIDEO_CLICKS_ATT_NAME]: this.videoClicks,
|
|
177
|
-
[PV_CLICKS_ATT_NAME]: this.pvClicks,
|
|
178
|
-
[DID_CUT_PV_ATT_NAME]: this.didCutPv,
|
|
179
|
-
[DID_CUT_VID_ATT_NAME]: this.didCutVideo,
|
|
180
|
-
[DID_START_VID_ATT_NAME]: this.didStartVideo,
|
|
181
|
-
[HTTP_COUNT_EXPECTED_ATT_NAME]: this.httpCount,
|
|
182
|
-
[ERR_COUNT_EXPECTED_ATT_NAME]: this.errCount,
|
|
183
|
-
[ON_URL_ATT_NAME]: ClientConfig.getInstance().globalUrl,
|
|
184
|
-
};
|
|
185
|
-
unwrapNoibuWrapped(fetch)(GET_METROPLEX_METRICS_URL(), {
|
|
186
|
-
method: 'POST',
|
|
187
|
-
headers: {
|
|
188
|
-
'content-type': 'application/json',
|
|
189
|
-
'User-Agent': await getUserAgent(),
|
|
190
|
-
},
|
|
191
|
-
body: stringifyJSON(lsMetrics),
|
|
192
|
-
// keep alive outlives the current page, its the same as beacon
|
|
193
|
-
keepalive: true,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export { StoredMetrics as default };
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import uuid from 'react-native-uuid';
|
|
2
|
-
import { TYPE_ATT_NAME, OCCURRED_AT_ATT_NAME, MAX_PAGEVISIT_EVENTS, MAX_PAGEVISIT_PARTS, PV_METROPLEX_TYPE, PV_EVENTS_ATT_NAME, PV_PART_COUNTER_ATT_NAME, PAGE_VISIT_PART_ATT_NAME } from '../constants.js';
|
|
3
|
-
import ClientConfig from '../api/clientConfig.js';
|
|
4
|
-
import MetroplexSocket from '../api/metroplexSocket.js';
|
|
5
|
-
import StoredMetrics from '../api/storedMetrics.js';
|
|
6
|
-
import { noibuLog } from '../utils/log.js';
|
|
7
|
-
|
|
8
|
-
/** @module Pagevisit */
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Singleton class to hold all the information
|
|
12
|
-
* about the gathered errors throught the session
|
|
13
|
-
*/
|
|
14
|
-
class PageVisit {
|
|
15
|
-
/**
|
|
16
|
-
* Creates an instance of a PageVisit
|
|
17
|
-
*/
|
|
18
|
-
constructor() {
|
|
19
|
-
this.partCounter = 0;
|
|
20
|
-
// TODO: Remove pvMap and related variables since we only send a single event at a time
|
|
21
|
-
this.pvMap = {};
|
|
22
|
-
this.partCounter = 0;
|
|
23
|
-
this.pvEventLength = 0;
|
|
24
|
-
// variables used for monitoring our posting frequency
|
|
25
|
-
this.visibilityChangedCounter = 0;
|
|
26
|
-
this.totalPvEventLength = 0;
|
|
27
|
-
this.inDebounceHandle = 0;
|
|
28
|
-
this.isInAcceleratedPvPostMode = false;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* creates a PV object
|
|
33
|
-
*/
|
|
34
|
-
static configureInstance() {
|
|
35
|
-
if (!this.instance) {
|
|
36
|
-
this.instance = new PageVisit();
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** gets the singleton instance
|
|
41
|
-
* @returns {PageVisit}
|
|
42
|
-
*/
|
|
43
|
-
static getInstance() {
|
|
44
|
-
if (!this.instance) {
|
|
45
|
-
throw new Error('Pagevisit was never configured');
|
|
46
|
-
}
|
|
47
|
-
return this.instance;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** adds page visit events into the current page visit map and then sends a page visit message
|
|
51
|
-
* @param {} eventObjects
|
|
52
|
-
* @param {} type
|
|
53
|
-
*/
|
|
54
|
-
addPageVisitEvents(eventObjects, type) {
|
|
55
|
-
eventObjects.forEach(eventObj => {
|
|
56
|
-
this._addPageVisitEvent(eventObj, type);
|
|
57
|
-
});
|
|
58
|
-
this._sendPageVisitMessage();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* adds the page visit event into the current page visit map and then sends a page visit message
|
|
63
|
-
* returns the the key to access this event in the map
|
|
64
|
-
* @param {} eventObj
|
|
65
|
-
* @param {} type
|
|
66
|
-
*/
|
|
67
|
-
addPageVisitEvent(eventObj, type) {
|
|
68
|
-
noibuLog('addPageVisitEvent', {
|
|
69
|
-
eventObj,
|
|
70
|
-
type,
|
|
71
|
-
});
|
|
72
|
-
const id = this._addPageVisitEvent(eventObj, type);
|
|
73
|
-
this._sendPageVisitMessage();
|
|
74
|
-
return id;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* adds a new page visit event into the current page visit map and returns the
|
|
79
|
-
* the key to access this event in the map
|
|
80
|
-
* @param {} eventObj
|
|
81
|
-
* @param {} type
|
|
82
|
-
*/
|
|
83
|
-
_addPageVisitEvent(eventObj, type) {
|
|
84
|
-
if (!('occurredAt' in eventObj && 'event' in eventObj)) {
|
|
85
|
-
throw new Error('missing attributes in the eventObj');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// creating the pvEvent from the passed pv
|
|
89
|
-
const pvEvent = {
|
|
90
|
-
[TYPE_ATT_NAME]: type,
|
|
91
|
-
[OCCURRED_AT_ATT_NAME]: eventObj.occurredAt,
|
|
92
|
-
[type]: eventObj.event,
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
// if we are over the limit set by the Beacon API limit, we need to
|
|
96
|
-
// send what we currently have in the buffer to metroplex
|
|
97
|
-
if (this.pvEventLength >= MAX_PAGEVISIT_EVENTS) {
|
|
98
|
-
this._sendPageVisitMessage();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const pvEventId = uuid.v4();
|
|
102
|
-
// updating sizes
|
|
103
|
-
this.pvMap[pvEventId] = pvEvent;
|
|
104
|
-
this.pvEventLength += 1;
|
|
105
|
-
this.totalPvEventLength += 1;
|
|
106
|
-
|
|
107
|
-
return pvEventId;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Creates a page visit frag from an events array and part counter. Appends
|
|
112
|
-
* the end time field and returns the frag
|
|
113
|
-
* @param {} pvEvents
|
|
114
|
-
* @param {} partCounter
|
|
115
|
-
*/
|
|
116
|
-
static makePageVisitFrag(pvEvents, partCounter) {
|
|
117
|
-
const pagevistFrag = {};
|
|
118
|
-
pagevistFrag[PV_EVENTS_ATT_NAME] = pvEvents;
|
|
119
|
-
pagevistFrag[PV_PART_COUNTER_ATT_NAME] = partCounter;
|
|
120
|
-
return MetroplexSocket.getInstance().addEndTimeToPayload(
|
|
121
|
-
pagevistFrag,
|
|
122
|
-
true,
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* _sendPageVisitMessage will reset the buffer and post the current
|
|
128
|
-
* content to metroplex
|
|
129
|
-
*/
|
|
130
|
-
_sendPageVisitMessage() {
|
|
131
|
-
// not using Object.values since we want to support as many browsers
|
|
132
|
-
// as possible
|
|
133
|
-
const pvEvents = Object.keys(this.pvMap).map(id => this.pvMap[id]);
|
|
134
|
-
|
|
135
|
-
if (pvEvents.length === 0) {
|
|
136
|
-
// don't send to metroplex if the event buffer is empty.
|
|
137
|
-
// A previous call to this function from visibilityChange
|
|
138
|
-
// would have sent it as a final post. Another reason it would be empty is
|
|
139
|
-
// if the user has not done anything on the page and switched tabs,
|
|
140
|
-
// or closed the browser etc
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (this.partCounter >= MAX_PAGEVISIT_PARTS) {
|
|
145
|
-
// if we are attempting to send over the MAX_PAGEVISIT_PARTS
|
|
146
|
-
// number of parts then we block any subsequent part post to not
|
|
147
|
-
// inondate our back end. We lock the client for 10 minute, something
|
|
148
|
-
// must be going bad.
|
|
149
|
-
ClientConfig.getInstance().lockClientUntilNextPage(
|
|
150
|
-
`NoibuJS will stop processing parts because we ` +
|
|
151
|
-
`reached max parts: ${MAX_PAGEVISIT_PARTS}. Variables: ` +
|
|
152
|
-
`
|
|
153
|
-
total Pv Event Length: ${this.totalPvEventLength}
|
|
154
|
-
visibility Changed Counter: ${this.visibilityChangedCounter}
|
|
155
|
-
`,
|
|
156
|
-
);
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const pagevistFrag = PageVisit.makePageVisitFrag(
|
|
161
|
-
pvEvents,
|
|
162
|
-
this.partCounter,
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
StoredMetrics.getInstance().setPvPart(this.partCounter);
|
|
166
|
-
|
|
167
|
-
const metroplexMsg = {
|
|
168
|
-
[PAGE_VISIT_PART_ATT_NAME]: pagevistFrag,
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
MetroplexSocket.getInstance().sendMessage(PV_METROPLEX_TYPE, metroplexMsg);
|
|
172
|
-
|
|
173
|
-
// since we sent the content of the buffer to metroplex, we reset
|
|
174
|
-
// all variables that contained information about the past buffer.
|
|
175
|
-
this.pvMap = {};
|
|
176
|
-
this.pvEventLength = 0;
|
|
177
|
-
this.partCounter += 1;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export { PageVisit };
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { timestampWrapper } from '../utils/date.js';
|
|
2
|
-
import { HTTP_RESP_CODE_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HTTP_METHOD_ATT_NAME, URL_ATT_NAME, PV_SEQ_ATT_NAME, PAGE_VISIT_HTTP_DATA_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_EVENT_TYPE, MAX_HTTP_DATA_EVENT_COUNT, MAX_HTTP_DATA_IF_ERROR_EVENT_COUNT } from '../constants.js';
|
|
3
|
-
import { PageVisit } from './pageVisit.js';
|
|
4
|
-
import StoredMetrics from '../api/storedMetrics.js';
|
|
5
|
-
import MetroplexSocket from '../api/metroplexSocket.js';
|
|
6
|
-
import { getMaxSubstringAllowed, asString, safeTrim } from '../utils/function.js';
|
|
7
|
-
import { EventDebouncer } from './EventDebouncer.js';
|
|
8
|
-
|
|
9
|
-
/** @module PageVisitEventHTTP */
|
|
10
|
-
/**
|
|
11
|
-
* Determines if a response is a failure
|
|
12
|
-
*/
|
|
13
|
-
function isHttpCodeFailure(code) {
|
|
14
|
-
if (typeof code !== 'number') {
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
return code >= 400 || code <= 0;
|
|
18
|
-
}
|
|
19
|
-
/** Class representing a PageVisitEventHTTP */
|
|
20
|
-
class PageVisitEventHTTP {
|
|
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;
|
|
35
|
-
}
|
|
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
|
-
[PAGE_VISIT_HTTP_DATA_ATT_NAME]: this.httpData,
|
|
59
|
-
};
|
|
60
|
-
MetroplexSocket.getInstance().sendMessage(HTTP_DATA_METROPLEX_TYPE, metroplexMsg);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
// have collected more than the max number of http requests for this
|
|
64
|
-
// page visit, so increment the over request limit count
|
|
65
|
-
StoredMetrics.getInstance().addHttpDataOverLimit();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
// if this was an error, send immediately so we don't lose it
|
|
69
|
-
if (isHttpCodeFailure(status)) {
|
|
70
|
-
PageVisit.getInstance().addPageVisitEvent({
|
|
71
|
-
event: this.httpEvent,
|
|
72
|
-
occurredAt: new Date(timestampWrapper(Date.now())).toISOString(),
|
|
73
|
-
}, HTTP_EVENT_TYPE);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
// debounce event
|
|
77
|
-
EventDebouncer.getInstance().addEvent(this.httpEvent, HTTP_EVENT_TYPE);
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Checks if sending data is allowed based on the HTTP status code and count.
|
|
81
|
-
* status - The HTTP status code to evaluate.
|
|
82
|
-
* count - The count of events to consider.
|
|
83
|
-
* isGqlError - Whether the context is considered as a GQL error.
|
|
84
|
-
* Returns `true` if sending data is allowed, `false` otherwise.
|
|
85
|
-
*/
|
|
86
|
-
static isSendAllowed(status, count, isGqlError = false) {
|
|
87
|
-
const isFailure = isHttpCodeFailure(status) || isGqlError;
|
|
88
|
-
const isSuccess = !isFailure;
|
|
89
|
-
if (isSuccess) {
|
|
90
|
-
if (count < MAX_HTTP_DATA_EVENT_COUNT) {
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return isFailure && count < MAX_HTTP_DATA_IF_ERROR_EVENT_COUNT;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export { PageVisitEventHTTP, isHttpCodeFailure };
|