connectbase-client 6.3.3 → 6.4.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 CHANGED
@@ -3,6 +3,38 @@
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.4.0] - 2026-10-01
7
+
8
+ ### Added — 웹 배포에 브라우저 ML 모델 확장자 허용 (`.onnx` `.tflite` `.task` `.safetensors`)
9
+
10
+ onnxruntime-web / TensorFlow Lite / MediaPipe Tasks / transformers.js 가 fetch 로 읽는 모델 파일을
11
+ `deploy` 가 허용목록에 없다는 이유로 빠뜨렸습니다. 배포는 성공으로 끝나는데 사이트에서는 404 였습니다.
12
+ 이제 네 확장자 모두 바이너리로 수집되며, 웹 스토리지 파일당 한도(약 6 MB)를 넘는 모델은 다른 대용량
13
+ 바이너리와 똑같이 presigned URL 로 오브젝트 스토리지에 직접 올라갑니다. `.bin` 으로 이름을 바꾸는
14
+ 우회는 더 이상 필요 없습니다.
15
+
16
+ ### Changed — 허용되지 않는 파일이 있으면 배포 때 알려줍니다
17
+
18
+ 허용되지 않는 확장자의 파일은 여전히 배포에서 제외되지만, 이제 조용히 넘어가지 않습니다. 파일 수집
19
+ 직후 제외된 파일 목록(앞 10개 + 외 N개), 확장자별 개수, 허용 확장자 목록을 경고로 보여주고, 배포 성공
20
+ 메시지 뒤에도 "N개는 포함되지 않았습니다" 를 한 번 더 찍습니다. 숨김 파일/폴더(`.env`, `.git/` 등)는
21
+ 의도적 제외라 목록에 넣지 않습니다. 배포 결과(종료 코드)는 바뀌지 않습니다.
22
+
23
+ ## [6.3.4] - 2026-09-08
24
+
25
+ ### Fixed — deploy 스크립트가 `npx` 로 CLI 를 부르면 6.3.3 의 "스크립트 안" 판정이 빠지던 문제
26
+
27
+ 6.3.3 은 `npm_lifecycle_event` 가 package.json scripts 의 이름이면 스크립트 안으로 봤습니다. 그런데
28
+ `"deploy": "vite build && npx -y -p connectbase-client@latest connectbase deploy ./dist"` 처럼 npx 로
29
+ CLI 를 부르는 스크립트(예전 init 이 만들던 형태)에서는 npx 가 `npm_lifecycle_event` 를 "npx" 로,
30
+ `npm_lifecycle_script` 도 덮어써 `npm run deploy → npx` 와 직접 `npx` 의 환경변수가 완전히 같아집니다.
31
+ 그래서 여전히 "deploy 스크립트를 쓰세요" 안내가 그 스크립트 안에서 찍혔습니다.
32
+
33
+ 이제 (1) pnpm 은 npx 가 덮어쓰지 않는 `PNPM_SCRIPT_SRC_DIR` 로, (2) npm / yarn / bun 은 부모 프로세스
34
+ 명령줄(Linux `/proc`, macOS `ps`)에서 `<pm> run <스크립트>` 를 찾아 스크립트 안임을 판정합니다.
35
+ `npm-cli.js exec …` 나 스크립트 본문 자체에는 맞지 않는 패턴이라 직접 `npx connectbase-client deploy`
36
+ 를 친 경우엔 종전대로 안내합니다. 판정에 실패해도 안내 한 줄이 더 나올 뿐 배포에는 영향이 없습니다.
37
+
6
38
  ## [6.3.3] - 2026-09-08
7
39
 
8
40
  ### Fixed — `deploy` 가 방금 빌드한 직후에도 "배포 전 빌드를 먼저 실행하세요" 를 찍던 문제
package/README.md CHANGED
@@ -294,7 +294,9 @@ In CI, read the Secret Key from a repository secret:
294
294
  ### Requirements
295
295
 
296
296
  - `index.html` must exist in the root of the deploy directory
297
- - Supported file types: `.html`, `.css`, `.js`, `.json`, `.svg`, `.png`, `.jpg`, `.gif`, `.webp`, `.woff`, `.woff2`, `.ttf`, `.mp3`, `.mp4`, `.pdf`, `.wasm`, etc.
297
+ - Supported file types: `.html`, `.css`, `.js`, `.json`, `.svg`, `.png`, `.jpg`, `.gif`, `.webp`, `.woff`, `.woff2`, `.ttf`, `.mp3`, `.mp4`, `.pdf`, `.wasm`, 3D assets (`.glb`, `.gltf`, `.bin`), browser ML models (`.onnx`, `.tflite`, `.task`, `.safetensors`), etc.
298
+ - Files with other extensions are skipped, and `deploy` prints the skipped list as a warning. Hidden files and folders (`.env`, `.git/`) are skipped silently.
299
+ - Binary files over the per-file limit (~6 MB) are uploaded directly to object storage via presigned URLs.
298
300
 
299
301
  ### SPA Mode
300
302
 
package/dist/cli.js CHANGED
@@ -32,10 +32,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
32
32
  var cli_exports = {};
33
33
  __export(cli_exports, {
34
34
  TunnelConnectSelector: () => TunnelConnectSelector,
35
+ ancestorCommandLines: () => ancestorCommandLines,
35
36
  apiErrorMessage: () => apiErrorMessage,
36
37
  buildFirstHint: () => buildFirstHint,
38
+ collectDeployFiles: () => collectDeployFiles,
37
39
  computeDeployDiff: () => computeDeployDiff,
38
40
  detectPackageManager: () => detectPackageManager,
41
+ formatSkippedFilesReport: () => formatSkippedFilesReport,
39
42
  getTunnelConnectCandidates: () => getTunnelConnectCandidates,
40
43
  guessMimeType: () => guessMimeType,
41
44
  isAllowedDeployExt: () => isAllowedDeployExt,
@@ -43,8 +46,10 @@ __export(cli_exports, {
43
46
  makeRequest: () => makeRequest,
44
47
  normalizeRelativePath: () => normalizeRelativePath,
45
48
  packageManagerCommands: () => packageManagerCommands,
49
+ packageScriptInvocationPattern: () => packageScriptInvocationPattern,
46
50
  parseArgs: () => parseArgs,
47
51
  registerEndpointBinding: () => registerEndpointBinding,
52
+ runningInsidePackageScript: () => runningInsidePackageScript,
48
53
  sha256Hex: () => sha256Hex,
49
54
  storageAdminHeaders: () => storageAdminHeaders
50
55
  });
@@ -151,7 +156,7 @@ function handleTunnelError(msg, appId, localPort) {
151
156
  }
152
157
 
153
158
  // src/cli.ts
154
- var VERSION = "6.3.3" ? "6.3.3" : getPackageVersion();
159
+ var VERSION = "6.4.0" ? "6.4.0" : getPackageVersion();
155
160
  var DEFAULT_BASE_URL = "https://api.connectbase.world";
156
161
  var colors = {
157
162
  reset: "\x1B[0m",
@@ -212,7 +217,17 @@ var ALLOWED_EXTENSIONS = /* @__PURE__ */ new Set([
212
217
  // 3D 에셋: .glb/.bin 은 바이너리, .gltf 는 JSON(텍스트)
213
218
  ".glb",
214
219
  ".gltf",
215
- ".bin"
220
+ ".bin",
221
+ // 브라우저 추론용 ML 모델 (platform-issue 01a0f660). 전부 바이너리다.
222
+ // .onnx — onnxruntime-web
223
+ // .tflite — TensorFlow Lite (tfjs-tflite 등)
224
+ // .task — MediaPipe Tasks 번들
225
+ // .safetensors — transformers.js 등의 가중치
226
+ // 수 MB~수십 MB 가 흔하므로 BINARY_EXTENSIONS 에도 넣어 대용량 오프로드(presign) 대상으로 만든다.
227
+ ".onnx",
228
+ ".tflite",
229
+ ".task",
230
+ ".safetensors"
216
231
  ]);
217
232
  var ALLOWED_EXTENSIONLESS_FILES = /* @__PURE__ */ new Set(["_redirects", "_headers"]);
218
233
  var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
@@ -237,7 +252,11 @@ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
237
252
  ".zip",
238
253
  ".wasm",
239
254
  ".glb",
240
- ".bin"
255
+ ".bin",
256
+ ".onnx",
257
+ ".tflite",
258
+ ".task",
259
+ ".safetensors"
241
260
  ]);
242
261
  var MIME_BY_EXT = {
243
262
  ".png": "image/png",
@@ -263,7 +282,13 @@ var MIME_BY_EXT = {
263
282
  ".wasm": "application/wasm",
264
283
  ".glb": "model/gltf-binary",
265
284
  ".gltf": "model/gltf+json",
266
- ".bin": "application/octet-stream"
285
+ ".bin": "application/octet-stream",
286
+ // ML 모델은 등록된 표준 MIME 이 없다. 로더(onnxruntime-web/MediaPipe/transformers.js)는
287
+ // fetch → ArrayBuffer 로 읽으므로 octet-stream 이면 충분하다.
288
+ ".onnx": "application/octet-stream",
289
+ ".tflite": "application/octet-stream",
290
+ ".task": "application/octet-stream",
291
+ ".safetensors": "application/octet-stream"
267
292
  };
268
293
  function guessMimeType(filePath) {
269
294
  if (ALLOWED_EXTENSIONLESS_FILES.has(path2.basename(filePath))) {
@@ -346,7 +371,13 @@ function loadConfig() {
346
371
  }
347
372
  return config;
348
373
  }
349
- function collectFiles(dir, baseDir = dir) {
374
+ function collectDeployFiles(dir) {
375
+ const skipped = [];
376
+ const files = collectFiles(dir, dir, skipped);
377
+ skipped.sort();
378
+ return { files, skipped };
379
+ }
380
+ function collectFiles(dir, baseDir, skipped) {
350
381
  const files = [];
351
382
  const entries = fs2.readdirSync(dir, { withFileTypes: true });
352
383
  for (const entry of entries) {
@@ -354,14 +385,15 @@ function collectFiles(dir, baseDir = dir) {
354
385
  const relativePath = path2.relative(baseDir, fullPath);
355
386
  if (entry.isDirectory()) {
356
387
  if (!entry.name.startsWith(".")) {
357
- files.push(...collectFiles(fullPath, baseDir));
388
+ files.push(...collectFiles(fullPath, baseDir, skipped));
358
389
  }
359
390
  } else if (entry.isFile()) {
360
391
  const ext = path2.extname(entry.name).toLowerCase();
361
- if (!isAllowedDeployExt(entry.name)) {
392
+ if (entry.name.startsWith(".")) {
362
393
  continue;
363
394
  }
364
- if (entry.name.startsWith(".")) {
395
+ if (!isAllowedDeployExt(entry.name)) {
396
+ skipped.push(normalizeRelativePath(relativePath));
365
397
  continue;
366
398
  }
367
399
  const isBinary = BINARY_EXTENSIONS.has(ext);
@@ -382,6 +414,44 @@ function collectFiles(dir, baseDir = dir) {
382
414
  }
383
415
  return files;
384
416
  }
417
+ var SKIPPED_FILES_LIST_LIMIT = 10;
418
+ function formatSkippedFilesReport(skipped, limit = SKIPPED_FILES_LIST_LIMIT) {
419
+ if (skipped.length === 0) return [];
420
+ const lines = [];
421
+ lines.push(
422
+ `\uD5C8\uC6A9\uB418\uC9C0 \uC54A\uB294 \uD655\uC7A5\uC790\uB77C \uBC30\uD3EC\uC5D0\uC11C \uC81C\uC678\uB41C \uD30C\uC77C ${skipped.length}\uAC1C \u2014 \uC0AC\uC774\uD2B8\uC5D0\uC11C 404 \uAC00 \uB429\uB2C8\uB2E4:`
423
+ );
424
+ for (const p of skipped.slice(0, limit)) lines.push(` \u2022 ${p}`);
425
+ if (skipped.length > limit) {
426
+ lines.push(` \u2026 \uC678 ${skipped.length - limit}\uAC1C`);
427
+ }
428
+ const byExt = /* @__PURE__ */ new Map();
429
+ for (const p of skipped) {
430
+ const ext = path2.extname(p).toLowerCase() || "(\uD655\uC7A5\uC790 \uC5C6\uC74C)";
431
+ byExt.set(ext, (byExt.get(ext) ?? 0) + 1);
432
+ }
433
+ const extSummary = [...byExt.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([ext, n]) => `${ext} ${n}\uAC1C`).join(", ");
434
+ lines.push(` \uD655\uC7A5\uC790\uBCC4: ${extSummary}`);
435
+ lines.push(
436
+ ` \uD5C8\uC6A9 \uD655\uC7A5\uC790: ${[...ALLOWED_EXTENSIONS].join(" ")} (+ \uD655\uC7A5\uC790 \uC5C6\uB294 ${[...ALLOWED_EXTENSIONLESS_FILES].join(", ")})`
437
+ );
438
+ lines.push(
439
+ " \uD544\uC694\uD55C \uD30C\uC77C\uC774\uBA74 \uD5C8\uC6A9 \uD655\uC7A5\uC790\uB85C \uBC14\uAFB8\uAC70\uB098, \uD30C\uC77C \uC2A4\uD1A0\uB9AC\uC9C0(cb.storage)\uC5D0 \uC62C\uB824 URL \uB85C \uCC38\uC870\uD558\uC138\uC694."
440
+ );
441
+ return lines;
442
+ }
443
+ function reportSkippedFiles(skipped) {
444
+ const lines = formatSkippedFilesReport(skipped);
445
+ if (lines.length === 0) return;
446
+ warn(`${colors.yellow}${lines[0]}${colors.reset}`);
447
+ for (const line of lines.slice(1)) log(line);
448
+ }
449
+ function remindSkippedFiles(skipped) {
450
+ if (skipped.length === 0) return;
451
+ warn(
452
+ `\uB2E8, \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uB294 \uD655\uC7A5\uC790 \uD30C\uC77C ${skipped.length}\uAC1C\uB294 \uBC30\uD3EC\uC5D0 \uD3EC\uD568\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 (\uC704 \uBAA9\uB85D \uCC38\uACE0).`
453
+ );
454
+ }
385
455
  function formatSize(bytes) {
386
456
  if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
387
457
  return `${(bytes / 1024).toFixed(1)} KB`;
@@ -680,7 +750,8 @@ async function deploy(directory, config, isDev = false, deployOpts = {}) {
680
750
  try {
681
751
  const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
682
752
  const pm = packageManagerCommands(detectPackageManager(process.cwd()));
683
- for (const line of buildFirstHint(pkg, pm)) warn(line);
753
+ const inside = runningInsidePackageScript(pkg.scripts ?? {});
754
+ for (const line of buildFirstHint(pkg, pm, inside)) warn(line);
684
755
  } catch {
685
756
  }
686
757
  }
@@ -695,17 +766,19 @@ async function deploy(directory, config, isDev = false, deployOpts = {}) {
695
766
  }
696
767
  info(`\uBC30\uD3EC \uC900\uBE44 \uC911... ${dir}`);
697
768
  process.stdout.write(`${colors.dim}\uD30C\uC77C \uC218\uC9D1 \uC911...${colors.reset}`);
698
- const files = collectFiles(dir);
769
+ const { files, skipped } = collectDeployFiles(dir);
699
770
  process.stdout.write(`\r${colors.dim} \r${colors.reset}`);
700
771
  if (files.length === 0) {
772
+ reportSkippedFiles(skipped);
701
773
  error("\uBC30\uD3EC\uD560 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
702
774
  process.exit(1);
703
775
  }
704
776
  const totalSize = files.reduce((sum, f) => sum + f.content.length, 0);
705
777
  const sizeKB = (totalSize / 1024).toFixed(1);
706
778
  log(
707
- `${colors.green}\u2713${colors.reset} ${files.length}\uAC1C \uD30C\uC77C \uBC1C\uACAC (${sizeKB} KB)`
779
+ `${colors.green}\u2713${colors.reset} ${files.length}\uAC1C \uD30C\uC77C \uBC1C\uACAC (${sizeKB} KB)${skipped.length > 0 ? ` ${colors.yellow}\u2014 ${skipped.length}\uAC1C \uC81C\uC678${colors.reset}` : ""}`
708
780
  );
781
+ reportSkippedFiles(skipped);
709
782
  const target = isDev ? "qa" : void 0;
710
783
  const envLabel = isDev ? "QA" : "Prod";
711
784
  if (isDev) {
@@ -732,6 +805,7 @@ async function deploy(directory, config, isDev = false, deployOpts = {}) {
732
805
  timeoutMs,
733
806
  target
734
807
  );
808
+ remindSkippedFiles(skipped);
735
809
  return;
736
810
  }
737
811
  const diff = computeDeployDiff(files, manifest);
@@ -750,6 +824,7 @@ ${colors.cyan}URL: https://${config.storageId}.web.connectbase.world${colors.res
750
824
  `
751
825
  );
752
826
  }
827
+ remindSkippedFiles(skipped);
753
828
  return;
754
829
  }
755
830
  await offloadLargeBinaries(
@@ -773,6 +848,7 @@ ${colors.cyan}URL: https://${config.storageId}.web.connectbase.world${colors.res
773
848
  timeoutMs,
774
849
  target
775
850
  );
851
+ remindSkippedFiles(skipped);
776
852
  } catch (err) {
777
853
  process.stdout.write("\r \r");
778
854
  error(`\uB124\uD2B8\uC6CC\uD06C \uC624\uB958: ${err instanceof Error ? err.message : err}`);
@@ -1642,12 +1718,63 @@ ${entry}
1642
1718
  success(".gitignore \uC0DD\uC131 \uC644\uB8CC");
1643
1719
  }
1644
1720
  }
1645
- function buildFirstHint(pkg, pm, lifecycleEvent = process.env.npm_lifecycle_event) {
1721
+ function runningInsidePackageScript(scripts, env = process.env, ancestors = ancestorCommandLines) {
1722
+ const names = Object.keys(scripts);
1723
+ if (names.length === 0) return false;
1724
+ if (env.npm_lifecycle_event && names.includes(env.npm_lifecycle_event)) {
1725
+ return true;
1726
+ }
1727
+ if (env.PNPM_SCRIPT_SRC_DIR) return true;
1728
+ if (env.npm_lifecycle_event !== "npx") return false;
1729
+ const pattern = packageScriptInvocationPattern(names);
1730
+ return ancestors().some((cmd) => pattern.test(cmd));
1731
+ }
1732
+ function packageScriptInvocationPattern(names) {
1733
+ const alt = names.map((n) => n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
1734
+ return new RegExp(
1735
+ `^(?:\\S*node(?:\\.exe)?\\s+)?\\S*(?:npm(?:-cli)?|pnpm|yarn|bun)(?:\\.c?js)?\\s+(?:run(?:-script)?\\s+)?(?:-\\S+\\s+)*(?:${alt})(?:\\s|$)`
1736
+ );
1737
+ }
1738
+ function ancestorCommandLines(maxDepth = 8) {
1739
+ const lines = [];
1740
+ let pid = process.ppid;
1741
+ for (let i = 0; i < maxDepth && pid > 1; i++) {
1742
+ let cmd = "";
1743
+ let ppid = 0;
1744
+ try {
1745
+ if (process.platform === "linux") {
1746
+ cmd = fs2.readFileSync(`/proc/${pid}/cmdline`).toString("utf8").replace(/\0/g, " ").trim();
1747
+ const stat = fs2.readFileSync(`/proc/${pid}/stat`, "utf8");
1748
+ ppid = parseInt(
1749
+ stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1],
1750
+ 10
1751
+ );
1752
+ } else if (process.platform === "darwin") {
1753
+ const { execSync } = require("child_process");
1754
+ const out = execSync(`ps -o ppid=,args= -p ${pid}`, {
1755
+ encoding: "utf-8",
1756
+ stdio: ["ignore", "pipe", "ignore"]
1757
+ }).trim();
1758
+ const m = out.match(/^\s*(\d+)\s+(.*)$/);
1759
+ if (!m) break;
1760
+ ppid = parseInt(m[1], 10);
1761
+ cmd = m[2];
1762
+ } else {
1763
+ break;
1764
+ }
1765
+ } catch {
1766
+ break;
1767
+ }
1768
+ lines.push(cmd);
1769
+ if (!Number.isFinite(ppid)) break;
1770
+ pid = ppid;
1771
+ }
1772
+ return lines;
1773
+ }
1774
+ function buildFirstHint(pkg, pm, insideScript) {
1646
1775
  const scripts = pkg?.scripts ?? {};
1647
1776
  if (!scripts.build) return [];
1648
- if (lifecycleEvent && Object.keys(scripts).includes(lifecycleEvent)) {
1649
- return [];
1650
- }
1777
+ if (insideScript) return [];
1651
1778
  if (typeof scripts.deploy === "string" && scripts.deploy.includes("build")) {
1652
1779
  return [
1653
1780
  `\uBE4C\uB4DC\uAE4C\uC9C0 \uD55C \uBC88\uC5D0 \uD558\uB824\uBA74 deploy \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC4F0\uC138\uC694: ${pm.run("deploy")}`
@@ -3822,10 +3949,13 @@ main().catch((err) => {
3822
3949
  // Annotate the CommonJS export names for ESM import in node:
3823
3950
  0 && (module.exports = {
3824
3951
  TunnelConnectSelector,
3952
+ ancestorCommandLines,
3825
3953
  apiErrorMessage,
3826
3954
  buildFirstHint,
3955
+ collectDeployFiles,
3827
3956
  computeDeployDiff,
3828
3957
  detectPackageManager,
3958
+ formatSkippedFilesReport,
3829
3959
  getTunnelConnectCandidates,
3830
3960
  guessMimeType,
3831
3961
  isAllowedDeployExt,
@@ -3833,8 +3963,10 @@ main().catch((err) => {
3833
3963
  makeRequest,
3834
3964
  normalizeRelativePath,
3835
3965
  packageManagerCommands,
3966
+ packageScriptInvocationPattern,
3836
3967
  parseArgs,
3837
3968
  registerEndpointBinding,
3969
+ runningInsidePackageScript,
3838
3970
  sha256Hex,
3839
3971
  storageAdminHeaders
3840
3972
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "connectbase-client",
3
- "version": "6.3.3",
3
+ "version": "6.4.0",
4
4
  "description": "Connect Base JavaScript/TypeScript SDK for browser and Node.js",
5
5
  "repository": {
6
6
  "type": "git",