connectbase-client 1.6.0 → 1.7.0
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/CHANGELOG.md +26 -0
- package/dist/connect-base.umd.js +1 -1
- package/dist/index.d.mts +12 -6
- package/dist/index.d.ts +12 -6
- package/dist/index.js +34 -27
- package/dist/index.mjs +34 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,32 @@
|
|
|
3
3
|
본 SDK 의 모든 주요 변경사항을 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/) 형식으로 기록합니다.
|
|
4
4
|
버전은 [Semantic Versioning](https://semver.org/lang/ko/) 을 따릅니다.
|
|
5
5
|
|
|
6
|
+
## [1.7.0] - 2026-04-19
|
|
7
|
+
|
|
8
|
+
콘솔(JWT) DB 관리 API 경로 정정 — 기존 메서드들이 실제로 존재하지 않는 라우트(`/v1/apps/:appID/tables/:tableID/...`, `/v1/apps/:appID/triggers`, `/v1/apps/:appID/security/rules`, `/v1/apps/:appID/tables/:tableID/relations`) 를 호출해 서버가 항상 404 를 반환하던 문제를 수정.
|
|
9
|
+
|
|
10
|
+
### Fixed — 404 를 반환하던 메서드들이 이제 정상 동작
|
|
11
|
+
|
|
12
|
+
실제 백엔드 라우트는 모두 `/v1/apps/:appID/databases/...` prefix 아래에 있습니다 ([route/api/v1.go:617-679](../../../backend/cmd/core-server/app/route/api/v1.go#L617)). SDK 가 이 prefix 를 빠뜨리고 있었습니다.
|
|
13
|
+
|
|
14
|
+
- **`database.listIndexes` / `createIndex` / `deleteIndex` / `analyzeIndexes`** — 경로 `/v1/apps/:appID/tables/:tableID/indexes*` → `/v1/apps/:appID/databases/tables/:tableID/indexes*`
|
|
15
|
+
- **`database.listSearchIndexes` / `createSearchIndex` / `deleteSearchIndex`** — 동일 패턴 수정
|
|
16
|
+
- **`database.listGeoIndexes` / `createGeoIndex` / `deleteGeoIndex`** — 동일 패턴 수정
|
|
17
|
+
- **`database.listTriggers` / `createTrigger` / `updateTrigger` / `deleteTrigger`** — 경로 `/v1/apps/:appID/triggers*` → `/v1/apps/:appID/databases/triggers*`
|
|
18
|
+
- **`database.listSecurityRules` / `createSecurityRule` / `updateSecurityRule` / `deleteSecurityRule`** — 경로 `/v1/apps/:appID/security/rules*` → `/v1/apps/:appID/databases/security/rules*`
|
|
19
|
+
|
|
20
|
+
### Breaking — relations API 시그니처 변경
|
|
21
|
+
|
|
22
|
+
실제 백엔드 `relations` 라우트는 app 전역(`/v1/apps/:appID/databases/relations`) 에 있고 관계는 UUID(`relation_id`) 로 식별됩니다. 기존 SDK 시그니처는 존재하지 않는 table-scoped 경로 + 관계 이름으로 삭제를 시도해 호출 자체가 불가능한 상태였습니다.
|
|
23
|
+
|
|
24
|
+
- **`database.listRelations(appId, tableId)` → `database.listRelations(appId, sourceTable?)`** — 두 번째 인자는 필터용(선택), 생략 시 앱 전체 관계 반환. `sourceTable` 은 query string `?source_table=` 으로 전달됩니다.
|
|
25
|
+
- **`database.createRelation(appId, tableId, data)` → `database.createRelation(appId, data)`** — `tableId` 인자 제거. 테이블 정보는 body 의 `source_table`/`target_table` 로 전달.
|
|
26
|
+
- **`database.deleteRelation(appId, tableId, relationName)` → `database.deleteRelation(appId, relationId)`** — `relationId` 는 `listRelations` 가 반환하는 UUID (`id` 필드). 기존 `(tableName, alias)` 조합으로 지정할 수 없습니다.
|
|
27
|
+
|
|
28
|
+
### Migration
|
|
29
|
+
|
|
30
|
+
기존 호출이 실제로 성공하는 경로가 없었으므로(항상 404) 깨지는 호출자는 없어야 합니다. relations 를 쓰던 소비자는 위 새 시그니처로 교체하고, triggers/indexes/security-rules 는 코드 변경 없이 자동으로 동작하게 됩니다.
|
|
31
|
+
|
|
6
32
|
## [1.6.0] - 2026-04-19
|
|
7
33
|
|
|
8
34
|
웹 방문 추적에 로그인 회원을 자동 연결 — 콘솔의 **앱 멤버 > 활동기록 > 웹방문기록** 탭이 이제 실제로 채워진다. 이전까지는 SDK 가 배치 이벤트를 `visitor_uid` 만 실어 보내 `web_visitors.app_member_id` 가 전부 NULL 로 남아 있었다.
|
package/dist/connect-base.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var ConnectBaseModule=(()=>{var Y=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var de=Object.prototype.hasOwnProperty;var pe=(l,e)=>{for(var t in e)Y(l,t,{get:e[t],enumerable:!0})},he=(l,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of le(e))!de.call(l,i)&&i!==t&&Y(l,i,{get:()=>e[i],enumerable:!(s=ce(e,i))||s.enumerable});return l};var ue=l=>he(Y({},"__esModule",{value:!0}),l);var Re={};pe(Re,{AIAPI:()=>k,AdsAPI:()=>_,ApiError:()=>f,AuthError:()=>P,ConnectBase:()=>J,GameAPI:()=>R,GameRoom:()=>I,GameRoomTransport:()=>z,NativeAPI:()=>T,SessionManager:()=>C,VideoProcessingError:()=>S,default:()=>Se,isWebTransportSupported:()=>te});var f=class extends Error{constructor(t,s,i,r){super(s);this.statusCode=t;this.name="ApiError",this.code=i,this.details=r}},P=class extends Error{constructor(e){super(e),this.name="AuthError"}};var se="cb_auth_tokens",$=class{constructor(e){this.isRefreshing=!1;this.refreshPromise=null;this.config={...e},this.storageKey=this.buildStorageKey(),this.warnIfUnsafePersistence(),this.restoreTokens()}warnIfUnsafePersistence(){typeof window>"u"||(this.config.persistence==="localStorage"?console.warn(`[connect-base-client] persistence="localStorage" \uB294 XSS \uC2DC \uD1A0\uD070 \uC601\uAD6C \uD0C8\uCDE8 \uC704\uD5D8\uC774 \uC788\uC2B5\uB2C8\uB2E4. refresh token \uC740 \uC11C\uBC84 HttpOnly \uCFE0\uD0A4\uB85C \uBC1C\uAE09\uBC1B\uACE0 \uAE30\uBCF8\uAC12('none')\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.`):this.config.persistence==="sessionStorage"&&console.warn('[connect-base-client] persistence="sessionStorage" \uB294 XSS \uC2DC \uD604\uC7AC \uD0ED \uC138\uC158 \uD0C8\uCDE8 \uC704\uD5D8\uC774 \uC788\uC2B5\uB2C8\uB2E4.'))}updateConfig(e){this.config={...this.config,...e}}setTokens(e,t){this.config.accessToken=e,this.config.refreshToken=t,this.persistTokens()}clearTokens(){this.config.accessToken=void 0,this.config.refreshToken=void 0,this.removePersistedTokens()}get persistence(){return this.config.persistence??"none"}getStorage(){return typeof window>"u"?null:this.persistence==="localStorage"&&typeof localStorage<"u"?localStorage:this.persistence==="sessionStorage"&&typeof sessionStorage<"u"?sessionStorage:null}getPersistenceStorage(){return this.getStorage()}buildStorageKey(){let e=this.config.publicKey??this.config.secretKey;if(!e)return se;let t=0;for(let s=0;s<e.length;s++)t=(t<<5)-t+e.charCodeAt(s),t=t&t;return`${se}_${Math.abs(t).toString(36)}`}persistTokens(){if(this.persistence==="none")return;let e=this.getStorage();!e||!this.config.accessToken||!this.config.refreshToken||e.setItem(this.storageKey,JSON.stringify({accessToken:this.config.accessToken,refreshToken:this.config.refreshToken}))}restoreTokens(){if(this.persistence==="none"||this.config.accessToken&&this.config.refreshToken)return;let e=this.getStorage();if(!e)return;let t=e.getItem(this.storageKey);if(t)try{let{accessToken:s,refreshToken:i}=JSON.parse(t);s&&i&&(this.config.accessToken=s,this.config.refreshToken=i)}catch{e.removeItem(this.storageKey)}}removePersistedTokens(){if(this.persistence==="none")return;let e=this.getStorage();e&&e.removeItem(this.storageKey)}hasPublicKey(){return!!this.config.publicKey}getPublicKey(){return this.config.publicKey}hasSecretKey(){return!!this.config.secretKey}getSecretKey(){return this.config.secretKey}getCredential(){return this.config.publicKey??this.config.secretKey}getAccessToken(){return this.config.accessToken}hasJWT(){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 P("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.setTokens(t.access_token,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 P("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;t.set("Content-Type","application/json");let s=this.getCredential();if(s&&t.set("X-Public-Key",s),!e?.skipAuth&&this.config.accessToken){let i=this.config.accessToken;if(this.isTokenExpired(i)&&this.config.refreshToken){let r=await this.refreshAccessToken();r&&(i=r)}t.set("Authorization",`Bearer ${i}`)}return e?.headers&&Object.entries(e.headers).forEach(([i,r])=>{t.set(i,r)}),t}async handleResponse(e){if(!e.ok){let t=await e.json().catch(()=>({message:e.statusText})),s=t.error;if(s&&typeof s=="object"&&"message"in s)throw new f(e.status,s.message||"Unknown error",s.code,s.details);let i=typeof s=="string"?s:t.message||"Unknown error";throw new f(e.status,i)}return e.status===204||e.headers.get("content-length")==="0"?{}:e.json()}async get(e,t){let s=await this.prepareHeaders(t),i=await fetch(`${this.config.baseUrl}${e}`,{method:"GET",headers:s});return this.handleResponse(i)}async post(e,t,s){let i=await this.prepareHeaders(s);t instanceof FormData&&i.delete("Content-Type");let r=await fetch(`${this.config.baseUrl}${e}`,{method:"POST",headers:i,body:t instanceof FormData?t:JSON.stringify(t)});return this.handleResponse(r)}async put(e,t,s){let i=await this.prepareHeaders(s),r=await fetch(`${this.config.baseUrl}${e}`,{method:"PUT",headers:i,body:JSON.stringify(t)});return this.handleResponse(r)}async patch(e,t,s){let i=await this.prepareHeaders(s),r=await fetch(`${this.config.baseUrl}${e}`,{method:"PATCH",headers:i,body:JSON.stringify(t)});return this.handleResponse(r)}async delete(e,t){let s=await this.prepareHeaders(t),i=await fetch(`${this.config.baseUrl}${e}`,{method:"DELETE",headers:s});return this.handleResponse(i)}async fetchRaw(e,t){let s=await this.prepareHeaders(),i=new Headers(s);return t?.headers&&new Headers(t.headers).forEach((n,o)=>i.set(o,n)),fetch(`${this.config.baseUrl}${e}`,{...t,headers:i})}};var ie="cb_guest_";function ge(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;this.analytics=null}_attachAnalytics(e){this.analytics=e}notifyVisitorTracker(e){if(this.analytics){this.analytics.setMemberId(e);return}typeof window>"u"||(e?typeof window.__cbSetMember=="function"&&window.__cbSetMember(e):typeof window.__cbClearMember=="function"&&window.__cbClearMember())}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),this.notifyVisitorTracker(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),this.notifyVisitorTracker(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(),this.notifyVisitorTracker(null)}}clearGuestMemberTokens(){let e=this.http.getPersistenceStorage();e&&e.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 this.notifyVisitorTracker(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),this.notifyVisitorTracker(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),this.notifyVisitorTracker(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.getCredential();if(!e)this.cachedGuestMemberTokenKey=`${ie}default`;else{let t=ge(e);this.cachedGuestMemberTokenKey=`${ie}${t}`}return this.cachedGuestMemberTokenKey}getStoredGuestMemberTokens(){let e=this.http.getPersistenceStorage();if(!e)return null;let t=e.getItem(this.getGuestMemberTokenKey());if(!t)return null;try{return JSON.parse(t)}catch{return null}}storeGuestMemberTokens(e,t,s){let i=this.http.getPersistenceStorage();i&&i.setItem(this.getGuestMemberTokenKey(),JSON.stringify({accessToken:e,refreshToken:t,memberId:s}))}};var E=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"/v1/public"}async getTables(){let e=this.getPublicPrefix();return(await this.http.get(`${e}/tables`)).tables}async getTable(e){let t=this.getPublicPrefix();return this.http.get(`${t}/tables/${e}`)}async createTable(e){let t=this.getPublicPrefix(),s={title:e.name,access_level:e.accessLevel??"Creator"};e.schema&&Object.keys(e.schema).length>0&&(s.schema=e.schema),await this.http.post(`${t}/tables`,s)}async updateTable(e,t){let s=this.getPublicPrefix(),i={};t.name!==void 0&&(i.title=t.name),t.schema!==void 0&&(i.schema=t.schema),t.accessLevel!==void 0&&(i.access_level=t.accessLevel),t.description!==void 0&&(i.description=t.description),await this.http.patch(`${s}/tables/${e}`,i)}async deleteTable(e){let t=this.getPublicPrefix();await this.http.delete(`${t}/tables/${e}`)}async getValidationSchema(e){let t=this.getPublicPrefix();return(await this.http.get(`${t}/tables/${e}/validation-schema`)).validation_schema}async setValidationSchema(e,t){await this.http.put(`/v1/apps/${this.requireAppId()}/databases/tables/${e}/validation-schema`,{validation_schema:t})}async deleteValidationSchema(e){await this.http.delete(`/v1/apps/${this.requireAppId()}/databases/tables/${e}/validation-schema`)}requireAppId(){let e=this.http.config?.appId;if(!e)throw new Error("setValidationSchema/deleteValidationSchema \uB294 \uCF58\uC194 (JWT) \uC778\uC99D\uC774 \uD544\uC694\uD558\uBA70 ConnectBase config \uC5D0 appId \uAC00 \uC124\uC815\uB418\uC5B4\uC57C \uD569\uB2C8\uB2E4.");return e}async getColumns(e){let t=await this.getTable(e),s=t.schema??{},i=new Set(Array.isArray(s.$required)?s.$required:[]),r=[],n=0;for(let[o,a]of Object.entries(s)){if(o.startsWith("$")||a===void 0||Array.isArray(a))continue;let c="string",d=i.has(o),h,p,g;typeof a=="string"?c=a:(c=a.type,a.required===!0&&(d=!0),a.default!==void 0&&(h=a.default),a.description!==void 0&&(p=a.description),a.encrypted!==void 0&&(g=a.encrypted)),r.push({id:o,name:o,data_type:c,is_required:d,default_value:h,description:p,encrypted:g,order:n++,created_at:t.created_at})}return r}async createColumn(e,t){let s=this.getPublicPrefix();await this.http.post(`${s}/tables/${e}/columns`,t)}async updateColumn(e,t,s){let i=this.getPublicPrefix();await this.http.patch(`${i}/tables/${e}/columns/${t}`,s)}async deleteColumn(e,t){let s=this.getPublicPrefix();await this.http.delete(`${s}/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 i=new URLSearchParams;t?.limit&&i.append("limit",t.limit.toString()),t?.offset&&i.append("offset",t.offset.toString());let r=i.toString(),n=r?`${s}/tables/${e}/data?${r}`:`${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,s){let i=this.getPublicPrefix();if(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(e))return this.http.post(`${i}/tables/${e}/data`,t);let n=s?.autoCreate?"?auto_create=true":"";return this.http.post(`${i}/tables/name/${encodeURIComponent(e)}/data${n}`,t)}async updateData(e,t,s){let i=this.getPublicPrefix();return this.http.patch(`${i}/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(i=>i.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,i){let r=this.getPublicPrefix();return this.http.post(`${r}/search`,{table_id:e,query:t,fields:s,options:i})}async autocomplete(e,t,s,i){let r=this.getPublicPrefix();return this.http.post(`${r}/autocomplete`,{table_id:e,query:t,field:s,...i})}async geoQuery(e,t,s,i){let r=this.getPublicPrefix();return this.http.post(`${r}/geo`,{table_id:e,field:t,query:s,...i})}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 i=`csub_${Date.now()}_${Math.random().toString(36).substring(2,9)}`;this.activeSubscriptions.set(i,{tableId:e,options:s,handlers:t});let r=this.sendSubscribeRequest(e,t,s);return r.catch(n=>{this.activeSubscriptions.delete(i),t.onError?.(n instanceof Error?n:new Error(String(n)))}),{subscriptionId:i,unsubscribe:()=>{this.activeSubscriptions.delete(i),r.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"&&r.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 i={};for(let r of s)r.data&&(i[r.id]=r.data);t(i)}}),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((i,r)=>{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"),r(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(),i()},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),r(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"),r(n)}})}sendSubscribeRequest(e,t,s){let i=this.generateRequestId();this.realtimeHandlers.set(i,t);let r=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:i,table_id:e,doc_id:s?.docId,query:r,options:{include_self:s?.includeSelf??!1,include_metadata_changes:s?.includeMetadataChanges??!1}}),new Promise((n,o)=>{let a=setTimeout(()=>{this.pendingRequests.delete(i),this.realtimeHandlers.delete(i),o(new Error("Subscribe request timeout"))},3e4);this.pendingRequests.set(i,{resolve:c=>{let d=c,h=this.realtimeHandlers.get(i);h&&(this.realtimeHandlers.delete(i),this.realtimeHandlers.set(d,h)),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,i=e.subscription_id,r=this.pendingRequests.get(s);r&&(clearTimeout(r.timeout),r.resolve(i),this.pendingRequests.delete(s));break}case"snapshot":{let s=e.subscription_id,i=this.realtimeHandlers.get(s);if(i?.onSnapshot){let r=e.docs||[],n=e.has_more||!1,o=n?e.next_offset:void 0;i.onSnapshot(r,{totalCount:e.total_count||0,hasMore:n,nextOffset:o})}break}case"change":{let s=e.subscription_id,i=this.realtimeHandlers.get(s);if(i?.onChange){let r=e.changes||[];i.onChange(r)}break}case"presence":{let s=this.realtimeHandlers.get("__presence__");if(s?.onSnapshot){let i=e.states,r=Object.entries(i||{}).map(([n,o])=>({id:n,data:o,exists:!0}));s.onSnapshot(r,{totalCount:r.length,hasMore:!1})}break}case"error":{let s=e.request_id,i=e.message||"Unknown error";if(s){let r=this.pendingRequests.get(s);r&&(clearTimeout(r.timeout),r.reject(new Error(i)),this.pendingRequests.delete(s));let n=this.realtimeHandlers.get(s);n?.onError&&n.onError(new Error(i))}else this.realtimeOnError?.(new Error(i));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(i=>{this.debugLog(`Reconnect failed: ${i}`)})},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 M=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasPublicKey()?"/v1/public":"/v1"}async getFiles(e,t){let s=this.getPublicPrefix(),i=t?`?parent_id=${encodeURIComponent(t)}`:"";return(await this.http.get(`${s}/storages/files/${e}/items${i}`)).files}async uploadFile(e,t,s){let i=this.getPublicPrefix(),r=await this.http.post(`${i}/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(r.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(`${i}/storages/files/${e}/complete-upload`,{file_id:r.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 i=[];for(let r of t){let n=await this.uploadFile(e,r,s);i.push(n)}return i}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){if(this.http.hasPublicKey()&&!this.http.hasJWT())throw new Error("storage.moveFile requires JWT (console token) auth; not available with Public Key alone.");await this.http.post(`/v1/storages/files/${e}/items/${t}/move`,s)}async renameFile(e,t,s){if(this.http.hasPublicKey()&&!this.http.hasJWT())throw new Error("storage.renameFile requires JWT (console token) auth; not available with Public Key alone.");return this.http.patch(`/v1/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,i){let r=this.getPublicPrefix(),n=t.startsWith("/")?t.slice(1):t,o=i?.overwrite!==!1,a=await this.http.post(`${r}/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(`${r}/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(),i=t.startsWith("/")?t.slice(1):t;return this.http.get(`${s}/storages/files/${e}/path/${i}`)}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(),i=new URLSearchParams;t?.limit!=null&&i.set("limit",String(t.limit)),t?.offset!=null&&i.set("offset",String(t.offset));let r=i.toString();return this.http.get(`${s}/storages/webs/${e}/page-metas${r?`?${r}`:""}`)}async getPageMeta(e,t){let s=this.getPublicPrefix(),i=encodeURIComponent(t);return this.http.get(`${s}/storages/webs/${e}/page-metas/get?path=${i}`)}async deletePageMeta(e,t){let s=this.getPublicPrefix(),i=encodeURIComponent(t);await this.http.delete(`${s}/storages/webs/${e}/page-metas?path=${i}`)}async deleteAllPageMetas(e){let t=this.getPublicPrefix();await this.http.delete(`${t}/storages/webs/${e}/page-metas/all`)}};var U=class{constructor(e){this.http=e}async getPublicKeys(e){return this.http.get(`/v1/apps/${e}/public-keys`)}async createPublicKey(e,t){return this.http.post(`/v1/apps/${e}/public-keys`,t)}async updatePublicKey(e,t,s){return this.http.patch(`/v1/apps/${e}/public-keys/${t}`,s)}async deletePublicKey(e,t){await this.http.delete(`/v1/apps/${e}/public-keys/${t}`)}};var q=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasPublicKey()?"/v1/public":"/v1"}async invoke(e,t,s){let i=this.getPublicPrefix(),r={};return t!==void 0&&(r.payload=t),s!==void 0&&(r.timeout=s),this.http.post(`${i}/functions/${e}/invoke`,r)}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(),i=await this.sendRequest({category:e,action:"subscribe",request_id:s}),r={category:i.category,persist:i.persist,historyCount:i.history_count,readReceipt:i.read_receipt},n=[];return this.subscriptions.set(e,{info:r,handlers:n}),{info:r,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 r=s.includeSelf!==!1,n=this.generateRequestId();await this.sendRequest({category:e,action:"send",data:{data:t,broadcast:r},request_id:n})}async getHistory(e,t){if(this.state!=="connected")throw new Error("Not connected");let s=this.generateRequestId(),i=await this.sendRequest({category:e,action:"history",data:t?{limit:t}:void 0,request_id:s});return{category:i.category,messages:i.messages.map(r=>({id:r.id,category:r.category,from:r.from,data:r.data,sentAt:r.sent_at})),total:i.total}}async stream(e,t,s={}){if(this.state!=="connected")throw new Error("Not connected. Call connect() first.");let i=this.generateRequestId(),r=s.sessionId||this.generateRequestId();this.streamSessions.set(r,{handlers:t,requestId:i});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:r,metadata:s.metadata,mcp_group:s.mcpGroup},request_id:i})}catch(n){throw this.streamSessions.delete(r),n}return{sessionId:r,stop:async()=>{await this.stopStream(r)}}}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}),i={};for(let[r,n]of Object.entries(s.users))i[r]={userId:n.user_id,status:n.status,lastSeen:n.last_seen,device:n.device,metadata:n.metadata};return{users:i}}async subscribePresence(e,t){if(this.state!=="connected")throw new Error("Not connected");if(!this.presenceSubscriptions.has(e)){let i=this.generateRequestId();await this.sendRequest({category:"",action:"presence_subscribe",data:{user_id:e},request_id:i}),this.presenceSubscriptions.set(e,[])}let s=this.presenceSubscriptions.get(e);return s.push(t),()=>{let i=s.indexOf(t);if(i>-1&&s.splice(i,1),s.length===0&&(this.presenceSubscriptions.delete(e),this.state==="connected")){let r=this.generateRequestId();this.sendRequest({category:"",action:"presence_unsubscribe",data:{user_id:e},request_id:r}).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 i=this.generateRequestId();await this.sendRequest({category:"",action:"typing_subscribe",data:{room_id:e},request_id:i}),this.typingHandlers.set(e,[])}let s=this.typingHandlers.get(e);return s.push(t),()=>{let i=s.indexOf(t);if(i>-1&&s.splice(i,1),s.length===0&&(this.typingHandlers.delete(e),this.state==="connected")){let r=this.generateRequestId();this.sendRequest({category:"",action:"typing_unsubscribe",data:{room_id:e},request_id:r}).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 i=s.indexOf(t);i>-1&&s.splice(i,1)}}async doConnect(){return new Promise((e,t)=>{this.state="connecting",this.notifyStateChange(),this.log("Connecting...");let s=this.socketUrl.replace(/^http/,"ws"),i;if(this.options.accessToken)i=`${s}/v1/realtime/auth?access_token=${encodeURIComponent(this.options.accessToken)}&client_id=${this.clientId}`,this.log("Using accessToken authentication");else{let o=this.http.getPublicKey();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}i=`${s}/v1/realtime/auth?public_key=${encodeURIComponent(o)}&client_id=${this.clientId}`,this.log("Using API Key authentication")}this.userId&&(i+=`&user_id=${encodeURIComponent(this.userId)}`);let r=!1,n=setTimeout(()=>{r||(r=!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(i),this.ws.onopen=()=>{this.log("WebSocket opened, waiting for connected event...")},this.ws.onmessage=o=>{let a=o.data.split(`
|
|
1
|
+
"use strict";var ConnectBaseModule=(()=>{var Y=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var de=Object.prototype.hasOwnProperty;var pe=(l,e)=>{for(var t in e)Y(l,t,{get:e[t],enumerable:!0})},he=(l,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of le(e))!de.call(l,i)&&i!==t&&Y(l,i,{get:()=>e[i],enumerable:!(s=ce(e,i))||s.enumerable});return l};var ue=l=>he(Y({},"__esModule",{value:!0}),l);var Re={};pe(Re,{AIAPI:()=>k,AdsAPI:()=>_,ApiError:()=>f,AuthError:()=>P,ConnectBase:()=>J,GameAPI:()=>R,GameRoom:()=>I,GameRoomTransport:()=>z,NativeAPI:()=>T,SessionManager:()=>C,VideoProcessingError:()=>S,default:()=>Se,isWebTransportSupported:()=>te});var f=class extends Error{constructor(t,s,i,r){super(s);this.statusCode=t;this.name="ApiError",this.code=i,this.details=r}},P=class extends Error{constructor(e){super(e),this.name="AuthError"}};var se="cb_auth_tokens",$=class{constructor(e){this.isRefreshing=!1;this.refreshPromise=null;this.config={...e},this.storageKey=this.buildStorageKey(),this.warnIfUnsafePersistence(),this.restoreTokens()}warnIfUnsafePersistence(){typeof window>"u"||(this.config.persistence==="localStorage"?console.warn(`[connect-base-client] persistence="localStorage" \uB294 XSS \uC2DC \uD1A0\uD070 \uC601\uAD6C \uD0C8\uCDE8 \uC704\uD5D8\uC774 \uC788\uC2B5\uB2C8\uB2E4. refresh token \uC740 \uC11C\uBC84 HttpOnly \uCFE0\uD0A4\uB85C \uBC1C\uAE09\uBC1B\uACE0 \uAE30\uBCF8\uAC12('none')\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.`):this.config.persistence==="sessionStorage"&&console.warn('[connect-base-client] persistence="sessionStorage" \uB294 XSS \uC2DC \uD604\uC7AC \uD0ED \uC138\uC158 \uD0C8\uCDE8 \uC704\uD5D8\uC774 \uC788\uC2B5\uB2C8\uB2E4.'))}updateConfig(e){this.config={...this.config,...e}}setTokens(e,t){this.config.accessToken=e,this.config.refreshToken=t,this.persistTokens()}clearTokens(){this.config.accessToken=void 0,this.config.refreshToken=void 0,this.removePersistedTokens()}get persistence(){return this.config.persistence??"none"}getStorage(){return typeof window>"u"?null:this.persistence==="localStorage"&&typeof localStorage<"u"?localStorage:this.persistence==="sessionStorage"&&typeof sessionStorage<"u"?sessionStorage:null}getPersistenceStorage(){return this.getStorage()}buildStorageKey(){let e=this.config.publicKey??this.config.secretKey;if(!e)return se;let t=0;for(let s=0;s<e.length;s++)t=(t<<5)-t+e.charCodeAt(s),t=t&t;return`${se}_${Math.abs(t).toString(36)}`}persistTokens(){if(this.persistence==="none")return;let e=this.getStorage();!e||!this.config.accessToken||!this.config.refreshToken||e.setItem(this.storageKey,JSON.stringify({accessToken:this.config.accessToken,refreshToken:this.config.refreshToken}))}restoreTokens(){if(this.persistence==="none"||this.config.accessToken&&this.config.refreshToken)return;let e=this.getStorage();if(!e)return;let t=e.getItem(this.storageKey);if(t)try{let{accessToken:s,refreshToken:i}=JSON.parse(t);s&&i&&(this.config.accessToken=s,this.config.refreshToken=i)}catch{e.removeItem(this.storageKey)}}removePersistedTokens(){if(this.persistence==="none")return;let e=this.getStorage();e&&e.removeItem(this.storageKey)}hasPublicKey(){return!!this.config.publicKey}getPublicKey(){return this.config.publicKey}hasSecretKey(){return!!this.config.secretKey}getSecretKey(){return this.config.secretKey}getCredential(){return this.config.publicKey??this.config.secretKey}getAccessToken(){return this.config.accessToken}hasJWT(){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 P("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.setTokens(t.access_token,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 P("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;t.set("Content-Type","application/json");let s=this.getCredential();if(s&&t.set("X-Public-Key",s),!e?.skipAuth&&this.config.accessToken){let i=this.config.accessToken;if(this.isTokenExpired(i)&&this.config.refreshToken){let r=await this.refreshAccessToken();r&&(i=r)}t.set("Authorization",`Bearer ${i}`)}return e?.headers&&Object.entries(e.headers).forEach(([i,r])=>{t.set(i,r)}),t}async handleResponse(e){if(!e.ok){let t=await e.json().catch(()=>({message:e.statusText})),s=t.error;if(s&&typeof s=="object"&&"message"in s)throw new f(e.status,s.message||"Unknown error",s.code,s.details);let i=typeof s=="string"?s:t.message||"Unknown error";throw new f(e.status,i)}return e.status===204||e.headers.get("content-length")==="0"?{}:e.json()}async get(e,t){let s=await this.prepareHeaders(t),i=await fetch(`${this.config.baseUrl}${e}`,{method:"GET",headers:s});return this.handleResponse(i)}async post(e,t,s){let i=await this.prepareHeaders(s);t instanceof FormData&&i.delete("Content-Type");let r=await fetch(`${this.config.baseUrl}${e}`,{method:"POST",headers:i,body:t instanceof FormData?t:JSON.stringify(t)});return this.handleResponse(r)}async put(e,t,s){let i=await this.prepareHeaders(s),r=await fetch(`${this.config.baseUrl}${e}`,{method:"PUT",headers:i,body:JSON.stringify(t)});return this.handleResponse(r)}async patch(e,t,s){let i=await this.prepareHeaders(s),r=await fetch(`${this.config.baseUrl}${e}`,{method:"PATCH",headers:i,body:JSON.stringify(t)});return this.handleResponse(r)}async delete(e,t){let s=await this.prepareHeaders(t),i=await fetch(`${this.config.baseUrl}${e}`,{method:"DELETE",headers:s});return this.handleResponse(i)}async fetchRaw(e,t){let s=await this.prepareHeaders(),i=new Headers(s);return t?.headers&&new Headers(t.headers).forEach((n,o)=>i.set(o,n)),fetch(`${this.config.baseUrl}${e}`,{...t,headers:i})}};var ie="cb_guest_";function ge(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;this.analytics=null}_attachAnalytics(e){this.analytics=e}notifyVisitorTracker(e){if(this.analytics){this.analytics.setMemberId(e);return}typeof window>"u"||(e?typeof window.__cbSetMember=="function"&&window.__cbSetMember(e):typeof window.__cbClearMember=="function"&&window.__cbClearMember())}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),this.notifyVisitorTracker(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),this.notifyVisitorTracker(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(),this.notifyVisitorTracker(null)}}clearGuestMemberTokens(){let e=this.http.getPersistenceStorage();e&&e.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 this.notifyVisitorTracker(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),this.notifyVisitorTracker(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),this.notifyVisitorTracker(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.getCredential();if(!e)this.cachedGuestMemberTokenKey=`${ie}default`;else{let t=ge(e);this.cachedGuestMemberTokenKey=`${ie}${t}`}return this.cachedGuestMemberTokenKey}getStoredGuestMemberTokens(){let e=this.http.getPersistenceStorage();if(!e)return null;let t=e.getItem(this.getGuestMemberTokenKey());if(!t)return null;try{return JSON.parse(t)}catch{return null}}storeGuestMemberTokens(e,t,s){let i=this.http.getPersistenceStorage();i&&i.setItem(this.getGuestMemberTokenKey(),JSON.stringify({accessToken:e,refreshToken:t,memberId:s}))}};var E=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"/v1/public"}async getTables(){let e=this.getPublicPrefix();return(await this.http.get(`${e}/tables`)).tables}async getTable(e){let t=this.getPublicPrefix();return this.http.get(`${t}/tables/${e}`)}async createTable(e){let t=this.getPublicPrefix(),s={title:e.name,access_level:e.accessLevel??"Creator"};e.schema&&Object.keys(e.schema).length>0&&(s.schema=e.schema),await this.http.post(`${t}/tables`,s)}async updateTable(e,t){let s=this.getPublicPrefix(),i={};t.name!==void 0&&(i.title=t.name),t.schema!==void 0&&(i.schema=t.schema),t.accessLevel!==void 0&&(i.access_level=t.accessLevel),t.description!==void 0&&(i.description=t.description),await this.http.patch(`${s}/tables/${e}`,i)}async deleteTable(e){let t=this.getPublicPrefix();await this.http.delete(`${t}/tables/${e}`)}async getValidationSchema(e){let t=this.getPublicPrefix();return(await this.http.get(`${t}/tables/${e}/validation-schema`)).validation_schema}async setValidationSchema(e,t){await this.http.put(`/v1/apps/${this.requireAppId()}/databases/tables/${e}/validation-schema`,{validation_schema:t})}async deleteValidationSchema(e){await this.http.delete(`/v1/apps/${this.requireAppId()}/databases/tables/${e}/validation-schema`)}requireAppId(){let e=this.http.config?.appId;if(!e)throw new Error("setValidationSchema/deleteValidationSchema \uB294 \uCF58\uC194 (JWT) \uC778\uC99D\uC774 \uD544\uC694\uD558\uBA70 ConnectBase config \uC5D0 appId \uAC00 \uC124\uC815\uB418\uC5B4\uC57C \uD569\uB2C8\uB2E4.");return e}async getColumns(e){let t=await this.getTable(e),s=t.schema??{},i=new Set(Array.isArray(s.$required)?s.$required:[]),r=[],n=0;for(let[o,a]of Object.entries(s)){if(o.startsWith("$")||a===void 0||Array.isArray(a))continue;let c="string",d=i.has(o),h,p,g;typeof a=="string"?c=a:(c=a.type,a.required===!0&&(d=!0),a.default!==void 0&&(h=a.default),a.description!==void 0&&(p=a.description),a.encrypted!==void 0&&(g=a.encrypted)),r.push({id:o,name:o,data_type:c,is_required:d,default_value:h,description:p,encrypted:g,order:n++,created_at:t.created_at})}return r}async createColumn(e,t){let s=this.getPublicPrefix();await this.http.post(`${s}/tables/${e}/columns`,t)}async updateColumn(e,t,s){let i=this.getPublicPrefix();await this.http.patch(`${i}/tables/${e}/columns/${t}`,s)}async deleteColumn(e,t){let s=this.getPublicPrefix();await this.http.delete(`${s}/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 i=new URLSearchParams;t?.limit&&i.append("limit",t.limit.toString()),t?.offset&&i.append("offset",t.offset.toString());let r=i.toString(),n=r?`${s}/tables/${e}/data?${r}`:`${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,s){let i=this.getPublicPrefix();if(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(e))return this.http.post(`${i}/tables/${e}/data`,t);let n=s?.autoCreate?"?auto_create=true":"";return this.http.post(`${i}/tables/name/${encodeURIComponent(e)}/data${n}`,t)}async updateData(e,t,s){let i=this.getPublicPrefix();return this.http.patch(`${i}/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(i=>i.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,i){let r=this.getPublicPrefix();return this.http.post(`${r}/search`,{table_id:e,query:t,fields:s,options:i})}async autocomplete(e,t,s,i){let r=this.getPublicPrefix();return this.http.post(`${r}/autocomplete`,{table_id:e,query:t,field:s,...i})}async geoQuery(e,t,s,i){let r=this.getPublicPrefix();return this.http.post(`${r}/geo`,{table_id:e,field:t,query:s,...i})}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}/databases/security/rules`)).rules}async createSecurityRule(e,t){return this.http.post(`/v1/apps/${e}/databases/security/rules`,t)}async updateSecurityRule(e,t,s){return this.http.put(`/v1/apps/${e}/databases/security/rules/${t}`,s)}async deleteSecurityRule(e,t){await this.http.delete(`/v1/apps/${e}/databases/security/rules/${t}`)}async listIndexes(e,t){return(await this.http.get(`/v1/apps/${e}/databases/tables/${t}/indexes`)).indexes}async createIndex(e,t,s){return this.http.post(`/v1/apps/${e}/databases/tables/${t}/indexes`,s)}async deleteIndex(e,t,s){await this.http.delete(`/v1/apps/${e}/databases/tables/${t}/indexes/${s}`)}async analyzeIndexes(e,t){return this.http.get(`/v1/apps/${e}/databases/tables/${t}/indexes/analyze`)}async listSearchIndexes(e,t){return(await this.http.get(`/v1/apps/${e}/databases/tables/${t}/search-indexes`)).indexes}async createSearchIndex(e,t,s){return this.http.post(`/v1/apps/${e}/databases/tables/${t}/search-indexes`,s)}async deleteSearchIndex(e,t,s){await this.http.delete(`/v1/apps/${e}/databases/tables/${t}/search-indexes/${s}`)}async listGeoIndexes(e,t){return(await this.http.get(`/v1/apps/${e}/databases/tables/${t}/geo-indexes`)).indexes}async createGeoIndex(e,t,s){return this.http.post(`/v1/apps/${e}/databases/tables/${t}/geo-indexes`,s)}async deleteGeoIndex(e,t,s){await this.http.delete(`/v1/apps/${e}/databases/tables/${t}/geo-indexes/${s}`)}async listRelations(e,t){let s=t?`?source_table=${encodeURIComponent(t)}`:"";return(await this.http.get(`/v1/apps/${e}/databases/relations${s}`)).relations}async createRelation(e,t){return this.http.post(`/v1/apps/${e}/databases/relations`,t)}async deleteRelation(e,t){await this.http.delete(`/v1/apps/${e}/databases/relations/${t}`)}async listTriggers(e){return(await this.http.get(`/v1/apps/${e}/databases/triggers`)).triggers}async createTrigger(e,t){return this.http.post(`/v1/apps/${e}/databases/triggers`,t)}async updateTrigger(e,t,s){return this.http.put(`/v1/apps/${e}/databases/triggers/${t}`,s)}async deleteTrigger(e,t){await this.http.delete(`/v1/apps/${e}/databases/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 i=`csub_${Date.now()}_${Math.random().toString(36).substring(2,9)}`;this.activeSubscriptions.set(i,{tableId:e,options:s,handlers:t});let r=this.sendSubscribeRequest(e,t,s);return r.catch(n=>{this.activeSubscriptions.delete(i),t.onError?.(n instanceof Error?n:new Error(String(n)))}),{subscriptionId:i,unsubscribe:()=>{this.activeSubscriptions.delete(i),r.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"&&r.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 i={};for(let r of s)r.data&&(i[r.id]=r.data);t(i)}}),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((i,r)=>{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"),r(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(),i()},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),r(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"),r(n)}})}sendSubscribeRequest(e,t,s){let i=this.generateRequestId();this.realtimeHandlers.set(i,t);let r=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:i,table_id:e,doc_id:s?.docId,query:r,options:{include_self:s?.includeSelf??!1,include_metadata_changes:s?.includeMetadataChanges??!1}}),new Promise((n,o)=>{let a=setTimeout(()=>{this.pendingRequests.delete(i),this.realtimeHandlers.delete(i),o(new Error("Subscribe request timeout"))},3e4);this.pendingRequests.set(i,{resolve:c=>{let d=c,h=this.realtimeHandlers.get(i);h&&(this.realtimeHandlers.delete(i),this.realtimeHandlers.set(d,h)),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,i=e.subscription_id,r=this.pendingRequests.get(s);r&&(clearTimeout(r.timeout),r.resolve(i),this.pendingRequests.delete(s));break}case"snapshot":{let s=e.subscription_id,i=this.realtimeHandlers.get(s);if(i?.onSnapshot){let r=e.docs||[],n=e.has_more||!1,o=n?e.next_offset:void 0;i.onSnapshot(r,{totalCount:e.total_count||0,hasMore:n,nextOffset:o})}break}case"change":{let s=e.subscription_id,i=this.realtimeHandlers.get(s);if(i?.onChange){let r=e.changes||[];i.onChange(r)}break}case"presence":{let s=this.realtimeHandlers.get("__presence__");if(s?.onSnapshot){let i=e.states,r=Object.entries(i||{}).map(([n,o])=>({id:n,data:o,exists:!0}));s.onSnapshot(r,{totalCount:r.length,hasMore:!1})}break}case"error":{let s=e.request_id,i=e.message||"Unknown error";if(s){let r=this.pendingRequests.get(s);r&&(clearTimeout(r.timeout),r.reject(new Error(i)),this.pendingRequests.delete(s));let n=this.realtimeHandlers.get(s);n?.onError&&n.onError(new Error(i))}else this.realtimeOnError?.(new Error(i));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(i=>{this.debugLog(`Reconnect failed: ${i}`)})},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 M=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasPublicKey()?"/v1/public":"/v1"}async getFiles(e,t){let s=this.getPublicPrefix(),i=t?`?parent_id=${encodeURIComponent(t)}`:"";return(await this.http.get(`${s}/storages/files/${e}/items${i}`)).files}async uploadFile(e,t,s){let i=this.getPublicPrefix(),r=await this.http.post(`${i}/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(r.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(`${i}/storages/files/${e}/complete-upload`,{file_id:r.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 i=[];for(let r of t){let n=await this.uploadFile(e,r,s);i.push(n)}return i}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){if(this.http.hasPublicKey()&&!this.http.hasJWT())throw new Error("storage.moveFile requires JWT (console token) auth; not available with Public Key alone.");await this.http.post(`/v1/storages/files/${e}/items/${t}/move`,s)}async renameFile(e,t,s){if(this.http.hasPublicKey()&&!this.http.hasJWT())throw new Error("storage.renameFile requires JWT (console token) auth; not available with Public Key alone.");return this.http.patch(`/v1/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,i){let r=this.getPublicPrefix(),n=t.startsWith("/")?t.slice(1):t,o=i?.overwrite!==!1,a=await this.http.post(`${r}/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(`${r}/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(),i=t.startsWith("/")?t.slice(1):t;return this.http.get(`${s}/storages/files/${e}/path/${i}`)}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(),i=new URLSearchParams;t?.limit!=null&&i.set("limit",String(t.limit)),t?.offset!=null&&i.set("offset",String(t.offset));let r=i.toString();return this.http.get(`${s}/storages/webs/${e}/page-metas${r?`?${r}`:""}`)}async getPageMeta(e,t){let s=this.getPublicPrefix(),i=encodeURIComponent(t);return this.http.get(`${s}/storages/webs/${e}/page-metas/get?path=${i}`)}async deletePageMeta(e,t){let s=this.getPublicPrefix(),i=encodeURIComponent(t);await this.http.delete(`${s}/storages/webs/${e}/page-metas?path=${i}`)}async deleteAllPageMetas(e){let t=this.getPublicPrefix();await this.http.delete(`${t}/storages/webs/${e}/page-metas/all`)}};var U=class{constructor(e){this.http=e}async getPublicKeys(e){return this.http.get(`/v1/apps/${e}/public-keys`)}async createPublicKey(e,t){return this.http.post(`/v1/apps/${e}/public-keys`,t)}async updatePublicKey(e,t,s){return this.http.patch(`/v1/apps/${e}/public-keys/${t}`,s)}async deletePublicKey(e,t){await this.http.delete(`/v1/apps/${e}/public-keys/${t}`)}};var q=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasPublicKey()?"/v1/public":"/v1"}async invoke(e,t,s){let i=this.getPublicPrefix(),r={};return t!==void 0&&(r.payload=t),s!==void 0&&(r.timeout=s),this.http.post(`${i}/functions/${e}/invoke`,r)}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(),i=await this.sendRequest({category:e,action:"subscribe",request_id:s}),r={category:i.category,persist:i.persist,historyCount:i.history_count,readReceipt:i.read_receipt},n=[];return this.subscriptions.set(e,{info:r,handlers:n}),{info:r,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 r=s.includeSelf!==!1,n=this.generateRequestId();await this.sendRequest({category:e,action:"send",data:{data:t,broadcast:r},request_id:n})}async getHistory(e,t){if(this.state!=="connected")throw new Error("Not connected");let s=this.generateRequestId(),i=await this.sendRequest({category:e,action:"history",data:t?{limit:t}:void 0,request_id:s});return{category:i.category,messages:i.messages.map(r=>({id:r.id,category:r.category,from:r.from,data:r.data,sentAt:r.sent_at})),total:i.total}}async stream(e,t,s={}){if(this.state!=="connected")throw new Error("Not connected. Call connect() first.");let i=this.generateRequestId(),r=s.sessionId||this.generateRequestId();this.streamSessions.set(r,{handlers:t,requestId:i});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:r,metadata:s.metadata,mcp_group:s.mcpGroup},request_id:i})}catch(n){throw this.streamSessions.delete(r),n}return{sessionId:r,stop:async()=>{await this.stopStream(r)}}}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}),i={};for(let[r,n]of Object.entries(s.users))i[r]={userId:n.user_id,status:n.status,lastSeen:n.last_seen,device:n.device,metadata:n.metadata};return{users:i}}async subscribePresence(e,t){if(this.state!=="connected")throw new Error("Not connected");if(!this.presenceSubscriptions.has(e)){let i=this.generateRequestId();await this.sendRequest({category:"",action:"presence_subscribe",data:{user_id:e},request_id:i}),this.presenceSubscriptions.set(e,[])}let s=this.presenceSubscriptions.get(e);return s.push(t),()=>{let i=s.indexOf(t);if(i>-1&&s.splice(i,1),s.length===0&&(this.presenceSubscriptions.delete(e),this.state==="connected")){let r=this.generateRequestId();this.sendRequest({category:"",action:"presence_unsubscribe",data:{user_id:e},request_id:r}).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 i=this.generateRequestId();await this.sendRequest({category:"",action:"typing_subscribe",data:{room_id:e},request_id:i}),this.typingHandlers.set(e,[])}let s=this.typingHandlers.get(e);return s.push(t),()=>{let i=s.indexOf(t);if(i>-1&&s.splice(i,1),s.length===0&&(this.typingHandlers.delete(e),this.state==="connected")){let r=this.generateRequestId();this.sendRequest({category:"",action:"typing_unsubscribe",data:{room_id:e},request_id:r}).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 i=s.indexOf(t);i>-1&&s.splice(i,1)}}async doConnect(){return new Promise((e,t)=>{this.state="connecting",this.notifyStateChange(),this.log("Connecting...");let s=this.socketUrl.replace(/^http/,"ws"),i;if(this.options.accessToken)i=`${s}/v1/realtime/auth?access_token=${encodeURIComponent(this.options.accessToken)}&client_id=${this.clientId}`,this.log("Using accessToken authentication");else{let o=this.http.getPublicKey();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}i=`${s}/v1/realtime/auth?public_key=${encodeURIComponent(o)}&client_id=${this.clientId}`,this.log("Using API Key authentication")}this.userId&&(i+=`&user_id=${encodeURIComponent(this.userId)}`);let r=!1,n=setTimeout(()=>{r||(r=!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(i),this.ws.onopen=()=>{this.log("WebSocket opened, waiting for connected event...")},this.ws.onmessage=o=>{let a=o.data.split(`
|
|
2
2
|
`).filter(c=>c.trim());for(let c of a)try{let d=JSON.parse(c);this.handleServerMessage(d,()=>{r||(r=!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}`),!r&&this.state==="connecting"&&(r=!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")),!r&&this.state==="connecting"&&(r=!0,clearTimeout(n),t(new Error("Failed to connect")))}}catch(o){r=!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,i=this.subscriptions.get(s.category);if(i){let r={id:s.id,category:s.category,from:s.from,data:s.data,sentAt:s.sent_at};i.handlers.forEach(n=>n(r))}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,i=this.streamSessions.get(s.session_id);i?.handlers.onToken&&i.handlers.onToken(s.token,s.index);break}case"stream_done":{let s=e.data,i=this.streamSessions.get(s.session_id);i?.handlers.onDone&&i.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_tool_call":{let s=e.data,i=this.streamSessions.get(s.session_id);i?.handlers.onToolCall&&i.handlers.onToolCall(s.tool_name,s.arguments||{},s.index);break}case"stream_tool_result":{let s=e.data,i=this.streamSessions.get(s.session_id);i?.handlers.onToolResult&&i.handlers.onToolResult(s.tool_name,s.success,s.duration_ms,s.index);break}case"stream_error":{let s=e.data;if(e.request_id){for(let[i,r]of this.streamSessions)if(r.requestId===e.request_id){r.handlers.onError&&r.handlers.onError(new Error(s.message)),this.streamSessions.delete(i);break}}break}case"presence":case"presence_status":{let s=e.data,i={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(i));let r=this.presenceSubscriptions.get(s.user_id);if(r&&r.forEach(n=>n(i)),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,i={roomId:s.room_id,users:s.users},r=this.typingHandlers.get(s.room_id);r&&r.forEach(n=>n(i));break}case"read_receipt":{let s=e.data,i={category:s.category,messageIds:s.message_ids,readerId:s.reader_id,readAt:s.read_at},r=this.readReceiptHandlers.get(s.category);r&&r.forEach(n=>n(i));break}}}handleDisconnect(){this.ws=null,this._connectionId=null,this.streamSessions.forEach(i=>{i.handlers.onError&&i.handlers.onError(new Error("Connection lost"))}),this.streamSessions.clear();let e=new Map;for(let[i,r]of this.subscriptions)e.set(i,[...r.handlers]);this.subscriptions.clear();let t=new Map;for(let[i,r]of this.presenceSubscriptions)t.set(i,[...r]);this.presenceSubscriptions.clear();let s=new Map;for(let[i,r]of this.typingHandlers)s.set(i,[...r]);if(this.typingHandlers.clear(),this.retryCount<this.options.maxRetries){this.state="reconnecting",this.notifyStateChange(),this.retryCount++;let i=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(r){console.error("[Realtime] Reconnect failed:",r)}},i)}else this.state="disconnected",this.notifyStateChange(),this.notifyError(new Error("Connection lost. Max retries exceeded."))}async restoreSubscriptions(e,t,s){for(let[i,r]of e)try{this.log(`Restoring subscription: ${i}`);let n=this.generateRequestId(),o=await this.sendRequest({category:i,action:"subscribe",request_id:n}),a={category:o.category,persist:o.persist,historyCount:o.history_count,readReceipt:o.read_receipt};this.subscriptions.set(i,{info:a,handlers:r}),this.log(`Restored subscription: ${i}`)}catch(n){console.error(`[Realtime] Failed to restore subscription for ${i}:`,n),this.notifyError(new Error(`Failed to restore subscription: ${i}`))}for(let[i,r]of t)try{this.log(`Restoring presence subscription: ${i}`);let n=this.generateRequestId();await this.sendRequest({category:"",action:"presence_subscribe",data:{user_id:i},request_id:n}),this.presenceSubscriptions.set(i,r),this.log(`Restored presence subscription: ${i}`)}catch(n){console.error(`[Realtime] Failed to restore presence subscription for ${i}:`,n)}for(let[i,r]of s)try{this.log(`Restoring typing subscription: ${i}`);let n=this.generateRequestId();await this.sendRequest({category:"",action:"typing_subscribe",data:{room_id:i},request_id:n}),this.typingHandlers.set(i,r),this.log(`Restored typing subscription: ${i}`)}catch(n){console.error(`[Realtime] Failed to restore typing subscription for ${i}:`,n)}}sendRequest(e){return new Promise((t,s)=>{if(!this.ws||this.ws.readyState!==WebSocket.OPEN){s(new Error("Not connected"));return}let i=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:i}),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 H=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(){if(!this.appId)throw new Error("WebRTC getICEServers \uC5D0\uB294 appId \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. ConnectBase \uCD08\uAE30\uD654 \uC2DC appId \uB97C \uC124\uC815\uD558\uC138\uC694.");let e=await this.http.get(`/v1/apps/${this.appId}/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 i=setTimeout(()=>{this.state==="connecting"&&(this.ws?.close(),t(new Error("\uC5F0\uACB0 \uC2DC\uAC04 \uCD08\uACFC")))},1e4);this.ws.onopen=()=>{clearTimeout(i),this.reconnectAttempts=0,this.sendSignaling({type:"join",room_id:this.currentRoomId,data:{user_id:this.currentUserId,is_broadcaster:this.isBroadcaster}})},this.ws.onmessage=async r=>{try{let n=JSON.parse(r.data);await this.handleSignalingMessage(n,e,t)}catch(n){console.error("Failed to parse signaling message:",n)}},this.ws.onerror=r=>{clearTimeout(i),console.error("WebSocket error:",r),this.emitError(new Error("WebSocket \uC5F0\uACB0 \uC624\uB958"))},this.ws.onclose=r=>{clearTimeout(i),this.state==="connecting"&&t(new Error("\uC5F0\uACB0\uC774 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4")),this.handleDisconnect(r)}})}buildWebSocketUrl(){let e=this.webrtcUrl.replace("https://","wss://").replace("http://","ws://"),t=this.http.getPublicKey(),s=this.http.getAccessToken(),i="";if(s?i=`access_token=${encodeURIComponent(s)}`:t&&(i=`public_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?${i}`}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 i=typeof e.data=="string"?e.data:"Unknown error",r=new Error(i);this.emitError(r),s?.(r);break}}async createPeerConnection(e,t){this.closePeerConnection(e);let s={iceServers:this.iceServers.map(r=>({urls:r.urls,username:r.username,credential:r.credential}))},i=new RTCPeerConnection(s);if(this.peerConnections.set(e,i),this.localStream&&this.localStream.getTracks().forEach(r=>{i.addTrack(r,this.localStream)}),i.onicecandidate=r=>{r.candidate&&this.sendSignaling({type:"ice_candidate",target_id:e,candidate:r.candidate.toJSON()})},i.ontrack=r=>{let[n]=r.streams;n&&(this.remoteStreams.set(e,n),this.emitRemoteStream(e,n))},i.onconnectionstatechange=()=>{i.connectionState==="failed"&&(console.warn(`Peer connection failed: ${e}`),this.closePeerConnection(e))},t){let r=await i.createOffer();await i.setLocalDescription(r),this.sendSignaling({type:"offer",target_id:e,sdp:r.sdp})}return i}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 i=await s.createAnswer();await s.setLocalDescription(i),this.sendSignaling({type:"answer",target_id:e,sdp:i.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(i){console.warn("Failed to add ICE candidate:",i)}}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,i)=>{s.close(),this.emitPeerLeft(i)}),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(i=>{let r=s.find(n=>n.track?.kind===i.kind);r?r.replaceTrack(i):t.addTrack(i,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}/stats`)}async getRooms(e){return this.http.get(`/v1/apps/${e}/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,i,r)=>(this.handleGlobalError(e,t,s,i,r),this.originalOnError?this.originalOnError(e,t,s,i,r):!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,i,r){let n={message:typeof e=="string"?e:e.type||"Unknown error",source:t||void 0,lineno:s||void 0,colno:i||void 0,stack:r?.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",i;t instanceof Error?(s=t.message,i=t.stack):typeof t=="string"?s=t:t&&typeof t=="object"&&(s=JSON.stringify(t));let r={message:s,stack:i,error_type:"unhandledrejection",url:typeof window<"u"?window.location.href:void 0,referrer:typeof document<"u"?document.referrer:void 0};this.queueError(r)}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 i=this.config.beforeSend(s);return i===!1||i===null?(this.log("Error filtered out by beforeSend"),null):i}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 i=new URLSearchParams({app_callback:t});s&&i.append("state",s);let r=await this.http.get(`/v1/public/oauth/${e}/authorize/central?${i.toString()}`);window.location.href=r.authorization_url}async signInWithPopup(e,t){let s=new URLSearchParams;t&&s.set("app_callback",t);let i=s.toString(),r=await this.http.get(`/v1/public/oauth/${e}/authorize/central${i?"?"+i:""}`),n=500,o=600,a=window.screenX+(window.outerWidth-n)/2,c=window.screenY+(window.outerHeight-o)/2,d=window.open(r.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((h,p)=>{let g=!1,y=()=>{g=!0,window.removeEventListener("message",b),clearInterval(m),clearTimeout(w)},b=async u=>{if(u.data?.type!=="oauth-callback"||g)return;if(y(),u.data.error){p(new Error(u.data.error));return}let v={member_id:u.data.member_id,access_token:u.data.access_token,refresh_token:u.data.refresh_token,is_new_member:u.data.is_new_member==="true"||u.data.is_new_member===!0};this.http.setTokens(v.access_token,v.refresh_token),h(v)};window.addEventListener("message",b);let m=setInterval(()=>{try{d.closed&&(g||(y(),p(new Error("\uB85C\uADF8\uC778\uC774 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."))))}catch{clearInterval(m)}},500),w=setTimeout(()=>{if(!g){y();try{d.close()}catch{}p(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"),i=e.get("refresh_token"),r=e.get("member_id");if(!s||!i||!r)return null;let n={access_token:s,refresh_token:i,member_id:r,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,i),n)}async exchangeCodeFromCallback(){let e=new URLSearchParams(window.location.search),t=e.get("code");if(!t||e.get("error"))return null;let s=await this.http.post("/v1/auth/oauth/exchange",{code:t}),i={access_token:s.access_token,refresh_token:s.refresh_token,member_id:s.member_id,is_new_member:s.is_new_member,state:e.get("state")||void 0};return window.opener?(window.opener.postMessage({type:"oauth-callback",...i},"*"),window.close(),i):(this.http.setTokens(i.access_token,i.refresh_token),i)}};var L=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasPublicKey()?"/v1/public":"/v1"}async prepare(e){let t=this.getPublicPrefix();return this.http.post(`${t}/payments/prepare`,e)}async createCheckoutSession(e){let t=this.getPublicPrefix();return this.http.post(`${t}/payments/checkout-session`,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 B=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasPublicKey()?"/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 i=s.toString();return this.http.get(`${t}/subscriptions${i?"?"+i:""}`)}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(),i=new URLSearchParams;t?.status&&i.set("status",t.status),t?.limit&&i.set("limit",String(t.limit)),t?.offset&&i.set("offset",String(t.offset));let r=i.toString();return this.http.get(`${s}/subscriptions/${e}/payments${r?"?"+r:""}`)}async chargeWithBillingKey(e){let t=this.getPublicPrefix();return this.http.post(`${t}/subscriptions/charge`,e)}};var F=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasPublicKey()?"/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 subscribeTopic(e,t){let s=this.getPublicPrefix(),i={topic_name:t};await this.http.post(`${s}/push/devices/${e}/topics/subscribe`,i)}async unsubscribeTopic(e,t){let s=this.getPublicPrefix();await this.http.delete(`${s}/push/devices/${e}/topics/${t}/unsubscribe`)}async getVAPIDPublicKey(){let e=this.getPublicPrefix();return this.http.get(`${e}/push/vapid-public-key`)}async registerWebPush(e){let t=this.getPublicPrefix(),s;if("toJSON"in e){let r=e.toJSON();s={endpoint:r.endpoint||"",expirationTime:r.expirationTime,keys:{p256dh:r.keys?.p256dh||"",auth:r.keys?.auth||""}}}else s=e;let i={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`,{...i,web_push_subscription:s})}async unregisterWebPush(e){let t=this.getPublicPrefix();await this.http.delete(`${t}/push/devices/${encodeURIComponent(e)}`)}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 re=5*1024*1024,S=class extends Error{constructor(e,t){super(e),this.name="VideoProcessingError",this.video=t}},N=class{constructor(e,t){this.http=e;this.storage={create:async e=>this.http.post("/v1/public/storages/videos",e),list:async()=>this.http.get("/v1/public/storages/videos"),get:async e=>this.http.get(`/v1/public/storages/videos/${e}`),update:async(e,t)=>this.http.put(`/v1/public/storages/videos/${e}`,t),delete:async e=>{await this.http.delete(`/v1/public/storages/videos/${e}`)},upload:async(e,t,s)=>{let i=await this.http.post(`/v1/public/storages/videos/${e}/uploads/init`,{filename:t.name,size:t.size,mime_type:t.type,title:s.title,description:s.description,visibility:s.visibility||"private",tags:s.tags}),r=i.chunk_size||re,n=Math.ceil(t.size/r),o=0,a=Date.now(),c=0;for(let h=0;h<n;h++){let p=h*r,g=Math.min(p+r,t.size),y=t.slice(p,g),b=new FormData;b.append("chunk",y),b.append("chunk_index",String(h)),await this.http.post(`/v1/public/storages/videos/${e}/uploads/${i.session_id}/chunk`,b),o++;let m=Date.now(),w=(m-a)/1e3,u=g,v=u-c,Q=w>0?v/w:0;a=m,c=u,s.onProgress&&s.onProgress({phase:"uploading",uploadedChunks:o,totalChunks:n,percentage:Math.round(o/n*100),currentSpeed:Q})}return(await this.http.post(`/v1/public/storages/videos/${e}/uploads/${i.session_id}/complete`,{})).video},listVideos:async(e,t)=>{let s=new URLSearchParams;t?.status&&s.set("status",t.status),t?.visibility&&s.set("visibility",t.visibility),t?.search&&s.set("search",t.search),t?.page&&s.set("page",String(t.page)),t?.limit&&s.set("limit",String(t.limit));let i=s.toString();return this.http.get(`/v1/public/storages/videos/${e}/videos${i?`?${i}`:""}`)},getVideo:async(e,t)=>this.http.get(`/v1/public/storages/videos/${e}/videos/${t}`),deleteVideo:async(e,t)=>{await this.http.delete(`/v1/public/storages/videos/${e}/videos/${t}`)},getStreamUrl:async(e,t)=>this.http.get(`/v1/public/storages/videos/${e}/videos/${t}/stream`),getTranscodeStatus:async(e,t)=>this.http.get(`/v1/public/storages/videos/${e}/videos/${t}/transcode`)};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.hasPublicKey()?"/v1/public":"/v1"}async videoFetch(e,t,s){let i={},r=this.http.getPublicKey();r&&(i["X-Public-Key"]=r);let n=this.http.getAccessToken();n&&(i.Authorization=`Bearer ${n}`),s&&!(s instanceof FormData)&&(i["Content-Type"]="application/json");let o=await fetch(`${this.videoBaseUrl}${t}`,{method:e,headers:i,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 f(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(),i=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}),r=i.chunk_size||re,n=Math.ceil(e.size/r),o=0,c=Date.now(),d=0;for(let p=0;p<n;p++){let g=p*r,y=Math.min(g+r,e.size),b=e.slice(g,y),m=new FormData;m.append("chunk",b),m.append("chunk_index",String(p)),await this.videoFetch("POST",`${s}/uploads/${i.session_id}/chunks`,m),o++;let w=Date.now(),u=(w-c)/1e3,v=y,Q=v-d,ae=u>0?Q/u:0;c=w,d=v,t.onProgress&&t.onProgress({phase:"uploading",uploadedChunks:o,totalChunks:n,percentage:Math.round(o/n*100),currentSpeed:ae})}return(await this.videoFetch("POST",`${s}/uploads/${i.session_id}/complete`,{})).video}async waitForReady(e,t){let s=t?.timeout||18e5,i=t?.interval||5e3,r=Date.now(),n=this.getPublicPrefix();for(;Date.now()-r<s;){let o=await this.videoFetch("GET",`${n}/videos/${e}`);if(o.status==="ready")return o;if(o.status==="failed")throw new S("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,i))}throw new S("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 i=s.toString();return this.videoFetch("GET",`${t}/videos${i?`?${i}`:""}`)}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(),i=t?`?quality=${t}`:"";return this.videoFetch("GET",`${s}/videos/${e}/stream-url${i}`)}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 i=this.getPublicPrefix();return this.videoFetch("POST",`${i}/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 i=s.toString();return this.videoFetch("GET",`${t}/shorts${i?`?${i}`:""}`)}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(),i=new URLSearchParams;t?.cursor&&i.set("cursor",t.cursor),t?.limit&&i.set("limit",String(t.limit)),t?.sort&&i.set("sort",t.sort);let r=i.toString();return this.videoFetch("GET",`${s}/videos/${e}/comments${r?`?${r}`:""}`)}async postComment(e,t,s){let i=this.getPublicPrefix();return this.videoFetch("POST",`${i}/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 i=s.toString();return this.videoFetch("GET",`${t}/watch-history${i?`?${i}`:""}`)}async clearWatchHistory(){let e=this.getPublicPrefix();await this.videoFetch("DELETE",`${e}/watch-history`)}async reportWatchProgress(e,t,s){let i=this.getPublicPrefix();await this.videoFetch("POST",`${i}/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,i){let r=this.getPublicPrefix();return this.videoFetch("POST",`${r}/videos/${e}/super-chats`,{amount:t,message:s,currency:i||"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(),i=t?`?limit=${t}`:"";return(await this.videoFetch("GET",`${s}/recommendations/related/${e}${i}`)).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 ne=()=>{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"},I=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:ne(),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 i=this.buildConnectionUrl(e);this.ws=new WebSocket(i);let r=()=>{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",r,{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 i=r=>{if(r.type==="room_created"){let n=r.data;return this._roomId=n.room_id,this._state=n.initial_state,t(n.initial_state),!0}else if(r.type==="error")return s(new Error(r.data.message)),!0;return!1};this.sendWithHandler("create_room",e,i,15e3,s)})}joinRoom(e,t){return new Promise((s,i)=>{let r=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 i(new Error(n.data.message)),!0;return!1};this.sendWithHandler("join_room",{room_id:e,metadata:t},r,15e3,i)})}leaveRoom(){return new Promise((e,t)=>{if(!this._roomId){t(new Error("Not in a room"));return}let s=i=>i.type==="room_left"?(this._roomId=null,this._state=null,e(),!0):i.type==="error"?(t(new Error(i.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=i=>{if(i.type==="state"){let r=i.data;return this._state=r,e(r),!0}else if(i.type==="error")return t(new Error(i.data.message)),!0;return!1};this.sendWithHandler("get_state",{},s,15e3,t)})}listRooms(){return new Promise((e,t)=>{let s=i=>{if(i.type==="room_list"){let r=i.data;return e(r.rooms),!0}else if(i.type==="error")return t(new Error(i.data.message)),!0;return!1};this.sendWithHandler("list_rooms",{},s,15e3,t)})}ping(){return new Promise((e,t)=>{let s=Date.now(),i=r=>{if(r.type==="pong"){let n=r.data,o=Date.now()-n.clientTimestamp;return this.handlers.onPong?.(n),e(o),!0}else if(r.type==="error")return t(new Error(r.data.message)),!0;return!1};this.sendWithHandler("ping",{timestamp:s},i,15e3,t)})}buildConnectionUrl(e){let s=this.config.gameServerUrl.replace(/^http/,"ws"),i=new URLSearchParams;i.set("client_id",this.config.clientId),e&&i.set("room_id",e),this.config.publicKey&&i.set("public_key",this.config.publicKey),this.config.accessToken&&i.set("token",this.config.accessToken);let r=this.config.appId||"";return`${s}/v1/game/${r}/ws?${i.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,i=15e3,r){let n=`${e}-${++this.msgIdCounter}`,o=null,a=()=>{this.ws?.removeEventListener("message",c),o&&(clearTimeout(o),o=null)},c=d=>{try{let h=JSON.parse(d.data);if(h.msg_id&&h.msg_id!==n)return;s(h)&&a()}catch{}};this.ws?.addEventListener("message",c),o=setTimeout(()=>{a();let d=new Error(`Request '${e}' timed out after ${i}ms`);r?.(d),this.handlers.onError?.({code:"TIMEOUT",message:d.message})},i);try{this.send(e,t,n)}catch(d){a();let h=d instanceof Error?d:new Error(String(d));r?.(h)}}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(i=>({path:i.path,operation:i.operation,value:i.value,oldValue:i.old_value})),tick:t.tick};if(this._state){for(let i of s.changes)this.applyChange(i);this._state.version=s.toVersion}if(this.handlers.onAction){for(let i of s.changes)if(i.path.startsWith("actions.")&&i.operation==="set"&&i.value){let r=i.value;this.handlers.onAction({type:r.type||"",clientId:r.client_id||"",data:r.data,timestamp:r.timestamp||0})}}this.handlers.onDelta?.(s)}applyChange(e){if(!this._state)return;let t=e.path.split("."),s=this._state.state;for(let r=0;r<t.length-1;r++){let n=t[r];n in s||(s[n]={}),s=s[n]}let i=t[t.length-1];e.operation==="delete"?delete s[i]:s[i]=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(i){console.error(`Failed to rejoin room ${s}:`,i),this.handlers.onError?.({code:"REJOIN_FAILED",message:`Failed to rejoin room: ${i}`})}}}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||ne().replace(/^ws/,"http"),this.appId=s}createClient(e){return new I({...e,gameServerUrl:this.gameServerUrl.replace(/^http/,"ws"),appId:this.appId,publicKey:this.http.getPublicKey(),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={}){throw new Error("cb.game.createRoom is not yet publicly available \u2014 use the admin console or request a backend public route.")}async deleteRoom(e){throw new Error("cb.game.deleteRoom is not yet publicly available \u2014 use the admin console or request a backend public route.")}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 r=await s.json().catch(()=>({}));throw new Error(r.error||`Failed to join queue: ${s.statusText}`)}let i=await s.json();return{ticketId:i.ticket_id,gameType:i.game_type,playerId:i.player_id,status:i.status,createdAt:i.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 i=await s.json().catch(()=>({}));throw new Error(i.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 i=await fetch(`${this.gameServerUrl}/v1/game/${t}/matchmaking/status?${s}`,{headers:this.getHeaders()});if(!i.ok){let n=await i.json().catch(()=>({}));throw new Error(n.error||`Failed to get match status: ${i.statusText}`)}let r=await i.json();return{ticketId:r.ticket_id,gameType:r.game_type,playerId:"",status:r.status,createdAt:"",waitTime:r.wait_time,matchId:r.match_id,roomId:r.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(i=>({id:i.id,name:i.name,hostId:i.host_id,gameType:i.game_type,playerCount:i.player_count,maxPlayers:i.max_players,hasPassword:i.has_password,visibility:i.visibility,region:i.region,settings:i.settings,tags:i.tags,status:i.status,createdAt:i.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 r=await s.json().catch(()=>({}));throw new Error(r.error||`Failed to create lobby: ${s.statusText}`)}let i=await s.json();return{id:i.id,name:i.name,hostId:i.host_id,gameType:i.game_type,playerCount:1,maxPlayers:i.max_players,hasPassword:!!e.password,visibility:i.visibility,region:i.region,settings:i.settings,tags:i.tags,status:i.status,createdAt:i.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 i=await s.json();return{id:i.id,name:i.name,hostId:i.host_id,gameType:i.game_type,playerCount:i.player_count,maxPlayers:i.max_players,hasPassword:i.has_password,visibility:i.visibility,region:i.region,settings:i.settings,tags:i.tags,status:i.status,roomId:i.room_id,members:(i.members||[]).map(r=>({playerId:r.player_id,displayName:r.display_name,role:r.role,team:r.team,ready:r.ready,slot:r.slot,joinedAt:r.joined_at})),createdAt:i.created_at}}async joinLobby(e,t,s,i){let r=this.appId||"",n=await fetch(`${this.gameServerUrl}/v1/game/${r}/lobbies/${e}/join`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,display_name:s,password:i})});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||"",i=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(!i.ok){let r=await i.json().catch(()=>({}));throw new Error(r.error||`Failed to leave lobby: ${i.statusText}`)}}async toggleReady(e,t,s){let i=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${i}/lobbies/${e}/ready`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,ready:s})});if(!r.ok){let n=await r.json().catch(()=>({}));throw new Error(n.error||`Failed to toggle ready: ${r.statusText}`)}}async startGame(e,t){let s=this.appId||"",i=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(!i.ok){let n=await i.json().catch(()=>({}));throw new Error(n.error||`Failed to start game: ${i.statusText}`)}return{roomId:(await i.json()).room_id}}async kickPlayer(e,t,s){let i=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${i}/lobbies/${e}/kick/${s}`,{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 kick player: ${r.statusText}`)}}async updateLobby(e,t){let s=this.appId||"",i=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(!i.ok){let n=await i.json().catch(()=>({}));throw new Error(n.error||`Failed to update lobby: ${i.statusText}`)}let r=await i.json();return{id:r.id,name:r.name,hostId:"",gameType:"",playerCount:0,maxPlayers:r.max_players,hasPassword:!1,visibility:r.visibility,region:"",settings:r.settings,tags:r.tags,status:"",createdAt:""}}async sendLobbyChat(e,t,s){let i=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${i}/lobbies/${e}/chat`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,message:s})});if(!r.ok){let n=await r.json().catch(()=>({}));throw new Error(n.error||`Failed to send chat: ${r.statusText}`)}}async invitePlayer(e,t,s){let i=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${i}/lobbies/${e}/invite`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({inviter_id:t,invitee_id:s})});if(!r.ok){let o=await r.json().catch(()=>({}));throw new Error(o.error||`Failed to invite player: ${r.statusText}`)}let n=await r.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 i=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${i}/lobbies/invites/${e}/accept`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t,display_name:s})});if(!r.ok){let o=await r.json().catch(()=>({}));throw new Error(o.error||`Failed to accept invite: ${r.statusText}`)}return{lobbyId:(await r.json()).lobby_id}}async declineInvite(e,t){let s=this.appId||"",i=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(!i.ok){let r=await i.json().catch(()=>({}));throw new Error(r.error||`Failed to decline invite: ${i.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(r=>({inviteId:r.invite_id,lobbyId:r.lobby_id,lobbyName:r.lobby_name,inviterId:r.inviter_id,inviteeId:"",status:r.status,createdAt:r.created_at,expiresAt:r.expires_at}))}async createParty(e,t){let s=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${s}/parties`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:e,max_size:t||4})});if(!i.ok)throw new Error(`Failed to create party: ${i.statusText}`);return i.json()}async joinParty(e,t){throw new Error("cb.game.joinParty is not supported \u2014 use inviteToParty + acceptPartyInvite flow.")}async acceptPartyInvite(e,t,s){let i=this.appId||"",r=new URLSearchParams({player_id:t});s&&r.set("display_name",s);let n=await fetch(`${this.gameServerUrl}/v1/game/${i}/invites/${e}/accept?${r.toString()}`,{method:"POST",headers:this.getHeaders()});if(!n.ok){let o=await n.json().catch(()=>({}));throw new Error(o.error||`Failed to accept party invite: ${n.statusText}`)}return n.json()}async declinePartyInvite(e,t){let s=this.appId||"",i=new URLSearchParams({player_id:t}),r=await fetch(`${this.gameServerUrl}/v1/game/${s}/invites/${e}/decline?${i.toString()}`,{method:"POST",headers:this.getHeaders()});if(!r.ok){let n=await r.json().catch(()=>({}));throw new Error(n.error||`Failed to decline party invite: ${r.statusText}`)}}async leaveParty(e,t){let s=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${s}/parties/${e}/leave`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t})});if(!i.ok)throw new Error(`Failed to leave party: ${i.statusText}`)}async kickFromParty(e,t){let s=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${s}/parties/${e}/kick/${t}`,{method:"POST",headers:this.getHeaders()});if(!i.ok)throw new Error(`Failed to kick from party: ${i.statusText}`)}async inviteToParty(e,t,s){let i=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${i}/parties/${e}/invite/${s}`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({inviter_id:t})});if(!r.ok)throw new Error(`Failed to invite to party: ${r.statusText}`);return r.json()}async sendPartyChat(e,t,s){let i=this.appId||"",r=await fetch(`${this.gameServerUrl}/v1/game/${i}/parties/${e}/chat`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({sender_id:t,content:s})});if(!r.ok)throw new Error(`Failed to send party chat: ${r.statusText}`)}async joinSpectator(e,t){let s=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${s}/rooms/${e}/spectators`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t})});if(!i.ok)throw new Error(`Failed to join spectator: ${i.statusText}`);return i.json()}async leaveSpectator(e,t){let s=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${s}/rooms/${e}/spectators/${t}`,{method:"DELETE",headers:this.getHeaders()});if(!i.ok)throw new Error(`Failed to leave spectator: ${i.statusText}`)}async getSpectators(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/rooms/${e}/spectators`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to get spectators: ${s.statusText}`);return(await s.json()).spectators||[]}async getLeaderboard(e,t=100,s="default"){let i=this.appId||"",r=new URLSearchParams({app_id:i,game_type:e,season:s,limit:String(t)}),n=await fetch(`${this.gameServerUrl}/v1/game/${i}/ranking/leaderboard/top?${r}`,{headers:this.getHeaders()});if(!n.ok)throw new Error(`Failed to get leaderboard: ${n.statusText}`);return(await n.json()).entries||[]}async getPlayerStats(e,t,s="default"){let i=this.appId||"",r=new URLSearchParams({app_id:i,game_type:t,season:s}),n=await fetch(`${this.gameServerUrl}/v1/game/${i}/ranking/players/${e}/stats?${r}`,{headers:this.getHeaders()});if(!n.ok)throw new Error(`Failed to get player stats: ${n.statusText}`);return n.json()}async getPlayerRank(e,t,s="default"){let i=this.appId||"",r=new URLSearchParams({app_id:i,game_type:t,season:s}),n=await fetch(`${this.gameServerUrl}/v1/game/${i}/ranking/players/${e}/rank?${r}`,{headers:this.getHeaders()});if(!n.ok)throw new Error(`Failed to get player rank: ${n.statusText}`);return n.json()}async joinVoiceChannel(e,t){let s=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${s}/voice/rooms/${e}/join`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t})});if(!i.ok)throw new Error(`Failed to join voice channel: ${i.statusText}`);return i.json()}async leaveVoiceChannel(e,t){let s=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${s}/voice/rooms/${e}/leave`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:t})});if(!i.ok)throw new Error(`Failed to leave voice channel: ${i.statusText}`)}async setMute(e,t){let s=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${s}/voice/mute`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({player_id:e,muted:t})});if(!i.ok)throw new Error(`Failed to set mute: ${i.statusText}`)}async listReplays(e){let t=this.appId||"",s=`${this.gameServerUrl}/v1/game/${t}/replays`;e&&(s+=`?room_id=${e}`);let i=await fetch(s,{headers:this.getHeaders()});if(i.status===404)throw new Error("cb.game.listReplays: replay storage is not configured on this server (REPLAY_STORAGE_PATH unset).");if(!i.ok)throw new Error(`Failed to list replays: ${i.statusText}`);return(await i.json()).replays||[]}async getReplay(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/replays/${e}`,{headers:this.getHeaders()});if(s.status===404)throw new Error("cb.game.getReplay: replay not found or replay storage unconfigured.");if(!s.ok)throw new Error(`Failed to get replay: ${s.statusText}`);return s.json()}async downloadReplay(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/replays/${e}/download`,{headers:this.getHeaders()});if(s.status===404)throw new Error("cb.game.downloadReplay: replay not found or replay storage unconfigured.");if(!s.ok)throw new Error(`Failed to download replay: ${s.statusText}`);return s.arrayBuffer()}async getReplayHighlights(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/replays/${e}/highlights`,{headers:this.getHeaders()});if(s.status===404)throw new Error("cb.game.getReplayHighlights: replay not found or replay storage unconfigured.");if(!s.ok)throw new Error(`Failed to get highlights: ${s.statusText}`);return(await s.json()).highlights||[]}getHeaders(){let e={},t=this.http.getPublicKey();t&&(e["X-Public-Key"]=t);let s=this.http.getAccessToken();return s&&(e.Authorization=`Bearer ${s}`),e}};var _=class{constructor(e){this.http=e}getPublicPrefix(){return this.http.hasPublicKey()?"/v1/public":"/v1"}async getConnectionStatus(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/connection`)}async getReport(e,t){let s=this.getPublicPrefix(),i=new URLSearchParams;e&&i.set("start",e),t&&i.set("end",t);let r=i.toString();return this.http.get(`${s}/ads/reports${r?`?${r}`:""}`)}async getReportSummary(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/reports/summary`)}async getAdMobReport(e,t){let s=this.getPublicPrefix(),i=new URLSearchParams;e&&i.set("start",e),t&&i.set("end",t);let r=i.toString();return this.http.get(`${s}/ads/admob/reports${r?`?${r}`:""}`)}async getAdMobReportSummary(){let e=this.getPublicPrefix();return this.http.get(`${e}/ads/admob/reports/summary`)}};var T=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(i=>new File([],i.split("/").pop()||"file"))}return new Promise(s=>{let i=document.createElement("input");i.type="file",e?.accept&&(i.accept=e.accept),e?.multiple&&(i.multiple=!0),i.onchange=()=>{s(i.files?Array.from(i.files):null)},i.click()})},saveFile:async(e,t,s)=>{let i=this.getPlatform();if(i==="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(i==="mobile"&&window.NativeBridge?.filesystem){let a=e instanceof Blob?await e.text():e;return(await window.NativeBridge.filesystem.writeFile(t,a)).success}let r=e instanceof Blob?e:new Blob([e],{type:"text/plain"}),n=URL.createObjectURL(r),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 i=document.createElement("input");i.type="file",i.accept="image/*",i.capture="environment",i.onchange=async()=>{let r=i.files?.[0];if(!r){s(null);return}let n=new FileReader;n.onload=()=>{let o=new Image;o.onload=()=>{s({uri:URL.createObjectURL(r),base64:e?.base64?n.result.split(",")[1]:void 0,width:o.width,height:o.height})},o.src=n.result},n.readAsDataURL(r)},i.click()}),pickImage:async e=>this.getPlatform()==="mobile"&&window.NativeBridge?.camera?window.NativeBridge.camera.pickImage(e):new Promise(s=>{let i=document.createElement("input");i.type="file",i.accept="image/*",e?.multiple&&(i.multiple=!0),i.onchange=async()=>{let r=i.files;if(!r?.length){s(null);return}let n=[];for(let o of Array.from(r)){let a=await new Promise(c=>{let d=new FileReader;d.onload=()=>{let h=new Image;h.onload=()=>{c({uri:URL.createObjectURL(o),base64:e?.base64?d.result.split(",")[1]:void 0,width:h.width,height:h.height})},h.src=d.result},d.readAsDataURL(o)});n.push(a)}s(n)},i.click()})};this.location={getCurrentPosition:async e=>this.getPlatform()==="mobile"&&window.NativeBridge?.location?window.NativeBridge.location.getCurrentPosition(e):new Promise((s,i)=>{navigator.geolocation.getCurrentPosition(r=>{s({latitude:r.coords.latitude,longitude:r.coords.longitude,altitude:r.coords.altitude,accuracy:r.coords.accuracy,timestamp:r.timestamp})},i,{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 G=class{constructor(e){this.http=e}async addDocument(e,t){return this.http.post(`/v1/public/knowledge-bases/${e}/documents`,t)}async listDocuments(e){return this.http.get(`/v1/public/knowledge-bases/${e}/documents`)}async deleteDocument(e,t){await this.http.delete(`/v1/public/knowledge-bases/${e}/documents/${t}`)}async search(e,t){return this.http.post(`/v1/public/knowledge-bases/${e}/search`,t)}async searchGet(e,t,s){let i=new URLSearchParams({query:t});return s&&i.append("top_k",String(s)),this.http.get(`/v1/public/knowledge-bases/${e}/search?${i.toString()}`)}};var k=class{constructor(e){this.http=e}async chat(e){return this.http.post("/v1/public/ai/chat",e)}async chatStream(e,t){let s=await this.http.fetchRaw("/v1/public/ai/chat/stream",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!s.ok){let o=await s.json().catch(()=>({error:"Stream request failed"}));t.onError?.(o.error||"Stream request failed");return}let i=s.body?.getReader();if(!i){t.onError?.("ReadableStream not supported");return}let r=new TextDecoder,n="";for(;;){let{done:o,value:a}=await i.read();if(o)break;n+=r.decode(a,{stream:!0});let c=n.split(`
|
|
3
3
|
`);n=c.pop()||"";for(let d of c){if(!d.startsWith("data: "))continue;let h=d.slice(6).trim();if(h==="[DONE]"){t.onDone?.();return}try{let p=JSON.parse(h);if(p.type==="sources"&&p.sources){t.onSources?.(p.sources);continue}if(p.type==="tool_start"||p.type==="tool_end"){t.onToolEvent?.({type:p.type,name:p.name,toolCallId:p.toolCallId,arguments:p.arguments,result:p.result,success:p.success,durationMs:p.durationMs});continue}if(p.type==="heartbeat"||p.type==="searching")continue;if(p.content&&t.onToken?.(p.content),p.done){t.onDone?.();return}}catch{}}}}};var W=class{constructor(e){this.http=e}async publish(e,t){return this.http.post(`/v1/public/queues/${e}/messages`,t)}async publishBatch(e,t){return this.http.post(`/v1/public/queues/${e}/messages/batch`,t)}async consume(e,t){let s=new URLSearchParams;t?.max_messages&&s.set("max_messages",String(t.max_messages)),t?.visibility_timeout&&s.set("visibility_timeout",String(t.visibility_timeout)),t?.auto_ack!==void 0&&s.set("auto_ack",String(t.auto_ack));let i=s.toString();return this.http.get(`/v1/public/queues/${e}/messages${i?`?${i}`:""}`)}async ack(e,t,s){let i={message_ids:t,ack_token:s};return this.http.post(`/v1/public/queues/${e}/messages/ack`,i)}async nack(e,t,s){return this.http.post(`/v1/public/queues/${e}/messages/${t}/nack`,s||{})}async getInfo(e){return this.http.get(`/v1/public/queues/${e}`)}};var me=1800*1e3,X="__cb_session",oe="__cb_visitor_uid",K="__cb_last_activity";function Z(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,l=>{let e=Math.random()*16|0;return(l==="x"?e:e&3|8).toString(16)})}var C=class{constructor(){this._sessionId=null;this._visitorUid=null;this._lastActivity=0;this._isNewSession=!1}get sessionId(){return this.ensureSession(),this._sessionId}get visitorUid(){return this._visitorUid||(this._visitorUid=this.loadOrCreateVisitorUid()),this._visitorUid}get isNewSession(){return this._isNewSession}touch(){this._lastActivity=Date.now(),this._isNewSession=!1;try{typeof sessionStorage<"u"&&sessionStorage.setItem(K,String(this._lastActivity))}catch{}}reset(){this._sessionId=null,this._isNewSession=!1;try{typeof sessionStorage<"u"&&(sessionStorage.removeItem(X),sessionStorage.removeItem(K))}catch{}}ensureSession(){let e=Date.now();if(!this._sessionId)try{if(typeof sessionStorage<"u"){this._sessionId=sessionStorage.getItem(X);let t=sessionStorage.getItem(K);this._lastActivity=t?parseInt(t,10):0}}catch{}if(!this._sessionId||this._lastActivity>0&&e-this._lastActivity>me){this._sessionId=Z(),this._isNewSession=!0,this._lastActivity=e;try{typeof sessionStorage<"u"&&(sessionStorage.setItem(X,this._sessionId),sessionStorage.setItem(K,String(e)))}catch{}}}loadOrCreateVisitorUid(){try{if(typeof localStorage<"u"){let e=localStorage.getItem(oe);if(e)return e;let t=Z();return localStorage.setItem(oe,t),t}}catch{}return Z()}};function fe(){if(typeof window>"u")return{};try{let l=new URLSearchParams(window.location.search),e={};for(let t of["utm_source","utm_medium","utm_campaign","utm_content","utm_term"]){let s=l.get(t);s&&(e[t]=s)}return e}catch{return{}}}var j=class{constructor(e){this.storageWebId=null;this.memberId=null;this.eventQueue=[];this.batchTimer=null;this.isInitialized=!1;this.heartbeatTimer=null;this.visibilityHandler=null;this.unloadHeartbeatHandler=null;this.popstateHandler=null;this.beforeUnloadHandler=null;this.origPushState=null;this.origReplaceState=null;this.heatmapClickHandler=null;this.heatmapScrollHandler=null;this.utm={};this.handleHeatmapClick=e=>{let t=e.clientX/window.innerWidth*100,s=e.clientY/window.innerHeight*100;this.recordHeatmapEvent("click",t,s)};this.heatmapQueue=[];this.http=e,this.config={trackPageViews:!0,trackEvents:!0,trackSessions:!0,heatmap:!1,recording:!1,batchSize:10,flushInterval:5e3,respectDoNotTrack:!0,debug:!1},this.consent={analytics:!0,heatmap:!1,recording:!1},this.session=new C}init(e,t){if(this.isInitialized){this.log("Analytics already initialized");return}if(typeof window>"u"){this.log("Analytics only works in browser environment");return}if(t?.respectDoNotTrack!==!1&&this.isDNT()){this.log("Do Not Track enabled, analytics disabled");return}this.storageWebId=e,Object.assign(this.config,t),this.isInitialized=!0,this.utm=fe(),this.config.trackSessions&&(this.trackSessionStart(),this.startHeartbeat()),this.config.trackPageViews&&(this.trackPageView(),this.setupAutoPageView()),this.startBatchTimer(),this.beforeUnloadHandler=()=>this.flushSync(),window.addEventListener("beforeunload",this.beforeUnloadHandler),this.log("Analytics initialized",{storageWebId:e})}destroy(){this.isInitialized&&(this.stopBatchTimer(),this.stopHeartbeat(),this.removeAutoPageView(),this.removeHeatmapListeners(),this.beforeUnloadHandler&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null),this.flush(),this.isInitialized=!1,this.log("Analytics destroyed"))}setConsent(e){Object.assign(this.consent,e),this.log("Consent updated",e),e.analytics===!1&&this.isInitialized&&this.destroy()}getConsent(){return{...this.consent}}trackPageView(e){if(!this.canTrack())return;this.session.touch();let t=this.createBaseEvent("page_view");t.page_path=e||window.location.pathname,t.page_url=window.location.href,t.page_title=document.title,t.referrer=document.referrer||void 0,t.screen_width=window.screen.width,t.screen_height=window.screen.height,Object.assign(t,this.utm),this.enqueue(t)}trackEvent(e,t){if(!this.canTrack()||!this.config.trackEvents)return;this.session.touch();let s=this.createBaseEvent("event");s.event_name=e,s.event_properties=t,s.page_path=window.location.pathname,s.page_url=window.location.href,this.enqueue(s)}identify(e){this.setMemberId(e)}setMemberId(e){this.memberId=e||null,typeof window<"u"&&(e?typeof window.__cbSetMember=="function"&&window.__cbSetMember(e):typeof window.__cbClearMember=="function"&&window.__cbClearMember()),this.log("Member id set",{memberId:e})}getMemberId(){return this.memberId}enableHeatmap(e){if(!this.canTrack()||!this.consent.heatmap)return;let t=e?.click??!0,s=e?.scroll??!0;if(t&&(this.heatmapClickHandler=this.handleHeatmapClick,document.addEventListener("click",this.heatmapClickHandler)),s){let i=null,r=0;this.heatmapScrollHandler=()=>{let n=Math.round((window.scrollY+window.innerHeight)/document.documentElement.scrollHeight*100);r=Math.max(r,n),i&&clearTimeout(i),i=setTimeout(()=>{this.recordHeatmapEvent("scroll",50,r*(window.innerHeight/100),r)},500)},window.addEventListener("scroll",this.heatmapScrollHandler,{passive:!0})}this.log("Heatmap enabled",e)}enableHeartbeat(){if(!this.canTrack()||this.heartbeatTimer)return;let e=()=>{if(!this.canTrack())return;let t=this.http.hasPublicKey()?"/v1/public":"/v1";this.http.post(`${t}/storages/web/${this.storageWebId}/sessions/heartbeat`,{visitor_uid:this.session.visitorUid,session_id:this.session.sessionId}).catch(()=>{})};this.heartbeatTimer=setInterval(e,3e4),document.addEventListener("visibilitychange",()=>{document.hidden?this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null):this.heartbeatTimer||(this.heartbeatTimer=setInterval(e,3e4),e())}),window.addEventListener("beforeunload",()=>{if(typeof navigator<"u"&&navigator.sendBeacon&&this.storageWebId){let t=this.http.hasPublicKey()?"/v1/public":"/v1",s=`${this.http.getBaseUrl()}${t}/storages/web/${this.storageWebId}/sessions/heartbeat`;navigator.sendBeacon(s,JSON.stringify({visitor_uid:this.session.visitorUid,session_id:this.session.sessionId}))}}),e(),this.log("Heartbeat enabled (30s interval)")}async flush(){await this.flushQueue()}getSession(){return this.session}canTrack(){return!(!this.isInitialized||!this.storageWebId||!this.consent.analytics)}isDNT(){return typeof navigator>"u"?!1:navigator.doNotTrack==="1"||navigator.globalPrivacyControl===!0}createBaseEvent(e){return{type:e,timestamp:new Date().toISOString(),session_id:this.session.sessionId,visitor_uid:this.session.visitorUid}}enqueue(e){this.eventQueue.push(e),this.eventQueue.length>=this.config.batchSize&&this.flushQueue()}async flushQueue(){if(this.eventQueue.length===0||!this.storageWebId)return;let e=this.eventQueue.splice(0),t=this.http.hasPublicKey()?"/v1/public":"/v1";try{await this.http.post(`${t}/storages/web/${this.storageWebId}/visitors/batch`,{visitor_uid:this.session.visitorUid,...this.memberId?{app_member_id:this.memberId}:{},events:e.map(s=>({timestamp:s.timestamp,page_path:s.page_path||"",page_url:s.page_url||"",page_title:s.page_title||"",referrer:s.referrer||"",user_agent:typeof navigator<"u"?navigator.userAgent:"",screen_width:s.screen_width||0,screen_height:s.screen_height||0,session_id:s.session_id,session_start:s.type==="session_start",is_page_view:s.type==="page_view",event_name:s.event_name,event_properties:s.event_properties,utm_source:s.utm_source,utm_medium:s.utm_medium,utm_campaign:s.utm_campaign,utm_content:s.utm_content,utm_term:s.utm_term}))}),this.log(`Flushed ${e.length} events`)}catch(s){this.eventQueue.length<this.config.batchSize*3&&this.eventQueue.unshift(...e),this.log("Flush failed",s)}}flushSync(){if(this.eventQueue.length===0||!this.storageWebId||typeof navigator>"u"||!navigator.sendBeacon)return;let e=this.eventQueue.splice(0),t=this.http.hasPublicKey()?"/v1/public":"/v1",i=`${this.http.getBaseUrl()}${t}/storages/web/${this.storageWebId}/visitors/batch`,r=JSON.stringify({visitor_uid:this.session.visitorUid,...this.memberId?{app_member_id:this.memberId}:{},events:e.map(n=>({timestamp:n.timestamp,page_path:n.page_path||"",page_url:n.page_url||"",page_title:n.page_title||"",referrer:n.referrer||"",session_id:n.session_id,session_start:n.type==="session_start",is_page_view:n.type==="page_view",event_name:n.event_name,event_properties:n.event_properties}))});try{navigator.sendBeacon(i,new Blob([r],{type:"application/json"}))}catch{}}trackSessionStart(){let e=this.createBaseEvent("session_start");e.page_path=window.location.pathname,e.page_url=window.location.href,e.referrer=document.referrer||void 0,e.screen_width=window.screen.width,e.screen_height=window.screen.height,Object.assign(e,this.utm),this.enqueue(e)}startBatchTimer(){this.batchTimer=setInterval(()=>this.flushQueue(),this.config.flushInterval)}stopBatchTimer(){this.batchTimer&&(clearInterval(this.batchTimer),this.batchTimer=null)}startHeartbeat(){this.heartbeatTimer=setInterval(()=>{this.canTrack()&&this.sendHeartbeat()},30*1e3),typeof document<"u"&&(this.visibilityHandler=()=>{document.visibilityState==="hidden"?(this.sendHeartbeatBeacon(),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)):document.visibilityState==="visible"&&(this.heartbeatTimer||(this.sendHeartbeat(),this.heartbeatTimer=setInterval(()=>{this.canTrack()&&this.sendHeartbeat()},30*1e3)))},document.addEventListener("visibilitychange",this.visibilityHandler)),typeof window<"u"&&(this.unloadHeartbeatHandler=()=>this.sendHeartbeatBeacon(),window.addEventListener("beforeunload",this.unloadHeartbeatHandler))}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),typeof document<"u"&&this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),typeof window<"u"&&this.unloadHeartbeatHandler&&(window.removeEventListener("beforeunload",this.unloadHeartbeatHandler),this.unloadHeartbeatHandler=null)}sendHeartbeat(){let e=this.createBaseEvent("heartbeat");if(e.page_path=window.location.pathname,this.enqueue(e),this.storageWebId){let t=this.http.hasPublicKey()?"/v1/public":"/v1";this.http.post(`${t}/storages/web/${this.storageWebId}/sessions/heartbeat`,{visitor_uid:this.session.visitorUid,session_id:this.session.sessionId}).catch(()=>{})}}sendHeartbeatBeacon(){if(!this.storageWebId||typeof navigator>"u"||!navigator.sendBeacon)return;let e=this.http.hasPublicKey()?"/v1/public":"/v1",s=`${this.http.getBaseUrl()}${e}/storages/web/${this.storageWebId}/sessions/heartbeat`,i=JSON.stringify({visitor_uid:this.session.visitorUid,session_id:this.session.sessionId});try{navigator.sendBeacon(s,new Blob([i],{type:"application/json"}))}catch{}}setupAutoPageView(){this.popstateHandler=()=>this.trackPageView(),window.addEventListener("popstate",this.popstateHandler),this.origPushState=history.pushState.bind(history),this.origReplaceState=history.replaceState.bind(history);let e=this;history.pushState=function(...t){e.origPushState(...t),e.trackPageView()},history.replaceState=function(...t){e.origReplaceState(...t),e.trackPageView()}}removeAutoPageView(){this.popstateHandler&&(window.removeEventListener("popstate",this.popstateHandler),this.popstateHandler=null),this.origPushState&&(history.pushState=this.origPushState,this.origPushState=null),this.origReplaceState&&(history.replaceState=this.origReplaceState,this.origReplaceState=null)}removeHeatmapListeners(){this.heatmapClickHandler&&(document.removeEventListener("click",this.heatmapClickHandler),this.heatmapClickHandler=null),this.heatmapScrollHandler&&(window.removeEventListener("scroll",this.heatmapScrollHandler),this.heatmapScrollHandler=null)}recordHeatmapEvent(e,t,s,i){if(!this.canTrack()||!this.storageWebId)return;let r=this.http.hasPublicKey()?"/v1/public":"/v1";if(this.heatmapQueue.push({page_path:window.location.pathname,event_type:e,x_percent:Math.round(t*100)/100,y_percent:Math.round(s*100)/100,viewport_width:window.innerWidth,viewport_height:window.innerHeight,scroll_depth_percent:i,session_id:this.session.sessionId}),this.heatmapQueue.length>=50){let n=this.heatmapQueue.splice(0);this.http.post(`${r}/storages/web/${this.storageWebId}/heatmap/batch`,{visitor_uid:this.session.visitorUid,events:n}).catch(()=>{})}}log(...e){this.config.debug&&console.log("[Analytics]",...e)}};var ee=class{constructor(e,t,s,i){this.type="webtransport";this.transport=null;this.writer=null;this.config=e,this.onMessage=t,this.onClose=s,this.onError=i}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.publicKey&&s.set("public_key",this.config.publicKey),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:i,done:r}=await t.read();if(r)break;let n=new Uint8Array(s.length+i.length);for(n.set(s),n.set(i,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 i=new Uint8Array(4);new DataView(i.buffer).setUint32(0,s.length,!0);let r=new Uint8Array(4+s.length);r.set(i),r.set(s,4),this.writer.write(r)}}else{let i=this.config.maxDatagramSize||1200;s.length<=i?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}},V=class{constructor(e,t,s,i){this.type="websocket";this.ws=null;this.config=e,this.onMessage=t,this.onClose=s,this.onError=i}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 i=()=>{e()},r=()=>{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",i,{once:!0}),this.ws.addEventListener("close",r),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.publicKey&&s.set("public_key",this.config.publicKey),this.config.accessToken&&s.set("token",this.config.accessToken);let i=this.config.appId||"";return`${t}/v1/game/${i}/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 te(){return typeof WebTransport<"u"}var z=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")&&te(),i=o=>{this.handleMessage(this.decoder.decode(o))},r=()=>{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 ee(this.config,i,r,n),await this.transport.connect(),this._transportType="webtransport"}catch{console.log("WebTransport failed, falling back to WebSocket"),this.transport=new V(this.config,i,r,n),await this.transport.connect(),this._transportType="websocket"}else this.transport=new V(this.config,i,r,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 i=r=>{if(r.type==="room_created"){let n=r.data;this._roomId=n.room_id,this._state=n.initial_state,t(n.initial_state)}else r.type==="error"&&s(new Error(r.data.message))};this.sendWithHandler("create_room",e,i)})}async joinRoom(e,t){return new Promise((s,i)=>{let r=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"&&i(new Error(n.data.message))};this.sendWithHandler("join_room",{room_id:e,metadata:t},r)})}async leaveRoom(){return new Promise((e,t)=>{if(!this._roomId){t(new Error("Not in a room"));return}let s=i=>{i.type==="room_left"?(this._roomId=null,this._state=null,e()):i.type==="error"&&t(new Error(i.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++}}),i=t||this._transportType!=="webtransport";this.transport?.send(s,i)}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=i=>{if(i.type==="state"){let r=i.data;this._state=r,e(r)}else i.type==="error"&&t(new Error(i.data.message))};this.sendWithHandler("get_state",{},s)})}async ping(){return new Promise((e,t)=>{let s=Date.now(),i=r=>{if(r.type==="pong"){let n=r.data,o=Date.now()-n.clientTimestamp;this._latency=o,this.handlers.onPong?.(n),e(o)}else r.type==="error"&&t(new Error(r.data.message))};this.sendWithHandler("ping",{timestamp:s},i)})}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 i=`msg_${this.messageId++}`;this.pendingHandlers.set(i,s),setTimeout(()=>{this.pendingHandlers.delete(i)},1e4),this.send(e,{...t,_msg_id:i})}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(i=>({path:i.path,operation:i.operation,value:i.value,oldValue:i.old_value})),tick:t.tick};if(this._state){for(let i of s.changes)this.applyChange(i);this._state.version=s.toVersion}if(this.handlers.onAction){for(let i of s.changes)if(i.path.startsWith("actions.")&&i.operation==="set"&&i.value){let r=i.value;this.handlers.onAction({type:r.type||"",clientId:r.client_id||"",data:r.data,timestamp:r.timestamp||0})}}this.handlers.onDelta?.(s)}applyChange(e){if(!this._state)return;let t=e.path.split("."),s=this._state.state;for(let r=0;r<t.length-1;r++){let n=t[r];n in s||(s[n]={}),s=s[n]}let i=t[t.length-1];e.operation==="delete"?delete s[i]:s[i]=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 ye="https://api.connectbase.world",be="https://socket.connectbase.world",ve="https://webrtc.connectbase.world",we="https://video.connectbase.world",Pe="https://game.connectbase.world",J=class{constructor(e={}){let t={baseUrl:e.baseUrl||ye,publicKey:e.publicKey,secretKey:e.secretKey,persistence:e.persistence,onTokenRefresh:e.onTokenRefresh,onAuthError:e.onAuthError,onTokenExpired:e.onTokenExpired};this.http=new $(t),this.auth=new x(this.http),this.database=new E(this.http),this.storage=new M(this.http),this.publicKey=new U(this.http),this.functions=new q(this.http),this.realtime=new A(this.http,e.socketUrl||be),this.webrtc=new H(this.http,e.webrtcUrl||ve,e.appId),this.errorTracker=new O(this.http,e.errorTracker),this.oauth=new D(this.http),this.payment=new L(this.http),this.subscription=new B(this.http),this.push=new F(this.http),this.video=new N(this.http,e.videoUrl||we),this.game=new R(this.http,e.gameUrl||Pe,e.appId),this.ads=new _(this.http),this.native=new T,this.knowledge=new G(this.http),this.ai=new k(this.http),this.queue=new W(this.http),this.analytics=new j(this.http),this.auth._attachAnalytics(this.analytics)}setTokens(e,t){this.http.setTokens(e,t)}clearTokens(){this.http.clearTokens()}updateConfig(e){this.http.updateConfig(e)}},Se=J;return ue(Re);})();
|
|
4
4
|
var ConnectBase = ConnectBaseModule.default || ConnectBaseModule.ConnectBase;
|
package/dist/index.d.mts
CHANGED
|
@@ -1506,17 +1506,23 @@ declare class DatabaseAPI {
|
|
|
1506
1506
|
createGeoIndex(appId: string, tableId: string, data: CreateGeoIndexRequest): Promise<GeoIndex>;
|
|
1507
1507
|
deleteGeoIndex(appId: string, tableId: string, indexId: string): Promise<void>;
|
|
1508
1508
|
/**
|
|
1509
|
-
* 테이블 릴레이션 목록
|
|
1509
|
+
* 테이블 릴레이션 목록 조회. `sourceTable` 생략 시 앱 전체의 릴레이션을 반환.
|
|
1510
|
+
*
|
|
1511
|
+
* 서버 경로: `GET /v1/apps/:appID/databases/relations[?source_table=...]`
|
|
1510
1512
|
*/
|
|
1511
|
-
listRelations(appId: string,
|
|
1513
|
+
listRelations(appId: string, sourceTable?: string): Promise<TableRelation[]>;
|
|
1512
1514
|
/**
|
|
1513
|
-
* 릴레이션
|
|
1515
|
+
* 릴레이션 생성.
|
|
1516
|
+
*
|
|
1517
|
+
* 서버 경로: `POST /v1/apps/:appID/databases/relations` — body 내 `source_table`/`target_table` 로 테이블 지정.
|
|
1514
1518
|
*/
|
|
1515
|
-
createRelation(appId: string,
|
|
1519
|
+
createRelation(appId: string, data: CreateRelationRequest): Promise<TableRelation>;
|
|
1516
1520
|
/**
|
|
1517
|
-
* 릴레이션
|
|
1521
|
+
* 릴레이션 삭제. `relationId` 는 서버에서 발급한 UUID (listRelations 로 조회해 얻음).
|
|
1522
|
+
*
|
|
1523
|
+
* 서버 경로: `DELETE /v1/apps/:appID/databases/relations/:relationID`
|
|
1518
1524
|
*/
|
|
1519
|
-
deleteRelation(appId: string,
|
|
1525
|
+
deleteRelation(appId: string, relationId: string): Promise<void>;
|
|
1520
1526
|
/**
|
|
1521
1527
|
* 트리거 목록 조회
|
|
1522
1528
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1506,17 +1506,23 @@ declare class DatabaseAPI {
|
|
|
1506
1506
|
createGeoIndex(appId: string, tableId: string, data: CreateGeoIndexRequest): Promise<GeoIndex>;
|
|
1507
1507
|
deleteGeoIndex(appId: string, tableId: string, indexId: string): Promise<void>;
|
|
1508
1508
|
/**
|
|
1509
|
-
* 테이블 릴레이션 목록
|
|
1509
|
+
* 테이블 릴레이션 목록 조회. `sourceTable` 생략 시 앱 전체의 릴레이션을 반환.
|
|
1510
|
+
*
|
|
1511
|
+
* 서버 경로: `GET /v1/apps/:appID/databases/relations[?source_table=...]`
|
|
1510
1512
|
*/
|
|
1511
|
-
listRelations(appId: string,
|
|
1513
|
+
listRelations(appId: string, sourceTable?: string): Promise<TableRelation[]>;
|
|
1512
1514
|
/**
|
|
1513
|
-
* 릴레이션
|
|
1515
|
+
* 릴레이션 생성.
|
|
1516
|
+
*
|
|
1517
|
+
* 서버 경로: `POST /v1/apps/:appID/databases/relations` — body 내 `source_table`/`target_table` 로 테이블 지정.
|
|
1514
1518
|
*/
|
|
1515
|
-
createRelation(appId: string,
|
|
1519
|
+
createRelation(appId: string, data: CreateRelationRequest): Promise<TableRelation>;
|
|
1516
1520
|
/**
|
|
1517
|
-
* 릴레이션
|
|
1521
|
+
* 릴레이션 삭제. `relationId` 는 서버에서 발급한 UUID (listRelations 로 조회해 얻음).
|
|
1522
|
+
*
|
|
1523
|
+
* 서버 경로: `DELETE /v1/apps/:appID/databases/relations/:relationID`
|
|
1518
1524
|
*/
|
|
1519
|
-
deleteRelation(appId: string,
|
|
1525
|
+
deleteRelation(appId: string, relationId: string): Promise<void>;
|
|
1520
1526
|
/**
|
|
1521
1527
|
* 트리거 목록 조회
|
|
1522
1528
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1063,7 +1063,7 @@ var DatabaseAPI = class {
|
|
|
1063
1063
|
*/
|
|
1064
1064
|
async listSecurityRules(appId) {
|
|
1065
1065
|
const response = await this.http.get(
|
|
1066
|
-
`/v1/apps/${appId}/security/rules`
|
|
1066
|
+
`/v1/apps/${appId}/databases/security/rules`
|
|
1067
1067
|
);
|
|
1068
1068
|
return response.rules;
|
|
1069
1069
|
}
|
|
@@ -1072,7 +1072,7 @@ var DatabaseAPI = class {
|
|
|
1072
1072
|
*/
|
|
1073
1073
|
async createSecurityRule(appId, data) {
|
|
1074
1074
|
return this.http.post(
|
|
1075
|
-
`/v1/apps/${appId}/security/rules`,
|
|
1075
|
+
`/v1/apps/${appId}/databases/security/rules`,
|
|
1076
1076
|
data
|
|
1077
1077
|
);
|
|
1078
1078
|
}
|
|
@@ -1081,7 +1081,7 @@ var DatabaseAPI = class {
|
|
|
1081
1081
|
*/
|
|
1082
1082
|
async updateSecurityRule(appId, ruleId, data) {
|
|
1083
1083
|
return this.http.put(
|
|
1084
|
-
`/v1/apps/${appId}/security/rules/${ruleId}`,
|
|
1084
|
+
`/v1/apps/${appId}/databases/security/rules/${ruleId}`,
|
|
1085
1085
|
data
|
|
1086
1086
|
);
|
|
1087
1087
|
}
|
|
@@ -1089,7 +1089,7 @@ var DatabaseAPI = class {
|
|
|
1089
1089
|
* 보안 규칙 삭제
|
|
1090
1090
|
*/
|
|
1091
1091
|
async deleteSecurityRule(appId, ruleId) {
|
|
1092
|
-
await this.http.delete(`/v1/apps/${appId}/security/rules/${ruleId}`);
|
|
1092
|
+
await this.http.delete(`/v1/apps/${appId}/databases/security/rules/${ruleId}`);
|
|
1093
1093
|
}
|
|
1094
1094
|
// ============ Indexes ============
|
|
1095
1095
|
/**
|
|
@@ -1097,7 +1097,7 @@ var DatabaseAPI = class {
|
|
|
1097
1097
|
*/
|
|
1098
1098
|
async listIndexes(appId, tableId) {
|
|
1099
1099
|
const response = await this.http.get(
|
|
1100
|
-
`/v1/apps/${appId}/tables/${tableId}/indexes`
|
|
1100
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/indexes`
|
|
1101
1101
|
);
|
|
1102
1102
|
return response.indexes;
|
|
1103
1103
|
}
|
|
@@ -1106,7 +1106,7 @@ var DatabaseAPI = class {
|
|
|
1106
1106
|
*/
|
|
1107
1107
|
async createIndex(appId, tableId, data) {
|
|
1108
1108
|
return this.http.post(
|
|
1109
|
-
`/v1/apps/${appId}/tables/${tableId}/indexes`,
|
|
1109
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/indexes`,
|
|
1110
1110
|
data
|
|
1111
1111
|
);
|
|
1112
1112
|
}
|
|
@@ -1114,72 +1114,79 @@ var DatabaseAPI = class {
|
|
|
1114
1114
|
* 인덱스 삭제
|
|
1115
1115
|
*/
|
|
1116
1116
|
async deleteIndex(appId, tableId, indexId) {
|
|
1117
|
-
await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/indexes/${indexId}`);
|
|
1117
|
+
await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/indexes/${indexId}`);
|
|
1118
1118
|
}
|
|
1119
1119
|
/**
|
|
1120
1120
|
* 인덱스 분석 및 추천
|
|
1121
1121
|
*/
|
|
1122
1122
|
async analyzeIndexes(appId, tableId) {
|
|
1123
1123
|
return this.http.get(
|
|
1124
|
-
`/v1/apps/${appId}/tables/${tableId}/indexes/analyze`
|
|
1124
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/indexes/analyze`
|
|
1125
1125
|
);
|
|
1126
1126
|
}
|
|
1127
1127
|
// ============ Search Indexes ============
|
|
1128
1128
|
async listSearchIndexes(appId, tableId) {
|
|
1129
1129
|
const response = await this.http.get(
|
|
1130
|
-
`/v1/apps/${appId}/tables/${tableId}/search-indexes`
|
|
1130
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/search-indexes`
|
|
1131
1131
|
);
|
|
1132
1132
|
return response.indexes;
|
|
1133
1133
|
}
|
|
1134
1134
|
async createSearchIndex(appId, tableId, data) {
|
|
1135
1135
|
return this.http.post(
|
|
1136
|
-
`/v1/apps/${appId}/tables/${tableId}/search-indexes`,
|
|
1136
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/search-indexes`,
|
|
1137
1137
|
data
|
|
1138
1138
|
);
|
|
1139
1139
|
}
|
|
1140
1140
|
async deleteSearchIndex(appId, tableId, indexId) {
|
|
1141
|
-
await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/search-indexes/${indexId}`);
|
|
1141
|
+
await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/search-indexes/${indexId}`);
|
|
1142
1142
|
}
|
|
1143
1143
|
// ============ Geo Indexes ============
|
|
1144
1144
|
async listGeoIndexes(appId, tableId) {
|
|
1145
1145
|
const response = await this.http.get(
|
|
1146
|
-
`/v1/apps/${appId}/tables/${tableId}/geo-indexes`
|
|
1146
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes`
|
|
1147
1147
|
);
|
|
1148
1148
|
return response.indexes;
|
|
1149
1149
|
}
|
|
1150
1150
|
async createGeoIndex(appId, tableId, data) {
|
|
1151
1151
|
return this.http.post(
|
|
1152
|
-
`/v1/apps/${appId}/tables/${tableId}/geo-indexes`,
|
|
1152
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes`,
|
|
1153
1153
|
data
|
|
1154
1154
|
);
|
|
1155
1155
|
}
|
|
1156
1156
|
async deleteGeoIndex(appId, tableId, indexId) {
|
|
1157
|
-
await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/geo-indexes/${indexId}`);
|
|
1157
|
+
await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes/${indexId}`);
|
|
1158
1158
|
}
|
|
1159
1159
|
// ============ Relations ============
|
|
1160
1160
|
/**
|
|
1161
|
-
* 테이블 릴레이션 목록
|
|
1161
|
+
* 테이블 릴레이션 목록 조회. `sourceTable` 생략 시 앱 전체의 릴레이션을 반환.
|
|
1162
|
+
*
|
|
1163
|
+
* 서버 경로: `GET /v1/apps/:appID/databases/relations[?source_table=...]`
|
|
1162
1164
|
*/
|
|
1163
|
-
async listRelations(appId,
|
|
1165
|
+
async listRelations(appId, sourceTable) {
|
|
1166
|
+
const qs = sourceTable ? `?source_table=${encodeURIComponent(sourceTable)}` : "";
|
|
1164
1167
|
const response = await this.http.get(
|
|
1165
|
-
`/v1/apps/${appId}/
|
|
1168
|
+
`/v1/apps/${appId}/databases/relations${qs}`
|
|
1166
1169
|
);
|
|
1167
1170
|
return response.relations;
|
|
1168
1171
|
}
|
|
1169
1172
|
/**
|
|
1170
|
-
* 릴레이션
|
|
1173
|
+
* 릴레이션 생성.
|
|
1174
|
+
*
|
|
1175
|
+
* 서버 경로: `POST /v1/apps/:appID/databases/relations` — body 내 `source_table`/`target_table` 로 테이블 지정.
|
|
1171
1176
|
*/
|
|
1172
|
-
async createRelation(appId,
|
|
1177
|
+
async createRelation(appId, data) {
|
|
1173
1178
|
return this.http.post(
|
|
1174
|
-
`/v1/apps/${appId}/
|
|
1179
|
+
`/v1/apps/${appId}/databases/relations`,
|
|
1175
1180
|
data
|
|
1176
1181
|
);
|
|
1177
1182
|
}
|
|
1178
1183
|
/**
|
|
1179
|
-
* 릴레이션
|
|
1184
|
+
* 릴레이션 삭제. `relationId` 는 서버에서 발급한 UUID (listRelations 로 조회해 얻음).
|
|
1185
|
+
*
|
|
1186
|
+
* 서버 경로: `DELETE /v1/apps/:appID/databases/relations/:relationID`
|
|
1180
1187
|
*/
|
|
1181
|
-
async deleteRelation(appId,
|
|
1182
|
-
await this.http.delete(`/v1/apps/${appId}/
|
|
1188
|
+
async deleteRelation(appId, relationId) {
|
|
1189
|
+
await this.http.delete(`/v1/apps/${appId}/databases/relations/${relationId}`);
|
|
1183
1190
|
}
|
|
1184
1191
|
// ============ Triggers ============
|
|
1185
1192
|
/**
|
|
@@ -1187,7 +1194,7 @@ var DatabaseAPI = class {
|
|
|
1187
1194
|
*/
|
|
1188
1195
|
async listTriggers(appId) {
|
|
1189
1196
|
const response = await this.http.get(
|
|
1190
|
-
`/v1/apps/${appId}/triggers`
|
|
1197
|
+
`/v1/apps/${appId}/databases/triggers`
|
|
1191
1198
|
);
|
|
1192
1199
|
return response.triggers;
|
|
1193
1200
|
}
|
|
@@ -1196,7 +1203,7 @@ var DatabaseAPI = class {
|
|
|
1196
1203
|
*/
|
|
1197
1204
|
async createTrigger(appId, data) {
|
|
1198
1205
|
return this.http.post(
|
|
1199
|
-
`/v1/apps/${appId}/triggers`,
|
|
1206
|
+
`/v1/apps/${appId}/databases/triggers`,
|
|
1200
1207
|
data
|
|
1201
1208
|
);
|
|
1202
1209
|
}
|
|
@@ -1205,7 +1212,7 @@ var DatabaseAPI = class {
|
|
|
1205
1212
|
*/
|
|
1206
1213
|
async updateTrigger(appId, triggerId, data) {
|
|
1207
1214
|
return this.http.put(
|
|
1208
|
-
`/v1/apps/${appId}/triggers/${triggerId}`,
|
|
1215
|
+
`/v1/apps/${appId}/databases/triggers/${triggerId}`,
|
|
1209
1216
|
data
|
|
1210
1217
|
);
|
|
1211
1218
|
}
|
|
@@ -1213,7 +1220,7 @@ var DatabaseAPI = class {
|
|
|
1213
1220
|
* 트리거 삭제
|
|
1214
1221
|
*/
|
|
1215
1222
|
async deleteTrigger(appId, triggerId) {
|
|
1216
|
-
await this.http.delete(`/v1/apps/${appId}/triggers/${triggerId}`);
|
|
1223
|
+
await this.http.delete(`/v1/apps/${appId}/databases/triggers/${triggerId}`);
|
|
1217
1224
|
}
|
|
1218
1225
|
// ============ Lifecycle ============
|
|
1219
1226
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1025,7 +1025,7 @@ var DatabaseAPI = class {
|
|
|
1025
1025
|
*/
|
|
1026
1026
|
async listSecurityRules(appId) {
|
|
1027
1027
|
const response = await this.http.get(
|
|
1028
|
-
`/v1/apps/${appId}/security/rules`
|
|
1028
|
+
`/v1/apps/${appId}/databases/security/rules`
|
|
1029
1029
|
);
|
|
1030
1030
|
return response.rules;
|
|
1031
1031
|
}
|
|
@@ -1034,7 +1034,7 @@ var DatabaseAPI = class {
|
|
|
1034
1034
|
*/
|
|
1035
1035
|
async createSecurityRule(appId, data) {
|
|
1036
1036
|
return this.http.post(
|
|
1037
|
-
`/v1/apps/${appId}/security/rules`,
|
|
1037
|
+
`/v1/apps/${appId}/databases/security/rules`,
|
|
1038
1038
|
data
|
|
1039
1039
|
);
|
|
1040
1040
|
}
|
|
@@ -1043,7 +1043,7 @@ var DatabaseAPI = class {
|
|
|
1043
1043
|
*/
|
|
1044
1044
|
async updateSecurityRule(appId, ruleId, data) {
|
|
1045
1045
|
return this.http.put(
|
|
1046
|
-
`/v1/apps/${appId}/security/rules/${ruleId}`,
|
|
1046
|
+
`/v1/apps/${appId}/databases/security/rules/${ruleId}`,
|
|
1047
1047
|
data
|
|
1048
1048
|
);
|
|
1049
1049
|
}
|
|
@@ -1051,7 +1051,7 @@ var DatabaseAPI = class {
|
|
|
1051
1051
|
* 보안 규칙 삭제
|
|
1052
1052
|
*/
|
|
1053
1053
|
async deleteSecurityRule(appId, ruleId) {
|
|
1054
|
-
await this.http.delete(`/v1/apps/${appId}/security/rules/${ruleId}`);
|
|
1054
|
+
await this.http.delete(`/v1/apps/${appId}/databases/security/rules/${ruleId}`);
|
|
1055
1055
|
}
|
|
1056
1056
|
// ============ Indexes ============
|
|
1057
1057
|
/**
|
|
@@ -1059,7 +1059,7 @@ var DatabaseAPI = class {
|
|
|
1059
1059
|
*/
|
|
1060
1060
|
async listIndexes(appId, tableId) {
|
|
1061
1061
|
const response = await this.http.get(
|
|
1062
|
-
`/v1/apps/${appId}/tables/${tableId}/indexes`
|
|
1062
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/indexes`
|
|
1063
1063
|
);
|
|
1064
1064
|
return response.indexes;
|
|
1065
1065
|
}
|
|
@@ -1068,7 +1068,7 @@ var DatabaseAPI = class {
|
|
|
1068
1068
|
*/
|
|
1069
1069
|
async createIndex(appId, tableId, data) {
|
|
1070
1070
|
return this.http.post(
|
|
1071
|
-
`/v1/apps/${appId}/tables/${tableId}/indexes`,
|
|
1071
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/indexes`,
|
|
1072
1072
|
data
|
|
1073
1073
|
);
|
|
1074
1074
|
}
|
|
@@ -1076,72 +1076,79 @@ var DatabaseAPI = class {
|
|
|
1076
1076
|
* 인덱스 삭제
|
|
1077
1077
|
*/
|
|
1078
1078
|
async deleteIndex(appId, tableId, indexId) {
|
|
1079
|
-
await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/indexes/${indexId}`);
|
|
1079
|
+
await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/indexes/${indexId}`);
|
|
1080
1080
|
}
|
|
1081
1081
|
/**
|
|
1082
1082
|
* 인덱스 분석 및 추천
|
|
1083
1083
|
*/
|
|
1084
1084
|
async analyzeIndexes(appId, tableId) {
|
|
1085
1085
|
return this.http.get(
|
|
1086
|
-
`/v1/apps/${appId}/tables/${tableId}/indexes/analyze`
|
|
1086
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/indexes/analyze`
|
|
1087
1087
|
);
|
|
1088
1088
|
}
|
|
1089
1089
|
// ============ Search Indexes ============
|
|
1090
1090
|
async listSearchIndexes(appId, tableId) {
|
|
1091
1091
|
const response = await this.http.get(
|
|
1092
|
-
`/v1/apps/${appId}/tables/${tableId}/search-indexes`
|
|
1092
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/search-indexes`
|
|
1093
1093
|
);
|
|
1094
1094
|
return response.indexes;
|
|
1095
1095
|
}
|
|
1096
1096
|
async createSearchIndex(appId, tableId, data) {
|
|
1097
1097
|
return this.http.post(
|
|
1098
|
-
`/v1/apps/${appId}/tables/${tableId}/search-indexes`,
|
|
1098
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/search-indexes`,
|
|
1099
1099
|
data
|
|
1100
1100
|
);
|
|
1101
1101
|
}
|
|
1102
1102
|
async deleteSearchIndex(appId, tableId, indexId) {
|
|
1103
|
-
await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/search-indexes/${indexId}`);
|
|
1103
|
+
await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/search-indexes/${indexId}`);
|
|
1104
1104
|
}
|
|
1105
1105
|
// ============ Geo Indexes ============
|
|
1106
1106
|
async listGeoIndexes(appId, tableId) {
|
|
1107
1107
|
const response = await this.http.get(
|
|
1108
|
-
`/v1/apps/${appId}/tables/${tableId}/geo-indexes`
|
|
1108
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes`
|
|
1109
1109
|
);
|
|
1110
1110
|
return response.indexes;
|
|
1111
1111
|
}
|
|
1112
1112
|
async createGeoIndex(appId, tableId, data) {
|
|
1113
1113
|
return this.http.post(
|
|
1114
|
-
`/v1/apps/${appId}/tables/${tableId}/geo-indexes`,
|
|
1114
|
+
`/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes`,
|
|
1115
1115
|
data
|
|
1116
1116
|
);
|
|
1117
1117
|
}
|
|
1118
1118
|
async deleteGeoIndex(appId, tableId, indexId) {
|
|
1119
|
-
await this.http.delete(`/v1/apps/${appId}/tables/${tableId}/geo-indexes/${indexId}`);
|
|
1119
|
+
await this.http.delete(`/v1/apps/${appId}/databases/tables/${tableId}/geo-indexes/${indexId}`);
|
|
1120
1120
|
}
|
|
1121
1121
|
// ============ Relations ============
|
|
1122
1122
|
/**
|
|
1123
|
-
* 테이블 릴레이션 목록
|
|
1123
|
+
* 테이블 릴레이션 목록 조회. `sourceTable` 생략 시 앱 전체의 릴레이션을 반환.
|
|
1124
|
+
*
|
|
1125
|
+
* 서버 경로: `GET /v1/apps/:appID/databases/relations[?source_table=...]`
|
|
1124
1126
|
*/
|
|
1125
|
-
async listRelations(appId,
|
|
1127
|
+
async listRelations(appId, sourceTable) {
|
|
1128
|
+
const qs = sourceTable ? `?source_table=${encodeURIComponent(sourceTable)}` : "";
|
|
1126
1129
|
const response = await this.http.get(
|
|
1127
|
-
`/v1/apps/${appId}/
|
|
1130
|
+
`/v1/apps/${appId}/databases/relations${qs}`
|
|
1128
1131
|
);
|
|
1129
1132
|
return response.relations;
|
|
1130
1133
|
}
|
|
1131
1134
|
/**
|
|
1132
|
-
* 릴레이션
|
|
1135
|
+
* 릴레이션 생성.
|
|
1136
|
+
*
|
|
1137
|
+
* 서버 경로: `POST /v1/apps/:appID/databases/relations` — body 내 `source_table`/`target_table` 로 테이블 지정.
|
|
1133
1138
|
*/
|
|
1134
|
-
async createRelation(appId,
|
|
1139
|
+
async createRelation(appId, data) {
|
|
1135
1140
|
return this.http.post(
|
|
1136
|
-
`/v1/apps/${appId}/
|
|
1141
|
+
`/v1/apps/${appId}/databases/relations`,
|
|
1137
1142
|
data
|
|
1138
1143
|
);
|
|
1139
1144
|
}
|
|
1140
1145
|
/**
|
|
1141
|
-
* 릴레이션
|
|
1146
|
+
* 릴레이션 삭제. `relationId` 는 서버에서 발급한 UUID (listRelations 로 조회해 얻음).
|
|
1147
|
+
*
|
|
1148
|
+
* 서버 경로: `DELETE /v1/apps/:appID/databases/relations/:relationID`
|
|
1142
1149
|
*/
|
|
1143
|
-
async deleteRelation(appId,
|
|
1144
|
-
await this.http.delete(`/v1/apps/${appId}/
|
|
1150
|
+
async deleteRelation(appId, relationId) {
|
|
1151
|
+
await this.http.delete(`/v1/apps/${appId}/databases/relations/${relationId}`);
|
|
1145
1152
|
}
|
|
1146
1153
|
// ============ Triggers ============
|
|
1147
1154
|
/**
|
|
@@ -1149,7 +1156,7 @@ var DatabaseAPI = class {
|
|
|
1149
1156
|
*/
|
|
1150
1157
|
async listTriggers(appId) {
|
|
1151
1158
|
const response = await this.http.get(
|
|
1152
|
-
`/v1/apps/${appId}/triggers`
|
|
1159
|
+
`/v1/apps/${appId}/databases/triggers`
|
|
1153
1160
|
);
|
|
1154
1161
|
return response.triggers;
|
|
1155
1162
|
}
|
|
@@ -1158,7 +1165,7 @@ var DatabaseAPI = class {
|
|
|
1158
1165
|
*/
|
|
1159
1166
|
async createTrigger(appId, data) {
|
|
1160
1167
|
return this.http.post(
|
|
1161
|
-
`/v1/apps/${appId}/triggers`,
|
|
1168
|
+
`/v1/apps/${appId}/databases/triggers`,
|
|
1162
1169
|
data
|
|
1163
1170
|
);
|
|
1164
1171
|
}
|
|
@@ -1167,7 +1174,7 @@ var DatabaseAPI = class {
|
|
|
1167
1174
|
*/
|
|
1168
1175
|
async updateTrigger(appId, triggerId, data) {
|
|
1169
1176
|
return this.http.put(
|
|
1170
|
-
`/v1/apps/${appId}/triggers/${triggerId}`,
|
|
1177
|
+
`/v1/apps/${appId}/databases/triggers/${triggerId}`,
|
|
1171
1178
|
data
|
|
1172
1179
|
);
|
|
1173
1180
|
}
|
|
@@ -1175,7 +1182,7 @@ var DatabaseAPI = class {
|
|
|
1175
1182
|
* 트리거 삭제
|
|
1176
1183
|
*/
|
|
1177
1184
|
async deleteTrigger(appId, triggerId) {
|
|
1178
|
-
await this.http.delete(`/v1/apps/${appId}/triggers/${triggerId}`);
|
|
1185
|
+
await this.http.delete(`/v1/apps/${appId}/databases/triggers/${triggerId}`);
|
|
1179
1186
|
}
|
|
1180
1187
|
// ============ Lifecycle ============
|
|
1181
1188
|
/**
|