connectbase-client 6.13.0 → 6.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,58 @@
3
3
  본 SDK 의 모든 주요 변경사항을 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/) 형식으로 기록합니다.
4
4
  버전은 [Semantic Versioning](https://semver.org/lang/ko/) 을 따릅니다.
5
5
 
6
+ ## [6.15.0] - 2026-11-11
7
+
8
+ ### Changed — `cb.database` 실시간 연결 거부의 이유를 알린다 (`reject_mode=close`)
9
+
10
+ - 브라우저는 실패한 WebSocket 핸드셰이크의 HTTP 상태를 읽지 못해, DB 실시간 연결의 거부(토큰 무효, 멤버 정지, 동시접속
11
+ 한도, 속도 제한, URL 쿼리 자격증명 거부 등)가 이유 없는 `Connection closed during handshake` 와 재연결 반복으로만 보였다.
12
+ 이제 `cb.database.connectRealtime()` 은 `cb.realtime` 처럼 `reject_mode=close` 로 협상하고, 서버가 보낸 이유를
13
+ `RealtimeConnectionError`(`code`, `message`, `closeCode` = 4000 + HTTP 상태, `retryable`, `retryAfterMs`, `details`)로
14
+ `connectRealtime()` 의 거부와 `onRealtimeError` 에 알린다.
15
+ - 재시도 규칙은 `cb.realtime` 과 같다. 다시 해도 같은 거부(4401 `unauthorized`, 4403 `member_revoked` 등)는 재연결을 멈추고
16
+ 알린다. 일시 장애, 속도 제한, 동시접속 한도(4503, 4429, 4402)는 `retryAfterMs` 보다 일찍 다시 붙지 않으면서 재연결을 이어
17
+ 가고, 재시도를 다 쓰면 일반 오류 대신 마지막 거부를 알린다. 티켓 발급 거부도 같은 규칙이다(예전에는 429 만 다시 붙었고,
18
+ 그때마다 `onRealtimeError` 로 알렸다).
19
+ - 열린 것만으로는 서버가 받아들였는지 알 수 없어, 열린 직후 `ping` 을 보내 첫 응답으로 연결을 확정한다. 그래서
20
+ `connectRealtime()` 이 한 왕복 늦게 끝난다. 협상을 모르는 예전 서버도 `ping` 에 답하므로 예전처럼 붙는다.
21
+ - `RealtimeConnectionError` 의 재시도 기본값: 서버가 `retryable` 을 보내지 않은 거부도 close 코드가 4429, 4500, 4503 이면
22
+ 재시도 가능으로 본다. `rate_limit_exceeded` 를 재시도 가능한 코드에 더했다.
23
+
24
+ ### Removed — 플랫폼 이슈의 게임 엔진 SDK 플랫폼 값
25
+
26
+ - `cb.support.reportPlatformBug({ sdkPlatform })` 와 `PlatformIssueDetail.sdk_platform` 의 타입에서 `"unity"`,
27
+ `"godot"`, `"unreal"` 을 뺀다. 게임 엔진 SDK 는 지원을 끝냈고, 서버도 이 값을 다른 모르는 값처럼 거부한다(400).
28
+ 남은 값은 `"web"`, `"node"`, `"cli"`, `"mcp"`, `"other"` 다. 값을 생략하면 SDK 가 `web`/`node` 를 정하는 동작은
29
+ 그대로다.
30
+
31
+ ## [6.14.0] - 2026-11-11
32
+
33
+ ### Security — WebSocket 연결 URL 에 자격증명을 싣지 않는다 (1회용 티켓)
34
+
35
+ - 브라우저 WebSocket 은 헤더를 붙일 수 없어 SDK 가 멤버 토큰과 공개 키를 URL 쿼리(`?access_token=`, `?token=`,
36
+ `?public_key=`)에 실었다. URL 은 브라우저 기록, 중간 프록시와 터널, 서버 로그에 남는다. 이제 연결(재연결)마다 헤더로
37
+ 30초짜리 1회용 티켓을 받아 `?ticket=` 만 싣는다. 서버는 티켓에서 자격증명을 되살려 예전과 같은 인증을 하므로 연결의
38
+ 권한, 토큰 만료 집행, 연결 위 토큰 갱신(`token_refresh`)은 그대로다.
39
+ - `cb.realtime.connect()` → `POST {socketUrl}/v1/realtime/ws-ticket`
40
+ - `cb.database.connectRealtime()` → `POST {dataServerUrl}/v1/database/realtime/ws-ticket` (cross-app OAuth 토큰 포함)
41
+ - `cb.game` 룸 클라이언트, WebSocket 전송 → `POST {gameServerUrl}/v1/game/{appId}/ws-ticket`
42
+ - `cb.webrtc.connect()` 시그널링 → `POST {webrtcUrl}/v1/apps/{appId}/signaling/ws-ticket`
43
+ - 서버가 티켓 발급을 모르면(404/405/501, 이 기능 전 서버) 그 서버에는 다시 묻지 않고 예전처럼 URL 자격증명으로 붙는다.
44
+ 티켓 저장소 일시 장애(503 `ws_ticket_unavailable`), 네트워크 또는 CORS 실패, 5초 시간 초과도 예전 방식으로 붙는다.
45
+ - 발급이 자격증명을 거부하면(401, 403, 402, 429 등) 소켓을 열지 않고 이유를 알린다. 브라우저 WebSocket 은 핸드셰이크
46
+ 거부의 이유를 읽을 수 없어 예전에는 같은 거부가 이유 없는 연결 실패로 보였다.
47
+ - `cb.realtime.connect()`: `RealtimeConnectionError`(`code` 는 서버 코드, `closeCode` 는 4000+HTTP 상태). `rate_limited`
48
+ 는 예전처럼 연결 제한 시간 안에서 다시 시도한다.
49
+ - `cb.database.connectRealtime()`: `RealtimeConnectionError` 로 reject 하고 `onRealtimeError` 로도 알린다.
50
+ - `cb.game`: `GameError`(`code` 는 서버 코드). `cb.webrtc.connect()`: `WsTicketError`(`status`, `code`).
51
+ - 새 실시간 거부 코드 `invalid_ws_ticket`(티켓 만료 또는 이미 쓰임), `ws_ticket_unavailable`(서버 티켓 저장소 일시 장애)은
52
+ `connect()` 가 새 티켓으로 스스로 다시 시도한다. `query_credential_rejected` 는 서버가 URL 쿼리 자격증명을 받지 않도록
53
+ 설정됐다는 뜻이다(`WS_QUERY_CREDENTIAL_POLICY`, 기본 허용).
54
+ - `WsTicketError` 를 내보낸다.
55
+ - 연결이 소켓을 열기 전에 발급 요청 한 번을 기다린다. 테스트에서 `WebSocket` 생성이 `connect()` 와 같은 틱에 일어난다고
56
+ 가정했다면 소켓이 만들어질 때까지 기다리도록 바꿔야 한다.
57
+
6
58
  ## [6.13.0] - 2026-11-11
7
59
 
8
60
  ### Security — WebRTC 역할과 룸 인가를 서버가 정한 대로 따른다
package/README.md CHANGED
@@ -1000,7 +1000,7 @@ await subscription.unsubscribe()
1000
1000
  await cb.realtime.disconnect()
1001
1001
  ```
1002
1002
 
1003
- #### 로그인 멤버 연결의 토큰 갱신과 멤버 폐기 (Unreleased)
1003
+ #### 로그인 멤버 연결의 토큰 갱신과 멤버 폐기 (6.12.0 부터)
1004
1004
 
1005
1005
  `cb.realtime.connect({ accessToken })` 과 `cb.database.connectRealtime({ accessToken })` 에 넘긴 토큰이 SDK 가 로그인으로
1006
1006
  들고 있는 멤버 세션(같은 앱, 같은 멤버)의 것이면, SDK 가 만료 전에 HTTP 요청과 같은 refresh 로 새 토큰을 받아 **연결을 끊지
@@ -1092,6 +1092,22 @@ try {
1092
1092
  구버전 서버면 지수 백오프). 연결 제한 시간(`timeout`, 기본 30초) 안에 못 붙을 때만 이 에러를 던집니다. `unauthorized` 처럼
1093
1093
  다시 해도 소용없는 거부는 바로 던집니다.
1094
1094
 
1095
+ `cb.database.connectRealtime()` 도 같은 방식으로 거부 이유를 받습니다(6.15.0 부터). 예전에는 이유 없는
1096
+ `Connection closed during handshake` 였습니다.
1097
+
1098
+ ```typescript
1099
+ try {
1100
+ await cb.database.connectRealtime({ accessToken })
1101
+ } catch (e) {
1102
+ if (e instanceof RealtimeConnectionError) {
1103
+ e.code // 'unauthorized' | 'member_revoked' | 'connection_limit_exceeded' | 'rate_limit_exceeded' | 'auth_unavailable' | ...
1104
+ e.closeCode // 4000 + HTTP 상태 (4401, 4403, 4402, 4429, 4503)
1105
+ e.retryable // true 면 SDK 가 retryAfterMs 이후로 스스로 다시 붙는다
1106
+ }
1107
+ }
1108
+ cb.database.onRealtimeError((e) => { /* 다시 붙지 않는 거부, 또는 재시도를 다 쓴 마지막 거부 */ })
1109
+ ```
1110
+
1095
1111
  #### Broadcast categories: publishers (v6.6.0)
1096
1112
 
1097
1113
  1명이 방송하고 많은 사람이 받는 카테고리는 콘솔에서 **방송인 역할**(`publisher_roles`)과 **발행 정책**(`send_policy`)을
package/dist/cli.js CHANGED
@@ -170,7 +170,7 @@ function handleTunnelError(msg, appId, localPort) {
170
170
  }
171
171
 
172
172
  // src/cli.ts
173
- var VERSION = "6.13.0" ? "6.13.0" : getPackageVersion();
173
+ var VERSION = "6.15.0" ? "6.15.0" : getPackageVersion();
174
174
  var DEFAULT_BASE_URL = "https://api.connectbase.world";
175
175
  var colors = {
176
176
  reset: "\x1B[0m",