connectbase-client 5.13.0 → 6.0.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,75 @@
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.0.0] - 2026-08-20
7
+
8
+ ### BREAKING — `realtime.isConnected()` 가 SSE 폴백에서 더 이상 true 를 반환하지 않습니다
9
+
10
+ WS 가 차단된 망에서 SDK 는 SSE 폴백으로 내려가는데, 이 모드에서는 `subscribe` / `sendMessage` /
11
+ `setPresence` / typing 이 **전부 예외를 던집니다**. 그런데 `isConnected()` 는 계속 true 였습니다.
12
+ 앱은 "연결됨"으로 판단하고 진행하지만 아무것도 오가지 않아, 다른 사용자가 화면에서 사라지고
13
+ 채팅이 나가지 않는데 에러도 없는 상태로 조용히 멈췄습니다 (platform-issue `01a01e6a-3cb1`).
14
+
15
+ 이제 `isConnected()` 는 **pub/sub 사용 가능 여부**를 반영합니다 — WS 로 연결됐을 때만 true 입니다.
16
+
17
+ 마이그레이션:
18
+
19
+ | 하려던 일 | 이전 | 지금 |
20
+ |---|---|---|
21
+ | pub/sub 가능한지 | `isConnected()` | `isConnected()` (그대로) |
22
+ | AI 스트리밍 가능한지 | `isConnected()` | **`isStreamReady()`** |
23
+ | 다운그레이드 안내 | `transport !== 'ws'` 폴링 | **`isDegraded()`** |
24
+
25
+ `stream()` 게이팅에 `isConnected()` 를 쓰고 있었다면 `isStreamReady()` 로 바꾸세요. 그대로 두면
26
+ SSE 폴백 상태에서 스트리밍을 건너뛰게 됩니다.
27
+
28
+ ### Added — `realtime.isDegraded()` / `realtime.isStreamReady()`
29
+
30
+ - `isDegraded()`: SSE 폴백으로 내려간 상태. 사용자에게 "제한된 네트워크" 배너를 띄울 지점입니다.
31
+ - `isStreamReady()`: WS/SSE 무관하게 연결이 서 있는지. 종전 `isConnected()` 와 같은 판정입니다.
32
+
33
+ ### Added — `webrtc.createSession()`: 기능별 독립 WebRTC 세션
34
+
35
+ `cb.webrtc` 는 인스턴스 하나가 소켓 하나와 룸 하나만 들고 이벤트 핸들러도 전역이라, 한 앱에
36
+ WebRTC 기능이 둘 이상이면(예: 공간 음성채팅 + 1:1 통화) 서로 연결을 뺏고 이벤트가 교차했습니다
37
+ — 음성채팅이 연결을 선점하면 전화가 "이미 연결되어 있거나 연결 중입니다"로 100% 실패하고,
38
+ 음성채팅에 누가 들어오면 전화 훅의 `onRemoteStream` 이 발동해 통화 화면이 뜨는 식입니다
39
+ (platform-issue `01a01e6a-38cc`).
40
+
41
+ ```typescript
42
+ const voice = cb.webrtc.createSession()
43
+ const call = cb.webrtc.createSession()
44
+
45
+ voice.onRemoteStream((peerId, stream) => attachToSpatialAudio(peerId, stream))
46
+ call.onRemoteStream((peerId, stream) => showCallScreen(stream))
47
+
48
+ await voice.connect({ roomId: 'voice:lobby', localStream: mic })
49
+ await call.connect({ roomId: 'call:alice-bob', localStream: mic })
50
+ ```
51
+
52
+ 각 세션은 소켓, 룸, 리스너, 피어 연결을 독립적으로 갖고 인증 정보만 공유합니다.
53
+
54
+ ### Added — `webrtc.switchRoom(roomId, options?)`
55
+
56
+ `disconnect()` 후 곧바로 `connect()` 하던 룸 전환을 안전하게 감쌉니다. 생략한 옵션
57
+ (`userId` / `isBroadcaster` / `localStream`)은 현재 세션 값을 이어받습니다.
58
+
59
+ ### Fixed — `webrtc.disconnect()` 후 옛 소켓의 늦은 `onclose` 가 새 연결을 오염시키던 문제
60
+
61
+ `disconnect()` 가 `this.ws = null` 로 참조만 끊고 핸들러를 떼지 않아, 뒤늦게 도착한 close
62
+ 이벤트가 **이미 새로 연결 중인 인스턴스**에 대고 실행됐습니다. `handleDisconnect()` 가 state 를
63
+ 'disconnected' 로 덮어쓰고 새로 만든 피어 연결까지 정리해, 룸 A → 룸 B 전환이 "끊겼다"로
64
+ 오판됐습니다 (platform-issue `01a01e6a-3550`).
65
+
66
+ 소켓마다 세대(generation) 토큰을 발급해 핸들러가 자기 소켓의 이벤트인지 확인하고,
67
+ `disconnect()` 는 핸들러를 명시적으로 떼어냅니다. 연결 중인 소켓도 확실히 닫아 서버에 유령
68
+ 피어로 남지 않게 했습니다.
69
+
70
+ ### Added — `ICEServersResponse.expires_at`
71
+
72
+ ephemeral TURN 자격증명의 만료 시각(Unix 초). STUN 전용 구성에서는 0 입니다. 서버는 이미
73
+ 내려주고 있었는데 타입에 없었습니다.
74
+
6
75
  ## [5.13.0] - 2026-08-13
7
76
 
8
77
  ### Added — 패키징 앱 네이티브 브릿지: OAuth 인앱 브라우저 로그인 + 데스크톱 창 제어/CPU/클립보드 `has` 노출
package/README.md CHANGED
@@ -939,6 +939,22 @@ await subscription.unsubscribe()
939
939
  await cb.realtime.disconnect()
940
940
  ```
941
941
 
942
+ #### Connection state (v6.0.0)
943
+
944
+ WS 가 차단된 망에서 SDK 는 SSE 폴백으로 내려갑니다. 이 모드에서는 AI 스트리밍만 되고
945
+ pub/sub 계열(`subscribe` / `sendMessage` / `setPresence` / typing)은 예외를 던집니다.
946
+ 그래서 판정이 세 갈래입니다:
947
+
948
+ ```typescript
949
+ cb.realtime.isConnected() // pub/sub 가능? — WS 로 연결됐을 때만 true
950
+ cb.realtime.isStreamReady() // AI 스트리밍 가능? — WS/SSE 무관, 연결만 서 있으면 true
951
+ cb.realtime.isDegraded() // SSE 폴백으로 내려갔나? — 사용자 안내용
952
+ cb.realtime.transport // 'ws' | 'sse' | null
953
+ ```
954
+
955
+ > **v5 → v6 BREAKING**: v5 까지 `isConnected()` 는 SSE 폴백에서도 true 였습니다.
956
+ > 스트리밍 게이팅에 쓰고 있었다면 `isStreamReady()` 로 바꾸세요.
957
+
942
958
  #### Presence / Typing
943
959
 
944
960
  Presence(온라인 상태) 와 typing(입력 중 표시) 은 `cb.realtime.*` 가 단일 SoT 입니다.
@@ -1286,10 +1302,32 @@ cb.webrtc.onRemoteStream((peerId, remoteStream) => {
1286
1302
  videoElement.srcObject = remoteStream
1287
1303
  })
1288
1304
 
1305
+ // 룸 전환 (생략한 옵션은 현재 세션 값을 이어받습니다)
1306
+ await cb.webrtc.switchRoom('live:room-2')
1307
+
1289
1308
  // 연결 해제
1290
1309
  cb.webrtc.disconnect()
1291
1310
  ```
1292
1311
 
1312
+ #### 기능별 독립 세션 (v6.0.0)
1313
+
1314
+ `cb.webrtc` 는 소켓 하나와 룸 하나만 듭니다. 한 앱에 WebRTC 기능이 둘 이상이면
1315
+ (예: 공간 음성채팅 + 1:1 통화) 기능마다 세션을 하나씩 만드세요 — 각자 소켓, 룸,
1316
+ 이벤트 리스너, 피어 연결을 독립적으로 갖습니다.
1317
+
1318
+ ```typescript
1319
+ const voice = cb.webrtc.createSession()
1320
+ const call = cb.webrtc.createSession()
1321
+
1322
+ voice.onRemoteStream((peerId, s) => attachToSpatialAudio(peerId, s))
1323
+ call.onRemoteStream((peerId, s) => showCallScreen(s))
1324
+
1325
+ await voice.connect({ roomId: 'voice:lobby', localStream: mic })
1326
+ await call.connect({ roomId: 'call:alice-bob', localStream: mic })
1327
+
1328
+ call.disconnect() // voice 는 그대로 유지됩니다
1329
+ ```
1330
+
1293
1331
  ### Payments & Subscriptions
1294
1332
 
1295
1333
  ```typescript