connectbase-client 0.16.0 → 0.16.1
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 +157 -0
- package/LICENSE +21 -0
- package/README.md +27 -17
- package/dist/cli.js +14 -14
- package/dist/connect-base.umd.js +2 -2
- package/dist/index.d.mts +6 -4
- package/dist/index.d.ts +6 -4
- package/package.json +11 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
본 SDK 의 모든 주요 변경사항을 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/) 형식으로 기록합니다.
|
|
4
|
+
버전은 [Semantic Versioning](https://semver.org/lang/ko/) 을 따릅니다.
|
|
5
|
+
|
|
6
|
+
## [0.16.1] - 2026-04-17
|
|
7
|
+
|
|
8
|
+
MCP/SDK 문서-코드 정합성 검증에서 발견된 불일치 소규모 정정. 런타임 동작 변경은 없으며, 이전 릴리스에서 도입된 타입 회귀를 롤백.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **`FetchDataResponse` 필드명 회귀 롤백**: `0.16.0` 에서 `datas→data`, `total_size→total_count` 로 바꿨으나 실제 서버 wire 는 여전히 `datas` / `total_size` 였음. 타입 정의를 서버 응답 그대로 `{ datas, total_size }` 로 되돌려 런타임 미스매치 제거.
|
|
13
|
+
- `cb.push.subscribeTopic()` JSDoc 예제가 `device_token` 인자 누락된 구 시그니처로 표기되던 문제 정정 (실 시그니처는 `subscribeTopic(deviceToken, topic)`).
|
|
14
|
+
- CLI 안내 문구·`setupMonorepoRoot` 로 추가되는 `cb:update`/`cb:docs`/`cb:mcp` 스크립트가 `connectbase-client` 를 가리키던 것을 정규 bin 이름인 `connectbase` 로 통일. 두 bin 은 모두 동작하지만 문서와 자동 생성 스크립트는 단일 이름 기준으로 일관화.
|
|
15
|
+
|
|
16
|
+
### Documentation
|
|
17
|
+
|
|
18
|
+
- README `### Push Notifications` 섹션의 예제를 실제 공개 API 와 일치하도록 수정: `push.register()` / `push.subscribeToTopic()` / `push.unsubscribeFromTopic()` (존재하지 않는 메서드) → `push.registerDevice()` / `push.subscribeTopic(deviceToken, topic)` / `push.unsubscribeTopic(deviceToken, topic)` / Web Push 등록 예제 추가.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- `package.json` 메타데이터 보강: `author`, `homepage`, `bugs`, `sideEffects: false` 필드 추가, `files` 에 `LICENSE`/`CHANGELOG.md`/`README.md` 명시적 포함.
|
|
23
|
+
- 저장소 루트에 `LICENSE` (MIT) 파일 신설 (이전에는 `license: "MIT"` 선언만 존재).
|
|
24
|
+
|
|
25
|
+
## [0.16.0] - 2026-04-17
|
|
26
|
+
|
|
27
|
+
CLI `update` 커맨드와 신규 저장소 API 옵션, 토큰 영속성 옵션 추가. 일부 타입 정정.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **CLI `update` 커맨드**: 현재 설치된 `connectbase-client` 버전을 npm 과 비교하고 `docs`·`mcp` 산출물을 일괄 최신화.
|
|
32
|
+
- **모노레포 지원**: `connectbase init --setup-root` 로 모노레포 루트 `package.json` 에 `cb:update`/`cb:docs`/`cb:mcp` 편의 스크립트 설치.
|
|
33
|
+
- **Storage `getFiles()` `parentId` 옵션**: 특정 폴더 하위 파일 목록 조회 지원.
|
|
34
|
+
- **토큰 영속성(persistence) 옵션**: `new ConnectBase({ persistence: 'localStorage' | 'sessionStorage' | 'none' })`.
|
|
35
|
+
- `localStorage` (기본값): 브라우저 종료 후에도 토큰 유지.
|
|
36
|
+
- `sessionStorage`: 탭 종료 시 삭제.
|
|
37
|
+
- `none`: 메모리에만 저장.
|
|
38
|
+
- 생성자에서 저장된 토큰 자동 복원 (명시적 토큰 전달 시 스킵). SSR 환경(`window` undefined) 안전 처리.
|
|
39
|
+
- **OAuthProvider 확장**: `kakao`, `apple` 프로바이더 추가 (서버 enum 과 동기화).
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- `VERSION` 상수가 `package.json` 에서 동적으로 로드되도록 변경 (이전: `0.10.6` 하드코딩).
|
|
44
|
+
- `FetchDataResponse` 필드명 변경: `datas` → `data`, `total_size` → `total_count` (서버 응답과 일치를 의도함).
|
|
45
|
+
- **⚠️ 본 변경은 실제 서버 wire 와 맞지 않는 회귀였으며 `0.16.1` 에서 롤백됩니다.** `0.16.0` 사용자는 `0.16.1` 이상으로 즉시 업그레이드 권장.
|
|
46
|
+
|
|
47
|
+
### Documentation
|
|
48
|
+
|
|
49
|
+
- SDK 문서 전체 감사 및 누락 섹션 보강.
|
|
50
|
+
|
|
51
|
+
## [0.15.0] - 2026-04-16
|
|
52
|
+
|
|
53
|
+
Web Analytics SDK 모듈 신설 및 터널 유틸 리팩터.
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- **AnalyticsAPI** 모듈 (`cb.analytics`): `init` / `trackEvent` / `trackPageView` / `identify` / `setConsent` / `enableHeatmap` / `enableHeartbeat` / `destroy`.
|
|
58
|
+
- **SessionManager**: 30분 타임아웃, `visitor_uid` localStorage 영속화.
|
|
59
|
+
- 백엔드 측 12개 서비스·9개 Ent 스키마(이벤트/퍼널/세션/코호트/어트리뷰션/세그먼트/A-B 테스트/히트맵/녹화/프라이버시) 와 매칭.
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
|
|
63
|
+
- CLI 내부에서 tunnel 관련 로직을 `src/tunnel-utils.ts` 로 추출 (테스트 용이성 확보).
|
|
64
|
+
- `vitest` 도입 및 tunnel/analytics 단위 테스트 23건 추가.
|
|
65
|
+
|
|
66
|
+
## [0.14.0] - 2026-04-15
|
|
67
|
+
|
|
68
|
+
Tunnel 안정성 개선.
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
|
|
72
|
+
- **Tunnel lockfile**: 앱+포트 기반 lockfile 로 동일 터널 중복 실행을 차단. stale lockfile 자동 감지(PID 생존 확인).
|
|
73
|
+
- `--force` 플래그: lockfile 무시 옵션.
|
|
74
|
+
|
|
75
|
+
### Changed
|
|
76
|
+
|
|
77
|
+
- 서버의 `tunnel_error code=replaced` 수신 시 재연결을 중단하고 안내 메시지 출력 (이전에는 끊임없이 재연결 시도).
|
|
78
|
+
- `TunnelMessage` 타입에 `code` / `error` / `message` 필드 추가.
|
|
79
|
+
|
|
80
|
+
## [0.13.0] - 2026-04-14
|
|
81
|
+
|
|
82
|
+
Database API 정합성 및 완성도 대규모 개선.
|
|
83
|
+
|
|
84
|
+
### Breaking Changes
|
|
85
|
+
|
|
86
|
+
- **`TableSchema` 응답 구조 전면 재정의**: 서버 ent 모델 (`backend/cmd/data-server/ent/schema/table.go`) 과 1:1 일치하도록 변경.
|
|
87
|
+
- `name` → `title`
|
|
88
|
+
- `columns: ColumnSchema[]` → `schema: TableSchemaDefinition` (평면 또는 중첩 맵)
|
|
89
|
+
- `created_at` → `create_time` (※ G2 작업에서 다시 `created_at` 로 표준화 예정)
|
|
90
|
+
- `updated_at` → `update_time`
|
|
91
|
+
- 신규 필드: `app_id`, `access_level`, `is_active`, `validation_schema?`
|
|
92
|
+
- **`CreateTableRequest` 형태 변경**: 서버 DTO 와 일치.
|
|
93
|
+
- `schema?: TableSchemaDefinition` 신규 필드. 평면 맵 (`{email: 'string'}`) 또는 중첩 객체 (`{email: {type: 'string', required: true}}`) 모두 지원. `$required` 키로 필수 컬럼 지정.
|
|
94
|
+
- `accessLevel?: 'Creator' | 'Public' | 'AppMember'` (기본 `'Creator'`)
|
|
95
|
+
- `description` 은 `@deprecated` — 서버에 저장되지 않음
|
|
96
|
+
- **`createTable()` 반환 타입**: `Promise<TableSchema>` → `Promise<void>`. 서버는 `{message}` 만 반환하므로 거짓 타입 제거.
|
|
97
|
+
- **`createColumn()` / `updateColumn()` 반환 타입**: 동일한 이유로 `Promise<void>` 로 변경.
|
|
98
|
+
- **`updateTable()` 시맨틱 정정**: PATCH 부분 업데이트가 정상 동작. 이전 버전에서는 모든 필드가 required 라 부분 업데이트 시 400 오류가 발생했음.
|
|
99
|
+
- **`DataType` 정렬**: 서버 `ValidSchemaTypes` 와 일치하도록 변경.
|
|
100
|
+
- 제거: `'boolean'`
|
|
101
|
+
- 추가: `'int'`, `'bool'`, `'uuid'`
|
|
102
|
+
- 최종 union: `'string' | 'int' | 'number' | 'bool' | 'uuid' | 'date' | 'object' | 'array'`
|
|
103
|
+
- **`CreateColumnRequest`**:
|
|
104
|
+
- `is_required` 가 optional 로 변경 (기본 false)
|
|
105
|
+
- `default_value` 타입 `string` → `unknown` (서버는 임의 타입 허용)
|
|
106
|
+
- `order`, `validation_rule` 은 `@deprecated` (서버 미지원)
|
|
107
|
+
- **`UpdateColumnRequest`**:
|
|
108
|
+
- `default_value` 타입 `string` → `unknown`
|
|
109
|
+
- `name` `@deprecated` (서버는 컬럼 rename 미지원)
|
|
110
|
+
- `order`, `validation_rule` `@deprecated`
|
|
111
|
+
- **`ColumnSchema`**:
|
|
112
|
+
- SDK 가 합성하는 객체임을 명시
|
|
113
|
+
- `default_value` 타입 `string` → `unknown`
|
|
114
|
+
- `created_at` 은 테이블의 `create_time` 으로 대체 (컬럼 개별 타임스탬프 없음)
|
|
115
|
+
- `order` 는 SDK 가 부여한 인덱스
|
|
116
|
+
- `updated_at`, `validation_rule` `@deprecated`
|
|
117
|
+
|
|
118
|
+
### Added
|
|
119
|
+
|
|
120
|
+
- `TableSchemaDefinition` interface — 컬럼 정의 맵 타입. 플랫 / 중첩 / `$required` 모두 지원.
|
|
121
|
+
- `TableColumnDef` union type — 단일 컬럼 정의 (플랫 string 또는 중첩 객체).
|
|
122
|
+
- `TableAccessLevel` type — `'Creator' | 'Public' | 'AppMember'`.
|
|
123
|
+
- `database.createTable()` 가 초기 schema 와 access level 을 한 번에 받아 1-step 생성 지원.
|
|
124
|
+
- `database.getColumns()` 가 플랫 / 중첩 schema 모두 정확히 파싱.
|
|
125
|
+
- `database` 모듈의 `getPublicPrefix()` 가 항상 `/v1/public` 반환 (이전: 인증 종류에 따라 `/v1/public` 또는 `/v1` — 후자는 dead path).
|
|
126
|
+
- `database.getValidationSchema()`, `setValidationSchema()`, `deleteValidationSchema()` — 테이블 검증 스키마 CRUD.
|
|
127
|
+
- `MemberInfoResponse` 에 `email?`, `role?` 필드 추가 — RLS `auth.email`/`auth.role` 과 일치.
|
|
128
|
+
- MCP `update_column` 툴 신설 (description, encrypted, data_type, is_required, default_value 변경).
|
|
129
|
+
- MCP `get_validation_schema`, `set_validation_schema`, `delete_validation_schema` 툴 신설.
|
|
130
|
+
|
|
131
|
+
### Fixed
|
|
132
|
+
|
|
133
|
+
- **🔴 `database.createTable()` 가 어떤 키로도 동작하지 않던 broken 상태 해결**.
|
|
134
|
+
- Public Key 경로: 요청 body 가 서버 DTO 와 불일치 (필드명 `name`/`title`, 누락 `access_level`, 빈 `schema`)
|
|
135
|
+
- Secret Key 경로: 존재하지 않는 `/v1/tables` 경로 호출 → 404
|
|
136
|
+
- 두 경로 모두 본 릴리스에서 정상 동작.
|
|
137
|
+
- **MCP `create_table` 툴이 빈 schema 거부로 항상 실패** 하던 문제 해결 (서버 hook 이 explicit 빈 맵을 거부했음). 서버 DTO/repository/MCP tool 세 곳을 동시에 수정.
|
|
138
|
+
- 서버 측 `CreateTableRequest.Schema` 가 `binding:"required"` 였으나 schema 생략 가능하도록 변경.
|
|
139
|
+
- 서버 측 `EditTableInternal` (PATCH) 가 full-replace 시맨틱이라 부분 업데이트 불가능했던 문제 해결. `PatchTableRequest` DTO 와 `PatchTable` repository 메서드 신설.
|
|
140
|
+
- MCP `create_column`, `update_column` 툴의 `data_type` enum 이 `'boolean'` 을 포함했으나 서버는 `'bool'` 만 허용 → 정정.
|
|
141
|
+
- `getColumns()` 가 플랫 schema (`"email": "string"`) 를 모두 `'string'` 으로 잘못 반환하던 문제 해결.
|
|
142
|
+
|
|
143
|
+
### Documentation
|
|
144
|
+
|
|
145
|
+
- `secretKey` 의 JSDoc 명확화: 앱 DB API 에는 사용 불가, CLI / tunnel 전용임을 명시.
|
|
146
|
+
- embedded SDK 문서 (04-sdk-database.md, 11-mcp-tools.md, 25-app-packaging.md) 의 `boolean` → `bool`, `auth.email`/`auth.role` 정합성 정리, `createTable` 예제 갱신.
|
|
147
|
+
- `TableSchemaDefinition` 의 `$required` 키 사용법, `TableColumnDef` 평면/중첩 형태 모두 JSDoc 예제 포함.
|
|
148
|
+
|
|
149
|
+
### Notes
|
|
150
|
+
|
|
151
|
+
본 변경의 대부분은 backwards-incompat 이지만, 이전 버전 (`0.12.x`) 의 `createTable` 자체가 broken 상태였으므로 해당 메서드를 사용하던 코드는 어차피 동작하지 않았습니다. read 메서드 (`getTables`, `getTable`, `getColumns`) 는 사용자 코드가 escape-hatch 캐스팅 (`as any`) 으로 우회하던 경우만 영향받습니다.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## [0.12.2] - 2026-04-?? (이전)
|
|
156
|
+
|
|
157
|
+
이전 릴리스 — 본 CHANGELOG 도입 이전. git history 참조.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Connect Base
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ Deploy your web application to Connect Base Web Storage with a single command.
|
|
|
89
89
|
|
|
90
90
|
```bash
|
|
91
91
|
# 1. Initialize (one-time setup)
|
|
92
|
-
npx connectbase
|
|
92
|
+
npx connectbase init
|
|
93
93
|
|
|
94
94
|
# 2. Deploy
|
|
95
95
|
npm run deploy
|
|
@@ -115,7 +115,7 @@ The `init` command will:
|
|
|
115
115
|
If you prefer not to use `init`, you can pass options directly:
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
|
-
npx connectbase
|
|
118
|
+
npx connectbase deploy ./dist -s <storage-id> -k <public-key>
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
### Options
|
|
@@ -136,14 +136,14 @@ Expose a local server to the internet through a secure WebSocket tunnel. Useful
|
|
|
136
136
|
|
|
137
137
|
```bash
|
|
138
138
|
# Expose local port 8084 to the internet
|
|
139
|
-
npx connectbase
|
|
139
|
+
npx connectbase tunnel 8084 -k <public-key>
|
|
140
140
|
|
|
141
141
|
# With environment variable
|
|
142
142
|
export CONNECTBASE_PUBLIC_KEY=your-public-key
|
|
143
|
-
npx connectbase
|
|
143
|
+
npx connectbase tunnel 8084
|
|
144
144
|
|
|
145
145
|
# For GPU servers or long-running tasks (e.g., image generation)
|
|
146
|
-
npx connectbase
|
|
146
|
+
npx connectbase tunnel 7860 --timeout 300 --max-body 50
|
|
147
147
|
```
|
|
148
148
|
|
|
149
149
|
The tunnel creates a public URL like `https://tunnel.connectbase.world/<tunnel-id>/` that proxies all HTTP requests to your local service.
|
|
@@ -181,7 +181,7 @@ The `init` command creates `.connectbaserc` automatically. You can also create i
|
|
|
181
181
|
```bash
|
|
182
182
|
export CONNECTBASE_PUBLIC_KEY=your-public-key
|
|
183
183
|
export CONNECTBASE_STORAGE_ID=your-storage-id
|
|
184
|
-
npx connectbase
|
|
184
|
+
npx connectbase deploy ./dist
|
|
185
185
|
```
|
|
186
186
|
|
|
187
187
|
### Requirements
|
|
@@ -439,19 +439,19 @@ await cb.auth.signOut()
|
|
|
439
439
|
|
|
440
440
|
```typescript
|
|
441
441
|
// Query data
|
|
442
|
-
const {
|
|
442
|
+
const { datas, total_size } = await cb.database.getData('table-id', {
|
|
443
443
|
where: { status: 'active' },
|
|
444
444
|
limit: 10
|
|
445
445
|
})
|
|
446
446
|
|
|
447
447
|
// Query with field selection (Projection) - improves response speed
|
|
448
|
-
const {
|
|
448
|
+
const { datas } = await cb.database.getData('table-id', {
|
|
449
449
|
select: ['id', 'name', 'thumbnail'], // Only return these fields
|
|
450
450
|
limit: 20
|
|
451
451
|
})
|
|
452
452
|
|
|
453
453
|
// Exclude specific fields (e.g., large HTML/CSS content)
|
|
454
|
-
const {
|
|
454
|
+
const { datas } = await cb.database.getData('table-id', {
|
|
455
455
|
exclude: ['html_content', 'css_content'],
|
|
456
456
|
limit: 20
|
|
457
457
|
})
|
|
@@ -764,17 +764,27 @@ await session.stop()
|
|
|
764
764
|
### Push Notifications
|
|
765
765
|
|
|
766
766
|
```typescript
|
|
767
|
-
// Register for
|
|
768
|
-
await cb.push.
|
|
769
|
-
|
|
770
|
-
platform: 'android' //
|
|
767
|
+
// Register a device (FCM for Android, APNS for iOS)
|
|
768
|
+
const device = await cb.push.registerDevice({
|
|
769
|
+
device_token: 'fcm-token-or-apns-token',
|
|
770
|
+
platform: 'android', // 'android' | 'ios' | 'web'
|
|
771
|
+
device_name: 'Galaxy S24'
|
|
771
772
|
})
|
|
772
773
|
|
|
773
|
-
// Subscribe to
|
|
774
|
-
await cb.push.
|
|
774
|
+
// Subscribe the device to a topic (deviceToken is required)
|
|
775
|
+
await cb.push.subscribeTopic(device.device_token, 'news')
|
|
775
776
|
|
|
776
|
-
// Unsubscribe from topic
|
|
777
|
-
await cb.push.
|
|
777
|
+
// Unsubscribe the device from a topic
|
|
778
|
+
await cb.push.unsubscribeTopic(device.device_token, 'news')
|
|
779
|
+
|
|
780
|
+
// Web Push (browsers)
|
|
781
|
+
const vapidKey = await cb.push.getVAPIDPublicKey()
|
|
782
|
+
const registration = await navigator.serviceWorker.ready
|
|
783
|
+
const subscription = await registration.pushManager.subscribe({
|
|
784
|
+
userVisibleOnly: true,
|
|
785
|
+
applicationServerKey: vapidKey.public_key
|
|
786
|
+
})
|
|
787
|
+
await cb.push.registerWebPush(subscription)
|
|
778
788
|
```
|
|
779
789
|
|
|
780
790
|
### WebRTC
|
package/dist/cli.js
CHANGED
|
@@ -311,8 +311,8 @@ async function deploy(directory, config, isDev = false) {
|
|
|
311
311
|
try {
|
|
312
312
|
const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
|
|
313
313
|
if (pkg.scripts?.build) {
|
|
314
|
-
warn(`\uBC30\uD3EC \uC804 \uBE4C\uB4DC\uB97C \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694: ${colors.cyan}npm run build && npx connectbase
|
|
315
|
-
warn(`\uB610\uB294 package.json\uC5D0 deploy \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uB4F1\uB85D\uD558\uC138\uC694: ${colors.cyan}npx connectbase
|
|
314
|
+
warn(`\uBC30\uD3EC \uC804 \uBE4C\uB4DC\uB97C \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694: ${colors.cyan}npm run build && npx connectbase deploy${colors.reset}`);
|
|
315
|
+
warn(`\uB610\uB294 package.json\uC5D0 deploy \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uB4F1\uB85D\uD558\uC138\uC694: ${colors.cyan}npx connectbase init${colors.reset}`);
|
|
316
316
|
}
|
|
317
317
|
} catch {
|
|
318
318
|
}
|
|
@@ -793,7 +793,7 @@ function addDeployScript(deployDir) {
|
|
|
793
793
|
info(`package.json\uC5D0 \uC774\uBBF8 deploy \uC2A4\uD06C\uB9BD\uD2B8\uAC00 \uC788\uC2B5\uB2C8\uB2E4: "${pkg.scripts.deploy}"`);
|
|
794
794
|
return;
|
|
795
795
|
}
|
|
796
|
-
const deployCmd = `connectbase
|
|
796
|
+
const deployCmd = `connectbase deploy ${deployDir}`;
|
|
797
797
|
pkg.scripts.deploy = pkg.scripts.build ? `${pkg.scripts.build} && ${deployCmd}` : deployCmd;
|
|
798
798
|
fs2.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
799
799
|
success(`package.json\uC5D0 deploy \uC2A4\uD06C\uB9BD\uD2B8 \uCD94\uAC00 \uC644\uB8CC`);
|
|
@@ -1252,15 +1252,15 @@ function setupMonorepoRoot(projectRoot, monorepo) {
|
|
|
1252
1252
|
if (!pkg.scripts) pkg.scripts = {};
|
|
1253
1253
|
let changed = false;
|
|
1254
1254
|
if (!pkg.scripts["cb:update"]) {
|
|
1255
|
-
pkg.scripts["cb:update"] = "npx connectbase
|
|
1255
|
+
pkg.scripts["cb:update"] = "npx connectbase update";
|
|
1256
1256
|
changed = true;
|
|
1257
1257
|
}
|
|
1258
1258
|
if (!pkg.scripts["cb:docs"]) {
|
|
1259
|
-
pkg.scripts["cb:docs"] = "npx connectbase
|
|
1259
|
+
pkg.scripts["cb:docs"] = "npx connectbase docs";
|
|
1260
1260
|
changed = true;
|
|
1261
1261
|
}
|
|
1262
1262
|
if (!pkg.scripts["cb:mcp"]) {
|
|
1263
|
-
pkg.scripts["cb:mcp"] = "npx connectbase
|
|
1263
|
+
pkg.scripts["cb:mcp"] = "npx connectbase mcp";
|
|
1264
1264
|
changed = true;
|
|
1265
1265
|
}
|
|
1266
1266
|
if (changed) {
|
|
@@ -1810,10 +1810,10 @@ ${colors.dim}Ctrl+C\uB85C \uC885\uB8CC${colors.reset}
|
|
|
1810
1810
|
}
|
|
1811
1811
|
function showHelp() {
|
|
1812
1812
|
log(`
|
|
1813
|
-
${colors.cyan}connectbase
|
|
1813
|
+
${colors.cyan}connectbase${colors.reset} - Connect Base SDK & CLI
|
|
1814
1814
|
|
|
1815
1815
|
${colors.yellow}\uC0AC\uC6A9\uBC95:${colors.reset}
|
|
1816
|
-
npx connectbase
|
|
1816
|
+
npx connectbase <command> [options]
|
|
1817
1817
|
|
|
1818
1818
|
${colors.yellow}\uBA85\uB839\uC5B4:${colors.reset}
|
|
1819
1819
|
init \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654 (\uC571 \uC0DD\uC131, MCP \uC124\uC815, SDK \uBB38\uC11C \uB2E4\uC6B4\uB85C\uB4DC)
|
|
@@ -1848,7 +1848,7 @@ ${colors.yellow}\uC635\uC158:${colors.reset}
|
|
|
1848
1848
|
|
|
1849
1849
|
${colors.yellow}\uBE60\uB978 \uC2DC\uC791:${colors.reset}
|
|
1850
1850
|
${colors.dim}# 1. \uCD08\uAE30\uD654 (\uCD5C\uCD08 1\uD68C)${colors.reset}
|
|
1851
|
-
npx connectbase
|
|
1851
|
+
npx connectbase init
|
|
1852
1852
|
|
|
1853
1853
|
${colors.dim}# 2. SDK \uC804\uCCB4 \uC5C5\uB370\uC774\uD2B8 (\uBC84\uC804 \uCCB4\uD06C + \uBB38\uC11C + MCP)${colors.reset}
|
|
1854
1854
|
npx connectbase update
|
|
@@ -1866,7 +1866,7 @@ ${colors.yellow}\uBE60\uB978 \uC2DC\uC791:${colors.reset}
|
|
|
1866
1866
|
npm run deploy
|
|
1867
1867
|
|
|
1868
1868
|
${colors.dim}# 4. Dev \uD658\uACBD \uBC30\uD3EC (\uB0B4\uBD80 QA\uC6A9)${colors.reset}
|
|
1869
|
-
npx connectbase
|
|
1869
|
+
npx connectbase deploy ./dist --dev
|
|
1870
1870
|
|
|
1871
1871
|
${colors.dim}# 5. \uD130\uB110 (\uAE30\uBCF8)${colors.reset}
|
|
1872
1872
|
npx connectbase tunnel 3000
|
|
@@ -1942,7 +1942,7 @@ function parseArgs(args) {
|
|
|
1942
1942
|
async function main() {
|
|
1943
1943
|
const parsed = parseArgs(process.argv.slice(2));
|
|
1944
1944
|
if (parsed.options.version) {
|
|
1945
|
-
log(`connectbase
|
|
1945
|
+
log(`connectbase v${VERSION}`);
|
|
1946
1946
|
return;
|
|
1947
1947
|
}
|
|
1948
1948
|
if (parsed.options.help || !parsed.command) {
|
|
@@ -1980,11 +1980,11 @@ async function main() {
|
|
|
1980
1980
|
} else if (parsed.command === "deploy") {
|
|
1981
1981
|
const directory = parsed.args[0] || fileConfig.deployDir || ".";
|
|
1982
1982
|
if (!config.publicKey && !config.publicKey) {
|
|
1983
|
-
error('Public Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase
|
|
1983
|
+
error('Public Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -k \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694');
|
|
1984
1984
|
process.exit(1);
|
|
1985
1985
|
}
|
|
1986
1986
|
if (!config.storageId) {
|
|
1987
|
-
error('\uC2A4\uD1A0\uB9AC\uC9C0 ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase
|
|
1987
|
+
error('\uC2A4\uD1A0\uB9AC\uC9C0 ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -s \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694');
|
|
1988
1988
|
process.exit(1);
|
|
1989
1989
|
}
|
|
1990
1990
|
const isDev = parsed.options.dev === "true";
|
|
@@ -1992,7 +1992,7 @@ async function main() {
|
|
|
1992
1992
|
} else if (parsed.command === "tunnel") {
|
|
1993
1993
|
const portStr = parsed.args[0];
|
|
1994
1994
|
if (!portStr) {
|
|
1995
|
-
error("\uD3EC\uD2B8 \uBC88\uD638\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC608: npx connectbase
|
|
1995
|
+
error("\uD3EC\uD2B8 \uBC88\uD638\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC608: npx connectbase tunnel 8084");
|
|
1996
1996
|
process.exit(1);
|
|
1997
1997
|
}
|
|
1998
1998
|
const port = parseInt(portStr, 10);
|
package/dist/connect-base.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var ConnectBaseModule=(()=>{var X=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var pe=Object.prototype.hasOwnProperty;var he=(l,e)=>{for(var t in e)X(l,t,{get:e[t],enumerable:!0})},ue=(l,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of de(e))!pe.call(l,i)&&i!==t&&X(l,i,{get:()=>e[i],enumerable:!(s=le(e,i))||s.enumerable});return l};var ge=l=>ue(X({},"__esModule",{value:!0}),l);var _e={};he(_e,{AIAPI:()=>I,AdsAPI:()=>T,ApiError:()=>f,AuthError:()=>P,ConnectBase:()=>Q,GameAPI:()=>_,GameRoom:()=>$,GameRoomTransport:()=>J,NativeAPI:()=>k,SessionManager:()=>x,VideoProcessingError:()=>R,default:()=>Re,isWebTransportSupported:()=>se});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 ie="cb_auth_tokens",C=class{constructor(e){this.isRefreshing=!1;this.refreshPromise=null;this.config={...e},this.storageKey=this.buildStorageKey(),this.restoreTokens()}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??"localStorage"}getStorage(){return typeof window>"u"?null:this.persistence==="localStorage"&&typeof localStorage<"u"?localStorage:this.persistence==="sessionStorage"&&typeof sessionStorage<"u"?sessionStorage:null}buildStorageKey(){let e=this.config.publicKey??this.config.secretKey;if(!e)return ie;let t=0;for(let s=0;s<e.length;s++)t=(t<<5)-t+e.charCodeAt(s),t=t&t;return`${ie}_${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}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 re="cb_guest_";function S(l){typeof window>"u"||(l?typeof window.__cbSetMember=="function"&&window.__cbSetMember(l):typeof window.__cbClearMember=="function"&&window.__cbClearMember())}function me(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 E=class{constructor(e){this.http=e;this.guestMemberLoginPromise=null;this.cachedGuestMemberTokenKey=null}async getAuthSettings(){return this.http.get("/v1/public/auth-settings",{skipAuth:!0})}async signUpMember(e){let t=await this.http.post("/v1/public/app-members/signup",e,{skipAuth:!0});return this.http.setTokens(t.access_token,t.refresh_token),S(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),S(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(),S(null)}}clearGuestMemberTokens(){typeof sessionStorage>"u"||sessionStorage.removeItem(this.getGuestMemberTokenKey())}async executeGuestMemberLogin(){let e=this.getStoredGuestMemberTokens();if(e){if(!this.isTokenExpired(e.accessToken))try{this.http.setTokens(e.accessToken,e.refreshToken);let s=await this.http.get("/v1/public/app-members/me");if(s.is_active)return S(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),S(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),S(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=`${re}default`;else{let t=me(e);this.cachedGuestMemberTokenKey=`${re}${t}`}return this.cachedGuestMemberTokenKey}getStoredGuestMemberTokens(){if(typeof sessionStorage>"u")return null;let e=sessionStorage.getItem(this.getGuestMemberTokenKey());if(!e)return null;try{return JSON.parse(e)}catch{return null}}storeGuestMemberTokens(e,t,s){typeof sessionStorage>"u"||sessionStorage.setItem(this.getGuestMemberTokenKey(),JSON.stringify({accessToken:e,refreshToken:t,memberId:s}))}};var U=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){let i=this.getPublicPrefix();await this.http.post(`${i}/storages/files/${e}/items/${t}/move`,s)}async renameFile(e,t,s){let i=this.getPublicPrefix();return this.http.patch(`${i}/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 q=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 H=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 X=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var pe=Object.prototype.hasOwnProperty;var he=(l,e)=>{for(var t in e)X(l,t,{get:e[t],enumerable:!0})},ue=(l,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of de(e))!pe.call(l,i)&&i!==t&&X(l,i,{get:()=>e[i],enumerable:!(s=le(e,i))||s.enumerable});return l};var ge=l=>ue(X({},"__esModule",{value:!0}),l);var _e={};he(_e,{AIAPI:()=>I,AdsAPI:()=>T,ApiError:()=>f,AuthError:()=>P,ConnectBase:()=>Q,GameAPI:()=>_,GameRoom:()=>$,GameRoomTransport:()=>J,NativeAPI:()=>k,SessionManager:()=>C,VideoProcessingError:()=>R,default:()=>Re,isWebTransportSupported:()=>se});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 ie="cb_auth_tokens",x=class{constructor(e){this.isRefreshing=!1;this.refreshPromise=null;this.config={...e},this.storageKey=this.buildStorageKey(),this.restoreTokens()}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??"localStorage"}getStorage(){return typeof window>"u"?null:this.persistence==="localStorage"&&typeof localStorage<"u"?localStorage:this.persistence==="sessionStorage"&&typeof sessionStorage<"u"?sessionStorage:null}buildStorageKey(){let e=this.config.publicKey??this.config.secretKey;if(!e)return ie;let t=0;for(let s=0;s<e.length;s++)t=(t<<5)-t+e.charCodeAt(s),t=t&t;return`${ie}_${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}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 re="cb_guest_";function S(l){typeof window>"u"||(l?typeof window.__cbSetMember=="function"&&window.__cbSetMember(l):typeof window.__cbClearMember=="function"&&window.__cbClearMember())}function me(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 E=class{constructor(e){this.http=e;this.guestMemberLoginPromise=null;this.cachedGuestMemberTokenKey=null}async getAuthSettings(){return this.http.get("/v1/public/auth-settings",{skipAuth:!0})}async signUpMember(e){let t=await this.http.post("/v1/public/app-members/signup",e,{skipAuth:!0});return this.http.setTokens(t.access_token,t.refresh_token),S(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),S(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(),S(null)}}clearGuestMemberTokens(){typeof sessionStorage>"u"||sessionStorage.removeItem(this.getGuestMemberTokenKey())}async executeGuestMemberLogin(){let e=this.getStoredGuestMemberTokens();if(e){if(!this.isTokenExpired(e.accessToken))try{this.http.setTokens(e.accessToken,e.refreshToken);let s=await this.http.get("/v1/public/app-members/me");if(s.is_active)return S(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),S(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),S(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=`${re}default`;else{let t=me(e);this.cachedGuestMemberTokenKey=`${re}${t}`}return this.cachedGuestMemberTokenKey}getStoredGuestMemberTokens(){if(typeof sessionStorage>"u")return null;let e=sessionStorage.getItem(this.getGuestMemberTokenKey());if(!e)return null;try{return JSON.parse(e)}catch{return null}}storeGuestMemberTokens(e,t,s){typeof sessionStorage>"u"||sessionStorage.setItem(this.getGuestMemberTokenKey(),JSON.stringify({accessToken:e,refreshToken:t,memberId:s}))}};var U=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){let i=this.getPublicPrefix();await this.http.post(`${i}/storages/files/${e}/items/${t}/move`,s)}async renameFile(e,t,s){let i=this.getPublicPrefix();return this.http.patch(`${i}/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 q=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 H=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 O=class{constructor(e,t,s){this.ws=null;this.state="disconnected";this.stateListeners=[];this.errorListeners=[];this.peerJoinedListeners=[];this.peerLeftListeners=[];this.remoteStreamListeners=[];this.reconnectAttempts=0;this.maxReconnectAttempts=5;this.reconnectTimeout=null;this.currentRoomId=null;this.currentPeerId=null;this.currentUserId=null;this.isBroadcaster=!1;this.localStream=null;this.channelType="interactive";this.peerConnections=new Map;this.remoteStreams=new Map;this.iceServers=[];this.http=e,this.webrtcUrl=t,this.appId=s}async getICEServers(){let e=await this.http.get("/v1/ice-servers");return this.iceServers=e.ice_servers,e.ice_servers}async connect(e){if(this.state==="connected"||this.state==="connecting")throw new Error("\uC774\uBBF8 \uC5F0\uACB0\uB418\uC5B4 \uC788\uAC70\uB098 \uC5F0\uACB0 \uC911\uC785\uB2C8\uB2E4");if(this.setState("connecting"),this.currentRoomId=e.roomId,this.currentUserId=e.userId||null,this.isBroadcaster=e.isBroadcaster||!1,this.localStream=e.localStream||null,this.iceServers.length===0)try{await this.getICEServers()}catch{this.iceServers=[{urls:"stun:stun.l.google.com:19302"}]}return this.connectWebSocket()}connectWebSocket(){return new Promise((e,t)=>{let s=this.buildWebSocketUrl();this.ws=new WebSocket(s);let 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}/webrtc/stats`)}async getRooms(e){return this.http.get(`/v1/apps/${e}/webrtc/rooms`)}};var D=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 L=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)}};var B=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 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 F=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 N=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 ne=5*1024*1024,R=class extends Error{constructor(e,t){super(e),this.name="VideoProcessingError",this.video=t}},G=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||ne,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,Y=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:Y})}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||ne,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,Y=v-d,ce=u>0?Y/u:0;c=w,d=v,t.onProgress&&t.onProgress({phase:"uploading",uploadedChunks:o,totalChunks:n,percentage:Math.round(o/n*100),currentSpeed:ce})}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 R("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 R("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 oe=()=>{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"},$=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:oe(),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)}},_=class{constructor(e,t,s){this.http=e,this.gameServerUrl=t||oe().replace(/^ws/,"http"),this.appId=s}createClient(e){return new $({...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={}){let s=e||this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${s}/rooms`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({app_id:e,category_id:t.categoryId,room_id:t.roomId,tick_rate:t.tickRate,max_players:t.maxPlayers,metadata:t.metadata})});if(!i.ok)throw new Error(`Failed to create room: ${i.statusText}`);return i.json()}async deleteRoom(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/rooms/${e}`,{method:"DELETE",headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to delete room: ${s.statusText}`)}async joinQueue(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/matchmaking/queue`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({game_type:e.gameType,player_id:e.playerId,rating:e.rating,region:e.region,mode:e.mode,party_members:e.partyMembers,metadata:e.metadata})});if(!s.ok){let 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){let s=this.appId||"",i=await fetch(`${this.gameServerUrl}/v1/game/${s}/parties/${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 party: ${i.statusText}`);return i.json()}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({player_id:t,message: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}/spectate`,{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}/spectate/stop`,{method:"POST",headers:{...this.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({spectator_id:t})});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){let t=this.appId||"",s=e||100,i=await fetch(`${this.gameServerUrl}/v1/game/${t}/ranking/leaderboard/top?limit=${s}`,{headers:this.getHeaders()});if(!i.ok)throw new Error(`Failed to get leaderboard: ${i.statusText}`);return(await i.json()).entries||[]}async getPlayerStats(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/ranking/players/${e}/stats`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to get player stats: ${s.statusText}`);return s.json()}async getPlayerRank(e){let t=this.appId||"",s=await fetch(`${this.gameServerUrl}/v1/game/${t}/ranking/players/${e}/rank`,{headers:this.getHeaders()});if(!s.ok)throw new Error(`Failed to get player rank: ${s.statusText}`);return s.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.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.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.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.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 T=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 k=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 W=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 I=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
|
-
`);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 K=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 fe=1800*1e3,Z="__cb_session",ae="__cb_visitor_uid",j="__cb_last_activity";function ee(){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 x=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(j,String(this._lastActivity))}catch{}}reset(){this._sessionId=null,this._isNewSession=!1;try{typeof sessionStorage<"u"&&(sessionStorage.removeItem(Z),sessionStorage.removeItem(j))}catch{}}ensureSession(){let e=Date.now();if(!this._sessionId)try{if(typeof sessionStorage<"u"){this._sessionId=sessionStorage.getItem(Z);let t=sessionStorage.getItem(j);this._lastActivity=t?parseInt(t,10):0}}catch{}if(!this._sessionId||this._lastActivity>0&&e-this._lastActivity>fe){this._sessionId=ee(),this._isNewSession=!0,this._lastActivity=e;try{typeof sessionStorage<"u"&&(sessionStorage.setItem(Z,this._sessionId),sessionStorage.setItem(j,String(e)))}catch{}}}loadOrCreateVisitorUid(){try{if(typeof localStorage<"u"){let e=localStorage.getItem(ae);if(e)return e;let t=ee();return localStorage.setItem(ae,t),t}}catch{}return ee()}};function ye(){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 V=class{constructor(e){this.storageWebId=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 x}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=ye(),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.canTrack()&&(typeof window.__cbSetMember=="function"&&window.__cbSetMember(e),this.log("User identified",{memberId:e}))}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,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,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 te=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}},z=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 se(){return typeof WebTransport<"u"}var J=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")&&se(),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 te(this.config,i,r,n),await this.transport.connect(),this._transportType="webtransport"}catch{console.log("WebTransport failed, falling back to WebSocket"),this.transport=new z(this.config,i,r,n),await this.transport.connect(),this._transportType="websocket"}else this.transport=new z(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 be="https://api.connectbase.world",ve="https://socket.connectbase.world",we="https://webrtc.connectbase.world",Pe="https://video.connectbase.world",Se="https://game.connectbase.world",Q=class{constructor(e={}){let t={baseUrl:e.baseUrl||be,publicKey:e.publicKey,secretKey:e.secretKey,persistence:e.persistence,onTokenRefresh:e.onTokenRefresh,onAuthError:e.onAuthError,onTokenExpired:e.onTokenExpired};this.http=new C(t),this.auth=new E(this.http),this.database=new U(this.http),this.storage=new M(this.http),this.publicKey=new q(this.http),this.functions=new H(this.http),this.realtime=new A(this.http,e.socketUrl||ve),this.webrtc=new O(this.http,e.webrtcUrl||we,e.appId),this.errorTracker=new D(this.http,e.errorTracker),this.oauth=new L(this.http),this.payment=new B(this.http),this.subscription=new F(this.http),this.push=new N(this.http),this.video=new G(this.http,e.videoUrl||Pe),this.game=new _(this.http,e.gameUrl||Se,e.appId),this.ads=new T(this.http),this.native=new k,this.knowledge=new W(this.http),this.ai=new I(this.http),this.queue=new K(this.http),this.analytics=new V(this.http)}setTokens(e,t){this.http.setTokens(e,t)}clearTokens(){this.http.clearTokens()}updateConfig(e){this.http.updateConfig(e)}},Re=Q;return ge(_e);})();
|
|
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 K=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 fe=1800*1e3,Z="__cb_session",ae="__cb_visitor_uid",j="__cb_last_activity";function ee(){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(j,String(this._lastActivity))}catch{}}reset(){this._sessionId=null,this._isNewSession=!1;try{typeof sessionStorage<"u"&&(sessionStorage.removeItem(Z),sessionStorage.removeItem(j))}catch{}}ensureSession(){let e=Date.now();if(!this._sessionId)try{if(typeof sessionStorage<"u"){this._sessionId=sessionStorage.getItem(Z);let t=sessionStorage.getItem(j);this._lastActivity=t?parseInt(t,10):0}}catch{}if(!this._sessionId||this._lastActivity>0&&e-this._lastActivity>fe){this._sessionId=ee(),this._isNewSession=!0,this._lastActivity=e;try{typeof sessionStorage<"u"&&(sessionStorage.setItem(Z,this._sessionId),sessionStorage.setItem(j,String(e)))}catch{}}}loadOrCreateVisitorUid(){try{if(typeof localStorage<"u"){let e=localStorage.getItem(ae);if(e)return e;let t=ee();return localStorage.setItem(ae,t),t}}catch{}return ee()}};function ye(){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 V=class{constructor(e){this.storageWebId=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=ye(),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.canTrack()&&(typeof window.__cbSetMember=="function"&&window.__cbSetMember(e),this.log("User identified",{memberId:e}))}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,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,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 te=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}},z=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 se(){return typeof WebTransport<"u"}var J=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")&&se(),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 te(this.config,i,r,n),await this.transport.connect(),this._transportType="webtransport"}catch{console.log("WebTransport failed, falling back to WebSocket"),this.transport=new z(this.config,i,r,n),await this.transport.connect(),this._transportType="websocket"}else this.transport=new z(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 be="https://api.connectbase.world",ve="https://socket.connectbase.world",we="https://webrtc.connectbase.world",Pe="https://video.connectbase.world",Se="https://game.connectbase.world",Q=class{constructor(e={}){let t={baseUrl:e.baseUrl||be,publicKey:e.publicKey,secretKey:e.secretKey,persistence:e.persistence,onTokenRefresh:e.onTokenRefresh,onAuthError:e.onAuthError,onTokenExpired:e.onTokenExpired};this.http=new x(t),this.auth=new E(this.http),this.database=new U(this.http),this.storage=new M(this.http),this.publicKey=new q(this.http),this.functions=new H(this.http),this.realtime=new A(this.http,e.socketUrl||ve),this.webrtc=new O(this.http,e.webrtcUrl||we,e.appId),this.errorTracker=new D(this.http,e.errorTracker),this.oauth=new L(this.http),this.payment=new B(this.http),this.subscription=new F(this.http),this.push=new N(this.http),this.video=new G(this.http,e.videoUrl||Pe),this.game=new _(this.http,e.gameUrl||Se,e.appId),this.ads=new T(this.http),this.native=new k,this.knowledge=new W(this.http),this.ai=new I(this.http),this.queue=new K(this.http),this.analytics=new V(this.http)}setTokens(e,t){this.http.setTokens(e,t)}clearTokens(){this.http.clearTokens()}updateConfig(e){this.http.updateConfig(e)}},Re=Q;return ge(_e);})();
|
|
4
4
|
var ConnectBase = ConnectBaseModule.default || ConnectBaseModule.ConnectBase;
|
package/dist/index.d.mts
CHANGED
|
@@ -509,8 +509,10 @@ interface UpdateDataRequest {
|
|
|
509
509
|
data: Record<string, unknown>;
|
|
510
510
|
}
|
|
511
511
|
interface FetchDataResponse {
|
|
512
|
-
|
|
513
|
-
|
|
512
|
+
/** 조회된 문서 배열 (서버는 `datas` 키로 반환합니다) */
|
|
513
|
+
datas: DataItem[];
|
|
514
|
+
/** 총 매칭 문서 수 (서버는 `total_size` 키로 반환합니다) */
|
|
515
|
+
total_size: number;
|
|
514
516
|
}
|
|
515
517
|
interface QueryOptions {
|
|
516
518
|
limit?: number;
|
|
@@ -3788,8 +3790,8 @@ interface WebPushSubscription {
|
|
|
3788
3790
|
* device_name: 'Galaxy S24',
|
|
3789
3791
|
* })
|
|
3790
3792
|
*
|
|
3791
|
-
* // 토픽 구독
|
|
3792
|
-
* await cb.push.subscribeTopic('announcements')
|
|
3793
|
+
* // 토픽 구독 (device_token 필수)
|
|
3794
|
+
* await cb.push.subscribeTopic(device.device_token, 'announcements')
|
|
3793
3795
|
*
|
|
3794
3796
|
* // Web Push 등록 (브라우저)
|
|
3795
3797
|
* const vapidKey = await cb.push.getVAPIDPublicKey()
|
package/dist/index.d.ts
CHANGED
|
@@ -509,8 +509,10 @@ interface UpdateDataRequest {
|
|
|
509
509
|
data: Record<string, unknown>;
|
|
510
510
|
}
|
|
511
511
|
interface FetchDataResponse {
|
|
512
|
-
|
|
513
|
-
|
|
512
|
+
/** 조회된 문서 배열 (서버는 `datas` 키로 반환합니다) */
|
|
513
|
+
datas: DataItem[];
|
|
514
|
+
/** 총 매칭 문서 수 (서버는 `total_size` 키로 반환합니다) */
|
|
515
|
+
total_size: number;
|
|
514
516
|
}
|
|
515
517
|
interface QueryOptions {
|
|
516
518
|
limit?: number;
|
|
@@ -3788,8 +3790,8 @@ interface WebPushSubscription {
|
|
|
3788
3790
|
* device_name: 'Galaxy S24',
|
|
3789
3791
|
* })
|
|
3790
3792
|
*
|
|
3791
|
-
* // 토픽 구독
|
|
3792
|
-
* await cb.push.subscribeTopic('announcements')
|
|
3793
|
+
* // 토픽 구독 (device_token 필수)
|
|
3794
|
+
* await cb.push.subscribeTopic(device.device_token, 'announcements')
|
|
3793
3795
|
*
|
|
3794
3796
|
* // Web Push 등록 (브라우저)
|
|
3795
3797
|
* const vapidKey = await cb.push.getVAPIDPublicKey()
|
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "connectbase-client",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "Connect Base JavaScript/TypeScript SDK for browser and Node.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/connectbase-world/connectbase.git",
|
|
8
8
|
"directory": "frontend/package/public/connect-base-client"
|
|
9
9
|
},
|
|
10
|
+
"homepage": "https://github.com/connectbase-world/connectbase/tree/release/frontend/package/public/connect-base-client#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/connectbase-world/connectbase/issues"
|
|
13
|
+
},
|
|
10
14
|
"publishConfig": {
|
|
11
15
|
"access": "public"
|
|
12
16
|
},
|
|
17
|
+
"sideEffects": false,
|
|
13
18
|
"main": "dist/index.js",
|
|
14
19
|
"module": "dist/index.mjs",
|
|
15
20
|
"types": "dist/index.d.ts",
|
|
@@ -27,7 +32,10 @@
|
|
|
27
32
|
}
|
|
28
33
|
},
|
|
29
34
|
"files": [
|
|
30
|
-
"dist"
|
|
35
|
+
"dist",
|
|
36
|
+
"LICENSE",
|
|
37
|
+
"CHANGELOG.md",
|
|
38
|
+
"README.md"
|
|
31
39
|
],
|
|
32
40
|
"scripts": {
|
|
33
41
|
"build": "tsup",
|
|
@@ -51,7 +59,7 @@
|
|
|
51
59
|
"realtime",
|
|
52
60
|
"tunnel"
|
|
53
61
|
],
|
|
54
|
-
"author": "",
|
|
62
|
+
"author": "Connect Base",
|
|
55
63
|
"license": "MIT",
|
|
56
64
|
"devDependencies": {
|
|
57
65
|
"@types/node": "^22.15.18",
|