senza-sdk 4.0.4 → 4.0.5

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/dist/bundle.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.senza=t():e.senza=t()}(this,(()=>(()=>{"use strict";var e={d:(t,n)=>{for(var i in n)e.o(n,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:n[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{ClientAssertionError:()=>j,ConnectReason:()=>C,alarmManager:()=>b,auth:()=>A,deviceManager:()=>v,envInfo:()=>z,getClientAssertion:()=>V,getConnectReason:()=>D,getDeviceInfo:()=>x,getPlatformInfo:()=>J,getTriggerEvent:()=>Q,init:()=>R,isRunningE2E:()=>M,lifecycle:()=>c,messageManager:()=>k,platformManager:()=>S,remotePlayer:()=>m,setTimezone:()=>X,uiReady:()=>U,writeLicenseResponse:()=>G});var n={};e.r(n),e.d(n,{ClientAssertionError:()=>j,ConnectReason:()=>C,alarmManager:()=>b,auth:()=>A,deviceManager:()=>v,envInfo:()=>z,getClientAssertion:()=>V,getConnectReason:()=>D,getDeviceInfo:()=>x,getPlatformInfo:()=>J,getTriggerEvent:()=>Q,init:()=>R,isRunningE2E:()=>M,lifecycle:()=>c,messageManager:()=>k,platformManager:()=>S,remotePlayer:()=>m,setTimezone:()=>X,uiReady:()=>U,writeLicenseResponse:()=>G});const i={version:"4.0.4"},{version:s}=i;function o(){return Math.round(1e5*Math.random())+"-"+J().sessionInfo?.connectionId}class r{constructor(e){this.logFields=e}debug(...e){console.debug(this.formatLogString(e))}log(...e){console.log(this.formatLogString(e))}info(...e){console.info(this.formatLogString(e))}warn(...e){console.warn(this.formatLogString(e))}error(...e){console.error(this.formatLogString(e))}withFields(e){return new r({...this.logFields,...e})}formatLogString(e){let t="[hs-sdk] "+e.join(" ");return this.logFields&&(t+=" [log-fields] "+JSON.stringify(this.logFields)),t}}const a=new r({sdkVersion:s,url:window?.location?.href??""}),d=new class{sessionInfoStr="{}";get sessionInfoObj(){try{return JSON.parse(this.sessionInfoStr)}catch(e){return void a.warn("Failed to return sdk")}}setSessionInfoStr(e){try{JSON.parse(e)}catch(e){throw Error("Failed to parse sessionInfo")}this.sessionInfoStr=e}};class l extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/uistatechange",(e=>{a.log("Got hs/uistatechange",e.detail);const t=new Event("onstatechange");t.state=e.detail,this.dispatchEvent(t)}))}getState(){if(window.cefQuery)return new Promise(((e,t)=>{window.cefQuery&&window.cefQuery({request:"uiState",persistent:!1,onSuccess:t=>{a.log(`uiState request successfully returned '${t}'`),e(t)},onFailure:(e,n)=>{a.error(`uiState request failed: ${e} ${n}`),t(n)}})}));a.warn("lifecycle getState is not supported if NOT running e2e")}moveToForeground(){if(window.cefQuery){const e=o(),t=a.withFields({FCID:e});t.log("lifecycle moveToForeground: sending uiActiveRequest action"),window.cefQuery({request:JSON.stringify({action:"uiActiveRequest",fcid:e}),persistent:!1,onSuccess:()=>{t.log("uiActiveRequest successfully sent")},onFailure:(e,n)=>{t.error(`uiActiveRequest failed: ${e} ${n}`)}})}else a.error("lifecycle moveToForeground: window.cefQuery is undefined")}moveToBackground(){if(window.cefQuery){const e=o(),t=a.withFields({FCID:e});t.log("lifecycle moveToBackground: sending play action");const n=m.getConfiguration(),i=m._selectedAudioTrack||n.preferredAudioLanguage||"",s=m._selectedSubtitlesTrack||n.preferredSubtitlesLanguage||"";window.cefQuery({request:JSON.stringify({action:"play",fcid:e,audioLanguage:i,subtitlesLanguage:s}),persistent:!1,onSuccess:()=>{t.log("[ moveToBackground ] play successfully sent")},onFailure:(e,n)=>{t.error(`[ moveToBackground ] play failed: ${e} ${n}`)}})}else a.error("lifecycle moveToBackground: window.cefQuery is undefined")}switchTenant(e){if(e&&e.length>0){if(e===J().sessionInfo?.tenantId)return a.warn(`SwitchTenant requires a different tenantId than the current one. CurrentTenantId=${J().sessionInfo?.tenantId} and tenantId=${e}`),Promise.reject("SwitchTenant requires a different tenantId than the current one");const t=J().sessionInfo?.homeSessionInfo?.tenantInfo?.contentHubTenantId,n=J().sessionInfo?.homeSessionInfo?.tenantId;return a.log(`SwitchTenant for ${e}`),window.cefQuery?new Promise(((i,s)=>{const r=o(),d=a.withFields({FCID:r}),l={type:"reconnect",fcid:r,session:btoa(JSON.stringify({tenantId:e,...J().sessionInfo?.tenantId===t&&e!==n&&{returnToTenantId:t}}))},c={target:"TC",waitForResponse:!1,message:JSON.stringify(l)};window.cefQuery({request:JSON.stringify(c),persistent:!1,onSuccess:()=>{d.log("SwitchTenant request successfully sent"),i(!0)},onFailure:(e,t)=>{d.error(`SwitchTenant failed: ${e} ${t}`),s(`SwitchTenant failed: ${e} ${t}`)}})})):(a.warn("SwitchTenant is not supported if NOT running e2e"),Promise.reject("SwitchTenant is not supported if NOT running e2e"))}return a.warn("SwitchTenant requires a valid tenantId string parameter"),Promise.reject("SwitchTenant requires a valid tenantId string parameter")}exitApplication(){return window.cefQuery?new Promise(((e,t)=>{const n=o(),i=a.withFields({FCID:n});let s,r;const l=d.sessionInfoObj;l?.homeSessionInfo&&(l?.returnToTenantId||l?.homeSessionInfo.tenantId!==l?.tenantId)?(r={type:"reconnect",splashUrl:l?.homeSessionInfo.tenantInfo.tenantSettings.applicationSwitchSplashUrl,fcid:n},l?.returnToTenantId&&(l?.returnToTenantId===l?.homeSessionInfo.tenantInfo.contentHubTenantId&&(r.splashUrl=l?.homeSessionInfo.contentHubTenantInfo.tenantSettings.applicationSwitchSplashUrl),r.session=btoa(JSON.stringify({tenantId:l?.returnToTenantId}))),s={target:"TC",waitForResponse:!1,message:JSON.stringify(r)}):(r={type:"launchHomeApplication",fcid:n},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(r)}),window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:()=>{i.log(`exitApplication request with type: '${r.type}' successfully sent`),e(!0)},onFailure:(e,n)=>{i.error(`exitApplication request with type: '${r.type}' failed: ${e} ${n}`),t(`exitApplication request with type: '${r.type}' failed: ${e} ${n}`)}})})):(a.warn("exitApplication is not supported if NOT running e2e"),Promise.reject("exitApplication is not supported if NOT running e2e"))}}const c=new l,u=e=>JSON.parse(JSON.stringify(e));class f extends Error{constructor(e,t){super(t),this.code=e,this.msg=t}}function g(){const e=window.getPlaybackInfo?window.getPlaybackInfo():JSON.stringify({playbackPosition:0,assetDuration:0});let t;try{t=JSON.parse(e)}catch(n){a.error(`Playback Info parse failed. playbackStr = ${e}`),t={playbackPosition:0,assetDuration:0}}return t}function y(e){try{const t=JSON.stringify(e);window.setPlaybackInfo&&window.setPlaybackInfo(t)}catch(e){a.error("Playback Info to json string failed")}}class w extends EventTarget{constructor(){super(),this._config={preferredAudioLanguage:"",preferredSubtitlesLanguage:""},this._selectedAudioTrack="",this._selectedSubtitlesTrack="",this._availableAudioTracks=[],this._availableTextTracks=[],this._textTrackVisibility=!1,this._ptsSessionId=0,this._videoElement=void 0,this._isInitialized=!1,"undefined"!=typeof document&&document.addEventListener("hs/playbackInfoEvent",(()=>{a.info("Got hs/playbackInfoEvent"),this.dispatchEvent(new Event("timeupdate"))})),"undefined"!=typeof document&&document.addEventListener("hs/playback",(e=>{a.info("Got hs/playback event with detail",JSON.stringify(e?.detail)),this._availabilityStartTime=e?.detail?.availabilityStartTime,this._updateTracks(e?.detail),this.dispatchEvent(new Event("tracksupdate"))})),"undefined"!=typeof document&&document.addEventListener("hs/EOS",(()=>{a.info("Got hs/EOS event"),this.dispatchEvent(new Event("ended"))})),"undefined"!=typeof document&&document.addEventListener("hs/ui_inactive",(()=>{a.info("Got hs/ui_inactive event")})),"undefined"!=typeof document&&document.addEventListener("hs/senzaPlayerSetRate",(e=>{this._videoElement&&(this._videoElement.playbackRate=e.detail.rate)})),"undefined"!=typeof document&&document.addEventListener("hs/senzaPlayerSetTime",(e=>{this._videoElement?(a.info(`Adding ${e.detail} seconds to current time ${this._videoElement.currentTime}`),this._videoElement.playbackRate=1,this._videoElement.currentTime+=e.detail):a.warn("video element is NOT set")})),"undefined"!=typeof document&&document.addEventListener("hs/ERR",(e=>{a.info("Got hs/ERR event"),delete e?.detail?.type,delete e?.detail?.eventCode,this.dispatchEvent(new CustomEvent("error",e))})),"undefined"!=typeof document&&document.addEventListener("hs/getLicense",(e=>{a.info("Got hs/getLicense event");const t=e?.detail,n=Uint8Array.from(t.request,(e=>e.charCodeAt(0))),i=new ArrayBuffer(n.byteLength);new Uint8Array(i).set(n),this.licenseRequest=i;const s=t.fcid,o=t.sessionId,r=new CustomEvent("license-request",{detail:{licenseRequest:i}});r.writeLicenseResponse=(e,t)=>{G(e,t,s,o)},this.dispatchEvent(r)}))}LoadMode=Object.freeze({NOT_LOADED:"notLoaded",LOADING:"loading",LOADED:"loaded",UNLOADING:"unloading"});async _init(e,t){let n={isLoaded:!1,playbackUrl:""};if(window.cefQuery){const e=o(),t=a.withFields({FCID:e}),i={type:"playerState",fcid:e},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};try{const e=await new Promise(((e,n)=>{window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:n=>{t.log("playerState request successfully returned",n),e(n)},onFailure:(e,i)=>{t.error(`playerState request failed: ${e} ${i}`),n()}})}));n=JSON.parse(e)}catch{t.error("either failed to get or failed to parse player state")}}this._loadMode=n?.isLoaded?this.LoadMode.LOADED:this.LoadMode.NOT_LOADED,this._loadedUrl=n?.playbackUrl||"",this._isInitialized=!0,this._setPlayableUriTimeout=e?.setPlayableUriTimeout??5e3,this._unloadTimeout=e?.unloadTimeout??5e3,this._requestVideoFrameInfo=e?.requestVideoFrameInfo??!0;let i={};try{i=JSON.parse(t?.playbackMetadata||"{}")}catch(e){a.error(`failed to parse playbackMetadata: ${e.message}`)}this._availabilityStartTime=i.availabilityStartTime,this._updateTracks(i)}_updateTracks(e){if(this._availableAudioTracks=e?.availableAudioTracks||this._availableAudioTracks,this._availableTextTracks=e?.availableSubtitlesTracks||this._availableTextTracks,"VOD"===e?.assetType&&(this._availableTextTracks=function(e){if(!e||e.length<1)return e;e.sort(((e,t)=>e.lang.toLowerCase()>t.lang.toLowerCase()?1:-1));const t=[{lang:"af",id:"*:af"},{lang:"ar",id:"*:ar"},{lang:"az",id:"*:az"},{lang:"bg",id:"*:bg"},{lang:"bs",id:"*:bs"},{lang:"ca",id:"*:ca"},{lang:"cs",id:"*:cs"},{lang:"cy",id:"*:cy"},{lang:"da",id:"*:da"},{lang:"de",id:"*:de"},{lang:"el",id:"*:el"},{lang:"en",id:"*:en"},{lang:"es",id:"*:es"},{lang:"es-MX",id:"*:es-MX"},{lang:"et",id:"*:et"},{lang:"fi",id:"*:fi"},{lang:"fr",id:"*:fr"},{lang:"fr-CA",id:"*:fr-CA"},{lang:"ga",id:"*:ga"},{lang:"ha",id:"*:ha"},{lang:"he",id:"*:he"},{lang:"hr",id:"*:hr"},{lang:"ht",id:"*:ht"},{lang:"hu",id:"*:hu"},{lang:"id",id:"*:id"},{lang:"is",id:"*:is"},{lang:"it",id:"*:it"},{lang:"kk",id:"*:kk"},{lang:"lt",id:"*:lt"},{lang:"lv",id:"*:lv"},{lang:"mk",id:"*:mk"},{lang:"mn",id:"*:mn"},{lang:"ms",id:"*:ms"},{lang:"mt",id:"*:mt"},{lang:"nl",id:"*:nl"},{lang:"no",id:"*:no"},{lang:"pl",id:"*:pl"},{lang:"pt",id:"*:pt"},{lang:"pt-PT",id:"*:pt-PT"},{lang:"ro",id:"*:ro"},{lang:"ru",id:"*:ru"},{lang:"sk",id:"*:sk"},{lang:"sl",id:"*:sl"},{lang:"so",id:"*:so"},{lang:"sq",id:"*:sq"},{lang:"sr",id:"*:sr"},{lang:"sv",id:"*:sv"},{lang:"sw",id:"*:sw"},{lang:"tl",id:"*:tl"},{lang:"tr",id:"*:tr"},{lang:"uk",id:"*:uk"},{lang:"uz",id:"*:uz"},{lang:"vi",id:"*:vi"},{lang:"zh",id:"*:zh"}],n=[...e];for(const i of t)e.find((e=>e.lang===i.lang))||(i.autoTranslate=!0,n.push(i));return n}(this._availableTextTracks)),this._availableAudioTracks){const e=this._availableAudioTracks.find((e=>!0===e.selected));this._selectedAudioTrack=e?.id||""}if(this._availableTextTracks){const e=this._availableTextTracks.find((e=>!0===e.selected));e?(this._selectedSubtitlesTrack=e.id,this._textTrackVisibility=!0):(this._selectedSubtitlesTrack="",this._textTrackVisibility=!1)}}getConfiguration(){return u(this._config)}configure(e){Object.entries(e).forEach((([e,t])=>{void 0!==this._config[e]&&(this._config[e]=t)}))}_changeLoadMode(e){this._loadMode!==e&&(this._loadMode=e,this.dispatchEvent(new Event("onloadmodechange")))}_handle_video_frame_info(e){if(!this._requestVideoFrameInfo||void 0===e)return void(this._videoElement=void 0);const t=o(),n=a.withFields({fcid:t}),i=(e,n)=>{const s={type:"currentFramePTS",fcid:t,currentFramePTS:n.mediaTime.toString(),ptsSessionId:this._ptsSessionId},o={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(o),persistent:!1}),this._videoElement?.requestVideoFrameCallback(i)};n.log("handle_video_frame_pts: requesting video frame info"),void 0!==this._videoElement&&this._videoElement===e||(e.requestVideoFrameCallback(i),e.addEventListener("loadstart",(e=>{this._ptsSessionId++,a.info("videoElement, loadstart ptsSessionId=",this._ptsSessionId," event=",e)}))),this._videoElement=e}_reset(){this._availableAudioTracks=[],this._availableTextTracks=[],this._selectedAudioTrack="",this._selectedSubtitlesTrack="",this._availabilityStartTime=void 0}registerVideoElement(e){this.attach(e)}attach(e){this._handle_video_frame_info(e)}async load(e,t){if(!this._isInitialized)throw new f(6500,"Cannot call load() if remote player is not initialized");if(e&&window.cefQuery){const n=await c.getState();if("background"===n||"inTransitionToBackground"===n)throw new f(6002,"Cannot call load() while in state 'background' or 'inTransitionToBackground'");if(this._loadMode===this.LoadMode.LOADING)throw new f(6501,"Cannot call load() while previous load is still in progress");this._reset();const i=this._loadMode;return this._changeLoadMode(this.LoadMode.LOADING),new Promise(((n,s)=>{y({playbackPosition:0});const r=o(),d=t??0,l=a.withFields({FCID:r,loadUrl:e,playbackPosition:d});l.log("remotePlayer load: sending setPlayableUri request");const c={type:"setPlayableUri",url:e,timeout:this._setPlayableUriTimeout,autoPlay:!1,playbackPosition:d,fcid:r},u={target:"TC",waitForResponse:!0,message:JSON.stringify(c)};let g=0;const w=Date.now(),m=window.cefQuery({request:JSON.stringify(u),persistent:!1,onSuccess:()=>{const i=Date.now()-w;l.withFields({duration:i}).log(`setPlayableUri completed successfully after ${i} ms`),t>0&&y({playbackPosition:t}),g&&(clearTimeout(g),g=0),this._changeLoadMode(this.LoadMode.LOADED),this._loadedUrl=e,this.dispatchEvent(new Event("canplay")),n()},onFailure:(e,t)=>{const n=Date.now()-w;l.withFields({duration:n}).log(`setPlayableUri failed after ${n} ms. Error code: ${e}, error message: ${t}`),g&&(clearTimeout(g),g=0),99===e?this._changeLoadMode(i):(this._changeLoadMode(this.LoadMode.NOT_LOADED),this._loadedUrl=""),s(new f(e,t))}});l.log(`window.cefQuery for setPlayableUri returned query id ${m}`);const p=this._setPlayableUriTimeout+1e3;g=setTimeout((()=>{l.log(`setPlayableUri reached timeout of ${p} ms, canceling query id ${m}`),window.cefQueryCancel(m),this._changeLoadMode(this.LoadMode.NOT_LOADED),this._loadedUrl="",s(new f(6e3,`load reached timeout of ${p} ms`))}),p,m)}))}a.error("remotePlayer load: either window.cefQuery or url is undefined")}async unload(){if(!this._isInitialized)throw new f(6500,"Cannot call unload() if remote player is not initialized");if(window.cefQuery){if(this._loadMode===this.LoadMode.LOADING)throw new f(6502,"Cannot call unload() while load is still in progress");const e=this._loadMode;return this._changeLoadMode(this.LoadMode.UNLOADING),new Promise(((t,n)=>{const i=o(),s=a.withFields({FCID:i});s.log("remotePlayer unload");const r={type:"remotePlayer.unload",class:"remotePlayer",action:"unload",fcid:i},d={target:"TC",waitForResponse:!0,message:JSON.stringify(r)};let l=0;const c=Date.now(),u=window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{const e=Date.now()-c;s.withFields({duration:e}).log(`unload completed successfully after ${e} ms`),l&&(clearTimeout(l),l=0),this._reset(),this._changeLoadMode(this.LoadMode.NOT_LOADED),this._loadedUrl=void 0,t()},onFailure:(t,i)=>{const o=Date.now()-c;s.withFields({duration:o}).log(`unload failed after ${o} ms. Error code: ${t}, error message: ${i}`),l&&(clearTimeout(l),l=0),this._changeLoadMode(e),n(new f(t,i))}});s.log(`window.cefQuery for unload returned query id ${u}`);const g=this._unloadTimeout+1e3;l=setTimeout((()=>{s.log(`unload reached timeout of ${g} ms, canceling query id ${u}`),window.cefQueryCancel(u),this._changeLoadMode(e),n(new f(6e3,`unload reached timeout of ${g} ms`))}),g,u)}))}a.error("remotePlayer unload: window.cefQuery is undefined")}play(){if(!this._isInitialized)throw new f(6500,"Cannot call play() if remote player is not initialized");if(window.cefQuery){if(this._loadMode!==this.LoadMode.LOADED)throw new f(6001,"Cannot call play() if player is not loaded");const e=o(),t=a.withFields({FCID:e});t.log("remotePlayer play: sending play action");const n=this._selectedAudioTrack||this._config.preferredAudioLanguage||"";let i="";this._textTrackVisibility&&(i=this._selectedSubtitlesTrack||this._config.preferredSubtitlesLanguage||"");const s={type:"remotePlayer.play",class:"remotePlayer",action:"play",fcid:e,audioLanguage:n,subtitlesLanguage:i,playbackPosition:this.currentTime},r={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};return new Promise(((e,n)=>{window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{t.log("remotePlayer play request successfully sent"),e()},onFailure:(e,i)=>{t.error(`remotePlayer play request failed: ${e} ${i}`),n(new f(e,i))}})}))}return a.error("remotePlayer play: window.cefQuery is undefined"),Promise.resolve(void 0)}pause(){if(!this._isInitialized)throw new f(6500,"Cannot call pause() if remote player is not initialized");if(window.cefQuery){if(this._loadMode!==this.LoadMode.LOADED)throw new f(6001,"Cannot call pause() if player is not loaded");const e=o(),t=a.withFields({FCID:e});t.log("remotePlayer pause: sending pause request");const n={type:"remotePlayer.pause",class:"remotePlayer",action:"pause",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};return new Promise(((e,n)=>{window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("remotePlayer pause request successfully sent"),e()},onFailure:(e,i)=>{t.error(`remotePlayer pause request failed: ${e} ${i}`),n(new f(e,i))}})}))}return a.error("remotePlayer pause: window.cefQuery is undefined"),Promise.resolve(void 0)}getAssetUri(){if(!this._isInitialized)throw new f(6500,"Cannot call getAssetUri() if remote player is not initialized");return this._loadedUrl}getLoadMode(){if(!this._isInitialized)throw new f(6500,"Cannot call getLoadMode() if remote player is not initialized");return this._loadMode}getTextTracks(){return u(this._availableTextTracks)}getAudioTracks(){return u(this._availableAudioTracks)}selectAudioTrack(e){for(const t of this.getAudioTracks())if(t.id===e)return void(this._selectedAudioTrack=e);a.warn(`Invalid audioTrackId ${e}`)}selectTextTrack(e){for(const t of this.getTextTracks())if(t.id===e)return void(this._selectedSubtitlesTrack=e);a.warn(`Invalid textTrackId ${e}`)}setTextTrackVisibility(e){const t=this._textTrackVisibility;if("boolean"!=typeof e)throw new TypeError("visible parameter must be a boolean");const n=e;n!==t&&(this._textTrackVisibility=n,n||(this._selectedSubtitlesTrack=""))}get currentTime(){return g()?.playbackPosition}set currentTime(e){if(y({playbackPosition:e}),window.cefQuery){const t=o(),n=a.withFields({FCID:t});n.log("setting remotePlayer currentTime");const i={type:"remotePlayer.seek",class:"remotePlayer",action:"seek",playbackPosition:e,fcid:t},s={target:"TC",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:()=>{n.log("remotePlayer seek request successfully sent")},onFailure:(e,t)=>{n.error(`remotePlayer seek request failed: ${e} ${t}`)}})}else a.error("setting remotePlayer currentTime: window.cefQuery is undefined")}get duration(){return g()?.assetDuration}get textTrackVisibility(){return this._textTrackVisibility}getPresentationStartTimeAsDate(){return void 0===this._availabilityStartTime?null:new Date(1e3*this._availabilityStartTime)}}const m=new w;"undefined"!=typeof window&&(window.remotePlayer=m);const p={};class h extends EventTarget{constructor(){super(),p.level=0,p.quality=0,p.ssid="unknown",p.bssid="unknown","undefined"!=typeof document&&document.addEventListener("wifiSignalReport",(e=>{a.log("Got wifiSignalReport",JSON.stringify(e.detail)),p.level=e.detail.level,p.quality=e.detail.quality,p.ssid=e.detail.ssid,p.bssid=e.detail.bssid,this.dispatchEvent(new Event("wifiInfoUpdated"))}))}get deviceInfo(){const e=d.sessionInfoObj;return M()&&e?{deviceId:e.deviceId,connectionId:e.connectionId,community:e.community,tenant:e.tenant,clientIp:e.clientIp,countryCode:e.general?.location?.["x-country-code"]}:(a.log("getDeviceInfo running locally, returning dummy info"),{deviceId:"123456789",connectionId:"dummy",community:"LocalDev",tenant:"XXXXXX",clientIp:"0.0.0.0",countryCode:"XX"})}get wifiInfo(){return p}reboot(){return new Promise(((e,t)=>{if(window.cefQuery){const n=o(),i=a.withFields({FCID:n}),s={type:"reboot",fcid:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{i.log("reboot request successfully sent"),e(!0)},onFailure:(e,n)=>{i.error(`reboot failed: ${e} ${n}`),t(`reboot failed: ${e} ${n}`)}})}else a.warn("reboot is not supported if NOT running e2e"),t("reboot is not supported if NOT running e2e")}))}clearWifi(){return new Promise(((e,t)=>{const n=o(),i=a.withFields({FCID:n}),s={type:"resetWifi",fcid:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{i.log("clearWifi successfully sent"),e(!0)},onFailure:(e,n)=>{i.error(`clearWifi failed: ${e} ${n}`),t(`clearWifi failed: ${e} ${n}`)}})}))}sendDataToDevice(e){if("string"!=typeof e)throw new Error("data must be of type 'string'");return new Promise(((t,n)=>{const i=o(),s=a.withFields({FCID:i}),r={type:"externalCommand",data:{command:"forward",payload:e},fcid:i},d={target:"TC",waitForResponse:!1,message:JSON.stringify(r)};window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{s.log("externalCommand successfully sent"),t()},onFailure:(e,t)=>{s.error(`externalCommand failed: ${e} ${t}`),n(`externalCommand failed: ${e} ${t}`)}})}))}async factoryReset(e=!0){if("boolean"!=typeof e)throw new Error("reboot param must be of type 'boolean'");return new Promise(((t,n)=>{const i=o(),s=a.withFields({FCID:i}),r={type:"factoryReset",fcid:i,reboot:e},d={target:"TC",waitForResponse:!0,message:JSON.stringify(r)};let l=0;const c=window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{l&&clearTimeout(l),s.log("factoryReset successfully sent"),t(!0)},onFailure:(e,t)=>{l&&clearTimeout(l),s.error(`factoryReset failed: ${e} ${t}`),n(`factoryReset failed: ${e} ${t}`)}});l=setTimeout((()=>{s.error("factoryReset failed: reached timeout of 5000 ms"),window.cefQueryCancel(c),n("factoryReset failed: reached timeout of 5000 ms")}),5e3)}))}}const v=new h;class T extends EventTarget{constructor(){super()}get appConfig(){const e=d.sessionInfoObj,t=e.homeSessionInfo?.appConfig||{};return a.info("PlatformManager get appConfig: \n"+JSON.stringify(t,null,2)),t}setTimezone(e){if(window.cefQuery){const t={message:JSON.stringify({type:"setTimeZone",timezone:e}),waitForResponse:!1,target:"UI-Streamer"};window.cefQuery({request:JSON.stringify(t),persistent:!1,onSuccess:()=>{a.log("PlatformManager timezome is successfully set to",e)},onFailure:(t,n)=>{a.error(`PlatformManager error occurred setting timezone to ${e}: ${t} ${n}`)}})}}}const S=new T;class I extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/alarmFiredEvent",(e=>{a.log("Got hs/alarmFiredEvent",JSON.stringify(e.detail)),e.detail?.alarmName&&this.dispatchEvent(new CustomEvent(e.detail.alarmName,{detail:e.detail.payload}))}))}addAlarm(e,t,n=""){if("string"!=typeof n)throw Error("data must be a string");const i=o(),s=a.withFields({alarmName:e,FCID:i});if(s.log(`addAlarm called for ${e} to be fired at ${t}`),window.cefQuery){const o={type:"addAlarm",fcid:i,alarmName:e,alarmTime:t,payload:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(o)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{s.log("addAlarm request successfully sent")},onFailure:(e,t)=>{s.error(`addAlarm failed: ${e} ${t}`)}})}else s.warn("addAlarm is not supported if NOT running e2e")}deleteAlarm(e){const t=o(),n=a.withFields({alarmName:e,FCID:t});if(n.log(`deleteAlarm called for ${e}`),window.cefQuery){const i={type:"deleteAlarm",fcid:t,alarmName:e},s={target:"TC",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:()=>{n.log("deleteAlarm request successfully sent")},onFailure:(e,t)=>{n.error(`deleteAlarm failed: ${e} ${t}`)}})}else n.warn("deleteAlarm is not supported if NOT running e2e")}deleteAllAlarms(){if(window.cefQuery){const e=o(),t=a.withFields({FCID:e}),n={type:"deleteAllAlarms",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("deleteAllAlarms request successfully sent")},onFailure:(e,n)=>{t.error(`deleteAllAlarms failed: ${e} ${n}`)}})}else a.warn("deleteAllAlarms is not supported if NOT running e2e")}getActiveAlarms(){throw Error("NOT IMPLEMENTED")}}const b=new I;"undefined"!=typeof window&&(window.alarmManager=b);class _ extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/externalEvent",(e=>{a.log("Got hs/externalEvent",JSON.stringify(e.detail)),this.dispatchEvent(new CustomEvent("message",{detail:{eventName:e.detail.eventName,payload:e.detail.payload,fcid:e.detail.fcid}}))}))}async registerGroups(e){return a.log(`register called for ${e}`),new Promise(((t,n)=>{if(window.cefQuery){const i=o(),s=a.withFields({FCID:i}),r={type:"registerGroupEvent",fcid:i,groups:e},d={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(r)};window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{s.log("registerGroupEvent request successfully sent"),t(!0)},onFailure:(e,t)=>{s.error(`registerGroupEvent failed: ${e} ${t}`),n(`registerGroupEvent failed: ${e} ${t}`)}})}else a.warn("registerGroupEvent is not supported if NOT running e2e"),n("registerGroupEvent is not supported if NOT running e2e")}))}}const k=new _;let O,E;"undefined"!=typeof window&&(window.messageManager=k),c.getState()?.then((e=>{E=e})),c.addEventListener("onstatechange",(e=>{E=e.state}));const N=e=>{"background"!==E&&"inTransitionToBackground"!==E||(O&&clearTimeout(O),O=setTimeout((()=>{"background"!==E&&"inTransitionToBackground"!==E||a.log(`${e.type} event received while in '${E}' state and there was no call to lifecycle.moveToForeground() for 500 ms. Make sure to call it if you want to move to foreground.`),O=0}),500))};"undefined"!=typeof document&&document.addEventListener("keydown",N),m.addEventListener("error",N),m.addEventListener("ended",N);const{version:F}=i;let $;const P="1.0";"undefined"!=typeof document&&document.addEventListener("keydown",(e=>{a.log(`Got ${e.key} key`)}));const A={getToken:async function(){return $?Promise.resolve($):(a.log("getToken wait for promise updateSession event"),new Promise((e=>{document.addEventListener("updateSession",(t=>{$=t.detail?.updateObj,a.log(`onUpdateSessionEvent: token= ${$}`),e($)}),{once:!0})})))},forceTokenUpdate:function(){if($=null,window.cefQuery){const e=o(),t=a.withFields({FCID:e});t.log("forceTokenUpdate: sending updateSessionRequest");const n={type:"updateSessionRequest",updateKey:"authorization",parentPath:"settings.webUI.backendHeaders.Authorization",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("updateSessionRequest successfully sent")},onFailure:(e,n)=>{t.error(`updateSessionRequest failed: ${e} ${n}`)}})}else a.error("forceTokenUpdate: window.cefQuery is undefined")},getClientAssertion:V},C=Object.freeze({UNKNOWN:"unknown",INITIAL_CONNECTION:"initial_connection",UI_RELEASE:"ui_release",UI_TERMINATION:"ui_termination",WEBRTC_ERROR:"webrtc_error",UI_WATCHDOG:"ui_watchdog"});let L=C.UNKNOWN,q={};async function R(){if(a.log(`init ${F}`),window.diagnostics||a.error("[ init ] window.diagnostics is undefined"),window.cefQuery){await new Promise(((e,t)=>{window.cefQuery({request:"apiVersion "+P,persistent:!1,onSuccess:()=>{a.log("api version compatability check succeeded"),e()},onFailure:(e,n)=>{a.error("api version compatability check failed: "+n),t(n)}})}));const e=await new Promise((e=>{window.cefQuery({request:"sessionInfo",persistent:!1,onSuccess:t=>{a.log("sessionInfo request successfully returned "+t),e(t)},onFailure:(e,t)=>{a.error(`sessionInfo request failed: ${e} ${t}`)}})}));d.setSessionInfoStr(e);const t=JSON.parse(e);$=t?.settings?.webUI?.backendHeaders?.Authorization,a.log(`authToken: token = ${$}`),document.addEventListener("updateSession",(e=>{$=e.detail?.updateObj,a.log(`onUpdateSessionEvent: token = ${$}`)})),L=await new Promise((e=>{const t=o(),n=a.withFields({FCID:t}),i={type:"connectReason",fcid:t},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:t=>{n.log(`connectReason request successfully returned '${t}'`),e(t)},onFailure:(t,i)=>{n.error(`connectReason request failed: ${t} ${i}`),e(C.UNKNOWN)}})}));const n=await new Promise((e=>{const t=o(),n=a.withFields({FCID:t}),i={type:"triggerEvent",fcid:t},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:t=>{n.log(`triggerEvent request successfully returned '${t}'`),e(t)},onFailure:(t,i)=>{n.error(`triggerEvent request failed: ${t} ${i}`),e("")}})}));q={};let i={};if(n)try{i=JSON.parse(n),q.type=i.type,"keyPressEvent"===q.type?q.data={keyValue:i.keyValue}:"alarmFiredEvent"===q.type?q.data={alarmName:i.alarmName,payload:i.payload}:"userAlertEvent"===q.type?q.data={eventCode:i.eventCode,message:i.message}:"externalEvent"===q.type?q.data={eventName:i.eventName,payload:i.payload}:"videoPlaybackEvent"===q.type?q.data={eventCode:i.eventCode,errorCode:i.errorCode}:a.warn("unknown trigger event type",q.type)}catch(e){a.error(`failed to parse trigger event string ${n}: ${e.message}`)}await m._init(t?.settings?.["ui-streamer"],i)}else $=J().sessionInfo?.settings?.webUI?.backendHeaders?.Authorization,a.log(`authToken dummy: token = ${$}`);window.auth=A,window.close=()=>{a.warn("window.close is disabled on Senza platform. Use lifecycle.exitApplication() instead.")}}function D(){return L}function Q(){return q}function J(){if("undefined"==typeof window||!window.diagnostics)return"undefined"==typeof window||window.diagnostics||a.error("[ getPlatformInfo ] window.diagnostics is undefined"),{version:"X.X.XX-X",pod:"ui-streamer-X.X.XX-X-QWERT-ASDFG-XXX-XXXXXX-XXXXX",podIP:"0.0.0.0",sessionInfo:{userAgent:"SynamediaSenza/XX.YY.ZZ",connectionId:"dummy",deviceId:"123456789",community:"LocalDev",tenant:"XXXXXX",tenantId:"XXXXXX",manifest:{transcontainer:"X.X.XX-X"},settings:{webUI:{backendHeaders:{Authorization:"Bearer dummytoken"}}},homeSessionInfo:{tenantId:"XXXXXX",community:"LocalDev"}}};try{const e=window.diagnostics()||{};return e.sessionInfo=d.sessionInfoObj,e}catch(e){a.error("Could not get platform info",e.stack)}}function X(e){if(window.cefQuery){const t={message:JSON.stringify({type:"setTimeZone",timezone:e}),waitForResponse:!1,target:"UI-Streamer"};window.cefQuery({request:JSON.stringify(t),persistent:!1,onSuccess:()=>{a.log("timezome is successfully set to",e)},onFailure:(t,n)=>{a.error(`error occurred setting timezone to ${e}: ${t} ${n}`)}})}}function M(){return!("undefined"==typeof window||!window.cefQuery)}function U(){window.cefQuery?window.cefQuery({request:"uiReady",persistent:!1,onSuccess:()=>{a.log("uiReady request successfully sent")},onFailure:(e,t)=>{a.error(`uiReady request failed: ${e} ${t}`)}}):a.error("uiReady: window.cefQuery is undefined")}function x(){const e=d.sessionInfoObj;return M()?{deviceId:e.deviceId,connectionId:e.connectionId,community:e.community,tenant:e.tenant,clientIp:e.clientIp}:(a.log("getDeviceInfo running locally, returning dummy info"),{deviceId:"123456789",connectionId:"dummy",community:"LocalDev",tenant:"XXXXXX",clientIp:"0.0.0.0"})}const z={remoteBrowserIp:window.diagnostics?window.diagnostics().podIP:"127.0.0.1",sdkVersion:F};function G(e,t,n,i){if(200===e&&(t=window.btoa(String.fromCharCode.apply(null,new Uint8Array(t)))),window.cefQuery){const s={type:"updateLicense",sessionId:i,fcid:n};s[200===e?"response":"error"]=t;const o={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:()=>{a.log("updateLicense request successfully sent")},onFailure:(e,t)=>{a.error(`updateLicense request failed: ${e} ${t}`)}})}}class j extends Error{constructor(e,t){super(t),this.code=e}}function V(){if(window.cefQuery)return a.log("getClientAssertion is called"),new Promise(((e,t)=>{window.cefQuery({request:"client_assertion",persistent:!1,onSuccess:n=>{try{const t=JSON.parse(n);a.log(`client_assertion request successfully returned ${n}`),e(t)}catch(e){a.error(`Failed to parse client assertion ${n}`),t(new j(0,"Failed to parse client assertion"))}},onFailure:(e,n)=>{a.log(`client_assertion request failed: ${e} ${n}`),t(new j(e,n))}})}));a.warn("getClientAssertion is not supported if NOT running e2e")}return"undefined"!=typeof window&&(window.hs=n),t})()));
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.senza=t():e.senza=t()}(this,(()=>(()=>{"use strict";var e={d:(t,n)=>{for(var i in n)e.o(n,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:n[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{ClientAssertionError:()=>ee,ConnectReason:()=>X,alarmManager:()=>P,auth:()=>x,deviceManager:()=>E,envInfo:()=>Z,getClientAssertion:()=>te,getConnectReason:()=>j,getDeviceInfo:()=>K,getPlatformInfo:()=>V,getTriggerEvent:()=>G,init:()=>z,isRunningE2E:()=>B,lifecycle:()=>k,messageManager:()=>q,platformManager:()=>$,remotePlayer:()=>b,setTimezone:()=>W,uiReady:()=>H,writeLicenseResponse:()=>Y});var n={};e.r(n),e.d(n,{ClientAssertionError:()=>ee,ConnectReason:()=>X,alarmManager:()=>P,auth:()=>x,deviceManager:()=>E,envInfo:()=>Z,getClientAssertion:()=>te,getConnectReason:()=>j,getDeviceInfo:()=>K,getPlatformInfo:()=>V,getTriggerEvent:()=>G,init:()=>z,isRunningE2E:()=>B,lifecycle:()=>k,messageManager:()=>q,platformManager:()=>$,remotePlayer:()=>b,setTimezone:()=>W,uiReady:()=>H,writeLicenseResponse:()=>Y});const i={version:"4.0.5"},{version:o}=i;function s(){return Math.round(1e5*Math.random())+"-"+V().sessionInfo?.connectionId}class r{constructor(e){this.logFields=e}debug(...e){console.debug(this.formatLogString(e))}log(...e){console.log(this.formatLogString(e))}info(...e){console.info(this.formatLogString(e))}warn(...e){console.warn(this.formatLogString(e))}error(...e){console.error(this.formatLogString(e))}withFields(e){return new r({...this.logFields,...e})}formatLogString(e){let t="[hs-sdk] "+e.join(" ");return this.logFields&&(t+=" [log-fields] "+JSON.stringify(this.logFields)),t}}const a=new r({sdkVersion:o,url:window?.location?.href??""}),d=new class{sessionInfoStr="{}";get sessionInfoObj(){try{return JSON.parse(this.sessionInfoStr)}catch(e){return void a.warn("Failed to return sdk")}}setSessionInfoStr(e){try{JSON.parse(e)}catch(e){throw Error("Failed to parse sessionInfo")}this.sessionInfoStr=e}},l={BACK:27,HOME:36,LEFT:37,RIGHT:39,UP:38,DOWN:40,ENTER:13},c={root:{top:"5vh",left:"82vw",height:"90vh",fontSize:"16px",width:"16vw",position:"fixed",zIndex:1e4,overflow:"hidden",visibility:"hidden"},item:{backgroundColor:"white",color:"black",fontSize:"12px",display:"flex",padding:"6px",border:"1px solid black",borderTop:"none"},item_key:{borderTopLeftRadius:"6px",borderTopRightRadius:"6px",marginTop:"20px",borderBottom:"3px solid black"},component:{fontWeight:"bold",width:"5vw"},component_key:{fontWeight:"normal",color:"darkgray"},id:{textAlign:"left",fontWeight:"normal",flex:1},id_key:{fontWeight:"bold"},time:{fontVariantNumeric:"tabular-nums",width:"3vw"},time_key:{fontWeight:"bold"}};let u=performance.now();const f=(e,t)=>"key"===t?new Date(e).toLocaleTimeString("en-US",{hour12:!1}):`${(e/1e3).toFixed(2)}s`,g=(e,t,n)=>{Object.entries(e).forEach((([e,i])=>{Object.getOwnPropertyNames(Object.getPrototypeOf(i)).forEach((o=>{if(n&&n(o))return;const s=i[o];"function"==typeof s&&(i[o]=function(...n){return t(e,o,...n),s.apply(this,n)})}))}))},y=(e,t)=>{e.innerHTML="",t.forEach(((n,i)=>{const o=document.createElement("div");Object.assign(o.style,{...c.item,...c[`item_${n?.component}`]}),["component","id","time"].forEach((e=>{if(n[e]){const t=document.createElement("div");Object.assign(t.style,c[e],c[`${e}_${n.component}`]),t.textContent="time"===e?f(n.time,n.component):n[e],o.appendChild(t)}})),e.appendChild(o),i===t.length-1&&o.scrollIntoView({behavior:"smooth"})}))},m=e=>{if(!e)return void a.error("No components to sequence");let t=document.getElementById("sequence-container");if(t)return;t=(()=>{const e=document.createElement("div");return e.id="sequence-container",Object.assign(e.style,c.root),document.body.appendChild(e),e})();const n=new Proxy([],{set:(e,i,o)=>(e[i]=o,"length"!==i&&y(t,n),!0)});window.printSequence=()=>(e=>{const t=e.map((e=>{const t=e.separator?"\n":"",n=e?.time?` ${f(e.time,e?.component)}`:"";if(e.args){const i=e.args.map((e=>"object"==typeof e?"object":e)).join(", ");return`${t}${e.component}.${e.id}(${i})${n}`}return`\n${e.component}: ${e.id}${n}`}));a.log("sequence:\n",t.join("\n"))})(n),((e,t)=>{t.push({component:"key",id:"BOOT",time:Date.now()}),g(e,((e,n,...i)=>{t.push({component:e,id:n,args:i,time:performance.now()-u})}),(e=>e.startsWith("_")||e.startsWith("get"))),(e=>{window.addEventListener("keydown",(t=>{var n;e.push({component:"key",id:(n=t.keyCode,Object.entries(l).find((([,e])=>e===n))?.[0]||String(n)),time:Date.now()}),u=performance.now()}))})(t),a.log("Sequence initialized.")})(e,n),y(t,n)},p=(e=!0)=>{const t=document.getElementById("sequence-container");t?t.style.visibility=e?"visible":"hidden":a.error("Sequence not initialized")},w=e=>JSON.parse(JSON.stringify(e));class h extends Error{constructor(e,t){super(t),this.code=e,this.msg=t}}function v(){const e=window.getPlaybackInfo?window.getPlaybackInfo():JSON.stringify({playbackPosition:0,assetDuration:0});let t;try{t=JSON.parse(e)}catch(n){a.error(`Playback Info parse failed. playbackStr = ${e}`),t={playbackPosition:0,assetDuration:0}}return t}function T(e){try{const t=JSON.stringify(e);window.setPlaybackInfo&&window.setPlaybackInfo(t)}catch(e){a.error("Playback Info to json string failed")}}class S extends EventTarget{constructor(){super(),this._config={preferredAudioLanguage:"",preferredSubtitlesLanguage:""},this._selectedAudioTrack="",this._selectedSubtitlesTrack="",this._availableAudioTracks=[],this._availableTextTracks=[],this._textTrackVisibility=!1,this._ptsSessionId=0,this._videoElement=void 0,this._isInitialized=!1,"undefined"!=typeof document&&document.addEventListener("hs/playbackInfoEvent",(()=>{a.info("Got hs/playbackInfoEvent"),this.dispatchEvent(new Event("timeupdate"))})),"undefined"!=typeof document&&document.addEventListener("hs/playback",(e=>{a.info("Got hs/playback event with detail",JSON.stringify(e?.detail)),this._availabilityStartTime=e?.detail?.availabilityStartTime,this._updateTracks(e?.detail),this.dispatchEvent(new Event("tracksupdate"))})),"undefined"!=typeof document&&document.addEventListener("hs/EOS",(()=>{a.info("Got hs/EOS event"),this.dispatchEvent(new Event("ended"))})),"undefined"!=typeof document&&document.addEventListener("hs/ui_inactive",(()=>{a.info("Got hs/ui_inactive event")})),"undefined"!=typeof document&&document.addEventListener("hs/senzaPlayerSetRate",(e=>{this._videoElement&&(this._videoElement.playbackRate=e.detail.rate)})),"undefined"!=typeof document&&document.addEventListener("hs/senzaPlayerSetTime",(e=>{this._videoElement?(a.info(`Adding ${e.detail} seconds to current time ${this._videoElement.currentTime}`),this._videoElement.playbackRate=1,this._videoElement.currentTime+=e.detail):a.warn("video element is NOT set")})),"undefined"!=typeof document&&document.addEventListener("hs/ERR",(e=>{a.info("Got hs/ERR event"),delete e?.detail?.type,delete e?.detail?.eventCode,this.dispatchEvent(new CustomEvent("error",e))})),"undefined"!=typeof document&&document.addEventListener("hs/getLicense",(e=>{a.info("Got hs/getLicense event");const t=e?.detail,n=Uint8Array.from(t.request,(e=>e.charCodeAt(0))),i=new ArrayBuffer(n.byteLength);new Uint8Array(i).set(n),this.licenseRequest=i;const o=t.fcid,s=t.sessionId,r=new CustomEvent("license-request",{detail:{licenseRequest:i}});r.writeLicenseResponse=(e,t)=>{Y(e,t,o,s)},this.dispatchEvent(r)}))}LoadMode=Object.freeze({NOT_LOADED:"notLoaded",LOADING:"loading",LOADED:"loaded",UNLOADING:"unloading"});async _init(e,t){let n={isLoaded:!1,playbackUrl:""};if(window.cefQuery){const e=s(),t=a.withFields({FCID:e}),i={type:"playerState",fcid:e},o={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};try{const e=await new Promise(((e,n)=>{window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:n=>{t.log("playerState request successfully returned",n),e(n)},onFailure:(e,i)=>{t.error(`playerState request failed: ${e} ${i}`),n()}})}));n=JSON.parse(e)}catch{t.error("either failed to get or failed to parse player state")}}this._loadMode=n?.isLoaded?this.LoadMode.LOADED:this.LoadMode.NOT_LOADED,this._loadedUrl=n?.playbackUrl||"",this._isInitialized=!0,this._setPlayableUriTimeout=e?.setPlayableUriTimeout??5e3,this._unloadTimeout=e?.unloadTimeout??5e3,this._requestVideoFrameInfo=e?.requestVideoFrameInfo??!0;let i={};try{i=JSON.parse(t?.playbackMetadata||"{}")}catch(e){a.error(`failed to parse playbackMetadata: ${e.message}`)}this._availabilityStartTime=i.availabilityStartTime,this._updateTracks(i)}_updateTracks(e){if(this._availableAudioTracks=e?.availableAudioTracks||this._availableAudioTracks,this._availableTextTracks=e?.availableSubtitlesTracks||this._availableTextTracks,"VOD"===e?.assetType&&(this._availableTextTracks=function(e){if(!e||e.length<1)return e;e.sort(((e,t)=>e.lang.toLowerCase()>t.lang.toLowerCase()?1:-1));const t=[{lang:"af",id:"*:af"},{lang:"ar",id:"*:ar"},{lang:"az",id:"*:az"},{lang:"bg",id:"*:bg"},{lang:"bs",id:"*:bs"},{lang:"ca",id:"*:ca"},{lang:"cs",id:"*:cs"},{lang:"cy",id:"*:cy"},{lang:"da",id:"*:da"},{lang:"de",id:"*:de"},{lang:"el",id:"*:el"},{lang:"en",id:"*:en"},{lang:"es",id:"*:es"},{lang:"es-MX",id:"*:es-MX"},{lang:"et",id:"*:et"},{lang:"fi",id:"*:fi"},{lang:"fr",id:"*:fr"},{lang:"fr-CA",id:"*:fr-CA"},{lang:"ga",id:"*:ga"},{lang:"ha",id:"*:ha"},{lang:"he",id:"*:he"},{lang:"hr",id:"*:hr"},{lang:"ht",id:"*:ht"},{lang:"hu",id:"*:hu"},{lang:"id",id:"*:id"},{lang:"is",id:"*:is"},{lang:"it",id:"*:it"},{lang:"kk",id:"*:kk"},{lang:"lt",id:"*:lt"},{lang:"lv",id:"*:lv"},{lang:"mk",id:"*:mk"},{lang:"mn",id:"*:mn"},{lang:"ms",id:"*:ms"},{lang:"mt",id:"*:mt"},{lang:"nl",id:"*:nl"},{lang:"no",id:"*:no"},{lang:"pl",id:"*:pl"},{lang:"pt",id:"*:pt"},{lang:"pt-PT",id:"*:pt-PT"},{lang:"ro",id:"*:ro"},{lang:"ru",id:"*:ru"},{lang:"sk",id:"*:sk"},{lang:"sl",id:"*:sl"},{lang:"so",id:"*:so"},{lang:"sq",id:"*:sq"},{lang:"sr",id:"*:sr"},{lang:"sv",id:"*:sv"},{lang:"sw",id:"*:sw"},{lang:"tl",id:"*:tl"},{lang:"tr",id:"*:tr"},{lang:"uk",id:"*:uk"},{lang:"uz",id:"*:uz"},{lang:"vi",id:"*:vi"},{lang:"zh",id:"*:zh"}],n=[...e];for(const i of t)e.find((e=>e.lang===i.lang))||(i.autoTranslate=!0,n.push(i));return n}(this._availableTextTracks)),this._availableAudioTracks){const e=this._availableAudioTracks.find((e=>!0===e.selected));this._selectedAudioTrack=e?.id||""}if(this._availableTextTracks){const e=this._availableTextTracks.find((e=>!0===e.selected));e?(this._selectedSubtitlesTrack=e.id,this._textTrackVisibility=!0):(this._selectedSubtitlesTrack="",this._textTrackVisibility=!1)}}getConfiguration(){return w(this._config)}configure(e){Object.entries(e).forEach((([e,t])=>{void 0!==this._config[e]&&(this._config[e]=t)}))}_changeLoadMode(e){this._loadMode!==e&&(this._loadMode=e,this.dispatchEvent(new Event("onloadmodechange")))}_handle_video_frame_info(e){if(!this._requestVideoFrameInfo||void 0===e)return void(this._videoElement=void 0);const t=s(),n=a.withFields({fcid:t}),i=(e,n)=>{const o={type:"currentFramePTS",fcid:t,currentFramePTS:n.mediaTime.toString(),ptsSessionId:this._ptsSessionId},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(o)};window.cefQuery({request:JSON.stringify(s),persistent:!1}),this._videoElement?.requestVideoFrameCallback(i)};n.log("handle_video_frame_pts: requesting video frame info"),void 0!==this._videoElement&&this._videoElement===e||(e.requestVideoFrameCallback(i),e.addEventListener("loadstart",(e=>{this._ptsSessionId++,a.info("videoElement, loadstart ptsSessionId=",this._ptsSessionId," event=",e)}))),this._videoElement=e}_reset(){this._availableAudioTracks=[],this._availableTextTracks=[],this._selectedAudioTrack="",this._selectedSubtitlesTrack="",this._availabilityStartTime=void 0}registerVideoElement(e){this.attach(e)}attach(e){this._handle_video_frame_info(e)}async load(e,t){if(!this._isInitialized)throw new h(6500,"Cannot call load() if remote player is not initialized");if(e&&window.cefQuery){const n=await k.getState();if("background"===n||"inTransitionToBackground"===n)throw new h(6002,"Cannot call load() while in state 'background' or 'inTransitionToBackground'");if(this._loadMode===this.LoadMode.LOADING)throw new h(6501,"Cannot call load() while previous load is still in progress");this._reset();const i=this._loadMode;return this._changeLoadMode(this.LoadMode.LOADING),new Promise(((n,o)=>{T({playbackPosition:0});const r=s(),d=t??0,l=a.withFields({FCID:r,loadUrl:e,playbackPosition:d});l.log("remotePlayer load: sending setPlayableUri request");const c={type:"setPlayableUri",url:e,timeout:this._setPlayableUriTimeout,autoPlay:!1,playbackPosition:d,fcid:r},u={target:"TC",waitForResponse:!0,message:JSON.stringify(c)};let f=0;const g=Date.now(),y=window.cefQuery({request:JSON.stringify(u),persistent:!1,onSuccess:()=>{const i=Date.now()-g;l.withFields({duration:i}).log(`setPlayableUri completed successfully after ${i} ms`),t>0&&T({playbackPosition:t}),f&&(clearTimeout(f),f=0),this._changeLoadMode(this.LoadMode.LOADED),this._loadedUrl=e,this.dispatchEvent(new Event("canplay")),n()},onFailure:(e,t)=>{const n=Date.now()-g;l.withFields({duration:n}).log(`setPlayableUri failed after ${n} ms. Error code: ${e}, error message: ${t}`),f&&(clearTimeout(f),f=0),99===e?this._changeLoadMode(i):(this._changeLoadMode(this.LoadMode.NOT_LOADED),this._loadedUrl=""),o(new h(e,t))}});l.log(`window.cefQuery for setPlayableUri returned query id ${y}`);const m=this._setPlayableUriTimeout+1e3;f=setTimeout((()=>{l.log(`setPlayableUri reached timeout of ${m} ms, canceling query id ${y}`),window.cefQueryCancel(y),this._changeLoadMode(this.LoadMode.NOT_LOADED),this._loadedUrl="",o(new h(6e3,`load reached timeout of ${m} ms`))}),m,y)}))}a.error("remotePlayer load: either window.cefQuery or url is undefined")}async unload(){if(!this._isInitialized)throw new h(6500,"Cannot call unload() if remote player is not initialized");if(window.cefQuery){if(this._loadMode===this.LoadMode.LOADING)throw new h(6502,"Cannot call unload() while load is still in progress");const e=this._loadMode;return this._changeLoadMode(this.LoadMode.UNLOADING),new Promise(((t,n)=>{const i=s(),o=a.withFields({FCID:i});o.log("remotePlayer unload");const r={type:"remotePlayer.unload",class:"remotePlayer",action:"unload",fcid:i},d={target:"TC",waitForResponse:!0,message:JSON.stringify(r)};let l=0;const c=Date.now(),u=window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{const e=Date.now()-c;o.withFields({duration:e}).log(`unload completed successfully after ${e} ms`),l&&(clearTimeout(l),l=0),this._reset(),this._changeLoadMode(this.LoadMode.NOT_LOADED),this._loadedUrl=void 0,t()},onFailure:(t,i)=>{const s=Date.now()-c;o.withFields({duration:s}).log(`unload failed after ${s} ms. Error code: ${t}, error message: ${i}`),l&&(clearTimeout(l),l=0),this._changeLoadMode(e),n(new h(t,i))}});o.log(`window.cefQuery for unload returned query id ${u}`);const f=this._unloadTimeout+1e3;l=setTimeout((()=>{o.log(`unload reached timeout of ${f} ms, canceling query id ${u}`),window.cefQueryCancel(u),this._changeLoadMode(e),n(new h(6e3,`unload reached timeout of ${f} ms`))}),f,u)}))}a.error("remotePlayer unload: window.cefQuery is undefined")}play(){if(!this._isInitialized)throw new h(6500,"Cannot call play() if remote player is not initialized");if(window.cefQuery){if(this._loadMode!==this.LoadMode.LOADED)throw new h(6001,"Cannot call play() if player is not loaded");const e=s(),t=a.withFields({FCID:e});t.log("remotePlayer play: sending play action");const n=this._selectedAudioTrack||this._config.preferredAudioLanguage||"";let i="";this._textTrackVisibility&&(i=this._selectedSubtitlesTrack||this._config.preferredSubtitlesLanguage||"");const o={type:"remotePlayer.play",class:"remotePlayer",action:"play",fcid:e,audioLanguage:n,subtitlesLanguage:i,playbackPosition:this.currentTime},r={target:"TC",waitForResponse:!1,message:JSON.stringify(o)};return new Promise(((e,n)=>{window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{t.log("remotePlayer play request successfully sent"),e()},onFailure:(e,i)=>{t.error(`remotePlayer play request failed: ${e} ${i}`),n(new h(e,i))}})}))}return a.error("remotePlayer play: window.cefQuery is undefined"),Promise.resolve(void 0)}pause(){if(!this._isInitialized)throw new h(6500,"Cannot call pause() if remote player is not initialized");if(window.cefQuery){if(this._loadMode!==this.LoadMode.LOADED)throw new h(6001,"Cannot call pause() if player is not loaded");const e=s(),t=a.withFields({FCID:e});t.log("remotePlayer pause: sending pause request");const n={type:"remotePlayer.pause",class:"remotePlayer",action:"pause",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};return new Promise(((e,n)=>{window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("remotePlayer pause request successfully sent"),e()},onFailure:(e,i)=>{t.error(`remotePlayer pause request failed: ${e} ${i}`),n(new h(e,i))}})}))}return a.error("remotePlayer pause: window.cefQuery is undefined"),Promise.resolve(void 0)}getAssetUri(){if(!this._isInitialized)throw new h(6500,"Cannot call getAssetUri() if remote player is not initialized");return this._loadedUrl}getLoadMode(){if(!this._isInitialized)throw new h(6500,"Cannot call getLoadMode() if remote player is not initialized");return this._loadMode}getTextTracks(){return w(this._availableTextTracks)}getAudioTracks(){return w(this._availableAudioTracks)}selectAudioTrack(e){for(const t of this.getAudioTracks())if(t.id===e)return void(this._selectedAudioTrack=e);a.warn(`Invalid audioTrackId ${e}`)}selectTextTrack(e){for(const t of this.getTextTracks())if(t.id===e)return void(this._selectedSubtitlesTrack=e);a.warn(`Invalid textTrackId ${e}`)}setTextTrackVisibility(e){const t=this._textTrackVisibility;if("boolean"!=typeof e)throw new TypeError("visible parameter must be a boolean");const n=e;n!==t&&(this._textTrackVisibility=n,n||(this._selectedSubtitlesTrack=""))}get currentTime(){return v()?.playbackPosition}set currentTime(e){if(T({playbackPosition:e}),window.cefQuery){const t=s(),n=a.withFields({FCID:t});n.log("setting remotePlayer currentTime");const i={type:"remotePlayer.seek",class:"remotePlayer",action:"seek",playbackPosition:e,fcid:t},o={target:"TC",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:()=>{n.log("remotePlayer seek request successfully sent")},onFailure:(e,t)=>{n.error(`remotePlayer seek request failed: ${e} ${t}`)}})}else a.error("setting remotePlayer currentTime: window.cefQuery is undefined")}get duration(){return v()?.assetDuration}get textTrackVisibility(){return this._textTrackVisibility}getPresentationStartTimeAsDate(){return void 0===this._availabilityStartTime?null:new Date(1e3*this._availabilityStartTime)}}const b=new S;"undefined"!=typeof window&&(window.remotePlayer=b);class I extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/uistatechange",(e=>{a.log("Got hs/uistatechange",e.detail);const t=new Event("onstatechange");t.state=e.detail,this.dispatchEvent(t)}))}getState(){if(window.cefQuery)return new Promise(((e,t)=>{window.cefQuery&&window.cefQuery({request:"uiState",persistent:!1,onSuccess:t=>{a.log(`uiState request successfully returned '${t}'`),e(t)},onFailure:(e,n)=>{a.error(`uiState request failed: ${e} ${n}`),t(n)}})}));a.warn("lifecycle getState is not supported if NOT running e2e")}moveToForeground(){if(window.cefQuery){const e=s(),t=a.withFields({FCID:e});t.log("lifecycle moveToForeground: sending uiActiveRequest action"),window.cefQuery({request:JSON.stringify({action:"uiActiveRequest",fcid:e}),persistent:!1,onSuccess:()=>{t.log("uiActiveRequest successfully sent")},onFailure:(e,n)=>{t.error(`uiActiveRequest failed: ${e} ${n}`)}})}else a.error("lifecycle moveToForeground: window.cefQuery is undefined")}moveToBackground(){if(window.cefQuery){const e=s(),t=a.withFields({FCID:e});t.log("lifecycle moveToBackground: sending play action");const n=b.getConfiguration(),i=b._selectedAudioTrack||n.preferredAudioLanguage||"",o=b._selectedSubtitlesTrack||n.preferredSubtitlesLanguage||"";window.cefQuery({request:JSON.stringify({action:"play",fcid:e,audioLanguage:i,subtitlesLanguage:o}),persistent:!1,onSuccess:()=>{t.log("[ moveToBackground ] play successfully sent")},onFailure:(e,n)=>{t.error(`[ moveToBackground ] play failed: ${e} ${n}`)}})}else a.error("lifecycle moveToBackground: window.cefQuery is undefined")}switchTenant(e){if(e&&e.length>0){if(e===V().sessionInfo?.tenantId)return a.warn(`SwitchTenant requires a different tenantId than the current one. CurrentTenantId=${V().sessionInfo?.tenantId} and tenantId=${e}`),Promise.reject("SwitchTenant requires a different tenantId than the current one");const t=V().sessionInfo?.homeSessionInfo?.tenantInfo?.contentHubTenantId,n=V().sessionInfo?.homeSessionInfo?.tenantId;return a.log(`SwitchTenant for ${e}`),window.cefQuery?new Promise(((i,o)=>{const r=s(),d=a.withFields({FCID:r}),l={type:"reconnect",fcid:r,session:btoa(JSON.stringify({tenantId:e,...V().sessionInfo?.tenantId===t&&e!==n&&{returnToTenantId:t}}))},c={target:"TC",waitForResponse:!1,message:JSON.stringify(l)};window.cefQuery({request:JSON.stringify(c),persistent:!1,onSuccess:()=>{d.log("SwitchTenant request successfully sent"),i(!0)},onFailure:(e,t)=>{d.error(`SwitchTenant failed: ${e} ${t}`),o(`SwitchTenant failed: ${e} ${t}`)}})})):(a.warn("SwitchTenant is not supported if NOT running e2e"),Promise.reject("SwitchTenant is not supported if NOT running e2e"))}return a.warn("SwitchTenant requires a valid tenantId string parameter"),Promise.reject("SwitchTenant requires a valid tenantId string parameter")}exitApplication(){return window.cefQuery?new Promise(((e,t)=>{const n=s(),i=a.withFields({FCID:n});let o,r;const l=d.sessionInfoObj;l?.homeSessionInfo&&(l?.returnToTenantId||l?.homeSessionInfo.tenantId!==l?.tenantId)?(r={type:"reconnect",splashUrl:l?.homeSessionInfo.tenantInfo.tenantSettings.applicationSwitchSplashUrl,fcid:n},l?.returnToTenantId&&(l?.returnToTenantId===l?.homeSessionInfo.tenantInfo.contentHubTenantId&&(r.splashUrl=l?.homeSessionInfo.contentHubTenantInfo.tenantSettings.applicationSwitchSplashUrl),r.session=btoa(JSON.stringify({tenantId:l?.returnToTenantId}))),o={target:"TC",waitForResponse:!1,message:JSON.stringify(r)}):(r={type:"launchHomeApplication",fcid:n},o={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(r)}),window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:()=>{i.log(`exitApplication request with type: '${r.type}' successfully sent`),e(!0)},onFailure:(e,n)=>{i.error(`exitApplication request with type: '${r.type}' failed: ${e} ${n}`),t(`exitApplication request with type: '${r.type}' failed: ${e} ${n}`)}})})):(a.warn("exitApplication is not supported if NOT running e2e"),Promise.reject("exitApplication is not supported if NOT running e2e"))}}const k=new I,_={};class O extends EventTarget{constructor(){super(),_.level=0,_.quality=0,_.ssid="unknown",_.bssid="unknown","undefined"!=typeof document&&document.addEventListener("wifiSignalReport",(e=>{a.log("Got wifiSignalReport",JSON.stringify(e.detail)),_.level=e.detail.level,_.quality=e.detail.quality,_.ssid=e.detail.ssid,_.bssid=e.detail.bssid,this.dispatchEvent(new Event("wifiInfoUpdated"))}))}get deviceInfo(){const e=d.sessionInfoObj;return B()&&e?{deviceId:e.deviceId,connectionId:e.connectionId,community:e.community,tenant:e.tenant,clientIp:e.clientIp,countryCode:e.general?.location?.["x-country-code"]}:(a.log("getDeviceInfo running locally, returning dummy info"),{deviceId:"123456789",connectionId:"dummy",community:"LocalDev",tenant:"XXXXXX",clientIp:"0.0.0.0",countryCode:"XX"})}get wifiInfo(){return _}reboot(){return new Promise(((e,t)=>{if(window.cefQuery){const n=s(),i=a.withFields({FCID:n}),o={type:"reboot",fcid:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(o)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{i.log("reboot request successfully sent"),e(!0)},onFailure:(e,n)=>{i.error(`reboot failed: ${e} ${n}`),t(`reboot failed: ${e} ${n}`)}})}else a.warn("reboot is not supported if NOT running e2e"),t("reboot is not supported if NOT running e2e")}))}clearWifi(){return new Promise(((e,t)=>{const n=s(),i=a.withFields({FCID:n}),o={type:"resetWifi",fcid:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(o)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{i.log("clearWifi successfully sent"),e(!0)},onFailure:(e,n)=>{i.error(`clearWifi failed: ${e} ${n}`),t(`clearWifi failed: ${e} ${n}`)}})}))}sendDataToDevice(e){if("string"!=typeof e)throw new Error("data must be of type 'string'");return new Promise(((t,n)=>{const i=s(),o=a.withFields({FCID:i}),r={type:"externalCommand",data:{command:"forward",payload:e},fcid:i},d={target:"TC",waitForResponse:!1,message:JSON.stringify(r)};window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{o.log("externalCommand successfully sent"),t()},onFailure:(e,t)=>{o.error(`externalCommand failed: ${e} ${t}`),n(`externalCommand failed: ${e} ${t}`)}})}))}async factoryReset(e=!0){if("boolean"!=typeof e)throw new Error("reboot param must be of type 'boolean'");return new Promise(((t,n)=>{const i=s(),o=a.withFields({FCID:i}),r={type:"factoryReset",fcid:i,reboot:e},d={target:"TC",waitForResponse:!0,message:JSON.stringify(r)};let l=0;const c=window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{l&&clearTimeout(l),o.log("factoryReset successfully sent"),t(!0)},onFailure:(e,t)=>{l&&clearTimeout(l),o.error(`factoryReset failed: ${e} ${t}`),n(`factoryReset failed: ${e} ${t}`)}});l=setTimeout((()=>{o.error("factoryReset failed: reached timeout of 5000 ms"),window.cefQueryCancel(c),n("factoryReset failed: reached timeout of 5000 ms")}),5e3)}))}}const E=new O;class N extends EventTarget{constructor(){super()}get appConfig(){const e=d.sessionInfoObj,t=e.homeSessionInfo?.appConfig||{};return a.info("PlatformManager get appConfig: \n"+JSON.stringify(t,null,2)),t}setTimezone(e){if(window.cefQuery){const t={message:JSON.stringify({type:"setTimeZone",timezone:e}),waitForResponse:!1,target:"UI-Streamer"};window.cefQuery({request:JSON.stringify(t),persistent:!1,onSuccess:()=>{a.log("PlatformManager timezome is successfully set to",e)},onFailure:(t,n)=>{a.error(`PlatformManager error occurred setting timezone to ${e}: ${t} ${n}`)}})}}}const $=new N;class F extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/alarmFiredEvent",(e=>{a.log("Got hs/alarmFiredEvent",JSON.stringify(e.detail)),e.detail?.alarmName&&this.dispatchEvent(new CustomEvent(e.detail.alarmName,{detail:e.detail.payload}))}))}addAlarm(e,t,n=""){if("string"!=typeof n)throw Error("data must be a string");const i=s(),o=a.withFields({alarmName:e,FCID:i});if(o.log(`addAlarm called for ${e} to be fired at ${t}`),window.cefQuery){const s={type:"addAlarm",fcid:i,alarmName:e,alarmTime:t,payload:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{o.log("addAlarm request successfully sent")},onFailure:(e,t)=>{o.error(`addAlarm failed: ${e} ${t}`)}})}else o.warn("addAlarm is not supported if NOT running e2e")}deleteAlarm(e){const t=s(),n=a.withFields({alarmName:e,FCID:t});if(n.log(`deleteAlarm called for ${e}`),window.cefQuery){const i={type:"deleteAlarm",fcid:t,alarmName:e},o={target:"TC",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:()=>{n.log("deleteAlarm request successfully sent")},onFailure:(e,t)=>{n.error(`deleteAlarm failed: ${e} ${t}`)}})}else n.warn("deleteAlarm is not supported if NOT running e2e")}deleteAllAlarms(){if(window.cefQuery){const e=s(),t=a.withFields({FCID:e}),n={type:"deleteAllAlarms",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("deleteAllAlarms request successfully sent")},onFailure:(e,n)=>{t.error(`deleteAllAlarms failed: ${e} ${n}`)}})}else a.warn("deleteAllAlarms is not supported if NOT running e2e")}getActiveAlarms(){throw Error("NOT IMPLEMENTED")}}const P=new F;"undefined"!=typeof window&&(window.alarmManager=P);class C extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/externalEvent",(e=>{a.log("Got hs/externalEvent",JSON.stringify(e.detail)),this.dispatchEvent(new CustomEvent("message",{detail:{eventName:e.detail.eventName,payload:e.detail.payload,fcid:e.detail.fcid}}))}))}async registerGroups(e){return a.log(`register called for ${e}`),new Promise(((t,n)=>{if(window.cefQuery){const i=s(),o=a.withFields({FCID:i}),r={type:"registerGroupEvent",fcid:i,groups:e},d={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(r)};window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{o.log("registerGroupEvent request successfully sent"),t(!0)},onFailure:(e,t)=>{o.error(`registerGroupEvent failed: ${e} ${t}`),n(`registerGroupEvent failed: ${e} ${t}`)}})}else a.warn("registerGroupEvent is not supported if NOT running e2e"),n("registerGroupEvent is not supported if NOT running e2e")}))}}const q=new C;let A,L;"undefined"!=typeof window&&(window.messageManager=q),k.getState()?.then((e=>{L=e})),k.addEventListener("onstatechange",(e=>{L=e.state}));const R=e=>{"background"!==L&&"inTransitionToBackground"!==L||(A&&clearTimeout(A),A=setTimeout((()=>{"background"!==L&&"inTransitionToBackground"!==L||a.log(`${e.type} event received while in '${L}' state and there was no call to lifecycle.moveToForeground() for 500 ms. Make sure to call it if you want to move to foreground.`),A=0}),500))};"undefined"!=typeof document&&document.addEventListener("keydown",R),b.addEventListener("error",R),b.addEventListener("ended",R);const{version:D}=i;let Q;const J="1.0";"undefined"!=typeof document&&document.addEventListener("keydown",(e=>{a.log(`Got ${e.key} key`)}));const x={getToken:async function(){return Q?Promise.resolve(Q):(a.log("getToken wait for promise updateSession event"),new Promise((e=>{document.addEventListener("updateSession",(t=>{Q=t.detail?.updateObj,a.log(`onUpdateSessionEvent: token= ${Q}`),e(Q)}),{once:!0})})))},forceTokenUpdate:function(){if(Q=null,window.cefQuery){const e=s(),t=a.withFields({FCID:e});t.log("forceTokenUpdate: sending updateSessionRequest");const n={type:"updateSessionRequest",updateKey:"authorization",parentPath:"settings.webUI.backendHeaders.Authorization",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("updateSessionRequest successfully sent")},onFailure:(e,n)=>{t.error(`updateSessionRequest failed: ${e} ${n}`)}})}else a.error("forceTokenUpdate: window.cefQuery is undefined")},getClientAssertion:te},X=Object.freeze({UNKNOWN:"unknown",INITIAL_CONNECTION:"initial_connection",UI_RELEASE:"ui_release",UI_TERMINATION:"ui_termination",WEBRTC_ERROR:"webrtc_error",UI_WATCHDOG:"ui_watchdog"});let M=X.UNKNOWN,U={};async function z(){if(a.log(`init ${D}`),window.diagnostics||a.error("[ init ] window.diagnostics is undefined"),window.cefQuery){await new Promise(((e,t)=>{window.cefQuery({request:"apiVersion "+J,persistent:!1,onSuccess:()=>{a.log("api version compatability check succeeded"),e()},onFailure:(e,n)=>{a.error("api version compatability check failed: "+n),t(n)}})}));const e=await new Promise((e=>{window.cefQuery({request:"sessionInfo",persistent:!1,onSuccess:t=>{a.log("sessionInfo request successfully returned "+t),e(t)},onFailure:(e,t)=>{a.error(`sessionInfo request failed: ${e} ${t}`)}})}));d.setSessionInfoStr(e);const t=JSON.parse(e);Q=t?.settings?.webUI?.backendHeaders?.Authorization,a.log(`authToken: token = ${Q}`),document.addEventListener("updateSession",(e=>{Q=e.detail?.updateObj,a.log(`onUpdateSessionEvent: token = ${Q}`)})),M=await new Promise((e=>{const t=s(),n=a.withFields({FCID:t}),i={type:"connectReason",fcid:t},o={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:t=>{n.log(`connectReason request successfully returned '${t}'`),e(t)},onFailure:(t,i)=>{n.error(`connectReason request failed: ${t} ${i}`),e(X.UNKNOWN)}})}));const n=await new Promise((e=>{const t=s(),n=a.withFields({FCID:t}),i={type:"triggerEvent",fcid:t},o={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:t=>{n.log(`triggerEvent request successfully returned '${t}'`),e(t)},onFailure:(t,i)=>{n.error(`triggerEvent request failed: ${t} ${i}`),e("")}})}));U={};let i={};if(n)try{i=JSON.parse(n),U.type=i.type,"keyPressEvent"===U.type?U.data={keyValue:i.keyValue}:"alarmFiredEvent"===U.type?U.data={alarmName:i.alarmName,payload:i.payload}:"userAlertEvent"===U.type?U.data={eventCode:i.eventCode,message:i.message}:"externalEvent"===U.type?U.data={eventName:i.eventName,payload:i.payload}:"videoPlaybackEvent"===U.type?U.data={eventCode:i.eventCode,errorCode:i.errorCode}:a.warn("unknown trigger event type",U.type)}catch(e){a.error(`failed to parse trigger event string ${n}: ${e.message}`)}await b._init(t?.settings?.["ui-streamer"],i);const o=t?.settings?.["ui-streamer"]?.devSequence;o&&(m({lifecycle:k,remotePlayer:b}),p(!0))}else Q=V().sessionInfo?.settings?.webUI?.backendHeaders?.Authorization,a.log(`authToken dummy: token = ${Q}`);window.auth=x,window.close=()=>{a.warn("window.close is disabled on Senza platform. Use lifecycle.exitApplication() instead.")}}function j(){return M}function G(){return U}function V(){if("undefined"==typeof window||!window.diagnostics)return"undefined"==typeof window||window.diagnostics||a.error("[ getPlatformInfo ] window.diagnostics is undefined"),{version:"X.X.XX-X",pod:"ui-streamer-X.X.XX-X-QWERT-ASDFG-XXX-XXXXXX-XXXXX",podIP:"0.0.0.0",sessionInfo:{userAgent:"SynamediaSenza/XX.YY.ZZ",connectionId:"dummy",deviceId:"123456789",community:"LocalDev",tenant:"XXXXXX",tenantId:"XXXXXX",manifest:{transcontainer:"X.X.XX-X"},settings:{webUI:{backendHeaders:{Authorization:"Bearer dummytoken"}}},homeSessionInfo:{tenantId:"XXXXXX",community:"LocalDev"}}};try{const e=window.diagnostics()||{};return e.sessionInfo=d.sessionInfoObj,e}catch(e){a.error("Could not get platform info",e.stack)}}function W(e){if(window.cefQuery){const t={message:JSON.stringify({type:"setTimeZone",timezone:e}),waitForResponse:!1,target:"UI-Streamer"};window.cefQuery({request:JSON.stringify(t),persistent:!1,onSuccess:()=>{a.log("timezome is successfully set to",e)},onFailure:(t,n)=>{a.error(`error occurred setting timezone to ${e}: ${t} ${n}`)}})}}function B(){return!("undefined"==typeof window||!window.cefQuery)}function H(){window.cefQuery?window.cefQuery({request:"uiReady",persistent:!1,onSuccess:()=>{a.log("uiReady request successfully sent")},onFailure:(e,t)=>{a.error(`uiReady request failed: ${e} ${t}`)}}):a.error("uiReady: window.cefQuery is undefined")}function K(){const e=d.sessionInfoObj;return B()?{deviceId:e.deviceId,connectionId:e.connectionId,community:e.community,tenant:e.tenant,clientIp:e.clientIp}:(a.log("getDeviceInfo running locally, returning dummy info"),{deviceId:"123456789",connectionId:"dummy",community:"LocalDev",tenant:"XXXXXX",clientIp:"0.0.0.0"})}const Z={remoteBrowserIp:window.diagnostics?window.diagnostics().podIP:"127.0.0.1",sdkVersion:D};function Y(e,t,n,i){if(200===e&&(t=window.btoa(String.fromCharCode.apply(null,new Uint8Array(t)))),window.cefQuery){const o={type:"updateLicense",sessionId:i,fcid:n};o[200===e?"response":"error"]=t;const s={target:"TC",waitForResponse:!1,message:JSON.stringify(o)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:()=>{a.log("updateLicense request successfully sent")},onFailure:(e,t)=>{a.error(`updateLicense request failed: ${e} ${t}`)}})}}class ee extends Error{constructor(e,t){super(t),this.code=e}}function te(){if(window.cefQuery)return a.log("getClientAssertion is called"),new Promise(((e,t)=>{window.cefQuery({request:"client_assertion",persistent:!1,onSuccess:n=>{try{const t=JSON.parse(n);a.log(`client_assertion request successfully returned ${n}`),e(t)}catch(e){a.error(`Failed to parse client assertion ${n}`),t(new ee(0,"Failed to parse client assertion"))}},onFailure:(e,n)=>{a.log(`client_assertion request failed: ${e} ${n}`),t(new ee(e,n))}})}));a.warn("getClientAssertion is not supported if NOT running e2e")}return"undefined"!=typeof window&&(window.hs=n),t})()));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "senza-sdk",
3
- "version": "4.0.4",
3
+ "version": "4.0.5",
4
4
  "main": "./src/api.js",
5
5
  "description": "API for Senza application",
6
6
  "license": "MIT",
package/src/api.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { getFCID, sdkLogger } from "./utils";
2
2
  import pack from "../package.json";
3
- import {sessionInfo} from "./SessionInfo";
3
+ import { sessionInfo } from "./SessionInfo";
4
4
  const { version } = pack;
5
+ import { initSequence, showSequence } from "./devSequence.js";
6
+ import { lifecycle } from "./lifecycle";
5
7
 
6
8
  let authToken;
7
9
 
@@ -48,8 +50,8 @@ export const ConnectReason = Object.freeze({
48
50
  let connectReason = ConnectReason.UNKNOWN;
49
51
  let triggerEvent = {};
50
52
 
51
- import {remotePlayer} from "./remotePlayer";
52
- export {remotePlayer};
53
+ import { remotePlayer } from "./remotePlayer";
54
+ export { remotePlayer };
53
55
 
54
56
  /** Should be called once to init the library
55
57
  *@example
@@ -111,7 +113,7 @@ export async function init() {
111
113
  // Get connection reason
112
114
  connectReason = await new Promise((resolve) => {
113
115
  const FCID = getFCID();
114
- const logger = sdkLogger.withFields({FCID});
116
+ const logger = sdkLogger.withFields({ FCID });
115
117
  const message = { type: "connectReason", fcid: FCID };
116
118
  const request = { target: "UI-Streamer", waitForResponse: false, message: JSON.stringify(message) };
117
119
  window.cefQuery({
@@ -137,7 +139,7 @@ export async function init() {
137
139
  // videoPlaybackEvent (eventCode, errorCode)
138
140
  const triggerEventStr = await new Promise((resolve) => {
139
141
  const FCID = getFCID();
140
- const logger = sdkLogger.withFields({FCID});
142
+ const logger = sdkLogger.withFields({ FCID });
141
143
  const message = { type: "triggerEvent", fcid: FCID };
142
144
  const request = { target: "UI-Streamer", waitForResponse: false, message: JSON.stringify(message) };
143
145
  window.cefQuery({
@@ -179,6 +181,12 @@ export async function init() {
179
181
 
180
182
  await remotePlayer._init(sessionInfoObj?.settings?.["ui-streamer"], originalTriggerEvent);
181
183
 
184
+ const devSequence = sessionInfoObj?.settings?.["ui-streamer"]?.devSequence;
185
+ if (devSequence) {
186
+ initSequence({ lifecycle, remotePlayer });
187
+ showSequence(true);
188
+ }
189
+
182
190
  } else {
183
191
  authToken = getPlatformInfo().sessionInfo?.settings?.webUI?.backendHeaders?.Authorization;
184
192
  sdkLogger.log(`authToken dummy: token = ${authToken}`);
@@ -265,7 +273,7 @@ export function getPlatformInfo() {
265
273
  export function setTimezone(timezone) {
266
274
  // STOP DO NOT CHANGE THIS FUNCTION AS IT IS DEPRECATED!!!!
267
275
  if (window.cefQuery) {
268
- const request = {message: JSON.stringify({type: "setTimeZone", timezone}), waitForResponse: false, target: "UI-Streamer"};
276
+ const request = { message: JSON.stringify({ type: "setTimeZone", timezone }), waitForResponse: false, target: "UI-Streamer" };
269
277
  window.cefQuery({
270
278
  request: JSON.stringify(request),
271
279
  persistent: false,
@@ -288,7 +296,7 @@ async function getToken() {
288
296
  authToken = e.detail?.updateObj;
289
297
  sdkLogger.log(`onUpdateSessionEvent: token= ${authToken}`);
290
298
  resolve(authToken);
291
- }, {once:true});
299
+ }, { once: true });
292
300
  });
293
301
  }
294
302
  return Promise.resolve(authToken);
@@ -299,7 +307,7 @@ function forceTokenUpdate() {
299
307
 
300
308
  if (window.cefQuery) {
301
309
  const FCID = getFCID();
302
- const logger = sdkLogger.withFields({FCID});
310
+ const logger = sdkLogger.withFields({ FCID });
303
311
  logger.log("forceTokenUpdate: sending updateSessionRequest");
304
312
  const message = {
305
313
  type: "updateSessionRequest",
@@ -307,7 +315,7 @@ function forceTokenUpdate() {
307
315
  parentPath: "settings.webUI.backendHeaders.Authorization",
308
316
  fcid: FCID
309
317
  };
310
- const request = { target:"TC", waitForResponse: false, message: JSON.stringify(message) };
318
+ const request = { target: "TC", waitForResponse: false, message: JSON.stringify(message) };
311
319
  window.cefQuery({
312
320
  request: JSON.stringify(request),
313
321
  persistent: false,
@@ -372,11 +380,11 @@ export function getDeviceInfo() {
372
380
  };
373
381
  }
374
382
 
375
- export {lifecycle} from "./lifecycle";
376
- export {deviceManager} from "./deviceManager";
377
- export {platformManager} from "./platformManager";
378
- export {alarmManager} from "./alarmManager";
379
- export {messageManager} from "./messageManager";
383
+ export { lifecycle } from "./lifecycle";
384
+ export { deviceManager } from "./deviceManager";
385
+ export { platformManager } from "./platformManager";
386
+ export { alarmManager } from "./alarmManager";
387
+ export { messageManager } from "./messageManager";
380
388
  import "./devHelper";
381
389
 
382
390
  /**
@@ -431,7 +439,7 @@ export function writeLicenseResponse(statusCode, licenseResponse, fcid, sessionI
431
439
  }
432
440
 
433
441
  export class ClientAssertionError extends Error {
434
- constructor(code,message) {
442
+ constructor(code, message) {
435
443
  super(message);
436
444
  this.code = code;
437
445
  }
@@ -462,7 +470,7 @@ export function getClientAssertion() {
462
470
  sdkLogger.log("getClientAssertion is called");
463
471
 
464
472
  return new Promise((resolve, reject) => {
465
- window.cefQuery ({
473
+ window.cefQuery({
466
474
  request: "client_assertion",
467
475
  persistent: false,
468
476
  onSuccess: (response) => {
@@ -0,0 +1,259 @@
1
+ import { sdkLogger } from "./utils";
2
+
3
+ /**
4
+ The sequence component is a debugging and visualization tool designed
5
+ to track and display a sequence of events or actions in a web application.
6
+ It enables developers to monitor key interactions, method calls,
7
+ and their associated timestamps in real time, presented in a floating container.
8
+ */
9
+
10
+ /**
11
+ * Key codes mapping for handling keyboard input.
12
+ */
13
+ const KEY_CODES = {
14
+ BACK: 27,
15
+ HOME: 36,
16
+ LEFT: 37,
17
+ RIGHT: 39,
18
+ UP: 38,
19
+ DOWN: 40,
20
+ ENTER: 13
21
+ };
22
+
23
+ /**
24
+ * Styling for various components of the sequence visualization.
25
+ */
26
+ const styles = {
27
+ root: {
28
+ top: "5vh",
29
+ left: "82vw",
30
+ height: "90vh",
31
+ fontSize: "16px",
32
+ width: "16vw",
33
+ position: "fixed",
34
+ zIndex: 10000,
35
+ overflow: "hidden",
36
+ visibility: "hidden"
37
+ },
38
+ item: {
39
+ backgroundColor: "white",
40
+ color: "black",
41
+ fontSize: "12px",
42
+ display: "flex",
43
+ padding: "6px",
44
+ border: "1px solid black",
45
+ borderTop: "none"
46
+ },
47
+ item_key: {
48
+ borderTopLeftRadius: "6px",
49
+ borderTopRightRadius: "6px",
50
+ marginTop: "20px",
51
+ borderBottom: "3px solid black"
52
+ },
53
+ component: {
54
+ fontWeight: "bold",
55
+ width: "5vw"
56
+ },
57
+ component_key: {
58
+ fontWeight: "normal",
59
+ color: "darkgray"
60
+ },
61
+ id: {
62
+ textAlign: "left",
63
+ fontWeight: "normal",
64
+ flex: 1
65
+ },
66
+ id_key: {
67
+ fontWeight: "bold"
68
+ },
69
+ time: {
70
+ fontVariantNumeric: "tabular-nums",
71
+ width: "3vw"
72
+ },
73
+ time_key: {
74
+ fontWeight: "bold"
75
+ }
76
+ };
77
+
78
+ // Stores the current time for measuring intervals between key events
79
+ let currentTime = performance.now();
80
+
81
+ /**
82
+ * Formats a given time value.
83
+ * @param {number} value - The time value in milliseconds.
84
+ * @param {string} component - The component type ("key" or others).
85
+ * @returns {string} - Formatted time string.
86
+ */
87
+ const formatTime = (value, component) =>
88
+ component === "key"
89
+ ? new Date(value).toLocaleTimeString("en-US", { hour12: false })
90
+ : `${(value / 1000).toFixed(2)}s`;
91
+
92
+ /**
93
+ * Retrieves a readable key identifier from a key code.
94
+ * @param {number} keyCode - The key code.
95
+ * @returns {string} - The key identifier.
96
+ */
97
+ const getKeyId = (keyCode) =>
98
+ Object.entries(KEY_CODES).find(([, val]) => val === keyCode)?.[0] || String(keyCode);
99
+
100
+ /**
101
+ * Injects a logging function into the methods of components.
102
+ * @param {object} components - The components to monitor.
103
+ * @param {function} inject - The logging function to inject.
104
+ * @param {function} filter - A filter to exclude certain methods.
105
+ */
106
+ const methodInject = (components, inject, filter) => {
107
+ Object.entries(components).forEach(([componentName, component]) => {
108
+ const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(component));
109
+ methods.forEach((methodName) => {
110
+ if (filter && filter(methodName)) {
111
+ return;
112
+ }
113
+ const original = component[methodName];
114
+ if (typeof original === "function") {
115
+ component[methodName] = function (...args) {
116
+ inject(componentName, methodName, ...args);
117
+ return original.apply(this, args);
118
+ };
119
+ }
120
+ });
121
+ });
122
+ };
123
+
124
+ /**
125
+ * Creates a container element for the sequence visualization.
126
+ * @returns {HTMLElement} - The container element.
127
+ */
128
+ const createSequenceContainer = () => {
129
+ const container = document.createElement("div");
130
+ container.id = "sequence-container";
131
+ Object.assign(container.style, styles.root);
132
+ document.body.appendChild(container);
133
+ return container;
134
+ };
135
+
136
+ /**
137
+ * Renders the list of sequence items into the container.
138
+ * @param {HTMLElement} container - The container element.
139
+ * @param {Array} items - The list of sequence items.
140
+ */
141
+ const renderElements = (container, items) => {
142
+ container.innerHTML = "";
143
+ items.forEach((item, idx) => {
144
+ const itemDiv = document.createElement("div");
145
+ Object.assign(itemDiv.style, { ...styles.item, ...styles[`item_${item?.component}`] });
146
+
147
+ ["component", "id", "time"].forEach((key) => {
148
+ if (item[key]) {
149
+ const div = document.createElement("div");
150
+ Object.assign(div.style, styles[key], styles[`${key}_${item.component}`]);
151
+ div.textContent = key === "time" ? formatTime(item.time, item.component) : item[key];
152
+ itemDiv.appendChild(div);
153
+ }
154
+ });
155
+
156
+ container.appendChild(itemDiv);
157
+ if (idx === items.length - 1) {
158
+ itemDiv.scrollIntoView({ behavior: "smooth" });
159
+ }
160
+ });
161
+ };
162
+
163
+ /**
164
+ * Sets up key event listeners to record key presses in the sequence.
165
+ * @param {Array} items - The list of sequence items.
166
+ * @returns {function} - A function to remove the event listener.
167
+ */
168
+ const handleKeys = (items) => {
169
+ const cb = (e) => {
170
+ items.push({ component: "key", id: getKeyId(e.keyCode), time: Date.now() });
171
+ currentTime = performance.now();
172
+ };
173
+ window.addEventListener("keydown", cb);
174
+ return () => window.removeEventListener("keydown", cb);
175
+ };
176
+
177
+ /**
178
+ * Prints a detailed log of the sequence items in a human-readable format.
179
+ *
180
+ * @param {Array} items - The list of sequence items to be printed.
181
+ */
182
+ const printSequence = (items) => {
183
+ const list = items.map(item => {
184
+ const seperator = item.separator ? "\n" : "";
185
+ const time = item?.time ? ` ${formatTime(item.time, item?.component)}` : "";
186
+ if (item.args) {
187
+ const args = item.args.map(arg => typeof arg === "object" ? "object" : arg).join(", ");
188
+ return `${seperator}${item.component}.${item.id}(${args})${time}`;
189
+ }
190
+ return `\n${item.component}: ${item.id}${time}`;
191
+ });
192
+ sdkLogger.log("sequence:\n", list.join("\n"));
193
+ };
194
+
195
+ /**
196
+ * Setup the sequence, setting up method injections and event listeners.
197
+ * @param {object} components - The components to monitor.
198
+ * @param {Array} items - The list of sequence items.
199
+ */
200
+ const setupSequence = (components, items) => {
201
+ items.push({ component: "key", id: "BOOT", time: Date.now() });
202
+ const inject = (component, id, ...args) => {
203
+ items.push({ component, id, args, time: performance.now() - currentTime });
204
+ };
205
+ methodInject(components, inject, (name) => name.startsWith("_") || name.startsWith("get"));
206
+ handleKeys(items);
207
+ sdkLogger.log("Sequence initialized.");
208
+ };
209
+
210
+ /**
211
+ * Initializes the sequence logging mechansims and UI
212
+ * @param {object} components - The components to monitor.
213
+ */
214
+ export const initSequence = (components) => {
215
+ if (!components) {
216
+ sdkLogger.error("No components to sequence");
217
+ return;
218
+ }
219
+ let container = document.getElementById("sequence-container");
220
+ if (container) {
221
+ return;
222
+ }
223
+ // Create the container for sequence visualization
224
+ container = createSequenceContainer();
225
+
226
+ // The handler is called when an item is pushed to the items array
227
+ const items = new Proxy([], {
228
+ set(target, prop, value) {
229
+ target[prop] = value;
230
+
231
+ // Render elements when new items are added, excluding length changes
232
+ if (prop !== "length") {
233
+ renderElements(container, items);
234
+ }
235
+ return true;
236
+ }
237
+ });
238
+
239
+ /* Allows to print the sequence in the debugger by calling window.printSequence */
240
+ window.printSequence = () => printSequence(items);
241
+ // Initialize the sequence logging and visualization
242
+ setupSequence(components, items);
243
+
244
+ // Render the initial state of the sequence container
245
+ renderElements(container, items);
246
+ };
247
+
248
+ /**
249
+ * Displays the sequence visualization and initializes logging mechanisms.
250
+ * @param {boolean} visible - Flag to determine if the sequence visualization should be shown.
251
+ */
252
+ export const showSequence = (visible = true) => {
253
+ const container = document.getElementById("sequence-container");
254
+ if (!container) {
255
+ sdkLogger.error("Sequence not initialized");
256
+ return;
257
+ }
258
+ container.style.visibility = visible ? "visible" : "hidden";
259
+ };