UNPKG

@klever-one/web-sdk

Version:

Web SDK for integrating real-time room management and streaming functionality into web applications

1 lines 351 kB
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).KleverOneSdk={})}(this,function(e){"use strict";const t="initialData",n="azureSttOpenai",s="openai",i="openai",r={1:"av_2",2:"av_5",3:"av_3",4:"av_4",5:"av_1"},a=new Proxy({"en-US":"Introduce yourself in exactly 2–3 sentences. Do not exceed 3 sentences. Be concise and clear about your main role and how you can help.","ko-KR":"자신을 반드시 2~3문장으로만 간단히 소개해주세요. 3문장을 넘기지 말고, 주요 역할과 어떻게 도울 수 있는지만 간결하게 설명해주세요."},{get:(e,t)=>"string"==typeof t&&t in e?e[t]:e["ko-KR"]});var o=(e=>(e.IDLE="IDLE",e.DISCONNECTED="DISCONNECTED",e.CONNECTING="CONNECTING",e.CONNECTED="CONNECTED",e.RECONNECTING="RECONNECTING",e.FAILED="FAILED",e.ALLOCATING="ALLOCATING",e))(o||{}),l=(e=>(e.SUCCESS="SUCCESS",e.ERROR="ERROR",e.IN_PROGRESS="IN_PROGRESS",e))(l||{}),c=(e=>(e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant",e.DATA="data",e))(c||{}),d=(e=>(e.ROOM_CONNECTED="ROOM_CONNECTED",e.ROOM_DISCONNECTED="ROOM_DISCONNECTED",e.ROOM_CONNECTING="ROOM_CONNECTING",e.ROOM_RECONNECTING="ROOM_RECONNECTING",e.ROOM_CONNECTION_FAILED="ROOM_CONNECTION_FAILED",e.ROOM_INFO_UPDATED="ROOM_INFO_UPDATED",e.ROOM_SESSION_TIMEOUT="ROOM_SESSION_TIMEOUT",e.STREAMING_CONNECTED="STREAMING_CONNECTED",e.STREAMING_DISCONNECTED="STREAMING_DISCONNECTED",e.STREAMING_CONNECTING="STREAMING_CONNECTING",e.STREAMING_ALLOCATING="STREAMING_ALLOCATING",e.STREAMING_RECONNECTING="STREAMING_RECONNECTING",e.STREAMING_CONNECTION_FAILED="STREAMING_CONNECTION_FAILED",e.IDLE_TIMEOUT_EXPIRED="IDLE_TIMEOUT_EXPIRED",e.PAGE_UNLOAD="PAGE_UNLOAD",e.LIP_MOTION_START="LIP_MOTION_START",e.END_CONVERSATION="END_CONVERSATION",e.STREAMER_LIST_UPDATED="STREAMER_LIST_UPDATED",e.UNREAL_CONNECTED="UNREAL_CONNECTED",e.RECORDER_ERROR="RECORDER_ERROR",e))(d||{});class h{static instance=null;listeners=new Map;constructor(){Object.values(d).forEach(e=>{this.listeners.set(e,new Set)})}static getInstance(){return h.instance||(h.instance=new h),h.instance}emit(e){const t=this.listeners.get(e.type);t&&t.forEach(t=>{try{t(e)}catch(n){e.type}})}subscribe(e,t){const n=this.listeners.get(e);return n?(n.add(t),()=>n.delete(t)):()=>{}}subscribeToMultiple(e,t){const n=e.map(e=>this.subscribe(e,t));return()=>n.forEach(e=>e())}clear(){this.listeners.forEach(e=>e.clear())}}class u{isDataChannelOpen=!1;isVideoInitialized=!1;isVideoStable=!1;videoFrameCallbackHandle=null;state="Initializing";metrics={networkQuality:-1,bitrate:-1,resolution:null};connectionTimeout=null;callbacks;constructor(e){this.callbacks=e}onDataChannelOpen=()=>{this.isDataChannelOpen=!0,this.checkReadyState()};onVideoInitialized=()=>{this.isVideoInitialized=!0,this.verifyVideoStreamPlayback()};onVideoStalled=()=>{"Ready"===this.state&&(this.state="Stalled",this.callbacks.onStalled())};onVideoResumed=()=>{"Stalled"===this.state&&(this.state="Ready",this.callbacks.onResumed())};onNetworkQualityChanged=e=>{this.metrics.networkQuality=e,this.callbacks.onMetricsUpdate(this.metrics)};onBitrateChanged=e=>{this.metrics.bitrate=e,this.callbacks.onMetricsUpdate(this.metrics)};onResolutionChanged=(e,t)=>{this.metrics.resolution={width:e,height:t},this.callbacks.onMetricsUpdate(this.metrics)};onStreamerListMessage=e=>{const t=e.data?.messageStreamerList?.ids||[];this.callbacks.onStreamerListUpdate(t)};onWebRtcFailed=e=>{this.callbacks.onWebRtcFailed(e)};startConnectionTimer=(e=6e4)=>{"undefined"!=typeof window&&(this.clearConnectionTimer(),this.connectionTimeout=window.setTimeout(()=>{"Ready"!==this.state&&(this.state,this.callbacks.onWebRtcFailed(`스트리밍 연결에 실패했습니다. 타임아웃: ${e}ms.`))},e))};clearConnectionTimer=()=>{"undefined"!=typeof window&&this.connectionTimeout&&(window.clearTimeout(this.connectionTimeout),this.connectionTimeout=null)};reset=()=>{this.isDataChannelOpen=!1,this.isVideoInitialized=!1,this.isVideoStable=!1,this.state="Initializing",this.metrics={networkQuality:-1,bitrate:-1,resolution:null},this.cancelVideoStreamVerification(),this.clearConnectionTimer()};checkReadyState(){"Initializing"===this.state&&this.isDataChannelOpen&&this.isVideoInitialized&&this.isVideoStable&&(this.state="Ready",this.clearConnectionTimer(),this.callbacks.onReady())}cancelVideoStreamVerification(){if("undefined"!=typeof document&&this.videoFrameCallbackHandle){const e=document.getElementById("streamingVideo");if(e)try{e.cancelVideoFrameCallback(this.videoFrameCallbackHandle)}catch(Se){}this.videoFrameCallbackHandle=null}}verifyVideoStreamPlayback(){if("undefined"==typeof document)return;const e=document.getElementById("streamingVideo");if(!e||"function"!=typeof e.requestVideoFrameCallback)return this.isVideoStable=!0,void this.checkReadyState();let t=0;const n=()=>{t++,t>=5?(this.isVideoStable=!0,this.checkReadyState()):this.videoFrameCallbackHandle=e.requestVideoFrameCallback(n)};this.videoFrameCallbackHandle=e.requestVideoFrameCallback(n)}}var m="object"==typeof global&&global&&global.Object===Object&&global,g="object"==typeof self&&self&&self.Object===Object&&self,p=m||g||Function("return this")(),v=p.Symbol,S=Object.prototype,f=S.hasOwnProperty,y=S.toString,C=v?v.toStringTag:void 0;var E=Object.prototype.toString;var T=v?v.toStringTag:void 0;function b(e){return null==e?void 0===e?"[object Undefined]":"[object Null]":T&&T in Object(e)?function(e){var t=f.call(e,C),n=e[C];try{e[C]=void 0;var s=!0}catch(Se){}var i=y.call(e);return s&&(t?e[C]=n:delete e[C]),i}(e):function(e){return E.call(e)}(e)}function w(e){return"symbol"==typeof e||function(e){return null!=e&&"object"==typeof e}(e)&&"[object Symbol]"==b(e)}var R=Array.isArray,M=v?v.prototype:void 0,k=M?M.toString:void 0;function I(e){if("string"==typeof e)return e;if(R(e))return function(e,t){for(var n=-1,s=null==e?0:e.length,i=Array(s);++n<s;)i[n]=t(e[n],n,e);return i}(e,I)+"";if(w(e))return k?k.call(e):"";var t=e+"";return"0"==t&&1/e==-1/0?"-0":t}var P=/\s/;var A=/^\s+/;function x(e){return e?e.slice(0,function(e){for(var t=e.length;t--&&P.test(e.charAt(t)););return t}(e)+1).replace(A,""):e}function L(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}var O=/^[-+]0x[0-9a-f]+$/i,D=/^0b[01]+$/i,_=/^0o[0-7]+$/i,N=parseInt;function F(e){if("number"==typeof e)return e;if(w(e))return NaN;if(L(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=L(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=x(e);var n=D.test(e);return n||_.test(e)?N(e.slice(2),n?2:8):O.test(e)?NaN:+e}var U=function(){return p.Date.now()},B=Math.max,z=Math.min;function H(e,t,n){var s,i,r,a,o,l,c=0,d=!1,h=!1,u=!0;if("function"!=typeof e)throw new TypeError("Expected a function");function m(t){var n=s,r=i;return s=i=void 0,c=t,a=e.apply(r,n)}function g(e){var n=e-l;return void 0===l||n>=t||n<0||h&&e-c>=r}function p(){var e=U();if(g(e))return v(e);o=setTimeout(p,function(e){var n=t-(e-l);return h?z(n,r-(e-c)):n}(e))}function v(e){return o=void 0,u&&s?m(e):(s=i=void 0,a)}function S(){var e=U(),n=g(e);if(s=arguments,i=this,l=e,n){if(void 0===o)return function(e){return c=e,o=setTimeout(p,t),d?m(e):a}(l);if(h)return clearTimeout(o),o=setTimeout(p,t),m(l)}return void 0===o&&(o=setTimeout(p,t)),a}return t=F(t)||0,L(n)&&(d=!!n.leading,r=(h="maxWait"in n)?B(F(n.maxWait)||0,t):r,u="trailing"in n?!!n.trailing:u),S.cancel=function(){void 0!==o&&clearTimeout(o),c=0,s=l=i=o=void 0},S.flush=function(){return void 0===o?a:v(U())},S}var G=0;function W(e){var t,n=++G;return(null==(t=e)?"":I(t))+n}class V{static instance=null;stream=null;mediaState={isStreamReady:!1,isReadyToSend:!1,keepAliveInterval:null};isReadyToSendListeners=[];hasSentResetMessage=!1;eventBus;constructor(){this.setupBeforeUnloadHandler(),this.eventBus=h.getInstance()}static getInstance(){return V.instance||(V.instance=new V),V.instance}setStream(e){this.stream=e,e?(this.setupStreamMediaHandlers(),this.startKeepAlive()):this.stopKeepAlive()}setupStreamMediaHandlers(){this.stream&&this.stream.addResponseEventListener("handleResponseFunction",e=>{this.handleResponseFunction(e)})}setupBeforeUnloadHandler(){"undefined"!=typeof window&&window.addEventListener("beforeunload",()=>{if(this.stream&&!this.hasSentResetMessage)try{this.emitToDataChannel({messageType:"reset",timestamp:Date.now(),sessionId:W("session_"),payload:{}}),this.hasSentResetMessage=!0}catch(e){}})}startKeepAlive(){this.mediaState.keepAliveInterval&&clearInterval(this.mediaState.keepAliveInterval),this.mediaState.keepAliveInterval=setInterval(()=>{this.sendKeepAlive()},3e4)}stopKeepAlive(){this.mediaState.keepAliveInterval&&(clearInterval(this.mediaState.keepAliveInterval),this.mediaState.keepAliveInterval=null)}emitToDataChannel(e){if(this.stream)try{this.stream.emitUIInteraction(e)}catch(t){}}sendKeepAlive(){if(this.stream)try{const e={messageType:"keepAlive",timestamp:Date.now(),sessionId:W("session_"),payload:{}};this.emitToDataChannel(e)}catch(e){}}async handleResponseFunction(e){try{if("UnrealConnected"===e)return void(this.mediaState.isStreamReady&&(this.eventBus.emit({type:d.UNREAL_CONNECTED,timestamp:Date.now()}),this.sendWebConnectedInfo(),this.sendAccountType(),this.setIsReadyToSend(!0)));if("LipmotionStart"===e)return void this.handleLipmotionStart();const t=JSON.parse(e);"updateMessage"===t.messageType&&this.handleUpdateMessage(t)}catch(t){e.includes("UnrealConnected")&&this.setIsReadyToSend(!0)}}sendWebConnectedInfo(){this.stream&&this.emitToDataChannel({Category:"SystemSetting",Type:"WebConnected",Width:"undefined"!=typeof window?window.innerWidth:0})}handleLipmotionStart(){this.eventBus.emit({type:d.LIP_MOTION_START,timestamp:Date.now()})}handleUpdateMessage(e){if("undefined"==typeof window||"undefined"==typeof CustomEvent)return;const{text:t,index:n,isAllCompleted:s}=e.payload,i=new CustomEvent("updateMessage",{detail:{source:"streaming",text:t,index:n,isAllCompleted:s}});window.dispatchEvent(i)}ttsInteractions(e,t,n,s){this.stream&&e&&(this.emitToDataChannel({Category:"VoiceSetting",Type:"TTS",Value:s}),this.emitToDataChannel({Category:"VoiceSetting",Type:"Voice",Value:t}),this.emitToDataChannel({Category:"VoiceSetting",Type:"Language",Value:n}),this.emitToDataChannel({Category:"VoiceSetting",Type:"Script",Value:encodeURIComponent(e)}))}sendStartConversation(){this.stream&&this.emitToDataChannel({Category:"ConversationSetting",Type:"StartConversation"})}endConversation(){if(this.stream)try{this.emitToDataChannel({Category:"ConversationSetting",Type:"EndConversation"}),this.eventBus.emit({type:d.END_CONVERSATION,timestamp:Date.now()})}catch(e){}}autoPlayVideo(){if(this.stream)try{this.stream.play()}catch(e){}}play(){if(this.stream)try{this.stream.play()}catch(e){}}isReadyToSendMessages(){return this.mediaState.isReadyToSend}isStreamReady(){return this.mediaState.isStreamReady}resetIsReadyToSend(){this.setIsReadyToSend(!1)}resetIsStreamReady(){this.setIsStreamReady(!1)}setIsReadyToSend(e){this.mediaState.isReadyToSend!==e&&(this.mediaState.isReadyToSend,this.mediaState.isReadyToSend=e,this.isReadyToSendListeners.forEach(t=>{try{t(e)}catch(n){}}))}setIsStreamReady(e){this.mediaState.isStreamReady!==e&&(this.mediaState.isStreamReady,this.mediaState.isStreamReady=e)}sendAccountType(){this.stream&&this.emitToDataChannel({Category:"SystemSetting",Type:"RoleId",Value:"ROLE_3"})}addIsReadyToSendListener(e){this.removeIsReadyToSendListener(e),this.isReadyToSendListeners.push(e),e(this.mediaState.isReadyToSend)}removeIsReadyToSendListener(e){this.isReadyToSendListeners=this.isReadyToSendListeners.filter(t=>t!==e)}cleanup(){this.stopKeepAlive(),this.setIsReadyToSend(!1),this.isReadyToSendListeners.length=0,this.hasSentResetMessage=!1,this.stream=null}}class Q{static instance=null;stream=null;resizeHandler=null;currentCamera="cam1";containerElement=null;constructor(){}static getInstance(){return Q.instance||(Q.instance=new Q),Q.instance}setupResizeHandler(){"undefined"!=typeof window&&this.containerElement&&this.stream&&(this.resizeHandler=()=>{setTimeout(()=>{const e=this.containerElement?.offsetWidth,t=this.containerElement?.offsetHeight;this.stream&&e&&t&&this.resize(e,t)},100)},window.addEventListener("resize",this.resizeHandler),this.resizeHandler())}setStream(e){this.stream=e}setContainer(e){this.containerElement=e}getContainer(){return this.containerElement}getResizeHandler(){return this.resizeHandler}resetResizeHandler(){this.resizeHandler=null}resize(e,t,n){if(!this.stream)return;const s=e/3*2,i=t/3*2;try{const n=`r.setRes ${s}x${i}`;this.emitToDataChannel({Category:"PageSetting",Type:"WindowSize",Value:n,Width:e,Height:t,CamNum:this.currentCamera})}catch(r){}}handleMouseDown=e=>{if("undefined"==typeof document)return;if(0!==e.button)return;const t=document.getElementById("streamingVideo");t&&(t.style.cursor="default",this.emitUnrealCoordinates(e,"MouseDown"))};handleMouseUp=e=>{if("undefined"==typeof document)return;if(0!==e.button)return;const t=document.getElementById("streamingVideo");t&&(t.style.cursor="default",this.emitUnrealCoordinates(e,"MouseUp"))};emitUnrealCoordinates=(e,t)=>{if("undefined"==typeof document)return;const n=document.getElementById("streamingVideo");if(!n)return;const s=n.videoWidth,i=n.videoHeight,r=n.getBoundingClientRect(),a=r.width,o=r.height,l=Math.max(a/s,o/i),c=s*l,d=i*l,h=(c-a)/2,u=(d-o)/2,m=(e.clientX-r.left+h)/c*s,g=(e.clientY-r.top+u)/d*i;this.emitToDataChannel({Category:"PageSetting",type:t,x:m,y:g})};emitToDataChannel(e){if(this.stream)try{this.stream.emitUIInteraction(e)}catch(t){}}enteredFullpage(){if("undefined"==typeof window||"undefined"==typeof document)return;if(!this.stream)return;const e=window.innerWidth,t=window.innerHeight;this.emitToDataChannel({Category:"PageSetting",Type:"EnteredFullPage"}),this.setCameraConfig("cam2");const n=document.getElementById("streamingVideo");n?.addEventListener("mousedown",this.handleMouseDown),n?.addEventListener("mouseup",this.handleMouseUp),this.resize(e,t)}exitedFullpage(e){if(this.stream)try{if(this.emitToDataChannel({Category:"UI",Type:"ExitedFullpage"}),e.current){const t=e.current.getBoundingClientRect();this.resize(t.width,t.height,"exitFullpage")}}catch(t){}}setCameraConfig(e){this.currentCamera=e}sendAvatarNum(e){if(this.stream)try{this.emitToDataChannel({Category:"AvatarSetting",Type:"AvatarNum",Value:e})}catch(t){}}sendAvatarAppearanceChange(e){if(this.stream)try{if(e.avatarType.includes("Custom")&&!["1","2","3","4","5"].includes(e.avatarAppearanceRefVal1??"")){const t={TaskID:e.avatarAppearanceRefVal1??"",Type:"Custom",Gender:e.gender??"M",selectedAppearance:e.outfit};this.sendAvatarAppearanceChangeInternal({payload:t,isCustom:!0})}else{const t={PresetID:r[e.avatarAppearanceRefVal1??""]??"av_3",Type:"Preset",selectedAppearance:e.outfit};this.sendAvatarAppearanceChangeInternal({payload:t,isCustom:!1})}}catch(t){}}sendAvatarAppearanceChangeInternal({payload:e}){if(this.stream)try{const t={sessionId:W(`#sess_${Date.now()}_`),messageType:"avatar.change",timestamp:Date.now(),payload:e};this.emitToDataChannel({Category:"AvatarSetting",Type:"AvatarAppearance",Value:t})}catch(t){}}generateDigitalHuman(e,t){if(this.stream)try{this.emitToDataChannel({Category:"CustomSetting",Type:"GenerateAvatarHead",TaskId:e,Gender:t})}catch(n){}}sendFailedGenerateAvatarHead(){if(this.stream)try{this.emitToDataChannel({Category:"CustomSetting",Type:"FailedGenerateAvatarHead"})}catch(e){}}sendPlaceBackgroundChange(e){if(this.stream)try{this.emitToDataChannel({Category:"BackgoundSetting",Type:"BackgroundImage",Value:e})}catch(t){}}sendPageSetting(e,t){if(this.stream)try{this.emitToDataChannel({Category:"PageSetting",Type:e,Value:t})}catch(n){}}sendVoiceSetting(e){if(this.stream)try{this.emitToDataChannel({Category:"VoiceSetting",Type:"Voice",Value:e})}catch(t){}}emitUIInteraction(e){if(this.stream)try{this.emitToDataChannel(e)}catch(t){}}reset(){if(this.stream)try{this.emitToDataChannel({Category:"SystemSetting",Type:"Reset"})}catch(e){}}cleanup(){"undefined"!=typeof window&&(this.resizeHandler&&(window.removeEventListener("resize",this.resizeHandler),this.resizeHandler=null),this.stream=null)}}class K{static instance=null;stream=null;application=null;currentStatus=o.IDLE;hasSentResetMessage=!1;onWebRtcConnectedHandler=null;onWebRtcDisconnectedHandler=null;onWebRtcPlayStreamErrorHandler=null;onWebRtcFailedEventHandler=null;beforeUnloadHandler=null;reconnectTimeout=null;hasFailedConnection=!1;reconnectAttempts=0;maxReconnectAttempts=3;isDisconnecting=!1;signalingServerUrl=null;config={};eventBus;statusListeners=[];disconnectListeners=[];eventUnsubscribeFunctions=[];keepAliveInterval=null;uiService;mediaService;readyStateManager;initialAudioTrack=null;lockedAudioElement=null;constructor(){this.eventBus=h.getInstance(),this.uiService=Q.getInstance(),this.mediaService=V.getInstance();const e={onReady:this.onStreamReady,onStalled:this.onStreamStalled,onResumed:this.onStreamResumed,onMetricsUpdate:this.onStreamMetricsUpdate,onStreamerListUpdate:this.onStreamerListUpdate,onWebRtcFailed:this.onWebRtcFailed};this.readyStateManager=new u(e),this.setupEventListeners()}static getInstance(){return K.instance||(K.instance=new K),K.instance}async loadEpicGamesLibraries(){if("undefined"==typeof window)throw new Error("Epic Games libraries can only be loaded in browser environment");const[e,t]=await Promise.all([Promise.resolve().then(()=>ai),Promise.resolve().then(()=>Xa)]);return{Config:e.Config,PixelStreaming:e.PixelStreaming,NumericParameters:e.NumericParameters,Application:t.Application,PixelStreamingApplicationStyle:t.PixelStreamingApplicationStyle,UIElementCreationMode:t.UIElementCreationMode}}onStreamReady=()=>{const e=this.uiService.getContainer(),t=("undefined"!=typeof document?document.getElementById("streaming-container"):null)||e;if(t){const{offsetWidth:e,offsetHeight:n}=t;this.uiService.resize(e,n)}this.mediaService.setIsStreamReady(!0)};onStreamStalled=()=>{};onStreamResumed=()=>{};onStreamMetricsUpdate=e=>{};onStreamerListUpdate=e=>{this.eventBus.emit({type:d.STREAMER_LIST_UPDATED,timestamp:Date.now(),data:{streamerList:e}})};onWebRtcFailed=e=>{const t=e||"연결에 실패했습니다. 잠시 후 다시 시도해 주세요.";this.eventBus.emit({type:d.STREAMING_CONNECTION_FAILED,timestamp:Date.now(),data:{message:t}})};cleanupEventListeners(){this.eventUnsubscribeFunctions.forEach(e=>e()),this.eventUnsubscribeFunctions.length=0,this.beforeUnloadHandler&&"undefined"!=typeof window&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null)}setupEventListeners(){this.cleanupEventListeners();const e=this.eventBus.subscribe(d.ROOM_INFO_UPDATED,e=>{const t=e.data?.roomInfo;t?.resourceInfo?.url&&this.connect(t.resourceInfo.url).catch(e=>{this.setStatus(o.FAILED)})}),t=this.eventBus.subscribe(d.ROOM_DISCONNECTED,()=>{this.disconnect()}),n=this.eventBus.subscribe(d.UNREAL_CONNECTED,()=>{this.stream&&this.setupLockedAudio(this.stream)});this.eventUnsubscribeFunctions.push(e,t,n),"undefined"!=typeof window&&(this.beforeUnloadHandler=()=>{if(this.stream&&!this.hasSentResetMessage)try{this.stream.webSocketController?.webSocket?.readyState===WebSocket.OPEN&&(this.reset(),this.hasSentResetMessage=!0)}catch(e){}},window.addEventListener("beforeunload",this.beforeUnloadHandler))}reset(){this.stream&&this.emitToDataChannel({Category:"SystemSetting",Type:"Reset"})}emitToDataChannel(e){if(this.stream)try{this.stream.emitUIInteraction(e)}catch(t){}}setContainer(e){this.uiService.setContainer(e),this.application?.rootElement&&e&&(e.appendChild(this.application.rootElement),this.uiService.setupResizeHandler())}forceResetContainer(e){const t=this.uiService.getContainer();if(this.application?.rootElement)try{t&&t.contains(this.application.rootElement)&&t.removeChild(this.application.rootElement),this.application.rootElement.parentElement&&this.application.rootElement.parentElement.removeChild(this.application.rootElement)}catch(n){}this.uiService.setContainer(e)}async connect(e,t={}){if(this.currentStatus!==o.CONNECTING&&this.currentStatus!==o.CONNECTED){this.signalingServerUrl=e,this.config=t,this.setStatus(o.CONNECTING);try{await this.createStreamingConnection()}catch(n){throw this.setStatus(o.FAILED),n}}}async createStreamingConnection(){if(!this.signalingServerUrl)throw new Error("Signaling server URL not provided");const e=await this.loadEpicGamesLibraries(),t=new e.Config({useUrlParams:!0});t.setTextSetting("ss",this.signalingServerUrl),t.setNumericSetting(e.NumericParameters.MaxReconnectAttempts,0),t.setFlagEnabled("KeyboardInput",this.config.setKeyboardEnabled??!1),t.setFlagEnabled("HoveringMouse",!1),t.setFlagEnabled("MouseInput",!1);const n=new e.PixelStreamingApplicationStyle;n.applyStyleSheet(),this.stream=new e.PixelStreaming(t),this.uiService.setStream(this.stream),this.application=new e.Application({stream:this.stream,onColorModeChanged:e=>n.setColorMode(e),fullScreenControlsConfig:{creationMode:e.UIElementCreationMode.Disable},settingsPanelConfig:{isEnabled:!1,visibilityButtonConfig:{creationMode:e.UIElementCreationMode.Disable}},statsPanelConfig:{isEnabled:!1,visibilityButtonConfig:{creationMode:e.UIElementCreationMode.Disable}},videoQpIndicatorConfig:{disableIndicator:!0}});const s=this.uiService.getContainer();if(s&&this.application.rootElement&&(s.innerHTML="",s.appendChild(this.application.rootElement),"undefined"!=typeof document)){const e=document.getElementById("streamingVideo");e&&(e.style.objectFit="cover",document.addEventListener("pointerlockchange",()=>{document.exitPointerLock()}))}this.stream._onDisconnect=()=>{this.setStatus(o.DISCONNECTED),this.notifyDisconnectListeners(),!this.isDisconnecting&&this.hasFailedConnection&&this.scheduleReconnect()},this.registerEventHandlers();try{this.readyStateManager.startConnectionTimer(),this.stream.connect(),this.keepAliveInterval&&clearInterval(this.keepAliveInterval),this.keepAliveInterval=setInterval(()=>{try{this.stream?.webSocketController?.webSocket?.readyState===WebSocket.OPEN&&this.stream.webSocketController.webSocket.send(JSON.stringify({type:"ping"}))}catch(e){}},3e4)}catch(i){throw this.hasFailedConnection=!0,this.setStatus(o.FAILED),i}}registerEventHandlers(){this.stream&&(this.onWebRtcConnectedHandler=()=>{this.hasFailedConnection=!1,this.reconnectAttempts=0,this.setStatus(o.CONNECTED)},this.stream.addEventListener("webRtcConnected",this.onWebRtcConnectedHandler),this.onWebRtcDisconnectedHandler=()=>{this.isDisconnecting||this.setStatus(o.DISCONNECTED)},this.stream.addEventListener("webRtcDisconnected",this.onWebRtcDisconnectedHandler),this.onWebRtcPlayStreamErrorHandler=()=>{},this.stream.addEventListener("playStreamError",this.onWebRtcPlayStreamErrorHandler),this.onWebRtcFailedEventHandler=()=>{this.readyStateManager.onWebRtcFailed("Failure reported by Streaming library.")},this.stream.addEventListener("webRtcFailed",this.onWebRtcFailedEventHandler),this.stream.addEventListener("videoInitialized",this.readyStateManager.onVideoInitialized),this.stream.addEventListener("dataChannelOpen",this.readyStateManager.onDataChannelOpen),this.stream.addEventListener("streamerListMessage",this.readyStateManager.onStreamerListMessage))}unregisterEventHandlers(){this.stream&&(this.onWebRtcConnectedHandler&&(this.stream.removeEventListener("webRtcConnected",this.onWebRtcConnectedHandler),this.onWebRtcConnectedHandler=null),this.onWebRtcDisconnectedHandler&&(this.stream.removeEventListener("webRtcDisconnected",this.onWebRtcDisconnectedHandler),this.onWebRtcDisconnectedHandler=null),this.onWebRtcPlayStreamErrorHandler&&(this.stream.removeEventListener("playStreamError",this.onWebRtcPlayStreamErrorHandler),this.onWebRtcPlayStreamErrorHandler=null),this.onWebRtcFailedEventHandler&&(this.stream.removeEventListener("webRtcFailed",this.onWebRtcFailedEventHandler),this.onWebRtcFailedEventHandler=null),this.stream.removeEventListener("videoInitialized",this.readyStateManager.onVideoInitialized),this.stream.removeEventListener("dataChannelOpen",this.readyStateManager.onDataChannelOpen),this.stream.removeEventListener("streamerListMessage",this.readyStateManager.onStreamerListMessage))}setupLockedAudio(e){const t=e,n=t._webRtcController?.streamController?.audioElement;if(!n)return;const s=n.srcObject;if(!s)return;const i=s.getAudioTracks();i.length>0&&!this.initialAudioTrack&&(this.initialAudioTrack=i[0],this.createLockedAudio(this.initialAudioTrack));s.addEventListener("addtrack",e=>{"audio"!==e.track.kind||this.initialAudioTrack||(this.initialAudioTrack=e.track,this.createLockedAudio(this.initialAudioTrack))})}createLockedAudio(e){"undefined"!=typeof document&&(this.lockedAudioElement=document.createElement("audio"),this.lockedAudioElement.autoplay=!0,this.lockedAudioElement.controls=!1,this.lockedAudioElement.muted=!1,this.lockedAudioElement.srcObject=new MediaStream([e]),document.body.appendChild(this.lockedAudioElement))}disconnect(){if(!this.isDisconnecting)if(this.isDisconnecting=!0,this.stream)try{this.reset(),setTimeout(()=>{this.performDisconnect()},100)}catch(e){this.performDisconnect()}else this.performDisconnect()}performDisconnect(){if(this.readyStateManager.reset(),this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null),this.initialAudioTrack){try{this.initialAudioTrack.stop()}catch(e){}this.initialAudioTrack=null}if(this.lockedAudioElement&&(this.lockedAudioElement.srcObject=null,this.lockedAudioElement.remove(),this.lockedAudioElement=null),this.keepAliveInterval&&(clearInterval(this.keepAliveInterval),this.keepAliveInterval=null),this.uiService.getResizeHandler()&&"undefined"!=typeof window&&(window.removeEventListener("resize",this.uiService.getResizeHandler()),this.uiService.resetResizeHandler()),this.stream&&(this.unregisterEventHandlers(),this.stream.disconnect(),this.stream.webSocketController?.webSocket&&this.stream.webSocketController.webSocket.close(),this.stream=null),this.application)try{const e=this.uiService.getContainer();e&&this.application.rootElement&&e.removeChild(this.application.rootElement),this.application=null}catch(t){}this.uiService.setContainer(null),this.setStatus(o.DISCONNECTED),this.notifyDisconnectListeners(),this.cleanupEventListeners(),this.isDisconnecting=!1,this.reconnectAttempts=0,this.hasFailedConnection=!1,this.hasSentResetMessage=!1}async reconnect(){this.eventBus.emit({type:d.STREAMING_RECONNECTING,timestamp:Date.now()})}scheduleReconnect(){if(this.reconnectAttempts>=this.maxReconnectAttempts)return void this.setStatus(o.FAILED);const e=1e3*Math.pow(2,this.reconnectAttempts);this.reconnectAttempts,this.reconnectTimeout=setTimeout(async()=>{this.reconnectAttempts++,this.setStatus(o.CONNECTING);try{this.signalingServerUrl&&await this.connect(this.signalingServerUrl,this.config)}catch(e){this.scheduleReconnect()}},e)}setStatus(e){if(this.currentStatus===e)return;this.currentStatus,this.currentStatus=e;const t=this.getConnectionEventType(e);this.eventBus.emit({type:t,timestamp:Date.now(),data:{status:e}}),this.statusListeners.length,this.statusListeners.forEach((t,n)=>{try{t(e)}catch(s){}})}getConnectionEventType(e){switch(e){case o.CONNECTED:return d.STREAMING_CONNECTED;case o.DISCONNECTED:return d.STREAMING_DISCONNECTED;case o.CONNECTING:return d.STREAMING_CONNECTING;case o.ALLOCATING:return d.STREAMING_ALLOCATING;case o.FAILED:return d.STREAMING_CONNECTION_FAILED;default:return d.STREAMING_DISCONNECTED}}notifyDisconnectListeners(){this.disconnectListeners.forEach(e=>{try{e()}catch(t){}})}updateInputOptions(e,t){this.stream&&(this.stream.config.setFlagEnabled("MouseInput",e),this.stream.config.setFlagEnabled("KeyboardInput",t)),this.config.setMouseEnabled=e,this.config.setKeyboardEnabled=t}getStatus(){return this.currentStatus}getStream(){return this.stream}getUIService(){return this.uiService}addStatusListener(e){this.statusListeners.push(e),e(this.currentStatus)}removeStatusListener(e){this.statusListeners=this.statusListeners.filter(t=>t!==e)}addDisconnectListener(e){this.disconnectListeners.push(e)}removeDisconnectListener(e){this.disconnectListeners=this.disconnectListeners.filter(t=>t!==e)}addResponseListener(e){this.stream&&this.stream.addResponseEventListener("handle_responses",e)}removeResponseListener(e){this.stream&&this.stream.removeResponseEventListener("handle_responses")}}class j{static instance=null;connectionService;mediaService;uiService;constructor(){this.connectionService=K.getInstance(),this.mediaService=V.getInstance(),this.uiService=Q.getInstance(),this.setupServiceCoordination()}static getInstance(){return j.instance||(j.instance=new j),j.instance}setupServiceCoordination(){this.connectionService.addStatusListener(e=>{const t=this.connectionService.getStream();e===o.CONNECTED&&t?(this.mediaService.setStream(t),this.uiService.setStream(t)):e===o.DISCONNECTED&&(this.mediaService.setStream(null),this.uiService.setStream(null))}),this.connectionService.addDisconnectListener(()=>{this.mediaService.cleanup()})}setContainer(e){this.connectionService.setContainer(e)}forceResetContainer(e){this.connectionService.forceResetContainer(e)}async connect(e,t={}){const n={setKeyboardEnabled:t.setKeyboardEnabled,setMouseEnabled:t.setMouseEnabled,initStreamingConfig:t.initStreamingConfig};return this.connectionService.connect(e,n)}disconnect(){this.connectionService.disconnect(),this.mediaService.cleanup(),this.uiService.cleanup()}async reconnect(){return this.connectionService.reconnect()}updateInputOptions(e,t){this.connectionService.updateInputOptions(e,t)}getStatus(){return this.connectionService.getStatus()}getStream(){return this.connectionService.getStream()}getApplication(){return this.connectionService.application}getConnectionService(){return this.connectionService}getContainer(){return this.uiService.getContainer()}addStatusListener(e){this.connectionService.addStatusListener(e)}removeStatusListener(e){this.connectionService.removeStatusListener(e)}addDisconnectListener(e){this.connectionService.addDisconnectListener(e)}removeDisconnectListener(e){this.connectionService.removeDisconnectListener(e)}ttsInteractions(e,t,n,s){this.mediaService.ttsInteractions(e,t,n,s)}sendStartConversation(){this.mediaService.sendStartConversation()}endConversation(){this.mediaService.endConversation()}autoPlayVideo(){this.mediaService.autoPlayVideo()}play(){this.mediaService.play()}isReadyToSendMessages(){return this.mediaService.isReadyToSendMessages()}resetIsReadyToSend(){this.mediaService.resetIsReadyToSend()}resetIsStreamReady(){this.mediaService.resetIsStreamReady()}addIsReadyToSendListener(e){this.mediaService.addIsReadyToSendListener(e)}removeIsReadyToSendListener(e){this.mediaService.removeIsReadyToSendListener(e)}resize(e,t,n){this.uiService.resize(e,t,n)}enteredFullpage(){this.uiService.enteredFullpage()}exitedFullpage(e){this.uiService.exitedFullpage(e)}sendAvatarNum(e){this.uiService.sendAvatarNum(e)}sendAvatarAppearanceChange(e){this.uiService.sendAvatarAppearanceChange(e)}generateDigitalHuman(e,t){this.uiService.generateDigitalHuman(e,t)}sendFailedGenerateAvatarHead(){this.uiService.sendFailedGenerateAvatarHead()}sendPlaceBackgroundChange(e){this.uiService.sendPlaceBackgroundChange(e)}sendPageSetting(e,t){this.uiService.sendPageSetting(e,t)}sendVoiceSetting(e){this.uiService.sendVoiceSetting(e)}reset(){this.uiService.reset()}async handleResponseFunction(e){return this.mediaService.handleResponseFunction(e)}emitUIInteraction(e){this.uiService.emitUIInteraction(e)}cleanup(){this.disconnect()}static destroyInstance(){j.instance&&(j.instance.cleanup(),j.instance=null)}}class q{static instance=null;autoDisconnectTimer=null;idleTimer=null;IDLE_TIMEOUT=3e5;AUTO_DISCONNECT_INTERVAL=5e3;userActivityEventsRegistered=!1;eventBus;userEvents=["mousemove","keydown","click","scroll","wheel","contextmenu","focus","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointercancel","dragstart","dragend","drop","input","change","submit","paste","copy","cut","select","selectstart","selectionchange","gesturestart","gesturechange","gestureend","orientationchange"];userEventHandler;boundHandleVisibilityChange;boundHandleBeforeUnload;constructor(){this.eventBus=h.getInstance(),this.userEventHandler=H(()=>this.onUserActivity(),200),this.boundHandleVisibilityChange=this.handleVisibilityChange.bind(this),this.boundHandleBeforeUnload=this.handleBeforeUnload.bind(this)}static getInstance(){return q.instance||(q.instance=new q),q.instance}startIdleTimer(){this.clearIdleTimer(),this.IDLE_TIMEOUT;const e=Date.now();this.idleTimer=setInterval(()=>{Date.now()-e>=this.IDLE_TIMEOUT&&(this.clearIdleTimer(),this.startAutoDisconnectTimer())},1e3)}resetIdleTimer(){this.clearIdleTimer(),this.startIdleTimer()}clearIdleTimer(){this.idleTimer&&(clearInterval(this.idleTimer),this.idleTimer=null)}startAutoDisconnectTimer(){this.stopAutoDisconnectTimer();const e=Date.now();this.autoDisconnectTimer=setInterval(()=>{Date.now()-e>=this.AUTO_DISCONNECT_INTERVAL&&(this.autoDisconnectTimer&&(clearInterval(this.autoDisconnectTimer),this.autoDisconnectTimer=null),this.eventBus.emit({type:d.IDLE_TIMEOUT_EXPIRED,timestamp:Date.now()}))},1e3),this.AUTO_DISCONNECT_INTERVAL}stopAutoDisconnectTimer(){this.autoDisconnectTimer&&(clearInterval(this.autoDisconnectTimer),this.autoDisconnectTimer=null)}registerUserActivityEvents(){"undefined"!=typeof window&&"undefined"!=typeof document&&"undefined"!=typeof navigator&&(this.userActivityEventsRegistered||(this.userActivityEventsRegistered=!0,this.userEvents.forEach(e=>window.addEventListener(e,this.userEventHandler)),document.addEventListener("visibilitychange",this.boundHandleVisibilityChange),window.addEventListener("online",this.userEventHandler),window.addEventListener("offline",this.userEventHandler),"connection"in navigator&&navigator.connection?.addEventListener("change",this.userEventHandler),window.addEventListener("beforeunload",this.boundHandleBeforeUnload),window.addEventListener("pagehide",this.boundHandleBeforeUnload)))}handleVisibilityChange(){"undefined"!=typeof document&&(document.hidden||this.onUserActivity())}handleBeforeUnload(){this.eventBus.emit({type:d.PAGE_UNLOAD,timestamp:Date.now()})}removeUserActivityEvents(){"undefined"!=typeof window&&"undefined"!=typeof document&&this.userActivityEventsRegistered&&(this.userEvents.forEach(e=>window.removeEventListener(e,this.userEventHandler)),document.removeEventListener("visibilitychange",this.boundHandleVisibilityChange),window.removeEventListener("online",this.userEventHandler),window.removeEventListener("offline",this.userEventHandler),"undefined"!=typeof navigator&&"connection"in navigator&&navigator.connection?.removeEventListener("change",this.userEventHandler),window.removeEventListener("beforeunload",this.boundHandleBeforeUnload),window.removeEventListener("pagehide",this.boundHandleBeforeUnload),this.userActivityEventsRegistered=!1)}onUserActivity(){this.userActivityEventsRegistered&&(this.stopAutoDisconnectTimer(),this.resetIdleTimer())}clearAllTimers(){this.clearIdleTimer(),this.stopAutoDisconnectTimer(),this.removeUserActivityEvents(),this.userEventHandler.cancel()}getTimerStatus(){return{idleTimerActive:null!==this.idleTimer,autoDisconnectTimerActive:null!==this.autoDisconnectTimer,eventsRegistered:this.userActivityEventsRegistered,idleTimeout:this.IDLE_TIMEOUT,autoDisconnectInterval:this.AUTO_DISCONNECT_INTERVAL}}}const X="klever_location_info",$=3e5,J=()=>{if("undefined"==typeof sessionStorage)return null;try{const e=sessionStorage.getItem(X);if(e){const t=JSON.parse(e),n=Date.now();if(t.timestamp&&n-t.timestamp<36e5)return t}}catch(e){}return null},Y=e=>{if("undefined"!=typeof sessionStorage)try{e.timestamp=Date.now(),sessionStorage.setItem(X,JSON.stringify(e))}catch(t){}};let Z=null,ee=null,te=null,ne="undefined"==typeof navigator||navigator.onLine;const se=async()=>{try{const e=await fetch("https://api.ipify.org?format=json",{signal:AbortSignal.timeout(3e3)});if(e.ok){return(await e.json()).ip}}catch(e){}return null},ie=async()=>{if("undefined"!=typeof sessionStorage)try{sessionStorage.removeItem(X)}catch(e){}return Z=null,re()},re=()=>(Z||(Z=(async()=>{const e=J();if(e)return e;const t={},n=[{url:"https://free.freeipapi.com/api/json",parser:e=>({country:e.countryCode,timezone:e.timeZones?.[0],ip:e.ipAddress})},{url:"https://api.ipify.org?format=json",parser:e=>({ip:e.ip})}];for(const i of n)try{const e=await fetch(i.url,{signal:AbortSignal.timeout(5e3)});if(e.ok){const n=await e.json(),s=i.parser(n);return Object.assign(t,s),Y(t),t}if(429===e.status){i.url;continue}}catch(s){i.url;continue}return Y(t),t})().then(e=>e).catch(e=>({}))),Z),ae=()=>{ee&&(clearInterval(ee),ee=null),te&&(clearInterval(te),te=null)};"undefined"!=typeof window&&(re(),(()=>{if("undefined"==typeof window||"undefined"==typeof document||"undefined"==typeof navigator)return;const e=()=>{const e=navigator.onLine;e&&!ne&&ie(),ne=e};window.addEventListener("online",e),window.addEventListener("offline",e),document.addEventListener("visibilitychange",async()=>{if(!document.hidden){const e=J();if(e&&e.ip){const t=await se();t&&t!==e.ip&&ie()}}}),te=setInterval(async()=>{if(document.hidden||!navigator.onLine)return;const e=J();if(e&&e.ip){const t=await se();t&&t!==e.ip&&ie()}},3e4),ee=setInterval(()=>{const e=J();e&&e.timestamp&&Date.now()-e.timestamp>$&&ie()},$)})(),window.addEventListener("beforeunload",ae));class oe{static instance=null;#e=o.IDLE;#t=null;apiKey;templatePersonaId;personaId;userId;onMessageReceived;roomId=null;token=null;checkRoom=null;webSocket=null;reconnectAttempts=0;maxReconnectAttempts=3;reconnectTimeout=null;STUDIO_API_PREFIX;STUDIO_ROOM_PREFIX;API_KEY_HEADER="X-Nlp-Api-Key";BASE_URL="https://kleverone-apigw.klever-one.com/kleverone-studio";heartbeatInterval=null;HEARTBEAT_INTERVAL=3e4;HEARTBEAT_MESSAGE="ping";connectionManager;eventBus;statusListeners=[];roomInfoListeners=[];disconnectListeners=[];errorHandlers=[];idleTimeoutHandler;pageUnloadHandler;unsubscribeIdleTimeout;unsubscribePageUnload;constructor(e,t,n,s,i){this.apiKey=e,this.templatePersonaId=t,this.personaId=n,this.userId=s,this.onMessageReceived=i,this.STUDIO_API_PREFIX=`${this.BASE_URL}/api`,this.STUDIO_ROOM_PREFIX=`${this.BASE_URL}/ws`,this.eventBus=h.getInstance(),this.connectionManager=q.getInstance(),this.idleTimeoutHandler=()=>{this.disconnect()},this.pageUnloadHandler=()=>{this.disconnect()},this.unsubscribeIdleTimeout=this.eventBus.subscribe(d.IDLE_TIMEOUT_EXPIRED,this.idleTimeoutHandler),this.unsubscribePageUnload=this.eventBus.subscribe(d.PAGE_UNLOAD,this.pageUnloadHandler)}static hasInstance(){return null!==oe.instance}static getInstance(e,t,n,s,i){if(oe.instance)e&&oe.instance.apiKey!==e&&(oe.instance.apiKey=e),void 0!==t&&(oe.instance.templatePersonaId=t),void 0!==n&&(oe.instance.personaId=n),void 0!==s&&(oe.instance.userId=s);else{if(!e)throw new Error("RoomManager가 초기화되지 않았습니다. API 키가 필요합니다.");oe.instance=new oe(e,t??null,n??null,s??null,i)}return i&&(oe.instance.onMessageReceived=i),oe.instance}get connectionStatus(){return this.#e}get roomInfo(){return this.#t}addStatusListener(e){this.statusListeners.push(e),e(this.#e)}removeStatusListener(e){this.statusListeners=this.statusListeners.filter(t=>t!==e)}addRoomInfoListener(e){this.roomInfoListeners.push(e),e(this.#t)}removeRoomInfoListener(e){this.roomInfoListeners=this.roomInfoListeners.filter(t=>t!==e)}addDisconnectListener(e){this.disconnectListeners.push(e)}removeDisconnectListener(e){this.disconnectListeners=this.disconnectListeners.filter(t=>t!==e)}addErrorHandler(e){return this.errorHandlers.push(e),()=>{const t=this.errorHandlers.indexOf(e);t>-1&&this.errorHandlers.splice(t,1)}}setConnectionStatus(e){let t;switch(this.#e=e,this.statusListeners.forEach(t=>t(e)),e){case o.CONNECTED:t=d.ROOM_CONNECTED;break;case o.DISCONNECTED:t=d.ROOM_DISCONNECTED;break;case o.CONNECTING:t=d.ROOM_CONNECTING;break;case o.RECONNECTING:t=d.ROOM_RECONNECTING;break;default:return}this.eventBus.emit({type:t,timestamp:Date.now(),data:{status:e}})}setRoomInfo(e){this.#t=e,this.roomInfoListeners.forEach(t=>t(e)),this.eventBus.emit({type:d.ROOM_INFO_UPDATED,timestamp:Date.now(),data:{roomInfo:e}}),e&&this.connectionManager.startIdleTimer()}notifyStreamingManagerDisconnect(){}handleStreamingDisconnect(){this.#e,o.CONNECTED}async createRoom({isReconnect:e}){if(this.#e!==o.IDLE&&this.#e!==o.DISCONNECTED)try{this.setConnectionStatus(e?o.RECONNECTING:o.CONNECTING);const t=await re(),n=await fetch(`${this.STUDIO_API_PREFIX}/no-auth/room/create-room`,{method:"POST",headers:{"Content-Type":"application/json","X-Client-IP":t?.ip?t?.ip:"",[this.API_KEY_HEADER]:this.apiKey},body:JSON.stringify({})});if(!n.ok){if(401===n.status){const e=await n.json();this.handleError(e.message)}else this.handleError("방 생성에 실패했습니다.");return n.status,void this.setConnectionStatus(o.DISCONNECTED)}const s=await n.json();if(!s.success||!s.data)return this.handleError("서버 응답이 올바르지 않습니다."),void this.setConnectionStatus(o.DISCONNECTED);this.roomId=s.data.roomId,this.token=s.data.token,this.roomId}catch(t){this.handleError("방 생성 중 오류가 발생했습니다."),this.setConnectionStatus(o.DISCONNECTED)}}async checkRoomStatus(){if(this.roomId)try{const e=await fetch(`${this.STUDIO_API_PREFIX}/no-auth/room/check-room/${this.roomId}`,{method:"GET",headers:{[this.API_KEY_HEADER]:this.apiKey}});if(!e.ok)return this.handleError("방 상태 확인에 실패했습니다."),void e.status;const t=await e.json();if(!t.success||!t.data)return void this.handleError("서버 응답이 올바르지 않습니다.");this.checkRoom=t.data.exists,this.checkRoom}catch(e){this.handleError("방 상태 확인 중 오류가 발생했습니다.")}}async connectRoom(){if(this.roomId&&this.token&&this.#e!==o.CONNECTED){this.setConnectionStatus(o.CONNECTING);try{const e=await fetch(`${this.STUDIO_API_PREFIX}/no-auth/room/connect`,{method:"POST",headers:{"Content-Type":"application/json",[this.API_KEY_HEADER]:this.apiKey},body:JSON.stringify({roomId:this.roomId,token:this.token})});if(!e.ok)return this.handleError("방 연결에 실패했습니다."),e.status,void this.setConnectionStatus(o.DISCONNECTED);const t=await e.json();if(!t.success||!t.data){const e=t.message||"서버 응답이 올바르지 않습니다.";return this.handleError(e),void this.setConnectionStatus(o.DISCONNECTED)}this.roomId,await this.waitForWebSocketConnection(t.data.address)}catch(e){this.handleError("방 연결 중 오류가 발생했습니다."),this.setConnectionStatus(o.DISCONNECTED)}}}requestInitialData(){this.sendMessage({actionName:t,payload:{id:this.templatePersonaId??this.personaId??"-1",userId:this.userId??null,type:this.templatePersonaId?"template":"persona"}}),this.eventBus.emit({type:d.STREAMING_CONNECTING,timestamp:Date.now()})}handleWebSocketOpen(e){this.setConnectionStatus(o.CONNECTED),this.requestInitialData(),this.startHeartbeat(),this.connectionManager.registerUserActivityEvents(),this.connectionManager.startIdleTimer()}handleWebSocketMessage(e){e.data;try{const n=JSON.parse(e.data);if(n.action===t){if(!this.handleInitialDataMessage(n))return}else if("timeout"===n.kind&&"roomSessionTimeout"===n.action)return void("string"==typeof n.body&&this.eventBus.emit({type:d.ROOM_SESSION_TIMEOUT,timestamp:Date.now(),data:{message:n.body}}))}catch(n){}this.onMessageReceived?.(e)}handleInitialDataMessage(e){return"string"==typeof e.body?(e.body.startsWith("Pending")?(this.eventBus.emit({type:d.STREAMING_ALLOCATING,timestamp:Date.now()}),e.body):e.body.startsWith("Failed")&&(e.body,this.eventBus.emit({type:d.STREAMING_CONNECTION_FAILED,timestamp:Date.now()})),!1):(this.setRoomInfo(e.body),!0)}handleError(e){const t=new Error(e||"Room error");this.errorHandlers.forEach(e=>{try{e(t)}catch(n){}})}handleWebSocketError(e){this.setConnectionStatus(o.DISCONNECTED),this.#e!==o.DISCONNECTED&&this.attemptReconnect()}handleWebSocketClose(e){this.stopHeartbeat(),this.setConnectionStatus(o.DISCONNECTED),this.disconnectListeners.forEach(e=>e()),1e3!==e.code&&this.notifyStreamingManagerDisconnect()}attemptReconnect(){if(this.#e===o.RECONNECTING||this.reconnectAttempts>=this.maxReconnectAttempts||this.#e===o.DISCONNECTED)return void(this.#e===o.RECONNECTING||(this.reconnectAttempts,this.maxReconnectAttempts));this.reconnectAttempts++,this.reconnectAttempts,this.maxReconnectAttempts;const e=1e3*Math.pow(2,this.reconnectAttempts-1);this.reconnectTimeout&&clearTimeout(this.reconnectTimeout),this.reconnectTimeout=setTimeout(()=>{this.setConnectionStatus(o.RECONNECTING),this.initializeRoom({isReconnect:!0}).catch(e=>{this.setConnectionStatus(o.DISCONNECTED),this.reconnectAttempts>=this.maxReconnectAttempts&&(this.setConnectionStatus(o.DISCONNECTED),this.notifyStreamingManagerDisconnect())})},e)}initiateWebSocketConnection(e){this.webSocket&&this.webSocket.close(),this.webSocket=new WebSocket(`${this.STUDIO_ROOM_PREFIX}${e}?roomId=${this.roomId}&token=${this.token}`),this.webSocket.onopen=e=>this.handleWebSocketOpen(e),this.webSocket.onmessage=e=>this.handleWebSocketMessage(e),this.webSocket.onerror=e=>this.handleWebSocketError(e),this.webSocket.onclose=e=>this.handleWebSocketClose(e)}async waitForWebSocketConnection(e){return new Promise((t,n)=>{this.initiateWebSocketConnection(e);let s=0;const i=setInterval(()=>{this.#e===o.CONNECTED&&(clearInterval(i),t()),s++,s>=10&&(clearInterval(i),this.setConnectionStatus(o.DISCONNECTED),this.attemptReconnect(),n(new Error("WebSocket connection timeout")))},500)})}async reconnect(){if(this.#e!==o.RECONNECTING&&this.apiKey){this.roomId=null,this.token=null,this.#t=null;try{await this.initializeRoom({isReconnect:!0}),this.setConnectionStatus(o.CONNECTED),this.reconnectAttempts=0;const e=this.#t;e?.resourceInfo?.url&&this.setRoomInfo(e)}catch(e){if(this.setConnectionStatus(o.DISCONNECTED),this.reconnectAttempts++,this.reconnectAttempts<this.maxReconnectAttempts){const e=1e3*Math.pow(2,this.reconnectAttempts);this.reconnectAttempts,this.reconnectTimeout&&clearTimeout(this.reconnectTimeout),this.reconnectTimeout=setTimeout(()=>{this.setConnectionStatus(o.RECONNECTING),this.initializeRoom({isReconnect:!0}).catch(e=>{this.setConnectionStatus(o.DISCONNECTED),this.reconnectAttempts++,this.reconnectAttempts,this.maxReconnectAttempts,this.reconnectAttempts>=this.maxReconnectAttempts&&this.setConnectionStatus(o.DISCONNECTED)})},e)}else this.maxReconnectAttempts,this.reconnectAttempts=0,this.setConnectionStatus(o.DISCONNECTED)}}}static throttledInitializeRoom=function(e,t,n){var s=!0,i=!0;if("function"!=typeof e)throw new TypeError("Expected a function");return L(n)&&(s=!("leading"in n)&&s,i="trailing"in n||i),H(e,t,{leading:s,maxWait:t,trailing:i})}(async(e,t)=>{await e._initializeRoom(t)},32,{leading:!1,trailing:!0});async _initializeRoom({isReconnect:e=!1}){if(this.#e!==o.CONNECTING&&this.#e!==o.RECONNECTING)try{this.setConnectionStatus(e?o.RECONNECTING:o.CONNECTING),await this.createRoom({isReconnect:e}),await this.checkRoomStatus(),await this.connectRoom(),this.#e,o.CONNECTED}catch(t){throw t}}async initializeRoom({isReconnect:e=!1}){return oe.throttledInitializeRoom(this,{isReconnect:e})}async sendMessage(e){if(this.webSocket&&this.webSocket.readyState===WebSocket.OPEN)this.sendMessageInternal(e);else try{if(await this.reconnect(),this.#e!==o.CONNECTED)throw new Error("Failed to reconnect WebSocket");this.sendMessageInternal(e)}catch(t){throw t}}sendMessageInternal(e){try{if(e instanceof Blob||e instanceof ArrayBuffer||ArrayBuffer.isView(e))this.webSocket.send(e);else if("object"==typeof e){const t=this.generateEventId(),n={...e,eventId:t},s=JSON.stringify(n);this.webSocket.send(s)}else"string"==typeof e&&this.webSocket.send(e)}catch(t){throw t}}createMessageBuffer({action:e,payload:t,header:n}){const s=(new TextEncoder).encode(e),i=new Uint8Array(4);new DataView(i.buffer).setUint32(0,s.length,!0);const r=n||new Uint8Array(0),a=new Uint8Array(4);new DataView(a.buffer).setUint32(0,r.length,!0);const o=i.length+s.length+a.length+r.length+t.length,l=new Uint8Array(o);let c=0;return l.set(i,c),c+=i.length,l.set(s,c),c+=s.length,l.set(a,c),c+=a.length,l.set(r,c),c+=r.length,l.set(t,c),l}synchronizedSendMessage(e){try{if(!this.webSocket)return;if(this.webSocket.readyState!==WebSocket.OPEN)return void this.webSocket.readyState;e()}catch(t){}}async sendDataInChunks({payload:e,actionName:t,chunkSize:n=16e3}){try{const s=this.generateEventId(),i=Math.ceil(e.length/n);e.length;for(let r=0;r<i;r++){const a=r*n,o=Math.min(a+n,e.length),l=e.slice(a,o);let c;if(0===r){const e={eventId:s,totalChunks:i,chunkIndex:r},n=JSON.stringify(e),a=(new TextEncoder).encode(n);c=this.createMessageBuffer({action:t,header:a,payload:l})}else{const e={eventId:s,chunkIndex:r},t=JSON.stringify(e),n=(new TextEncoder).encode(t);c=this.createMessageBuffer({action:"",header:n,payload:l})}this.synchronizedSendMessage(()=>this.sendMessage(c))}}catch(s){}}disconnect(){try{this.unsubscribeIdleTimeout&&this.unsubscribeIdleTimeout(),this.unsubscribePageUnload&&this.unsubscribePageUnload()}catch(e){}if(this.stopHeartbeat(),this.connectionManager.clearAllTimers(),this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null),this.webSocket)try{this.webSocket.readyState!==WebSocket.OPEN&&this.webSocket.readyState!==WebSocket.CONNECTING||this.webSocket.close(1e3,"Client disconnecting"),this.webSocket.onopen=null,this.webSocket.onmessage=null,this.webSocket.onerror=null,this.webSocket.onclose=null,this.webSocket=null}catch(e){}this.setConnectionStatus(o.DISCONNECTED),this.roomId=null,this.token=null,this.checkRoom=null,this.#t=null,this.reconnectAttempts=0,this.disconnectListeners.forEach(t=>{try{t()}catch(e){}}),this.notifyStreamingManagerDisconnect(),this.statusListeners.length=0,this.roomInfoListeners.length=0,this.disconnectListeners.length=0,this.errorHandlers.length=0}startHeartbeat(){this.heartbeatInterval&&this.stopHeartbeat(),this.heartbeatInterval=setInterval(()=>{this.webSocket&&this.webSocket.readyState===WebSocket.OPEN&&(this.sendMessage({action:"occupyingResource",payload:{}}),this.HEARTBEAT_MESSAGE)},this.HEARTBEAT_INTERVAL),this.HEARTBEAT_INTERVAL}stopHeartbeat(){this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null)}generateEventId(){return W(`#event_${this.