mekong-cli 1.1.0 → 1.2.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 +155 -85
- package/bin/mekong-cli.js +42 -14
- package/lib/wait-for-port.js +24 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# mekong-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Expose your Node.js dev server to the internet in one command.
|
|
4
|
+
> Works with Next.js, Vite, Nuxt, Angular, Astro, Svelte, Express, and more.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
[](https://www.npmjs.com/package/mekong-cli)
|
|
7
|
+
[](LICENSE)
|
|
6
8
|
|
|
7
9
|
---
|
|
8
10
|
|
|
@@ -12,7 +14,7 @@ Think of it as the glue between `next dev` / `vite` / `nuxt dev` and `mekong <po
|
|
|
12
14
|
npm install -g mekong-cli
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
Or use
|
|
17
|
+
Or use without installing:
|
|
16
18
|
|
|
17
19
|
```bash
|
|
18
20
|
npx mekong-cli 3000
|
|
@@ -23,90 +25,133 @@ npx mekong-cli 3000
|
|
|
23
25
|
## Requirements
|
|
24
26
|
|
|
25
27
|
- **Node.js 14+**
|
|
26
|
-
- **mekong binary**
|
|
28
|
+
- **mekong binary** — install separately (see below)
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
### Install the mekong binary
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
```bash
|
|
33
|
+
# macOS / Linux (auto-detect arch)
|
|
34
|
+
curl -fsSL https://github.com/MuyleangIng/MekongTunnel/releases/latest/download/mekong-$(uname -s | tr A-Z a-z)-$(uname -m) \
|
|
35
|
+
-o ~/.local/bin/mekong && chmod +x ~/.local/bin/mekong
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
# macOS Intel
|
|
38
|
+
curl -fsSL https://github.com/MuyleangIng/MekongTunnel/releases/latest/download/mekong-darwin-amd64 \
|
|
39
|
+
-o /usr/local/bin/mekong && chmod +x /usr/local/bin/mekong
|
|
33
40
|
|
|
34
|
-
|
|
41
|
+
# macOS Apple Silicon
|
|
42
|
+
curl -fsSL https://github.com/MuyleangIng/MekongTunnel/releases/latest/download/mekong-darwin-arm64 \
|
|
43
|
+
-o /usr/local/bin/mekong && chmod +x /usr/local/bin/mekong
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
curl -
|
|
45
|
+
# Linux amd64
|
|
46
|
+
curl -fsSL https://github.com/MuyleangIng/MekongTunnel/releases/latest/download/mekong-linux-amd64 \
|
|
38
47
|
-o /usr/local/bin/mekong && chmod +x /usr/local/bin/mekong
|
|
48
|
+
|
|
49
|
+
# Windows — download from:
|
|
50
|
+
# https://github.com/MuyleangIng/MekongTunnel/releases/latest
|
|
39
51
|
```
|
|
40
52
|
|
|
41
|
-
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Commands
|
|
56
|
+
|
|
57
|
+
### 1. `mekong-cli <port>` — Tunnel an already-running server
|
|
58
|
+
|
|
59
|
+
Your server is already running. Just pass the port:
|
|
42
60
|
|
|
43
61
|
```bash
|
|
44
|
-
|
|
45
|
-
|
|
62
|
+
mekong-cli 3000
|
|
63
|
+
mekong-cli 5173
|
|
64
|
+
mekong-cli 8080
|
|
46
65
|
```
|
|
47
66
|
|
|
48
|
-
|
|
67
|
+
> If nothing is listening on that port, mekong-cli will tell you clearly and exit — it will **not** start the tunnel.
|
|
49
68
|
|
|
50
69
|
---
|
|
51
70
|
|
|
52
|
-
|
|
71
|
+
### 2. `mekong-cli` — Auto-detect port from package.json
|
|
53
72
|
|
|
54
|
-
|
|
73
|
+
No port needed if your `package.json` uses a known framework:
|
|
55
74
|
|
|
56
75
|
```bash
|
|
57
|
-
mekong-cli
|
|
76
|
+
mekong-cli
|
|
58
77
|
```
|
|
59
78
|
|
|
60
|
-
|
|
79
|
+
mekong-cli reads your `package.json` and detects the port automatically:
|
|
80
|
+
|
|
81
|
+
| Framework | Detected port |
|
|
82
|
+
|---|---|
|
|
83
|
+
| Next.js | 3000 |
|
|
84
|
+
| Nuxt | 3000 |
|
|
85
|
+
| React (CRA) | 3000 |
|
|
86
|
+
| Remix | 3000 |
|
|
87
|
+
| Express / Fastify / Koa | 3000 |
|
|
88
|
+
| Vite | 5173 |
|
|
89
|
+
| SvelteKit | 5173 |
|
|
90
|
+
| Angular | 4200 |
|
|
91
|
+
| Astro | 4321 |
|
|
92
|
+
| Gatsby | 8000 |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### 3. `mekong-cli --with "<cmd>" --port <n>` — Start server + tunnel together
|
|
97
|
+
|
|
98
|
+
Start your dev server AND the tunnel at the same time — no separate terminals:
|
|
61
99
|
|
|
62
100
|
```bash
|
|
101
|
+
# Next.js
|
|
63
102
|
mekong-cli --with "next dev" --port 3000
|
|
103
|
+
|
|
104
|
+
# Vite (React, Vue, Svelte, etc.)
|
|
64
105
|
mekong-cli --with "vite" --port 5173
|
|
106
|
+
|
|
107
|
+
# Nuxt
|
|
65
108
|
mekong-cli --with "nuxt dev" --port 3000
|
|
109
|
+
|
|
110
|
+
# Angular
|
|
66
111
|
mekong-cli --with "ng serve" --port 4200
|
|
112
|
+
|
|
113
|
+
# Astro
|
|
67
114
|
mekong-cli --with "astro dev" --port 4321
|
|
68
|
-
```
|
|
69
115
|
|
|
70
|
-
|
|
116
|
+
# SvelteKit
|
|
117
|
+
mekong-cli --with "vite dev" --port 5173
|
|
71
118
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
mekong-cli --with "next dev" --port 3000 --expire 2h
|
|
119
|
+
# Express / Node server
|
|
120
|
+
mekong-cli --with "node server.js" --port 3000
|
|
75
121
|
|
|
76
|
-
#
|
|
77
|
-
mekong-cli --with "
|
|
122
|
+
# Any custom command
|
|
123
|
+
mekong-cli --with "npm run dev" --port 3000
|
|
124
|
+
```
|
|
78
125
|
|
|
79
|
-
|
|
80
|
-
|
|
126
|
+
mekong-cli will:
|
|
127
|
+
1. Start your dev server
|
|
128
|
+
2. Wait for port to accept connections (up to 30s)
|
|
129
|
+
3. Start the mekong tunnel
|
|
130
|
+
4. Print the public URL banner
|
|
131
|
+
5. On Ctrl+C — stop both cleanly
|
|
81
132
|
|
|
82
|
-
|
|
83
|
-
mekong-cli --with "next dev" --port 3000 --mekong ~/bin/mekong
|
|
84
|
-
```
|
|
133
|
+
---
|
|
85
134
|
|
|
86
|
-
###
|
|
135
|
+
### 4. `mekong-cli init` — Auto-setup in your project
|
|
87
136
|
|
|
88
|
-
|
|
89
|
-
--with <cmd> Shell command to start the dev server
|
|
90
|
-
--port <n> Local port (auto-detected from package.json if omitted)
|
|
91
|
-
--expire <val> Expiry duration passed to mekong (e.g. 2h, 30m)
|
|
92
|
-
--daemon Run mekong in the background (-d flag)
|
|
93
|
-
--no-qr Suppress QR code output
|
|
94
|
-
--mekong <path> Custom path to the mekong binary
|
|
95
|
-
--help Show help
|
|
96
|
-
```
|
|
137
|
+
Run this once in your project root:
|
|
97
138
|
|
|
98
|
-
|
|
139
|
+
```bash
|
|
140
|
+
mekong-cli init
|
|
141
|
+
```
|
|
99
142
|
|
|
100
|
-
|
|
143
|
+
mekong-cli init will:
|
|
144
|
+
- Detect your framework (Next.js, Vite, Nuxt, etc.)
|
|
145
|
+
- Ask which port your server runs on
|
|
146
|
+
- Inject a `dev:tunnel` script into your `package.json`
|
|
101
147
|
|
|
102
|
-
|
|
148
|
+
After running init, your `package.json` will have:
|
|
103
149
|
|
|
104
150
|
```json
|
|
105
151
|
{
|
|
106
152
|
"scripts": {
|
|
107
153
|
"dev": "next dev",
|
|
108
|
-
"tunnel": "mekong-cli --with \"next dev\" --port 3000"
|
|
109
|
-
"tunnel:share": "mekong-cli --with \"next dev\" --port 3000 --expire 2h"
|
|
154
|
+
"dev:tunnel": "mekong-cli --with \"next dev\" --port 3000"
|
|
110
155
|
}
|
|
111
156
|
}
|
|
112
157
|
```
|
|
@@ -114,74 +159,99 @@ You can wire `mekong-cli` directly into your project's `package.json` so the who
|
|
|
114
159
|
Then just run:
|
|
115
160
|
|
|
116
161
|
```bash
|
|
117
|
-
npm run tunnel
|
|
162
|
+
npm run dev:tunnel
|
|
118
163
|
```
|
|
119
164
|
|
|
120
|
-
|
|
165
|
+
---
|
|
121
166
|
|
|
122
|
-
|
|
167
|
+
## All options
|
|
123
168
|
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
169
|
+
```
|
|
170
|
+
mekong-cli [options] [port]
|
|
171
|
+
|
|
172
|
+
<port> Port of an already-running server to tunnel
|
|
173
|
+
--with <cmd> Start this dev server command first, then tunnel
|
|
174
|
+
--port <n> Explicit port (used with --with, or overrides auto-detect)
|
|
175
|
+
--expire <val> Tunnel expiry: 30m, 2h, 1d, 1w
|
|
176
|
+
--daemon Run mekong tunnel in background
|
|
177
|
+
--no-qr Suppress QR code in terminal
|
|
178
|
+
--mekong <path> Custom path to mekong binary
|
|
179
|
+
--help, -h Show help
|
|
180
|
+
|
|
181
|
+
init Auto-setup dev:tunnel script in your project
|
|
131
182
|
```
|
|
132
183
|
|
|
133
|
-
|
|
184
|
+
---
|
|
134
185
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
186
|
+
## Framework quick reference
|
|
187
|
+
|
|
188
|
+
| Framework | Command |
|
|
189
|
+
|---|---|
|
|
190
|
+
| **Next.js** | `mekong-cli --with "next dev" --port 3000` |
|
|
191
|
+
| **Vite** | `mekong-cli --with "vite" --port 5173` |
|
|
192
|
+
| **Nuxt** | `mekong-cli --with "nuxt dev" --port 3000` |
|
|
193
|
+
| **Angular** | `mekong-cli --with "ng serve" --port 4200` |
|
|
194
|
+
| **Astro** | `mekong-cli --with "astro dev" --port 4321` |
|
|
195
|
+
| **SvelteKit** | `mekong-cli --with "vite dev" --port 5173` |
|
|
196
|
+
| **Remix** | `mekong-cli --with "remix dev" --port 3000` |
|
|
197
|
+
| **Gatsby** | `mekong-cli --with "gatsby develop" --port 8000` |
|
|
198
|
+
| **Express** | `mekong-cli --with "node server.js" --port 3000` |
|
|
199
|
+
| **Fastify** | `mekong-cli --with "node server.js" --port 3000` |
|
|
143
200
|
|
|
144
|
-
|
|
201
|
+
---
|
|
145
202
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
203
|
+
## With expiry and options
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# Expire tunnel after 2 hours
|
|
207
|
+
mekong-cli --with "next dev" --port 3000 --expire 2h
|
|
208
|
+
|
|
209
|
+
# Run tunnel in background (daemon mode)
|
|
210
|
+
mekong-cli --with "next dev" --port 3000 --daemon
|
|
211
|
+
|
|
212
|
+
# No QR code
|
|
213
|
+
mekong-cli --with "vite" --port 5173 --no-qr
|
|
214
|
+
|
|
215
|
+
# Custom mekong binary path
|
|
216
|
+
mekong-cli --with "next dev" --port 3000 --mekong ~/bin/mekong
|
|
153
217
|
```
|
|
154
218
|
|
|
155
|
-
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Add scripts to package.json manually
|
|
156
222
|
|
|
157
223
|
```json
|
|
158
224
|
{
|
|
159
225
|
"scripts": {
|
|
160
|
-
"dev": "
|
|
161
|
-
"tunnel": "mekong-cli --with \"
|
|
226
|
+
"dev": "next dev",
|
|
227
|
+
"dev:tunnel": "mekong-cli --with \"next dev\" --port 3000",
|
|
228
|
+
"dev:tunnel:share": "mekong-cli --with \"next dev\" --port 3000 --expire 2h"
|
|
162
229
|
}
|
|
163
230
|
}
|
|
164
231
|
```
|
|
165
232
|
|
|
233
|
+
Or just run `mekong-cli init` and it does this for you automatically.
|
|
234
|
+
|
|
166
235
|
---
|
|
167
236
|
|
|
168
237
|
## How it works
|
|
169
238
|
|
|
170
|
-
1. Spawns your dev server (`--with`) with its stdout/stderr streamed to your terminal, prefixed with `[server]`.
|
|
171
|
-
2. Polls the local port every 500 ms until the server is accepting connections (up to 30 s).
|
|
172
|
-
3. Starts `mekong <port>` and streams its output prefixed with `[tunnel]`.
|
|
173
|
-
4. When the public URL appears in mekong's output, prints a banner:
|
|
174
|
-
|
|
175
239
|
```
|
|
176
|
-
|
|
240
|
+
mekong-cli --with "next dev" --port 3000
|
|
241
|
+
|
|
242
|
+
[server] ready - started server on 0.0.0.0:3000
|
|
243
|
+
[server] ...
|
|
244
|
+
✔ Port 3000 is ready. Starting tunnel...
|
|
245
|
+
[tunnel] ✔ Tunnel is live!
|
|
246
|
+
[tunnel] URL https://happy-tiger-a1b2c3d4.mekongtunnel.dev
|
|
247
|
+
|
|
248
|
+
╔══════════════════════════════════════════════════╗
|
|
177
249
|
║ Public URL: https://happy-tiger-a1b2c3d4.mekongtunnel.dev ║
|
|
178
|
-
|
|
250
|
+
╚══════════════════════════════════════════════════╝
|
|
179
251
|
```
|
|
180
252
|
|
|
181
|
-
5. On `Ctrl+C` (or `SIGTERM`), kills the tunnel first, then the server, and exits cleanly.
|
|
182
|
-
|
|
183
253
|
---
|
|
184
254
|
|
|
185
255
|
## License
|
|
186
256
|
|
|
187
|
-
MIT
|
|
257
|
+
MIT © [Ing Muyleang](https://github.com/MuyleangIng) — KhmerStack
|
package/bin/mekong-cli.js
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
const { spawn } = require('child_process');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
|
|
7
|
-
const { findMekong }
|
|
8
|
-
const { detectPort }
|
|
7
|
+
const { findMekong } = require('../lib/find-mekong');
|
|
8
|
+
const { detectPort } = require('../lib/detect-port');
|
|
9
9
|
const { runWithServer } = require('../lib/runner');
|
|
10
|
+
const { checkPortOpen } = require('../lib/wait-for-port');
|
|
10
11
|
|
|
11
12
|
const BOLD = '\x1b[1m';
|
|
12
13
|
const DIM = '\x1b[2m';
|
|
@@ -23,37 +24,51 @@ const HELP = `
|
|
|
23
24
|
${BOLD}mekong-cli${RESET} — Run your dev server + Mekong tunnel in one command
|
|
24
25
|
|
|
25
26
|
${BOLD}USAGE${RESET}
|
|
26
|
-
mekong-cli <port> Tunnel an already-running server
|
|
27
|
-
mekong-cli
|
|
27
|
+
mekong-cli <port> Tunnel an already-running server on <port>
|
|
28
|
+
mekong-cli Auto-detect port from package.json + tunnel
|
|
28
29
|
mekong-cli --with "<cmd>" --port <n> Start server + tunnel together
|
|
30
|
+
mekong-cli init Auto-setup dev:tunnel script in your project
|
|
29
31
|
|
|
30
32
|
${BOLD}OPTIONS${RESET}
|
|
31
33
|
--with <cmd> Shell command to start the dev server
|
|
32
34
|
--port <n> Local port (auto-detected from package.json if omitted)
|
|
33
|
-
--expire <val> Expiry duration passed to mekong (e.g. 2h, 30m)
|
|
35
|
+
--expire <val> Expiry duration passed to mekong (e.g. 2h, 30m, 1d, 1w)
|
|
34
36
|
--daemon Run mekong in the background (-d flag)
|
|
35
37
|
--no-qr Suppress QR code output
|
|
36
38
|
--mekong <path> Custom path to the mekong binary
|
|
37
|
-
--help
|
|
39
|
+
--help, -h Show this help message
|
|
40
|
+
|
|
41
|
+
${BOLD}SUBCOMMANDS${RESET}
|
|
42
|
+
init Auto-detect your framework, inject dev:tunnel into package.json
|
|
38
43
|
|
|
39
44
|
${BOLD}EXAMPLES${RESET}
|
|
45
|
+
${DIM}# Tunnel a server already running on port 3000${RESET}
|
|
40
46
|
mekong-cli 3000
|
|
47
|
+
|
|
48
|
+
${DIM}# Auto-detect port from package.json and tunnel${RESET}
|
|
49
|
+
mekong-cli
|
|
50
|
+
|
|
51
|
+
${DIM}# Start your dev server AND open a tunnel together${RESET}
|
|
41
52
|
mekong-cli --with "next dev" --port 3000
|
|
42
53
|
mekong-cli --with "vite" --port 5173
|
|
43
54
|
mekong-cli --with "nuxt dev" --port 3000
|
|
44
55
|
mekong-cli --with "ng serve" --port 4200
|
|
45
56
|
mekong-cli --with "astro dev" --port 4321
|
|
57
|
+
|
|
58
|
+
${DIM}# With options${RESET}
|
|
46
59
|
mekong-cli --with "next dev" --port 3000 --expire 2h
|
|
47
|
-
mekong-cli --with "
|
|
60
|
+
mekong-cli --with "vite" --port 5173 --daemon
|
|
61
|
+
mekong-cli --with "next dev" --port 3000 --no-qr
|
|
48
62
|
|
|
49
|
-
${
|
|
50
|
-
|
|
63
|
+
${DIM}# Auto-setup script (run once in your project root)${RESET}
|
|
64
|
+
mekong-cli init
|
|
51
65
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
66
|
+
${BOLD}INSTALL MEKONG BINARY${RESET}
|
|
67
|
+
Linux/macOS (auto-detect arch):
|
|
68
|
+
curl -fsSL https://github.com/MuyleangIng/MekongTunnel/releases/latest/download/mekong-\\$(uname -s | tr A-Z a-z)-\\$(uname -m) \\
|
|
69
|
+
-o ~/.local/bin/mekong && chmod +x ~/.local/bin/mekong
|
|
55
70
|
|
|
56
|
-
Windows: download
|
|
71
|
+
Windows: download from https://github.com/MuyleangIng/MekongTunnel/releases/latest
|
|
57
72
|
`;
|
|
58
73
|
|
|
59
74
|
// ---------------------------------------------------------------------------
|
|
@@ -179,7 +194,20 @@ async function main() {
|
|
|
179
194
|
return;
|
|
180
195
|
}
|
|
181
196
|
|
|
182
|
-
// Tunnel-only mode:
|
|
197
|
+
// Tunnel-only mode: verify the port is actually listening before calling mekong
|
|
198
|
+
const isOpen = await checkPortOpen(port);
|
|
199
|
+
if (!isOpen) {
|
|
200
|
+
process.stderr.write(
|
|
201
|
+
`${RED}${BOLD}mekong-cli: nothing is listening on port ${port}.${RESET}\n\n` +
|
|
202
|
+
` Start your server first, then run:\n` +
|
|
203
|
+
` ${CYAN}mekong-cli ${port}${RESET}\n\n` +
|
|
204
|
+
` Or let mekong-cli start it for you:\n` +
|
|
205
|
+
` ${CYAN}mekong-cli --with "your-start-cmd" --port ${port}${RESET}\n\n` +
|
|
206
|
+
` Or run ${CYAN}mekong-cli init${RESET} to set it up automatically.\n`
|
|
207
|
+
);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
|
|
183
211
|
const mekongArgs = [String(port)];
|
|
184
212
|
if (opts.expire) mekongArgs.push('--expire', opts.expire);
|
|
185
213
|
if (opts.daemon) mekongArgs.push('-d');
|
package/lib/wait-for-port.js
CHANGED
|
@@ -49,4 +49,27 @@ function waitForPort(port) {
|
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Single immediate check — resolves true if port is open right now, false otherwise.
|
|
54
|
+
* @param {number} port
|
|
55
|
+
* @returns {Promise<boolean>}
|
|
56
|
+
*/
|
|
57
|
+
function checkPortOpen(port) {
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
const sock = new net.Socket();
|
|
60
|
+
let done = false;
|
|
61
|
+
function finish(open) {
|
|
62
|
+
if (done) return;
|
|
63
|
+
done = true;
|
|
64
|
+
sock.destroy();
|
|
65
|
+
resolve(open);
|
|
66
|
+
}
|
|
67
|
+
sock.setTimeout(1000);
|
|
68
|
+
sock.once('connect', () => finish(true));
|
|
69
|
+
sock.once('error', () => finish(false));
|
|
70
|
+
sock.once('timeout', () => finish(false));
|
|
71
|
+
sock.connect(port, '127.0.0.1');
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = { waitForPort, checkPortOpen };
|