connectbase-client 0.3.0 → 0.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/README.md +15 -0
- package/dist/cli.js +49 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,6 +98,8 @@ npx connectbase-client deploy ./dist -s <storage-id> -k <api-key>
|
|
|
98
98
|
| `--storage <id>` | `-s` | Storage ID |
|
|
99
99
|
| `--api-key <key>` | `-k` | API Key |
|
|
100
100
|
| `--base-url <url>` | `-u` | Custom server URL |
|
|
101
|
+
| `--timeout <sec>` | `-t` | Tunnel request timeout in seconds (tunnel only) |
|
|
102
|
+
| `--max-body <MB>` | | Tunnel max body size in MB (tunnel only) |
|
|
101
103
|
| `--help` | `-h` | Show help |
|
|
102
104
|
| `--version` | `-v` | Show version |
|
|
103
105
|
|
|
@@ -112,11 +114,24 @@ npx connectbase-client tunnel 8084 -k <api-key>
|
|
|
112
114
|
# With environment variable
|
|
113
115
|
export CONNECTBASE_API_KEY=your-api-key
|
|
114
116
|
npx connectbase-client tunnel 8084
|
|
117
|
+
|
|
118
|
+
# For GPU servers or long-running tasks (e.g., image generation)
|
|
119
|
+
npx connectbase-client tunnel 7860 --timeout 300 --max-body 50
|
|
115
120
|
```
|
|
116
121
|
|
|
117
122
|
The tunnel creates a public URL like `https://tunnel.connectbase.world/<tunnel-id>/` that proxies all HTTP requests to your local service.
|
|
118
123
|
|
|
124
|
+
**Plan-based limits:** Timeout and body size are clamped to your plan's maximum:
|
|
125
|
+
|
|
126
|
+
| Plan | Max Timeout | Max Body |
|
|
127
|
+
|------|-------------|----------|
|
|
128
|
+
| Free | 60s | 10MB |
|
|
129
|
+
| Starter | 120s | 25MB |
|
|
130
|
+
| Pro | 300s | 50MB |
|
|
131
|
+
| Business | 600s | 100MB |
|
|
132
|
+
|
|
119
133
|
Features:
|
|
134
|
+
- Per-tunnel timeout and body size configuration
|
|
120
135
|
- Automatic reconnection with exponential backoff
|
|
121
136
|
- Request/response logging in terminal
|
|
122
137
|
- Graceful shutdown with Ctrl+C
|
package/dist/cli.js
CHANGED
|
@@ -470,6 +470,13 @@ function createWsCloseFrame(code) {
|
|
|
470
470
|
header[1] = 128 | 2;
|
|
471
471
|
return Buffer.concat([header, maskKey, masked]);
|
|
472
472
|
}
|
|
473
|
+
function createWsPongFrame() {
|
|
474
|
+
const maskKey = crypto.randomBytes(4);
|
|
475
|
+
const header = Buffer.alloc(2);
|
|
476
|
+
header[0] = 138;
|
|
477
|
+
header[1] = 128 | 0;
|
|
478
|
+
return Buffer.concat([header, maskKey]);
|
|
479
|
+
}
|
|
473
480
|
var WsFrameParser = class {
|
|
474
481
|
constructor(handlers) {
|
|
475
482
|
this.buffer = Buffer.alloc(0);
|
|
@@ -539,7 +546,7 @@ function getTunnelServerUrl(baseUrl) {
|
|
|
539
546
|
}
|
|
540
547
|
return baseUrl.replace(/:\d+/, ":8090");
|
|
541
548
|
}
|
|
542
|
-
async function startTunnel(port, config) {
|
|
549
|
+
async function startTunnel(port, config, tunnelOpts) {
|
|
543
550
|
if (!config.apiKey) {
|
|
544
551
|
error("API Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. -k \uC635\uC158 \uB610\uB294 CONNECTBASE_API_KEY \uD658\uACBD\uBCC0\uC218\uB97C \uC124\uC815\uD558\uC138\uC694");
|
|
545
552
|
process.exit(1);
|
|
@@ -547,7 +554,13 @@ async function startTunnel(port, config) {
|
|
|
547
554
|
const tunnelServerUrl = getTunnelServerUrl(config.baseUrl);
|
|
548
555
|
const parsedUrl = new URL(tunnelServerUrl);
|
|
549
556
|
const isHttps = parsedUrl.protocol === "https:";
|
|
550
|
-
|
|
557
|
+
let wsPath = `/v1/tunnel/connect?api_key=${encodeURIComponent(config.apiKey)}`;
|
|
558
|
+
if (tunnelOpts?.timeout) {
|
|
559
|
+
wsPath += `&timeout=${tunnelOpts.timeout}`;
|
|
560
|
+
}
|
|
561
|
+
if (tunnelOpts?.maxBody) {
|
|
562
|
+
wsPath += `&max_body=${tunnelOpts.maxBody}`;
|
|
563
|
+
}
|
|
551
564
|
let reconnectAttempts = 0;
|
|
552
565
|
const maxReconnectAttempts = 10;
|
|
553
566
|
let shouldReconnect = true;
|
|
@@ -608,8 +621,7 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
608
621
|
sock.destroy();
|
|
609
622
|
},
|
|
610
623
|
onPing: () => {
|
|
611
|
-
|
|
612
|
-
sock.write(createWsTextFrame(pongMsg));
|
|
624
|
+
sock.write(createWsPongFrame());
|
|
613
625
|
}
|
|
614
626
|
});
|
|
615
627
|
sock.on("data", (chunk) => parser.feed(chunk));
|
|
@@ -673,6 +685,9 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
673
685
|
success(`\uD130\uB110 \uD65C\uC131\uD654!`);
|
|
674
686
|
log(`${colors.green}\u2192${colors.reset} URL: ${colors.cyan}${msg.url}${colors.reset}`);
|
|
675
687
|
log(`${colors.green}\u2192${colors.reset} \uB85C\uCEEC: ${colors.cyan}http://localhost:${localPort}${colors.reset}`);
|
|
688
|
+
if (msg.timeout || msg.max_body) {
|
|
689
|
+
log(`${colors.green}\u2192${colors.reset} \uC124\uC815: timeout=${colors.cyan}${msg.timeout}s${colors.reset}, max-body=${colors.cyan}${msg.max_body}MB${colors.reset}`);
|
|
690
|
+
}
|
|
676
691
|
log(`
|
|
677
692
|
${colors.dim}Ctrl+C\uB85C \uC885\uB8CC${colors.reset}
|
|
678
693
|
`);
|
|
@@ -696,14 +711,20 @@ ${colors.dim}Ctrl+C\uB85C \uC885\uB8CC${colors.reset}
|
|
|
696
711
|
const headers = msg.headers || {};
|
|
697
712
|
const bodyBase64 = msg.body;
|
|
698
713
|
const fullPath = query ? `${reqPath}?${query}` : reqPath;
|
|
714
|
+
const localHeaders = {};
|
|
715
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
716
|
+
if (key.toLowerCase() !== "host") {
|
|
717
|
+
localHeaders[key] = value;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
localHeaders["host"] = `localhost:${localPort}`;
|
|
699
721
|
const reqOptions = {
|
|
700
722
|
hostname: "127.0.0.1",
|
|
701
723
|
port: localPort,
|
|
702
724
|
path: fullPath,
|
|
703
725
|
method,
|
|
704
|
-
headers:
|
|
726
|
+
headers: localHeaders
|
|
705
727
|
};
|
|
706
|
-
delete reqOptions.headers["Host"];
|
|
707
728
|
const localReq = http.request(reqOptions, (res) => {
|
|
708
729
|
const chunks = [];
|
|
709
730
|
res.on("data", (chunk) => chunks.push(chunk));
|
|
@@ -768,6 +789,8 @@ ${colors.yellow}\uC635\uC158:${colors.reset}
|
|
|
768
789
|
-s, --storage <id> \uC2A4\uD1A0\uB9AC\uC9C0 ID
|
|
769
790
|
-k, --api-key <key> API Key
|
|
770
791
|
-u, --base-url <url> \uC11C\uBC84 URL (\uAE30\uBCF8: ${DEFAULT_BASE_URL})
|
|
792
|
+
-t, --timeout <sec> \uD130\uB110 \uC694\uCCAD \uD0C0\uC784\uC544\uC6C3 (\uCD08, tunnel \uC804\uC6A9)
|
|
793
|
+
--max-body <MB> \uD130\uB110 \uCD5C\uB300 \uBC14\uB514 \uD06C\uAE30 (MB, tunnel \uC804\uC6A9)
|
|
771
794
|
-h, --help \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
|
|
772
795
|
-v, --version \uBC84\uC804 \uD45C\uC2DC
|
|
773
796
|
|
|
@@ -778,6 +801,12 @@ ${colors.yellow}\uBE60\uB978 \uC2DC\uC791:${colors.reset}
|
|
|
778
801
|
${colors.dim}# 2. \uBC30\uD3EC${colors.reset}
|
|
779
802
|
npm run deploy
|
|
780
803
|
|
|
804
|
+
${colors.dim}# 3. \uD130\uB110 (\uAE30\uBCF8)${colors.reset}
|
|
805
|
+
npx connectbase-client tunnel 3000
|
|
806
|
+
|
|
807
|
+
${colors.dim}# 4. \uD130\uB110 (GPU \uC11C\uBC84 \uB4F1 \uAE34 \uC751\uB2F5 \uC2DC)${colors.reset}
|
|
808
|
+
npx connectbase-client tunnel 7860 --timeout 300 --max-body 50
|
|
809
|
+
|
|
781
810
|
${colors.yellow}\uD658\uACBD\uBCC0\uC218:${colors.reset}
|
|
782
811
|
CONNECTBASE_API_KEY API Key
|
|
783
812
|
CONNECTBASE_STORAGE_ID \uC2A4\uD1A0\uB9AC\uC9C0 ID
|
|
@@ -805,6 +834,10 @@ function parseArgs(args) {
|
|
|
805
834
|
result.options.apiKey = args[++i];
|
|
806
835
|
} else if (arg === "-u" || arg === "--base-url") {
|
|
807
836
|
result.options.baseUrl = args[++i];
|
|
837
|
+
} else if (arg === "-t" || arg === "--timeout") {
|
|
838
|
+
result.options.timeout = args[++i];
|
|
839
|
+
} else if (arg === "--max-body") {
|
|
840
|
+
result.options.maxBody = args[++i];
|
|
808
841
|
} else if (arg === "-h" || arg === "--help") {
|
|
809
842
|
result.options.help = "true";
|
|
810
843
|
} else if (arg === "-v" || arg === "--version") {
|
|
@@ -860,7 +893,16 @@ async function main() {
|
|
|
860
893
|
error("\uC720\uD6A8\uD55C \uD3EC\uD2B8 \uBC88\uD638\uB97C \uC785\uB825\uD558\uC138\uC694 (1-65535)");
|
|
861
894
|
process.exit(1);
|
|
862
895
|
}
|
|
863
|
-
|
|
896
|
+
const tunnelOpts = {};
|
|
897
|
+
if (parsed.options.timeout) {
|
|
898
|
+
const t = parseInt(parsed.options.timeout, 10);
|
|
899
|
+
if (!isNaN(t) && t > 0) tunnelOpts.timeout = t;
|
|
900
|
+
}
|
|
901
|
+
if (parsed.options.maxBody) {
|
|
902
|
+
const m = parseInt(parsed.options.maxBody, 10);
|
|
903
|
+
if (!isNaN(m) && m > 0) tunnelOpts.maxBody = m;
|
|
904
|
+
}
|
|
905
|
+
await startTunnel(port, config, tunnelOpts);
|
|
864
906
|
} else {
|
|
865
907
|
error(`\uC54C \uC218 \uC5C6\uB294 \uBA85\uB839\uC5B4: ${parsed.command}`);
|
|
866
908
|
showHelp();
|