@newrelic/video-core 5.0.1 → 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 (79) hide show
  1. package/CHANGELOG.md +20 -2
  2. package/README.md +13 -0
  3. package/__mock__.js +8 -4
  4. package/dist/cjs/browser/index.js +1 -1
  5. package/dist/cjs/browser/index.js.LICENSE.txt +1 -1
  6. package/dist/cjs/browser/index.js.map +1 -1
  7. package/dist/cjs/index.js +1 -1
  8. package/dist/cjs/index.js.LICENSE.txt +1 -1
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/vega/index.js +1 -1
  11. package/dist/cjs/vega/index.js.LICENSE.txt +1 -1
  12. package/dist/cjs/vega/index.js.map +1 -1
  13. package/dist/esm/browser/index.js +1 -1
  14. package/dist/esm/browser/index.js.LICENSE.txt +1 -1
  15. package/dist/esm/browser/index.js.map +1 -1
  16. package/dist/esm/index.js +1 -1
  17. package/dist/esm/index.js.LICENSE.txt +1 -1
  18. package/dist/esm/index.js.map +1 -1
  19. package/dist/esm/vega/index.js +1 -1
  20. package/dist/esm/vega/index.js.LICENSE.txt +1 -1
  21. package/dist/esm/vega/index.js.map +1 -1
  22. package/dist/types/browser/agent.d.ts +46 -0
  23. package/dist/types/browser/harvestScheduler.d.ts +125 -0
  24. package/dist/types/browser/index.d.ts +34 -0
  25. package/dist/types/chrono.d.ts +52 -0
  26. package/dist/types/connectedDevice/connectedDeviceAgent.d.ts +63 -0
  27. package/dist/types/connectedDevice/connectedDeviceConstants.d.ts +51 -0
  28. package/dist/types/connectedDevice/connectedDeviceHarvester.d.ts +198 -0
  29. package/dist/types/connectedDevice/index.d.ts +30 -0
  30. package/dist/types/constants.d.ts +30 -0
  31. package/dist/types/core.d.ts +54 -0
  32. package/dist/types/emitter.d.ts +42 -0
  33. package/dist/types/eventAggregator.d.ts +97 -0
  34. package/dist/types/index.d.ts +33 -0
  35. package/dist/types/log.d.ts +61 -0
  36. package/dist/types/obfuscate.d.ts +13 -0
  37. package/dist/types/optimizedHttpClient.d.ts +83 -0
  38. package/dist/types/recordEvent.d.ts +30 -0
  39. package/dist/types/retryQueueHandler.d.ts +46 -0
  40. package/dist/types/tracker.d.ts +176 -0
  41. package/dist/types/utils/eventBuilder.d.ts +69 -0
  42. package/dist/types/utils/harvestTimer.d.ts +45 -0
  43. package/dist/types/utils/index.d.ts +38 -0
  44. package/dist/types/utils/qoeFilters.d.ts +88 -0
  45. package/dist/types/videoConfiguration.d.ts +90 -0
  46. package/dist/types/videotracker.d.ts +366 -0
  47. package/dist/types/videotrackerstate.d.ts +228 -0
  48. package/dist/umd/nrvideo.min.js +1 -1
  49. package/dist/umd/nrvideo.min.js.LICENSE.txt +1 -1
  50. package/dist/umd/nrvideo.min.js.map +1 -1
  51. package/package.json +15 -2
  52. package/src/browser/{agent.js → agent.ts} +21 -16
  53. package/src/browser/{harvestScheduler.js → harvestScheduler.ts} +51 -24
  54. package/src/{chrono.js → chrono.ts} +29 -24
  55. package/src/connectedDevice/{connectedDeviceAgent.js → connectedDeviceAgent.ts} +14 -10
  56. package/src/connectedDevice/{connectedDeviceConstants.js → connectedDeviceConstants.ts} +5 -3
  57. package/src/connectedDevice/{connectedDeviceHarvester.js → connectedDeviceHarvester.ts} +71 -34
  58. package/src/constants.ts +62 -0
  59. package/src/{core.js → core.ts} +31 -18
  60. package/src/{emitter.js → emitter.ts} +16 -5
  61. package/src/{eventAggregator.js → eventAggregator.ts} +33 -19
  62. package/src/global.d.ts +25 -0
  63. package/src/{log.js → log.ts} +23 -17
  64. package/src/{obfuscate.js → obfuscate.ts} +6 -1
  65. package/src/{optimizedHttpClient.js → optimizedHttpClient.ts} +37 -13
  66. package/src/{recordEvent.js → recordEvent.ts} +11 -9
  67. package/src/{retryQueueHandler.js → retryQueueHandler.ts} +17 -12
  68. package/src/{tracker.js → tracker.ts} +56 -23
  69. package/src/utils/{eventBuilder.js → eventBuilder.ts} +31 -14
  70. package/src/utils/{harvestTimer.js → harvestTimer.ts} +21 -4
  71. package/src/utils/{index.js → index.ts} +14 -14
  72. package/src/utils/{qoeFilters.js → qoeFilters.ts} +19 -8
  73. package/src/{videoConfiguration.js → videoConfiguration.ts} +44 -10
  74. package/src/{videotracker.js → videotracker.ts} +119 -78
  75. package/src/{videotrackerstate.js → videotrackerstate.ts} +113 -49
  76. package/src/constants.js +0 -63
  77. /package/src/browser/{index.js → index.ts} +0 -0
  78. /package/src/connectedDevice/{index.js → index.ts} +0 -0
  79. /package/src/{index.js → index.ts} +0 -0
package/package.json CHANGED
@@ -1,26 +1,31 @@
1
1
  {
2
2
  "name": "@newrelic/video-core",
3
- "version": "5.0.1",
3
+ "version": "5.1.0",
4
4
  "description": "New Relic video tracking core library",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
7
+ "types": "./dist/types/index.d.ts",
7
8
  "exports": {
8
9
  ".": {
10
+ "types": "./dist/types/index.d.ts",
9
11
  "import": "./dist/esm/index.js",
10
12
  "require": "./dist/cjs/index.js"
11
13
  },
12
14
  "./browser": {
15
+ "types": "./dist/types/browser/index.d.ts",
13
16
  "import": "./dist/esm/browser/index.js",
14
17
  "require": "./dist/cjs/browser/index.js"
15
18
  },
16
19
  "./vega": {
20
+ "types": "./dist/types/connectedDevice/index.d.ts",
17
21
  "import": "./dist/esm/vega/index.js",
18
22
  "require": "./dist/cjs/vega/index.js"
19
23
  },
20
24
  "./package.json": "./package.json"
21
25
  },
22
26
  "scripts": {
23
- "build": "webpack --mode production",
27
+ "build": "webpack --mode production && npm run build:types",
28
+ "build:types": "tsc --emitDeclarationOnly",
24
29
  "build:dev": "webpack --mode development",
25
30
  "watch": "webpack --mode production --progress --color --watch",
26
31
  "watch:dev": "webpack --progress --color --watch",
@@ -46,6 +51,7 @@
46
51
  "@babel/core": "^7.24.5",
47
52
  "@babel/plugin-transform-modules-commonjs": "^7.24.1",
48
53
  "@babel/preset-env": "^7.24.5",
54
+ "@babel/preset-typescript": "^7.29.7",
49
55
  "@babel/register": "^7.24.6",
50
56
  "@newrelic/newrelic-oss-cli": "^0.1.2",
51
57
  "@semantic-release/changelog": "^6.0.3",
@@ -56,6 +62,7 @@
56
62
  "@semantic-release/release-notes-generator": "^13.0.0",
57
63
  "babel-jest": "^30.0.0",
58
64
  "babel-loader": "^9.1.3",
65
+ "conventional-changelog-conventionalcommits": "^7.0.2",
59
66
  "diff": "^5.0.0",
60
67
  "jest": "^30.2.0",
61
68
  "jest-environment-jsdom": "^30.2.0",
@@ -64,6 +71,7 @@
64
71
  "nyc": "^18.0.0",
65
72
  "semantic-release": "^25.0.8",
66
73
  "sinon": "^2.4.1",
74
+ "typescript": "^7.0.2",
67
75
  "webpack": "^5.91.0",
68
76
  "webpack-cli": "^4.9.2"
69
77
  },
@@ -83,5 +91,10 @@
83
91
  },
84
92
  "dependencies": {
85
93
  "terser-webpack-plugin": "^5.6.1"
94
+ },
95
+ "overrides": {
96
+ "ip-address": "^10.3.1",
97
+ "serialize-javascript": "^7.0.5",
98
+ "undici": "^6.28.0"
86
99
  }
87
100
  }
@@ -1,16 +1,21 @@
1
- import { HarvestScheduler } from "./harvestScheduler.js";
2
- import { NrVideoEventAggregator } from "../eventAggregator.js";
3
- import Log from "../log.js";
4
- import { registerHarvester } from "../recordEvent.js";
1
+ import { HarvestScheduler } from "./harvestScheduler";
2
+ import { NrVideoEventAggregator } from "../eventAggregator";
3
+ import Log from "../log";
4
+ import { registerHarvester } from "../recordEvent";
5
5
  import {
6
6
  bufferEventWithQoeDedup,
7
7
  refreshQoeKpisInBuffer,
8
8
  } from "../utils/qoeFilters";
9
+ import { EventAttributes, Harvester } from "../utils/eventBuilder";
9
10
 
10
11
  /**
11
12
  * Enhanced video analytics agent with HarvestScheduler only.
12
13
  */
13
- class VideoAnalyticsAgent {
14
+ class VideoAnalyticsAgent implements Harvester {
15
+ isInitialized: boolean;
16
+ harvestScheduler: HarvestScheduler | null;
17
+ eventBuffer: NrVideoEventAggregator | null;
18
+
14
19
  constructor() {
15
20
  this.isInitialized = false;
16
21
  this.harvestScheduler = null;
@@ -20,7 +25,7 @@ class VideoAnalyticsAgent {
20
25
  /**
21
26
  * Initializes the video analytics agent with enhanced HarvestScheduler.
22
27
  */
23
- initialize() {
28
+ initialize(): void {
24
29
  if (this.isInitialized) {
25
30
  Log.warn("Video analytics agent already initialized");
26
31
  return;
@@ -35,7 +40,7 @@ class VideoAnalyticsAgent {
35
40
 
36
41
  this.isInitialized = true;
37
42
  Log.notice("Video analytics agent initialized successfully");
38
- } catch (error) {
43
+ } catch (error: any) {
39
44
  Log.error("Failed to initialize video analytics agent:", error.message);
40
45
  }
41
46
  }
@@ -45,7 +50,7 @@ class VideoAnalyticsAgent {
45
50
  * @param {object} eventObject - Event to add
46
51
  * @returns {boolean} True if event was added successfully
47
52
  */
48
- addEvent(eventObject) {
53
+ addEvent(eventObject: EventAttributes): boolean {
49
54
  if (!this.isInitialized) {
50
55
  Log.warn("Video analytics agent not initialized, initializing now");
51
56
  this.initialize();
@@ -53,8 +58,8 @@ class VideoAnalyticsAgent {
53
58
 
54
59
  try {
55
60
  // QOE_AGGREGATE dedup + plain append, shared with the Vega pipeline.
56
- return bufferEventWithQoeDedup(this.eventBuffer, eventObject);
57
- } catch (error) {
61
+ return bufferEventWithQoeDedup(this.eventBuffer as NrVideoEventAggregator, eventObject);
62
+ } catch (error: any) {
58
63
  Log.error("Failed to add event to harvesting system:", error.message);
59
64
  return false;
60
65
  }
@@ -65,19 +70,19 @@ class VideoAnalyticsAgent {
65
70
  * @param {number} interval - The harvest interval in milliseconds.
66
71
  */
67
72
 
68
- setHarvestInterval(interval) {
73
+ setHarvestInterval(interval: number): void {
69
74
  if (!this.isInitialized) {
70
75
  this.initialize();
71
76
  }
72
77
 
73
- this.harvestScheduler.updateHarvestInterval(interval);
78
+ (this.harvestScheduler as HarvestScheduler).updateHarvestInterval(interval);
74
79
  }
75
80
 
76
81
  /**
77
82
  * Forces the next harvest cycle to include QOE_AGGREGATE events.
78
83
  * Called at CONTENT_END to ensure final QoE is sent.
79
84
  */
80
- forceNextQoeCycle() {
85
+ forceNextQoeCycle(): void {
81
86
  if (this.harvestScheduler) {
82
87
  this.harvestScheduler.forceNextQoeCycle = true;
83
88
  }
@@ -87,7 +92,7 @@ class VideoAnalyticsAgent {
87
92
  * Sets a callback to be called before each drain to refresh QoE KPIs.
88
93
  * @param {Function|null} callback - Function that refreshes QoE data in the buffer, or null to clear
89
94
  */
90
- setBeforeDrainCallback(callback) {
95
+ setBeforeDrainCallback(callback: (() => void) | null): void {
91
96
  if (this.harvestScheduler) {
92
97
  this.harvestScheduler.beforeDrainCallback = callback;
93
98
  }
@@ -99,8 +104,8 @@ class VideoAnalyticsAgent {
99
104
  * @param {object} freshKpis - Object with latest KPI values
100
105
  * @param {string} [viewId] - The viewId of the player whose QoE event to update
101
106
  */
102
- refreshQoeKpis(freshKpis, viewId) {
103
- refreshQoeKpisInBuffer(this.eventBuffer, freshKpis, viewId);
107
+ refreshQoeKpis(freshKpis: EventAttributes, viewId?: string): void {
108
+ refreshQoeKpisInBuffer(this.eventBuffer as NrVideoEventAggregator, freshKpis, viewId);
104
109
  }
105
110
  }
106
111
 
@@ -6,10 +6,24 @@ import {
6
6
  partitionByQoeCycle,
7
7
  applyQoeDirtyFilter,
8
8
  } from "../utils/qoeFilters";
9
- import { createHarvestTimer } from "../utils/harvestTimer";
9
+ import { createHarvestTimer, HarvestTimer } from "../utils/harvestTimer";
10
10
  import Constants from "../constants";
11
11
  import Tracker from "../tracker";
12
12
  import Log from "../log";
13
+ import { EventAttributes } from "../utils/eventBuilder";
14
+
15
+ interface HarvestOptions {
16
+ isFinalHarvest?: boolean;
17
+ force?: boolean;
18
+ }
19
+
20
+ interface HarvestResult {
21
+ success: boolean;
22
+ reason?: string;
23
+ totalChunks?: number;
24
+ results?: any[];
25
+ error?: string;
26
+ }
13
27
 
14
28
  /**
15
29
  * Enhanced harvest scheduler that orchestrates the video analytics data collection,
@@ -17,7 +31,20 @@ import Log from "../log";
17
31
  */
18
32
 
19
33
  export class HarvestScheduler {
20
- constructor(eventAggregator) {
34
+ eventBuffer: NrVideoEventAggregator;
35
+ retryQueueHandler: RetryQueueHandler;
36
+ httpClient: OptimizedHttpClient;
37
+ fallBackUrl: string;
38
+ retryCount: number;
39
+ harvestCycle: number;
40
+ isHarvesting: boolean;
41
+ qoeCycleCount: number;
42
+ forceNextQoeCycle: boolean;
43
+ beforeDrainCallback: (() => void) | null;
44
+ _lastSentQoeKpis: Record<string, any>;
45
+ timer: HarvestTimer;
46
+
47
+ constructor(eventAggregator: NrVideoEventAggregator) {
21
48
  // Core components
22
49
  this.eventBuffer = eventAggregator;
23
50
  this.retryQueueHandler = new RetryQueueHandler();
@@ -55,14 +82,14 @@ export class HarvestScheduler {
55
82
  * Whether the scheduler is currently running. Backed by the shared timer.
56
83
  * @returns {boolean}
57
84
  */
58
- get isStarted() {
85
+ get isStarted(): boolean {
59
86
  return this.timer.isRunning();
60
87
  }
61
88
 
62
89
  /**
63
90
  * Starts the harvest scheduler.
64
91
  */
65
- startScheduler() {
92
+ startScheduler(): void {
66
93
  if (this.timer.isRunning()) {
67
94
  Log.warn("Harvest scheduler is already started");
68
95
  return;
@@ -79,7 +106,7 @@ export class HarvestScheduler {
79
106
  /**
80
107
  * Stops the harvest scheduler.
81
108
  */
82
- stopScheduler() {
109
+ stopScheduler(): void {
83
110
  if (!this.timer.isRunning()) return;
84
111
  this.timer.stop();
85
112
  Log.notice("Harvest scheduler stopped");
@@ -90,7 +117,7 @@ export class HarvestScheduler {
90
117
  * @param {string} type - Type of harvest trigger ('smart' or 'overflow')
91
118
  * @param {number} threshold - Threshold percentage that triggered the harvest (60 or 90)
92
119
  */
93
- async triggerSmartHarvest(type, threshold) {
120
+ async triggerSmartHarvest(type: string, threshold: number): Promise<void> {
94
121
  Log.notice(`${type} harvest triggered at ${threshold}% threshold`, {
95
122
  type,
96
123
  threshold,
@@ -101,7 +128,7 @@ export class HarvestScheduler {
101
128
 
102
129
  try {
103
130
  await this.triggerHarvest({});
104
- } catch (error) {
131
+ } catch (error: any) {
105
132
  Log.error(`${type} harvest failed:`, error.message);
106
133
  } finally {
107
134
  // Reset the periodic clock — next periodic tick happens `harvestCycle`
@@ -114,7 +141,7 @@ export class HarvestScheduler {
114
141
  * Periodic-tick callback. Invoked by the shared harvest timer on each cycle.
115
142
  * @private
116
143
  */
117
- async onHarvestInterval() {
144
+ async onHarvestInterval(): Promise<void> {
118
145
  // Check if there's any data to harvest (buffer or retry queue) before
119
146
  // starting the harvest process — avoids unnecessary network calls when
120
147
  // there's nothing to ship.
@@ -132,7 +159,7 @@ export class HarvestScheduler {
132
159
  * @param {boolean} options.force - Force harvest even if buffer is empty
133
160
  * @returns {Promise<object>} Harvest result
134
161
  */
135
- async triggerHarvest(options = {}) {
162
+ async triggerHarvest(options: HarvestOptions = {}): Promise<HarvestResult> {
136
163
  if (this.isHarvesting) {
137
164
  return { success: false, reason: "harvest_in_progress" };
138
165
  }
@@ -146,7 +173,7 @@ export class HarvestScheduler {
146
173
  // For beacon harvests, trim events to fit beacon size if necessary
147
174
  if (options.isFinalHarvest) {
148
175
  const maxBeaconSize = Constants.MAX_BEACON_SIZE;
149
- const payloadSize = dataSize(events);
176
+ const payloadSize = dataSize(events) ?? 0;
150
177
 
151
178
  if (payloadSize > maxBeaconSize) {
152
179
  // Trim events to fit beacon size (keep most recent events)
@@ -162,7 +189,7 @@ export class HarvestScheduler {
162
189
  totalChunks: 1,
163
190
  results: [result],
164
191
  };
165
- } catch (error) {
192
+ } catch (error: any) {
166
193
  Log.error("Harvest cycle failed:", error.message);
167
194
  this.handleHarvestFailure(error);
168
195
 
@@ -183,18 +210,18 @@ export class HarvestScheduler {
183
210
  * @returns {Array} Trimmed events that fit within size limit
184
211
  * @private
185
212
  */
186
- trimEventsToFit(events, maxSize) {
213
+ trimEventsToFit(events: EventAttributes[], maxSize: number): EventAttributes[] {
187
214
  if (events.length === 0) return events;
188
215
 
189
216
  // Start from the most recent events (end of array) and work backwards
190
- const trimmedEvents = [];
217
+ const trimmedEvents: EventAttributes[] = [];
191
218
  let currentSize = 0;
192
219
 
193
220
  for (let i = events.length - 1; i >= 0; i--) {
194
221
  const event = events[i];
195
222
 
196
223
  // Check if adding this event would exceed the limit
197
- const testPayloadSize = dataSize({ ins: [event, ...trimmedEvents] });
224
+ const testPayloadSize = dataSize({ ins: [event, ...trimmedEvents] }) ?? 0;
198
225
 
199
226
  if (testPayloadSize > maxSize) continue;
200
227
 
@@ -231,7 +258,7 @@ export class HarvestScheduler {
231
258
  * @returns {Array} Drained events
232
259
  * @private
233
260
  */
234
- drainEvents(options = {}) {
261
+ drainEvents(options: HarvestOptions = {}): EventAttributes[] {
235
262
  // Determine if this cycle should include the QOE_AGGREGATE event
236
263
  const multiplier = window.NRVIDEO?.config?.qoeIntervalFactor ?? 1;
237
264
  const isForced = !!options.isFinalHarvest || this.forceNextQoeCycle;
@@ -245,7 +272,7 @@ export class HarvestScheduler {
245
272
  if (this.beforeDrainCallback && typeof this.beforeDrainCallback === 'function') {
246
273
  try {
247
274
  this.beforeDrainCallback();
248
- } catch (e) {
275
+ } catch (e: any) {
249
276
  Log.error("Before drain callback failed:", e.message);
250
277
  }
251
278
  }
@@ -265,7 +292,7 @@ export class HarvestScheduler {
265
292
  applyQoeDirtyFilter(filteredFreshEvents, this._lastSentQoeKpis, isForced);
266
293
 
267
294
  let events = [...filteredFreshEvents];
268
- let currentPayloadSize = dataSize(filteredFreshEvents);
295
+ let currentPayloadSize = dataSize(filteredFreshEvents) ?? 0;
269
296
 
270
297
  // Always check retry queue if it has data - no flags needed
271
298
  if (this.retryQueueHandler && this.retryQueueHandler.getQueueSize() > 0) {
@@ -298,8 +325,8 @@ export class HarvestScheduler {
298
325
  * @returns {Promise<object>} Send result
299
326
  * @private
300
327
  */
301
- async sendChunk(chunk, options, isLastChunk) {
302
- const url = buildUrl(this.fallBackUrl); //
328
+ async sendChunk(chunk: EventAttributes[], options: HarvestOptions, isLastChunk: boolean): Promise<{ success: boolean; status: number; error?: string; chunk: EventAttributes[]; eventCount: number }> {
329
+ const url = buildUrl(this.fallBackUrl) as string; //
303
330
  const payload = { body: { ins: chunk } };
304
331
  const requestOptions = {
305
332
  url,
@@ -334,7 +361,7 @@ export class HarvestScheduler {
334
361
  * @param {Array} chunk - Failed chunk to add to retry queue
335
362
  * @private
336
363
  */
337
- handleRequestFailure(chunk) {
364
+ handleRequestFailure(chunk: EventAttributes[]): void {
338
365
  // Add failed events to retry queue
339
366
  this.retryQueueHandler.addFailedEvents(chunk);
340
367
  // Only apply failover logic for US region
@@ -346,7 +373,7 @@ export class HarvestScheduler {
346
373
  this.fallBackUrl = "";
347
374
  } else if (this.retryCount >= 2) {
348
375
  // Switch to fallback after 2 consecutive failures
349
- this.fallBackUrl = Constants.COLLECTOR["US"][1];
376
+ this.fallBackUrl = (Constants.COLLECTOR["US"] as string[])[1];
350
377
  }
351
378
  }
352
379
 
@@ -355,7 +382,7 @@ export class HarvestScheduler {
355
382
  * @param {Error} error - Harvest error
356
383
  * @private
357
384
  */
358
- handleHarvestFailure(error) {
385
+ handleHarvestFailure(error: Error): void {
359
386
  Log.warn("Harvest failure handled", { error: error.message });
360
387
  }
361
388
 
@@ -365,7 +392,7 @@ export class HarvestScheduler {
365
392
  * @returns {boolean} - True if interval was updated successfully, false otherwise
366
393
  */
367
394
 
368
- updateHarvestInterval(newInterval) {
395
+ updateHarvestInterval(newInterval: number): void {
369
396
  if (typeof newInterval !== "number" || isNaN(newInterval)) {
370
397
  Log.warn("Invalid newInterval provided to updateHarvestInterval");
371
398
  return;
@@ -388,7 +415,7 @@ export class HarvestScheduler {
388
415
  * Sets up page lifecycle event handlers.
389
416
  * @private
390
417
  */
391
- setupPageLifecycleHandlers() {
418
+ setupPageLifecycleHandlers(): void {
392
419
  let finalHarvestTriggered = false;
393
420
 
394
421
  const triggerFinalHarvest = () => {
@@ -2,6 +2,29 @@
2
2
  * This class calculates time lapses between two points on time.
3
3
  */
4
4
  class Chrono {
5
+ /** Start time */
6
+ startTime: number = 0;
7
+
8
+ /** Stop time */
9
+ stopTime: number = 0;
10
+
11
+ /** accumulation of all the start and stop intervals */
12
+ accumulator: number = 0;
13
+
14
+ /**
15
+ * If you set an offset in a chrono, its value will be added getDeltaTime and stop.
16
+ *
17
+ * @example
18
+ * let chrono = new Chrono()
19
+ * chrono.offset = 500
20
+ * chrono.start()
21
+ * process.sleep(500)
22
+ * chrono.stop() // Will return 1000
23
+ *
24
+ * @type {number}
25
+ */
26
+ offset: number = 0;
27
+
5
28
  /**
6
29
  * Constructor
7
30
  */
@@ -10,28 +33,10 @@ class Chrono {
10
33
  }
11
34
 
12
35
  /** Reset chrono values. */
13
- reset() {
14
- /** Start time */
36
+ reset(): void {
15
37
  this.startTime = 0;
16
-
17
- /** Stop time */
18
38
  this.stopTime = 0;
19
-
20
- /** accumulation of all the start and stop intervals */
21
39
  this.accumulator = 0;
22
-
23
- /**
24
- * If you set an offset in a chrono, its value will be added getDeltaTime and stop.
25
- *
26
- * @example
27
- * let chrono = new Chrono()
28
- * chrono.offset = 500
29
- * chrono.start()
30
- * process.sleep(500)
31
- * chrono.stop() // Will return 1000
32
- *
33
- * @type {number}
34
- */
35
40
  this.offset = 0;
36
41
  }
37
42
 
@@ -40,7 +45,7 @@ class Chrono {
40
45
  * called.
41
46
  * @return {(number|null)} Time lapse in ms.
42
47
  */
43
- getDeltaTime() {
48
+ getDeltaTime(): number | null {
44
49
  if (this.startTime) {
45
50
  return this.offset + (new Date().getTime() - this.startTime);
46
51
  } else {
@@ -51,7 +56,7 @@ class Chrono {
51
56
  /**
52
57
  * Starts the chrono.
53
58
  */
54
- start() {
59
+ start(): void {
55
60
  this.startTime = new Date().getTime();
56
61
  this.stopTime = 0;
57
62
  }
@@ -60,7 +65,7 @@ class Chrono {
60
65
  * Stops the timer and returns delta time.
61
66
  * @return {(number|null)} Returns the delta time
62
67
  */
63
- stop() {
68
+ stop(): number | null {
64
69
  this.stopTime = new Date().getTime();
65
70
  if(this.startTime < this.stopTime) {
66
71
  this.accumulator += (this.stopTime - this.startTime);
@@ -68,7 +73,7 @@ class Chrono {
68
73
  return this.getDeltaTime();
69
74
  }
70
75
 
71
- getDuration() {
76
+ getDuration(): number {
72
77
  if(this.stopTime) {
73
78
  return this.accumulator + this.offset;
74
79
  } else {
@@ -80,7 +85,7 @@ class Chrono {
80
85
  * Creates a copy of the chrono.
81
86
  * @returns {Chrono} Cloned chrono
82
87
  */
83
- clone() {
88
+ clone(): Chrono {
84
89
  var chrono = new Chrono();
85
90
  chrono.startTime = this.startTime;
86
91
  chrono.stopTime = this.stopTime;
@@ -1,11 +1,15 @@
1
1
  import ConnectedDeviceHarvester from "./connectedDeviceHarvester";
2
2
  import Log from "../log";
3
3
  import { registerHarvester } from "../recordEvent";
4
+ import { EventAttributes, Harvester } from "../utils/eventBuilder";
4
5
 
5
6
  /**
6
7
  * Vega-side analytics agent. Mirror of `VideoAnalyticsAgent` in `agent.js`.
7
8
  */
8
- class ConnectedDeviceAnalyticsAgent {
9
+ class ConnectedDeviceAnalyticsAgent implements Harvester {
10
+ isInitialized: boolean;
11
+ harvester: ConnectedDeviceHarvester | null;
12
+
9
13
  constructor() {
10
14
  this.isInitialized = false;
11
15
  this.harvester = null;
@@ -16,7 +20,7 @@ class ConnectedDeviceAnalyticsAgent {
16
20
  * constructs the wrapped `ConnectedDeviceHarvester`. If `info` is not yet populated,
17
21
  * returns without flipping `isInitialized` so the next `addEvent` retries.
18
22
  */
19
- initialize() {
23
+ initialize(): void {
20
24
  if (this.isInitialized) return;
21
25
 
22
26
  const info = globalThis.__NRVIDEO_CD__?.info;
@@ -31,7 +35,7 @@ class ConnectedDeviceAnalyticsAgent {
31
35
  this.harvester = new ConnectedDeviceHarvester(info);
32
36
  this.isInitialized = true;
33
37
  Log.notice("ConnectedDeviceAnalyticsAgent initialized");
34
- } catch (err) {
38
+ } catch (err: any) {
35
39
  Log.error("ConnectedDeviceAnalyticsAgent.initialize failed:", err.message);
36
40
  }
37
41
  }
@@ -46,17 +50,17 @@ class ConnectedDeviceAnalyticsAgent {
46
50
  * @param {object} eventObject
47
51
  * @returns {boolean}
48
52
  */
49
- addEvent(eventObject) {
53
+ addEvent(eventObject: EventAttributes): boolean {
50
54
  if (!this.isInitialized) this.initialize();
51
55
  if (!this.isInitialized) return false;
52
- return this.harvester.addEvent(eventObject);
56
+ return (this.harvester as ConnectedDeviceHarvester).addEvent(eventObject);
53
57
  }
54
58
 
55
59
  /**
56
60
  * Forwards to the underlying ConnectedDeviceHarvester. No-op if not yet initialized.
57
61
  * @see ConnectedDeviceHarvester#forceQoeNextHarvest
58
62
  */
59
- forceQoeNextHarvest() {
63
+ forceQoeNextHarvest(): void {
60
64
  if (this.harvester) this.harvester.forceQoeNextHarvest();
61
65
  }
62
66
 
@@ -65,7 +69,7 @@ class ConnectedDeviceAnalyticsAgent {
65
69
  * single method name on whichever harvester `getHarvester()` returns —
66
70
  * Browser exposes `forceNextQoeCycle`, Vega exposes both names.
67
71
  */
68
- forceNextQoeCycle() {
72
+ forceNextQoeCycle(): void {
69
73
  this.forceQoeNextHarvest();
70
74
  }
71
75
 
@@ -74,7 +78,7 @@ class ConnectedDeviceAnalyticsAgent {
74
78
  * @see ConnectedDeviceHarvester#setBeforeDrainCallback
75
79
  * @param {Function|null} cb
76
80
  */
77
- setBeforeDrainCallback(cb) {
81
+ setBeforeDrainCallback(cb: (() => void) | null): void {
78
82
  if (this.harvester) this.harvester.setBeforeDrainCallback(cb);
79
83
  }
80
84
 
@@ -86,7 +90,7 @@ class ConnectedDeviceAnalyticsAgent {
86
90
  * @param {object} freshKpis
87
91
  * @param {string} [viewId]
88
92
  */
89
- refreshQoeKpis(freshKpis, viewId) {
93
+ refreshQoeKpis(freshKpis: EventAttributes, viewId?: string): void {
90
94
  if (!this.isInitialized) this.initialize();
91
95
  if (this.harvester) this.harvester.refreshQoeKpis(freshKpis, viewId);
92
96
  }
@@ -98,7 +102,7 @@ class ConnectedDeviceAnalyticsAgent {
98
102
  *
99
103
  * @param {number} interval
100
104
  */
101
- setHarvestInterval(interval) {
105
+ setHarvestInterval(interval: number): void {
102
106
  if (!this.isInitialized) this.initialize();
103
107
  if (this.harvester) this.harvester.setHarvestInterval(interval);
104
108
  }
@@ -6,11 +6,13 @@
6
6
  // Only `connectedDeviceHarvester.js` imports these — browser builds
7
7
  // never reference this file, keeping the browser bundle lean.
8
8
 
9
+ export type VegaEndpoint = "us" | "eu" | "staging" | "gov" | "jp";
10
+
9
11
  /**
10
12
  * Maps region key (lowercase) directly to the regional mobile collector base URL.
11
13
  * Accepts global.region.key values: us, eu, gov, jp, staging.
12
14
  */
13
- export const ENDPOINT_URL = {
15
+ export const ENDPOINT_URL: Record<VegaEndpoint, string> = {
14
16
  us: "https://mobile-collector.newrelic.com/mobile",
15
17
  eu: "https://mobile-collector.eu01.nr-data.net/mobile",
16
18
  staging: "https://staging-mobile-collector.newrelic.com/mobile",
@@ -55,7 +57,7 @@ export const CD_DATA_TIMEOUT_MS = 30000;
55
57
  * `agentName='AndroidAgent'` for collector auth; the real device identity
56
58
  * is recorded in slot [1] / slot [8] of `/v3/data`.
57
59
  */
58
- export const CD_DATA_TOKENS_PAYLOAD = [
60
+ export const CD_DATA_TOKENS_PAYLOAD: any[] = [
59
61
  // appInfo
60
62
  [
61
63
  "newrelic_mobile_example", // appName
@@ -86,7 +88,7 @@ export const CD_DATA_TOKENS_PAYLOAD = [
86
88
  * (Vega + Amazon by default). Customer-supplied `info.deviceInfo` overrides
87
89
  * the runtime fields; static slots (osName, agentName, etc.) stay fixed.
88
90
  */
89
- export const CD_DEVICE_INFO = [
91
+ export const CD_DEVICE_INFO: any[] = [
90
92
  "Vega", // osName
91
93
  "1.0", // osVersion
92
94
  "VegaDevice", // deviceModel