@newrelic/video-core 4.1.8 → 5.0.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 (41) hide show
  1. package/README.md +140 -27
  2. package/dist/cjs/browser/index.js +3 -0
  3. package/dist/cjs/browser/index.js.LICENSE.txt +6 -0
  4. package/dist/cjs/browser/index.js.map +1 -0
  5. package/dist/cjs/index.js +1 -1
  6. package/dist/cjs/index.js.LICENSE.txt +1 -1
  7. package/dist/cjs/index.js.map +1 -1
  8. package/dist/cjs/vega/index.js +3 -0
  9. package/dist/cjs/vega/index.js.LICENSE.txt +6 -0
  10. package/dist/cjs/vega/index.js.map +1 -0
  11. package/dist/esm/browser/index.js +3 -0
  12. package/dist/esm/browser/index.js.LICENSE.txt +6 -0
  13. package/dist/esm/browser/index.js.map +1 -0
  14. package/dist/esm/index.js +1 -1
  15. package/dist/esm/index.js.LICENSE.txt +1 -1
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/vega/index.js +3 -0
  18. package/dist/esm/vega/index.js.LICENSE.txt +6 -0
  19. package/dist/esm/vega/index.js.map +1 -0
  20. package/dist/umd/nrvideo.min.js +1 -1
  21. package/dist/umd/nrvideo.min.js.LICENSE.txt +1 -1
  22. package/dist/umd/nrvideo.min.js.map +1 -1
  23. package/package.json +25 -7
  24. package/src/{agent.js → browser/agent.js} +14 -35
  25. package/src/{harvestScheduler.js → browser/harvestScheduler.js} +55 -137
  26. package/src/browser/index.js +58 -0
  27. package/src/connectedDevice/connectedDeviceAgent.js +116 -0
  28. package/src/connectedDevice/connectedDeviceConstants.js +121 -0
  29. package/src/connectedDevice/connectedDeviceHarvester.js +522 -0
  30. package/src/connectedDevice/index.js +49 -0
  31. package/src/constants.js +2 -0
  32. package/src/core.js +4 -18
  33. package/src/index.js +9 -10
  34. package/src/recordEvent.js +56 -49
  35. package/src/tracker.js +14 -4
  36. package/src/utils/eventBuilder.js +126 -0
  37. package/src/utils/harvestTimer.js +109 -0
  38. package/src/{utils.js → utils/index.js} +2 -2
  39. package/src/utils/qoeFilters.js +149 -0
  40. package/src/videoConfiguration.js +56 -10
  41. package/src/videotracker.js +26 -9
@@ -15,18 +15,42 @@ class VideoConfiguration {
15
15
  * @returns {boolean} True if configuration is valid and set
16
16
  */
17
17
 
18
- setConfiguration(userInfo, config) {
19
- if (!this.validateRequiredFields(userInfo)) {
18
+ setConfiguration(userInfo, config, src) {
19
+ const validated = src === "Vega"
20
+ ? this.validateVegaFields(userInfo)
21
+ : this.validateRequiredFields(userInfo);
22
+ if (!validated) {
20
23
  return false;
21
24
  }
22
25
  if (!this.validateConfigFields(config)) {
23
26
  return false;
24
27
  }
25
- this.initializeGlobalConfig(userInfo, config);
28
+ this.initializeGlobalConfig(userInfo, config, src);
26
29
  Log.notice("Video analytics configuration initialized successfully");
27
30
  return true;
28
31
  }
29
32
 
33
+ /**
34
+ * Validates required Vega configuration fields.
35
+ * @param {object} info
36
+ * @returns {boolean} True if valid
37
+ */
38
+ validateVegaFields(info) {
39
+ if (!info || typeof info !== "object") {
40
+ Log.error("Configuration must be an object");
41
+ return false;
42
+ }
43
+ if (!info.applicationToken) {
44
+ Log.error("applicationToken is required");
45
+ return false;
46
+ }
47
+ if (!["US", "EU", "staging", "GOV"].includes(info.endpoint)) {
48
+ Log.error("Invalid endpoint (must be US, EU, staging, or GOV)");
49
+ return false;
50
+ }
51
+ return true;
52
+ }
53
+
30
54
  /**
31
55
  * Validates required configuration fields.
32
56
  * @param {object} config - Configuration to validate
@@ -126,15 +150,16 @@ class VideoConfiguration {
126
150
  }
127
151
 
128
152
  /**
129
- * Sanitizes qoeIntervalFactor, defaulting to 2 if the value is not a positive integer.
153
+ * Sanitizes qoeIntervalFactor, defaulting to Constants.DEFAULT_QOE_INTERVAL_FACTOR
154
+ * if the value is not a positive integer.
130
155
  * @param {*} value
131
156
  * @returns {number}
132
157
  */
133
158
  sanitizeQoeIntervalFactor(value) {
134
- if (value === undefined || value === null) return 2;
159
+ if (value === undefined || value === null) return Constants.DEFAULT_QOE_INTERVAL_FACTOR;
135
160
  if (typeof value === "number" && Number.isInteger(value) && value >= 1) return value;
136
- Log.warn(`Invalid qoeIntervalFactor "${value}" — must be a positive integer. Defaulting to 2.`);
137
- return 2;
161
+ Log.warn(`Invalid qoeIntervalFactor "${value}" — must be a positive integer. Defaulting to ${Constants.DEFAULT_QOE_INTERVAL_FACTOR}.`);
162
+ return Constants.DEFAULT_QOE_INTERVAL_FACTOR;
138
163
  }
139
164
 
140
165
  /**
@@ -142,7 +167,28 @@ class VideoConfiguration {
142
167
  * @param {object} userInfo - User provided configuration
143
168
  * @param {object} [config] - Optional configuration object
144
169
  */
145
- initializeGlobalConfig(userInfo, config) {
170
+ initializeGlobalConfig(userInfo, config, src) {
171
+ // Vega path: write `globalThis.__NRVIDEO_CD__` with info+config only.
172
+ // The harvester is owned by `connectedDeviceAgent.js` as a module singleton — no
173
+ // harvester field on this global.
174
+ if (src === "Vega") {
175
+ globalThis.__NRVIDEO_CD__ = {
176
+ info: {
177
+ accountId: userInfo.accountId,
178
+ applicationToken: userInfo.applicationToken,
179
+ endpoint: userInfo.endpoint,
180
+ ...(userInfo.appName ? { appName: userInfo.appName } : {}),
181
+ ...(userInfo.applicationID ? { applicationID: userInfo.applicationID } : {}),
182
+ ...(userInfo.deviceInfo ? { deviceInfo: userInfo.deviceInfo } : {}),
183
+ },
184
+ config: {
185
+ qoeAggregate: config?.qoeAggregate ?? true,
186
+ qoeIntervalFactor: this.sanitizeQoeIntervalFactor(config?.qoeIntervalFactor),
187
+ obfuscate: this.filterObfuscateRules(config?.obfuscate),
188
+ },
189
+ };
190
+ return;
191
+ }
146
192
 
147
193
  let { licenseKey, appName, region, beacon, applicationID } = userInfo;
148
194
 
@@ -179,8 +225,8 @@ const videoConfiguration = new VideoConfiguration();
179
225
  * @param {object} [config] - Optional configuration object
180
226
  * @returns {boolean} True if configuration was set successfully
181
227
  */
182
- export function setVideoConfig(info, config) {
183
- return videoConfiguration.setConfiguration(info, config);
228
+ export function setVideoConfig(info, config, src) {
229
+ return videoConfiguration.setConfiguration(info, config, src);
184
230
  }
185
231
 
186
232
  export { videoConfiguration };
@@ -1,7 +1,6 @@
1
1
  import Log from "./log";
2
2
  import Tracker from "./tracker";
3
3
  import TrackerState from "./videotrackerstate";
4
- import { videoAnalyticsHarvester } from "./agent";
5
4
  import pkg from "../package.json";
6
5
 
7
6
  /**
@@ -45,6 +44,7 @@ class VideoTracker extends Tracker {
45
44
  */
46
45
  this._lastBufferType = null;
47
46
  this._userId = null;
47
+ this._src = null;
48
48
 
49
49
  options = options || {};
50
50
  this.setOptions(options);
@@ -84,6 +84,16 @@ class VideoTracker extends Tracker {
84
84
  if (typeof options.isAd === "boolean") {
85
85
  this.setIsAd(options.isAd);
86
86
  }
87
+ if (options.src !== undefined) {
88
+ if (this._src !== null && this._src !== options.src) {
89
+ Log.warn(`setOptions: src is locked to '${this._src}'. Ignoring override '${options.src}'.`);
90
+ } else {
91
+ this._src = options.src;
92
+ if (this.adsTracker && this.adsTracker._src == null) {
93
+ this.adsTracker._src = this._src;
94
+ }
95
+ }
96
+ }
87
97
  Tracker.prototype.setOptions.apply(this, arguments);
88
98
  }
89
99
  }
@@ -135,6 +145,12 @@ class VideoTracker extends Tracker {
135
145
  this.adsTracker = tracker;
136
146
  this.adsTracker.setIsAd(true);
137
147
  this.adsTracker.parentTracker = this;
148
+ // Propagate src so ads events route to the same pipeline as content events.
149
+ // Covers the case where setAdsTracker is called after the content tracker
150
+ // is fully initialised and this._src is already set.
151
+ if (this._src != null && tracker._src == null) {
152
+ tracker._src = this._src;
153
+ }
138
154
  this.adsTracker.on("*", funnelAdEvents.bind(this));
139
155
  }
140
156
  }
@@ -465,7 +481,7 @@ class VideoTracker extends Tracker {
465
481
  att["instrumentation.name"] = this.getInstrumentationName();
466
482
  att["instrumentation.version"] = this.getInstrumentationVersion();
467
483
  att["enduser.id"] = this._userId;
468
- att["src"] = "Browser";
484
+ att["src"] = this._src || "Browser";
469
485
 
470
486
  if (type === "customAction") return att;
471
487
 
@@ -639,11 +655,11 @@ class VideoTracker extends Tracker {
639
655
  this.state.setStartupTime(totalAdsTime)
640
656
  this.sendVideoAction(ev, att);
641
657
 
642
- // Register callback to refresh QoE KPIs with latest state before each drain
643
- videoAnalyticsHarvester.setBeforeDrainCallback(() => {
658
+ const harvester = this.getHarvester?.();
659
+ harvester?.setBeforeDrainCallback(() => {
644
660
  if (this.state) {
645
661
  const freshKpis = this.state.getQoeAttributes({}).qoe;
646
- videoAnalyticsHarvester.refreshQoeKpis(freshKpis, this.getViewId());
662
+ harvester.refreshQoeKpis(freshKpis, this.getViewId());
647
663
  }
648
664
  });
649
665
  }
@@ -688,14 +704,15 @@ class VideoTracker extends Tracker {
688
704
  this.state.goViewCountUp();
689
705
  this.state.totalPlaytime = 0;
690
706
  if(!this.isAd()) {
707
+ const harvester = this.getHarvester?.();
691
708
  // Force QoE to be included in the next harvest cycle at content end
692
- videoAnalyticsHarvester.forceNextQoeCycle();
709
+ harvester?.forceNextQoeCycle?.();
693
710
  // Clear the before-drain callback so the next harvest doesn't overwrite
694
711
  // the final QoE (already in buffer) with zeroed-out state values
695
- videoAnalyticsHarvester.setBeforeDrainCallback(null);
712
+ harvester?.setBeforeDrainCallback?.(null);
696
713
  // reset the states after the view count is up
697
- if(this.adsTracker) this.adsTracker.state.clearTotalAdsTime();
698
- this.state.resetViewIdTrackedState();
714
+ if(this.adsTracker) this.adsTracker.state.clearTotalAdsTime();
715
+ this.state.resetViewIdTrackedState();
699
716
  }
700
717
  }
701
718
  }