@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
@@ -0,0 +1,3 @@
1
+ /*! For license information please see index.js.LICENSE.txt */
2
+ (()=>{"use strict";const t={d:(e,i)=>{if(Array.isArray(i))for(var s=0;s<i.length;){var a=i[s++],r=i[s++];t.o(e,a)?0===r&&s++:0===r?Object.defineProperty(e,a,{enumerable:!0,value:i[s++]}):Object.defineProperty(e,a,{enumerable:!0,get:r})}else for(var a in i)t.o(i,a)&&!t.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:i[a]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}};let e={};t.r(e),t.d(e,{Chrono:()=>u,ConnectedDeviceHarvester:()=>U,Constants:()=>d,Core:()=>D,Emitter:()=>l,Log:()=>n,NrVideoEventAggregator:()=>P,Tracker:()=>m,VideoTracker:()=>C,VideoTrackerState:()=>k,connectedDeviceAnalyticsHarvester:()=>M,default:()=>z,getRegisteredHarvester:()=>p,recordEvent:()=>v,version:()=>h.rE});class i{static error(...t){s(t,i.Levels.ERROR,"darkred")}static warn(...t){s(t,i.Levels.WARNING,"darkorange")}static notice(...t){s([].slice.call(arguments),i.Levels.NOTICE,"darkcyan")}static debug(...t){s(t,i.Levels.DEBUG,"indigo")}static debugCommonVideoEvents(t,e,s){try{if(i.level<=i.Levels.DEBUG){s=s||function(t){i.debug("Event: "+t.type)};var a=["canplay","buffering","waiting","ended","play","playing","pause","resume","error","abort","seek","seeking","seeked","stalled","dispose","loadeddata","loadstart","loadedmetadata"];e&&(null===e[0]?(e.shift(),a=e):a=a.concat(e));for(var r=0;r<a.length;r++)"function"==typeof t?t.call(window,a[r],s):t.on?t.on(a[r],s):t.addEventListener?t.addEventListener(a[r],s):t.addEventHandler?t.addEventHandler(a[r],s):i.warn("debugCommonVideoEvents: No common listener function found for ",t)}}catch(t){i.warn(t)}}}function s(t,e,s){e=e||i.Levels.NOTICE,s=s||"darkcyan";var n,o,d,h,l,c,u=i.prefix;(i.includeTime&&(u+=(n=new Date,o=("0"+n.getDate()).slice(-2),d=("0"+n.getMinutes()).slice(-2),h=("0"+n.getSeconds()).slice(-2),l=("00"+n.getMilliseconds()).slice(-3),"["+o+":"+d+":"+h+"."+l+"] ")),u+=function(t){return r[t]}(e)+":",i.level<=e&&e!==i.Levels.SILENT)&&(!i.colorful||"undefined"!=typeof document&&document.documentMode?a(t,u):(c=e===i.Levels.ERROR&&console.error?console.error:e===i.Levels.WARNING&&console.warn?console.warn:e===i.Levels.DEBUG&&console.debug&&null==window.cast?console.debug:console.log,u="%c"+u,t.splice(0,0,u,"color: "+s),c.apply(console,t)))}function a(t,e){if(t instanceof Array)for(var i in t)a(t[i],e);else"string"==typeof t?console.log(e+" "+t):(console.log(e+"↵"),console.log(t))}i.Levels={SILENT:5,ERROR:4,WARNING:3,NOTICE:2,DEBUG:1,ALL:0},i.level=i.Levels.ERROR,i.colorful=!0,i.includeTime=!0,i.prefix="[nrvideo]";const r={4:"e",3:"w",2:"n",1:"d"};!function(){if("undefined"!=typeof window&&window.location&&window.location.search){var t=/\?.*&*nrvideo-debug=(.+)/i.exec(window.location.search);null!==t&&("true"===t[1]?i.level=i.Levels.ALL:i.level=t[1]),null!==/\?.*&*nrvideo-colors=false/i.exec(window.location.search)&&(i.colorful=!1)}}();const n=i;class o{}o.AdPositions={PRE:"pre",MID:"mid",POST:"post"},o.COLLECTOR={US:["bam.nr-data.net","bam-cell.nr-data.net"],EU:"bam.eu01.nr-data.net",JP:"bam.jp.nr-data.net",Staging:"staging-bam-cell.nr-data.net",GOV:"gov-bam.nr-data.net"},o.VALID_EVENT_TYPES=["VideoAction","VideoAdAction","VideoErrorAction","VideoCustomAction"],o.MAX_PAYLOAD_SIZE=1048576,o.MAX_BEACON_SIZE=61440,o.MAX_EVENTS_PER_BATCH=1e3,o.INTERVAL=1e4,o.DEFAULT_QOE_INTERVAL_FACTOR=2,o.QOE_KPI_KEYS=["startupTime","peakBitrate","averageBitrate","totalPlaytime","totalRebufferingTime","rebufferingRatio","hadStartupError","hadPlaybackError","numberOfErrors"],o.QOE_AGGREGATE_KEYS=["coreVersion","instrumentation.name","instrumentation.provider","instrumentation.version","isBackgroundEvent","playerName","playerVersion","src","viewId","viewSession","contentIsAutoplayed","contentIsMuted","contentRenditionHeight","contentRenditionWidth","contentSrc","numberOfVideos","pageUrl","trackerName","trackerVersion","contentDuration","contentPlayrate","contentPlayhead","contentPreload","elapsedTime","contentTitle","contentId","contentIsLive","deviceType","deviceGroup","deviceManufacturer","deviceModel","deviceName","deviceSize","deviceUuid","contentRenditionName","contentIsFullscreen","contentCdn","contentFps","asnOrganization","asnLongitude","asnLatitude","asn","timeSinceRequested","timeSinceStarted"];const d=o,h={rE:"5.0.0"};const l=class{on(t,e){if(this._listeners=this._listeners||{},"function"==typeof e)return this._listeners[t]=this._listeners[t]||[],this._listeners[t].push(e),this}off(t,e){if(this._listeners=this._listeners||{},this._listeners[t]){var i=this._listeners[t].indexOf(e);-1!==i&&this._listeners[t].splice(i,1)}return this}emit(t,e,i){return this._listeners=this._listeners||{},i=i||{},Array.isArray(this._listeners[e])&&this._listeners[e].forEach(s=>{s.call(this,{eventType:t,type:e,data:i,target:this})}),Array.isArray(this._listeners["*"])&&this._listeners["*"].forEach(s=>{s.call(this,{eventType:t,type:e,data:i,target:this})}),this}};class c{constructor(){this.reset()}reset(){this.startTime=0,this.stopTime=0,this.accumulator=0,this.offset=0}getDeltaTime(){return this.startTime?this.offset+((new Date).getTime()-this.startTime):null}start(){this.startTime=(new Date).getTime(),this.stopTime=0}stop(){return this.stopTime=(new Date).getTime(),this.startTime<this.stopTime&&(this.accumulator+=this.stopTime-this.startTime),this.getDeltaTime()}getDuration(){return this.stopTime?this.accumulator+this.offset:this.accumulator+(this.getDeltaTime()??0)}clone(){var t=new c;return t.startTime=this.startTime,t.stopTime=this.stopTime,t.offset=this.offset,t.accumulator=this.accumulator,t}}const u=c;class g extends l{constructor(t){super(),this.customData={},this.heartbeat=null,this.parentTracker=null,this._trackerReadyChrono=new u,this._trackerReadyChrono.start(),this._actionTable=d.ACTION_TABLE,this._actionAdTable=d.ACTION_AD_TABLE,t=t||{},this.setOptions(t)}setOptions(t){t&&(t.parentTracker&&(this.parentTracker=t.parentTracker),t.customData&&(this.customData=t.customData),t.heartbeat&&(this.heartbeat=t.heartbeat))}dispose(){this.unregisterListeners()}registerListeners(){}unregisterListeners(){}getHeartbeat(){return this.state._isAd?2e3:this.heartbeat?this.heartbeat:this.parentTracker&&this.parentTracker.heartbeat?this.parentTracker.heartbeat:3e4}startHeartbeat(){this._heartbeatInterval=setInterval(this.sendHeartbeat.bind(this),Math.max(this.getHeartbeat(),2e3))}stopHeartbeat(){this._heartbeatInterval&&clearInterval(this._heartbeatInterval)}sendHeartbeat(t){this.sendVideoAction(g.Events.HEARTBEAT,t)}getAttributes(t,e){(t=t||{}).trackerName=this.getTrackerName(),t.trackerVersion=this.getTrackerVersion(),t.coreVersion=h.rE,t.timeSinceTrackerReady=this._trackerReadyChrono.getDeltaTime();for(let e in this.customData)t[e]=this.customData[e];return null!=document.hidden&&(t.isBackgroundEvent=document.hidden),t}getTrackerVersion(){return h.rE}getTrackerName(){return"base-tracker"}sendVideoAction(t,e){this.emit("VideoAction",t,this.getAttributes(e))}sendVideoAdAction(t,e){this.emit("VideoAdAction",t,this.getAttributes(e))}sendVideoErrorAction(t,e){let i=this.isAd()?"adError":"videoError";this.emit("VideoErrorAction",t,this.getAttributes(e,i))}sendVideoCustomAction(t,e){this.emit("VideoCustomAction",t,this.getAttributes(e,"customAction"))}setHarvestInterval(t){const e=this.getHarvester?.();if(e)try{e.setHarvestInterval(t)}catch(t){return void n.error("Failed to set harvest interval:",t.message)}else n.error("Tracker has no harvester; setHarvestInterval ignored")}getHarvester(){return null}}g.Events={HEARTBEAT:"HEARTBEAT",QOE_AGGREGATE:"QOE_AGGREGATE"};const m=g;function f(t){try{return JSON.stringify(t,(()=>{const t=new WeakSet;return(e,i)=>{if("object"==typeof i&&null!==i){if(t.has(i))return;t.add(i)}return i}})())??""}catch(t){return n.error("Error stringifying value:",t.message),""}}function T(t){if("string"==typeof t&&t.length)return t.length;if("object"==typeof t){if("undefined"!=typeof ArrayBuffer&&t instanceof ArrayBuffer&&t.byteLength)return t.byteLength;if("undefined"!=typeof Blob&&t instanceof Blob&&t.size)return t.size;if(!("undefined"!=typeof FormData&&t instanceof FormData))try{return f(t).length}catch(t){return}}}function A(t,e,i,{addTimeSinceLoad:s=!1}={}){const{appName:a,applicationID:r}=i,{qoe:n,...o}=e,h=n?{...n}:{},l={...r?{}:{appName:a},timestamp:Date.now(),...s?{timeSinceLoad:"undefined"!=typeof window&&window.performance?window.performance.now()/1e3:null}:{}},c={...o,eventType:t,...l};let u=null;if("VideoAction"===t){const t=(g=d.QOE_AGGREGATE_KEYS,f=e,g&&Array.isArray(g)&&0!==g.length?f&&"object"==typeof f?g.reduce((t,e)=>(e in f&&(t[e]=f[e]),t),{}):{}:f);u={eventType:"VideoAction",actionName:m.Events.QOE_AGGREGATE,qoeAggregateVersion:"1.0.0",...h,...t,...l}}var g,f;return{eventObject:c,qoeEventObject:u}}const E=Object.create(null);function p(t){return E[t]}function v(t,e={}){try{if(!d.VALID_EVENT_TYPES.includes(t))return n.warn("Invalid event type provided to recordEvent",{eventType:t}),!1;const i="Vega"===e.src,s=i?"Vega":"Browser",a="undefined"!=typeof window?window:void 0,r=i?globalThis.__NRVIDEO_CD__?.info:a?.NRVIDEO?.info;if(!r)return;const o=E[s];if(!o)return n.warn("No harvester registered for routing key",{routingKey:s}),!1;return function(t,e,i,s,a,{addTimeSinceLoad:r=!1}={}){if(!s)return!1;const{eventObject:n,qoeEventObject:o}=A(t,e,i,{addTimeSinceLoad:r}),d=s.addEvent(n);return o&&a?d&&s.addEvent(o):d}(t,e,r,o,i?globalThis.__NRVIDEO_CD__?.config?.qoeAggregate:a?.NRVIDEO?.config?.qoeAggregate,{addTimeSinceLoad:!i})}catch(t){return n.error("Failed to record event:",t.message),!1}}const{COLLECTOR:S}=d;class _{setConfiguration(t,e,i){return!!("Vega"===i?this.validateVegaFields(t):this.validateRequiredFields(t))&&(!!this.validateConfigFields(e)&&(this.initializeGlobalConfig(t,e,i),n.notice("Video analytics configuration initialized successfully"),!0))}validateVegaFields(t){return t&&"object"==typeof t?t.applicationToken?!!["US","EU","staging","GOV"].includes(t.endpoint)||(n.error("Invalid endpoint (must be US, EU, staging, or GOV)"),!1):(n.error("applicationToken is required"),!1):(n.error("Configuration must be an object"),!1)}validateRequiredFields(t){if(!t||"object"!=typeof t)return n.error("Configuration must be an object"),!1;const{licenseKey:e,appName:i,region:s,applicationID:a,beacon:r}=t;if(!e)return n.error("licenseKey is required"),!1;if(a){if(!r)return n.error("beacon is required when applicationID is provided"),!1;if(!Object.values(S).flatMap(t=>t).includes(r))return n.error(`Invalid beacon: ${r}`),!1}else{if(!i||!s)return n.error("appName and region are required when applicationID is not provided"),!1;if(!S[s])return n.error(`Invalid region: ${s}. Valid regions are: ${Object.keys(S).join(", ")}`),!1}return!0}validateConfigFields(t){if(null==t)return!0;if("object"!=typeof t||Array.isArray(t))return n.error("config must be an object"),!1;const{qoeAggregate:e,obfuscate:i}=t;return void 0!==e&&"boolean"!=typeof e?(n.error("qoeAggregate must be a boolean"),!1):!(void 0!==i&&!Array.isArray(i))||(n.error("obfuscate must be an array"),!1)}filterObfuscateRules(t){return t?t.filter(t=>{const e=void 0!==t.regex&&("string"==typeof t.regex||t.regex instanceof RegExp),i=void 0!==t.replacement&&"string"==typeof t.replacement;return!(!e||!i)||(n.warn("obfuscate rule missing required 'regex' (string|RegExp) and/or 'replacement' (string), skipping:",t),!1)}):[]}sanitizeQoeIntervalFactor(t){return null==t?d.DEFAULT_QOE_INTERVAL_FACTOR:"number"==typeof t&&Number.isInteger(t)&&t>=1?t:(n.warn(`Invalid qoeIntervalFactor "${t}" — must be a positive integer. Defaulting to ${d.DEFAULT_QOE_INTERVAL_FACTOR}.`),d.DEFAULT_QOE_INTERVAL_FACTOR)}initializeGlobalConfig(t,e,i){if("Vega"===i)return void(globalThis.__NRVIDEO_CD__={info:{accountId:t.accountId,applicationToken:t.applicationToken,endpoint:t.endpoint,...t.appName?{appName:t.appName}:{},...t.applicationID?{applicationID:t.applicationID}:{},...t.deviceInfo?{deviceInfo:t.deviceInfo}:{}},config:{qoeAggregate:e?.qoeAggregate??!0,qoeIntervalFactor:this.sanitizeQoeIntervalFactor(e?.qoeIntervalFactor),obfuscate:this.filterObfuscateRules(e?.obfuscate)}});let{licenseKey:s,appName:a,region:r,beacon:n,applicationID:o}=t;n="US"===r?d.COLLECTOR.US[0]:n||S[r],window.NRVIDEO={info:{...r?{region:r}:{},beacon:n,licenseKey:s,applicationID:o,...o?{}:{appName:a}},config:{qoeAggregate:e?.qoeAggregate??!0,qoeIntervalFactor:this.sanitizeQoeIntervalFactor(e?.qoeIntervalFactor),obfuscate:this.filterObfuscateRules(e?.obfuscate)}}}}const y=new _;class B{static addTracker(t,e){var i,s,a;e?.info&&(i=e.info,s=e?.config,a=e?.src,y.setConfiguration(i,s,a)),t.on&&t.emit?(b.push(t),t.on("*",R),"function"==typeof t.trackerInit&&t.trackerInit()):n.error("Tried to load a non-tracker.",t)}static removeTracker(t){t.off("*",R),t.dispose();let e=b.indexOf(t);-1!==e&&b.splice(e,1)}static getTrackers(){return b}static send(t,e,i){return v(t,{actionName:e,...i})}static sendError(t){return v("VideoErrorAction",{actionName:"ERROR",...t})}}let b=[];function R(t){try{let e=function(t){let e={};for(let i in t)null!==t[i]&&void 0!==t[i]&&(e[i]=t[i]);return e}(t.data);n.level<=n.Levels.DEBUG?n.notice("Sent",t.type,e):n.notice("Sent",t.type),B.send(t.eventType,t.type,e)}catch(t){n.error("Error in event handler:",t.message)}}const D=B;const k=class{constructor(){this.reset(),this._createdAt=Date.now(),this._hb=!0,this._acc=0,this._bufferAcc=0}reset(){this._viewSession=null,this._viewCount=0,this._isAd=!1,this.numberOfErrors=0,this.numberOfAds=0,this.numberOfVideos=0,this.totalPlaytime=0,this.weightedAverageBitrate=0,this.totalAdPlaytime=0,this.isAdBreak=!1,this.initialBufferingHappened=!1,this.startupTime=null,this.peakBitrate=0,this.partialAverageBitrate=0,this._totalBitrateDuration=0,this.weightedBitrate=0,this._lastBitrate=null,this._lastBitrateChangeTimestamp=null,this._downloadBitrates=[],this._lastDownloadBitrate=null,this.totalSwitchUps=0,this.totalSwitchDowns=0,this.totalPauseTime=0,this._playedRenditions=new Set,this.hadStartupError=!1,this.hadPlaybackError=!1,this.totalRebufferingTime=0,this.resetFlags(),this.resetChronos()}resetFlags(){this.isPlayerReady=!1,this.isRequested=!1,this.isStarted=!1,this.isPaused=!1,this.isSeeking=!1,this.isBuffering=!1,this.isPlaying=!1}resetChronos(){this.timeSinceRequested=new u,this.timeSinceStarted=new u,this.timeSincePaused=new u,this.timeSinceSeekBegin=new u,this.timeSinceBufferBegin=new u,this.timeSinceAdBreakStart=new u,this.timeSinceLastDownload=new u,this.timeSinceLastHeartbeat=new u,this.timeSinceLastRenditionChange=new u,this.timeSinceLastAdQuartile=new u,this.timeSinceLastAd=new u,this.timeSinceLastError=new u,this.timeSinceLastAdError=new u,this.timeSinceResumed=new u,this.timeSinceSeekEnd=new u,this.playtimeSinceLastEvent=new u,this.customTimeSinceAttributes={},this.elapsedTime=new u,this.bufferElapsedTime=new u,this._totalAdPlaytime=new u}isAd(){return this._isAd}setIsAd(t){this._isAd=t}setTimeSinceAttribute(t){this.customTimeSinceAttributes[t]=new u,this.customTimeSinceAttributes[t].start()}removeTimeSinceAttribute(t){delete this.customTimeSinceAttributes[t]}getViewSession(){if(!this._viewSession){let t=(new Date).getTime(),e=Math.random().toString(36).substring(2)+Math.random().toString(36).substring(2);this._viewSession=t+"-"+e}return this._viewSession}getViewId(){return this.getViewSession()+"-"+this._viewCount}getStateAttributes(t){t=t||{},this.isAd()?(this.isRequested&&(t.timeSinceAdRequested=this.timeSinceRequested.getDeltaTime(),t.timeSinceLastAdHeartbeat=this.timeSinceLastHeartbeat.getDeltaTime()),this.isStarted&&(t.timeSinceAdStarted=this.timeSinceStarted.getDeltaTime()),this.isPaused&&(t.timeSinceAdPaused=this.timeSincePaused.getDeltaTime()),this.isBuffering&&(t.timeSinceAdBufferBegin=this.timeSinceBufferBegin.getDeltaTime()),this.isSeeking&&(t.timeSinceAdSeekBegin=this.timeSinceSeekBegin.getDeltaTime()),this.isAdBreak&&(t.timeSinceAdBreakBegin=this.timeSinceAdBreakStart.getDeltaTime()),this.numberOfErrors>0&&this.timeSinceLastAdError.startTime>0&&(t.timeSinceLastAdError=this.timeSinceLastAdError.getDeltaTime()),t.numberOfAds=this.numberOfAds):(this.isRequested&&(t.timeSinceRequested=this.timeSinceRequested.getDeltaTime(),t.timeSinceLastHeartbeat=this.timeSinceLastHeartbeat.getDeltaTime()),this.isStarted&&(t.timeSinceStarted=this.timeSinceStarted.getDeltaTime()),this.isPaused&&(t.timeSincePaused=this.timeSincePaused.getDeltaTime()),this.isBuffering&&(t.timeSinceBufferBegin=this.timeSinceBufferBegin.getDeltaTime()),this.isSeeking&&(t.timeSinceSeekBegin=this.timeSinceSeekBegin.getDeltaTime()),t.timeSinceLastAd=this.timeSinceLastAd.getDeltaTime(),this.numberOfErrors>0&&this.timeSinceLastError.startTime>0&&(t.timeSinceLastError=this.timeSinceLastError.getDeltaTime()),t.numberOfVideos=this.numberOfVideos),t.numberOfErrors=this.numberOfErrors,this.isAd()||(this.playtimeSinceLastEvent.startTime>0?t.playtimeSinceLastEvent=this.playtimeSinceLastEvent.getDeltaTime():t.playtimeSinceLastEvent=0,this.isPlaying?this.playtimeSinceLastEvent.start():this.playtimeSinceLastEvent.reset(),this.totalPlaytime+=t.playtimeSinceLastEvent,t.totalPlaytime=this.totalPlaytime);for(const[e,i]of Object.entries(this.customTimeSinceAttributes))t[e]=i.getDeltaTime();return t}getQoeAttributes(t){t=t||{};const e={};try{if(null!==this.startupTime&&(e.startupTime=this.startupTime),this.peakBitrate>0&&(e.peakBitrate=this.peakBitrate),e.hadStartupError=this.hadStartupError,e.hadPlaybackError=this.hadPlaybackError,e.totalRebufferingTime=this.totalRebufferingTime,e.rebufferingRatio=this.totalPlaytime>0?this.totalRebufferingTime/this.totalPlaytime*100:0,e.totalPlaytime=this.totalPlaytime,e.averageBitrate=this.weightedBitrate,e.numberOfErrors=this.numberOfErrors,this._downloadBitrates.length>0){const t=this._downloadBitrates.reduce((t,e)=>t+e,0);e.avgDownloadRate=Math.round(t/this._downloadBitrates.length),e.minDownloadRate=Math.min(...this._downloadBitrates),e.maxDownloadRate=Math.max(...this._downloadBitrates)}e.totalSwitchUps=this.totalSwitchUps,e.totalSwitchDowns=this.totalSwitchDowns,e.totalPauseTime=this.timeSincePaused.getDuration(),e.totalViewSessionTime=this.totalPlaytime,e.totalRenditions=this._playedRenditions.size,e.qoeAggregateVersion="1.1.0"}catch(t){n.error("Failed to add attributes for QOE KPIs",t.message)}return t.qoe=e,t}calculateBufferType(t){let e="";return e=t?"initial":this.isSeeking?"seek":this.isPaused?"pause":"connection",n.debug("Buffer Type = "+e),e}goViewCountUp(){this._viewCount++}goPlayerReady(){return!this.isPlayerReady&&(this.isPlayerReady=!0,!0)}goRequest(){return!this.isRequested&&(this.isRequested=!0,this.timeSinceLastAd.reset(),this.timeSinceRequested.start(),!0)}goStart(){return!(!this.isRequested||this.isStarted)&&(this.isAd()?this.numberOfAds++:this.numberOfVideos++,this.isStarted=!0,this.isPlaying=!0,this.timeSinceStarted.start(),this.playtimeSinceLastEvent.start(),!0)}goEnd(){return!!this.isRequested&&(this.numberOfErrors=0,this.resetFlags(),this.timeSinceRequested.stop(),this.timeSinceStarted.stop(),this.playtimeSinceLastEvent.stop(),this.isPlaying=!1,!0)}goPause(){return!(!this.isStarted||this.isPaused)&&(this.isPaused=!0,this.isPlaying=!1,this.timeSincePaused.start(),this.playtimeSinceLastEvent.stop(),this.timeSinceResumed.reset(),this.isBuffering&&(this._bufferAcc+=this.bufferElapsedTime.getDeltaTime()),this.elapsedTime.start(),!0)}goResume(){return!(!this.isStarted||!this.isPaused)&&(this.isPaused=!1,this.isPlaying=!0,this.timeSincePaused.stop(),this.timeSinceResumed.start(),this._hb?(this._acc=this.elapsedTime.getDeltaTime(),this._hb=!1):(this.isBuffering&&this.bufferElapsedTime.start(),this._acc+=this.elapsedTime.getDeltaTime()),!0)}goBufferStart(){return!(!this.isRequested||this.isBuffering)&&(this.isBuffering=!0,this.isPlaying=!1,this.timeSinceBufferBegin.start(),this.bufferElapsedTime.start(),!0)}goBufferEnd(){return!(!this.isRequested||!this.isBuffering)&&(this.isBuffering=!1,this.isPlaying=!0,this.timeSinceBufferBegin.stop(),this._hb?(this._bufferAcc=this.bufferElapsedTime.getDeltaTime(),this._hb=!1):this._bufferAcc+=this.bufferElapsedTime.getDeltaTime(),!this.isAd()&&this.initialBufferingHappened&&(this.totalRebufferingTime+=this.timeSinceBufferBegin.stopTime-this.timeSinceBufferBegin.startTime),!0)}goSeekStart(){return!(!this.isStarted||this.isSeeking)&&(this.isSeeking=!0,this.isPlaying=!1,this.timeSinceSeekBegin.start(),this.timeSinceSeekEnd.reset(),!0)}goSeekEnd(){return!(!this.isStarted||!this.isSeeking)&&(this.isSeeking=!1,this.isPlaying=!0,this.timeSinceSeekBegin.stop(),this.timeSinceSeekEnd.start(),!0)}goAdBreakStart(){return!this.isAdBreak&&(this.isAdBreak=!0,this.timeSinceAdBreakStart.start(),!0)}goAdBreakEnd(){return!!this.isAdBreak&&(this.isRequested=!1,this.isAdBreak=!1,this.totalAdPlaytime=this.timeSinceAdBreakStart.getDeltaTime(),this.timeSinceAdBreakStart.stop(),!0)}goDownload(){this.timeSinceLastDownload.start()}goHeartbeat(){this.timeSinceLastHeartbeat.start()}goRenditionChange(){this.timeSinceLastRenditionChange.start()}goAdQuartile(){this.timeSinceLastAdQuartile.start()}goError(){this.isError=!0,this.numberOfErrors++,this.isAd()?this.timeSinceLastAdError.start():(this.timeSinceLastError.start(),this.isStarted?this.hadPlaybackError=!0:this.hadStartupError=!0)}goLastAd(){this.timeSinceLastAd.start()}trackContentBitrateState(t){if(t&&"number"==typeof t){this.peakBitrate=Math.max(this.peakBitrate,t);const e=Date.now();if(!this.isPlaying){if(null!==this._lastBitrate&&null!==this._lastBitrateChangeTimestamp){const t=e-this._lastBitrateChangeTimestamp;t>0&&(this.partialAverageBitrate+=this._lastBitrate*t,this._totalBitrateDuration+=t),this._lastBitrateChangeTimestamp=null}return void(this._lastBitrate=t)}if(null===this._lastBitrateChangeTimestamp&&null!==this._lastBitrate&&(this._lastBitrateChangeTimestamp=e),null!==this._lastBitrate&&this._lastBitrate!==t&&null!==this._lastBitrateChangeTimestamp){const t=e-this._lastBitrateChangeTimestamp;t>0&&(this.partialAverageBitrate+=this._lastBitrate*t,this._totalBitrateDuration+=t),this._lastBitrateChangeTimestamp=e}null===this._lastBitrateChangeTimestamp&&(this._lastBitrateChangeTimestamp=e),this._lastBitrate=t;let i=this.partialAverageBitrate,s=this._totalBitrateDuration;const a=e-this._lastBitrateChangeTimestamp;a>0&&(i+=t*a,s+=a),this.weightedBitrate=s>0?Math.round(i/s):t}}trackDownloadRate(t){!t||"number"!=typeof t||t<=0||t!==this._lastDownloadBitrate&&(this._downloadBitrates.push(t),this._lastDownloadBitrate=t)}addPlayedRendition(t,e){t&&e&&this._playedRenditions.add(`${t}x${e}`)}resetViewIdTrackedState(){this.peakBitrate=0,this.startupTime=null,this.partialAverageBitrate=0,this._totalBitrateDuration=0,this.weightedBitrate=0,this._lastBitrate=null,this._lastBitrateChangeTimestamp=null,this._downloadBitrates=[],this._lastDownloadBitrate=null,this.totalSwitchUps=0,this.totalSwitchDowns=0,this.timeSincePaused.reset(),this._playedRenditions=new Set}clearTotalAdsTime(){n.debug("clear total ads time",this.totalAdTime),this._totalAdPlaytime.reset()}totalAdTime(){return this._totalAdPlaytime.getDuration()}startAdsTime(){return n.debug("startAdsTime"),this._totalAdPlaytime.start()}stopAdsTime(){return n.debug("stopAdsTime"),this._totalAdPlaytime.stop()}setStartupTime(t){null===this.startupTime&&(this.startupTime=Math.max(this.timeSinceRequested.getDeltaTime()-t,0))}};class w extends m{constructor(t,e){super(),this.state=new k,this.adsTracker=null,this._lastBufferType=null,this._userId=null,this._src=null,e=e||{},this.setOptions(e),t&&this.setPlayer(t,e.tag),n.notice("Tracker "+this.getTrackerName()+" v"+this.getTrackerVersion()+" is ready.")}setUserId(t){this._userId=t}setOptions(t){t&&(t.adsTracker&&this.setAdsTracker(t.adsTracker),"boolean"==typeof t.isAd&&this.setIsAd(t.isAd),void 0!==t.src&&(null!==this._src&&this._src!==t.src?n.warn(`setOptions: src is locked to '${this._src}'. Ignoring override '${t.src}'.`):(this._src=t.src,this.adsTracker&&null==this.adsTracker._src&&(this.adsTracker._src=this._src))),m.prototype.setOptions.apply(this,arguments))}setPlayer(t,e){(this.player||this.tag)&&this.dispose(),"undefined"!=typeof document&&document.getElementById&&("string"==typeof t&&(t=document.getElementById(t)),"string"==typeof e&&(e=document.getElementById(e))),e=e||t,this.player=t,this.tag=e,this.registerListeners()}isAd(){return this.state.isAd()}setIsAd(t){this.state.setIsAd(t)}setAdsTracker(t){this.disposeAdsTracker(),t&&(this.adsTracker=t,this.adsTracker.setIsAd(!0),this.adsTracker.parentTracker=this,null!=this._src&&null==t._src&&(t._src=this._src),this.adsTracker.on("*",N.bind(this)))}disposeAdsTracker(){this.adsTracker&&(this.adsTracker.off("*",N),this.adsTracker.dispose())}dispose(){this.stopHeartbeat(),this.disposeAdsTracker(),this.unregisterListeners(),this.player=null,this.tag=null}registerListeners(){}unregisterListeners(){}getViewId(){return this.parentTracker?this.parentTracker.getViewId():this.state.getViewId()}getViewSession(){return this.parentTracker?this.parentTracker.getViewSession():this.state.getViewSession()}getVideoId(){return null}getTitle(){return null}isLive(){return null}getBitrate(){return null}getManifestBitrate(){return null}getSegmentDownloadBitrate(){return null}getNetworkDownloadBitrate(){return null}getWebkitBitrate(){if(this.tag&&this.tag.webkitVideoDecodedByteCount){let t;if(this._lastWebkitBitrate){t=this.tag.webkitVideoDecodedByteCount;let e=t-this._lastWebkitBitrate,i=this.getHeartbeat()/1e3;t=Math.round(e/i*8)}return this._lastWebkitBitrate=this.tag.webkitVideoDecodedByteCount,t||null}}getRenditionName(){return null}getRenditionBitrate(){return null}getRenditionShift(t){let e,i=this.getManifestBitrate();return this.isAd()?(e=this._lastAdRendition,t&&(this._lastAdRendition=i)):(e=this._lastRendition,t&&(this._lastRendition=i)),i&&e?i>e?"up":i<e?"down":null:null}getRenditionHeight(){return this.tag?this.tag.videoHeight:null}getRenditionWidth(){return this.tag?this.tag.videoWidth:null}getDuration(){return this.tag?this.tag.duration:null}getPlayhead(){return this.tag?this.tag.currentTime:null}getLanguage(){return null}getSrc(){return this.tag?this.tag.currentSrc:null}getPlayrate(){return this.tag?this.tag.playbackRate:null}isMuted(){return this.tag?this.tag.muted:null}isFullscreen(){return null}getCdn(){return null}getPlayerName(){return this.getTrackerName()}getPlayerVersion(){return h.rE}getFps(){return null}isAutoplayed(){return this.tag?this.tag.autoplay:null}getPreload(){return this.tag?this.tag.preload:null}getAdQuartile(){return null}getAdPosition(){return this.parentTracker?this.parentTracker.state.isStarted?"mid":"pre":null}getAdPartner(){return null}getAdCreativeId(){return null}getInstrumentationProvider(){return null}getInstrumentationName(){return null}getInstrumentationVersion(){return null}getAttributes(t,e){if(void 0===(t=m.prototype.getAttributes.apply(this,arguments)).isAd&&(t.isAd=this.isAd()),t.viewSession=this.getViewSession(),t.viewId=this.getViewId(),t.playerName=this.getPlayerName(),t.playerVersion=this.getPlayerVersion(),t["instrumentation.provider"]=this.getInstrumentationProvider(),t["instrumentation.name"]=this.getInstrumentationName(),t["instrumentation.version"]=this.getInstrumentationVersion(),t["enduser.id"]=this._userId,t.src=this._src||"Browser","customAction"===e)return t;try{t.pageUrl=window.location.href}catch(t){}this.isAd()?(t.adId=this.getVideoId(),t.adTitle=this.getTitle(),t.adSrc=this.getSrc(),t.adCdn=this.getCdn(),this.state.isStarted&&(t.adBitrate=this.getBitrate()||0),t.adRenditionName=this.getRenditionName(),t.adRenditionHeight=this.getRenditionHeight(),t.adRenditionWidth=this.getRenditionWidth(),t.adDuration=this.getDuration(),t.adPlayhead=this.getPlayhead(),t.adLanguage=this.getLanguage(),t.adIsMuted=this.isMuted(),t.adFps=this.getFps(),t.adPosition=this.getAdPosition(),t.adCreativeId=this.getAdCreativeId(),t.adPartner=this.getAdPartner()):(t.contentId=this.getVideoId(),t.contentTitle=this.getTitle(),t.contentSrc=this.getSrc(),t.contentCdn=this.getCdn(),t.contentPlayhead=this.getPlayhead(),t.contentIsLive=this.isLive(),this.state.isStarted&&(t.contentBitrate=this.getBitrate()||0,t.contentManifestBitrate=this.getManifestBitrate()||0,t.contentSegmentDownloadBitrate=this.getSegmentDownloadBitrate()||0,t.contentNetworkDownloadBitrate=this.getNetworkDownloadBitrate()||0),t.contentRenditionName=this.getRenditionName(),t.contentRenditionHeight=this.getRenditionHeight(),t.contentRenditionWidth=this.getRenditionWidth(),t.contentDuration=this.getDuration(),t.contentLanguage=this.getLanguage(),t.contentPlayrate=this.getPlayrate(),t.contentIsFullscreen=this.isFullscreen(),t.contentIsMuted=this.isMuted(),t.contentIsAutoplayed=this.isAutoplayed(),t.contentPreload=this.getPreload(),t.contentFps=this.getFps(),null!=this.adsTracker&&this.adsTracker.state.totalAdPlaytime>0&&(t.totalAdPlaytime=this.adsTracker.state.totalAdPlaytime)),this.state.getStateAttributes(t),this.state.isStarted&&!this.isAd()&&(this.state.trackContentBitrateState(t.contentBitrate),this.state.trackDownloadRate(t.contentNetworkDownloadBitrate),this.state.addPlayedRendition(t.contentRenditionHeight,t.contentRenditionWidth));for(let e in this.customData)t[e]=this.customData[e];if(!this.isAd()){this.state.getQoeAttributes(t);const e=t.qoe;for(let t in this.customData)e[t]=this.customData[t]}return t}sendCustom(t,e,i){i=i||{},this.sendVideoCustomAction(t,i),this.state.setTimeSinceAttribute(e)}sendPlayerReady(t){this.state.goPlayerReady()&&(t=t||{},this.sendVideoAction(w.Events.PLAYER_READY,t))}sendRequest(t){if(this.state.goRequest()){let e;this.isAd()?(e=w.Events.AD_REQUEST,this.sendVideoAdAction(e,t)):(e=w.Events.CONTENT_REQUEST,this.sendVideoAction(e,t))}}sendStart(t){if(this.state.goStart()){let e;if(this.isAd())e=w.Events.AD_START,this.parentTracker&&(this.parentTracker.state.isPlaying=!1),this.sendVideoAdAction(e,t),this.state.startAdsTime();else{e=w.Events.CONTENT_START;let i=0;this.adsTracker&&((this.adsTracker.state.isPlaying||this.adsTracker.state.isBuffering)&&(this.adsTracker.state.stopAdsTime(),this.adsTracker.state.isPlaying=!1,this.adsTracker.state.isBuffering=!1),i=this.adsTracker.state.totalAdTime()??0),this.state.setStartupTime(i),this.sendVideoAction(e,t);const s=this.getHarvester?.();s?.setBeforeDrainCallback(()=>{if(this.state){const t=this.state.getQoeAttributes({}).qoe;s.refreshQoeKpis(t,this.getViewId())}})}this.startHeartbeat(),this.state.goHeartbeat()}}sendEnd(t){if(this.state.goEnd()){let e;if(t=t||{},this.isAd()?(e=w.Events.AD_END,t.timeSinceAdRequested=this.state.timeSinceRequested.getDeltaTime(),t.timeSinceAdStarted=this.state.timeSinceStarted.getDeltaTime(),this.parentTracker&&(this.parentTracker.state.isPlaying=!0,this.parentTracker.state.timeSincePaused.reset()),this.state.stopAdsTime()):(e=w.Events.CONTENT_END,t.timeSinceRequested=this.state.timeSinceRequested.getDeltaTime(),t.timeSinceStarted=this.state.timeSinceStarted.getDeltaTime()),this.stopHeartbeat(),this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t),this.parentTracker&&this.isAd()&&this.parentTracker.state.goLastAd(),this.state.goViewCountUp(),this.state.totalPlaytime=0,!this.isAd()){const t=this.getHarvester?.();t?.forceNextQoeCycle?.(),t?.setBeforeDrainCallback?.(null),this.adsTracker&&this.adsTracker.state.clearTotalAdsTime(),this.state.resetViewIdTrackedState()}}}sendPause(t){if(this.state.goPause()){let e=this.isAd()?w.Events.AD_PAUSE:w.Events.CONTENT_PAUSE;this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t)}}sendResume(t){if(this.state.goResume()){let e;t=t||{},this.isAd()?(e=w.Events.AD_RESUME,t.timeSinceAdPaused=this.state.timeSincePaused.getDeltaTime()):(e=w.Events.CONTENT_RESUME,t.timeSincePaused=this.state.timeSincePaused.getDeltaTime()),this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t)}}sendBufferStart(t){if(this.state.goBufferStart()){let e;t=t||{},e=this.isAd()?w.Events.AD_BUFFER_START:w.Events.CONTENT_BUFFER_START,t=this.buildBufferAttributes(t),this._lastBufferType=t.bufferType,this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t)}}sendBufferEnd(t){if(this.state.goBufferEnd()){let e;t=t||{},this.isAd()?(e=w.Events.AD_BUFFER_END,t.timeSinceAdBufferBegin=this.state.timeSinceBufferBegin.getDeltaTime()):(e=w.Events.CONTENT_BUFFER_END,t.timeSinceBufferBegin=this.state.timeSinceBufferBegin.getDeltaTime()),t=this.buildBufferAttributes(t),null!=this._lastBufferType&&(t.bufferType=this._lastBufferType),this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t),this.state.initialBufferingHappened=!0}}buildBufferAttributes(t){return null==t.timeSinceStarted||t.timeSinceStarted<100?t.isInitialBuffering=!this.state.initialBufferingHappened:t.isInitialBuffering=!1,t.bufferType=this.state.calculateBufferType(t.isInitialBuffering),t.timeSinceResumed=this.state.timeSinceResumed.getDeltaTime(),t.timeSinceSeekEnd=this.state.timeSinceSeekEnd.getDeltaTime(),t}sendSeekStart(t){if(this.state.goSeekStart()){let e;e=this.isAd()?w.Events.AD_SEEK_START:w.Events.CONTENT_SEEK_START,this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t)}}sendSeekEnd(t){if(this.state.goSeekEnd()){let e;t=t||{},this.isAd()?(e=w.Events.AD_SEEK_END,t.timeSinceAdSeekBegin=this.state.timeSinceSeekBegin.getDeltaTime()):(e=w.Events.CONTENT_SEEK_END,t.timeSinceSeekBegin=this.state.timeSinceSeekBegin.getDeltaTime()),this.isAd()?this.sendVideoAdAction(e,t):this.sendVideoAction(e,t)}}sendDownload(t){(t=t||{}).state||n.warn("Called sendDownload without { state: xxxxx }."),this.sendVideoAction(w.Events.DOWNLOAD,t),this.state.goDownload()}sendError(t){(t=t||{}).isAd=this.isAd(),this.state.goError();let e=this.isAd()?w.Events.AD_ERROR:w.Events.CONTENT_ERROR;this.sendVideoErrorAction(e,t)}sendRenditionChanged(t){(t=t||{}).timeSinceLastRenditionChange=this.state.timeSinceLastRenditionChange.getDeltaTime();const{oldBitrate:e,newBitrate:i}=t;let s;this.isAd()||void 0===e||void 0===i||(i>e?(t.shift="up",this.state.totalSwitchUps+=1):i<e?(t.shift="down",this.state.totalSwitchDowns+=1):t.shift=null),delete t.oldBitrate,delete t.newBitrate,s=this.isAd()?w.Events.AD_RENDITION_CHANGE:w.Events.CONTENT_RENDITION_CHANGE,this.isAd()?this.sendVideoAdAction(s,t):this.sendVideoAction(s,t),this.state.goRenditionChange()}sendHeartbeat(t){if(this.state.isRequested){let e,i=this.getHeartbeat();this.state._hb=!0,i=this.adjustElapsedTimeForPause(i),this.isAd()?(e=w.Events.AD_HEARTBEAT,"bitmovin-ads"===this.getPlayerName()?this.sendVideoAdAction(e,t):this.sendVideoAdAction(e,{elapsedTime:i,...t})):(e=w.Events.CONTENT_HEARTBEAT,this.sendVideoAction(e,{elapsedTime:i,...t})),this.state.goHeartbeat()}}adjustElapsedTimeForPause(t){return this.state._acc&&(t-=this.state._acc,this.state._acc=0),this.state.isPaused&&((t-=this.state.elapsedTime.getDeltaTime())<10&&(t=0),this.state.elapsedTime.start()),this.state._bufferAcc?(t-=this.state._bufferAcc,this.state._bufferAcc=0):this.state.isBuffering&&((t-=this.state.bufferElapsedTime.getDeltaTime())<5&&(t=0),this.state.bufferElapsedTime.start()),Math.max(0,t)}sendAdBreakStart(t){this.isAd()&&this.state.goAdBreakStart()&&(this.state.totalAdPlaytime=0,this.parentTracker&&(this.parentTracker.state.isPlaying=!1),this.sendVideoAdAction(w.Events.AD_BREAK_START,t))}sendAdBreakEnd(t){this.isAd()&&this.state.goAdBreakEnd()&&((t=t||{}).timeSinceAdBreakBegin=this.state.timeSinceAdBreakStart.getDeltaTime(),this.sendVideoAdAction(w.Events.AD_BREAK_END,t),this.parentTracker&&(this.parentTracker.state.isPlaying=!0),this.stopHeartbeat(),this.parentTracker&&this.isAd()&&this.parentTracker.state.goLastAd())}sendAdQuartile(t){this.isAd()&&((t=t||{}).quartile||n.warn("Called sendAdQuartile without { quartile: xxxxx }."),t.timeSinceLastAdQuartile=this.state.timeSinceLastAdQuartile.getDeltaTime(),this.sendVideoAdAction(w.Events.AD_QUARTILE,t),this.state.goAdQuartile())}sendAdClick(t){this.isAd()&&((t=t||{}).url||n.warn("Called sendAdClick without { url: xxxxx }."),this.sendVideoAdAction(w.Events.AD_CLICK,t))}}function N(t){t.type!==w.Events.AD_ERROR?this.sendVideoAdAction(t.type,t.data):this.sendVideoErrorAction(t.type,t.data)}w.Events={PLAYER_READY:"PLAYER_READY",DOWNLOAD:"DOWNLOAD",ERROR:"ERROR",CONTENT_REQUEST:"CONTENT_REQUEST",CONTENT_START:"CONTENT_START",CONTENT_END:"CONTENT_END",CONTENT_PAUSE:"CONTENT_PAUSE",CONTENT_RESUME:"CONTENT_RESUME",CONTENT_SEEK_START:"CONTENT_SEEK_START",CONTENT_SEEK_END:"CONTENT_SEEK_END",CONTENT_BUFFER_START:"CONTENT_BUFFER_START",CONTENT_BUFFER_END:"CONTENT_BUFFER_END",CONTENT_HEARTBEAT:"CONTENT_HEARTBEAT",CONTENT_RENDITION_CHANGE:"CONTENT_RENDITION_CHANGE",CONTENT_ERROR:"CONTENT_ERROR",AD_REQUEST:"AD_REQUEST",AD_START:"AD_START",AD_END:"AD_END",AD_PAUSE:"AD_PAUSE",AD_RESUME:"AD_RESUME",AD_SEEK_START:"AD_SEEK_START",AD_SEEK_END:"AD_SEEK_END",AD_BUFFER_START:"AD_BUFFER_START",AD_BUFFER_END:"AD_BUFFER_END",AD_HEARTBEAT:"AD_HEARTBEAT",AD_RENDITION_CHANGE:"AD_RENDITION_CHANGE",AD_ERROR:"AD_ERROR",AD_BREAK_START:"AD_BREAK_START",AD_BREAK_END:"AD_BREAK_END",AD_QUARTILE:"AD_QUARTILE",AD_CLICK:"AD_CLICK"};const C=w,{MAX_PAYLOAD_SIZE:I,MAX_EVENTS_PER_BATCH:O}=d;class P{constructor(){this.buffer=[],this.maxPayloadSize=I,this.maxEventsPerBatch=O,this.currentPayloadSize=0,this.totalEvents=0,this.smartHarvestPayloadThreshold=Math.floor(.6*this.maxPayloadSize),this.overflowPayloadThreshold=Math.floor(.9*this.maxPayloadSize),this.smartHarvestEventThreshold=Math.floor(.6*this.maxEventsPerBatch),this.overflowEventThreshold=Math.floor(.9*this.maxEventsPerBatch),this.onSmartHarvestTrigger=null}addOrReplaceByActionName(t,e){const i=this.buffer.findIndex(e=>e.actionName===t);try{return-1===i?this.add(e):this.add(e,i),!0}catch(t){return n.error("Failed to set or replace the event to buffer:",t.message),!1}}addOrReplaceByActionNameAndViewId(t,e,i){const s=this.buffer.findIndex(i=>i.actionName===t&&i.viewId===e);try{return-1===s?this.add(i):this.add(i,s),!0}catch(t){return n.error("Failed to set or replace the event to buffer:",t.message),!1}}findByActionNameAndViewId(t,e){return this.buffer.find(i=>i.actionName===t&&i.viewId===e)||null}findByActionName(t){return this.buffer.find(e=>e.actionName===t)||null}add(t,e){try{const i=T(t),s=this.currentPayloadSize+i>=this.maxPayloadSize,a=this.totalEvents+1>=this.maxEventsPerBatch;if((s||a)&&this.makeRoom(i),null!=e&&e>-1){const s=T(this.buffer[e]);this.buffer[e]=t,this.currentPayloadSize+=i-s}else this.buffer.push(t),this.totalEvents++,this.currentPayloadSize+=i;return this.checkSmartHarvestTrigger(),!0}catch(t){return n.error("Failed to add event to buffer:",t.message),!1}}checkSmartHarvestTrigger(){const t=this.currentPayloadSize/this.maxPayloadSize,e=this.totalEvents/this.maxEventsPerBatch,i=this.currentPayloadSize>=this.overflowPayloadThreshold,s=this.totalEvents>=this.overflowEventThreshold;if(i||s){const s=i?`payload ${this.currentPayloadSize}/${this.maxPayloadSize} bytes (${Math.round(100*t)}%)`:`events ${this.totalEvents}/${this.maxEventsPerBatch} (${Math.round(100*e)}%)`;n.warn(`OVERFLOW PREVENTION: ${s} - Emergency harvest triggered`),this.onSmartHarvestTrigger&&"function"==typeof this.onSmartHarvestTrigger&&this.onSmartHarvestTrigger("overflow",90)}else{const t=this.currentPayloadSize>=this.smartHarvestPayloadThreshold,e=this.totalEvents>=this.smartHarvestEventThreshold;(t||e)&&this.onSmartHarvestTrigger&&"function"==typeof this.onSmartHarvestTrigger&&this.onSmartHarvestTrigger("smart",60)}}setSmartHarvestCallback(t){this.onSmartHarvestTrigger=t}drain(){try{const t=this.buffer.splice(0);return this.totalEvents=0,this.currentPayloadSize=0,t}catch(t){return n.error("Failed to drain events from buffer:",t.message),[]}}isEmpty(){return 0===this.totalEvents}size(){return this.totalEvents}clear(){this.buffer=[],this.totalEvents=0}makeRoom(t){if(t>this.maxPayloadSize)n.error("Event dropped: Event size exceeds maximum payload size.");else for(;(this.totalEvents>=this.maxEventsPerBatch||this.currentPayloadSize+t>=this.maxPayloadSize)&&this.buffer.length>0;){const t=T(this.buffer.shift());this.totalEvents--,this.currentPayloadSize-=t,n.warn("Event buffer full, oldest event removed.")}}}const V={US:"US",EU:"EU",STAGING:"staging",GOV:"GOV"},L=[["newrelic_mobile_example","1.1","com.newrelic.newrelic_mobile_example"],["Android","14","sdk_gphone64_arm64","AndroidAgent","7.4.0-alpha01","b797aee6-aa69-4879-9ba3-1f4aed1a7777","","","Google",{size:"normal",platform:"Flutter",platformVersion:"1.0.8"}]],H=["Vega","1.0","VegaDevice","VegaAgent","1.0.0","00000000-0000-0000-0000-000000000000","","","Amazon",{size:"normal",platform:"Native",platformVersion:"1.0.0"}],x={osBuild:"1",osName:"Vega",platform:"Native",appBuild:"1",architecture:"aarch64"};function F(t,e){const i=t[e.viewId];if(!i)return!1;for(const t of d.QOE_KPI_KEYS)if(e[t]!==i[t])return!1;return!0}function G(t,e){const i={};for(const t of d.QOE_KPI_KEYS)i[t]=e[t];t[e.viewId]=i}class U{constructor({accountId:t,applicationToken:e,endpoint:i,deviceInfo:s}={}){if(!e)throw new Error("applicationToken is required");if(!Object.values(V).includes(i))throw new Error("Invalid endpoint");this.accountId=t,this.applicationToken=e,this.endpoint=i,this.harvestInterval=6e4,this.maxBufferSize=100,s||n.warn("ConnectedDeviceHarvester: no deviceInfo provided — using placeholder defaults. Pass info.deviceInfo for accurate device data.");const{uuid:a,osVersion:r,deviceModel:o,deviceManufacturer:d,osBuild:h,appBuild:l,architecture:c}=s??{};this.deviceInfo={uuid:a||H[5],osVersion:r||H[1],deviceModel:o||H[2],deviceManufacturer:d||H[8],osBuild:h||x.osBuild,appBuild:l||x.appBuild,architecture:c||x.architecture},this.eventBuffer=new P,this.eventBuffer.setSmartHarvestCallback((t,e)=>this.triggerSmartHarvest(t,e)),this.dataToken=null,this.isHarvesting=!1,this.isDisposed=!1,this._isFetchingToken=!1,this.timer=function({interval:t,onTick:e,errorLabel:i}){let s=!1,a=null,r=t;function o(){s&&(a=setTimeout(async()=>{a=null;try{await e()}catch(t){n.error(`${i}: scheduled tick failed:`,t.message)}finally{s&&o()}},r))}return{start(){s||(s=!0,o())},stop(){s=!1,a&&(clearTimeout(a),a=null)},cancelAndReschedule(){a&&(clearTimeout(a),a=null),s&&o()},updateInterval(t){"number"!=typeof t||t<=0||(r=t,s&&a&&(clearTimeout(a),a=null,o()))},isRunning:()=>s}}({interval:this.harvestInterval,onTick:()=>this.sendBufferedEvents(),errorLabel:"ConnectedDeviceHarvester"}),this.qoeCycleCount=1,this.forceQoeNextCycle=!1,this.beforeDrainCallback=null,this._lastSentQoeKpis={},this._connectAttempt=0,this.initialise()}getEndpointBaseUrl(){switch(this.endpoint){case V.EU:return"https://mobile-collector.eu01.nr-data.net/mobile";case V.STAGING:return"https://staging-mobile-collector.newrelic.com/mobile";case V.GOV:return"https://gov-mobile-collector.newrelic.com/mobile";default:return"https://mobile-collector.newrelic.com/mobile"}}async initialise(){await this.fetchDataTokens(),this.isDisposed||this.dataToken&&this.startHarvestInterval()}async fetchDataTokens(){if(!this._isFetchingToken){this._isFetchingToken=!0;try{for(let t=0;t<3;t++){if(this.isDisposed)return;const e=`${this.getEndpointBaseUrl()}/v5/connect`;try{n.notice(`ConnectedDeviceHarvester: POST ${e} (attempt ${t+1}/3)`);const i=await this._fetchWithTimeout(e,{method:"POST",headers:{"Content-Type":"application/json","X-App-License-Key":this.applicationToken},body:JSON.stringify(L)},1e4);if(!i.ok){let t="";try{t=await i.text()}catch(t){}throw new Error(`HTTP ${i.status} body=${t}`)}const s=await i.json();if(!s||!s.data_token)throw new Error("Missing data_token in connect response");return this.dataToken=s.data_token,this._connectAttempt=t+1,void n.notice("ConnectedDeviceHarvester: dataToken acquired")}catch(e){if(this._connectAttempt=t+1,n.error(`ConnectedDeviceHarvester: /v5/connect failed (attempt ${this._connectAttempt}/3):`,e.message),t>=2)return void n.error("ConnectedDeviceHarvester: Max retries reached — dataToken stays null");await new Promise(t=>setTimeout(t,1e4))}}}finally{this._isFetchingToken=!1}}}startHarvestInterval(){this.isDisposed||this.timer.start()}async triggerSmartHarvest(t,e){if(n.notice(`ConnectedDeviceHarvester: smart-harvest trigger (${t} at ${e}%)`),this.eventBuffer&&!this.eventBuffer.isEmpty())try{await this.sendBufferedEvents()}catch(e){n.error(`${t} smart-harvest failed:`,e.message)}finally{this.timer.cancelAndReschedule()}}addEvent(t){try{return function(t,e){return!!e&&(e.actionName===m.Events.QOE_AGGREGATE?e.viewId?t.addOrReplaceByActionNameAndViewId(m.Events.QOE_AGGREGATE,e.viewId,e):t.addOrReplaceByActionName(m.Events.QOE_AGGREGATE,e):t.add(e))}(this.eventBuffer,t)}catch(t){return n.error("ConnectedDeviceHarvester.addEvent failed:",t.message),!1}}forceQoeNextHarvest(){this.forceQoeNextCycle=!0}setBeforeDrainCallback(t){"function"!=typeof t&&null!==t||(this.beforeDrainCallback=t)}refreshQoeKpis(t,e){!function(t,e,i){if(!t||!e)return;const s=i?t.findByActionNameAndViewId(m.Events.QOE_AGGREGATE,i):t.findByActionName(m.Events.QOE_AGGREGATE);if(!s)return;const a={...s};for(const t of d.QOE_KPI_KEYS)t in e&&(a[t]=e[t]);i?t.addOrReplaceByActionNameAndViewId(m.Events.QOE_AGGREGATE,i,a):t.addOrReplaceByActionName(m.Events.QOE_AGGREGATE,a)}(this.eventBuffer,t,e)}setHarvestInterval(t){"number"!=typeof t||t<=0||(this.harvestInterval=t,this.timer.updateInterval(t))}async sendBufferedEvents(){if(this.isHarvesting)return;if(!this.dataToken)return;if(this.eventBuffer.isEmpty())return;if("function"==typeof this.beforeDrainCallback)try{this.beforeDrainCallback()}catch(t){n.error("ConnectedDeviceHarvester beforeDrainCallback failed:",t.message)}this.isHarvesting=!0;const t=this.eventBuffer.drain(),e=globalThis.__NRVIDEO_CD__?.config?.qoeIntervalFactor??1,i=this.forceQoeNextCycle,s=(this.qoeCycleCount-1)%e==0||i;this.forceQoeNextCycle&&(this.forceQoeNextCycle=!1);const a=function(t,e,i){if(e)return t;const s=[];for(const e of t)e.actionName===m.Events.QOE_AGGREGATE?i.add(e):s.push(e);return s}(t,s,this.eventBuffer);if(this.qoeCycleCount++,function(t,e,i){for(let s=t.length-1;s>=0;s--){const a=t[s];a.actionName===m.Events.QOE_AGGREGATE&&(!i&&F(e,a)?t.splice(s,1):G(e,a))}}(a,this._lastSentQoeKpis,i),0===a.length)return void(this.isHarvesting=!1);const r=`${this.getEndpointBaseUrl()}/v3/data`,o={"Content-Type":"application/json","X-App-License-Key":this.applicationToken},d=()=>{const t=JSON.stringify([this.dataToken,this._buildDeviceInfo(),0,[],[],[],[],[],this._buildMetadata(),a]);return e=t,i=globalThis.__NRVIDEO_CD__?.config?.obfuscate,i&&0!==i.length?i.reduce((t,e)=>{let i;try{if(e.regex instanceof RegExp){const t=e.regex.flags.includes("g")?e.regex.flags:e.regex.flags+"g";i=new RegExp(e.regex.source,t)}else i=new RegExp(e.regex,"g")}catch(i){return n.warn("applyObfuscationRules: invalid regex, skipping rule:",e.regex,i.message),t}return t.replace(i,e.replacement)},e):e;var e,i};try{let t=await this._fetchWithTimeout(r,{method:"POST",headers:o,body:d()},3e4);if(401===t.status){n.notice("ConnectedDeviceHarvester: /v3/data returned 401 — re-queuing events and reconnecting"),this.dataToken=null,this._connectAttempt=0;for(const t of a)this.eventBuffer.add(t);return void this.initialise()}if(!t.ok)throw new Error(`HTTP ${t.status}`);n.notice(`ConnectedDeviceHarvester: sent ${a.length} events`)}catch(t){n.error("ConnectedDeviceHarvester: /v3/data send failed:",t.message);for(const t of a)this.eventBuffer.add(t)}finally{this.isHarvesting=!1}}_buildDeviceInfo(){const t=this.deviceInfo;return[H[0],t.osVersion,t.deviceModel,H[3],H[4],t.uuid,"","",t.deviceManufacturer,H[9]]}_buildMetadata(){const t=this.deviceInfo;return{...x,osBuild:t.osBuild,appBuild:t.appBuild,architecture:t.architecture}}_fetchWithTimeout(t,e,i){const s=new AbortController,a=setTimeout(()=>s.abort(),i);return fetch(t,{...e,signal:s.signal}).finally(()=>clearTimeout(a))}async dispose(){return this.isDisposed=!0,this.timer.stop(),this.sendBufferedEvents()}}const q=new class{constructor(){this.isInitialized=!1,this.harvester=null}initialize(){if(this.isInitialized)return;const t=globalThis.__NRVIDEO_CD__?.info;if(t)try{this.harvester=new U(t),this.isInitialized=!0,n.notice("ConnectedDeviceAnalyticsAgent initialized")}catch(t){n.error("ConnectedDeviceAnalyticsAgent.initialize failed:",t.message)}else n.warn("ConnectedDeviceAnalyticsAgent.initialize: globalThis.__NRVIDEO_CD__.info is missing")}addEvent(t){return this.isInitialized||this.initialize(),!!this.isInitialized&&this.harvester.addEvent(t)}forceQoeNextHarvest(){this.harvester&&this.harvester.forceQoeNextHarvest()}forceNextQoeCycle(){this.forceQoeNextHarvest()}setBeforeDrainCallback(t){this.harvester&&this.harvester.setBeforeDrainCallback(t)}refreshQoeKpis(t,e){this.isInitialized||this.initialize(),this.harvester&&this.harvester.refreshQoeKpis(t,e)}setHarvestInterval(t){this.isInitialized||this.initialize(),this.harvester&&this.harvester.setHarvestInterval(t)}};var Q;Q=q,E["Vega"]=Q;const M=q,z={Constants:d,Chrono:u,Log:n,Emitter:l,Tracker:m,VideoTracker:C,VideoTrackerState:k,Core:D,version:h.rE,NrVideoEventAggregator:P,ConnectedDeviceHarvester:U,recordEvent:v};module.exports=e})();
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,6 @@
1
+ /*!
2
+ * @license Apache-2.0
3
+ * @newrelic/video-core 5.0.0
4
+ * Copyright New Relic <http://newrelic.com/>
5
+ * @author Jordi Aguilar
6
+ */