@iamken/cloudtunnel 0.1.0 → 0.1.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 thanhken
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,57 +1,154 @@
1
- # cloudtunnel
1
+ <div align="center">
2
2
 
3
- Expose a local port at a public HTTPS subdomain on **your own Cloudflare domains** — nport-style, but the tunnel and DNS live in your Cloudflare account. Manage every tunnel subdomain across the whole account from one CLI.
3
+ # cloudtunnel
4
4
 
5
- ## Quickstart
5
+ **Expose any local port at a public HTTPS subdomain — on _your own_ Cloudflare domains.**
6
+
7
+ Instant, self-owned tunnel sharing — the tunnel and DNS live in **your** Cloudflare account, so you keep clean, stable URLs and full control.
8
+
9
+ [![npm version](https://img.shields.io/npm/v/@iamken/cloudtunnel?color=cb3837&logo=npm&style=flat-square)](https://www.npmjs.com/package/@iamken/cloudtunnel)
10
+ [![CI](https://img.shields.io/github/actions/workflow/status/thanhken/cloudtunnel/ci.yml?branch=main&label=CI&logo=github&style=flat-square)](https://github.com/thanhken/cloudtunnel/actions)
11
+ [![license](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](#-license)
12
+ [![node](https://img.shields.io/badge/node-%E2%89%A520-brightgreen?style=flat-square&logo=node.js)](#-requirements)
13
+
14
+ </div>
6
15
 
7
16
  ```bash
8
17
  npm i -g @iamken/cloudtunnel
9
18
 
10
- cloudtunnel login # once — paste a token (or set CLOUDFLARE_API_TOKEN); account + zone auto-resolved
11
- cloudtunnel 3000 # → https://brave-otter-1a2b.example.com is live
19
+ cloudtunnel login # once — paste a Cloudflare token; account + domain auto-resolved
20
+ cloudtunnel 3000 # → https://brave-otter-1a2b.example.com is live
21
+ ```
22
+
23
+ ---
24
+
25
+ ## ✨ Why cloudtunnel
26
+
27
+ - 🔗 **Your domains, real subdomains** — routes through native Cloudflare Tunnel to `*.your-domain.com`, not a shared third-party host.
28
+ - ⚡ **One command** — `cloudtunnel 3000` creates the tunnel, DNS, and connector, then prints a live HTTPS URL. It even asks you which domain + subdomain to use.
29
+ - 🧭 **Just two states** — `up` brings a subdomain online; `down` (or Ctrl-C) releases it (deletes the tunnel + DNS). Re-running `up` always starts clean — no leftovers, no conflicts.
30
+ - 🗂️ **Profiles** — save a whole project's services and bring them all up with `cloudtunnel run mb`.
31
+ - 🌙 **Background mode** — `--detach` keeps connectors running after you close the terminal.
32
+ - 🔒 **Secure by default** — token passed via env (never argv), stored `0600`, destructive ops are ownership-gated and re-verified.
33
+
34
+ ---
35
+
36
+ ## 🚀 Quickstart
37
+
38
+ ```bash
39
+ cloudtunnel login # authenticate once
40
+ cloudtunnel 3000 # asks for domain + subdomain, then goes live
41
+ cloudtunnel 3000 -s api # skip the prompts: api.<your-domain>
42
+ cloudtunnel 3000 -s api -d foo.io # subdomain + domain
43
+ cloudtunnel 3000 --detach # run in the background
12
44
  ```
13
45
 
14
- `cloudtunnel 3000` is shorthand for `cloudtunnel up 3000`. Press **Ctrl-C** to stop the connector — the subdomain is **kept** (delete it with `cloudtunnel rm`). Want the nport-style throwaway behaviour? add `--ephemeral`.
46
+ Run `cloudtunnel 3000` with no flags and it guides you:
15
47
 
16
- ## How it works
48
+ ```
49
+ ┌ cloudtunnel
50
+ ◇ Choose a domain
51
+ │ ● example.com ○ foo.io
52
+ ◇ Subdomain
53
+ │ api (leave blank for a random name)
54
+ ◇ Connected
55
+
56
+ ◇ Live ─────────────────────────────────────────╮
57
+ │ https://api.example.com → http://localhost:3000
58
+ │ Ctrl-C stops and releases this subdomain
59
+ ╰─────────────────────────────────────────────────╯
60
+ ```
17
61
 
18
- `cloudtunnel` uses **native Cloudflare Tunnel**: it creates a remotely-managed tunnel via the Cloudflare API, points a proxied CNAME at it (`<id>.cfargotunnel.com`), and runs the `cloudflared` connector for you. Traffic flows `browser → Cloudflare edge → cloudflared → your local port`.
62
+ ---
19
63
 
20
- ## Commands
64
+ ## 📦 Commands
21
65
 
22
- | Command | Does |
23
- |---------|------|
24
- | `cloudtunnel login` | Authenticate; auto-resolve account + default zone. `--status` to inspect. |
25
- | `cloudtunnel <port>` / `up <port>` | Create + serve a subdomain. Flags: `-s/--subdomain`, `-d/--domain`, `--hostname`, `--detach`, `--ephemeral`, `--proto`. Pick a domain interactively when you have several and none is passed. |
26
- | `cloudtunnel ls [--all]` | List tunnel subdomains. `--all` also scans the account for unmanaged ones. |
27
- | `cloudtunnel update <name> --port <p>` | Repoint a subdomain to a new port **zero downtime** (hot-reload, no restart). |
28
- | `cloudtunnel rm <name> [--dry-run] [--force]` | Delete a subdomain (stops connector, removes tunnel + DNS). |
29
- | `cloudtunnel status <name>` | Tunnel health + connector state. |
30
- | `cloudtunnel down [name] [--all]` | Stop connector(s); keep the tunnel + DNS. |
31
- | `cloudtunnel gc [--yes]` | Prune crash orphans. |
66
+ | Command | What it does |
67
+ | --- | --- |
68
+ | `cloudtunnel login` | Authenticate; resolve account + list your domains. `--status` to inspect. |
69
+ | `cloudtunnel <port>` · `up` | Bring a subdomain online. `-s/--subdomain`, `-d/--domain`, `--detach`, `-f/--force`, `--proto`. |
70
+ | `cloudtunnel ls` · `ps` | List subdomains — `# · SUBDOMAIN · TARGET · STATE · PID`. `--all` scans the whole account. |
71
+ | `cloudtunnel down <target>` · `rm` · `stop` | Release a subdomain stop connector + delete tunnel + DNS. `--all`, `--dry-run`, `-f`. |
72
+ | `cloudtunnel logs <target>` | Show a connector's log. `-f` to follow, `-n` for line count. |
32
73
  | `cloudtunnel zones` | List the domains in your account. |
74
+ | `cloudtunnel save <profile> <svc…>` | Save a group of services. `svc` = `name:port[:proto]`, or `--from-running`. |
75
+ | `cloudtunnel run <profile> [--detach]` | Bring up every service in a profile at once. |
76
+ | `cloudtunnel profiles [--rm <name>]` | List saved profiles (or delete one). |
77
+
78
+ > A **`<target>`** is a `#` number, a subdomain name, a full hostname, or a tunnel-id prefix — all shown in `ls`. `down` also accepts `rm` / `remove` / `delete` / `stop`.
79
+
80
+ ```
81
+ $ cloudtunnel ls
82
+ ┌───┬─────────────────────┬────────────────────────┬───────┬───────┐
83
+ │ # │ SUBDOMAIN │ TARGET │ STATE │ PID │
84
+ ├───┼─────────────────────┼────────────────────────┼───────┼───────┤
85
+ │ 1 │ api.example.com │ http://localhost:3000 │ up │ 48213 │
86
+ │ 2 │ web.example.com │ https://localhost:5173 │ down │ - │
87
+ └───┴─────────────────────┴────────────────────────┴───────┴───────┘
88
+
89
+ $ cloudtunnel down 1 # release by number
90
+ $ cloudtunnel down --all # release everything
91
+ ```
92
+
93
+ ---
94
+
95
+ ## 🗂️ Profiles
96
+
97
+ Expose a whole project's services with one command:
98
+
99
+ ```bash
100
+ cloudtunnel save mb api:3000 web:5173:https # define the group (or: save mb --from-running)
101
+ cloudtunnel run mb --detach # backend + frontend live in the background
102
+ cloudtunnel logs api -f # follow one service's log
103
+ cloudtunnel down --all # release them all
104
+ ```
105
+
106
+ ---
107
+
108
+ ## 🧭 Two states: up & down
109
+
110
+ There are only two states. **`up`** brings a subdomain online (creating the tunnel + DNS). **`down`** — or pressing <kbd>Ctrl-C</kbd> in a foreground `up` — **releases** it: it stops the connector and deletes the tunnel + DNS on Cloudflare. Running `up` again recreates it cleanly (any leftover tunnel record for that name is cleaned up first, so you never hit conflicts).
111
+
112
+ Add **`--detach`** to keep a connector running in the **background** after the CLI exits (and after you close the terminal). Release it later with `cloudtunnel down <target>` (or `--all`) and tail its output with `cloudtunnel logs <target> -f`.
113
+
114
+ ---
115
+
116
+ ## 🔑 Authentication
117
+
118
+ Create a **Cloudflare API token** with these scopes (least-privilege — a token limited to the domains you tunnel into is recommended):
119
+
120
+ | Resource | Permission |
121
+ | --- | --- |
122
+ | Account | Cloudflare Tunnel · **Edit** |
123
+ | Account | Account Settings · **Read** |
124
+ | Zone | DNS · **Edit** |
125
+ | Zone | Zone · **Read** |
126
+
127
+ Provide it via (highest precedence first): `CLOUDFLARE_API_TOKEN` env → `cloudtunnel login --token-stdin` → the hidden prompt from `cloudtunnel login`.
33
128
 
34
- ## Authentication
129
+ > 🔒 The token is **never** passed on the command line (that would leak into `ps` / shell history) and is stored `0600`. Rotate it if a shared host is compromised.
35
130
 
36
- Create a **Cloudflare API token** with these scopes (least-privilege; a zone-scoped token limited to the domains you tunnel into is recommended):
131
+ ---
37
132
 
38
- - Account · **Cloudflare Tunnel** · Edit
39
- - Account · **Account Settings** · Read
40
- - Zone · **DNS** · Edit
41
- - Zone · **Zone** · Read
133
+ ## Requirements
42
134
 
43
- Provide it via (in order of precedence): `CLOUDFLARE_API_TOKEN` env var → `cloudtunnel login --token-stdin` the hidden prompt from `cloudtunnel login`. The token is **never** passed on the command line (it would leak into `ps` / shell history) and is stored `0600`. Rotate it if a shared host is compromised.
135
+ - **Node.js 20**
136
+ - **`cloudflared`** on your `PATH` — install via `brew install cloudflared`, your package manager, or the [releases page](https://github.com/cloudflare/cloudflared/releases).
137
+ <br/>_(Auto-download is built in and fetches a pinned, SHA256-verified binary, but stays disabled until release checksums are pinned — treat `cloudflared` as a prerequisite for now.)_
44
138
 
45
- ## Requirements
139
+ ---
46
140
 
47
- - Node.js ≥ 20
48
- - `cloudflared` on your `PATH` — install via `brew install cloudflared` / your package manager, or from <https://github.com/cloudflare/cloudflared/releases>. (Auto-download is built in and fetches a pinned, SHA256-verified binary, but stays disabled until release checksums are pinned — so treat `cloudflared` as a prerequisite for now.)
141
+ ## 🩺 Troubleshooting
49
142
 
50
- ## Troubleshooting
143
+ | Symptom | Cause & fix |
144
+ | --- | --- |
145
+ | **HTTP 1016** / subdomain won't load | The connector isn't running (`STATE = down` in `ls`). Bring it back up: `cloudtunnel <port> -s <name>`. |
146
+ | **`down` says "active connections"** | Handled automatically — cloudtunnel cleans up the connections and retries the delete. |
147
+ | **"grey-clouded" error** | The zone couldn't proxy the record; cfargotunnel routing needs an orange-cloud (proxied) CNAME. |
148
+ | **A DNS record already occupies the name** | Pick another `-s`/`-d`, or pass `-f/--force` to replace a non-tunnel record. |
51
149
 
52
- - **HTTP 1016 / subdomain not loading** — the connector isn't running. Start it with `cloudtunnel <port> --name <sub>` (re-attaches) or check `cloudtunnel status <sub>`.
53
- - **"grey-clouded" error** — the zone couldn't proxy the record; cfargotunnel routing needs an orange-cloud (proxied) CNAME.
150
+ ---
54
151
 
55
- ## License
152
+ ## 📄 License
56
153
 
57
- MIT
154
+ [MIT](LICENSE) © thanhken