@newrelic/video-core 5.0.2 → 5.1.0

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 (78) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +13 -0
  3. package/dist/cjs/browser/index.js +1 -1
  4. package/dist/cjs/browser/index.js.LICENSE.txt +1 -1
  5. package/dist/cjs/browser/index.js.map +1 -1
  6. package/dist/cjs/index.js +1 -1
  7. package/dist/cjs/index.js.LICENSE.txt +1 -1
  8. package/dist/cjs/index.js.map +1 -1
  9. package/dist/cjs/vega/index.js +1 -1
  10. package/dist/cjs/vega/index.js.LICENSE.txt +1 -1
  11. package/dist/cjs/vega/index.js.map +1 -1
  12. package/dist/esm/browser/index.js +1 -1
  13. package/dist/esm/browser/index.js.LICENSE.txt +1 -1
  14. package/dist/esm/browser/index.js.map +1 -1
  15. package/dist/esm/index.js +1 -1
  16. package/dist/esm/index.js.LICENSE.txt +1 -1
  17. package/dist/esm/index.js.map +1 -1
  18. package/dist/esm/vega/index.js +1 -1
  19. package/dist/esm/vega/index.js.LICENSE.txt +1 -1
  20. package/dist/esm/vega/index.js.map +1 -1
  21. package/dist/types/browser/agent.d.ts +46 -0
  22. package/dist/types/browser/harvestScheduler.d.ts +125 -0
  23. package/dist/types/browser/index.d.ts +34 -0
  24. package/dist/types/chrono.d.ts +52 -0
  25. package/dist/types/connectedDevice/connectedDeviceAgent.d.ts +63 -0
  26. package/dist/types/connectedDevice/connectedDeviceConstants.d.ts +51 -0
  27. package/dist/types/connectedDevice/connectedDeviceHarvester.d.ts +198 -0
  28. package/dist/types/connectedDevice/index.d.ts +30 -0
  29. package/dist/types/constants.d.ts +30 -0
  30. package/dist/types/core.d.ts +54 -0
  31. package/dist/types/emitter.d.ts +42 -0
  32. package/dist/types/eventAggregator.d.ts +97 -0
  33. package/dist/types/index.d.ts +33 -0
  34. package/dist/types/log.d.ts +61 -0
  35. package/dist/types/obfuscate.d.ts +13 -0
  36. package/dist/types/optimizedHttpClient.d.ts +83 -0
  37. package/dist/types/recordEvent.d.ts +30 -0
  38. package/dist/types/retryQueueHandler.d.ts +46 -0
  39. package/dist/types/tracker.d.ts +176 -0
  40. package/dist/types/utils/eventBuilder.d.ts +69 -0
  41. package/dist/types/utils/harvestTimer.d.ts +45 -0
  42. package/dist/types/utils/index.d.ts +38 -0
  43. package/dist/types/utils/qoeFilters.d.ts +88 -0
  44. package/dist/types/videoConfiguration.d.ts +90 -0
  45. package/dist/types/videotracker.d.ts +366 -0
  46. package/dist/types/videotrackerstate.d.ts +228 -0
  47. package/dist/umd/nrvideo.min.js +1 -1
  48. package/dist/umd/nrvideo.min.js.LICENSE.txt +1 -1
  49. package/dist/umd/nrvideo.min.js.map +1 -1
  50. package/package.json +14 -2
  51. package/src/browser/{agent.js → agent.ts} +21 -16
  52. package/src/browser/{harvestScheduler.js → harvestScheduler.ts} +51 -24
  53. package/src/{chrono.js → chrono.ts} +29 -24
  54. package/src/connectedDevice/{connectedDeviceAgent.js → connectedDeviceAgent.ts} +14 -10
  55. package/src/connectedDevice/{connectedDeviceConstants.js → connectedDeviceConstants.ts} +5 -3
  56. package/src/connectedDevice/{connectedDeviceHarvester.js → connectedDeviceHarvester.ts} +71 -34
  57. package/src/constants.ts +62 -0
  58. package/src/{core.js → core.ts} +31 -18
  59. package/src/{emitter.js → emitter.ts} +16 -5
  60. package/src/{eventAggregator.js → eventAggregator.ts} +33 -19
  61. package/src/global.d.ts +25 -0
  62. package/src/{log.js → log.ts} +23 -17
  63. package/src/{obfuscate.js → obfuscate.ts} +6 -1
  64. package/src/{optimizedHttpClient.js → optimizedHttpClient.ts} +37 -13
  65. package/src/{recordEvent.js → recordEvent.ts} +11 -9
  66. package/src/{retryQueueHandler.js → retryQueueHandler.ts} +17 -12
  67. package/src/{tracker.js → tracker.ts} +56 -23
  68. package/src/utils/{eventBuilder.js → eventBuilder.ts} +31 -14
  69. package/src/utils/{harvestTimer.js → harvestTimer.ts} +21 -4
  70. package/src/utils/{index.js → index.ts} +14 -14
  71. package/src/utils/{qoeFilters.js → qoeFilters.ts} +19 -8
  72. package/src/{videoConfiguration.js → videoConfiguration.ts} +44 -10
  73. package/src/{videotracker.js → videotracker.ts} +119 -78
  74. package/src/{videotrackerstate.js → videotrackerstate.ts} +113 -49
  75. package/src/constants.js +0 -63
  76. /package/src/browser/{index.js → index.ts} +0 -0
  77. /package/src/connectedDevice/{index.js → index.ts} +0 -0
  78. /package/src/{index.js → index.ts} +0 -0
@@ -1,15 +1,29 @@
1
1
  import Log from "./log";
2
2
  import Constants from "./constants";
3
3
  import { dataSize } from "./utils";
4
+ import { EventAttributes } from "./utils/eventBuilder";
4
5
 
5
6
  const { MAX_PAYLOAD_SIZE, MAX_EVENTS_PER_BATCH } = Constants;
6
7
 
8
+ export type SmartHarvestCallback = (reason: "overflow" | "smart", percentage: number) => void;
9
+
7
10
  /**
8
11
  * Enhanced event buffer that manages video events with unified priority handling
9
12
  * and automatic size management. All events are treated with equal priority
10
13
  * unless explicitly specified otherwise.
11
14
  */
12
15
  export class NrVideoEventAggregator {
16
+ buffer: EventAttributes[];
17
+ maxPayloadSize: number;
18
+ maxEventsPerBatch: number;
19
+ currentPayloadSize: number;
20
+ totalEvents: number;
21
+ smartHarvestPayloadThreshold: number;
22
+ overflowPayloadThreshold: number;
23
+ smartHarvestEventThreshold: number;
24
+ overflowEventThreshold: number;
25
+ onSmartHarvestTrigger: SmartHarvestCallback | null;
26
+
13
27
  constructor() {
14
28
  // Simplified to single priority queue for equal treatment
15
29
 
@@ -39,7 +53,7 @@ export class NrVideoEventAggregator {
39
53
  * @param {object} eventObject - The event object to add or use as replacement. Should contain an actionName property.
40
54
  * @returns {boolean} True if the operation succeeded, false if an error occurred
41
55
  */
42
- addOrReplaceByActionName(actionName, eventObject) {
56
+ addOrReplaceByActionName(actionName: string, eventObject: EventAttributes): boolean {
43
57
  const i = this.buffer.findIndex(e => e.actionName === actionName);
44
58
 
45
59
  try {
@@ -49,7 +63,7 @@ export class NrVideoEventAggregator {
49
63
  this.add(eventObject, i);
50
64
  }
51
65
  return true;
52
- } catch (error) {
66
+ } catch (error: any) {
53
67
  Log.error("Failed to set or replace the event to buffer:", error.message);
54
68
  return false;
55
69
  }
@@ -63,7 +77,7 @@ export class NrVideoEventAggregator {
63
77
  * @param {object} eventObject - The event object to add or use as replacement.
64
78
  * @returns {boolean} True if the operation succeeded, false if an error occurred
65
79
  */
66
- addOrReplaceByActionNameAndViewId(actionName, viewId, eventObject) {
80
+ addOrReplaceByActionNameAndViewId(actionName: string, viewId: string, eventObject: EventAttributes): boolean {
67
81
  const i = this.buffer.findIndex(
68
82
  e => e.actionName === actionName && e.viewId === viewId
69
83
  );
@@ -74,7 +88,7 @@ export class NrVideoEventAggregator {
74
88
  this.add(eventObject, i);
75
89
  }
76
90
  return true;
77
- } catch (error) {
91
+ } catch (error: any) {
78
92
  Log.error("Failed to set or replace the event to buffer:", error.message);
79
93
  return false;
80
94
  }
@@ -86,7 +100,7 @@ export class NrVideoEventAggregator {
86
100
  * @param {string} viewId
87
101
  * @returns {object|null}
88
102
  */
89
- findByActionNameAndViewId(actionName, viewId) {
103
+ findByActionNameAndViewId(actionName: string, viewId: string): EventAttributes | null {
90
104
  const event = this.buffer.find(
91
105
  e => e.actionName === actionName && e.viewId === viewId
92
106
  );
@@ -98,7 +112,7 @@ export class NrVideoEventAggregator {
98
112
  * @param {string} actionName
99
113
  * @returns {object|null}
100
114
  */
101
- findByActionName(actionName) {
115
+ findByActionName(actionName: string): EventAttributes | null {
102
116
  const event = this.buffer.find(e => e.actionName === actionName);
103
117
  return event || null;
104
118
  }
@@ -109,10 +123,10 @@ export class NrVideoEventAggregator {
109
123
  * @param {object} eventObject - The event to add
110
124
  * @param {number} index - index at which the event should be replaced with
111
125
  */
112
- add(eventObject, index) {
126
+ add(eventObject: EventAttributes, index?: number): boolean {
113
127
  try {
114
128
  // Calculate event payload size
115
- const eventSize = dataSize(eventObject);
129
+ const eventSize = dataSize(eventObject) ?? 0;
116
130
 
117
131
  // Check if we need to make room based on EITHER payload size OR event count limits
118
132
  const wouldExceedPayload =
@@ -126,7 +140,7 @@ export class NrVideoEventAggregator {
126
140
 
127
141
  if(index !== undefined && index !== null && index > -1) {
128
142
  // replace in unified buffer
129
- const previousPayloadSize = dataSize(this.buffer[index]);
143
+ const previousPayloadSize = dataSize(this.buffer[index]) ?? 0;
130
144
  this.buffer[index] = eventObject;
131
145
  // Updating the payload size for the replaced event
132
146
  this.currentPayloadSize += eventSize - previousPayloadSize;
@@ -141,7 +155,7 @@ export class NrVideoEventAggregator {
141
155
  this.checkSmartHarvestTrigger();
142
156
 
143
157
  return true;
144
- } catch (error) {
158
+ } catch (error: any) {
145
159
  Log.error("Failed to add event to buffer:", error.message);
146
160
  return false;
147
161
  }
@@ -154,7 +168,7 @@ export class NrVideoEventAggregator {
154
168
  * - 90% of payload size (900KB) OR 90% of event count (900 events)
155
169
  * @private
156
170
  */
157
- checkSmartHarvestTrigger() {
171
+ checkSmartHarvestTrigger(): void {
158
172
  const payloadPercentage = this.currentPayloadSize / this.maxPayloadSize;
159
173
  const eventPercentage = this.totalEvents / this.maxEventsPerBatch;
160
174
 
@@ -209,7 +223,7 @@ export class NrVideoEventAggregator {
209
223
  * Sets the callback function for smart harvest triggers.
210
224
  * @param {Function} callback - Function to call when smart harvest is triggered
211
225
  */
212
- setSmartHarvestCallback(callback) {
226
+ setSmartHarvestCallback(callback: SmartHarvestCallback): void {
213
227
  this.onSmartHarvestTrigger = callback;
214
228
  }
215
229
 
@@ -218,7 +232,7 @@ export class NrVideoEventAggregator {
218
232
  * No limits needed since buffer already manages size via makeRoom() and smart harvest triggers.
219
233
  * @returns {Array} Array of events in order they were added
220
234
  */
221
- drain() {
235
+ drain(): EventAttributes[] {
222
236
  try {
223
237
  // Drain ALL events - buffer size is already managed by makeRoom() and smart harvest
224
238
  const events = this.buffer.splice(0);
@@ -228,7 +242,7 @@ export class NrVideoEventAggregator {
228
242
  this.currentPayloadSize = 0;
229
243
 
230
244
  return events;
231
- } catch (error) {
245
+ } catch (error: any) {
232
246
  Log.error("Failed to drain events from buffer:", error.message);
233
247
  return [];
234
248
  }
@@ -238,7 +252,7 @@ export class NrVideoEventAggregator {
238
252
  * Checks if the buffer is empty.
239
253
  * @returns {boolean} True if all buffers are empty
240
254
  */
241
- isEmpty() {
255
+ isEmpty(): boolean {
242
256
  return this.totalEvents === 0;
243
257
  }
244
258
 
@@ -246,14 +260,14 @@ export class NrVideoEventAggregator {
246
260
  * Gets the total number of events across all buffers.
247
261
  * @returns {number} Total event count
248
262
  */
249
- size() {
263
+ size(): number {
250
264
  return this.totalEvents;
251
265
  }
252
266
 
253
267
  /**
254
268
  * Clears the entire buffer.
255
269
  */
256
- clear() {
270
+ clear(): void {
257
271
  this.buffer = [];
258
272
  this.totalEvents = 0;
259
273
  }
@@ -263,7 +277,7 @@ export class NrVideoEventAggregator {
263
277
  * Uses FIFO approach - removes the first (oldest) event.
264
278
  * @private
265
279
  */
266
- makeRoom(newEventSize) {
280
+ makeRoom(newEventSize: number): void {
267
281
  // Before the while loop in makeRoom()
268
282
  if (newEventSize > this.maxPayloadSize) {
269
283
  Log.error("Event dropped: Event size exceeds maximum payload size.");
@@ -281,7 +295,7 @@ export class NrVideoEventAggregator {
281
295
  const removed = this.buffer.shift(); // Remove the oldest event (FIFO)
282
296
 
283
297
  // Recalculate size and count after removal
284
- const removedSize = dataSize(removed);
298
+ const removedSize = dataSize(removed) ?? 0;
285
299
  this.totalEvents--;
286
300
  this.currentPayloadSize -= removedSize;
287
301
 
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Ambient global augmentation for the two configuration slots the library
3
+ * writes at runtime — see videoConfiguration.ts::initializeGlobalConfig,
4
+ * which is the single source of truth for these shapes.
5
+ */
6
+
7
+ import type {
8
+ NrVideoBrowserInfo,
9
+ NrVideoBrowserConfig,
10
+ NrVideoCdInfo,
11
+ NrVideoCdConfig,
12
+ } from "./videoConfiguration";
13
+
14
+ declare global {
15
+ interface Window {
16
+ NRVIDEO?: { info: NrVideoBrowserInfo; config: NrVideoBrowserConfig };
17
+ }
18
+
19
+ // eslint-disable-next-line no-var
20
+ var __NRVIDEO_CD__:
21
+ | { info: NrVideoCdInfo; config: NrVideoCdConfig }
22
+ | undefined;
23
+ }
24
+
25
+ export {};
@@ -5,12 +5,18 @@
5
5
  * @static
6
6
  */
7
7
  class Log {
8
+ static Levels: Record<string, number>;
9
+ static level: number | string;
10
+ static colorful: boolean;
11
+ static includeTime: boolean;
12
+ static prefix: string;
13
+
8
14
  /**
9
15
  * Sends an error console log.
10
16
  * @param {...any} [msg] Message to show
11
17
  * @static
12
18
  */
13
- static error(...msg) {
19
+ static error(...msg: any[]) {
14
20
  _report(msg, Log.Levels.ERROR, "darkred");
15
21
  }
16
22
 
@@ -20,7 +26,7 @@ class Log {
20
26
  * @static
21
27
  * @param {...any} msg Message to show
22
28
  */
23
- static warn(...msg) {
29
+ static warn(...msg: any[]) {
24
30
  _report(msg, Log.Levels.WARNING, "darkorange");
25
31
  }
26
32
 
@@ -30,7 +36,7 @@ class Log {
30
36
  * @static
31
37
  * @param {...any} msg Message to show
32
38
  */
33
- static notice(...msg) {
39
+ static notice(...msg: any[]) {
34
40
  _report([].slice.call(arguments), Log.Levels.NOTICE, "darkcyan");
35
41
  }
36
42
 
@@ -40,7 +46,7 @@ class Log {
40
46
  * @static
41
47
  * @param {...any} msg Message to show
42
48
  */
43
- static debug(...msg) {
49
+ static debug(...msg: any[]) {
44
50
  _report(msg, Log.Levels.DEBUG, "indigo");
45
51
  }
46
52
 
@@ -63,12 +69,12 @@ class Log {
63
69
  * @param {function} [report] Callback function called to report events.
64
70
  * Default calls Log.debug()
65
71
  */
66
- static debugCommonVideoEvents(o, extraEvents, report) {
72
+ static debugCommonVideoEvents(o: any, extraEvents?: any[], report?: (e: any) => void) {
67
73
  try {
68
- if (Log.level <= Log.Levels.DEBUG) {
74
+ if ((Log.level as any) <= Log.Levels.DEBUG) {
69
75
  report =
70
76
  report ||
71
- function (e) {
77
+ function (e: any) {
72
78
  Log.debug("Event: " + e.type);
73
79
  };
74
80
 
@@ -186,7 +192,7 @@ Log.prefix = "[nrvideo]";
186
192
  * @param {string} [color='darkgreen'] Color of the header
187
193
  * @see {@link Log.level}
188
194
  */
189
- function _report(msg, level, color) {
195
+ function _report(msg: any[], level?: number | string, color?: string) {
190
196
  level = level || Log.Levels.NOTICE;
191
197
  color = color || "darkcyan";
192
198
 
@@ -195,23 +201,23 @@ function _report(msg, level, color) {
195
201
  prefix += _level2letter(level) + ":";
196
202
 
197
203
  // Show messages in actual console if level is enought
198
- if (Log.level <= level && level !== Log.Levels.SILENT) {
204
+ if ((Log.level as any) <= level && level !== Log.Levels.SILENT) {
199
205
  if (
200
206
  !Log.colorful ||
201
- (typeof document !== "undefined" && document.documentMode)
207
+ (typeof document !== "undefined" && (document as any).documentMode)
202
208
  ) {
203
209
  // document.documentMode exits only in IE
204
210
  _plainReport(msg, prefix);
205
211
  } else {
206
212
  // choose log method
207
- var logMethod;
213
+ var logMethod: (...args: any[]) => void;
208
214
  if (level === Log.Levels.ERROR && console.error) {
209
215
  logMethod = console.error;
210
216
  } else if (level === Log.Levels.WARNING && console.warn) {
211
217
  logMethod = console.warn;
212
218
  } else if (level === Log.Levels.DEBUG && console.debug) {
213
219
  // NOTE: for some reason console.debug doesn't work on CAF Receivers.
214
- if (window.cast == undefined) {
220
+ if ((window as any).cast == undefined) {
215
221
  logMethod = console.debug;
216
222
  } else {
217
223
  logMethod = console.log;
@@ -233,7 +239,7 @@ function _report(msg, level, color) {
233
239
  * @private
234
240
  * @return {string} Current time.
235
241
  */
236
- function _getCurrentTime() {
242
+ function _getCurrentTime(): string {
237
243
  var d = new Date();
238
244
  var hh = ("0" + d.getDate()).slice(-2);
239
245
  var mm = ("0" + d.getMinutes()).slice(-2);
@@ -249,7 +255,7 @@ function _getCurrentTime() {
249
255
  * @param {(string|object|array)} msg Message string, object or array of messages.
250
256
  * @param {string} prefix Prefix of the message.
251
257
  */
252
- function _plainReport(msg, prefix) {
258
+ function _plainReport(msg: any, prefix: string) {
253
259
  if (msg instanceof Array) {
254
260
  for (var m in msg) {
255
261
  _plainReport(msg[m], prefix);
@@ -264,7 +270,7 @@ function _plainReport(msg, prefix) {
264
270
  }
265
271
  }
266
272
 
267
- const _letters = {
273
+ const _letters: Record<number, string> = {
268
274
  4: "e", // Error
269
275
  3: "w", // Warning
270
276
  2: "n", // Notice
@@ -277,8 +283,8 @@ const _letters = {
277
283
  * @private
278
284
  * @param {sLog.Level} level Level of the message
279
285
  */
280
- function _level2letter(level) {
281
- return _letters[level];
286
+ function _level2letter(level: number | string): string {
287
+ return _letters[level as number];
282
288
  }
283
289
 
284
290
  /**
@@ -1,5 +1,10 @@
1
1
  import Log from "./log";
2
2
 
3
+ export interface ObfuscationRule {
4
+ regex: string | RegExp;
5
+ replacement: string;
6
+ }
7
+
3
8
  /**
4
9
  * Applies obfuscation rules to a JSON string before sending to the collector.
5
10
  * Each rule replaces matches of `regex` with `replacement` in the string.
@@ -8,7 +13,7 @@ import Log from "./log";
8
13
  * @param {Array<{regex: string|RegExp, replacement: string}>} rules - Obfuscation rules
9
14
  * @returns {string} Obfuscated string
10
15
  */
11
- export function applyObfuscationRules(jsonString, rules) {
16
+ export function applyObfuscationRules(jsonString: string, rules?: ObfuscationRule[]): string {
12
17
  if (!rules || rules.length === 0) return jsonString;
13
18
 
14
19
  return rules.reduce((str, rule) => {
@@ -2,6 +2,30 @@ import { shouldRetry } from "./utils";
2
2
  import Log from "./log";
3
3
  import { applyObfuscationRules } from "./obfuscate";
4
4
 
5
+ export interface HttpRequestOptions {
6
+ url: string;
7
+ payload: { body: any };
8
+ options?: { isFinalHarvest?: boolean };
9
+ }
10
+
11
+ export interface HttpResultCallback {
12
+ (result: { retry?: boolean; status: number; statusText?: string; error?: string }): void;
13
+ }
14
+
15
+ interface InternalRequest {
16
+ url: string;
17
+ payload: { body: any };
18
+ options: { isFinalHarvest?: boolean };
19
+ callback: HttpResultCallback;
20
+ }
21
+
22
+ interface RequestResult {
23
+ success: boolean;
24
+ status: number;
25
+ statusText?: string;
26
+ error?: string;
27
+ }
28
+
5
29
  /**
6
30
  * Optimized HTTP client for video analytics data transmission with
7
31
  * performance monitoring and efficient request handling.
@@ -16,7 +40,7 @@ export class OptimizedHttpClient {
16
40
  * @param {Function} callback - Callback function for handling response
17
41
  * @returns {Promise<void>}
18
42
  */
19
- async send(requestOptions, callback) {
43
+ async send(requestOptions: HttpRequestOptions, callback: HttpResultCallback): Promise<void> {
20
44
  const { url, payload, options = {} } = requestOptions;
21
45
 
22
46
  try {
@@ -26,7 +50,7 @@ export class OptimizedHttpClient {
26
50
  }
27
51
 
28
52
  // Create request object
29
- const request = {
53
+ const request: InternalRequest = {
30
54
  url,
31
55
  payload,
32
56
  options,
@@ -35,7 +59,7 @@ export class OptimizedHttpClient {
35
59
 
36
60
  // Execute request immediately
37
61
  await this.executeRequest(request);
38
- } catch (error) {
62
+ } catch (error: any) {
39
63
  Log.error("Failed to send request:", error.message);
40
64
  callback({ retry: false, status: 0, error: error.message });
41
65
  }
@@ -46,7 +70,7 @@ export class OptimizedHttpClient {
46
70
  * @param {object} request - Request object
47
71
  * @private
48
72
  */
49
- async executeRequest(request) {
73
+ async executeRequest(request: InternalRequest): Promise<void> {
50
74
  const { url, payload, options, callback } = request;
51
75
  const startTime = Date.now();
52
76
 
@@ -59,7 +83,7 @@ export class OptimizedHttpClient {
59
83
  // Handle final harvest with sendBeacon
60
84
  if (options.isFinalHarvest && navigator.sendBeacon) {
61
85
  const success = await this.sendWithBeacon(url, requestBody);
62
- const result = { success, status: success ? 204 : 0 };
86
+ const result: RequestResult = { success, status: success ? 204 : 0 };
63
87
  this.handleRequestComplete(request, result, startTime);
64
88
  return;
65
89
  }
@@ -78,15 +102,15 @@ export class OptimizedHttpClient {
78
102
  10000
79
103
  );
80
104
 
81
- const result = {
105
+ const result: RequestResult = {
82
106
  success: response.ok,
83
107
  status: response.status,
84
108
  statusText: response.statusText,
85
109
  };
86
110
 
87
111
  this.handleRequestComplete(request, result, startTime);
88
- } catch (error) {
89
- const result = {
112
+ } catch (error: any) {
113
+ const result: RequestResult = {
90
114
  success: false,
91
115
  status: 0,
92
116
  error: error.message,
@@ -104,7 +128,7 @@ export class OptimizedHttpClient {
104
128
  * @param {string} endpoint - The endpoint that was used for the request
105
129
  * @private
106
130
  */
107
- handleRequestComplete(request, result) {
131
+ handleRequestComplete(request: InternalRequest, result: RequestResult, startTime?: number): void {
108
132
  const { callback } = request;
109
133
 
110
134
  // Use smart retry logic based on HTTP status codes
@@ -127,10 +151,10 @@ export class OptimizedHttpClient {
127
151
  * @returns {Promise<boolean>} True if successful
128
152
  * @private
129
153
  */
130
- async sendWithBeacon(url, body) {
154
+ async sendWithBeacon(url: string, body: string): Promise<boolean> {
131
155
  try {
132
156
  return navigator.sendBeacon(url, body);
133
- } catch (error) {
157
+ } catch (error: any) {
134
158
  Log.warn("sendBeacon failed, falling back to fetch:", error.message);
135
159
  return false;
136
160
  }
@@ -145,7 +169,7 @@ export class OptimizedHttpClient {
145
169
  * @returns {Promise<Response>} Fetch response
146
170
  * @private
147
171
  */
148
- async fetchWithTimeout(url, options, timeout) {
172
+ async fetchWithTimeout(url: string, options: RequestInit, timeout: number): Promise<Response> {
149
173
  const controller = new AbortController();
150
174
  const timeoutId = setTimeout(() => controller.abort(), timeout);
151
175
 
@@ -156,7 +180,7 @@ export class OptimizedHttpClient {
156
180
  });
157
181
  clearTimeout(timeoutId);
158
182
  return response;
159
- } catch (error) {
183
+ } catch (error: any) {
160
184
  clearTimeout(timeoutId);
161
185
  if (error.name === "AbortError") {
162
186
  throw new Error(`Request timeout after ${timeout}ms`);
@@ -1,6 +1,8 @@
1
- import Constants from "./constants.js";
2
- import Log from "./log.js";
3
- import { dispatchRecordEvent } from "./utils/eventBuilder";
1
+ import Constants from "./constants";
2
+ import Log from "./log";
3
+ import { dispatchRecordEvent, EventAttributes, Harvester } from "./utils/eventBuilder";
4
+
5
+ export type { EventAttributes, Harvester };
4
6
 
5
7
  /**
6
8
  * Registry-based recordEvent (split build).
@@ -8,7 +10,7 @@ import { dispatchRecordEvent } from "./utils/eventBuilder";
8
10
  * No static harvester imports. Each harvester self-registers under a key
9
11
  * (`'Browser'` or `'Vega'`) at module load time via `registerHarvester`.
10
12
  */
11
- const harvesters = Object.create(null);
13
+ const harvesters: Record<string, Harvester> = Object.create(null);
12
14
 
13
15
  /**
14
16
  * Register a harvester implementation under a routing key.
@@ -18,7 +20,7 @@ const harvesters = Object.create(null);
18
20
  * @param {string} key Routing key matching `attributes.src`.
19
21
  * @param {{ addEvent: function }} harvester
20
22
  */
21
- export function registerHarvester(key, harvester) {
23
+ export function registerHarvester(key: string, harvester: Harvester): void {
22
24
  harvesters[key] = harvester;
23
25
  }
24
26
 
@@ -39,11 +41,11 @@ export function registerHarvester(key, harvester) {
39
41
  * @param {string} key
40
42
  * @returns {{ addEvent: function }|undefined}
41
43
  */
42
- export function getRegisteredHarvester(key) {
44
+ export function getRegisteredHarvester(key: string): Harvester | undefined {
43
45
  return harvesters[key];
44
46
  }
45
47
 
46
- export function recordEvent(eventType, attributes = {}) {
48
+ export function recordEvent(eventType: string, attributes: EventAttributes = {}): boolean | undefined {
47
49
  try {
48
50
  if (!Constants.VALID_EVENT_TYPES.includes(eventType)) {
49
51
  Log.warn("Invalid event type provided to recordEvent", { eventType });
@@ -67,10 +69,10 @@ export function recordEvent(eventType, attributes = {}) {
67
69
  : w?.NRVIDEO?.config?.qoeAggregate;
68
70
 
69
71
  return dispatchRecordEvent(
70
- eventType, attributes, info, harvester, qoeEnabled,
72
+ eventType, attributes, info, harvester, !!qoeEnabled,
71
73
  { addTimeSinceLoad: !isVega }
72
74
  );
73
- } catch (error) {
75
+ } catch (error: any) {
74
76
  Log.error("Failed to record event:", error.message);
75
77
  return false;
76
78
  }
@@ -1,6 +1,7 @@
1
1
  import Log from "./log";
2
2
  import { dataSize } from "./utils";
3
3
  import Constants from "./constants";
4
+ import { EventAttributes } from "./utils/eventBuilder";
4
5
 
5
6
  const { MAX_PAYLOAD_SIZE, MAX_EVENTS_PER_BATCH } = Constants;
6
7
 
@@ -9,6 +10,10 @@ const { MAX_PAYLOAD_SIZE, MAX_EVENTS_PER_BATCH } = Constants;
9
10
  * backoff strategies, and persistent storage capabilities.
10
11
  */
11
12
  export class RetryQueueHandler {
13
+ retryQueue: EventAttributes[];
14
+ maxQueueSize: number;
15
+ maxQueueSizeBytes: number;
16
+
12
17
  constructor() {
13
18
  this.retryQueue = [];
14
19
  this.maxQueueSize = MAX_EVENTS_PER_BATCH; // Max 1000 events
@@ -19,7 +24,7 @@ export class RetryQueueHandler {
19
24
  * Adds failed events to the retry queue for retry processing.
20
25
  * @param {Array|object} events - Failed event(s) to add to retry queue
21
26
  */
22
- addFailedEvents(events) {
27
+ addFailedEvents(events: EventAttributes | EventAttributes[]): void {
23
28
  try {
24
29
  const eventsArray = Array.isArray(events) ? events : [events];
25
30
 
@@ -34,15 +39,15 @@ export class RetryQueueHandler {
34
39
  }
35
40
 
36
41
  // Check queue memory size and make room if necessary
37
- const eventSize = dataSize(event);
38
- while (dataSize(this.retryQueue) + eventSize > this.maxQueueSizeBytes) {
42
+ const eventSize = dataSize(event) ?? 0;
43
+ while ((dataSize(this.retryQueue) ?? 0) + eventSize > this.maxQueueSizeBytes) {
39
44
  this.evictOldestEvent();
40
45
  }
41
46
 
42
47
  // Store event directly - no wrapper needed
43
48
  this.retryQueue.push({ ...event });
44
49
  }
45
- } catch (err) {
50
+ } catch (err: any) {
46
51
  Log.error("Failed to add events to retry queue:", err.message);
47
52
  }
48
53
  }
@@ -53,7 +58,7 @@ export class RetryQueueHandler {
53
58
  * @param {string} reason - Reason for discarding
54
59
  * @private
55
60
  */
56
- discardEvent(event, reason) {
61
+ discardEvent(event: EventAttributes, reason: string): void {
57
62
  Log.warn(`Discarded event`, {
58
63
  reason,
59
64
  eventType: event.eventType,
@@ -64,10 +69,10 @@ export class RetryQueueHandler {
64
69
  * Evicts the oldest event from the queue to make room.
65
70
  * @private
66
71
  */
67
- evictOldestEvent() {
72
+ evictOldestEvent(): void {
68
73
  if (this.retryQueue.length > 0) {
69
74
  const oldest = this.retryQueue.shift();
70
- this.discardEvent(oldest, "Queue full - evicted oldest");
75
+ this.discardEvent(oldest as EventAttributes, "Queue full - evicted oldest");
71
76
  }
72
77
  }
73
78
 
@@ -78,8 +83,8 @@ export class RetryQueueHandler {
78
83
  * @param {number} availableEventCount - Available event count
79
84
  * @returns {Array} Array of events that fit within limits
80
85
  */
81
- getRetryEventsToFit(availableSpace, availableEventCount) {
82
- const retryEvents = [];
86
+ getRetryEventsToFit(availableSpace: number, availableEventCount: number): EventAttributes[] {
87
+ const retryEvents: EventAttributes[] = [];
83
88
  let usedSpace = 0;
84
89
  let eventCount = 0;
85
90
 
@@ -90,7 +95,7 @@ export class RetryQueueHandler {
90
95
 
91
96
  if (eventCount >= availableEventCount) break;
92
97
 
93
- const eventSize = dataSize(event);
98
+ const eventSize = dataSize(event) ?? 0;
94
99
  if (usedSpace + eventSize > availableSpace) break;
95
100
 
96
101
  // Add to beginning of retryEvents to maintain chronological order (oldest first)
@@ -109,14 +114,14 @@ export class RetryQueueHandler {
109
114
  * Gets the current retry queue size.
110
115
  * @returns {number} Queue size
111
116
  */
112
- getQueueSize() {
117
+ getQueueSize(): number {
113
118
  return this.retryQueue.length;
114
119
  }
115
120
 
116
121
  /**
117
122
  * Clears the retry queue.
118
123
  */
119
- clear() {
124
+ clear(): void {
120
125
  this.retryQueue = [];
121
126
  }
122
127
  }