connectbase-client 3.13.0 → 3.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 +80 -0
- package/README.md +44 -17
- package/dist/connect-base.umd.js +4 -4
- package/dist/index.d.mts +181 -10
- package/dist/index.d.ts +181 -10
- package/dist/index.js +161 -50
- package/dist/index.mjs +160 -50
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,86 @@
|
|
|
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.14.0] - 2026-05-14
|
|
7
|
+
|
|
8
|
+
### Added — `GameError` 클래스 + `createRoom` 응답 메타
|
|
9
|
+
|
|
10
|
+
- 신규 export: `GameError` (extends `Error`) — game-server 의 `error` 메시지를 일관된
|
|
11
|
+
인스턴스로 surface. `.code`, `.phase`, `.feature`, `.originClientId`, `.requested`,
|
|
12
|
+
`.available` 모두 노출. `instanceof GameError` 로 UI 분기 가능.
|
|
13
|
+
- 신규 export: `GameErrorCode` literal union — `'SCRIPT_NOT_FOUND' | 'NO_ACTION_HANDLER'
|
|
14
|
+
| 'FEATURE_DISABLED' | 'SCRIPT_ERROR' | 'SCRIPT_TIMEOUT' | 'RATE_LIMITED' |
|
|
15
|
+
'QUOTA_EXCEEDED' | 'TIMEOUT' | 'UNKNOWN' | (string & {})`.
|
|
16
|
+
- 신규 export: `CreateRoomResult` 타입 — `{ roomId, state, scriptName?, scriptVersion? }`.
|
|
17
|
+
- 신규 메서드: `GameRoom.createRoomDetailed(config)` + `GameRoomTransport.createRoomDetailed(config)`
|
|
18
|
+
— server 가 attach 한 lua script 의 이름/버전을 client 가 즉시 검증할 수 있게 응답에 포함.
|
|
19
|
+
- 신규 getter: `room.scriptName` / `room.scriptVersion` (`GameRoom` + `GameRoomTransport`)
|
|
20
|
+
— 마지막 `createRoom` 응답의 메타. `joinRoom`/`leaveRoom`/`disconnect` 시 reset.
|
|
21
|
+
- 기존 `createRoom(config)` 의 시그니처는 그대로 (호환). 내부적으로 `createRoomDetailed`
|
|
22
|
+
를 호출하고 `.state` 만 반환.
|
|
23
|
+
- `onError` 콜백 시그니처가 `Event | ErrorMessage` → `Event | GameError` 로 변경 (호환:
|
|
24
|
+
`ErrorMessage` 의 모든 필드가 `GameError` 인스턴스에 동일하게 surface 됨).
|
|
25
|
+
|
|
26
|
+
### Changed (BREAKING) — `disableScript` rename + `deleteScript` 신규
|
|
27
|
+
|
|
28
|
+
server 측 `DELETE /v1/game/:appID/scripts/:name` 의 의미가 **Disable → hard-delete** 로
|
|
29
|
+
변경된 것에 대응:
|
|
30
|
+
|
|
31
|
+
- `GameAPI.disableScript(appId, name)` **제거**. 대체: `GameAPI.deactivateScript(appId, name)`
|
|
32
|
+
— `POST /scripts/:name/deactivate` 호출 (코드/버전 보존, 재활성화 가능).
|
|
33
|
+
- `GameAPI.deleteScript(appId, name)` **신규** — `DELETE /scripts/:name` 호출 (메타 + 모든
|
|
34
|
+
버전 영구 제거, 복구 불가).
|
|
35
|
+
|
|
36
|
+
### Fixed — `error` 메시지 분류 메타 손실 회귀
|
|
37
|
+
|
|
38
|
+
이전엔 모든 `reject(new Error(msg.data.message))` 로 server 의 `code`/`phase`/`feature`/
|
|
39
|
+
`origin_client_id`/`requested`/`available` 가 손실되어 SDK 사용자가 UI 분기를 만들 수
|
|
40
|
+
없었다 (platform-issue 019e21dd, NJB 2026-05-13). 이제 `GameError` 인스턴스로 reject
|
|
41
|
+
되어 모든 메타가 보존된다.
|
|
42
|
+
|
|
43
|
+
### Migration
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// Before
|
|
47
|
+
import { ErrorMessage } from 'connectbase-client'
|
|
48
|
+
room.on('error', (err) => {
|
|
49
|
+
if ((err as ErrorMessage).code === 'FEATURE_DISABLED') { /* ... */ }
|
|
50
|
+
})
|
|
51
|
+
await cb.game.disableScript(appId, 'old-script')
|
|
52
|
+
|
|
53
|
+
// After
|
|
54
|
+
import { GameError } from 'connectbase-client'
|
|
55
|
+
room.on('error', (err) => {
|
|
56
|
+
if (err instanceof GameError) {
|
|
57
|
+
if (err.code === 'SCRIPT_NOT_FOUND') console.error('candidates:', err.available)
|
|
58
|
+
if (err.code === 'NO_ACTION_HANDLER') console.error('handler for', err.phase, 'undefined')
|
|
59
|
+
if (err.code === 'FEATURE_DISABLED') console.error('feature off:', err.feature)
|
|
60
|
+
if (err.originClientId) console.warn('error from other player:', err.originClientId)
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
await cb.game.deactivateScript(appId, 'old-script') // 비활성화 (코드 보존)
|
|
64
|
+
await cb.game.deleteScript(appId, 'really-old') // 영구 삭제 (신규)
|
|
65
|
+
|
|
66
|
+
// createRoom 응답 검증 패턴 (NJB regression 가드)
|
|
67
|
+
const { state, scriptName, scriptVersion } = await room.createRoomDetailed({ scriptName: 'njb-main' })
|
|
68
|
+
if (scriptName !== 'njb-main') {
|
|
69
|
+
throw new Error(`script attach mismatch: expected njb-main got ${scriptName}`)
|
|
70
|
+
}
|
|
71
|
+
console.log('attached', scriptName, 'v', scriptVersion)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## [3.13.1] - 2026-05-13
|
|
75
|
+
|
|
76
|
+
### Documentation — README batch/transaction 예제 타입 회귀 수정
|
|
77
|
+
|
|
78
|
+
README 의 `cb.database.batch()` / `cb.database.transaction()` 예제가 구 시그니처
|
|
79
|
+
(`table: 'string'`) 를 사용해 `tsc --noEmit` 에서 `TS2353` 발생하던 문제 수정.
|
|
80
|
+
|
|
81
|
+
- `table:` → `table_id:` (UUID, 실제 `BatchOperation` 타입과 일치)
|
|
82
|
+
- 3.12+ 의 `success:false` throw 동작 반영 — try/catch 패턴 명시
|
|
83
|
+
|
|
84
|
+
코드 변경은 없음. README 만 갱신.
|
|
85
|
+
|
|
6
86
|
## [3.13.0] - 2026-05-13
|
|
7
87
|
|
|
8
88
|
### Removed — `PlatformIssueDetail.triage_summary` / `triaged_at` 필드
|
package/README.md
CHANGED
|
@@ -65,8 +65,20 @@ gameClient
|
|
|
65
65
|
await gameClient.connect()
|
|
66
66
|
const state = await gameClient.createRoom({
|
|
67
67
|
maxPlayers: 4,
|
|
68
|
-
tickRate: 64
|
|
68
|
+
tickRate: 64,
|
|
69
|
+
scriptName: 'my-script', // Optional: attach a lua script (must be pre-uploaded + active)
|
|
69
70
|
})
|
|
71
|
+
|
|
72
|
+
// 3.14+ — Attached script 의 이름/버전을 검증하고 싶으면 createRoomDetailed 사용
|
|
73
|
+
import { GameError } from 'connectbase-client'
|
|
74
|
+
try {
|
|
75
|
+
const r = await gameClient.createRoomDetailed({ scriptName: 'my-script' })
|
|
76
|
+
console.log('attached', r.scriptName, 'v', r.scriptVersion)
|
|
77
|
+
} catch (e) {
|
|
78
|
+
if (e instanceof GameError && e.code === 'SCRIPT_NOT_FOUND') {
|
|
79
|
+
console.error('script missing — candidates:', e.available)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
70
82
|
```
|
|
71
83
|
|
|
72
84
|
## Features
|
|
@@ -587,26 +599,41 @@ nearby.results.forEach(place => {
|
|
|
587
599
|
|
|
588
600
|
#### Batch & Transactions
|
|
589
601
|
|
|
602
|
+
`table_id` 는 항상 UUID. 콘솔/REST 로 생성한 테이블의 UUID 를 그대로 사용한다.
|
|
603
|
+
|
|
604
|
+
v3.12+ 부터 server 가 부분 실패(`success: false`)를 응답하면 SDK 가 첫 실패 op 의
|
|
605
|
+
error 메시지로 throw 한다 — silent success 회귀 방지 차원. 호출자는 try/catch 로 감싼다.
|
|
606
|
+
|
|
590
607
|
```typescript
|
|
591
608
|
// Batch: atomic multi-table operations
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
609
|
+
try {
|
|
610
|
+
const result = await cb.database.batch([
|
|
611
|
+
{ type: 'create', table_id: ORDERS_TABLE_ID, data: { product: 'A', qty: 1 } },
|
|
612
|
+
{ type: 'update', table_id: INVENTORY_TABLE_ID, doc_id: 'item-a', operators: {
|
|
613
|
+
qty: { type: 'increment', value: -1 }
|
|
614
|
+
}},
|
|
615
|
+
{ type: 'update', table_id: STATS_TABLE_ID, doc_id: 'daily', operators: {
|
|
616
|
+
order_count: { type: 'increment', value: 1 },
|
|
617
|
+
last_order: { type: 'serverTimestamp' }
|
|
618
|
+
}}
|
|
619
|
+
])
|
|
620
|
+
// result.success, result.results[i].{success, doc_id, error}
|
|
621
|
+
} catch (e) {
|
|
622
|
+
// RLS 거부 / 검증 실패 / table_id 오타 등 — 전체 batch 가 atomic 하게 롤백
|
|
623
|
+
console.error('batch failed:', (e as Error).message)
|
|
624
|
+
}
|
|
602
625
|
|
|
603
626
|
// Transaction: read-then-write with ACID guarantees
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
627
|
+
try {
|
|
628
|
+
await cb.database.transaction(
|
|
629
|
+
[{ table_id: ACCOUNTS_TABLE_ID, doc_id: 'user-1', alias: 'sender' }],
|
|
630
|
+
[{ type: 'update', table_id: ACCOUNTS_TABLE_ID, doc_id: 'user-1', operators: {
|
|
631
|
+
balance: { type: 'increment', value: -100 }
|
|
632
|
+
}}]
|
|
633
|
+
)
|
|
634
|
+
} catch (e) {
|
|
635
|
+
console.error('transaction failed:', (e as Error).message)
|
|
636
|
+
}
|
|
610
637
|
```
|
|
611
638
|
|
|
612
639
|
#### Populate (Relation Query / JOIN)
|