noibu-react-native 0.2.6 → 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.
Files changed (97) hide show
  1. package/README.md +15 -15
  2. package/dist/api/{clientConfig.js → ClientConfig.js} +69 -52
  3. package/dist/api/{helpCode.js → HelpCode.js} +6 -13
  4. package/dist/api/InputManager.js +156 -0
  5. package/dist/api/{metroplexSocket.js → MetroplexSocket.js} +189 -178
  6. package/dist/api/StoredMetrics.js +158 -0
  7. package/dist/api/{storedPageVisit.js → StoredPageVisit.js} +61 -48
  8. package/dist/const_matchers.js +1 -5
  9. package/dist/constants.js +15 -390
  10. package/dist/entry/index.js +3 -4
  11. package/dist/entry/init.js +33 -19
  12. package/dist/monitors/AppNavigationMonitor.js +19 -19
  13. package/dist/monitors/BaseMonitor.js +9 -4
  14. package/dist/monitors/ClickMonitor.js +72 -76
  15. package/dist/monitors/ErrorMonitor.js +45 -55
  16. package/dist/monitors/KeyboardInputMonitor.js +13 -11
  17. package/dist/monitors/PageMonitor.js +25 -2
  18. package/dist/monitors/RequestMonitor.js +46 -57
  19. package/dist/monitors/http-tools/GqlErrorValidator.js +39 -69
  20. package/dist/monitors/http-tools/HTTPDataBundler.js +71 -66
  21. package/dist/monitors/integrations/{react-native-navigation-integration.js → ReactNativeNavigationIntegration.js} +15 -12
  22. package/dist/pageVisit/EventDebouncer.js +43 -74
  23. package/dist/pageVisit/HttpEventManager.js +88 -0
  24. package/dist/pageVisit/PageVisitManager.js +99 -0
  25. package/dist/pageVisit/pageVisitEventError.js +170 -280
  26. package/dist/react/ErrorBoundary.js +3 -6
  27. package/dist/sessionRecorder/{sessionRecorder.js → SessionRecorder.js} +58 -70
  28. package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -5
  29. package/dist/storage/{rnStorageProvider.js → RNStorageProvider.js} +3 -7
  30. package/dist/storage/{storage.js → Storage.js} +17 -30
  31. package/dist/storage/{storageProvider.js → StorageProvider.js} +7 -8
  32. package/dist/utils/date.js +39 -50
  33. package/dist/utils/eventlistener.js +5 -12
  34. package/dist/utils/function.js +42 -113
  35. package/dist/utils/log.js +5 -5
  36. package/dist/utils/object.js +12 -12
  37. package/dist/utils/piiRedactor.js +31 -3
  38. package/dist/utils/stacktrace-parser.js +29 -21
  39. package/package.json +14 -14
  40. package/dist/api/inputManager.js +0 -227
  41. package/dist/api/storedMetrics.js +0 -198
  42. package/dist/pageVisit/pageVisit.js +0 -181
  43. package/dist/pageVisit/pageVisitEventHTTP.js +0 -98
  44. package/dist/pageVisit/userStep.js +0 -20
  45. package/dist/src/api/clientConfig.d.ts +0 -100
  46. package/dist/src/api/clientConfig.test.d.ts +0 -1
  47. package/dist/src/api/helpCode.d.ts +0 -23
  48. package/dist/src/api/inputManager.d.ts +0 -87
  49. package/dist/src/api/metroplexSocket.d.ts +0 -137
  50. package/dist/src/api/storedMetrics.d.ts +0 -73
  51. package/dist/src/api/storedPageVisit.d.ts +0 -40
  52. package/dist/src/const_matchers.d.ts +0 -1
  53. package/dist/src/constants.d.ts +0 -290
  54. package/dist/src/entry/index.d.ts +0 -14
  55. package/dist/src/entry/init.d.ts +0 -5
  56. package/dist/src/monitors/AppNavigationMonitor.d.ts +0 -18
  57. package/dist/src/monitors/BaseMonitor.d.ts +0 -13
  58. package/dist/src/monitors/BaseMonitor.test.d.ts +0 -1
  59. package/dist/src/monitors/ClickMonitor.d.ts +0 -31
  60. package/dist/src/monitors/ErrorMonitor.d.ts +0 -63
  61. package/dist/src/monitors/KeyboardInputMonitor.d.ts +0 -20
  62. package/dist/src/monitors/PageMonitor.d.ts +0 -20
  63. package/dist/src/monitors/RequestMonitor.d.ts +0 -94
  64. package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +0 -59
  65. package/dist/src/monitors/http-tools/HTTPDataBundler.d.ts +0 -112
  66. package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +0 -20
  67. package/dist/src/pageVisit/EventDebouncer.d.ts +0 -24
  68. package/dist/src/pageVisit/pageVisit.d.ts +0 -52
  69. package/dist/src/pageVisit/pageVisitEventError.d.ts +0 -15
  70. package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +0 -25
  71. package/dist/src/pageVisit/userStep.d.ts +0 -5
  72. package/dist/src/react/ErrorBoundary.d.ts +0 -72
  73. package/dist/src/sessionRecorder/nativeSessionRecorderSubscription.d.ts +0 -79
  74. package/dist/src/sessionRecorder/sessionRecorder.d.ts +0 -60
  75. package/dist/src/sessionRecorder/types.d.ts +0 -91
  76. package/dist/src/storage/rnStorageProvider.d.ts +0 -23
  77. package/dist/src/storage/storage.d.ts +0 -39
  78. package/dist/src/storage/storageProvider.d.ts +0 -26
  79. package/dist/src/utils/date.d.ts +0 -6
  80. package/dist/src/utils/eventlistener.d.ts +0 -8
  81. package/dist/src/utils/function.d.ts +0 -102
  82. package/dist/src/utils/log.d.ts +0 -4
  83. package/dist/src/utils/object.d.ts +0 -44
  84. package/dist/src/utils/performance.d.ts +0 -6
  85. package/dist/src/utils/piiRedactor.d.ts +0 -11
  86. package/dist/src/utils/polyfills.d.ts +0 -4
  87. package/dist/src/utils/stacktrace-parser.d.ts +0 -7
  88. package/dist/types/Config.d.ts +0 -31
  89. package/dist/types/Metroplex.types.d.ts +0 -73
  90. package/dist/types/NavigationIntegration.d.ts +0 -6
  91. package/dist/types/PageVisit.types.d.ts +0 -8
  92. package/dist/types/PageVisitErrors.types.d.ts +0 -114
  93. package/dist/types/PageVisitEvents.types.d.ts +0 -91
  94. package/dist/types/PageVisitMetrics.types.d.ts +0 -27
  95. package/dist/types/Storage.d.ts +0 -14
  96. package/dist/types/StoredPageVisit.types.d.ts +0 -11
  97. package/dist/types/WrappedObjects.d.ts +0 -6
@@ -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 };