@nnepoch/dtc-sdk 3.0.15 → 3.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -106,4 +106,4 @@ onmessage = async (event) => {
106
106
  }
107
107
  };
108
108
  postMessage({ type: 'ready' });\n`}var U=class extends Error{constructor(e,t,n){super(t),this.code=e,this.details=n,this.name=`BusinessProgramRuntimeError`}},Fn=class{constructor(e,t=In){this.host=e,this.workerFactory=t,this.loaded=new Map,this.active=new Map,this.activeProgramLocks=new Map}async load(e){if(this.loaded.has(e.capsuleHash))return{loaded:!1};if(!/^[a-f0-9]{64}$/.test(e.capsuleHash))throw new U(`PROGRAM_HASH_INVALID`,`capsuleHash must be a SHA-256 hex string.`);if(await Ln(e),await zn(Rn(e))!==e.capsuleHash)throw new U(`PROGRAM_HASH_INVALID`,`Business Program capsuleHash mismatch.`);return this.validatePermissions(e.manifest),this.loaded.set(e.capsuleHash,{manifest:structuredClone(e.manifest),bundle:e.bundle,data:structuredClone(e.data)}),{loaded:!0}}async start(e,t){if(this.active.has(e.executionId))throw new U(`PROGRAM_EXECUTION_EXISTS`,`Execution "${e.executionId}" already exists.`);let n=this.loaded.get(e.capsuleHash);if(!n)throw new U(`PROGRAM_NOT_LOADED`,`Business Program capsule is not loaded.`);let r=this.activeProgramLocks.get(n.manifest.programId);if(r)throw new U(`PROGRAM_LOCK_CONFLICT`,`Business Program "${n.manifest.programId}" is already running.`,{executionId:r});let i;try{i=this.workerFactory(Pn(n.bundle))}catch(e){throw new U(`PROGRAM_WORKER_UNAVAILABLE`,`Business Program Worker could not be created. Check the page CSP worker-src policy.`,Gn(e))}let a={};Object.assign(a,{request:e,program:n,worker:i,onEvent:t,timeout:setTimeout(()=>{this.finishExecution(a,`failed`,`Business Program execution timed out.`)},n.manifest.limits.timeoutMs),sdkCallCount:0,totalDelayMs:0,emittedEventCount:0,pendingDelays:new Set,streams:new Map,nextStreamId:1,terminal:!1}),this.active.set(e.executionId,a),this.activeProgramLocks.set(n.manifest.programId,e.executionId);try{return await this.waitForWorkerReady(a),i.postMessage({type:`start`,inputs:structuredClone(e.inputs),data:structuredClone(n.data)}),this.emit(a,{type:`started`},!1,`running`),{executionId:e.executionId,state:`running`}}catch(e){throw this.finishExecution(a,`failed`,e instanceof Error?e.message:String(e)),e}}cancel(e){let t=this.active.get(e.executionId);return t&&this.finishExecution(t,`cancelled`,e.reason??`Business Program cancelled.`),{executionId:e.executionId,state:`cancelled`}}cancelAll(e=`Business Program runtime disposed.`){for(let t of[...this.active.values()])this.finishExecution(t,`cancelled`,e)}validatePermissions(e){let t=new Set;for(let n of e.permissions.methods){let e=`${n.module}\u0000${n.method}\u0000${n.mode}`;if(t.has(e))throw new U(`PROGRAM_PERMISSION_INVALID`,`Business Program permissions must be unique.`);t.add(e);let r=this.host.getMethodMetadata(n.module,n.method);if(!r)throw new U(`PROGRAM_PERMISSION_INVALID`,`Business Program method "${n.module}.${n.method}" is not exposed.`);if(n.mode===`query`&&(r.responseMode!==`single`||r.sideEffects.some(e=>e!==`read`)))throw new U(`PROGRAM_PERMISSION_INVALID`,`Query permission requires a read-only single method: ${n.module}.${n.method}.`);if(n.mode===`stage`&&r.responseMode!==`single`)throw new U(`PROGRAM_PERMISSION_INVALID`,`Stage permission requires responseMode=single: ${n.module}.${n.method}.`);if(n.mode===`stream`&&r.responseMode!==`stream`)throw new U(`PROGRAM_PERMISSION_INVALID`,`Stream permission requires responseMode=stream: ${n.module}.${n.method}.`)}}waitForWorkerReady(e){return new Promise((t,n)=>{let r=setTimeout(()=>n(new U(`PROGRAM_WORKER_UNAVAILABLE`,`Business Program Worker did not become ready in 5 seconds.`)),5e3);e.worker.onmessage=n=>{G(n.data)?.type===`ready`&&(clearTimeout(r),e.worker.onmessage=t=>{this.handleWorkerMessage(e,t.data)},e.worker.onerror=t=>{this.finishExecution(e,`failed`,t.message||`Business Program Worker failed.`)},t())},e.worker.onerror=e=>{clearTimeout(r),n(new U(`PROGRAM_WORKER_ERROR`,e.message||`Business Program Worker failed.`))}})}async handleWorkerMessage(e,t){if(e.terminal)return;let n=G(t);if(!(!n||typeof n.type!=`string`)){if(n.type===`host-request`&&typeof n.id==`string`&&typeof n.operation==`string`){try{let t=await this.handleHostRequest(e,n.operation,n.payload);if(e.terminal)return;e.worker.postMessage({type:`host-response`,id:n.id,ok:!0,result:t})}catch(t){if(e.terminal)return;e.worker.postMessage({type:`host-response`,id:n.id,ok:!1,error:Gn(t)})}return}if(n.type===`emit`){let t=G(n.event);this.emit(e,{type:t?.type===`action`?`action`:`progress`,phase:typeof t?.phase==`string`?t.phase:void 0,message:typeof t?.message==`string`?t.message:void 0,data:t?.data},!1,`running`);return}if(n.type===`complete`){this.finishExecution(e,`completed`,void 0,n.result);return}if(n.type===`fail`){let t=G(n.error);this.finishExecution(e,`failed`,typeof t?.message==`string`?t.message:`Business Program failed.`,t?.details)}}}async handleHostRequest(e,t,n){if(t===`query`){let t=Hn(n);this.requirePermission(e.program.manifest,t,`query`),this.incrementSdkCalls(e,1);let r=await this.host.invoke(t);if(!r.ok)throw new U(r.error.code,r.error.message,r.error.details);return r.data}if(t===`execute-stage`)return this.executeStage(e,n);if(t===`open-stream`)return this.openStream(e,n);if(t===`stream-next`)return this.nextStreamEvent(e,n);if(t===`close-stream`)return this.closeStream(e,n);if(t===`delay`){let t=G(n)?.delayMs;if(!Number.isInteger(t)||t<0)throw new U(`PROGRAM_REQUEST_INVALID`,`delayMs must be a non-negative integer.`);return await this.controlledDelay(e,t),null}throw new U(`PROGRAM_REQUEST_INVALID`,`Unsupported host operation "${t}".`)}async executeStage(e,t){let n=G(t)?.actions;if(!Array.isArray(n)||n.length===0||n.length>e.program.manifest.limits.maxStageActions)throw new U(`PROGRAM_STAGE_INVALID`,`Program stage action count is invalid.`);let r=Wn(n),i=r.filter(e=>e.type===`invoke`);for(let t of i)this.requirePermission(e.program.manifest,Un(t),`stage`);this.incrementSdkCalls(e,i.length);let a=this.host.validateActions({actions:i.map(e=>({id:e.id,...Un(e),responseMode:`single`}))});if(!a.ok)throw new U(a.error.code,a.error.message,a.error.details);let o=a.data.items.find(e=>!e.valid);if(!a.data.valid||o)throw new U(o?.error?.code??`INVALID_PAYLOAD`,o?.error?.message??`Business Program stage preflight failed.`,o?.error?.details);let s=[],c={};for(let[t,n]of r.entries()){if(e.terminal)throw new U(`PROGRAM_CANCELLED`,`Business Program execution is no longer active.`);if(n.type===`delay`)await this.controlledDelay(e,n.delayMs);else{let e=await this.host.invoke(Un(n));if(!e.ok)return{state:`failed`,completedActionIds:s,skippedActionIds:r.slice(t+1).map(e=>e.id),results:c,failedAction:{id:n.id,...e.error}};n.saveAs&&(c[n.saveAs]=e.data)}s.push(n.id)}return{state:`completed`,completedActionIds:s,skippedActionIds:[],results:c}}async openStream(e,t){let n=Hn(t);this.requirePermission(e.program.manifest,n,`stream`),this.incrementSdkCalls(e,1);let r=`${e.request.executionId}:stream:${e.nextStreamId++}`,i={streamId:r,requestId:``,events:[],waiters:[],terminal:!1};e.streams.set(r,i);let a=await this.host.startStream({...n,streamId:r},t=>{this.pushStreamEvent(e,i,t)});if(!a.ok)throw e.streams.delete(r),new U(a.error.code,a.error.message,a.error.details);return i.requestId=a.data.requestId,a.data}nextStreamEvent(e,t){let n=this.requireProgramStream(e,t),r=n.events.shift();return r?(r.terminal&&e.streams.delete(n.streamId),Promise.resolve(r)):n.terminal?(e.streams.delete(n.streamId),Promise.reject(new U(`PROGRAM_STREAM_CLOSED`,`Stream "${n.streamId}" is closed.`))):new Promise((e,t)=>{n.waiters.push({resolve:e,reject:t})})}async closeStream(e,t){let n=this.requireProgramStream(e,t),r=G(t)?.reason,i=await this.host.closeStream({streamId:n.streamId,reason:typeof r==`string`?r:`Business Program closed stream.`});if(!i.ok)throw new U(i.error.code,i.error.message,i.error.details);return this.disposeProgramStream(e,n,`Business Program closed stream.`,!1),{streamId:n.streamId,closed:!0}}requireProgramStream(e,t){let n=G(t)?.streamId,r=typeof n==`string`?e.streams.get(n):void 0;if(!r)throw new U(`PROGRAM_STREAM_NOT_FOUND`,`Business Program stream does not exist.`);return r}pushStreamEvent(e,t,n){if(e.terminal||!e.streams.has(t.streamId))return;t.terminal=n.terminal;let r=t.waiters.shift();r?(r.resolve(n),n.terminal&&e.streams.delete(t.streamId)):t.events.push(n)}disposeProgramStream(e,t,n,r=!0){e.streams.delete(t.streamId),t.terminal=!0;for(let e of t.waiters.splice(0))e.reject(new U(`PROGRAM_CANCELLED`,n));r&&this.host.closeStream({streamId:t.streamId,reason:n})}async controlledDelay(e,t){if(e.terminal)throw new U(`PROGRAM_CANCELLED`,`Business Program execution is no longer active.`);if(e.totalDelayMs+=t,e.totalDelayMs>e.program.manifest.limits.maxTotalDelayMs)throw new U(`PROGRAM_LIMIT_EXCEEDED`,`Business Program total delay limit exceeded.`);await new Promise((n,r)=>{let i={};i.reject=r,i.timer=setTimeout(()=>{e.pendingDelays.delete(i),n()},t),e.pendingDelays.add(i)})}requirePermission(e,t,n){if(!e.permissions.methods.some(e=>e.module===t.moduleName&&e.method===t.methodName&&e.mode===n))throw new U(`PROGRAM_PERMISSION_DENIED`,`Business Program cannot use ${t.moduleName}.${t.methodName} as ${n}.`)}incrementSdkCalls(e,t){if(e.sdkCallCount+=t,e.sdkCallCount>e.program.manifest.limits.maxSdkCalls)throw new U(`PROGRAM_LIMIT_EXCEEDED`,`Business Program SDK call limit exceeded.`)}emit(e,t,n,r){if(e.emittedEventCount+=1,e.emittedEventCount>e.program.manifest.limits.maxEventCount){this.finishExecution(e,`failed`,`Business Program event limit exceeded.`);return}e.onEvent({executionId:e.request.executionId,traceId:e.request.traceId,event:t,terminal:n,state:r})}finishExecution(e,t,n,r){if(!e.terminal){e.terminal=!0,clearTimeout(e.timeout);for(let t of e.pendingDelays)clearTimeout(t.timer),t.reject(new U(`PROGRAM_CANCELLED`,n??`Business Program stopped.`));e.pendingDelays.clear();for(let r of[...e.streams.values()])this.disposeProgramStream(e,r,n??`Business Program ${t}.`);e.worker.terminate(),this.active.delete(e.request.executionId),this.activeProgramLocks.get(e.program.manifest.programId)===e.request.executionId&&this.activeProgramLocks.delete(e.program.manifest.programId),e.onEvent({executionId:e.request.executionId,traceId:e.request.traceId,event:{type:t,message:n,data:r},terminal:!0,state:t})}}};function In(e){let t=URL.createObjectURL(new Blob([e],{type:`text/javascript`}));try{return new Worker(t)}finally{URL.revokeObjectURL(t)}}async function Ln(e){if(await zn(e.bundle)!==e.manifest.entry.sha256)throw new U(`PROGRAM_HASH_INVALID`,`Business Program entry sha256 mismatch.`);for(let t of e.manifest.data){let n=e.data[t.name];if(typeof n!=`string`||await zn(n)!==t.sha256)throw new U(`PROGRAM_HASH_INVALID`,`Business Program data "${t.name}" sha256 mismatch.`)}}function Rn(e){return JSON.stringify(e.manifest)+e.bundle+e.manifest.data.map(t=>e.data[t.name]??``).join(``)}async function zn(e){let t=new TextEncoder().encode(e);if(typeof crypto<`u`&&crypto.subtle){let e=await crypto.subtle.digest(`SHA-256`,t);return Vn(new Uint8Array(e))}return Vn(Bn(t))}function Bn(e){let t=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),n=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),r=Math.ceil((e.length+9)/64)*64,i=new Uint8Array(r);i.set(e),i[e.length]=128;let a=e.length*8,o=new DataView(i.buffer);o.setUint32(r-8,Math.floor(a/4294967296)),o.setUint32(r-4,a>>>0);let s=new Uint32Array(64);for(let e=0;e<r;e+=64){for(let t=0;t<16;t+=1)s[t]=o.getUint32(e+t*4);for(let e=16;e<64;e+=1){let t=W(s[e-15],7)^W(s[e-15],18)^s[e-15]>>>3,n=W(s[e-2],17)^W(s[e-2],19)^s[e-2]>>>10;s[e]=s[e-16]+t+s[e-7]+n>>>0}let[r,i,a,c,l,u,d,f]=n;for(let e=0;e<64;e+=1){let n=W(l,6)^W(l,11)^W(l,25),o=l&u^~l&d,p=f+n+o+t[e]+s[e]>>>0,m=(W(r,2)^W(r,13)^W(r,22))+(r&i^r&a^i&a)>>>0;f=d,d=u,u=l,l=c+p>>>0,c=a,a=i,i=r,r=p+m>>>0}n[0]=n[0]+r>>>0,n[1]=n[1]+i>>>0,n[2]=n[2]+a>>>0,n[3]=n[3]+c>>>0,n[4]=n[4]+l>>>0,n[5]=n[5]+u>>>0,n[6]=n[6]+d>>>0,n[7]=n[7]+f>>>0}let c=new Uint8Array(32),l=new DataView(c.buffer);return n.forEach((e,t)=>l.setUint32(t*4,e)),c}function W(e,t){return e>>>t|e<<32-t}function Vn(e){return Array.from(e,e=>e.toString(16).padStart(2,`0`)).join(``)}function Hn(e){let t=G(e);if(!t||typeof t.module!=`string`||typeof t.method!=`string`)throw new U(`PROGRAM_REQUEST_INVALID`,`SDK request requires module and method.`);return{moduleName:t.module,methodName:t.method,payload:t.payload}}function Un(e){return{moduleName:e.module,methodName:e.method,payload:e.payload}}function Wn(e){let t=new Map,n=new Set;for(let r of e){if(!r||typeof r.id!=`string`||!r.id||t.has(r.id))throw new U(`PROGRAM_STAGE_INVALID`,`Program stage action IDs must be unique.`);if(r.type!==`invoke`&&r.type!==`delay`)throw new U(`PROGRAM_STAGE_INVALID`,`Unsupported Program stage action type.`);if(r.type===`invoke`){if(!r.module||!r.method||r.responseMode!==`single`)throw new U(`PROGRAM_STAGE_INVALID`,`Invoke action "${r.id}" is invalid.`);if(r.saveAs&&(n.has(r.saveAs)||!/^[A-Za-z][A-Za-z0-9-]*$/.test(r.saveAs)))throw new U(`PROGRAM_STAGE_INVALID`,`saveAs "${r.saveAs}" is invalid or duplicated.`);r.saveAs&&n.add(r.saveAs)}else if(!Number.isInteger(r.delayMs)||r.delayMs<0)throw new U(`PROGRAM_STAGE_INVALID`,`Delay action "${r.id}" is invalid.`);t.set(r.id,r)}for(let n of e)for(let e of n.dependsOn??[])if(!t.has(e)||e===n.id)throw new U(`PROGRAM_STAGE_INVALID`,`Action "${n.id}" has an invalid dependency.`);let r=[],i=new Set;for(;r.length<e.length;){let t=e.find(e=>!i.has(e.id)&&(e.dependsOn??[]).every(e=>i.has(e)));if(!t)throw new U(`PROGRAM_STAGE_INVALID`,`Program stage dependency graph contains a cycle.`);r.push(t),i.add(t.id)}return r}function G(e){return typeof e==`object`&&e?e:void 0}function Gn(e){return e instanceof U?{name:e.name,message:e.message,code:e.code,details:e.details}:e instanceof Error?{name:e.name,message:e.message}:{name:`Error`,message:String(e)}}function Kn(){return typeof crypto<`u`&&typeof crypto.randomUUID==`function`?`sdk3_${crypto.randomUUID()}`:`sdk3_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}function K(e){return{ok:!0,data:e,ts:Date.now()}}function q(e,t,n){return{ok:!1,error:{code:e,message:t,moduleName:n?.moduleName,methodName:n?.methodName,details:n?.details},ts:Date.now()}}function qn(){return typeof document>`u`?void 0:document.title}function Jn(){return typeof window>`u`?void 0:window.location.href}function Yn(e){return e.runtimeName??e.engineConfig?.sceneName??qn()??e.engineConfig?.engineUuid}function Xn(e){if(e)return{sceneName:e.sceneName,engineUuid:e.engineUuid,mapType:e.mapType,operationType:e.operationType,viewMode:e.viewMode,centerIP:e.centerIP,signalingServer:e.signalingServer,codec:e.codec}}function Zn(e){return typeof e==`object`&&!!e}function Qn(e){return Zn(e)&&Object.keys(e).length===0}function $n(e){return Zn(e)&&e.ok===!1&&typeof e.ts==`number`}function er(e){return new Promise(t=>{setTimeout(t,e)})}function tr(e,t){let n=t?.fields.filter(e=>e.required)??[];if(n.length!==0)return Zn(e)?n.find(t=>e[t.name]===void 0):n[0]}function nr(e){return e instanceof d?e.toJSON():e instanceof Error?{name:e.name,message:e.message}:e}function rr(e){if(typeof e!=`object`&&typeof e!=`function`||e===null)return!1;let t=e;return typeof t.then==`function`&&typeof t.cancel==`function`&&typeof t.requestId==`string`}function ir(e){if(!(!Zn(e)||typeof e.id!=`string`))return{parentId:typeof e.parentId==`string`?e.parentId:``,id:e.id}}function ar(e){if(typeof e!=`string`)return e;try{return JSON.parse(e)}catch{return}}function or(e){let t=e.response,n=ar(t?.param??t?.params??e.param??e.params);return Zn(n)&&n.status===`finished`}function sr(e,t={},n={}){let r=t.bridgeId??Kn(),i=Dn(t.expose),a=new Map,o=!1,s=()=>{o=!0},c=()=>{o=!1};e.on(e.Events.WebRtcConnected,s),e.on(e.Events.WebRtcDisconnected,c),e.on(e.Events.WebRtcFailed,c);function l(){return{bridgeId:r,connected:o,runtimeName:Yn(t),title:qn(),pageUrl:Jn(),sdkVersion:t.sdkVersion,metadata:t.metadata,engine:Xn(t.engineConfig)}}function u(e){return En(e)?On(e,i)?e:q(`API_NOT_EXPOSED`,`API module "${e}" is not exposed by agentBridge.expose.`,{moduleName:e}):q(`API_NOT_FOUND`,`API module "${e}" does not exist.`,{moduleName:e})}function p(t,n){if(!kn(t,n,i))return q(`API_NOT_EXPOSED`,`API method "${t}.${n}" is not exposed.`,{moduleName:t,methodName:n});let r=e[t];return!Zn(r)||typeof r[n]!=`function`?q(`API_NOT_FOUND`,`API method "${t}.${n}" does not exist.`,{moduleName:t,methodName:n}):r}function m(e,t=!0){let n=u(e.moduleName);if(typeof n!=`string`)return n;let r=p(n,e.methodName);if($n(r))return r;let a=Mn(n,e.methodName,i);if(!a)return q(`METHOD_SCHEMA_NOT_FOUND`,`Schema for "${n}.${e.methodName}" is not available.`,{moduleName:n,methodName:e.methodName});let o=l();if(!o.connected)return q(`SDK_NOT_READY`,`DTCEngine is not connected yet.`,{moduleName:n,methodName:e.methodName,details:o});if(t&&a.payloadKind===`none`&&e.payload!==void 0&&!Qn(e.payload))return q(`INVALID_PAYLOAD`,`API method "${n}.${e.methodName}" does not accept payload.`,{moduleName:n,methodName:e.methodName,details:e.payload});let s=t?tr(e.payload,a):void 0;if(s)return q(`INVALID_PAYLOAD`,`Missing required payload field "${s.name}".`,{moduleName:n,methodName:e.methodName,details:{field:s.name}});let c=r[e.methodName];return typeof c==`function`?{resolvedModule:n,resolvedMethod:r,methodRef:c,schema:a}:q(`API_NOT_FOUND`,`API method "${n}.${e.methodName}" does not exist.`,{moduleName:n,methodName:e.methodName})}function h(e){return{type:e.type,requestId:e.requestId,response:e.response,...e.error?{error:{name:e.error.name,message:e.error.message}}:{}}}function g(e,t,n){let r=e.request.streamId;a.get(r)===e&&(a.delete(r),e.onEvent({streamId:r,requestId:e.promise.requestId,moduleName:e.request.moduleName,methodName:e.request.methodName,event:{type:`cancel`,requestId:e.promise.requestId,error:{name:`StreamClosedError`,message:n}},terminal:!0,terminalReason:t}),e.promise.cancel(n))}function _(e,t){let n=a.get(e);if(!n)return;let r=n.request.moduleName===`PathPatrol`&&n.request.methodName===`add`&&or(t),i=r||t.type===`done`||t.type===`error`||t.type===`cancel`,o=r?`finished`:t.type===`done`?`completed`:t.type===`error`?`error`:t.type===`cancel`?`cancelled`:void 0;n.onEvent({streamId:e,requestId:t.requestId||n.promise.requestId,moduleName:n.request.moduleName,methodName:n.request.methodName,event:h(t),terminal:i,terminalReason:o}),i&&(a.delete(e),r&&t.type!==`done`&&n.promise.cancel(`PathPatrol.add reported status=finished`))}function ee(e){let t=ir(e);if(t)for(let e of[...a.values()]){let n=ir(e.request.payload);e.request.moduleName===`PathPatrol`&&e.request.methodName===`add`&&n?.id===t.id&&n.parentId===t.parentId&&g(e,`stopped`,`Matching PathPatrol.stop succeeded`)}}function te(e=`Agent bridge disconnected`){for(let t of[...a.values()])g(t,`bridge-disconnected`,e)}let v,y=new Fn({getMethodMetadata(e,t){if(!En(e)||!On(e,i))return;let n=jn(e,i).find(e=>e.methodName===t);return n?{responseMode:n.responseMode,sideEffects:n.sideEffects}:void 0},validateActions(e){return v.validateActions(e)},invoke(e){return v.invoke(e)},startStream(e,t){return v.startStream(e,t)},closeStream(e){return v.closeStream(e)}},n.businessProgramWorkerFactory);return v={getSnapshot:l,dispose(){te(`Agent bridge runtime disposed`),y.cancelAll(`Agent bridge runtime disposed`),e.off(e.Events.WebRtcConnected,s),e.off(e.Events.WebRtcDisconnected,c),e.off(e.Events.WebRtcFailed,c)},closeAllStreams:te,cancelAllPrograms(e){y.cancelAll(e)},listModules(){return An(i)},listMethods(e){let t=u(e);return typeof t==`string`?K(jn(t,i)):t},getMethodSchema(e,t){let n=u(e);if(typeof n!=`string`)return n;if(!kn(n,t,i))return q(`API_NOT_EXPOSED`,`API method "${n}.${t}" is not exposed.`,{moduleName:n,methodName:t});let r=Mn(n,t,i);return r?K(r):q(`METHOD_SCHEMA_NOT_FOUND`,`Schema for "${n}.${t}" is not available.`,{moduleName:n,methodName:t})},validateActions(e){let t=e.actions.map(e=>{let t=m(e,!1);if($n(t))return{id:e.id,valid:!1,error:t.error};if(t.schema.responseMode!==e.responseMode)return{id:e.id,valid:!1,error:{code:`STREAM_INVOKE_REQUIRED`,message:`API method "${t.resolvedModule}.${e.methodName}" is ${t.schema.responseMode}, not ${e.responseMode}.`,moduleName:t.resolvedModule,methodName:e.methodName,details:{expected:e.responseMode,actual:t.schema.responseMode}}};let n=Nn(t.resolvedModule,e.methodName,i);if(!n)return{id:e.id,valid:!1,error:{code:`METHOD_SCHEMA_NOT_FOUND`,message:`Validation schema for "${t.resolvedModule}.${e.methodName}" is not available.`,moduleName:t.resolvedModule,methodName:e.methodName}};try{return f(n,t.schema.payloadKind===`none`?void 0:e.payload,t.resolvedModule,e.methodName),{id:e.id,valid:!0}}catch(n){return{id:e.id,valid:!1,error:{code:`INVALID_PAYLOAD`,message:n instanceof Error?n.message:String(n),moduleName:t.resolvedModule,methodName:e.methodName,details:nr(n)}}}});return K({valid:t.every(e=>e.valid),items:t})},async invoke(e){let n=m(e);if($n(n))return n;let{resolvedModule:r,resolvedMethod:i,methodRef:a,schema:o}=n;if(o.responseMode===`stream`)return q(`STREAM_INVOKE_REQUIRED`,`API method "${r}.${e.methodName}" requires a streaming invoke.`,{moduleName:r,methodName:e.methodName,details:{responseMode:o.responseMode,tool:`sdk3_invoke_stream`}});if(t.mockInvoke===!0)return await er(100),K({success:!0,code:`MOCK_OK`,message:`mock invoke success`,data:null});try{let t=o.payloadKind===`none`||e.payload===void 0?await a.call(i):await a.call(i,e.payload);return r===`PathPatrol`&&e.methodName===`stop`&&(!Zn(t)||t.success!==!1)&&ee(e.payload),K(t)}catch(t){return t instanceof d?q(`INVALID_PAYLOAD`,t.message,{moduleName:r,methodName:e.methodName,details:t.toJSON()}):q(`API_EXECUTION_FAILED`,`API method "${r}.${e.methodName}" failed.`,{moduleName:r,methodName:e.methodName,details:nr(t)})}},async startStream(e,t){if(a.has(e.streamId))return q(`INVALID_PAYLOAD`,`Stream "${e.streamId}" already exists.`,{moduleName:e.moduleName,methodName:e.methodName});let n=m(e);if($n(n))return n;let{resolvedModule:r,resolvedMethod:i,methodRef:o,schema:s}=n;if(s.responseMode!==`stream`)return q(`API_NOT_STREAMING`,`API method "${r}.${e.methodName}" is not streaming.`,{moduleName:r,methodName:e.methodName});try{let n,c=[],l=!1,u=t=>{if(!l){c.push(t);return}_(e.streamId,t)};if(n=s.payloadKind===`none`||e.payload===void 0?o.call(i,u):o.call(i,e.payload,u),!rr(n))return q(`API_NOT_STREAMING`,`API method "${r}.${e.methodName}" did not return a stream handle.`,{moduleName:r,methodName:e.methodName});let d={request:e,promise:n,onEvent:t};a.set(e.streamId,d),l=!0,n.catch(()=>void 0),c.forEach(t=>_(e.streamId,t));let f=c.find(e=>e.type===`error`);return f?q(`INVALID_PAYLOAD`,f.error?.message??`API method "${r}.${e.methodName}" failed before stream start.`,{moduleName:r,methodName:e.methodName,details:nr(f.error)}):K({streamId:e.streamId,requestId:n.requestId})}catch(t){return q(`API_EXECUTION_FAILED`,`API method "${r}.${e.methodName}" failed to start a stream.`,{moduleName:r,methodName:e.methodName,details:nr(t)})}},async closeStream(e){let t=a.get(e.streamId);return t?(g(t,`cancelled`,e.reason?.trim()||`Stream closed by MCP client`),K({streamId:e.streamId,closed:!0})):K({streamId:e.streamId,closed:!1})},async loadProgram(e){try{return K(await y.load(e))}catch(e){return q(`PROGRAM_INVALID`,e instanceof Error?e.message:String(e),{details:cr(e)})}},async startProgram(e,t){if(!o)return q(`SDK_NOT_READY`,`SDK runtime is not connected.`);try{return K(await y.start(e,t))}catch(e){return q(`PROGRAM_EXECUTION_FAILED`,e instanceof Error?e.message:String(e),{details:cr(e)})}},async cancelProgram(e){try{return K(y.cancel(e))}catch(e){return q(`PROGRAM_EXECUTION_FAILED`,e instanceof Error?e.message:String(e),{details:cr(e)})}}},v}function cr(e){return e instanceof U?{code:e.code,message:e.message,details:e.details}:nr(e)}function lr(){return typeof globalThis<`u`&&typeof globalThis.location?.href==`string`?globalThis.location?.href??``:``}function ur(){return typeof globalThis<`u`&&typeof globalThis.navigator?.userAgent==`string`?globalThis.navigator?.userAgent??``:``}const dr=r.string().min(1),fr=[`bs`,`cs`],pr=r.custom(e=>typeof e==`object`&&!!e,`dom must be a valid HTMLDivElement`),mr={centerHeartbeatIntervalMs:5e3,centerHeartbeatTimeoutMs:5e4},J={runMode:`RunMode/`,centerIP:`CenterIP/`,privateKey:`PrivateKey/`,showProgressBar:`showProgressBar/`},hr=r.object({centerIP:dr.optional(),signalingServer:dr.optional(),sceneName:dr.optional(),token:dr.optional(),dom:pr.optional(),showProgressBar:r.boolean().optional().default(!0),codec:r.string().optional().default(`H264`),viewMode:r.enum(fr).optional().default(`bs`),turnServer:r.string().optional(),turnUser:r.string().optional(),turnPwd:r.string().optional(),privateKey:r.string().optional(),engineUuid:r.string().optional(),mapType:r.string().optional().default(`web`),operationType:r.string().optional().default(`viewer`),freeCheckInterval:r.number().int().min(0).optional().default(0),initialSettings:r.record(r.unknown()).optional().default({}),logger:r.enum([`silent`,`error`,`warn`,`info`,`debug`]).optional().default(`info`),includeStack:r.enum([`silent`,`error`,`warn`,`info`,`debug`]).optional().default(`warn`),pixelStreamingLogger:r.enum([`silent`,`error`,`warn`,`info`,`debug`]).optional().default(`warn`),centerHeartbeatIntervalMs:r.never().optional(),centerHeartbeatTimeoutMs:r.never().optional()}).strict().superRefine((e,t)=>{!e.centerIP&&!e.signalingServer&&t.addIssue({code:r.ZodIssueCode.custom,path:[`centerIP`],message:`one of centerIP, signalingServer is required`}),e.sceneName||t.addIssue({code:r.ZodIssueCode.custom,path:[`sceneName`],message:`sceneName is required`}),e.token||t.addIssue({code:r.ZodIssueCode.custom,path:[`token`],message:`token is required`}),e.dom||t.addIssue({code:r.ZodIssueCode.custom,path:[`dom`],message:`dom is required`})});function gr(e){let t={};return e.split(` `).forEach(e=>{if(e.startsWith(J.runMode)){t.viewMode=e.slice(J.runMode.length);return}if(e.startsWith(J.centerIP)){t.centerIP=e.slice(J.centerIP.length);return}if(e.startsWith(J.privateKey)){t.privateKey=e.slice(J.privateKey.length);return}if(e.startsWith(J.showProgressBar)){let n=e.slice(J.showProgressBar.length);n===`true`?t.showProgressBar=!0:n===`false`&&(t.showProgressBar=!1)}}),t}function _r(e){let t=ur()||void 0;if(!t)return e;let n=gr(t);return Object.keys(n).length===0?e:{...e,...n}}function vr(e){let t=_r(e),n=hr.safeParse(t);if(!n.success)throw new d(`Core`,`DTCEngine.constructor`,n.error.issues.map(e=>({field:e.path.length>0?e.path.join(`.`):`<root>`,reason:e.message,code:e.code})));let r=n.data;return{centerIP:r.centerIP??``,signalingServer:r.signalingServer,sceneName:r.sceneName??``,token:r.token??``,dom:r.dom,showProgressBar:r.showProgressBar,codec:r.codec,viewMode:r.viewMode,turnServer:r.turnServer,turnUser:r.turnUser,turnPwd:r.turnPwd,privateKey:r.privateKey??``,engineUuid:r.engineUuid,mapType:r.mapType,operationType:r.operationType,freeCheckInterval:r.freeCheckInterval,initialSettings:r.initialSettings,logger:r.logger,includeStack:r.includeStack,pixelStreamingLogger:r.pixelStreamingLogger,centerHeartbeatIntervalMs:mr.centerHeartbeatIntervalMs,centerHeartbeatTimeoutMs:mr.centerHeartbeatTimeoutMs}}const yr=[`token`,`privatekey`,`authorization`,`cookie`,`set-cookie`],br={enabled:!1,endpoint:``,apiKey:``,app:{name:`@nnepoch/dtc-sdk`,version:`0.1.0`,environment:`production`},batching:{enabled:!0,itemLimit:20,sendTimeoutMs:3e4},retry:{maxAttempts:2},failure:{disableAfterConsecutiveFailures:5,warningIntervalMs:3e4},redactKeys:yr},xr=r.object({enabled:r.boolean().default(!1),endpoint:r.string().optional(),apiKey:r.string().optional(),app:r.object({name:r.string().min(1).default(`@nnepoch/dtc-sdk`),version:r.string().min(1).default(`0.1.0`),environment:r.string().min(1).default(`production`)}).default({name:`@nnepoch/dtc-sdk`,version:`0.1.0`,environment:`production`}),batching:r.object({enabled:r.boolean().default(!0),itemLimit:r.number().int().min(1).default(20),sendTimeoutMs:r.number().int().min(200).default(3e3)}).default({enabled:!0,itemLimit:20,sendTimeoutMs:3e3}),retry:r.object({maxAttempts:r.number().int().min(1).max(5).default(2)}).default({maxAttempts:2}),failure:r.object({disableAfterConsecutiveFailures:r.number().int().min(1).default(5),warningIntervalMs:r.number().int().min(1e3).default(3e4)}).default({disableAfterConsecutiveFailures:5,warningIntervalMs:3e4}),redactKeys:r.array(r.string().min(1)).default(yr)}).superRefine((e,t)=>{let n=typeof e.endpoint==`string`?e.endpoint.trim():``,i=n.length>0;if(e.enabled&&!i){t.addIssue({code:r.ZodIssueCode.custom,path:[`endpoint`],message:`qos reporting enabled requires endpoint`});return}e.enabled&&i&&!r.string().url().safeParse(n).success&&t.addIssue({code:r.ZodIssueCode.custom,path:[`endpoint`],message:`qos reporting endpoint must be a valid url`})});function Sr(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Cr(e,t){let n={...e};return Object.entries(t).forEach(([e,t])=>{if(t!==void 0){if(Sr(t)&&Sr(n[e])){n[e]=Cr(n[e],t);return}n[e]=t}}),n}function wr(){let e=Sr(globalThis.__ENGINE3_INTERNAL_QOS_REPORTING__)?{...globalThis.__ENGINE3_INTERNAL_QOS_REPORTING__}:{};typeof e.endpoint==`string`&&e.endpoint.trim().length===0&&delete e.endpoint,typeof e.apiKey==`string`&&e.apiKey.trim().length===0&&delete e.apiKey;let t=Cr(br,e);return xr.parse(t)}function Tr(e,t){let n=e.toLowerCase();return t.some(e=>n.includes(e.toLowerCase()))}function Er(e){if(typeof e==`string`)return e;if(e===void 0)return`undefined`;if(e===null)return`null`;if(typeof e==`number`||typeof e==`boolean`||typeof e==`bigint`)return String(e);try{return JSON.stringify(e)}catch{return String(e)}}function Dr(e,t){let n=new WeakSet,r=(e,i)=>{if(i&&Tr(i,t.redactKeys))return`[REDACTED]`;if(e===null||typeof e==`string`||typeof e==`number`||typeof e==`boolean`)return e;if(typeof e==`bigint`)return e.toString();if(e===void 0)return`undefined`;if(typeof e==`function`||typeof e==`symbol`)return String(e);if(e instanceof Date)return e.toISOString();if(e instanceof Error)return{name:e.name,message:e.message,stack:e.stack};if(Array.isArray(e))return e.map(e=>r(e));if(typeof e==`object`&&e){if(n.has(e))return`[CIRCULAR]`;n.add(e);let t=Object.entries(e),i={};return t.forEach(([e,t])=>{i[e]=r(t,e)}),i}return Er(e)};return r(e)}function Or(e){let t=e.toLowerCase();return t.includes(`auth`)?`auth`:t.includes(`center`)?`center`:t.includes(`sessionadapter`)||t.includes(`webrtc`)||t.includes(`pixelstreaming`)?`webrtc`:t.includes(`enginestatus`)||t.includes(`stream`)?`media`:t.includes(`requestbridge`)||t.includes(`camera`)||t.includes(`scene`)||t.includes(`model`)||t.includes(`poi`)||t.includes(`weather`)||t.includes(`timeline`)||t.includes(`popup`)||t.includes(`animation`)?`ue_api`:`session`}function kr(e){if(typeof e!=`string`)return;let t=e.trim();return t.length>0?t:void 0}function Ar(e){return e.trim().replace(/\s+/g,`_`).slice(0,64)}function jr(e){if(!Sr(e))return;let t=kr(e.code)??kr(e.errorCode)??kr(e.status);if(t)return Ar(t);let n=e.error;if(Sr(n)){let e=kr(n.code)??kr(n.errorCode)??kr(n.status);if(e)return Ar(e)}}var Mr=class{constructor(e,t){this.config=e,this.deps=t}async send(e){let t=typeof AbortController<`u`?new AbortController:void 0,n=t?setTimeout(()=>{t.abort()},this.config.batching.sendTimeoutMs):void 0;try{let n=await this.deps.fetchImpl(this.config.endpoint??``,{method:`POST`,headers:{"Content-Type":`application/json`,...this.config.apiKey?{"x-api-key":this.config.apiKey}:{}},body:JSON.stringify(e),signal:t?.signal});if(!n.ok)throw Error(`qos reporting request failed: ${n.status}`)}finally{n&&clearTimeout(n)}}};function Nr(){return typeof fetch==`function`}var Pr=class{constructor(e,t,n,r,i={}){if(this.config=e,this.session=t,this.runtime=n,this.onWarning=r,this.queue=[],this.flushing=!1,this.consecutiveFailures=0,this.lastWarningAt=0,this.disabledByFailure=!1,this.warnCount=0,this.errorCount=0,this.errorByStage={},this.errorCodeCounts=new Map,this.now=i.now??Date.now,this.setTimeoutImpl=i.setTimeoutImpl??setTimeout,this.clearTimeoutImpl=i.clearTimeoutImpl??clearTimeout,!e.enabled){this.enabled=!1,this.transport=void 0;return}if(this.enabled=!0,i.createTransport){this.transport=i.createTransport(e);return}if(!Nr()){this.transport=void 0,this.warnLimited(`qos reporting skipped: fetch unavailable`);return}this.transport=new Mr(e,{fetchImpl:fetch})}startSession(e){this.resetWarnErrorSummary(),this.recordEvent({eventName:`session_start`,stage:`session`,status:`start`,attrs:e})}endSession(e){this.recordEvent({eventName:`session_end`,stage:`session`,status:`end`,attrs:e,metrics:{summary:this.getWarnErrorSummary()}}),this.flush()}recordEvent(e){if(!this.enabled||!this.transport||this.disabledByFailure)return;let t=e.attrs?Dr(e.attrs,this.config):void 0,n=e.metrics?Dr(e.metrics,this.config):void 0;if(this.queue.push({eventName:e.eventName,stage:e.stage,status:e.status,ts:e.ts??this.now(),level:e.level??(e.status===`failed`?`error`:`info`),durationMs:e.durationMs,errorCode:e.errorCode,errorMessage:e.errorMessage,attrs:t,metrics:n}),!this.config.batching.enabled||this.queue.length>=this.config.batching.itemLimit){this.flush();return}this.flushTimer||=this.setTimeoutImpl(()=>{this.flushTimer=void 0,this.flush()},this.config.batching.sendTimeoutMs)}recordLogSignal(e){if(e.level===`warn`){this.warnCount+=1;return}this.errorCount+=1;let t=Or(e.moduleName);this.errorByStage[t]=(this.errorByStage[t]??0)+1;let n=jr(e.meta)??`UNKNOWN`;this.errorCodeCounts.set(n,(this.errorCodeCounts.get(n)??0)+1)}getWarnErrorSummary(){let e=Array.from(this.errorCodeCounts.entries()).sort((e,t)=>t[1]-e[1]).map(([e,t])=>({code:e,count:t}));return{logWarnCount:this.warnCount,logErrorCount:this.errorCount,logErrorByStage:{...this.errorByStage},logErrorTopCodes:e}}async flush(){if(this.flushing||this.queue.length===0||!this.transport||this.disabledByFailure)return;this.flushing=!0,this.flushTimer&&=(this.clearTimeoutImpl(this.flushTimer),void 0);let e=this.config.batching.enabled?this.config.batching.itemLimit:this.queue.length,t=this.queue.splice(0,e),n={schemaVersion:`1.0.0`,source:`enginesdk3`,sdkVersion:this.config.app.version,sentAt:this.now(),session:this.session,context:this.runtime,events:t};try{await this.sendWithRetry(n),this.consecutiveFailures=0}catch(e){this.onFailure(e,`send qos payload failed`)}finally{this.flushing=!1,this.queue.length>0&&!this.disabledByFailure&&this.flush()}}async sendWithRetry(e){let t=Math.max(1,this.config.retry.maxAttempts),n;for(let r=1;r<=t;r+=1)try{await this.transport?.send(e);return}catch(e){n=e}throw n instanceof Error?n:Error(String(n))}onFailure(e,t){this.consecutiveFailures+=1,this.warnLimited(t,{consecutiveFailures:this.consecutiveFailures,error:e instanceof Error?`${e.name}: ${e.message}`:String(e)}),this.consecutiveFailures>=this.config.failure.disableAfterConsecutiveFailures&&(this.disabledByFailure=!0,this.warnLimited(`qos reporting disabled after repeated failures`))}warnLimited(e,t){let n=this.now();n-this.lastWarningAt<this.config.failure.warningIntervalMs||(this.lastWarningAt=n,this.onWarning(e,t))}resetWarnErrorSummary(){this.warnCount=0,this.errorCount=0,this.errorByStage={},this.errorCodeCounts.clear()}},Fr=class{constructor(){this.listeners=new Map,this.debugMode=!1}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),this.debugMode&&console.log(`[EventBus] Subscribed to "${String(e)}"`)}off(e,t){let n=this.listeners.get(e);n&&(n.delete(t),n.size===0&&this.listeners.delete(e)),this.debugMode&&console.log(`[EventBus] Unsubscribed from "${String(e)}"`)}emit(e,t){let n=this.listeners.get(e);this.debugMode&&console.log(`[EventBus] Emitting "${String(e)}"`,t),!(!n||n.size===0)&&n.forEach(n=>{try{n(t)}catch(t){console.error(`[EventBus] Error in handler for "${String(e)}":`,t)}})}once(e,t){let n=r=>{this.off(e,n),t(r)};this.on(e,n)}removeAllListeners(e){e===void 0?(this.listeners.clear(),this.debugMode&&console.log(`[EventBus] Removed all listeners`)):(this.listeners.delete(e),this.debugMode&&console.log(`[EventBus] Removed all listeners for "${String(e)}"`))}listenerCount(e){return this.listeners.get(e)?.size??0}eventNames(){return Array.from(this.listeners.keys())}setDebugMode(e){this.debugMode=e}};const Ir=[`webRtcConnected`,`webRtcDisconnected`,`webRtcConnecting`,`webRtcFailed`,`statsReceived`,`subscribeFailed`,`streamerAssigned`];var Lr=class{constructor(){this.mode=`bs`,this.forwardEvents=[...Ir,`streamLoading`]}applyInitialSettings(e){return{[o.KeyboardInput]:!0,[o.MouseInput]:!0,[o.TouchInput]:!0,[o.GamepadInput]:!0,[o.XRControllerInput]:!0,[o.HoveringMouseMode]:!0,[o.AutoPlayVideo]:!0,[o.MatchViewportResolution]:!0,[o.StartVideoMuted]:!0,[s.MaxReconnectAttempts]:0,...e}}onBeforeConnect(e){e.info(`session connect preparing for bs mode`)}onAfterConnect(e){e.info(`session connect triggered for bs mode`)}},Rr=class{constructor(){this.mode=`cs`,this.forwardEvents=Ir}applyInitialSettings(e){return{[o.KeyboardInput]:!0,[o.MouseInput]:!1,[o.TouchInput]:!1,[o.GamepadInput]:!1,[o.XRControllerInput]:!1,[o.HoveringMouseMode]:!0,[o.AutoPlayVideo]:!0,[o.MatchViewportResolution]:!0,[o.StartVideoMuted]:!0,[s.MaxReconnectAttempts]:0,...e}}onBeforeConnect(e){e.info(`session connect preparing for cs mode`)}onAfterConnect(e){e.info(`session connect triggered for cs mode`)}};function zr(e){return e===`cs`?new Rr:new Lr}var Br=class{constructor(e,t,n=h){this.logger=n,this.streamerAssignedListeners=new Set,this.handlePoiCursorResponse=e=>{try{let t=JSON.parse(e);if(t.uuid!==`POICursor`)return;this.setVideoCursor(t.param===`pointer`?`pointer`:`default`)}catch{}},this.videoElementParent=t,this.modeStrategy=zr(e.viewMode);let r=this.modeStrategy.applyInitialSettings(e.initialSettings??{});this.psConfig=new a({initialSettings:{...r}}),t?.classList?.add(`fixed-size`),t&&getComputedStyle(t).position===`static`&&(t.style.position=`relative`),this.stream=new l(this.psConfig,t?{videoElementParent:t}:void 0),this.stream.addResponseEventListener(`enginesdk_poi_cursor_listener`,this.handlePoiCursorResponse),this.setupStreamerAssignedListener(),this.logger.info(`session initialized`,{hasVideoParent:!!t,viewMode:this.modeStrategy.mode})}connect(){this.modeStrategy.onBeforeConnect(this.logger),this.logger.info(`connect`),this.stream.connect(),this.modeStrategy.onAfterConnect(this.logger)}reconnect(){this.logger.info(`reconnect`),this.stream.reconnect()}disconnect(){this.logger.info(`disconnect`),this.setVideoCursor(`default`),this.stream.disconnect()}beginPointEditorMouseInput(){let e=[o.MouseInput,o.HoveringMouseMode],t=e.map(e=>this.psConfig.isFlagEnabled(e));e.forEach(e=>this.psConfig.setFlagEnabled(e,!0));let n=!1;return()=>{n||(n=!0,e.forEach((e,n)=>this.psConfig.setFlagEnabled(e,t[n])))}}setSignallingUrlBuilder(e){this.logger.info(`setSignallingUrlBuilder configured`),this.stream.setSignallingUrlBuilder(e)}emitUIInteraction(e){let t=this.stream.emitUIInteraction(e);return t?this.logger.debug(`emitUIInteraction sent`):this.logger.warn(`emitUIInteraction failed`),t}emitCommand(e){let t=this.stream.emitCommand(e);return t?this.logger.debug(`emitCommand sent`):this.logger.warn(`emitCommand failed`),t}addResponseEventListener(e,t){this.logger.debug(`addResponseEventListener`,{name:e}),this.stream.addResponseEventListener(e,t)}removeResponseEventListener(e){this.logger.debug(`removeResponseEventListener`,{name:e}),this.stream.removeResponseEventListener(e)}addEventListener(e,t){if(this.logger.debug(`addEventListener`,{event:e}),e===`streamerAssigned`){this.streamerAssignedListeners.add(t);return}this.stream.addEventListener(e,t)}removeEventListener(e,t){if(this.logger.debug(`removeEventListener`,{event:e}),e===`streamerAssigned`){this.streamerAssignedListeners.delete(t);return}this.stream.removeEventListener(e,t)}getForwardEvents(){return this.modeStrategy.forwardEvents}getViewMode(){return this.modeStrategy.mode}isReconnecting(){return this.stream.isReconnecting()}setVideoCursor(e){this.videoElementParent&&(this.videoElementParent.style.cursor=e,this.videoElementParent.querySelectorAll(`video`).forEach(t=>{t.style.cursor=e}))}setupStreamerAssignedListener(){try{let e=this.stream.webRtcController?.protocol;if(!e||typeof e.addListener!=`function`){this.logger.warn(`webRtcController.protocol not available, streamerAssigned listener not registered`);return}e.addListener(`streamerAssigned`,e=>{if(this.logger.info(`streamerAssigned received`,{streamerId:e.streamerId}),e.streamerId)try{this.psConfig.setOptionSettingValue(c.StreamerId,e.streamerId),this.logger.info(`StreamerId configured`,{streamerId:e.streamerId})}catch(t){this.logger.error(`Failed to set StreamerId`,{streamerId:e.streamerId,error:t instanceof Error?t.message:String(t)})}else this.logger.warn(`streamerAssigned received without streamerId`,{msg:e});this.streamerAssignedListeners.forEach(t=>{try{t(e)}catch(e){this.logger.error(`streamerAssigned listener error`,{error:e instanceof Error?e.message:String(e)})}})}),this.logger.debug(`streamerAssigned listener registered`)}catch(e){this.logger.error(`Failed to setup streamerAssigned listener`,{error:e instanceof Error?e.message:String(e)})}}};const Y={SignallingBootstrapFailed:`SIGNALLING_BOOTSTRAP_FAILED`,CenterUnavailable:`CENTER_UNAVAILABLE`,CenterProtocolInvalid:`CENTER_PROTOCOL_INVALID`,ConnectResultFailed:`CONNECT_RESULT_FAILED`,ServiceAllocationFailed:`SERVICE_ALLOCATION_FAILED`,ResourceWaiting:`RESOURCE_WAITING`,AuthorizeFailed:`AUTHORIZE_FAILED`,TokenInvalid:`TOKEN_INVALID`,TokenExpired:`TOKEN_EXPIRED`,SignallingUrlMissing:`SIGNALLING_URL_MISSING`,HeartbeatTimeout:`HEARTBEAT_TIMEOUT`,CenterDisconnected:`CENTER_DISCONNECTED`};var X=class extends Error{constructor(e,t,n,r){super(t),this.code=e,this.retryable=n,this.details=r,this.name=`SDKAuthError`}toErrorInfo(){return{code:this.code,message:this.message,retryable:this.retryable}}};function Vr(e){return e instanceof X?e:e instanceof Error?new X(Y.CenterUnavailable,e.message,!0,{cause:e.message}):new X(Y.CenterUnavailable,String(e),!0)}var Hr=class{constructor(t,n=h,r){this.config=t,this.logger=n,this.authEvents=r,this.textEncoder=new TextEncoder,this.connectId=``,this.events=new e,this.manualClose=!1}on(e,t){this.events.on(e,t)}off(e,t){this.events.off(e,t)}isConnected(){return this.socket?.readyState===WebSocket.OPEN}getConnectId(){return this.connectId}async connect(){if(this.isConnected())return;this.disposeSocket(),this.connectId=this.generateConnectId();let e=this.buildCenterWsUrl(this.connectId),t=this.defaultWebSocketFactory;return this.logger.info(`center connecting`,{wsUrl:e}),this.manualClose=!1,this.closeReasonError=void 0,new Promise((n,r)=>{try{let i=t(e);this.socket=i,i.onopen=()=>{this.startHeartbeatLoops(),this.sendHeartbeat(),this.logger.info(`center connected`),i.binaryType=`arraybuffer`,n()},i.onmessage=e=>{this.handleIncomingData(e.data)},i.onerror=()=>{},i.onclose=()=>{this.stopHeartbeatLoops(),this.socket=void 0;let e=this.closeReasonError??new X(Y.CenterDisconnected,`Center websocket disconnected`,!0);this.manualClose||(this.events.emit(`disconnected`,e),r(e)),this.closeReasonError=void 0}}catch(e){this.authEvents.emit(`progress`,{kind:`loading`,message:b.ServiceUrlInValid,key:`ServiceUrlInValid`,isClose:!0}),r(new X(Y.CenterUnavailable,`Failed to create center websocket: ${e instanceof Error?e.message:String(e)}`,!0,{cause:e instanceof Error?e.message:String(e)}))}})}disconnect(){this.manualClose=!0,this.closeReasonError=void 0,this.disposeSocket()}sendApiData(e,t,n){if(!this.socket||this.socket.readyState!==WebSocket.OPEN)throw new X(Y.CenterDisconnected,`Center websocket is not connected`,!0);let r={projectKey:this.config.sceneName,cls:`WebAPI`,method:e,param:t,fn:n},i=JSON.stringify(r),a=this.textEncoder.encode(i),o=new Uint8Array(a.length+1);o.set(a),this.socket.send(o.buffer),e!==`Heart`&&this.logger.debug(`center send`,{method:e,callbackName:n})}defaultWebSocketFactory(e){if(typeof WebSocket>`u`)throw Error(`WebSocket is not available in current runtime.`);return new WebSocket(e)}startHeartbeatLoops(){this.stopHeartbeatLoops(),this.heartbeatTimer=setInterval(()=>{try{this.isConnected()&&this.sendHeartbeat()}catch(e){this.logger.warn(`send heartbeat failed`,{error:e instanceof Error?e.message:String(e)})}},this.config.centerHeartbeatIntervalMs)}sendHeartbeat(){this.sendApiData(`Heart`),this.armHeartbeatTimeout()}stopHeartbeatLoops(){this.heartbeatTimer&&=(clearInterval(this.heartbeatTimer),void 0),this.clearHeartbeatTimeout()}armHeartbeatTimeout(){this.heartbeatTimeoutTimer||=setTimeout(()=>{this.heartbeatTimeoutTimer=void 0;let e=new X(Y.HeartbeatTimeout,`Center heartbeat timed out after ${this.config.centerHeartbeatTimeoutMs}ms`,!0);this.closeReasonError=e,this.events.emit(`heartbeatTimeout`,e),this.socket?.close()},this.config.centerHeartbeatTimeoutMs)}clearHeartbeatTimeout(){this.heartbeatTimeoutTimer&&=(clearTimeout(this.heartbeatTimeoutTimer),void 0)}disposeSocket(){this.stopHeartbeatLoops(),this.socket&&=(this.socket.onopen=null,this.socket.onmessage=null,this.socket.onerror=null,this.socket.onclose=null,this.socket.close(),void 0)}async handleIncomingData(e){this.clearHeartbeatTimeout();let t=await this.decodeToBytes(e);if(!t)return;let n;try{n=u(t,{to:`string`})}catch{this.logger.warn(`center message inflate failed`);return}if(!n)return;let r;try{r=JSON.parse(n)}catch{this.logger.warn(`center message parse failed`);return}if(!r.fn){this.logger.warn(`center message missing fn`);return}r.fn!==`Heart`&&this.events.emit(`message`,r)}async decodeToBytes(e){if(e instanceof ArrayBuffer)return new Uint8Array(e);if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);if(typeof Blob<`u`&&e instanceof Blob){let t=await e.arrayBuffer();return new Uint8Array(t)}return typeof e==`string`?this.textEncoder.encode(e):(this.logger.warn(`unsupported center message format`),null)}buildCenterWsUrl(e){return`${this.config.centerIP.replace(/^https:/i,`wss:`).replace(/^http:/i,`ws:`).replace(/\/+$/,``)}/${[this.config.mapType,e,this.config.sceneName,this.config.token,this.config.operationType].map(e=>encodeURIComponent(e)).join(`/`)}`}generateConnectId(){return`w_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}};function Ur(e,t,n){let r=e.endsWith(`/`)?e:`${e}/`,i=new URL(`api/v1/allocate`,r);return i.searchParams.set(`token`,t),i.searchParams.set(`proj`,n),i.toString()}function Wr(e){if(typeof e.signalingAddress==`string`&&e.signalingAddress.trim().length>0)return e.signalingAddress.trim();if(typeof e.signallingAddress==`string`&&e.signallingAddress.trim().length>0)return e.signallingAddress.trim()}function Gr(e,t){return new X(Y.SignallingBootstrapFailed,`Signalling allocate request timed out after ${t}ms`,!0,{endpoint:e,timeoutMs:t})}async function Kr(e,t=h){if(typeof fetch!=`function`)throw new X(Y.SignallingBootstrapFailed,`Fetch API is not available for signalling allocation`,!1);let n=Ur(e.signalingServer,e.token,e.proj),r=e.timeoutMs??15e3,i=typeof AbortController==`function`?new AbortController:void 0,a=!1,o,s=i?void 0:new Promise((e,t)=>{o=t}),c;c=setTimeout(()=>{if(a=!0,i){i.abort();return}o?.(Gr(n,r))},r);try{let e=fetch(n,{method:`GET`,...i?{signal:i.signal}:{}}),r=i?await e:await Promise.race([e,s]);if(!r.ok)throw new X(Y.SignallingBootstrapFailed,`Signalling allocate request failed with status ${r.status}`,!0,{endpoint:n,status:r.status});let a;try{a=await r.json()}catch(e){throw new X(Y.SignallingBootstrapFailed,`Signalling allocate response is not valid JSON`,!1,{endpoint:n,cause:e instanceof Error?e.message:String(e)})}let o=Wr(a);if(!o)throw new X(Y.SignallingUrlMissing,`Signalling allocate response missing signalingAddress`,!1,a);return t.info(`signalling allocate resolved url`,{endpoint:n}),o}catch(e){throw a?Gr(n,r):e instanceof X?e:new X(Y.SignallingBootstrapFailed,e instanceof Error?e.message:`Signalling allocate request failed`,!0,{endpoint:n,cause:e})}finally{c!==void 0&&clearTimeout(c)}}var qr=class{constructor(t,n,r=h){this.config=t,this.session=n,this.logger=r,this.events=new e,this.handleWebRtcDisconnected=()=>{this.recoverFromWebRtcDisconnection()},this.nextOperationId=0,this.phase=`idle`,this.stopRequested=!1,this.reconnecting=!1,this.snapshot={state:`idle`,reconnecting:!1,updatedAt:Date.now()},this.centerClient=new Hr(t,r,this.events),this.centerClient.on(`heartbeatTimeout`,e=>{this.logger.warn(`center heartbeat timeout`,{message:e.message}),this.handleCenterInterruption(e)}),this.centerClient.on(`disconnected`,e=>{this.logger.warn(`center disconnected`,{message:e.message}),this.handleCenterInterruption(e)}),this.centerClient.on(`message`,e=>{this.handleCenterMessage(e)}),this.session.addEventListener(`webRtcDisconnected`,this.handleWebRtcDisconnected)}on(e,t){this.events.on(e,t)}off(e,t){this.events.off(e,t)}getSnapshot(){return{...this.snapshot,reconnecting:this.reconnecting||this.session.isReconnecting()}}start(){return this.runningFlow?this.runningFlow.promise:this.startFlow({route:this.shouldUseDirectSignallingBootstrap()?`direct`:`center`,reconnecting:!1,disconnectSession:!1,resolveOnStop:!0})}reconnect(){return this.startFlow({route:this.shouldUseDirectSignallingBootstrap()?`direct`:`center`,reconnecting:!0,disconnectSession:!0,resolveOnStop:!0})}reconnectSignalling(){let e=this.signallingAllocationSource;return e?this.startFlow({route:`signalling`,reconnecting:!0,disconnectSession:!0,resolveOnStop:!1,signallingSource:e}):this.reconnect()}startFlow(e){if(this.runningFlow)return e.reconnecting&&(this.reconnecting=!0),e.disconnectSession&&this.session.disconnect(),this.runningFlow.promise;e.disconnectSession&&this.session.disconnect(),this.stopRequested=!1,this.reconnecting=e.reconnecting;let t=this.advanceOperation(),n=this.createRunningFlow(t,e.resolveOnStop);return this.runningFlow=n,this.phase=e.route===`signalling`?`settling`:`starting`,n.promise=this.decorateRunningFlow(n),(e.route===`center`||e.route===`direct`)&&this.prepareAuthBootstrap(t),this.runFlowRoute(e,t),n.promise}runFlowRoute(e,t){switch(e.route){case`center`:this.runCenterFlow(t);return;case`direct`:this.runDirectFlow(t);return;case`signalling`:this.runSignallingFlow(e.signallingSource,t);return}}prepareAuthBootstrap(e){this.centerClient.disconnect(),this.clearRunningContext(),this.pendingCenterInterruption=void 0,this.updateSnapshot(`centerConnecting`,{lastError:void 0,signallingUrl:void 0,engineToken:void 0,webToken:void 0}),this.isCurrentOperation(e)}runCenterFlow(e){this.runAuthFlowOnce(e)}runDirectFlow(e){this.startDirectSignallingBootstrap(e).catch(t=>{this.rejectActiveFlow(t,e)})}runSignallingFlow(e,t){if(!e){this.rejectActiveFlow(new X(Y.SignallingBootstrapFailed,`Signalling bootstrap source is missing`,!1),t);return}this.signallingAllocationSource=e,this.resolveAndConnectSignalling(e,t).catch(e=>{this.rejectActiveFlow(e,t)})}disconnect(){let e=this.runningFlow;this.advanceOperation(),this.runningFlow=void 0,this.reconnecting=!1,this.stopRequested=!0,this.pendingCenterInterruption=void 0,this.phase=`idle`;let t=new X(Y.CenterDisconnected,`Auth workflow disconnected by user`,!0);e&&(e.stopRequested=!0,e.reject?.(t),e.resolve=void 0,e.reject=void 0),this.centerClient.disconnect(),this.session.disconnect(),this.updateSnapshot(`idle`,{webToken:void 0,engineToken:void 0,signallingUrl:void 0,lastError:void 0}),e&&(e.stopSnapshot=this.getSnapshot())}disconnectAndWait(){let e=this.runningFlow?.promise;return this.disconnect(),e?e.then(()=>void 0,()=>void 0):Promise.resolve()}runAuthFlowOnce(e){this.isCurrentOperation(e)&&this.centerClient.connect().then(()=>{this.isCurrentOperation(e)&&(this.updateSnapshot(`centerConnected`),this.expectMessage(`ConnectResult`))}).catch(t=>{this.rejectActiveFlow(t,e)})}shouldUseDirectSignallingBootstrap(){return!!this.config.signalingServer}async startDirectSignallingBootstrap(e){if(!this.isCurrentOperation(e))return;this.setPhase(`settling`,e);let t=this.resolveDirectSignallingAllocationSource();this.signallingAllocationSource=t,await this.resolveAndConnectSignalling(t,e)}resolveDirectSignallingAllocationSource(){if(this.config.signalingServer)return{signalingServer:this.config.signalingServer,token:this.config.token,proj:this.config.sceneName};throw new X(Y.SignallingBootstrapFailed,`No signalling bootstrap source configured`,!1)}handleCenterMessage(e){switch(e.fn){case`ConnectResult`:this.emitCenterEvent(`ConnectResult`,e),this.handleConnectResult(e);return;case`EngineServiceInit`:this.emitCenterEvent(`EngineServiceInit`,e),this.handleEngineServiceInit(e);return;case`TokenAuthorize`:this.emitCenterEvent(`TokenAuthorize`,e),this.handleTokenAuthorize(e);return;case`CenterCloseMessage`:this.emitCenterEvent(`CenterCloseMessage`,e),this.handleCenterCloseMessage(e);return;case`EngineSocketClose`:this.emitCenterEvent(`EngineSocketClose`,e),this.handleEngineSocketClose(e);return;case`TokenWillExpired`:this.emitCenterEvent(`TokenWillExpired`,e),this.handleTokenWillExpired(e);return;case`Offer`:case`Answer`:case`IceCandidate`:this.logger.debug(`center message ignored by current change scope`,{fn:e.fn});return;default:this.logger.debug(`unhandled center message`,{fn:e.fn})}}handleConnectResult(e){if(this.isExpecting(`ConnectResult`))try{if(e.success===!1){this.logger.warn(`connect result failed`,{status:e.status??``,message:e.message??``});return}let t=this.parseValues(e),n=t.webToken;if(!n)throw new X(Y.ConnectResultFailed,`ConnectResult missing webToken`,!0,e);this.connectResult=t,this.emitCenterEvent(`Connect`,e),this.emitLoadingProgress(b.EngineIniting,`EngineIniting`),this.updateSnapshot(`serviceAllocating`,{webToken:n}),this.centerClient.sendApiData(`GetServiceInfo`,this.config.privateKey||void 0),this.expectMessage(`EngineServiceInit`)}catch(e){this.rejectActiveFlow(e)}}handleEngineServiceInit(e){if(this.isExpecting(`EngineServiceInit`))try{if(e.success===!1){let t=e.message??``;this.emitWaitingProgress(t),this.config.viewMode!==`cs`&&this.emitCenterEvent(`EngineServiceInitWait`,e),this.updateSnapshot(`waiting`);return}let t=this.parseValues(e),n=t.token;if(!n)throw new X(Y.ServiceAllocationFailed,`EngineServiceInit missing engine token`,!0,e);this.serviceInfo=t,this.emitLoadingProgress(b.EngineTockenChecking,`EngineTockenChecking`),this.updateSnapshot(`authorizing`,{engineToken:n});let r=JSON.stringify({engineToken:n,webUuid:this.centerClient.getConnectId(),webToken:this.snapshot.webToken});this.centerClient.sendApiData(`AuthorizeToken`,r,`TokenAuthorize`),this.expectMessage(`TokenAuthorize`)}catch(e){this.rejectActiveFlow(e)}}handleTokenAuthorize(e){if(!this.isExpecting(`TokenAuthorize`))return;if(e.success===!1){this.logger.warn(`token authorize failed, wait center close message`,{status:e.status??``,message:e.message??``});return}let t=this.runningFlow?.operationId;t!==void 0&&this.handleTokenAuthorizeSuccess(e,t).catch(e=>{this.rejectActiveFlow(e,t)})}async handleTokenAuthorizeSuccess(e,t){if(!this.isCurrentOperation(t))return;this.setPhase(`settling`,t);let n=(this.tryParseValues(e)??{}).signalingServer?.trim();if(!n)throw new X(Y.SignallingUrlMissing,`TokenAuthorize missing signalingServer`,!1,e);let r=this.snapshot.engineToken;if(!r)throw new X(Y.ServiceAllocationFailed,`Engine token is missing before signaling allocation`,!1,e);let i={signalingServer:n,token:r,proj:this.config.sceneName};this.signallingAllocationSource=i,await this.resolveAndConnectSignalling(i,t)}async resolveAndConnectSignalling(e,t){let n=await Kr(e,this.logger);if(!this.isCurrentOperation(t)){this.logger.debug(`ignore stale signalling allocation result`,{operationId:t});return}this.connectWithSignallingUrl(n,t)}connectWithSignallingUrl(e,t){if(!this.isCurrentOperation(t)){this.logger.debug(`ignore stale signalling connect result`,{operationId:t});return}if(!e)throw new X(Y.SignallingUrlMissing,`Signalling url is missing before connect`,!1);this.session.setSignallingUrlBuilder(()=>{let e=this.snapshot.signallingUrl;if(!e)throw new X(Y.SignallingUrlMissing,`Signalling url not ready before connect`,!1);return e}),this.emitLoadingProgress(b.EngineConnectioning,`EngineConnectioning`),this.updateSnapshot(`webrtcConnecting`,{signallingUrl:e}),this.session.connect(),this.setPhase(`connected`,t),this.updateSnapshot(`connected`),this.completeRunningFlow(this.getSnapshot(),t)}handleCenterCloseMessage(e){let t=e.message??`CenterCloseMessage received`;if(e.status===`TokenInValid`){this.emitLoadingProgress(b.TokenInValid,`TokenInValid`);let n=new X(Y.TokenInvalid,t,!1,e);this.rejectActiveFlow(n)||this.publishFailure(n),this.centerClient.disconnect();return}if(e.status===`TokenExpired`){this.emitLoadingProgress(b.TokenExpired,`TokenExpired`);let n=new X(Y.TokenExpired,t,!1,e);this.rejectActiveFlow(n)||this.publishFailure(n),this.centerClient.disconnect();return}this.emitLoadingProgress(b.EngineTokenCheckFail,`EngineTokenCheckFail`);let n=new X(Y.AuthorizeFailed,t,!1,e);this.rejectActiveFlow(n)||this.publishFailure(n)}handleEngineSocketClose(e){let t=this.snapshot.engineToken,n=this.extractEngineSocketCloseToken(e.values);if(!t||!n||t!==n){this.logger.debug(`ignore EngineSocketClose for non-current session`,{currentToken:t,closedToken:n});return}let r=new X(Y.CenterDisconnected,e.message??`Engine socket closed`,!0,e);this.emitLoadingProgress(b.EngineClose,`EngineClose`),this.handleCenterInterruption(r)}handleTokenWillExpired(e){this.logger.warn(`token will expire soon`,{message:e.message??``}),this.emitTokenWillExpireProgress(e.message??``)}expectMessage(e){this.expectedCenterFn=e}isExpecting(e){return this.expectedCenterFn===e&&this.hasActiveRunningFlow()}advanceOperation(){return this.nextOperationId+=1,this.nextOperationId}isCurrentOperation(e){return this.runningFlow?.operationId===e}setPhase(e,t){return this.isCurrentOperation(t)?(this.phase=e,!0):!1}createRunningFlow(e,t=!1){let n=()=>void 0,r=()=>void 0;return{operationId:e,promise:new Promise((e,t)=>{n=e,r=t}),resolve:n,reject:r,stopRequested:!1,resolveOnStop:t}}decorateRunningFlow(e){return e.promise.then(t=>e.stopRequested?e.stopSnapshot??this.getSnapshot():(this.reconnecting=!1,this.events.emit(`connected`,t),t)).catch(t=>{if(e.stopRequested){if(e.resolveOnStop)return e.stopSnapshot??this.getSnapshot();throw Vr(t)}let n=Vr(t);throw this.isCurrentOperation(e.operationId)&&(this.updateSnapshot(`failed`,{lastError:n.toErrorInfo()}),this.events.emit(`failed`,this.getSnapshot())),n}).finally(()=>{if(!this.isCurrentOperation(e.operationId))return;let t=e.stopRequested||this.stopRequested;this.setPhase(this.snapshot.state===`connected`?`connected`:`idle`,e.operationId),this.runningFlow=void 0,this.reconnecting=!1,this.stopRequested=!1,this.flushPendingCenterInterruption(t,e.operationId)})}completeRunningFlow(e,t){if(!this.isCurrentOperation(t)){this.logger.debug(`ignore stale auth flow completion`,{operationId:t});return}let n=this.runningFlow;this.clearRunningContext(t),n?.resolve?.(e),n&&(n.resolve=void 0,n.reject=void 0)}rejectActiveFlow(e,t){let n=Vr(e),r=this.runningFlow;if(!r||t!==void 0&&r.operationId!==t)return this.logger.debug(`ignore stale auth flow failure`,{operationId:t,currentOperationId:r?.operationId,code:n.code,message:n.message}),!1;let i=r.reject;return i?(this.clearRunningContext(r.operationId),r.resolve=void 0,r.reject=void 0,i(n),!0):(this.logger.debug(`ignore auth flow failure without active deferred`,{operationId:r.operationId,code:n.code,message:n.message}),!1)}publishFailure(e){this.updateSnapshot(`failed`,{lastError:e.toErrorInfo()}),this.events.emit(`failed`,this.getSnapshot())}hasActiveRunningFlow(){return!!this.runningFlow?.reject}clearRunningContext(e){e!==void 0&&!this.isCurrentOperation(e)||(this.expectedCenterFn=void 0,this.connectResult=void 0,this.serviceInfo=void 0)}isWaitingMessage(e){return[`坐席已满`,`服务已满`,`排队`,`没有服务资源`,`资源`].some(t=>e.includes(t))}parseValues(e){if(!e.values)return{};try{return JSON.parse(e.values)}catch(t){throw new X(Y.CenterProtocolInvalid,`Invalid center values json for ${e.fn}`,!1,{envelope:e,cause:t instanceof Error?t.message:String(t)})}}tryParseValues(e){if(e.values)try{return JSON.parse(e.values)}catch(t){this.logger.warn(`center values parse failed, fallback to empty payload`,{fn:e.fn,cause:t instanceof Error?t.message:String(t)});return}}extractEngineSocketCloseToken(e){if(!e)return;let t=e.trim();if(t){try{let e=JSON.parse(t);if(typeof e==`string`)return e;if(e&&typeof e.token==`string`&&e.token.trim().length>0)return e.token}catch{}return t}}handleCenterInterruption(e){let t=this.decideCenterInterruption();switch(t.kind){case`ignore`:return;case`reject`:this.rejectActiveFlow(e,t.operationId);return;case`defer`:this.deferCenterInterruption(e,t.operationId);return;case`recover`:this.recoverFromCenterInterruption(e);return}}decideCenterInterruption(){if(this.isTerminalSnapshot())return{kind:`ignore`};let e=this.runningFlow;return e?this.phase===`settling`?{kind:`defer`,operationId:e.operationId}:this.hasActiveRunningFlow()?{kind:`reject`,operationId:e.operationId}:{kind:`defer`,operationId:e.operationId}:{kind:`recover`}}isTerminalSnapshot(){return this.isTerminalSnapshotState(this.snapshot.state)}deferCenterInterruption(e,t){if(this.isCurrentOperation(t)){if(this.pendingCenterInterruption){this.logger.debug(`center interruption already deferred during flow settlement`,{currentCode:this.pendingCenterInterruption.error.code,incomingCode:e.code});return}this.pendingCenterInterruption={operationId:t,error:e},this.logger.debug(`defer center interruption until current flow settles`,{operationId:t,code:e.code,message:e.message})}}flushPendingCenterInterruption(e,t){let n=this.pendingCenterInterruption;if(!(!n||n.operationId!==t)){if(this.pendingCenterInterruption=void 0,e||this.snapshot.state===`idle`||this.snapshot.state===`failed`||this.runningFlow){this.logger.debug(`drop deferred center interruption`,{skip:e,state:this.snapshot.state,code:n.error.code,operationId:t});return}this.recoverFromCenterInterruption(n.error)}}recoverFromWebRtcDisconnection(){let e=this.snapshot.state;if(this.shouldIgnoreWebRtcDisconnection(e)){this.logger.debug(`ignore WebRTC disconnection for current workflow state`,{stopRequested:this.stopRequested,reconnecting:this.reconnecting,hasRunningPromise:!!this.runningFlow,state:e});return}this.logger.warn(`WebRTC disconnected, reconnect signalling`,{state:e}),this.reconnectSignalling().catch(e=>{let t=Vr(e);this.publishFailure(t)})}shouldIgnoreWebRtcDisconnection(e){return this.stopRequested||this.reconnecting||!!this.runningFlow||this.isTerminalSnapshotState(e)}isTerminalSnapshotState(e){return e===`idle`||e===`failed`}recoverFromCenterInterruption(e){this.logger.warn(`center interruption detected, start reconnect`,{state:this.snapshot.state,code:e.code,message:e.message}),this.emitCenterEvent(`UnConnect`,{code:e.code,message:e.message}),this.emitLoadingProgress(b.SerriceError,`SerriceError`),this.reconnect().catch(e=>{let t=Vr(e);this.publishFailure(t)})}updateSnapshot(e,t){this.snapshot={...this.snapshot,...t,state:e,reconnecting:this.reconnecting||this.session.isReconnecting(),updatedAt:Date.now()},this.events.emit(`stateChanged`,this.getSnapshot())}emitLoadingProgress(e,t,n=!0){this.events.emit(`progress`,{kind:`loading`,message:e,key:t,isClose:n})}emitTokenWillExpireProgress(e,t=!0){this.events.emit(`progress`,{kind:`tokenWillExpire`,message:e,key:`TokenWillExpired`,isClose:t})}emitCenterEvent(e,t){this.events.emit(`centerEvent`,{eventName:e,payload:t})}emitWaitingProgress(e){if(this.config.viewMode!==`cs`){if(e.includes(`云渲染服务坐席已满`)||e.includes(`坐席已满`)||e.includes(`当前服务已满`)){this.emitLoadingProgress(e,`EngineWaiting`);return}e.includes(`没有服务资源`)&&this.emitLoadingProgress(b.SerriceUnAvaible,`SerriceUnAvaible`)}}};function Jr(e){return typeof e==`object`&&!!e}var Yr=class{constructor(e,t=h,n={},r={}){this.session=e,this.logger=t,this.hooks=n,this.pending=new Map,this.sendRetries=new Map,this.listenerName=`enginesdk3_response_listener`,this.disconnectEvents=[`webRtcDisconnected`,`webRtcFailed`],this.onResponse=this.handleResponse.bind(this),this.onSessionDisconnected=()=>{this.cleanupPendingOnDisconnect()},this.retryOptions={enabled:r.enabled??!0,intervalMs:r.intervalMs??250,maxWaitMs:r.maxWaitMs??15e3},this.logger.debug(`register response listener`,{listenerName:this.listenerName}),this.session.addResponseEventListener(this.listenerName,this.onResponse),this.disconnectEvents.forEach(e=>{this.session.addEventListener(e,this.onSessionDisconnected)})}sendRequest(e,t,n){let{requestId:r,envelope:i}=this.createRequestEnvelope(e,t,n),a,o,s=new Promise((e,t)=>{a=e,o=t}),c={mode:`single`,module:e,method:t,sentAt:Date.now(),resolve:a,reject:o};return this.pending.set(r,c),this.handleSendAttempt(r,i,c,!1),s}sendStreamRequest(e,t,n,r){let{requestId:i,envelope:a}=this.createRequestEnvelope(e,t,n),o=r??(()=>void 0),s,c,l=new Promise((e,t)=>{s=e,c=t});Object.defineProperty(l,"requestId",{value:i,enumerable:!0}),l.cancel=e=>{this.cancelStreamRequest(i,e)};let u={mode:`stream`,module:e,method:t,sentAt:Date.now(),callback:o,isDone:e=>this.defaultStreamDonePredicate(e),resolve:s,reject:e=>c(e)};return this.pending.set(i,u),this.handleSendAttempt(i,a,u,!0),l}sendPendingRequest(e,t,n){if(this.logger.debug(`emit ${n.mode} request`,{requestId:e,module:n.module,method:n.method}),!this.session.emitUIInteraction(t)){let t=Error(`Failed to send ${n.mode} request: ${n.module}.${n.method}`);return this.logger.error(`emit request failed`,{requestId:e,module:n.module,method:n.method}),t}this.hooks.onRequestSent?.({requestId:e,module:n.module,method:n.method})}handleSendAttempt(e,t,n,r){let i=this.sendPendingRequest(e,t,n);if(i){if(!this.retryOptions.enabled){this.settlePendingFailure(e,n,i,{notifyStream:r});return}this.logger.warn(`emit request failed, will retry until transport ready`,{requestId:e,module:n.module,method:n.method,error:i.message}),this.scheduleSendRetry(e,t,n,r,i)}}scheduleSendRetry(e,t,n,r,i){let a=this.sendRetries.get(e);if(a){a.lastError=i,a.timer===void 0&&(a.timer=setTimeout(()=>this.runSendRetry(a),this.retryOptions.intervalMs));return}let o={requestId:e,envelope:t,pending:n,notifyStream:r,queuedAt:Date.now(),lastError:i};this.sendRetries.set(e,o),o.timer=setTimeout(()=>this.runSendRetry(o),this.retryOptions.intervalMs)}runSendRetry(e){if(e.timer=void 0,this.sendRetries.get(e.requestId)!==e)return;let t=Date.now()-e.queuedAt;if(t>=this.retryOptions.maxWaitMs){this.sendRetries.delete(e.requestId);let{module:n,method:r,mode:i}=e.pending,a=Error(`Failed to send ${i} request: ${n}.${r} after retrying for ${t}ms (${e.lastError.message})`);this.logger.error(`send retry gave up`,{requestId:e.requestId,module:n,method:r,error:a.message}),this.settlePendingFailure(e.requestId,e.pending,a,{notifyStream:e.notifyStream});return}let n=this.sendPendingRequest(e.requestId,e.envelope,e.pending);if(!n){this.sendRetries.delete(e.requestId),this.logger.info(`request sent after transport ready retry`,{requestId:e.requestId,module:e.pending.module,method:e.pending.method});return}e.lastError=n,this.logger.debug(`send retry attempt failed, will retry again`,{requestId:e.requestId,module:e.pending.module,method:e.pending.method,error:n.message}),e.timer=setTimeout(()=>this.runSendRetry(e),this.retryOptions.intervalMs)}clearSendRetry(e){let t=this.sendRetries.get(e);t&&(t.timer!==void 0&&clearTimeout(t.timer),this.sendRetries.delete(e))}settlePendingFailure(e,t,n,r={}){this.pending.get(e)===t&&(this.pending.delete(e),this.clearSendRetry(e),t.mode===`stream`&&r.notifyStream&&this.emitStreamCallback(t,{type:`error`,requestId:e,response:r.response,error:n}),t.reject(n))}handleResponse(e){let t;try{t=JSON.parse(e)}catch(e){this.logger.warn(`response parse failed`,{error:p(e)});return}let n=t.requestId??t.uuid;if(!n){this.logger.warn(`response missing requestId`);return}t.requestId=n,t.param!==void 0&&t.params===void 0&&(t.params=t.param);let r=this.pending.get(n);if(!r){this.logger.debug(`response ignored, no pending request`,{requestId:n});return}if(r.mode===`single`){this.pending.delete(n),this.resolveSingleResponse(t,r);return}this.resolveStreamResponse(t,r)}createRequestEnvelope(e,t,n){let r=`r_${Date.now()}_${Math.random().toString(16).slice(2,10)}`;return{requestId:r,envelope:{AssemblyName:`EngineApi`,fn:r,ClassName:e,FunctionName:t,Value:JSON.stringify(n),ts:Date.now()}}}defaultStreamDonePredicate(e){if(typeof e.code==`string`){let t=e.code.trim().toUpperCase();if(t===`DONE`||t===`STREAM_DONE`)return!0}return!!this.hasDoneFlag(e)}hasDoneFlag(e){return[e,e.data].some(e=>Jr(e)?e.done===!0||e.isEnd===!0:!1)}resolveSingleResponse(e,t){if(e.success||!e.success&&e.errorMsg!=null){this.emitResponseReceivedHook(e,t),this.logger.info(`response success`,{requestId:e.requestId,code:e.code}),t.resolve(e);return}this.logger.warn(`response failed`,{requestId:e.requestId,code:``,message:e.errorMsg}),t.reject(Error(` ${e.errorMsg}`))}resolveStreamResponse(e,t){if(!e.success){let n=Error(` ${e.errorMsg??e.message}`);this.logger.warn(`stream response failed`,{requestId:e.requestId,code:e.code,message:e.errorMsg??e.message}),this.settlePendingFailure(e.requestId,t,n,{response:e,notifyStream:!0});return}if(this.emitResponseReceivedHook(e,t),t.isDone(e)){this.pending.delete(e.requestId);let n=this.emitStreamCallback(t,this.createStreamResponseEvent(`done`,e));if(n){t.reject(n);return}this.logger.info(`stream request done`,{requestId:e.requestId,code:e.code}),t.resolve(e);return}let n=this.emitStreamCallback(t,this.createStreamResponseEvent(`data`,e));n&&this.settlePendingFailure(e.requestId,t,n)}createStreamResponseEvent(e,t){return{...t,type:e,requestId:t.requestId,response:t,data:t.data,params:t.params,param:t.params??t.param,errorMsg:t.errorMsg}}emitResponseReceivedHook(e,t){this.hooks.onResponseReceived?.({requestId:e.requestId,module:t.module,method:t.method,durationMs:Math.max(0,Date.now()-t.sentAt),code:e.code})}emitStreamCallback(e,t){try{e.callback(t);return}catch(e){let n=e instanceof Error?e:Error(String(e));return this.logger.warn(`stream callback failed`,{requestId:t.requestId,type:t.type,error:n.message}),n}}cancelStreamRequest(e,t){let n=this.pending.get(e);if(!n||n.mode!==`stream`)return;this.pending.delete(e),this.clearSendRetry(e);let r=t?.trim()||`Stream request cancelled by client`,i=Error(r);this.logger.info(`stream request cancelled`,{requestId:e,module:n.module,method:n.method}),this.emitStreamCallback(n,{type:`cancel`,requestId:e,error:i}),n.reject(i)}cleanupPendingOnDisconnect(){if(this.sendRetries.forEach(e=>{e.timer!==void 0&&clearTimeout(e.timer)}),this.sendRetries.clear(),this.pending.size===0)return;let e=Error(`Session disconnected before request completed`);this.pending.forEach((t,n)=>{t.mode===`single`||this.emitStreamCallback(t,{type:`error`,requestId:n,error:e}),t.reject(e),this.logger.warn(`pending request cleared on disconnect`,{requestId:n,mode:t.mode})}),this.pending.clear()}};function Xr(e){return typeof e==`object`&&!!e}function Z(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function Zr(e){if(!Xr(e))return;let t=e.data;if(!Xr(t))return;let n=t.aggregatedStats;if(Xr(n))return n}function Qr(e,t,n){if(e===void 0||t===void 0)return{packetLossRate:void 0,next:n};let r={packetsLost:e,packetsReceived:t};if(!n)return{packetLossRate:void 0,next:r};let i=e-n.packetsLost,a=t-n.packetsReceived;if(i<0||a<0)return{packetLossRate:void 0,next:r};let o=i+a;if(o<=0)return{packetLossRate:void 0,next:r};let s=i/o;return{packetLossRate:Math.max(0,Math.min(1,s)),next:r}}function $r(e){let t=e.getActiveCandidatePair;if(typeof t!=`function`)return;let n=t.call(e);if(!Xr(n))return;let r=Z(n.currentRoundTripTime);return r===void 0?void 0:r*1e3}function ei(e,t){let n=Zr(e);if(!n)return;let r=Xr(n.inboundVideoStats)?n.inboundVideoStats:{},i=Z(r.bitrate),a=Qr(Z(r.packetsLost),Z(r.packetsReceived),t);return{aggregatedStats:n,inboundVideoStats:r,metrics:{fps:Z(r.framesPerSecond),bitrateKbps:i===void 0?void 0:i/1e3,packetLossRate:a.packetLossRate,jitterMs:(()=>{let e=Z(r.jitter);return e===void 0?void 0:e*1e3})(),rttMs:$r(n),frameWidth:Z(r.frameWidth),frameHeight:Z(r.frameHeight)},packetCounters:a.next}}function ti(){return{CameraHeight:`-`,FPS:`-`,Width:`-`,Height:`-`,runTime:`-`,bytePerSecond:`-`,lostPacketsRate:`-`,delayTime:`-`,Codec:`-`}}function ni(e){if(typeof e==`string`)return e;if(typeof e==`number`||typeof e==`boolean`)return String(e)}function ri(e){if(e<=0||!Number.isFinite(e))return`00:00:00`;let t=Math.floor(e/1e3);return[Math.floor(t/3600),Math.floor(t%3600/60),t%60].map(e=>String(e).padStart(2,`0`)).join(`:`)}var ii=class{constructor(e,t,n=h,r){this.session=e,this.onStatus=t,this.logger=n,this.onSample=r,this.connected=!1,this.status=ti(),this.onWebRtcConnected=()=>{this.connected=!0,this.firstStatsTimestampMs=void 0,this.lastStatsTimestamp=void 0,this.packetCounters=void 0,this.logger.info(`engine status collector started`)},this.onWebRtcDisconnected=()=>{this.pause(`webRtcDisconnected`)},this.onWebRtcFailed=()=>{this.pause(`webRtcFailed`)},this.onWebRtcConnecting=()=>{this.pause(`webRtcConnecting`)},this.onStatsReceived=e=>{if(!this.connected)return;let t=ei(e,this.packetCounters);t&&(this.packetCounters=t.packetCounters,this.status=this.patchByStats(this.status,t),this.onSample?.(this.extractMediaSample(t)),this.emit())},this.session.addEventListener(`webRtcConnected`,this.onWebRtcConnected),this.session.addEventListener(`webRtcDisconnected`,this.onWebRtcDisconnected),this.session.addEventListener(`webRtcFailed`,this.onWebRtcFailed),this.session.addEventListener(`webRtcConnecting`,this.onWebRtcConnecting),this.session.addEventListener(`statsReceived`,this.onStatsReceived)}stop(){this.pause(`manualStop`)}dispose(){this.stop(),this.session.removeEventListener(`webRtcConnected`,this.onWebRtcConnected),this.session.removeEventListener(`webRtcDisconnected`,this.onWebRtcDisconnected),this.session.removeEventListener(`webRtcFailed`,this.onWebRtcFailed),this.session.removeEventListener(`webRtcConnecting`,this.onWebRtcConnecting),this.session.removeEventListener(`statsReceived`,this.onStatsReceived)}pause(e){this.connected&&(this.connected=!1,this.lastStatsTimestamp=void 0,this.packetCounters=void 0,this.logger.info(`engine status collector paused`,{reason:e}))}patchByStats(e,t){let n=t.aggregatedStats,r=t.inboundVideoStats,i={...e},a=t.metrics.frameWidth;a!==void 0&&(i.Width=String(a));let o=t.metrics.frameHeight;o!==void 0&&(i.Height=String(o));let s=t.metrics.fps;s!==void 0&&(i.FPS=String(s));let c=t.metrics.bitrateKbps;c!==void 0&&(i.bytePerSecond=`${Math.round(c)} kb/s`),i.lostPacketsRate=t.metrics.packetLossRate===void 0?`-`:`${(t.metrics.packetLossRate*100).toFixed(2)}%`;let l=Z(r.timestamp);if(l!==void 0){if(this.lastStatsTimestamp!==void 0){let e=l-this.lastStatsTimestamp;i.delayTime=`${Math.max(0,1e3-e).toFixed(2)} ms`}this.lastStatsTimestamp=l}this.firstStatsTimestampMs===void 0&&(this.firstStatsTimestampMs=Date.now()),i.runTime=ni(n.sessionStats?.runTime)??ri(Date.now()-this.firstStatsTimestampMs);let u=ni(r.codecId),d=u?this.getCodecMimeType(n,u):void 0;return d&&(i.Codec=d),i}extractMediaSample(e){return{...e.metrics,bitrateKbps:e.metrics.bitrateKbps===void 0?void 0:Math.round(e.metrics.bitrateKbps)}}getCodecMimeType(e,t){let n=e.codecs;if(!n)return;let r;(n instanceof Map||typeof n.get==`function`)&&(r=n.get(t));let i=r?.mimeType;return typeof i==`string`&&i.length>0?i:void 0}emit(){this.onStatus({...this.status})}};const ai=[`Normal`,`Mild`,`Moderate`,`Severe`];function oi(e){return ai.indexOf(e)}function si(e,t){return oi(e)>=oi(t)?e:t}function ci(e,t){let n=oi(t);return e.filter(e=>oi(e)>=n).length}function li(e){return e===`Severe`?`Moderate`:e===`Moderate`?`Mild`:`Normal`}function ui(e){return e===void 0?`Normal`:e>=.1?`Severe`:e>=.06?`Moderate`:e>=.03?`Mild`:`Normal`}function di(e){return e===void 0?`Normal`:e>=240?`Severe`:e>=180?`Moderate`:e>=120?`Mild`:`Normal`}function fi(e){return e===void 0?`Normal`:e>=80?`Severe`:e>=50?`Moderate`:e>=25?`Mild`:`Normal`}function pi(e){return e===void 0?`Normal`:e<=12?`Severe`:e<=20?`Moderate`:e<=28?`Mild`:`Normal`}function mi(e){let t=ui(e.packetLossRate),n=si(di(e.rttMs),fi(e.jitterMs)),r=[t,n,pi(e.fps)],i=[t,n];return r.some(e=>e===`Severe`)?`Severe`:ci(r,`Moderate`)>=2||ci(i,`Moderate`)>=1&&ci(r,`Mild`)>=2?`Moderate`:ci(r,`Mild`)>=2||ci(i,`Moderate`)>=1?`Mild`:`Normal`}function hi(e,t,n,r,i=e){return{measuredLevel:t,outcome:n,reason:r,degradeStreak:i.degradeStreak,recoverStreak:i.recoverStreak}}const gi=[{evaluate(e,t){if(!(e.connected&&e.metrics.connected))return hi(e,t,`hold`,`session not connected, skip adaptation`)}},{evaluate(e,t){if(e.actionInFlight)return hi(e,t,`hold`,`action in flight`)}},{evaluate(e,t){if(!(e.now>=e.cooldownUntil))return hi(e,t,`skip_cooldown`,`cooldown until ${e.cooldownUntil}`)}},{evaluate(e,t){if(oi(t)<=oi(e.stableLevel))return;let n=e.degradeStreak+1,r=t===`Severe`?1:2;return n<r?hi(e,t,`skip_hysteresis`,`degrade streak ${n}/${r}`,{degradeStreak:n,recoverStreak:0}):{measuredLevel:t,outcome:`downgrade`,targetLevel:t,reason:`measured ${t}`,degradeStreak:0,recoverStreak:0}}},{evaluate(e,t){if(t!==`Normal`||e.stableLevel===`Normal`)return;let n=e.recoverStreak+1;if(n<4)return hi(e,t,`skip_hysteresis`,`recover streak ${n}/4`,{degradeStreak:0,recoverStreak:n});let r=li(e.stableLevel);return{measuredLevel:t,outcome:`recover`,targetLevel:r,reason:`recover to ${r}`,degradeStreak:0,recoverStreak:0}}},{evaluate(e,t){return hi(e,t,`hold`,`no transition`,{degradeStreak:0,recoverStreak:t===`Normal`?e.recoverStreak:0})}}];function _i(e){let t=mi(e.metrics);for(let n of gi){let r=n.evaluate(e,t);if(r)return r}return hi(e,t,`hold`,`no transition`)}const vi={Normal:{bitrate:12e6,fps:60,width:1920,height:1080},Mild:{bitrate:8e6,fps:45,width:1600,height:900},Moderate:{bitrate:4e6,fps:30,width:1280,height:720},Severe:{bitrate:2e6,fps:20,width:960,height:540}};function yi(e){let t=e.filter(e=>typeof e==`number`&&Number.isFinite(e));if(t.length!==0)return t.reduce((e,t)=>e+t,0)/t.length}var bi=class{constructor(e){this.metricsWindow=[],this.traces=[],this.connected=!1,this.mode=`auto`,this.currentLevel=`Normal`,this.stableLevel=`Normal`,this.diagnosticsVisible=!1,this.degradeStreak=0,this.recoverStreak=0,this.cooldownUntil=0,this.actionInFlight=!1,this.lastAppliedProfileKey=``,this.transitionGeneration=0,this.onStatsReceived=e=>{this.handleStatsReceived(e)},this.onWebRtcConnected=()=>{this.connected=!0,this.metricsWindow.length=0,this.degradeStreak=0,this.recoverStreak=0,this.cooldownUntil=0,this.actionInFlight=!1,this.packetCounters=void 0,this.lastMetrics=void 0,this.currentLevel=`Normal`,this.stableLevel=`Normal`,this.lastAppliedProfileKey=``,this.transitionGeneration+=1,this.logger.info(`network adaptation received webRtcConnected`),this.pushTrace({outcome:`hold`,reason:`webrtc connected, resume adaptation`}),this.emitDiagnosticsSnapshot()},this.onWebRtcConnecting=()=>{this.handleConnectionInterrupted(`webRtcConnecting`)},this.onWebRtcDisconnected=()=>{this.handleConnectionInterrupted(`webRtcDisconnected`)},this.onWebRtcFailed=()=>{this.handleConnectionInterrupted(`webRtcFailed`)},this.session=e.session,this.screen=e.screen,this.logger=e.logger??h,this.onStateChange=e.onStateChange,this.onAction=e.onAction,this.onDiagnostics=e.onDiagnostics}start(){this.session.addEventListener(`statsReceived`,this.onStatsReceived),this.session.addEventListener(`webRtcConnected`,this.onWebRtcConnected),this.session.addEventListener(`webRtcConnecting`,this.onWebRtcConnecting),this.session.addEventListener(`webRtcDisconnected`,this.onWebRtcDisconnected),this.session.addEventListener(`webRtcFailed`,this.onWebRtcFailed)}dispose(){this.session.removeEventListener(`statsReceived`,this.onStatsReceived),this.session.removeEventListener(`webRtcConnected`,this.onWebRtcConnected),this.session.removeEventListener(`webRtcConnecting`,this.onWebRtcConnecting),this.session.removeEventListener(`webRtcDisconnected`,this.onWebRtcDisconnected),this.session.removeEventListener(`webRtcFailed`,this.onWebRtcFailed)}setMode(e){this.mode!==e&&(this.mode=e,this.pushTrace({outcome:`manual`,reason:`mode switched to ${e}`}),this.emitDiagnosticsSnapshot(),e===`auto`&&this.lastMetrics&&this.evaluateAutoStrategy(this.lastMetrics))}setManualLevel(e){this.setMode(`manual`),this.transitionToLevel(e,`manual`,`manual override to ${e}`,!0)}setDiagnosticsVisible(e){this.diagnosticsVisible=e,this.emitDiagnosticsSnapshot()}getDiagnosticsSnapshot(){return{ts:Date.now(),visible:this.diagnosticsVisible,mode:this.mode,currentLevel:this.currentLevel,connected:this.connected,lastMetrics:this.lastMetrics,lastAction:this.lastAction,traces:[...this.traces]}}handleStatsReceived(e){let t=ei(e,this.packetCounters);if(!t)return;this.packetCounters=t.packetCounters;let n={ts:Date.now(),connected:this.connected,...t.metrics};this.lastMetrics=this.pushMetrics(n),this.emitDiagnosticsSnapshot(),this.mode!==`manual`&&this.evaluateAutoStrategy(this.lastMetrics)}handleConnectionInterrupted(e){this.connected=!1,this.logger.warn(`network adaptation connection interrupted`,{source:e}),this.metricsWindow.length=0,this.recoverStreak=0,this.degradeStreak=0,this.cooldownUntil=0,this.actionInFlight=!1,this.packetCounters=void 0,this.transitionGeneration+=1,this.pushTrace({outcome:`hold`,reason:`${e}; session disconnected, pause adaptation`}),this.emitDiagnosticsSnapshot()}pushMetrics(e){return this.metricsWindow.push(e),this.metricsWindow.length>5&&this.metricsWindow.shift(),{ts:e.ts,connected:e.connected,fps:yi(this.metricsWindow.map(e=>e.fps)),bitrateKbps:yi(this.metricsWindow.map(e=>e.bitrateKbps)),packetLossRate:yi(this.metricsWindow.map(e=>e.packetLossRate)),jitterMs:yi(this.metricsWindow.map(e=>e.jitterMs)),rttMs:yi(this.metricsWindow.map(e=>e.rttMs)),frameWidth:yi(this.metricsWindow.map(e=>e.frameWidth)),frameHeight:yi(this.metricsWindow.map(e=>e.frameHeight))}}evaluateAutoStrategy(e){let t=_i({connected:this.connected,metrics:e,currentLevel:this.currentLevel,stableLevel:this.stableLevel,mode:this.mode,actionInFlight:this.actionInFlight,cooldownUntil:this.cooldownUntil,now:Date.now(),degradeStreak:this.degradeStreak,recoverStreak:this.recoverStreak});this.applyStrategyDecision(t,e)}applyStrategyDecision(e,t){if(this.degradeStreak=e.degradeStreak,this.recoverStreak=e.recoverStreak,e.outcome===`downgrade`||e.outcome===`recover`){this.transitionToLevel(e.targetLevel??e.measuredLevel,e.outcome,e.reason,!1,t);return}this.pushTrace({measuredLevel:e.measuredLevel,currentLevel:this.currentLevel,mode:this.mode,metrics:t,outcome:e.outcome,reason:e.reason})}transitionToLevel(e,t,n,r,i=this.lastMetrics){if(console.log(`transitionToLevel`,e,t,n,r,i),!r&&e===this.stableLevel){this.pushTrace({measuredLevel:mi(i??{ts:Date.now(),connected:!1}),currentLevel:this.currentLevel,mode:this.mode,metrics:i,outcome:`hold`,reason:`target level equals current level`});return}let a=this.transitionGeneration;this.actionInFlight=!0,this.runTransition(e,t,n,a,i).finally(()=>{a===this.transitionGeneration&&(this.actionInFlight=!1)})}async runTransition(e,t,n,r,i=this.lastMetrics){if(r!==this.transitionGeneration){this.logger.info(`network adaptation transition ignored before start`,{targetLevel:e,reason:n});return}let a=this.currentLevel,o=this.stableLevel,s=mi(i??{ts:Date.now(),connected:!1});t===`recover`&&this.currentLevel!==`Recovering`&&(this.currentLevel=`Recovering`,this.onStateChange?.({from:a,to:`Recovering`,mode:this.mode,reason:`enter recovering before ${e}`,ts:Date.now(),metrics:i}));let c=await this.applyLevelProfile(e,n);if(r!==this.transitionGeneration){this.logger.info(`network adaptation transition discarded after action (stale generation)`,{targetLevel:e,reason:n}),this.pushTrace({measuredLevel:s,currentLevel:this.currentLevel,mode:this.mode,targetLevel:e,metrics:i,outcome:`hold`,reason:`${n}; stale transition discarded`}),this.emitDiagnosticsSnapshot();return}if(this.lastAction=c,this.onAction?.(c),!c.success){this.logger.warn(`network adaptation transition not committed due to action failure`,{targetLevel:e,reason:n});let t=this.currentLevel;this.currentLevel=o,t!==this.currentLevel&&this.onStateChange?.({from:t,to:this.currentLevel,mode:this.mode,reason:`${n}; action failed rollback`,ts:Date.now(),metrics:i}),this.pushTrace({measuredLevel:s,currentLevel:t,mode:this.mode,targetLevel:e,metrics:i,outcome:`hold`,reason:`${n}; action failed, keep ${o}`}),this.emitDiagnosticsSnapshot();return}let l=this.currentLevel;this.stableLevel=e,this.currentLevel=e,this.cooldownUntil=Date.now()+6e3,this.onStateChange?.({from:l,to:e,mode:this.mode,reason:n,ts:Date.now(),metrics:i}),this.pushTrace({measuredLevel:s,currentLevel:l,mode:this.mode,targetLevel:e,metrics:i,outcome:t,reason:n}),this.emitDiagnosticsSnapshot()}async applyLevelProfile(e,t){let n=vi[e],r=`${n.bitrate}-${n.fps}-${n.width}x${n.height}`;if(r===this.lastAppliedProfileKey)return{level:e,mode:this.mode,success:!0,skipped:!0,reason:`${t}; profile already applied`,ts:Date.now(),steps:[]};let i=[];i.push(await this.runActionStep(`SetSceneRenderBitrate`,{bitrate:n.bitrate})),i.push(await this.runActionStep(`SetSceneFPS`,{fps:n.fps})),i.push(await this.runActionStep(`SetScreenResolution`,{width:n.width,height:n.height}));let a=i.every(e=>e.success);return a&&(this.lastAppliedProfileKey=r),{level:e,mode:this.mode,success:a,skipped:!1,reason:t,ts:Date.now(),steps:i}}async runActionStep(e,t){try{return this.logger.info(`network adaptation action success`,{type:e,payload:t}),{type:e,payload:t,success:!0}}catch(n){let r=n instanceof Error?n.message:String(n);return this.logger.warn(`network adaptation action failed`,{type:e,payload:t,error:r}),{type:e,payload:t,success:!1,error:r}}}pushTrace(e){let t={ts:Date.now(),mode:e.mode??this.mode,currentLevel:e.currentLevel??this.currentLevel,measuredLevel:e.measuredLevel??mi(this.lastMetrics??{ts:Date.now(),connected:this.connected}),targetLevel:e.targetLevel,outcome:e.outcome,reason:e.reason,metrics:e.metrics};this.traces.unshift(t),this.traces.length>30&&(this.traces.length=30),this.emitDiagnosticsSnapshot()}emitDiagnosticsSnapshot(){this.onDiagnostics?.(this.getDiagnosticsSnapshot())}},xi=class{constructor(e){this.visible=!1,this.onKeyDown=e=>{e.ctrlKey&&e.altKey&&e.code===`KeyD`&&(e.preventDefault(),this.toggle())},this.options=e,this.logger=e.logger??h,typeof window<`u`&&window.addEventListener(`keydown`,this.onKeyDown)}dispose(){typeof window<`u`&&window.removeEventListener(`keydown`,this.onKeyDown),this.root?.remove(),this.root=void 0}update(e){this.snapshot=e,this.visible&&(this.ensureRoot(),this.render())}setVisible(e){this.visible!==e&&(this.visible=e,this.ensureRoot(),this.root&&(this.root.style.display=e?`block`:`none`),e&&this.render(),this.options.onVisibilityChange?.(e))}toggle(){this.setVisible(!this.visible)}ensureRoot(){if(this.root||typeof document>`u`||!document.body)return;let e=document.createElement(`div`);e.id=`enginesdk3-network-diagnostics-panel`,e.style.position=`fixed`,e.style.right=`16px`,e.style.bottom=`16px`,e.style.zIndex=`2147483647`,e.style.width=`360px`,e.style.maxWidth=`calc(100vw - 32px)`,e.style.maxHeight=`70vh`,e.style.overflow=`auto`,e.style.padding=`12px`,e.style.borderRadius=`8px`,e.style.boxShadow=`0 6px 24px rgba(0, 0, 0, 0.35)`,e.style.background=`rgba(12, 17, 24, 0.94)`,e.style.color=`#e8f0ff`,e.style.fontFamily=`Menlo, Consolas, Monaco, monospace`,e.style.fontSize=`12px`,e.style.lineHeight=`1.4`,e.style.display=this.visible?`block`:`none`;let t=document.createElement(`div`);t.style.display=`flex`,t.style.justifyContent=`space-between`,t.style.alignItems=`center`,t.style.marginBottom=`8px`;let n=document.createElement(`strong`);n.textContent=`Network Diagnostics`,t.appendChild(n),this.levelLabel=document.createElement(`span`),this.levelLabel.style.color=`#7ee787`,this.levelLabel.textContent=`Normal`,t.appendChild(this.levelLabel),e.appendChild(t);let r=document.createElement(`div`);r.style.display=`flex`,r.style.alignItems=`center`,r.style.gap=`8px`,r.style.marginBottom=`8px`;let i=document.createElement(`span`);i.textContent=`Mode`,r.appendChild(i),this.modeSelect=document.createElement(`select`),this.modeSelect.style.flex=`1`,this.modeSelect.innerHTML=`<option value="auto">Auto</option><option value="manual">Manual</option>`,this.modeSelect.onchange=()=>{let e=this.modeSelect?.value===`manual`?`manual`:`auto`;this.options.onModeChange(e)},r.appendChild(this.modeSelect),e.appendChild(r);let a=document.createElement(`div`);a.style.display=`flex`,a.style.alignItems=`center`,a.style.gap=`8px`,a.style.marginBottom=`8px`;let o=document.createElement(`span`);o.textContent=`Manual Level`,a.appendChild(o),this.levelSelect=document.createElement(`select`),this.levelSelect.style.flex=`1`,this.levelSelect.innerHTML=[`<option value="Normal">Normal</option>`,`<option value="Mild">Mild</option>`,`<option value="Moderate">Moderate</option>`,`<option value="Severe">Severe</option>`].join(``),this.levelSelect.onchange=()=>{let e=this.levelSelect?.value??`Normal`;this.options.onManualLevelChange(e)},a.appendChild(this.levelSelect),e.appendChild(a),this.metricsPre=document.createElement(`pre`),this.metricsPre.style.margin=`0 0 8px 0`,this.metricsPre.style.padding=`8px`,this.metricsPre.style.background=`rgba(255, 255, 255, 0.06)`,this.metricsPre.style.borderRadius=`6px`,this.metricsPre.style.whiteSpace=`pre-wrap`,this.metricsPre.style.wordBreak=`break-word`,e.appendChild(this.metricsPre);let s=document.createElement(`div`);s.style.marginBottom=`6px`,s.textContent=`Recent Decisions`,e.appendChild(s),this.traceList=document.createElement(`div`),this.traceList.style.display=`flex`,this.traceList.style.flexDirection=`column`,this.traceList.style.gap=`4px`,e.appendChild(this.traceList),document.body.appendChild(e),this.root=e,this.logger.info(`network diagnostics panel ready`)}render(){!this.root||!this.snapshot||(this.levelLabel&&(this.levelLabel.textContent=this.snapshot.currentLevel,this.levelLabel.style.color=this.snapshot.currentLevel===`Severe`?`#ff7b72`:`#7ee787`),this.modeSelect&&(this.modeSelect.value=this.snapshot.mode),this.levelSelect&&(this.levelSelect.disabled=this.snapshot.mode!==`manual`),this.metricsPre&&(this.metricsPre.textContent=this.buildMetricsText(this.snapshot)),this.traceList&&(this.traceList.innerHTML=``,this.snapshot.traces.slice(0,10).forEach(e=>{let t=document.createElement(`div`);t.style.padding=`6px`,t.style.borderRadius=`6px`,t.style.background=`rgba(255, 255, 255, 0.04)`,t.textContent=`${new Date(e.ts).toLocaleTimeString()} | ${e.outcome} | ${e.reason}`,this.traceList?.appendChild(t)})))}buildMetricsText(e){let t=e.lastMetrics;if(!t)return`No metrics yet`;let n=t.packetLossRate===void 0?`-`:`${(t.packetLossRate*100).toFixed(2)}%`;return[`connected: ${e.connected}`,`mode: ${e.mode}`,`level: ${e.currentLevel}`,`fps: ${t.fps?.toFixed(2)??`-`}`,`bitrate(kbps): ${t.bitrateKbps?.toFixed(2)??`-`}`,`packetLoss: ${n}`,`rtt(ms): ${t.rttMs?.toFixed(2)??`-`}`,`jitter(ms): ${t.jitterMs?.toFixed(2)??`-`}`,`resolution: ${t.frameWidth??`-`}x${t.frameHeight??`-`}`,`lastAction: ${e.lastAction?`${e.lastAction.level} (${e.lastAction.success?`ok`:`fail`})`:`-`}`].join(`
109
- `)}},Si=class{constructor(e){this.disconnected=!1,this.hasEverConnected=!1,this.authWorkflow=e.authWorkflow,this.logger=e.logger}async connect(){if(this.disconnected)throw Error(`Cannot connect after disconnect. Use restart() instead.`);this.logger.info(`Starting connection flow`);try{let e=await this.authWorkflow.start();return this.logger.info(`Connection established`,{engineToken:e.engineToken?.substring(0,16)+`...`}),e}catch(e){throw this.logger.error(`Connection failed`,{error:e}),e}}async disconnect(){return this.disconnected?(this.logger.info(`Already disconnected, skipping`),this.disconnectPromise||Promise.resolve()):(this.logger.info(`Disconnecting...`),this.disconnected=!0,this.disconnectPromise=(async()=>{try{await this.authWorkflow.disconnectAndWait(),this.logger.info(`Disconnected successfully`)}catch(e){throw this.logger.error(`Error during disconnect`,{error:e}),e}})(),this.disconnectPromise)}async prepareConnectAfterDisconnect(){this.disconnectPromise&&await this.disconnectPromise,this.disconnected=!1,this.disconnectPromise=void 0,this.hasEverConnected=!1}async restart(){return this.logger.info(`Restarting connection...`),await this.disconnect(),await this.prepareConnectAfterDisconnect(),this.connect()}getStatus(){return{disconnected:this.disconnected,hasEverConnected:this.hasEverConnected}}hasConnectedBefore(){return this.hasEverConnected}markConnected(){this.hasEverConnected=!0}},Q=class extends Error{constructor(e,t,n,r){super(t),this.code=e,this.moduleName=n,this.dependencyName=r,this.name=`ApiRegistryError`}};function Ci(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function wi(e,t){return Ci(e)&&typeof e[t]==`function`}function Ti(e){if(!Ci(e))throw new Q(`CONTEXT_INVALID`,`API registry context must be an object`);let t=[[`bridge`,e.bridge,`sendRequest`],[`authWorkflow`,e.authWorkflow,`getSnapshot`],[`connectionLifecycle`,e.connectionLifecycle,`connect`],[`createLogger`,e.createLogger,void 0]];for(let[e,n,r]of t)if(!(r?wi(n,r):typeof n==`function`||n!=null))throw new Q(`CONTEXT_INVALID`,`API registry context dependency '${e}'${r?` with ${r}()`:``} is required`,void 0,e)}function Ei(e){if(!Ci(e))throw new Q(`REGISTRY_INVALID`,`API registry must be a non-null object`);let t=Object.keys(e).find(e=>!dn.includes(e));if(t)throw new Q(`REGISTRY_UNKNOWN_MODULE`,`API registry contains unknown module '${t}'`,t);let n=dn.find(t=>!(t in e));if(n)throw new Q(`REGISTRY_INCOMPLETE`,`API registry is missing module '${n}'`,n);for(let t of dn)if(typeof e[t]!=`function`)throw new Q(`FACTORY_INVALID`,`API registry factory for '${t}' must be a function`,t)}function Di(e,t,n,r){let i;try{i=t[r](n)}catch(e){throw new Q(`FACTORY_FAILED`,`API registry factory for '${r}' failed: ${e instanceof Error?e.message:String(e)}`,r,void 0)}if(i==null)throw new Q(`FACTORY_EMPTY_RESULT`,`API registry factory for '${r}' returned ${i===null?`null`:`undefined`}`,r);e[r]=i}function Oi(e,t=un){if(Ti(e),Ei(t),typeof t.Popup==`function`&&(e.popupManager===null||e.popupManager===void 0))throw new Q(`CONTEXT_INVALID`,`API registry context dependency 'popupManager' is required by the Popup module`,`Popup`,`popupManager`);let n={};return dn.forEach(r=>{Di(n,t,e,r)}),n}const ki=.78;var $=class extends Error{constructor(e,t,n,r){super(t),this.code=e,this.buildingId=n,this.floorId=r,this.name=`BuildingFloorError`}};function Ai(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function ji(e){return Ai(e)&&typeof e.x==`number`&&Number.isFinite(e.x)&&typeof e.y==`number`&&Number.isFinite(e.y)&&typeof e.z==`number`&&Number.isFinite(e.z)}function Mi(e){return{position:Ni(e.position),target:Ni(e.target),fov:e.fov,time:e.time}}function Ni(e){return new C(e.x,e.y,e.z,e.ePSGType)}var Pi=class{constructor(e,t){this.dependencies=e,this.buildings=new Map,this.logger=t?.logger??h}async register(e){let t=Array.isArray(e)?e:[e],n=this.normalizeRegistrations(t),r=await Promise.all(n.map(async e=>({definition:e,positions:await this.measureFloorPositions(e)})));this.assertBuildingsRemainAvailable(n),r.forEach(({definition:e,positions:t})=>{this.buildings.set(e.buildingId,{definition:e,originalPositions:t,explodedDistances:new Map,visibleFloorIds:e.floors.map(e=>e.id),transitionId:0,status:`overview`,activeMoves:new Set})});let i=n.map(e=>e.buildingId);return this.logger.info(`building floors registered`,{buildingIds:i}),{buildingIds:i}}async switchTo(e){let t=this.requireBuilding(e.buildingId),n=t.definition.floors.findIndex(t=>t.id===e.floorId);if(n<0)throw new $(`FLOOR_NOT_FOUND`,`Floor "${e.floorId}" is not registered for building "${e.buildingId}".`,e.buildingId,e.floorId);let r=t.definition.floors[n];return this.transition(t,{floorId:r.id,visibleFloorIds:t.definition.floors.slice(0,n+1).map(e=>e.id),hiddenFloorIds:t.definition.floors.slice(n+1).map(e=>e.id),viewPoint:r.viewPoint,objectIds:r.objects??[],overview:!1,focus:e.focus===!0})}async showOverview(e){let t=this.requireBuilding(e.buildingId);return this.transition(t,{visibleFloorIds:t.definition.floors.map(e=>e.id),hiddenFloorIds:[],viewPoint:t.definition.overview.viewPoint,objectIds:t.definition.overview.objects??[],overview:!0,focus:e.focus===!0})}async cancel(e){let t=this.requireBuilding(e.buildingId);t.transitionId+=1,await this.stopActiveTransition(t),t.currentFloorId=void 0,t.status=`cancelled`,this.logger.info(`building floor transition cancelled`,{buildingId:e.buildingId})}getState(e){let t=this.requireBuilding(e.buildingId);return{buildingId:t.definition.buildingId,status:t.status,currentFloorId:t.currentFloorId,visibleFloorIds:[...t.visibleFloorIds],transitionId:t.transitionId}}normalizeRegistrations(e){if(e.length===0)throw new $(`INVALID_REGISTRATION`,`At least one building is required.`);let t=new Set;return e.map(e=>{let n=this.requireNonEmptyString(e?.buildingId,`buildingId`),r=this.requireNonEmptyString(e?.parentId,`parentId`,n);if(t.has(n))throw new $(`INVALID_REGISTRATION`,`Building "${n}" is duplicated in the registration batch.`,n);if(this.buildings.has(n))throw new $(`BUILDING_ALREADY_REGISTERED`,`Building "${n}" is already registered.`,n);if(t.add(n),!Array.isArray(e.floors)||e.floors.length===0)throw new $(`INVALID_REGISTRATION`,`Building "${n}" must contain at least one floor.`,n);let i=new Set,a=e.floors.map((e,t)=>{let r=this.normalizeFloor(e,n,t);if(i.has(r.id))throw new $(`INVALID_REGISTRATION`,`Floor "${r.id}" is duplicated in building "${n}".`,n,r.id);return i.add(r.id),r}),o=e.overview??{},s=o.objects??[];if(!Array.isArray(s)||s.some(e=>typeof e!=`string`||e.trim()===``))throw new $(`INVALID_REGISTRATION`,`Building "${n}" overview objects must contain non-empty IDs.`,n);return o.viewPoint&&this.validateViewPoint(o.viewPoint,n,`overview`),{buildingId:n,parentId:r,floors:a,overview:{objects:[...s],viewPoint:o.viewPoint?Mi(o.viewPoint):void 0}}})}normalizeFloor(e,t,n){let r=typeof e==`string`?{id:e}:e;if(!Ai(r))throw new $(`INVALID_REGISTRATION`,`Floor at index ${n} in building "${t}" must be a string or object.`,t);let i=this.requireNonEmptyString(r.id,`floors[${n}].id`,t),a=r.viewPoint;return a!==void 0&&this.validateViewPoint(a,t,i),{id:i,viewPoint:a?Mi(a):void 0,objects:this.normalizeObjectIds(r.objects,t,i)}}normalizeObjectIds(e,t,n){if(e!==void 0){if(!Array.isArray(e)||e.some(e=>typeof e!=`string`||e.trim()===``))throw new $(`INVALID_REGISTRATION`,`Objects for "${t}@${n}" must contain non-empty IDs.`,t,n);return[...e]}}validateViewPoint(e,t,n){if(!Ai(e)||!ji(e.position)||!ji(e.target))throw new $(`INVALID_REGISTRATION`,`View point for "${t}@${n}" requires valid position and target vectors.`,t,n);if(e.fov!==void 0&&(!Number.isFinite(e.fov)||e.fov<10||e.fov>150))throw new $(`INVALID_REGISTRATION`,`View point fov for "${t}@${n}" must be between 10 and 150.`,t,n);if(e.time!==void 0&&(!Number.isFinite(e.time)||e.time<0))throw new $(`INVALID_REGISTRATION`,`View point time for "${t}@${n}" must be a non-negative number.`,t,n)}requireNonEmptyString(e,t,n){if(typeof e!=`string`||e.trim()===``)throw new $(`INVALID_REGISTRATION`,`${t} must be a non-empty string.`,n);return e}assertBuildingsRemainAvailable(e){let t=e.find(e=>this.buildings.has(e.buildingId));if(t)throw new $(`BUILDING_ALREADY_REGISTERED`,`Building "${t.buildingId}" was registered while its model information was loading.`,t.buildingId)}async measureFloorPositions(e){let t=await Promise.all(e.floors.map(async t=>{let n=await this.dependencies.model.getModelInfo({parentId:e.parentId,id:t.id});return[t.id,this.extractPosition(n,e.buildingId,t.id)]}));return new Map(t)}extractPosition(e,t,n){let r=e,i=e.params??e.data??r.param;if(Ai(i)&&(`param`in i||`params`in i)&&(i=i.param??i.params),typeof i==`string`)try{i=JSON.parse(i)}catch{i=void 0}let a=Ai(i)?i.position:void 0;if(!ji(a))throw new $(`MODEL_INFO_INVALID`,`Model information for "${t}@${n}" does not contain a valid position.`,t,n);return{x:a.x,y:a.y,z:a.z,ePSGType:typeof a.ePSGType==`string`&&a.ePSGType!==``?a.ePSGType:`0000`}}requireBuilding(e){let t=this.buildings.get(e);if(!t)throw new $(`BUILDING_NOT_REGISTERED`,`Building "${e}" is not registered.`,e);return t}async transition(e,t){let n=e.transitionId+1;if(e.transitionId=n,await this.stopActiveTransition(e),n!==e.transitionId)return this.createResult(e,t,`cancelled`,`none`);e.status=`switching`;let r=t.visibleFloorIds.filter(t=>e.explodedDistances.has(t)),i=t.hiddenFloorIds.filter(t=>!e.explodedDistances.has(t)),a=t.hiddenFloorIds.filter(t=>e.explodedDistances.has(t));try{let r=this.getAccessoryObjectIds(e.definition);if(r.length>0&&(await this.dependencies.model.setVisible({id:r,visible:!1}),n!==e.transitionId)||t.visibleFloorIds.length>0&&(await this.dependencies.model.setVisible({parentId:e.definition.parentId,id:t.visibleFloorIds,visible:!0}),n!==e.transitionId))return this.createResult(e,t,`cancelled`,`none`);a.length>0&&await this.dependencies.model.setVisible({parentId:e.definition.parentId,id:a,visible:!1})}catch(t){throw n===e.transitionId&&(e.status=`cancelled`),t}return n===e.transitionId?new Promise((a,o)=>{let s={id:n,timers:new Set,pendingActions:new Set,settled:!1,resolve:a,reject:o};e.activeTransition=s,r.forEach((t,n)=>{this.schedule(e,s,n*105,async()=>{let n=e.originalPositions.get(t),r=this.getHideOffset(e),i=Math.max(r*.035,.5),a=e.explodedDistances.get(t)??r;e.activeMoves.add(t),await this.dependencies.modelTransform.startMoveByNodes({parentId:e.definition.parentId,id:t,nodes:[this.positionAtZ(n,n.z-i),this.positionAtZ(n,n.z)],speed:this.getMotionSpeed(a+i*2),linear:6,isLookAtTarget:!1,needDirection:!1})})}),[...i].reverse().forEach((t,n)=>{this.schedule(e,s,n*105,async()=>{let r=e.originalPositions.get(t),i=this.getHideOffset(e),a=Math.max(i*.045,.6),o=i*(1+.24*n);e.explodedDistances.set(t,o),e.activeMoves.add(t),await this.dependencies.modelTransform.startMoveByNodes({parentId:e.definition.parentId,id:t,nodes:[this.positionAtZ(r,r.z-a),this.positionAtZ(r,r.z+o)],speed:this.getMotionSpeed(o+a*2),linear:5,isLookAtTarget:!1,needDirection:!1})})});let c=Math.max(this.getBatchDurationMs(r.length),this.getBatchDurationMs(i.length));this.scheduleCompletion(e,s,c,t)}):this.createResult(e,t,`cancelled`,`none`)}schedule(e,t,n,r){let i=setTimeout(()=>{if(t.timers.delete(i),t.settled||t.id!==e.transitionId)return;let n=Promise.resolve().then(()=>{if(!(t.settled||t.id!==e.transitionId))return r()});t.pendingActions.add(n),n.then(()=>{t.pendingActions.delete(n)}).catch(r=>{t.pendingActions.delete(n),this.failTransition(e,t,r)})},n);t.timers.add(i)}scheduleCompletion(e,t,n,r){let i=setTimeout(()=>{t.timers.delete(i),!(t.settled||t.id!==e.transitionId)&&Promise.all([...t.pendingActions]).then(()=>this.completeTransition(e,t,r)).catch(n=>{this.failTransition(e,t,n)})},n);t.timers.add(i)}async completeTransition(e,t,n){if(!(t.settled||t.id!==e.transitionId))try{if(n.hiddenFloorIds.length>0&&(await this.dependencies.model.setVisible({parentId:e.definition.parentId,id:n.hiddenFloorIds,visible:!1}),t.settled||t.id!==e.transitionId)||(n.visibleFloorIds.forEach(t=>e.explodedDistances.delete(t)),e.activeMoves.clear(),e.visibleFloorIds=[...n.visibleFloorIds],e.currentFloorId=n.floorId,e.status=n.overview?`overview`:`floor`,n.objectIds.length>0&&(await this.dependencies.model.setVisible({id:n.objectIds,visible:!0}),t.settled||t.id!==e.transitionId)))return;let r=await this.focusTarget(e,n);if(t.settled||t.id!==e.transitionId)return;this.settleTransition(e,t,this.createResult(e,n,`completed`,r))}catch(n){this.failTransition(e,t,n)}}async focusTarget(e,t){return t.focus?t.viewPoint?(await this.dependencies.camera.flyToTarget({point:t.viewPoint.position,target:t.viewPoint.target,fov:t.viewPoint.fov,time:t.viewPoint.time??.2}),`viewPoint`):(await this.dependencies.camera.lookAt({parentId:e.definition.parentId,id:t.visibleFloorIds,time:.2,isRotate:!1,isHighlight:!1}),`bounds`):`none`}failTransition(e,t,n){t.settled||(t.settled=!0,t.timers.forEach(e=>clearTimeout(e)),t.timers.clear(),e.activeTransition===t&&(e.activeTransition=void 0),e.status===`switching`&&(e.currentFloorId=void 0,e.status=`cancelled`),this.stopActiveMoves(e),this.logger.warn(`building floor transition failed`,{buildingId:e.definition.buildingId,error:n}),t.reject(n))}settleTransition(e,t,n){t.settled||(t.settled=!0,t.timers.forEach(e=>clearTimeout(e)),t.timers.clear(),e.activeTransition===t&&(e.activeTransition=void 0),t.resolve(n))}async stopActiveTransition(e){let t=e.activeTransition;t&&this.settleTransition(e,t,{buildingId:e.definition.buildingId,status:`cancelled`,visibleFloorIds:[...e.visibleFloorIds],focusMode:`none`,completion:`estimated`}),await this.stopActiveMoves(e)}async stopActiveMoves(e){let t=[...e.activeMoves];e.activeMoves.clear(),t.forEach(t=>{this.dependencies.modelTransform.endMove({parentId:e.definition.parentId,id:t}).catch(n=>{this.logger.warn(`failed to stop building floor move`,{buildingId:e.definition.buildingId,floorId:t,error:n})})}),await Promise.resolve()}createResult(e,t,n,r){return{buildingId:e.definition.buildingId,floorId:t.floorId,status:n,visibleFloorIds:n===`completed`?[...t.visibleFloorIds]:[...e.visibleFloorIds],focusMode:r,completion:`estimated`}}getHideOffset(e){let t=[...e.originalPositions.values()].map(e=>e.z);return t.length<2?2e3:Math.max(Math.max(...t)-Math.min(...t),1)*2.2}getAccessoryObjectIds(e){let t=new Set(e.overview.objects??[]);return e.floors.forEach(e=>{e.objects?.forEach(e=>t.add(e))}),[...t]}getBatchDurationMs(e){return e===0?0:(e-1)*105+ki*1e3}getMotionSpeed(e){return Math.max(e/ki,1)}positionAtZ(e,t){return{x:e.x,y:e.y,z:t,ePSGType:e.ePSGType}}},Fi=class{bind(e){this.lifecycle=e}connect(){return this.getLifecycle().connect()}disconnect(){return this.getLifecycle().disconnect()}reconnect(){return this.getLifecycle().reconnect()}getLifecycle(){if(!this.lifecycle)throw Error(`Connection lifecycle is not bound`);return this.lifecycle}};function Ii(e){return`${e}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}var Li=class{withConfig(e){return this.userConfig=e,this}withOptions(e){return this.videoElementParent=e?.videoElementParent,this}build(){if(!this.userConfig)throw Error(`Config must be set via withConfig() before calling build()`);let e=vr(this.userConfig),t=Ii(`sess`),n=Ii(`trace`);te(e.pixelStreamingLogger);let r=new ae(e.logger,void 0,{includeStack:e.includeStack}),i=r.child(`QoS`),a=wr(),o=new Pr(a,{sessionId:t,traceId:n,runMode:e.viewMode,viewMode:e.viewMode},{appId:e.sceneName,env:a.app.environment,pageUrl:lr(),userAgent:ur()},(e,t)=>{i.warn(e,t)});r.setReporter(o);let s=new Fr,c=r.child(`Core`);c.info(`engine init`,{logLevel:r.level,qosReportingEnabled:a.enabled}),o.startSession({engineUuid:e.engineUuid??``});let l=new Br(e,e.dom||this.videoElementParent,r.child(`SessionAdapter`)),u=new qr(e,l,r.child(`AuthWorkflow`)),d=new Yr(l,r.child(`RequestBridge`),{onRequestSent:({requestId:e,module:t,method:n})=>{o.recordEvent({eventName:`ue_request_sent`,stage:`ue_api`,status:`start`,attrs:{requestId:e,apiName:`${t}.${n}`,module:t,method:n}})},onResponseReceived:({requestId:e,module:t,method:n,durationMs:r,code:i})=>{o.recordEvent({eventName:`ue_response_received`,stage:`ue_api`,status:`success`,durationMs:r,attrs:{requestId:e,apiName:`${t}.${n}`,module:t,method:n},metrics:{ueApiRttMs:r,code:i}})}}),f=new Si({authWorkflow:u,logger:r.child(`ConnectionManager`)}),p=new Fi,m=new oe({enabled:e.showProgressBar,hostElement:e.dom,emit:e=>{s.emit(`LoadingProgress`,e)},logger:r.child(`LoadingProgress`)}),h=new ii(l,e=>{s.emit(`EngineStatus`,e)},r.child(`EngineStatus`),e=>{o.recordEvent({eventName:`media_stats_sample`,stage:`media`,status:`update`,metrics:e})}),g=new Qt({getEngineConfig:()=>e,on:(e,t)=>s.on(e,t),off:(e,t)=>s.off(e,t)}),_=Oi({bridge:d,authWorkflow:u,connectionLifecycle:p,createLogger:e=>r.child(e),popupManager:g,videoElementParent:e.dom||this.videoElementParent,beginPointEditorMouseInput:()=>l.beginPointEditorMouseInput()}),ee=new Pi({model:_.Model,modelTransform:_.ModelTransform,camera:_.Camera},{logger:r.child(`BuildingFloor`)}),v={},y=new bi({session:l,screen:_.Screen,logger:r.child(`NetworkAdaptation`),onStateChange:e=>{c.info(`network level changed`,e),s.emit(`networkLevelChanged`,e)},onAction:e=>{(e.success?c.info.bind(c):c.warn.bind(c))(`network adaptation action executed`,e),s.emit(`networkActionExecuted`,e)},onDiagnostics:e=>{s.emit(`networkDiagnosticsUpdated`,e),v.current?.update(e)}}),ne=new xi({logger:r.child(`NetworkDiagnosticsPanel`),onModeChange:e=>{c.info(`network mode changed`,{mode:e}),s.emit(`networkModeChanged`,{mode:e}),y.setMode(e)},onManualLevelChange:e=>{c.info(`network manual level set`,{level:e}),y.setManualLevel(e)},onVisibilityChange:e=>{c.info(`network diagnostics visibility changed`,{visible:e}),y.setDiagnosticsVisible(e),s.emit(`networkDiagnosticsVisibilityChanged`,{visible:e})}});return v.current=ne,{config:e,qosMonitor:o,loggerManager:r,eventBus:s,session:l,authWorkflow:u,bridge:d,connectionManager:f,connectionLifecycle:p,loadingProgress:m,engineStatus:h,networkAdaptation:y,networkDiagnosticsPanel:ne,popupManager:g,buildingFloor:ee,apiFacade:_,sessionId:t,traceId:n}}};const Ri={centerConnecting:`authConnecting`,waiting:`authWaiting`,authorizing:`authAuthorizing`,connected:`authConnected`,failed:`authFailed`};var zi=class{constructor(e,t){this.Events={WebRtcConnected:`webRtcConnected`,WebOnConnect:`webRtcConnected`,MapLoaded:`OnApiDataChannelStarted`,WebRtcDisconnected:`webRtcDisconnected`,WebOnDisconnect:`webRtcDisconnected`,DataChannelDisconnet:`webRtcDisconnected`,WebRtcConnecting:`webRtcConnecting`,WebRtcFailed:`webRtcFailed`,StatsReceived:`statsReceived`,EngineStatus:`EngineStatus`,StreamLoading:`streamLoading`,LoadingProgress:`LoadingProgress`,CenterConnected:`Connect`,CenterDisconnected:`UnConnect`,ConnectResult:`ConnectResult`,CenterCloseMessage:`CenterCloseMessage`,TokenAuthorize:`TokenAuthorize`,EngineServiceInit:`EngineServiceInit`,EngineServiceInitWait:`EngineServiceInitWait`,EngineSocketClose:`EngineSocketClose`,TokenWillExpired:`TokenWillExpired`,AuthStateChanged:`authStateChanged`,AuthConnecting:`authConnecting`,AuthWaiting:`authWaiting`,AuthAuthorizing:`authAuthorizing`,AuthConnected:`authConnected`,AuthFailed:`authFailed`,SessionModeReady:`sessionModeReady`,SessionModeFailed:`sessionModeFailed`,SceneConfig:`SceneConfig`,ModelClick:`ModelClick`,ModelUpdate:`ModelUpdate`,CameraHeight:`CameraHeight`,LeftClick:`MouseLeftButtonClick`,LeftDoubleClick:`MouseLeftButtonDoubleClick`,LeftLongPressed:`MouseLeftButtonLongPressed`,RightClick:`MouseRightButtonClick`,RightDoubleClick:`MouseRightButtonDoubleClick`,RightLongPressed:`MouseRightButtonLongPressed`,ModelTrigger:`ModelTrigger`,SyncPops:`SyncPops`,NetworkLevelChanged:`networkLevelChanged`,NetworkActionExecuted:`networkActionExecuted`,NetworkModeChanged:`networkModeChanged`,NetworkDiagnosticsVisibilityChanged:`networkDiagnosticsVisibilityChanged`,NetworkDiagnosticsUpdated:`networkDiagnosticsUpdated`,LoadMQTTDataFinished:`LoadMQTTDataFinished`,LoadMQTTDataProgress:`LoadMQTTDataProgress`,TrainsVisible:`TrainsVisible`,TrainsInfo:`TrainsInfo`},this.Enums={DlssQuality:w,FilterMode:Re,GizmoType:Ve,LayerEnum:Fe,ModelTransformType:Le,ScreenRenderBitratePreset:T,Season:Ie,TrainBehavior:ze,UIPopState:Be,VideoCodeType:Pe},this.uePushResponseListenerName=`enginesdk3_ue_push_listener`,this.uePushResponseHandler=this.handleUePushResponse.bind(this);let n=new Li().withConfig(e).withOptions({videoElementParent:t?.videoElementParent}).build();this.resolvedConfig=n.config,this.agentBridgeOptions=t?.agentBridge,this.eventBus=n.eventBus,this.qosMonitor=n.qosMonitor,this.session=n.session,this.authWorkflow=n.authWorkflow,this.connectionManager=n.connectionManager,this.loadingProgressController=n.loadingProgress,this.engineStatusCollector=n.engineStatus,this.networkAdaptation=n.networkAdaptation,this.networkDiagnosticsPanel=n.networkDiagnosticsPanel,this.popupManager=n.popupManager,n.connectionLifecycle.bind({connect:this.connect.bind(this),disconnect:()=>this.disconnectAndWait(),reconnect:this.restart.bind(this)});let r=n.loggerManager.child(`Core`),i=this.resolvedConfig;this.uePushEventNames=new Set([this.Events.MapLoaded,this.Events.ModelClick,this.Events.ModelUpdate,this.Events.CameraHeight,this.Events.LeftClick,this.Events.LeftDoubleClick,this.Events.LeftLongPressed,this.Events.RightClick,this.Events.RightDoubleClick,this.Events.RightLongPressed,this.Events.SceneConfig,this.Events.ModelTrigger,this.Events.SyncPops,this.Events.LoadMQTTDataFinished,this.Events.LoadMQTTDataProgress,this.Events.NetworkDiagnosticsUpdated,this.Events.TrainsVisible,this.Events.TrainsInfo]),this.session.addResponseEventListener(this.uePushResponseListenerName,this.uePushResponseHandler),i.viewMode===`cs`?this.loadingProgressController.show(b.SourcePreparing,`SourcePreparing`):this.loadingProgressController.show(b.EngineIniting,`EngineIniting`),this.mountApiFacade(n.apiFacade),this.BuildingFloor=n.buildingFloor,this.networkAdaptation.start(),this.networkDiagnosticsPanel.update(this.networkAdaptation.getDiagnosticsSnapshot()),this.initializeOptionalRuntimeExtensions(),this.setupEventListeners(r),this.bootstrapPromise=this.startAuthFlowWithQos().catch(e=>(r.error(`auto auth bootstrap failed`,{error:p(e)}),this.authWorkflow.getSnapshot()))}setupEventListeners(e){this.session.getForwardEvents().forEach(t=>{this.session.addEventListener(t,n=>{(t===`webRtcConnecting`||t===`webRtcDisconnected`||t===`webRtcFailed`)&&(this.PointEditor.cancelPlacement(),this.GizmosTool.resetRuntime()),t===`webRtcConnected`&&(this.connectionManager.markConnected(),this.loadingProgressController.show(b.EngineConnectionSuccess,`EngineConnectionSuccess`,!1)),(t===`webRtcDisconnected`||t===`subscribeFailed`)&&this.loadingProgressController.show(b.EngineClose,`EngineClose`,!0),t===`streamerAssigned`&&(this.connectionManager.hasConnectedBefore()?(this.loadingProgressController.show(b.EngineConnectionSuccess,`EngineConnectionSuccess`,!1),e.info(`streamerAssigned during reconnect, showing success progress`)):e.info(`streamerAssigned during initial connect, skip progress (will show on webRtcConnected)`)),this.handleSessionForwardEventForQos(t),e.debug(`forward event`,{eventName:t}),this.eventBus.emit(t,n)})}),this.authWorkflow.on(`stateChanged`,t=>{this.handleAuthStateForQos(t.state),e.debug(`auth state changed`,{state:t.state}),this.eventBus.emit(this.Events.AuthStateChanged,t);let n=Ri[t.state];n&&this.eventBus.emit(n,t)}),this.authWorkflow.on(`progress`,e=>{this.handleProgressNotice(e)}),this.authWorkflow.on(`centerEvent`,({eventName:e,payload:t})=>{this.handleCenterEventForQos(e),this.eventBus.emit(e,t)}),this.authWorkflow.on(`failed`,t=>{let n=this.durationFrom(this.authStartedAt);this.authStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`auth_failed`,stage:`auth`,status:`failed`,durationMs:n,errorCode:t.lastError?.code,errorMessage:t.lastError?.message}),e.error(`auth workflow failed`,{error:t.lastError?JSON.stringify(t.lastError):`unknown`}),this.eventBus.emit(this.Events.SessionModeFailed,{mode:this.session.getViewMode(),snapshot:t})}),this.authWorkflow.on(`connected`,e=>{let t=this.durationFrom(this.authStartedAt);this.authStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`auth_success`,stage:`auth`,status:`success`,durationMs:t}),this.eventBus.emit(this.Events.SessionModeReady,{mode:this.session.getViewMode(),snapshot:e})})}on(e,t){this.eventBus.on(e,t)}off(e,t){this.eventBus.off(e,t)}whenReady(){return this.bootstrapPromise}setNetworkAdaptationMode(e){this.handleNetworkModeChange(e)}setNetworkManualLevel(e){this.handleNetworkModeChange(`manual`),this.networkAdaptation.setManualLevel(e)}getNetworkDiagnosticsSnapshot(){return this.latestNetworkDiagnostics??this.networkAdaptation.getDiagnosticsSnapshot()}async disconnectAndWait(){this.connectionManager.getStatus().disconnected||(this.qosMonitor.endSession({reason:`disconnect`}),this.stopRuntimeForLifecycle({disconnectAuth:!1,removeListener:!0}),await this.connectionManager.disconnect())}disconnect(){this.disconnectAndWait()}async connect(){return this.connectionManager.getStatus().disconnected?(await this.connectionManager.prepareConnectAfterDisconnect(),this.session.addResponseEventListener(this.uePushResponseListenerName,this.uePushResponseHandler),this.initializeOptionalRuntimeExtensions(),this.qosMonitor.startSession({reason:`connect`}),this.startAuthFlowWithQos()):this.authWorkflow.getSnapshot()}async restart(){return this.qosMonitor.endSession({reason:`restart`}),this.stopRuntimeForLifecycle({disconnectAuth:!1,stopAgentBridge:!1,removeListener:!0}),this.session.addResponseEventListener(this.uePushResponseListenerName,this.uePushResponseHandler),this.initializeOptionalRuntimeExtensions(),this.qosMonitor.startSession({reason:`restart`}),this.authStartedAt=Date.now(),this.centerConnectStartedAt=void 0,this.webrtcConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`auth_start`,stage:`auth`,status:`start`}),this.connectionManager.restart()}startAuthFlowWithQos(){return this.authStartedAt=Date.now(),this.centerConnectStartedAt=void 0,this.webrtcConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`auth_start`,stage:`auth`,status:`start`}),this.connectionManager.connect()}handleSessionForwardEventForQos(e){if(e===`webRtcConnecting`){this.webrtcConnectStartedAt===void 0&&(this.webrtcConnectStartedAt=Date.now(),this.qosMonitor.recordEvent({eventName:`webrtc_connect_start`,stage:`webrtc`,status:`start`}));return}if(e===`webRtcConnected`){let e=this.durationFrom(this.webrtcConnectStartedAt);this.webrtcConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`webrtc_connected`,stage:`webrtc`,status:`success`,durationMs:e}),this.qosMonitor.recordEvent({eventName:`first_frame_rendered`,stage:`media`,status:`success`,durationMs:e});return}(e===`webRtcDisconnected`||e===`webRtcFailed`)&&(this.webrtcConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`webrtc_disconnected`,stage:`webrtc`,status:`failed`,attrs:{reason:e}}))}handleAuthStateForQos(e){if(e===`centerConnecting`){this.centerConnectStartedAt=Date.now(),this.qosMonitor.recordEvent({eventName:`center_connect_start`,stage:`center`,status:`start`});return}if(e===`centerConnected`){let e=this.durationFrom(this.centerConnectStartedAt);this.centerConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`center_connected`,stage:`center`,status:`success`,durationMs:e});return}e===`webrtcConnecting`&&this.webrtcConnectStartedAt===void 0&&(this.webrtcConnectStartedAt=Date.now(),this.qosMonitor.recordEvent({eventName:`webrtc_connect_start`,stage:`webrtc`,status:`start`}))}handleCenterEventForQos(e){if(this.qosMonitor.recordEvent({eventName:`center_message_received`,stage:`center`,status:`update`,attrs:{fn:e}}),e===this.Events.CenterDisconnected){this.qosMonitor.recordEvent({eventName:`center_disconnected`,stage:`center`,status:`failed`,attrs:{reason:e}});return}if(e===this.Events.CenterConnected&&this.centerConnectStartedAt!==void 0){let e=this.durationFrom(this.centerConnectStartedAt);this.centerConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`center_connected`,stage:`center`,status:`success`,durationMs:e})}}durationFrom(e){if(e===void 0)return;let t=Date.now()-e;return Number.isFinite(t)&&t>=0?t:void 0}handleProgressNotice(e){if(e.kind===`tokenWillExpire`){this.loadingProgressController.showTokenWillExpire(e.message,e.key,e.isClose);return}this.loadingProgressController.show(e.message,e.key,e.isClose)}handleNetworkModeChange(e){this.networkAdaptation.setMode(e);let t={mode:e,ts:Date.now(),diagnostics:this.networkAdaptation.getDiagnosticsSnapshot()};this.eventBus.emit(this.Events.NetworkModeChanged,t)}mountApiFacade(e){let t=this;Object.keys(e).forEach(n=>{this.setApiModule(t,e,n)})}setApiModule(e,t,n){e[n]=t[n]}initializeOptionalRuntimeExtensions(){if(this.agentBridge||!this.agentBridgeOptions?.enabled)return;let e={...this.agentBridgeOptions,serverUrl:this.agentBridgeOptions.serverUrl??`ws://127.0.0.1:8787/sdk3-bridge`},t=sr(this,{runtimeName:e.runtimeName,expose:e.expose,metadata:e.metadata,engineConfig:this.resolvedConfig,getAuthSnapshot:()=>this.authWorkflow.getSnapshot(),mockInvoke:e.mockInvoke});this.agentBridge=new fe(t,e),this.agentBridge.start()}stopRuntimeForLifecycle(e){this.PointEditor.cancelPlacement(),this.GizmosTool.resetRuntime(),e?.stopAgentBridge!==!1&&(this.agentBridge?.stop(`disconnect`),this.agentBridge=void 0),e?.removeListener!==!1&&this.session.removeResponseEventListener(this.uePushResponseListenerName),this.engineStatusCollector.stop(),e?.disconnectAuth!==!1&&this.authWorkflow.disconnect(),this.loadingProgressController.dispose(),this.qosMonitor.flush()}handleUePushResponse(e){let t=e,n;try{if(t=JSON.parse(e),typeof t==`object`&&t){let e=t,r=e.uuid??e.fn;typeof r==`string`&&r.length>0&&(n=r)}}catch{}if(n===`PointEditorGizmoEnded`){this.GizmosTool.finishFromEngine();return}!n&&this.uePushEventNames.has(e)&&(n=e),!(!n||!this.uePushEventNames.has(n))&&this.eventBus.emit(n,t)}getEngineConfig(){return this.resolvedConfig}};export{wn as AGENT_BRIDGE_API_METADATA,dn as API_MODULE_KEYS,fe as AgentRuntimeBridge,jt as Animation,Q as ApiRegistryError,Pi as BuildingFloor,$ as BuildingFloorError,Mt as Camera,Nt as Connect,zi as DTCEngine,Pt as Dlss,w as DlssQuality,Re as FilterMode,Ve as GizmoType,Oe as GizmosTool,Ft as HeatMap,It as HighLighterEffect,zt as Layer,Fe as LayerEnum,Bt as Model,Vt as ModelPOI,Ht as ModelTransform,Le as ModelTransformType,Ut as Navigation,Wt as PathPatrol,kt as PendingValidationSchemaMap,Xt as PointEditor,qt as PointIcon,en as Popup,d as SDKValidationError,nn as Scene,tn as Screen,T as ScreenRenderBitratePreset,Me as ScreenRenderBitratePresetOptions,Ie as Season,rn as SpatialQuery,an as TimeLine,ze as TrainBehavior,on as TrainSimulate,sn as UIPOI,Pe as VideoCodeType,ln as WeatherSystem,cn as WebView,un as apiRegistry,Tn as createAgentBridgeMetadata,Oi as createApiFacade,sr as createBridgeRuntime,Mn as getAgentBridgeMethodSchema,kn as isAgentBridgeMethodExposed,On as isAgentBridgeModuleExposed,En as isAgentBridgeModuleName,jn as listAgentBridgeMethods,An as listAgentBridgeModules,Dn as resolveAgentBridgeExposeConfig};
109
+ `)}},Si=class{constructor(e){this.disconnected=!1,this.hasEverConnected=!1,this.authWorkflow=e.authWorkflow,this.logger=e.logger}async connect(){if(this.disconnected)throw Error(`Cannot connect after disconnect. Use restart() instead.`);this.logger.info(`Starting connection flow`);try{let e=await this.authWorkflow.start();return this.logger.info(`Connection established`,{engineToken:e.engineToken?.substring(0,16)+`...`}),e}catch(e){throw this.logger.error(`Connection failed`,{error:e}),e}}async disconnect(){return this.disconnected?(this.logger.info(`Already disconnected, skipping`),this.disconnectPromise||Promise.resolve()):(this.logger.info(`Disconnecting...`),this.disconnected=!0,this.disconnectPromise=(async()=>{try{await this.authWorkflow.disconnectAndWait(),this.logger.info(`Disconnected successfully`)}catch(e){throw this.logger.error(`Error during disconnect`,{error:e}),e}})(),this.disconnectPromise)}async prepareConnectAfterDisconnect(){this.disconnectPromise&&await this.disconnectPromise,this.disconnected=!1,this.disconnectPromise=void 0,this.hasEverConnected=!1}async restart(){return this.logger.info(`Restarting connection...`),await this.disconnect(),await this.prepareConnectAfterDisconnect(),this.connect()}getStatus(){return{disconnected:this.disconnected,hasEverConnected:this.hasEverConnected}}hasConnectedBefore(){return this.hasEverConnected}markConnected(){this.hasEverConnected=!0}},Q=class extends Error{constructor(e,t,n,r){super(t),this.code=e,this.moduleName=n,this.dependencyName=r,this.name=`ApiRegistryError`}};function Ci(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function wi(e,t){return Ci(e)&&typeof e[t]==`function`}function Ti(e){if(!Ci(e))throw new Q(`CONTEXT_INVALID`,`API registry context must be an object`);let t=[[`bridge`,e.bridge,`sendRequest`],[`authWorkflow`,e.authWorkflow,`getSnapshot`],[`connectionLifecycle`,e.connectionLifecycle,`connect`],[`createLogger`,e.createLogger,void 0]];for(let[e,n,r]of t)if(!(r?wi(n,r):typeof n==`function`||n!=null))throw new Q(`CONTEXT_INVALID`,`API registry context dependency '${e}'${r?` with ${r}()`:``} is required`,void 0,e)}function Ei(e){if(!Ci(e))throw new Q(`REGISTRY_INVALID`,`API registry must be a non-null object`);let t=Object.keys(e).find(e=>!dn.includes(e));if(t)throw new Q(`REGISTRY_UNKNOWN_MODULE`,`API registry contains unknown module '${t}'`,t);let n=dn.find(t=>!(t in e));if(n)throw new Q(`REGISTRY_INCOMPLETE`,`API registry is missing module '${n}'`,n);for(let t of dn)if(typeof e[t]!=`function`)throw new Q(`FACTORY_INVALID`,`API registry factory for '${t}' must be a function`,t)}function Di(e,t,n,r){let i;try{i=t[r](n)}catch(e){throw new Q(`FACTORY_FAILED`,`API registry factory for '${r}' failed: ${e instanceof Error?e.message:String(e)}`,r,void 0)}if(i==null)throw new Q(`FACTORY_EMPTY_RESULT`,`API registry factory for '${r}' returned ${i===null?`null`:`undefined`}`,r);e[r]=i}function Oi(e,t=un){if(Ti(e),Ei(t),typeof t.Popup==`function`&&(e.popupManager===null||e.popupManager===void 0))throw new Q(`CONTEXT_INVALID`,`API registry context dependency 'popupManager' is required by the Popup module`,`Popup`,`popupManager`);let n={};return dn.forEach(r=>{Di(n,t,e,r)}),n}const ki=.78;var $=class extends Error{constructor(e,t,n,r){super(t),this.code=e,this.buildingId=n,this.floorId=r,this.name=`BuildingFloorError`}};function Ai(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function ji(e){return Ai(e)&&typeof e.x==`number`&&Number.isFinite(e.x)&&typeof e.y==`number`&&Number.isFinite(e.y)&&typeof e.z==`number`&&Number.isFinite(e.z)}function Mi(e){return{position:Ni(e.position),target:Ni(e.target),fov:e.fov,time:e.time}}function Ni(e){return new C(e.x,e.y,e.z,e.ePSGType)}var Pi=class{constructor(e,t){this.dependencies=e,this.buildings=new Map,this.logger=t?.logger??h}async register(e){let t=Array.isArray(e)?e:[e],n=this.normalizeRegistrations(t),r=await Promise.all(n.map(async e=>({definition:e,positions:await this.measureFloorPositions(e)})));this.assertBuildingsRemainAvailable(n),r.forEach(({definition:e,positions:t})=>{this.buildings.set(e.buildingId,{definition:e,originalPositions:t,explodedDistances:new Map,visibleFloorIds:e.floors.map(e=>e.id),transitionId:0,status:`overview`,activeMoves:new Set})});let i=n.map(e=>e.buildingId);return this.logger.info(`building floors registered`,{buildingIds:i}),{buildingIds:i}}async switchTo(e){let t=this.requireBuilding(e.buildingId),n=t.definition.floors.findIndex(t=>t.id===e.floorId);if(n<0)throw new $(`FLOOR_NOT_FOUND`,`Floor "${e.floorId}" is not registered for building "${e.buildingId}".`,e.buildingId,e.floorId);let r=t.definition.floors[n];return this.transition(t,{floorId:r.id,visibleFloorIds:t.definition.floors.slice(0,n+1).map(e=>e.id),hiddenFloorIds:t.definition.floors.slice(n+1).map(e=>e.id),viewPoint:r.viewPoint,objectIds:r.objects??[],showLayers:r.showLayers??[],hideLayers:r.hideLayers??[],overview:!1,focus:e.focus===!0})}async showOverview(e){let t=this.requireBuilding(e.buildingId);return this.transition(t,{visibleFloorIds:t.definition.floors.map(e=>e.id),hiddenFloorIds:[],viewPoint:t.definition.overview.viewPoint,objectIds:t.definition.overview.objects??[],showLayers:t.definition.overview.showLayers??[],hideLayers:t.definition.overview.hideLayers??[],overview:!0,focus:e.focus===!0})}async cancel(e){let t=this.requireBuilding(e.buildingId);t.transitionId+=1,await this.stopActiveTransition(t),t.currentFloorId=void 0,t.status=`cancelled`,this.logger.info(`building floor transition cancelled`,{buildingId:e.buildingId})}getState(e){let t=this.requireBuilding(e.buildingId);return{buildingId:t.definition.buildingId,status:t.status,currentFloorId:t.currentFloorId,visibleFloorIds:[...t.visibleFloorIds],transitionId:t.transitionId}}normalizeRegistrations(e){if(e.length===0)throw new $(`INVALID_REGISTRATION`,`At least one building is required.`);let t=new Set;return e.map(e=>{let n=this.requireNonEmptyString(e?.buildingId,`buildingId`),r=this.requireNonEmptyString(e?.parentId,`parentId`,n);if(t.has(n))throw new $(`INVALID_REGISTRATION`,`Building "${n}" is duplicated in the registration batch.`,n);if(this.buildings.has(n))throw new $(`BUILDING_ALREADY_REGISTERED`,`Building "${n}" is already registered.`,n);if(t.add(n),!Array.isArray(e.floors)||e.floors.length===0)throw new $(`INVALID_REGISTRATION`,`Building "${n}" must contain at least one floor.`,n);let i=new Set,a=e.floors.map((e,t)=>{let r=this.normalizeFloor(e,n,t);if(i.has(r.id))throw new $(`INVALID_REGISTRATION`,`Floor "${r.id}" is duplicated in building "${n}".`,n,r.id);return i.add(r.id),r}),o=e.overview??{},s=o.objects??[];if(!Array.isArray(s)||s.some(e=>typeof e!=`string`||e.trim()===``))throw new $(`INVALID_REGISTRATION`,`Building "${n}" overview objects must contain non-empty IDs.`,n);return o.viewPoint&&this.validateViewPoint(o.viewPoint,n,`overview`),{buildingId:n,parentId:r,floors:a,overview:{objects:[...s],showLayers:this.normalizeObjectIds(o.showLayers,n,`overview`,`showLayers`),hideLayers:this.normalizeObjectIds(o.hideLayers,n,`overview`,`hideLayers`),viewPoint:o.viewPoint?Mi(o.viewPoint):void 0}}})}normalizeFloor(e,t,n){let r=typeof e==`string`?{id:e}:e;if(!Ai(r))throw new $(`INVALID_REGISTRATION`,`Floor at index ${n} in building "${t}" must be a string or object.`,t);let i=this.requireNonEmptyString(r.id,`floors[${n}].id`,t),a=r.viewPoint;return a!==void 0&&this.validateViewPoint(a,t,i),{id:i,viewPoint:a?Mi(a):void 0,objects:this.normalizeObjectIds(r.objects,t,i),showLayers:this.normalizeObjectIds(r.showLayers,t,i,`showLayers`),hideLayers:this.normalizeObjectIds(r.hideLayers,t,i,`hideLayers`)}}normalizeObjectIds(e,t,n,r=`Objects`){if(e!==void 0){if(!Array.isArray(e)||e.some(e=>typeof e!=`string`||e.trim()===``))throw new $(`INVALID_REGISTRATION`,`${r} for "${t}@${n}" must contain non-empty IDs.`,t,n);return[...e]}}validateViewPoint(e,t,n){if(!Ai(e)||!ji(e.position)||!ji(e.target))throw new $(`INVALID_REGISTRATION`,`View point for "${t}@${n}" requires valid position and target vectors.`,t,n);if(e.fov!==void 0&&(!Number.isFinite(e.fov)||e.fov<10||e.fov>150))throw new $(`INVALID_REGISTRATION`,`View point fov for "${t}@${n}" must be between 10 and 150.`,t,n);if(e.time!==void 0&&(!Number.isFinite(e.time)||e.time<0))throw new $(`INVALID_REGISTRATION`,`View point time for "${t}@${n}" must be a non-negative number.`,t,n)}requireNonEmptyString(e,t,n){if(typeof e!=`string`||e.trim()===``)throw new $(`INVALID_REGISTRATION`,`${t} must be a non-empty string.`,n);return e}assertBuildingsRemainAvailable(e){let t=e.find(e=>this.buildings.has(e.buildingId));if(t)throw new $(`BUILDING_ALREADY_REGISTERED`,`Building "${t.buildingId}" was registered while its model information was loading.`,t.buildingId)}async measureFloorPositions(e){let t=await Promise.all(e.floors.map(async t=>{let n=await this.dependencies.model.getModelInfo({parentId:e.parentId,id:t.id});return[t.id,this.extractPosition(n,e.buildingId,t.id)]}));return new Map(t)}extractPosition(e,t,n){let r=e,i=e.params??e.data??r.param;if(Ai(i)&&(`param`in i||`params`in i)&&(i=i.param??i.params),typeof i==`string`)try{i=JSON.parse(i)}catch{i=void 0}let a=Ai(i)?i.position:void 0;if(!ji(a))throw new $(`MODEL_INFO_INVALID`,`Model information for "${t}@${n}" does not contain a valid position.`,t,n);return{x:a.x,y:a.y,z:a.z,ePSGType:typeof a.ePSGType==`string`&&a.ePSGType!==``?a.ePSGType:`0000`}}requireBuilding(e){let t=this.buildings.get(e);if(!t)throw new $(`BUILDING_NOT_REGISTERED`,`Building "${e}" is not registered.`,e);return t}async transition(e,t){let n=e.transitionId+1;if(e.transitionId=n,await this.stopActiveTransition(e),n!==e.transitionId)return this.createResult(e,t,`cancelled`,`none`);e.status=`switching`;let r=t.visibleFloorIds.filter(t=>e.explodedDistances.has(t)),i=t.hiddenFloorIds.filter(t=>!e.explodedDistances.has(t)),a=t.hiddenFloorIds.filter(t=>e.explodedDistances.has(t));try{let r=this.getAccessoryObjectIds(e.definition).filter(e=>!t.showLayers.includes(e));if(r.length>0&&(await this.dependencies.model.setVisible({id:r,visible:!1}),n!==e.transitionId))return this.createResult(e,t,`cancelled`,`none`);for(let[r,i]of[[t.showLayers,!0],[t.hideLayers,!1]])if(r.length!==0&&(await this.dependencies.model.setVisible({id:r,visible:i}),n!==e.transitionId))return this.createResult(e,t,`cancelled`,`none`);if(t.visibleFloorIds.length>0&&(await this.dependencies.model.setVisible({parentId:e.definition.parentId,id:t.visibleFloorIds,visible:!0}),n!==e.transitionId))return this.createResult(e,t,`cancelled`,`none`);a.length>0&&await this.dependencies.model.setVisible({parentId:e.definition.parentId,id:a,visible:!1})}catch(t){throw n===e.transitionId&&(e.status=`cancelled`),t}return n===e.transitionId?new Promise((a,o)=>{let s={id:n,timers:new Set,pendingActions:new Set,settled:!1,resolve:a,reject:o};e.activeTransition=s,r.forEach((t,n)=>{this.schedule(e,s,n*105,async()=>{let n=e.originalPositions.get(t),r=this.getHideOffset(e),i=Math.max(r*.035,.5),a=e.explodedDistances.get(t)??r;e.activeMoves.add(t),await this.dependencies.modelTransform.startMoveByNodes({parentId:e.definition.parentId,id:t,nodes:[this.positionAtZ(n,n.z-i),this.positionAtZ(n,n.z)],speed:this.getMotionSpeed(a+i*2),linear:6,isLookAtTarget:!1,needDirection:!1})})}),[...i].reverse().forEach((t,n)=>{this.schedule(e,s,n*105,async()=>{let r=e.originalPositions.get(t),i=this.getHideOffset(e),a=Math.max(i*.045,.6),o=i*(1+.24*n);e.explodedDistances.set(t,o),e.activeMoves.add(t),await this.dependencies.modelTransform.startMoveByNodes({parentId:e.definition.parentId,id:t,nodes:[this.positionAtZ(r,r.z-a),this.positionAtZ(r,r.z+o)],speed:this.getMotionSpeed(o+a*2),linear:5,isLookAtTarget:!1,needDirection:!1})})});let c=Math.max(this.getBatchDurationMs(r.length),this.getBatchDurationMs(i.length));this.scheduleCompletion(e,s,c,t)}):this.createResult(e,t,`cancelled`,`none`)}schedule(e,t,n,r){let i=setTimeout(()=>{if(t.timers.delete(i),t.settled||t.id!==e.transitionId)return;let n=Promise.resolve().then(()=>{if(!(t.settled||t.id!==e.transitionId))return r()});t.pendingActions.add(n),n.then(()=>{t.pendingActions.delete(n)}).catch(r=>{t.pendingActions.delete(n),this.failTransition(e,t,r)})},n);t.timers.add(i)}scheduleCompletion(e,t,n,r){let i=setTimeout(()=>{t.timers.delete(i),!(t.settled||t.id!==e.transitionId)&&Promise.all([...t.pendingActions]).then(()=>this.completeTransition(e,t,r)).catch(n=>{this.failTransition(e,t,n)})},n);t.timers.add(i)}async completeTransition(e,t,n){if(!(t.settled||t.id!==e.transitionId))try{if(n.hiddenFloorIds.length>0&&(await this.dependencies.model.setVisible({parentId:e.definition.parentId,id:n.hiddenFloorIds,visible:!1}),t.settled||t.id!==e.transitionId))return;n.visibleFloorIds.forEach(t=>e.explodedDistances.delete(t)),e.activeMoves.clear(),e.visibleFloorIds=[...n.visibleFloorIds],e.currentFloorId=n.floorId,e.status=n.overview?`overview`:`floor`;let r=n.objectIds.filter(e=>!n.hideLayers.includes(e));if(r.length>0&&(await this.dependencies.model.setVisible({id:r,visible:!0}),t.settled||t.id!==e.transitionId))return;let i=await this.focusTarget(e,n);if(t.settled||t.id!==e.transitionId)return;this.settleTransition(e,t,this.createResult(e,n,`completed`,i))}catch(n){this.failTransition(e,t,n)}}async focusTarget(e,t){return t.focus?t.viewPoint?(await this.dependencies.camera.flyToTarget({point:t.viewPoint.position,target:t.viewPoint.target,fov:t.viewPoint.fov,time:t.viewPoint.time??.2}),`viewPoint`):(await this.dependencies.camera.lookAt({parentId:e.definition.parentId,id:t.visibleFloorIds,time:.2,isRotate:!1,isHighlight:!1}),`bounds`):`none`}failTransition(e,t,n){t.settled||(t.settled=!0,t.timers.forEach(e=>clearTimeout(e)),t.timers.clear(),e.activeTransition===t&&(e.activeTransition=void 0),e.status===`switching`&&(e.currentFloorId=void 0,e.status=`cancelled`),this.stopActiveMoves(e),this.logger.warn(`building floor transition failed`,{buildingId:e.definition.buildingId,error:n}),t.reject(n))}settleTransition(e,t,n){t.settled||(t.settled=!0,t.timers.forEach(e=>clearTimeout(e)),t.timers.clear(),e.activeTransition===t&&(e.activeTransition=void 0),t.resolve(n))}async stopActiveTransition(e){let t=e.activeTransition;t&&this.settleTransition(e,t,{buildingId:e.definition.buildingId,status:`cancelled`,visibleFloorIds:[...e.visibleFloorIds],focusMode:`none`,completion:`estimated`}),await this.stopActiveMoves(e)}async stopActiveMoves(e){let t=[...e.activeMoves];e.activeMoves.clear(),t.forEach(t=>{this.dependencies.modelTransform.endMove({parentId:e.definition.parentId,id:t}).catch(n=>{this.logger.warn(`failed to stop building floor move`,{buildingId:e.definition.buildingId,floorId:t,error:n})})}),await Promise.resolve()}createResult(e,t,n,r){return{buildingId:e.definition.buildingId,floorId:t.floorId,status:n,visibleFloorIds:n===`completed`?[...t.visibleFloorIds]:[...e.visibleFloorIds],focusMode:r,completion:`estimated`}}getHideOffset(e){let t=[...e.originalPositions.values()].map(e=>e.z);return t.length<2?2e3:Math.max(Math.max(...t)-Math.min(...t),1)*2.2}getAccessoryObjectIds(e){let t=new Set(e.overview.objects??[]);return e.floors.forEach(e=>{e.objects?.forEach(e=>t.add(e))}),[...t]}getBatchDurationMs(e){return e===0?0:(e-1)*105+ki*1e3}getMotionSpeed(e){return Math.max(e/ki,1)}positionAtZ(e,t){return{x:e.x,y:e.y,z:t,ePSGType:e.ePSGType}}},Fi=class{bind(e){this.lifecycle=e}connect(){return this.getLifecycle().connect()}disconnect(){return this.getLifecycle().disconnect()}reconnect(){return this.getLifecycle().reconnect()}getLifecycle(){if(!this.lifecycle)throw Error(`Connection lifecycle is not bound`);return this.lifecycle}};function Ii(e){return`${e}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}var Li=class{withConfig(e){return this.userConfig=e,this}withOptions(e){return this.videoElementParent=e?.videoElementParent,this}build(){if(!this.userConfig)throw Error(`Config must be set via withConfig() before calling build()`);let e=vr(this.userConfig),t=Ii(`sess`),n=Ii(`trace`);te(e.pixelStreamingLogger);let r=new ae(e.logger,void 0,{includeStack:e.includeStack}),i=r.child(`QoS`),a=wr(),o=new Pr(a,{sessionId:t,traceId:n,runMode:e.viewMode,viewMode:e.viewMode},{appId:e.sceneName,env:a.app.environment,pageUrl:lr(),userAgent:ur()},(e,t)=>{i.warn(e,t)});r.setReporter(o);let s=new Fr,c=r.child(`Core`);c.info(`engine init`,{logLevel:r.level,qosReportingEnabled:a.enabled}),o.startSession({engineUuid:e.engineUuid??``});let l=new Br(e,e.dom||this.videoElementParent,r.child(`SessionAdapter`)),u=new qr(e,l,r.child(`AuthWorkflow`)),d=new Yr(l,r.child(`RequestBridge`),{onRequestSent:({requestId:e,module:t,method:n})=>{o.recordEvent({eventName:`ue_request_sent`,stage:`ue_api`,status:`start`,attrs:{requestId:e,apiName:`${t}.${n}`,module:t,method:n}})},onResponseReceived:({requestId:e,module:t,method:n,durationMs:r,code:i})=>{o.recordEvent({eventName:`ue_response_received`,stage:`ue_api`,status:`success`,durationMs:r,attrs:{requestId:e,apiName:`${t}.${n}`,module:t,method:n},metrics:{ueApiRttMs:r,code:i}})}}),f=new Si({authWorkflow:u,logger:r.child(`ConnectionManager`)}),p=new Fi,m=new oe({enabled:e.showProgressBar,hostElement:e.dom,emit:e=>{s.emit(`LoadingProgress`,e)},logger:r.child(`LoadingProgress`)}),h=new ii(l,e=>{s.emit(`EngineStatus`,e)},r.child(`EngineStatus`),e=>{o.recordEvent({eventName:`media_stats_sample`,stage:`media`,status:`update`,metrics:e})}),g=new Qt({getEngineConfig:()=>e,on:(e,t)=>s.on(e,t),off:(e,t)=>s.off(e,t)}),_=Oi({bridge:d,authWorkflow:u,connectionLifecycle:p,createLogger:e=>r.child(e),popupManager:g,videoElementParent:e.dom||this.videoElementParent,beginPointEditorMouseInput:()=>l.beginPointEditorMouseInput()}),ee=new Pi({model:_.Model,modelTransform:_.ModelTransform,camera:_.Camera},{logger:r.child(`BuildingFloor`)}),v={},y=new bi({session:l,screen:_.Screen,logger:r.child(`NetworkAdaptation`),onStateChange:e=>{c.info(`network level changed`,e),s.emit(`networkLevelChanged`,e)},onAction:e=>{(e.success?c.info.bind(c):c.warn.bind(c))(`network adaptation action executed`,e),s.emit(`networkActionExecuted`,e)},onDiagnostics:e=>{s.emit(`networkDiagnosticsUpdated`,e),v.current?.update(e)}}),ne=new xi({logger:r.child(`NetworkDiagnosticsPanel`),onModeChange:e=>{c.info(`network mode changed`,{mode:e}),s.emit(`networkModeChanged`,{mode:e}),y.setMode(e)},onManualLevelChange:e=>{c.info(`network manual level set`,{level:e}),y.setManualLevel(e)},onVisibilityChange:e=>{c.info(`network diagnostics visibility changed`,{visible:e}),y.setDiagnosticsVisible(e),s.emit(`networkDiagnosticsVisibilityChanged`,{visible:e})}});return v.current=ne,{config:e,qosMonitor:o,loggerManager:r,eventBus:s,session:l,authWorkflow:u,bridge:d,connectionManager:f,connectionLifecycle:p,loadingProgress:m,engineStatus:h,networkAdaptation:y,networkDiagnosticsPanel:ne,popupManager:g,buildingFloor:ee,apiFacade:_,sessionId:t,traceId:n}}};const Ri={centerConnecting:`authConnecting`,waiting:`authWaiting`,authorizing:`authAuthorizing`,connected:`authConnected`,failed:`authFailed`};var zi=class{constructor(e,t){this.Events={WebRtcConnected:`webRtcConnected`,WebOnConnect:`webRtcConnected`,MapLoaded:`OnApiDataChannelStarted`,WebRtcDisconnected:`webRtcDisconnected`,WebOnDisconnect:`webRtcDisconnected`,DataChannelDisconnet:`webRtcDisconnected`,WebRtcConnecting:`webRtcConnecting`,WebRtcFailed:`webRtcFailed`,StatsReceived:`statsReceived`,EngineStatus:`EngineStatus`,StreamLoading:`streamLoading`,LoadingProgress:`LoadingProgress`,CenterConnected:`Connect`,CenterDisconnected:`UnConnect`,ConnectResult:`ConnectResult`,CenterCloseMessage:`CenterCloseMessage`,TokenAuthorize:`TokenAuthorize`,EngineServiceInit:`EngineServiceInit`,EngineServiceInitWait:`EngineServiceInitWait`,EngineSocketClose:`EngineSocketClose`,TokenWillExpired:`TokenWillExpired`,AuthStateChanged:`authStateChanged`,AuthConnecting:`authConnecting`,AuthWaiting:`authWaiting`,AuthAuthorizing:`authAuthorizing`,AuthConnected:`authConnected`,AuthFailed:`authFailed`,SessionModeReady:`sessionModeReady`,SessionModeFailed:`sessionModeFailed`,SceneConfig:`SceneConfig`,ModelClick:`ModelClick`,ModelUpdate:`ModelUpdate`,CameraHeight:`CameraHeight`,LeftClick:`MouseLeftButtonClick`,LeftDoubleClick:`MouseLeftButtonDoubleClick`,LeftLongPressed:`MouseLeftButtonLongPressed`,RightClick:`MouseRightButtonClick`,RightDoubleClick:`MouseRightButtonDoubleClick`,RightLongPressed:`MouseRightButtonLongPressed`,ModelTrigger:`ModelTrigger`,SyncPops:`SyncPops`,NetworkLevelChanged:`networkLevelChanged`,NetworkActionExecuted:`networkActionExecuted`,NetworkModeChanged:`networkModeChanged`,NetworkDiagnosticsVisibilityChanged:`networkDiagnosticsVisibilityChanged`,NetworkDiagnosticsUpdated:`networkDiagnosticsUpdated`,LoadMQTTDataFinished:`LoadMQTTDataFinished`,LoadMQTTDataProgress:`LoadMQTTDataProgress`,TrainsVisible:`TrainsVisible`,TrainsInfo:`TrainsInfo`},this.Enums={DlssQuality:w,FilterMode:Re,GizmoType:Ve,LayerEnum:Fe,ModelTransformType:Le,ScreenRenderBitratePreset:T,Season:Ie,TrainBehavior:ze,UIPopState:Be,VideoCodeType:Pe},this.uePushResponseListenerName=`enginesdk3_ue_push_listener`,this.uePushResponseHandler=this.handleUePushResponse.bind(this);let n=new Li().withConfig(e).withOptions({videoElementParent:t?.videoElementParent}).build();this.resolvedConfig=n.config,this.agentBridgeOptions=t?.agentBridge,this.eventBus=n.eventBus,this.qosMonitor=n.qosMonitor,this.session=n.session,this.authWorkflow=n.authWorkflow,this.connectionManager=n.connectionManager,this.loadingProgressController=n.loadingProgress,this.engineStatusCollector=n.engineStatus,this.networkAdaptation=n.networkAdaptation,this.networkDiagnosticsPanel=n.networkDiagnosticsPanel,this.popupManager=n.popupManager,n.connectionLifecycle.bind({connect:this.connect.bind(this),disconnect:()=>this.disconnectAndWait(),reconnect:this.restart.bind(this)});let r=n.loggerManager.child(`Core`),i=this.resolvedConfig;this.uePushEventNames=new Set([this.Events.MapLoaded,this.Events.ModelClick,this.Events.ModelUpdate,this.Events.CameraHeight,this.Events.LeftClick,this.Events.LeftDoubleClick,this.Events.LeftLongPressed,this.Events.RightClick,this.Events.RightDoubleClick,this.Events.RightLongPressed,this.Events.SceneConfig,this.Events.ModelTrigger,this.Events.SyncPops,this.Events.LoadMQTTDataFinished,this.Events.LoadMQTTDataProgress,this.Events.NetworkDiagnosticsUpdated,this.Events.TrainsVisible,this.Events.TrainsInfo]),this.session.addResponseEventListener(this.uePushResponseListenerName,this.uePushResponseHandler),i.viewMode===`cs`?this.loadingProgressController.show(b.SourcePreparing,`SourcePreparing`):this.loadingProgressController.show(b.EngineIniting,`EngineIniting`),this.mountApiFacade(n.apiFacade),this.BuildingFloor=n.buildingFloor,this.networkAdaptation.start(),this.networkDiagnosticsPanel.update(this.networkAdaptation.getDiagnosticsSnapshot()),this.initializeOptionalRuntimeExtensions(),this.setupEventListeners(r),this.bootstrapPromise=this.startAuthFlowWithQos().catch(e=>(r.error(`auto auth bootstrap failed`,{error:p(e)}),this.authWorkflow.getSnapshot()))}setupEventListeners(e){this.session.getForwardEvents().forEach(t=>{this.session.addEventListener(t,n=>{(t===`webRtcConnecting`||t===`webRtcDisconnected`||t===`webRtcFailed`)&&(this.PointEditor.cancelPlacement(),this.GizmosTool.resetRuntime()),t===`webRtcConnected`&&(this.connectionManager.markConnected(),this.loadingProgressController.show(b.EngineConnectionSuccess,`EngineConnectionSuccess`,!1)),(t===`webRtcDisconnected`||t===`subscribeFailed`)&&this.loadingProgressController.show(b.EngineClose,`EngineClose`,!0),t===`streamerAssigned`&&(this.connectionManager.hasConnectedBefore()?(this.loadingProgressController.show(b.EngineConnectionSuccess,`EngineConnectionSuccess`,!1),e.info(`streamerAssigned during reconnect, showing success progress`)):e.info(`streamerAssigned during initial connect, skip progress (will show on webRtcConnected)`)),this.handleSessionForwardEventForQos(t),e.debug(`forward event`,{eventName:t}),this.eventBus.emit(t,n)})}),this.authWorkflow.on(`stateChanged`,t=>{this.handleAuthStateForQos(t.state),e.debug(`auth state changed`,{state:t.state}),this.eventBus.emit(this.Events.AuthStateChanged,t);let n=Ri[t.state];n&&this.eventBus.emit(n,t)}),this.authWorkflow.on(`progress`,e=>{this.handleProgressNotice(e)}),this.authWorkflow.on(`centerEvent`,({eventName:e,payload:t})=>{this.handleCenterEventForQos(e),this.eventBus.emit(e,t)}),this.authWorkflow.on(`failed`,t=>{let n=this.durationFrom(this.authStartedAt);this.authStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`auth_failed`,stage:`auth`,status:`failed`,durationMs:n,errorCode:t.lastError?.code,errorMessage:t.lastError?.message}),e.error(`auth workflow failed`,{error:t.lastError?JSON.stringify(t.lastError):`unknown`}),this.eventBus.emit(this.Events.SessionModeFailed,{mode:this.session.getViewMode(),snapshot:t})}),this.authWorkflow.on(`connected`,e=>{let t=this.durationFrom(this.authStartedAt);this.authStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`auth_success`,stage:`auth`,status:`success`,durationMs:t}),this.eventBus.emit(this.Events.SessionModeReady,{mode:this.session.getViewMode(),snapshot:e})})}on(e,t){this.eventBus.on(e,t)}off(e,t){this.eventBus.off(e,t)}whenReady(){return this.bootstrapPromise}setNetworkAdaptationMode(e){this.handleNetworkModeChange(e)}setNetworkManualLevel(e){this.handleNetworkModeChange(`manual`),this.networkAdaptation.setManualLevel(e)}getNetworkDiagnosticsSnapshot(){return this.latestNetworkDiagnostics??this.networkAdaptation.getDiagnosticsSnapshot()}async disconnectAndWait(){this.connectionManager.getStatus().disconnected||(this.qosMonitor.endSession({reason:`disconnect`}),this.stopRuntimeForLifecycle({disconnectAuth:!1,removeListener:!0}),await this.connectionManager.disconnect())}disconnect(){this.disconnectAndWait()}async connect(){return this.connectionManager.getStatus().disconnected?(await this.connectionManager.prepareConnectAfterDisconnect(),this.session.addResponseEventListener(this.uePushResponseListenerName,this.uePushResponseHandler),this.initializeOptionalRuntimeExtensions(),this.qosMonitor.startSession({reason:`connect`}),this.startAuthFlowWithQos()):this.authWorkflow.getSnapshot()}async restart(){return this.qosMonitor.endSession({reason:`restart`}),this.stopRuntimeForLifecycle({disconnectAuth:!1,stopAgentBridge:!1,removeListener:!0}),this.session.addResponseEventListener(this.uePushResponseListenerName,this.uePushResponseHandler),this.initializeOptionalRuntimeExtensions(),this.qosMonitor.startSession({reason:`restart`}),this.authStartedAt=Date.now(),this.centerConnectStartedAt=void 0,this.webrtcConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`auth_start`,stage:`auth`,status:`start`}),this.connectionManager.restart()}startAuthFlowWithQos(){return this.authStartedAt=Date.now(),this.centerConnectStartedAt=void 0,this.webrtcConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`auth_start`,stage:`auth`,status:`start`}),this.connectionManager.connect()}handleSessionForwardEventForQos(e){if(e===`webRtcConnecting`){this.webrtcConnectStartedAt===void 0&&(this.webrtcConnectStartedAt=Date.now(),this.qosMonitor.recordEvent({eventName:`webrtc_connect_start`,stage:`webrtc`,status:`start`}));return}if(e===`webRtcConnected`){let e=this.durationFrom(this.webrtcConnectStartedAt);this.webrtcConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`webrtc_connected`,stage:`webrtc`,status:`success`,durationMs:e}),this.qosMonitor.recordEvent({eventName:`first_frame_rendered`,stage:`media`,status:`success`,durationMs:e});return}(e===`webRtcDisconnected`||e===`webRtcFailed`)&&(this.webrtcConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`webrtc_disconnected`,stage:`webrtc`,status:`failed`,attrs:{reason:e}}))}handleAuthStateForQos(e){if(e===`centerConnecting`){this.centerConnectStartedAt=Date.now(),this.qosMonitor.recordEvent({eventName:`center_connect_start`,stage:`center`,status:`start`});return}if(e===`centerConnected`){let e=this.durationFrom(this.centerConnectStartedAt);this.centerConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`center_connected`,stage:`center`,status:`success`,durationMs:e});return}e===`webrtcConnecting`&&this.webrtcConnectStartedAt===void 0&&(this.webrtcConnectStartedAt=Date.now(),this.qosMonitor.recordEvent({eventName:`webrtc_connect_start`,stage:`webrtc`,status:`start`}))}handleCenterEventForQos(e){if(this.qosMonitor.recordEvent({eventName:`center_message_received`,stage:`center`,status:`update`,attrs:{fn:e}}),e===this.Events.CenterDisconnected){this.qosMonitor.recordEvent({eventName:`center_disconnected`,stage:`center`,status:`failed`,attrs:{reason:e}});return}if(e===this.Events.CenterConnected&&this.centerConnectStartedAt!==void 0){let e=this.durationFrom(this.centerConnectStartedAt);this.centerConnectStartedAt=void 0,this.qosMonitor.recordEvent({eventName:`center_connected`,stage:`center`,status:`success`,durationMs:e})}}durationFrom(e){if(e===void 0)return;let t=Date.now()-e;return Number.isFinite(t)&&t>=0?t:void 0}handleProgressNotice(e){if(e.kind===`tokenWillExpire`){this.loadingProgressController.showTokenWillExpire(e.message,e.key,e.isClose);return}this.loadingProgressController.show(e.message,e.key,e.isClose)}handleNetworkModeChange(e){this.networkAdaptation.setMode(e);let t={mode:e,ts:Date.now(),diagnostics:this.networkAdaptation.getDiagnosticsSnapshot()};this.eventBus.emit(this.Events.NetworkModeChanged,t)}mountApiFacade(e){let t=this;Object.keys(e).forEach(n=>{this.setApiModule(t,e,n)})}setApiModule(e,t,n){e[n]=t[n]}initializeOptionalRuntimeExtensions(){if(this.agentBridge||!this.agentBridgeOptions?.enabled)return;let e={...this.agentBridgeOptions,serverUrl:this.agentBridgeOptions.serverUrl??`ws://127.0.0.1:8787/sdk3-bridge`},t=sr(this,{runtimeName:e.runtimeName,expose:e.expose,metadata:e.metadata,engineConfig:this.resolvedConfig,getAuthSnapshot:()=>this.authWorkflow.getSnapshot(),mockInvoke:e.mockInvoke});this.agentBridge=new fe(t,e),this.agentBridge.start()}stopRuntimeForLifecycle(e){this.PointEditor.cancelPlacement(),this.GizmosTool.resetRuntime(),e?.stopAgentBridge!==!1&&(this.agentBridge?.stop(`disconnect`),this.agentBridge=void 0),e?.removeListener!==!1&&this.session.removeResponseEventListener(this.uePushResponseListenerName),this.engineStatusCollector.stop(),e?.disconnectAuth!==!1&&this.authWorkflow.disconnect(),this.loadingProgressController.dispose(),this.qosMonitor.flush()}handleUePushResponse(e){let t=e,n;try{if(t=JSON.parse(e),typeof t==`object`&&t){let e=t,r=e.uuid??e.fn;typeof r==`string`&&r.length>0&&(n=r)}}catch{}if(n===`PointEditorGizmoEnded`){this.GizmosTool.finishFromEngine();return}!n&&this.uePushEventNames.has(e)&&(n=e),!(!n||!this.uePushEventNames.has(n))&&this.eventBus.emit(n,t)}getEngineConfig(){return this.resolvedConfig}};export{wn as AGENT_BRIDGE_API_METADATA,dn as API_MODULE_KEYS,fe as AgentRuntimeBridge,jt as Animation,Q as ApiRegistryError,Pi as BuildingFloor,$ as BuildingFloorError,Mt as Camera,Nt as Connect,zi as DTCEngine,Pt as Dlss,w as DlssQuality,Re as FilterMode,Ve as GizmoType,Oe as GizmosTool,Ft as HeatMap,It as HighLighterEffect,zt as Layer,Fe as LayerEnum,Bt as Model,Vt as ModelPOI,Ht as ModelTransform,Le as ModelTransformType,Ut as Navigation,Wt as PathPatrol,kt as PendingValidationSchemaMap,Xt as PointEditor,qt as PointIcon,en as Popup,d as SDKValidationError,nn as Scene,tn as Screen,T as ScreenRenderBitratePreset,Me as ScreenRenderBitratePresetOptions,Ie as Season,rn as SpatialQuery,an as TimeLine,ze as TrainBehavior,on as TrainSimulate,sn as UIPOI,Pe as VideoCodeType,ln as WeatherSystem,cn as WebView,un as apiRegistry,Tn as createAgentBridgeMetadata,Oi as createApiFacade,sr as createBridgeRuntime,Mn as getAgentBridgeMethodSchema,kn as isAgentBridgeMethodExposed,On as isAgentBridgeModuleExposed,En as isAgentBridgeModuleName,jn as listAgentBridgeMethods,An as listAgentBridgeModules,Dn as resolveAgentBridgeExposeConfig};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nnepoch/dtc-sdk",
3
- "version": "3.0.15",
3
+ "version": "3.0.16",
4
4
  "description": "UE frontend SDK built on official Pixel Streaming frontend package",
5
5
  "license": "MIT",
6
6
  "type": "module",