connectbase-client 0.6.9 → 0.6.11
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 +63 -4
- package/dist/index.d.ts +63 -4
- package/dist/index.js +103 -23
- package/dist/index.mjs +103 -23
- 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:()=>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);})();
|
|
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 _=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 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 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(),N=(B-p)/1e3,V=S,J=V-l,Q=N>0?J/N:0;p=B,l=V,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);break;case"state":this._state=t.data,this.handlers.onStateUpdate?.(this._state);break;case"player_event":this.handlePlayerEvent(t);break;case"chat":this.handlers.onChat?.({roomId:t.room_id||"",clientId:t.client_id||"",userId:t.user_id,message:t.message||"",serverTime:t.server_time||0});break;case"error":this.handlers.onError?.({code:t.code||"UNKNOWN",message:t.message||"Unknown error"});break;default:break}}catch{console.error("Failed to parse game message:",e)}}handleDelta(e){let t=e.delta;if(!t)return;let s={fromVersion:t.from_version,toVersion:t.to_version,changes:t.changes.map(r=>({path:r.path,operation:r.operation,value:r.value,oldValue:r.old_value})),tick:t.tick};if(this._state){for(let r of s.changes)this.applyChange(r);this._state.version=s.toVersion}if(this.handlers.onAction){for(let r of s.changes)if(r.path.startsWith("actions.")&&r.operation==="set"&&r.value){let i=r.value;this.handlers.onAction({type:i.type||"",clientId:i.client_id||"",data:i.data,timestamp:i.timestamp||0})}}this.handlers.onDelta?.(s)}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){let t={clientId:e.player?.client_id||"",userId:e.player?.user_id,joinedAt:e.player?.joined_at||0,metadata:e.player?.metadata};e.event==="joined"?this.handlers.onPlayerJoined?.(t):e.event==="left"&&this.handlers.onPlayerLeft?.(t)}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?.({code:"CONNECTION_ERROR",message:o.message})};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);break;case"state":this._state=t.data,this.handlers.onStateUpdate?.(this._state);break;case"player_event":this.handlePlayerEvent(t);break;case"chat":this.handlers.onChat?.({roomId:t.room_id||"",clientId:t.client_id||"",userId:t.user_id,message:t.message||"",serverTime:t.server_time||0});break;case"error":this.handlers.onError?.({code:t.code||"UNKNOWN",message:t.message||"Unknown error"});break}}catch{console.error("Failed to parse game message:",e)}}handleDelta(e){let t=e.delta;if(!t)return;let s={fromVersion:t.from_version,toVersion:t.to_version,changes:t.changes.map(r=>({path:r.path,operation:r.operation,value:r.value,oldValue:r.old_value})),tick:t.tick};if(this._state){for(let r of s.changes)this.applyChange(r);this._state.version=s.toVersion}if(this.handlers.onAction){for(let r of s.changes)if(r.path.startsWith("actions.")&&r.operation==="set"&&r.value){let i=r.value;this.handlers.onAction({type:i.type||"",clientId:i.client_id||"",data:i.data,timestamp:i.timestamp||0})}}this.handlers.onDelta?.(s)}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){let t={clientId:e.player?.client_id||"",userId:e.player?.user_id,joinedAt:e.player?.joined_at||0,metadata:e.player?.metadata};e.event==="joined"?this.handlers.onPlayerJoined?.(t):e.event==="left"&&this.handlers.onPlayerLeft?.(t)}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 _(this.http),this.database=new C(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
|
@@ -198,6 +198,13 @@ interface CreateColumnRequest {
|
|
|
198
198
|
validation_rule?: string;
|
|
199
199
|
order: number;
|
|
200
200
|
description?: string;
|
|
201
|
+
/**
|
|
202
|
+
* 필드 레벨 암호화 활성화 여부.
|
|
203
|
+
* true로 설정 시 AES-256-GCM으로 DB에 암호화 저장되며, 조회 시 자동 복호화됩니다.
|
|
204
|
+
* 암호화된 필드는 DB 레벨 필터/정렬이 불가하며, 앱 레벨 검색은 정상 동작합니다.
|
|
205
|
+
* 서버에 SECRET_ENCRYPTION_KEY가 설정되어 있어야 합니다.
|
|
206
|
+
*/
|
|
207
|
+
encrypted?: boolean;
|
|
201
208
|
}
|
|
202
209
|
interface UpdateColumnRequest {
|
|
203
210
|
name?: string;
|
|
@@ -524,6 +531,24 @@ interface RetentionPolicy {
|
|
|
524
531
|
schedule?: string;
|
|
525
532
|
enabled: boolean;
|
|
526
533
|
}
|
|
534
|
+
interface CreateBackupRequest {
|
|
535
|
+
/** 백업 이름 */
|
|
536
|
+
name?: string;
|
|
537
|
+
/** 특정 테이블만 백업 (비어있으면 전체) */
|
|
538
|
+
tables?: string[];
|
|
539
|
+
/** gzip 압축 여부 */
|
|
540
|
+
compress?: boolean;
|
|
541
|
+
/** AES-256-GCM 암호화 여부 (SECRET_ENCRYPTION_KEY 필요) */
|
|
542
|
+
encrypt?: boolean;
|
|
543
|
+
}
|
|
544
|
+
interface BackupInfo {
|
|
545
|
+
id: string;
|
|
546
|
+
name: string;
|
|
547
|
+
status: 'pending' | 'completed' | 'failed' | 'in_progress';
|
|
548
|
+
encrypted: boolean;
|
|
549
|
+
compression: boolean;
|
|
550
|
+
created_at: string;
|
|
551
|
+
}
|
|
527
552
|
|
|
528
553
|
declare class DatabaseAPI {
|
|
529
554
|
private http;
|
|
@@ -3363,12 +3388,40 @@ interface GameRoomInfo {
|
|
|
3363
3388
|
type GameServerMessageType = 'room_created' | 'room_joined' | 'room_left' | 'state' | 'delta' | 'player_event' | 'chat' | 'pong' | 'room_list' | 'error';
|
|
3364
3389
|
/**
|
|
3365
3390
|
* 게임 서버 메시지
|
|
3391
|
+
* 서버는 모든 필드를 최상위에 보냄 (data 래퍼 없음)
|
|
3366
3392
|
*/
|
|
3367
|
-
interface GameServerMessage
|
|
3393
|
+
interface GameServerMessage {
|
|
3368
3394
|
type: GameServerMessageType;
|
|
3369
|
-
data: T;
|
|
3370
|
-
serverTime: number;
|
|
3371
3395
|
msg_id?: string;
|
|
3396
|
+
room_id?: string;
|
|
3397
|
+
server_time?: number;
|
|
3398
|
+
delta?: {
|
|
3399
|
+
from_version: number;
|
|
3400
|
+
to_version: number;
|
|
3401
|
+
changes: {
|
|
3402
|
+
path: string;
|
|
3403
|
+
operation: string;
|
|
3404
|
+
value?: unknown;
|
|
3405
|
+
old_value?: unknown;
|
|
3406
|
+
}[];
|
|
3407
|
+
tick: number;
|
|
3408
|
+
};
|
|
3409
|
+
tick?: number;
|
|
3410
|
+
event?: string;
|
|
3411
|
+
player?: {
|
|
3412
|
+
client_id: string;
|
|
3413
|
+
user_id?: string;
|
|
3414
|
+
joined_at: number;
|
|
3415
|
+
metadata?: Record<string, string>;
|
|
3416
|
+
};
|
|
3417
|
+
client_id?: string;
|
|
3418
|
+
user_id?: string;
|
|
3419
|
+
message?: string;
|
|
3420
|
+
data?: unknown;
|
|
3421
|
+
code?: string;
|
|
3422
|
+
timestamp?: number;
|
|
3423
|
+
client_timestamp?: number;
|
|
3424
|
+
server_timestamp?: number;
|
|
3372
3425
|
}
|
|
3373
3426
|
/**
|
|
3374
3427
|
* 플레이어 이벤트
|
|
@@ -3412,6 +3465,12 @@ interface GameEventHandlers {
|
|
|
3412
3465
|
onError?: (error: Event | ErrorMessage) => void;
|
|
3413
3466
|
onStateUpdate?: (state: GameState) => void;
|
|
3414
3467
|
onDelta?: (delta: GameDelta) => void;
|
|
3468
|
+
onAction?: (action: {
|
|
3469
|
+
type: string;
|
|
3470
|
+
clientId: string;
|
|
3471
|
+
data?: unknown;
|
|
3472
|
+
timestamp: number;
|
|
3473
|
+
}) => void;
|
|
3415
3474
|
onPlayerJoined?: (player: GamePlayer) => void;
|
|
3416
3475
|
onPlayerLeft?: (player: GamePlayer) => void;
|
|
3417
3476
|
onChat?: (message: ChatMessage) => void;
|
|
@@ -4000,4 +4059,4 @@ declare class ConnectBase {
|
|
|
4000
4059
|
updateConfig(config: Partial<ConnectBaseConfig>): void;
|
|
4001
4060
|
}
|
|
4002
4061
|
|
|
4003
|
-
export { type AdReportResponse, type AdReportSummary, AdsAPI, type AggregateResult, type AggregateStage, ApiError, type ApiKeyItem, type AppStatsResponse, type AtomicOperator, type AtomicOperatorType, AuthError, type AuthSettingsResponse, type BatchOperation, type BatchSetPageMetaRequest, type BillingCycle, type BillingKeyResponse, type BulkCreateResponse, type BulkError, type CancelPaymentRequest, type CancelPaymentResponse, type CancelSubscriptionRequest, type CategoryInfo, type Channel, type ChannelMembership, type ChargeWithBillingKeyRequest, type ChargeWithBillingKeyResponse, type ChatMessage, type ClientMessage, type ColumnSchema, type CommentListResponse, type ConfirmBillingKeyRequest, type ConfirmPaymentRequest, type ConfirmPaymentResponse, ConnectBase, type ConnectBaseConfig, type ConnectedData, type ConnectionState, type CreateApiKeyRequest, type CreateApiKeyResponse, type CreateChannelRequest, type CreateColumnRequest, type CreateDataRequest, type CreateFolderRequest, type CreateFolderResponse, type CreateIndexRequest, type CreatePlaylistRequest, type CreateRelationRequest, type CreateSecurityRuleRequest, type CreateSubscriptionRequest, type CreateTableRequest, type CreateTriggerRequest, type DailyReport, type DataItem, type DataType, type DeleteWhereResponse, type DeviceInfo, type EnabledProviderInfo, type EnabledProvidersResponse, type ErrorHandler, type ErrorMessage, type ErrorReport, type ErrorTrackerConfig, type ErrorType, type FetchApiKeysResponse, type FetchDataResponse, type FetchFilesResponse, type FileItem, GameAPI, type GameAction, type GameClientConfig, type GameConnectionState, type GameConnectionStatus, type GameDelta, type GameEventHandlers, type GamePlayer, GameRoom, type GameRoomConfig, type GameRoomInfo, GameRoomTransport, type GameServerMessage, type GameServerMessageType, type GameState, type GameTransportConfig, type GeoNear, type GeoPoint, type GeoPolygon, type GeoQuery, type GeoResponse, type GeoResult, type GeoWithin, type GetAuthorizationURLResponse, type GetFileByPathResponse, type GoogleConnectionStatus, type GuestMemberSignInResponse, type HistoryResponse, type ICEServer, type ICEServersResponse, type IndexAnalysis, type IndexRecommendation, type InitUploadResponse, type InvokeFunctionRequest, type InvokeFunctionResponse, type IssueBillingKeyRequest, type IssueBillingKeyResponse, type JoinRoomRequest, type JoinRoomResponse, type ListBillingKeysResponse, type ListPageMetasResponse, type ListSubscriptionPaymentsRequest, type ListSubscriptionPaymentsResponse, type ListSubscriptionsRequest, type ListSubscriptionsResponse, type MemberSignInRequest, type MemberSignInResponse, type MemberSignUpRequest, type MemberSignUpResponse, type MembershipTier, type MessageHandler, type MoveFileRequest, type OAuthCallbackResponse, type OAuthProvider, type PageMetaResponse, type PauseSubscriptionRequest, type PaymentDetail, type PaymentStatus, type PeerInfo, type PlayerEvent, type Playlist, type PlaylistItem, type PongMessage, type PopulateOption, type PreparePaymentRequest, type PreparePaymentResponse, type PushPlatform, type QualityProgress, type QueryOptions, type RealtimeConnectOptions, type RealtimeMessage, type RegisterDeviceRequest, type RelationType, type RenameFileRequest, type RenameFileResponse, type RetentionPolicy, type RoomInfo, type RoomStats, type RoomsResponse, type SearchOptions, type SearchResponse, type SearchResult, type SecurityRule, type SendOptions, type ServerMessage, type SetPageMetaRequest, type Shorts, type ShortsListResponse, type SignalingMessage, type SignalingMessageType, type SlowQueryInfo, type StateChange, type StateChangeHandler, type StreamDoneCallback, type StreamDoneData, type StreamErrorCallback, type StreamHandlers, type StreamMessage, type StreamOptions, type StreamSession, type StreamTokenCallback, type StreamURLResponse, type SubscribeOptions, type SubscribeTopicRequest, type SubscribedData, type Subscription, type SubscriptionPaymentResponse, type SubscriptionPaymentStatus, type SubscriptionResponse, type SubscriptionStatus, type SuperChat, type TTLConfig, type TableIndex, type TableRelation, type TableSchema, type TransactionRead, type TransactionWrite, type TranscodeStatus, type TransportType, type Trigger, type TriggerEvent, type TriggerHandlerType, type UpdateApiKeyRequest, type UpdateApiKeyResponse, type UpdateBillingKeyRequest, type UpdateChannelRequest, type UpdateColumnRequest, type UpdateDataRequest, type UpdateSecurityRuleRequest, type UpdateSubscriptionRequest, type UpdateTriggerRequest, type UpdateVideoRequest, type UploadByPathOptions, type UploadFileResponse, type UploadOptions, type UploadProgress, type VAPIDPublicKeyResponse, type ValidateResponse, type Video, type VideoComment, type VideoListOptions, type VideoListResponse, VideoProcessingError, type VideoQuality, type VideoStatus, type VideoVisibility, type WaitOptions, type WatchHistoryItem, type WebPushSubscription, type WebRTCConnectOptions, type WebRTCConnectionState, type WebRTCMode, type WhereCondition, type WhereOperator, ConnectBase as default, isWebTransportSupported };
|
|
4062
|
+
export { type AdReportResponse, type AdReportSummary, AdsAPI, type AggregateResult, type AggregateStage, ApiError, type ApiKeyItem, type AppStatsResponse, type AtomicOperator, type AtomicOperatorType, AuthError, type AuthSettingsResponse, type BackupInfo, type BatchOperation, type BatchSetPageMetaRequest, type BillingCycle, type BillingKeyResponse, type BulkCreateResponse, type BulkError, type CancelPaymentRequest, type CancelPaymentResponse, type CancelSubscriptionRequest, type CategoryInfo, type Channel, type ChannelMembership, type ChargeWithBillingKeyRequest, type ChargeWithBillingKeyResponse, type ChatMessage, type ClientMessage, type ColumnSchema, type CommentListResponse, type ConfirmBillingKeyRequest, type ConfirmPaymentRequest, type ConfirmPaymentResponse, ConnectBase, type ConnectBaseConfig, type ConnectedData, type ConnectionState, type CreateApiKeyRequest, type CreateApiKeyResponse, type CreateBackupRequest, type CreateChannelRequest, type CreateColumnRequest, type CreateDataRequest, type CreateFolderRequest, type CreateFolderResponse, type CreateIndexRequest, type CreatePlaylistRequest, type CreateRelationRequest, type CreateSecurityRuleRequest, type CreateSubscriptionRequest, type CreateTableRequest, type CreateTriggerRequest, type DailyReport, type DataItem, type DataType, type DeleteWhereResponse, type DeviceInfo, type EnabledProviderInfo, type EnabledProvidersResponse, type ErrorHandler, type ErrorMessage, type ErrorReport, type ErrorTrackerConfig, type ErrorType, type FetchApiKeysResponse, type FetchDataResponse, type FetchFilesResponse, type FileItem, GameAPI, type GameAction, type GameClientConfig, type GameConnectionState, type GameConnectionStatus, type GameDelta, type GameEventHandlers, type GamePlayer, GameRoom, type GameRoomConfig, type GameRoomInfo, GameRoomTransport, type GameServerMessage, type GameServerMessageType, type GameState, type GameTransportConfig, type GeoNear, type GeoPoint, type GeoPolygon, type GeoQuery, type GeoResponse, type GeoResult, type GeoWithin, type GetAuthorizationURLResponse, type GetFileByPathResponse, type GoogleConnectionStatus, type GuestMemberSignInResponse, type HistoryResponse, type ICEServer, type ICEServersResponse, type IndexAnalysis, type IndexRecommendation, type InitUploadResponse, type InvokeFunctionRequest, type InvokeFunctionResponse, type IssueBillingKeyRequest, type IssueBillingKeyResponse, type JoinRoomRequest, type JoinRoomResponse, type ListBillingKeysResponse, type ListPageMetasResponse, type ListSubscriptionPaymentsRequest, type ListSubscriptionPaymentsResponse, type ListSubscriptionsRequest, type ListSubscriptionsResponse, type MemberSignInRequest, type MemberSignInResponse, type MemberSignUpRequest, type MemberSignUpResponse, type MembershipTier, type MessageHandler, type MoveFileRequest, type OAuthCallbackResponse, type OAuthProvider, type PageMetaResponse, type PauseSubscriptionRequest, type PaymentDetail, type PaymentStatus, type PeerInfo, type PlayerEvent, type Playlist, type PlaylistItem, type PongMessage, type PopulateOption, type PreparePaymentRequest, type PreparePaymentResponse, type PushPlatform, type QualityProgress, type QueryOptions, type RealtimeConnectOptions, type RealtimeMessage, type RegisterDeviceRequest, type RelationType, type RenameFileRequest, type RenameFileResponse, type RetentionPolicy, type RoomInfo, type RoomStats, type RoomsResponse, type SearchOptions, type SearchResponse, type SearchResult, type SecurityRule, type SendOptions, type ServerMessage, type SetPageMetaRequest, type Shorts, type ShortsListResponse, type SignalingMessage, type SignalingMessageType, type SlowQueryInfo, type StateChange, type StateChangeHandler, type StreamDoneCallback, type StreamDoneData, type StreamErrorCallback, type StreamHandlers, type StreamMessage, type StreamOptions, type StreamSession, type StreamTokenCallback, type StreamURLResponse, type SubscribeOptions, type SubscribeTopicRequest, type SubscribedData, type Subscription, type SubscriptionPaymentResponse, type SubscriptionPaymentStatus, type SubscriptionResponse, type SubscriptionStatus, type SuperChat, type TTLConfig, type TableIndex, type TableRelation, type TableSchema, type TransactionRead, type TransactionWrite, type TranscodeStatus, type TransportType, type Trigger, type TriggerEvent, type TriggerHandlerType, type UpdateApiKeyRequest, type UpdateApiKeyResponse, type UpdateBillingKeyRequest, type UpdateChannelRequest, type UpdateColumnRequest, type UpdateDataRequest, type UpdateSecurityRuleRequest, type UpdateSubscriptionRequest, type UpdateTriggerRequest, type UpdateVideoRequest, type UploadByPathOptions, type UploadFileResponse, type UploadOptions, type UploadProgress, type VAPIDPublicKeyResponse, type ValidateResponse, type Video, type VideoComment, type VideoListOptions, type VideoListResponse, VideoProcessingError, type VideoQuality, type VideoStatus, type VideoVisibility, type WaitOptions, type WatchHistoryItem, type WebPushSubscription, type WebRTCConnectOptions, type WebRTCConnectionState, type WebRTCMode, type WhereCondition, type WhereOperator, ConnectBase as default, isWebTransportSupported };
|
package/dist/index.d.ts
CHANGED
|
@@ -198,6 +198,13 @@ interface CreateColumnRequest {
|
|
|
198
198
|
validation_rule?: string;
|
|
199
199
|
order: number;
|
|
200
200
|
description?: string;
|
|
201
|
+
/**
|
|
202
|
+
* 필드 레벨 암호화 활성화 여부.
|
|
203
|
+
* true로 설정 시 AES-256-GCM으로 DB에 암호화 저장되며, 조회 시 자동 복호화됩니다.
|
|
204
|
+
* 암호화된 필드는 DB 레벨 필터/정렬이 불가하며, 앱 레벨 검색은 정상 동작합니다.
|
|
205
|
+
* 서버에 SECRET_ENCRYPTION_KEY가 설정되어 있어야 합니다.
|
|
206
|
+
*/
|
|
207
|
+
encrypted?: boolean;
|
|
201
208
|
}
|
|
202
209
|
interface UpdateColumnRequest {
|
|
203
210
|
name?: string;
|
|
@@ -524,6 +531,24 @@ interface RetentionPolicy {
|
|
|
524
531
|
schedule?: string;
|
|
525
532
|
enabled: boolean;
|
|
526
533
|
}
|
|
534
|
+
interface CreateBackupRequest {
|
|
535
|
+
/** 백업 이름 */
|
|
536
|
+
name?: string;
|
|
537
|
+
/** 특정 테이블만 백업 (비어있으면 전체) */
|
|
538
|
+
tables?: string[];
|
|
539
|
+
/** gzip 압축 여부 */
|
|
540
|
+
compress?: boolean;
|
|
541
|
+
/** AES-256-GCM 암호화 여부 (SECRET_ENCRYPTION_KEY 필요) */
|
|
542
|
+
encrypt?: boolean;
|
|
543
|
+
}
|
|
544
|
+
interface BackupInfo {
|
|
545
|
+
id: string;
|
|
546
|
+
name: string;
|
|
547
|
+
status: 'pending' | 'completed' | 'failed' | 'in_progress';
|
|
548
|
+
encrypted: boolean;
|
|
549
|
+
compression: boolean;
|
|
550
|
+
created_at: string;
|
|
551
|
+
}
|
|
527
552
|
|
|
528
553
|
declare class DatabaseAPI {
|
|
529
554
|
private http;
|
|
@@ -3363,12 +3388,40 @@ interface GameRoomInfo {
|
|
|
3363
3388
|
type GameServerMessageType = 'room_created' | 'room_joined' | 'room_left' | 'state' | 'delta' | 'player_event' | 'chat' | 'pong' | 'room_list' | 'error';
|
|
3364
3389
|
/**
|
|
3365
3390
|
* 게임 서버 메시지
|
|
3391
|
+
* 서버는 모든 필드를 최상위에 보냄 (data 래퍼 없음)
|
|
3366
3392
|
*/
|
|
3367
|
-
interface GameServerMessage
|
|
3393
|
+
interface GameServerMessage {
|
|
3368
3394
|
type: GameServerMessageType;
|
|
3369
|
-
data: T;
|
|
3370
|
-
serverTime: number;
|
|
3371
3395
|
msg_id?: string;
|
|
3396
|
+
room_id?: string;
|
|
3397
|
+
server_time?: number;
|
|
3398
|
+
delta?: {
|
|
3399
|
+
from_version: number;
|
|
3400
|
+
to_version: number;
|
|
3401
|
+
changes: {
|
|
3402
|
+
path: string;
|
|
3403
|
+
operation: string;
|
|
3404
|
+
value?: unknown;
|
|
3405
|
+
old_value?: unknown;
|
|
3406
|
+
}[];
|
|
3407
|
+
tick: number;
|
|
3408
|
+
};
|
|
3409
|
+
tick?: number;
|
|
3410
|
+
event?: string;
|
|
3411
|
+
player?: {
|
|
3412
|
+
client_id: string;
|
|
3413
|
+
user_id?: string;
|
|
3414
|
+
joined_at: number;
|
|
3415
|
+
metadata?: Record<string, string>;
|
|
3416
|
+
};
|
|
3417
|
+
client_id?: string;
|
|
3418
|
+
user_id?: string;
|
|
3419
|
+
message?: string;
|
|
3420
|
+
data?: unknown;
|
|
3421
|
+
code?: string;
|
|
3422
|
+
timestamp?: number;
|
|
3423
|
+
client_timestamp?: number;
|
|
3424
|
+
server_timestamp?: number;
|
|
3372
3425
|
}
|
|
3373
3426
|
/**
|
|
3374
3427
|
* 플레이어 이벤트
|
|
@@ -3412,6 +3465,12 @@ interface GameEventHandlers {
|
|
|
3412
3465
|
onError?: (error: Event | ErrorMessage) => void;
|
|
3413
3466
|
onStateUpdate?: (state: GameState) => void;
|
|
3414
3467
|
onDelta?: (delta: GameDelta) => void;
|
|
3468
|
+
onAction?: (action: {
|
|
3469
|
+
type: string;
|
|
3470
|
+
clientId: string;
|
|
3471
|
+
data?: unknown;
|
|
3472
|
+
timestamp: number;
|
|
3473
|
+
}) => void;
|
|
3415
3474
|
onPlayerJoined?: (player: GamePlayer) => void;
|
|
3416
3475
|
onPlayerLeft?: (player: GamePlayer) => void;
|
|
3417
3476
|
onChat?: (message: ChatMessage) => void;
|
|
@@ -4000,4 +4059,4 @@ declare class ConnectBase {
|
|
|
4000
4059
|
updateConfig(config: Partial<ConnectBaseConfig>): void;
|
|
4001
4060
|
}
|
|
4002
4061
|
|
|
4003
|
-
export { type AdReportResponse, type AdReportSummary, AdsAPI, type AggregateResult, type AggregateStage, ApiError, type ApiKeyItem, type AppStatsResponse, type AtomicOperator, type AtomicOperatorType, AuthError, type AuthSettingsResponse, type BatchOperation, type BatchSetPageMetaRequest, type BillingCycle, type BillingKeyResponse, type BulkCreateResponse, type BulkError, type CancelPaymentRequest, type CancelPaymentResponse, type CancelSubscriptionRequest, type CategoryInfo, type Channel, type ChannelMembership, type ChargeWithBillingKeyRequest, type ChargeWithBillingKeyResponse, type ChatMessage, type ClientMessage, type ColumnSchema, type CommentListResponse, type ConfirmBillingKeyRequest, type ConfirmPaymentRequest, type ConfirmPaymentResponse, ConnectBase, type ConnectBaseConfig, type ConnectedData, type ConnectionState, type CreateApiKeyRequest, type CreateApiKeyResponse, type CreateChannelRequest, type CreateColumnRequest, type CreateDataRequest, type CreateFolderRequest, type CreateFolderResponse, type CreateIndexRequest, type CreatePlaylistRequest, type CreateRelationRequest, type CreateSecurityRuleRequest, type CreateSubscriptionRequest, type CreateTableRequest, type CreateTriggerRequest, type DailyReport, type DataItem, type DataType, type DeleteWhereResponse, type DeviceInfo, type EnabledProviderInfo, type EnabledProvidersResponse, type ErrorHandler, type ErrorMessage, type ErrorReport, type ErrorTrackerConfig, type ErrorType, type FetchApiKeysResponse, type FetchDataResponse, type FetchFilesResponse, type FileItem, GameAPI, type GameAction, type GameClientConfig, type GameConnectionState, type GameConnectionStatus, type GameDelta, type GameEventHandlers, type GamePlayer, GameRoom, type GameRoomConfig, type GameRoomInfo, GameRoomTransport, type GameServerMessage, type GameServerMessageType, type GameState, type GameTransportConfig, type GeoNear, type GeoPoint, type GeoPolygon, type GeoQuery, type GeoResponse, type GeoResult, type GeoWithin, type GetAuthorizationURLResponse, type GetFileByPathResponse, type GoogleConnectionStatus, type GuestMemberSignInResponse, type HistoryResponse, type ICEServer, type ICEServersResponse, type IndexAnalysis, type IndexRecommendation, type InitUploadResponse, type InvokeFunctionRequest, type InvokeFunctionResponse, type IssueBillingKeyRequest, type IssueBillingKeyResponse, type JoinRoomRequest, type JoinRoomResponse, type ListBillingKeysResponse, type ListPageMetasResponse, type ListSubscriptionPaymentsRequest, type ListSubscriptionPaymentsResponse, type ListSubscriptionsRequest, type ListSubscriptionsResponse, type MemberSignInRequest, type MemberSignInResponse, type MemberSignUpRequest, type MemberSignUpResponse, type MembershipTier, type MessageHandler, type MoveFileRequest, type OAuthCallbackResponse, type OAuthProvider, type PageMetaResponse, type PauseSubscriptionRequest, type PaymentDetail, type PaymentStatus, type PeerInfo, type PlayerEvent, type Playlist, type PlaylistItem, type PongMessage, type PopulateOption, type PreparePaymentRequest, type PreparePaymentResponse, type PushPlatform, type QualityProgress, type QueryOptions, type RealtimeConnectOptions, type RealtimeMessage, type RegisterDeviceRequest, type RelationType, type RenameFileRequest, type RenameFileResponse, type RetentionPolicy, type RoomInfo, type RoomStats, type RoomsResponse, type SearchOptions, type SearchResponse, type SearchResult, type SecurityRule, type SendOptions, type ServerMessage, type SetPageMetaRequest, type Shorts, type ShortsListResponse, type SignalingMessage, type SignalingMessageType, type SlowQueryInfo, type StateChange, type StateChangeHandler, type StreamDoneCallback, type StreamDoneData, type StreamErrorCallback, type StreamHandlers, type StreamMessage, type StreamOptions, type StreamSession, type StreamTokenCallback, type StreamURLResponse, type SubscribeOptions, type SubscribeTopicRequest, type SubscribedData, type Subscription, type SubscriptionPaymentResponse, type SubscriptionPaymentStatus, type SubscriptionResponse, type SubscriptionStatus, type SuperChat, type TTLConfig, type TableIndex, type TableRelation, type TableSchema, type TransactionRead, type TransactionWrite, type TranscodeStatus, type TransportType, type Trigger, type TriggerEvent, type TriggerHandlerType, type UpdateApiKeyRequest, type UpdateApiKeyResponse, type UpdateBillingKeyRequest, type UpdateChannelRequest, type UpdateColumnRequest, type UpdateDataRequest, type UpdateSecurityRuleRequest, type UpdateSubscriptionRequest, type UpdateTriggerRequest, type UpdateVideoRequest, type UploadByPathOptions, type UploadFileResponse, type UploadOptions, type UploadProgress, type VAPIDPublicKeyResponse, type ValidateResponse, type Video, type VideoComment, type VideoListOptions, type VideoListResponse, VideoProcessingError, type VideoQuality, type VideoStatus, type VideoVisibility, type WaitOptions, type WatchHistoryItem, type WebPushSubscription, type WebRTCConnectOptions, type WebRTCConnectionState, type WebRTCMode, type WhereCondition, type WhereOperator, ConnectBase as default, isWebTransportSupported };
|
|
4062
|
+
export { type AdReportResponse, type AdReportSummary, AdsAPI, type AggregateResult, type AggregateStage, ApiError, type ApiKeyItem, type AppStatsResponse, type AtomicOperator, type AtomicOperatorType, AuthError, type AuthSettingsResponse, type BackupInfo, type BatchOperation, type BatchSetPageMetaRequest, type BillingCycle, type BillingKeyResponse, type BulkCreateResponse, type BulkError, type CancelPaymentRequest, type CancelPaymentResponse, type CancelSubscriptionRequest, type CategoryInfo, type Channel, type ChannelMembership, type ChargeWithBillingKeyRequest, type ChargeWithBillingKeyResponse, type ChatMessage, type ClientMessage, type ColumnSchema, type CommentListResponse, type ConfirmBillingKeyRequest, type ConfirmPaymentRequest, type ConfirmPaymentResponse, ConnectBase, type ConnectBaseConfig, type ConnectedData, type ConnectionState, type CreateApiKeyRequest, type CreateApiKeyResponse, type CreateBackupRequest, type CreateChannelRequest, type CreateColumnRequest, type CreateDataRequest, type CreateFolderRequest, type CreateFolderResponse, type CreateIndexRequest, type CreatePlaylistRequest, type CreateRelationRequest, type CreateSecurityRuleRequest, type CreateSubscriptionRequest, type CreateTableRequest, type CreateTriggerRequest, type DailyReport, type DataItem, type DataType, type DeleteWhereResponse, type DeviceInfo, type EnabledProviderInfo, type EnabledProvidersResponse, type ErrorHandler, type ErrorMessage, type ErrorReport, type ErrorTrackerConfig, type ErrorType, type FetchApiKeysResponse, type FetchDataResponse, type FetchFilesResponse, type FileItem, GameAPI, type GameAction, type GameClientConfig, type GameConnectionState, type GameConnectionStatus, type GameDelta, type GameEventHandlers, type GamePlayer, GameRoom, type GameRoomConfig, type GameRoomInfo, GameRoomTransport, type GameServerMessage, type GameServerMessageType, type GameState, type GameTransportConfig, type GeoNear, type GeoPoint, type GeoPolygon, type GeoQuery, type GeoResponse, type GeoResult, type GeoWithin, type GetAuthorizationURLResponse, type GetFileByPathResponse, type GoogleConnectionStatus, type GuestMemberSignInResponse, type HistoryResponse, type ICEServer, type ICEServersResponse, type IndexAnalysis, type IndexRecommendation, type InitUploadResponse, type InvokeFunctionRequest, type InvokeFunctionResponse, type IssueBillingKeyRequest, type IssueBillingKeyResponse, type JoinRoomRequest, type JoinRoomResponse, type ListBillingKeysResponse, type ListPageMetasResponse, type ListSubscriptionPaymentsRequest, type ListSubscriptionPaymentsResponse, type ListSubscriptionsRequest, type ListSubscriptionsResponse, type MemberSignInRequest, type MemberSignInResponse, type MemberSignUpRequest, type MemberSignUpResponse, type MembershipTier, type MessageHandler, type MoveFileRequest, type OAuthCallbackResponse, type OAuthProvider, type PageMetaResponse, type PauseSubscriptionRequest, type PaymentDetail, type PaymentStatus, type PeerInfo, type PlayerEvent, type Playlist, type PlaylistItem, type PongMessage, type PopulateOption, type PreparePaymentRequest, type PreparePaymentResponse, type PushPlatform, type QualityProgress, type QueryOptions, type RealtimeConnectOptions, type RealtimeMessage, type RegisterDeviceRequest, type RelationType, type RenameFileRequest, type RenameFileResponse, type RetentionPolicy, type RoomInfo, type RoomStats, type RoomsResponse, type SearchOptions, type SearchResponse, type SearchResult, type SecurityRule, type SendOptions, type ServerMessage, type SetPageMetaRequest, type Shorts, type ShortsListResponse, type SignalingMessage, type SignalingMessageType, type SlowQueryInfo, type StateChange, type StateChangeHandler, type StreamDoneCallback, type StreamDoneData, type StreamErrorCallback, type StreamHandlers, type StreamMessage, type StreamOptions, type StreamSession, type StreamTokenCallback, type StreamURLResponse, type SubscribeOptions, type SubscribeTopicRequest, type SubscribedData, type Subscription, type SubscriptionPaymentResponse, type SubscriptionPaymentStatus, type SubscriptionResponse, type SubscriptionStatus, type SuperChat, type TTLConfig, type TableIndex, type TableRelation, type TableSchema, type TransactionRead, type TransactionWrite, type TranscodeStatus, type TransportType, type Trigger, type TriggerEvent, type TriggerHandlerType, type UpdateApiKeyRequest, type UpdateApiKeyResponse, type UpdateBillingKeyRequest, type UpdateChannelRequest, type UpdateColumnRequest, type UpdateDataRequest, type UpdateSecurityRuleRequest, type UpdateSubscriptionRequest, type UpdateTriggerRequest, type UpdateVideoRequest, type UploadByPathOptions, type UploadFileResponse, type UploadOptions, type UploadProgress, type VAPIDPublicKeyResponse, type ValidateResponse, type Video, type VideoComment, type VideoListOptions, type VideoListResponse, VideoProcessingError, type VideoQuality, type VideoStatus, type VideoVisibility, type WaitOptions, type WatchHistoryItem, type WebPushSubscription, type WebRTCConnectOptions, type WebRTCConnectionState, type WebRTCMode, type WhereCondition, type WhereOperator, ConnectBase as default, isWebTransportSupported };
|
package/dist/index.js
CHANGED
|
@@ -4161,20 +4161,29 @@ var GameRoom = class {
|
|
|
4161
4161
|
const msg = JSON.parse(data);
|
|
4162
4162
|
switch (msg.type) {
|
|
4163
4163
|
case "delta":
|
|
4164
|
-
this.handleDelta(msg
|
|
4164
|
+
this.handleDelta(msg);
|
|
4165
4165
|
break;
|
|
4166
4166
|
case "state":
|
|
4167
4167
|
this._state = msg.data;
|
|
4168
4168
|
this.handlers.onStateUpdate?.(this._state);
|
|
4169
4169
|
break;
|
|
4170
4170
|
case "player_event":
|
|
4171
|
-
this.handlePlayerEvent(msg
|
|
4171
|
+
this.handlePlayerEvent(msg);
|
|
4172
4172
|
break;
|
|
4173
4173
|
case "chat":
|
|
4174
|
-
this.handlers.onChat?.(
|
|
4174
|
+
this.handlers.onChat?.({
|
|
4175
|
+
roomId: msg.room_id || "",
|
|
4176
|
+
clientId: msg.client_id || "",
|
|
4177
|
+
userId: msg.user_id,
|
|
4178
|
+
message: msg.message || "",
|
|
4179
|
+
serverTime: msg.server_time || 0
|
|
4180
|
+
});
|
|
4175
4181
|
break;
|
|
4176
4182
|
case "error":
|
|
4177
|
-
this.handlers.onError?.(
|
|
4183
|
+
this.handlers.onError?.({
|
|
4184
|
+
code: msg.code || "UNKNOWN",
|
|
4185
|
+
message: msg.message || "Unknown error"
|
|
4186
|
+
});
|
|
4178
4187
|
break;
|
|
4179
4188
|
default:
|
|
4180
4189
|
break;
|
|
@@ -4183,14 +4192,39 @@ var GameRoom = class {
|
|
|
4183
4192
|
console.error("Failed to parse game message:", data);
|
|
4184
4193
|
}
|
|
4185
4194
|
}
|
|
4186
|
-
handleDelta(
|
|
4187
|
-
const
|
|
4195
|
+
handleDelta(msg) {
|
|
4196
|
+
const raw = msg.delta;
|
|
4197
|
+
if (!raw) return;
|
|
4198
|
+
const delta = {
|
|
4199
|
+
fromVersion: raw.from_version,
|
|
4200
|
+
toVersion: raw.to_version,
|
|
4201
|
+
changes: raw.changes.map((c) => ({
|
|
4202
|
+
path: c.path,
|
|
4203
|
+
operation: c.operation,
|
|
4204
|
+
value: c.value,
|
|
4205
|
+
oldValue: c.old_value
|
|
4206
|
+
})),
|
|
4207
|
+
tick: raw.tick
|
|
4208
|
+
};
|
|
4188
4209
|
if (this._state) {
|
|
4189
4210
|
for (const change of delta.changes) {
|
|
4190
4211
|
this.applyChange(change);
|
|
4191
4212
|
}
|
|
4192
4213
|
this._state.version = delta.toVersion;
|
|
4193
4214
|
}
|
|
4215
|
+
if (this.handlers.onAction) {
|
|
4216
|
+
for (const change of delta.changes) {
|
|
4217
|
+
if (change.path.startsWith("actions.") && change.operation === "set" && change.value) {
|
|
4218
|
+
const actionData = change.value;
|
|
4219
|
+
this.handlers.onAction({
|
|
4220
|
+
type: actionData.type || "",
|
|
4221
|
+
clientId: actionData.client_id || "",
|
|
4222
|
+
data: actionData.data,
|
|
4223
|
+
timestamp: actionData.timestamp || 0
|
|
4224
|
+
});
|
|
4225
|
+
}
|
|
4226
|
+
}
|
|
4227
|
+
}
|
|
4194
4228
|
this.handlers.onDelta?.(delta);
|
|
4195
4229
|
}
|
|
4196
4230
|
applyChange(change) {
|
|
@@ -4211,11 +4245,17 @@ var GameRoom = class {
|
|
|
4211
4245
|
current[lastKey] = change.value;
|
|
4212
4246
|
}
|
|
4213
4247
|
}
|
|
4214
|
-
handlePlayerEvent(
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4248
|
+
handlePlayerEvent(msg) {
|
|
4249
|
+
const player = {
|
|
4250
|
+
clientId: msg.player?.client_id || "",
|
|
4251
|
+
userId: msg.player?.user_id,
|
|
4252
|
+
joinedAt: msg.player?.joined_at || 0,
|
|
4253
|
+
metadata: msg.player?.metadata
|
|
4254
|
+
};
|
|
4255
|
+
if (msg.event === "joined") {
|
|
4256
|
+
this.handlers.onPlayerJoined?.(player);
|
|
4257
|
+
} else if (msg.event === "left") {
|
|
4258
|
+
this.handlers.onPlayerLeft?.(player);
|
|
4219
4259
|
}
|
|
4220
4260
|
}
|
|
4221
4261
|
scheduleReconnect(roomId) {
|
|
@@ -4781,7 +4821,7 @@ var GameRoomTransport = class {
|
|
|
4781
4821
|
const onError = (error) => {
|
|
4782
4822
|
this._connectionStatus = "error";
|
|
4783
4823
|
this._lastError = error;
|
|
4784
|
-
this.handlers.onError?.(error);
|
|
4824
|
+
this.handlers.onError?.({ code: "CONNECTION_ERROR", message: error.message });
|
|
4785
4825
|
};
|
|
4786
4826
|
if (useWebTransport) {
|
|
4787
4827
|
try {
|
|
@@ -4996,34 +5036,68 @@ var GameRoomTransport = class {
|
|
|
4996
5036
|
}
|
|
4997
5037
|
switch (msg.type) {
|
|
4998
5038
|
case "delta":
|
|
4999
|
-
this.handleDelta(msg
|
|
5039
|
+
this.handleDelta(msg);
|
|
5000
5040
|
break;
|
|
5001
5041
|
case "state":
|
|
5002
5042
|
this._state = msg.data;
|
|
5003
5043
|
this.handlers.onStateUpdate?.(this._state);
|
|
5004
5044
|
break;
|
|
5005
5045
|
case "player_event":
|
|
5006
|
-
this.handlePlayerEvent(msg
|
|
5046
|
+
this.handlePlayerEvent(msg);
|
|
5007
5047
|
break;
|
|
5008
5048
|
case "chat":
|
|
5009
|
-
this.handlers.onChat?.(
|
|
5049
|
+
this.handlers.onChat?.({
|
|
5050
|
+
roomId: msg.room_id || "",
|
|
5051
|
+
clientId: msg.client_id || "",
|
|
5052
|
+
userId: msg.user_id,
|
|
5053
|
+
message: msg.message || "",
|
|
5054
|
+
serverTime: msg.server_time || 0
|
|
5055
|
+
});
|
|
5010
5056
|
break;
|
|
5011
5057
|
case "error":
|
|
5012
|
-
this.handlers.onError?.(
|
|
5058
|
+
this.handlers.onError?.({
|
|
5059
|
+
code: msg.code || "UNKNOWN",
|
|
5060
|
+
message: msg.message || "Unknown error"
|
|
5061
|
+
});
|
|
5013
5062
|
break;
|
|
5014
5063
|
}
|
|
5015
5064
|
} catch {
|
|
5016
5065
|
console.error("Failed to parse game message:", data);
|
|
5017
5066
|
}
|
|
5018
5067
|
}
|
|
5019
|
-
handleDelta(
|
|
5020
|
-
const
|
|
5068
|
+
handleDelta(msg) {
|
|
5069
|
+
const raw = msg.delta;
|
|
5070
|
+
if (!raw) return;
|
|
5071
|
+
const delta = {
|
|
5072
|
+
fromVersion: raw.from_version,
|
|
5073
|
+
toVersion: raw.to_version,
|
|
5074
|
+
changes: raw.changes.map((c) => ({
|
|
5075
|
+
path: c.path,
|
|
5076
|
+
operation: c.operation,
|
|
5077
|
+
value: c.value,
|
|
5078
|
+
oldValue: c.old_value
|
|
5079
|
+
})),
|
|
5080
|
+
tick: raw.tick
|
|
5081
|
+
};
|
|
5021
5082
|
if (this._state) {
|
|
5022
5083
|
for (const change of delta.changes) {
|
|
5023
5084
|
this.applyChange(change);
|
|
5024
5085
|
}
|
|
5025
5086
|
this._state.version = delta.toVersion;
|
|
5026
5087
|
}
|
|
5088
|
+
if (this.handlers.onAction) {
|
|
5089
|
+
for (const change of delta.changes) {
|
|
5090
|
+
if (change.path.startsWith("actions.") && change.operation === "set" && change.value) {
|
|
5091
|
+
const actionData = change.value;
|
|
5092
|
+
this.handlers.onAction({
|
|
5093
|
+
type: actionData.type || "",
|
|
5094
|
+
clientId: actionData.client_id || "",
|
|
5095
|
+
data: actionData.data,
|
|
5096
|
+
timestamp: actionData.timestamp || 0
|
|
5097
|
+
});
|
|
5098
|
+
}
|
|
5099
|
+
}
|
|
5100
|
+
}
|
|
5027
5101
|
this.handlers.onDelta?.(delta);
|
|
5028
5102
|
}
|
|
5029
5103
|
applyChange(change) {
|
|
@@ -5044,11 +5118,17 @@ var GameRoomTransport = class {
|
|
|
5044
5118
|
current[lastKey] = change.value;
|
|
5045
5119
|
}
|
|
5046
5120
|
}
|
|
5047
|
-
handlePlayerEvent(
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5121
|
+
handlePlayerEvent(msg) {
|
|
5122
|
+
const player = {
|
|
5123
|
+
clientId: msg.player?.client_id || "",
|
|
5124
|
+
userId: msg.player?.user_id,
|
|
5125
|
+
joinedAt: msg.player?.joined_at || 0,
|
|
5126
|
+
metadata: msg.player?.metadata
|
|
5127
|
+
};
|
|
5128
|
+
if (msg.event === "joined") {
|
|
5129
|
+
this.handlers.onPlayerJoined?.(player);
|
|
5130
|
+
} else if (msg.event === "left") {
|
|
5131
|
+
this.handlers.onPlayerLeft?.(player);
|
|
5052
5132
|
}
|
|
5053
5133
|
}
|
|
5054
5134
|
scheduleReconnect(roomId) {
|
package/dist/index.mjs
CHANGED
|
@@ -4126,20 +4126,29 @@ var GameRoom = class {
|
|
|
4126
4126
|
const msg = JSON.parse(data);
|
|
4127
4127
|
switch (msg.type) {
|
|
4128
4128
|
case "delta":
|
|
4129
|
-
this.handleDelta(msg
|
|
4129
|
+
this.handleDelta(msg);
|
|
4130
4130
|
break;
|
|
4131
4131
|
case "state":
|
|
4132
4132
|
this._state = msg.data;
|
|
4133
4133
|
this.handlers.onStateUpdate?.(this._state);
|
|
4134
4134
|
break;
|
|
4135
4135
|
case "player_event":
|
|
4136
|
-
this.handlePlayerEvent(msg
|
|
4136
|
+
this.handlePlayerEvent(msg);
|
|
4137
4137
|
break;
|
|
4138
4138
|
case "chat":
|
|
4139
|
-
this.handlers.onChat?.(
|
|
4139
|
+
this.handlers.onChat?.({
|
|
4140
|
+
roomId: msg.room_id || "",
|
|
4141
|
+
clientId: msg.client_id || "",
|
|
4142
|
+
userId: msg.user_id,
|
|
4143
|
+
message: msg.message || "",
|
|
4144
|
+
serverTime: msg.server_time || 0
|
|
4145
|
+
});
|
|
4140
4146
|
break;
|
|
4141
4147
|
case "error":
|
|
4142
|
-
this.handlers.onError?.(
|
|
4148
|
+
this.handlers.onError?.({
|
|
4149
|
+
code: msg.code || "UNKNOWN",
|
|
4150
|
+
message: msg.message || "Unknown error"
|
|
4151
|
+
});
|
|
4143
4152
|
break;
|
|
4144
4153
|
default:
|
|
4145
4154
|
break;
|
|
@@ -4148,14 +4157,39 @@ var GameRoom = class {
|
|
|
4148
4157
|
console.error("Failed to parse game message:", data);
|
|
4149
4158
|
}
|
|
4150
4159
|
}
|
|
4151
|
-
handleDelta(
|
|
4152
|
-
const
|
|
4160
|
+
handleDelta(msg) {
|
|
4161
|
+
const raw = msg.delta;
|
|
4162
|
+
if (!raw) return;
|
|
4163
|
+
const delta = {
|
|
4164
|
+
fromVersion: raw.from_version,
|
|
4165
|
+
toVersion: raw.to_version,
|
|
4166
|
+
changes: raw.changes.map((c) => ({
|
|
4167
|
+
path: c.path,
|
|
4168
|
+
operation: c.operation,
|
|
4169
|
+
value: c.value,
|
|
4170
|
+
oldValue: c.old_value
|
|
4171
|
+
})),
|
|
4172
|
+
tick: raw.tick
|
|
4173
|
+
};
|
|
4153
4174
|
if (this._state) {
|
|
4154
4175
|
for (const change of delta.changes) {
|
|
4155
4176
|
this.applyChange(change);
|
|
4156
4177
|
}
|
|
4157
4178
|
this._state.version = delta.toVersion;
|
|
4158
4179
|
}
|
|
4180
|
+
if (this.handlers.onAction) {
|
|
4181
|
+
for (const change of delta.changes) {
|
|
4182
|
+
if (change.path.startsWith("actions.") && change.operation === "set" && change.value) {
|
|
4183
|
+
const actionData = change.value;
|
|
4184
|
+
this.handlers.onAction({
|
|
4185
|
+
type: actionData.type || "",
|
|
4186
|
+
clientId: actionData.client_id || "",
|
|
4187
|
+
data: actionData.data,
|
|
4188
|
+
timestamp: actionData.timestamp || 0
|
|
4189
|
+
});
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4159
4193
|
this.handlers.onDelta?.(delta);
|
|
4160
4194
|
}
|
|
4161
4195
|
applyChange(change) {
|
|
@@ -4176,11 +4210,17 @@ var GameRoom = class {
|
|
|
4176
4210
|
current[lastKey] = change.value;
|
|
4177
4211
|
}
|
|
4178
4212
|
}
|
|
4179
|
-
handlePlayerEvent(
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4213
|
+
handlePlayerEvent(msg) {
|
|
4214
|
+
const player = {
|
|
4215
|
+
clientId: msg.player?.client_id || "",
|
|
4216
|
+
userId: msg.player?.user_id,
|
|
4217
|
+
joinedAt: msg.player?.joined_at || 0,
|
|
4218
|
+
metadata: msg.player?.metadata
|
|
4219
|
+
};
|
|
4220
|
+
if (msg.event === "joined") {
|
|
4221
|
+
this.handlers.onPlayerJoined?.(player);
|
|
4222
|
+
} else if (msg.event === "left") {
|
|
4223
|
+
this.handlers.onPlayerLeft?.(player);
|
|
4184
4224
|
}
|
|
4185
4225
|
}
|
|
4186
4226
|
scheduleReconnect(roomId) {
|
|
@@ -4746,7 +4786,7 @@ var GameRoomTransport = class {
|
|
|
4746
4786
|
const onError = (error) => {
|
|
4747
4787
|
this._connectionStatus = "error";
|
|
4748
4788
|
this._lastError = error;
|
|
4749
|
-
this.handlers.onError?.(error);
|
|
4789
|
+
this.handlers.onError?.({ code: "CONNECTION_ERROR", message: error.message });
|
|
4750
4790
|
};
|
|
4751
4791
|
if (useWebTransport) {
|
|
4752
4792
|
try {
|
|
@@ -4961,34 +5001,68 @@ var GameRoomTransport = class {
|
|
|
4961
5001
|
}
|
|
4962
5002
|
switch (msg.type) {
|
|
4963
5003
|
case "delta":
|
|
4964
|
-
this.handleDelta(msg
|
|
5004
|
+
this.handleDelta(msg);
|
|
4965
5005
|
break;
|
|
4966
5006
|
case "state":
|
|
4967
5007
|
this._state = msg.data;
|
|
4968
5008
|
this.handlers.onStateUpdate?.(this._state);
|
|
4969
5009
|
break;
|
|
4970
5010
|
case "player_event":
|
|
4971
|
-
this.handlePlayerEvent(msg
|
|
5011
|
+
this.handlePlayerEvent(msg);
|
|
4972
5012
|
break;
|
|
4973
5013
|
case "chat":
|
|
4974
|
-
this.handlers.onChat?.(
|
|
5014
|
+
this.handlers.onChat?.({
|
|
5015
|
+
roomId: msg.room_id || "",
|
|
5016
|
+
clientId: msg.client_id || "",
|
|
5017
|
+
userId: msg.user_id,
|
|
5018
|
+
message: msg.message || "",
|
|
5019
|
+
serverTime: msg.server_time || 0
|
|
5020
|
+
});
|
|
4975
5021
|
break;
|
|
4976
5022
|
case "error":
|
|
4977
|
-
this.handlers.onError?.(
|
|
5023
|
+
this.handlers.onError?.({
|
|
5024
|
+
code: msg.code || "UNKNOWN",
|
|
5025
|
+
message: msg.message || "Unknown error"
|
|
5026
|
+
});
|
|
4978
5027
|
break;
|
|
4979
5028
|
}
|
|
4980
5029
|
} catch {
|
|
4981
5030
|
console.error("Failed to parse game message:", data);
|
|
4982
5031
|
}
|
|
4983
5032
|
}
|
|
4984
|
-
handleDelta(
|
|
4985
|
-
const
|
|
5033
|
+
handleDelta(msg) {
|
|
5034
|
+
const raw = msg.delta;
|
|
5035
|
+
if (!raw) return;
|
|
5036
|
+
const delta = {
|
|
5037
|
+
fromVersion: raw.from_version,
|
|
5038
|
+
toVersion: raw.to_version,
|
|
5039
|
+
changes: raw.changes.map((c) => ({
|
|
5040
|
+
path: c.path,
|
|
5041
|
+
operation: c.operation,
|
|
5042
|
+
value: c.value,
|
|
5043
|
+
oldValue: c.old_value
|
|
5044
|
+
})),
|
|
5045
|
+
tick: raw.tick
|
|
5046
|
+
};
|
|
4986
5047
|
if (this._state) {
|
|
4987
5048
|
for (const change of delta.changes) {
|
|
4988
5049
|
this.applyChange(change);
|
|
4989
5050
|
}
|
|
4990
5051
|
this._state.version = delta.toVersion;
|
|
4991
5052
|
}
|
|
5053
|
+
if (this.handlers.onAction) {
|
|
5054
|
+
for (const change of delta.changes) {
|
|
5055
|
+
if (change.path.startsWith("actions.") && change.operation === "set" && change.value) {
|
|
5056
|
+
const actionData = change.value;
|
|
5057
|
+
this.handlers.onAction({
|
|
5058
|
+
type: actionData.type || "",
|
|
5059
|
+
clientId: actionData.client_id || "",
|
|
5060
|
+
data: actionData.data,
|
|
5061
|
+
timestamp: actionData.timestamp || 0
|
|
5062
|
+
});
|
|
5063
|
+
}
|
|
5064
|
+
}
|
|
5065
|
+
}
|
|
4992
5066
|
this.handlers.onDelta?.(delta);
|
|
4993
5067
|
}
|
|
4994
5068
|
applyChange(change) {
|
|
@@ -5009,11 +5083,17 @@ var GameRoomTransport = class {
|
|
|
5009
5083
|
current[lastKey] = change.value;
|
|
5010
5084
|
}
|
|
5011
5085
|
}
|
|
5012
|
-
handlePlayerEvent(
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5086
|
+
handlePlayerEvent(msg) {
|
|
5087
|
+
const player = {
|
|
5088
|
+
clientId: msg.player?.client_id || "",
|
|
5089
|
+
userId: msg.player?.user_id,
|
|
5090
|
+
joinedAt: msg.player?.joined_at || 0,
|
|
5091
|
+
metadata: msg.player?.metadata
|
|
5092
|
+
};
|
|
5093
|
+
if (msg.event === "joined") {
|
|
5094
|
+
this.handlers.onPlayerJoined?.(player);
|
|
5095
|
+
} else if (msg.event === "left") {
|
|
5096
|
+
this.handlers.onPlayerLeft?.(player);
|
|
5017
5097
|
}
|
|
5018
5098
|
}
|
|
5019
5099
|
scheduleReconnect(roomId) {
|