connectbase-client 0.6.7 → 0.6.9
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/connect-base.umd.js +2 -2
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +47 -14
- package/dist/index.mjs +47 -14
- package/package.json +1 -1
package/dist/connect-base.umd.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var ConnectBaseModule=(()=>{var H=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var ee=(a,e)=>{for(var t in e)H(a,t,{get:e[t],enumerable:!0})},te=(a,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Y(e))!Z.call(a,r)&&r!==t&&H(a,r,{get:()=>e[r],enumerable:!(s=X(e,r))||s.enumerable});return a};var se=a=>te(H({},"__esModule",{value:!0}),a);var he={};ee(he,{AdsAPI:()=>P,ApiError:()=>d,AuthError:()=>m,ConnectBase:()=>F,GameAPI:()=>v,GameRoom:()=>w,GameRoomTransport:()=>L,VideoProcessingError:()=>b,default:()=>le,isWebTransportSupported:()=>K});var d=class extends Error{constructor(t,s){super(s);this.statusCode=t;this.name="ApiError"}},m=class extends Error{constructor(e){super(e),this.name="AuthError"}};var S=class{constructor(e){this.isRefreshing=!1;this.refreshPromise=null;this.config=e}updateConfig(e){this.config={...this.config,...e}}setTokens(e,t){this.config.accessToken=e,this.config.refreshToken=t}clearTokens(){this.config.accessToken=void 0,this.config.refreshToken=void 0}hasApiKey(){return!!this.config.apiKey}getApiKey(){return this.config.apiKey}getAccessToken(){return this.config.accessToken}getBaseUrl(){return this.config.baseUrl}async refreshAccessToken(){if(this.isRefreshing)return this.refreshPromise;if(this.isRefreshing=!0,!this.config.refreshToken){this.isRefreshing=!1;let e=new m("Refresh token is missing. Please login again.");throw this.config.onAuthError?.(e),e}return this.refreshPromise=(async()=>{try{let e=await fetch(`${this.config.baseUrl}/v1/auth/re-issue`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.refreshToken}`}});if(!e.ok)throw new Error("Token refresh failed");let t=await e.json();return this.config.accessToken=t.access_token,this.config.refreshToken=t.refresh_token,this.config.onTokenRefresh?.({accessToken:t.access_token,refreshToken:t.refresh_token}),t.access_token}catch{this.clearTokens();let e=new m("Token refresh failed. Please login again.");throw this.config.onAuthError?.(e),e}finally{this.isRefreshing=!1,this.refreshPromise=null}})(),this.refreshPromise}isTokenExpired(e){try{let t=JSON.parse(atob(e.split(".")[1])),s=Date.now()/1e3;return t.exp<s+300}catch{return!0}}async prepareHeaders(e){let t=new Headers;if(t.set("Content-Type","application/json"),this.config.apiKey&&t.set("X-API-Key",this.config.apiKey),!e?.skipAuth&&this.config.accessToken){let s=this.config.accessToken;if(this.isTokenExpired(s)&&this.config.refreshToken){let r=await this.refreshAccessToken();r&&(s=r)}t.set("Authorization",`Bearer ${s}`)}return e?.headers&&Object.entries(e.headers).forEach(([s,r])=>{t.set(s,r)}),t}async handleResponse(e){if(!e.ok){let t=await e.json().catch(()=>({message:e.statusText}));throw new d(e.status,t.message||t.error||"Unknown error")}return e.status===204||e.headers.get("content-length")==="0"?{}:e.json()}async get(e,t){let s=await this.prepareHeaders(t),r=await fetch(`${this.config.baseUrl}${e}`,{method:"GET",headers:s});return this.handleResponse(r)}async post(e,t,s){let r=await this.prepareHeaders(s);t instanceof FormData&&r.delete("Content-Type");let i=await fetch(`${this.config.baseUrl}${e}`,{method:"POST",headers:r,body:t instanceof FormData?t:JSON.stringify(t)});return this.handleResponse(i)}async put(e,t,s){let r=await this.prepareHeaders(s),i=await fetch(`${this.config.baseUrl}${e}`,{method:"PUT",headers:r,body:JSON.stringify(t)});return this.handleResponse(i)}async patch(e,t,s){let r=await this.prepareHeaders(s),i=await fetch(`${this.config.baseUrl}${e}`,{method:"PATCH",headers:r,body:JSON.stringify(t)});return this.handleResponse(i)}async delete(e,t){let s=await this.prepareHeaders(t),r=await fetch(`${this.config.baseUrl}${e}`,{method:"DELETE",headers:s});return this.handleResponse(r)}};var j="cb_guest_";function y(a){typeof window>"u"||(a?typeof window.__cbSetMember=="function"&&window.__cbSetMember(a):typeof window.__cbClearMember=="function"&&window.__cbClearMember())}function re(a){let e=0;for(let t=0;t<a.length;t++){let s=a.charCodeAt(t);e=(e<<5)-e+s,e=e&e}return Math.abs(e).toString(36)}var T=class{constructor(e){this.http=e;this.guestMemberLoginPromise=null;this.cachedGuestMemberTokenKey=null}async getAuthSettings(){return this.http.get("/v1/public/auth-settings",{skipAuth:!0})}async signUpMember(e){let t=await this.http.post("/v1/public/app-members/signup",e,{skipAuth:!0});return this.http.setTokens(t.access_token,t.refresh_token),y(t.member_id),t}async signInMember(e){let t=await this.http.post("/v1/public/app-members/signin",e,{skipAuth:!0});return this.http.setTokens(t.access_token,t.refresh_token),y(t.member_id),t}async signInAsGuestMember(){if(this.guestMemberLoginPromise)return this.guestMemberLoginPromise;this.guestMemberLoginPromise=this.executeGuestMemberLogin();try{return await this.guestMemberLoginPromise}finally{this.guestMemberLoginPromise=null}}async signOut(){try{await this.http.post("/v1/auth/logout")}finally{this.http.clearTokens(),y(null)}}clearGuestMemberTokens(){typeof sessionStorage>"u"||sessionStorage.removeItem(this.getGuestMemberTokenKey())}async executeGuestMemberLogin(){let e=this.getStoredGuestMemberTokens();if(e){if(!this.isTokenExpired(e.accessToken))try{this.http.setTokens(e.accessToken,e.refreshToken);let s=await this.http.get("/v1/public/app-members/me");if(s.is_active)return y(s.member_id),{member_id:s.member_id,access_token:e.accessToken,refresh_token:e.refreshToken};this.clearGuestMemberTokens()}catch{this.http.clearTokens()}if(e.refreshToken&&!this.isTokenExpired(e.refreshToken))try{let s=await this.http.post("/v1/auth/re-issue",{},{headers:{Authorization:`Bearer ${e.refreshToken}`},skipAuth:!0});return this.http.setTokens(s.access_token,s.refresh_token),this.storeGuestMemberTokens(s.access_token,s.refresh_token,e.memberId),y(e.memberId),{member_id:e.memberId,access_token:s.access_token,refresh_token:s.refresh_token}}catch{this.clearGuestMemberTokens()}else this.clearGuestMemberTokens()}let t=await this.http.post("/v1/public/app-members",{},{skipAuth:!0});return this.http.setTokens(t.access_token,t.refresh_token),this.storeGuestMemberTokens(t.access_token,t.refresh_token,t.member_id),y(t.member_id),t}isTokenExpired(e){try{let t=JSON.parse(atob(e.split(".")[1])),s=Date.now()/1e3;return t.exp<s}catch{return!0}}getGuestMemberTokenKey(){if(this.cachedGuestMemberTokenKey)return this.cachedGuestMemberTokenKey;let e=this.http.getApiKey();if(!e)this.cachedGuestMemberTokenKey=`${j}default`;else{let t=re(e);this.cachedGuestMemberTokenKey=`${j}${t}`}return this.cachedGuestMemberTokenKey}getStoredGuestMemberTokens(){if(typeof sessionStorage>"u")return null;let e=sessionStorage.getItem(this.getGuestMemberTokenKey());if(!e)return null;try{return JSON.parse(e)}catch{return null}}storeGuestMemberTokens(e,t,s){typeof sessionStorage>"u"||sessionStorage.setItem(this.getGuestMemberTokenKey(),JSON.stringify({accessToken:e,refreshToken:t,memberId:s}))}};var C=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async getTables(e){return(await this.http.get(`/v1/databases/json-databases/${e}/tables`)).tables}async createTable(e,t){return this.http.post(`/v1/databases/json-databases/${e}/tables`,t)}async deleteTable(e,t){await this.http.delete(`/v1/databases/json-databases/${e}/tables/${t}`)}async getColumns(e){return(await this.http.get(`/v1/tables/${e}/columns`)).columns}async createColumn(e,t){return this.http.post(`/v1/tables/${e}/columns`,t)}async updateColumn(e,t,s){return this.http.patch(`/v1/tables/${e}/columns/${t}`,s)}async deleteColumn(e,t){await this.http.delete(`/v1/tables/${e}/columns/${t}`)}async getData(e,t){let s=this.getPublicPrefix();if(t?.where||t?.select||t?.exclude)return this.queryData(e,t);let r=new URLSearchParams;t?.limit&&r.append("limit",t.limit.toString()),t?.offset&&r.append("offset",t.offset.toString());let i=r.toString(),n=i?`${s}/tables/${e}/data?${i}`:`${s}/tables/${e}/data`;return this.http.get(n)}async queryData(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/tables/${e}/data/query`,{where:t.where,order_by:t.orderBy,order_direction:t.orderDirection,limit:t.limit,offset:t.offset,select:t.select,exclude:t.exclude})}async getDataById(e,t){let s=this.getPublicPrefix();return this.http.get(`${s}/tables/${e}/data/${t}`)}async createData(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/tables/${e}/data`,t)}async updateData(e,t,s){let r=this.getPublicPrefix();return this.http.put(`${r}/tables/${e}/data/${t}`,s)}async deleteData(e,t){let s=this.getPublicPrefix();await this.http.delete(`${s}/tables/${e}/data/${t}`)}async createMany(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/tables/${e}/data/bulk`,{data:t.map(r=>r.data)})}async deleteWhere(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/tables/${e}/data/delete-where`,{where:t})}async aggregate(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/aggregate`,{table_id:e,pipeline:t})}async search(e,t,s,r){let i=this.getPublicPrefix();return this.http.post(`${i}/search`,{table_id:e,query:t,fields:s,...r})}async autocomplete(e,t,s,r){let i=this.getPublicPrefix();return this.http.post(`${i}/autocomplete`,{table_id:e,query:t,field:s,...r})}async geoQuery(e,t,s,r){let i=this.getPublicPrefix();return this.http.post(`${i}/geo`,{table_id:e,field:t,...s,...r})}async batch(e){let t=this.getPublicPrefix();return this.http.post(`${t}/batch`,{operations:e})}async transaction(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/transactions`,{reads:e,writes:t})}async getDataWithPopulate(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/tables/${e}/data/query`,{where:t.where,order_by:t.orderBy,order_direction:t.orderDirection,limit:t.limit,offset:t.offset,select:t.select,exclude:t.exclude,populate:t.populate})}async listSecurityRules(e){return(await this.http.get(`/v1/apps/${e}/security/rules`)).rules}async createSecurityRule(e,t){return this.http.post(`/v1/apps/${e}/security/rules`,t)}async updateSecurityRule(e,t,s){return this.http.put(`/v1/apps/${e}/security/rules/${t}`,s)}async deleteSecurityRule(e,t){await this.http.delete(`/v1/apps/${e}/security/rules/${t}`)}async listIndexes(e,t){return(await this.http.get(`/v1/apps/${e}/tables/${t}/indexes`)).indexes}async createIndex(e,t,s){return this.http.post(`/v1/apps/${e}/tables/${t}/indexes`,s)}async deleteIndex(e,t,s){await this.http.delete(`/v1/apps/${e}/tables/${t}/indexes/${s}`)}async analyzeIndexes(e,t){return this.http.get(`/v1/apps/${e}/tables/${t}/indexes/analyze`)}async listRelations(e,t){return(await this.http.get(`/v1/apps/${e}/tables/${t}/relations`)).relations}async createRelation(e,t,s){return this.http.post(`/v1/apps/${e}/tables/${t}/relations`,s)}async deleteRelation(e,t,s){await this.http.delete(`/v1/apps/${e}/tables/${t}/relations/${s}`)}async listTriggers(e){return(await this.http.get(`/v1/apps/${e}/triggers`)).triggers}async createTrigger(e,t){return this.http.post(`/v1/apps/${e}/triggers`,t)}async updateTrigger(e,t,s){return this.http.put(`/v1/apps/${e}/triggers/${t}`,s)}async deleteTrigger(e,t){await this.http.delete(`/v1/apps/${e}/triggers/${t}`)}async setTTL(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/ttl`,t)}async getTTL(e,t){return this.http.get(`/v1/apps/${e}/lifecycle/ttl/${t}`)}async setRetentionPolicy(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/retention`,t)}async getRetentionPolicy(e,t){return this.http.get(`/v1/apps/${e}/lifecycle/retention/${t}`)}};var _=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async getFiles(e){let t=this.getPublicPrefix();return(await this.http.get(`${t}/storages/files/${e}/items`)).files}async uploadFile(e,t,s){let r=this.getPublicPrefix(),i=new FormData;return i.append("file",t),s&&i.append("parent_id",s),this.http.post(`${r}/storages/files/${e}/upload`,i)}async uploadFiles(e,t,s){let r=[];for(let i of t){let n=await this.uploadFile(e,i,s);r.push(n)}return r}async createFolder(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/storages/files/${e}/folders`,t)}async deleteFile(e,t){let s=this.getPublicPrefix();await this.http.delete(`${s}/storages/files/${e}/items/${t}`)}async moveFile(e,t,s){let r=this.getPublicPrefix();await this.http.post(`${r}/storages/files/${e}/items/${t}/move`,s)}async renameFile(e,t,s){let r=this.getPublicPrefix();return this.http.patch(`${r}/storages/files/${e}/items/${t}/rename`,s)}getFileUrl(e){return e.url||null}isImageFile(e){return e.mime_type?.startsWith("image/")||!1}async uploadByPath(e,t,s,r){let i=this.getPublicPrefix(),n=new FormData;n.append("file",s);let o=r?.overwrite!==!1;n.append("overwrite",o.toString());let c=t.startsWith("/")?t.slice(1):t;return this.http.post(`${i}/storages/files/${e}/path/${c}`,n)}async getByPath(e,t){let s=this.getPublicPrefix(),r=t.startsWith("/")?t.slice(1):t;return this.http.get(`${s}/storages/files/${e}/path/${r}`)}async getUrlByPath(e,t){try{return(await this.getByPath(e,t)).url||null}catch{return null}}async setPageMeta(e,t){let s=this.getPublicPrefix();return this.http.put(`${s}/storages/webs/${e}/page-metas`,t)}async batchSetPageMeta(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/storages/webs/${e}/page-metas/batch`,t)}async listPageMetas(e){let t=this.getPublicPrefix();return this.http.get(`${t}/storages/webs/${e}/page-metas`)}async getPageMeta(e,t){let s=this.getPublicPrefix(),r=encodeURIComponent(t);return this.http.get(`${s}/storages/webs/${e}/page-metas/get?path=${r}`)}async deletePageMeta(e,t){let s=this.getPublicPrefix(),r=encodeURIComponent(t);await this.http.delete(`${s}/storages/webs/${e}/page-metas?path=${r}`)}async deleteAllPageMetas(e){let t=this.getPublicPrefix();await this.http.delete(`${t}/storages/webs/${e}/page-metas/all`)}};var k=class{constructor(e){this.http=e}async getApiKeys(e){return this.http.get(`/v1/apps/${e}/api-keys`)}async createApiKey(e,t){return this.http.post(`/v1/apps/${e}/api-keys`,t)}async updateApiKey(e,t,s){return this.http.patch(`/v1/apps/${e}/api-keys/${t}`,s)}async deleteApiKey(e,t){await this.http.delete(`/v1/apps/${e}/api-keys/${t}`)}};var x=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async invoke(e,t,s){let r=this.getPublicPrefix(),i={};return t!==void 0&&(i.payload=t),s!==void 0&&(i.timeout=s),this.http.post(`${r}/functions/${e}/invoke`,i)}async call(e,t){let s=await this.invoke(e,t);if(!s.success)throw new Error(s.error||"Function execution failed");return s.result}};var E=class{constructor(e,t){this.ws=null;this.state="disconnected";this._connectionId=null;this._appId=null;this.options={maxRetries:5,retryInterval:1e3,userId:"",accessToken:""};this.retryCount=0;this.pendingRequests=new Map;this.subscriptions=new Map;this.streamSessions=new Map;this.stateHandlers=[];this.errorHandlers=[];this.http=e,this.socketUrl=t,this.clientId=this.generateClientId()}get connectionId(){return this._connectionId}get appId(){return this._appId}async connect(e={}){if(!(this.state==="connected"||this.state==="connecting"))return this.options={...this.options,...e},e.userId&&(this.userId=e.userId),this.doConnect()}disconnect(){this.state="disconnected",this.notifyStateChange(),this.ws&&(this.ws.close(),this.ws=null),this.pendingRequests.forEach(e=>{clearTimeout(e.timeout),e.reject(new Error("Connection closed"))}),this.pendingRequests.clear(),this.subscriptions.clear()}async subscribe(e,t={}){if(this.state!=="connected")throw new Error("Not connected. Call connect() first.");let s=this.generateRequestId(),r=await this.sendRequest({category:e,action:"subscribe",request_id:s}),i={category:r.category,persist:r.persist,historyCount:r.history_count,readReceipt:r.read_receipt},n=[];return this.subscriptions.set(e,{info:i,handlers:n}),{info:i,send:async(c,p)=>{await this.sendMessage(e,c,p)},getHistory:async c=>this.getHistory(e,c??t.historyLimit),unsubscribe:async()=>{await this.unsubscribe(e)},onMessage:c=>{n.push(c)}}}async unsubscribe(e){if(this.state!=="connected")return;let t=this.generateRequestId();await this.sendRequest({category:e,action:"unsubscribe",request_id:t}),this.subscriptions.delete(e)}async sendMessage(e,t,s={}){if(this.state!=="connected")throw new Error("Not connected");let i=s.includeSelf!==!1,n=this.generateRequestId();await this.sendRequest({category:e,action:"send",data:{data:t,broadcast:i},request_id:n})}async getHistory(e,t){if(this.state!=="connected")throw new Error("Not connected");let s=this.generateRequestId(),r=await this.sendRequest({category:e,action:"history",data:t?{limit:t}:void 0,request_id:s});return{category:r.category,messages:r.messages.map(i=>({id:i.id,category:i.category,from:i.from,data:i.data,sentAt:i.sent_at})),total:r.total}}async stream(e,t,s={}){if(this.state!=="connected")throw new Error("Not connected. Call connect() first.");let r=this.generateRequestId(),i=s.sessionId||this.generateRequestId();return this.streamSessions.set(i,{handlers:t,requestId:r}),this.sendRaw({category:"",action:"stream",data:{provider:s.provider,model:s.model,messages:e,system:s.system,temperature:s.temperature,max_tokens:s.maxTokens,session_id:i,metadata:s.metadata},request_id:r}),{sessionId:i,stop:async()=>{await this.stopStream(i)}}}async stopStream(e){if(this.state!=="connected")return;let t=this.generateRequestId();this.sendRaw({category:"",action:"stream_stop",data:{session_id:e},request_id:t}),this.streamSessions.delete(e)}getState(){return this.state}onStateChange(e){return this.stateHandlers.push(e),()=>{let t=this.stateHandlers.indexOf(e);t>-1&&this.stateHandlers.splice(t,1)}}onError(e){return this.errorHandlers.push(e),()=>{let t=this.errorHandlers.indexOf(e);t>-1&&this.errorHandlers.splice(t,1)}}async doConnect(){return new Promise((e,t)=>{this.state="connecting",this.notifyStateChange();let s=this.socketUrl.replace(/^http/,"ws"),r;if(this.options.accessToken)r=`${s}/v1/realtime/auth?access_token=${encodeURIComponent(this.options.accessToken)}&client_id=${this.clientId}`;else{let i=this.http.getApiKey();if(!i){t(new Error("API Key or accessToken is required for realtime connection"));return}r=`${s}/v1/realtime/auth?api_key=${encodeURIComponent(i)}&client_id=${this.clientId}`}this.userId&&(r+=`&user_id=${encodeURIComponent(this.userId)}`);try{this.ws=new WebSocket(r),this.ws.onopen=()=>{},this.ws.onmessage=i=>{let n=i.data.split(`
|
|
2
|
-
`).filter(o=>o.trim());for(let o of n)try{let c=JSON.parse(o);this.handleServerMessage(c,e)}catch(c){console.error("[Realtime] Failed to parse message:",o,c)}},this.ws.onclose=()=>{(this.state==="connected"||this.state==="connecting")&&this.handleDisconnect()},this.ws.onerror=i=>{console.error("[Realtime] WebSocket error:",i),this.notifyError(new Error("WebSocket connection error")),this.state==="connecting"&&t(new Error("Failed to connect"))}}catch(i){t(i)}})}handleServerMessage(e,t){switch(e.event){case"connected":{let s=e.data;this._connectionId=s.connection_id,this._appId=s.app_id,this.state="connected",this.retryCount=0,this.notifyStateChange(),t&&t();break}case"subscribed":case"unsubscribed":case"sent":case"result":case"history":{if(e.request_id){let s=this.pendingRequests.get(e.request_id);s&&(clearTimeout(s.timeout),s.resolve(e.data),this.pendingRequests.delete(e.request_id))}break}case"message":{let s=e.data,r=this.subscriptions.get(s.category);if(r){let i={id:s.id,category:s.category,from:s.from,data:s.data,sentAt:s.sent_at};r.handlers.forEach(n=>n(i))}break}case"error":{if(e.request_id){let s=this.pendingRequests.get(e.request_id);s&&(clearTimeout(s.timeout),s.reject(new Error(e.error||"Unknown error")),this.pendingRequests.delete(e.request_id))}else this.notifyError(new Error(e.error||"Unknown error"));break}case"pong":break;case"stream_token":{let s=e.data,r=this.streamSessions.get(s.session_id);r?.handlers.onToken&&r.handlers.onToken(s.token,s.index);break}case"stream_done":{let s=e.data,r=this.streamSessions.get(s.session_id);r?.handlers.onDone&&r.handlers.onDone({sessionId:s.session_id,fullText:s.full_text,totalTokens:s.total_tokens,promptTokens:s.prompt_tokens,duration:s.duration_ms}),this.streamSessions.delete(s.session_id);break}case"stream_error":{let s=e.data;if(e.request_id){for(let[r,i]of this.streamSessions)if(i.requestId===e.request_id){i.handlers.onError&&i.handlers.onError(new Error(s.message)),this.streamSessions.delete(r);break}}break}}}handleDisconnect(){this.ws=null,this._connectionId=null,this.retryCount<this.options.maxRetries?(this.state="reconnecting",this.notifyStateChange(),this.retryCount++,setTimeout(()=>{this.doConnect().catch(e=>{console.error("[Realtime] Reconnect failed:",e)})},this.options.retryInterval*this.retryCount)):(this.state="disconnected",this.notifyStateChange(),this.notifyError(new Error("Connection lost. Max retries exceeded.")))}sendRequest(e){return new Promise((t,s)=>{if(!this.ws||this.ws.readyState!==WebSocket.OPEN){s(new Error("Not connected"));return}let r=setTimeout(()=>{this.pendingRequests.delete(e.request_id),s(new Error("Request timeout"))},3e4);this.pendingRequests.set(e.request_id,{resolve:t,reject:s,timeout:r}),this.ws.send(JSON.stringify(e))})}sendRaw(e){if(!this.ws||this.ws.readyState!==WebSocket.OPEN)throw new Error("Not connected");this.ws.send(JSON.stringify(e))}notifyStateChange(){this.stateHandlers.forEach(e=>e(this.state))}notifyError(e){this.errorHandlers.forEach(t=>t(e))}generateClientId(){return"cb_"+Math.random().toString(36).substring(2,15)}generateRequestId(){return"req_"+Date.now()+"_"+Math.random().toString(36).substring(2,9)}};var $=class{constructor(e,t,s){this.ws=null;this.state="disconnected";this.stateListeners=[];this.errorListeners=[];this.peerJoinedListeners=[];this.peerLeftListeners=[];this.remoteStreamListeners=[];this.reconnectAttempts=0;this.maxReconnectAttempts=5;this.reconnectTimeout=null;this.currentRoomId=null;this.currentPeerId=null;this.currentUserId=null;this.isBroadcaster=!1;this.localStream=null;this.channelType="interactive";this.peerConnections=new Map;this.remoteStreams=new Map;this.iceServers=[];this.http=e,this.webrtcUrl=t,this.appId=s}async getICEServers(){let e=await this.http.get("/v1/ice-servers");return this.iceServers=e.ice_servers,e.ice_servers}async connect(e){if(this.state==="connected"||this.state==="connecting")throw new Error("\uC774\uBBF8 \uC5F0\uACB0\uB418\uC5B4 \uC788\uAC70\uB098 \uC5F0\uACB0 \uC911\uC785\uB2C8\uB2E4");if(this.setState("connecting"),this.currentRoomId=e.roomId,this.currentUserId=e.userId||null,this.isBroadcaster=e.isBroadcaster||!1,this.localStream=e.localStream||null,this.iceServers.length===0)try{await this.getICEServers()}catch{this.iceServers=[{urls:"stun:stun.l.google.com:19302"}]}return this.connectWebSocket()}connectWebSocket(){return new Promise((e,t)=>{let s=this.buildWebSocketUrl();this.ws=new WebSocket(s);let r=setTimeout(()=>{this.state==="connecting"&&(this.ws?.close(),t(new Error("\uC5F0\uACB0 \uC2DC\uAC04 \uCD08\uACFC")))},1e4);this.ws.onopen=()=>{clearTimeout(r),this.reconnectAttempts=0,this.sendSignaling({type:"join",room_id:this.currentRoomId,data:{user_id:this.currentUserId,is_broadcaster:this.isBroadcaster}})},this.ws.onmessage=async i=>{try{let n=JSON.parse(i.data);await this.handleSignalingMessage(n,e,t)}catch(n){console.error("Failed to parse signaling message:",n)}},this.ws.onerror=i=>{clearTimeout(r),console.error("WebSocket error:",i),this.emitError(new Error("WebSocket \uC5F0\uACB0 \uC624\uB958"))},this.ws.onclose=i=>{clearTimeout(r),this.state==="connecting"&&t(new Error("\uC5F0\uACB0\uC774 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4")),this.handleDisconnect(i)}})}buildWebSocketUrl(){let e=this.webrtcUrl.replace("https://","wss://").replace("http://","ws://"),t=this.http.getApiKey(),s=this.http.getAccessToken(),r="";if(s?r=`access_token=${encodeURIComponent(s)}`:t&&(r=`api_key=${encodeURIComponent(t)}`),!this.appId)throw new Error("WebRTC \uC5F0\uACB0\uC5D0\uB294 appId\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. ConnectBase \uCD08\uAE30\uD654 \uC2DC appId\uB97C \uC124\uC815\uD558\uC138\uC694.");return`${e}/v1/apps/${this.appId}/signaling?${r}`}async handleSignalingMessage(e,t,s){switch(e.type){case"joined":if(this.setState("connected"),this.currentPeerId=e.peer_id||null,e.data&&typeof e.data=="object"){let n=e.data;n.channel_type&&(this.channelType=n.channel_type);let o=n.peers||[];for(let c of o)c.peer_id!==this.currentPeerId&&await this.createPeerConnection(c.peer_id,!0)}t?.();break;case"peer_joined":if(e.peer_id&&e.peer_id!==this.currentPeerId){let n={peer_id:e.peer_id,...typeof e.data=="object"?e.data:{}};this.emitPeerJoined(e.peer_id,n),await this.createPeerConnection(e.peer_id,!1)}break;case"peer_left":e.peer_id&&(this.closePeerConnection(e.peer_id),this.emitPeerLeft(e.peer_id));break;case"offer":e.peer_id&&e.sdp&&await this.handleOffer(e.peer_id,e.sdp);break;case"answer":e.peer_id&&e.sdp&&await this.handleAnswer(e.peer_id,e.sdp);break;case"ice_candidate":e.peer_id&&e.candidate&&await this.handleICECandidate(e.peer_id,e.candidate);break;case"error":let r=typeof e.data=="string"?e.data:"Unknown error",i=new Error(r);this.emitError(i),s?.(i);break}}async createPeerConnection(e,t){this.closePeerConnection(e);let s={iceServers:this.iceServers.map(i=>({urls:i.urls,username:i.username,credential:i.credential}))},r=new RTCPeerConnection(s);if(this.peerConnections.set(e,r),this.localStream&&this.localStream.getTracks().forEach(i=>{r.addTrack(i,this.localStream)}),r.onicecandidate=i=>{i.candidate&&this.sendSignaling({type:"ice_candidate",target_id:e,candidate:i.candidate.toJSON()})},r.ontrack=i=>{let[n]=i.streams;n&&(this.remoteStreams.set(e,n),this.emitRemoteStream(e,n))},r.onconnectionstatechange=()=>{r.connectionState==="failed"&&(console.warn(`Peer connection failed: ${e}`),this.closePeerConnection(e))},t){let i=await r.createOffer();await r.setLocalDescription(i),this.sendSignaling({type:"offer",target_id:e,sdp:i.sdp})}return r}async handleOffer(e,t){let s=this.peerConnections.get(e);s||(s=await this.createPeerConnection(e,!1)),await s.setRemoteDescription(new RTCSessionDescription({type:"offer",sdp:t}));let r=await s.createAnswer();await s.setLocalDescription(r),this.sendSignaling({type:"answer",target_id:e,sdp:r.sdp})}async handleAnswer(e,t){let s=this.peerConnections.get(e);s&&await s.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:t}))}async handleICECandidate(e,t){let s=this.peerConnections.get(e);if(s)try{await s.addIceCandidate(new RTCIceCandidate(t))}catch(r){console.warn("Failed to add ICE candidate:",r)}}closePeerConnection(e){let t=this.peerConnections.get(e);t&&(t.close(),this.peerConnections.delete(e)),this.remoteStreams.delete(e)}sendSignaling(e){this.ws&&this.ws.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(e))}handleDisconnect(e){let t=this.state==="connected";this.setState("disconnected"),this.peerConnections.forEach((s,r)=>{s.close(),this.emitPeerLeft(r)}),this.peerConnections.clear(),this.remoteStreams.clear(),t&&e.code!==1e3&&this.reconnectAttempts<this.maxReconnectAttempts&&this.attemptReconnect()}attemptReconnect(){this.reconnectAttempts++,this.setState("reconnecting");let e=Math.min(5e3*Math.pow(2,this.reconnectAttempts-1),3e4);this.reconnectTimeout=setTimeout(async()=>{try{await this.connectWebSocket()}catch{this.reconnectAttempts<this.maxReconnectAttempts?this.attemptReconnect():(this.setState("failed"),this.emitError(new Error("\uC7AC\uC5F0\uACB0 \uC2E4\uD328: \uCD5C\uB300 \uC2DC\uB3C4 \uD69F\uC218 \uCD08\uACFC")))}},e)}disconnect(){this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null),this.ws&&this.ws.readyState===WebSocket.OPEN&&(this.sendSignaling({type:"leave"}),this.ws.close(1e3,"User disconnected")),this.peerConnections.forEach(e=>e.close()),this.peerConnections.clear(),this.remoteStreams.clear(),this.ws=null,this.currentRoomId=null,this.currentPeerId=null,this.localStream=null,this.setState("disconnected")}getState(){return this.state}getRoomId(){return this.currentRoomId}getPeerId(){return this.currentPeerId}getChannelType(){return this.channelType}getRemoteStream(e){return this.remoteStreams.get(e)}getAllRemoteStreams(){return new Map(this.remoteStreams)}replaceLocalStream(e){this.localStream=e,this.peerConnections.forEach(t=>{let s=t.getSenders();e.getTracks().forEach(r=>{let i=s.find(n=>n.track?.kind===r.kind);i?i.replaceTrack(r):t.addTrack(r,e)})})}setAudioEnabled(e){this.localStream&&this.localStream.getAudioTracks().forEach(t=>{t.enabled=e})}setVideoEnabled(e){this.localStream&&this.localStream.getVideoTracks().forEach(t=>{t.enabled=e})}onStateChange(e){return this.stateListeners.push(e),()=>{this.stateListeners=this.stateListeners.filter(t=>t!==e)}}onError(e){return this.errorListeners.push(e),()=>{this.errorListeners=this.errorListeners.filter(t=>t!==e)}}onPeerJoined(e){return this.peerJoinedListeners.push(e),()=>{this.peerJoinedListeners=this.peerJoinedListeners.filter(t=>t!==e)}}onPeerLeft(e){return this.peerLeftListeners.push(e),()=>{this.peerLeftListeners=this.peerLeftListeners.filter(t=>t!==e)}}onRemoteStream(e){return this.remoteStreamListeners.push(e),()=>{this.remoteStreamListeners=this.remoteStreamListeners.filter(t=>t!==e)}}setState(e){this.state!==e&&(this.state=e,this.stateListeners.forEach(t=>t(e)))}emitError(e){this.errorListeners.forEach(t=>t(e))}emitPeerJoined(e,t){this.peerJoinedListeners.forEach(s=>s(e,t))}emitPeerLeft(e){this.peerLeftListeners.forEach(t=>t(e))}emitRemoteStream(e,t){this.remoteStreamListeners.forEach(s=>s(e,t))}async validate(){if(!this.appId)throw new Error("WebRTC \uAC80\uC99D\uC5D0\uB294 appId\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. ConnectBase \uCD08\uAE30\uD654 \uC2DC appId\uB97C \uC124\uC815\uD558\uC138\uC694.");return this.http.get(`/v1/apps/${this.appId}/validate`)}async getStats(e){return this.http.get(`/v1/apps/${e}/webrtc/stats`)}async getRooms(e){return this.http.get(`/v1/apps/${e}/webrtc/rooms`)}};var I=class{constructor(e,t={}){this.storageWebId=null;this.errorQueue=[];this.batchTimer=null;this.isInitialized=!1;this.originalOnError=null;this.originalOnUnhandledRejection=null;this.http=e,this.config={autoCapture:t.autoCapture??!0,captureTypes:t.captureTypes??["error","unhandledrejection"],batchInterval:t.batchInterval??5e3,maxBatchSize:t.maxBatchSize??10,beforeSend:t.beforeSend??(s=>s),debug:t.debug??!1}}init(e){if(this.isInitialized){this.log("ErrorTracker already initialized");return}if(typeof window>"u"){this.log("ErrorTracker only works in browser environment");return}this.storageWebId=e,this.isInitialized=!0,this.config.autoCapture&&this.setupAutoCapture(),this.startBatchTimer(),this.log("ErrorTracker initialized",{storageWebId:e})}destroy(){this.stopBatchTimer(),this.removeAutoCapture(),this.flushQueue(),this.isInitialized=!1,this.log("ErrorTracker destroyed")}async captureError(e,t){let s=this.createErrorReport(e,t);s&&this.queueError(s)}async captureMessage(e,t){let s={message:e,error_type:"custom",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0,...t};this.queueError(s)}async flush(){await this.flushQueue()}log(...e){this.config.debug&&console.log("[ErrorTracker]",...e)}setupAutoCapture(){typeof window>"u"||(this.config.captureTypes.includes("error")&&(this.originalOnError=window.onerror,window.onerror=(e,t,s,r,i)=>(this.handleGlobalError(e,t,s,r,i),this.originalOnError?this.originalOnError(e,t,s,r,i):!1)),this.config.captureTypes.includes("unhandledrejection")&&(this.originalOnUnhandledRejection=window.onunhandledrejection,window.onunhandledrejection=e=>{this.handleUnhandledRejection(e),this.originalOnUnhandledRejection&&this.originalOnUnhandledRejection(e)}),this.log("Auto capture enabled",{types:this.config.captureTypes}))}removeAutoCapture(){typeof window>"u"||(this.originalOnError!==null&&(window.onerror=this.originalOnError),this.originalOnUnhandledRejection!==null&&(window.onunhandledrejection=this.originalOnUnhandledRejection))}handleGlobalError(e,t,s,r,i){let n={message:typeof e=="string"?e:e.type||"Unknown error",source:t||void 0,lineno:s||void 0,colno:r||void 0,stack:i?.stack,error_type:"error",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0};this.queueError(n)}handleUnhandledRejection(e){let t=e.reason,s="Unhandled Promise Rejection",r;t instanceof Error?(s=t.message,r=t.stack):typeof t=="string"?s=t:t&&typeof t=="object"&&(s=JSON.stringify(t));let i={message:s,stack:r,error_type:"unhandledrejection",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0};this.queueError(i)}createErrorReport(e,t){let s;e instanceof Error?s={message:e.message,stack:e.stack,error_type:"error",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0,...t}:s={message:e,error_type:"custom",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0,...t};let r=this.config.beforeSend(s);return r===!1||r===null?(this.log("Error filtered out by beforeSend"),null):r}queueError(e){this.errorQueue.push(e),this.log("Error queued",{message:e.message,queueSize:this.errorQueue.length}),this.errorQueue.length>=this.config.maxBatchSize&&this.flushQueue()}startBatchTimer(){this.batchTimer||(this.batchTimer=setInterval(()=>{this.flushQueue()},this.config.batchInterval))}stopBatchTimer(){this.batchTimer&&(clearInterval(this.batchTimer),this.batchTimer=null)}async flushQueue(){if(!this.storageWebId||this.errorQueue.length===0)return;let e=[...this.errorQueue];this.errorQueue=[];try{e.length===1?await this.http.post(`/v1/public/storages/web/${this.storageWebId}/errors/report`,e[0]):await this.http.post(`/v1/public/storages/web/${this.storageWebId}/errors/batch`,{errors:e,user_agent:typeof navigator<"u"?navigator.userAgent:void 0}),this.log("Errors sent",{count:e.length})}catch(t){let s=this.config.maxBatchSize-this.errorQueue.length;s>0&&this.errorQueue.unshift(...e.slice(0,s)),this.log("Failed to send errors, re-queued",{error:t})}}};var M=class{constructor(e){this.http=e}async getEnabledProviders(){return this.http.get("/v1/public/oauth/providers")}async signIn(e,t,s){let r=new URLSearchParams({app_callback:t});s&&r.append("state",s);let i=await this.http.get(`/v1/public/oauth/${e}/authorize/central?${r.toString()}`);window.location.href=i.authorization_url}async signInWithPopup(e,t){let s=new URLSearchParams;t&&s.set("app_callback",t);let r=s.toString(),i=await this.http.get(`/v1/public/oauth/${e}/authorize/central${r?"?"+r:""}`),n=500,o=600,c=window.screenX+(window.outerWidth-n)/2,p=window.screenY+(window.outerHeight-o)/2,h=window.open(i.authorization_url,"oauth-popup",`width=${n},height=${o},left=${c},top=${p}`);if(!h)throw new Error("\uD31D\uC5C5\uC774 \uCC28\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uD31D\uC5C5 \uCC28\uB2E8\uC744 \uD574\uC81C\uD574\uC8FC\uC138\uC694.");return new Promise((W,u)=>{let f=async l=>{if(l.data?.type!=="oauth-callback")return;if(window.removeEventListener("message",f),l.data.error){u(new Error(l.data.error));return}let g={member_id:l.data.member_id,access_token:l.data.access_token,refresh_token:l.data.refresh_token,is_new_member:l.data.is_new_member==="true"||l.data.is_new_member===!0};this.http.setTokens(g.access_token,g.refresh_token),W(g)};window.addEventListener("message",f);let R=setInterval(()=>{h.closed&&(clearInterval(R),window.removeEventListener("message",f),u(new Error("\uB85C\uADF8\uC778\uC774 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.")))},500)})}getCallbackResult(){let e=new URLSearchParams(window.location.search),t=e.get("error");if(t){let o={error:t};return window.opener&&(window.opener.postMessage({type:"oauth-callback",...o},"*"),window.close()),o}let s=e.get("access_token"),r=e.get("refresh_token"),i=e.get("member_id");if(!s||!r||!i)return null;let n={access_token:s,refresh_token:r,member_id:i,is_new_member:e.get("is_new_member")==="true",state:e.get("state")||void 0};return window.opener?(window.opener.postMessage({type:"oauth-callback",...n},"*"),window.close(),n):(this.http.setTokens(s,r),n)}};var A=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async prepare(e){let t=this.getPublicPrefix();return this.http.post(`${t}/payments/prepare`,e)}async confirm(e){let t=this.getPublicPrefix();return this.http.post(`${t}/payments/confirm`,e)}async cancel(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/payments/cancel`,{payment_id:e,...t})}async getByOrderId(e){let t=this.getPublicPrefix();return this.http.get(`${t}/payments/orders/${e}`)}};var U=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async issueBillingKey(){let e=this.getPublicPrefix();return this.http.post(`${e}/subscriptions/billing-keys`,{})}async confirmBillingKey(e){let t=this.getPublicPrefix();return this.http.post(`${t}/subscriptions/billing-keys/confirm`,e)}async listBillingKeys(e){let t=this.getPublicPrefix(),s=e?`?customer_id=${e}`:"";return this.http.get(`${t}/subscriptions/billing-keys${s}`)}async getBillingKey(e){let t=this.getPublicPrefix();return this.http.get(`${t}/subscriptions/billing-keys/${e}`)}async updateBillingKey(e,t){let s=this.getPublicPrefix();return this.http.patch(`${s}/subscriptions/billing-keys/${e}`,t)}async deleteBillingKey(e){let t=this.getPublicPrefix();return this.http.delete(`${t}/subscriptions/billing-keys/${e}`)}async create(e){let t=this.getPublicPrefix();return this.http.post(`${t}/subscriptions`,e)}async list(e){let t=this.getPublicPrefix(),s=new URLSearchParams;e?.status&&s.set("status",e.status),e?.limit&&s.set("limit",String(e.limit)),e?.offset&&s.set("offset",String(e.offset));let r=s.toString();return this.http.get(`${t}/subscriptions${r?"?"+r:""}`)}async get(e){let t=this.getPublicPrefix();return this.http.get(`${t}/subscriptions/${e}`)}async update(e,t){let s=this.getPublicPrefix();return this.http.patch(`${s}/subscriptions/${e}`,t)}async pause(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/subscriptions/${e}/pause`,t||{})}async resume(e){let t=this.getPublicPrefix();return this.http.post(`${t}/subscriptions/${e}/resume`,{})}async cancel(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/subscriptions/${e}/cancel`,t)}async listPayments(e,t){let s=this.getPublicPrefix(),r=new URLSearchParams;t?.status&&r.set("status",t.status),t?.limit&&r.set("limit",String(t.limit)),t?.offset&&r.set("offset",String(t.offset));let i=r.toString();return this.http.get(`${s}/subscriptions/${e}/payments${i?"?"+i:""}`)}async chargeWithBillingKey(e){let t=this.getPublicPrefix();return this.http.post(`${t}/subscriptions/charge`,e)}};var q=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async registerDevice(e){let t=this.getPublicPrefix();return this.http.post(`${t}/push/devices`,e)}async unregisterDevice(e){let t=this.getPublicPrefix();await this.http.delete(`${t}/push/devices/${e}`)}async getDevices(){let e=this.getPublicPrefix();return(await this.http.get(`${e}/push/devices`)).devices||[]}async subscribeTopic(e){let t=this.getPublicPrefix(),s={topic_name:e};await this.http.post(`${t}/push/topics/subscribe`,s)}async unsubscribeTopic(e){let t=this.getPublicPrefix(),s={topic_name:e};await this.http.post(`${t}/push/topics/unsubscribe`,s)}async getSubscribedTopics(){let e=this.getPublicPrefix();return(await this.http.get(`${e}/push/topics/subscribed`)).topics||[]}async getVAPIDPublicKey(){let e=this.getPublicPrefix();return this.http.get(`${e}/push/vapid-key`)}async registerWebPush(e){let t=this.getPublicPrefix(),s;if("toJSON"in e){let i=e.toJSON();s={endpoint:i.endpoint||"",expirationTime:i.expirationTime,keys:{p256dh:i.keys?.p256dh||"",auth:i.keys?.auth||""}}}else s=e;let r={device_token:s.endpoint,platform:"web",device_id:this.generateDeviceId(),device_name:this.getBrowserName(),os_version:this.getOSInfo()};return this.http.post(`${t}/push/devices/web`,{...r,web_push_subscription:s})}async unregisterWebPush(){let e=this.getPublicPrefix();await this.http.delete(`${e}/push/devices/web`)}generateDeviceId(){if(typeof window>"u"||typeof localStorage>"u")return`device_${Date.now()}_${Math.random().toString(36).substr(2,9)}`;let e="cb_push_device_id",t=localStorage.getItem(e);return t||(t=`web_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,localStorage.setItem(e,t)),t}getBrowserName(){if(typeof navigator>"u")return"Unknown Browser";let e=navigator.userAgent;return e.includes("Chrome")&&!e.includes("Edg")?"Chrome":e.includes("Safari")&&!e.includes("Chrome")?"Safari":e.includes("Firefox")?"Firefox":e.includes("Edg")?"Edge":e.includes("Opera")||e.includes("OPR")?"Opera":"Unknown Browser"}getOSInfo(){if(typeof navigator>"u")return"Unknown OS";let e=navigator.userAgent;return e.includes("Windows")?"Windows":e.includes("Mac OS")?"macOS":e.includes("Linux")?"Linux":e.includes("Android")?"Android":e.includes("iOS")||e.includes("iPhone")||e.includes("iPad")?"iOS":"Unknown OS"}};var ie=5*1024*1024,b=class extends Error{constructor(e,t){super(e),this.name="VideoProcessingError",this.video=t}},G=class{constructor(e,t){this.http=e;this.videoBaseUrl=t||this.getDefaultVideoUrl()}getDefaultVideoUrl(){if(typeof window<"u"){let e=window.location.hostname;if(e==="localhost"||e==="127.0.0.1")return"http://localhost:8089"}return"https://video.connectbase.world"}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async videoFetch(e,t,s){let r={},i=this.http.getApiKey();i&&(r["X-API-Key"]=i);let n=this.http.getAccessToken();n&&(r.Authorization=`Bearer ${n}`),s&&!(s instanceof FormData)&&(r["Content-Type"]="application/json");let o=await fetch(`${this.videoBaseUrl}${t}`,{method:e,headers:r,body:s instanceof FormData?s:s?JSON.stringify(s):void 0});if(!o.ok){let c=await o.json().catch(()=>({message:o.statusText}));throw new d(o.status,c.message||"Unknown error")}return o.status===204||o.headers.get("content-length")==="0"?{}:o.json()}async upload(e,t){let s=this.getPublicPrefix(),r=await this.videoFetch("POST",`${s}/uploads`,{filename:e.name,size:e.size,mime_type:e.type,title:t.title,description:t.description,visibility:t.visibility||"private",tags:t.tags,channel_id:t.channel_id}),i=r.chunk_size||ie,n=Math.ceil(e.size/i),o=0,p=Date.now(),h=0;for(let u=0;u<n;u++){let f=u*i,R=Math.min(f+i,e.size),l=e.slice(f,R),g=new FormData;g.append("chunk",l),g.append("chunk_index",String(u)),await this.videoFetch("POST",`${s}/uploads/${r.session_id}/chunks`,g),o++;let B=Date.now(),V=(B-p)/1e3,N=R,J=N-h,Q=V>0?J/V:0;p=B,h=N,t.onProgress&&t.onProgress({phase:"uploading",uploadedChunks:o,totalChunks:n,percentage:Math.round(o/n*100),currentSpeed:Q})}return(await this.videoFetch("POST",`${s}/uploads/${r.session_id}/complete`,{})).video}async waitForReady(e,t){let s=t?.timeout||18e5,r=t?.interval||5e3,i=Date.now(),n=this.getPublicPrefix();for(;Date.now()-i<s;){let o=await this.videoFetch("GET",`${n}/videos/${e}`);if(o.status==="ready")return o;if(o.status==="failed")throw new b("Video processing failed",o);if(t?.onProgress){let c=o.qualities.filter(h=>h.status==="ready").length,p=o.qualities.length||1;t.onProgress({phase:"processing",uploadedChunks:0,totalChunks:0,percentage:Math.round(c/p*100)})}await new Promise(c=>setTimeout(c,r))}throw new b("Timeout waiting for video to be ready")}async list(e){let t=this.getPublicPrefix(),s=new URLSearchParams;e?.status&&s.set("status",e.status),e?.visibility&&s.set("visibility",e.visibility),e?.search&&s.set("search",e.search),e?.channel_id&&s.set("channel_id",e.channel_id),e?.page&&s.set("page",String(e.page)),e?.limit&&s.set("limit",String(e.limit));let r=s.toString();return this.videoFetch("GET",`${t}/videos${r?`?${r}`:""}`)}async get(e){let t=this.getPublicPrefix();return this.videoFetch("GET",`${t}/videos/${e}`)}async update(e,t){let s=this.getPublicPrefix();return this.videoFetch("PATCH",`${s}/videos/${e}`,t)}async delete(e){let t=this.getPublicPrefix();await this.videoFetch("DELETE",`${t}/videos/${e}`)}async getStreamUrl(e,t){let s=this.getPublicPrefix(),r=t?`?quality=${t}`:"";return this.videoFetch("GET",`${s}/videos/${e}/stream-url${r}`)}async getThumbnails(e){let t=this.getPublicPrefix();return(await this.videoFetch("GET",`${t}/videos/${e}/thumbnails`)).thumbnails}async getTranscodeStatus(e){let t=this.getPublicPrefix();return this.videoFetch("GET",`${t}/videos/${e}/transcode/status`)}async retryTranscode(e){let t=this.getPublicPrefix();await this.videoFetch("POST",`${t}/videos/${e}/transcode/retry`,{})}async createChannel(e){let t=this.getPublicPrefix();return this.videoFetch("POST",`${t}/channels`,e)}async getChannel(e){let t=this.getPublicPrefix();return this.videoFetch("GET",`${t}/channels/${e}`)}async getChannelByHandle(e){let t=this.getPublicPrefix();return this.videoFetch("GET",`${t}/channels/handle/${e}`)}async updateChannel(e,t){let s=this.getPublicPrefix();return this.videoFetch("PATCH",`${s}/channels/${e}`,t)}async subscribeChannel(e){let t=this.getPublicPrefix();await this.videoFetch("POST",`${t}/channels/${e}/subscribe`,{})}async unsubscribeChannel(e){let t=this.getPublicPrefix();await this.videoFetch("DELETE",`${t}/channels/${e}/subscribe`)}async createPlaylist(e,t){let s=this.getPublicPrefix();return this.videoFetch("POST",`${s}/channels/${e}/playlists`,t)}async getPlaylists(e){let t=this.getPublicPrefix();return(await this.videoFetch("GET",`${t}/channels/${e}/playlists`)).playlists}async getPlaylistItems(e){let t=this.getPublicPrefix();return(await this.videoFetch("GET",`${t}/playlists/${e}/items`)).items}async addToPlaylist(e,t,s){let r=this.getPublicPrefix();return this.videoFetch("POST",`${r}/playlists/${e}/items`,{video_id:t,position:s})}async removeFromPlaylist(e,t){let s=this.getPublicPrefix();await this.videoFetch("DELETE",`${s}/playlists/${e}/items/${t}`)}async getShortsFeed(e){let t=this.getPublicPrefix(),s=new URLSearchParams;e?.cursor&&s.set("cursor",e.cursor),e?.limit&&s.set("limit",String(e.limit));let r=s.toString();return this.videoFetch("GET",`${t}/shorts${r?`?${r}`:""}`)}async getTrendingShorts(e){let t=this.getPublicPrefix(),s=e?`?limit=${e}`:"";return this.videoFetch("GET",`${t}/shorts/trending${s}`)}async getShorts(e){let t=this.getPublicPrefix();return this.videoFetch("GET",`${t}/shorts/${e}`)}async getComments(e,t){let s=this.getPublicPrefix(),r=new URLSearchParams;t?.cursor&&r.set("cursor",t.cursor),t?.limit&&r.set("limit",String(t.limit)),t?.sort&&r.set("sort",t.sort);let i=r.toString();return this.videoFetch("GET",`${s}/videos/${e}/comments${i?`?${i}`:""}`)}async postComment(e,t,s){let r=this.getPublicPrefix();return this.videoFetch("POST",`${r}/videos/${e}/comments`,{content:t,parent_id:s})}async deleteComment(e){let t=this.getPublicPrefix();await this.videoFetch("DELETE",`${t}/comments/${e}`)}async likeVideo(e){let t=this.getPublicPrefix();await this.videoFetch("POST",`${t}/videos/${e}/like`,{})}async unlikeVideo(e){let t=this.getPublicPrefix();await this.videoFetch("DELETE",`${t}/videos/${e}/like`)}async getWatchHistory(e){let t=this.getPublicPrefix(),s=new URLSearchParams;e?.cursor&&s.set("cursor",e.cursor),e?.limit&&s.set("limit",String(e.limit));let r=s.toString();return this.videoFetch("GET",`${t}/watch-history${r?`?${r}`:""}`)}async clearWatchHistory(){let e=this.getPublicPrefix();await this.videoFetch("DELETE",`${e}/watch-history`)}async reportWatchProgress(e,t,s){let r=this.getPublicPrefix();await this.videoFetch("POST",`${r}/videos/${e}/watch-progress`,{position:t,duration:s})}async getMembershipTiers(e){let t=this.getPublicPrefix();return(await this.videoFetch("GET",`${t}/channels/${e}/memberships/tiers`)).tiers}async joinMembership(e,t){let s=this.getPublicPrefix();return this.videoFetch("POST",`${s}/channels/${e}/memberships/${t}/join`,{})}async cancelMembership(e,t){let s=this.getPublicPrefix();await this.videoFetch("POST",`${s}/channels/${e}/memberships/${t}/cancel`,{})}async sendSuperChat(e,t,s,r){let i=this.getPublicPrefix();return this.videoFetch("POST",`${i}/videos/${e}/super-chats`,{amount:t,message:s,currency:r||"USD"})}async getSuperChats(e){let t=this.getPublicPrefix();return(await this.videoFetch("GET",`${t}/videos/${e}/super-chats`)).super_chats}async getRecommendations(e){let t=this.getPublicPrefix(),s=e?`?limit=${e}`:"";return(await this.videoFetch("GET",`${t}/recommendations${s}`)).videos}async getHomeFeed(e){let t=this.getPublicPrefix(),s=e?`?limit=${e}`:"";return(await this.videoFetch("GET",`${t}/recommendations/home${s}`)).videos}async getRelatedVideos(e,t){let s=this.getPublicPrefix(),r=t?`?limit=${t}`:"";return(await this.videoFetch("GET",`${s}/recommendations/related/${e}${r}`)).videos}async getTrendingVideos(e){let t=this.getPublicPrefix(),s=e?`?limit=${e}`:"";return(await this.videoFetch("GET",`${t}/recommendations/trending${s}`)).videos}async submitFeedback(e,t){let s=this.getPublicPrefix();await this.videoFetch("POST",`${s}/recommendations/feedback`,{video_id:e,feedback:t})}};var z=()=>{if(typeof window<"u"){let a=window.location.hostname;if(a==="localhost"||a==="127.0.0.1")return"ws://localhost:8087"}return"wss://game.connectbase.world"},w=class{constructor(e){this.ws=null;this.handlers={};this.reconnectAttempts=0;this.reconnectTimer=null;this.pingInterval=null;this.actionSequence=0;this._roomId=null;this._state=null;this._isConnected=!1;this.config={gameServerUrl:z(),autoReconnect:!0,maxReconnectAttempts:5,reconnectInterval:1e3,...e}}get roomId(){return this._roomId}get state(){return this._state}get isConnected(){return this._isConnected}on(e,t){return this.handlers[e]=t,this}connect(e){return new Promise((t,s)=>{if(this.ws?.readyState===WebSocket.OPEN){t();return}let r=this.buildConnectionUrl(e);this.ws=new WebSocket(r);let i=()=>{this._isConnected=!0,this.reconnectAttempts=0,this.startPingInterval(),this.handlers.onConnect?.(),t()},n=p=>{this._isConnected=!1,this.stopPingInterval(),this.handlers.onDisconnect?.(p),this.config.autoReconnect&&p.code!==1e3&&this.scheduleReconnect(e)},o=p=>{this.handlers.onError?.(p),s(new Error("WebSocket connection failed"))},c=p=>{this.handleMessage(p.data)};this.ws.addEventListener("open",i,{once:!0}),this.ws.addEventListener("close",n),this.ws.addEventListener("error",o,{once:!0}),this.ws.addEventListener("message",c)})}disconnect(){this.stopPingInterval(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws&&(this.ws.close(1e3,"Client disconnected"),this.ws=null),this._isConnected=!1,this._roomId=null}createRoom(e={}){return new Promise((t,s)=>{let r=i=>{if(i.type==="room_created"){let n=i.data;return this._roomId=n.room_id,this._state=n.initial_state,t(n.initial_state),!0}else if(i.type==="error")return s(new Error(i.data.message)),!0;return!1};this.sendWithHandler("create_room",e,r)})}joinRoom(e,t){return new Promise((s,r)=>{let i=n=>{if(n.type==="room_joined"){let o=n.data;return this._roomId=o.room_id,this._state=o.initial_state,s(o.initial_state),!0}else if(n.type==="error")return r(new Error(n.data.message)),!0;return!1};this.sendWithHandler("join_room",{room_id:e,metadata:t},i)})}leaveRoom(){return new Promise((e,t)=>{if(!this._roomId){t(new Error("Not in a room"));return}let s=r=>r.type==="room_left"?(this._roomId=null,this._state=null,e(),!0):r.type==="error"?(t(new Error(r.data.message)),!0):!1;this.sendWithHandler("leave_room",{},s)})}sendAction(e){if(!this._roomId)throw new Error("Not in a room");this.send("action",{type:e.type,data:e.data,client_timestamp:e.clientTimestamp??Date.now(),sequence:this.actionSequence++})}sendChat(e){if(!this._roomId)throw new Error("Not in a room");this.send("chat",{message:e})}requestState(){return new Promise((e,t)=>{if(!this._roomId){t(new Error("Not in a room"));return}let s=r=>{if(r.type==="state"){let i=r.data;return this._state=i,e(i),!0}else if(r.type==="error")return t(new Error(r.data.message)),!0;return!1};this.sendWithHandler("get_state",{},s)})}listRooms(){return new Promise((e,t)=>{let s=r=>{if(r.type==="room_list"){let i=r.data;return e(i.rooms),!0}else if(r.type==="error")return t(new Error(r.data.message)),!0;return!1};this.sendWithHandler("list_rooms",{},s)})}ping(){return new Promise((e,t)=>{let s=Date.now(),r=i=>{if(i.type==="pong"){let n=i.data,o=Date.now()-n.clientTimestamp;return this.handlers.onPong?.(n),e(o),!0}else if(i.type==="error")return t(new Error(i.data.message)),!0;return!1};this.sendWithHandler("ping",{timestamp:s},r)})}buildConnectionUrl(e){let s=this.config.gameServerUrl.replace(/^http/,"ws"),r=new URLSearchParams;r.set("client_id",this.config.clientId),e&&r.set("room_id",e),this.config.apiKey&&r.set("api_key",this.config.apiKey),this.config.accessToken&&r.set("token",this.config.accessToken);let i=this.config.appId||"";return`${s}/v1/game/${i}/ws?${r.toString()}`}send(e,t){if(!this.ws||this.ws.readyState!==WebSocket.OPEN)throw new Error("WebSocket is not connected");this.ws.send(JSON.stringify({type:e,data:t}))}sendWithHandler(e,t,s,r=15e3){let i=null,n=()=>{this.ws?.removeEventListener("message",o),i&&(clearTimeout(i),i=null)},o=c=>{try{let p=JSON.parse(c.data);s(p)&&n()}catch{}};this.ws?.addEventListener("message",o),i=setTimeout(()=>{n(),this.handlers.onError?.({code:"TIMEOUT",message:`Request '${e}' timed out after ${r}ms`})},r),this.send(e,t)}handleMessage(e){try{let t=JSON.parse(e);switch(t.type){case"delta":this.handleDelta(t.data);break;case"state":this._state=t.data,this.handlers.onStateUpdate?.(this._state);break;case"player_event":this.handlePlayerEvent(t.data);break;case"chat":this.handlers.onChat?.(t.data);break;case"error":this.handlers.onError?.(t.data);break;default:break}}catch{console.error("Failed to parse game message:",e)}}handleDelta(e){let t=e.delta;if(this._state){for(let s of t.changes)this.applyChange(s);this._state.version=t.toVersion}this.handlers.onDelta?.(t)}applyChange(e){if(!this._state)return;let t=e.path.split("."),s=this._state.state;for(let i=0;i<t.length-1;i++){let n=t[i];n in s||(s[n]={}),s=s[n]}let r=t[t.length-1];e.operation==="delete"?delete s[r]:s[r]=e.value}handlePlayerEvent(e){e.event==="joined"?this.handlers.onPlayerJoined?.(e.player):e.event==="left"&&this.handlers.onPlayerLeft?.(e.player)}scheduleReconnect(e){if(this.reconnectAttempts>=(this.config.maxReconnectAttempts??5)){console.error("Max reconnect attempts reached");return}let t=Math.min((this.config.reconnectInterval??1e3)*Math.pow(2,this.reconnectAttempts),3e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{console.log(`Reconnecting... (attempt ${this.reconnectAttempts})`),this.connect(e||this._roomId||void 0).catch(()=>{})},t)}startPingInterval(){this.pingInterval=setInterval(()=>{this.ping().catch(()=>{})},3e4)}stopPingInterval(){this.pingInterval&&(clearInterval(this.pingInterval),this.pingInterval=null)}},v=class{constructor(e,t,s){this.http=e,this.gameServerUrl=t||z().replace(/^ws/,"http"),this.appId=s}createClient(e){return new w({...e,gameServerUrl:this.gameServerUrl.replace(/^http/,"ws"),appId:this.appId,apiKey:this.http.getApiKey(),accessToken:this.http.getAccessToken()})}async listRooms(e){let t=e||this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/rooms`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to list rooms: ${s.statusText}`);return(await s.json()).rooms}async getRoom(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/rooms/${e}`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to get room: ${s.statusText}`);return s.json()}async createRoom(e,t={}){let s=e||this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${s}/rooms`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({app_id:e,category_id:t.categoryId,room_id:t.roomId,tick_rate:t.tickRate,max_players:t.maxPlayers,metadata:t.metadata})});if(!r.ok)throw new Error(`Failed to create room: ${r.statusText}`);return r.json()}async deleteRoom(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/rooms/${e}`,{method:"DELETE",headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to delete room: ${s.statusText}`)}getHeaders(){let e={},t=this.http.getApiKey();t&&(e["X-API-Key"]=t);let s=this.http.getAccessToken();return s&&(e.Authorization=`Bearer ${s}`),e}};var P=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async getConnectionStatus(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/connection`)}async getReport(e,t){let s=this.getPublicPrefix(),r=new URLSearchParams;e&&r.set("start",e),t&&r.set("end",t);let i=r.toString();return this.http.get(`${s}/ads/reports${i?`?${i}`:""}`)}async getReportSummary(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/reports/summary`)}async getAdMobReport(e,t){let s=this.getPublicPrefix(),r=new URLSearchParams;e&&r.set("start",e),t&&r.set("end",t);let i=r.toString();return this.http.get(`${s}/ads/admob/reports${i?`?${i}`:""}`)}async getAdMobReportSummary(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/admob/reports/summary`)}};var O=class{constructor(e,t,s,r){this.type="webtransport";this.transport=null;this.writer=null;this.config=e,this.onMessage=t,this.onClose=s,this.onError=r}async connect(){let e=this.buildUrl();this.transport=new WebTransport(e),await this.transport.ready,this.config.useUnreliableDatagrams!==!1&&this.readDatagrams();let t=await this.transport.createBidirectionalStream();this.writer=t.writable.getWriter(),this.readStream(t.readable),this.transport.closed.then(()=>{this.onClose()}).catch(s=>{this.onError(s)})}buildUrl(){let t=(this.config.gameServerUrl||"https://game.connectbase.world").replace(/^ws/,"http").replace(/^http:/,"https:"),s=new URLSearchParams;return s.set("client_id",this.config.clientId),this.config.apiKey&&s.set("api_key",this.config.apiKey),this.config.accessToken&&s.set("token",this.config.accessToken),`${t}/v1/game/webtransport?${s.toString()}`}async readDatagrams(){if(!this.transport)return;let e=this.transport.datagrams.readable.getReader();try{for(;;){let{value:t,done:s}=await e.read();if(s)break;this.onMessage(t)}}catch{}}async readStream(e){let t=e.getReader(),s=new Uint8Array(0);try{for(;;){let{value:r,done:i}=await t.read();if(i)break;let n=new Uint8Array(s.length+r.length);for(n.set(s),n.set(r,s.length),s=n;s.length>=4;){let o=new DataView(s.buffer).getUint32(0,!0);if(s.length<4+o)break;let c=s.slice(4,4+o);s=s.slice(4+o),this.onMessage(c)}}}catch{}}disconnect(){this.transport&&(this.transport.close(),this.transport=null,this.writer=null)}send(e,t=!0){if(!this.transport)throw new Error("Not connected");let s=typeof e=="string"?new TextEncoder().encode(e):e;if(t){if(this.writer){let r=new Uint8Array(4);new DataView(r.buffer).setUint32(0,s.length,!0);let i=new Uint8Array(4+s.length);i.set(r),i.set(s,4),this.writer.write(i)}}else{let r=this.config.maxDatagramSize||1200;s.length<=r?this.transport.datagrams.writable.getWriter().write(s):(console.warn("Datagram too large, falling back to reliable stream"),this.send(e,!0))}}isConnected(){return this.transport!==null}},D=class{constructor(e,t,s,r){this.type="websocket";this.ws=null;this.config=e,this.onMessage=t,this.onClose=s,this.onError=r}connect(){return new Promise((e,t)=>{let s=this.buildUrl();try{this.ws=new WebSocket(s),this.ws.binaryType="arraybuffer"}catch(c){t(c);return}let r=()=>{e()},i=()=>{this.onClose()},n=c=>{let p=new Error("WebSocket error");this.onError(p),t(p)},o=c=>{c.data instanceof ArrayBuffer?this.onMessage(new Uint8Array(c.data)):typeof c.data=="string"&&this.onMessage(new TextEncoder().encode(c.data))};this.ws.addEventListener("open",r,{once:!0}),this.ws.addEventListener("close",i),this.ws.addEventListener("error",n,{once:!0}),this.ws.addEventListener("message",o)})}buildUrl(){let t=(this.config.gameServerUrl||"wss://game.connectbase.world").replace(/^http/,"ws"),s=new URLSearchParams;s.set("client_id",this.config.clientId),this.config.apiKey&&s.set("api_key",this.config.apiKey),this.config.accessToken&&s.set("token",this.config.accessToken);let r=this.config.appId||"";return`${t}/v1/game/${r}/ws?${s.toString()}`}disconnect(){this.ws&&(this.ws.close(1e3,"Client disconnected"),this.ws=null)}send(e,t){if(!this.ws||this.ws.readyState!==WebSocket.OPEN)throw new Error("Not connected");typeof e=="string"?this.ws.send(e):this.ws.send(e)}isConnected(){return this.ws!==null&&this.ws.readyState===WebSocket.OPEN}};function K(){return typeof WebTransport<"u"}var L=class{constructor(e){this.transport=null;this.handlers={};this.reconnectAttempts=0;this.reconnectTimer=null;this.pingInterval=null;this.actionSequence=0;this._roomId=null;this._state=null;this._isConnected=!1;this._connectionStatus="disconnected";this._lastError=null;this._latency=0;this._transportType="websocket";this.decoder=new TextDecoder;this.pendingHandlers=new Map;this.messageId=0;this.config={gameServerUrl:this.getDefaultGameServerUrl(),autoReconnect:!0,maxReconnectAttempts:5,reconnectInterval:1e3,connectionTimeout:1e4,transport:"auto",useUnreliableDatagrams:!0,...e}}getDefaultGameServerUrl(){if(typeof window<"u"){let e=window.location.hostname;if(e==="localhost"||e==="127.0.0.1")return"ws://localhost:8087"}return"wss://game.connectbase.world"}get transportType(){return this._transportType}get roomId(){return this._roomId}get state(){return this._state}get isConnected(){return this._isConnected}get connectionState(){return{status:this._connectionStatus,transport:this._transportType==="auto"?null:this._transportType,roomId:this._roomId,latency:this._latency,reconnectAttempt:this.reconnectAttempts,lastError:this._lastError||void 0}}get latency(){return this._latency}on(e,t){return this.handlers[e]=t,this}async connect(e){if(this.transport?.isConnected())return;this._connectionStatus=this.reconnectAttempts>0?"reconnecting":"connecting";let t=this.config.transport||"auto",s=(t==="webtransport"||t==="auto")&&K(),r=o=>{this.handleMessage(this.decoder.decode(o))},i=()=>{this._isConnected=!1,this._connectionStatus="disconnected",this.stopPingInterval(),this.handlers.onDisconnect?.(new CloseEvent("close")),this.config.autoReconnect&&(this._connectionStatus="reconnecting",this.scheduleReconnect(e))},n=o=>{this._connectionStatus="error",this._lastError=o,this.handlers.onError?.(o)};if(s)try{this.transport=new O(this.config,r,i,n),await this.transport.connect(),this._transportType="webtransport"}catch{console.log("WebTransport failed, falling back to WebSocket"),this.transport=new D(this.config,r,i,n),await this.transport.connect(),this._transportType="websocket"}else this.transport=new D(this.config,r,i,n),await this.transport.connect(),this._transportType="websocket";this._isConnected=!0,this._connectionStatus="connected",this._lastError=null,this.reconnectAttempts=0,this.startPingInterval(),this.handlers.onConnect?.(),e&&await this.joinRoom(e)}disconnect(){this.stopPingInterval(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.transport&&(this.transport.disconnect(),this.transport=null),this._isConnected=!1,this._connectionStatus="disconnected",this._roomId=null,this._state=null}async createRoom(e={}){return new Promise((t,s)=>{let r=i=>{if(i.type==="room_created"){let n=i.data;this._roomId=n.room_id,this._state=n.initial_state,t(n.initial_state)}else i.type==="error"&&s(new Error(i.data.message))};this.sendWithHandler("create_room",e,r)})}async joinRoom(e,t){return new Promise((s,r)=>{let i=n=>{if(n.type==="room_joined"){let o=n.data;this._roomId=o.room_id,this._state=o.initial_state,s(o.initial_state)}else n.type==="error"&&r(new Error(n.data.message))};this.sendWithHandler("join_room",{room_id:e,metadata:t},i)})}async leaveRoom(){return new Promise((e,t)=>{if(!this._roomId){t(new Error("Not in a room"));return}let s=r=>{r.type==="room_left"?(this._roomId=null,this._state=null,e()):r.type==="error"&&t(new Error(r.data.message))};this.sendWithHandler("leave_room",{},s)})}sendAction(e,t=!1){if(!this._roomId)throw new Error("Not in a room");let s=JSON.stringify({type:"action",data:{type:e.type,data:e.data,client_timestamp:e.clientTimestamp??Date.now(),sequence:this.actionSequence++}}),r=t||this._transportType!=="webtransport";this.transport?.send(s,r)}sendChat(e){if(!this._roomId)throw new Error("Not in a room");this.send("chat",{message:e})}async requestState(){return new Promise((e,t)=>{if(!this._roomId){t(new Error("Not in a room"));return}let s=r=>{if(r.type==="state"){let i=r.data;this._state=i,e(i)}else r.type==="error"&&t(new Error(r.data.message))};this.sendWithHandler("get_state",{},s)})}async ping(){return new Promise((e,t)=>{let s=Date.now(),r=i=>{if(i.type==="pong"){let n=i.data,o=Date.now()-n.clientTimestamp;this._latency=o,this.handlers.onPong?.(n),e(o)}else i.type==="error"&&t(new Error(i.data.message))};this.sendWithHandler("ping",{timestamp:s},r)})}send(e,t){if(!this.transport?.isConnected())throw new Error("Not connected");let s=JSON.stringify({type:e,data:t});this.transport.send(s,!0)}sendWithHandler(e,t,s){let r=`msg_${this.messageId++}`;this.pendingHandlers.set(r,s),setTimeout(()=>{this.pendingHandlers.delete(r)},1e4),this.send(e,{...t,_msg_id:r})}handleMessage(e){try{let t=JSON.parse(e);if(t._msg_id&&this.pendingHandlers.has(t._msg_id)){let s=this.pendingHandlers.get(t._msg_id);this.pendingHandlers.delete(t._msg_id),s(t);return}switch(t.type){case"delta":this.handleDelta(t.data);break;case"state":this._state=t.data,this.handlers.onStateUpdate?.(this._state);break;case"player_event":this.handlePlayerEvent(t.data);break;case"chat":this.handlers.onChat?.(t.data);break;case"error":this.handlers.onError?.(t.data);break}}catch{console.error("Failed to parse game message:",e)}}handleDelta(e){let t=e.delta;if(this._state){for(let s of t.changes)this.applyChange(s);this._state.version=t.toVersion}this.handlers.onDelta?.(t)}applyChange(e){if(!this._state)return;let t=e.path.split("."),s=this._state.state;for(let i=0;i<t.length-1;i++){let n=t[i];n in s||(s[n]={}),s=s[n]}let r=t[t.length-1];e.operation==="delete"?delete s[r]:s[r]=e.value}handlePlayerEvent(e){e.event==="joined"?this.handlers.onPlayerJoined?.(e.player):e.event==="left"&&this.handlers.onPlayerLeft?.(e.player)}scheduleReconnect(e){if(this.reconnectAttempts>=(this.config.maxReconnectAttempts??5)){console.error("Max reconnect attempts reached");return}let t=Math.min((this.config.reconnectInterval??1e3)*Math.pow(2,this.reconnectAttempts),3e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{console.log(`Reconnecting... (attempt ${this.reconnectAttempts})`),this.connect(e||this._roomId||void 0).catch(()=>{})},t)}startPingInterval(){this.pingInterval=setInterval(()=>{this.ping().catch(()=>{})},3e4)}stopPingInterval(){this.pingInterval&&(clearInterval(this.pingInterval),this.pingInterval=null)}};var ne="https://api.connectbase.world",oe="https://socket.connectbase.world",ae="https://webrtc.connectbase.world",ce="https://video.connectbase.world",pe="https://game.connectbase.world",F=class{constructor(e={}){let t={baseUrl:e.baseUrl||ne,apiKey:e.apiKey,onTokenRefresh:e.onTokenRefresh,onAuthError:e.onAuthError};this.http=new S(t),this.auth=new T(this.http),this.database=new C(this.http),this.storage=new _(this.http),this.apiKey=new k(this.http),this.functions=new x(this.http),this.realtime=new E(this.http,e.socketUrl||oe),this.webrtc=new $(this.http,e.webrtcUrl||ae,e.appId),this.errorTracker=new I(this.http,e.errorTracker),this.oauth=new M(this.http),this.payment=new A(this.http),this.subscription=new U(this.http),this.push=new q(this.http),this.video=new G(this.http,e.videoUrl||ce),this.game=new v(this.http,e.gameUrl||pe,e.appId),this.ads=new P(this.http)}setTokens(e,t){this.http.setTokens(e,t)}clearTokens(){this.http.clearTokens()}updateConfig(e){this.http.updateConfig(e)}},le=F;return se(he);})();
|
|
1
|
+
"use strict";var ConnectBaseModule=(()=>{var H=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var ee=(a,e)=>{for(var t in e)H(a,t,{get:e[t],enumerable:!0})},te=(a,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Y(e))!Z.call(a,r)&&r!==t&&H(a,r,{get:()=>e[r],enumerable:!(s=X(e,r))||s.enumerable});return a};var se=a=>te(H({},"__esModule",{value:!0}),a);var he={};ee(he,{AdsAPI:()=>w,ApiError:()=>g,AuthError:()=>f,ConnectBase:()=>O,GameAPI:()=>P,GameRoom:()=>R,GameRoomTransport:()=>F,VideoProcessingError:()=>v,default:()=>le,isWebTransportSupported:()=>W});var g=class extends Error{constructor(t,s){super(s);this.statusCode=t;this.name="ApiError"}},f=class extends Error{constructor(e){super(e),this.name="AuthError"}};var T=class{constructor(e){this.isRefreshing=!1;this.refreshPromise=null;this.config=e}updateConfig(e){this.config={...this.config,...e}}setTokens(e,t){this.config.accessToken=e,this.config.refreshToken=t}clearTokens(){this.config.accessToken=void 0,this.config.refreshToken=void 0}hasApiKey(){return!!this.config.apiKey}getApiKey(){return this.config.apiKey}getAccessToken(){return this.config.accessToken}getBaseUrl(){return this.config.baseUrl}async refreshAccessToken(){if(this.isRefreshing)return this.refreshPromise;if(this.isRefreshing=!0,!this.config.refreshToken){this.isRefreshing=!1;let e=new f("Refresh token is missing. Please login again.");throw this.config.onAuthError?.(e),e}return this.refreshPromise=(async()=>{try{let e=await fetch(`${this.config.baseUrl}/v1/auth/re-issue`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.refreshToken}`}});if(!e.ok)throw new Error("Token refresh failed");let t=await e.json();return this.config.accessToken=t.access_token,this.config.refreshToken=t.refresh_token,this.config.onTokenRefresh?.({accessToken:t.access_token,refreshToken:t.refresh_token}),t.access_token}catch{this.clearTokens();let e=new f("Token refresh failed. Please login again.");throw this.config.onAuthError?.(e),e}finally{this.isRefreshing=!1,this.refreshPromise=null}})(),this.refreshPromise}isTokenExpired(e){try{let t=JSON.parse(atob(e.split(".")[1])),s=Date.now()/1e3;return t.exp<s+300}catch{return!0}}async prepareHeaders(e){let t=new Headers;if(t.set("Content-Type","application/json"),this.config.apiKey&&t.set("X-API-Key",this.config.apiKey),!e?.skipAuth&&this.config.accessToken){let s=this.config.accessToken;if(this.isTokenExpired(s)&&this.config.refreshToken){let r=await this.refreshAccessToken();r&&(s=r)}t.set("Authorization",`Bearer ${s}`)}return e?.headers&&Object.entries(e.headers).forEach(([s,r])=>{t.set(s,r)}),t}async handleResponse(e){if(!e.ok){let t=await e.json().catch(()=>({message:e.statusText}));throw new g(e.status,t.message||t.error||"Unknown error")}return e.status===204||e.headers.get("content-length")==="0"?{}:e.json()}async get(e,t){let s=await this.prepareHeaders(t),r=await fetch(`${this.config.baseUrl}${e}`,{method:"GET",headers:s});return this.handleResponse(r)}async post(e,t,s){let r=await this.prepareHeaders(s);t instanceof FormData&&r.delete("Content-Type");let i=await fetch(`${this.config.baseUrl}${e}`,{method:"POST",headers:r,body:t instanceof FormData?t:JSON.stringify(t)});return this.handleResponse(i)}async put(e,t,s){let r=await this.prepareHeaders(s),i=await fetch(`${this.config.baseUrl}${e}`,{method:"PUT",headers:r,body:JSON.stringify(t)});return this.handleResponse(i)}async patch(e,t,s){let r=await this.prepareHeaders(s),i=await fetch(`${this.config.baseUrl}${e}`,{method:"PATCH",headers:r,body:JSON.stringify(t)});return this.handleResponse(i)}async delete(e,t){let s=await this.prepareHeaders(t),r=await fetch(`${this.config.baseUrl}${e}`,{method:"DELETE",headers:s});return this.handleResponse(r)}};var j="cb_guest_";function b(a){typeof window>"u"||(a?typeof window.__cbSetMember=="function"&&window.__cbSetMember(a):typeof window.__cbClearMember=="function"&&window.__cbClearMember())}function re(a){let e=0;for(let t=0;t<a.length;t++){let s=a.charCodeAt(t);e=(e<<5)-e+s,e=e&e}return Math.abs(e).toString(36)}var C=class{constructor(e){this.http=e;this.guestMemberLoginPromise=null;this.cachedGuestMemberTokenKey=null}async getAuthSettings(){return this.http.get("/v1/public/auth-settings",{skipAuth:!0})}async signUpMember(e){let t=await this.http.post("/v1/public/app-members/signup",e,{skipAuth:!0});return this.http.setTokens(t.access_token,t.refresh_token),b(t.member_id),t}async signInMember(e){let t=await this.http.post("/v1/public/app-members/signin",e,{skipAuth:!0});return this.http.setTokens(t.access_token,t.refresh_token),b(t.member_id),t}async signInAsGuestMember(){if(this.guestMemberLoginPromise)return this.guestMemberLoginPromise;this.guestMemberLoginPromise=this.executeGuestMemberLogin();try{return await this.guestMemberLoginPromise}finally{this.guestMemberLoginPromise=null}}async signOut(){try{await this.http.post("/v1/auth/logout")}finally{this.http.clearTokens(),b(null)}}clearGuestMemberTokens(){typeof sessionStorage>"u"||sessionStorage.removeItem(this.getGuestMemberTokenKey())}async executeGuestMemberLogin(){let e=this.getStoredGuestMemberTokens();if(e){if(!this.isTokenExpired(e.accessToken))try{this.http.setTokens(e.accessToken,e.refreshToken);let s=await this.http.get("/v1/public/app-members/me");if(s.is_active)return b(s.member_id),{member_id:s.member_id,access_token:e.accessToken,refresh_token:e.refreshToken};this.clearGuestMemberTokens()}catch{this.http.clearTokens()}if(e.refreshToken&&!this.isTokenExpired(e.refreshToken))try{let s=await this.http.post("/v1/auth/re-issue",{},{headers:{Authorization:`Bearer ${e.refreshToken}`},skipAuth:!0});return this.http.setTokens(s.access_token,s.refresh_token),this.storeGuestMemberTokens(s.access_token,s.refresh_token,e.memberId),b(e.memberId),{member_id:e.memberId,access_token:s.access_token,refresh_token:s.refresh_token}}catch{this.clearGuestMemberTokens()}else this.clearGuestMemberTokens()}let t=await this.http.post("/v1/public/app-members",{},{skipAuth:!0});return this.http.setTokens(t.access_token,t.refresh_token),this.storeGuestMemberTokens(t.access_token,t.refresh_token,t.member_id),b(t.member_id),t}isTokenExpired(e){try{let t=JSON.parse(atob(e.split(".")[1])),s=Date.now()/1e3;return t.exp<s}catch{return!0}}getGuestMemberTokenKey(){if(this.cachedGuestMemberTokenKey)return this.cachedGuestMemberTokenKey;let e=this.http.getApiKey();if(!e)this.cachedGuestMemberTokenKey=`${j}default`;else{let t=re(e);this.cachedGuestMemberTokenKey=`${j}${t}`}return this.cachedGuestMemberTokenKey}getStoredGuestMemberTokens(){if(typeof sessionStorage>"u")return null;let e=sessionStorage.getItem(this.getGuestMemberTokenKey());if(!e)return null;try{return JSON.parse(e)}catch{return null}}storeGuestMemberTokens(e,t,s){typeof sessionStorage>"u"||sessionStorage.setItem(this.getGuestMemberTokenKey(),JSON.stringify({accessToken:e,refreshToken:t,memberId:s}))}};var _=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async getTables(e){return(await this.http.get(`/v1/databases/json-databases/${e}/tables`)).tables}async createTable(e,t){return this.http.post(`/v1/databases/json-databases/${e}/tables`,t)}async deleteTable(e,t){await this.http.delete(`/v1/databases/json-databases/${e}/tables/${t}`)}async getColumns(e){return(await this.http.get(`/v1/tables/${e}/columns`)).columns}async createColumn(e,t){return this.http.post(`/v1/tables/${e}/columns`,t)}async updateColumn(e,t,s){return this.http.patch(`/v1/tables/${e}/columns/${t}`,s)}async deleteColumn(e,t){await this.http.delete(`/v1/tables/${e}/columns/${t}`)}async getData(e,t){let s=this.getPublicPrefix();if(t?.where||t?.select||t?.exclude)return this.queryData(e,t);let r=new URLSearchParams;t?.limit&&r.append("limit",t.limit.toString()),t?.offset&&r.append("offset",t.offset.toString());let i=r.toString(),n=i?`${s}/tables/${e}/data?${i}`:`${s}/tables/${e}/data`;return this.http.get(n)}async queryData(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/tables/${e}/data/query`,{where:t.where,order_by:t.orderBy,order_direction:t.orderDirection,limit:t.limit,offset:t.offset,select:t.select,exclude:t.exclude})}async getDataById(e,t){let s=this.getPublicPrefix();return this.http.get(`${s}/tables/${e}/data/${t}`)}async createData(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/tables/${e}/data`,t)}async updateData(e,t,s){let r=this.getPublicPrefix();return this.http.put(`${r}/tables/${e}/data/${t}`,s)}async deleteData(e,t){let s=this.getPublicPrefix();await this.http.delete(`${s}/tables/${e}/data/${t}`)}async createMany(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/tables/${e}/data/bulk`,{data:t.map(r=>r.data)})}async deleteWhere(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/tables/${e}/data/delete-where`,{where:t})}async aggregate(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/aggregate`,{table_id:e,pipeline:t})}async search(e,t,s,r){let i=this.getPublicPrefix();return this.http.post(`${i}/search`,{table_id:e,query:t,fields:s,...r})}async autocomplete(e,t,s,r){let i=this.getPublicPrefix();return this.http.post(`${i}/autocomplete`,{table_id:e,query:t,field:s,...r})}async geoQuery(e,t,s,r){let i=this.getPublicPrefix();return this.http.post(`${i}/geo`,{table_id:e,field:t,...s,...r})}async batch(e){let t=this.getPublicPrefix();return this.http.post(`${t}/batch`,{operations:e})}async transaction(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/transactions`,{reads:e,writes:t})}async getDataWithPopulate(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/tables/${e}/data/query`,{where:t.where,order_by:t.orderBy,order_direction:t.orderDirection,limit:t.limit,offset:t.offset,select:t.select,exclude:t.exclude,populate:t.populate})}async listSecurityRules(e){return(await this.http.get(`/v1/apps/${e}/security/rules`)).rules}async createSecurityRule(e,t){return this.http.post(`/v1/apps/${e}/security/rules`,t)}async updateSecurityRule(e,t,s){return this.http.put(`/v1/apps/${e}/security/rules/${t}`,s)}async deleteSecurityRule(e,t){await this.http.delete(`/v1/apps/${e}/security/rules/${t}`)}async listIndexes(e,t){return(await this.http.get(`/v1/apps/${e}/tables/${t}/indexes`)).indexes}async createIndex(e,t,s){return this.http.post(`/v1/apps/${e}/tables/${t}/indexes`,s)}async deleteIndex(e,t,s){await this.http.delete(`/v1/apps/${e}/tables/${t}/indexes/${s}`)}async analyzeIndexes(e,t){return this.http.get(`/v1/apps/${e}/tables/${t}/indexes/analyze`)}async listRelations(e,t){return(await this.http.get(`/v1/apps/${e}/tables/${t}/relations`)).relations}async createRelation(e,t,s){return this.http.post(`/v1/apps/${e}/tables/${t}/relations`,s)}async deleteRelation(e,t,s){await this.http.delete(`/v1/apps/${e}/tables/${t}/relations/${s}`)}async listTriggers(e){return(await this.http.get(`/v1/apps/${e}/triggers`)).triggers}async createTrigger(e,t){return this.http.post(`/v1/apps/${e}/triggers`,t)}async updateTrigger(e,t,s){return this.http.put(`/v1/apps/${e}/triggers/${t}`,s)}async deleteTrigger(e,t){await this.http.delete(`/v1/apps/${e}/triggers/${t}`)}async setTTL(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/ttl`,t)}async getTTL(e,t){return this.http.get(`/v1/apps/${e}/lifecycle/ttl/${t}`)}async setRetentionPolicy(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/retention`,t)}async getRetentionPolicy(e,t){return this.http.get(`/v1/apps/${e}/lifecycle/retention/${t}`)}};var k=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async getFiles(e){let t=this.getPublicPrefix();return(await this.http.get(`${t}/storages/files/${e}/items`)).files}async uploadFile(e,t,s){let r=this.getPublicPrefix(),i=new FormData;return i.append("file",t),s&&i.append("parent_id",s),this.http.post(`${r}/storages/files/${e}/upload`,i)}async uploadFiles(e,t,s){let r=[];for(let i of t){let n=await this.uploadFile(e,i,s);r.push(n)}return r}async createFolder(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/storages/files/${e}/folders`,t)}async deleteFile(e,t){let s=this.getPublicPrefix();await this.http.delete(`${s}/storages/files/${e}/items/${t}`)}async moveFile(e,t,s){let r=this.getPublicPrefix();await this.http.post(`${r}/storages/files/${e}/items/${t}/move`,s)}async renameFile(e,t,s){let r=this.getPublicPrefix();return this.http.patch(`${r}/storages/files/${e}/items/${t}/rename`,s)}getFileUrl(e){return e.url||null}isImageFile(e){return e.mime_type?.startsWith("image/")||!1}async uploadByPath(e,t,s,r){let i=this.getPublicPrefix(),n=new FormData;n.append("file",s);let o=r?.overwrite!==!1;n.append("overwrite",o.toString());let c=t.startsWith("/")?t.slice(1):t;return this.http.post(`${i}/storages/files/${e}/path/${c}`,n)}async getByPath(e,t){let s=this.getPublicPrefix(),r=t.startsWith("/")?t.slice(1):t;return this.http.get(`${s}/storages/files/${e}/path/${r}`)}async getUrlByPath(e,t){try{return(await this.getByPath(e,t)).url||null}catch{return null}}async setPageMeta(e,t){let s=this.getPublicPrefix();return this.http.put(`${s}/storages/webs/${e}/page-metas`,t)}async batchSetPageMeta(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/storages/webs/${e}/page-metas/batch`,t)}async listPageMetas(e){let t=this.getPublicPrefix();return this.http.get(`${t}/storages/webs/${e}/page-metas`)}async getPageMeta(e,t){let s=this.getPublicPrefix(),r=encodeURIComponent(t);return this.http.get(`${s}/storages/webs/${e}/page-metas/get?path=${r}`)}async deletePageMeta(e,t){let s=this.getPublicPrefix(),r=encodeURIComponent(t);await this.http.delete(`${s}/storages/webs/${e}/page-metas?path=${r}`)}async deleteAllPageMetas(e){let t=this.getPublicPrefix();await this.http.delete(`${t}/storages/webs/${e}/page-metas/all`)}};var x=class{constructor(e){this.http=e}async getApiKeys(e){return this.http.get(`/v1/apps/${e}/api-keys`)}async createApiKey(e,t){return this.http.post(`/v1/apps/${e}/api-keys`,t)}async updateApiKey(e,t,s){return this.http.patch(`/v1/apps/${e}/api-keys/${t}`,s)}async deleteApiKey(e,t){await this.http.delete(`/v1/apps/${e}/api-keys/${t}`)}};var E=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async invoke(e,t,s){let r=this.getPublicPrefix(),i={};return t!==void 0&&(i.payload=t),s!==void 0&&(i.timeout=s),this.http.post(`${r}/functions/${e}/invoke`,i)}async call(e,t){let s=await this.invoke(e,t);if(!s.success)throw new Error(s.error||"Function execution failed");return s.result}};var $=class{constructor(e,t){this.ws=null;this.state="disconnected";this._connectionId=null;this._appId=null;this.options={maxRetries:5,retryInterval:1e3,userId:"",accessToken:""};this.retryCount=0;this.pendingRequests=new Map;this.subscriptions=new Map;this.streamSessions=new Map;this.stateHandlers=[];this.errorHandlers=[];this.http=e,this.socketUrl=t,this.clientId=this.generateClientId()}get connectionId(){return this._connectionId}get appId(){return this._appId}async connect(e={}){if(!(this.state==="connected"||this.state==="connecting"))return this.options={...this.options,...e},e.userId&&(this.userId=e.userId),this.doConnect()}disconnect(){this.state="disconnected",this.notifyStateChange(),this.ws&&(this.ws.close(),this.ws=null),this.pendingRequests.forEach(e=>{clearTimeout(e.timeout),e.reject(new Error("Connection closed"))}),this.pendingRequests.clear(),this.subscriptions.clear()}async subscribe(e,t={}){if(this.state!=="connected")throw new Error("Not connected. Call connect() first.");let s=this.generateRequestId(),r=await this.sendRequest({category:e,action:"subscribe",request_id:s}),i={category:r.category,persist:r.persist,historyCount:r.history_count,readReceipt:r.read_receipt},n=[];return this.subscriptions.set(e,{info:i,handlers:n}),{info:i,send:async(c,p)=>{await this.sendMessage(e,c,p)},getHistory:async c=>this.getHistory(e,c??t.historyLimit),unsubscribe:async()=>{await this.unsubscribe(e)},onMessage:c=>{n.push(c)}}}async unsubscribe(e){if(this.state!=="connected")return;let t=this.generateRequestId();await this.sendRequest({category:e,action:"unsubscribe",request_id:t}),this.subscriptions.delete(e)}async sendMessage(e,t,s={}){if(this.state!=="connected")throw new Error("Not connected");let i=s.includeSelf!==!1,n=this.generateRequestId();await this.sendRequest({category:e,action:"send",data:{data:t,broadcast:i},request_id:n})}async getHistory(e,t){if(this.state!=="connected")throw new Error("Not connected");let s=this.generateRequestId(),r=await this.sendRequest({category:e,action:"history",data:t?{limit:t}:void 0,request_id:s});return{category:r.category,messages:r.messages.map(i=>({id:i.id,category:i.category,from:i.from,data:i.data,sentAt:i.sent_at})),total:r.total}}async stream(e,t,s={}){if(this.state!=="connected")throw new Error("Not connected. Call connect() first.");let r=this.generateRequestId(),i=s.sessionId||this.generateRequestId();return this.streamSessions.set(i,{handlers:t,requestId:r}),this.sendRaw({category:"",action:"stream",data:{provider:s.provider,model:s.model,messages:e,system:s.system,temperature:s.temperature,max_tokens:s.maxTokens,session_id:i,metadata:s.metadata},request_id:r}),{sessionId:i,stop:async()=>{await this.stopStream(i)}}}async stopStream(e){if(this.state!=="connected")return;let t=this.generateRequestId();this.sendRaw({category:"",action:"stream_stop",data:{session_id:e},request_id:t}),this.streamSessions.delete(e)}getState(){return this.state}onStateChange(e){return this.stateHandlers.push(e),()=>{let t=this.stateHandlers.indexOf(e);t>-1&&this.stateHandlers.splice(t,1)}}onError(e){return this.errorHandlers.push(e),()=>{let t=this.errorHandlers.indexOf(e);t>-1&&this.errorHandlers.splice(t,1)}}async doConnect(){return new Promise((e,t)=>{this.state="connecting",this.notifyStateChange();let s=this.socketUrl.replace(/^http/,"ws"),r;if(this.options.accessToken)r=`${s}/v1/realtime/auth?access_token=${encodeURIComponent(this.options.accessToken)}&client_id=${this.clientId}`;else{let i=this.http.getApiKey();if(!i){t(new Error("API Key or accessToken is required for realtime connection"));return}r=`${s}/v1/realtime/auth?api_key=${encodeURIComponent(i)}&client_id=${this.clientId}`}this.userId&&(r+=`&user_id=${encodeURIComponent(this.userId)}`);try{this.ws=new WebSocket(r),this.ws.onopen=()=>{},this.ws.onmessage=i=>{let n=i.data.split(`
|
|
2
|
+
`).filter(o=>o.trim());for(let o of n)try{let c=JSON.parse(o);this.handleServerMessage(c,e)}catch(c){console.error("[Realtime] Failed to parse message:",o,c)}},this.ws.onclose=()=>{(this.state==="connected"||this.state==="connecting")&&this.handleDisconnect()},this.ws.onerror=i=>{console.error("[Realtime] WebSocket error:",i),this.notifyError(new Error("WebSocket connection error")),this.state==="connecting"&&t(new Error("Failed to connect"))}}catch(i){t(i)}})}handleServerMessage(e,t){switch(e.event){case"connected":{let s=e.data;this._connectionId=s.connection_id,this._appId=s.app_id,this.state="connected",this.retryCount=0,this.notifyStateChange(),t&&t();break}case"subscribed":case"unsubscribed":case"sent":case"result":case"history":{if(e.request_id){let s=this.pendingRequests.get(e.request_id);s&&(clearTimeout(s.timeout),s.resolve(e.data),this.pendingRequests.delete(e.request_id))}break}case"message":{let s=e.data,r=this.subscriptions.get(s.category);if(r){let i={id:s.id,category:s.category,from:s.from,data:s.data,sentAt:s.sent_at};r.handlers.forEach(n=>n(i))}break}case"error":{if(e.request_id){let s=this.pendingRequests.get(e.request_id);s&&(clearTimeout(s.timeout),s.reject(new Error(e.error||"Unknown error")),this.pendingRequests.delete(e.request_id))}else this.notifyError(new Error(e.error||"Unknown error"));break}case"pong":break;case"stream_token":{let s=e.data,r=this.streamSessions.get(s.session_id);r?.handlers.onToken&&r.handlers.onToken(s.token,s.index);break}case"stream_done":{let s=e.data,r=this.streamSessions.get(s.session_id);r?.handlers.onDone&&r.handlers.onDone({sessionId:s.session_id,fullText:s.full_text,totalTokens:s.total_tokens,promptTokens:s.prompt_tokens,duration:s.duration_ms}),this.streamSessions.delete(s.session_id);break}case"stream_error":{let s=e.data;if(e.request_id){for(let[r,i]of this.streamSessions)if(i.requestId===e.request_id){i.handlers.onError&&i.handlers.onError(new Error(s.message)),this.streamSessions.delete(r);break}}break}}}handleDisconnect(){this.ws=null,this._connectionId=null,this.retryCount<this.options.maxRetries?(this.state="reconnecting",this.notifyStateChange(),this.retryCount++,setTimeout(()=>{this.doConnect().catch(e=>{console.error("[Realtime] Reconnect failed:",e)})},this.options.retryInterval*this.retryCount)):(this.state="disconnected",this.notifyStateChange(),this.notifyError(new Error("Connection lost. Max retries exceeded.")))}sendRequest(e){return new Promise((t,s)=>{if(!this.ws||this.ws.readyState!==WebSocket.OPEN){s(new Error("Not connected"));return}let r=setTimeout(()=>{this.pendingRequests.delete(e.request_id),s(new Error("Request timeout"))},3e4);this.pendingRequests.set(e.request_id,{resolve:t,reject:s,timeout:r}),this.ws.send(JSON.stringify(e))})}sendRaw(e){if(!this.ws||this.ws.readyState!==WebSocket.OPEN)throw new Error("Not connected");this.ws.send(JSON.stringify(e))}notifyStateChange(){this.stateHandlers.forEach(e=>e(this.state))}notifyError(e){this.errorHandlers.forEach(t=>t(e))}generateClientId(){return"cb_"+Math.random().toString(36).substring(2,15)}generateRequestId(){return"req_"+Date.now()+"_"+Math.random().toString(36).substring(2,9)}};var I=class{constructor(e,t,s){this.ws=null;this.state="disconnected";this.stateListeners=[];this.errorListeners=[];this.peerJoinedListeners=[];this.peerLeftListeners=[];this.remoteStreamListeners=[];this.reconnectAttempts=0;this.maxReconnectAttempts=5;this.reconnectTimeout=null;this.currentRoomId=null;this.currentPeerId=null;this.currentUserId=null;this.isBroadcaster=!1;this.localStream=null;this.channelType="interactive";this.peerConnections=new Map;this.remoteStreams=new Map;this.iceServers=[];this.http=e,this.webrtcUrl=t,this.appId=s}async getICEServers(){let e=await this.http.get("/v1/ice-servers");return this.iceServers=e.ice_servers,e.ice_servers}async connect(e){if(this.state==="connected"||this.state==="connecting")throw new Error("\uC774\uBBF8 \uC5F0\uACB0\uB418\uC5B4 \uC788\uAC70\uB098 \uC5F0\uACB0 \uC911\uC785\uB2C8\uB2E4");if(this.setState("connecting"),this.currentRoomId=e.roomId,this.currentUserId=e.userId||null,this.isBroadcaster=e.isBroadcaster||!1,this.localStream=e.localStream||null,this.iceServers.length===0)try{await this.getICEServers()}catch{this.iceServers=[{urls:"stun:stun.l.google.com:19302"}]}return this.connectWebSocket()}connectWebSocket(){return new Promise((e,t)=>{let s=this.buildWebSocketUrl();this.ws=new WebSocket(s);let r=setTimeout(()=>{this.state==="connecting"&&(this.ws?.close(),t(new Error("\uC5F0\uACB0 \uC2DC\uAC04 \uCD08\uACFC")))},1e4);this.ws.onopen=()=>{clearTimeout(r),this.reconnectAttempts=0,this.sendSignaling({type:"join",room_id:this.currentRoomId,data:{user_id:this.currentUserId,is_broadcaster:this.isBroadcaster}})},this.ws.onmessage=async i=>{try{let n=JSON.parse(i.data);await this.handleSignalingMessage(n,e,t)}catch(n){console.error("Failed to parse signaling message:",n)}},this.ws.onerror=i=>{clearTimeout(r),console.error("WebSocket error:",i),this.emitError(new Error("WebSocket \uC5F0\uACB0 \uC624\uB958"))},this.ws.onclose=i=>{clearTimeout(r),this.state==="connecting"&&t(new Error("\uC5F0\uACB0\uC774 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4")),this.handleDisconnect(i)}})}buildWebSocketUrl(){let e=this.webrtcUrl.replace("https://","wss://").replace("http://","ws://"),t=this.http.getApiKey(),s=this.http.getAccessToken(),r="";if(s?r=`access_token=${encodeURIComponent(s)}`:t&&(r=`api_key=${encodeURIComponent(t)}`),!this.appId)throw new Error("WebRTC \uC5F0\uACB0\uC5D0\uB294 appId\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. ConnectBase \uCD08\uAE30\uD654 \uC2DC appId\uB97C \uC124\uC815\uD558\uC138\uC694.");return`${e}/v1/apps/${this.appId}/signaling?${r}`}async handleSignalingMessage(e,t,s){switch(e.type){case"joined":if(this.setState("connected"),this.currentPeerId=e.peer_id||null,e.data&&typeof e.data=="object"){let n=e.data;n.channel_type&&(this.channelType=n.channel_type);let o=n.peers||[];for(let c of o)c.peer_id!==this.currentPeerId&&await this.createPeerConnection(c.peer_id,!0)}t?.();break;case"peer_joined":if(e.peer_id&&e.peer_id!==this.currentPeerId){let n={peer_id:e.peer_id,...typeof e.data=="object"?e.data:{}};this.emitPeerJoined(e.peer_id,n),await this.createPeerConnection(e.peer_id,!1)}break;case"peer_left":e.peer_id&&(this.closePeerConnection(e.peer_id),this.emitPeerLeft(e.peer_id));break;case"offer":e.peer_id&&e.sdp&&await this.handleOffer(e.peer_id,e.sdp);break;case"answer":e.peer_id&&e.sdp&&await this.handleAnswer(e.peer_id,e.sdp);break;case"ice_candidate":e.peer_id&&e.candidate&&await this.handleICECandidate(e.peer_id,e.candidate);break;case"error":let r=typeof e.data=="string"?e.data:"Unknown error",i=new Error(r);this.emitError(i),s?.(i);break}}async createPeerConnection(e,t){this.closePeerConnection(e);let s={iceServers:this.iceServers.map(i=>({urls:i.urls,username:i.username,credential:i.credential}))},r=new RTCPeerConnection(s);if(this.peerConnections.set(e,r),this.localStream&&this.localStream.getTracks().forEach(i=>{r.addTrack(i,this.localStream)}),r.onicecandidate=i=>{i.candidate&&this.sendSignaling({type:"ice_candidate",target_id:e,candidate:i.candidate.toJSON()})},r.ontrack=i=>{let[n]=i.streams;n&&(this.remoteStreams.set(e,n),this.emitRemoteStream(e,n))},r.onconnectionstatechange=()=>{r.connectionState==="failed"&&(console.warn(`Peer connection failed: ${e}`),this.closePeerConnection(e))},t){let i=await r.createOffer();await r.setLocalDescription(i),this.sendSignaling({type:"offer",target_id:e,sdp:i.sdp})}return r}async handleOffer(e,t){let s=this.peerConnections.get(e);s||(s=await this.createPeerConnection(e,!1)),await s.setRemoteDescription(new RTCSessionDescription({type:"offer",sdp:t}));let r=await s.createAnswer();await s.setLocalDescription(r),this.sendSignaling({type:"answer",target_id:e,sdp:r.sdp})}async handleAnswer(e,t){let s=this.peerConnections.get(e);s&&await s.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:t}))}async handleICECandidate(e,t){let s=this.peerConnections.get(e);if(s)try{await s.addIceCandidate(new RTCIceCandidate(t))}catch(r){console.warn("Failed to add ICE candidate:",r)}}closePeerConnection(e){let t=this.peerConnections.get(e);t&&(t.close(),this.peerConnections.delete(e)),this.remoteStreams.delete(e)}sendSignaling(e){this.ws&&this.ws.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(e))}handleDisconnect(e){let t=this.state==="connected";this.setState("disconnected"),this.peerConnections.forEach((s,r)=>{s.close(),this.emitPeerLeft(r)}),this.peerConnections.clear(),this.remoteStreams.clear(),t&&e.code!==1e3&&this.reconnectAttempts<this.maxReconnectAttempts&&this.attemptReconnect()}attemptReconnect(){this.reconnectAttempts++,this.setState("reconnecting");let e=Math.min(5e3*Math.pow(2,this.reconnectAttempts-1),3e4);this.reconnectTimeout=setTimeout(async()=>{try{await this.connectWebSocket()}catch{this.reconnectAttempts<this.maxReconnectAttempts?this.attemptReconnect():(this.setState("failed"),this.emitError(new Error("\uC7AC\uC5F0\uACB0 \uC2E4\uD328: \uCD5C\uB300 \uC2DC\uB3C4 \uD69F\uC218 \uCD08\uACFC")))}},e)}disconnect(){this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null),this.ws&&this.ws.readyState===WebSocket.OPEN&&(this.sendSignaling({type:"leave"}),this.ws.close(1e3,"User disconnected")),this.peerConnections.forEach(e=>e.close()),this.peerConnections.clear(),this.remoteStreams.clear(),this.ws=null,this.currentRoomId=null,this.currentPeerId=null,this.localStream=null,this.setState("disconnected")}getState(){return this.state}getRoomId(){return this.currentRoomId}getPeerId(){return this.currentPeerId}getChannelType(){return this.channelType}getRemoteStream(e){return this.remoteStreams.get(e)}getAllRemoteStreams(){return new Map(this.remoteStreams)}replaceLocalStream(e){this.localStream=e,this.peerConnections.forEach(t=>{let s=t.getSenders();e.getTracks().forEach(r=>{let i=s.find(n=>n.track?.kind===r.kind);i?i.replaceTrack(r):t.addTrack(r,e)})})}setAudioEnabled(e){this.localStream&&this.localStream.getAudioTracks().forEach(t=>{t.enabled=e})}setVideoEnabled(e){this.localStream&&this.localStream.getVideoTracks().forEach(t=>{t.enabled=e})}onStateChange(e){return this.stateListeners.push(e),()=>{this.stateListeners=this.stateListeners.filter(t=>t!==e)}}onError(e){return this.errorListeners.push(e),()=>{this.errorListeners=this.errorListeners.filter(t=>t!==e)}}onPeerJoined(e){return this.peerJoinedListeners.push(e),()=>{this.peerJoinedListeners=this.peerJoinedListeners.filter(t=>t!==e)}}onPeerLeft(e){return this.peerLeftListeners.push(e),()=>{this.peerLeftListeners=this.peerLeftListeners.filter(t=>t!==e)}}onRemoteStream(e){return this.remoteStreamListeners.push(e),()=>{this.remoteStreamListeners=this.remoteStreamListeners.filter(t=>t!==e)}}setState(e){this.state!==e&&(this.state=e,this.stateListeners.forEach(t=>t(e)))}emitError(e){this.errorListeners.forEach(t=>t(e))}emitPeerJoined(e,t){this.peerJoinedListeners.forEach(s=>s(e,t))}emitPeerLeft(e){this.peerLeftListeners.forEach(t=>t(e))}emitRemoteStream(e,t){this.remoteStreamListeners.forEach(s=>s(e,t))}async validate(){if(!this.appId)throw new Error("WebRTC \uAC80\uC99D\uC5D0\uB294 appId\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. ConnectBase \uCD08\uAE30\uD654 \uC2DC appId\uB97C \uC124\uC815\uD558\uC138\uC694.");return this.http.get(`/v1/apps/${this.appId}/validate`)}async getStats(e){return this.http.get(`/v1/apps/${e}/webrtc/stats`)}async getRooms(e){return this.http.get(`/v1/apps/${e}/webrtc/rooms`)}};var M=class{constructor(e,t={}){this.storageWebId=null;this.errorQueue=[];this.batchTimer=null;this.isInitialized=!1;this.originalOnError=null;this.originalOnUnhandledRejection=null;this.http=e,this.config={autoCapture:t.autoCapture??!0,captureTypes:t.captureTypes??["error","unhandledrejection"],batchInterval:t.batchInterval??5e3,maxBatchSize:t.maxBatchSize??10,beforeSend:t.beforeSend??(s=>s),debug:t.debug??!1}}init(e){if(this.isInitialized){this.log("ErrorTracker already initialized");return}if(typeof window>"u"){this.log("ErrorTracker only works in browser environment");return}this.storageWebId=e,this.isInitialized=!0,this.config.autoCapture&&this.setupAutoCapture(),this.startBatchTimer(),this.log("ErrorTracker initialized",{storageWebId:e})}destroy(){this.stopBatchTimer(),this.removeAutoCapture(),this.flushQueue(),this.isInitialized=!1,this.log("ErrorTracker destroyed")}async captureError(e,t){let s=this.createErrorReport(e,t);s&&this.queueError(s)}async captureMessage(e,t){let s={message:e,error_type:"custom",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0,...t};this.queueError(s)}async flush(){await this.flushQueue()}log(...e){this.config.debug&&console.log("[ErrorTracker]",...e)}setupAutoCapture(){typeof window>"u"||(this.config.captureTypes.includes("error")&&(this.originalOnError=window.onerror,window.onerror=(e,t,s,r,i)=>(this.handleGlobalError(e,t,s,r,i),this.originalOnError?this.originalOnError(e,t,s,r,i):!1)),this.config.captureTypes.includes("unhandledrejection")&&(this.originalOnUnhandledRejection=window.onunhandledrejection,window.onunhandledrejection=e=>{this.handleUnhandledRejection(e),this.originalOnUnhandledRejection&&this.originalOnUnhandledRejection(e)}),this.log("Auto capture enabled",{types:this.config.captureTypes}))}removeAutoCapture(){typeof window>"u"||(this.originalOnError!==null&&(window.onerror=this.originalOnError),this.originalOnUnhandledRejection!==null&&(window.onunhandledrejection=this.originalOnUnhandledRejection))}handleGlobalError(e,t,s,r,i){let n={message:typeof e=="string"?e:e.type||"Unknown error",source:t||void 0,lineno:s||void 0,colno:r||void 0,stack:i?.stack,error_type:"error",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0};this.queueError(n)}handleUnhandledRejection(e){let t=e.reason,s="Unhandled Promise Rejection",r;t instanceof Error?(s=t.message,r=t.stack):typeof t=="string"?s=t:t&&typeof t=="object"&&(s=JSON.stringify(t));let i={message:s,stack:r,error_type:"unhandledrejection",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0};this.queueError(i)}createErrorReport(e,t){let s;e instanceof Error?s={message:e.message,stack:e.stack,error_type:"error",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0,...t}:s={message:e,error_type:"custom",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0,...t};let r=this.config.beforeSend(s);return r===!1||r===null?(this.log("Error filtered out by beforeSend"),null):r}queueError(e){this.errorQueue.push(e),this.log("Error queued",{message:e.message,queueSize:this.errorQueue.length}),this.errorQueue.length>=this.config.maxBatchSize&&this.flushQueue()}startBatchTimer(){this.batchTimer||(this.batchTimer=setInterval(()=>{this.flushQueue()},this.config.batchInterval))}stopBatchTimer(){this.batchTimer&&(clearInterval(this.batchTimer),this.batchTimer=null)}async flushQueue(){if(!this.storageWebId||this.errorQueue.length===0)return;let e=[...this.errorQueue];this.errorQueue=[];try{e.length===1?await this.http.post(`/v1/public/storages/web/${this.storageWebId}/errors/report`,e[0]):await this.http.post(`/v1/public/storages/web/${this.storageWebId}/errors/batch`,{errors:e,user_agent:typeof navigator<"u"?navigator.userAgent:void 0}),this.log("Errors sent",{count:e.length})}catch(t){let s=this.config.maxBatchSize-this.errorQueue.length;s>0&&this.errorQueue.unshift(...e.slice(0,s)),this.log("Failed to send errors, re-queued",{error:t})}}};var A=class{constructor(e){this.http=e}async getEnabledProviders(){return this.http.get("/v1/public/oauth/providers")}async signIn(e,t,s){let r=new URLSearchParams({app_callback:t});s&&r.append("state",s);let i=await this.http.get(`/v1/public/oauth/${e}/authorize/central?${r.toString()}`);window.location.href=i.authorization_url}async signInWithPopup(e,t){let s=new URLSearchParams;t&&s.set("app_callback",t);let r=s.toString(),i=await this.http.get(`/v1/public/oauth/${e}/authorize/central${r?"?"+r:""}`),n=500,o=600,c=window.screenX+(window.outerWidth-n)/2,p=window.screenY+(window.outerHeight-o)/2,l=window.open(i.authorization_url,"oauth-popup",`width=${n},height=${o},left=${c},top=${p}`);if(!l)throw new Error("\uD31D\uC5C5\uC774 \uCC28\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uD31D\uC5C5 \uCC28\uB2E8\uC744 \uD574\uC81C\uD574\uC8FC\uC138\uC694.");return new Promise((d,u)=>{let y=async h=>{if(h.data?.type!=="oauth-callback")return;if(window.removeEventListener("message",y),h.data.error){u(new Error(h.data.error));return}let m={member_id:h.data.member_id,access_token:h.data.access_token,refresh_token:h.data.refresh_token,is_new_member:h.data.is_new_member==="true"||h.data.is_new_member===!0};this.http.setTokens(m.access_token,m.refresh_token),d(m)};window.addEventListener("message",y);let S=setInterval(()=>{l.closed&&(clearInterval(S),window.removeEventListener("message",y),u(new Error("\uB85C\uADF8\uC778\uC774 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.")))},500)})}getCallbackResult(){let e=new URLSearchParams(window.location.search),t=e.get("error");if(t){let o={error:t};return window.opener&&(window.opener.postMessage({type:"oauth-callback",...o},"*"),window.close()),o}let s=e.get("access_token"),r=e.get("refresh_token"),i=e.get("member_id");if(!s||!r||!i)return null;let n={access_token:s,refresh_token:r,member_id:i,is_new_member:e.get("is_new_member")==="true",state:e.get("state")||void 0};return window.opener?(window.opener.postMessage({type:"oauth-callback",...n},"*"),window.close(),n):(this.http.setTokens(s,r),n)}};var U=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async prepare(e){let t=this.getPublicPrefix();return this.http.post(`${t}/payments/prepare`,e)}async confirm(e){let t=this.getPublicPrefix();return this.http.post(`${t}/payments/confirm`,e)}async cancel(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/payments/cancel`,{payment_id:e,...t})}async getByOrderId(e){let t=this.getPublicPrefix();return this.http.get(`${t}/payments/orders/${e}`)}};var q=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async issueBillingKey(){let e=this.getPublicPrefix();return this.http.post(`${e}/subscriptions/billing-keys`,{})}async confirmBillingKey(e){let t=this.getPublicPrefix();return this.http.post(`${t}/subscriptions/billing-keys/confirm`,e)}async listBillingKeys(e){let t=this.getPublicPrefix(),s=e?`?customer_id=${e}`:"";return this.http.get(`${t}/subscriptions/billing-keys${s}`)}async getBillingKey(e){let t=this.getPublicPrefix();return this.http.get(`${t}/subscriptions/billing-keys/${e}`)}async updateBillingKey(e,t){let s=this.getPublicPrefix();return this.http.patch(`${s}/subscriptions/billing-keys/${e}`,t)}async deleteBillingKey(e){let t=this.getPublicPrefix();return this.http.delete(`${t}/subscriptions/billing-keys/${e}`)}async create(e){let t=this.getPublicPrefix();return this.http.post(`${t}/subscriptions`,e)}async list(e){let t=this.getPublicPrefix(),s=new URLSearchParams;e?.status&&s.set("status",e.status),e?.limit&&s.set("limit",String(e.limit)),e?.offset&&s.set("offset",String(e.offset));let r=s.toString();return this.http.get(`${t}/subscriptions${r?"?"+r:""}`)}async get(e){let t=this.getPublicPrefix();return this.http.get(`${t}/subscriptions/${e}`)}async update(e,t){let s=this.getPublicPrefix();return this.http.patch(`${s}/subscriptions/${e}`,t)}async pause(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/subscriptions/${e}/pause`,t||{})}async resume(e){let t=this.getPublicPrefix();return this.http.post(`${t}/subscriptions/${e}/resume`,{})}async cancel(e,t){let s=this.getPublicPrefix();return this.http.post(`${s}/subscriptions/${e}/cancel`,t)}async listPayments(e,t){let s=this.getPublicPrefix(),r=new URLSearchParams;t?.status&&r.set("status",t.status),t?.limit&&r.set("limit",String(t.limit)),t?.offset&&r.set("offset",String(t.offset));let i=r.toString();return this.http.get(`${s}/subscriptions/${e}/payments${i?"?"+i:""}`)}async chargeWithBillingKey(e){let t=this.getPublicPrefix();return this.http.post(`${t}/subscriptions/charge`,e)}};var G=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async registerDevice(e){let t=this.getPublicPrefix();return this.http.post(`${t}/push/devices`,e)}async unregisterDevice(e){let t=this.getPublicPrefix();await this.http.delete(`${t}/push/devices/${e}`)}async getDevices(){let e=this.getPublicPrefix();return(await this.http.get(`${e}/push/devices`)).devices||[]}async subscribeTopic(e){let t=this.getPublicPrefix(),s={topic_name:e};await this.http.post(`${t}/push/topics/subscribe`,s)}async unsubscribeTopic(e){let t=this.getPublicPrefix(),s={topic_name:e};await this.http.post(`${t}/push/topics/unsubscribe`,s)}async getSubscribedTopics(){let e=this.getPublicPrefix();return(await this.http.get(`${e}/push/topics/subscribed`)).topics||[]}async getVAPIDPublicKey(){let e=this.getPublicPrefix();return this.http.get(`${e}/push/vapid-key`)}async registerWebPush(e){let t=this.getPublicPrefix(),s;if("toJSON"in e){let i=e.toJSON();s={endpoint:i.endpoint||"",expirationTime:i.expirationTime,keys:{p256dh:i.keys?.p256dh||"",auth:i.keys?.auth||""}}}else s=e;let r={device_token:s.endpoint,platform:"web",device_id:this.generateDeviceId(),device_name:this.getBrowserName(),os_version:this.getOSInfo()};return this.http.post(`${t}/push/devices/web`,{...r,web_push_subscription:s})}async unregisterWebPush(){let e=this.getPublicPrefix();await this.http.delete(`${e}/push/devices/web`)}generateDeviceId(){if(typeof window>"u"||typeof localStorage>"u")return`device_${Date.now()}_${Math.random().toString(36).substr(2,9)}`;let e="cb_push_device_id",t=localStorage.getItem(e);return t||(t=`web_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,localStorage.setItem(e,t)),t}getBrowserName(){if(typeof navigator>"u")return"Unknown Browser";let e=navigator.userAgent;return e.includes("Chrome")&&!e.includes("Edg")?"Chrome":e.includes("Safari")&&!e.includes("Chrome")?"Safari":e.includes("Firefox")?"Firefox":e.includes("Edg")?"Edge":e.includes("Opera")||e.includes("OPR")?"Opera":"Unknown Browser"}getOSInfo(){if(typeof navigator>"u")return"Unknown OS";let e=navigator.userAgent;return e.includes("Windows")?"Windows":e.includes("Mac OS")?"macOS":e.includes("Linux")?"Linux":e.includes("Android")?"Android":e.includes("iOS")||e.includes("iPhone")||e.includes("iPad")?"iOS":"Unknown OS"}};var ie=5*1024*1024,v=class extends Error{constructor(e,t){super(e),this.name="VideoProcessingError",this.video=t}},D=class{constructor(e,t){this.http=e;this.videoBaseUrl=t||this.getDefaultVideoUrl()}getDefaultVideoUrl(){if(typeof window<"u"){let e=window.location.hostname;if(e==="localhost"||e==="127.0.0.1")return"http://localhost:8089"}return"https://video.connectbase.world"}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async videoFetch(e,t,s){let r={},i=this.http.getApiKey();i&&(r["X-API-Key"]=i);let n=this.http.getAccessToken();n&&(r.Authorization=`Bearer ${n}`),s&&!(s instanceof FormData)&&(r["Content-Type"]="application/json");let o=await fetch(`${this.videoBaseUrl}${t}`,{method:e,headers:r,body:s instanceof FormData?s:s?JSON.stringify(s):void 0});if(!o.ok){let c=await o.json().catch(()=>({message:o.statusText}));throw new g(o.status,c.message||"Unknown error")}return o.status===204||o.headers.get("content-length")==="0"?{}:o.json()}async upload(e,t){let s=this.getPublicPrefix(),r=await this.videoFetch("POST",`${s}/uploads`,{filename:e.name,size:e.size,mime_type:e.type,title:t.title,description:t.description,visibility:t.visibility||"private",tags:t.tags,channel_id:t.channel_id}),i=r.chunk_size||ie,n=Math.ceil(e.size/i),o=0,p=Date.now(),l=0;for(let u=0;u<n;u++){let y=u*i,S=Math.min(y+i,e.size),h=e.slice(y,S),m=new FormData;m.append("chunk",h),m.append("chunk_index",String(u)),await this.videoFetch("POST",`${s}/uploads/${r.session_id}/chunks`,m),o++;let B=Date.now(),V=(B-p)/1e3,N=S,J=N-l,Q=V>0?J/V:0;p=B,l=N,t.onProgress&&t.onProgress({phase:"uploading",uploadedChunks:o,totalChunks:n,percentage:Math.round(o/n*100),currentSpeed:Q})}return(await this.videoFetch("POST",`${s}/uploads/${r.session_id}/complete`,{})).video}async waitForReady(e,t){let s=t?.timeout||18e5,r=t?.interval||5e3,i=Date.now(),n=this.getPublicPrefix();for(;Date.now()-i<s;){let o=await this.videoFetch("GET",`${n}/videos/${e}`);if(o.status==="ready")return o;if(o.status==="failed")throw new v("Video processing failed",o);if(t?.onProgress){let c=o.qualities.filter(l=>l.status==="ready").length,p=o.qualities.length||1;t.onProgress({phase:"processing",uploadedChunks:0,totalChunks:0,percentage:Math.round(c/p*100)})}await new Promise(c=>setTimeout(c,r))}throw new v("Timeout waiting for video to be ready")}async list(e){let t=this.getPublicPrefix(),s=new URLSearchParams;e?.status&&s.set("status",e.status),e?.visibility&&s.set("visibility",e.visibility),e?.search&&s.set("search",e.search),e?.channel_id&&s.set("channel_id",e.channel_id),e?.page&&s.set("page",String(e.page)),e?.limit&&s.set("limit",String(e.limit));let r=s.toString();return this.videoFetch("GET",`${t}/videos${r?`?${r}`:""}`)}async get(e){let t=this.getPublicPrefix();return this.videoFetch("GET",`${t}/videos/${e}`)}async update(e,t){let s=this.getPublicPrefix();return this.videoFetch("PATCH",`${s}/videos/${e}`,t)}async delete(e){let t=this.getPublicPrefix();await this.videoFetch("DELETE",`${t}/videos/${e}`)}async getStreamUrl(e,t){let s=this.getPublicPrefix(),r=t?`?quality=${t}`:"";return this.videoFetch("GET",`${s}/videos/${e}/stream-url${r}`)}async getThumbnails(e){let t=this.getPublicPrefix();return(await this.videoFetch("GET",`${t}/videos/${e}/thumbnails`)).thumbnails}async getTranscodeStatus(e){let t=this.getPublicPrefix();return this.videoFetch("GET",`${t}/videos/${e}/transcode/status`)}async retryTranscode(e){let t=this.getPublicPrefix();await this.videoFetch("POST",`${t}/videos/${e}/transcode/retry`,{})}async createChannel(e){let t=this.getPublicPrefix();return this.videoFetch("POST",`${t}/channels`,e)}async getChannel(e){let t=this.getPublicPrefix();return this.videoFetch("GET",`${t}/channels/${e}`)}async getChannelByHandle(e){let t=this.getPublicPrefix();return this.videoFetch("GET",`${t}/channels/handle/${e}`)}async updateChannel(e,t){let s=this.getPublicPrefix();return this.videoFetch("PATCH",`${s}/channels/${e}`,t)}async subscribeChannel(e){let t=this.getPublicPrefix();await this.videoFetch("POST",`${t}/channels/${e}/subscribe`,{})}async unsubscribeChannel(e){let t=this.getPublicPrefix();await this.videoFetch("DELETE",`${t}/channels/${e}/subscribe`)}async createPlaylist(e,t){let s=this.getPublicPrefix();return this.videoFetch("POST",`${s}/channels/${e}/playlists`,t)}async getPlaylists(e){let t=this.getPublicPrefix();return(await this.videoFetch("GET",`${t}/channels/${e}/playlists`)).playlists}async getPlaylistItems(e){let t=this.getPublicPrefix();return(await this.videoFetch("GET",`${t}/playlists/${e}/items`)).items}async addToPlaylist(e,t,s){let r=this.getPublicPrefix();return this.videoFetch("POST",`${r}/playlists/${e}/items`,{video_id:t,position:s})}async removeFromPlaylist(e,t){let s=this.getPublicPrefix();await this.videoFetch("DELETE",`${s}/playlists/${e}/items/${t}`)}async getShortsFeed(e){let t=this.getPublicPrefix(),s=new URLSearchParams;e?.cursor&&s.set("cursor",e.cursor),e?.limit&&s.set("limit",String(e.limit));let r=s.toString();return this.videoFetch("GET",`${t}/shorts${r?`?${r}`:""}`)}async getTrendingShorts(e){let t=this.getPublicPrefix(),s=e?`?limit=${e}`:"";return this.videoFetch("GET",`${t}/shorts/trending${s}`)}async getShorts(e){let t=this.getPublicPrefix();return this.videoFetch("GET",`${t}/shorts/${e}`)}async getComments(e,t){let s=this.getPublicPrefix(),r=new URLSearchParams;t?.cursor&&r.set("cursor",t.cursor),t?.limit&&r.set("limit",String(t.limit)),t?.sort&&r.set("sort",t.sort);let i=r.toString();return this.videoFetch("GET",`${s}/videos/${e}/comments${i?`?${i}`:""}`)}async postComment(e,t,s){let r=this.getPublicPrefix();return this.videoFetch("POST",`${r}/videos/${e}/comments`,{content:t,parent_id:s})}async deleteComment(e){let t=this.getPublicPrefix();await this.videoFetch("DELETE",`${t}/comments/${e}`)}async likeVideo(e){let t=this.getPublicPrefix();await this.videoFetch("POST",`${t}/videos/${e}/like`,{})}async unlikeVideo(e){let t=this.getPublicPrefix();await this.videoFetch("DELETE",`${t}/videos/${e}/like`)}async getWatchHistory(e){let t=this.getPublicPrefix(),s=new URLSearchParams;e?.cursor&&s.set("cursor",e.cursor),e?.limit&&s.set("limit",String(e.limit));let r=s.toString();return this.videoFetch("GET",`${t}/watch-history${r?`?${r}`:""}`)}async clearWatchHistory(){let e=this.getPublicPrefix();await this.videoFetch("DELETE",`${e}/watch-history`)}async reportWatchProgress(e,t,s){let r=this.getPublicPrefix();await this.videoFetch("POST",`${r}/videos/${e}/watch-progress`,{position:t,duration:s})}async getMembershipTiers(e){let t=this.getPublicPrefix();return(await this.videoFetch("GET",`${t}/channels/${e}/memberships/tiers`)).tiers}async joinMembership(e,t){let s=this.getPublicPrefix();return this.videoFetch("POST",`${s}/channels/${e}/memberships/${t}/join`,{})}async cancelMembership(e,t){let s=this.getPublicPrefix();await this.videoFetch("POST",`${s}/channels/${e}/memberships/${t}/cancel`,{})}async sendSuperChat(e,t,s,r){let i=this.getPublicPrefix();return this.videoFetch("POST",`${i}/videos/${e}/super-chats`,{amount:t,message:s,currency:r||"USD"})}async getSuperChats(e){let t=this.getPublicPrefix();return(await this.videoFetch("GET",`${t}/videos/${e}/super-chats`)).super_chats}async getRecommendations(e){let t=this.getPublicPrefix(),s=e?`?limit=${e}`:"";return(await this.videoFetch("GET",`${t}/recommendations${s}`)).videos}async getHomeFeed(e){let t=this.getPublicPrefix(),s=e?`?limit=${e}`:"";return(await this.videoFetch("GET",`${t}/recommendations/home${s}`)).videos}async getRelatedVideos(e,t){let s=this.getPublicPrefix(),r=t?`?limit=${t}`:"";return(await this.videoFetch("GET",`${s}/recommendations/related/${e}${r}`)).videos}async getTrendingVideos(e){let t=this.getPublicPrefix(),s=e?`?limit=${e}`:"";return(await this.videoFetch("GET",`${t}/recommendations/trending${s}`)).videos}async submitFeedback(e,t){let s=this.getPublicPrefix();await this.videoFetch("POST",`${s}/recommendations/feedback`,{video_id:e,feedback:t})}};var z=()=>{if(typeof window<"u"){let a=window.location.hostname;if(a==="localhost"||a==="127.0.0.1")return"ws://localhost:8087"}return"wss://game.connectbase.world"},R=class{constructor(e){this.ws=null;this.handlers={};this.reconnectAttempts=0;this.reconnectTimer=null;this.pingInterval=null;this.actionSequence=0;this._roomId=null;this._state=null;this._isConnected=!1;this.msgIdCounter=0;this.config={gameServerUrl:z(),autoReconnect:!0,maxReconnectAttempts:5,reconnectInterval:1e3,...e}}get roomId(){return this._roomId}get state(){return this._state}get isConnected(){return this._isConnected}on(e,t){return this.handlers[e]=t,this}connect(e){return new Promise((t,s)=>{if(this.ws?.readyState===WebSocket.OPEN){t();return}let r=this.buildConnectionUrl(e);this.ws=new WebSocket(r);let i=()=>{this._isConnected=!0,this.reconnectAttempts=0,this.startPingInterval(),this.handlers.onConnect?.(),t()},n=p=>{this._isConnected=!1,this.stopPingInterval(),this.handlers.onDisconnect?.(p),this.config.autoReconnect&&p.code!==1e3&&this.scheduleReconnect(e)},o=p=>{this.handlers.onError?.(p),s(new Error("WebSocket connection failed"))},c=p=>{this.handleMessage(p.data)};this.ws.addEventListener("open",i,{once:!0}),this.ws.addEventListener("close",n),this.ws.addEventListener("error",o,{once:!0}),this.ws.addEventListener("message",c)})}disconnect(){this.stopPingInterval(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws&&(this.ws.close(1e3,"Client disconnected"),this.ws=null),this._isConnected=!1,this._roomId=null}createRoom(e={}){return new Promise((t,s)=>{let r=i=>{if(i.type==="room_created"){let n=i.data;return this._roomId=n.room_id,this._state=n.initial_state,t(n.initial_state),!0}else if(i.type==="error")return s(new Error(i.data.message)),!0;return!1};this.sendWithHandler("create_room",e,r,15e3,s)})}joinRoom(e,t){return new Promise((s,r)=>{let i=n=>{if(n.type==="room_joined"){let o=n.data;return this._roomId=o.room_id,this._state=o.initial_state,s(o.initial_state),!0}else if(n.type==="error")return r(new Error(n.data.message)),!0;return!1};this.sendWithHandler("join_room",{room_id:e,metadata:t},i,15e3,r)})}leaveRoom(){return new Promise((e,t)=>{if(!this._roomId){t(new Error("Not in a room"));return}let s=r=>r.type==="room_left"?(this._roomId=null,this._state=null,e(),!0):r.type==="error"?(t(new Error(r.data.message)),!0):!1;this.sendWithHandler("leave_room",{},s,15e3,t)})}sendAction(e){if(!this._roomId)throw new Error("Not in a room");this.send("action",{type:e.type,data:e.data,client_timestamp:e.clientTimestamp??Date.now(),sequence:this.actionSequence++})}sendChat(e){if(!this._roomId)throw new Error("Not in a room");this.send("chat",{message:e})}requestState(){return new Promise((e,t)=>{if(!this._roomId){t(new Error("Not in a room"));return}let s=r=>{if(r.type==="state"){let i=r.data;return this._state=i,e(i),!0}else if(r.type==="error")return t(new Error(r.data.message)),!0;return!1};this.sendWithHandler("get_state",{},s,15e3,t)})}listRooms(){return new Promise((e,t)=>{let s=r=>{if(r.type==="room_list"){let i=r.data;return e(i.rooms),!0}else if(r.type==="error")return t(new Error(r.data.message)),!0;return!1};this.sendWithHandler("list_rooms",{},s,15e3,t)})}ping(){return new Promise((e,t)=>{let s=Date.now(),r=i=>{if(i.type==="pong"){let n=i.data,o=Date.now()-n.clientTimestamp;return this.handlers.onPong?.(n),e(o),!0}else if(i.type==="error")return t(new Error(i.data.message)),!0;return!1};this.sendWithHandler("ping",{timestamp:s},r,15e3,t)})}buildConnectionUrl(e){let s=this.config.gameServerUrl.replace(/^http/,"ws"),r=new URLSearchParams;r.set("client_id",this.config.clientId),e&&r.set("room_id",e),this.config.apiKey&&r.set("api_key",this.config.apiKey),this.config.accessToken&&r.set("token",this.config.accessToken);let i=this.config.appId||"";return`${s}/v1/game/${i}/ws?${r.toString()}`}send(e,t,s){if(!this.ws||this.ws.readyState!==WebSocket.OPEN)throw new Error("WebSocket is not connected");this.ws.send(JSON.stringify({type:e,data:t,msg_id:s}))}sendWithHandler(e,t,s,r=15e3,i){let n=`${e}-${++this.msgIdCounter}`,o=null,c=()=>{this.ws?.removeEventListener("message",p),o&&(clearTimeout(o),o=null)},p=l=>{try{let d=JSON.parse(l.data);if(d.msg_id&&d.msg_id!==n)return;s(d)&&c()}catch{}};this.ws?.addEventListener("message",p),o=setTimeout(()=>{c();let l=new Error(`Request '${e}' timed out after ${r}ms`);i?.(l),this.handlers.onError?.({code:"TIMEOUT",message:l.message})},r);try{this.send(e,t,n)}catch(l){c();let d=l instanceof Error?l:new Error(String(l));i?.(d)}}handleMessage(e){try{let t=JSON.parse(e);switch(t.type){case"delta":this.handleDelta(t.data);break;case"state":this._state=t.data,this.handlers.onStateUpdate?.(this._state);break;case"player_event":this.handlePlayerEvent(t.data);break;case"chat":this.handlers.onChat?.(t.data);break;case"error":this.handlers.onError?.(t.data);break;default:break}}catch{console.error("Failed to parse game message:",e)}}handleDelta(e){let t=e.delta;if(this._state){for(let s of t.changes)this.applyChange(s);this._state.version=t.toVersion}this.handlers.onDelta?.(t)}applyChange(e){if(!this._state)return;let t=e.path.split("."),s=this._state.state;for(let i=0;i<t.length-1;i++){let n=t[i];n in s||(s[n]={}),s=s[n]}let r=t[t.length-1];e.operation==="delete"?delete s[r]:s[r]=e.value}handlePlayerEvent(e){e.event==="joined"?this.handlers.onPlayerJoined?.(e.player):e.event==="left"&&this.handlers.onPlayerLeft?.(e.player)}scheduleReconnect(e){if(this.reconnectAttempts>=(this.config.maxReconnectAttempts??5)){console.error("Max reconnect attempts reached"),this.handlers.onError?.({code:"MAX_RECONNECT_ATTEMPTS",message:"Maximum reconnection attempts reached"});return}let t=Math.min((this.config.reconnectInterval??1e3)*Math.pow(2,this.reconnectAttempts),3e4);this.reconnectAttempts++;let s=e||this._roomId;this.reconnectTimer=setTimeout(async()=>{console.log(`Reconnecting... (attempt ${this.reconnectAttempts})`);try{if(await this.connect(),s){console.log(`Rejoining room ${s}...`);try{await this.joinRoom(s),console.log(`Successfully rejoined room ${s}`)}catch(r){console.error(`Failed to rejoin room ${s}:`,r),this.handlers.onError?.({code:"REJOIN_FAILED",message:`Failed to rejoin room: ${r}`})}}}catch{}},t)}startPingInterval(){this.pingInterval=setInterval(()=>{this.ping().catch(()=>{})},3e4)}stopPingInterval(){this.pingInterval&&(clearInterval(this.pingInterval),this.pingInterval=null)}},P=class{constructor(e,t,s){this.http=e,this.gameServerUrl=t||z().replace(/^ws/,"http"),this.appId=s}createClient(e){return new R({...e,gameServerUrl:this.gameServerUrl.replace(/^http/,"ws"),appId:this.appId,apiKey:this.http.getApiKey(),accessToken:this.http.getAccessToken()})}async listRooms(e){let t=e||this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/rooms`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to list rooms: ${s.statusText}`);return(await s.json()).rooms}async getRoom(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/rooms/${e}`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to get room: ${s.statusText}`);return s.json()}async createRoom(e,t={}){let s=e||this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${s}/rooms`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({app_id:e,category_id:t.categoryId,room_id:t.roomId,tick_rate:t.tickRate,max_players:t.maxPlayers,metadata:t.metadata})});if(!r.ok)throw new Error(`Failed to create room: ${r.statusText}`);return r.json()}async deleteRoom(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/rooms/${e}`,{method:"DELETE",headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to delete room: ${s.statusText}`)}getHeaders(){let e={},t=this.http.getApiKey();t&&(e["X-API-Key"]=t);let s=this.http.getAccessToken();return s&&(e.Authorization=`Bearer ${s}`),e}};var w=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async getConnectionStatus(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/connection`)}async getReport(e,t){let s=this.getPublicPrefix(),r=new URLSearchParams;e&&r.set("start",e),t&&r.set("end",t);let i=r.toString();return this.http.get(`${s}/ads/reports${i?`?${i}`:""}`)}async getReportSummary(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/reports/summary`)}async getAdMobReport(e,t){let s=this.getPublicPrefix(),r=new URLSearchParams;e&&r.set("start",e),t&&r.set("end",t);let i=r.toString();return this.http.get(`${s}/ads/admob/reports${i?`?${i}`:""}`)}async getAdMobReportSummary(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/admob/reports/summary`)}};var K=class{constructor(e,t,s,r){this.type="webtransport";this.transport=null;this.writer=null;this.config=e,this.onMessage=t,this.onClose=s,this.onError=r}async connect(){let e=this.buildUrl();this.transport=new WebTransport(e),await this.transport.ready,this.config.useUnreliableDatagrams!==!1&&this.readDatagrams();let t=await this.transport.createBidirectionalStream();this.writer=t.writable.getWriter(),this.readStream(t.readable),this.transport.closed.then(()=>{this.onClose()}).catch(s=>{this.onError(s)})}buildUrl(){let t=(this.config.gameServerUrl||"https://game.connectbase.world").replace(/^ws/,"http").replace(/^http:/,"https:"),s=new URLSearchParams;return s.set("client_id",this.config.clientId),this.config.apiKey&&s.set("api_key",this.config.apiKey),this.config.accessToken&&s.set("token",this.config.accessToken),`${t}/v1/game/webtransport?${s.toString()}`}async readDatagrams(){if(!this.transport)return;let e=this.transport.datagrams.readable.getReader();try{for(;;){let{value:t,done:s}=await e.read();if(s)break;this.onMessage(t)}}catch{}}async readStream(e){let t=e.getReader(),s=new Uint8Array(0);try{for(;;){let{value:r,done:i}=await t.read();if(i)break;let n=new Uint8Array(s.length+r.length);for(n.set(s),n.set(r,s.length),s=n;s.length>=4;){let o=new DataView(s.buffer).getUint32(0,!0);if(s.length<4+o)break;let c=s.slice(4,4+o);s=s.slice(4+o),this.onMessage(c)}}}catch{}}disconnect(){this.transport&&(this.transport.close(),this.transport=null,this.writer=null)}send(e,t=!0){if(!this.transport)throw new Error("Not connected");let s=typeof e=="string"?new TextEncoder().encode(e):e;if(t){if(this.writer){let r=new Uint8Array(4);new DataView(r.buffer).setUint32(0,s.length,!0);let i=new Uint8Array(4+s.length);i.set(r),i.set(s,4),this.writer.write(i)}}else{let r=this.config.maxDatagramSize||1200;s.length<=r?this.transport.datagrams.writable.getWriter().write(s):(console.warn("Datagram too large, falling back to reliable stream"),this.send(e,!0))}}isConnected(){return this.transport!==null}},L=class{constructor(e,t,s,r){this.type="websocket";this.ws=null;this.config=e,this.onMessage=t,this.onClose=s,this.onError=r}connect(){return new Promise((e,t)=>{let s=this.buildUrl();try{this.ws=new WebSocket(s),this.ws.binaryType="arraybuffer"}catch(c){t(c);return}let r=()=>{e()},i=()=>{this.onClose()},n=c=>{let p=new Error("WebSocket error");this.onError(p),t(p)},o=c=>{c.data instanceof ArrayBuffer?this.onMessage(new Uint8Array(c.data)):typeof c.data=="string"&&this.onMessage(new TextEncoder().encode(c.data))};this.ws.addEventListener("open",r,{once:!0}),this.ws.addEventListener("close",i),this.ws.addEventListener("error",n,{once:!0}),this.ws.addEventListener("message",o)})}buildUrl(){let t=(this.config.gameServerUrl||"wss://game.connectbase.world").replace(/^http/,"ws"),s=new URLSearchParams;s.set("client_id",this.config.clientId),this.config.apiKey&&s.set("api_key",this.config.apiKey),this.config.accessToken&&s.set("token",this.config.accessToken);let r=this.config.appId||"";return`${t}/v1/game/${r}/ws?${s.toString()}`}disconnect(){this.ws&&(this.ws.close(1e3,"Client disconnected"),this.ws=null)}send(e,t){if(!this.ws||this.ws.readyState!==WebSocket.OPEN)throw new Error("Not connected");typeof e=="string"?this.ws.send(e):this.ws.send(e)}isConnected(){return this.ws!==null&&this.ws.readyState===WebSocket.OPEN}};function W(){return typeof WebTransport<"u"}var F=class{constructor(e){this.transport=null;this.handlers={};this.reconnectAttempts=0;this.reconnectTimer=null;this.pingInterval=null;this.actionSequence=0;this._roomId=null;this._state=null;this._isConnected=!1;this._connectionStatus="disconnected";this._lastError=null;this._latency=0;this._transportType="websocket";this.decoder=new TextDecoder;this.pendingHandlers=new Map;this.messageId=0;this.config={gameServerUrl:this.getDefaultGameServerUrl(),autoReconnect:!0,maxReconnectAttempts:5,reconnectInterval:1e3,connectionTimeout:1e4,transport:"auto",useUnreliableDatagrams:!0,...e}}getDefaultGameServerUrl(){if(typeof window<"u"){let e=window.location.hostname;if(e==="localhost"||e==="127.0.0.1")return"ws://localhost:8087"}return"wss://game.connectbase.world"}get transportType(){return this._transportType}get roomId(){return this._roomId}get state(){return this._state}get isConnected(){return this._isConnected}get connectionState(){return{status:this._connectionStatus,transport:this._transportType==="auto"?null:this._transportType,roomId:this._roomId,latency:this._latency,reconnectAttempt:this.reconnectAttempts,lastError:this._lastError||void 0}}get latency(){return this._latency}on(e,t){return this.handlers[e]=t,this}async connect(e){if(this.transport?.isConnected())return;this._connectionStatus=this.reconnectAttempts>0?"reconnecting":"connecting";let t=this.config.transport||"auto",s=(t==="webtransport"||t==="auto")&&W(),r=o=>{this.handleMessage(this.decoder.decode(o))},i=()=>{this._isConnected=!1,this._connectionStatus="disconnected",this.stopPingInterval(),this.handlers.onDisconnect?.(new CloseEvent("close")),this.config.autoReconnect&&(this._connectionStatus="reconnecting",this.scheduleReconnect(e))},n=o=>{this._connectionStatus="error",this._lastError=o,this.handlers.onError?.(o)};if(s)try{this.transport=new K(this.config,r,i,n),await this.transport.connect(),this._transportType="webtransport"}catch{console.log("WebTransport failed, falling back to WebSocket"),this.transport=new L(this.config,r,i,n),await this.transport.connect(),this._transportType="websocket"}else this.transport=new L(this.config,r,i,n),await this.transport.connect(),this._transportType="websocket";this._isConnected=!0,this._connectionStatus="connected",this._lastError=null,this.reconnectAttempts=0,this.startPingInterval(),this.handlers.onConnect?.(),e&&await this.joinRoom(e)}disconnect(){this.stopPingInterval(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.transport&&(this.transport.disconnect(),this.transport=null),this._isConnected=!1,this._connectionStatus="disconnected",this._roomId=null,this._state=null}async createRoom(e={}){return new Promise((t,s)=>{let r=i=>{if(i.type==="room_created"){let n=i.data;this._roomId=n.room_id,this._state=n.initial_state,t(n.initial_state)}else i.type==="error"&&s(new Error(i.data.message))};this.sendWithHandler("create_room",e,r)})}async joinRoom(e,t){return new Promise((s,r)=>{let i=n=>{if(n.type==="room_joined"){let o=n.data;this._roomId=o.room_id,this._state=o.initial_state,s(o.initial_state)}else n.type==="error"&&r(new Error(n.data.message))};this.sendWithHandler("join_room",{room_id:e,metadata:t},i)})}async leaveRoom(){return new Promise((e,t)=>{if(!this._roomId){t(new Error("Not in a room"));return}let s=r=>{r.type==="room_left"?(this._roomId=null,this._state=null,e()):r.type==="error"&&t(new Error(r.data.message))};this.sendWithHandler("leave_room",{},s)})}sendAction(e,t=!1){if(!this._roomId)throw new Error("Not in a room");let s=JSON.stringify({type:"action",data:{type:e.type,data:e.data,client_timestamp:e.clientTimestamp??Date.now(),sequence:this.actionSequence++}}),r=t||this._transportType!=="webtransport";this.transport?.send(s,r)}sendChat(e){if(!this._roomId)throw new Error("Not in a room");this.send("chat",{message:e})}async requestState(){return new Promise((e,t)=>{if(!this._roomId){t(new Error("Not in a room"));return}let s=r=>{if(r.type==="state"){let i=r.data;this._state=i,e(i)}else r.type==="error"&&t(new Error(r.data.message))};this.sendWithHandler("get_state",{},s)})}async ping(){return new Promise((e,t)=>{let s=Date.now(),r=i=>{if(i.type==="pong"){let n=i.data,o=Date.now()-n.clientTimestamp;this._latency=o,this.handlers.onPong?.(n),e(o)}else i.type==="error"&&t(new Error(i.data.message))};this.sendWithHandler("ping",{timestamp:s},r)})}send(e,t){if(!this.transport?.isConnected())throw new Error("Not connected");let s=JSON.stringify({type:e,data:t});this.transport.send(s,!0)}sendWithHandler(e,t,s){let r=`msg_${this.messageId++}`;this.pendingHandlers.set(r,s),setTimeout(()=>{this.pendingHandlers.delete(r)},1e4),this.send(e,{...t,_msg_id:r})}handleMessage(e){try{let t=JSON.parse(e);if(t._msg_id&&this.pendingHandlers.has(t._msg_id)){let s=this.pendingHandlers.get(t._msg_id);this.pendingHandlers.delete(t._msg_id),s(t);return}switch(t.type){case"delta":this.handleDelta(t.data);break;case"state":this._state=t.data,this.handlers.onStateUpdate?.(this._state);break;case"player_event":this.handlePlayerEvent(t.data);break;case"chat":this.handlers.onChat?.(t.data);break;case"error":this.handlers.onError?.(t.data);break}}catch{console.error("Failed to parse game message:",e)}}handleDelta(e){let t=e.delta;if(this._state){for(let s of t.changes)this.applyChange(s);this._state.version=t.toVersion}this.handlers.onDelta?.(t)}applyChange(e){if(!this._state)return;let t=e.path.split("."),s=this._state.state;for(let i=0;i<t.length-1;i++){let n=t[i];n in s||(s[n]={}),s=s[n]}let r=t[t.length-1];e.operation==="delete"?delete s[r]:s[r]=e.value}handlePlayerEvent(e){e.event==="joined"?this.handlers.onPlayerJoined?.(e.player):e.event==="left"&&this.handlers.onPlayerLeft?.(e.player)}scheduleReconnect(e){if(this.reconnectAttempts>=(this.config.maxReconnectAttempts??5)){console.error("Max reconnect attempts reached");return}let t=Math.min((this.config.reconnectInterval??1e3)*Math.pow(2,this.reconnectAttempts),3e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{console.log(`Reconnecting... (attempt ${this.reconnectAttempts})`),this.connect(e||this._roomId||void 0).catch(()=>{})},t)}startPingInterval(){this.pingInterval=setInterval(()=>{this.ping().catch(()=>{})},3e4)}stopPingInterval(){this.pingInterval&&(clearInterval(this.pingInterval),this.pingInterval=null)}};var ne="https://api.connectbase.world",oe="https://socket.connectbase.world",ae="https://webrtc.connectbase.world",ce="https://video.connectbase.world",pe="https://game.connectbase.world",O=class{constructor(e={}){let t={baseUrl:e.baseUrl||ne,apiKey:e.apiKey,onTokenRefresh:e.onTokenRefresh,onAuthError:e.onAuthError};this.http=new T(t),this.auth=new C(this.http),this.database=new _(this.http),this.storage=new k(this.http),this.apiKey=new x(this.http),this.functions=new E(this.http),this.realtime=new $(this.http,e.socketUrl||oe),this.webrtc=new I(this.http,e.webrtcUrl||ae,e.appId),this.errorTracker=new M(this.http,e.errorTracker),this.oauth=new A(this.http),this.payment=new U(this.http),this.subscription=new q(this.http),this.push=new G(this.http),this.video=new D(this.http,e.videoUrl||ce),this.game=new P(this.http,e.gameUrl||pe,e.appId),this.ads=new w(this.http)}setTokens(e,t){this.http.setTokens(e,t)}clearTokens(){this.http.clearTokens()}updateConfig(e){this.http.updateConfig(e)}},le=O;return se(he);})();
|
|
3
3
|
var ConnectBase = ConnectBaseModule.default || ConnectBaseModule.ConnectBase;
|
package/dist/index.d.mts
CHANGED
|
@@ -3368,6 +3368,7 @@ interface GameServerMessage<T = unknown> {
|
|
|
3368
3368
|
type: GameServerMessageType;
|
|
3369
3369
|
data: T;
|
|
3370
3370
|
serverTime: number;
|
|
3371
|
+
msg_id?: string;
|
|
3371
3372
|
}
|
|
3372
3373
|
/**
|
|
3373
3374
|
* 플레이어 이벤트
|
|
@@ -3528,6 +3529,7 @@ declare class GameRoom {
|
|
|
3528
3529
|
*/
|
|
3529
3530
|
ping(): Promise<number>;
|
|
3530
3531
|
private buildConnectionUrl;
|
|
3532
|
+
private msgIdCounter;
|
|
3531
3533
|
private send;
|
|
3532
3534
|
private sendWithHandler;
|
|
3533
3535
|
private handleMessage;
|
package/dist/index.d.ts
CHANGED
|
@@ -3368,6 +3368,7 @@ interface GameServerMessage<T = unknown> {
|
|
|
3368
3368
|
type: GameServerMessageType;
|
|
3369
3369
|
data: T;
|
|
3370
3370
|
serverTime: number;
|
|
3371
|
+
msg_id?: string;
|
|
3371
3372
|
}
|
|
3372
3373
|
/**
|
|
3373
3374
|
* 플레이어 이벤트
|
|
@@ -3528,6 +3529,7 @@ declare class GameRoom {
|
|
|
3528
3529
|
*/
|
|
3529
3530
|
ping(): Promise<number>;
|
|
3530
3531
|
private buildConnectionUrl;
|
|
3532
|
+
private msgIdCounter;
|
|
3531
3533
|
private send;
|
|
3532
3534
|
private sendWithHandler;
|
|
3533
3535
|
private handleMessage;
|
package/dist/index.js
CHANGED
|
@@ -3848,6 +3848,7 @@ var GameRoom = class {
|
|
|
3848
3848
|
this._roomId = null;
|
|
3849
3849
|
this._state = null;
|
|
3850
3850
|
this._isConnected = false;
|
|
3851
|
+
this.msgIdCounter = 0;
|
|
3851
3852
|
this.config = {
|
|
3852
3853
|
gameServerUrl: getDefaultGameServerUrl(),
|
|
3853
3854
|
autoReconnect: true,
|
|
@@ -3954,7 +3955,7 @@ var GameRoom = class {
|
|
|
3954
3955
|
}
|
|
3955
3956
|
return false;
|
|
3956
3957
|
};
|
|
3957
|
-
this.sendWithHandler("create_room", config, handler);
|
|
3958
|
+
this.sendWithHandler("create_room", config, handler, 15e3, reject);
|
|
3958
3959
|
});
|
|
3959
3960
|
}
|
|
3960
3961
|
/**
|
|
@@ -3975,7 +3976,7 @@ var GameRoom = class {
|
|
|
3975
3976
|
}
|
|
3976
3977
|
return false;
|
|
3977
3978
|
};
|
|
3978
|
-
this.sendWithHandler("join_room", { room_id: roomId, metadata }, handler);
|
|
3979
|
+
this.sendWithHandler("join_room", { room_id: roomId, metadata }, handler, 15e3, reject);
|
|
3979
3980
|
});
|
|
3980
3981
|
}
|
|
3981
3982
|
/**
|
|
@@ -3999,7 +4000,7 @@ var GameRoom = class {
|
|
|
3999
4000
|
}
|
|
4000
4001
|
return false;
|
|
4001
4002
|
};
|
|
4002
|
-
this.sendWithHandler("leave_room", {}, handler);
|
|
4003
|
+
this.sendWithHandler("leave_room", {}, handler, 15e3, reject);
|
|
4003
4004
|
});
|
|
4004
4005
|
}
|
|
4005
4006
|
/**
|
|
@@ -4046,7 +4047,7 @@ var GameRoom = class {
|
|
|
4046
4047
|
}
|
|
4047
4048
|
return false;
|
|
4048
4049
|
};
|
|
4049
|
-
this.sendWithHandler("get_state", {}, handler);
|
|
4050
|
+
this.sendWithHandler("get_state", {}, handler, 15e3, reject);
|
|
4050
4051
|
});
|
|
4051
4052
|
}
|
|
4052
4053
|
/**
|
|
@@ -4065,7 +4066,7 @@ var GameRoom = class {
|
|
|
4065
4066
|
}
|
|
4066
4067
|
return false;
|
|
4067
4068
|
};
|
|
4068
|
-
this.sendWithHandler("list_rooms", {}, handler);
|
|
4069
|
+
this.sendWithHandler("list_rooms", {}, handler, 15e3, reject);
|
|
4069
4070
|
});
|
|
4070
4071
|
}
|
|
4071
4072
|
/**
|
|
@@ -4087,7 +4088,7 @@ var GameRoom = class {
|
|
|
4087
4088
|
}
|
|
4088
4089
|
return false;
|
|
4089
4090
|
};
|
|
4090
|
-
this.sendWithHandler("ping", { timestamp }, handler);
|
|
4091
|
+
this.sendWithHandler("ping", { timestamp }, handler, 15e3, reject);
|
|
4091
4092
|
});
|
|
4092
4093
|
}
|
|
4093
4094
|
// Private methods
|
|
@@ -4108,13 +4109,14 @@ var GameRoom = class {
|
|
|
4108
4109
|
const appId = this.config.appId || "";
|
|
4109
4110
|
return `${wsUrl}/v1/game/${appId}/ws?${params.toString()}`;
|
|
4110
4111
|
}
|
|
4111
|
-
send(type, data) {
|
|
4112
|
+
send(type, data, msgId) {
|
|
4112
4113
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
4113
4114
|
throw new Error("WebSocket is not connected");
|
|
4114
4115
|
}
|
|
4115
|
-
this.ws.send(JSON.stringify({ type, data }));
|
|
4116
|
+
this.ws.send(JSON.stringify({ type, data, msg_id: msgId }));
|
|
4116
4117
|
}
|
|
4117
|
-
sendWithHandler(type, data, handler, timeoutMs = 15e3) {
|
|
4118
|
+
sendWithHandler(type, data, handler, timeoutMs = 15e3, onError) {
|
|
4119
|
+
const msgId = `${type}-${++this.msgIdCounter}`;
|
|
4118
4120
|
let timeoutId = null;
|
|
4119
4121
|
const cleanup = () => {
|
|
4120
4122
|
this.ws?.removeEventListener("message", messageHandler);
|
|
@@ -4126,6 +4128,9 @@ var GameRoom = class {
|
|
|
4126
4128
|
const messageHandler = (event) => {
|
|
4127
4129
|
try {
|
|
4128
4130
|
const msg = JSON.parse(event.data);
|
|
4131
|
+
if (msg.msg_id && msg.msg_id !== msgId) {
|
|
4132
|
+
return;
|
|
4133
|
+
}
|
|
4129
4134
|
const handled = handler(msg);
|
|
4130
4135
|
if (handled) {
|
|
4131
4136
|
cleanup();
|
|
@@ -4136,12 +4141,20 @@ var GameRoom = class {
|
|
|
4136
4141
|
this.ws?.addEventListener("message", messageHandler);
|
|
4137
4142
|
timeoutId = setTimeout(() => {
|
|
4138
4143
|
cleanup();
|
|
4144
|
+
const err = new Error(`Request '${type}' timed out after ${timeoutMs}ms`);
|
|
4145
|
+
onError?.(err);
|
|
4139
4146
|
this.handlers.onError?.({
|
|
4140
4147
|
code: "TIMEOUT",
|
|
4141
|
-
message:
|
|
4148
|
+
message: err.message
|
|
4142
4149
|
});
|
|
4143
4150
|
}, timeoutMs);
|
|
4144
|
-
|
|
4151
|
+
try {
|
|
4152
|
+
this.send(type, data, msgId);
|
|
4153
|
+
} catch (err) {
|
|
4154
|
+
cleanup();
|
|
4155
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
4156
|
+
onError?.(error);
|
|
4157
|
+
}
|
|
4145
4158
|
}
|
|
4146
4159
|
handleMessage(data) {
|
|
4147
4160
|
try {
|
|
@@ -4208,6 +4221,10 @@ var GameRoom = class {
|
|
|
4208
4221
|
scheduleReconnect(roomId) {
|
|
4209
4222
|
if (this.reconnectAttempts >= (this.config.maxReconnectAttempts ?? 5)) {
|
|
4210
4223
|
console.error("Max reconnect attempts reached");
|
|
4224
|
+
this.handlers.onError?.({
|
|
4225
|
+
code: "MAX_RECONNECT_ATTEMPTS",
|
|
4226
|
+
message: "Maximum reconnection attempts reached"
|
|
4227
|
+
});
|
|
4211
4228
|
return;
|
|
4212
4229
|
}
|
|
4213
4230
|
const delay = Math.min(
|
|
@@ -4216,10 +4233,26 @@ var GameRoom = class {
|
|
|
4216
4233
|
// Max 30초
|
|
4217
4234
|
);
|
|
4218
4235
|
this.reconnectAttempts++;
|
|
4219
|
-
|
|
4236
|
+
const previousRoomId = roomId || this._roomId;
|
|
4237
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
4220
4238
|
console.log(`Reconnecting... (attempt ${this.reconnectAttempts})`);
|
|
4221
|
-
|
|
4222
|
-
|
|
4239
|
+
try {
|
|
4240
|
+
await this.connect();
|
|
4241
|
+
if (previousRoomId) {
|
|
4242
|
+
console.log(`Rejoining room ${previousRoomId}...`);
|
|
4243
|
+
try {
|
|
4244
|
+
await this.joinRoom(previousRoomId);
|
|
4245
|
+
console.log(`Successfully rejoined room ${previousRoomId}`);
|
|
4246
|
+
} catch (rejoinError) {
|
|
4247
|
+
console.error(`Failed to rejoin room ${previousRoomId}:`, rejoinError);
|
|
4248
|
+
this.handlers.onError?.({
|
|
4249
|
+
code: "REJOIN_FAILED",
|
|
4250
|
+
message: `Failed to rejoin room: ${rejoinError}`
|
|
4251
|
+
});
|
|
4252
|
+
}
|
|
4253
|
+
}
|
|
4254
|
+
} catch {
|
|
4255
|
+
}
|
|
4223
4256
|
}, delay);
|
|
4224
4257
|
}
|
|
4225
4258
|
startPingInterval() {
|
package/dist/index.mjs
CHANGED
|
@@ -3813,6 +3813,7 @@ var GameRoom = class {
|
|
|
3813
3813
|
this._roomId = null;
|
|
3814
3814
|
this._state = null;
|
|
3815
3815
|
this._isConnected = false;
|
|
3816
|
+
this.msgIdCounter = 0;
|
|
3816
3817
|
this.config = {
|
|
3817
3818
|
gameServerUrl: getDefaultGameServerUrl(),
|
|
3818
3819
|
autoReconnect: true,
|
|
@@ -3919,7 +3920,7 @@ var GameRoom = class {
|
|
|
3919
3920
|
}
|
|
3920
3921
|
return false;
|
|
3921
3922
|
};
|
|
3922
|
-
this.sendWithHandler("create_room", config, handler);
|
|
3923
|
+
this.sendWithHandler("create_room", config, handler, 15e3, reject);
|
|
3923
3924
|
});
|
|
3924
3925
|
}
|
|
3925
3926
|
/**
|
|
@@ -3940,7 +3941,7 @@ var GameRoom = class {
|
|
|
3940
3941
|
}
|
|
3941
3942
|
return false;
|
|
3942
3943
|
};
|
|
3943
|
-
this.sendWithHandler("join_room", { room_id: roomId, metadata }, handler);
|
|
3944
|
+
this.sendWithHandler("join_room", { room_id: roomId, metadata }, handler, 15e3, reject);
|
|
3944
3945
|
});
|
|
3945
3946
|
}
|
|
3946
3947
|
/**
|
|
@@ -3964,7 +3965,7 @@ var GameRoom = class {
|
|
|
3964
3965
|
}
|
|
3965
3966
|
return false;
|
|
3966
3967
|
};
|
|
3967
|
-
this.sendWithHandler("leave_room", {}, handler);
|
|
3968
|
+
this.sendWithHandler("leave_room", {}, handler, 15e3, reject);
|
|
3968
3969
|
});
|
|
3969
3970
|
}
|
|
3970
3971
|
/**
|
|
@@ -4011,7 +4012,7 @@ var GameRoom = class {
|
|
|
4011
4012
|
}
|
|
4012
4013
|
return false;
|
|
4013
4014
|
};
|
|
4014
|
-
this.sendWithHandler("get_state", {}, handler);
|
|
4015
|
+
this.sendWithHandler("get_state", {}, handler, 15e3, reject);
|
|
4015
4016
|
});
|
|
4016
4017
|
}
|
|
4017
4018
|
/**
|
|
@@ -4030,7 +4031,7 @@ var GameRoom = class {
|
|
|
4030
4031
|
}
|
|
4031
4032
|
return false;
|
|
4032
4033
|
};
|
|
4033
|
-
this.sendWithHandler("list_rooms", {}, handler);
|
|
4034
|
+
this.sendWithHandler("list_rooms", {}, handler, 15e3, reject);
|
|
4034
4035
|
});
|
|
4035
4036
|
}
|
|
4036
4037
|
/**
|
|
@@ -4052,7 +4053,7 @@ var GameRoom = class {
|
|
|
4052
4053
|
}
|
|
4053
4054
|
return false;
|
|
4054
4055
|
};
|
|
4055
|
-
this.sendWithHandler("ping", { timestamp }, handler);
|
|
4056
|
+
this.sendWithHandler("ping", { timestamp }, handler, 15e3, reject);
|
|
4056
4057
|
});
|
|
4057
4058
|
}
|
|
4058
4059
|
// Private methods
|
|
@@ -4073,13 +4074,14 @@ var GameRoom = class {
|
|
|
4073
4074
|
const appId = this.config.appId || "";
|
|
4074
4075
|
return `${wsUrl}/v1/game/${appId}/ws?${params.toString()}`;
|
|
4075
4076
|
}
|
|
4076
|
-
send(type, data) {
|
|
4077
|
+
send(type, data, msgId) {
|
|
4077
4078
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
4078
4079
|
throw new Error("WebSocket is not connected");
|
|
4079
4080
|
}
|
|
4080
|
-
this.ws.send(JSON.stringify({ type, data }));
|
|
4081
|
+
this.ws.send(JSON.stringify({ type, data, msg_id: msgId }));
|
|
4081
4082
|
}
|
|
4082
|
-
sendWithHandler(type, data, handler, timeoutMs = 15e3) {
|
|
4083
|
+
sendWithHandler(type, data, handler, timeoutMs = 15e3, onError) {
|
|
4084
|
+
const msgId = `${type}-${++this.msgIdCounter}`;
|
|
4083
4085
|
let timeoutId = null;
|
|
4084
4086
|
const cleanup = () => {
|
|
4085
4087
|
this.ws?.removeEventListener("message", messageHandler);
|
|
@@ -4091,6 +4093,9 @@ var GameRoom = class {
|
|
|
4091
4093
|
const messageHandler = (event) => {
|
|
4092
4094
|
try {
|
|
4093
4095
|
const msg = JSON.parse(event.data);
|
|
4096
|
+
if (msg.msg_id && msg.msg_id !== msgId) {
|
|
4097
|
+
return;
|
|
4098
|
+
}
|
|
4094
4099
|
const handled = handler(msg);
|
|
4095
4100
|
if (handled) {
|
|
4096
4101
|
cleanup();
|
|
@@ -4101,12 +4106,20 @@ var GameRoom = class {
|
|
|
4101
4106
|
this.ws?.addEventListener("message", messageHandler);
|
|
4102
4107
|
timeoutId = setTimeout(() => {
|
|
4103
4108
|
cleanup();
|
|
4109
|
+
const err = new Error(`Request '${type}' timed out after ${timeoutMs}ms`);
|
|
4110
|
+
onError?.(err);
|
|
4104
4111
|
this.handlers.onError?.({
|
|
4105
4112
|
code: "TIMEOUT",
|
|
4106
|
-
message:
|
|
4113
|
+
message: err.message
|
|
4107
4114
|
});
|
|
4108
4115
|
}, timeoutMs);
|
|
4109
|
-
|
|
4116
|
+
try {
|
|
4117
|
+
this.send(type, data, msgId);
|
|
4118
|
+
} catch (err) {
|
|
4119
|
+
cleanup();
|
|
4120
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
4121
|
+
onError?.(error);
|
|
4122
|
+
}
|
|
4110
4123
|
}
|
|
4111
4124
|
handleMessage(data) {
|
|
4112
4125
|
try {
|
|
@@ -4173,6 +4186,10 @@ var GameRoom = class {
|
|
|
4173
4186
|
scheduleReconnect(roomId) {
|
|
4174
4187
|
if (this.reconnectAttempts >= (this.config.maxReconnectAttempts ?? 5)) {
|
|
4175
4188
|
console.error("Max reconnect attempts reached");
|
|
4189
|
+
this.handlers.onError?.({
|
|
4190
|
+
code: "MAX_RECONNECT_ATTEMPTS",
|
|
4191
|
+
message: "Maximum reconnection attempts reached"
|
|
4192
|
+
});
|
|
4176
4193
|
return;
|
|
4177
4194
|
}
|
|
4178
4195
|
const delay = Math.min(
|
|
@@ -4181,10 +4198,26 @@ var GameRoom = class {
|
|
|
4181
4198
|
// Max 30초
|
|
4182
4199
|
);
|
|
4183
4200
|
this.reconnectAttempts++;
|
|
4184
|
-
|
|
4201
|
+
const previousRoomId = roomId || this._roomId;
|
|
4202
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
4185
4203
|
console.log(`Reconnecting... (attempt ${this.reconnectAttempts})`);
|
|
4186
|
-
|
|
4187
|
-
|
|
4204
|
+
try {
|
|
4205
|
+
await this.connect();
|
|
4206
|
+
if (previousRoomId) {
|
|
4207
|
+
console.log(`Rejoining room ${previousRoomId}...`);
|
|
4208
|
+
try {
|
|
4209
|
+
await this.joinRoom(previousRoomId);
|
|
4210
|
+
console.log(`Successfully rejoined room ${previousRoomId}`);
|
|
4211
|
+
} catch (rejoinError) {
|
|
4212
|
+
console.error(`Failed to rejoin room ${previousRoomId}:`, rejoinError);
|
|
4213
|
+
this.handlers.onError?.({
|
|
4214
|
+
code: "REJOIN_FAILED",
|
|
4215
|
+
message: `Failed to rejoin room: ${rejoinError}`
|
|
4216
|
+
});
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
} catch {
|
|
4220
|
+
}
|
|
4188
4221
|
}, delay);
|
|
4189
4222
|
}
|
|
4190
4223
|
startPingInterval() {
|