uplink-cli 0.1.26 → 0.1.28

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.
@@ -0,0 +1,134 @@
1
+ # Tunnel Setup Guide - Step by Step
2
+
3
+ ## Prerequisites
4
+
5
+ 1. **Backend API running** (recommended: behind Caddy at `api.uplink.spot`)
6
+ 2. **Tunnel relay running** (on server: ports 7070/7071)
7
+ 3. **Caddy running** (on server: handles routing)
8
+ 4. **Your app running locally** (e.g., `npm run dev` on port 3000)
9
+
10
+ ## Step-by-Step Instructions
11
+
12
+ ### Step 1: Start Your App
13
+
14
+ In **Cursor window #1** (or terminal):
15
+
16
+ ```bash
17
+ cd /path/to/marketmaker # or your app directory
18
+ npm run dev # or whatever starts your app
19
+ # Make sure it's running on localhost:3000 (or note the port)
20
+ ```
21
+
22
+ **Verify it's running:**
23
+ ```bash
24
+ curl http://localhost:3000
25
+ # Should see your app's HTML/response
26
+ ```
27
+
28
+ ### Step 2: Create Tunnel
29
+
30
+ In **Terminal 2** (uplink directory):
31
+
32
+ ```bash
33
+ cd /path/to/uplink # or wherever you cloned the repo
34
+
35
+ # Recommended production env (API via Caddy; tunnel ctrl is raw TCP)
36
+ export AGENTCLOUD_API_BASE=https://api.uplink.spot
37
+ export TUNNEL_CTRL=tunnel.uplink.spot:7071
38
+ export TUNNEL_DOMAIN=t.uplink.spot
39
+
40
+ # Create tunnel (replace 3000 with your app's port)
41
+ npm run dev:cli -- dev --tunnel --port 3000
42
+ ```
43
+
44
+ **You'll see:**
45
+ ```
46
+ Tunnel URL: https://abc123.t.uplink.spot
47
+ Starting tunnel client...
48
+ 2025-12-11T18:30:39.424Z connected to relay ctrl
49
+ 2025-12-11T18:30:39.438Z registered with relay
50
+ ```
51
+
52
+ **Keep this terminal running!** (The tunnel client must stay active)
53
+
54
+ ### Step 3: Access Your App
55
+
56
+ **Via HTTPS (wildcard TLS via Cloudflare DNS-01):**
57
+
58
+ ```bash
59
+ curl https://abc123.t.uplink.spot
60
+ ```
61
+
62
+ **Direct HTTP (bypasses Caddy):**
63
+ ```bash
64
+ curl -H "Host: abc123.t.uplink.spot" http://<SERVER_IP>:7070/
65
+ ```
66
+
67
+ ### Step 4: Stop Tunnel
68
+
69
+ When done, press `Ctrl+C` in the tunnel client terminal to stop it.
70
+
71
+ ## Troubleshooting
72
+
73
+ ### Check What's Running
74
+
75
+ ```bash
76
+ # Check local ports
77
+ lsof -i -P | grep LISTEN | grep -E ":(3000|4000|7070|7071)"
78
+
79
+ # Check backend API
80
+ curl http://localhost:4000/health
81
+ # (production via Caddy)
82
+ curl https://api.uplink.spot/health
83
+
84
+ # Check server services
85
+ ssh root@<SERVER_IP> "systemctl status backend-api tunnel-relay caddy"
86
+ ```
87
+
88
+ ### Common Issues
89
+
90
+ 1. **"Connection refused"** → Tunnel client not running or wrong port
91
+ 2. **"Tunnel not connected"** → Check tunnel client is running and connected
92
+ 3. **HTTPS errors** → Use HTTP instead (http:// not https://)
93
+ 4. **App not accessible** → Make sure your app is running on the correct port
94
+
95
+ ### Manual Method (if CLI doesn't work)
96
+
97
+ ```bash
98
+ # 1. Create tunnel
99
+ curl -X POST https://api.uplink.spot/v1/tunnels \
100
+ -H "Authorization: Bearer dev-token" \
101
+ -H "Content-Type: application/json" \
102
+ -d '{"port":3000}'
103
+
104
+ # Response: {"token":"abc123...", "url":"https://abc123.t.uplink.spot"}
105
+
106
+ # 2. Start tunnel client
107
+ node scripts/tunnel/client.js \
108
+ --token abc123... \
109
+ --port 3000 \
110
+ --ctrl tunnel.uplink.spot:7071
111
+ ```
112
+
113
+ ## Current Status
114
+
115
+ - ✅ **HTTPS tunnel (recommended)**: Use Cloudflare DNS hosting + wildcard TLS
116
+ - ✅ **Tunnel client**: Connects and routes traffic
117
+ - ✅ **Database persistence**: Tunnels saved to database
118
+
119
+ ## Quick Reference
120
+
121
+ ```bash
122
+ # Create tunnel for port 3000
123
+ npm run dev:cli -- dev --tunnel --port 3000
124
+
125
+ # Create tunnel for port 3001
126
+ npm run dev:cli -- dev --tunnel --port 3001
127
+
128
+ # Access via HTTP
129
+ https://<token>.t.uplink.spot
130
+ ```
131
+
132
+
133
+
134
+
@@ -0,0 +1,247 @@
1
+ # AgentCloud Service Usage Guide
2
+
3
+ ## What You Can Do Now
4
+
5
+ Your AgentCloud service is fully deployed and running! Here's what you can do:
6
+
7
+ ### 🌐 Tunnel Service (ngrok-like)
8
+
9
+ Expose your local development servers to the internet with a public URL.
10
+
11
+ #### Using the CLI:
12
+
13
+ ```bash
14
+ # Start a tunnel for a local server on port 3000
15
+ npm run dev:cli -- dev --tunnel --port 3000
16
+
17
+ # Or with the tunnel client directly
18
+ node scripts/tunnel/client.js --token <token> --port 3000 --ctrl tunnel.uplink.spot:7071
19
+ ```
20
+
21
+ #### Using the API:
22
+
23
+ ```bash
24
+ # Create a tunnel
25
+ curl -X POST https://api.uplink.spot/v1/tunnels \
26
+ -H "Authorization: Bearer dev-token" \
27
+ -H "Content-Type: application/json" \
28
+ -d '{"port": 3000}'
29
+
30
+ # Response includes:
31
+ # {
32
+ # "id": "tun_...",
33
+ # "token": "abc123...",
34
+ # "url": "https://abc123.t.uplink.spot",
35
+ # "targetPort": 3000,
36
+ # "status": "active"
37
+ # }
38
+
39
+ # List your tunnels
40
+ curl https://api.uplink.spot/v1/tunnels \
41
+ -H "Authorization: Bearer dev-token"
42
+
43
+ # Delete a tunnel
44
+ curl -X DELETE https://api.uplink.spot/v1/tunnels/<tunnel-id> \
45
+ -H "Authorization: Bearer dev-token"
46
+ ```
47
+
48
+ #### How It Works:
49
+
50
+ 1. **Create tunnel**: Request a tunnel from the control plane API
51
+ 2. **Get token**: Receive a unique token (e.g., `abc123`)
52
+ 3. **Start client**: Run the tunnel client locally, connecting to the relay
53
+ 4. **Access**: Your local server is now accessible at `https://abc123.dev.uplink.spot`
54
+ 5. **HTTPS**: Recommended: Cloudflare DNS hosting + wildcard TLS (`*.t.uplink.spot`)
55
+
56
+ ### 🗄️ Database Service
57
+
58
+ Create and manage PostgreSQL databases via Neon.
59
+
60
+ #### Using the CLI:
61
+
62
+ ```bash
63
+ # Create a database
64
+ npm run dev:cli -- db create myapp-db --project myproject
65
+
66
+ # List databases
67
+ npm run dev:cli -- db list
68
+
69
+ # Get database info
70
+ npm run dev:cli -- db info <db-id>
71
+
72
+ # Delete database
73
+ npm run dev:cli -- db delete <db-id>
74
+ ```
75
+
76
+ #### Using the API:
77
+
78
+ ```bash
79
+ # Create a database
80
+ curl -X POST https://api.uplink.spot/v1/dbs \
81
+ -H "Authorization: Bearer dev-token" \
82
+ -H "Content-Type: application/json" \
83
+ -d '{
84
+ "name": "myapp-db",
85
+ "project": "myproject",
86
+ "provider": "neon",
87
+ "region": "us-east-1"
88
+ }'
89
+
90
+ # List databases
91
+ curl https://api.uplink.spot/v1/dbs \
92
+ -H "Authorization: Bearer dev-token"
93
+
94
+ # Get database details
95
+ curl https://api.uplink.spot/v1/dbs/<db-id> \
96
+ -H "Authorization: Bearer dev-token"
97
+
98
+ # Delete database
99
+ curl -X DELETE https://api.uplink.spot/v1/dbs/<db-id> \
100
+ -H "Authorization: Bearer dev-token"
101
+ ```
102
+
103
+ ### 🔧 Configuration
104
+
105
+ #### Environment Variables (on server):
106
+
107
+ - `CONTROL_PLANE_DATABASE_URL`: Postgres connection for control plane
108
+ - `CONTROL_PLANE_TOKEN_PEPPER`: Optional HMAC pepper for token hashing (set in prod)
109
+ - `ADMIN_TOKENS`: Comma-separated break-glass admin tokens (env-only; bypass DB)
110
+ - `NEON_API_KEY`: Neon API key for database provisioning
111
+ - `NEON_PROJECT_ID`: Neon project ID
112
+ - `PORT`: Backend API port (default: 4000)
113
+ - `TUNNEL_DOMAIN`: Domain for tunnels (recommended: `t.uplink.spot`)
114
+
115
+ #### CLI Configuration:
116
+
117
+ Set in your local `.env`:
118
+ - `AGENTCLOUD_API_BASE`: API base URL (default: http://localhost:4000)
119
+ - `AGENTCLOUD_TOKEN`: Auth token (use a minted token; dev-token only for local sqlite)
120
+ - `TUNNEL_CTRL`: Tunnel control channel (default: 127.0.0.1:7071)
121
+
122
+ ### 📊 Service Status
123
+
124
+ Check service health:
125
+
126
+ ```bash
127
+ # Backend API health
128
+ curl https://api.uplink.spot/health
129
+
130
+ # Check services on server
131
+ ssh root@<SERVER_IP> "systemctl status backend-api tunnel-relay caddy"
132
+ ```
133
+
134
+ ### 🚀 Example Workflow
135
+
136
+ 1. **Start a local dev server**:
137
+ ```bash
138
+ npm start # Runs on localhost:3000
139
+ ```
140
+
141
+ 2. **Create a tunnel**:
142
+ ```bash
143
+ npm run dev:cli -- dev --tunnel --port 3000
144
+ ```
145
+
146
+ 3. **Get public URL**: The CLI will output something like:
147
+ ```
148
+ Tunnel URL: https://abc123.dev.uplink.spot
149
+ ```
150
+
151
+ 4. **Access your app**: Open `https://abc123.dev.uplink.spot` in a browser
152
+
153
+ 5. **Create a database** (if needed):
154
+ ```bash
155
+ npm run dev:cli -- db create myapp-db --project myproject
156
+ ```
157
+
158
+ 6. **Use connection string**: The CLI will output connection details
159
+
160
+ ### 🔐 Authentication & Tokens (DB-backed)
161
+
162
+ - Tokens are stored hashed in the database and can be revoked or set to expire.
163
+ - Admin vs user roles are enforced by the backend.
164
+ - Break-glass `ADMIN_TOKENS` (env-only) remain as emergency access during transition.
165
+ - Local dev with SQLite can still use `AGENTCLOUD_TOKEN_DEV=dev-token`; production should use minted tokens.
166
+
167
+ **Mint an admin token (one-time raw value shown):**
168
+ ```bash
169
+ uplink admin tokens create --role admin --label "my-admin-laptop"
170
+ ```
171
+ Save the printed token securely, then set locally:
172
+ ```bash
173
+ export AGENTCLOUD_TOKEN=<minted-admin-token>
174
+ ```
175
+
176
+ **Mint a user token:**
177
+ ```bash
178
+ uplink admin tokens create --role user --label "teammate"
179
+ ```
180
+
181
+ **List tokens (metadata only, no raw tokens):**
182
+ ```bash
183
+ uplink admin tokens list
184
+ ```
185
+
186
+ **Revoke a token:**
187
+ ```bash
188
+ uplink admin tokens revoke --id <token-id>
189
+ ```
190
+
191
+ **Cleanup legacy tunnels (dev-user):**
192
+ ```bash
193
+ uplink admin cleanup --dev-user-tunnels
194
+ ```
195
+
196
+ ### 👨‍💼 Admin Commands
197
+
198
+ View system status and manage resources:
199
+
200
+ ```bash
201
+ # Show system statistics
202
+ npm run dev:cli -- admin status
203
+
204
+ # List all tunnels
205
+ npm run dev:cli -- admin tunnels
206
+ npm run dev:cli -- admin tunnels --status active --limit 50
207
+
208
+ # List all databases
209
+ npm run dev:cli -- admin databases
210
+ npm run dev:cli -- admin databases --status ready
211
+
212
+ # Token management (DB-backed)
213
+ npm run dev:cli -- admin tokens create --role admin --label "ops"
214
+ npm run dev:cli -- admin tokens list
215
+ npm run dev:cli -- admin tokens revoke --id <token-id>
216
+
217
+ # Cleanup legacy dev-user tunnels
218
+ npm run dev:cli -- admin cleanup --dev-user-tunnels
219
+
220
+ # JSON output for scripting
221
+ npm run dev:cli -- admin status --json
222
+ ```
223
+
224
+ **Admin API Endpoints:**
225
+ - `GET /v1/admin/stats` - System statistics
226
+ - `GET /v1/admin/tunnels` - List all tunnels (with filters)
227
+ - `GET /v1/admin/databases` - List all databases (with filters)
228
+ - `GET /v1/admin/tokens` - List tokens (metadata only)
229
+ - `POST /v1/admin/tokens` - Mint token (returns raw token once)
230
+ - `POST /v1/admin/tokens/revoke` - Revoke by id or raw token
231
+ - `POST /v1/admin/cleanup/dev-user-tunnels` - Soft-delete legacy dev-user tunnels
232
+
233
+ ### 📝 Notes
234
+
235
+ - Tunnels are stored in the database and persist across server restarts
236
+ - Databases are provisioned via Neon API (PostgreSQL)
237
+ - HTTPS is handled automatically by Caddy
238
+ - All operations are idempotent and agent-friendly
239
+ - Admin endpoints require authentication (Bearer token)
240
+
241
+
242
+
243
+
244
+
245
+
246
+
247
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uplink-cli",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "description": "Expose localhost to the internet in seconds. Interactive terminal UI, permanent custom domains, zero config. A modern ngrok alternative.",
5
5
  "keywords": [
6
6
  "tunnel",
@@ -39,7 +39,8 @@
39
39
  "cli/",
40
40
  "scripts/tunnel/client-improved.js",
41
41
  "README.md",
42
- "assets/"
42
+ "assets/",
43
+ "docs/"
43
44
  ],
44
45
  "scripts": {
45
46
  "dev:relay": "node scripts/tunnel/relay.js",
@@ -60,6 +60,7 @@ let reconnectTimer = null;
60
60
  let isConnected = false;
61
61
  let isRegistered = false;
62
62
  let healthCheckTimer = null;
63
+ let lastHealthTimeoutLog = 0;
63
64
  let stats = {
64
65
  requests: 0,
65
66
  errors: 0,
@@ -93,12 +94,18 @@ function logError(err, context) {
93
94
  }
94
95
 
95
96
  function checkLocalService() {
97
+ // Allow disabling the health check if it is noisy or not needed
98
+ if ((process.env.TUNNEL_HEALTH_CHECK_DISABLE || "").toLowerCase() === "true") {
99
+ return;
100
+ }
101
+
102
+ const timeoutMs = Number(process.env.TUNNEL_HEALTH_CHECK_TIMEOUT_MS || 2000);
96
103
  const options = {
97
104
  hostname: "127.0.0.1",
98
105
  port,
99
106
  path: "/",
100
107
  method: "HEAD",
101
- timeout: 2000,
108
+ timeout: timeoutMs,
102
109
  };
103
110
 
104
111
  const req = http.request(options, (res) => {
@@ -119,7 +126,12 @@ function checkLocalService() {
119
126
 
120
127
  req.on("timeout", () => {
121
128
  req.destroy();
122
- log("warn", `Health check timeout. Local service may be slow or unresponsive.`);
129
+ // Rate-limit timeout warnings to avoid log spam
130
+ const now = Date.now();
131
+ if (now - lastHealthTimeoutLog > 60_000) {
132
+ lastHealthTimeoutLog = now;
133
+ log("warn", `Health check timeout. Local service may be slow or unresponsive.`);
134
+ }
123
135
  });
124
136
 
125
137
  req.end();