@3dsource/angular-unreal-module 0.0.174 → 0.0.177

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.174",
3
+ "version": "0.0.177",
4
4
  "description": "Angular integration for Unreal Engine Pixel Streaming",
5
5
  "keywords": [
6
6
  "3dsource",
@@ -41,6 +41,10 @@
41
41
  ".": {
42
42
  "types": "./types/3dsource-angular-unreal-module.d.ts",
43
43
  "default": "./fesm2022/3dsource-angular-unreal-module.mjs"
44
+ },
45
+ "./config": {
46
+ "types": "./types/3dsource-angular-unreal-module-config.d.ts",
47
+ "default": "./fesm2022/3dsource-angular-unreal-module-config.mjs"
44
48
  }
45
49
  },
46
50
  "type": "module"
@@ -0,0 +1,27 @@
1
+ import { InjectionToken } from '@angular/core';
2
+
3
+ /**
4
+ * Which command protocol the module speaks.
5
+ *
6
+ * - `'metabox'` (default) — the full Metabox command protocol.
7
+ * - `'default'` — a stock Pixel Streaming application: the module sends none of
8
+ * its own `MetaBoxCommand` packets.
9
+ */
10
+ type UnrealMode = 'metabox' | 'default';
11
+ interface UnrealInitialConfig {
12
+ mode?: UnrealMode;
13
+ playwright?: boolean;
14
+ customErrorsEndpoint?: string;
15
+ commandTelemetryReceiver?: string;
16
+ regionsPingUrl?: string;
17
+ screenLockerContainerId?: string;
18
+ dataChannelConnectionTimeout?: number;
19
+ streamTelemetryV2Url?: string;
20
+ fpsMonitor?: boolean;
21
+ autoHighResolution?: boolean;
22
+ }
23
+
24
+ declare const UNREAL_CONFIG: InjectionToken<UnrealInitialConfig>;
25
+
26
+ export { UNREAL_CONFIG };
27
+ export type { UnrealInitialConfig, UnrealMode };
@@ -1,6 +1,8 @@
1
1
  import * as _3dsource_angular_unreal_module from '@3dsource/angular-unreal-module';
2
2
  import * as i0 from '@angular/core';
3
- import { Signal, TemplateRef, ElementRef, InjectionToken, DestroyRef, PipeTransform } from '@angular/core';
3
+ import { Signal, TemplateRef, ElementRef, DestroyRef, PipeTransform } from '@angular/core';
4
+ import { UnrealInitialConfig } from '@3dsource/angular-unreal-module/config';
5
+ export { UNREAL_CONFIG, UnrealInitialConfig, UnrealMode } from '@3dsource/angular-unreal-module/config';
4
6
  import * as _ngrx_store from '@ngrx/store';
5
7
  import { Store } from '@ngrx/store';
6
8
  import * as rxjs from 'rxjs';
@@ -354,27 +356,6 @@ interface FreezeFrameMessage {
354
356
  progress: number | null;
355
357
  }
356
358
 
357
- /**
358
- * Which command protocol the module speaks.
359
- *
360
- * - `'metabox'` (default) — the full Metabox command protocol.
361
- * - `'default'` — a stock Pixel Streaming application: the module sends none of
362
- * its own `MetaBoxCommand` packets.
363
- */
364
- type UnrealMode = 'metabox' | 'default';
365
- interface UnrealInitialConfig {
366
- mode?: UnrealMode;
367
- playwright?: boolean;
368
- customErrorsEndpoint?: string;
369
- commandTelemetryReceiver?: string;
370
- regionsPingUrl?: string;
371
- screenLockerContainerId?: string;
372
- dataChannelConnectionTimeout?: number;
373
- streamTelemetryV2Url?: string;
374
- fpsMonitor?: boolean;
375
- autoHighResolution?: boolean;
376
- }
377
-
378
359
  interface SignalingData {
379
360
  instanceType: string;
380
361
  branchInfo: string;
@@ -385,11 +366,84 @@ interface SignalingData {
385
366
  connectionId: string;
386
367
  }
387
368
 
369
+ type Quality = 'lime' | 'red' | 'orange';
370
+
371
+ interface AggregatedStat {
372
+ quality: Quality;
373
+ aggregatedStats: InboundVideoStats;
374
+ }
375
+ interface InboundVideoStats extends RTCInboundRtpStreamStats {
376
+ VideoEncoderQP: number;
377
+ runTime: number;
378
+ pixelRatio: number;
379
+ bytesReceivedStart: number;
380
+ framesDecodedStart: number;
381
+ timestampStart: number;
382
+ videoCodec: string;
383
+ avgBitrate: number;
384
+ avgFrameRate: number;
385
+ selectedPair: {
386
+ local: {
387
+ type: string;
388
+ url: string;
389
+ };
390
+ remote: {
391
+ type: string;
392
+ url: string;
393
+ };
394
+ } | null;
395
+ currentRoundTripTime: number;
396
+ codecs: Record<string, string>;
397
+ receiveToCompositeMs: number;
398
+ bitrate: number;
399
+ }
388
400
  /**
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.
401
+ * Which orchestration transport was asked for the Cirrus endpoint:
402
+ * - `polling` — HTTP orchestration poll (`requestCirrusViaPolling`)
403
+ * - `socket` — orchestration control socket + `instanceReady`
404
+ * (`requestCirrusViaSocket`)
405
+ *
406
+ * Undefined when nothing was requested at all — a `ws://` URL that already points
407
+ * at Cirrus (`requestCirrusDirect`, dev/playwright). An adopted prefetched stream
408
+ * carries the kind the script actually used, so its state matches the native flow.
409
+ *
410
+ * Replaces the previous hostname sniffing (`/^wss:\/\/orchestration-websocket/`)
411
+ * in `selectTotalProgress` — the flow is now stated, not guessed.
412
+ */
413
+ type CirrusRequestKind = 'polling' | 'socket';
414
+ interface AwsInstance {
415
+ /**
416
+ * WebSocket URL of the CIRRUS the player connects to. In the socket flow
417
+ * this is the stream machine's `originInstanceUri`, NOT the orchestration
418
+ * URL (the control socket is tracked separately by `SignallingService`).
419
+ */
420
+ wsUrl: string | null;
421
+ /** See {@link CirrusRequestKind}. */
422
+ kind?: CirrusRequestKind;
423
+ pollingUrl: string | null;
424
+ instanceName: string | null;
425
+ /**
426
+ * Unique identifier for the streaming request.
427
+ * Coming with a new orchestration message "instanceReserved".
428
+ */
429
+ streamRequestId?: string;
430
+ /**
431
+ * Estimated time of arrival (in seconds) for the instance to be ready.
432
+ * Coming with a new orchestration message "instanceReserved".
433
+ */
434
+ eta?: number;
435
+ /**
436
+ * Progress of completion for the instance launch (0-1).
437
+ * Based on ETA time comes from the backend with new orchestration.
438
+ * If eta is not provided, this value will be undefined.
439
+ */
440
+ progressComplete?: number;
441
+ message?: string;
442
+ }
443
+
444
+ /**
445
+ * Live connection parked on `window.__stream` by `stream-prefetch.js` for
446
+ * {@link StreamAdoptionService} to adopt. Handoff contract — keep both in sync.
393
447
  */
394
448
  interface ParkedStream {
395
449
  state: 'connecting' | 'ready' | 'failed' | 'adopted';
@@ -397,7 +451,7 @@ interface ParkedStream {
397
451
  dc?: RTCDataChannel;
398
452
  /** video(+audio) MediaStream from the `track` event */
399
453
  stream?: MediaStream;
400
- /** live signalling socket (handshake already done, `requestStream` sent) */
454
+ /** Cirrus socket, handshake already done. */
401
455
  ws?: WebSocket;
402
456
  /** `data` from the streamer's `ssInfo` message — received before adoption */
403
457
  ssData?: SignalingData;
@@ -405,13 +459,23 @@ interface ParkedStream {
405
459
  machineId?: string;
406
460
  /** orchestration endpoint the script polled to get `machineId` */
407
461
  pollingUrl?: string;
462
+ /** Transport that produced it, so the adopted state matches the native flow. */
463
+ kind?: CirrusRequestKind;
464
+ /** Machine id: `originInstanceId` (socket) / `signallingServer` (polling). */
465
+ instanceName?: string | null;
466
+ /** Provisioning estimate from `instanceReserved`; socket flow only. */
467
+ eta?: number | null;
468
+ /**
469
+ * Control socket, handed over still open (the orchestration closes its own).
470
+ * Socket flow only — parked so the service can tear it down.
471
+ */
472
+ controlWs?: WebSocket;
408
473
  /** `peerConnectionOptions` the machine sent in its `config` message */
409
474
  config?: RTCConfiguration;
410
475
  /**
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.
476
+ * Reused as-is, none generated: `clientId`/`viewId` from the configurator
477
+ * cache (same values the host app dispatches), `correlationId` is the
478
+ * configurator id, `streamRequestId` comes from the orchestration.
415
479
  */
416
480
  ids: {
417
481
  clientId: string;
@@ -428,16 +492,26 @@ interface ParkedStream {
428
492
  /** Stops the script's watchdog and flips state to `adopted`. */
429
493
  adopt: () => ParkedStream;
430
494
  /**
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.
495
+ * One-shot callback fired the instant the stream settles; on the next
496
+ * microtask if already settled. Required — adoption waits on it.
435
497
  */
436
498
  onSettled: (cb: (state: ParkedStream['state']) => void) => void;
437
499
  }
500
+ /** Marker the service writes when it finds the slot free and connects itself. */
501
+ interface AppOwnedStream {
502
+ owner: 'app';
503
+ }
504
+ /** True when the slot is the app's own marker rather than a prefetched stream. */
505
+ declare function isAppOwned(slot: ParkedStream | AppOwnedStream): slot is AppOwnedStream;
438
506
  declare global {
439
507
  interface Window {
440
- __stream?: ParkedStream;
508
+ /**
509
+ * The page's stream slot AND the lock: first writer owns the connection,
510
+ * whoever finds it taken stands down. Both sides read-then-write with no
511
+ * `await` between, so exactly one wins and a page never builds two
512
+ * connections. An older script writes no `owner` — still "taken".
513
+ */
514
+ __stream?: ParkedStream | AppOwnedStream;
441
515
  }
442
516
  }
443
517
 
@@ -446,8 +520,6 @@ interface InputProps {
446
520
  suppressBrowserKeys: boolean;
447
521
  }
448
522
 
449
- type Quality = 'lime' | 'red' | 'orange';
450
-
451
523
  declare const OrchestrationMessageTypes: {
452
524
  readonly error: "error";
453
525
  readonly offer: "offer";
@@ -929,81 +1001,6 @@ type UnrealUiClasses = Partial<Record<UnrealUiPart, string | string[]>>;
929
1001
 
930
1002
  type TelemetryType = 'commandSent' | 'commandStop';
931
1003
 
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
- declare const UNREAL_CONFIG: InjectionToken<UnrealInitialConfig>;
1006
-
1007
1004
  declare const InputOptions: InputProps;
1008
1005
 
1009
1006
  /** Disconnect reasons that should trigger remote connection cleanup. */
@@ -1543,7 +1540,7 @@ declare class SignallingService extends SubService {
1543
1540
  * {@link OnOpenHandler} (which would re-`setCirrusConnected`). Reuses the
1544
1541
  * head-script's `correlationId` so correlated messages line up.
1545
1542
  */
1546
- adoptSocket(ws: WebSocket, correlationId: string): void;
1543
+ adoptSocket(ws: WebSocket, correlationId: string, controlWs?: WebSocket | null): void;
1547
1544
  private showStatusMessage;
1548
1545
  /**
1549
1546
  * Abort/teardown: closes the Cirrus socket AND the control one, handed over or
@@ -1621,44 +1618,32 @@ declare class StreamAdoptionService {
1621
1618
  private readonly signalling;
1622
1619
  private readonly webRtc;
1623
1620
  /**
1624
- * Decide adoption, WAITING for an in-flight prefetch instead of racing it.
1621
+ * Decide adoption, WAITING for an in-flight prefetch instead of racing it:
1622
+ * nothing parked → `false`; settled → adopt-if-ready; still `connecting` →
1623
+ * wait for `onSettled`. Emits exactly once.
1625
1624
  *
1626
- * - nothing parked → emit `false` at once (caller connects normally).
1627
- * - already settled (`ready`/`failed`/`adopted`) → adopt-if-ready at once.
1628
- * - still `connecting` → wait for the script's `onSettled` callback and
1629
- * adopt-if-ready the instant it fires (event-driven, zero polling latency).
1625
+ * NO time budget: provisioning can take minutes, and a deadline would open a
1626
+ * second connection mid-flight. Bounded by liveness instead — the script
1627
+ * flips to `failed` on a dead socket — and by the caller's
1628
+ * `takeUntil(abortEstablishingConnection)`.
1630
1629
  *
1631
- * Deliberately NO time budget: for DIRECT orchestration the prefetch holds
1632
- * the socket open while the orchestrator provisions a machine, which can take
1633
- * minutes (150–200s+). A fixed deadline would make Angular give up and open a
1634
- * second connection mid-provisioning — exactly the race/orphan this avoids.
1635
- * The wait is bounded by liveness instead: the script flips the parked state
1636
- * to `failed` on a dead socket (`ws.onclose`/`onerror`), and the caller wraps
1637
- * this in `takeUntil(abortEstablishingConnection)`, so a route change / teardown
1638
- * cancels it. Emits exactly once. Cancelling runs no adoption — which is what
1639
- * stops a fast route-switch from starting overlapping connections.
1640
- *
1641
- * Wrapped in `defer` so the `tryAdopt()` side effect (which dispatches
1642
- * `streamAdopted`) runs at SUBSCRIPTION time, not when the observable is
1643
- * built. The effect prepends `startWith(setEstablishingConnection(true))` —
1644
- * the single dispatch site for that boundary — which starts the telemetry
1645
- * session and subscribes its phase catalog; that must happen BEFORE
1646
- * `streamAdopted`, or `emitAdoptedConnection` fires into a session that does
1647
- * not exist yet and the whole connection waterfall is lost. `defer`
1648
- * guarantees that ordering.
1630
+ * `defer` so the `streamAdopted` dispatch happens at SUBSCRIPTION time: the
1631
+ * effect's `startWith(setEstablishingConnection(true))` must land first, or
1632
+ * the telemetry session does not exist yet and the waterfall is lost.
1649
1633
  */
1650
1634
  awaitAndAdopt$(): Observable<boolean>;
1651
1635
  /**
1652
- * Event-driven wait: the script fires `onSettled` the instant it parks
1653
- * `ready`/`failed`, so we adopt with zero polling lag. Emits exactly once.
1654
- *
1655
- * No timer/budget by design: an indefinitely `connecting` stream is valid
1656
- * (DIRECT orchestration holds the socket open for minutes while it
1657
- * provisions), and every terminal state — including a dead socket — flips to
1658
- * `ready`/`failed` and fires the hook. Teardown (route change → unsubscribe)
1659
- * sets `done`, so a late callback after cancel can't trigger a stray adoption.
1636
+ * Event-driven wait on the script's `onSettled`; emits exactly once. No timer
1637
+ * — see `awaitAndAdopt$`. Teardown sets `done`, so a late callback after
1638
+ * cancel can't trigger a stray adoption.
1660
1639
  */
1661
1640
  private awaitSettled$;
1641
+ /** Every `false` here means we are about to connect ourselves — take the slot. */
1642
+ private tryAdoptOrTakeSlot;
1643
+ /** Mark the slot as the app's, replacing a spent prefetch object. */
1644
+ private takeSlot;
1645
+ /** Best-effort teardown of a parked stream we are about to abandon. */
1646
+ private closeParked;
1662
1647
  /**
1663
1648
  * @returns `true` if a ready parked stream was adopted (caller must NOT
1664
1649
  * start a fresh connection), `false` otherwise.
@@ -3028,6 +3013,19 @@ declare const streamAdopted: _ngrx_store.ActionCreator<string, (props: {
3028
3013
  * `connectionId` (see `selectCirrusConnectionId`).
3029
3014
  */
3030
3015
  streamRequestId: string | null;
3016
+ /**
3017
+ * Which transport the prefetch used. Lets the adopted instance carry the
3018
+ * same `kind` the service's own flow would have set.
3019
+ */
3020
+ kind: CirrusRequestKind | null;
3021
+ /**
3022
+ * The machine's own id (`originInstanceId` / `signallingServer`). `null`
3023
+ * from a script that predates this field — the reducer then falls back to a
3024
+ * placeholder label.
3025
+ */
3026
+ instanceName: string | null;
3027
+ /** Provisioning estimate from `instanceReserved`; socket flow only. */
3028
+ eta: number | null;
3031
3029
  /**
3032
3030
  * `performance.now()` marks the prefetch script recorded while it
3033
3031
  * established the connection (`prefetch_start` / `ws_open` / `dc_open` /
@@ -3049,6 +3047,19 @@ declare const streamAdopted: _ngrx_store.ActionCreator<string, (props: {
3049
3047
  * `connectionId` (see `selectCirrusConnectionId`).
3050
3048
  */
3051
3049
  streamRequestId: string | null;
3050
+ /**
3051
+ * Which transport the prefetch used. Lets the adopted instance carry the
3052
+ * same `kind` the service's own flow would have set.
3053
+ */
3054
+ kind: CirrusRequestKind | null;
3055
+ /**
3056
+ * The machine's own id (`originInstanceId` / `signallingServer`). `null`
3057
+ * from a script that predates this field — the reducer then falls back to a
3058
+ * placeholder label.
3059
+ */
3060
+ instanceName: string | null;
3061
+ /** Provisioning estimate from `instanceReserved`; socket flow only. */
3062
+ eta: number | null;
3052
3063
  /**
3053
3064
  * `performance.now()` marks the prefetch script recorded while it
3054
3065
  * established the connection (`prefetch_start` / `ws_open` / `dc_open` /
@@ -3470,5 +3481,5 @@ declare const selectUserInactivityDetected: _ngrx_store.MemoizedSelector<Record<
3470
3481
  /** Used by external consumers (e.g., metabox). Do not remove. */
3471
3482
  declare const selectIsVideoPlayingAndDataChannelConnected: _ngrx_store.MemoizedSelector<Record<string, any>, boolean, (s1: boolean, s2: boolean) => boolean>;
3472
3483
 
3473
- 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 };
3474
- 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 };
3484
+ 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, 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 };
3485
+ 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, UnrealResumeSlotContext, UnrealSlotTemplateContext, UnrealState, UnrealStatusSlotContext, UnrealUiClasses, UnrealUiPart, WSCloseCodesValues, WindowAggregate };