@sharnix/agent 1.0.5 → 1.0.7

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.
Files changed (3) hide show
  1. package/README.md +70 -32
  2. package/index.js +25 -12
  3. package/package.json +6 -16
package/README.md CHANGED
@@ -2,47 +2,57 @@
2
2
 
3
3
  Instantly share your local app with anyone — no config, no port forwarding, no deployment.
4
4
 
5
+ ## Usage
6
+
5
7
  ```bash
6
- SHARNIX_API_KEY=shx_... npx @sharnix/agent --port 3000
8
+ npx @sharnix/agent --port 3000
7
9
  ```
8
10
 
9
- ## What it does
11
+ That's it. If this is your first time on this machine, the CLI will handle setup automatically — no separate setup step needed.
10
12
 
11
- `@sharnix/agent` opens a secure tunnel from [relay.sharnix.com](https://relay.sharnix.com) to your local machine. Visitors access your app through a shareable link — you never expose a port publicly.
13
+ ## First-time setup (automatic)
12
14
 
13
- - **Stable tunnel ID** per project directory the same tunnel URL survives restarts
14
- - **Auto-provisioned** — creates an agent credential on first run, stored in `~/.sharnix/`
15
- - **Auto-suspends** share links when you disconnect, reactivates when you reconnect
16
- - **Works with any framework** — Next.js, Vite, Django, Rails, anything on localhost
15
+ When no key is found, the CLI starts a one-time device flow:
17
16
 
18
- ## Requirements
17
+ 1. Generates a short-lived auth URL and prints it in the terminal
18
+ 2. You (or your AI agent) open the URL in any browser — phone, laptop, doesn't matter
19
+ 3. Sign in and click **"Authorize"** — one click
20
+ 4. The CLI receives your key automatically via polling — nothing to copy or paste
21
+ 5. Key saved to `~/.sharnix/key.json` for all future runs
22
+ 6. Tunnel connects immediately
19
23
 
20
- - Node.js 18 or later
21
- - A free Sharnix account at [relay.sharnix.com](https://relay.sharnix.com)
22
- - An API key from **Settings → API Keys**
24
+ **Every run after that is silent** — the CLI reads the saved key and connects with no prompts.
23
25
 
24
- ## Usage
26
+ ## Tunneling your app
25
27
 
26
28
  ```bash
27
- # Tunnel port 3000
29
+ # Tunnel port 3000 (key read from ~/.sharnix/key.json or env)
30
+ npx @sharnix/agent --port 3000
31
+
32
+ # Pass key explicitly
28
33
  SHARNIX_API_KEY=shx_... npx @sharnix/agent --port 3000
29
34
 
30
- # Tunnel a different port with a label
31
- SHARNIX_API_KEY=shx_... npx @sharnix/agent --port 8080 --label "staging"
35
+ # With a label
36
+ npx @sharnix/agent --port 8080 --label "staging"
32
37
  ```
33
38
 
34
- Set the key in your shell profile so you don't repeat it:
39
+ ## Key resolution order
35
40
 
36
- ```bash
37
- # ~/.bashrc or ~/.zshrc
38
- export SHARNIX_API_KEY=shx_...
39
- ```
41
+ The CLI checks for a key in this order:
40
42
 
41
- Then just:
43
+ 1. `SHARNIX_API_KEY` environment variable
44
+ 2. `SHARNIX_KEY` environment variable
45
+ 3. `~/.sharnix/key.json` (saved automatically after first setup)
46
+ 4. Device flow (auto-started if none of the above exist)
42
47
 
43
- ```bash
44
- npx @sharnix/agent --port 3000
45
- ```
48
+ ## What it does
49
+
50
+ `@sharnix/agent` opens a secure tunnel from [relay.sharnix.com](https://relay.sharnix.com) to your local machine. Visitors access your app through a shareable link — you never expose a port publicly.
51
+
52
+ - **Stable tunnel ID** per project directory — same URL survives restarts
53
+ - **Auto-provisioned** — creates agent credentials on first run, stored in `~/.sharnix/`
54
+ - **Auto-suspends** share links when you disconnect, reactivates when you reconnect
55
+ - **Works with any framework** — Next.js, Vite, Django, Rails, anything on localhost
46
56
 
47
57
  ## Options
48
58
 
@@ -50,32 +60,60 @@ npx @sharnix/agent --port 3000
50
60
  |------|---------|-------------|
51
61
  | `--port`, `-p` | `3000` | Local port to forward |
52
62
  | `--label`, `-l` | — | Human-readable label for this tunnel |
53
- | `--name` | `local-dev` | Agent name used on first-time setup |
63
+ | `--name` | `local-dev` | Agent name registered on first setup |
54
64
  | `--help`, `-h` | — | Show help |
55
65
 
56
66
  ## Environment variables
57
67
 
58
68
  | Variable | Description |
59
69
  |----------|-------------|
60
- | `SHARNIX_API_KEY` | Your API key (required) |
70
+ | `SHARNIX_API_KEY` | API key overrides saved key file |
71
+ | `SHARNIX_KEY` | Alias for `SHARNIX_API_KEY` |
61
72
  | `SHARNIX_URL` | Override relay URL (default: `https://relay.sharnix.com`) |
62
73
 
74
+ ## MCP config for AI editors
75
+
76
+ To give your AI agent (Claude Desktop, Cursor, Windsurf) MCP access to Sharnix, add this to your editor's config file and restart:
77
+
78
+ ```json
79
+ {
80
+ "mcpServers": {
81
+ "sharnix": {
82
+ "command": "npx",
83
+ "args": ["-y", "@sharnix/mcp-server"],
84
+ "env": {
85
+ "SHARNIX_API_KEY": "shx_your_key_here"
86
+ }
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ | Editor | Config file |
93
+ |--------|-------------|
94
+ | Claude Desktop (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
95
+ | Claude Desktop (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
96
+ | Claude Desktop (Linux) | `~/.config/Claude/claude_desktop_config.json` |
97
+ | Cursor | `~/.cursor/mcp.json` |
98
+ | Windsurf | `~/.codeium/windsurf/mcp_config.json` |
99
+
63
100
  ## Creating share links
64
101
 
65
102
  Once the agent is running, create share links from:
66
103
 
104
+ - **AI agent** — ask Claude/Cursor: *"share my app with the client"* via [`@sharnix/mcp-server`](https://www.npmjs.com/package/@sharnix/mcp-server)
67
105
  - **Dashboard** — [relay.sharnix.com/app](https://relay.sharnix.com/app)
68
- - **AI agent** — via the [`@sharnix/mcp-server`](https://www.npmjs.com/package/@sharnix/mcp-server) MCP integration
69
- - **API** — `POST /api/v1/orgs/:slug/tunnels/:id/links`
70
106
 
71
107
  Share links support permissions (`read-only`, `full`), expiry dates, email restrictions, and one-time view mode.
72
108
 
73
109
  ## How it works
74
110
 
75
- 1. On first run, the agent calls the Sharnix API to create a credential pair (`agentId` + `secret`), saved to `~/.sharnix/agent.json`
76
- 2. A stable tunnel ID is generated for the current working directory and saved to `~/.sharnix/tunnel-<hash>.json`
77
- 3. The agent opens a WebSocket to the relay and registers the tunnel
78
- 4. When a visitor opens a share link, the relay forwards their HTTP request over the WebSocket to your local app and streams the response back
111
+ 1. On first run with no key, the CLI starts a device flow: prints a one-time auth URL and polls for completion
112
+ 2. You open the URL in any browser, sign in, click Authorize key is saved to `~/.sharnix/key.json` automatically
113
+ 3. Agent credentials (`agentId` + `secret`) are provisioned via the API and saved to `~/.sharnix/agent.json`
114
+ 4. A stable tunnel ID is generated per working directory and saved to `~/.sharnix/tunnel-<hash>.json`
115
+ 5. The agent opens a WebSocket to the relay and registers the tunnel
116
+ 6. When a visitor opens a share link, the relay forwards their HTTP request over the WebSocket to your local app and streams the response back
79
117
 
80
118
  ## License
81
119
 
package/index.js CHANGED
@@ -12,6 +12,10 @@ const RELAY_BASE = (process.env.SHARNIX_URL || 'https://relay.sharnix.com').repl
12
12
  const WS_BASE = RELAY_BASE.replace(/^http/, 'ws');
13
13
  const API_KEY = process.env.SHARNIX_API_KEY || '';
14
14
 
15
+ // ── Config persistence (declared early so dispatch below can rely on it) ──────
16
+ const CONFIG_DIR = path.join(os.homedir(), '.sharnix');
17
+ if (!fs.existsSync(CONFIG_DIR)) fs.mkdirSync(CONFIG_DIR, { recursive: true });
18
+
15
19
  // ── CLI args ──────────────────────────────────────────────────────────────────
16
20
  const args = process.argv.slice(2);
17
21
  const get = (flag) => {
@@ -30,7 +34,8 @@ if (has('--help') || has('-h')) {
30
34
  sharnix — tunnel your local app through Sharnix
31
35
 
32
36
  Usage:
33
- npx @sharnix/agent setup First-time setup (no API key needed)
37
+ npx @sharnix/agent setup First-time setup on your local machine
38
+ npx @sharnix/agent setup --print-url Print auth URL and exit (for remote/agent use)
34
39
  npx @sharnix/agent --port <port> Tunnel a local port
35
40
  SHARNIX_API_KEY=shx_... npx @sharnix/agent --port 3000
36
41
 
@@ -50,11 +55,13 @@ if (has('--help') || has('-h')) {
50
55
 
51
56
  // ── Setup command (device-flow bootstrap, no API key required) ────────────────
52
57
  if (args[0] === 'setup') {
53
- runSetup().catch((err) => { console.error(`\n Error: ${err.message}\n`); process.exit(1); });
58
+ runSetup(has('--print-url')).catch((err) => { console.error(`\n Error: ${err.message}\n`); process.exit(1); });
54
59
  } else {
55
60
  if (!API_KEY) {
56
- console.error('\n Error: SHARNIX_API_KEY is not set.');
57
- console.error(' Run: npx @sharnix/agent setup\n');
61
+ console.error('\n Error: SHARNIX_API_KEY is not set.\n');
62
+ console.error(' On your local machine: npx @sharnix/agent setup');
63
+ console.error(' On a remote machine: SHARNIX_API_KEY=shx_... npx @sharnix/agent --port 3000');
64
+ console.error('\n Get your key from relay.sharnix.com/app/settings → API Keys\n');
58
65
  process.exit(1);
59
66
  }
60
67
  if (isNaN(port) || port < 1 || port > 65535) {
@@ -65,10 +72,7 @@ if (args[0] === 'setup') {
65
72
  }
66
73
 
67
74
 
68
- // ── Config persistence ────────────────────────────────────────────────────────
69
- const CONFIG_DIR = path.join(os.homedir(), '.sharnix');
70
- if (!fs.existsSync(CONFIG_DIR)) fs.mkdirSync(CONFIG_DIR, { recursive: true });
71
-
75
+ // ── Config persistence helpers ────────────────────────────────────────────────
72
76
  function loadJson(file) {
73
77
  try { return JSON.parse(fs.readFileSync(file, 'utf8')); } catch { return null; }
74
78
  }
@@ -271,8 +275,8 @@ function main() {
271
275
  }
272
276
 
273
277
  // ── Setup: device-flow bootstrap ─────────────────────────────────────────────
274
- async function runSetup() {
275
- const { execSync, spawn } = require('child_process');
278
+ async function runSetup(printUrlOnly = false) {
279
+ const { spawn } = require('child_process');
276
280
 
277
281
  console.log('\n Sharnix Setup\n');
278
282
 
@@ -283,16 +287,25 @@ async function runSetup() {
283
287
  const { code, authUrl } = await r.json();
284
288
  process.stdout.write(' done\n\n');
285
289
 
290
+ if (printUrlOnly) {
291
+ // Non-blocking mode for agents running on remote machines
292
+ console.log(' Authorization URL (open this in your browser):\n');
293
+ console.log(` ${authUrl}\n`);
294
+ console.log(' After authorizing, run the tunnel with:');
295
+ console.log(` SHARNIX_API_KEY=<your-key> npx @sharnix/agent --port 3000\n`);
296
+ console.log(' Your key will be shown on the authorization page after you click "Authorize".\n');
297
+ process.exit(0);
298
+ }
299
+
286
300
  console.log(' Opening your browser to authorize…');
287
301
  console.log(` URL: ${authUrl}\n`);
288
302
 
289
303
  // Open browser cross-platform
290
304
  try {
291
- const cmd = process.platform === 'win32' ? 'start' :
292
- process.platform === 'darwin' ? 'open' : 'xdg-open';
293
305
  if (process.platform === 'win32') {
294
306
  spawn('cmd', ['/c', 'start', '', authUrl], { detached: true, stdio: 'ignore' });
295
307
  } else {
308
+ const cmd = process.platform === 'darwin' ? 'open' : 'xdg-open';
296
309
  spawn(cmd, [authUrl], { detached: true, stdio: 'ignore' });
297
310
  }
298
311
  } catch {}
package/package.json CHANGED
@@ -1,27 +1,17 @@
1
1
  {
2
2
  "name": "@sharnix/agent",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Tunnel your local app through Sharnix — share previews with one command",
5
- "keywords": [
6
- "tunnel",
7
- "preview",
8
- "sharing",
9
- "localhost",
10
- "sharnix"
11
- ],
5
+ "keywords": ["tunnel", "preview", "sharing", "localhost", "sharnix"],
12
6
  "homepage": "https://relay.sharnix.com",
13
7
  "license": "MIT",
14
- "engines": {
15
- "node": ">=18"
16
- },
8
+ "engines": { "node": ">=18" },
17
9
  "main": "./index.js",
18
10
  "bin": {
19
- "sharnix-agent": "./index.js",
20
- "sharnix": "./index.js"
11
+ "sharnix-agent": "index.js",
12
+ "sharnix": "index.js"
21
13
  },
22
- "files": [
23
- "index.js"
24
- ],
14
+ "files": ["index.js"],
25
15
  "dependencies": {
26
16
  "ws": "^8.18.0"
27
17
  }