connectbase-client 3.24.0 → 3.25.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 +27 -0
- package/dist/cli.js +59 -18
- package/dist/connect-base.umd.js +4 -4
- package/dist/index.d.mts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +102 -1
- package/dist/index.mjs +100 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,33 @@
|
|
|
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.25.1] - 2026-05-27
|
|
7
|
+
|
|
8
|
+
### Fixed — 3.25.0 회귀 복구 + heartbeat 헬퍼 정리
|
|
9
|
+
|
|
10
|
+
3.25.0 이 NativeBridge / inApp 우회 / deploy timeout 을 추가하면서, 같은 시기 3.24.0 에 들어가 있던
|
|
11
|
+
incremental deploy(manifest 기반 +/− diff) 와 `signUp` / `startCentralOAuth` 흐름을 통째로 누락한 채
|
|
12
|
+
release 됐다. 본 패치는 두 라인을 머지해 3.24.0 의 동작을 회복하면서 3.25.0 의 신규 기능을 모두 유지한다.
|
|
13
|
+
|
|
14
|
+
- **CLI deploy** — `fullDeploy` 만 호출되던 회귀를 닫고 `incrementalDeploy` + `tryFetchManifest` + `computeDeployDiff` + `handleDeployResponse` 복원.
|
|
15
|
+
- Dev 는 항상 전량(`/deploy/dev`), Prod 는 manifest 기반 `+upsert/-delete` 전송, 변경 0 이면 업로드 skip.
|
|
16
|
+
- 409 revision conflict 자동 1회 재시도.
|
|
17
|
+
- 두 경로 모두 `computeDeployTimeout(totalBytes, override)` 결과를 `makeRequest` 의 `timeoutMs` 로 전달.
|
|
18
|
+
- `startUploadHeartbeat()` 헬퍼로 분리해 incremental / full 양쪽에서 TTY heartbeat 표시 (CI 환경은 무음).
|
|
19
|
+
- `VERSION` 을 빌드된 `package.json` 에서 읽도록 복원 (`getPackageVersion()`).
|
|
20
|
+
- **OAuth** — `signUp(provider, callbackUrl, state)` 와 `startCentralOAuth(intent)` 가 다시 export.
|
|
21
|
+
- `signIn` / `signUp` 모두 `startCentralOAuth` 를 거치며, 내부에서 ① NativeBridge 감지 ②
|
|
22
|
+
3rd-party 인앱 브라우저(`detectInAppBrowser` + `escapeToExternalBrowser`) 처리 ③ 일반 웹 redirect
|
|
23
|
+
순으로 분기. 3.25.0 에서 `signIn` 만 inApp 처리를 받던 비대칭을 해소.
|
|
24
|
+
- `signInWithPopup` 도 같은 3-way 분기 + `options.intent` 유지.
|
|
25
|
+
- **Exports** — `detectInAppBrowser`, `escapeToExternalBrowser` 외에 3.24.0 의 `TokenPersistence` 타입과
|
|
26
|
+
`GameError` 도 함께 re-export (3.25.0 에서 export 라인이 충돌 머지로 일부 빠져있던 회귀).
|
|
27
|
+
|
|
28
|
+
### Notes — 누락된 CHANGELOG 보강
|
|
29
|
+
|
|
30
|
+
3.24.0 / 3.25.0 은 CHANGELOG 엔트리 없이 publish 됐다. 향후 retro 엔트리를 보강할 수 있으나, 본 릴리스는
|
|
31
|
+
3.25.0 → 3.25.1 의 diff 만 다룬다.
|
|
32
|
+
|
|
6
33
|
## [3.23.0] - 2026-05-26
|
|
7
34
|
|
|
8
35
|
### Fixed — OAuth 표준 흐름 페이지 리로드 후 세션 유실 (platform-issue 019e638d)
|
package/dist/cli.js
CHANGED
|
@@ -131,7 +131,7 @@ function getPackageVersion() {
|
|
|
131
131
|
}
|
|
132
132
|
} catch {
|
|
133
133
|
}
|
|
134
|
-
return "
|
|
134
|
+
return "3.25.1";
|
|
135
135
|
}
|
|
136
136
|
var VERSION = getPackageVersion();
|
|
137
137
|
var DEFAULT_BASE_URL = "https://api.connectbase.world";
|
|
@@ -280,7 +280,8 @@ function collectFiles(dir, baseDir = dir) {
|
|
|
280
280
|
}
|
|
281
281
|
return files;
|
|
282
282
|
}
|
|
283
|
-
|
|
283
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
|
|
284
|
+
async function makeRequest(url, method, headers, body, reqOpts = {}) {
|
|
284
285
|
return new Promise((resolve2, reject) => {
|
|
285
286
|
const parsedUrl = new URL(url);
|
|
286
287
|
const isHttps = parsedUrl.protocol === "https:";
|
|
@@ -313,8 +314,16 @@ async function makeRequest(url, method, headers, body) {
|
|
|
313
314
|
}
|
|
314
315
|
});
|
|
315
316
|
});
|
|
316
|
-
req.
|
|
317
|
-
|
|
317
|
+
req.on("socket", (socket) => {
|
|
318
|
+
socket.setKeepAlive(true, 3e4);
|
|
319
|
+
});
|
|
320
|
+
const timeoutMs = reqOpts.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
321
|
+
req.setTimeout(timeoutMs, () => {
|
|
322
|
+
req.destroy(
|
|
323
|
+
new Error(
|
|
324
|
+
`\uC694\uCCAD \uC2DC\uAC04 \uCD08\uACFC (${Math.round(timeoutMs / 1e3)}\uCD08). \uD070 \uC0AC\uC774\uD2B8\uB294 --timeout <\uCD08> \uB610\uB294 CONNECTBASE_DEPLOY_TIMEOUT \uD658\uACBD\uBCC0\uC218\uB85C \uB298\uB9AC\uC138\uC694.`
|
|
325
|
+
)
|
|
326
|
+
);
|
|
318
327
|
});
|
|
319
328
|
req.on("error", reject);
|
|
320
329
|
if (bodyBuffer) {
|
|
@@ -323,7 +332,17 @@ async function makeRequest(url, method, headers, body) {
|
|
|
323
332
|
req.end();
|
|
324
333
|
});
|
|
325
334
|
}
|
|
326
|
-
|
|
335
|
+
var DEPLOY_TIMEOUT_BASE_MS = 5 * 6e4;
|
|
336
|
+
var DEPLOY_TIMEOUT_PER_10MB_MS = 6e4;
|
|
337
|
+
var DEPLOY_TIMEOUT_MIN_MS = 10 * 6e4;
|
|
338
|
+
function computeDeployTimeout(totalBytes, override) {
|
|
339
|
+
if (override && override > 0) return override;
|
|
340
|
+
const envOverride = process.env.CONNECTBASE_DEPLOY_TIMEOUT ? parseInt(process.env.CONNECTBASE_DEPLOY_TIMEOUT, 10) * 1e3 : 0;
|
|
341
|
+
if (envOverride > 0) return envOverride;
|
|
342
|
+
const sizeBased = Math.ceil(totalBytes / (10 * 1024 * 1024)) * DEPLOY_TIMEOUT_PER_10MB_MS;
|
|
343
|
+
return Math.max(DEPLOY_TIMEOUT_MIN_MS, DEPLOY_TIMEOUT_BASE_MS + sizeBased);
|
|
344
|
+
}
|
|
345
|
+
async function deploy(directory, config, isDev = false, deployOpts = {}) {
|
|
327
346
|
const dir = path2.resolve(directory);
|
|
328
347
|
if (!fs2.existsSync(dir)) {
|
|
329
348
|
error(`\uB514\uB809\uD1A0\uB9AC\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${dir}`);
|
|
@@ -363,14 +382,16 @@ async function deploy(directory, config, isDev = false) {
|
|
|
363
382
|
const envLabel = isDev ? "Dev" : "Prod";
|
|
364
383
|
const baseStorageUrl = `${config.baseUrl}/v1/public/storages/webs/${config.storageId}`;
|
|
365
384
|
const headers = { "X-Public-Key": config.publicKey };
|
|
385
|
+
const timeoutMs = computeDeployTimeout(totalSize, deployOpts.timeoutMs);
|
|
386
|
+
log(`${colors.dim}\uD0C0\uC784\uC544\uC6C3: ${Math.round(timeoutMs / 1e3)}\uCD08${colors.reset}`);
|
|
366
387
|
if (isDev) {
|
|
367
|
-
await fullDeploy(baseStorageUrl, headers, files, envLabel, "deploy/dev");
|
|
388
|
+
await fullDeploy(baseStorageUrl, headers, files, envLabel, "deploy/dev", timeoutMs);
|
|
368
389
|
return;
|
|
369
390
|
}
|
|
370
391
|
try {
|
|
371
392
|
const manifest = await tryFetchManifest(baseStorageUrl, headers);
|
|
372
393
|
if (!manifest) {
|
|
373
|
-
await fullDeploy(baseStorageUrl, headers, files, envLabel, "deploy");
|
|
394
|
+
await fullDeploy(baseStorageUrl, headers, files, envLabel, "deploy", timeoutMs);
|
|
374
395
|
return;
|
|
375
396
|
}
|
|
376
397
|
const diff = computeDeployDiff(files, manifest);
|
|
@@ -384,7 +405,7 @@ ${colors.cyan}URL: https://${config.storageId}.web.connectbase.world${colors.res
|
|
|
384
405
|
info(`\uBCC0\uACBD: ${colors.green}+${diff.upsert.length}${colors.reset} / ${colors.red}-${diff.delete.length}${colors.reset} (\uC804\uCCB4 ${files.length}\uAC1C \uC911)`);
|
|
385
406
|
const uploadSize = diff.upsert.reduce((s, f) => s + f.content.length, 0);
|
|
386
407
|
info(`\uC5C5\uB85C\uB4DC \uD06C\uAE30: ${(uploadSize / 1024).toFixed(1)} KB`);
|
|
387
|
-
await incrementalDeploy(baseStorageUrl, headers, diff, manifest.revision, envLabel);
|
|
408
|
+
await incrementalDeploy(baseStorageUrl, headers, diff, manifest.revision, envLabel, timeoutMs);
|
|
388
409
|
} catch (err) {
|
|
389
410
|
process.stdout.write("\r \r");
|
|
390
411
|
error(`\uB124\uD2B8\uC6CC\uD06C \uC624\uB958: ${err instanceof Error ? err.message : err}`);
|
|
@@ -428,15 +449,25 @@ function computeDeployDiff(local, manifest) {
|
|
|
428
449
|
}
|
|
429
450
|
return { upsert, delete: toDelete };
|
|
430
451
|
}
|
|
431
|
-
|
|
452
|
+
function startUploadHeartbeat(envLabel, suffix = "\uBC30\uD3EC \uC911") {
|
|
453
|
+
if (!process.stdout.isTTY) return null;
|
|
454
|
+
const startedAt = Date.now();
|
|
455
|
+
return setInterval(() => {
|
|
456
|
+
const elapsed = Math.floor((Date.now() - startedAt) / 1e3);
|
|
457
|
+
process.stdout.write(`\r${colors.blue}\u27F3${colors.reset} ${envLabel} ${suffix}... ${colors.dim}(${elapsed}s)${colors.reset}`);
|
|
458
|
+
}, 1e3);
|
|
459
|
+
}
|
|
460
|
+
async function incrementalDeploy(baseStorageUrl, headers, diff, baseRevision, envLabel, timeoutMs) {
|
|
432
461
|
process.stdout.write(`${colors.blue}\u27F3${colors.reset} ${envLabel} \uC99D\uBD84 \uBC30\uD3EC \uC911...`);
|
|
462
|
+
let heartbeat = startUploadHeartbeat(envLabel, "\uC99D\uBD84 \uBC30\uD3EC \uC911");
|
|
433
463
|
const body = JSON.stringify({
|
|
434
464
|
upsert: diff.upsert,
|
|
435
465
|
delete: diff.delete,
|
|
436
466
|
base_revision: baseRevision
|
|
437
467
|
});
|
|
438
|
-
const res = await makeRequest(`${baseStorageUrl}/deploy/incremental`, "POST", headers, body);
|
|
439
|
-
|
|
468
|
+
const res = await makeRequest(`${baseStorageUrl}/deploy/incremental`, "POST", headers, body, { timeoutMs });
|
|
469
|
+
if (heartbeat) clearInterval(heartbeat);
|
|
470
|
+
process.stdout.write("\r \r");
|
|
440
471
|
if (res.status === 409) {
|
|
441
472
|
warn("\uC11C\uBC84 revision \uC774 \uBCC0\uACBD\uB418\uC5C8\uC2B5\uB2C8\uB2E4. manifest \uC7AC\uC870\uD68C \uD6C4 \uC7AC\uC2DC\uB3C4\uD569\uB2C8\uB2E4.");
|
|
442
473
|
const manifest = await tryFetchManifest(baseStorageUrl, headers);
|
|
@@ -450,15 +481,18 @@ async function incrementalDeploy(baseStorageUrl, headers, diff, baseRevision, en
|
|
|
450
481
|
base_revision: manifest.revision
|
|
451
482
|
});
|
|
452
483
|
process.stdout.write(`${colors.blue}\u27F3${colors.reset} ${envLabel} \uC99D\uBD84 \uBC30\uD3EC \uC7AC\uC2DC\uB3C4...`);
|
|
453
|
-
|
|
454
|
-
|
|
484
|
+
heartbeat = startUploadHeartbeat(envLabel, "\uC99D\uBD84 \uBC30\uD3EC \uC7AC\uC2DC\uB3C4");
|
|
485
|
+
const res2 = await makeRequest(`${baseStorageUrl}/deploy/incremental`, "POST", headers, body2, { timeoutMs });
|
|
486
|
+
if (heartbeat) clearInterval(heartbeat);
|
|
487
|
+
process.stdout.write("\r \r");
|
|
455
488
|
handleDeployResponse(res2, envLabel);
|
|
456
489
|
return;
|
|
457
490
|
}
|
|
458
491
|
handleDeployResponse(res, envLabel);
|
|
459
492
|
}
|
|
460
|
-
async function fullDeploy(baseStorageUrl, headers, files, envLabel, endpoint) {
|
|
493
|
+
async function fullDeploy(baseStorageUrl, headers, files, envLabel, endpoint, timeoutMs) {
|
|
461
494
|
process.stdout.write(`${colors.blue}\u27F3${colors.reset} ${envLabel} \uBC30\uD3EC \uC911...`);
|
|
495
|
+
const heartbeat = startUploadHeartbeat(envLabel);
|
|
462
496
|
const body = JSON.stringify({
|
|
463
497
|
files: files.map((f) => ({
|
|
464
498
|
path: f.path,
|
|
@@ -466,8 +500,9 @@ async function fullDeploy(baseStorageUrl, headers, files, envLabel, endpoint) {
|
|
|
466
500
|
is_binary: f.isBinary
|
|
467
501
|
}))
|
|
468
502
|
});
|
|
469
|
-
const res = await makeRequest(`${baseStorageUrl}/${endpoint}`, "POST", headers, body);
|
|
470
|
-
|
|
503
|
+
const res = await makeRequest(`${baseStorageUrl}/${endpoint}`, "POST", headers, body, { timeoutMs });
|
|
504
|
+
if (heartbeat) clearInterval(heartbeat);
|
|
505
|
+
process.stdout.write("\r \r");
|
|
471
506
|
handleDeployResponse(res, envLabel);
|
|
472
507
|
}
|
|
473
508
|
function handleDeployResponse(response, envLabel) {
|
|
@@ -2308,7 +2343,7 @@ ${colors.yellow}\uC635\uC158:${colors.reset}
|
|
|
2308
2343
|
-s, --storage <id> \uC2A4\uD1A0\uB9AC\uC9C0 ID
|
|
2309
2344
|
-k, --public-key <key> API Key
|
|
2310
2345
|
-u, --base-url <url> \uC11C\uBC84 URL (\uAE30\uBCF8: ${DEFAULT_BASE_URL})
|
|
2311
|
-
-t, --timeout <sec> \
|
|
2346
|
+
-t, --timeout <sec> \uC694\uCCAD \uD0C0\uC784\uC544\uC6C3 (\uCD08, tunnel/deploy \uACF5\uD1B5. deploy \uBBF8\uC9C0\uC815 \uC2DC \uD30C\uC77C \uD06C\uAE30\uC5D0 \uB530\uB77C \uC790\uB3D9 \uC0B0\uC815)
|
|
2312
2347
|
--max-body <MB> \uD130\uB110 \uCD5C\uB300 \uBC14\uB514 \uD06C\uAE30 (MB, tunnel \uC804\uC6A9)
|
|
2313
2348
|
--force \uD130\uB110 lockfile \uBB34\uC2DC (\uC911\uBCF5 \uC2E4\uD589 \uAC15\uC81C, tunnel \uC804\uC6A9)
|
|
2314
2349
|
--public proxy_token \uAC80\uC99D \uBE44\uD65C\uC131\uD654 \u2014 \uC6F9\uD6C5/\uC678\uBD80 \uC9C1\uC811 \uD638\uCD9C\uC6A9 (tunnel \uC804\uC6A9)
|
|
@@ -2466,7 +2501,13 @@ async function main() {
|
|
|
2466
2501
|
process.exit(1);
|
|
2467
2502
|
}
|
|
2468
2503
|
const isDev = parsed.options.dev === "true";
|
|
2469
|
-
|
|
2504
|
+
const deployOpts = {};
|
|
2505
|
+
if (parsed.options.timeout) {
|
|
2506
|
+
const t = parseInt(parsed.options.timeout, 10);
|
|
2507
|
+
if (!isNaN(t) && t > 0) deployOpts.timeoutMs = t * 1e3;
|
|
2508
|
+
else warn(`--timeout \uAC12\uC774 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC544 \uBB34\uC2DC\uB429\uB2C8\uB2E4: ${parsed.options.timeout}`);
|
|
2509
|
+
}
|
|
2510
|
+
await deploy(directory, config, isDev, deployOpts);
|
|
2470
2511
|
} else if (parsed.command === "tunnel") {
|
|
2471
2512
|
const portStr = parsed.args[0];
|
|
2472
2513
|
if (!portStr) {
|