connectbase-client 6.12.0 → 6.14.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 +71 -0
- package/README.md +8 -1
- package/dist/cli.js +1 -1
- package/dist/connect-base.umd.js +5 -5
- package/dist/index.d.mts +259 -67
- package/dist/index.d.ts +259 -67
- package/dist/index.js +441 -79
- package/dist/index.mjs +440 -79
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,77 @@
|
|
|
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.14.0] - 2026-11-11
|
|
7
|
+
|
|
8
|
+
### Security — WebSocket 연결 URL 에 자격증명을 싣지 않는다 (1회용 티켓)
|
|
9
|
+
|
|
10
|
+
- 브라우저 WebSocket 은 헤더를 붙일 수 없어 SDK 가 멤버 토큰과 공개 키를 URL 쿼리(`?access_token=`, `?token=`,
|
|
11
|
+
`?public_key=`)에 실었다. URL 은 브라우저 기록, 중간 프록시와 터널, 서버 로그에 남는다. 이제 연결(재연결)마다 헤더로
|
|
12
|
+
30초짜리 1회용 티켓을 받아 `?ticket=` 만 싣는다. 서버는 티켓에서 자격증명을 되살려 예전과 같은 인증을 하므로 연결의
|
|
13
|
+
권한, 토큰 만료 집행, 연결 위 토큰 갱신(`token_refresh`)은 그대로다.
|
|
14
|
+
- `cb.realtime.connect()` → `POST {socketUrl}/v1/realtime/ws-ticket`
|
|
15
|
+
- `cb.database.connectRealtime()` → `POST {dataServerUrl}/v1/database/realtime/ws-ticket` (cross-app OAuth 토큰 포함)
|
|
16
|
+
- `cb.game` 룸 클라이언트, WebSocket 전송 → `POST {gameServerUrl}/v1/game/{appId}/ws-ticket`
|
|
17
|
+
- `cb.webrtc.connect()` 시그널링 → `POST {webrtcUrl}/v1/apps/{appId}/signaling/ws-ticket`
|
|
18
|
+
- 서버가 티켓 발급을 모르면(404/405/501, 이 기능 전 서버) 그 서버에는 다시 묻지 않고 예전처럼 URL 자격증명으로 붙는다.
|
|
19
|
+
티켓 저장소 일시 장애(503 `ws_ticket_unavailable`), 네트워크 또는 CORS 실패, 5초 시간 초과도 예전 방식으로 붙는다.
|
|
20
|
+
- 발급이 자격증명을 거부하면(401, 403, 402, 429 등) 소켓을 열지 않고 이유를 알린다. 브라우저 WebSocket 은 핸드셰이크
|
|
21
|
+
거부의 이유를 읽을 수 없어 예전에는 같은 거부가 이유 없는 연결 실패로 보였다.
|
|
22
|
+
- `cb.realtime.connect()`: `RealtimeConnectionError`(`code` 는 서버 코드, `closeCode` 는 4000+HTTP 상태). `rate_limited`
|
|
23
|
+
는 예전처럼 연결 제한 시간 안에서 다시 시도한다.
|
|
24
|
+
- `cb.database.connectRealtime()`: `RealtimeConnectionError` 로 reject 하고 `onRealtimeError` 로도 알린다.
|
|
25
|
+
- `cb.game`: `GameError`(`code` 는 서버 코드). `cb.webrtc.connect()`: `WsTicketError`(`status`, `code`).
|
|
26
|
+
- 새 실시간 거부 코드 `invalid_ws_ticket`(티켓 만료 또는 이미 쓰임), `ws_ticket_unavailable`(서버 티켓 저장소 일시 장애)은
|
|
27
|
+
`connect()` 가 새 티켓으로 스스로 다시 시도한다. `query_credential_rejected` 는 서버가 URL 쿼리 자격증명을 받지 않도록
|
|
28
|
+
설정됐다는 뜻이다(`WS_QUERY_CREDENTIAL_POLICY`, 기본 허용).
|
|
29
|
+
- `WsTicketError` 를 내보낸다.
|
|
30
|
+
- 연결이 소켓을 열기 전에 발급 요청 한 번을 기다린다. 테스트에서 `WebSocket` 생성이 `connect()` 와 같은 틱에 일어난다고
|
|
31
|
+
가정했다면 소켓이 만들어질 때까지 기다리도록 바꿔야 한다.
|
|
32
|
+
|
|
33
|
+
## [6.13.0] - 2026-11-11
|
|
34
|
+
|
|
35
|
+
### Security — WebRTC 역할과 룸 인가를 서버가 정한 대로 따른다
|
|
36
|
+
|
|
37
|
+
- `cb.webrtc.connect({ allowedMemberIds })`(REST `joinRoom` 의 `allowed_member_ids`)를 더한다. 이 연결이 룸을 새로 열면
|
|
38
|
+
목록의 회원과 자신만 들어오는 비공개 룸이 된다(로그인 회원만, 최대 50명). 목록 밖 회원과 익명은 들어오지도, 룸 목록과
|
|
39
|
+
참가자 조회로 보지도 못한다. 이미 공개 룸으로 열린 같은 ID 에 목록을 들고 오면 들어가지 않고 오류로 끝난다.
|
|
40
|
+
`cb.webrtc.isPrivateRoom()` 으로 확인한다. `switchRoom()` 은 이 목록을 이어받지 않는다.
|
|
41
|
+
- `cb.webrtc.isBroadcaster()` 를 더한다. `joined` 의 `is_broadcaster`(서버가 정한 역할)를 돌려준다. 요청(`isBroadcaster: true`)과
|
|
42
|
+
다를 수 있다 — 익명 연결, 채널 방송자 역할(`publisher_roles`)이 없는 회원은 시청자다.
|
|
43
|
+
- `cb.webrtc.onWarning(({ code, message }) => ...)` 를 더한다. 서버가 요청을 바꾼 이유(`broadcaster_requires_auth`,
|
|
44
|
+
`broadcaster_role_required`, `quota_check_degraded`)가 온다. 예전에는 버려졌다.
|
|
45
|
+
- join 메시지에 `user_id` 를 싣지 않는다. 서버는 2026-11-08 부터 읽지 않았다(참가자 신원은 인증 정보에서 온다).
|
|
46
|
+
`connect({ userId })` 는 SDK 안에서만 쓰는 값으로 남는다.
|
|
47
|
+
|
|
48
|
+
### Fixed — WebRTC 오류 문구, 서버에 없는 필드
|
|
49
|
+
|
|
50
|
+
- 할당량, 동시접속 초과처럼 `{ error, message }` 객체로 오는 시그널링 `error` 가 `Unknown error` 로 바뀌던 것을 고쳐
|
|
51
|
+
`message` 를 그대로 전한다.
|
|
52
|
+
- `PeerInfo.joined_at` 을 뺀다. 서버가 보낸 적이 없는 필드였다(늘 `undefined`).
|
|
53
|
+
- `RoomSummary.private`, `JoinRoomResponse.private`, `JoinRoomRequest.allowed_member_ids` 타입을 서버 응답에 맞춰 더한다.
|
|
54
|
+
|
|
55
|
+
### Security — 구독 금액도 서버의 가격표가 정한다
|
|
56
|
+
|
|
57
|
+
- `cb.subscription.create({ product_id })` 형태를 더한다. 콘솔 가격표의 **정기 상품**(주기가 있는 상품)으로 구독하면
|
|
58
|
+
금액, 통화, 주기, 플랜명, 무료 체험, MoR PG 가격 ref 를 서버가 상품에서 정하고, 첫 청구는 기본으로 즉시다.
|
|
59
|
+
`changePlan(id, { product_id })`, `previewChangePlan`, `chargeWithBillingKey({ product_id, quantity })`,
|
|
60
|
+
`update(id, { product_id })`(서버 호출만)도 같다.
|
|
61
|
+
- 금액을 직접 보내는 기존 형태는 그대로 동작한다. 다만 서버는 결제 설정의 금액 출처가 `client`(레거시)인 앱이거나 서버 호출
|
|
62
|
+
(시크릿 키, service_role 함수)일 때만 받는다. 가격표 전용(`catalog`) 앱의 브라우저 호출에서는:
|
|
63
|
+
- 금액 지정 403 `client_amount_not_allowed`, `start_now: false` 와 `billing_day` 403 `client_schedule_not_allowed`
|
|
64
|
+
- `update()` 로 금액, 플랜명, 상품 변경 403 `client_plan_change_not_allowed`
|
|
65
|
+
- `changePlan()` 에 `provider_price_ref` 직접 지정 403, 지금 정산하지 않는 `proration_mode` 와 `on_payment_failure:
|
|
66
|
+
'apply_change'` 403 `proration_mode_not_allowed`
|
|
67
|
+
- 요청 타입을 유니온으로 나눴다(`CreateSubscriptionWithProduct | CreateSubscriptionWithAmount`,
|
|
68
|
+
`ChangePlanWithProduct | ChangePlanWithPriceRef`, `ChargeWithBillingKeyProduct | ChargeWithBillingKeyAmount`). 두 형태를
|
|
69
|
+
섞으면 컴파일 에러다(서버도 400 `product_with_amount_fields`).
|
|
70
|
+
- `SubscriptionResponse.product_id` 를 더한다. 권한은 `metadata` 가 아니라 이 값으로 지급한다. 서버가 금액을 직접 바꾸거나
|
|
71
|
+
PG 가 가격표에 없는 가격으로 바꾸면 비워진다. `chargeWithBillingKey()` 응답에 `currency`, `product_id`, `quantity` 가 온다.
|
|
72
|
+
- 새 오류 코드: `product_not_recurring`, `product_is_recurring`(정기 상품을 `payment.prepare` 에 넘김),
|
|
73
|
+
`product_price_ref_missing`(MoR 구독에 쓸 PG 가격 ref 가 상품에 없음), `subscription_amount_update_unsupported`
|
|
74
|
+
(PG 가 청구 금액을 정하는 구독의 금액만 변경), `order_id_conflict`(같은 `order_id` 를 다른 금액이나 상품으로 재시도),
|
|
75
|
+
`subscription_amount_mismatch`(첫 청구 승인 금액 불일치).
|
|
76
|
+
|
|
6
77
|
## [6.12.0] - 2026-11-11
|
|
7
78
|
|
|
8
79
|
### Changed — 세션이 없다는 것을 이미 알면 `getMe()` 가 서버에 묻지 않는다
|
package/README.md
CHANGED
|
@@ -1486,7 +1486,14 @@ cb.webrtc.onRemoteStream((peerId, remoteStream) => {
|
|
|
1486
1486
|
videoElement.srcObject = remoteStream
|
|
1487
1487
|
})
|
|
1488
1488
|
|
|
1489
|
-
//
|
|
1489
|
+
// 역할은 서버가 정한다 — 익명 연결이나 채널 방송자 역할(publisher_roles)이 없는 회원은 시청자
|
|
1490
|
+
cb.webrtc.onWarning(({ code, message }) => console.warn(code, message))
|
|
1491
|
+
console.log(cb.webrtc.isBroadcaster())
|
|
1492
|
+
|
|
1493
|
+
// 비공개 룸 (로그인 회원) — 목록의 회원만 들어오고 볼 수 있다. 참가자 모두 같은 목록을 보낸다
|
|
1494
|
+
await cb.webrtc.connect({ roomId: `call:${callId}`, allowedMemberIds: [aliceId, bobId], localStream: stream })
|
|
1495
|
+
|
|
1496
|
+
// 룸 전환 (생략한 옵션은 현재 세션 값을 이어받습니다. allowedMemberIds 는 이어받지 않습니다)
|
|
1490
1497
|
await cb.webrtc.switchRoom('live:room-2')
|
|
1491
1498
|
|
|
1492
1499
|
// 연결 해제
|
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.
|
|
173
|
+
var VERSION = "6.14.0" ? "6.14.0" : getPackageVersion();
|
|
174
174
|
var DEFAULT_BASE_URL = "https://api.connectbase.world";
|
|
175
175
|
var colors = {
|
|
176
176
|
reset: "\x1B[0m",
|