@3dsource/angular-unreal-module 0.0.173 → 0.0.175

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.
@@ -1,4 +1,4 @@
1
- "use strict";(()=>{"use strict";const g=/metabox-configurator\/(modular|basic)\//i,m="features",k="3dsource:region-ping",w="assets/config.json",f="https://datacenter.3dsource.com/signallingserver",y="42e01f";function l(){return typeof crypto!="undefined"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,o=>{const t=Math.random()*16|0;return(o==="x"?t:t&3|8).toString(16)})}function b(o){return o.replace("http://","ws://").replace("https://","wss://")}const h="[stream-prefetch]",r=(...o)=>console.log(h,...o),c=(...o)=>console.warn(h,...o),u=(...o)=>console.error(h,...o);class T{constructor(){const t=document.currentScript||(()=>{const s=document.getElementsByTagName("script");return s[s.length-1]})(),e=t&&t.dataset||{};this.configUrl=e.configUrl||w,this.fallbackPollingUrl=e.fallbackUrl||"",this.skipRouteCheck=this.boolOr(e.skipRouteCheck,!1),this.config={ws_timeout:this.numberOr(e.wsTimeout,6e3),poll_timeout:this.numberOr(e.pollTimeout,4e3)};const i=new URLSearchParams(window.location.search);this.forceTURN=i.has("ForceTURN"),this.forceMaxBundle=i.has("ForceMaxBundle"),this.forceMonoAudio=i.has("forceMono"),this.ids={clientId:l(),viewId:l(),correlationId:l(),streamRequestId:""},this.region="",this.pc=null,this.dc=null,this.stream=null,this.ws=null,this.remoteDescriptionSet=!1,this.iceBuffer=[],this.wsTimeoutId=null,this.settled=!1}run(){if(!(typeof window=="undefined"||!("WebSocket"in window)||!("RTCPeerConnection"in window))){if(this.isNewOrchestrationEnabled()){r("skip \u2014 features.newOrchestration is enabled");return}if(this.skipRouteCheck){c("skipRouteCheck=true \u2014 ignoring URL gate; using fallback polling"),this.publishParked("connecting"),this.connect().catch(t=>this.fail("exception",t));return}if(!g.test(window.location.href)){r("skip \u2014 not a metabox-configurator/{modular|basic} route");return}r("start",{ids:this.ids}),this.publishParked("connecting"),this.connect().catch(t=>this.fail("exception",t))}}connect(){return this.mark("prefetch_start"),this.region=this.readRegion()||"",r("region from cache:",this.region||"(none)"),(this.skipRouteCheck?Promise.resolve(null):this.fetchConfig()).then(e=>{let i;if(e){if(i=this.chooseEndpoint(e),i&&!this.isAllowedEndpoint(i.url)){r("skip \u2014 signalling URL not sanctioned for prefetch",i.url),this.fail("endpoint-not-allowed");return}}else if(this.fallbackPollingUrl)c("no app config \u2014 falling back to polling",this.fallbackPollingUrl),i={type:"polling",url:this.fallbackPollingUrl};else{this.fail("no-config");return}if(!i){this.fail("no-endpoint");return}r("endpoint chosen",{type:i.type,url:i.url});const s=this.adaptUrlToRegion(i.url);return this.pollOrchestration(s).then(n=>{if(!n){this.fail("no-ws-url");return}return this.parked.machineId=n,this.parked.pollingUrl=s,r("opening socket",n),this.openSocket(n)})})}fetchConfig(){const t=new URL(this.configUrl,window.location.origin).href;return this.fetchWithTimeout(t,{credentials:"omit"},this.config.poll_timeout).then(e=>e.ok?e.json().catch(()=>null):null).catch(()=>null)}chooseEndpoint(t){const e=t.signalling,i=this.firstVersionUrl(e&&e.versions);return i?{type:"polling",url:i}:null}isAllowedEndpoint(t){if(typeof t!="string")return!1;const e=t.replace(/\/+$/,"");return e===f||e.startsWith(f+"/")}firstVersionUrl(t){if(!t||typeof t!="object")return"";for(const e of Object.keys(t))if(t[e])return t[e];return""}pollOrchestration(t){const e=`${t}${this.ids.clientId}/${this.ids.viewId}`;return this.fetchWithTimeout(e,{credentials:"omit"},this.config.poll_timeout).then(i=>i.ok?i.json().catch(()=>({})):null).then(i=>!i||!i.signallingServer?null:(this.ids.streamRequestId=i.streamRequestId||"",b(`${window.location.protocol}//${i.signallingServer}`))).catch(()=>null)}adaptUrlToRegion(t){return this.region&&t.indexOf(":region")===-1?t.replace(/signallingserver/gi,`signallingserver/region:${this.region}`):t}openSocket(t){const e=this.ids.streamRequestId,i=e?t+(t.indexOf("?")===-1?"?":"&")+"streamRequestId="+encodeURIComponent(e):t,s=new WebSocket(i);s.binaryType="arraybuffer",this.ws=s,this.parked.ws=s,this.wsTimeoutId=setTimeout(()=>{s.readyState!==WebSocket.OPEN&&this.fail("ws-timeout")},this.config.ws_timeout),s.onopen=()=>{clearTimeout(this.wsTimeoutId),this.mark("ws_open"),r("WS open \u2014 waiting for config",{region:this.region,streamRequestId:e||"(none)"})},s.onmessage=n=>this.onWsMessage(n),s.onerror=n=>{u("WS error",n),this.fail("ws-error")},s.onclose=n=>{!this.settled&&this.parked.state!=="ready"&&(c("WS closed before ready",{code:n&&n.code}),this.fail("ws-closed"))}}onWsMessage(t){let e;try{const i=typeof t.data=="string"?t.data:null;if(i===null)return;e=JSON.parse(i)}catch{return}switch(r("WS \u2190",e.type),e.type){case"ssInfo":this.parked.ssData=e.data;break;case"config":this.onConfig(e);break;case"offer":this.onOffer(e);break;case"answer":this.onAnswer(e);break;case"iceCandidate":this.onIceCandidate(e.candidate);break;default:break}}onConfig(t){if(this.pc)return;const e=Object.assign({},t.peerConnectionOptions);this.forceTURN&&(e.iceTransportPolicy="relay"),e.bundlePolicy=this.forceMaxBundle?"max-bundle":"balanced",e.iceCandidatePoolSize=1,this.parked.config=e;const i=new RTCPeerConnection(e);this.pc=i,this.parked.pc=i,r("PeerConnection created from config"),i.onicecandidate=s=>{s.candidate&&this.send({type:"iceCandidate",candidate:s.candidate})},i.ondatachannel=s=>this.wireDataChannel(s.channel),i.ontrack=s=>{s.track&&s.track.kind==="video"&&s.streams[0]&&(r("video track received"),this.stream=s.streams[0],this.parked.stream=this.stream,this.maybeReady())}}onOffer(t){return this.pc?(this.remoteDescriptionSet=!1,this.iceBuffer.length=0,this.pc.setRemoteDescription(t).then(()=>(this.remoteDescriptionSet=!0,this.flushIce(),this.pc.createAnswer())).then(e=>(e.sdp=this.mungeSDP(e.sdp||""),this.pc.setLocalDescription(e).then(()=>{r("WS \u2192 answer sent"),this.send(e)}))).catch(e=>this.fail("offer-failed",e))):Promise.resolve()}onAnswer(t){return this.pc?this.pc.setRemoteDescription(t).then(()=>{this.remoteDescriptionSet=!0,this.flushIce()}).catch(e=>this.fail("answer-failed",e)):Promise.resolve()}onIceCandidate(t){t&&(this.forceTURN&&String(t.candidate).indexOf("relay")<0||(this.remoteDescriptionSet&&this.pc?this.pc.addIceCandidate(t).catch(()=>{}):this.iceBuffer.push(t)))}flushIce(){for(const t of this.iceBuffer)this.pc.addIceCandidate(t).catch(()=>{});this.iceBuffer.length=0}wireDataChannel(t){t.binaryType="arraybuffer",this.dc=t,this.parked.dc=t,t.onmessage=e=>{this.parked.dcBuffer.push(e.data)},t.onopen=()=>{r("DataChannel open"),this.mark("dc_open"),this.maybeReady()},t.onclose=()=>{!this.settled&&this.parked.state!=="ready"&&(c("DataChannel closed before ready"),this.fail("dc-closed"))},t.readyState==="open"&&this.maybeReady()}maybeReady(){this.settled||!this.dc||this.dc.readyState!=="open"||this.stream&&(this.settled=!0,this.mark("ready"),this.parked.state="ready",r("READY \u2014 parked on window.__stream",this.parked.timings),this.fireSettled())}publishParked(t){const e=this;this.parked={state:t,pc:null,dc:null,stream:null,ws:null,ssData:void 0,machineId:void 0,pollingUrl:void 0,config:void 0,ids:this.ids,dcBuffer:[],timings:{},adopt(){return e.clearTimers(),this.state="adopted",this},onSettled(i){if(typeof i=="function"){if(this.state!=="connecting"){const s=this.state;Promise.resolve().then(()=>i(s));return}e.settledCb=i}}},window.__stream=this.parked}fireSettled(){const t=this.settledCb;if(t){this.settledCb=null;try{t(this.parked.state)}catch{}}}clearTimers(){this.wsTimeoutId&&(clearTimeout(this.wsTimeoutId),this.wsTimeoutId=null)}fail(t,e){if(!(this.parked&&(this.parked.state==="adopted"||this.parked.state==="failed"))){u("FAILED:",t,e||""),this.settled=!0,this.clearTimers();try{this.dc&&this.dc.close()}catch{}try{this.pc&&this.pc.close()}catch{}try{this.ws&&this.ws.close()}catch{}this.parked&&(this.parked.state="failed",this.parked.failReason=t,e&&(this.parked.failError=String(e&&e.message||e)),this.fireSettled())}}mungeSDP(t){let e=this.prioritizeH264Profile(t,y);e=e.replace(/(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n/gm,`$1;x-google-start-bitrate=10000;x-google-max-bitrate=100000\r
2
- `);let i="maxaveragebitrate=510000;";return i+=this.forceMonoAudio?"stereo=0;":"stereo=1;",i+="useinbandfec=1",e=e.replace("useinbandfec=1",i),e}prioritizeH264Profile(t,e){const i=t.split(`\r
3
- `),s=[];for(const n of i)if(n.startsWith("a=fmtp:")&&n.toLowerCase().includes(`profile-level-id=${e}`)){const a=n.split(":")[1]&&n.split(":")[1].split(" ")[0];a&&s.push(a)}return s.length===0?t:i.map(n=>{if(!n.startsWith("m=video"))return n;const a=n.split(" "),x=a.slice(0,3),p=a.slice(3),S=[...s.filter(d=>p.includes(d)),...p.filter(d=>!s.includes(d))];return[...x,...S].join(" ")}).join(`\r
4
- `)}send(t){const e=typeof t=="string"?t:JSON.stringify(t);if(this.ws&&this.ws.readyState===WebSocket.OPEN)try{this.ws.send(e)}catch{}}mark(t){this.parked&&(this.parked.timings[t]=performance.now())}isNewOrchestrationEnabled(){try{const t=localStorage.getItem(m);if(!t)return!1;const e=JSON.parse(t);return!!(e&&e.newOrchestration===!0)}catch{return!1}}readRegion(){try{const t=localStorage.getItem(k);if(!t)return null;const e=JSON.parse(t);return!e||typeof e.region_code!="string"||typeof e.ts!="number"||Date.now()-e.ts>=2592e6?null:e.region_code}catch{return null}}fetchWithTimeout(t,e,i){const s=new AbortController;e.signal=s.signal;const n=setTimeout(()=>s.abort(),i);return fetch(t,e).finally(()=>clearTimeout(n))}numberOr(t,e){const i=Number(t);return t!=null&&t!==""&&!Number.isNaN(i)?i:e}boolOr(t,e){return t==="true"||t===""?!0:t==="false"?!1:e}}new T().run()})();
1
+ "use strict";(()=>{"use strict";const p=/metabox-configurator\/modular\/([^/?#]+)/i,m="features",g="3dsource:region-ping",w="assets/config.json",I="assets/features.json",y="metaboxModularConfigurator",T=new Set(["insecure-endpoint","no-endpoint","no-config"]),k="42e01f";function R(a){return a.replace("http://","ws://").replace("https://","wss://")}const l="[stream-prefetch]",r=(...a)=>console.log(l,...a),c=(...a)=>console.warn(l,...a),d=(...a)=>console.error(l,...a);class S{constructor(){this.readOptions(),this.ids={clientId:"",viewId:"",correlationId:"",streamRequestId:""},this.configuratorId="",this.region="",this.newOrchestration=!1,this.environmentId="",this.controlWs=null,this.handedOverControlWs=null,this.orchestrationRetryId=null,this.instanceReadyTimeoutId=null,this.streamReadyTimeoutId=null,this.pc=null,this.dc=null,this.stream=null,this.ws=null,this.remoteDescriptionSet=!1,this.iceBuffer=[],this.wsTimeoutId=null,this.settled=!1,this.settledCbs=[]}readOptions(){const e=document.currentScript||(()=>{const n=document.getElementsByTagName("script");return n[n.length-1]})(),t=e&&e.dataset||{};this.configUrl=t.configUrl||w,this.featuresUrl=t.featuresUrl||I,this.config={ws_timeout:this.numberOr(t.wsTimeout,6e3),poll_timeout:this.numberOr(t.pollTimeout,4e3)};const i=new URLSearchParams(window.location.search);this.forceTURN=i.has("ForceTURN"),this.forceMaxBundle=i.has("ForceMaxBundle"),this.forceMonoAudio=i.has("forceMono")}run(){if(!(typeof window=="undefined"||!("WebSocket"in window)||!("RTCPeerConnection"in window))){if(window.__stream){r("skip \u2014 this page already has a stream owner",{owner:window.__stream.owner||"prefetch"});return}if(this.configuratorId=this.resolveConfiguratorId(),!this.configuratorId){r("skip \u2014 not a metabox-configurator/modular route");return}this.ids.correlationId=this.configuratorId,r("start",{configuratorId:this.configuratorId}),this.publishParked("connecting"),this.connect().catch(e=>this.fail("exception",e))}}connect(){return this.mark("prefetch_start"),this.region=this.readRegion()||"",r("region from cache:",this.region||"(none)"),Promise.all([this.fetchConfig(),this.fetchFeatures()]).then(([e,t])=>this.withConfig(e,t))}withConfig(e,t){if(this.newOrchestration=this.isNewOrchestrationEnabled(t),r("orchestration mode",{newOrchestration:this.newOrchestration}),!e){this.fail("no-config");return}return this.fetchConfigurator(e).then(i=>this.withConfigurator(e,i))}withConfigurator(e,t){if(!t){this.fail("no-configurator");return}if(this.deriveIdentity(t),!this.ids.clientId||!this.ids.viewId){this.fail("no-identity");return}r("identity from configurator cache",{clientId:this.ids.clientId,viewId:this.ids.viewId});const i=this.chooseEndpoint(e,t);if(!i||!i.url){this.fail("no-endpoint");return}if(!this.isAllowedEndpoint(i.url)){r("skip \u2014 endpoint is not encrypted",i.url),this.fail("insecure-endpoint");return}return r("endpoint chosen",i),i.type==="orchestration"?this.runOrchestration(i.url):this.runLegacy(i.url)}resolveConfiguratorId(){const e=p.exec(window.location.href);if(!e)return"";try{return decodeURIComponent(e[1])}catch{return e[1]}}fetchConfig(){return this.fetchJson(this.configUrl)}fetchFeatures(){return this.fetchJson(this.featuresUrl)}fetchJson(e){const t=new URL(e,window.location.origin).href;return this.fetchWithTimeout(t,{credentials:"omit"},this.config.poll_timeout).then(i=>i.ok?i.json().catch(()=>null):null).catch(()=>null)}isNewOrchestrationEnabled(e){const t=e&&typeof e=="object"?e:{},i=this.readFeatureOverrides();return("newOrchestration"in i?i.newOrchestration:t.newOrchestration)===!0}readFeatureOverrides(){try{const e=localStorage.getItem(m);if(!e)return{};const t=JSON.parse(e);return t&&typeof t=="object"?t:{}}catch{return{}}}fetchConfigurator(e){const t=e&&e.cdn;if(!t)return c("app config has no `cdn` \u2014 cannot read the configurator identity"),Promise.resolve(null);const i=`${String(t).replace(/\/+$/,"")}/cache/configurator/${encodeURIComponent(this.configuratorId)}.json`;return this.fetchWithTimeout(i,{credentials:"omit"},this.config.poll_timeout).then(n=>n.ok?n.json().catch(()=>null):null).then(n=>{const s=n&&n.data&&n.data.modularConfigurator;return s||(c("configurator cache response has no modularConfigurator",i),null)}).catch(()=>null)}deriveIdentity(e){const t=e.client&&e.client.id;this.ids.clientId=t?`${t}_configurator`:"",this.ids.viewId=e.id||""}chooseEndpoint(e,t){const i=this.newOrchestration?e.newSignalling:e.signalling;if(!i)return null;this.environmentId=i.environmentId||"";const n=this.versionKey(t),s=i.versions,o=n&&s&&s[n]||"";return o||c("no endpoint for Unreal version key",n||"(none)"),{type:this.newOrchestration?"orchestration":"polling",url:o}}versionKey(e){const i=(Array.isArray(e.components)?e.components.slice().sort((o,h)=>(o&&o.position)-(h&&h.position)):[])[0],n=i&&i.product&&i.product.model?i.product.model.unrealVersion:"";if(!n)return"";const s=String(n).split(".");return s.length<2?"":[s[0],s[1],"*"].join(".")}isAllowedEndpoint(e){if(typeof e!="string")return!1;let t;try{t=new URL(e,window.location.href)}catch{return!1}return t.protocol==="https:"||t.protocol==="wss:"?!0:t.protocol!=="http:"&&t.protocol!=="ws:"?!1:t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="[::1]"}readRegion(){try{const e=localStorage.getItem(g);if(!e)return null;const t=JSON.parse(e);return!t||typeof t.region_code!="string"||typeof t.ts!="number"||Date.now()-t.ts>=2592e6?null:t.region_code}catch{return null}}adaptUrlToRegion(e){return this.region&&e.indexOf(":region")===-1?e.replace(/signallingserver/gi,`signallingserver/region:${this.region}`):e}runLegacy(e){const t=this.adaptUrlToRegion(e);return this.pollOrchestration(t).then(i=>{if(!i){this.fail("no-ws-url");return}return this.parked.machineId=i,this.parked.pollingUrl=t,this.parked.kind="polling",r("opening socket",i),this.openSocket(i)})}pollOrchestration(e){const t=`${e}${this.ids.clientId}/${this.ids.viewId}`;return this.fetchWithTimeout(t,{credentials:"omit"},this.config.poll_timeout).then(i=>i.ok?i.json().catch(()=>({})):null).then(i=>!i||!i.signallingServer?null:(this.ids.streamRequestId=i.streamRequestId||"",this.parked.instanceName=i.signallingServer,R(`${window.location.protocol}//${i.signallingServer}`))).catch(()=>null)}runOrchestration(e){if(!this.environmentId)return this.fail("no-environment-id"),Promise.resolve();const t=this.adaptUrlToRegion(e);this.parked.pollingUrl=t;const i=new WebSocket(t);return this.controlWs=i,this.wsTimeoutId=setTimeout(()=>{i.readyState!==WebSocket.OPEN&&this.fail("control-ws-timeout")},this.config.ws_timeout),i.onopen=()=>{clearTimeout(this.wsTimeoutId),this.wsTimeoutId=null,this.mark("control_ws_open"),r("control socket open \u2014 requesting stream"),this.instanceReadyTimeoutId=setTimeout(()=>this.fail("instance-ready-timeout"),18e4),this.sendRequestStream()},i.onmessage=n=>this.guard("control-message-failed",()=>this.onControlMessage(n)),i.onerror=n=>{d("control WS error",n),this.fail("control-ws-error")},i.onclose=()=>{!this.settled&&!this.ws&&(c("control WS closed before instanceReady"),this.fail("control-ws-closed"))},Promise.resolve()}sendRequestStream(){this.sendControl({type:"requestStream",correlationId:this.ids.correlationId,payload:{region:this.region,environmentId:this.environmentId,context:{id:y,data:{configuratorId:this.configuratorId}}}})}sendControl(e){const t=this.controlWs;if(t&&t.readyState===WebSocket.OPEN)try{t.send(JSON.stringify(e))}catch{}}onControlMessage(e){var i;let t;try{const n=typeof e.data=="string"?e.data:null;if(n===null)return;t=JSON.parse(n)}catch{return}switch(r("control \u2190",t.type),t.type){case"instanceReserved":this.parked.eta=(i=t.payload&&t.payload.eta)!=null?i:null;break;case"instanceReady":this.onInstanceReady(t.payload||{});break;case"error":this.onOrchestrationError(t.payload||{});break;default:break}}onInstanceReady(e){if(this.ws)return;const t=e.originInstanceUri;if(!t){this.fail("no-instance-uri");return}clearTimeout(this.orchestrationRetryId),this.orchestrationRetryId=null,clearTimeout(this.instanceReadyTimeoutId),this.instanceReadyTimeoutId=null,this.ids.streamRequestId=e.streamRequestId||"",this.parked.machineId=t,this.parked.kind="socket",this.parked.instanceName=e.originInstanceId||null,this.mark("instance_ready"),r("instance ready \u2014 opening Cirrus socket",t),this.handOverControlWs(),this.openSocket(t)}onOrchestrationError(e){const t=e.code;if(t===4001||t===4002){c("orchestration refused the request, retrying",t),clearTimeout(this.orchestrationRetryId),this.orchestrationRetryId=setTimeout(()=>this.sendRequestStream(),this.config.poll_timeout);return}t!==4003&&this.fail("orchestration-error",e.message||String(t))}handOverControlWs(){const e=this.controlWs;e&&(this.controlWs=null,this.handedOverControlWs=e,this.parked.controlWs=e,e.onmessage=null,e.onerror=null,e.onclose=null,r("control socket handed over \u2014 left open for orchestration"))}closeControlWs(){const e=[this.controlWs,this.handedOverControlWs];this.controlWs=null,this.handedOverControlWs=null;for(const t of e)if(t){t.onopen=null,t.onmessage=null,t.onerror=null,t.onclose=null;try{t.close()}catch{}}}openSocket(e){const t=this.ids.streamRequestId,i=t?e+(e.indexOf("?")===-1?"?":"&")+"streamRequestId="+encodeURIComponent(t):e,n=new WebSocket(i);n.binaryType="arraybuffer",this.ws=n,this.parked.ws=n,this.wsTimeoutId=setTimeout(()=>{n.readyState!==WebSocket.OPEN&&this.fail("ws-timeout")},this.config.ws_timeout),n.onopen=()=>{clearTimeout(this.wsTimeoutId),this.wsTimeoutId=null,this.streamReadyTimeoutId=setTimeout(()=>this.fail("stream-ready-timeout"),6e4),this.mark("ws_open"),r("WS open \u2014 waiting for config",{region:this.region,streamRequestId:t||"(none)"})},n.onmessage=s=>this.guard("message-failed",()=>this.onWsMessage(s)),n.onerror=s=>{d("WS error",s),this.fail("ws-error")},n.onclose=s=>{!this.settled&&this.parked.state!=="ready"&&(c("WS closed before ready",{code:s&&s.code}),this.fail("ws-closed"))}}send(e){const t=typeof e=="string"?e:JSON.stringify(e);if(this.ws&&this.ws.readyState===WebSocket.OPEN)try{this.ws.send(t)}catch{}}onWsMessage(e){let t;try{const i=typeof e.data=="string"?e.data:null;if(i===null)return;t=JSON.parse(i)}catch{return}switch(r("WS \u2190",t.type),t.type){case"ssInfo":this.parked.ssData=t.data;break;case"config":this.onConfig(t);break;case"offer":this.onOffer(t);break;case"answer":this.onAnswer(t);break;case"iceCandidate":this.onIceCandidate(t.candidate);break;default:break}}onConfig(e){if(this.pc)return;const t=Object.assign({},e.peerConnectionOptions);this.forceTURN&&(t.iceTransportPolicy="relay"),t.bundlePolicy=this.forceMaxBundle?"max-bundle":"balanced",t.iceCandidatePoolSize=1,this.parked.config=t;const i=new RTCPeerConnection(t);this.pc=i,this.parked.pc=i,r("PeerConnection created from config"),i.onicecandidate=n=>{n.candidate&&this.send({type:"iceCandidate",candidate:n.candidate})},i.ondatachannel=n=>this.wireDataChannel(n.channel),i.ontrack=n=>{n.track&&n.track.kind==="video"&&n.streams[0]&&(r("video track received"),this.stream=n.streams[0],this.parked.stream=this.stream,this.maybeReady())}}onOffer(e){return this.pc?(this.remoteDescriptionSet=!1,this.iceBuffer.length=0,this.pc.setRemoteDescription(e).then(()=>(this.remoteDescriptionSet=!0,this.flushIce(),this.pc.createAnswer())).then(t=>(t.sdp=this.mungeSDP(t.sdp||""),this.pc.setLocalDescription(t).then(()=>{r("WS \u2192 answer sent"),this.send(t)}))).catch(t=>this.fail("offer-failed",t))):Promise.resolve()}onAnswer(e){return this.pc?this.pc.setRemoteDescription(e).then(()=>{this.remoteDescriptionSet=!0,this.flushIce()}).catch(t=>this.fail("answer-failed",t)):Promise.resolve()}onIceCandidate(e){e&&(this.forceTURN&&String(e.candidate).indexOf("relay")<0||(this.remoteDescriptionSet&&this.pc?this.pc.addIceCandidate(e).catch(()=>{}):this.iceBuffer.push(e)))}flushIce(){for(const e of this.iceBuffer)this.pc.addIceCandidate(e).catch(()=>{});this.iceBuffer.length=0}wireDataChannel(e){e.binaryType="arraybuffer",this.dc=e,this.parked.dc=e,e.onmessage=t=>{this.parked.dcBuffer.push(t.data)},e.onopen=()=>{r("DataChannel open"),this.mark("dc_open"),this.maybeReady()},e.onclose=()=>{!this.settled&&this.parked.state!=="ready"&&(c("DataChannel closed before ready"),this.fail("dc-closed"))},e.readyState==="open"&&this.maybeReady()}maybeReady(){this.settled||!this.dc||this.dc.readyState!=="open"||this.stream&&(this.settled=!0,clearTimeout(this.streamReadyTimeoutId),this.streamReadyTimeoutId=null,this.mark("ready"),this.parked.state="ready",r("READY \u2014 parked on window.__stream",this.parked.timings),this.fireSettled())}mungeSDP(e){let t=this.prioritizeH264Profile(e,k);t=t.replace(/(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n/gm,`$1;x-google-start-bitrate=10000;x-google-max-bitrate=100000\r
2
+ `);let i="maxaveragebitrate=510000;";return i+=this.forceMonoAudio?"stereo=0;":"stereo=1;",i+="useinbandfec=1",t=t.replace("useinbandfec=1",i),t}prioritizeH264Profile(e,t){const i=e.split(`\r
3
+ `),n=[];for(const s of i)if(s.startsWith("a=fmtp:")&&s.toLowerCase().includes(`profile-level-id=${t}`)){const o=s.split(":")[1]&&s.split(":")[1].split(" ")[0];o&&n.push(o)}return n.length===0?e:i.map(s=>{if(!s.startsWith("m=video"))return s;const o=s.split(" "),h=o.slice(0,3),f=o.slice(3),O=[...n.filter(u=>f.includes(u)),...f.filter(u=>!n.includes(u))];return[...h,...O].join(" ")}).join(`\r
4
+ `)}publishParked(e){const t=this;this.parked={state:e,pc:null,dc:null,stream:null,ws:null,ssData:void 0,machineId:void 0,pollingUrl:void 0,kind:void 0,instanceName:void 0,eta:void 0,controlWs:void 0,config:void 0,ids:this.ids,dcBuffer:[],timings:{},adopt(){return t.clearTimers(),this.state="adopted",this},onSettled(i){if(typeof i=="function"){if(this.state!=="connecting"){const n=this.state;Promise.resolve().then(()=>i(n));return}t.settledCbs.push(i)}}},window.__stream=this.parked}fireSettled(){const e=this.settledCbs;this.settledCbs=[];for(const t of e)try{t(this.parked.state)}catch{}}mark(e){this.parked&&(this.parked.timings[e]=performance.now())}clearTimers(){this.wsTimeoutId&&(clearTimeout(this.wsTimeoutId),this.wsTimeoutId=null),clearTimeout(this.orchestrationRetryId),this.orchestrationRetryId=null,clearTimeout(this.instanceReadyTimeoutId),this.instanceReadyTimeoutId=null,clearTimeout(this.streamReadyTimeoutId),this.streamReadyTimeoutId=null}fail(e,t){if(!(this.parked&&(this.parked.state==="adopted"||this.parked.state==="failed"))){(T.has(e)?r:d)("FAILED:",e,t||""),this.settled=!0,this.clearTimers(),this.closeControlWs();try{this.dc&&this.dc.close()}catch{}try{this.pc&&this.pc.close()}catch{}try{this.ws&&this.ws.close()}catch{}this.parked&&(this.parked.state="failed",this.parked.failReason=e,t&&(this.parked.failError=String(t&&t.message||t)),this.fireSettled())}}guard(e,t){try{t()}catch(i){this.fail(e,i)}}fetchWithTimeout(e,t,i){const n=new AbortController;t.signal=n.signal;const s=setTimeout(()=>n.abort(),i);return fetch(e,t).finally(()=>clearTimeout(s))}numberOr(e,t){const i=Number(e);return e!=null&&e!==""&&!Number.isNaN(i)?i:t}}new S().run()})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3dsource/angular-unreal-module",
3
- "version": "0.0.173",
3
+ "version": "0.0.175",
4
4
  "description": "Angular integration for Unreal Engine Pixel Streaming",
5
5
  "keywords": [
6
6
  "3dsource",
@@ -385,11 +385,84 @@ interface SignalingData {
385
385
  connectionId: string;
386
386
  }
387
387
 
388
+ type Quality = 'lime' | 'red' | 'orange';
389
+
390
+ interface AggregatedStat {
391
+ quality: Quality;
392
+ aggregatedStats: InboundVideoStats;
393
+ }
394
+ interface InboundVideoStats extends RTCInboundRtpStreamStats {
395
+ VideoEncoderQP: number;
396
+ runTime: number;
397
+ pixelRatio: number;
398
+ bytesReceivedStart: number;
399
+ framesDecodedStart: number;
400
+ timestampStart: number;
401
+ videoCodec: string;
402
+ avgBitrate: number;
403
+ avgFrameRate: number;
404
+ selectedPair: {
405
+ local: {
406
+ type: string;
407
+ url: string;
408
+ };
409
+ remote: {
410
+ type: string;
411
+ url: string;
412
+ };
413
+ } | null;
414
+ currentRoundTripTime: number;
415
+ codecs: Record<string, string>;
416
+ receiveToCompositeMs: number;
417
+ bitrate: number;
418
+ }
419
+ /**
420
+ * Which orchestration transport was asked for the Cirrus endpoint:
421
+ * - `polling` — HTTP orchestration poll (`requestCirrusViaPolling`)
422
+ * - `socket` — orchestration control socket + `instanceReady`
423
+ * (`requestCirrusViaSocket`)
424
+ *
425
+ * Undefined when nothing was requested at all — a `ws://` URL that already points
426
+ * at Cirrus (`requestCirrusDirect`, dev/playwright). An adopted prefetched stream
427
+ * carries the kind the script actually used, so its state matches the native flow.
428
+ *
429
+ * Replaces the previous hostname sniffing (`/^wss:\/\/orchestration-websocket/`)
430
+ * in `selectTotalProgress` — the flow is now stated, not guessed.
431
+ */
432
+ type CirrusRequestKind = 'polling' | 'socket';
433
+ interface AwsInstance {
434
+ /**
435
+ * WebSocket URL of the CIRRUS the player connects to. In the socket flow
436
+ * this is the stream machine's `originInstanceUri`, NOT the orchestration
437
+ * URL (the control socket is tracked separately by `SignallingService`).
438
+ */
439
+ wsUrl: string | null;
440
+ /** See {@link CirrusRequestKind}. */
441
+ kind?: CirrusRequestKind;
442
+ pollingUrl: string | null;
443
+ instanceName: string | null;
444
+ /**
445
+ * Unique identifier for the streaming request.
446
+ * Coming with a new orchestration message "instanceReserved".
447
+ */
448
+ streamRequestId?: string;
449
+ /**
450
+ * Estimated time of arrival (in seconds) for the instance to be ready.
451
+ * Coming with a new orchestration message "instanceReserved".
452
+ */
453
+ eta?: number;
454
+ /**
455
+ * Progress of completion for the instance launch (0-1).
456
+ * Based on ETA time comes from the backend with new orchestration.
457
+ * If eta is not provided, this value will be undefined.
458
+ */
459
+ progressComplete?: number;
460
+ message?: string;
461
+ }
462
+
388
463
  /**
389
- * Live WebRTC connection parked on `window.__stream` by the `stream-prefetch.js`
390
- * head-script, ready for the Angular services to ADOPT instead of building a
391
- * connection from scratch. The shape is the handoff contract between that
392
- * framework-free script and {@link StreamAdoptionService} — keep the two in sync.
464
+ * Live connection parked on `window.__stream` by `stream-prefetch.js` for
465
+ * {@link StreamAdoptionService} to adopt. Handoff contract — keep both in sync.
393
466
  */
394
467
  interface ParkedStream {
395
468
  state: 'connecting' | 'ready' | 'failed' | 'adopted';
@@ -397,7 +470,7 @@ interface ParkedStream {
397
470
  dc?: RTCDataChannel;
398
471
  /** video(+audio) MediaStream from the `track` event */
399
472
  stream?: MediaStream;
400
- /** live signalling socket (handshake already done, `requestStream` sent) */
473
+ /** Cirrus socket, handshake already done. */
401
474
  ws?: WebSocket;
402
475
  /** `data` from the streamer's `ssInfo` message — received before adoption */
403
476
  ssData?: SignalingData;
@@ -405,13 +478,23 @@ interface ParkedStream {
405
478
  machineId?: string;
406
479
  /** orchestration endpoint the script polled to get `machineId` */
407
480
  pollingUrl?: string;
481
+ /** Transport that produced it, so the adopted state matches the native flow. */
482
+ kind?: CirrusRequestKind;
483
+ /** Machine id: `originInstanceId` (socket) / `signallingServer` (polling). */
484
+ instanceName?: string | null;
485
+ /** Provisioning estimate from `instanceReserved`; socket flow only. */
486
+ eta?: number | null;
487
+ /**
488
+ * Control socket, handed over still open (the orchestration closes its own).
489
+ * Socket flow only — parked so the service can tear it down.
490
+ */
491
+ controlWs?: WebSocket;
408
492
  /** `peerConnectionOptions` the machine sent in its `config` message */
409
493
  config?: RTCConfiguration;
410
494
  /**
411
- * ids the script generated; Angular reuses them (no regeneration).
412
- * `streamRequestId` is the exception — it is NOT generated but read from the
413
- * polling response and passed to Cirrus on the upgrade URL; empty when the
414
- * backend didn't issue one.
495
+ * Reused as-is, none generated: `clientId`/`viewId` from the configurator
496
+ * cache (same values the host app dispatches), `correlationId` is the
497
+ * configurator id, `streamRequestId` comes from the orchestration.
415
498
  */
416
499
  ids: {
417
500
  clientId: string;
@@ -428,16 +511,26 @@ interface ParkedStream {
428
511
  /** Stops the script's watchdog and flips state to `adopted`. */
429
512
  adopt: () => ParkedStream;
430
513
  /**
431
- * Register a one-shot callback fired the instant the stream settles
432
- * (`ready`/`failed`); fires on the next microtask if already settled. This is
433
- * how {@link StreamAdoptionService} adopts event-driven (no polling) — the
434
- * head-script must provide it.
514
+ * One-shot callback fired the instant the stream settles; on the next
515
+ * microtask if already settled. Required — adoption waits on it.
435
516
  */
436
517
  onSettled: (cb: (state: ParkedStream['state']) => void) => void;
437
518
  }
519
+ /** Marker the service writes when it finds the slot free and connects itself. */
520
+ interface AppOwnedStream {
521
+ owner: 'app';
522
+ }
523
+ /** True when the slot is the app's own marker rather than a prefetched stream. */
524
+ declare function isAppOwned(slot: ParkedStream | AppOwnedStream): slot is AppOwnedStream;
438
525
  declare global {
439
526
  interface Window {
440
- __stream?: ParkedStream;
527
+ /**
528
+ * The page's stream slot AND the lock: first writer owns the connection,
529
+ * whoever finds it taken stands down. Both sides read-then-write with no
530
+ * `await` between, so exactly one wins and a page never builds two
531
+ * connections. An older script writes no `owner` — still "taken".
532
+ */
533
+ __stream?: ParkedStream | AppOwnedStream;
441
534
  }
442
535
  }
443
536
 
@@ -446,8 +539,6 @@ interface InputProps {
446
539
  suppressBrowserKeys: boolean;
447
540
  }
448
541
 
449
- type Quality = 'lime' | 'red' | 'orange';
450
-
451
542
  declare const OrchestrationMessageTypes: {
452
543
  readonly error: "error";
453
544
  readonly offer: "offer";
@@ -929,79 +1020,6 @@ type UnrealUiClasses = Partial<Record<UnrealUiPart, string | string[]>>;
929
1020
 
930
1021
  type TelemetryType = 'commandSent' | 'commandStop';
931
1022
 
932
- interface AggregatedStat {
933
- quality: Quality;
934
- aggregatedStats: InboundVideoStats;
935
- }
936
- interface InboundVideoStats extends RTCInboundRtpStreamStats {
937
- VideoEncoderQP: number;
938
- runTime: number;
939
- pixelRatio: number;
940
- bytesReceivedStart: number;
941
- framesDecodedStart: number;
942
- timestampStart: number;
943
- videoCodec: string;
944
- avgBitrate: number;
945
- avgFrameRate: number;
946
- selectedPair: {
947
- local: {
948
- type: string;
949
- url: string;
950
- };
951
- remote: {
952
- type: string;
953
- url: string;
954
- };
955
- } | null;
956
- currentRoundTripTime: number;
957
- codecs: Record<string, string>;
958
- receiveToCompositeMs: number;
959
- bitrate: number;
960
- }
961
- /**
962
- * Which orchestration transport was asked for the Cirrus endpoint:
963
- * - `polling` — HTTP orchestration poll (`requestCirrusViaPolling`)
964
- * - `socket` — orchestration control socket + `instanceReady`
965
- * (`requestCirrusViaSocket`)
966
- *
967
- * Undefined when nothing was requested at all — a `ws://` URL that already points
968
- * at Cirrus (`requestCirrusDirect`, dev/playwright) or an adopted prefetched
969
- * stream. Those are not request kinds, they are the absence of a request.
970
- *
971
- * Replaces the previous hostname sniffing (`/^wss:\/\/orchestration-websocket/`)
972
- * in `selectTotalProgress` — the flow is now stated, not guessed.
973
- */
974
- type CirrusRequestKind = 'polling' | 'socket';
975
- interface AwsInstance {
976
- /**
977
- * WebSocket URL of the CIRRUS the player connects to. In the socket flow
978
- * this is the stream machine's `originInstanceUri`, NOT the orchestration
979
- * URL (the control socket is tracked separately by `SignallingService`).
980
- */
981
- wsUrl: string | null;
982
- /** See {@link CirrusRequestKind}. */
983
- kind?: CirrusRequestKind;
984
- pollingUrl: string | null;
985
- instanceName: string | null;
986
- /**
987
- * Unique identifier for the streaming request.
988
- * Coming with a new orchestration message "instanceReserved".
989
- */
990
- streamRequestId?: string;
991
- /**
992
- * Estimated time of arrival (in seconds) for the instance to be ready.
993
- * Coming with a new orchestration message "instanceReserved".
994
- */
995
- eta?: number;
996
- /**
997
- * Progress of completion for the instance launch (0-1).
998
- * Based on ETA time comes from the backend with new orchestration.
999
- * If eta is not provided, this value will be undefined.
1000
- */
1001
- progressComplete?: number;
1002
- message?: string;
1003
- }
1004
-
1005
1023
  declare const UNREAL_CONFIG: InjectionToken<UnrealInitialConfig>;
1006
1024
 
1007
1025
  declare const InputOptions: InputProps;
@@ -1319,6 +1337,18 @@ declare class InputService extends SubService {
1319
1337
  private registerHoveringMouseEvents;
1320
1338
  private registerMouseEnterAndLeaveEvents;
1321
1339
  private isKeyCodeBrowserKey;
1340
+ /**
1341
+ * The key code Unreal expects, which is the Windows virtual-key code.
1342
+ *
1343
+ * `e.keyCode` is not that on Gecko: Firefox reports the punctuation keys by
1344
+ * their ASCII value — `=` as 61 and `-` as 173, where Chrome sends 187 and 189
1345
+ * — so zoom-on-plus/minus reached the engine as codes it does not know.
1346
+ * `KeyboardNumericCode` is keyed by `e.code` and holds the virtual-key value,
1347
+ * so it resolves the same number on every browser; a no-op on Chrome.
1348
+ *
1349
+ * Checked after the right-hand modifiers, which need their own distinct codes
1350
+ * that the map does not carry.
1351
+ */
1322
1352
  private getKeyCode;
1323
1353
  private registerKeyboardEvents;
1324
1354
  private startListenKeys;
@@ -1531,7 +1561,7 @@ declare class SignallingService extends SubService {
1531
1561
  * {@link OnOpenHandler} (which would re-`setCirrusConnected`). Reuses the
1532
1562
  * head-script's `correlationId` so correlated messages line up.
1533
1563
  */
1534
- adoptSocket(ws: WebSocket, correlationId: string): void;
1564
+ adoptSocket(ws: WebSocket, correlationId: string, controlWs?: WebSocket | null): void;
1535
1565
  private showStatusMessage;
1536
1566
  /**
1537
1567
  * Abort/teardown: closes the Cirrus socket AND the control one, handed over or
@@ -1609,44 +1639,32 @@ declare class StreamAdoptionService {
1609
1639
  private readonly signalling;
1610
1640
  private readonly webRtc;
1611
1641
  /**
1612
- * Decide adoption, WAITING for an in-flight prefetch instead of racing it.
1642
+ * Decide adoption, WAITING for an in-flight prefetch instead of racing it:
1643
+ * nothing parked → `false`; settled → adopt-if-ready; still `connecting` →
1644
+ * wait for `onSettled`. Emits exactly once.
1613
1645
  *
1614
- * - nothing parked → emit `false` at once (caller connects normally).
1615
- * - already settled (`ready`/`failed`/`adopted`) → adopt-if-ready at once.
1616
- * - still `connecting` → wait for the script's `onSettled` callback and
1617
- * adopt-if-ready the instant it fires (event-driven, zero polling latency).
1646
+ * NO time budget: provisioning can take minutes, and a deadline would open a
1647
+ * second connection mid-flight. Bounded by liveness instead — the script
1648
+ * flips to `failed` on a dead socket — and by the caller's
1649
+ * `takeUntil(abortEstablishingConnection)`.
1618
1650
  *
1619
- * Deliberately NO time budget: for DIRECT orchestration the prefetch holds
1620
- * the socket open while the orchestrator provisions a machine, which can take
1621
- * minutes (150–200s+). A fixed deadline would make Angular give up and open a
1622
- * second connection mid-provisioning — exactly the race/orphan this avoids.
1623
- * The wait is bounded by liveness instead: the script flips the parked state
1624
- * to `failed` on a dead socket (`ws.onclose`/`onerror`), and the caller wraps
1625
- * this in `takeUntil(abortEstablishingConnection)`, so a route change / teardown
1626
- * cancels it. Emits exactly once. Cancelling runs no adoption — which is what
1627
- * stops a fast route-switch from starting overlapping connections.
1628
- *
1629
- * Wrapped in `defer` so the `tryAdopt()` side effect (which dispatches
1630
- * `streamAdopted`) runs at SUBSCRIPTION time, not when the observable is
1631
- * built. The effect prepends `startWith(setEstablishingConnection(true))` —
1632
- * the single dispatch site for that boundary — which starts the telemetry
1633
- * session and subscribes its phase catalog; that must happen BEFORE
1634
- * `streamAdopted`, or `emitAdoptedConnection` fires into a session that does
1635
- * not exist yet and the whole connection waterfall is lost. `defer`
1636
- * guarantees that ordering.
1651
+ * `defer` so the `streamAdopted` dispatch happens at SUBSCRIPTION time: the
1652
+ * effect's `startWith(setEstablishingConnection(true))` must land first, or
1653
+ * the telemetry session does not exist yet and the waterfall is lost.
1637
1654
  */
1638
1655
  awaitAndAdopt$(): Observable<boolean>;
1639
1656
  /**
1640
- * Event-driven wait: the script fires `onSettled` the instant it parks
1641
- * `ready`/`failed`, so we adopt with zero polling lag. Emits exactly once.
1642
- *
1643
- * No timer/budget by design: an indefinitely `connecting` stream is valid
1644
- * (DIRECT orchestration holds the socket open for minutes while it
1645
- * provisions), and every terminal state — including a dead socket — flips to
1646
- * `ready`/`failed` and fires the hook. Teardown (route change → unsubscribe)
1647
- * sets `done`, so a late callback after cancel can't trigger a stray adoption.
1657
+ * Event-driven wait on the script's `onSettled`; emits exactly once. No timer
1658
+ * — see `awaitAndAdopt$`. Teardown sets `done`, so a late callback after
1659
+ * cancel can't trigger a stray adoption.
1648
1660
  */
1649
1661
  private awaitSettled$;
1662
+ /** Every `false` here means we are about to connect ourselves — take the slot. */
1663
+ private tryAdoptOrTakeSlot;
1664
+ /** Mark the slot as the app's, replacing a spent prefetch object. */
1665
+ private takeSlot;
1666
+ /** Best-effort teardown of a parked stream we are about to abandon. */
1667
+ private closeParked;
1650
1668
  /**
1651
1669
  * @returns `true` if a ready parked stream was adopted (caller must NOT
1652
1670
  * start a fresh connection), `false` otherwise.
@@ -3016,6 +3034,19 @@ declare const streamAdopted: _ngrx_store.ActionCreator<string, (props: {
3016
3034
  * `connectionId` (see `selectCirrusConnectionId`).
3017
3035
  */
3018
3036
  streamRequestId: string | null;
3037
+ /**
3038
+ * Which transport the prefetch used. Lets the adopted instance carry the
3039
+ * same `kind` the service's own flow would have set.
3040
+ */
3041
+ kind: CirrusRequestKind | null;
3042
+ /**
3043
+ * The machine's own id (`originInstanceId` / `signallingServer`). `null`
3044
+ * from a script that predates this field — the reducer then falls back to a
3045
+ * placeholder label.
3046
+ */
3047
+ instanceName: string | null;
3048
+ /** Provisioning estimate from `instanceReserved`; socket flow only. */
3049
+ eta: number | null;
3019
3050
  /**
3020
3051
  * `performance.now()` marks the prefetch script recorded while it
3021
3052
  * established the connection (`prefetch_start` / `ws_open` / `dc_open` /
@@ -3037,6 +3068,19 @@ declare const streamAdopted: _ngrx_store.ActionCreator<string, (props: {
3037
3068
  * `connectionId` (see `selectCirrusConnectionId`).
3038
3069
  */
3039
3070
  streamRequestId: string | null;
3071
+ /**
3072
+ * Which transport the prefetch used. Lets the adopted instance carry the
3073
+ * same `kind` the service's own flow would have set.
3074
+ */
3075
+ kind: CirrusRequestKind | null;
3076
+ /**
3077
+ * The machine's own id (`originInstanceId` / `signallingServer`). `null`
3078
+ * from a script that predates this field — the reducer then falls back to a
3079
+ * placeholder label.
3080
+ */
3081
+ instanceName: string | null;
3082
+ /** Provisioning estimate from `instanceReserved`; socket flow only. */
3083
+ eta: number | null;
3040
3084
  /**
3041
3085
  * `performance.now()` marks the prefetch script recorded while it
3042
3086
  * established the connection (`prefetch_start` / `ws_open` / `dc_open` /
@@ -3458,5 +3502,5 @@ declare const selectUserInactivityDetected: _ngrx_store.MemoizedSelector<Record<
3458
3502
  /** Used by external consumers (e.g., metabox). Do not remove. */
3459
3503
  declare const selectIsVideoPlayingAndDataChannelConnected: _ngrx_store.MemoizedSelector<Record<string, any>, boolean, (s1: boolean, s2: boolean) => boolean>;
3460
3504
 
3461
- export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DESTROY_DISCONNECT_REASONS, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, INSTANCE_READY_TIMEOUT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, LatencyTimings, LoadingProgressService, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PlayerCountHandler, RECONNECT_CONFIG, REGION_PING_ACCURATE_SAMPLES, REGION_PING_BACKGROUND_REFRESH_DELAY_MS, REGION_PING_CACHE_KEY, REGION_PING_CACHE_TTL_MS, REGION_PING_WARMUP_DEADLINE_MS, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamAdoptionService, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealAfkSlotDirective, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealResumeSlotDirective, UnrealSceneComponent, UnrealStatusMessage, UnrealStatusSlotDirective, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, isMetaboxMode, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, resolveSkin, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
3462
- export type { AggregatedStat, AnySignalingMessage, AwsInstance, BootstrapInfo, CandidateMessage, CirrusRequestKind, CloseReason, CommandInProgress, ConfigMessage, ConnectionError, ControlSchemeValues, DisconnectReasonType, EmittedMilestone, EventId, FpsLowData, FreezeFrameMessage, InboundVideoStats, InputProps, InstanceReady, InstanceReserved, InterruptClientStream, ListStreamersMessage, MessageBase, MessageTypeValues, OrchestrationErrorMessage, OrchestrationMessageType, P2PEstablishedMessage, ParkedStream, PhaseEndedData, PhaseOverlay, PhaseParam, PlayerCountMessage, PollingOrchestrationMessage, Quality, QualityAnomalyData, ReceivedFile, RequestStream, ResourceBucket, ResourceTotals, SSInfo, SampleData, SelectedIceCandidatePair, SessionEndReason, SessionEndedData, SessionStartedData, SignalingData, SignalingMessageHandler, SignalingMessageMap, SignalingRetryData, SignalingRetryKind, SlowResource, StreamConfig, StreamRequestContext, StreamResolutionProps, StreamTelemetryEvent, StreamTelemetryEventMap, StreamTelemetryEventName, StreamTelemetryLifecycleData, StreamTelemetryLifecycleEventName, StreamTelemetryTrackData, StreamerListMessage, TelemetryEventEnvelope, TelemetryLifecycleEnvelope, TelemetryType, UnknownFields, UnrealAfkSlotContext, UnrealCallbackDescriptor, UnrealCallbackEventMap, UnrealCallbackJson, UnrealCallbackJsonWrapped, UnrealInitialConfig, UnrealMode, UnrealResumeSlotContext, UnrealSlotTemplateContext, UnrealState, UnrealStatusSlotContext, UnrealUiClasses, UnrealUiPart, WSCloseCodesValues, WindowAggregate };
3505
+ export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DESTROY_DISCONNECT_REASONS, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, INSTANCE_READY_TIMEOUT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, LatencyTimings, LoadingProgressService, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PlayerCountHandler, RECONNECT_CONFIG, REGION_PING_ACCURATE_SAMPLES, REGION_PING_BACKGROUND_REFRESH_DELAY_MS, REGION_PING_CACHE_KEY, REGION_PING_CACHE_TTL_MS, REGION_PING_WARMUP_DEADLINE_MS, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamAdoptionService, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealAfkSlotDirective, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealResumeSlotDirective, UnrealSceneComponent, UnrealStatusMessage, UnrealStatusSlotDirective, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, isAppOwned, isMetaboxMode, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, resolveSkin, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
3506
+ export type { AggregatedStat, AnySignalingMessage, AppOwnedStream, AwsInstance, BootstrapInfo, CandidateMessage, CirrusRequestKind, CloseReason, CommandInProgress, ConfigMessage, ConnectionError, ControlSchemeValues, DisconnectReasonType, EmittedMilestone, EventId, FpsLowData, FreezeFrameMessage, InboundVideoStats, InputProps, InstanceReady, InstanceReserved, InterruptClientStream, ListStreamersMessage, MessageBase, MessageTypeValues, OrchestrationErrorMessage, OrchestrationMessageType, P2PEstablishedMessage, ParkedStream, PhaseEndedData, PhaseOverlay, PhaseParam, PlayerCountMessage, PollingOrchestrationMessage, Quality, QualityAnomalyData, ReceivedFile, RequestStream, ResourceBucket, ResourceTotals, SSInfo, SampleData, SelectedIceCandidatePair, SessionEndReason, SessionEndedData, SessionStartedData, SignalingData, SignalingMessageHandler, SignalingMessageMap, SignalingRetryData, SignalingRetryKind, SlowResource, StreamConfig, StreamRequestContext, StreamResolutionProps, StreamTelemetryEvent, StreamTelemetryEventMap, StreamTelemetryEventName, StreamTelemetryLifecycleData, StreamTelemetryLifecycleEventName, StreamTelemetryTrackData, StreamerListMessage, TelemetryEventEnvelope, TelemetryLifecycleEnvelope, TelemetryType, UnknownFields, UnrealAfkSlotContext, UnrealCallbackDescriptor, UnrealCallbackEventMap, UnrealCallbackJson, UnrealCallbackJsonWrapped, UnrealInitialConfig, UnrealMode, UnrealResumeSlotContext, UnrealSlotTemplateContext, UnrealState, UnrealStatusSlotContext, UnrealUiClasses, UnrealUiPart, WSCloseCodesValues, WindowAggregate };