@3dsource/angular-unreal-module 0.0.146-dev.0 → 0.0.146-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- "use strict";(()=>{"use strict";const l="metabox-configurator",d=/metabox-configurator\/(modular|basic)\/([^/?#]+)/i,u="3dsource:region-ping",f="assets/config.json",p="42e01f";function a(){return typeof crypto!="undefined"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,o=>{const e=Math.random()*16|0;return(o==="x"?e:e&3|8).toString(16)})}function m(o){return o.replace("http://","ws://").replace("https://","wss://")}class g{constructor(){const e=document.currentScript||(()=>{const n=document.getElementsByTagName("script");return n[n.length-1]})(),t=e&&e.dataset||{};this.configUrl=t.configUrl||f,this.config={watchdog_ms:this.numberOr(t.watchdogMs,15e3),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"),this.ids={clientId:a(),viewId:a(),correlationId:a()},this.context=null,this.environmentId="",this.orchestrationType="",this.region="",this.pc=null,this.dc=null,this.stream=null,this.ws=null,this.remoteDescriptionSet=!1,this.iceBuffer=[],this.watchdogId=null,this.wsTimeoutId=null,this.settled=!1}run(){if(typeof window=="undefined"||!("WebSocket"in window)||!("RTCPeerConnection"in window)||window.location.href.indexOf(l)===-1)return;const e=this.parseConfiguratorUrl();e&&(this.context={id:e.contextId,data:{configuratorId:e.configuratorId}},this.publishParked("connecting"),this.connect().catch(t=>this.fail("exception",t)))}parseConfiguratorUrl(){const e=window.location.pathname.match(d);return e?{contextId:e[1].toLowerCase()==="modular"?"metaboxModularConfigurator":"metaboxBasicConfigurator",configuratorId:decodeURIComponent(e[2])}:null}connect(){return this.mark("prefetch_start"),this.region=this.readRegion()||"",this.fetchConfig().then(e=>{if(!e){this.fail("no-config");return}const t=this.chooseEndpoint(e);if(!t){this.fail("no-endpoint");return}if(!t.environmentId){this.fail("no-environment-id");return}this.orchestrationType=t.type,this.environmentId=t.environmentId;const i=this.adaptUrlToRegion(t.url);return(t.type==="polling"?this.pollOrchestration(i):Promise.resolve(i)).then(r=>{if(!r){this.fail("no-ws-url");return}return this.parked.machineId=r,this.openSocket(r)})})}fetchConfig(){const e=new URL(this.configUrl,window.location.origin).href;return this.fetchWithTimeout(e,{credentials:"omit"},this.config.poll_timeout).then(t=>t.ok?t.json().catch(()=>null):null).catch(()=>null)}chooseEndpoint(e){const t=e.newSignalling,i=this.firstVersionUrl(t&&t.versions);if(i&&/^wss?:\/\//i.test(i))return{type:"direct",url:i,environmentId:t&&t.environmentId||""};const n=e.signalling,r=this.firstVersionUrl(n&&n.versions);return r?{type:"polling",url:r,environmentId:n&&n.environmentId||""}:null}firstVersionUrl(e){if(!e||typeof e!="object")return"";for(const t of Object.keys(e))if(e[t])return e[t];return""}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?m(`${window.location.protocol}//${i.signallingServer}`):null).catch(()=>null)}adaptUrlToRegion(e){return this.region&&e.indexOf(":region")===-1?e.replace(/signallingserver/gi,`signallingserver/region:${this.region}`):e}openSocket(e){const t=new WebSocket(e);t.binaryType="arraybuffer",this.ws=t,this.parked.ws=t,this.wsTimeoutId=setTimeout(()=>{t.readyState!==WebSocket.OPEN&&this.fail("ws-timeout")},this.config.ws_timeout),t.onopen=()=>{clearTimeout(this.wsTimeoutId),this.mark("ws_open"),this.sendRequestStream()},t.onmessage=i=>this.onWsMessage(i),t.onerror=()=>this.fail("ws-error"),t.onclose=()=>{!this.settled&&this.parked.state!=="ready"&&this.fail("ws-closed")},this.armWatchdog()}sendRequestStream(){this.send({type:"requestStream",correlationId:this.ids.correlationId,payload:{region:this.region,environmentId:this.environmentId,context:this.context}})}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(t.type){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;case"ping":this.send({type:"pong",source:"front"});break;case"streamerDisconnected":case"playerDisconnected":this.fail("streamer-disconnected");break;case"error":this.fail("orchestration-error");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,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]&&(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(()=>{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=()=>{this.mark("dc_open"),this.maybeReady()},e.onclose=()=>{!this.settled&&this.parked.state!=="ready"&&this.fail("dc-closed")},e.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")}publishParked(e){const t=this;this.parked={state:e,pc:null,dc:null,stream:null,ws:null,machineId:void 0,config:void 0,ids:this.ids,dcBuffer:[],timings:{},adopt(){return t.clearWatchdog(),this.state="adopted",this}},window.__stream=this.parked}armWatchdog(){this.clearWatchdog(),this.watchdogId=setTimeout(()=>{this.parked.state!=="adopted"&&this.fail("watchdog")},this.config.watchdog_ms)}clearWatchdog(){this.watchdogId&&(clearTimeout(this.watchdogId),this.watchdogId=null),this.wsTimeoutId&&(clearTimeout(this.wsTimeoutId),this.wsTimeoutId=null)}fail(e,t){if(!(this.parked&&this.parked.state==="adopted")){this.settled=!0,this.clearWatchdog();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)))}}mungeSDP(e){let t=this.prioritizeH264Profile(e,p);t=t.replace(/(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n/gm,`$1;x-google-start-bitrate=10000;x-google-max-bitrate=100000\r
1
+ "use strict";(()=>{"use strict";const f="metabox-configurator",m=/metabox-configurator\/(modular|basic)\/([^/?#]+)/i,g="3dsource:region-ping",w="assets/config.json",k="42e01f";function h(){return typeof crypto!="undefined"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,o=>{const e=Math.random()*16|0;return(o==="x"?e:e&3|8).toString(16)})}function I(o){return o.replace("http://","ws://").replace("https://","wss://")}const l="[stream-prefetch]",s=(...o)=>console.log(l,...o),c=(...o)=>console.warn(l,...o),u=(...o)=>console.error(l,...o);class y{constructor(){const e=document.currentScript||(()=>{const n=document.getElementsByTagName("script");return n[n.length-1]})(),t=e&&e.dataset||{};this.configUrl=t.configUrl||w,this.fallbackPollingUrl=t.fallbackUrl||"",this.skipRouteCheck=this.boolOr(t.skipRouteCheck,!1),this.config={watchdog_ms:this.numberOr(t.watchdogMs,15e3),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"),this.ids={clientId:h(),viewId:h(),correlationId:h()},this.context=null,this.environmentId=void 0,this.orchestrationType="",this.region="",this.requireEnvironmentId=!0,this.pc=null,this.dc=null,this.stream=null,this.ws=null,this.remoteDescriptionSet=!1,this.iceBuffer=[],this.watchdogId=null,this.wsTimeoutId=null,this.settled=!1}run(){if(typeof window=="undefined"||!("WebSocket"in window)||!("RTCPeerConnection"in window))return;if(this.skipRouteCheck){this.context={},this.requireEnvironmentId=!1,c("skipRouteCheck=true \u2014 ignoring URL gate, route, context and environmentId; using fallback polling"),this.publishParked("connecting"),this.connect().catch(t=>this.fail("exception",t));return}if(window.location.href.indexOf(f)===-1){s("skip \u2014 URL does not contain gate",`"${f}"`);return}const e=this.parseConfiguratorUrl();e?(this.context={id:e.contextId,data:{configuratorId:e.configuratorId}},this.requireEnvironmentId=!0,s("start",{contextId:e.contextId,configuratorId:e.configuratorId,ids:this.ids})):(this.context={},this.requireEnvironmentId=!1,c("URL is not a configurator route \u2014 prefetching with empty context {} and no required environmentId",window.location.pathname)),this.publishParked("connecting"),this.connect().catch(t=>this.fail("exception",t))}parseConfiguratorUrl(){const e=window.location.pathname.match(m);return e?{contextId:e[1].toLowerCase()==="modular"?"metaboxModularConfigurator":"metaboxBasicConfigurator",configuratorId:decodeURIComponent(e[2])}:null}connect(){return this.mark("prefetch_start"),this.region=this.readRegion()||"",s("region from cache:",this.region||"(none)"),(this.skipRouteCheck?Promise.resolve(null):this.fetchConfig()).then(t=>{let i;if(t)i=this.chooseEndpoint(t);else if(this.fallbackPollingUrl)c("no app config \u2014 falling back to polling",this.fallbackPollingUrl),i={type:"polling",url:this.fallbackPollingUrl,environmentId:""},this.requireEnvironmentId=!1;else{this.fail("no-config");return}if(!i){this.fail("no-endpoint");return}if(s("endpoint chosen",{type:i.type,url:i.url,environmentId:i.environmentId}),this.requireEnvironmentId&&!i.environmentId){this.fail("no-environment-id");return}this.orchestrationType=i.type,this.environmentId=i.environmentId||void 0;const n=this.adaptUrlToRegion(i.url);return(i.type==="polling"?this.pollOrchestration(n):Promise.resolve(n)).then(a=>{if(!a){this.fail("no-ws-url");return}return this.parked.machineId=a,s("opening socket",a),this.openSocket(a)})})}fetchConfig(){const e=new URL(this.configUrl,window.location.origin).href;return this.fetchWithTimeout(e,{credentials:"omit"},this.config.poll_timeout).then(t=>t.ok?t.json().catch(()=>null):null).catch(()=>null)}chooseEndpoint(e){const t=e.newSignalling,i=this.firstVersionUrl(t&&t.versions);if(i&&/^wss?:\/\//i.test(i))return{type:"direct",url:i,environmentId:t&&t.environmentId||""};const n=e.signalling,r=this.firstVersionUrl(n&&n.versions);return r?{type:"polling",url:r,environmentId:n&&n.environmentId||""}:null}firstVersionUrl(e){if(!e||typeof e!="object")return"";for(const t of Object.keys(e))if(e[t])return e[t];return""}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?I(`${window.location.protocol}//${i.signallingServer}`):null).catch(()=>null)}adaptUrlToRegion(e){return this.region&&e.indexOf(":region")===-1?e.replace(/signallingserver/gi,`signallingserver/region:${this.region}`):e}openSocket(e){const t=new WebSocket(e);t.binaryType="arraybuffer",this.ws=t,this.parked.ws=t,this.wsTimeoutId=setTimeout(()=>{t.readyState!==WebSocket.OPEN&&this.fail("ws-timeout")},this.config.ws_timeout),t.onopen=()=>{clearTimeout(this.wsTimeoutId),this.mark("ws_open"),s("WS open \u2192 sending requestStream",{environmentId:this.environmentId,region:this.region,context:this.context}),this.sendRequestStream()},t.onmessage=i=>this.onWsMessage(i),t.onerror=i=>{u("WS error",i),this.fail("ws-error")},t.onclose=i=>{!this.settled&&this.parked.state!=="ready"&&(c("WS closed before ready",{code:i&&i.code}),this.fail("ws-closed"))},this.armWatchdog()}sendRequestStream(){this.send({type:"requestStream",correlationId:this.ids.correlationId,payload:{region:this.region,environmentId:this.environmentId,context:this.context}})}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(s("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;case"ping":this.send({type:"pong",source:"front"});break;case"streamerDisconnected":case"playerDisconnected":this.fail("streamer-disconnected");break;case"error":this.fail("orchestration-error");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,s("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]&&(s("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(()=>{s("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=()=>{s("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,this.mark("ready"),this.parked.state="ready",s("READY \u2014 parked on window.__stream",this.parked.timings))}publishParked(e){const t=this;this.parked={state:e,pc:null,dc:null,stream:null,ws:null,ssData:void 0,machineId:void 0,config:void 0,ids:this.ids,dcBuffer:[],timings:{},adopt(){return t.clearWatchdog(),this.state="adopted",this}},window.__stream=this.parked}armWatchdog(){this.clearWatchdog(),this.watchdogId=setTimeout(()=>{this.parked.state!=="adopted"&&(c(`not adopted within ${this.config.watchdog_ms}ms \u2014 tearing down`,{state:this.parked.state}),this.fail("watchdog"))},this.config.watchdog_ms)}clearWatchdog(){this.watchdogId&&(clearTimeout(this.watchdogId),this.watchdogId=null),this.wsTimeoutId&&(clearTimeout(this.wsTimeoutId),this.wsTimeoutId=null)}fail(e,t){if(!(this.parked&&(this.parked.state==="adopted"||this.parked.state==="failed"))){u("FAILED:",e,t||""),this.settled=!0,this.clearWatchdog();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)))}}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
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 r of i)if(r.startsWith("a=fmtp:")&&r.toLowerCase().includes(`profile-level-id=${t}`)){const s=r.split(":")[1]&&r.split(":")[1].split(" ")[0];s&&n.push(s)}return n.length===0?e:i.map(r=>{if(!r.startsWith("m=video"))return r;const s=r.split(" "),w=s.slice(0,3),h=s.slice(3),y=[...n.filter(c=>h.includes(c)),...h.filter(c=>!n.includes(c))];return[...w,...y].join(" ")}).join(`\r
4
- `)}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{}}mark(e){this.parked&&(this.parked.timings[e]=performance.now())}readRegion(){try{const e=localStorage.getItem(u);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}}fetchWithTimeout(e,t,i){const n=new AbortController;t.signal=n.signal;const r=setTimeout(()=>n.abort(),i);return fetch(e,t).finally(()=>clearTimeout(r))}numberOr(e,t){const i=Number(e);return e!=null&&e!==""&&!Number.isNaN(i)?i:t}}new g().run()})();
3
+ `),n=[];for(const r of i)if(r.startsWith("a=fmtp:")&&r.toLowerCase().includes(`profile-level-id=${t}`)){const a=r.split(":")[1]&&r.split(":")[1].split(" ")[0];a&&n.push(a)}return n.length===0?e:i.map(r=>{if(!r.startsWith("m=video"))return r;const a=r.split(" "),x=a.slice(0,3),p=a.slice(3),b=[...n.filter(d=>p.includes(d)),...p.filter(d=>!n.includes(d))];return[...x,...b].join(" ")}).join(`\r
4
+ `)}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{}}mark(e){this.parked&&(this.parked.timings[e]=performance.now())}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}}fetchWithTimeout(e,t,i){const n=new AbortController;t.signal=n.signal;const r=setTimeout(()=>n.abort(),i);return fetch(e,t).finally(()=>clearTimeout(r))}numberOr(e,t){const i=Number(e);return e!=null&&e!==""&&!Number.isNaN(i)?i:t}boolOr(e,t){return e==="true"||e===""?!0:e==="false"?!1:t}}new y().run()})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3dsource/angular-unreal-module",
3
- "version": "0.0.146-dev.0",
3
+ "version": "0.0.146-dev.1",
4
4
  "description": "Unreal module for connect with unreal engine stream",
5
5
  "keywords": [
6
6
  "3dsource",
@@ -243,6 +243,16 @@ interface UnrealInitialConfig {
243
243
  autoHighResolution?: boolean;
244
244
  }
245
245
 
246
+ interface SignalingData {
247
+ instanceType: string;
248
+ branchInfo: string;
249
+ cirrusVersion: string;
250
+ streamerVersion: string;
251
+ streamPath: string;
252
+ streamApp: string;
253
+ connectionId: string;
254
+ }
255
+
246
256
  /**
247
257
  * Live WebRTC connection parked on `window.__stream` by the `stream-prefetch.js`
248
258
  * head-script, ready for the Angular services to ADOPT instead of building a
@@ -257,6 +267,8 @@ interface ParkedStream {
257
267
  stream?: MediaStream;
258
268
  /** live signalling socket (handshake already done, `requestStream` sent) */
259
269
  ws?: WebSocket;
270
+ /** `data` from the streamer's `ssInfo` message — received before adoption */
271
+ ssData?: SignalingData;
260
272
  /** = resolved wsUrl of the winning machine */
261
273
  machineId?: string;
262
274
  /** `peerConnectionOptions` the machine sent in its `config` message */
@@ -422,16 +434,6 @@ interface InputProps {
422
434
 
423
435
  type Quality = 'lime' | 'red' | 'orange';
424
436
 
425
- interface SignalingData {
426
- instanceType: string;
427
- branchInfo: string;
428
- cirrusVersion: string;
429
- streamerVersion: string;
430
- streamPath: string;
431
- streamApp: string;
432
- connectionId: string;
433
- }
434
-
435
437
  declare const OrchestrationMessageTypes: {
436
438
  readonly ping: "ping";
437
439
  readonly error: "error";
@@ -1083,6 +1085,19 @@ declare class StreamAdoptionService {
1083
1085
  private readonly store;
1084
1086
  private readonly signalling;
1085
1087
  private readonly webRtc;
1088
+ /**
1089
+ * Decide adoption, WAITING for an in-flight prefetch instead of racing it.
1090
+ *
1091
+ * - nothing parked → emit `false` at once (caller connects normally).
1092
+ * - already settled (`ready`/`failed`/`adopted`) → adopt-if-ready at once.
1093
+ * - still `connecting` → poll until it settles, then adopt-if-ready. Bounded
1094
+ * by `timeoutMs` so a stuck prefetch can't block the fallback forever.
1095
+ *
1096
+ * Emits exactly once. Cancel by unsubscribing (the effect does this on
1097
+ * teardown via `takeUntil`) — no adoption runs after cancellation, which is
1098
+ * what stops a fast route-switch from starting overlapping connections.
1099
+ */
1100
+ awaitAndAdopt$(timeoutMs: number): Observable<boolean>;
1086
1101
  /**
1087
1102
  * @returns `true` if a ready parked stream was adopted (caller must NOT
1088
1103
  * start a fresh connection), `false` otherwise.
@@ -2553,8 +2568,10 @@ declare const initSignalling: node_modules__ngrx_store_types_ngrx_store.ActionCr
2553
2568
  */
2554
2569
  declare const streamAdopted: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, (props: {
2555
2570
  machineId: string | null;
2571
+ ssData: SignalingData | null;
2556
2572
  }) => {
2557
2573
  machineId: string | null;
2574
+ ssData: SignalingData | null;
2558
2575
  } & node_modules__ngrx_store_types_ngrx_store.Action<string>>;
2559
2576
  declare const startStream: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, (props: {
2560
2577
  config: Partial<StreamConfig>;
@@ -2770,7 +2787,9 @@ declare class UnrealEffects {
2770
2787
  id: string;
2771
2788
  now: number;
2772
2789
  } & node_modules__ngrx_store_types_ngrx_store.Action<string>> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
2773
- connectToSignaling$: node_modules_rxjs_dist_types.Observable<WebSocket> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
2790
+ connectToSignaling$: node_modules_rxjs_dist_types.Observable<{
2791
+ value: boolean;
2792
+ } & node_modules__ngrx_store_types_ngrx_store.Action<string>> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
2774
2793
  private canPeerReconnect;
2775
2794
  /**
2776
2795
  * Either schedules the next peer-reconnect attempt or gives up with the