connectbase-client 3.7.2 → 3.8.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 CHANGED
@@ -3,6 +3,162 @@
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
+ ## [3.8.1] - 2026-05-07
7
+
8
+ ### Fixed — `/v1/auth/re-issue` 가 콘솔/SDK cookie 공존 시 잘못된 토큰 발급
9
+
10
+ 3.8.0 의 cookie 우선순위가 [member → user → Bearer] 로 고정되어, 같은 브라우저에
11
+ platform 콘솔용 `refresh_token` 과 SDK 용 `cb_member_refresh_token` 이 공존할 때
12
+ (예: 외부 앱 SDK 로그인 후 콘솔 로그인) 콘솔의 `/v1/auth/re-issue` 호출이
13
+ AppMember access token 을 받아 콘솔 측 endpoint(예: `/v1/cli-auth/approve/:id`,
14
+ `claims.UserID == nil`) 에서 401 발생하던 회귀를 수정했습니다.
15
+
16
+ - SDK 의 `refreshAccessToken()` 이 `/v1/auth/re-issue` 호출 시 `X-Public-Key` 헤더를
17
+ 첨부합니다. 백엔드는 이 헤더로 SDK 호출(member cookie 우선) vs 콘솔 호출
18
+ (user cookie 우선) 을 식별합니다.
19
+ - 백엔드 `auth_controller.ReIssueAccessToken` 우선순위:
20
+ 1. `Authorization: Bearer` (가장 명시적)
21
+ 2. cookie 단독 시 X-Public-Key 헤더 유무로 분기
22
+ - Bearer 흐름 / 단일 cookie 흐름은 영향 없음. 회귀 시나리오만 정상화.
23
+
24
+ 3.8.0 사용자는 3.8.1 로 업데이트하면 됩니다. 백엔드 측은 함께 배포 필요.
25
+
26
+ ## [3.8.0] - 2026-05-07
27
+
28
+ ### Added — HttpOnly cookie 기반 refresh token 흐름 (XSS 면역 default 세션)
29
+
30
+ 3.7.x 의 `persistence` 콘솔 경고가 권고하던 "HttpOnly cookie + 기본값('none')" 흐름을
31
+ 실제로 동작하도록 SDK + 백엔드를 함께 구현했습니다.
32
+
33
+ - `persistence: 'none'` (기본값) 으로도 **새로고침 후 자동 복구** 가능. refresh token 은
34
+ 서버 HttpOnly cookie 로만 보관되어 JS 가 접근할 수 없습니다 (XSS 시 탈취 불가).
35
+ - `localStorage` / `sessionStorage` 옵션은 여전히 사용 가능하지만 위험 경고가 유지됩니다.
36
+
37
+ **SDK 변경:**
38
+
39
+ - 모든 ConnectBase API fetch 호출에 `credentials: 'include'` 적용 — HttpOnly refresh cookie 가
40
+ 자동 첨부됩니다 (`api.connectbase.world` host-only cookie 기준).
41
+ - `/v1/auth/re-issue` 호출이 cookie 만으로 동작 — 메모리에 refresh token 이 없어도 cookie 가
42
+ 있으면 access token 회복.
43
+ - `ConnectBase` 옵션에 `autoRestoreSession?: boolean` 추가 (브라우저 기본 true). 인스턴스 생성
44
+ 시 자동으로 cookie 기반 세션 복구를 시도하며, 미로그인/cookie 만료 시 silent 실패.
45
+ - `cb.restoreSession(): Promise<boolean>` 메서드로 명시적 await 도 가능.
46
+ - `persistence` 콘솔 경고를 갱신: 위험은 그대로 표시하되 'none' + HttpOnly cookie 흐름이
47
+ 실제로 작동함을 안내.
48
+
49
+ **백엔드 변경 (core-server):**
50
+
51
+ - `pkg/util/cookie` 에 `CrossSite` / `HostOnly` 옵션 추가 (SameSite=None + Secure + host-only).
52
+ - 새 공용 헬퍼 `core-server/app/util/auth_cookie/` — platform 용 `refresh_token` 과 AppMember/OAuth
53
+ 용 `cb_member_refresh_token` 두 종류를 분리해 충돌 방지.
54
+ - `/v1/public/app-members/{signin,signup,signout}` + `CreateGuestMember` + OAuth callback/exchange
55
+ 엔드포인트가 refresh token 을 HttpOnly cookie 로 발급.
56
+ - `/v1/auth/re-issue` 가 입력 우선순위 `[member cookie → user cookie → Authorization Bearer]`
57
+ 로 처리하며, cookie 흐름은 sliding (재호출 시 cookie 만료 7일 연장).
58
+ - 응답 body 의 `refresh_token` 은 하위호환을 위해 그대로 유지 (구버전 SDK / Node.js / 게임 SDK
59
+ 호환). 신규 SDK 는 cookie 만 신뢰합니다.
60
+
61
+ **마이그레이션:**
62
+
63
+ 기존 `persistence: 'sessionStorage'` 또는 `'localStorage'` 사용 중이었다면 옵션을 제거하기만
64
+ 하면 됩니다 (default 가 안전 흐름):
65
+
66
+ ```ts
67
+ // before (3.7.x)
68
+ new ConnectBase({ publicKey, persistence: 'sessionStorage' })
69
+
70
+ // after (3.8.0)
71
+ new ConnectBase({ publicKey }) // persistence: 'none' + autoRestoreSession: true (기본)
72
+ ```
73
+
74
+ 다른 origin 에서 호출하는 경우 (앱 도메인 ≠ `api.connectbase.world`) CORS 화이트리스트에 등록되어
75
+ 있어야 합니다 — 콘솔의 커스텀 도메인 등록 흐름이 그대로 적용됩니다.
76
+
77
+ ## [3.7.2] - 2026-05-01
78
+
79
+ ### Fixed — `cb.endpoint.connectWebSocket()` 메시지 깨짐 + permessage-deflate 누설
80
+
81
+ 3.7.0/3.7.1 의 endpoint WS pass-through 가 handshake 는 101 정상이지만 모든
82
+ 메시지가 binary frame 으로 도착하고 payload 가 origin (ComfyUI/aiohttp) 의
83
+ raw WS frame bytes (RSV1=1 압축 frame 포함) 라 client 의 native WebSocket
84
+ 이 디코드 불가하던 문제를 수정했습니다. 두 개의 별개 버그가 합쳐진 회귀:
85
+
86
+ 1. **CLI 가 WS frame parse/encode 안 함** — 기존 `startWSStream` 이
87
+ `socket.on('data')` 의 raw bytes 를 그대로 v2 binary frame payload 로
88
+ forward 해서 client 에 frame header (0x81/0x82/0xc1) 가 섞인 상태로 도달.
89
+ 2. **`Sec-WebSocket-Extensions` 가 upstream 까지 forward 됨** — 브라우저 native
90
+ WebSocket 이 default 로 `permessage-deflate` 를 광고하고, sanitize 가 hop-by-hop
91
+ 만 strip 해서 upstream (aiohttp default) 이 accept → compressed frame 송신
92
+ 시작. CLI 는 deflate context 가 없어 디코드 불가.
93
+
94
+ **Fix (CLI):**
95
+
96
+ - `UpstreamWsFrameParser`: incoming WS frame 을 parse 해서 payload 만 추출.
97
+ TEXT/BINARY/CONTINUATION/PING/CLOSE 처리, fragmented frame 은 누적, RSV1
98
+ (compression) frame 은 protocol error 로 거부.
99
+ - `buildClientFrame` / `createUpstreamTextFrame`: outgoing payload 를 RFC 6455
100
+ §5.3 client masking 적용한 masked WS frame 으로 encode 후 upstream 에 write.
101
+ - 로컬 upstream 요청에서 `Sec-WebSocket-Extensions` 헤더 strip — proxy chain 이
102
+ deflate context 를 end-to-end 로 carry 하지 못하므로 compression 자체를 비활성.
103
+
104
+ **회귀 영향 범위:** 3.7.0 의 모든 `cb.endpoint.connectWebSocket()` 사용자.
105
+ ComfyUI / vLLM 등 default-on compression origin 영향. 사용자가 3.7.2 로 업그레이드
106
+ + 터널 재시작 시 즉시 정상화. text/binary 구분은 client 측에서 항상 binary
107
+ (ArrayBuffer) 로 도달 — JSON 은 `TextDecoder.decode` 로 string 변환 필요.
108
+ Opcode propagation 은 별도 follow-up.
109
+
110
+ **회귀 가드:** `UpstreamWsFrameParser` 단위 테스트 (TEXT payload 추출 / fragmented
111
+ 누적 / RSV1 reject / TCP coalescing / split-across-chunks / PING callback) +
112
+ `buildClientFrame` masking round-trip + `WSStreamForwarder` e2e (real local HTTP
113
+ server 로 `Sec-WebSocket-Extensions` 미도달 검증).
114
+
115
+ ## [3.7.1] - 2026-05-01
116
+
117
+ ### Fixed — `cb.endpoint.connectWebSocket()` 가 502 로 떨어지던 회귀
118
+
119
+ 3.7.0 의 endpoint WS pass-through 가 client 단에서 항상 CF 502 page 로 떨어지던
120
+ 문제를 수정했습니다. Root cause 는 CLI 가 로컬 upstream HTTP 요청에 WebSocket
121
+ upgrade 헤더 (`Connection: Upgrade` + `Upgrade: websocket`) 를 누락한 것:
122
+ upstream (ComfyUI 등) 이 일반 GET 으로 인식하고 400 Bad Request 반환 → core-server
123
+ ReverseProxy 가 비-101 body 를 relay 하려다 `net/http: abort Handler` panic →
124
+ CF 가 corrupted response 를 자체 502 page 로 substitute.
125
+
126
+ **Primary fix (CLI):**
127
+
128
+ - `cli.ts` `startWSStream` 과 `tunnel-v2.ts` `WSStreamForwarder` 가 upstream
129
+ 요청에 `Connection: Upgrade` + `Upgrade: websocket` 명시적으로 set. tunnel-server
130
+ 의 `sanitizeRequestHeaders` 가 RFC 7230 hop-by-hop 으로 strip 하므로 CLI →
131
+ upstream 새 hop 에서 다시 추가 필요.
132
+
133
+ **Defensive fix (core-server, 자동 deploy):**
134
+
135
+ - `ForwardWebSocket` `ModifyResponse` 에서 비-101 upstream 응답 시 ErrorHandler
136
+ 경로로 라우팅 — ReverseProxy 가 비-101 body 를 relay 하려다 panic 하는 path
137
+ 차단. Upstream 이 정당한 사유로 비-101 (rate limit / auth 실패 등) 반환할 때도
138
+ 깨끗한 502 + 진단 메시지가 client 까지 도달.
139
+
140
+ **회귀 영향 범위:** 3.7.0 의 모든 `cb.endpoint.connectWebSocket()` 사용자.
141
+ 사용자가 3.7.1 로 업그레이드 + 터널 재시작 시 정상 동작.
142
+
143
+ **회귀 가드:** `tunnel-v2.test.ts` 가 `WSStreamForwarder` 의 upgrade 헤더 송신을
144
+ real local HTTP server 로 e2e 검증. Go 측 `proxy_service_test.go
145
+ TestForwardWebSocket_Non101UpstreamReturnsCleanError` 가 panic 없는 깨끗한 502
146
+ 반환을 락인.
147
+
148
+ ## [3.7.0] - 2026-05-01
149
+
150
+ ### Added — `cb.endpoint.connectWebSocket()` 네이티브 WebSocket 지원
151
+
152
+ Endpoint Proxy v2 (Phase 5) 가 출하되어, SDK 사용자가 `cb.endpoint.connectWebSocket()`
153
+ 한 줄로 ComfyUI / vLLM / 일반 모델 서버의 WebSocket 엔드포인트를 직접 연결할 수
154
+ 있습니다. CLI 도 v2 endpoint (`/v2/tunnel/connect`) 를 사용하도록 전환.
155
+
156
+ > **요구사항:** 백엔드 v2 endpoint 가 먼저 배포돼 있어야 동작합니다. 프로덕션
157
+ > 배포 완료 후 SDK 업그레이드를 권장합니다.
158
+
159
+ > **알려진 이슈:** 3.7.0 / 3.7.1 에서 WS frame leakage / 502 회귀가 발견되어
160
+ > **3.7.2 이상 사용 권장**. 자세한 내용은 3.7.1 / 3.7.2 항목 참고.
161
+
6
162
  ## [3.6.0] - 2026-05-01
7
163
 
8
164
  ### Added — `cb.realtime.stream()` 멀티모달 메시지 (Vision) 지원
@@ -168,6 +324,38 @@ await cb.knowledge.search(kbId, {
168
324
 
169
325
  자세한 사용법: [docs/knowledge-base/USER_ISOLATION.md](https://github.com/connectbase-world/connectbase/blob/release/docs/knowledge-base/USER_ISOLATION.md)
170
326
 
327
+ ## [3.4.0] - 2026-04-30
328
+
329
+ ### Added — `cb.analytics.reset()` 사용자 전환 오염 방지 helper
330
+
331
+ 같은 브라우저에서 다른 사용자로 로그인할 때 방문자 (`visitor_uid`) 데이터가 이전
332
+ 사용자의 식별자에 묶인 채로 남아 데이터가 오염되던 문제를 SDK 측에서 끊어 낼 수
333
+ 있는 helper 를 추가했습니다.
334
+
335
+ - **`cb.analytics.reset()`** — 로그아웃 시 호출. `visitor_uid` 를 새로 발급하고
336
+ in-flight 큐를 비웁니다.
337
+ - **자동 reset (1) — `identify(memberId)` 가 다른 멤버 감지** — 직전 세션과 다른
338
+ `memberId` 가 들어오면 SDK 가 자동으로 `reset()` → identify 순으로 처리.
339
+ - **자동 reset (2) — `linkMemberSilent` conflict 안전망** — 백엔드가 `409
340
+ VISITOR_LINKED_TO_OTHER_MEMBER` 응답을 주면 SDK 가 자동으로 reset 후 1회 재시도.
341
+ 명시적 `reset()` 호출을 누락한 경우의 fallback.
342
+
343
+ ### Changed — BatchEvent 멱등성
344
+
345
+ - 모든 `BatchEvent` 에 `event_id` (UUID) 자동 부여. 백엔드가 `(visitor_id,
346
+ event_id)` UNIQUE 인덱스 + `OnConflict DoNothing` 으로 at-least-once 재전송 시
347
+ 중복 INSERT 차단. SDK 사용자 입장에서 추가 작업 없음.
348
+
349
+ ### Fixed — 첫 방문 봇 오판 방지
350
+
351
+ - `flushSync` (`navigator.sendBeacon`) 호출에 `user_agent` 를 첨부 — 첫 방문 직후
352
+ `pagehide` 로 flush 될 때 백엔드가 UA 누락으로 봇으로 분류해 카운트가 누락되던
353
+ 문제 해결.
354
+
355
+ **서버 측 동시 변경:** `LinkMember` idempotent 처리, `WebPageView.event_id` 컬럼 +
356
+ UNIQUE 인덱스, `link-member` 옵셔널 토큰 검증 (Authorization Bearer 가 있으면
357
+ AppMember 토큰의 `member_id` 와 body 일치 검증, 없으면 BC 보존 + 경고 로그).
358
+
171
359
  ## [3.3.1] - 2026-04-30
172
360
 
173
361
  ### Fixed — Docs