@newrelic/video-core 4.1.8 → 5.0.1
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.
- package/CHANGELOG.md +56 -0
- package/README.md +140 -27
- package/dist/cjs/browser/index.js +3 -0
- package/dist/cjs/browser/index.js.LICENSE.txt +6 -0
- package/dist/cjs/browser/index.js.map +1 -0
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.LICENSE.txt +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/vega/index.js +3 -0
- package/dist/cjs/vega/index.js.LICENSE.txt +6 -0
- package/dist/cjs/vega/index.js.map +1 -0
- package/dist/esm/browser/index.js +3 -0
- package/dist/esm/browser/index.js.LICENSE.txt +6 -0
- package/dist/esm/browser/index.js.map +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.LICENSE.txt +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/vega/index.js +3 -0
- package/dist/esm/vega/index.js.LICENSE.txt +6 -0
- package/dist/esm/vega/index.js.map +1 -0
- package/dist/umd/nrvideo.min.js +1 -1
- package/dist/umd/nrvideo.min.js.LICENSE.txt +1 -1
- package/dist/umd/nrvideo.min.js.map +1 -1
- package/package.json +25 -7
- package/src/{agent.js → browser/agent.js} +14 -35
- package/src/{harvestScheduler.js → browser/harvestScheduler.js} +55 -137
- package/src/browser/index.js +58 -0
- package/src/connectedDevice/connectedDeviceAgent.js +116 -0
- package/src/connectedDevice/connectedDeviceConstants.js +112 -0
- package/src/connectedDevice/connectedDeviceHarvester.js +514 -0
- package/src/connectedDevice/index.js +49 -0
- package/src/constants.js +2 -0
- package/src/core.js +4 -18
- package/src/index.js +9 -10
- package/src/recordEvent.js +56 -49
- package/src/tracker.js +14 -4
- package/src/utils/eventBuilder.js +126 -0
- package/src/utils/harvestTimer.js +109 -0
- package/src/{utils.js → utils/index.js} +2 -2
- package/src/utils/qoeFilters.js +149 -0
- package/src/videoConfiguration.js +57 -10
- package/src/videotracker.js +26 -9
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Log from "./log";
|
|
2
2
|
import Constants from "./constants";
|
|
3
|
+
import { ENDPOINT_URL } from "./connectedDevice/connectedDeviceConstants";
|
|
3
4
|
|
|
4
5
|
const { COLLECTOR } = Constants;
|
|
5
6
|
|
|
@@ -15,18 +16,42 @@ class VideoConfiguration {
|
|
|
15
16
|
* @returns {boolean} True if configuration is valid and set
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
|
-
setConfiguration(userInfo, config) {
|
|
19
|
-
|
|
19
|
+
setConfiguration(userInfo, config, src) {
|
|
20
|
+
const validated = src === "Vega"
|
|
21
|
+
? this.validateVegaFields(userInfo)
|
|
22
|
+
: this.validateRequiredFields(userInfo);
|
|
23
|
+
if (!validated) {
|
|
20
24
|
return false;
|
|
21
25
|
}
|
|
22
26
|
if (!this.validateConfigFields(config)) {
|
|
23
27
|
return false;
|
|
24
28
|
}
|
|
25
|
-
this.initializeGlobalConfig(userInfo, config);
|
|
29
|
+
this.initializeGlobalConfig(userInfo, config, src);
|
|
26
30
|
Log.notice("Video analytics configuration initialized successfully");
|
|
27
31
|
return true;
|
|
28
32
|
}
|
|
29
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Validates required Vega configuration fields.
|
|
36
|
+
* @param {object} info
|
|
37
|
+
* @returns {boolean} True if valid
|
|
38
|
+
*/
|
|
39
|
+
validateVegaFields(info) {
|
|
40
|
+
if (!info || typeof info !== "object") {
|
|
41
|
+
Log.error("Configuration must be an object");
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (!info.applicationToken) {
|
|
45
|
+
Log.error("applicationToken is required");
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (!(info.endpoint?.toLowerCase() in ENDPOINT_URL)) {
|
|
49
|
+
Log.error("Invalid endpoint (must be us, eu, staging, gov, or jp)");
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
30
55
|
/**
|
|
31
56
|
* Validates required configuration fields.
|
|
32
57
|
* @param {object} config - Configuration to validate
|
|
@@ -126,15 +151,16 @@ class VideoConfiguration {
|
|
|
126
151
|
}
|
|
127
152
|
|
|
128
153
|
/**
|
|
129
|
-
* Sanitizes qoeIntervalFactor, defaulting to
|
|
154
|
+
* Sanitizes qoeIntervalFactor, defaulting to Constants.DEFAULT_QOE_INTERVAL_FACTOR
|
|
155
|
+
* if the value is not a positive integer.
|
|
130
156
|
* @param {*} value
|
|
131
157
|
* @returns {number}
|
|
132
158
|
*/
|
|
133
159
|
sanitizeQoeIntervalFactor(value) {
|
|
134
|
-
if (value === undefined || value === null) return
|
|
160
|
+
if (value === undefined || value === null) return Constants.DEFAULT_QOE_INTERVAL_FACTOR;
|
|
135
161
|
if (typeof value === "number" && Number.isInteger(value) && value >= 1) return value;
|
|
136
|
-
Log.warn(`Invalid qoeIntervalFactor "${value}" — must be a positive integer. Defaulting to
|
|
137
|
-
return
|
|
162
|
+
Log.warn(`Invalid qoeIntervalFactor "${value}" — must be a positive integer. Defaulting to ${Constants.DEFAULT_QOE_INTERVAL_FACTOR}.`);
|
|
163
|
+
return Constants.DEFAULT_QOE_INTERVAL_FACTOR;
|
|
138
164
|
}
|
|
139
165
|
|
|
140
166
|
/**
|
|
@@ -142,7 +168,28 @@ class VideoConfiguration {
|
|
|
142
168
|
* @param {object} userInfo - User provided configuration
|
|
143
169
|
* @param {object} [config] - Optional configuration object
|
|
144
170
|
*/
|
|
145
|
-
initializeGlobalConfig(userInfo, config) {
|
|
171
|
+
initializeGlobalConfig(userInfo, config, src) {
|
|
172
|
+
// Vega path: write `globalThis.__NRVIDEO_CD__` with info+config only.
|
|
173
|
+
// The harvester is owned by `connectedDeviceAgent.js` as a module singleton — no
|
|
174
|
+
// harvester field on this global.
|
|
175
|
+
if (src === "Vega") {
|
|
176
|
+
globalThis.__NRVIDEO_CD__ = {
|
|
177
|
+
info: {
|
|
178
|
+
accountId: userInfo.accountId,
|
|
179
|
+
applicationToken: userInfo.applicationToken,
|
|
180
|
+
endpoint: userInfo.endpoint?.toLowerCase(),
|
|
181
|
+
...(userInfo.appName ? { appName: userInfo.appName } : {}),
|
|
182
|
+
...(userInfo.applicationID ? { applicationID: userInfo.applicationID } : {}),
|
|
183
|
+
...(userInfo.deviceInfo ? { deviceInfo: userInfo.deviceInfo } : {}),
|
|
184
|
+
},
|
|
185
|
+
config: {
|
|
186
|
+
qoeAggregate: config?.qoeAggregate ?? true,
|
|
187
|
+
qoeIntervalFactor: this.sanitizeQoeIntervalFactor(config?.qoeIntervalFactor),
|
|
188
|
+
obfuscate: this.filterObfuscateRules(config?.obfuscate),
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
146
193
|
|
|
147
194
|
let { licenseKey, appName, region, beacon, applicationID } = userInfo;
|
|
148
195
|
|
|
@@ -179,8 +226,8 @@ const videoConfiguration = new VideoConfiguration();
|
|
|
179
226
|
* @param {object} [config] - Optional configuration object
|
|
180
227
|
* @returns {boolean} True if configuration was set successfully
|
|
181
228
|
*/
|
|
182
|
-
export function setVideoConfig(info, config) {
|
|
183
|
-
return videoConfiguration.setConfiguration(info, config);
|
|
229
|
+
export function setVideoConfig(info, config, src) {
|
|
230
|
+
return videoConfiguration.setConfiguration(info, config, src);
|
|
184
231
|
}
|
|
185
232
|
|
|
186
233
|
export { videoConfiguration };
|
package/src/videotracker.js
CHANGED
|
@@ -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
|
-
|
|
643
|
-
|
|
658
|
+
const harvester = this.getHarvester?.();
|
|
659
|
+
harvester?.setBeforeDrainCallback(() => {
|
|
644
660
|
if (this.state) {
|
|
645
661
|
const freshKpis = this.state.getQoeAttributes({}).qoe;
|
|
646
|
-
|
|
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
|
-
|
|
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
|
-
|
|
712
|
+
harvester?.setBeforeDrainCallback?.(null);
|
|
696
713
|
// reset the states after the view count is up
|
|
697
|
-
|
|
698
|
-
|
|
714
|
+
if(this.adsTracker) this.adsTracker.state.clearTotalAdsTime();
|
|
715
|
+
this.state.resetViewIdTrackedState();
|
|
699
716
|
}
|
|
700
717
|
}
|
|
701
718
|
}
|