connectbase-client 3.22.0 → 3.23.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 +40 -0
- package/README.md +103 -0
- package/dist/connect-base.umd.js +4 -4
- package/dist/index.d.mts +33 -5
- package/dist/index.d.ts +33 -5
- package/dist/index.js +80 -19
- package/dist/index.mjs +80 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,46 @@
|
|
|
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.23.0] - 2026-05-26
|
|
7
|
+
|
|
8
|
+
### Fixed — OAuth 표준 흐름 페이지 리로드 후 세션 유실 (platform-issue 019e638d)
|
|
9
|
+
|
|
10
|
+
문서의 OAuth redirect 표준 예제 그대로 따라가도 **콜백 → 메인 페이지** 전환 직후 `cb.auth.getMe()` 가 401 으로 떨어져 비개발자 사용자가 영원히 로그인 루프에 갇히던 회귀를 3개 race + 1개 충돌 가드로 동시에 닫는다.
|
|
11
|
+
|
|
12
|
+
**(1) Race A — callback fire-and-forget cookie 부트스트랩**
|
|
13
|
+
`getCallbackResult()` / `exchangeCodeFromCallback()` 가 `setTokens` 직후 `bootstrapRefreshCookie()` 를 fire-and-forget 으로 호출했다. 표준 예제처럼 `window.location.href='/'` 가 즉시 발화하면 fetch 가 abort 되어 `cb_member_refresh_token` cookie 가 발급되지 않았다. 모바일·느린 네트워크에서 특히 잘 깨졌다.
|
|
14
|
+
- **변경**: `getCallbackResult()` 시그니처를 동기 → `Promise` 로 변경 (BREAKING — prelaunch 단계라 backward-compat 가드 생략). `exchangeCodeFromCallback()` / popup 핸들러도 cookie 부트스트랩을 *await* 한 뒤에 resolve. 호출자가 `await cb.oauth.getCallbackResult()` 후 navigation 하면 cookie 가 안전하게 저장된 상태가 보장된다.
|
|
15
|
+
|
|
16
|
+
**(2) Race B — 메인 페이지 entry race**
|
|
17
|
+
ConnectBase 인스턴스 생성 시 `tryRestoreSessionFromCookie()` 가 fire-and-forget 으로 진행되는데, 사용자 코드의 첫 인증 호출(`getMe()` 등) 이 그 promise 보다 먼저 발화하면 메모리 토큰 빈 채로 401 받았다.
|
|
18
|
+
- **변경**: 부팅 시 시작된 복구 promise 를 HttpClient 에 등록해, `prepareHeaders` 가 인증 호출 직전에 1회 await. 표준 예제 무수정으로 race 가 닫힌다.
|
|
19
|
+
|
|
20
|
+
**(3) 401 자동 복구**
|
|
21
|
+
인증 호출이 401 받으면 cookie 기반 복구를 *한 번* 시도하고 retry. cookie 가 살아 있는 사용자의 첫 호출이 화면 401 으로 깨지지 않게 한다 (cookie 복구 실패 시엔 원본 401 그대로 throw — 무한 retry 차단).
|
|
22
|
+
|
|
23
|
+
**(4) Backend strict X-Public-Key dispatch (충돌 C)**
|
|
24
|
+
같은 `.connectbase.world` 루트의 콘솔 admin refresh cookie 가 `credentials:'include'` 로 SDK 호출에 함께 첨부되어, SDK 가 콘솔 User JWT 를 silent reject 하는 케이스 차단. backend `/v1/auth/re-issue` 에서 cross-source cookie fallback 을 제거 — SDK 호출(X-Public-Key 있음) 은 `cb_member_refresh_token` 만, 콘솔 호출은 `refresh_token` 만 사용한다. 한쪽이 없으면 401 로 깔끔히 떨어뜨려 SDK 가드(`isConsolePlatformToken`) 가 더 이상 트리거되지 않는다.
|
|
25
|
+
|
|
26
|
+
### Breaking
|
|
27
|
+
|
|
28
|
+
- `cb.oauth.getCallbackResult()` 가 `Promise` 를 반환합니다. 호출자는 반드시 `await` 해야 합니다. 컴파일 타임에 잡히지만, 동기 호출 코드는 콜백 결과를 `Promise<...>` 로 받아 `result.error` 가 항상 undefined 로 보입니다.
|
|
29
|
+
- **마이그레이션**: `const result = cb.oauth.getCallbackResult()` → `const result = await cb.oauth.getCallbackResult()`. React `useEffect` 안에서는 IIFE 패턴: `;(async () => { const result = await cb.oauth.getCallbackResult(); ... })()`.
|
|
30
|
+
|
|
31
|
+
### Tests
|
|
32
|
+
|
|
33
|
+
- `test/http-race-recovery.test.ts` — race B / 401 auto-recovery / skipAuth 보존 5 케이스
|
|
34
|
+
- `test/oauth-callback-cookie-bootstrap.test.ts` — `await` 시그니처 + bootstrap-before-result 보장 추가
|
|
35
|
+
|
|
36
|
+
## [3.22.1] - 2026-05-26
|
|
37
|
+
|
|
38
|
+
### Documentation
|
|
39
|
+
|
|
40
|
+
README 에 3.22.0 에서 추가된 공개 API 3종을 정식 섹션으로 문서화. 코드 동작 변경 없음.
|
|
41
|
+
|
|
42
|
+
- **Key Types** 섹션에 `Server-side admin context` 추가 — `new ConnectBase({ publicKey, secretKey })` 가 admin 헤더(`X-Public-Key` + `Authorization: Bearer cb_sk_*`) 를 첨부하고 서버 `OptionalAdminSecretKey` 미들웨어가 RLS 를 우회한다는 점을 명시.
|
|
43
|
+
- **Authentication** 섹션에 `cb.auth.adminUpdateMember(memberID, fields)` 예제 + `secretKey` 미설정 시 throw / self-update 거절 동작 + `role` 이 RLS `auth.role` 의 backing field 임을 명시.
|
|
44
|
+
- **Server Functions** 섹션 신설 (Realtime 과 Endpoint 사이) — `cb.functions.invoke` + `cb.functions.getWebhookURL` + `http_trigger_auth` 3종(`none` / `public_key` / `secret_key`) + raw body / 헤더 forward / 10MB 한도 / Discord interactions 응답 예제.
|
|
45
|
+
|
|
6
46
|
## [3.22.0] - 2026-05-25
|
|
7
47
|
|
|
8
48
|
### Added — 서버사이드 admin (cb_sk_) 권한으로 data CRUD + 멤버 role 관리 (platform-issue 019e5a04, 019e59ca)
|
package/README.md
CHANGED
|
@@ -37,6 +37,29 @@ Connect Base provides **two types** of Keys. Use the right key for your use case
|
|
|
37
37
|
|
|
38
38
|
Create Keys in the Console under **Settings > API tab**. Choose Public or Secret type when creating. The full key is shown **only once** at creation time.
|
|
39
39
|
|
|
40
|
+
#### Server-side admin context (v3.22.0+)
|
|
41
|
+
|
|
42
|
+
When you create the SDK with **both** `publicKey` and `secretKey`, the client
|
|
43
|
+
attaches `X-Public-Key` (app identity) and `Authorization: Bearer cb_sk_*`
|
|
44
|
+
(privilege escalation) on every request. The server's `OptionalAdminSecretKey`
|
|
45
|
+
middleware verifies the secret key, sets an admin context, and **skips RLS**
|
|
46
|
+
for that request — useful for backend sync scripts, admin tools, and
|
|
47
|
+
`cb.auth.adminUpdateMember()`.
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// SERVER-SIDE ONLY — never ship this in a browser/mobile bundle
|
|
51
|
+
const cb = new ConnectBase({
|
|
52
|
+
publicKey: process.env.CB_PUBLIC_KEY!, // cb_pk_
|
|
53
|
+
secretKey: process.env.CB_SECRET_KEY!, // cb_sk_ (admin)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// Bypasses RLS .write/.read rules
|
|
57
|
+
await cb.database.createData('orders', { ... })
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Without `secretKey`, every request is RLS-evaluated as normal — there is no
|
|
61
|
+
behavioral change for browser clients.
|
|
62
|
+
|
|
40
63
|
## Quick Start
|
|
41
64
|
|
|
42
65
|
```typescript
|
|
@@ -515,6 +538,36 @@ const result = await cb.oauth.signInWithPopup('google', 'https://myapp.com/oauth
|
|
|
515
538
|
await cb.auth.signOut()
|
|
516
539
|
```
|
|
517
540
|
|
|
541
|
+
#### Admin: update another member (v3.22.0+)
|
|
542
|
+
|
|
543
|
+
Set another member's `nickname`, `role`, or `custom_data` from a server-side
|
|
544
|
+
admin context. Requires the SDK to be initialized with `secretKey` — calling
|
|
545
|
+
this without one throws synchronously. Self-update is rejected by the server.
|
|
546
|
+
|
|
547
|
+
```typescript
|
|
548
|
+
// SERVER-SIDE ONLY — admin context required (publicKey + secretKey)
|
|
549
|
+
const cb = new ConnectBase({
|
|
550
|
+
publicKey: process.env.CB_PUBLIC_KEY!,
|
|
551
|
+
secretKey: process.env.CB_SECRET_KEY!,
|
|
552
|
+
})
|
|
553
|
+
|
|
554
|
+
// Grant role used by RLS `auth.role` expressions
|
|
555
|
+
await cb.auth.adminUpdateMember('019abc12-...', { role: 'editor' })
|
|
556
|
+
|
|
557
|
+
// Clear the role
|
|
558
|
+
await cb.auth.adminUpdateMember('019abc12-...', { role: '' })
|
|
559
|
+
|
|
560
|
+
// Multi-field update
|
|
561
|
+
await cb.auth.adminUpdateMember('019abc12-...', {
|
|
562
|
+
nickname: 'Alice',
|
|
563
|
+
role: 'admin',
|
|
564
|
+
custom_data: { level: 5 },
|
|
565
|
+
})
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
`role` is the only way to populate the RLS expression variable `auth.role` —
|
|
569
|
+
end-users can't set it on themselves through the public profile API.
|
|
570
|
+
|
|
518
571
|
### Database
|
|
519
572
|
|
|
520
573
|
```typescript
|
|
@@ -956,6 +1009,56 @@ await session.stop()
|
|
|
956
1009
|
| `promptTokens` | `number` | Input prompt tokens |
|
|
957
1010
|
| `duration` | `number` | Generation time in ms |
|
|
958
1011
|
|
|
1012
|
+
### Server Functions
|
|
1013
|
+
|
|
1014
|
+
Invoke a deployed function from the SDK, or expose it as a raw HTTP webhook
|
|
1015
|
+
that external services (Discord, Stripe, GitHub, Slack Events, etc.) can call
|
|
1016
|
+
directly.
|
|
1017
|
+
|
|
1018
|
+
```typescript
|
|
1019
|
+
// Invoke a function (publicKey-authenticated; runs in your Knative pod)
|
|
1020
|
+
const result = await cb.functions.invoke('019abc12-...', { orderId: '...' })
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
#### Raw HTTP webhook URL (v3.22.0+)
|
|
1024
|
+
|
|
1025
|
+
For external SaaS webhooks where you can't customize the request shape (raw
|
|
1026
|
+
body, vendor-specific signature headers, arbitrary HTTP methods), enable
|
|
1027
|
+
`http_trigger_enabled` on the function (Console or MCP `update_function`) and
|
|
1028
|
+
register the URL returned by `getWebhookURL()` with the upstream service.
|
|
1029
|
+
|
|
1030
|
+
```typescript
|
|
1031
|
+
const url = cb.functions.getWebhookURL('019abc12-...')
|
|
1032
|
+
// → https://api.connectbase.world/v1/public/functions/019abc12-.../webhook
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
| `http_trigger_auth` | Required header | Use for |
|
|
1036
|
+
|---|---|---|
|
|
1037
|
+
| `none` | _(none)_ | External SaaS webhooks (function verifies signature itself) |
|
|
1038
|
+
| `public_key` | `X-Public-Key: cb_pk_*` | Your own clients/services |
|
|
1039
|
+
| `secret_key` | `Authorization: Bearer cb_sk_*` | Server-to-server admin calls |
|
|
1040
|
+
|
|
1041
|
+
The endpoint forwards the **raw request body** (no JSON wrap), preserves
|
|
1042
|
+
method/path/query, and forwards all headers — so signature checks (Ed25519,
|
|
1043
|
+
HMAC-SHA256, Stripe-Signature, X-Hub-Signature-256) work end-to-end. Body
|
|
1044
|
+
limit is 10MB.
|
|
1045
|
+
|
|
1046
|
+
Return `{ statusCode, headers, body }` from the handler to emit a custom
|
|
1047
|
+
HTTP response (for example, Discord Interactions requires a `200` with a
|
|
1048
|
+
JSON body within 3 seconds):
|
|
1049
|
+
|
|
1050
|
+
```javascript
|
|
1051
|
+
export async function handler(event, ctx) {
|
|
1052
|
+
// event.method / event.path / event.query / event.headers / event.body
|
|
1053
|
+
// are populated for webhook invocations.
|
|
1054
|
+
return {
|
|
1055
|
+
statusCode: 200,
|
|
1056
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1057
|
+
body: JSON.stringify({ type: 1 }), // Discord PING ack
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
```
|
|
1061
|
+
|
|
959
1062
|
### Endpoint (Local Model Tunnel)
|
|
960
1063
|
|
|
961
1064
|
`cb.endpoint.*` is a dumb pipe to your own GPU/model server running behind a
|