connectbase-client 0.10.14 → 0.12.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/README.md CHANGED
@@ -12,9 +12,9 @@ pnpm add connectbase-client
12
12
  yarn add connectbase-client
13
13
  ```
14
14
 
15
- ## API Key Types
15
+ ## Key Types
16
16
 
17
- Connect Base provides **two types** of API Keys. Use the right key for your use case:
17
+ Connect Base provides **two types** of Keys. Use the right key for your use case:
18
18
 
19
19
  | Type | Prefix | Use For | Permissions | Safe to Expose? |
20
20
  |------|--------|---------|-------------|-----------------|
@@ -26,7 +26,7 @@ Connect Base provides **two types** of API Keys. Use the right key for your use
26
26
  | Context | Key Type | Example |
27
27
  |---------|----------|---------|
28
28
  | Frontend SDK (`new ConnectBase()`) | **Public Key** (`cb_pk_`) | Web/app: DB queries, auth, file uploads |
29
- | `.env` file (`VITE_CONNECTBASE_API_KEY`) | **Public Key** (`cb_pk_`) | React, Vue, etc. |
29
+ | `.env` file (`VITE_CONNECTBASE_PUBLIC_KEY`) | **Public Key** (`cb_pk_`) | React, Vue, etc. |
30
30
  | CLI deploy (`.connectbaserc`) | **Public Key** (`cb_pk_`) | `npx connectbase deploy` |
31
31
  | MCP server (AI tools) | **Secret Key** (`cb_sk_`) | Claude, Cursor, Windsurf |
32
32
  | Server-side admin tasks | **Secret Key** (`cb_sk_`) | Backend full data access |
@@ -35,7 +35,7 @@ Connect Base provides **two types** of API Keys. Use the right key for your use
35
35
  >
36
36
  > ⚠️ **Never use Secret Keys in frontend code** — RLS is bypassed, exposing all data.
37
37
 
38
- Create API 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.
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
40
  ## Quick Start
41
41
 
@@ -44,7 +44,7 @@ import ConnectBase from 'connectbase-client'
44
44
 
45
45
  // Initialize the SDK — use a Public Key (cb_pk_)
46
46
  const cb = new ConnectBase({
47
- apiKey: 'cb_pk_your-public-key'
47
+ publicKey: 'cb_pk_your-public-key'
48
48
  })
49
49
 
50
50
  // Create a game room client
@@ -96,7 +96,7 @@ npm run deploy
96
96
  ```
97
97
 
98
98
  The `init` command will:
99
- - Ask for your API Key
99
+ - Ask for your Public Key
100
100
  - List existing web storages or create a new one automatically
101
101
  - Create a `.connectbaserc` config file
102
102
  - Add `.connectbaserc` to `.gitignore`
@@ -115,7 +115,7 @@ The `init` command will:
115
115
  If you prefer not to use `init`, you can pass options directly:
116
116
 
117
117
  ```bash
118
- npx connectbase-client deploy ./dist -s <storage-id> -k <api-key>
118
+ npx connectbase-client deploy ./dist -s <storage-id> -k <public-key>
119
119
  ```
120
120
 
121
121
  ### Options
@@ -123,7 +123,7 @@ npx connectbase-client deploy ./dist -s <storage-id> -k <api-key>
123
123
  | Option | Alias | Description |
124
124
  |--------|-------|-------------|
125
125
  | `--storage <id>` | `-s` | Storage ID |
126
- | `--api-key <key>` | `-k` | API Key |
126
+ | `--public-key <key>` | `-k` | API Key |
127
127
  | `--base-url <url>` | `-u` | Custom server URL |
128
128
  | `--timeout <sec>` | `-t` | Tunnel request timeout in seconds (tunnel only) |
129
129
  | `--max-body <MB>` | | Tunnel max body size in MB (tunnel only) |
@@ -136,10 +136,10 @@ Expose a local server to the internet through a secure WebSocket tunnel. Useful
136
136
 
137
137
  ```bash
138
138
  # Expose local port 8084 to the internet
139
- npx connectbase-client tunnel 8084 -k <api-key>
139
+ npx connectbase-client tunnel 8084 -k <public-key>
140
140
 
141
141
  # With environment variable
142
- export CONNECTBASE_API_KEY=your-api-key
142
+ export CONNECTBASE_PUBLIC_KEY=your-public-key
143
143
  npx connectbase-client tunnel 8084
144
144
 
145
145
  # For GPU servers or long-running tasks (e.g., image generation)
@@ -170,7 +170,7 @@ The `init` command creates `.connectbaserc` automatically. You can also create i
170
170
 
171
171
  ```json
172
172
  {
173
- "apiKey": "your-api-key",
173
+ "publicKey": "your-public-key",
174
174
  "storageId": "your-storage-id",
175
175
  "deployDir": "./dist"
176
176
  }
@@ -179,7 +179,7 @@ The `init` command creates `.connectbaserc` automatically. You can also create i
179
179
  ### Environment Variables
180
180
 
181
181
  ```bash
182
- export CONNECTBASE_API_KEY=your-api-key
182
+ export CONNECTBASE_PUBLIC_KEY=your-public-key
183
183
  export CONNECTBASE_STORAGE_ID=your-storage-id
184
184
  npx connectbase-client deploy ./dist
185
185
  ```
@@ -780,7 +780,7 @@ await cb.push.unsubscribeFromTopic('news')
780
780
  ### WebRTC
781
781
 
782
782
  ```typescript
783
- // API Key/JWT 유효성 사전 검증
783
+ // Public Key/JWT 유효성 사전 검증
784
784
  const result = await cb.webrtc.validate()
785
785
  if (result.valid) {
786
786
  console.log('인증 성공:', result.app_id)
@@ -939,7 +939,7 @@ setInterval(async () => {
939
939
  ```typescript
940
940
  import ConnectBase from 'connectbase-client'
941
941
 
942
- const cb = new ConnectBase({ apiKey: 'your-api-key' })
942
+ const cb = new ConnectBase({ publicKey: 'your-public-key' })
943
943
  const game = cb.game.createClient({ clientId: `player-${Date.now()}` })
944
944
 
945
945
  // Local player state
package/dist/cli.js CHANGED
@@ -113,7 +113,8 @@ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
113
113
  ]);
114
114
  function loadConfig() {
115
115
  const config = {
116
- apiKey: process.env.CONNECTBASE_API_KEY,
116
+ publicKey: process.env.CONNECTBASE_PUBLIC_KEY,
117
+ secretKey: process.env.CONNECTBASE_SECRET_KEY,
117
118
  storageId: process.env.CONNECTBASE_STORAGE_ID,
118
119
  baseUrl: process.env.CONNECTBASE_BASE_URL || DEFAULT_BASE_URL
119
120
  };
@@ -121,7 +122,7 @@ function loadConfig() {
121
122
  if (fs.existsSync(rcPath)) {
122
123
  try {
123
124
  const rcContent = JSON.parse(fs.readFileSync(rcPath, "utf-8"));
124
- if (rcContent.apiKey) config.apiKey = rcContent.apiKey;
125
+ if (rcContent.publicKey) config.publicKey = rcContent.publicKey;
125
126
  if (rcContent.secretKey) config.secretKey = rcContent.secretKey;
126
127
  if (rcContent.storageId) config.storageId = rcContent.storageId;
127
128
  if (rcContent.baseUrl) config.baseUrl = rcContent.baseUrl;
@@ -256,7 +257,7 @@ async function deploy(directory, config, isDev = false) {
256
257
  url,
257
258
  "POST",
258
259
  {
259
- "X-API-Key": config.apiKey
260
+ "X-Public-Key": config.publicKey ?? config.publicKey
260
261
  },
261
262
  JSON.stringify({
262
263
  files: files.map((f) => ({
@@ -496,7 +497,7 @@ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${co
496
497
  const appsRes = await makeRequest(
497
498
  `${DEFAULT_BASE_URL}/v1/public/cli/apps`,
498
499
  "GET",
499
- { "X-API-Key": secretKey }
500
+ { "X-Public-Key": secretKey }
500
501
  );
501
502
  if (appsRes.status === 401) {
502
503
  error("Secret Key\uAC00 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uCF58\uC194\uC5D0\uC11C \uD0A4\uB97C \uD655\uC778\uD558\uC138\uC694");
@@ -523,9 +524,9 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `);
523
524
  success(`\uC120\uD0DD\uB428: ${apps[num - 1].name}`);
524
525
  info("Public Key \uC0DD\uC131 \uC911...");
525
526
  const newKeyRes = await makeRequest(
526
- `${DEFAULT_BASE_URL}/v1/public/cli/apps/${appId}/api-keys/public`,
527
+ `${DEFAULT_BASE_URL}/v1/public/cli/apps/${appId}/public-keys/public`,
527
528
  "POST",
528
- { "X-API-Key": secretKey },
529
+ { "X-Public-Key": secretKey },
529
530
  JSON.stringify({})
530
531
  );
531
532
  if (newKeyRes.status === 201) {
@@ -544,7 +545,7 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `);
544
545
  const createRes = await makeRequest(
545
546
  `${DEFAULT_BASE_URL}/v1/public/cli/apps`,
546
547
  "POST",
547
- { "X-API-Key": secretKey },
548
+ { "X-Public-Key": secretKey },
548
549
  JSON.stringify({ name: appName })
549
550
  );
550
551
  if (createRes.status === 402) {
@@ -574,14 +575,14 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `);
574
575
  process.exit(1);
575
576
  }
576
577
  }
577
- const apiKeyForSdk = publicKey || secretKey;
578
+ const publicKeyForSdk = publicKey || secretKey;
578
579
  let storageId = "";
579
580
  try {
580
581
  info("\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC870\uD68C \uC911...");
581
582
  const listRes = await makeRequest(
582
583
  `${DEFAULT_BASE_URL}/v1/public/storages/webs`,
583
584
  "GET",
584
- { "X-API-Key": apiKeyForSdk }
585
+ { "X-Public-Key": publicKeyForSdk }
585
586
  );
586
587
  if (listRes.status === 200) {
587
588
  const listData = listRes.data;
@@ -608,7 +609,7 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `);
608
609
  const createRes = await makeRequest(
609
610
  `${DEFAULT_BASE_URL}/v1/public/storages/webs`,
610
611
  "POST",
611
- { "X-API-Key": apiKeyForSdk },
612
+ { "X-Public-Key": publicKeyForSdk },
612
613
  JSON.stringify({ name })
613
614
  );
614
615
  if (createRes.status !== 200) {
@@ -635,7 +636,7 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `);
635
636
  const defaultDir = detectBuildDir();
636
637
  const deployDir = await prompt(`${colors.blue}?${colors.reset} \uBC30\uD3EC \uB514\uB809\uD1A0\uB9AC (${defaultDir}): `) || defaultDir;
637
638
  const config = {
638
- apiKey: publicKey || "",
639
+ publicKey: publicKey || "",
639
640
  storageId,
640
641
  deployDir
641
642
  };
@@ -646,7 +647,7 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `);
646
647
  success(".connectbaserc \uC0DD\uC131 \uC644\uB8CC");
647
648
  addToGitignore(".connectbaserc");
648
649
  addDeployScript(deployDir);
649
- await setupClaudeCode(apiKeyForSdk, secretKey, projectRoot);
650
+ await setupClaudeCode(publicKeyForSdk, secretKey, projectRoot);
650
651
  log(`
651
652
  ${colors.green}\uCD08\uAE30\uD654 \uC644\uB8CC!${colors.reset}
652
653
  `);
@@ -751,7 +752,7 @@ function detectMonorepo(gitRoot) {
751
752
  }
752
753
  return result;
753
754
  }
754
- async function downloadDocs(apiKey, templates, baseDir) {
755
+ async function downloadDocs(publicKey, templates, baseDir) {
755
756
  if (!baseDir) {
756
757
  baseDir = getProjectRoot();
757
758
  }
@@ -775,7 +776,7 @@ async function downloadDocs(apiKey, templates, baseDir) {
775
776
  try {
776
777
  const templateParam = templates.join(",");
777
778
  const res = await makeRequest(
778
- `${DEFAULT_BASE_URL}/v1/storages/webs/claude-md?template=${encodeURIComponent(templateParam)}&format=sections&api_key=${encodeURIComponent(apiKey)}`,
779
+ `${DEFAULT_BASE_URL}/v1/storages/webs/claude-md?template=${encodeURIComponent(templateParam)}&format=sections&public_key=${encodeURIComponent(publicKey)}`,
779
780
  "GET",
780
781
  {}
781
782
  );
@@ -955,9 +956,9 @@ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${co
955
956
  log(`
956
957
  ${colors.dim}Claude Code\uC5D0\uC11C ConnectBase MCP \uB3C4\uAD6C\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.${colors.reset}`);
957
958
  }
958
- async function setupClaudeCode(apiKey, secretKey, projectRoot) {
959
+ async function setupClaudeCode(publicKey, secretKey, projectRoot) {
959
960
  const root = projectRoot || getProjectRoot();
960
- await downloadDocs(apiKey, void 0, root);
961
+ await downloadDocs(publicKey, void 0, root);
961
962
  await setupMcp(secretKey);
962
963
  }
963
964
  function createWsTextFrame(payload) {
@@ -1074,7 +1075,7 @@ function getTunnelServerUrl(baseUrl) {
1074
1075
  }
1075
1076
  return baseUrl.replace(/:\d+/, ":8090");
1076
1077
  }
1077
- async function resolveAppForTunnel(apiKey, baseUrl, appIdOption) {
1078
+ async function resolveAppForTunnel(secretKey, baseUrl, appIdOption) {
1078
1079
  if (appIdOption) {
1079
1080
  return appIdOption;
1080
1081
  }
@@ -1084,7 +1085,7 @@ async function resolveAppForTunnel(apiKey, baseUrl, appIdOption) {
1084
1085
  const appsRes = await makeRequest(
1085
1086
  `${baseUrl}/v1/public/cli/apps`,
1086
1087
  "GET",
1087
- { "X-API-Key": apiKey }
1088
+ { "X-Public-Key": secretKey }
1088
1089
  );
1089
1090
  if (appsRes.status === 401) {
1090
1091
  error("Secret Key\uAC00 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uCF58\uC194\uC5D0\uC11C \uD0A4\uB97C \uD655\uC778\uD558\uC138\uC694");
@@ -1125,7 +1126,7 @@ ${colors.blue}?${colors.reset} \uC571 \uC120\uD0DD (\uBC88\uD638): `);
1125
1126
  const createRes = await makeRequest(
1126
1127
  `${baseUrl}/v1/public/cli/apps`,
1127
1128
  "POST",
1128
- { "X-API-Key": apiKey },
1129
+ { "X-Public-Key": secretKey },
1129
1130
  JSON.stringify({ name: appName })
1130
1131
  );
1131
1132
  if (createRes.status === 402) {
@@ -1142,7 +1143,7 @@ ${colors.blue}?${colors.reset} \uC571 \uC120\uD0DD (\uBC88\uD638): `);
1142
1143
  return createData.app_id;
1143
1144
  }
1144
1145
  async function startTunnel(port, config, tunnelOpts) {
1145
- const tunnelKey = config.secretKey || (config.apiKey?.startsWith("cb_sk_") ? config.apiKey : "");
1146
+ let tunnelKey = config.secretKey || (config.publicKey?.startsWith("cb_sk_") ? config.publicKey : "");
1146
1147
  if (!tunnelKey) {
1147
1148
  info("Secret Key\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC73C\uB85C \uBC1C\uAE09\uD569\uB2C8\uB2E4...");
1148
1149
  try {
@@ -1159,14 +1160,15 @@ async function startTunnel(port, config, tunnelOpts) {
1159
1160
  fs.writeFileSync(rcPath2, JSON.stringify(rcData, null, 2) + "\n");
1160
1161
  addToGitignore(".connectbaserc");
1161
1162
  success("Secret Key \uBC1C\uAE09 \uBC0F \uC800\uC7A5 \uC644\uB8CC");
1162
- config.apiKey = sk;
1163
+ tunnelKey = sk;
1164
+ config.secretKey = sk;
1163
1165
  } catch (err) {
1164
1166
  error(`\uC778\uC99D \uC2E4\uD328: ${err instanceof Error ? err.message : err}`);
1165
1167
  info("-k \uC635\uC158\uC73C\uB85C Secret Key\uB97C \uC9C1\uC811 \uC804\uB2EC\uD560 \uC218\uB3C4 \uC788\uC2B5\uB2C8\uB2E4");
1166
1168
  process.exit(1);
1167
1169
  }
1168
1170
  } else {
1169
- config.apiKey = tunnelKey;
1171
+ config.secretKey = tunnelKey;
1170
1172
  }
1171
1173
  const rcPath = path.join(process.cwd(), ".connectbaserc");
1172
1174
  let savedAppId = tunnelOpts?.appId || "";
@@ -1177,7 +1179,7 @@ async function startTunnel(port, config, tunnelOpts) {
1177
1179
  } catch {
1178
1180
  }
1179
1181
  }
1180
- const appId = await resolveAppForTunnel(config.apiKey, config.baseUrl, savedAppId);
1182
+ const appId = await resolveAppForTunnel(tunnelKey, config.baseUrl, savedAppId);
1181
1183
  try {
1182
1184
  let rcData = {};
1183
1185
  if (fs.existsSync(rcPath)) {
@@ -1242,7 +1244,7 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
1242
1244
  "Connection": "Upgrade",
1243
1245
  "Sec-WebSocket-Key": wsKey,
1244
1246
  "Sec-WebSocket-Version": "13",
1245
- "Authorization": `Bearer ${config.apiKey}`
1247
+ "Authorization": `Bearer ${config.secretKey ?? config.publicKey}`
1246
1248
  }
1247
1249
  };
1248
1250
  const req = lib.request(reqOptions);
@@ -1487,7 +1489,7 @@ ${colors.yellow}\uCF54\uB4DC \uBD84\uC11D (MCP \uD1B5\uD574 \uC0AC\uC6A9):${colo
1487
1489
 
1488
1490
  ${colors.yellow}\uC635\uC158:${colors.reset}
1489
1491
  -s, --storage <id> \uC2A4\uD1A0\uB9AC\uC9C0 ID
1490
- -k, --api-key <key> API Key
1492
+ -k, --public-key <key> API Key
1491
1493
  -u, --base-url <url> \uC11C\uBC84 URL (\uAE30\uBCF8: ${DEFAULT_BASE_URL})
1492
1494
  -t, --timeout <sec> \uD130\uB110 \uC694\uCCAD \uD0C0\uC784\uC544\uC6C3 (\uCD08, tunnel \uC804\uC6A9)
1493
1495
  --max-body <MB> \uD130\uB110 \uCD5C\uB300 \uBC14\uB514 \uD06C\uAE30 (MB, tunnel \uC804\uC6A9)
@@ -1519,13 +1521,16 @@ ${colors.yellow}\uBE60\uB978 \uC2DC\uC791:${colors.reset}
1519
1521
  npx connectbase tunnel 7860 --timeout 300 --max-body 50
1520
1522
 
1521
1523
  ${colors.yellow}\uD658\uACBD\uBCC0\uC218:${colors.reset}
1522
- CONNECTBASE_API_KEY API Key
1524
+ CONNECTBASE_PUBLIC_KEY Public Key (cb_pk_*)
1525
+ CONNECTBASE_SECRET_KEY Secret Key (cb_sk_*, \uD130\uB110\uC6A9)
1526
+ CONNECTBASE_PUBLIC_KEY (deprecated) \uB808\uAC70\uC2DC \u2014 publicKey \uB610\uB294 secretKey \uB85C \uC0AC\uC6A9
1523
1527
  CONNECTBASE_STORAGE_ID \uC2A4\uD1A0\uB9AC\uC9C0 ID
1524
1528
  CONNECTBASE_BASE_URL \uC11C\uBC84 URL
1525
1529
 
1526
1530
  ${colors.yellow}\uC124\uC815 \uD30C\uC77C (.connectbaserc):${colors.reset}
1527
1531
  {
1528
- "apiKey": "your-api-key",
1532
+ "publicKey": "cb_pk_...",
1533
+ "secretKey": "cb_sk_...",
1529
1534
  "storageId": "your-storage-id",
1530
1535
  "deployDir": "./dist"
1531
1536
  }
@@ -1541,8 +1546,10 @@ function parseArgs(args) {
1541
1546
  const arg = args[i];
1542
1547
  if (arg === "-s" || arg === "--storage") {
1543
1548
  result.options.storageId = args[++i];
1544
- } else if (arg === "-k" || arg === "--api-key") {
1545
- result.options.apiKey = args[++i];
1549
+ } else if (arg === "-k" || arg === "--public-key" || arg === "--public-key") {
1550
+ result.options.publicKey = args[++i];
1551
+ } else if (arg === "--secret-key") {
1552
+ result.options.secretKey = args[++i];
1546
1553
  } else if (arg === "-u" || arg === "--base-url") {
1547
1554
  result.options.baseUrl = args[++i];
1548
1555
  } else if (arg === "-t" || arg === "--timeout") {
@@ -1580,28 +1587,29 @@ async function main() {
1580
1587
  }
1581
1588
  const fileConfig = loadConfig();
1582
1589
  const config = {
1583
- apiKey: parsed.options.apiKey || fileConfig.apiKey,
1590
+ publicKey: parsed.options.publicKey || fileConfig.publicKey,
1591
+ secretKey: parsed.options.secretKey || fileConfig.secretKey,
1584
1592
  storageId: parsed.options.storageId || fileConfig.storageId,
1585
1593
  baseUrl: parsed.options.baseUrl || fileConfig.baseUrl || DEFAULT_BASE_URL
1586
1594
  };
1587
1595
  if (parsed.command === "init") {
1588
1596
  await init();
1589
1597
  } else if (parsed.command === "docs") {
1590
- let docsApiKey = config.apiKey;
1591
- if (!docsApiKey) {
1592
- docsApiKey = await prompt(`${colors.blue}?${colors.reset} API Key: `);
1593
- if (!docsApiKey) {
1594
- error("API Key\uB294 \uD544\uC218\uC785\uB2C8\uB2E4");
1598
+ let docsPublicKey = config.publicKey ?? config.publicKey;
1599
+ if (!docsPublicKey) {
1600
+ docsPublicKey = await prompt(`${colors.blue}?${colors.reset} Public Key: `);
1601
+ if (!docsPublicKey) {
1602
+ error("Public Key\uB294 \uD544\uC218\uC785\uB2C8\uB2E4");
1595
1603
  process.exit(1);
1596
1604
  }
1597
1605
  }
1598
- await downloadDocs(docsApiKey);
1606
+ await downloadDocs(docsPublicKey);
1599
1607
  } else if (parsed.command === "mcp") {
1600
1608
  await setupMcp();
1601
1609
  } else if (parsed.command === "deploy") {
1602
1610
  const directory = parsed.args[0] || fileConfig.deployDir || ".";
1603
- if (!config.apiKey) {
1604
- error('API Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase-client init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -k \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694');
1611
+ if (!config.publicKey && !config.publicKey) {
1612
+ error('Public Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase-client init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -k \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694');
1605
1613
  process.exit(1);
1606
1614
  }
1607
1615
  if (!config.storageId) {