connectbase-client 3.28.0 → 3.29.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 +34 -0
- package/dist/cli.js +14 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,40 @@
|
|
|
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.29.0] - 2026-06-02
|
|
7
|
+
|
|
8
|
+
### Added — `connectbase tunnel --token <고정값>` proxy_token 핀 (platform-issue 019e8623)
|
|
9
|
+
|
|
10
|
+
비-public 터널의 `proxy_token` 이 **재연결마다 회전**해, 그 토큰을 스냅샷 저장하는 통합
|
|
11
|
+
(외부 MCP `custom_header X-Proxy-Token`, 터널을 가리키는 웹훅 등)이 다음 재연결부터
|
|
12
|
+
`401 invalid or missing proxy token` 으로 깨지던 문제를 해결한다.
|
|
13
|
+
|
|
14
|
+
- **`cli.ts` — `tunnel --token <value>`** — proxy_token 을 고정값으로 핀. 재연결 핸드셰이크마다
|
|
15
|
+
같은 값(`?proxy_token=`)을 보내 회전을 방지한다. 16~128자 `[A-Za-z0-9_-]` 검증(클라 선검사 +
|
|
16
|
+
서버 `ValidateProxyToken` 동일 규칙). 미지정 시 기존 동작(매 연결 새 발급) 유지 — 하위호환.
|
|
17
|
+
- **CLI 라벨 재등록 idempotent** — 같은 라벨 + 같은 `tunnel_id` 재등록은 더 이상 409 경고를
|
|
18
|
+
내지 않고 기존 바인딩을 그대로 유지한다(콘솔 수동 PATCH 안내 제거). 라벨이 *다른* tunnel_id 에
|
|
19
|
+
묶여 있을 때만 충돌로 처리. 회전이 이미 일어나 깨진 경우의 즉시 복구용으로 백엔드에
|
|
20
|
+
현재 토큰 조회 경로(MCP `get_tunnel_label_proxy_token` / REST `GET .../endpoint-proxy-token/:label`)도
|
|
21
|
+
추가됐다.
|
|
22
|
+
|
|
23
|
+
## [3.28.1] - 2026-06-02
|
|
24
|
+
|
|
25
|
+
### Added — `RelationType` 에 `many-to-one` 추가 (platform-issue 019e83a0-c7d0)
|
|
26
|
+
|
|
27
|
+
`cb.database.createRelation` 의 `relation_type` 으로 `many-to-one`(외래키→부모 단일 객체
|
|
28
|
+
populate 의 정석)을 지정할 수 있게 됐다. 기존엔 문서/MCP 는 `many-to-one` 을 안내하면서도
|
|
29
|
+
SDK/REST 관계 API 는 `one-to-one | one-to-many | many-to-many` 3종만 허용해, 문서대로
|
|
30
|
+
`many-to-one` 을 쓰면 `400 유효하지 않은 관계 타입` + TS 타입 에러가 났다.
|
|
31
|
+
|
|
32
|
+
- **`types/database.ts` — `RelationType`** 에 `'many-to-one'` 추가(4종 동등). additive 변경이라
|
|
33
|
+
하위호환. 백엔드(data-server)도 ent enum·populate(단일 객체) 동등 처리하도록 함께 수정됨.
|
|
34
|
+
|
|
35
|
+
### Fixed — `oauth.signIn` JSDoc 예시 정정
|
|
36
|
+
|
|
37
|
+
`createIfNotExists` 예시가 `callbackUrl` 자리에 클라이언트 인스턴스(`cb`)를 넘기는 오기였다.
|
|
38
|
+
실제 URL 문자열로 교정(런타임/타입 영향 없음, 문서만).
|
|
39
|
+
|
|
6
40
|
## [3.28.0] - 2026-06-02
|
|
7
41
|
|
|
8
42
|
### Added — `cb.ai.chatStream` 취소(AbortSignal) 지원 (platform-issue 019e82e1)
|
package/dist/cli.js
CHANGED
|
@@ -1779,7 +1779,7 @@ async function registerEndpointBinding(baseUrl, appId, secretKey, tunnelId, labe
|
|
|
1779
1779
|
success(`Endpoint "${label}" \uC790\uB3D9 \uB4F1\uB85D \uC644\uB8CC`);
|
|
1780
1780
|
log(`${colors.green}\u2192${colors.reset} SDK: ${colors.cyan}cb.endpoint.call("${label}", { path: "/...", method: "POST", body: ... })${colors.reset}`);
|
|
1781
1781
|
} else if (res.status === 409) {
|
|
1782
|
-
warn(`"${label}" \uB77C\uBCA8\uC774 \
|
|
1782
|
+
warn(`"${label}" \uB77C\uBCA8\uC774 \uB2E4\uB978 \uD130\uB110\uC5D0 \uC774\uBBF8 \uBB36\uC5EC \uC788\uC2B5\uB2C8\uB2E4. \uC774 \uD130\uB110\uB85C \uC62E\uAE30\uB824\uBA74 \uCF58\uC194\uC5D0\uC11C endpoint \uC758 tunnel_id \uB97C \uC218\uC815(PATCH)\uD558\uC138\uC694.`);
|
|
1783
1783
|
} else {
|
|
1784
1784
|
const text = await res.text().catch(() => "");
|
|
1785
1785
|
error(`Endpoint "${label}" \uC790\uB3D9 \uB4F1\uB85D \uC2E4\uD328 (status ${res.status}): ${text || "(\uBE48 \uC751\uB2F5)"}`);
|
|
@@ -1867,6 +1867,9 @@ async function startTunnel(port, config, tunnelOpts) {
|
|
|
1867
1867
|
if (tunnelOpts?.public) {
|
|
1868
1868
|
wsPath += `&public=1`;
|
|
1869
1869
|
}
|
|
1870
|
+
if (tunnelOpts?.token) {
|
|
1871
|
+
wsPath += `&proxy_token=${encodeURIComponent(tunnelOpts.token)}`;
|
|
1872
|
+
}
|
|
1870
1873
|
let reconnectAttempts = 0;
|
|
1871
1874
|
const maxReconnectAttempts = 10;
|
|
1872
1875
|
let shouldReconnect = true;
|
|
@@ -2350,6 +2353,7 @@ ${colors.yellow}\uC635\uC158:${colors.reset}
|
|
|
2350
2353
|
--force \uD130\uB110 lockfile \uBB34\uC2DC (\uC911\uBCF5 \uC2E4\uD589 \uAC15\uC81C, tunnel \uC804\uC6A9)
|
|
2351
2354
|
--public proxy_token \uAC80\uC99D \uBE44\uD65C\uC131\uD654 \u2014 \uC6F9\uD6C5/\uC678\uBD80 \uC9C1\uC811 \uD638\uCD9C\uC6A9 (tunnel \uC804\uC6A9)
|
|
2352
2355
|
--show-token proxy_token \uACFC curl \uC608\uC2DC\uB97C \uCD9C\uB825 (--public \uC544\uB2CC \uACBD\uC6B0)
|
|
2356
|
+
--token <value> proxy_token \uACE0\uC815\uAC12 (16-128\uC790 [A-Za-z0-9_-]) \u2014 \uC7AC\uC5F0\uACB0\uC5D0\uB3C4 \uD1A0\uD070 \uD68C\uC804 \uBC29\uC9C0. \uC678\uBD80 MCP custom_header \uB4F1 \uC548\uC815 \uD1B5\uD569\uC6A9 (tunnel \uC804\uC6A9)
|
|
2353
2357
|
--label <name> Endpoint binding \uC790\uB3D9 \uB4F1\uB85D (tunnel \uC804\uC6A9) \u2014 SDK \uC758 cb.endpoint.call(label) \uD638\uCD9C \uAC00\uB2A5
|
|
2354
2358
|
--description <text> Endpoint binding \uC124\uBA85 (--label \uB3D9\uBC18 \uC2DC\uB9CC)
|
|
2355
2359
|
-d, --dev Dev \uD658\uACBD\uC5D0 \uBC30\uD3EC (deploy \uC804\uC6A9)
|
|
@@ -2429,6 +2433,8 @@ function parseArgs(args) {
|
|
|
2429
2433
|
result.options.label = args[++i];
|
|
2430
2434
|
} else if (arg === "--description") {
|
|
2431
2435
|
result.options.description = args[++i];
|
|
2436
|
+
} else if (arg === "--token") {
|
|
2437
|
+
result.options.token = args[++i];
|
|
2432
2438
|
} else if (arg === "-a" || arg === "--app") {
|
|
2433
2439
|
result.options.appId = args[++i];
|
|
2434
2440
|
} else if (arg === "--force") {
|
|
@@ -2548,6 +2554,13 @@ async function main() {
|
|
|
2548
2554
|
if (parsed.options.description) {
|
|
2549
2555
|
tunnelOpts.description = parsed.options.description;
|
|
2550
2556
|
}
|
|
2557
|
+
if (parsed.options.token) {
|
|
2558
|
+
if (!/^[A-Za-z0-9_-]{16,128}$/.test(parsed.options.token)) {
|
|
2559
|
+
error("--token \uC740 16-128\uC790\uC758 [A-Za-z0-9_-] \uC5EC\uC57C \uD569\uB2C8\uB2E4");
|
|
2560
|
+
process.exit(1);
|
|
2561
|
+
}
|
|
2562
|
+
tunnelOpts.token = parsed.options.token;
|
|
2563
|
+
}
|
|
2551
2564
|
await startTunnel(port, config, tunnelOpts);
|
|
2552
2565
|
} else {
|
|
2553
2566
|
error(`\uC54C \uC218 \uC5C6\uB294 \uBA85\uB839\uC5B4: ${parsed.command}`);
|
package/dist/index.d.mts
CHANGED
|
@@ -1372,7 +1372,7 @@ interface SlowQueryInfo {
|
|
|
1372
1372
|
count: number;
|
|
1373
1373
|
avg_time: number;
|
|
1374
1374
|
}
|
|
1375
|
-
type RelationType = 'one-to-one' | 'one-to-many' | 'many-to-many';
|
|
1375
|
+
type RelationType = 'one-to-one' | 'one-to-many' | 'many-to-one' | 'many-to-many';
|
|
1376
1376
|
interface TableRelation {
|
|
1377
1377
|
id: string;
|
|
1378
1378
|
app_id: string;
|
|
@@ -3874,7 +3874,7 @@ declare class OAuthAPI {
|
|
|
3874
3874
|
* await cb.oauth.signIn('google', 'https://myapp.com/oauth/callback')
|
|
3875
3875
|
*
|
|
3876
3876
|
* // 로그인=가입 통합 버튼 — 신규면 자동 가입
|
|
3877
|
-
* await cb.oauth.signIn('google',
|
|
3877
|
+
* await cb.oauth.signIn('google', 'https://myapp.com/oauth/callback', undefined, { createIfNotExists: true })
|
|
3878
3878
|
* ```
|
|
3879
3879
|
*
|
|
3880
3880
|
* @example
|
package/dist/index.d.ts
CHANGED
|
@@ -1372,7 +1372,7 @@ interface SlowQueryInfo {
|
|
|
1372
1372
|
count: number;
|
|
1373
1373
|
avg_time: number;
|
|
1374
1374
|
}
|
|
1375
|
-
type RelationType = 'one-to-one' | 'one-to-many' | 'many-to-many';
|
|
1375
|
+
type RelationType = 'one-to-one' | 'one-to-many' | 'many-to-one' | 'many-to-many';
|
|
1376
1376
|
interface TableRelation {
|
|
1377
1377
|
id: string;
|
|
1378
1378
|
app_id: string;
|
|
@@ -3874,7 +3874,7 @@ declare class OAuthAPI {
|
|
|
3874
3874
|
* await cb.oauth.signIn('google', 'https://myapp.com/oauth/callback')
|
|
3875
3875
|
*
|
|
3876
3876
|
* // 로그인=가입 통합 버튼 — 신규면 자동 가입
|
|
3877
|
-
* await cb.oauth.signIn('google',
|
|
3877
|
+
* await cb.oauth.signIn('google', 'https://myapp.com/oauth/callback', undefined, { createIfNotExists: true })
|
|
3878
3878
|
* ```
|
|
3879
3879
|
*
|
|
3880
3880
|
* @example
|
package/dist/index.js
CHANGED
|
@@ -4837,7 +4837,7 @@ var OAuthAPI = class {
|
|
|
4837
4837
|
* await cb.oauth.signIn('google', 'https://myapp.com/oauth/callback')
|
|
4838
4838
|
*
|
|
4839
4839
|
* // 로그인=가입 통합 버튼 — 신규면 자동 가입
|
|
4840
|
-
* await cb.oauth.signIn('google',
|
|
4840
|
+
* await cb.oauth.signIn('google', 'https://myapp.com/oauth/callback', undefined, { createIfNotExists: true })
|
|
4841
4841
|
* ```
|
|
4842
4842
|
*
|
|
4843
4843
|
* @example
|
package/dist/index.mjs
CHANGED
|
@@ -4791,7 +4791,7 @@ var OAuthAPI = class {
|
|
|
4791
4791
|
* await cb.oauth.signIn('google', 'https://myapp.com/oauth/callback')
|
|
4792
4792
|
*
|
|
4793
4793
|
* // 로그인=가입 통합 버튼 — 신규면 자동 가입
|
|
4794
|
-
* await cb.oauth.signIn('google',
|
|
4794
|
+
* await cb.oauth.signIn('google', 'https://myapp.com/oauth/callback', undefined, { createIfNotExists: true })
|
|
4795
4795
|
* ```
|
|
4796
4796
|
*
|
|
4797
4797
|
* @example
|