connectbase-client 1.12.0 → 3.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 +132 -0
- package/MIGRATION-v2.md +149 -0
- package/README.md +23 -0
- package/dist/connect-base.umd.js +3 -3
- package/dist/index.d.mts +118 -98
- package/dist/index.d.ts +118 -98
- package/dist/index.js +161 -555
- package/dist/index.mjs +161 -555
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,138 @@
|
|
|
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.0.0] - 2026-04-28 — BREAKING
|
|
7
|
+
|
|
8
|
+
게임 서버 mechanism-only 재설계. ConnectBase 가 박아두던 게임 룰 (파티/로비/랭킹/매치메이킹/
|
|
9
|
+
killcam/highlight) 을 모두 제거하고, primitive (`cb.game.matchqueue`, `cb.game.leaderboard`,
|
|
10
|
+
`cb.game.scripts`) + 사용자 Lua 로 대체. 1:1 마이그레이션은 [MIGRATION_v3.md](../../../docs/sdk/MIGRATION_v3.md).
|
|
11
|
+
|
|
12
|
+
### Removed (BREAKING)
|
|
13
|
+
|
|
14
|
+
- **Lobby**: `listLobbies`, `createLobby`, `getLobby`, `joinLobby`, `leaveLobby`, `toggleReady`,
|
|
15
|
+
`startGame`, `kickPlayer`, `updateLobby`, `sendLobbyChat`, `invitePlayer`, `acceptInvite`,
|
|
16
|
+
`declineInvite`, `getPlayerInvites` 메서드 + 관련 타입 (`LobbyInfo`, `CreateLobbyRequest`,
|
|
17
|
+
`UpdateLobbyRequest`, `LobbyInvite`)
|
|
18
|
+
- **Party**: `createParty`, `joinParty`, `acceptPartyInvite`, `declinePartyInvite`,
|
|
19
|
+
`leaveParty`, `kickFromParty`, `inviteToParty`, `getParty`, `getMyParties`, `setReady`,
|
|
20
|
+
`setPartyMetadata`, `getPartyInvites`, `sendPartyChat` + `PartyInfo`, `PartyInvite`
|
|
21
|
+
- **Matchmaking**: `joinQueue`, `leaveQueue`, `getMatchStatus` + `JoinQueueRequest`,
|
|
22
|
+
`MatchmakingTicket`
|
|
23
|
+
- **Ranking**: `getLeaderboard`, `getPlayerStats`, `getPlayerRank` + `LeaderboardEntry` (구
|
|
24
|
+
player_id/rating/tier/wins/losses 시그니처. 신규 `LeaderboardScoreEntry` 가 대체).
|
|
25
|
+
- **Killcam/Highlight**: `cb.game.replay.killcam(...)`, `cb.game.replay.highlights(...)`
|
|
26
|
+
관련 endpoint 가 백엔드에서 제거되어 SDK 호출 시 404. 사용자가 `cb.game.replay.download`
|
|
27
|
+
로 raw frame 받아 클라/Lua 에서 직접 처리.
|
|
28
|
+
|
|
29
|
+
### Added — v3 primitive
|
|
30
|
+
|
|
31
|
+
- **Matchqueue** (`cb.game.matchqueue.*` → `enqueueMatch / listMatchqueue / cancelMatch`):
|
|
32
|
+
rating/region 등 attributes 는 free-form. 매칭 알고리즘은 사용자 Lua 가 list → notify.
|
|
33
|
+
- **Leaderboard** (`submitScore / getTopScores / getMemberRank / getRankAround / resetLeaderboard / removeFromLeaderboard`):
|
|
34
|
+
ELO/티어/시즌 박지 않음. 시즌은 key suffix (`ranks:2026q2`) 로 분리, 점수 공식은 Lua.
|
|
35
|
+
- **Scripts** (`uploadScript / listScripts / getScript / listScriptVersions /
|
|
36
|
+
activateScript / rollbackScript / disableScript`): Lua 스크립트 영속 메타 + 버전 + hot reload.
|
|
37
|
+
- 신규 타입: `MatchqueueTicket`, `MatchqueueListResponse`, `LeaderboardScoreEntry`,
|
|
38
|
+
`LeaderboardListResponse`, `ScriptMeta`, `ScriptVersion`, `ScriptListResponse`,
|
|
39
|
+
`ScriptVersionListResponse`, `ScriptDetailResponse`.
|
|
40
|
+
|
|
41
|
+
### Backend 영향
|
|
42
|
+
|
|
43
|
+
- game-server v3 부터 `/v1/game/:appID/matchqueue/:key/*`, `/leaderboards/:key/*`,
|
|
44
|
+
`/scripts/*` 라우트가 유일한 게임 메커니즘 endpoint. lobby/party/ranking/matchmaking
|
|
45
|
+
엔드포인트는 모두 404.
|
|
46
|
+
- 자세한 변경: [`docs/sdk/MIGRATION_v3.md`](../../../docs/sdk/MIGRATION_v3.md),
|
|
47
|
+
[`docs/game-server/RECIPES.md`](../../../docs/game-server/RECIPES.md).
|
|
48
|
+
|
|
49
|
+
### Migration 요약
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// Before (v2.x)
|
|
53
|
+
await cb.game.matchmaking.join({ mode: "ranked", rating: 1500 })
|
|
54
|
+
await cb.game.ranking.submit({ leaderboard: "elo", score: 2150 })
|
|
55
|
+
|
|
56
|
+
// After (v3.0)
|
|
57
|
+
await cb.game.enqueueMatch(appId, "ranked", userId, { rating: 1500 })
|
|
58
|
+
await cb.game.submitScore(appId, "elo", userId, 32, "incr")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## [2.0.0] - 2026-04-27 — BREAKING
|
|
62
|
+
|
|
63
|
+
Realtime presence/typing 단일화의 최종 단계. 1.13 deprecation 단계를 건너뛰고 즉시
|
|
64
|
+
deprecated 코드를 제거. presence/typing 의 단일 SoT 는 `cb.realtime.*`.
|
|
65
|
+
|
|
66
|
+
### Removed (BREAKING)
|
|
67
|
+
|
|
68
|
+
- **`cb.database.setPresence(status, device, metadata)`** — 코드 자체 제거. 호출 시 `TypeError`.
|
|
69
|
+
- **`cb.database.subscribePresence(userIds, callback)`** — 코드 자체 제거.
|
|
70
|
+
- **`DatabasePresenceState`** type — `PresenceInfo` (from `'./realtime'`) 사용.
|
|
71
|
+
- 1.13 에서 추가됐던 deprecation `console.warn` 헬퍼도 함께 제거 (필요 없음).
|
|
72
|
+
|
|
73
|
+
### Migration
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
// Before
|
|
77
|
+
cb.database.setPresence('online', 'web', { nickname: '홍길동' })
|
|
78
|
+
cb.database.subscribePresence(['user1', 'user2'], (states) => {
|
|
79
|
+
console.log(states['user1']?.last_seen)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
// After
|
|
83
|
+
await cb.realtime.setPresence('online', { device: 'web', metadata: { nickname: '홍길동' } })
|
|
84
|
+
const unsub = await cb.realtime.subscribePresence('user1', (info) => {
|
|
85
|
+
console.log(info.lastSeen)
|
|
86
|
+
})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
자세한 가이드: [MIGRATION-v2.md](./MIGRATION-v2.md). 필드 차이는 `user_id`→`userId`,
|
|
90
|
+
`last_seen` (ISO) → `lastSeen` (epoch ms), `'busy'` 상태 추가.
|
|
91
|
+
|
|
92
|
+
### Server-side
|
|
93
|
+
|
|
94
|
+
데이터 서버 측 presence/typing 코드도 함께 제거되었습니다. `presence_set` / `presence_subscribe`
|
|
95
|
+
/ `typing_*` 메시지를 데이터 서버 WebSocket 으로 보내면 `USE_SOCKET_SERVER` 에러가 반환됩니다.
|
|
96
|
+
|
|
97
|
+
## [1.13.0] - 2026-04-27
|
|
98
|
+
|
|
99
|
+
Realtime presence/typing 단일화 — `cb.database.setPresence` / `cb.database.subscribePresence`
|
|
100
|
+
는 v2.0.0 에서 제거됩니다. 신규 코드는 `cb.realtime.*` 를 사용하세요. 자세한 마이그레이션은
|
|
101
|
+
[MIGRATION-v2.md](./MIGRATION-v2.md) 참고.
|
|
102
|
+
|
|
103
|
+
### Deprecated
|
|
104
|
+
|
|
105
|
+
- **`cb.database.setPresence(status, device, metadata)`** → `cb.realtime.setPresence(status, { device, metadata })`
|
|
106
|
+
- **`cb.database.subscribePresence(userIds, onPresence)`** → `cb.realtime.subscribePresence(userId, handler)` 또는
|
|
107
|
+
`cb.realtime.onPresenceChange(handler)` (다중 사용자 일괄 수신).
|
|
108
|
+
- **`DatabasePresenceState`** type → `PresenceInfo` (from `'./realtime'`).
|
|
109
|
+
- 필드 네이밍: `user_id` → `userId`, `last_seen` (ISO) → `lastSeen` (epoch ms 숫자).
|
|
110
|
+
- 상태값: `'busy'` 추가 (PresenceInfo 만 지원).
|
|
111
|
+
|
|
112
|
+
호출 시 개발 환경(`process.env.NODE_ENV !== 'production'`)에서 `console.warn` 이 1회 출력됩니다.
|
|
113
|
+
런타임 동작은 1.12.x 와 동일합니다 (이번 버전은 deprecate 만, 코드 제거는 v2.0.0).
|
|
114
|
+
|
|
115
|
+
### Changed
|
|
116
|
+
|
|
117
|
+
- **WebSocket URL 기본값** `cb.database.connectRealtime` 의 기본 endpoint 가
|
|
118
|
+
`/v1/realtime/ws` → `/v1/database/realtime/ws` 로 변경. 기존 경로는 30일간 alias 로
|
|
119
|
+
유지되며 응답에 `Sunset` (RFC 8594) + `X-Deprecated-Endpoint` 헤더가 부착됩니다.
|
|
120
|
+
명시적으로 `dataServerUrl` 을 지정한 경우 자동 변환은 하지 않습니다 (Hyrum's Law 준수).
|
|
121
|
+
|
|
122
|
+
### Migration
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
// Before (1.12.x)
|
|
126
|
+
cb.database.setPresence('online', 'web', { nickname: '홍길동' })
|
|
127
|
+
cb.database.subscribePresence(['user1', 'user2'], (states) => {
|
|
128
|
+
console.log(states['user1']?.last_seen) // ISO string
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
// After (1.13+, 권장 — v2 호환)
|
|
132
|
+
cb.realtime.setPresence('online', { device: 'web', metadata: { nickname: '홍길동' } })
|
|
133
|
+
const unsubscribe = await cb.realtime.subscribePresence('user1', (info) => {
|
|
134
|
+
console.log(info.lastSeen) // epoch ms number
|
|
135
|
+
})
|
|
136
|
+
```
|
|
137
|
+
|
|
6
138
|
## [1.12.0] - 2026-04-26
|
|
7
139
|
|
|
8
140
|
Analytics 조회 정렬 옵션 정합성 수정 — `VisitorListOptions.sort_by` 의 TypeScript
|
package/MIGRATION-v2.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Migration to v2.0.0 — Presence/Typing 단일화
|
|
2
|
+
|
|
3
|
+
> 작성일: 2026-04-27
|
|
4
|
+
> 대상 버전: 1.12.x → 2.0.0 (1.13 deprecation 단계 생략, 즉시 제거)
|
|
5
|
+
> 영향: `cb.database.setPresence`, `cb.database.subscribePresence`, `DatabasePresenceState`, WebSocket URL
|
|
6
|
+
|
|
7
|
+
본 문서는 v1.12.x 이전에서 v2.0.0 으로 업그레이드할 때 필요한 변경 사항을 안내합니다.
|
|
8
|
+
v2.0.0 에서 데이터베이스 측 presence/typing API 가 코드에서 완전히 제거되었습니다
|
|
9
|
+
(호출 시 `TypeError`). presence/typing 의 단일 SoT 는 `cb.realtime.*` 입니다.
|
|
10
|
+
|
|
11
|
+
## 1. 책임 경계 변경
|
|
12
|
+
|
|
13
|
+
| 기능 | v1.12.x | v2.0.0 |
|
|
14
|
+
|------|---------|--------|
|
|
15
|
+
| presence 상태 설정/조회/구독 | `cb.database` / `cb.realtime` 양쪽 | `cb.realtime` 만 |
|
|
16
|
+
| typing 상태 | `cb.database` | `cb.realtime` 만 |
|
|
17
|
+
| DB 변경 구독 | `cb.database.connectRealtime` | (변경 없음) |
|
|
18
|
+
| WebSocket URL (DB) | `/v1/realtime/ws` | `/v1/database/realtime/ws` |
|
|
19
|
+
|
|
20
|
+
## 2. setPresence 마이그레이션
|
|
21
|
+
|
|
22
|
+
### Before (v1.12.x)
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
cb.database.setPresence('online', 'web', { nickname: '홍길동' })
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### After (v1.13+ / v2)
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
await cb.realtime.setPresence('online', {
|
|
32
|
+
device: 'web',
|
|
33
|
+
metadata: { nickname: '홍길동' }
|
|
34
|
+
})
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**차이점**
|
|
38
|
+
|
|
39
|
+
- `cb.realtime.setPresence` 는 `Promise<void>` 를 반환합니다 (기존은 동기 void).
|
|
40
|
+
- `device` 와 `metadata` 가 두 번째 객체 파라미터의 옵션 필드입니다.
|
|
41
|
+
- 상태값에 `'busy'` 가 추가되어 있습니다 (`'online' | 'away' | 'busy' | 'offline'`).
|
|
42
|
+
|
|
43
|
+
## 3. subscribePresence 마이그레이션
|
|
44
|
+
|
|
45
|
+
### Before (v1.12.x)
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
cb.database.subscribePresence(['user1', 'user2'], (states) => {
|
|
49
|
+
console.log(states['user1']?.last_seen) // string ISO
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### After (옵션 1 — 단일 사용자별 구독)
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const unsub1 = await cb.realtime.subscribePresence('user1', (info) => {
|
|
57
|
+
console.log(info.lastSeen) // number (epoch ms)
|
|
58
|
+
})
|
|
59
|
+
const unsub2 = await cb.realtime.subscribePresence('user2', (info) => {
|
|
60
|
+
console.log(info.userId, info.status, info.eventType) // join/leave/update
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// 정리
|
|
64
|
+
unsub1()
|
|
65
|
+
unsub2()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### After (옵션 2 — 앱 전체 변경 일괄 수신)
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const unsub = cb.realtime.onPresenceChange((info) => {
|
|
72
|
+
// 모든 사용자의 변경 이벤트가 한 콜백으로 전달됨
|
|
73
|
+
if (['user1', 'user2'].includes(info.userId)) {
|
|
74
|
+
console.log(info.userId, info.status)
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**차이점**
|
|
80
|
+
|
|
81
|
+
| 필드 | v1.12 (`DatabasePresenceState`) | v1.13+ (`PresenceInfo`) |
|
|
82
|
+
|------|-------------------------------|-----------------------|
|
|
83
|
+
| ID | `user_id` (snake) | `userId` (camel) |
|
|
84
|
+
| 마지막 활동 | `last_seen: string` (ISO) | `lastSeen: number` (epoch ms) |
|
|
85
|
+
| 상태 | `'online' \| 'away' \| 'offline'` | `'online' \| 'away' \| 'busy' \| 'offline'` |
|
|
86
|
+
| 이벤트 타입 | (없음) | `eventType?: 'join' \| 'leave' \| 'update'` |
|
|
87
|
+
|
|
88
|
+
### 변환 헬퍼 (마이그레이션 보조)
|
|
89
|
+
|
|
90
|
+
기존 `DatabasePresenceState` 모양으로 데이터를 가공하던 코드를 점진적으로 옮길 때 도움이
|
|
91
|
+
되도록, v1 호환 형태(snake_case · ISO 문자열) 로 변환하는 헬퍼 예제. v2.0.0 에서는
|
|
92
|
+
`DatabasePresenceState` type 이 제거되었으므로 inline 타입으로 정의한다.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import type { PresenceInfo } from 'connectbase-client'
|
|
96
|
+
|
|
97
|
+
interface LegacyPresenceState {
|
|
98
|
+
user_id: string
|
|
99
|
+
status: 'online' | 'away' | 'offline'
|
|
100
|
+
last_seen: string
|
|
101
|
+
device?: string
|
|
102
|
+
metadata?: Record<string, unknown>
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function fromPresenceInfo(info: PresenceInfo): LegacyPresenceState {
|
|
106
|
+
return {
|
|
107
|
+
user_id: info.userId,
|
|
108
|
+
status: info.status === 'busy' ? 'away' : info.status,
|
|
109
|
+
last_seen: new Date(info.lastSeen).toISOString(),
|
|
110
|
+
device: info.device,
|
|
111
|
+
metadata: info.metadata,
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 4. typing 마이그레이션 (있는 경우)
|
|
117
|
+
|
|
118
|
+
`cb.database` 에는 공개된 typing 메서드가 없으므로 추가 마이그레이션은 불필요합니다.
|
|
119
|
+
`cb.realtime.startTyping(roomId)` / `cb.realtime.stopTyping(roomId)` /
|
|
120
|
+
`cb.realtime.onTypingChange(roomId, handler)` 를 그대로 사용하세요.
|
|
121
|
+
|
|
122
|
+
## 5. WebSocket URL 변경
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
await cb.database.connectRealtime({
|
|
126
|
+
accessToken: 'xxx',
|
|
127
|
+
dataServerUrl: 'https://data.connectbase.world',
|
|
128
|
+
})
|
|
129
|
+
// SDK 는 자동으로 /v1/database/realtime/ws 로 연결 (v1.13+).
|
|
130
|
+
// 사용자가 dataServerUrl 의 host:port 만 지정하면 path 는 SDK 가 결정.
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
옛 경로(`/v1/realtime/ws`) 는 v2.0.0 과 함께 서버에서도 제거되었습니다. 사용자 측
|
|
134
|
+
firewall/proxy 에 `/v1/database/realtime/` 경로 허용 규칙이 있는지 확인하세요.
|
|
135
|
+
|
|
136
|
+
## 6. 런타임 동작 차이
|
|
137
|
+
|
|
138
|
+
- **v1.12.x**: 두 API 모두 동작.
|
|
139
|
+
- **v2.0.0**: `cb.database.setPresence` / `subscribePresence` 호출 시 `TypeError` (메서드 미존재).
|
|
140
|
+
|
|
141
|
+
## 7. 자동 마이그레이션 (codemod)
|
|
142
|
+
|
|
143
|
+
향후 별도 codemod 스크립트가 제공될 예정입니다. 우선은 위 가이드에 따라 수동 변경을
|
|
144
|
+
권장합니다 (필드 네이밍/시그니처 차이가 있어 수동 검토가 안전).
|
|
145
|
+
|
|
146
|
+
## 8. 문의
|
|
147
|
+
|
|
148
|
+
- 이슈: GitHub Issues
|
|
149
|
+
- 디스코드: 공식 채널의 `#sdk` 룸
|
package/README.md
CHANGED
|
@@ -708,6 +708,29 @@ await subscription.unsubscribe()
|
|
|
708
708
|
await cb.realtime.disconnect()
|
|
709
709
|
```
|
|
710
710
|
|
|
711
|
+
#### Presence / Typing
|
|
712
|
+
|
|
713
|
+
Presence(온라인 상태) 와 typing(입력 중 표시) 은 `cb.realtime.*` 가 단일 SoT 입니다.
|
|
714
|
+
v2.0.0 에서 `cb.database.setPresence` / `subscribePresence` 는 제거되었습니다.
|
|
715
|
+
v1.x 에서 마이그레이션은 [MIGRATION-v2.md](./MIGRATION-v2.md) 참고.
|
|
716
|
+
|
|
717
|
+
```typescript
|
|
718
|
+
// 본인 온라인 상태 publish
|
|
719
|
+
await cb.realtime.setPresence('online', { device: 'web', metadata: { nickname: '홍길동' } })
|
|
720
|
+
|
|
721
|
+
// 다른 사용자 상태 구독
|
|
722
|
+
const unsub = await cb.realtime.subscribePresence('user-id', (info) => {
|
|
723
|
+
console.log(info.userId, info.status, info.eventType) // join | leave | update
|
|
724
|
+
})
|
|
725
|
+
|
|
726
|
+
// 룸 단위 typing indicator
|
|
727
|
+
await cb.realtime.startTyping('room-id')
|
|
728
|
+
await cb.realtime.stopTyping('room-id')
|
|
729
|
+
const unsubTyping = await cb.realtime.onTypingChange('room-id', (typing) => {
|
|
730
|
+
console.log(typing.users) // 현재 입력 중인 사용자 ID 목록
|
|
731
|
+
})
|
|
732
|
+
```
|
|
733
|
+
|
|
711
734
|
#### AI Streaming
|
|
712
735
|
|
|
713
736
|
Real-time AI text generation using Gemini API through WebSocket.
|