connectbase-client 6.3.0 → 6.3.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 +19 -0
- package/dist/cli.js +66 -39
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
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
|
+
## [6.3.1] - 2026-09-08
|
|
7
|
+
|
|
8
|
+
### Fixed — `init` 의 웹 스토리지 생성 실패가 `[object Object]` 로만 찍히던 문제
|
|
9
|
+
|
|
10
|
+
앱에 이미 같은 이름의 웹 스토리지가 있는 상태에서 `init` 이 같은 이름으로 생성을 시도하면
|
|
11
|
+
서버는 409 를 돌려주는데, CLI 가 그 응답 본문(`{ error: { code, message } }`)을 문자열로
|
|
12
|
+
찍어 `생성 실패: [object Object]` 만 보였습니다. 원인이 이름 충돌이라는 사실을 알 길이
|
|
13
|
+
없었고, 스토리지 선택 프롬프트에서 Enter 만 치면 정확히 이 경로로 들어갔습니다.
|
|
14
|
+
|
|
15
|
+
- 에러 응답 형식이 `{ error: "문자열" }` 이든 표준 봉투 `{ error: { code, message,
|
|
16
|
+
suggestion } }` 이든 사람이 읽을 메시지로 정리하는 헬퍼(`apiErrorMessage`)를 두고,
|
|
17
|
+
`init` / `deploy` / `promote` / 배포 이력 / presign / 앱 생성 / 인증 세션의 에러 출력을
|
|
18
|
+
전부 이 헬퍼로 통일했습니다. 서버가 제안(suggestion)을 보내면 함께 보여 줍니다.
|
|
19
|
+
- 대화형 `init` 도 `--yes` 와 같은 규칙으로, 입력한 이름과 같은 웹 스토리지가 이미 있으면
|
|
20
|
+
생성 대신 그 스토리지를 재사용합니다. 서버 요청 없이 즉시 넘어가므로 409 자체가 나지
|
|
21
|
+
않습니다.
|
|
22
|
+
- 서버(core-server)도 같은 앱의 이름 중복을 미리 검사해 `같은 이름의 웹 스토리지가 이미
|
|
23
|
+
있습니다: "<이름>"` 이라는 409 를 돌려줍니다. 구버전 CLI 로도 이제 이 문장이 보입니다.
|
|
24
|
+
|
|
6
25
|
## [6.3.0] - 2026-09-07
|
|
7
26
|
|
|
8
27
|
### Fixed — Secret Key 가 만료되면 `init` 을 다시 돌릴 수 없던 문제
|
package/dist/cli.js
CHANGED
|
@@ -32,6 +32,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
var cli_exports = {};
|
|
33
33
|
__export(cli_exports, {
|
|
34
34
|
TunnelConnectSelector: () => TunnelConnectSelector,
|
|
35
|
+
apiErrorMessage: () => apiErrorMessage,
|
|
35
36
|
computeDeployDiff: () => computeDeployDiff,
|
|
36
37
|
getTunnelConnectCandidates: () => getTunnelConnectCandidates,
|
|
37
38
|
guessMimeType: () => guessMimeType,
|
|
@@ -147,7 +148,7 @@ function handleTunnelError(msg, appId, localPort) {
|
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
// src/cli.ts
|
|
150
|
-
var VERSION = "6.3.
|
|
151
|
+
var VERSION = "6.3.1" ? "6.3.1" : getPackageVersion();
|
|
151
152
|
var DEFAULT_BASE_URL = "https://api.connectbase.world";
|
|
152
153
|
var colors = {
|
|
153
154
|
reset: "\x1B[0m",
|
|
@@ -420,9 +421,9 @@ async function requestDeployPresign(baseStorageUrl, headers, files, timeoutMs) {
|
|
|
420
421
|
);
|
|
421
422
|
if (res.status === 404) return null;
|
|
422
423
|
if (res.status < 200 || res.status >= 300) {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
424
|
+
throw new Error(
|
|
425
|
+
`presign \uC694\uCCAD \uC2E4\uD328: ${apiErrorMessage(res.data, res.status)}`
|
|
426
|
+
);
|
|
426
427
|
}
|
|
427
428
|
const parsed = res.data;
|
|
428
429
|
return parsed?.urls ?? [];
|
|
@@ -580,6 +581,27 @@ async function offloadLargeBinaries(baseStorageUrl, headers, diff, _envLabel, ti
|
|
|
580
581
|
}
|
|
581
582
|
}
|
|
582
583
|
var DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
|
|
584
|
+
function apiErrorMessage(data, status) {
|
|
585
|
+
const fallback = `HTTP ${status}`;
|
|
586
|
+
if (typeof data === "string") return data.trim() || fallback;
|
|
587
|
+
if (typeof data !== "object" || data === null) return fallback;
|
|
588
|
+
const body = data;
|
|
589
|
+
const str = (v) => typeof v === "string" && v.trim() ? v.trim() : void 0;
|
|
590
|
+
let message;
|
|
591
|
+
let suggestion;
|
|
592
|
+
if (typeof body.error === "object" && body.error !== null) {
|
|
593
|
+
const detail = body.error;
|
|
594
|
+
message = str(detail.message) ?? str(detail.code);
|
|
595
|
+
suggestion = str(detail.suggestion);
|
|
596
|
+
} else {
|
|
597
|
+
message = str(body.message) ?? str(body.error);
|
|
598
|
+
}
|
|
599
|
+
if (!message) {
|
|
600
|
+
const raw = JSON.stringify(body);
|
|
601
|
+
return raw === "{}" ? fallback : `${fallback}: ${raw}`;
|
|
602
|
+
}
|
|
603
|
+
return suggestion ? `${message} (${suggestion})` : message;
|
|
604
|
+
}
|
|
583
605
|
async function makeRequest(url, method, headers, body, reqOpts = {}) {
|
|
584
606
|
return new Promise((resolve2, reject) => {
|
|
585
607
|
const parsedUrl = new URL(url);
|
|
@@ -768,9 +790,9 @@ async function tryFetchManifest(baseStorageUrl, headers) {
|
|
|
768
790
|
);
|
|
769
791
|
if (res.status === 404) return null;
|
|
770
792
|
if (res.status < 200 || res.status >= 300) {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
793
|
+
throw new Error(
|
|
794
|
+
`manifest \uC870\uD68C \uC2E4\uD328: ${apiErrorMessage(res.data, res.status)}`
|
|
795
|
+
);
|
|
774
796
|
}
|
|
775
797
|
const parsed = res.data;
|
|
776
798
|
if (!parsed || !Array.isArray(parsed.files)) {
|
|
@@ -920,8 +942,7 @@ ${colors.cyan}URL: ${data.url}${colors.reset}
|
|
|
920
942
|
`);
|
|
921
943
|
}
|
|
922
944
|
} else {
|
|
923
|
-
const
|
|
924
|
-
const errorMsg = typeof data === "object" && data !== null ? data.message || data.error || JSON.stringify(data) : typeof data === "string" ? data : `HTTP ${response.status}`;
|
|
945
|
+
const errorMsg = apiErrorMessage(response.data, response.status);
|
|
925
946
|
if (!reportDeployAuthError(response.status, response.data)) {
|
|
926
947
|
error(`\uBC30\uD3EC \uC2E4\uD328: ${errorMsg}`);
|
|
927
948
|
}
|
|
@@ -950,8 +971,7 @@ async function promote(config, deploymentId) {
|
|
|
950
971
|
process.exit(1);
|
|
951
972
|
}
|
|
952
973
|
if (res.status < 200 || res.status >= 300) {
|
|
953
|
-
const
|
|
954
|
-
const msg = typeof data2 === "object" && data2 !== null ? data2.error || data2.message || JSON.stringify(data2) : `HTTP ${res.status}`;
|
|
974
|
+
const msg = apiErrorMessage(res.data, res.status);
|
|
955
975
|
if (!reportDeployAuthError(res.status, res.data)) {
|
|
956
976
|
error(`promote \uC2E4\uD328: ${msg}`);
|
|
957
977
|
}
|
|
@@ -974,8 +994,7 @@ async function listReleases(config) {
|
|
|
974
994
|
headers
|
|
975
995
|
);
|
|
976
996
|
if (res.status < 200 || res.status >= 300) {
|
|
977
|
-
const
|
|
978
|
-
const msg = typeof data2 === "object" && data2 !== null ? data2.error || data2.message || JSON.stringify(data2) : `HTTP ${res.status}`;
|
|
997
|
+
const msg = apiErrorMessage(res.data, res.status);
|
|
979
998
|
if (!reportDeployAuthError(res.status, res.data)) {
|
|
980
999
|
error(`\uBC30\uD3EC \uC774\uB825 \uC870\uD68C \uC2E4\uD328: ${msg}`);
|
|
981
1000
|
}
|
|
@@ -1100,9 +1119,9 @@ async function browserAuthFlow(baseUrl = DEFAULT_BASE_URL) {
|
|
|
1100
1119
|
{}
|
|
1101
1120
|
);
|
|
1102
1121
|
if (startRes.status !== 200) {
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1122
|
+
error(
|
|
1123
|
+
`\uC778\uC99D \uC138\uC158 \uC2DC\uC791\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4: ${apiErrorMessage(startRes.data, startRes.status)}`
|
|
1124
|
+
);
|
|
1106
1125
|
process.exit(1);
|
|
1107
1126
|
}
|
|
1108
1127
|
const { session_id } = startRes.data;
|
|
@@ -1413,8 +1432,9 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `
|
|
|
1413
1432
|
process.exit(1);
|
|
1414
1433
|
}
|
|
1415
1434
|
if (createRes.status !== 201) {
|
|
1416
|
-
|
|
1417
|
-
|
|
1435
|
+
error(
|
|
1436
|
+
`\uC571 \uC0DD\uC131 \uC2E4\uD328: ${apiErrorMessage(createRes.data, createRes.status)}`
|
|
1437
|
+
);
|
|
1418
1438
|
process.exit(1);
|
|
1419
1439
|
}
|
|
1420
1440
|
const createData = createRes.data;
|
|
@@ -1498,27 +1518,34 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `
|
|
|
1498
1518
|
const name = nonInteractive ? projectName : await prompt(
|
|
1499
1519
|
`${colors.blue}?${colors.reset} \uC2A4\uD1A0\uB9AC\uC9C0 \uC774\uB984 (${projectName}): `
|
|
1500
1520
|
) || projectName;
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
"X-Public-Key": publicKeyForSdk,
|
|
1507
|
-
"X-User-Secret-Key": secretKey,
|
|
1508
|
-
Authorization: `Bearer ${secretKey}`
|
|
1509
|
-
},
|
|
1510
|
-
JSON.stringify({ name })
|
|
1511
|
-
);
|
|
1512
|
-
if (createRes.status !== 200) {
|
|
1513
|
-
const data = createRes.data;
|
|
1514
|
-
error(
|
|
1515
|
-
`\uC0DD\uC131 \uC2E4\uD328: ${data?.error || data?.message || `HTTP ${createRes.status}`}`
|
|
1521
|
+
const sameName = storages.find((s) => s.name === name);
|
|
1522
|
+
if (sameName) {
|
|
1523
|
+
storageId = sameName.id;
|
|
1524
|
+
success(
|
|
1525
|
+
`\uAC19\uC740 \uC774\uB984\uC758 \uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0\uAC00 \uC774\uBBF8 \uC788\uC5B4 \uC7AC\uC0AC\uC6A9\uD569\uB2C8\uB2E4: ${sameName.name}`
|
|
1516
1526
|
);
|
|
1517
|
-
|
|
1527
|
+
} else {
|
|
1528
|
+
info("\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC0DD\uC131 \uC911...");
|
|
1529
|
+
const createRes = await makeRequest(
|
|
1530
|
+
`${baseUrl}/v1/public/storages/webs`,
|
|
1531
|
+
"POST",
|
|
1532
|
+
{
|
|
1533
|
+
"X-Public-Key": publicKeyForSdk,
|
|
1534
|
+
"X-User-Secret-Key": secretKey,
|
|
1535
|
+
Authorization: `Bearer ${secretKey}`
|
|
1536
|
+
},
|
|
1537
|
+
JSON.stringify({ name })
|
|
1538
|
+
);
|
|
1539
|
+
if (createRes.status !== 200) {
|
|
1540
|
+
error(
|
|
1541
|
+
`\uC0DD\uC131 \uC2E4\uD328: ${apiErrorMessage(createRes.data, createRes.status)}`
|
|
1542
|
+
);
|
|
1543
|
+
process.exit(1);
|
|
1544
|
+
}
|
|
1545
|
+
const createData = createRes.data;
|
|
1546
|
+
storageId = createData.storage_web_id;
|
|
1547
|
+
success(`\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC0DD\uC131 \uC644\uB8CC: ${createData.name}`);
|
|
1518
1548
|
}
|
|
1519
|
-
const createData = createRes.data;
|
|
1520
|
-
storageId = createData.storage_web_id;
|
|
1521
|
-
success(`\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC0DD\uC131 \uC644\uB8CC: ${createData.name}`);
|
|
1522
1549
|
}
|
|
1523
1550
|
} else {
|
|
1524
1551
|
throw new Error(`HTTP ${listRes.status}`);
|
|
@@ -2664,8 +2691,7 @@ ${colors.blue}?${colors.reset} \uC571 \uC120\uD0DD (\uBC88\uD638): `
|
|
|
2664
2691
|
process.exit(1);
|
|
2665
2692
|
}
|
|
2666
2693
|
if (createRes.status !== 201) {
|
|
2667
|
-
|
|
2668
|
-
error(`\uC571 \uC0DD\uC131 \uC2E4\uD328: ${data?.error || `HTTP ${createRes.status}`}`);
|
|
2694
|
+
error(`\uC571 \uC0DD\uC131 \uC2E4\uD328: ${apiErrorMessage(createRes.data, createRes.status)}`);
|
|
2669
2695
|
process.exit(1);
|
|
2670
2696
|
}
|
|
2671
2697
|
const createData = createRes.data;
|
|
@@ -3744,6 +3770,7 @@ main().catch((err) => {
|
|
|
3744
3770
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3745
3771
|
0 && (module.exports = {
|
|
3746
3772
|
TunnelConnectSelector,
|
|
3773
|
+
apiErrorMessage,
|
|
3747
3774
|
computeDeployDiff,
|
|
3748
3775
|
getTunnelConnectCandidates,
|
|
3749
3776
|
guessMimeType,
|