connectbase-client 0.6.37 → 0.6.38
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/README.md +4 -4
- package/dist/connect-base.umd.js +2 -2
- package/dist/index.d.mts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +33 -5
- package/dist/index.mjs +33 -5
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -425,12 +425,12 @@ const result = await cb.auth.signInMember({
|
|
|
425
425
|
// Guest login
|
|
426
426
|
const guest = await cb.auth.signInAsGuestMember()
|
|
427
427
|
|
|
428
|
-
// OAuth login (
|
|
429
|
-
const result = await cb.oauth.signInWithPopup('google', 'https://myapp.com/oauth/callback')
|
|
430
|
-
|
|
431
|
-
// OAuth login (redirect)
|
|
428
|
+
// OAuth login (redirect - recommended)
|
|
432
429
|
await cb.oauth.signIn('google', 'https://myapp.com/oauth/callback')
|
|
433
430
|
|
|
431
|
+
// OAuth login (popup - COOP restrictions may apply)
|
|
432
|
+
const result = await cb.oauth.signInWithPopup('google', 'https://myapp.com/oauth/callback')
|
|
433
|
+
|
|
434
434
|
// Sign out
|
|
435
435
|
await cb.auth.signOut()
|
|
436
436
|
```
|
package/dist/connect-base.umd.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var ConnectBaseModule=(()=>{var G=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var ee=Object.prototype.hasOwnProperty;var te=(l,e)=>{for(var t in e)G(l,t,{get:e[t],enumerable:!0})},se=(l,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Z(e))!ee.call(l,r)&&r!==t&&G(l,r,{get:()=>e[r],enumerable:!(s=Y(e,r))||s.enumerable});return l};var re=l=>se(G({},"__esModule",{value:!0}),l);var he={};te(he,{AdsAPI:()=>P,ApiError:()=>g,AuthError:()=>f,ConnectBase:()=>F,GameAPI:()=>w,GameRoom:()=>S,GameRoomTransport:()=>B,NativeAPI:()=>R,VideoProcessingError:()=>v,default:()=>pe,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,this.config.onTokenExpired?.();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(),this.config.onTokenExpired?.();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 z="cb_guest_";function b(l){typeof window>"u"||(l?typeof window.__cbSetMember=="function"&&window.__cbSetMember(l):typeof window.__cbClearMember=="function"&&window.__cbClearMember())}function ie(l){let e=0;for(let t=0;t<l.length;t++){let s=l.charCodeAt(t);e=(e<<5)-e+s,e=e&e}return Math.abs(e).toString(36)}var I=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 getMe(){return this.http.get("/v1/public/app-members/me")}async updateCustomData(e){return this.http.patch("/v1/public/app-members/me/custom-data",e)}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=`${z}default`;else{let t=ie(e);this.cachedGuestMemberTokenKey=`${z}${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 k=class{constructor(e){this.realtimeWs=null;this.realtimeState="disconnected";this.realtimeHandlers=new Map;this.realtimeRetryCount=0;this.realtimeOptions=null;this.pendingRequests=new Map;this.pingInterval=null;this.realtimeOnStateChange=null;this.realtimeOnError=null;this.activeSubscriptions=new Map;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.patch(`${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,options: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,query: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 listSearchIndexes(e,t){return(await this.http.get(`/v1/apps/${e}/tables/${t}/search-indexes`)).indexes}async createSearchIndex(e,t,s){return this.http.post(`/v1/apps/${e}/tables/${t}/search-indexes`,s)}async deleteSearchIndex(e,t,s){await this.http.delete(`/v1/apps/${e}/tables/${t}/search-indexes/${s}`)}async listGeoIndexes(e,t){return(await this.http.get(`/v1/apps/${e}/tables/${t}/geo-indexes`)).indexes}async createGeoIndex(e,t,s){return this.http.post(`/v1/apps/${e}/tables/${t}/geo-indexes`,s)}async deleteGeoIndex(e,t,s){await this.http.delete(`/v1/apps/${e}/tables/${t}/geo-indexes/${s}`)}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}`)}async setArchivePolicy(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/archive`,t)}async getArchivePolicy(e,t){return this.http.get(`/v1/apps/${e}/lifecycle/archive/${t}`)}async executeTTL(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/ttl/${t}/execute`,{})}async executeArchive(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/archive/${t}/execute`,{})}async executeRetention(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/retention/${t}/execute`,{})}async listPolicies(e){return(await this.http.get(`/v1/apps/${e}/lifecycle`)).policies}async deletePolicy(e,t){await this.http.delete(`/v1/apps/${e}/lifecycle/${t}`)}async generateTypes(e){return this.http.get(`/v1/apps/${e}/types`)}async listBackups(e){return this.http.get(`/v1/apps/${e}/backups`)}async createBackup(e,t){return this.http.post(`/v1/apps/${e}/backups`,t)}async getBackup(e,t){return this.http.get(`/v1/apps/${e}/backups/${t}`)}async deleteBackup(e,t){await this.http.delete(`/v1/apps/${e}/backups/${t}`)}async restoreBackup(e,t,s){return this.http.post(`/v1/apps/${e}/backups/${t}/restore`,s||{backup_id:t})}async exportData(e,t){return this.http.post(`/v1/apps/${e}/data/export`,t||{format:"json"})}async importData(e,t){return this.http.post(`/v1/apps/${e}/data/import`,t)}async copyTable(e,t){return this.http.post(`/v1/apps/${e}/tables/copy`,t)}async migrateData(e,t){return this.http.post(`/v1/apps/${e}/tables/migrate`,t)}connectRealtime(e){return this.realtimeState==="connected"?Promise.resolve():this.realtimeState==="connecting"?Promise.reject(new Error("Already connecting")):(this.realtimeOptions=e,this.realtimeRetryCount=0,this.doRealtimeConnect())}disconnectRealtime(){this.realtimeOptions=null,this.setRealtimeState("disconnected"),this.realtimeRetryCount=0,this.stopRealtimePing(),this.realtimeWs&&(this.realtimeWs.close(),this.realtimeWs=null),this.pendingRequests.forEach(e=>{clearTimeout(e.timeout),e.reject(new Error("Connection closed"))}),this.pendingRequests.clear(),this.realtimeHandlers.clear(),this.activeSubscriptions.clear()}subscribe(e,t,s){if(this.realtimeState!=="connected")throw new Error("Not connected. Call connectRealtime() first.");let r=`csub_${Date.now()}_${Math.random().toString(36).substring(2,9)}`;this.activeSubscriptions.set(r,{tableId:e,options:s,handlers:t});let i=this.sendSubscribeRequest(e,t,s);return i.catch(n=>{this.activeSubscriptions.delete(r),t.onError?.(n instanceof Error?n:new Error(String(n)))}),{subscriptionId:r,unsubscribe:()=>{this.activeSubscriptions.delete(r),i.then(n=>{this.realtimeHandlers.delete(n),this.realtimeState==="connected"&&this.sendRealtimeMessage({type:"unsubscribe",request_id:this.generateRequestId(),subscription_id:n})}).catch(()=>{})},loadMore:(n,o)=>{this.realtimeState==="connected"&&i.then(a=>{let c={type:"snapshot_more",request_id:this.generateRequestId(),subscription_id:a,offset:n};o!==void 0&&(c.limit=o),this.sendRealtimeMessage(c)}).catch(()=>{})}}}setPresence(e,t,s){this.realtimeState==="connected"&&this.sendRealtimeMessage({type:"presence_set",request_id:this.generateRequestId(),status:e,device:t,metadata:s})}subscribePresence(e,t){this.realtimeState==="connected"&&(this.realtimeHandlers.set("__presence__",{onSnapshot:s=>{let r={};for(let i of s)i.data&&(r[i.id]=i.data);t(r)}}),this.sendRealtimeMessage({type:"presence_subscribe",request_id:this.generateRequestId(),user_ids:e}))}isRealtimeConnected(){return this.realtimeState==="connected"}getRealtimeState(){return this.realtimeState}onRealtimeStateChange(e){return this.realtimeOnStateChange=e,()=>{this.realtimeOnStateChange=null}}onRealtimeError(e){return this.realtimeOnError=e,()=>{this.realtimeOnError=null}}setRealtimeState(e){this.realtimeState!==e&&(this.realtimeState=e,this.realtimeOnStateChange?.(e))}doRealtimeConnect(){if(!this.realtimeOptions)return Promise.reject(new Error("No realtime options"));this.setRealtimeState("connecting");let s=`${(this.realtimeOptions.dataServerUrl||this.http.getBaseUrl()).replace(/^http/,"ws")}/v1/realtime/ws?access_token=${encodeURIComponent(this.realtimeOptions.accessToken)}`;return new Promise((r,i)=>{try{this.realtimeWs=new WebSocket(s);let n=!1,o=setTimeout(()=>{n||(n=!0,this.realtimeWs&&(this.realtimeWs.close(),this.realtimeWs=null),this.setRealtimeState("disconnected"),i(new Error("Connection timeout")))},15e3);this.realtimeWs.onopen=()=>{n||(n=!0,clearTimeout(o)),this.setRealtimeState("connected"),this.realtimeRetryCount=0,this.startRealtimePing(),this.debugLog("Database realtime connected"),this.resubscribeAll(),r()},this.realtimeWs.onmessage=a=>{try{let c=JSON.parse(a.data);this.handleRealtimeMessage(c)}catch{this.debugLog("Failed to parse realtime message")}},this.realtimeWs.onclose=()=>{this.debugLog("Database realtime disconnected"),this.realtimeWs=null,this.stopRealtimePing(),n||(n=!0,clearTimeout(o),i(new Error("Connection closed during handshake"))),this.realtimeOptions&&this.realtimeState!=="disconnected"&&this.attemptRealtimeReconnect()},this.realtimeWs.onerror=()=>{this.debugLog("Database realtime error"),this.realtimeOnError?.(new Error("WebSocket connection error"))}}catch(n){this.setRealtimeState("disconnected"),i(n)}})}sendSubscribeRequest(e,t,s){let r=this.generateRequestId();this.realtimeHandlers.set(r,t);let i=s?.where?{filters:s.where.map(n=>({field:n.field,operator:n.operator,value:n.value}))}:void 0;return this.sendRealtimeMessage({type:"subscribe",request_id:r,table_id:e,doc_id:s?.docId,query:i,options:{include_self:s?.includeSelf??!1,include_metadata_changes:s?.includeMetadataChanges??!1}}),new Promise((n,o)=>{let a=setTimeout(()=>{this.pendingRequests.delete(r),this.realtimeHandlers.delete(r),o(new Error("Subscribe request timeout"))},3e4);this.pendingRequests.set(r,{resolve:c=>{let d=c,p=this.realtimeHandlers.get(r);p&&(this.realtimeHandlers.delete(r),this.realtimeHandlers.set(d,p)),n(d)},reject:o,timeout:a})})}resubscribeAll(){if(this.activeSubscriptions.size!==0){this.realtimeHandlers.clear(),this.pendingRequests.forEach(e=>clearTimeout(e.timeout)),this.pendingRequests.clear(),this.debugLog(`Resubscribing ${this.activeSubscriptions.size} subscriptions`);for(let[,e]of this.activeSubscriptions)this.sendSubscribeRequest(e.tableId,e.handlers,e.options).catch(t=>{e.handlers.onError?.(t instanceof Error?t:new Error(String(t)))})}}handleRealtimeMessage(e){switch(e.type){case"subscribed":{let s=e.request_id,r=e.subscription_id,i=this.pendingRequests.get(s);i&&(clearTimeout(i.timeout),i.resolve(r),this.pendingRequests.delete(s));break}case"snapshot":{let s=e.subscription_id,r=this.realtimeHandlers.get(s);if(r?.onSnapshot){let i=e.docs||[],n=e.has_more||!1,o=n?e.next_offset:void 0;r.onSnapshot(i,{totalCount:e.total_count||0,hasMore:n,nextOffset:o})}break}case"change":{let s=e.subscription_id,r=this.realtimeHandlers.get(s);if(r?.onChange){let i=e.changes||[];r.onChange(i)}break}case"presence":{let s=this.realtimeHandlers.get("__presence__");if(s?.onSnapshot){let r=e.states,i=Object.entries(r||{}).map(([n,o])=>({id:n,data:o,exists:!0}));s.onSnapshot(i,{totalCount:i.length,hasMore:!1})}break}case"error":{let s=e.request_id,r=e.message||"Unknown error";if(s){let i=this.pendingRequests.get(s);i&&(clearTimeout(i.timeout),i.reject(new Error(r)),this.pendingRequests.delete(s));let n=this.realtimeHandlers.get(s);n?.onError&&n.onError(new Error(r))}else this.realtimeOnError?.(new Error(r));break}case"pong":break;case"unsubscribed":case"presence_set_ack":case"presence_subscribed":case"typing_subscribed":break}}attemptRealtimeReconnect(){let e=this.realtimeOptions?.maxRetries??5,t=this.realtimeOptions?.retryInterval??1e3;if(this.realtimeRetryCount>=e){this.setRealtimeState("disconnected"),this.realtimeOnError?.(new Error("Realtime connection lost. Max retries exceeded."));return}this.setRealtimeState("connecting"),this.realtimeRetryCount++;let s=Math.min(t*Math.pow(2,this.realtimeRetryCount-1),3e4);this.debugLog(`Reconnecting in ${s}ms (attempt ${this.realtimeRetryCount}/${e})`),setTimeout(()=>{this.realtimeOptions&&this.doRealtimeConnect().catch(r=>{this.debugLog(`Reconnect failed: ${r}`)})},s)}startRealtimePing(){this.stopRealtimePing(),this.pingInterval=setInterval(()=>{this.realtimeState==="connected"&&this.realtimeWs?.readyState===WebSocket.OPEN&&this.sendRealtimeMessage({type:"ping",timestamp:Date.now()})},3e4)}stopRealtimePing(){this.pingInterval&&(clearInterval(this.pingInterval),this.pingInterval=null)}sendRealtimeMessage(e){this.realtimeWs?.readyState===WebSocket.OPEN&&this.realtimeWs.send(JSON.stringify(e))}generateRequestId(){return"req_"+Date.now()+"_"+Math.random().toString(36).substring(2,9)}debugLog(e){this.realtimeOptions?.debug&&console.log(`[DatabaseRealtime] ${e}`)}};var C=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=await this.http.post(`${r}/storages/files/${e}/presigned-url`,{file_name:t.name,file_size:t.size,mime_type:t.type||"application/octet-stream",parent_id:s}),n=await fetch(i.upload_url,{method:"PUT",body:t,headers:{"Content-Type":t.type||"application/octet-stream"}});if(!n.ok)throw new Error(`Upload failed: ${n.statusText}`);let o=await this.http.post(`${r}/storages/files/${e}/complete-upload`,{file_id:i.file_id});return{id:o.id,name:o.name,path:o.path,type:o.type,mime_type:o.mime_type,size:o.size,url:o.url,parent_id:o.parent_id,created_at:o.created_at}}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=t.startsWith("/")?t.slice(1):t,o=r?.overwrite!==!1,a=await this.http.post(`${i}/storages/files/${e}/presigned-url/path/${n}`,{file_name:s.name,file_size:s.size,mime_type:s.type||"application/octet-stream",overwrite:o}),c=await fetch(a.upload_url,{method:"PUT",body:s,headers:{"Content-Type":s.type||"application/octet-stream"}});if(!c.ok)throw new Error(`Upload failed: ${c.statusText}`);let d=await this.http.post(`${i}/storages/files/${e}/complete-upload`,{file_id:a.file_id});return{id:d.id,name:d.name,path:d.path,type:d.type,mime_type:d.mime_type,size:d.size,url:d.url,parent_id:d.parent_id,created_at:d.created_at}}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,t){let s=this.getPublicPrefix(),r=new URLSearchParams;t?.limit!=null&&r.set("limit",String(t.limit)),t?.offset!=null&&r.set("offset",String(t.offset));let i=r.toString();return this.http.get(`${s}/storages/webs/${e}/page-metas${i?`?${i}`:""}`)}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 $=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async invoke(e,t,s){let r=this.getPublicPrefix(),i={};return t!==void 0&&(i.payload=t),s!==void 0&&(i.timeout=s),this.http.post(`${r}/functions/${e}/invoke`,i)}async call(e,t){let s=await this.invoke(e,t);if(!s.success)throw new Error(s.error||"Function execution failed");return s.result}};var E=class{constructor(e,t){this.ws=null;this.state="disconnected";this._connectionId=null;this._appId=null;this.options={maxRetries:5,retryInterval:1e3,userId:"",accessToken:"",timeout:3e4,debug:!1};this.retryCount=0;this.pendingRequests=new Map;this.subscriptions=new Map;this.streamSessions=new Map;this.stateHandlers=[];this.errorHandlers=[];this.presenceHandlers=[];this.presenceSubscriptions=new Map;this.typingHandlers=new Map;this.readReceiptHandlers=new Map;this.connectPromise=null;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"){if(this.state==="connecting"&&this.connectPromise)return this.connectPromise;this.options={...this.options,...e},e.userId&&(this.userId=e.userId),this.connectPromise=this.doConnect();try{await this.connectPromise}finally{this.connectPromise=null}}}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(),this.streamSessions.forEach(e=>{e.handlers.onError&&e.handlers.onError(new Error("Connection closed"))}),this.streamSessions.clear(),this.presenceHandlers=[],this.presenceSubscriptions.clear(),this.typingHandlers.clear(),this.readReceiptHandlers.clear(),this._connectionId=null,this._appId=null,this.retryCount=0,this.connectPromise=null}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(a,c)=>{await this.sendMessage(e,a,c)},getHistory:async a=>this.getHistory(e,a??t.historyLimit),unsubscribe:async()=>{await this.unsubscribe(e)},onMessage:a=>(n.push(a),()=>{let c=n.indexOf(a);c>-1&&n.splice(c,1)})}}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();this.streamSessions.set(i,{handlers:t,requestId:r});try{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})}catch(n){throw this.streamSessions.delete(i),n}return{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}isConnected(){return this.state==="connected"}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 setPresence(e,t={}){if(this.state!=="connected")throw new Error("Not connected");let s=this.generateRequestId();await this.sendRequest({category:"",action:"presence_set",data:{status:e,device:t.device,metadata:t.metadata},request_id:s})}async setPresenceOnDisconnect(e,t){if(this.state!=="connected")throw new Error("Not connected");let s=this.generateRequestId();await this.sendRequest({category:"",action:"presence_on_disconnect",data:{status:e,metadata:t},request_id:s})}async getPresence(e){if(this.state!=="connected")throw new Error("Not connected");let t=this.generateRequestId(),s=await this.sendRequest({category:"",action:"presence_get",data:{user_id:e},request_id:t});return{userId:s.user_id,status:s.status,lastSeen:s.last_seen,device:s.device,metadata:s.metadata}}async getPresenceMany(e){if(this.state!=="connected")throw new Error("Not connected");let t=this.generateRequestId(),s=await this.sendRequest({category:"",action:"presence_get_many",data:{user_ids:e},request_id:t}),r={};for(let[i,n]of Object.entries(s.users))r[i]={userId:n.user_id,status:n.status,lastSeen:n.last_seen,device:n.device,metadata:n.metadata};return{users:r}}async subscribePresence(e,t){if(this.state!=="connected")throw new Error("Not connected");if(!this.presenceSubscriptions.has(e)){let r=this.generateRequestId();await this.sendRequest({category:"",action:"presence_subscribe",data:{user_id:e},request_id:r}),this.presenceSubscriptions.set(e,[])}let s=this.presenceSubscriptions.get(e);return s.push(t),()=>{let r=s.indexOf(t);if(r>-1&&s.splice(r,1),s.length===0&&(this.presenceSubscriptions.delete(e),this.state==="connected")){let i=this.generateRequestId();this.sendRequest({category:"",action:"presence_unsubscribe",data:{user_id:e},request_id:i}).catch(n=>{this.log(`Failed to unsubscribe presence for ${e}: ${n}`)})}}}onPresenceChange(e){return this.presenceHandlers.push(e),()=>{let t=this.presenceHandlers.indexOf(e);t>-1&&this.presenceHandlers.splice(t,1)}}async startTyping(e){if(this.state!=="connected")throw new Error("Not connected");let t=this.generateRequestId();await this.sendRequest({category:"",action:"typing_start",data:{room_id:e},request_id:t})}async stopTyping(e){if(this.state!=="connected")throw new Error("Not connected");let t=this.generateRequestId();await this.sendRequest({category:"",action:"typing_stop",data:{room_id:e},request_id:t})}async onTypingChange(e,t){if(this.state!=="connected")throw new Error("Not connected");if(!this.typingHandlers.has(e)){let r=this.generateRequestId();await this.sendRequest({category:"",action:"typing_subscribe",data:{room_id:e},request_id:r}),this.typingHandlers.set(e,[])}let s=this.typingHandlers.get(e);return s.push(t),()=>{let r=s.indexOf(t);if(r>-1&&s.splice(r,1),s.length===0&&(this.typingHandlers.delete(e),this.state==="connected")){let i=this.generateRequestId();this.sendRequest({category:"",action:"typing_unsubscribe",data:{room_id:e},request_id:i}).catch(n=>{this.log(`Failed to unsubscribe typing for ${e}: ${n}`)})}}}async markRead(e,t){if(this.state!=="connected")throw new Error("Not connected");let s=this.generateRequestId();await this.sendRequest({category:e,action:"mark_read",data:{message_ids:t},request_id:s})}onReadReceipt(e,t){this.readReceiptHandlers.has(e)||this.readReceiptHandlers.set(e,[]);let s=this.readReceiptHandlers.get(e);return s.push(t),()=>{let r=s.indexOf(t);r>-1&&s.splice(r,1)}}async doConnect(){return new Promise((e,t)=>{this.state="connecting",this.notifyStateChange(),this.log("Connecting...");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}`,this.log("Using accessToken authentication");else{let o=this.http.getApiKey();if(!o){let a=new Error("API Key or accessToken is required for realtime connection");this.log("Connection failed: no API Key or accessToken"),t(a);return}r=`${s}/v1/realtime/auth?api_key=${encodeURIComponent(o)}&client_id=${this.clientId}`,this.log("Using API Key authentication")}this.userId&&(r+=`&user_id=${encodeURIComponent(this.userId)}`);let i=!1,n=setTimeout(()=>{i||(i=!0,this.log(`Connection timeout after ${this.options.timeout}ms`),this.ws&&(this.ws.close(),this.ws=null),this.state="disconnected",this.notifyStateChange(),t(new Error(`Connection timeout after ${this.options.timeout}ms`)))},this.options.timeout);try{this.log(`Connecting to ${s}`),this.ws=new WebSocket(r),this.ws.onopen=()=>{this.log("WebSocket opened, waiting for connected event...")},this.ws.onmessage=o=>{let a=o.data.split(`
|
|
2
|
-
`).filter(c=>c.trim());for(let c of a)try{let d=JSON.parse(c);this.handleServerMessage(d,()=>{i||(i=!0,clearTimeout(n),this.log("Connected successfully"),e())})}catch(d){console.error("[Realtime] Failed to parse message:",c,d)}},this.ws.onclose=o=>{this.log(`WebSocket closed: code=${o.code}, reason=${o.reason}`),!i&&this.state==="connecting"&&(i=!0,clearTimeout(n),t(new Error(`Connection closed: ${o.reason||"unknown reason"}`))),(this.state==="connected"||this.state==="connecting")&&this.handleDisconnect()},this.ws.onerror=o=>{this.log("WebSocket error occurred"),console.error("[Realtime] WebSocket error:",o),this.notifyError(new Error("WebSocket connection error")),!i&&this.state==="connecting"&&(i=!0,clearTimeout(n),t(new Error("Failed to connect")))}}catch(o){i=!0,clearTimeout(n),t(o)}})}log(e){this.options.debug&&console.log(`[Realtime] ${e}`)}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}case"presence":case"presence_status":{let s=e.data,r={userId:s.user_id,status:s.status,lastSeen:s.last_seen,device:s.device,metadata:s.metadata,eventType:s.event_type};this.presenceHandlers.forEach(n=>n(r));let i=this.presenceSubscriptions.get(s.user_id);if(i&&i.forEach(n=>n(r)),e.request_id){let n=this.pendingRequests.get(e.request_id);n&&(clearTimeout(n.timeout),n.resolve(e.data),this.pendingRequests.delete(e.request_id))}break}case"typing":{let s=e.data,r={roomId:s.room_id,users:s.users},i=this.typingHandlers.get(s.room_id);i&&i.forEach(n=>n(r));break}case"read_receipt":{let s=e.data,r={category:s.category,messageIds:s.message_ids,readerId:s.reader_id,readAt:s.read_at},i=this.readReceiptHandlers.get(s.category);i&&i.forEach(n=>n(r));break}}}handleDisconnect(){this.ws=null,this._connectionId=null,this.streamSessions.forEach(r=>{r.handlers.onError&&r.handlers.onError(new Error("Connection lost"))}),this.streamSessions.clear();let e=new Map;for(let[r,i]of this.subscriptions)e.set(r,[...i.handlers]);this.subscriptions.clear();let t=new Map;for(let[r,i]of this.presenceSubscriptions)t.set(r,[...i]);this.presenceSubscriptions.clear();let s=new Map;for(let[r,i]of this.typingHandlers)s.set(r,[...i]);if(this.typingHandlers.clear(),this.retryCount<this.options.maxRetries){this.state="reconnecting",this.notifyStateChange(),this.retryCount++;let r=Math.min(this.options.retryInterval*Math.pow(2,this.retryCount-1),3e4);setTimeout(async()=>{try{await this.doConnect(),this.log("Reconnected successfully, restoring subscriptions..."),await this.restoreSubscriptions(e,t,s)}catch(i){console.error("[Realtime] Reconnect failed:",i)}},r)}else this.state="disconnected",this.notifyStateChange(),this.notifyError(new Error("Connection lost. Max retries exceeded."))}async restoreSubscriptions(e,t,s){for(let[r,i]of e)try{this.log(`Restoring subscription: ${r}`);let n=this.generateRequestId(),o=await this.sendRequest({category:r,action:"subscribe",request_id:n}),a={category:o.category,persist:o.persist,historyCount:o.history_count,readReceipt:o.read_receipt};this.subscriptions.set(r,{info:a,handlers:i}),this.log(`Restored subscription: ${r}`)}catch(n){console.error(`[Realtime] Failed to restore subscription for ${r}:`,n),this.notifyError(new Error(`Failed to restore subscription: ${r}`))}for(let[r,i]of t)try{this.log(`Restoring presence subscription: ${r}`);let n=this.generateRequestId();await this.sendRequest({category:"",action:"presence_subscribe",data:{user_id:r},request_id:n}),this.presenceSubscriptions.set(r,i),this.log(`Restored presence subscription: ${r}`)}catch(n){console.error(`[Realtime] Failed to restore presence subscription for ${r}:`,n)}for(let[r,i]of s)try{this.log(`Restoring typing subscription: ${r}`);let n=this.generateRequestId();await this.sendRequest({category:"",action:"typing_subscribe",data:{room_id:r},request_id:n}),this.typingHandlers.set(r,i),this.log(`Restored typing subscription: ${r}`)}catch(n){console.error(`[Realtime] Failed to restore typing subscription for ${r}:`,n)}}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"))},this.options.timeout);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 M=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 a of o)a.peer_id!==this.currentPeerId&&await this.createPeerConnection(a.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 q=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,a=window.screenX+(window.outerWidth-n)/2,c=window.screenY+(window.outerHeight-o)/2,d=window.open(i.authorization_url,"oauth-popup",`width=${n},height=${o},left=${a},top=${c}`);if(!d)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((p,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),p(m)};window.addEventListener("message",y);let _=setInterval(()=>{d.closed&&(clearInterval(_),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 O=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 D=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 ne=5*1024*1024,v=class extends Error{constructor(e,t){super(e),this.name="VideoProcessingError",this.video=t}},H=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 a=await o.json().catch(()=>({message:o.statusText}));throw new g(o.status,a.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||ne,n=Math.ceil(e.size/i),o=0,c=Date.now(),d=0;for(let u=0;u<n;u++){let y=u*i,_=Math.min(y+i,e.size),h=e.slice(y,_),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 K=Date.now(),j=(K-c)/1e3,V=_,Q=V-d,X=j>0?Q/j:0;c=K,d=V,t.onProgress&&t.onProgress({phase:"uploading",uploadedChunks:o,totalChunks:n,percentage:Math.round(o/n*100),currentSpeed:X})}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 a=o.qualities.filter(d=>d.status==="ready").length,c=o.qualities.length||1;t.onProgress({phase:"processing",uploadedChunks:0,totalChunks:0,percentage:Math.round(a/c*100)})}await new Promise(a=>setTimeout(a,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 J=()=>{if(typeof window<"u"){let l=window.location.hostname;if(l==="localhost"||l==="127.0.0.1")return"ws://localhost:8087"}return"wss://game.connectbase.world"},S=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:J(),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=c=>{this._isConnected=!1,this.stopPingInterval(),this.handlers.onDisconnect?.(c),this.config.autoReconnect&&c.code!==1e3&&this.scheduleReconnect(e)},o=c=>{this.handlers.onError?.(c),s(new Error("WebSocket connection failed"))},a=c=>{this.handleMessage(c.data)};this.ws.addEventListener("open",i,{once:!0}),this.ws.addEventListener("close",n),this.ws.addEventListener("error",o,{once:!0}),this.ws.addEventListener("message",a)})}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,a=()=>{this.ws?.removeEventListener("message",c),o&&(clearTimeout(o),o=null)},c=d=>{try{let p=JSON.parse(d.data);if(p.msg_id&&p.msg_id!==n)return;s(p)&&a()}catch{}};this.ws?.addEventListener("message",c),o=setTimeout(()=>{a();let d=new Error(`Request '${e}' timed out after ${r}ms`);i?.(d),this.handlers.onError?.({code:"TIMEOUT",message:d.message})},r);try{this.send(e,t,n)}catch(d){a();let p=d instanceof Error?d:new Error(String(d));i?.(p)}}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)}},w=class{constructor(e,t,s){this.http=e,this.gameServerUrl=t||J().replace(/^ws/,"http"),this.appId=s}createClient(e){return new S({...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}`)}async joinQueue(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/matchmaking/queue`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({game_type:e.gameType,player_id:e.playerId,rating:e.rating,region:e.region,mode:e.mode,party_members:e.partyMembers,metadata:e.metadata})});if(!s.ok){let i=await s.json().catch(()=>({}));throw new Error(i.error||`Failed to join queue: ${s.statusText}`)}let r=await s.json();return{ticketId:r.ticket_id,gameType:r.game_type,playerId:r.player_id,status:r.status,createdAt:r.created_at}}async leaveQueue(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/matchmaking/queue`,{method:"DELETE",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({ticket_id:e})});if(!s.ok){let r=await s.json().catch(()=>({}));throw new Error(r.error||`Failed to leave queue: ${s.statusText}`)}}async getMatchStatus(e){let t=this.appId||"",s=new URLSearchParams;e.ticketId&&s.set("ticket_id",e.ticketId),e.playerId&&s.set("player_id",e.playerId);let r=await fetch(`${this.gameServerUrl}/v1/game/${t}/matchmaking/status?${s}`,{headers:this.getHeaders()});if(!r.ok){let n=await r.json().catch(()=>({}));throw new Error(n.error||`Failed to get match status: ${r.statusText}`)}let i=await r.json();return{ticketId:i.ticket_id,gameType:i.game_type,playerId:"",status:i.status,createdAt:"",waitTime:i.wait_time,matchId:i.match_id,roomId:i.room_id}}async listLobbies(){let e=this.appId||"",t=await fetch(`${this.gameServerUrl}/v1/game/${e}/lobbies`,{headers:this.getHeaders()});if(!t.ok)throw new Error(`Failed to list lobbies: ${t.statusText}`);return((await t.json()).lobbies||[]).map(r=>({id:r.id,name:r.name,hostId:r.host_id,gameType:r.game_type,playerCount:r.player_count,maxPlayers:r.max_players,hasPassword:r.has_password,visibility:r.visibility,region:r.region,settings:r.settings,tags:r.tags,status:r.status,createdAt:r.created_at}))}async createLobby(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/lobbies`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:e.playerId,display_name:e.displayName,name:e.name,game_type:e.gameType,password:e.password,max_players:e.maxPlayers,visibility:e.visibility,region:e.region,settings:e.settings,tags:e.tags})});if(!s.ok){let i=await s.json().catch(()=>({}));throw new Error(i.error||`Failed to create lobby: ${s.statusText}`)}let r=await s.json();return{id:r.id,name:r.name,hostId:r.host_id,gameType:r.game_type,playerCount:1,maxPlayers:r.max_players,hasPassword:!!e.password,visibility:r.visibility,region:r.region,settings:r.settings,tags:r.tags,status:r.status,createdAt:r.created_at}}async getLobby(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/lobbies/${e}`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to get lobby: ${s.statusText}`);let r=await s.json();return{id:r.id,name:r.name,hostId:r.host_id,gameType:r.game_type,playerCount:r.player_count,maxPlayers:r.max_players,hasPassword:r.has_password,visibility:r.visibility,region:r.region,settings:r.settings,tags:r.tags,status:r.status,roomId:r.room_id,members:(r.members||[]).map(i=>({playerId:i.player_id,displayName:i.display_name,role:i.role,team:i.team,ready:i.ready,slot:i.slot,joinedAt:i.joined_at})),createdAt:r.created_at}}async joinLobby(e,t,s,r){let i=this.appId||"",n=await fetch(`${this.gameServerUrl}/v1/game/${i}/lobbies/${e}/join`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,display_name:s,password:r})});if(!n.ok){let a=await n.json().catch(()=>({}));throw new Error(a.error||`Failed to join lobby: ${n.statusText}`)}return{lobbyId:(await n.json()).lobby_id}}async leaveLobby(e,t){let s=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${s}/lobbies/${e}/leave`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error||`Failed to leave lobby: ${r.statusText}`)}}async toggleReady(e,t,s){let r=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/${e}/ready`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,ready:s})});if(!i.ok){let n=await i.json().catch(()=>({}));throw new Error(n.error||`Failed to toggle ready: ${i.statusText}`)}}async startGame(e,t){let s=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${s}/lobbies/${e}/start`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({host_id:t})});if(!r.ok){let n=await r.json().catch(()=>({}));throw new Error(n.error||`Failed to start game: ${r.statusText}`)}return{roomId:(await r.json()).room_id}}async kickPlayer(e,t,s){let r=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/${e}/kick/${s}`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({host_id:t})});if(!i.ok){let n=await i.json().catch(()=>({}));throw new Error(n.error||`Failed to kick player: ${i.statusText}`)}}async updateLobby(e,t){let s=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${s}/lobbies/${e}`,{method:"PATCH",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({host_id:t.hostId,name:t.name,max_players:t.maxPlayers,visibility:t.visibility,password:t.password,settings:t.settings,tags:t.tags})});if(!r.ok){let n=await r.json().catch(()=>({}));throw new Error(n.error||`Failed to update lobby: ${r.statusText}`)}let i=await r.json();return{id:i.id,name:i.name,hostId:"",gameType:"",playerCount:0,maxPlayers:i.max_players,hasPassword:!1,visibility:i.visibility,region:"",settings:i.settings,tags:i.tags,status:"",createdAt:""}}async sendLobbyChat(e,t,s){let r=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/${e}/chat`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,message:s})});if(!i.ok){let n=await i.json().catch(()=>({}));throw new Error(n.error||`Failed to send chat: ${i.statusText}`)}}async invitePlayer(e,t,s){let r=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/${e}/invite`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({inviter_id:t,invitee_id:s})});if(!i.ok){let o=await i.json().catch(()=>({}));throw new Error(o.error||`Failed to invite player: ${i.statusText}`)}let n=await i.json();return{inviteId:n.invite_id,lobbyId:n.lobby_id,lobbyName:n.lobby_name,inviterId:n.inviter_id,inviteeId:n.invitee_id,status:"pending",createdAt:"",expiresAt:n.expires_at}}async acceptInvite(e,t,s){let r=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/invites/${e}/accept`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,display_name:s})});if(!i.ok){let o=await i.json().catch(()=>({}));throw new Error(o.error||`Failed to accept invite: ${i.statusText}`)}return{lobbyId:(await i.json()).lobby_id}}async declineInvite(e,t){let s=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${s}/lobbies/invites/${e}/decline`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error||`Failed to decline invite: ${r.statusText}`)}}async getPlayerInvites(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/lobbies/player/${e}/invites`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to get invites: ${s.statusText}`);return((await s.json()).invites||[]).map(i=>({inviteId:i.invite_id,lobbyId:i.lobby_id,lobbyName:i.lobby_name,inviterId:i.inviter_id,inviteeId:"",status:i.status,createdAt:i.created_at,expiresAt:i.expires_at}))}getHeaders(){let e={},t=this.http.getApiKey();t&&(e["X-API-Key"]=t);let s=this.http.getAccessToken();return s&&(e.Authorization=`Bearer ${s}`),e}};var P=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasApiKey()?"/v1/public":"/v1"}async getConnectionStatus(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/connection`)}async getReport(e,t){let s=this.getPublicPrefix(),r=new URLSearchParams;e&&r.set("start",e),t&&r.set("end",t);let i=r.toString();return this.http.get(`${s}/ads/reports${i?`?${i}`:""}`)}async getReportSummary(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/reports/summary`)}async getAdMobReport(e,t){let s=this.getPublicPrefix(),r=new URLSearchParams;e&&r.set("start",e),t&&r.set("end",t);let i=r.toString();return this.http.get(`${s}/ads/admob/reports${i?`?${i}`:""}`)}async getAdMobReportSummary(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/admob/reports/summary`)}};var R=class{constructor(){this.clipboard={writeText:async e=>{this.getPlatform()==="desktop"&&window.NativeBridge?.clipboard?await window.NativeBridge.clipboard.writeText(e):await navigator.clipboard.writeText(e)},readText:async()=>this.getPlatform()==="desktop"&&window.NativeBridge?.clipboard?window.NativeBridge.clipboard.readText():navigator.clipboard.readText(),writeHTML:async e=>{window.NativeBridge?.clipboard?.writeHTML?await window.NativeBridge.clipboard.writeHTML(e):await navigator.clipboard.writeText(e)},writeImage:async e=>{if(window.NativeBridge?.clipboard?.writeImage)await window.NativeBridge.clipboard.writeImage(e);else throw new Error("Image clipboard not supported on this platform")},readImage:async()=>window.NativeBridge?.clipboard?.readImage?window.NativeBridge.clipboard.readImage():null};this.filesystem={pickFile:async e=>{if(this.getPlatform()==="desktop"&&window.NativeBridge?.filesystem?.showOpenDialog){let s=await window.NativeBridge.filesystem.showOpenDialog({properties:e?.multiple?["openFile","multiSelections"]:["openFile"],filters:e?.filters});return s.canceled||!s.filePaths.length?null:s.filePaths.map(r=>new File([],r.split("/").pop()||"file"))}return new Promise(s=>{let r=document.createElement("input");r.type="file",e?.accept&&(r.accept=e.accept),e?.multiple&&(r.multiple=!0),r.onchange=()=>{s(r.files?Array.from(r.files):null)},r.click()})},saveFile:async(e,t,s)=>{let r=this.getPlatform();if(r==="desktop"&&window.NativeBridge?.filesystem){let a=await window.NativeBridge.filesystem.showSaveDialog?.({defaultPath:t,filters:s?.filters});if(a?.canceled||!a?.filePath)return!1;let c=e instanceof Blob?await e.text():e;return(await window.NativeBridge.filesystem.writeFile(a.filePath,c)).success}if(r==="mobile"&&window.NativeBridge?.filesystem){let a=e instanceof Blob?await e.text():e;return(await window.NativeBridge.filesystem.writeFile(t,a)).success}let i=e instanceof Blob?e:new Blob([e],{type:"text/plain"}),n=URL.createObjectURL(i),o=document.createElement("a");return o.href=n,o.download=t,o.click(),URL.revokeObjectURL(n),!0},readFile:async e=>{if(window.NativeBridge?.filesystem?.readFile){let t=await window.NativeBridge.filesystem.readFile(e);return t.success?t.content??null:null}return null},exists:async e=>window.NativeBridge?.filesystem?.exists?window.NativeBridge.filesystem.exists(e):!1};this.camera={takePicture:async e=>this.getPlatform()==="mobile"&&window.NativeBridge?.camera?window.NativeBridge.camera.takePicture(e):new Promise(s=>{let r=document.createElement("input");r.type="file",r.accept="image/*",r.capture="environment",r.onchange=async()=>{let i=r.files?.[0];if(!i){s(null);return}let n=new FileReader;n.onload=()=>{let o=new Image;o.onload=()=>{s({uri:URL.createObjectURL(i),base64:e?.base64?n.result.split(",")[1]:void 0,width:o.width,height:o.height})},o.src=n.result},n.readAsDataURL(i)},r.click()}),pickImage:async e=>this.getPlatform()==="mobile"&&window.NativeBridge?.camera?window.NativeBridge.camera.pickImage(e):new Promise(s=>{let r=document.createElement("input");r.type="file",r.accept="image/*",e?.multiple&&(r.multiple=!0),r.onchange=async()=>{let i=r.files;if(!i?.length){s(null);return}let n=[];for(let o of Array.from(i)){let a=await new Promise(c=>{let d=new FileReader;d.onload=()=>{let p=new Image;p.onload=()=>{c({uri:URL.createObjectURL(o),base64:e?.base64?d.result.split(",")[1]:void 0,width:p.width,height:p.height})},p.src=d.result},d.readAsDataURL(o)});n.push(a)}s(n)},r.click()})};this.location={getCurrentPosition:async e=>this.getPlatform()==="mobile"&&window.NativeBridge?.location?window.NativeBridge.location.getCurrentPosition(e):new Promise((s,r)=>{navigator.geolocation.getCurrentPosition(i=>{s({latitude:i.coords.latitude,longitude:i.coords.longitude,altitude:i.coords.altitude,accuracy:i.coords.accuracy,timestamp:i.timestamp})},r,{enableHighAccuracy:e?.accuracy==="high",timeout:1e4,maximumAge:0})})};this.notification={show:async e=>this.getPlatform()==="desktop"&&window.NativeBridge?.notification?(await window.NativeBridge.notification.show(e)).success:!("Notification"in window)||Notification.permission!=="granted"&&await Notification.requestPermission()!=="granted"?!1:(new Notification(e.title,{body:e.body,icon:e.icon,silent:e.silent}),!0),requestPermission:async()=>this.getPlatform()==="mobile"&&window.NativeBridge?.push?(await window.NativeBridge.push.requestPermission()).granted:"Notification"in window?await Notification.requestPermission()==="granted":!1};this.shell={openExternal:async e=>this.getPlatform()==="desktop"&&window.NativeBridge?.shell?(await window.NativeBridge.shell.openExternal(e)).success:(window.open(e,"_blank"),!0)};this.window={minimize:async()=>{await window.NativeBridge?.window?.minimize()},maximize:async()=>{await window.NativeBridge?.window?.maximize()},unmaximize:async()=>{await window.NativeBridge?.window?.unmaximize()},close:async()=>{await window.NativeBridge?.window?.close()},isMaximized:async()=>await window.NativeBridge?.window?.isMaximized()??!1,setTitle:async e=>{window.NativeBridge?.window?await window.NativeBridge.window.setTitle(e):document.title=e},setFullScreen:async e=>{window.NativeBridge?.window?await window.NativeBridge.window.setFullScreen(e):document.documentElement.requestFullscreen&&(e?await document.documentElement.requestFullscreen():document.exitFullscreen&&await document.exitFullscreen())}};this.system={getInfo:async()=>window.NativeBridge?.system?window.NativeBridge.system.getInfo():null,getMemory:async()=>window.NativeBridge?.system?window.NativeBridge.system.getMemory():null};this.biometric={isAvailable:async()=>window.NativeBridge?.biometric?window.NativeBridge.biometric.isAvailable():null,authenticate:async e=>window.NativeBridge?.biometric?window.NativeBridge.biometric.authenticate(e):null};this.secureStore={setItem:async(e,t)=>window.NativeBridge?.secureStore?(await window.NativeBridge.secureStore.setItem(e,t)).success:(localStorage.setItem(e,t),!0),getItem:async e=>window.NativeBridge?.secureStore?(await window.NativeBridge.secureStore.getItem(e)).value:localStorage.getItem(e),deleteItem:async e=>window.NativeBridge?.secureStore?(await window.NativeBridge.secureStore.deleteItem(e)).success:(localStorage.removeItem(e),!0)};this.admob={showInterstitial:async()=>window.NativeBridge?.admob?(await window.NativeBridge.admob.showInterstitial()).shown:!1,showRewarded:async()=>window.NativeBridge?.admob?(await window.NativeBridge.admob.showRewarded()).rewarded:!1}}getPlatform(){if(typeof window>"u")return"web";let e=window.NativeBridge;return e?.platform==="electron"?"desktop":e?.platform==="react-native"||e?.platform==="ios"||e?.platform==="android"||e?.camera||window.ReactNativeWebView?"mobile":"web"}hasFeature(e){return typeof window>"u"?!1:!!window.NativeBridge?.[e]}get bridge(){if(!(typeof window>"u"))return window.NativeBridge}};var N=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 a=s.slice(4,4+o);s=s.slice(4+o),this.onMessage(a)}}}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(a){t(a);return}let r=()=>{e()},i=()=>{this.onClose()},n=a=>{let c=new Error("WebSocket error");this.onError(c),t(c)},o=a=>{a.data instanceof ArrayBuffer?this.onMessage(new Uint8Array(a.data)):typeof a.data=="string"&&this.onMessage(new TextEncoder().encode(a.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 B=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 N(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 oe="https://api.connectbase.world",ae="https://socket.connectbase.world",ce="https://webrtc.connectbase.world",le="https://video.connectbase.world",de="https://game.connectbase.world",F=class{constructor(e={}){let t={baseUrl:e.baseUrl||oe,apiKey:e.apiKey,onTokenRefresh:e.onTokenRefresh,onAuthError:e.onAuthError,onTokenExpired:e.onTokenExpired};this.http=new T(t),this.auth=new I(this.http),this.database=new k(this.http),this.storage=new C(this.http),this.apiKey=new x(this.http),this.functions=new $(this.http),this.realtime=new E(this.http,e.socketUrl||ae),this.webrtc=new M(this.http,e.webrtcUrl||ce,e.appId),this.errorTracker=new q(this.http,e.errorTracker),this.oauth=new A(this.http),this.payment=new U(this.http),this.subscription=new O(this.http),this.push=new D(this.http),this.video=new H(this.http,e.videoUrl||le),this.game=new w(this.http,e.gameUrl||de,e.appId),this.ads=new P(this.http),this.native=new R}setTokens(e,t){this.http.setTokens(e,t)}clearTokens(){this.http.clearTokens()}updateConfig(e){this.http.updateConfig(e)}},pe=F;return re(he);})();
|
|
1
|
+
"use strict";var ConnectBaseModule=(()=>{var K=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var ee=Object.prototype.hasOwnProperty;var te=(l,e)=>{for(var t in e)K(l,t,{get:e[t],enumerable:!0})},se=(l,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Z(e))!ee.call(l,r)&&r!==t&&K(l,r,{get:()=>e[r],enumerable:!(s=Y(e,r))||s.enumerable});return l};var re=l=>se(K({},"__esModule",{value:!0}),l);var he={};te(he,{AdsAPI:()=>S,ApiError:()=>m,AuthError:()=>f,ConnectBase:()=>W,GameAPI:()=>R,GameRoom:()=>T,GameRoomTransport:()=>N,NativeAPI:()=>_,VideoProcessingError:()=>P,default:()=>pe,isWebTransportSupported:()=>V});var m=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 C=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,this.config.onTokenExpired?.();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(),this.config.onTokenExpired?.();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 m(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 z="cb_guest_";function w(l){typeof window>"u"||(l?typeof window.__cbSetMember=="function"&&window.__cbSetMember(l):typeof window.__cbClearMember=="function"&&window.__cbClearMember())}function ie(l){let e=0;for(let t=0;t<l.length;t++){let s=l.charCodeAt(t);e=(e<<5)-e+s,e=e&e}return Math.abs(e).toString(36)}var x=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),w(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),w(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 getMe(){return this.http.get("/v1/public/app-members/me")}async updateCustomData(e){return this.http.patch("/v1/public/app-members/me/custom-data",e)}async signOut(){try{await this.http.post("/v1/auth/logout")}finally{this.http.clearTokens(),w(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 w(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),w(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),w(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=`${z}default`;else{let t=ie(e);this.cachedGuestMemberTokenKey=`${z}${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.realtimeWs=null;this.realtimeState="disconnected";this.realtimeHandlers=new Map;this.realtimeRetryCount=0;this.realtimeOptions=null;this.pendingRequests=new Map;this.pingInterval=null;this.realtimeOnStateChange=null;this.realtimeOnError=null;this.activeSubscriptions=new Map;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.patch(`${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,options: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,query: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 listSearchIndexes(e,t){return(await this.http.get(`/v1/apps/${e}/tables/${t}/search-indexes`)).indexes}async createSearchIndex(e,t,s){return this.http.post(`/v1/apps/${e}/tables/${t}/search-indexes`,s)}async deleteSearchIndex(e,t,s){await this.http.delete(`/v1/apps/${e}/tables/${t}/search-indexes/${s}`)}async listGeoIndexes(e,t){return(await this.http.get(`/v1/apps/${e}/tables/${t}/geo-indexes`)).indexes}async createGeoIndex(e,t,s){return this.http.post(`/v1/apps/${e}/tables/${t}/geo-indexes`,s)}async deleteGeoIndex(e,t,s){await this.http.delete(`/v1/apps/${e}/tables/${t}/geo-indexes/${s}`)}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}`)}async setArchivePolicy(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/archive`,t)}async getArchivePolicy(e,t){return this.http.get(`/v1/apps/${e}/lifecycle/archive/${t}`)}async executeTTL(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/ttl/${t}/execute`,{})}async executeArchive(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/archive/${t}/execute`,{})}async executeRetention(e,t){return this.http.post(`/v1/apps/${e}/lifecycle/retention/${t}/execute`,{})}async listPolicies(e){return(await this.http.get(`/v1/apps/${e}/lifecycle`)).policies}async deletePolicy(e,t){await this.http.delete(`/v1/apps/${e}/lifecycle/${t}`)}async generateTypes(e){return this.http.get(`/v1/apps/${e}/types`)}async listBackups(e){return this.http.get(`/v1/apps/${e}/backups`)}async createBackup(e,t){return this.http.post(`/v1/apps/${e}/backups`,t)}async getBackup(e,t){return this.http.get(`/v1/apps/${e}/backups/${t}`)}async deleteBackup(e,t){await this.http.delete(`/v1/apps/${e}/backups/${t}`)}async restoreBackup(e,t,s){return this.http.post(`/v1/apps/${e}/backups/${t}/restore`,s||{backup_id:t})}async exportData(e,t){return this.http.post(`/v1/apps/${e}/data/export`,t||{format:"json"})}async importData(e,t){return this.http.post(`/v1/apps/${e}/data/import`,t)}async copyTable(e,t){return this.http.post(`/v1/apps/${e}/tables/copy`,t)}async migrateData(e,t){return this.http.post(`/v1/apps/${e}/tables/migrate`,t)}connectRealtime(e){return this.realtimeState==="connected"?Promise.resolve():this.realtimeState==="connecting"?Promise.reject(new Error("Already connecting")):(this.realtimeOptions=e,this.realtimeRetryCount=0,this.doRealtimeConnect())}disconnectRealtime(){this.realtimeOptions=null,this.setRealtimeState("disconnected"),this.realtimeRetryCount=0,this.stopRealtimePing(),this.realtimeWs&&(this.realtimeWs.close(),this.realtimeWs=null),this.pendingRequests.forEach(e=>{clearTimeout(e.timeout),e.reject(new Error("Connection closed"))}),this.pendingRequests.clear(),this.realtimeHandlers.clear(),this.activeSubscriptions.clear()}subscribe(e,t,s){if(this.realtimeState!=="connected")throw new Error("Not connected. Call connectRealtime() first.");let r=`csub_${Date.now()}_${Math.random().toString(36).substring(2,9)}`;this.activeSubscriptions.set(r,{tableId:e,options:s,handlers:t});let i=this.sendSubscribeRequest(e,t,s);return i.catch(n=>{this.activeSubscriptions.delete(r),t.onError?.(n instanceof Error?n:new Error(String(n)))}),{subscriptionId:r,unsubscribe:()=>{this.activeSubscriptions.delete(r),i.then(n=>{this.realtimeHandlers.delete(n),this.realtimeState==="connected"&&this.sendRealtimeMessage({type:"unsubscribe",request_id:this.generateRequestId(),subscription_id:n})}).catch(()=>{})},loadMore:(n,o)=>{this.realtimeState==="connected"&&i.then(a=>{let c={type:"snapshot_more",request_id:this.generateRequestId(),subscription_id:a,offset:n};o!==void 0&&(c.limit=o),this.sendRealtimeMessage(c)}).catch(()=>{})}}}setPresence(e,t,s){this.realtimeState==="connected"&&this.sendRealtimeMessage({type:"presence_set",request_id:this.generateRequestId(),status:e,device:t,metadata:s})}subscribePresence(e,t){this.realtimeState==="connected"&&(this.realtimeHandlers.set("__presence__",{onSnapshot:s=>{let r={};for(let i of s)i.data&&(r[i.id]=i.data);t(r)}}),this.sendRealtimeMessage({type:"presence_subscribe",request_id:this.generateRequestId(),user_ids:e}))}isRealtimeConnected(){return this.realtimeState==="connected"}getRealtimeState(){return this.realtimeState}onRealtimeStateChange(e){return this.realtimeOnStateChange=e,()=>{this.realtimeOnStateChange=null}}onRealtimeError(e){return this.realtimeOnError=e,()=>{this.realtimeOnError=null}}setRealtimeState(e){this.realtimeState!==e&&(this.realtimeState=e,this.realtimeOnStateChange?.(e))}doRealtimeConnect(){if(!this.realtimeOptions)return Promise.reject(new Error("No realtime options"));this.setRealtimeState("connecting");let s=`${(this.realtimeOptions.dataServerUrl||this.http.getBaseUrl()).replace(/^http/,"ws")}/v1/realtime/ws?access_token=${encodeURIComponent(this.realtimeOptions.accessToken)}`;return new Promise((r,i)=>{try{this.realtimeWs=new WebSocket(s);let n=!1,o=setTimeout(()=>{n||(n=!0,this.realtimeWs&&(this.realtimeWs.close(),this.realtimeWs=null),this.setRealtimeState("disconnected"),i(new Error("Connection timeout")))},15e3);this.realtimeWs.onopen=()=>{n||(n=!0,clearTimeout(o)),this.setRealtimeState("connected"),this.realtimeRetryCount=0,this.startRealtimePing(),this.debugLog("Database realtime connected"),this.resubscribeAll(),r()},this.realtimeWs.onmessage=a=>{try{let c=JSON.parse(a.data);this.handleRealtimeMessage(c)}catch{this.debugLog("Failed to parse realtime message")}},this.realtimeWs.onclose=()=>{this.debugLog("Database realtime disconnected"),this.realtimeWs=null,this.stopRealtimePing(),n||(n=!0,clearTimeout(o),i(new Error("Connection closed during handshake"))),this.realtimeOptions&&this.realtimeState!=="disconnected"&&this.attemptRealtimeReconnect()},this.realtimeWs.onerror=()=>{this.debugLog("Database realtime error"),this.realtimeOnError?.(new Error("WebSocket connection error"))}}catch(n){this.setRealtimeState("disconnected"),i(n)}})}sendSubscribeRequest(e,t,s){let r=this.generateRequestId();this.realtimeHandlers.set(r,t);let i=s?.where?{filters:s.where.map(n=>({field:n.field,operator:n.operator,value:n.value}))}:void 0;return this.sendRealtimeMessage({type:"subscribe",request_id:r,table_id:e,doc_id:s?.docId,query:i,options:{include_self:s?.includeSelf??!1,include_metadata_changes:s?.includeMetadataChanges??!1}}),new Promise((n,o)=>{let a=setTimeout(()=>{this.pendingRequests.delete(r),this.realtimeHandlers.delete(r),o(new Error("Subscribe request timeout"))},3e4);this.pendingRequests.set(r,{resolve:c=>{let d=c,p=this.realtimeHandlers.get(r);p&&(this.realtimeHandlers.delete(r),this.realtimeHandlers.set(d,p)),n(d)},reject:o,timeout:a})})}resubscribeAll(){if(this.activeSubscriptions.size!==0){this.realtimeHandlers.clear(),this.pendingRequests.forEach(e=>clearTimeout(e.timeout)),this.pendingRequests.clear(),this.debugLog(`Resubscribing ${this.activeSubscriptions.size} subscriptions`);for(let[,e]of this.activeSubscriptions)this.sendSubscribeRequest(e.tableId,e.handlers,e.options).catch(t=>{e.handlers.onError?.(t instanceof Error?t:new Error(String(t)))})}}handleRealtimeMessage(e){switch(e.type){case"subscribed":{let s=e.request_id,r=e.subscription_id,i=this.pendingRequests.get(s);i&&(clearTimeout(i.timeout),i.resolve(r),this.pendingRequests.delete(s));break}case"snapshot":{let s=e.subscription_id,r=this.realtimeHandlers.get(s);if(r?.onSnapshot){let i=e.docs||[],n=e.has_more||!1,o=n?e.next_offset:void 0;r.onSnapshot(i,{totalCount:e.total_count||0,hasMore:n,nextOffset:o})}break}case"change":{let s=e.subscription_id,r=this.realtimeHandlers.get(s);if(r?.onChange){let i=e.changes||[];r.onChange(i)}break}case"presence":{let s=this.realtimeHandlers.get("__presence__");if(s?.onSnapshot){let r=e.states,i=Object.entries(r||{}).map(([n,o])=>({id:n,data:o,exists:!0}));s.onSnapshot(i,{totalCount:i.length,hasMore:!1})}break}case"error":{let s=e.request_id,r=e.message||"Unknown error";if(s){let i=this.pendingRequests.get(s);i&&(clearTimeout(i.timeout),i.reject(new Error(r)),this.pendingRequests.delete(s));let n=this.realtimeHandlers.get(s);n?.onError&&n.onError(new Error(r))}else this.realtimeOnError?.(new Error(r));break}case"pong":break;case"unsubscribed":case"presence_set_ack":case"presence_subscribed":case"typing_subscribed":break}}attemptRealtimeReconnect(){let e=this.realtimeOptions?.maxRetries??5,t=this.realtimeOptions?.retryInterval??1e3;if(this.realtimeRetryCount>=e){this.setRealtimeState("disconnected"),this.realtimeOnError?.(new Error("Realtime connection lost. Max retries exceeded."));return}this.setRealtimeState("connecting"),this.realtimeRetryCount++;let s=Math.min(t*Math.pow(2,this.realtimeRetryCount-1),3e4);this.debugLog(`Reconnecting in ${s}ms (attempt ${this.realtimeRetryCount}/${e})`),setTimeout(()=>{this.realtimeOptions&&this.doRealtimeConnect().catch(r=>{this.debugLog(`Reconnect failed: ${r}`)})},s)}startRealtimePing(){this.stopRealtimePing(),this.pingInterval=setInterval(()=>{this.realtimeState==="connected"&&this.realtimeWs?.readyState===WebSocket.OPEN&&this.sendRealtimeMessage({type:"ping",timestamp:Date.now()})},3e4)}stopRealtimePing(){this.pingInterval&&(clearInterval(this.pingInterval),this.pingInterval=null)}sendRealtimeMessage(e){this.realtimeWs?.readyState===WebSocket.OPEN&&this.realtimeWs.send(JSON.stringify(e))}generateRequestId(){return"req_"+Date.now()+"_"+Math.random().toString(36).substring(2,9)}debugLog(e){this.realtimeOptions?.debug&&console.log(`[DatabaseRealtime] ${e}`)}};var E=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=await this.http.post(`${r}/storages/files/${e}/presigned-url`,{file_name:t.name,file_size:t.size,mime_type:t.type||"application/octet-stream",parent_id:s}),n=await fetch(i.upload_url,{method:"PUT",body:t,headers:{"Content-Type":t.type||"application/octet-stream"}});if(!n.ok)throw new Error(`Upload failed: ${n.statusText}`);let o=await this.http.post(`${r}/storages/files/${e}/complete-upload`,{file_id:i.file_id});return{id:o.id,name:o.name,path:o.path,type:o.type,mime_type:o.mime_type,size:o.size,url:o.url,parent_id:o.parent_id,created_at:o.created_at}}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=t.startsWith("/")?t.slice(1):t,o=r?.overwrite!==!1,a=await this.http.post(`${i}/storages/files/${e}/presigned-url/path/${n}`,{file_name:s.name,file_size:s.size,mime_type:s.type||"application/octet-stream",overwrite:o}),c=await fetch(a.upload_url,{method:"PUT",body:s,headers:{"Content-Type":s.type||"application/octet-stream"}});if(!c.ok)throw new Error(`Upload failed: ${c.statusText}`);let d=await this.http.post(`${i}/storages/files/${e}/complete-upload`,{file_id:a.file_id});return{id:d.id,name:d.name,path:d.path,type:d.type,mime_type:d.mime_type,size:d.size,url:d.url,parent_id:d.parent_id,created_at:d.created_at}}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,t){let s=this.getPublicPrefix(),r=new URLSearchParams;t?.limit!=null&&r.set("limit",String(t.limit)),t?.offset!=null&&r.set("offset",String(t.offset));let i=r.toString();return this.http.get(`${s}/storages/webs/${e}/page-metas${i?`?${i}`:""}`)}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 M=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 q=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 A=class{constructor(e,t){this.ws=null;this.state="disconnected";this._connectionId=null;this._appId=null;this.options={maxRetries:5,retryInterval:1e3,userId:"",accessToken:"",timeout:3e4,debug:!1};this.retryCount=0;this.pendingRequests=new Map;this.subscriptions=new Map;this.streamSessions=new Map;this.stateHandlers=[];this.errorHandlers=[];this.presenceHandlers=[];this.presenceSubscriptions=new Map;this.typingHandlers=new Map;this.readReceiptHandlers=new Map;this.connectPromise=null;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"){if(this.state==="connecting"&&this.connectPromise)return this.connectPromise;this.options={...this.options,...e},e.userId&&(this.userId=e.userId),this.connectPromise=this.doConnect();try{await this.connectPromise}finally{this.connectPromise=null}}}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(),this.streamSessions.forEach(e=>{e.handlers.onError&&e.handlers.onError(new Error("Connection closed"))}),this.streamSessions.clear(),this.presenceHandlers=[],this.presenceSubscriptions.clear(),this.typingHandlers.clear(),this.readReceiptHandlers.clear(),this._connectionId=null,this._appId=null,this.retryCount=0,this.connectPromise=null}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(a,c)=>{await this.sendMessage(e,a,c)},getHistory:async a=>this.getHistory(e,a??t.historyLimit),unsubscribe:async()=>{await this.unsubscribe(e)},onMessage:a=>(n.push(a),()=>{let c=n.indexOf(a);c>-1&&n.splice(c,1)})}}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();this.streamSessions.set(i,{handlers:t,requestId:r});try{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})}catch(n){throw this.streamSessions.delete(i),n}return{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}isConnected(){return this.state==="connected"}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 setPresence(e,t={}){if(this.state!=="connected")throw new Error("Not connected");let s=this.generateRequestId();await this.sendRequest({category:"",action:"presence_set",data:{status:e,device:t.device,metadata:t.metadata},request_id:s})}async setPresenceOnDisconnect(e,t){if(this.state!=="connected")throw new Error("Not connected");let s=this.generateRequestId();await this.sendRequest({category:"",action:"presence_on_disconnect",data:{status:e,metadata:t},request_id:s})}async getPresence(e){if(this.state!=="connected")throw new Error("Not connected");let t=this.generateRequestId(),s=await this.sendRequest({category:"",action:"presence_get",data:{user_id:e},request_id:t});return{userId:s.user_id,status:s.status,lastSeen:s.last_seen,device:s.device,metadata:s.metadata}}async getPresenceMany(e){if(this.state!=="connected")throw new Error("Not connected");let t=this.generateRequestId(),s=await this.sendRequest({category:"",action:"presence_get_many",data:{user_ids:e},request_id:t}),r={};for(let[i,n]of Object.entries(s.users))r[i]={userId:n.user_id,status:n.status,lastSeen:n.last_seen,device:n.device,metadata:n.metadata};return{users:r}}async subscribePresence(e,t){if(this.state!=="connected")throw new Error("Not connected");if(!this.presenceSubscriptions.has(e)){let r=this.generateRequestId();await this.sendRequest({category:"",action:"presence_subscribe",data:{user_id:e},request_id:r}),this.presenceSubscriptions.set(e,[])}let s=this.presenceSubscriptions.get(e);return s.push(t),()=>{let r=s.indexOf(t);if(r>-1&&s.splice(r,1),s.length===0&&(this.presenceSubscriptions.delete(e),this.state==="connected")){let i=this.generateRequestId();this.sendRequest({category:"",action:"presence_unsubscribe",data:{user_id:e},request_id:i}).catch(n=>{this.log(`Failed to unsubscribe presence for ${e}: ${n}`)})}}}onPresenceChange(e){return this.presenceHandlers.push(e),()=>{let t=this.presenceHandlers.indexOf(e);t>-1&&this.presenceHandlers.splice(t,1)}}async startTyping(e){if(this.state!=="connected")throw new Error("Not connected");let t=this.generateRequestId();await this.sendRequest({category:"",action:"typing_start",data:{room_id:e},request_id:t})}async stopTyping(e){if(this.state!=="connected")throw new Error("Not connected");let t=this.generateRequestId();await this.sendRequest({category:"",action:"typing_stop",data:{room_id:e},request_id:t})}async onTypingChange(e,t){if(this.state!=="connected")throw new Error("Not connected");if(!this.typingHandlers.has(e)){let r=this.generateRequestId();await this.sendRequest({category:"",action:"typing_subscribe",data:{room_id:e},request_id:r}),this.typingHandlers.set(e,[])}let s=this.typingHandlers.get(e);return s.push(t),()=>{let r=s.indexOf(t);if(r>-1&&s.splice(r,1),s.length===0&&(this.typingHandlers.delete(e),this.state==="connected")){let i=this.generateRequestId();this.sendRequest({category:"",action:"typing_unsubscribe",data:{room_id:e},request_id:i}).catch(n=>{this.log(`Failed to unsubscribe typing for ${e}: ${n}`)})}}}async markRead(e,t){if(this.state!=="connected")throw new Error("Not connected");let s=this.generateRequestId();await this.sendRequest({category:e,action:"mark_read",data:{message_ids:t},request_id:s})}onReadReceipt(e,t){this.readReceiptHandlers.has(e)||this.readReceiptHandlers.set(e,[]);let s=this.readReceiptHandlers.get(e);return s.push(t),()=>{let r=s.indexOf(t);r>-1&&s.splice(r,1)}}async doConnect(){return new Promise((e,t)=>{this.state="connecting",this.notifyStateChange(),this.log("Connecting...");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}`,this.log("Using accessToken authentication");else{let o=this.http.getApiKey();if(!o){let a=new Error("API Key or accessToken is required for realtime connection");this.log("Connection failed: no API Key or accessToken"),t(a);return}r=`${s}/v1/realtime/auth?api_key=${encodeURIComponent(o)}&client_id=${this.clientId}`,this.log("Using API Key authentication")}this.userId&&(r+=`&user_id=${encodeURIComponent(this.userId)}`);let i=!1,n=setTimeout(()=>{i||(i=!0,this.log(`Connection timeout after ${this.options.timeout}ms`),this.ws&&(this.ws.close(),this.ws=null),this.state="disconnected",this.notifyStateChange(),t(new Error(`Connection timeout after ${this.options.timeout}ms`)))},this.options.timeout);try{this.log(`Connecting to ${s}`),this.ws=new WebSocket(r),this.ws.onopen=()=>{this.log("WebSocket opened, waiting for connected event...")},this.ws.onmessage=o=>{let a=o.data.split(`
|
|
2
|
+
`).filter(c=>c.trim());for(let c of a)try{let d=JSON.parse(c);this.handleServerMessage(d,()=>{i||(i=!0,clearTimeout(n),this.log("Connected successfully"),e())})}catch(d){console.error("[Realtime] Failed to parse message:",c,d)}},this.ws.onclose=o=>{this.log(`WebSocket closed: code=${o.code}, reason=${o.reason}`),!i&&this.state==="connecting"&&(i=!0,clearTimeout(n),t(new Error(`Connection closed: ${o.reason||"unknown reason"}`))),(this.state==="connected"||this.state==="connecting")&&this.handleDisconnect()},this.ws.onerror=o=>{this.log("WebSocket error occurred"),console.error("[Realtime] WebSocket error:",o),this.notifyError(new Error("WebSocket connection error")),!i&&this.state==="connecting"&&(i=!0,clearTimeout(n),t(new Error("Failed to connect")))}}catch(o){i=!0,clearTimeout(n),t(o)}})}log(e){this.options.debug&&console.log(`[Realtime] ${e}`)}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}case"presence":case"presence_status":{let s=e.data,r={userId:s.user_id,status:s.status,lastSeen:s.last_seen,device:s.device,metadata:s.metadata,eventType:s.event_type};this.presenceHandlers.forEach(n=>n(r));let i=this.presenceSubscriptions.get(s.user_id);if(i&&i.forEach(n=>n(r)),e.request_id){let n=this.pendingRequests.get(e.request_id);n&&(clearTimeout(n.timeout),n.resolve(e.data),this.pendingRequests.delete(e.request_id))}break}case"typing":{let s=e.data,r={roomId:s.room_id,users:s.users},i=this.typingHandlers.get(s.room_id);i&&i.forEach(n=>n(r));break}case"read_receipt":{let s=e.data,r={category:s.category,messageIds:s.message_ids,readerId:s.reader_id,readAt:s.read_at},i=this.readReceiptHandlers.get(s.category);i&&i.forEach(n=>n(r));break}}}handleDisconnect(){this.ws=null,this._connectionId=null,this.streamSessions.forEach(r=>{r.handlers.onError&&r.handlers.onError(new Error("Connection lost"))}),this.streamSessions.clear();let e=new Map;for(let[r,i]of this.subscriptions)e.set(r,[...i.handlers]);this.subscriptions.clear();let t=new Map;for(let[r,i]of this.presenceSubscriptions)t.set(r,[...i]);this.presenceSubscriptions.clear();let s=new Map;for(let[r,i]of this.typingHandlers)s.set(r,[...i]);if(this.typingHandlers.clear(),this.retryCount<this.options.maxRetries){this.state="reconnecting",this.notifyStateChange(),this.retryCount++;let r=Math.min(this.options.retryInterval*Math.pow(2,this.retryCount-1),3e4);setTimeout(async()=>{try{await this.doConnect(),this.log("Reconnected successfully, restoring subscriptions..."),await this.restoreSubscriptions(e,t,s)}catch(i){console.error("[Realtime] Reconnect failed:",i)}},r)}else this.state="disconnected",this.notifyStateChange(),this.notifyError(new Error("Connection lost. Max retries exceeded."))}async restoreSubscriptions(e,t,s){for(let[r,i]of e)try{this.log(`Restoring subscription: ${r}`);let n=this.generateRequestId(),o=await this.sendRequest({category:r,action:"subscribe",request_id:n}),a={category:o.category,persist:o.persist,historyCount:o.history_count,readReceipt:o.read_receipt};this.subscriptions.set(r,{info:a,handlers:i}),this.log(`Restored subscription: ${r}`)}catch(n){console.error(`[Realtime] Failed to restore subscription for ${r}:`,n),this.notifyError(new Error(`Failed to restore subscription: ${r}`))}for(let[r,i]of t)try{this.log(`Restoring presence subscription: ${r}`);let n=this.generateRequestId();await this.sendRequest({category:"",action:"presence_subscribe",data:{user_id:r},request_id:n}),this.presenceSubscriptions.set(r,i),this.log(`Restored presence subscription: ${r}`)}catch(n){console.error(`[Realtime] Failed to restore presence subscription for ${r}:`,n)}for(let[r,i]of s)try{this.log(`Restoring typing subscription: ${r}`);let n=this.generateRequestId();await this.sendRequest({category:"",action:"typing_subscribe",data:{room_id:r},request_id:n}),this.typingHandlers.set(r,i),this.log(`Restored typing subscription: ${r}`)}catch(n){console.error(`[Realtime] Failed to restore typing subscription for ${r}:`,n)}}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"))},this.options.timeout);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 U=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 a of o)a.peer_id!==this.currentPeerId&&await this.createPeerConnection(a.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 O=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 D=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,a=window.screenX+(window.outerWidth-n)/2,c=window.screenY+(window.outerHeight-o)/2,d=window.open(i.authorization_url,"oauth-popup",`width=${n},height=${o},left=${a},top=${c}`);if(!d)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((p,u)=>{let g=!1,y=()=>{g=!0,window.removeEventListener("message",I),clearInterval(b),clearTimeout(k)},I=async h=>{if(h.data?.type!=="oauth-callback"||g)return;if(y(),h.data.error){u(new Error(h.data.error));return}let v={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(v.access_token,v.refresh_token),p(v)};window.addEventListener("message",I);let b=setInterval(()=>{try{d.closed&&(g||(y(),u(new Error("\uB85C\uADF8\uC778\uC774 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."))))}catch{clearInterval(b)}},500),k=setTimeout(()=>{if(!g){y();try{d.close()}catch{}u(new Error("\uB85C\uADF8\uC778 \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694."))}},18e4)})}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 H=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 L=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 B=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 ne=5*1024*1024,P=class extends Error{constructor(e,t){super(e),this.name="VideoProcessingError",this.video=t}},F=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 a=await o.json().catch(()=>({message:o.statusText}));throw new m(o.status,a.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||ne,n=Math.ceil(e.size/i),o=0,c=Date.now(),d=0;for(let u=0;u<n;u++){let g=u*i,y=Math.min(g+i,e.size),I=e.slice(g,y),b=new FormData;b.append("chunk",I),b.append("chunk_index",String(u)),await this.videoFetch("POST",`${s}/uploads/${r.session_id}/chunks`,b),o++;let k=Date.now(),h=(k-c)/1e3,v=y,Q=v-d,X=h>0?Q/h:0;c=k,d=v,t.onProgress&&t.onProgress({phase:"uploading",uploadedChunks:o,totalChunks:n,percentage:Math.round(o/n*100),currentSpeed:X})}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 P("Video processing failed",o);if(t?.onProgress){let a=o.qualities.filter(d=>d.status==="ready").length,c=o.qualities.length||1;t.onProgress({phase:"processing",uploadedChunks:0,totalChunks:0,percentage:Math.round(a/c*100)})}await new Promise(a=>setTimeout(a,r))}throw new P("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 J=()=>{if(typeof window<"u"){let l=window.location.hostname;if(l==="localhost"||l==="127.0.0.1")return"ws://localhost:8087"}return"wss://game.connectbase.world"},T=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:J(),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=c=>{this._isConnected=!1,this.stopPingInterval(),this.handlers.onDisconnect?.(c),this.config.autoReconnect&&c.code!==1e3&&this.scheduleReconnect(e)},o=c=>{this.handlers.onError?.(c),s(new Error("WebSocket connection failed"))},a=c=>{this.handleMessage(c.data)};this.ws.addEventListener("open",i,{once:!0}),this.ws.addEventListener("close",n),this.ws.addEventListener("error",o,{once:!0}),this.ws.addEventListener("message",a)})}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,a=()=>{this.ws?.removeEventListener("message",c),o&&(clearTimeout(o),o=null)},c=d=>{try{let p=JSON.parse(d.data);if(p.msg_id&&p.msg_id!==n)return;s(p)&&a()}catch{}};this.ws?.addEventListener("message",c),o=setTimeout(()=>{a();let d=new Error(`Request '${e}' timed out after ${r}ms`);i?.(d),this.handlers.onError?.({code:"TIMEOUT",message:d.message})},r);try{this.send(e,t,n)}catch(d){a();let p=d instanceof Error?d:new Error(String(d));i?.(p)}}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)}},R=class{constructor(e,t,s){this.http=e,this.gameServerUrl=t||J().replace(/^ws/,"http"),this.appId=s}createClient(e){return new T({...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}`)}async joinQueue(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/matchmaking/queue`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({game_type:e.gameType,player_id:e.playerId,rating:e.rating,region:e.region,mode:e.mode,party_members:e.partyMembers,metadata:e.metadata})});if(!s.ok){let i=await s.json().catch(()=>({}));throw new Error(i.error||`Failed to join queue: ${s.statusText}`)}let r=await s.json();return{ticketId:r.ticket_id,gameType:r.game_type,playerId:r.player_id,status:r.status,createdAt:r.created_at}}async leaveQueue(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/matchmaking/queue`,{method:"DELETE",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({ticket_id:e})});if(!s.ok){let r=await s.json().catch(()=>({}));throw new Error(r.error||`Failed to leave queue: ${s.statusText}`)}}async getMatchStatus(e){let t=this.appId||"",s=new URLSearchParams;e.ticketId&&s.set("ticket_id",e.ticketId),e.playerId&&s.set("player_id",e.playerId);let r=await fetch(`${this.gameServerUrl}/v1/game/${t}/matchmaking/status?${s}`,{headers:this.getHeaders()});if(!r.ok){let n=await r.json().catch(()=>({}));throw new Error(n.error||`Failed to get match status: ${r.statusText}`)}let i=await r.json();return{ticketId:i.ticket_id,gameType:i.game_type,playerId:"",status:i.status,createdAt:"",waitTime:i.wait_time,matchId:i.match_id,roomId:i.room_id}}async listLobbies(){let e=this.appId||"",t=await fetch(`${this.gameServerUrl}/v1/game/${e}/lobbies`,{headers:this.getHeaders()});if(!t.ok)throw new Error(`Failed to list lobbies: ${t.statusText}`);return((await t.json()).lobbies||[]).map(r=>({id:r.id,name:r.name,hostId:r.host_id,gameType:r.game_type,playerCount:r.player_count,maxPlayers:r.max_players,hasPassword:r.has_password,visibility:r.visibility,region:r.region,settings:r.settings,tags:r.tags,status:r.status,createdAt:r.created_at}))}async createLobby(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/lobbies`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:e.playerId,display_name:e.displayName,name:e.name,game_type:e.gameType,password:e.password,max_players:e.maxPlayers,visibility:e.visibility,region:e.region,settings:e.settings,tags:e.tags})});if(!s.ok){let i=await s.json().catch(()=>({}));throw new Error(i.error||`Failed to create lobby: ${s.statusText}`)}let r=await s.json();return{id:r.id,name:r.name,hostId:r.host_id,gameType:r.game_type,playerCount:1,maxPlayers:r.max_players,hasPassword:!!e.password,visibility:r.visibility,region:r.region,settings:r.settings,tags:r.tags,status:r.status,createdAt:r.created_at}}async getLobby(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/lobbies/${e}`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to get lobby: ${s.statusText}`);let r=await s.json();return{id:r.id,name:r.name,hostId:r.host_id,gameType:r.game_type,playerCount:r.player_count,maxPlayers:r.max_players,hasPassword:r.has_password,visibility:r.visibility,region:r.region,settings:r.settings,tags:r.tags,status:r.status,roomId:r.room_id,members:(r.members||[]).map(i=>({playerId:i.player_id,displayName:i.display_name,role:i.role,team:i.team,ready:i.ready,slot:i.slot,joinedAt:i.joined_at})),createdAt:r.created_at}}async joinLobby(e,t,s,r){let i=this.appId||"",n=await fetch(`${this.gameServerUrl}/v1/game/${i}/lobbies/${e}/join`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,display_name:s,password:r})});if(!n.ok){let a=await n.json().catch(()=>({}));throw new Error(a.error||`Failed to join lobby: ${n.statusText}`)}return{lobbyId:(await n.json()).lobby_id}}async leaveLobby(e,t){let s=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${s}/lobbies/${e}/leave`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error||`Failed to leave lobby: ${r.statusText}`)}}async toggleReady(e,t,s){let r=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/${e}/ready`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,ready:s})});if(!i.ok){let n=await i.json().catch(()=>({}));throw new Error(n.error||`Failed to toggle ready: ${i.statusText}`)}}async startGame(e,t){let s=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${s}/lobbies/${e}/start`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({host_id:t})});if(!r.ok){let n=await r.json().catch(()=>({}));throw new Error(n.error||`Failed to start game: ${r.statusText}`)}return{roomId:(await r.json()).room_id}}async kickPlayer(e,t,s){let r=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/${e}/kick/${s}`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({host_id:t})});if(!i.ok){let n=await i.json().catch(()=>({}));throw new Error(n.error||`Failed to kick player: ${i.statusText}`)}}async updateLobby(e,t){let s=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${s}/lobbies/${e}`,{method:"PATCH",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({host_id:t.hostId,name:t.name,max_players:t.maxPlayers,visibility:t.visibility,password:t.password,settings:t.settings,tags:t.tags})});if(!r.ok){let n=await r.json().catch(()=>({}));throw new Error(n.error||`Failed to update lobby: ${r.statusText}`)}let i=await r.json();return{id:i.id,name:i.name,hostId:"",gameType:"",playerCount:0,maxPlayers:i.max_players,hasPassword:!1,visibility:i.visibility,region:"",settings:i.settings,tags:i.tags,status:"",createdAt:""}}async sendLobbyChat(e,t,s){let r=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/${e}/chat`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,message:s})});if(!i.ok){let n=await i.json().catch(()=>({}));throw new Error(n.error||`Failed to send chat: ${i.statusText}`)}}async invitePlayer(e,t,s){let r=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/${e}/invite`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({inviter_id:t,invitee_id:s})});if(!i.ok){let o=await i.json().catch(()=>({}));throw new Error(o.error||`Failed to invite player: ${i.statusText}`)}let n=await i.json();return{inviteId:n.invite_id,lobbyId:n.lobby_id,lobbyName:n.lobby_name,inviterId:n.inviter_id,inviteeId:n.invitee_id,status:"pending",createdAt:"",expiresAt:n.expires_at}}async acceptInvite(e,t,s){let r=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/invites/${e}/accept`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,display_name:s})});if(!i.ok){let o=await i.json().catch(()=>({}));throw new Error(o.error||`Failed to accept invite: ${i.statusText}`)}return{lobbyId:(await i.json()).lobby_id}}async declineInvite(e,t){let s=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${s}/lobbies/invites/${e}/decline`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error||`Failed to decline invite: ${r.statusText}`)}}async getPlayerInvites(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/lobbies/player/${e}/invites`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to get invites: ${s.statusText}`);return((await s.json()).invites||[]).map(i=>({inviteId:i.invite_id,lobbyId:i.lobby_id,lobbyName:i.lobby_name,inviterId:i.inviter_id,inviteeId:"",status:i.status,createdAt:i.created_at,expiresAt:i.expires_at}))}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 S=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 _=class{constructor(){this.clipboard={writeText:async e=>{this.getPlatform()==="desktop"&&window.NativeBridge?.clipboard?await window.NativeBridge.clipboard.writeText(e):await navigator.clipboard.writeText(e)},readText:async()=>this.getPlatform()==="desktop"&&window.NativeBridge?.clipboard?window.NativeBridge.clipboard.readText():navigator.clipboard.readText(),writeHTML:async e=>{window.NativeBridge?.clipboard?.writeHTML?await window.NativeBridge.clipboard.writeHTML(e):await navigator.clipboard.writeText(e)},writeImage:async e=>{if(window.NativeBridge?.clipboard?.writeImage)await window.NativeBridge.clipboard.writeImage(e);else throw new Error("Image clipboard not supported on this platform")},readImage:async()=>window.NativeBridge?.clipboard?.readImage?window.NativeBridge.clipboard.readImage():null};this.filesystem={pickFile:async e=>{if(this.getPlatform()==="desktop"&&window.NativeBridge?.filesystem?.showOpenDialog){let s=await window.NativeBridge.filesystem.showOpenDialog({properties:e?.multiple?["openFile","multiSelections"]:["openFile"],filters:e?.filters});return s.canceled||!s.filePaths.length?null:s.filePaths.map(r=>new File([],r.split("/").pop()||"file"))}return new Promise(s=>{let r=document.createElement("input");r.type="file",e?.accept&&(r.accept=e.accept),e?.multiple&&(r.multiple=!0),r.onchange=()=>{s(r.files?Array.from(r.files):null)},r.click()})},saveFile:async(e,t,s)=>{let r=this.getPlatform();if(r==="desktop"&&window.NativeBridge?.filesystem){let a=await window.NativeBridge.filesystem.showSaveDialog?.({defaultPath:t,filters:s?.filters});if(a?.canceled||!a?.filePath)return!1;let c=e instanceof Blob?await e.text():e;return(await window.NativeBridge.filesystem.writeFile(a.filePath,c)).success}if(r==="mobile"&&window.NativeBridge?.filesystem){let a=e instanceof Blob?await e.text():e;return(await window.NativeBridge.filesystem.writeFile(t,a)).success}let i=e instanceof Blob?e:new Blob([e],{type:"text/plain"}),n=URL.createObjectURL(i),o=document.createElement("a");return o.href=n,o.download=t,o.click(),URL.revokeObjectURL(n),!0},readFile:async e=>{if(window.NativeBridge?.filesystem?.readFile){let t=await window.NativeBridge.filesystem.readFile(e);return t.success?t.content??null:null}return null},exists:async e=>window.NativeBridge?.filesystem?.exists?window.NativeBridge.filesystem.exists(e):!1};this.camera={takePicture:async e=>this.getPlatform()==="mobile"&&window.NativeBridge?.camera?window.NativeBridge.camera.takePicture(e):new Promise(s=>{let r=document.createElement("input");r.type="file",r.accept="image/*",r.capture="environment",r.onchange=async()=>{let i=r.files?.[0];if(!i){s(null);return}let n=new FileReader;n.onload=()=>{let o=new Image;o.onload=()=>{s({uri:URL.createObjectURL(i),base64:e?.base64?n.result.split(",")[1]:void 0,width:o.width,height:o.height})},o.src=n.result},n.readAsDataURL(i)},r.click()}),pickImage:async e=>this.getPlatform()==="mobile"&&window.NativeBridge?.camera?window.NativeBridge.camera.pickImage(e):new Promise(s=>{let r=document.createElement("input");r.type="file",r.accept="image/*",e?.multiple&&(r.multiple=!0),r.onchange=async()=>{let i=r.files;if(!i?.length){s(null);return}let n=[];for(let o of Array.from(i)){let a=await new Promise(c=>{let d=new FileReader;d.onload=()=>{let p=new Image;p.onload=()=>{c({uri:URL.createObjectURL(o),base64:e?.base64?d.result.split(",")[1]:void 0,width:p.width,height:p.height})},p.src=d.result},d.readAsDataURL(o)});n.push(a)}s(n)},r.click()})};this.location={getCurrentPosition:async e=>this.getPlatform()==="mobile"&&window.NativeBridge?.location?window.NativeBridge.location.getCurrentPosition(e):new Promise((s,r)=>{navigator.geolocation.getCurrentPosition(i=>{s({latitude:i.coords.latitude,longitude:i.coords.longitude,altitude:i.coords.altitude,accuracy:i.coords.accuracy,timestamp:i.timestamp})},r,{enableHighAccuracy:e?.accuracy==="high",timeout:1e4,maximumAge:0})})};this.notification={show:async e=>this.getPlatform()==="desktop"&&window.NativeBridge?.notification?(await window.NativeBridge.notification.show(e)).success:!("Notification"in window)||Notification.permission!=="granted"&&await Notification.requestPermission()!=="granted"?!1:(new Notification(e.title,{body:e.body,icon:e.icon,silent:e.silent}),!0),requestPermission:async()=>this.getPlatform()==="mobile"&&window.NativeBridge?.push?(await window.NativeBridge.push.requestPermission()).granted:"Notification"in window?await Notification.requestPermission()==="granted":!1};this.shell={openExternal:async e=>this.getPlatform()==="desktop"&&window.NativeBridge?.shell?(await window.NativeBridge.shell.openExternal(e)).success:(window.open(e,"_blank"),!0)};this.window={minimize:async()=>{await window.NativeBridge?.window?.minimize()},maximize:async()=>{await window.NativeBridge?.window?.maximize()},unmaximize:async()=>{await window.NativeBridge?.window?.unmaximize()},close:async()=>{await window.NativeBridge?.window?.close()},isMaximized:async()=>await window.NativeBridge?.window?.isMaximized()??!1,setTitle:async e=>{window.NativeBridge?.window?await window.NativeBridge.window.setTitle(e):document.title=e},setFullScreen:async e=>{window.NativeBridge?.window?await window.NativeBridge.window.setFullScreen(e):document.documentElement.requestFullscreen&&(e?await document.documentElement.requestFullscreen():document.exitFullscreen&&await document.exitFullscreen())}};this.system={getInfo:async()=>window.NativeBridge?.system?window.NativeBridge.system.getInfo():null,getMemory:async()=>window.NativeBridge?.system?window.NativeBridge.system.getMemory():null};this.biometric={isAvailable:async()=>window.NativeBridge?.biometric?window.NativeBridge.biometric.isAvailable():null,authenticate:async e=>window.NativeBridge?.biometric?window.NativeBridge.biometric.authenticate(e):null};this.secureStore={setItem:async(e,t)=>window.NativeBridge?.secureStore?(await window.NativeBridge.secureStore.setItem(e,t)).success:(localStorage.setItem(e,t),!0),getItem:async e=>window.NativeBridge?.secureStore?(await window.NativeBridge.secureStore.getItem(e)).value:localStorage.getItem(e),deleteItem:async e=>window.NativeBridge?.secureStore?(await window.NativeBridge.secureStore.deleteItem(e)).success:(localStorage.removeItem(e),!0)};this.admob={showInterstitial:async()=>window.NativeBridge?.admob?(await window.NativeBridge.admob.showInterstitial()).shown:!1,showRewarded:async()=>window.NativeBridge?.admob?(await window.NativeBridge.admob.showRewarded()).rewarded:!1}}getPlatform(){if(typeof window>"u")return"web";let e=window.NativeBridge;return e?.platform==="electron"?"desktop":e?.platform==="react-native"||e?.platform==="ios"||e?.platform==="android"||e?.camera||window.ReactNativeWebView?"mobile":"web"}hasFeature(e){return typeof window>"u"?!1:!!window.NativeBridge?.[e]}get bridge(){if(!(typeof window>"u"))return window.NativeBridge}};var j=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 a=s.slice(4,4+o);s=s.slice(4+o),this.onMessage(a)}}}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}},G=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(a){t(a);return}let r=()=>{e()},i=()=>{this.onClose()},n=a=>{let c=new Error("WebSocket error");this.onError(c),t(c)},o=a=>{a.data instanceof ArrayBuffer?this.onMessage(new Uint8Array(a.data)):typeof a.data=="string"&&this.onMessage(new TextEncoder().encode(a.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 V(){return typeof WebTransport<"u"}var N=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")&&V(),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 j(this.config,r,i,n),await this.transport.connect(),this._transportType="webtransport"}catch{console.log("WebTransport failed, falling back to WebSocket"),this.transport=new G(this.config,r,i,n),await this.transport.connect(),this._transportType="websocket"}else this.transport=new G(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 oe="https://api.connectbase.world",ae="https://socket.connectbase.world",ce="https://webrtc.connectbase.world",le="https://video.connectbase.world",de="https://game.connectbase.world",W=class{constructor(e={}){let t={baseUrl:e.baseUrl||oe,apiKey:e.apiKey,onTokenRefresh:e.onTokenRefresh,onAuthError:e.onAuthError,onTokenExpired:e.onTokenExpired};this.http=new C(t),this.auth=new x(this.http),this.database=new $(this.http),this.storage=new E(this.http),this.apiKey=new M(this.http),this.functions=new q(this.http),this.realtime=new A(this.http,e.socketUrl||ae),this.webrtc=new U(this.http,e.webrtcUrl||ce,e.appId),this.errorTracker=new O(this.http,e.errorTracker),this.oauth=new D(this.http),this.payment=new H(this.http),this.subscription=new L(this.http),this.push=new B(this.http),this.video=new F(this.http,e.videoUrl||le),this.game=new R(this.http,e.gameUrl||de,e.appId),this.ads=new S(this.http),this.native=new _}setTokens(e,t){this.http.setTokens(e,t)}clearTokens(){this.http.clearTokens()}updateConfig(e){this.http.updateConfig(e)}},pe=W;return re(he);})();
|
|
3
3
|
var ConnectBase = ConnectBaseModule.default || ConnectBaseModule.ConnectBase;
|
package/dist/index.d.mts
CHANGED
|
@@ -2607,9 +2607,10 @@ declare class OAuthAPI {
|
|
|
2607
2607
|
*/
|
|
2608
2608
|
getEnabledProviders(): Promise<EnabledProvidersResponse>;
|
|
2609
2609
|
/**
|
|
2610
|
-
* 소셜 로그인 (
|
|
2610
|
+
* 소셜 로그인 (리다이렉트 방식) - 권장
|
|
2611
2611
|
* Google Cloud Console에 별도로 redirect_uri를 등록할 필요가 없습니다.
|
|
2612
2612
|
* OAuth 완료 후 지정한 콜백 URL로 토큰과 함께 리다이렉트됩니다.
|
|
2613
|
+
* 모든 배포 환경에서 안정적으로 동작합니다.
|
|
2613
2614
|
*
|
|
2614
2615
|
* @param provider - OAuth 프로바이더 (google, naver, github, discord)
|
|
2615
2616
|
* @param callbackUrl - OAuth 완료 후 리다이렉트될 앱의 URL
|
|
@@ -2644,6 +2645,10 @@ declare class OAuthAPI {
|
|
|
2644
2645
|
* Google Cloud Console에 별도 등록 불필요.
|
|
2645
2646
|
* 콜백 페이지가 자동으로 제공되므로 callbackUrl은 선택사항입니다.
|
|
2646
2647
|
*
|
|
2648
|
+
* ⚠️ 일부 배포 환경에서 COOP(Cross-Origin-Opener-Policy) 정책으로 인해
|
|
2649
|
+
* 팝업 닫힘 감지가 제한될 수 있습니다. 3분 타임아웃이 적용되며,
|
|
2650
|
+
* 안정적인 동작이 필요하면 signIn() (리다이렉트 방식)을 사용하세요.
|
|
2651
|
+
*
|
|
2647
2652
|
* @param provider - OAuth 프로바이더
|
|
2648
2653
|
* @param callbackUrl - (선택) OAuth 완료 후 리다이렉트될 팝업의 URL. 미지정 시 서버 제공 콜백 사용.
|
|
2649
2654
|
* @returns 로그인 결과
|
package/dist/index.d.ts
CHANGED
|
@@ -2607,9 +2607,10 @@ declare class OAuthAPI {
|
|
|
2607
2607
|
*/
|
|
2608
2608
|
getEnabledProviders(): Promise<EnabledProvidersResponse>;
|
|
2609
2609
|
/**
|
|
2610
|
-
* 소셜 로그인 (
|
|
2610
|
+
* 소셜 로그인 (리다이렉트 방식) - 권장
|
|
2611
2611
|
* Google Cloud Console에 별도로 redirect_uri를 등록할 필요가 없습니다.
|
|
2612
2612
|
* OAuth 완료 후 지정한 콜백 URL로 토큰과 함께 리다이렉트됩니다.
|
|
2613
|
+
* 모든 배포 환경에서 안정적으로 동작합니다.
|
|
2613
2614
|
*
|
|
2614
2615
|
* @param provider - OAuth 프로바이더 (google, naver, github, discord)
|
|
2615
2616
|
* @param callbackUrl - OAuth 완료 후 리다이렉트될 앱의 URL
|
|
@@ -2644,6 +2645,10 @@ declare class OAuthAPI {
|
|
|
2644
2645
|
* Google Cloud Console에 별도 등록 불필요.
|
|
2645
2646
|
* 콜백 페이지가 자동으로 제공되므로 callbackUrl은 선택사항입니다.
|
|
2646
2647
|
*
|
|
2648
|
+
* ⚠️ 일부 배포 환경에서 COOP(Cross-Origin-Opener-Policy) 정책으로 인해
|
|
2649
|
+
* 팝업 닫힘 감지가 제한될 수 있습니다. 3분 타임아웃이 적용되며,
|
|
2650
|
+
* 안정적인 동작이 필요하면 signIn() (리다이렉트 방식)을 사용하세요.
|
|
2651
|
+
*
|
|
2647
2652
|
* @param provider - OAuth 프로바이더
|
|
2648
2653
|
* @param callbackUrl - (선택) OAuth 완료 후 리다이렉트될 팝업의 URL. 미지정 시 서버 제공 콜백 사용.
|
|
2649
2654
|
* @returns 로그인 결과
|
package/dist/index.js
CHANGED
|
@@ -3731,9 +3731,10 @@ var OAuthAPI = class {
|
|
|
3731
3731
|
return this.http.get("/v1/public/oauth/providers");
|
|
3732
3732
|
}
|
|
3733
3733
|
/**
|
|
3734
|
-
* 소셜 로그인 (
|
|
3734
|
+
* 소셜 로그인 (리다이렉트 방식) - 권장
|
|
3735
3735
|
* Google Cloud Console에 별도로 redirect_uri를 등록할 필요가 없습니다.
|
|
3736
3736
|
* OAuth 완료 후 지정한 콜백 URL로 토큰과 함께 리다이렉트됩니다.
|
|
3737
|
+
* 모든 배포 환경에서 안정적으로 동작합니다.
|
|
3737
3738
|
*
|
|
3738
3739
|
* @param provider - OAuth 프로바이더 (google, naver, github, discord)
|
|
3739
3740
|
* @param callbackUrl - OAuth 완료 후 리다이렉트될 앱의 URL
|
|
@@ -3777,6 +3778,10 @@ var OAuthAPI = class {
|
|
|
3777
3778
|
* Google Cloud Console에 별도 등록 불필요.
|
|
3778
3779
|
* 콜백 페이지가 자동으로 제공되므로 callbackUrl은 선택사항입니다.
|
|
3779
3780
|
*
|
|
3781
|
+
* ⚠️ 일부 배포 환경에서 COOP(Cross-Origin-Opener-Policy) 정책으로 인해
|
|
3782
|
+
* 팝업 닫힘 감지가 제한될 수 있습니다. 3분 타임아웃이 적용되며,
|
|
3783
|
+
* 안정적인 동작이 필요하면 signIn() (리다이렉트 방식)을 사용하세요.
|
|
3784
|
+
*
|
|
3780
3785
|
* @param provider - OAuth 프로바이더
|
|
3781
3786
|
* @param callbackUrl - (선택) OAuth 완료 후 리다이렉트될 팝업의 URL. 미지정 시 서버 제공 콜백 사용.
|
|
3782
3787
|
* @returns 로그인 결과
|
|
@@ -3813,9 +3818,17 @@ var OAuthAPI = class {
|
|
|
3813
3818
|
throw new Error("\uD31D\uC5C5\uC774 \uCC28\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uD31D\uC5C5 \uCC28\uB2E8\uC744 \uD574\uC81C\uD574\uC8FC\uC138\uC694.");
|
|
3814
3819
|
}
|
|
3815
3820
|
return new Promise((resolve, reject) => {
|
|
3821
|
+
let settled = false;
|
|
3822
|
+
const cleanup = () => {
|
|
3823
|
+
settled = true;
|
|
3824
|
+
window.removeEventListener("message", handleMessage);
|
|
3825
|
+
clearInterval(checkClosed);
|
|
3826
|
+
clearTimeout(timeout);
|
|
3827
|
+
};
|
|
3816
3828
|
const handleMessage = async (event) => {
|
|
3817
3829
|
if (event.data?.type !== "oauth-callback") return;
|
|
3818
|
-
|
|
3830
|
+
if (settled) return;
|
|
3831
|
+
cleanup();
|
|
3819
3832
|
if (event.data.error) {
|
|
3820
3833
|
reject(new Error(event.data.error));
|
|
3821
3834
|
return;
|
|
@@ -3831,12 +3844,27 @@ var OAuthAPI = class {
|
|
|
3831
3844
|
};
|
|
3832
3845
|
window.addEventListener("message", handleMessage);
|
|
3833
3846
|
const checkClosed = setInterval(() => {
|
|
3834
|
-
|
|
3847
|
+
try {
|
|
3848
|
+
if (popup.closed) {
|
|
3849
|
+
if (!settled) {
|
|
3850
|
+
cleanup();
|
|
3851
|
+
reject(new Error("\uB85C\uADF8\uC778\uC774 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
} catch {
|
|
3835
3855
|
clearInterval(checkClosed);
|
|
3836
|
-
window.removeEventListener("message", handleMessage);
|
|
3837
|
-
reject(new Error("\uB85C\uADF8\uC778\uC774 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
3838
3856
|
}
|
|
3839
3857
|
}, 500);
|
|
3858
|
+
const timeout = setTimeout(() => {
|
|
3859
|
+
if (!settled) {
|
|
3860
|
+
cleanup();
|
|
3861
|
+
try {
|
|
3862
|
+
popup.close();
|
|
3863
|
+
} catch {
|
|
3864
|
+
}
|
|
3865
|
+
reject(new Error("\uB85C\uADF8\uC778 \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694."));
|
|
3866
|
+
}
|
|
3867
|
+
}, 18e4);
|
|
3840
3868
|
});
|
|
3841
3869
|
}
|
|
3842
3870
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -3695,9 +3695,10 @@ var OAuthAPI = class {
|
|
|
3695
3695
|
return this.http.get("/v1/public/oauth/providers");
|
|
3696
3696
|
}
|
|
3697
3697
|
/**
|
|
3698
|
-
* 소셜 로그인 (
|
|
3698
|
+
* 소셜 로그인 (리다이렉트 방식) - 권장
|
|
3699
3699
|
* Google Cloud Console에 별도로 redirect_uri를 등록할 필요가 없습니다.
|
|
3700
3700
|
* OAuth 완료 후 지정한 콜백 URL로 토큰과 함께 리다이렉트됩니다.
|
|
3701
|
+
* 모든 배포 환경에서 안정적으로 동작합니다.
|
|
3701
3702
|
*
|
|
3702
3703
|
* @param provider - OAuth 프로바이더 (google, naver, github, discord)
|
|
3703
3704
|
* @param callbackUrl - OAuth 완료 후 리다이렉트될 앱의 URL
|
|
@@ -3741,6 +3742,10 @@ var OAuthAPI = class {
|
|
|
3741
3742
|
* Google Cloud Console에 별도 등록 불필요.
|
|
3742
3743
|
* 콜백 페이지가 자동으로 제공되므로 callbackUrl은 선택사항입니다.
|
|
3743
3744
|
*
|
|
3745
|
+
* ⚠️ 일부 배포 환경에서 COOP(Cross-Origin-Opener-Policy) 정책으로 인해
|
|
3746
|
+
* 팝업 닫힘 감지가 제한될 수 있습니다. 3분 타임아웃이 적용되며,
|
|
3747
|
+
* 안정적인 동작이 필요하면 signIn() (리다이렉트 방식)을 사용하세요.
|
|
3748
|
+
*
|
|
3744
3749
|
* @param provider - OAuth 프로바이더
|
|
3745
3750
|
* @param callbackUrl - (선택) OAuth 완료 후 리다이렉트될 팝업의 URL. 미지정 시 서버 제공 콜백 사용.
|
|
3746
3751
|
* @returns 로그인 결과
|
|
@@ -3777,9 +3782,17 @@ var OAuthAPI = class {
|
|
|
3777
3782
|
throw new Error("\uD31D\uC5C5\uC774 \uCC28\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uD31D\uC5C5 \uCC28\uB2E8\uC744 \uD574\uC81C\uD574\uC8FC\uC138\uC694.");
|
|
3778
3783
|
}
|
|
3779
3784
|
return new Promise((resolve, reject) => {
|
|
3785
|
+
let settled = false;
|
|
3786
|
+
const cleanup = () => {
|
|
3787
|
+
settled = true;
|
|
3788
|
+
window.removeEventListener("message", handleMessage);
|
|
3789
|
+
clearInterval(checkClosed);
|
|
3790
|
+
clearTimeout(timeout);
|
|
3791
|
+
};
|
|
3780
3792
|
const handleMessage = async (event) => {
|
|
3781
3793
|
if (event.data?.type !== "oauth-callback") return;
|
|
3782
|
-
|
|
3794
|
+
if (settled) return;
|
|
3795
|
+
cleanup();
|
|
3783
3796
|
if (event.data.error) {
|
|
3784
3797
|
reject(new Error(event.data.error));
|
|
3785
3798
|
return;
|
|
@@ -3795,12 +3808,27 @@ var OAuthAPI = class {
|
|
|
3795
3808
|
};
|
|
3796
3809
|
window.addEventListener("message", handleMessage);
|
|
3797
3810
|
const checkClosed = setInterval(() => {
|
|
3798
|
-
|
|
3811
|
+
try {
|
|
3812
|
+
if (popup.closed) {
|
|
3813
|
+
if (!settled) {
|
|
3814
|
+
cleanup();
|
|
3815
|
+
reject(new Error("\uB85C\uADF8\uC778\uC774 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3818
|
+
} catch {
|
|
3799
3819
|
clearInterval(checkClosed);
|
|
3800
|
-
window.removeEventListener("message", handleMessage);
|
|
3801
|
-
reject(new Error("\uB85C\uADF8\uC778\uC774 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
3802
3820
|
}
|
|
3803
3821
|
}, 500);
|
|
3822
|
+
const timeout = setTimeout(() => {
|
|
3823
|
+
if (!settled) {
|
|
3824
|
+
cleanup();
|
|
3825
|
+
try {
|
|
3826
|
+
popup.close();
|
|
3827
|
+
} catch {
|
|
3828
|
+
}
|
|
3829
|
+
reject(new Error("\uB85C\uADF8\uC778 \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694."));
|
|
3830
|
+
}
|
|
3831
|
+
}, 18e4);
|
|
3804
3832
|
});
|
|
3805
3833
|
}
|
|
3806
3834
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "connectbase-client",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.38",
|
|
4
4
|
"description": "Connect Base JavaScript/TypeScript SDK for browser and Node.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,12 +29,6 @@
|
|
|
29
29
|
"files": [
|
|
30
30
|
"dist"
|
|
31
31
|
],
|
|
32
|
-
"scripts": {
|
|
33
|
-
"build": "tsup",
|
|
34
|
-
"dev": "tsup --watch",
|
|
35
|
-
"typecheck": "tsc --noEmit",
|
|
36
|
-
"release": "pnpm build && npm publish --access public"
|
|
37
|
-
},
|
|
38
32
|
"keywords": [
|
|
39
33
|
"connect-base",
|
|
40
34
|
"baas",
|
|
@@ -58,5 +52,11 @@
|
|
|
58
52
|
},
|
|
59
53
|
"engines": {
|
|
60
54
|
"node": ">=16"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsup",
|
|
58
|
+
"dev": "tsup --watch",
|
|
59
|
+
"typecheck": "tsc --noEmit",
|
|
60
|
+
"release": "pnpm build && npm publish --access public"
|
|
61
61
|
}
|
|
62
|
-
}
|
|
62
|
+
}
|