noibu-react-native 0.2.2 → 0.2.4

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 (100) hide show
  1. package/README.md +1 -1
  2. package/dist/api/clientConfig.js +225 -217
  3. package/dist/api/helpCode.js +61 -87
  4. package/dist/api/metroplexSocket.js +460 -463
  5. package/dist/api/storedPageVisit.js +150 -208
  6. package/dist/constants.js +10 -2
  7. package/dist/entry/init.js +65 -63
  8. package/dist/monitors/{appNavigationMonitor.js → AppNavigationMonitor.js} +12 -22
  9. package/dist/monitors/ClickMonitor.js +198 -0
  10. package/dist/monitors/ErrorMonitor.js +206 -0
  11. package/dist/monitors/KeyboardInputMonitor.js +60 -0
  12. package/dist/monitors/PageMonitor.js +98 -0
  13. package/dist/monitors/RequestMonitor.js +390 -0
  14. package/dist/monitors/http-tools/GqlErrorValidator.js +259 -0
  15. package/dist/monitors/http-tools/HTTPDataBundler.js +458 -0
  16. package/dist/monitors/integrations/react-native-navigation-integration.js +4 -2
  17. package/dist/pageVisit/EventDebouncer.js +99 -0
  18. package/dist/pageVisit/pageVisitEventError.js +2 -2
  19. package/dist/pageVisit/pageVisitEventHTTP.js +79 -93
  20. package/dist/react/ErrorBoundary.js +18 -15
  21. package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -2
  22. package/dist/sessionRecorder/sessionRecorder.js +152 -151
  23. package/dist/{api → src/api}/clientConfig.d.ts +2 -2
  24. package/dist/{api → src/api}/helpCode.d.ts +10 -16
  25. package/dist/{api → src/api}/metroplexSocket.d.ts +48 -67
  26. package/dist/{api → src/api}/storedPageVisit.d.ts +12 -21
  27. package/dist/{constants.d.ts → src/constants.d.ts} +45 -0
  28. package/dist/{entry → src/entry}/init.d.ts +1 -1
  29. package/dist/src/monitors/AppNavigationMonitor.d.ts +18 -0
  30. package/dist/src/monitors/ClickMonitor.d.ts +31 -0
  31. package/dist/src/monitors/ErrorMonitor.d.ts +63 -0
  32. package/dist/{monitors/keyboardInputMonitor.d.ts → src/monitors/KeyboardInputMonitor.d.ts} +7 -4
  33. package/dist/{monitors/pageMonitor.d.ts → src/monitors/PageMonitor.d.ts} +6 -8
  34. package/dist/src/monitors/RequestMonitor.d.ts +94 -0
  35. package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +59 -0
  36. package/dist/src/monitors/http-tools/HTTPDataBundler.d.ts +112 -0
  37. package/dist/{monitors → src/monitors}/integrations/react-native-navigation-integration.d.ts +3 -2
  38. package/dist/src/pageVisit/EventDebouncer.d.ts +24 -0
  39. package/dist/{pageVisit → src/pageVisit}/pageVisit.d.ts +1 -1
  40. package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +25 -0
  41. package/dist/{sessionRecorder → src/sessionRecorder}/types.d.ts +1 -1
  42. package/dist/{storage → src/storage}/rnStorageProvider.d.ts +1 -1
  43. package/dist/{storage → src/storage}/storage.d.ts +2 -2
  44. package/dist/{storage → src/storage}/storageProvider.d.ts +3 -3
  45. package/dist/{utils → src/utils}/function.d.ts +27 -7
  46. package/dist/{utils → src/utils}/object.d.ts +11 -8
  47. package/dist/src/utils/piiRedactor.d.ts +11 -0
  48. package/dist/src/utils/polyfills.d.ts +4 -0
  49. package/dist/storage/rnStorageProvider.js +7 -4
  50. package/dist/storage/storage.js +43 -35
  51. package/dist/storage/storageProvider.js +23 -19
  52. package/dist/types/Config.d.ts +24 -20
  53. package/dist/types/Metroplex.types.d.ts +73 -0
  54. package/dist/types/Monitor.d.ts +11 -0
  55. package/dist/types/Monitor.js +19 -0
  56. package/dist/types/PageVisit.types.d.ts +8 -0
  57. package/dist/types/PageVisitErrors.types.d.ts +114 -0
  58. package/dist/types/PageVisitEvents.types.d.ts +91 -0
  59. package/dist/types/PageVisitMetrics.types.d.ts +27 -0
  60. package/dist/types/Storage.d.ts +1 -1
  61. package/dist/types/StoredPageVisit.types.d.ts +4 -47
  62. package/dist/types/WrappedObjects.d.ts +6 -0
  63. package/dist/utils/function.js +110 -77
  64. package/dist/utils/object.js +59 -6
  65. package/dist/utils/piiRedactor.js +98 -0
  66. package/dist/utils/polyfills.js +24 -0
  67. package/package.json +8 -8
  68. package/dist/monitors/appNavigationMonitor.d.ts +0 -22
  69. package/dist/monitors/clickMonitor.d.ts +0 -44
  70. package/dist/monitors/clickMonitor.js +0 -251
  71. package/dist/monitors/errorMonitor.d.ts +0 -28
  72. package/dist/monitors/errorMonitor.js +0 -180
  73. package/dist/monitors/gqlErrorValidator.d.ts +0 -82
  74. package/dist/monitors/gqlErrorValidator.js +0 -306
  75. package/dist/monitors/httpDataBundler.d.ts +0 -161
  76. package/dist/monitors/httpDataBundler.js +0 -725
  77. package/dist/monitors/inputMonitor.d.ts +0 -34
  78. package/dist/monitors/inputMonitor.js +0 -138
  79. package/dist/monitors/keyboardInputMonitor.js +0 -66
  80. package/dist/monitors/pageMonitor.js +0 -122
  81. package/dist/monitors/requestMonitor.d.ts +0 -10
  82. package/dist/monitors/requestMonitor.js +0 -401
  83. package/dist/pageVisit/pageVisitEventHTTP.d.ts +0 -18
  84. package/dist/types/PageVisit.d.ts +0 -22
  85. package/dist/types/ReactNative.d.ts +0 -4
  86. package/dist/types/globals.d.ts +0 -45
  87. /package/dist/{api → src/api}/inputManager.d.ts +0 -0
  88. /package/dist/{api → src/api}/storedMetrics.d.ts +0 -0
  89. /package/dist/{const_matchers.d.ts → src/const_matchers.d.ts} +0 -0
  90. /package/dist/{entry → src/entry}/index.d.ts +0 -0
  91. /package/dist/{pageVisit → src/pageVisit}/pageVisitEventError.d.ts +0 -0
  92. /package/dist/{pageVisit → src/pageVisit}/userStep.d.ts +0 -0
  93. /package/dist/{react → src/react}/ErrorBoundary.d.ts +0 -0
  94. /package/dist/{sessionRecorder → src/sessionRecorder}/nativeSessionRecorderSubscription.d.ts +0 -0
  95. /package/dist/{sessionRecorder → src/sessionRecorder}/sessionRecorder.d.ts +0 -0
  96. /package/dist/{utils → src/utils}/date.d.ts +0 -0
  97. /package/dist/{utils → src/utils}/eventlistener.d.ts +0 -0
  98. /package/dist/{utils → src/utils}/log.d.ts +0 -0
  99. /package/dist/{utils → src/utils}/performance.d.ts +0 -0
  100. /package/dist/{utils → src/utils}/stacktrace-parser.d.ts +0 -0
@@ -1,7 +1,8 @@
1
+ import { __awaiter } from 'tslib';
1
2
  import uuid from 'react-native-uuid';
2
3
  import { getUserAgent, stringifyJSON, getVideoRecorderType } from '../utils/function.js';
3
4
  import { addSafeEventListener } from '../utils/eventlistener.js';
4
- import { GET_METROPLEX_BASE_SOCKET_URL, METROPLEX_FRAG_ROUTE, GET_METROPLEX_POST_URL, METROPLEX_RETRY_FREQUENCY, META_DATA_METROPLEX_TYPE, PAGE_VISIT_META_DATA_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, PAGE_VISIT_HTTP_DATA_ATT_NAME, VIDEO_METROPLEX_TYPE, PAGE_VISIT_VID_FRAG_ATT_NAME, PV_METROPLEX_TYPE, PAGE_VISIT_PART_ATT_NAME, SEQ_NUM_ATT_NAME, WORK_REQUEST_ATT_NAME, HELP_CODE_ATT_NAME, PV_EVENTS_ATT_NAME, TYPE_ATT_NAME, USERSTEP_EVENT_TYPE, GET_MAX_METROPLEX_RECONNECTION_NUMBER, MAX_METROPLEX_CONNECTION_COUNT, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, END_AT_ATT_NAME, SEVERITY, OK_SOCKET_MESSAGE, CLOSE_CONNECTION_FORCEFULLY, BLOCK_SOCKET_MESSAGE, STOP_STORING_PV_SOCKET_MESSAGE, STOP_STORING_VID_SOCKET_MESSAGE, MAX_BEACON_PAYLOAD_SIZE, PAGE_VISIT_INFORMATION_ATT_NAME, VIDEO_PART_COUNT_ATT_NAME, IS_LAST_ATT_NAME, BROWSER_ID_ATT_NAME, PV_ID_ATT_NAME, VER_ATT_NAME, CURRENT_PV_VERSION, PV_SEQ_ATT_NAME, ON_URL_ATT_NAME, REF_URL_ATT_NAME, STARTED_AT_ATT_NAME, CONN_COUNT_ATT_NAME, COLLECT_VER_ATT_NAME, CURRENT_NOIBUJS_VERSION, SCRIPT_ID_ATT_NAME, GET_SCRIPT_ID, SCRIPT_INSTANCE_ID_ATT_NAME, METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME, SOCKET_INSTANCE_ID_ATT_NAME, VIDEO_RECORDER_ATT_NAME } from '../constants.js';
5
+ import { GET_METROPLEX_BASE_SOCKET_URL, METROPLEX_FRAG_ROUTE, GET_METROPLEX_POST_URL, METROPLEX_RETRY_FREQUENCY, SEQ_NUM_ATT_NAME, WORK_REQUEST_ATT_NAME, HELP_CODE_ATT_NAME, PV_METROPLEX_TYPE, PAGE_VISIT_PART_ATT_NAME, PV_EVENTS_ATT_NAME, TYPE_ATT_NAME, USERSTEP_EVENT_TYPE, GET_MAX_METROPLEX_RECONNECTION_NUMBER, MAX_METROPLEX_CONNECTION_COUNT, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, END_AT_ATT_NAME, SEVERITY, OK_SOCKET_MESSAGE, CLOSE_CONNECTION_FORCEFULLY, BLOCK_SOCKET_MESSAGE, STOP_STORING_PV_SOCKET_MESSAGE, STOP_STORING_VID_SOCKET_MESSAGE, VIDEO_METROPLEX_TYPE, PAGE_VISIT_VID_FRAG_ATT_NAME, MAX_BEACON_PAYLOAD_SIZE, PAGE_VISIT_INFORMATION_ATT_NAME, PAGE_VISIT_HTTP_DATA_ATT_NAME, VIDEO_PART_COUNT_ATT_NAME, IS_LAST_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, BROWSER_ID_ATT_NAME, PV_ID_ATT_NAME, VER_ATT_NAME, CURRENT_PV_VERSION, PV_SEQ_ATT_NAME, ON_URL_ATT_NAME, REF_URL_ATT_NAME, STARTED_AT_ATT_NAME, CONN_COUNT_ATT_NAME, COLLECT_VER_ATT_NAME, CURRENT_NOIBUJS_VERSION, SCRIPT_ID_ATT_NAME, GET_SCRIPT_ID, SCRIPT_INSTANCE_ID_ATT_NAME, METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME, SOCKET_INSTANCE_ID_ATT_NAME, VIDEO_RECORDER_ATT_NAME, META_DATA_METROPLEX_TYPE, PAGE_VISIT_META_DATA_ATT_NAME, MAX_RETRY_MSG_Q_SIZE } from '../constants.js';
5
6
  import ClientConfig from './clientConfig.js';
6
7
  import StoredMetrics from './storedMetrics.js';
7
8
  import StoredPageVisit from './storedPageVisit.js';
@@ -9,47 +10,39 @@ import { safePerformanceNow } from '../utils/performance.js';
9
10
  import { isDateOverwritten } from '../utils/date.js';
10
11
  import { unwrapNoibuWrapped } from '../utils/object.js';
11
12
  import { noibuLog } from '../utils/log.js';
13
+ import { Singleton } from '../types/Monitor.js';
12
14
 
13
- /** @module MetroplexSocket */
15
+ /**
16
+ * Implements rolling window of specified size,
17
+ * but only makes a cut once array length exceeds 150%.
18
+ * During downsize deletes oldest (lowest indexes) elements.
19
+ */
20
+ function createSlidingArrayOfSize(size, arraySource = [], downsizeThreshold = 1.5, downsizeFactor = 2) {
21
+ return new Proxy(arraySource, {
22
+ /**
23
+ * override push to implement sliding window
24
+ */
25
+ get(target, p) {
26
+ if (p === 'push') {
27
+ return (...args) => {
28
+ target.push(...args);
29
+ if (target.length >= downsizeThreshold * size) {
30
+ target.splice(0, size / downsizeFactor);
31
+ }
32
+ };
33
+ }
34
+ return target[p];
35
+ },
36
+ });
37
+ }
14
38
  /** Manages the socket to Metroplex */
15
- class MetroplexSocket {
16
- _initialURL;
17
- ackedOnce;
18
- connectionCount;
19
- // promise that will resolve once the socket is connected and metroplex has acknowledged
20
- connectionPromise;
21
- connectionURL;
22
- currentConnectionAttempts;
23
- forceClosed;
24
- helpCodeCb;
25
- initialReferingURL;
26
- static instance;
27
- instanceId;
28
- isRetryLoopDisabled;
29
- latestReceivedSeqNumStoredTime;
30
- latestReceivedSeqNumber;
31
- messageSequenceNum;
32
- metroRetryFrequencyMS;
33
- metroplexTypeLock;
34
- pageVisitInfoSent;
35
- postURL;
36
- previousMessageType;
37
- retryMessageQueue;
38
- retryMetroplexInterval;
39
- scriptInstanceId;
40
- sessionLength;
41
- sessionStartTime;
42
- sessionTimestamp;
43
- socket;
44
- socketInstanceId;
45
- socketCloseCodes;
46
- socketOpens;
39
+ class MetroplexSocket extends Singleton {
47
40
  /**
48
41
  * Creates an instance of metroplex
49
42
  * id of script, to make sure only a single socket is open
50
43
  */
51
44
  constructor(scriptInstanceId) {
52
- const socketBase = GET_METROPLEX_BASE_SOCKET_URL();
45
+ super();
53
46
  // this flag is set to true when we manually need to close the
54
47
  // socket. It happens currently during the pagehide event and
55
48
  // if we havent sent a message to our backend in some time.
@@ -64,12 +57,13 @@ class MetroplexSocket {
64
57
  this.currentConnectionAttempts = 0;
65
58
  // how many successful connections to metroplex
66
59
  this.connectionCount = 0;
67
- // sessiont start time, used to calculate accurate end time
60
+ // session start time, used to calculate accurate end time
68
61
  this.sessionStartTime = safePerformanceNow();
62
+ this.connectionPromise = null;
69
63
  // Whether or not we have sent the page visit information after connecting the socket
70
64
  this.pageVisitInfoSent = false;
71
65
  // socket connection url
72
- this.connectionURL = `${socketBase}/${METROPLEX_FRAG_ROUTE}`;
66
+ this.connectionURL = `${GET_METROPLEX_BASE_SOCKET_URL()}/${METROPLEX_FRAG_ROUTE}`;
73
67
  // post endpoint for the same events we would send to the socket
74
68
  this.postURL = GET_METROPLEX_POST_URL();
75
69
  // sequence number of the message sent to metroplex
@@ -78,25 +72,20 @@ class MetroplexSocket {
78
72
  this.latestReceivedSeqNumber = -1;
79
73
  // set to true only when we start running behind on messages in metroplex
80
74
  this.isRetryLoopDisabled = false;
81
- // messages that need to be resent to metroplex since they are lacking confirmation
82
- this.retryMessageQueue = [];
75
+ /** messages that need to be resent to metroplex since they are lacking confirmation */
76
+ this.retryMessageQueue = createSlidingArrayOfSize(MAX_RETRY_MSG_Q_SIZE);
83
77
  // this map will hold all types that noibujs should not send to metroplex
84
78
  this.metroplexTypeLock = {};
85
79
  // setting initial URL at the start in order to guarentee that the
86
80
  // current page visit has the real initial onURL. Fragments and SPA's
87
81
  // can change the URL without reloading the page.
88
- this._initialURL = ClientConfig.getInstance().globalUrl;
89
- noibuLog('metroplex constructor', {
90
- initialURL: this._initialURL,
91
- });
92
- this.initialReferingURL = '';
82
+ this.initialURL = ClientConfig.getInstance().globalUrl;
83
+ this.initialReferringURL = '';
93
84
  this.sessionTimestamp = new Date();
94
85
  // latest time that we received a confirmation message from metroplex
95
86
  this.latestReceivedSeqNumStoredTime = new Date();
96
87
  // unique instance id of Metroplex Socket
97
88
  this.instanceId = uuid.v4();
98
- // unique script instance id
99
- this.scriptInstanceId = scriptInstanceId;
100
89
  // length of the session based on page visit events
101
90
  this.sessionLength = 0;
102
91
  // track socket closure codes for debug
@@ -107,51 +96,30 @@ class MetroplexSocket {
107
96
  this.ackedOnce = false;
108
97
  // retry frequency in ms
109
98
  this.metroRetryFrequencyMS = METROPLEX_RETRY_FREQUENCY;
110
- this.helpCodeCb = null;
111
99
  this.retryMetroplexInterval = null;
100
+ this.helpCodeCb = null;
101
+ noibuLog('Metroplex constructor', {
102
+ initialURL: this.initialURL,
103
+ scriptInstanceId,
104
+ });
105
+ this.scriptInstanceId = scriptInstanceId;
112
106
  // Connect the WS
113
107
  this.connectionPromise = this.connectSocket();
114
108
  // Set up the offload events immediately
115
109
  this._setupOffloadEvents();
116
110
  }
117
- /**
118
- * gets the singleton instance
119
- * @returns {MetroplexSocket}
120
- */
121
- static getInstance(scriptInstanceId) {
122
- if (!this.instance) {
123
- this.instance = new MetroplexSocket(scriptInstanceId);
124
- }
125
- return this.instance;
126
- }
127
111
  /**
128
112
  * Adds the seq num field to the given payload depending on whether its
129
113
  * a page visit part or video frag
130
114
  */
131
115
  _addSeqNumToPayload(type, payload) {
132
- switch (type) {
133
- case PV_METROPLEX_TYPE:
134
- this._setSeqNumInPayloadAndIncrementSeqNum(PAGE_VISIT_PART_ATT_NAME, payload);
135
- break;
136
- case VIDEO_METROPLEX_TYPE:
137
- this._setSeqNumInPayloadAndIncrementSeqNum(PAGE_VISIT_VID_FRAG_ATT_NAME, payload);
138
- break;
139
- case HTTP_DATA_METROPLEX_TYPE:
140
- this._setSeqNumInPayloadAndIncrementSeqNum(PAGE_VISIT_HTTP_DATA_ATT_NAME, payload);
141
- break;
142
- case META_DATA_METROPLEX_TYPE:
143
- this._setSeqNumInPayloadAndIncrementSeqNum(PAGE_VISIT_META_DATA_ATT_NAME, payload);
144
- break;
116
+ const newPayload = Object.assign({}, payload);
117
+ const key = MetroplexSocket.typeToPayloadPropMap[type];
118
+ if (key) {
119
+ newPayload[key][SEQ_NUM_ATT_NAME] = this.messageSequenceNum;
120
+ this.messageSequenceNum += 1;
145
121
  }
146
- }
147
- /**
148
- * sets the seq num in the payload for the given key and increments the
149
- * global seq number
150
- */
151
- _setSeqNumInPayloadAndIncrementSeqNum(payloadKey, payload) {
152
- // eslint-disable-next-line no-param-reassign
153
- payload[payloadKey][SEQ_NUM_ATT_NAME] = this.messageSequenceNum;
154
- this.messageSequenceNum += 1;
122
+ return newPayload;
155
123
  }
156
124
  /** requests help code and saves a callback to be called on response */
157
125
  requestHelpCode(cb) {
@@ -165,50 +133,53 @@ class MetroplexSocket {
165
133
  * Queues the message if the connection isn't open yet.
166
134
  * returns true if message was sent succefully, false otherwise
167
135
  */
168
- async sendMessage(type, payload) {
169
- noibuLog('sendMessage start', { type, payload: JSON.stringify(payload) });
170
- // if we have a lock on this specific type, we dont send it
171
- if (type in this.metroplexTypeLock ||
172
- ClientConfig.getInstance().isClientDisabled) {
173
- noibuLog('sendMessage quitting due to', {
174
- typeInLock: type in this.metroplexTypeLock,
175
- isClientDisabled: ClientConfig.getInstance().isClientDisabled,
176
- });
177
- return false;
178
- }
179
- const payloadData = payload;
180
- if (type !== WORK_REQUEST_ATT_NAME) {
181
- // Increasing the message sequence number for every message we send to metroplex
182
- // and move the data to the retry queue.
183
- this._addSeqNumToPayload(type, payloadData);
184
- // push the message to the retry queue immediately in case socket isnt connected
185
- this.retryMessageQueue.push({ payload: payloadData, type });
186
- StoredPageVisit.getInstance().checkAndStoreRetryQueue(this.retryMessageQueue, await this.getPageInformation());
187
- }
188
- // send the socket message if we are connected and have sent page visit info
189
- if (this.isConnected() && this.pageVisitInfoSent) {
190
- // sending the data to metroplex
191
- await this._sendSocketMessage(payloadData);
192
- }
193
- this.previousMessageType = type;
194
- // Only update the last message send if its a page visit with user action
195
- // ensure this is done regardless of whether socket is connected or not,
196
- // so that pagehide will post PV if user is active but socket is not
197
- if (type === PV_METROPLEX_TYPE && payload[PAGE_VISIT_PART_ATT_NAME]) {
198
- const events = payload[PAGE_VISIT_PART_ATT_NAME][PV_EVENTS_ATT_NAME]
199
- ? payload[PAGE_VISIT_PART_ATT_NAME][PV_EVENTS_ATT_NAME]
200
- : [];
201
- await this._updateLatestPvTimestamp(events);
202
- }
203
- return true;
136
+ sendMessage(type, payload) {
137
+ return __awaiter(this, void 0, void 0, function* () {
138
+ noibuLog('sendMessage start', { type });
139
+ // if we have a lock on this specific type, we dont send it
140
+ if (type in this.metroplexTypeLock ||
141
+ ClientConfig.getInstance().isClientDisabled) {
142
+ noibuLog('sendMessage quitting due to', {
143
+ typeInLock: type in this.metroplexTypeLock,
144
+ isClientDisabled: ClientConfig.getInstance().isClientDisabled,
145
+ });
146
+ return false;
147
+ }
148
+ if (type !== WORK_REQUEST_ATT_NAME) {
149
+ // Increasing the message sequence number for every message we send to metroplex
150
+ // and move the data to the retry queue.
151
+ this._addSeqNumToPayload(type, payload);
152
+ // push the message to the retry queue immediately in case socket isnt connected
153
+ this.retryMessageQueue.push({ payload, type });
154
+ StoredPageVisit.getInstance().checkAndStoreRetryQueue(this.retryMessageQueue, yield this.getPageInformation());
155
+ }
156
+ // send the socket message if we are connected and have sent page visit info
157
+ if (this.isConnected() && this.pageVisitInfoSent) {
158
+ // sending the data to metroplex
159
+ yield this._sendSocketMessage(payload);
160
+ }
161
+ this.previousMessageType = type;
162
+ // Only update the last message send if its a page visit with user action
163
+ // ensure this is done regardless of whether socket is connected or not,
164
+ // so that pagehide will post PV if user is active but socket is not
165
+ if (type === PV_METROPLEX_TYPE && payload[PAGE_VISIT_PART_ATT_NAME]) {
166
+ const events = payload[PAGE_VISIT_PART_ATT_NAME][PV_EVENTS_ATT_NAME]
167
+ ? payload[PAGE_VISIT_PART_ATT_NAME][PV_EVENTS_ATT_NAME]
168
+ : [];
169
+ yield this._updateLatestPvTimestamp(events);
170
+ }
171
+ return true;
172
+ });
204
173
  }
205
174
  /** Updates the latest pv message sent timestamp if events contain any user steps
206
175
  */
207
- async _updateLatestPvTimestamp(events) {
208
- const userstepsEvents = events.filter(ev => ev[TYPE_ATT_NAME] === USERSTEP_EVENT_TYPE);
209
- if (userstepsEvents.length > 0) {
210
- await ClientConfig.getInstance().updateLastActiveTime(new Date());
211
- }
176
+ _updateLatestPvTimestamp(events) {
177
+ return __awaiter(this, void 0, void 0, function* () {
178
+ const userstepsEvents = events.filter(ev => ev[TYPE_ATT_NAME] === USERSTEP_EVENT_TYPE);
179
+ if (userstepsEvents.length > 0) {
180
+ yield ClientConfig.getInstance().updateLastActiveTime(new Date());
181
+ }
182
+ });
212
183
  }
213
184
  /** returns true if the socket is either connecting or connected to metroplex */
214
185
  isConnected() {
@@ -231,77 +202,79 @@ class MetroplexSocket {
231
202
  }
232
203
  /** Connects the web socket to metroplex and calls callback upon successfully connecting
233
204
  */
234
- async handleConnect(forceOpen) {
235
- noibuLog('metroplex handleConnect');
236
- // if we are connected or about to connect, we do not reset
237
- // the socket information
238
- if (!forceOpen && (this.isConnected() || this.isConnecting())) {
239
- return;
240
- }
241
- this.currentConnectionAttempts += 1;
242
- this.socket = new WebSocket(this.connectionURL, undefined, {
243
- headers: {
244
- 'User-Agent': await getUserAgent(), // must pass useragent explicitly
245
- },
246
- });
247
- this.socketInstanceId = uuid.v4();
248
- this.socket.onerror = error => {
249
- noibuLog('metroplex handleConnect, onerror', { error });
250
- // use for metrics
251
- // there is no useful error message/description from this event
252
- };
253
- // once the socket closes
254
- this.socket.onclose = async (event) => {
255
- noibuLog('metroplex handleConnect, onclose', { event });
256
- // Reset this to prevent sending messages before the PVI is sent on reconnect
257
- this.pageVisitInfoSent = false;
258
- // we do not reconnect if the page is unloading
259
- if (this.forceClosed) {
205
+ handleConnect(forceOpen) {
206
+ return __awaiter(this, void 0, void 0, function* () {
207
+ noibuLog('metroplex handleConnect');
208
+ // if we are connected or about to connect, we do not reset
209
+ // the socket information
210
+ if (!forceOpen && (this.isConnected() || this.isConnecting())) {
260
211
  return;
261
212
  }
262
- // track socket closure codes and times
263
- this.socketCloseCodes.push(`${!isDateOverwritten() ? new Date().toISOString() : ''}:${event.code}`);
264
- // we are already in the process of reconnecting
265
- // we do not attempt to reconnect yet
266
- if (this.isConnecting()) {
267
- return;
268
- }
269
- // Clear the interval that resends unconfirmed msgs so we don't try send while the socket
270
- // is and starting back up, after which it will be restarted
271
- if (this.retryMetroplexInterval) {
272
- clearInterval(this.retryMetroplexInterval);
273
- }
274
- // if we tried reconnecting too many times we abandon
275
- if (this.currentConnectionAttempts >=
276
- GET_MAX_METROPLEX_RECONNECTION_NUMBER()) {
277
- // if we tried beyond the threshold, we block ourselves a short
278
- // while fix the issue
279
- await ClientConfig.getInstance().lockClientUntilNextPage('Too many reconnection attempts, locking until next page');
280
- return;
281
- }
282
- // if we tried reconnecting too many times we abandon
283
- if (this.connectionCount >= MAX_METROPLEX_CONNECTION_COUNT) {
284
- // if we tried beyond the threshold, we block ourselves a short
285
- // while while fix the issue
286
- await ClientConfig.getInstance().lockClientUntilNextPage('Too many connections, locking until next page');
287
- return;
288
- }
289
- // try to reconnect on close but after a certain delay based off unsuccessful connections
290
- setTimeout(() => {
291
- this.handleConnect(false);
292
- }, this.currentConnectionAttempts ** 2 * GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY());
293
- };
294
- // everytime we get a message from the socket
295
- this.socket.onmessage = event => {
296
- noibuLog('metroplex handleConnect, onmessage', { event });
297
- this._onSocketMessage(event);
298
- };
299
- // the moment we open the socket
300
- this.socket.onopen = () => {
301
- // track socket open codes and times
302
- this.socketOpens.push(`${!isDateOverwritten() ? new Date().toISOString() : ''}`);
303
- this._onSocketOpen();
304
- };
213
+ this.currentConnectionAttempts += 1;
214
+ this.socket = new WebSocket(this.connectionURL, undefined, {
215
+ headers: {
216
+ 'User-Agent': yield getUserAgent(), // must pass useragent explicitly
217
+ },
218
+ });
219
+ this.socketInstanceId = uuid.v4();
220
+ this.socket.onerror = error => {
221
+ noibuLog('metroplex handleConnect, onerror', { error });
222
+ // use for metrics
223
+ // there is no useful error message/description from this event
224
+ };
225
+ // once the socket closes
226
+ this.socket.onclose = (event) => __awaiter(this, void 0, void 0, function* () {
227
+ noibuLog('metroplex handleConnect, onclose', { event });
228
+ // Reset this to prevent sending messages before the PVI is sent on reconnect
229
+ this.pageVisitInfoSent = false;
230
+ // we do not reconnect if the page is unloading
231
+ if (this.forceClosed) {
232
+ return;
233
+ }
234
+ // track socket closure codes and times
235
+ this.socketCloseCodes.push(`${!isDateOverwritten() ? new Date().toISOString() : ''}:${event.code}`);
236
+ // we are already in the process of reconnecting
237
+ // we do not attempt to reconnect yet
238
+ if (this.isConnecting()) {
239
+ return;
240
+ }
241
+ // Clear the interval that resends unconfirmed msgs so we don't try send while the socket
242
+ // is and starting back up, after which it will be restarted
243
+ if (this.retryMetroplexInterval) {
244
+ clearInterval(this.retryMetroplexInterval);
245
+ }
246
+ // if we tried reconnecting too many times we abandon
247
+ if (this.currentConnectionAttempts >=
248
+ GET_MAX_METROPLEX_RECONNECTION_NUMBER()) {
249
+ // if we tried beyond the threshold, we block ourselves a short
250
+ // while fix the issue
251
+ yield ClientConfig.getInstance().lockClientUntilNextPage('Too many reconnection attempts, locking until next page');
252
+ return;
253
+ }
254
+ // if we tried reconnecting too many times we abandon
255
+ if (this.connectionCount >= MAX_METROPLEX_CONNECTION_COUNT) {
256
+ // if we tried beyond the threshold, we block ourselves a short
257
+ // while fix the issue
258
+ yield ClientConfig.getInstance().lockClientUntilNextPage('Too many connections, locking until next page');
259
+ return;
260
+ }
261
+ // try to reconnect on close but after a certain delay based off unsuccessful connections
262
+ setTimeout(() => {
263
+ this.handleConnect(false);
264
+ }, Math.pow(this.currentConnectionAttempts, 2) * GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY());
265
+ });
266
+ // everytime we get a message from the socket
267
+ this.socket.onmessage = event => {
268
+ noibuLog('metroplex handleConnect, onmessage', { event });
269
+ this._onSocketMessage(event);
270
+ };
271
+ // the moment we open the socket
272
+ this.socket.onopen = () => {
273
+ // track socket open codes and times
274
+ this.socketOpens.push(`${!isDateOverwritten() ? new Date().toISOString() : ''}`);
275
+ this._onSocketOpen();
276
+ };
277
+ });
305
278
  }
306
279
  /**
307
280
  * connectSocket will establish a websocket connection to the metroplex
@@ -328,95 +301,99 @@ class MetroplexSocket {
328
301
  if (isPageVisit) {
329
302
  this.sessionLength = delta;
330
303
  }
331
- return {
332
- ...payload,
333
- [END_AT_ATT_NAME]: new Date(this.sessionTimestamp.getTime() + delta).toISOString(),
334
- };
304
+ return Object.assign(Object.assign({}, payload), { [END_AT_ATT_NAME]: new Date(this.sessionTimestamp.getTime() + delta).toISOString() });
335
305
  }
336
306
  /** open handler for socket */
337
- async _onSocketOpen() {
338
- // if we are not connected, we do not send any messages
339
- if (!this.isConnected() || ClientConfig.getInstance().isClientDisabled) {
340
- return;
341
- }
342
- await this._sendSocketMessage(await this.getPageInformation());
343
- // Set this to allow normal page visit and video frag messages to be sent
344
- this.pageVisitInfoSent = true;
345
- this.currentConnectionAttempts = 0;
346
- // Resend the pagevisit or video message type before sending data so reset the prev type
347
- this.previousMessageType = '';
348
- // attempt to send the unconfirmed messages again
349
- await this._sendUnconfirmedMessages(false);
350
- // setting up the socket retry mechanism
351
- this.setupRetryMechanism();
352
- // increasing the connection count everytime we connect
353
- this.connectionCount += 1;
307
+ _onSocketOpen() {
308
+ return __awaiter(this, void 0, void 0, function* () {
309
+ // if we are not connected, we do not send any messages
310
+ if (!this.isConnected() || ClientConfig.getInstance().isClientDisabled) {
311
+ return;
312
+ }
313
+ yield this._sendSocketMessage(yield this.getPageInformation());
314
+ // Set this to allow normal page visit and video frag messages to be sent
315
+ this.pageVisitInfoSent = true;
316
+ this.currentConnectionAttempts = 0;
317
+ // Resend the pagevisit or video message type before sending data so reset the prev type
318
+ this.previousMessageType = '';
319
+ // attempt to send the unconfirmed messages again
320
+ yield this._sendUnconfirmedMessages(false);
321
+ // setting up the socket retry mechanism
322
+ this.setupRetryMechanism();
323
+ // increasing the connection count everytime we connect
324
+ this.connectionCount += 1;
325
+ });
354
326
  }
355
327
  /** message handler for socket
356
328
  * @param {} event
357
329
  */
358
- async _onSocketMessage(event) {
359
- switch (event.data) {
360
- case STOP_STORING_VID_SOCKET_MESSAGE:
361
- // stopping vids from being sent
362
- this.metroplexTypeLock[VIDEO_METROPLEX_TYPE] = true;
363
- StoredMetrics.getInstance().setDidCutVideo();
364
- break;
365
- case STOP_STORING_PV_SOCKET_MESSAGE:
366
- // stopping pv from being sent
367
- this.metroplexTypeLock[PV_METROPLEX_TYPE] = true;
368
- StoredMetrics.getInstance().setDidCutPv();
369
- break;
370
- case BLOCK_SOCKET_MESSAGE:
371
- // we are disabling collect for 1 day if we get the
372
- // block message from metroplex. We are probably on it
373
- await ClientConfig.getInstance().lockClient(1440, 'Metroplex blocked script');
374
- this.close();
375
- break;
376
- case CLOSE_CONNECTION_FORCEFULLY:
377
- this.close();
378
- break;
379
- case OK_SOCKET_MESSAGE:
380
- // we do nothing on an OK
381
- break;
382
- default:
383
- // we now need to check if we receive text that contains
384
- // the text SEQ_NUM. if that is true, then its a seq num
385
- // and we need to clear out the retry queue.
386
- if (event.data.includes(SEQ_NUM_ATT_NAME)) {
387
- const seqNumSplit = event.data.split(`${SEQ_NUM_ATT_NAME}:`);
388
- if (seqNumSplit.length < 2) {
389
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(`Invalid message received from metroplex while clearing retry queue ${event.data}`, false, SEVERITY.error);
390
- break;
391
- }
392
- // the second element in the string split is the sequence number
393
- const seqNum = parseInt(seqNumSplit[1], 10);
394
- // ignore sequence num if this is just page info, it will always be -1 and we don't want
395
- // to disable the retry loop on this
396
- if (seqNum === -1) {
330
+ _onSocketMessage(event) {
331
+ return __awaiter(this, void 0, void 0, function* () {
332
+ switch (event.data) {
333
+ case STOP_STORING_VID_SOCKET_MESSAGE:
334
+ // stopping vids from being sent
335
+ this.metroplexTypeLock[VIDEO_METROPLEX_TYPE] = true;
336
+ StoredMetrics.getInstance().setDidCutVideo();
337
+ break;
338
+ case STOP_STORING_PV_SOCKET_MESSAGE:
339
+ // stopping pv from being sent
340
+ this.metroplexTypeLock[PV_METROPLEX_TYPE] = true;
341
+ StoredMetrics.getInstance().setDidCutPv();
342
+ break;
343
+ case BLOCK_SOCKET_MESSAGE:
344
+ // we are disabling collect for 1 day if we get the
345
+ // block message from metroplex. We are probably on it
346
+ yield ClientConfig.getInstance().lockClient(1440, 'Metroplex blocked script');
347
+ this.close();
348
+ break;
349
+ case CLOSE_CONNECTION_FORCEFULLY:
350
+ this.close();
351
+ break;
352
+ case OK_SOCKET_MESSAGE:
353
+ // we do nothing on an OK
354
+ break;
355
+ default:
356
+ if (!event.data) {
397
357
  break;
398
358
  }
399
- // we disable the retry loop if we start running behind
400
- if (seqNum <= this.latestReceivedSeqNumber) {
401
- this.isRetryLoopDisabled = true;
359
+ // we now need to check if we receive text that contains
360
+ // the text SEQ_NUM. if that is true, then its a seq num
361
+ // and we need to clear out the retry queue.
362
+ if (event.data.includes(SEQ_NUM_ATT_NAME)) {
363
+ const seqNumSplit = event.data.split(`${SEQ_NUM_ATT_NAME}:`);
364
+ if (seqNumSplit.length < 2) {
365
+ ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(`Invalid message received from metroplex while clearing retry queue ${event.data}`, false, SEVERITY.error);
366
+ break;
367
+ }
368
+ // the second element in the string split is the sequence number
369
+ const seqNum = parseInt(seqNumSplit[1], 10);
370
+ // ignore sequence num if this is just page info, it will always be -1 and we don't want
371
+ // to disable the retry loop on this
372
+ if (seqNum === -1) {
373
+ break;
374
+ }
375
+ // we disable the retry loop if we start running behind
376
+ if (seqNum <= this.latestReceivedSeqNumber) {
377
+ this.isRetryLoopDisabled = true;
378
+ }
379
+ else {
380
+ this.isRetryLoopDisabled = false;
381
+ // setting the latest received seqNum
382
+ this.latestReceivedSeqNumber = seqNum;
383
+ // clear the retry queue when for this seqNum and below
384
+ this._clearRetryQueue(seqNum);
385
+ }
386
+ if (!this.ackedOnce) {
387
+ this.ackedOnce = true;
388
+ }
402
389
  }
403
- else {
404
- this.isRetryLoopDisabled = false;
405
- // setting the latest received seqNum
406
- this.latestReceivedSeqNumber = seqNum;
407
- // clear the retry queue when for this seqNum and below
408
- this._clearRetryQueue(seqNum);
409
- }
410
- if (!this.ackedOnce) {
411
- this.ackedOnce = true;
390
+ if (this._tryProcessHelpCodeResponse(event.data)) {
391
+ break;
412
392
  }
413
- }
414
- if (this._tryProcessHelpCodeResponse(event.data)) {
415
393
  break;
416
- }
417
- break;
418
- // still need to collect the id sent back from metroplex
419
- }
394
+ // still need to collect the id sent back from metroplex
395
+ }
396
+ });
420
397
  }
421
398
  /**
422
399
  * Returns true if the message's payload has the payload type given and has a sequence
@@ -433,41 +410,44 @@ class MetroplexSocket {
433
410
  */
434
411
  _clearRetryQueue(seqNum) {
435
412
  this.latestReceivedSeqNumStoredTime = new Date();
436
- this.retryMessageQueue = this.retryMessageQueue.filter(message => this._messagePayloadHasLargerSeqNum(message, PAGE_VISIT_PART_ATT_NAME, seqNum) ||
413
+ const newQueue = this.retryMessageQueue.filter(message => this._messagePayloadHasLargerSeqNum(message, PAGE_VISIT_PART_ATT_NAME, seqNum) ||
437
414
  this._messagePayloadHasLargerSeqNum(message, PAGE_VISIT_VID_FRAG_ATT_NAME, seqNum));
415
+ this.retryMessageQueue = createSlidingArrayOfSize(MAX_RETRY_MSG_Q_SIZE, newQueue);
438
416
  }
439
417
  /** will resend everything that is in the retry queue */
440
- async _sendUnconfirmedMessages(socketWasAlreadyOpen) {
441
- noibuLog('_sendUnconfirmedMessages');
442
- // we only check once. If the socket is disconnected midway, the events would
443
- // still be in the retry queue.
444
- if (!this.isConnected() || ClientConfig.getInstance().isClientDisabled) {
445
- return;
446
- }
447
- // We always send if this is on socket open
448
- if (socketWasAlreadyOpen) {
449
- // we do not send the messages to metroplex if we are falling behind on received
450
- // sequence numbers
451
- const someTimeAgo = new Date();
452
- someTimeAgo.setMilliseconds(someTimeAgo.getMilliseconds() - this.metroRetryFrequencyMS);
453
- if (someTimeAgo < this.latestReceivedSeqNumStoredTime) {
418
+ _sendUnconfirmedMessages(socketWasAlreadyOpen) {
419
+ return __awaiter(this, void 0, void 0, function* () {
420
+ noibuLog('_sendUnconfirmedMessages');
421
+ // we only check once. If the socket is disconnected midway, the events would
422
+ // still be in the retry queue.
423
+ if (!this.isConnected() || ClientConfig.getInstance().isClientDisabled) {
454
424
  return;
455
425
  }
456
- // we do not resend messages to metroplex if we are running behind
457
- if (this.isRetryLoopDisabled) {
458
- return;
426
+ // We always send if this is on socket open
427
+ if (socketWasAlreadyOpen) {
428
+ // we do not send the messages to metroplex if we are falling behind on received
429
+ // sequence numbers
430
+ const someTimeAgo = new Date();
431
+ someTimeAgo.setMilliseconds(someTimeAgo.getMilliseconds() - this.metroRetryFrequencyMS);
432
+ if (someTimeAgo < this.latestReceivedSeqNumStoredTime) {
433
+ return;
434
+ }
435
+ // we do not resend messages to metroplex if we are running behind
436
+ if (this.isRetryLoopDisabled) {
437
+ return;
438
+ }
459
439
  }
460
- }
461
- // removing all the messages with a blocked type from the retry queue
462
- this.retryMessageQueue = this.retryMessageQueue.filter(message => !(message.type in this.metroplexTypeLock));
463
- // we dont remove any items from this queue in this function
464
- for (let i = 0; i < this.retryMessageQueue.length; i += 1) {
465
- const { type, payload } = this.retryMessageQueue[i];
466
- // sending the data to metroplex
467
- // eslint-disable-next-line no-await-in-loop
468
- await this._sendSocketMessage(payload);
469
- this.previousMessageType = type;
470
- }
440
+ // removing all the messages with a blocked type from the retry queue
441
+ this.retryMessageQueue = this.retryMessageQueue.filter(message => !(message.type in this.metroplexTypeLock));
442
+ // we dont remove any items from this queue in this function
443
+ for (let i = 0; i < this.retryMessageQueue.length; i += 1) {
444
+ const { type, payload } = this.retryMessageQueue[i];
445
+ // sending the data to metroplex
446
+ // eslint-disable-next-line no-await-in-loop
447
+ yield this._sendSocketMessage(payload);
448
+ this.previousMessageType = type;
449
+ }
450
+ });
471
451
  }
472
452
  /** sets up the interval to empty the queue as we receive confirmation messages from metroplex */
473
453
  setupRetryMechanism() {
@@ -485,143 +465,149 @@ class MetroplexSocket {
485
465
  * will handle the final moments of a page being active. It
486
466
  * will try to empty both the queues with beacons.
487
467
  */
488
- async _handleUnload() {
489
- // closing the socket since the page is unloading
490
- this.close();
491
- // if we disable the client within the pagevisit, we do not
492
- // post anything during the unloading.
493
- if (ClientConfig.getInstance().isClientDisabled) {
494
- return;
495
- }
496
- // Don't send the final complete PV if the session has become inactive
497
- // we already sent the PV when went inactive
498
- if (ClientConfig.getInstance().isInactive()) {
499
- return;
500
- }
501
- await this.postFullPageVisit(MAX_BEACON_PAYLOAD_SIZE);
468
+ _handleUnload() {
469
+ return __awaiter(this, void 0, void 0, function* () {
470
+ // closing the socket since the page is unloading
471
+ this.close();
472
+ // if we disable the client within the pagevisit, we do not
473
+ // post anything during the unloading.
474
+ if (ClientConfig.getInstance().isClientDisabled) {
475
+ return;
476
+ }
477
+ // Don't send the final complete PV if the session has become inactive
478
+ // we already sent the PV when went inactive
479
+ if (ClientConfig.getInstance().isInactive()) {
480
+ return;
481
+ }
482
+ yield this.postFullPageVisit(MAX_BEACON_PAYLOAD_SIZE);
483
+ });
502
484
  }
503
485
  /**
504
486
  * will post full page visit to metroplex. It
505
487
  * will try to empty both the queues with beacons.
506
488
  */
507
- async postFullPageVisit(maxMessageSize) {
508
- if (this.retryMessageQueue.length === 0) {
509
- return;
510
- }
511
- // debug counters
512
- const postInfo = [];
513
- const numDropped = {
514
- [VIDEO_METROPLEX_TYPE]: 0,
515
- [PV_METROPLEX_TYPE]: 0,
516
- };
517
- let currentMsgPayloadSize = 0;
518
- let currentCompletePv = {
519
- [PAGE_VISIT_INFORMATION_ATT_NAME]: await this.getPageInformation(),
520
- [PAGE_VISIT_PART_ATT_NAME]: [],
521
- [PAGE_VISIT_VID_FRAG_ATT_NAME]: [],
522
- [PAGE_VISIT_HTTP_DATA_ATT_NAME]: [],
523
- [VIDEO_PART_COUNT_ATT_NAME]: this.connectionCount,
524
- };
525
- currentCompletePv[PAGE_VISIT_INFORMATION_ATT_NAME][IS_LAST_ATT_NAME] = true;
526
- const pageInfo = await this.getPageInformation();
527
- this.retryMessageQueue.forEach(msg => {
528
- // can't use two variables types in obj deconstruction
529
- // eslint-disable-next-line prefer-const
530
- let { type, payload } = msg;
531
- // If the message is larger than the beacon limit then skip to the next message
532
- const currentPayloadSize = new Blob([stringifyJSON(payload)]).size;
533
- if (currentPayloadSize > maxMessageSize) {
534
- // increment dropped count for this type
535
- numDropped[type] += 1;
489
+ postFullPageVisit(maxMessageSize) {
490
+ return __awaiter(this, void 0, void 0, function* () {
491
+ if (this.retryMessageQueue.length === 0) {
536
492
  return;
537
493
  }
538
- currentMsgPayloadSize += currentPayloadSize;
539
- if (currentMsgPayloadSize >= maxMessageSize) {
540
- this.postMessage(currentCompletePv);
541
- // add to post info
494
+ // debug counters
495
+ const postInfo = [];
496
+ const numDropped = {
497
+ [VIDEO_METROPLEX_TYPE]: 0,
498
+ [PV_METROPLEX_TYPE]: 0,
499
+ };
500
+ let currentMsgPayloadSize = 0;
501
+ let currentCompletePv = {
502
+ [PAGE_VISIT_INFORMATION_ATT_NAME]: yield this.getPageInformation(),
503
+ [PAGE_VISIT_PART_ATT_NAME]: [],
504
+ [PAGE_VISIT_VID_FRAG_ATT_NAME]: [],
505
+ [PAGE_VISIT_HTTP_DATA_ATT_NAME]: [],
506
+ [VIDEO_PART_COUNT_ATT_NAME]: this.connectionCount,
507
+ };
508
+ currentCompletePv[PAGE_VISIT_INFORMATION_ATT_NAME][IS_LAST_ATT_NAME] = true;
509
+ const pageInfo = yield this.getPageInformation();
510
+ this.retryMessageQueue.forEach(msg => {
511
+ // can't use two variables types in obj deconstruction
512
+ // eslint-disable-next-line prefer-const
513
+ let { type, payload } = msg;
514
+ // If the message is larger than the beacon limit then skip to the next message
515
+ const currentPayloadSize = new Blob([stringifyJSON(payload)]).size;
516
+ if (currentPayloadSize > maxMessageSize) {
517
+ // increment dropped count for this type
518
+ numDropped[type] += 1;
519
+ return;
520
+ }
521
+ currentMsgPayloadSize += currentPayloadSize;
522
+ if (currentMsgPayloadSize >= maxMessageSize) {
523
+ this.postMessage(currentCompletePv);
524
+ // add to post info
525
+ let postInfoMessage = `Vid: ${currentCompletePv[PAGE_VISIT_VID_FRAG_ATT_NAME].length}`;
526
+ postInfoMessage += ` PV: ${currentCompletePv[PAGE_VISIT_PART_ATT_NAME].length}`;
527
+ postInfoMessage += ` HTTP: ${currentCompletePv[PAGE_VISIT_HTTP_DATA_ATT_NAME].length},`;
528
+ postInfo.push(postInfoMessage);
529
+ // resetting currentCompletePv, since we need to keep adding
530
+ // events to a blank object to send to metroplex.
531
+ // retain the video part count, so we don't overwrite anything
532
+ currentCompletePv = {
533
+ [PAGE_VISIT_INFORMATION_ATT_NAME]: pageInfo,
534
+ [PAGE_VISIT_PART_ATT_NAME]: [],
535
+ [PAGE_VISIT_VID_FRAG_ATT_NAME]: [],
536
+ [PAGE_VISIT_HTTP_DATA_ATT_NAME]: [],
537
+ [VIDEO_PART_COUNT_ATT_NAME]: currentCompletePv[VIDEO_PART_COUNT_ATT_NAME],
538
+ };
539
+ currentCompletePv[PAGE_VISIT_INFORMATION_ATT_NAME][IS_LAST_ATT_NAME] =
540
+ true;
541
+ // resetting the message size based on what is being added
542
+ currentMsgPayloadSize = currentPayloadSize;
543
+ }
544
+ switch (type) {
545
+ case VIDEO_METROPLEX_TYPE:
546
+ currentCompletePv[PAGE_VISIT_VID_FRAG_ATT_NAME].push(payload[PAGE_VISIT_VID_FRAG_ATT_NAME]);
547
+ break;
548
+ case PV_METROPLEX_TYPE:
549
+ currentCompletePv[PAGE_VISIT_PART_ATT_NAME].push(payload[PAGE_VISIT_PART_ATT_NAME]);
550
+ break;
551
+ case HTTP_DATA_METROPLEX_TYPE:
552
+ currentCompletePv[PAGE_VISIT_HTTP_DATA_ATT_NAME].push(payload[PAGE_VISIT_HTTP_DATA_ATT_NAME]);
553
+ break;
554
+ }
555
+ });
556
+ this.postMessage(currentCompletePv);
557
+ // debug log if large retry message queue
558
+ if (this.retryMessageQueue.length > 100) {
542
559
  let postInfoMessage = `Vid: ${currentCompletePv[PAGE_VISIT_VID_FRAG_ATT_NAME].length}`;
543
560
  postInfoMessage += ` PV: ${currentCompletePv[PAGE_VISIT_PART_ATT_NAME].length}`;
544
561
  postInfoMessage += ` HTTP: ${currentCompletePv[PAGE_VISIT_HTTP_DATA_ATT_NAME].length},`;
545
562
  postInfo.push(postInfoMessage);
546
- // resetting currentCompletePv, since we need to keep adding
547
- // events to a blank object to send to metroplex.
548
- // retain the video part count, so we don't overwrite anything
549
- currentCompletePv = {
550
- [PAGE_VISIT_INFORMATION_ATT_NAME]: pageInfo,
551
- [PAGE_VISIT_PART_ATT_NAME]: [],
552
- [PAGE_VISIT_VID_FRAG_ATT_NAME]: [],
553
- [PAGE_VISIT_HTTP_DATA_ATT_NAME]: [],
554
- [VIDEO_PART_COUNT_ATT_NAME]: currentCompletePv[VIDEO_PART_COUNT_ATT_NAME],
555
- };
556
- currentCompletePv[PAGE_VISIT_INFORMATION_ATT_NAME][IS_LAST_ATT_NAME] =
557
- true;
558
- // resetting the message size based on what is being added
559
- currentMsgPayloadSize = currentPayloadSize;
560
- }
561
- switch (type) {
562
- case VIDEO_METROPLEX_TYPE:
563
- currentCompletePv[PAGE_VISIT_VID_FRAG_ATT_NAME].push(payload[PAGE_VISIT_VID_FRAG_ATT_NAME]);
564
- break;
565
- case PV_METROPLEX_TYPE:
566
- currentCompletePv[PAGE_VISIT_PART_ATT_NAME].push(payload[PAGE_VISIT_PART_ATT_NAME]);
567
- break;
568
- case HTTP_DATA_METROPLEX_TYPE:
569
- currentCompletePv[PAGE_VISIT_HTTP_DATA_ATT_NAME].push(payload[PAGE_VISIT_HTTP_DATA_ATT_NAME]);
570
- break;
563
+ // we completed posted the full pv, send the confirmation debug logs
564
+ // build the debug message
565
+ let message = 'POST Full PV complete';
566
+ // POST counts
567
+ message += `, POSTs count: ${postInfo.length}`;
568
+ message += `, POSTs info: ${stringifyJSON(postInfo)}`;
569
+ // Initial retry message queue size
570
+ message += `, Retry message queue size: ${this.retryMessageQueue.length}`;
571
+ // Num drops
572
+ if (numDropped[VIDEO_METROPLEX_TYPE] > 0) {
573
+ message += `, Video parts dropped: ${numDropped[VIDEO_METROPLEX_TYPE]}`;
574
+ }
575
+ if (numDropped[PV_METROPLEX_TYPE] > 0) {
576
+ message += `, Page visit parts dropped: ${numDropped[PV_METROPLEX_TYPE]}`;
577
+ }
578
+ if (numDropped[HTTP_DATA_METROPLEX_TYPE] > 0) {
579
+ message += `, HTTP data parts dropped: ${numDropped[HTTP_DATA_METROPLEX_TYPE]}`;
580
+ }
581
+ // Sequence info
582
+ message += `, Sequence Info: Latest ${this.messageSequenceNum}`;
583
+ message += ` Ack'd ${this.latestReceivedSeqNumStoredTime} ${this.latestReceivedSeqNumber}`;
584
+ // if client was disabled (due to inactive or otherwise) enable briefly so the
585
+ // debug message gets through
586
+ const clientDisabled = ClientConfig.getInstance().isClientDisabled;
587
+ ClientConfig.getInstance().isClientDisabled = false;
588
+ ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(message, clientDisabled, SEVERITY.warn);
571
589
  }
572
590
  });
573
- this.postMessage(currentCompletePv);
574
- // debug log if large retry message queue
575
- if (this.retryMessageQueue.length > 100) {
576
- let postInfoMessage = `Vid: ${currentCompletePv[PAGE_VISIT_VID_FRAG_ATT_NAME].length}`;
577
- postInfoMessage += ` PV: ${currentCompletePv[PAGE_VISIT_PART_ATT_NAME].length}`;
578
- postInfoMessage += ` HTTP: ${currentCompletePv[PAGE_VISIT_HTTP_DATA_ATT_NAME].length},`;
579
- postInfo.push(postInfoMessage);
580
- // we completed posted the full pv, send the confirmation debug logs
581
- // build the debug message
582
- let message = 'POST Full PV complete';
583
- // POST counts
584
- message += `, POSTs count: ${postInfo.length}`;
585
- message += `, POSTs info: ${stringifyJSON(postInfo)}`;
586
- // Initial retry message queue size
587
- message += `, Retry message queue size: ${this.retryMessageQueue.length}`;
588
- // Num drops
589
- if (numDropped[VIDEO_METROPLEX_TYPE] > 0) {
590
- message += `, Video parts dropped: ${numDropped[VIDEO_METROPLEX_TYPE]}`;
591
- }
592
- if (numDropped[PV_METROPLEX_TYPE] > 0) {
593
- message += `, Page visit parts dropped: ${numDropped[PV_METROPLEX_TYPE]}`;
594
- }
595
- if (numDropped[HTTP_DATA_METROPLEX_TYPE] > 0) {
596
- message += `, HTTP data parts dropped: ${numDropped[HTTP_DATA_METROPLEX_TYPE]}`;
597
- }
598
- // Sequence info
599
- message += `, Sequence Info: Latest ${this.messageSequenceNum}`;
600
- message += ` Ack'd ${this.latestReceivedSeqNumStoredTime} ${this.latestReceivedSeqNumber}`;
601
- // if client was disabled (due to inactive or otherwise) enable briefly so the
602
- // debug message gets through
603
- const clientDisabled = ClientConfig.getInstance().isClientDisabled;
604
- ClientConfig.getInstance().isClientDisabled = false;
605
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(message, clientDisabled, SEVERITY.warn);
606
- }
607
591
  }
608
592
  /**
609
593
  * will send a message to metroplex via a post request that will outlive the current page
610
594
  */
611
- async postMessage(msg) {
612
- const updatedMsg = msg;
613
- // ensure a unique video part number each call
614
- updatedMsg[VIDEO_PART_COUNT_ATT_NAME] += 1;
615
- // we send the remainder elements
616
- unwrapNoibuWrapped(fetch)(this.postURL, {
617
- method: 'POST',
618
- headers: {
619
- 'content-type': 'application/json',
620
- 'User-Agent': await getUserAgent(),
621
- },
622
- body: stringifyJSON(updatedMsg),
623
- // keep alive outlives the current page, its the same as beacon
624
- keepalive: true,
595
+ postMessage(msg) {
596
+ return __awaiter(this, void 0, void 0, function* () {
597
+ const updatedMsg = msg;
598
+ // ensure a unique video part number each call
599
+ updatedMsg[VIDEO_PART_COUNT_ATT_NAME] += 1;
600
+ // we send the remainder elements
601
+ unwrapNoibuWrapped(fetch)(this.postURL, {
602
+ method: 'POST',
603
+ headers: {
604
+ 'content-type': 'application/json',
605
+ 'User-Agent': yield getUserAgent(),
606
+ },
607
+ body: stringifyJSON(updatedMsg),
608
+ // keep alive outlives the current page, its the same as beacon
609
+ keepalive: true,
610
+ });
625
611
  });
626
612
  }
627
613
  /**
@@ -629,64 +615,69 @@ class MetroplexSocket {
629
615
  * is active and returns true. If inactive the session and socket are closed
630
616
  * and this method returns false.
631
617
  */
632
- async _sendSocketMessage(payload) {
633
- noibuLog('_sendSocketMessage');
634
- const closeIfInactive = await this.closeIfInactive();
635
- if (closeIfInactive) {
636
- noibuLog('_sendSocketMessage dropped due to', { closeIfInactive });
637
- return;
638
- }
639
- const payloadJson = stringifyJSON(payload);
640
- noibuLog(`_sendSocketMessage sending: ${payloadJson}`);
641
- if (this.socket) {
642
- this.socket.send(payloadJson);
643
- }
618
+ _sendSocketMessage(payload) {
619
+ return __awaiter(this, void 0, void 0, function* () {
620
+ noibuLog('_sendSocketMessage');
621
+ const closeIfInactive = yield this.closeIfInactive();
622
+ if (closeIfInactive) {
623
+ noibuLog('_sendSocketMessage dropped due to', { closeIfInactive });
624
+ return;
625
+ }
626
+ const payloadJson = stringifyJSON(payload);
627
+ noibuLog(`_sendSocketMessage sending: ${PAGE_VISIT_VID_FRAG_ATT_NAME in payload
628
+ ? PAGE_VISIT_VID_FRAG_ATT_NAME
629
+ : payloadJson}`);
630
+ if (this.socket) {
631
+ this.socket.send(payloadJson);
632
+ }
633
+ });
644
634
  }
645
635
  /**
646
636
  * Closes the socket connection if the session is inactive. Returns true if the
647
637
  * session is inactive
648
638
  */
649
- async closeIfInactive() {
650
- const inactive = ClientConfig.getInstance().isInactive();
651
- // if we weren't already inactive, go to inactive state
652
- if (inactive && !ClientConfig.getInstance().isClientDisabled) {
653
- // lock the client for 1 minute, since the lock expires
654
- // only on new page loads this will lock the client until
655
- // the next page is loaded.
656
- await ClientConfig.getInstance().lockClientUntilNextPage('Session is inactive, locking until next page');
657
- this.close();
658
- Promise.all([
639
+ closeIfInactive() {
640
+ return __awaiter(this, void 0, void 0, function* () {
641
+ const inactive = ClientConfig.getInstance().isInactive();
642
+ // if we weren't already inactive, go to inactive state
643
+ if (inactive && !ClientConfig.getInstance().isClientDisabled) {
644
+ // lock the client for 1 minute, since the lock expires
645
+ // only on new page loads this will lock the client until
646
+ // the next page is loaded.
647
+ yield ClientConfig.getInstance().lockClientUntilNextPage('Session is inactive, locking until next page');
648
+ this.close();
659
649
  // post metrics now so we don't include events after going inactive
660
- StoredMetrics.getInstance().postMetrics(),
650
+ StoredMetrics.getInstance().postMetrics();
661
651
  // post retry queue now so we don't include event after going inactive
662
- this.postFullPageVisit(MAX_BEACON_PAYLOAD_SIZE),
663
- ]);
664
- }
665
- return inactive;
652
+ this.postFullPageVisit(MAX_BEACON_PAYLOAD_SIZE);
653
+ }
654
+ return inactive;
655
+ });
666
656
  }
667
657
  /** will get page information, calling this will increase the connection count */
668
- async getPageInformation() {
669
- return {
670
- [BROWSER_ID_ATT_NAME]: ClientConfig.getInstance().browserId,
671
- [PV_ID_ATT_NAME]: ClientConfig.getInstance().pageVisitId,
672
- [VER_ATT_NAME]: CURRENT_PV_VERSION,
673
- [PV_SEQ_ATT_NAME]: await ClientConfig.getInstance().getPageVisitSeq(),
674
- [ON_URL_ATT_NAME]: this._initialURL,
675
- [REF_URL_ATT_NAME]: this.initialReferingURL,
676
- [STARTED_AT_ATT_NAME]: this.sessionTimestamp.toISOString(),
677
- [CONN_COUNT_ATT_NAME]: this.connectionCount,
678
- [COLLECT_VER_ATT_NAME]: CURRENT_NOIBUJS_VERSION,
679
- [IS_LAST_ATT_NAME]: false,
680
- [SCRIPT_ID_ATT_NAME]: GET_SCRIPT_ID(),
681
- [SCRIPT_INSTANCE_ID_ATT_NAME]: this.scriptInstanceId,
682
- [METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME]: this.instanceId,
683
- [SOCKET_INSTANCE_ID_ATT_NAME]: this.socketInstanceId,
684
- [VIDEO_RECORDER_ATT_NAME]: await getVideoRecorderType(),
685
- };
658
+ getPageInformation() {
659
+ return __awaiter(this, void 0, void 0, function* () {
660
+ return {
661
+ [BROWSER_ID_ATT_NAME]: ClientConfig.getInstance().browserId,
662
+ [PV_ID_ATT_NAME]: ClientConfig.getInstance().pageVisitId,
663
+ [VER_ATT_NAME]: CURRENT_PV_VERSION,
664
+ [PV_SEQ_ATT_NAME]: yield ClientConfig.getInstance().getPageVisitSeq(),
665
+ [ON_URL_ATT_NAME]: this.initialURL,
666
+ [REF_URL_ATT_NAME]: this.initialReferringURL,
667
+ [STARTED_AT_ATT_NAME]: this.sessionTimestamp.toISOString(),
668
+ [CONN_COUNT_ATT_NAME]: this.connectionCount,
669
+ [COLLECT_VER_ATT_NAME]: CURRENT_NOIBUJS_VERSION,
670
+ [IS_LAST_ATT_NAME]: false,
671
+ [SCRIPT_ID_ATT_NAME]: GET_SCRIPT_ID(),
672
+ [SCRIPT_INSTANCE_ID_ATT_NAME]: this.scriptInstanceId,
673
+ [METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME]: this.instanceId,
674
+ [SOCKET_INSTANCE_ID_ATT_NAME]: this.socketInstanceId,
675
+ [VIDEO_RECORDER_ATT_NAME]: yield getVideoRecorderType(),
676
+ };
677
+ });
686
678
  }
687
679
  /**
688
680
  * Try to parse help code response and fire custom event
689
- * @param {String} response
690
681
  */
691
682
  _tryProcessHelpCodeResponse(response) {
692
683
  const prefix = `${HELP_CODE_ATT_NAME}:`;
@@ -701,5 +692,11 @@ class MetroplexSocket {
701
692
  return true;
702
693
  }
703
694
  }
695
+ MetroplexSocket.typeToPayloadPropMap = {
696
+ [HTTP_DATA_METROPLEX_TYPE]: PAGE_VISIT_HTTP_DATA_ATT_NAME,
697
+ [META_DATA_METROPLEX_TYPE]: PAGE_VISIT_META_DATA_ATT_NAME,
698
+ [PV_METROPLEX_TYPE]: PAGE_VISIT_PART_ATT_NAME,
699
+ [VIDEO_METROPLEX_TYPE]: PAGE_VISIT_VID_FRAG_ATT_NAME,
700
+ };
704
701
 
705
- export { MetroplexSocket as default };
702
+ export { createSlidingArrayOfSize, MetroplexSocket as default };