connectbase-client 6.14.0 → 6.16.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,50 @@
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.16.0] - 2026-11-12
7
+
8
+ ### Added — `cb.webrtc.getSFUToken()` (SFU 방 입장 토큰)
9
+
10
+ - `cb.webrtc.connect()` 는 미디어가 브라우저끼리 직접(P2P) 오가서 상대에게 IP 가 보이고 참가자가 많은 방을 만들 수 없다.
11
+ `cb.webrtc.getSFUToken({ roomId, publish, name, device })` 는 서버가 미디어를 나눠 주는 SFU 방의 입장 토큰(`url`, `token`,
12
+ `can_publish` 등)을 돌려준다. 미디어 연결은 앱이 `livekit-client` 의 `room.connect(url, token)` 으로 한다(SDK 는
13
+ `livekit-client` 를 포함하지 않는다).
14
+ - 입장과 보내기 권한은 채널 설정(`require_auth`, `join_roles`, `publisher_roles`, `max_participants`)을 따르고, 보내기 권한이
15
+ 없는 참가자의 미디어는 서버가 받지 않는다. 사용량은 `traffic_egress` 에 합산된다.
16
+ - SFU 가 켜져 있지 않은 서버는 503 `sfu_unavailable` 을 돌려준다.
17
+
18
+ ### Added — `cb.storage.getPathUrl()` (파일을 경로로 읽는 고정 주소)
19
+
20
+ - 2026-11-11 부터 새 파일의 직접 주소(`url`)에는 경로가 들어 있지 않다(객체 이름이 파일 ID). `url` 의 모양에 기대 형제 파일
21
+ 주소를 조립하던 코드는 새 파일에서 404 가 난다. `cb.storage.getPathUrl(storageId, path)` 는 그 경로의 파일로 리다이렉트되는
22
+ 주소(`/v1/file-path/{storageID}/{경로}`)를 돌려준다. 인증 헤더가 필요 없어 `<img src>`, 기준 주소 + 상대 경로 로딩에 쓸 수 있다.
23
+ - 대상은 `server_write`, `public_read`, `shared` 스토리지다. `private` 은 404 이고 응답의 `url`(서명 주소)을 쓴다.
24
+
25
+ ## [6.15.0] - 2026-11-11
26
+
27
+ ### Changed — `cb.database` 실시간 연결 거부의 이유를 알린다 (`reject_mode=close`)
28
+
29
+ - 브라우저는 실패한 WebSocket 핸드셰이크의 HTTP 상태를 읽지 못해, DB 실시간 연결의 거부(토큰 무효, 멤버 정지, 동시접속
30
+ 한도, 속도 제한, URL 쿼리 자격증명 거부 등)가 이유 없는 `Connection closed during handshake` 와 재연결 반복으로만 보였다.
31
+ 이제 `cb.database.connectRealtime()` 은 `cb.realtime` 처럼 `reject_mode=close` 로 협상하고, 서버가 보낸 이유를
32
+ `RealtimeConnectionError`(`code`, `message`, `closeCode` = 4000 + HTTP 상태, `retryable`, `retryAfterMs`, `details`)로
33
+ `connectRealtime()` 의 거부와 `onRealtimeError` 에 알린다.
34
+ - 재시도 규칙은 `cb.realtime` 과 같다. 다시 해도 같은 거부(4401 `unauthorized`, 4403 `member_revoked` 등)는 재연결을 멈추고
35
+ 알린다. 일시 장애, 속도 제한, 동시접속 한도(4503, 4429, 4402)는 `retryAfterMs` 보다 일찍 다시 붙지 않으면서 재연결을 이어
36
+ 가고, 재시도를 다 쓰면 일반 오류 대신 마지막 거부를 알린다. 티켓 발급 거부도 같은 규칙이다(예전에는 429 만 다시 붙었고,
37
+ 그때마다 `onRealtimeError` 로 알렸다).
38
+ - 열린 것만으로는 서버가 받아들였는지 알 수 없어, 열린 직후 `ping` 을 보내 첫 응답으로 연결을 확정한다. 그래서
39
+ `connectRealtime()` 이 한 왕복 늦게 끝난다. 협상을 모르는 예전 서버도 `ping` 에 답하므로 예전처럼 붙는다.
40
+ - `RealtimeConnectionError` 의 재시도 기본값: 서버가 `retryable` 을 보내지 않은 거부도 close 코드가 4429, 4500, 4503 이면
41
+ 재시도 가능으로 본다. `rate_limit_exceeded` 를 재시도 가능한 코드에 더했다.
42
+
43
+ ### Removed — 플랫폼 이슈의 게임 엔진 SDK 플랫폼 값
44
+
45
+ - `cb.support.reportPlatformBug({ sdkPlatform })` 와 `PlatformIssueDetail.sdk_platform` 의 타입에서 `"unity"`,
46
+ `"godot"`, `"unreal"` 을 뺀다. 게임 엔진 SDK 는 지원을 끝냈고, 서버도 이 값을 다른 모르는 값처럼 거부한다(400).
47
+ 남은 값은 `"web"`, `"node"`, `"cli"`, `"mcp"`, `"other"` 다. 값을 생략하면 SDK 가 `web`/`node` 를 정하는 동작은
48
+ 그대로다.
49
+
6
50
  ## [6.14.0] - 2026-11-11
7
51
 
8
52
  ### Security — WebSocket 연결 URL 에 자격증명을 싣지 않는다 (1회용 티켓)
package/README.md CHANGED
@@ -870,6 +870,12 @@ console.log(result.url) // 항상 동일한 URL
870
870
  // 경로로 파일 조회
871
871
  const file = await cb.storage.getByPath('storage-id', '/profiles/user123/avatar.png')
872
872
 
873
+ // 경로 주소 (6.16.0 부터) — 그 경로의 파일로 리다이렉트되는 고정 주소. 요청을 보내지 않고 주소만 만든다.
874
+ // 파일의 url(직접 주소)에는 경로가 없으므로, 한 폴더의 파일을 상대 경로로 읽을 때는 이 주소를 기준으로 쓴다.
875
+ // 대상: server_write, public_read, shared 스토리지 (private 은 404 — 응답의 url 을 쓴다)
876
+ const base = cb.storage.getPathUrl('storage-id', '/avatars/rig-1/')
877
+ const meta = await (await fetch(base + 'meta.json')).json()
878
+
873
879
  // 경로로 URL만 가져오기 (없으면 null)
874
880
  const url = await cb.storage.getUrlByPath('storage-id', '/profiles/user123/avatar.png')
875
881
 
@@ -1000,7 +1006,7 @@ await subscription.unsubscribe()
1000
1006
  await cb.realtime.disconnect()
1001
1007
  ```
1002
1008
 
1003
- #### 로그인 멤버 연결의 토큰 갱신과 멤버 폐기 (Unreleased)
1009
+ #### 로그인 멤버 연결의 토큰 갱신과 멤버 폐기 (6.12.0 부터)
1004
1010
 
1005
1011
  `cb.realtime.connect({ accessToken })` 과 `cb.database.connectRealtime({ accessToken })` 에 넘긴 토큰이 SDK 가 로그인으로
1006
1012
  들고 있는 멤버 세션(같은 앱, 같은 멤버)의 것이면, SDK 가 만료 전에 HTTP 요청과 같은 refresh 로 새 토큰을 받아 **연결을 끊지
@@ -1092,6 +1098,22 @@ try {
1092
1098
  구버전 서버면 지수 백오프). 연결 제한 시간(`timeout`, 기본 30초) 안에 못 붙을 때만 이 에러를 던집니다. `unauthorized` 처럼
1093
1099
  다시 해도 소용없는 거부는 바로 던집니다.
1094
1100
 
1101
+ `cb.database.connectRealtime()` 도 같은 방식으로 거부 이유를 받습니다(6.15.0 부터). 예전에는 이유 없는
1102
+ `Connection closed during handshake` 였습니다.
1103
+
1104
+ ```typescript
1105
+ try {
1106
+ await cb.database.connectRealtime({ accessToken })
1107
+ } catch (e) {
1108
+ if (e instanceof RealtimeConnectionError) {
1109
+ e.code // 'unauthorized' | 'member_revoked' | 'connection_limit_exceeded' | 'rate_limit_exceeded' | 'auth_unavailable' | ...
1110
+ e.closeCode // 4000 + HTTP 상태 (4401, 4403, 4402, 4429, 4503)
1111
+ e.retryable // true 면 SDK 가 retryAfterMs 이후로 스스로 다시 붙는다
1112
+ }
1113
+ }
1114
+ cb.database.onRealtimeError((e) => { /* 다시 붙지 않는 거부, 또는 재시도를 다 쓴 마지막 거부 */ })
1115
+ ```
1116
+
1095
1117
  #### Broadcast categories: publishers (v6.6.0)
1096
1118
 
1097
1119
  1명이 방송하고 많은 사람이 받는 카테고리는 콘솔에서 **방송인 역할**(`publisher_roles`)과 **발행 정책**(`send_policy`)을
@@ -1493,6 +1515,14 @@ console.log(cb.webrtc.isBroadcaster())
1493
1515
  // 비공개 룸 (로그인 회원) — 목록의 회원만 들어오고 볼 수 있다. 참가자 모두 같은 목록을 보낸다
1494
1516
  await cb.webrtc.connect({ roomId: `call:${callId}`, allowedMemberIds: [aliceId, bobId], localStream: stream })
1495
1517
 
1518
+ // SFU 방 (6.16.0 부터) — 서버가 미디어를 나눠 주는 방. 참가자끼리 IP 를 보지 못하고 수십 명이 들어갈 수 있다.
1519
+ // SDK 는 입장 토큰만 발급하고, 미디어 연결은 livekit-client 로 한다(SDK 에 포함되지 않음).
1520
+ // import { Room } from 'livekit-client'
1521
+ const sfu = await cb.webrtc.getSFUToken({ roomId: 'voice:fanmeeting-1', publish: true })
1522
+ const room = new Room()
1523
+ await room.connect(sfu.url, sfu.token)
1524
+ if (sfu.can_publish) await room.localParticipant.setMicrophoneEnabled(true)
1525
+
1496
1526
  // 룸 전환 (생략한 옵션은 현재 세션 값을 이어받습니다. allowedMemberIds 는 이어받지 않습니다)
1497
1527
  await cb.webrtc.switchRoom('live:room-2')
1498
1528
 
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.14.0" ? "6.14.0" : getPackageVersion();
173
+ var VERSION = "6.16.0" ? "6.16.0" : getPackageVersion();
174
174
  var DEFAULT_BASE_URL = "https://api.connectbase.world";
175
175
  var colors = {
176
176
  reset: "\x1B[0m",