@sharnix/agent 1.0.6 → 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.
- package/README.md +43 -47
- package/index.js +25 -12
- package/package.json +6 -16
package/README.md
CHANGED
|
@@ -2,47 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
Instantly share your local app with anyone — no config, no port forwarding, no deployment.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Usage
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npx @sharnix/agent
|
|
8
|
+
npx @sharnix/agent --port 3000
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
That's it. If this is your first time on this machine, the CLI will handle setup automatically — no separate setup step needed.
|
|
12
|
+
|
|
13
|
+
## First-time setup (automatic)
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
2. Click **"Authorize & create key"** — one click
|
|
15
|
-
3. The CLI captures your API key automatically
|
|
16
|
-
4. Writes the MCP config to Claude Desktop, Cursor, and Windsurf automatically (whichever are installed)
|
|
17
|
-
5. Prints your key and tells you to restart your editor
|
|
15
|
+
When no key is found, the CLI starts a one-time device flow:
|
|
18
16
|
|
|
19
|
-
|
|
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
|
|
23
|
+
|
|
24
|
+
**Every run after that is silent** — the CLI reads the saved key and connects with no prompts.
|
|
20
25
|
|
|
21
26
|
## Tunneling your app
|
|
22
27
|
|
|
23
28
|
```bash
|
|
29
|
+
# Tunnel port 3000 (key read from ~/.sharnix/key.json or env)
|
|
24
30
|
npx @sharnix/agent --port 3000
|
|
25
|
-
```
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
# Tunnel port 3000
|
|
32
|
+
# Pass key explicitly
|
|
31
33
|
SHARNIX_API_KEY=shx_... npx @sharnix/agent --port 3000
|
|
32
34
|
|
|
33
|
-
# Tunnel and immediately print a share link (no dashboard needed)
|
|
34
|
-
SHARNIX_API_KEY=shx_... npx @sharnix/agent --port 3000 --share
|
|
35
|
-
|
|
36
35
|
# With a label
|
|
37
|
-
|
|
36
|
+
npx @sharnix/agent --port 8080 --label "staging"
|
|
38
37
|
```
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
## Key resolution order
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
The CLI checks for a key in this order:
|
|
42
|
+
|
|
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)
|
|
46
47
|
|
|
47
48
|
## What it does
|
|
48
49
|
|
|
@@ -57,35 +58,22 @@ export SHARNIX_API_KEY=shx_...
|
|
|
57
58
|
|
|
58
59
|
| Flag | Default | Description |
|
|
59
60
|
|------|---------|-------------|
|
|
60
|
-
| `setup` | — | First-time setup: creates API key and writes MCP config automatically |
|
|
61
61
|
| `--port`, `-p` | `3000` | Local port to forward |
|
|
62
62
|
| `--label`, `-l` | — | Human-readable label for this tunnel |
|
|
63
|
-
| `--name` | `local-dev` | Agent name
|
|
64
|
-
| `--share` | — | Create a read-only share link on connect and print the URL |
|
|
63
|
+
| `--name` | `local-dev` | Agent name registered on first setup |
|
|
65
64
|
| `--help`, `-h` | — | Show help |
|
|
66
65
|
|
|
67
66
|
## Environment variables
|
|
68
67
|
|
|
69
68
|
| Variable | Description |
|
|
70
69
|
|----------|-------------|
|
|
71
|
-
| `SHARNIX_API_KEY` |
|
|
70
|
+
| `SHARNIX_API_KEY` | API key — overrides saved key file |
|
|
71
|
+
| `SHARNIX_KEY` | Alias for `SHARNIX_API_KEY` |
|
|
72
72
|
| `SHARNIX_URL` | Override relay URL (default: `https://relay.sharnix.com`) |
|
|
73
73
|
|
|
74
|
-
##
|
|
75
|
-
|
|
76
|
-
`npx @sharnix/agent setup` detects which editors are installed and writes the MCP config to:
|
|
77
|
-
|
|
78
|
-
| Editor | Config file |
|
|
79
|
-
|--------|-------------|
|
|
80
|
-
| Claude Desktop (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
81
|
-
| Claude Desktop (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
82
|
-
| Claude Desktop (Linux) | `~/.config/Claude/claude_desktop_config.json` |
|
|
83
|
-
| Cursor | `~/.cursor/mcp.json` |
|
|
84
|
-
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
|
|
85
|
-
|
|
86
|
-
It merges into the existing config — it will never overwrite other MCP servers you have configured.
|
|
74
|
+
## MCP config for AI editors
|
|
87
75
|
|
|
88
|
-
|
|
76
|
+
To give your AI agent (Claude Desktop, Cursor, Windsurf) MCP access to Sharnix, add this to your editor's config file and restart:
|
|
89
77
|
|
|
90
78
|
```json
|
|
91
79
|
{
|
|
@@ -101,11 +89,18 @@ The block it writes looks like this:
|
|
|
101
89
|
}
|
|
102
90
|
```
|
|
103
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
|
+
|
|
104
100
|
## Creating share links
|
|
105
101
|
|
|
106
102
|
Once the agent is running, create share links from:
|
|
107
103
|
|
|
108
|
-
- **Terminal** — `npx @sharnix/agent --port 3000 --share` prints a URL immediately
|
|
109
104
|
- **AI agent** — ask Claude/Cursor: *"share my app with the client"* via [`@sharnix/mcp-server`](https://www.npmjs.com/package/@sharnix/mcp-server)
|
|
110
105
|
- **Dashboard** — [relay.sharnix.com/app](https://relay.sharnix.com/app)
|
|
111
106
|
|
|
@@ -113,11 +108,12 @@ Share links support permissions (`read-only`, `full`), expiry dates, email restr
|
|
|
113
108
|
|
|
114
109
|
## How it works
|
|
115
110
|
|
|
116
|
-
1.
|
|
117
|
-
2.
|
|
118
|
-
3.
|
|
119
|
-
4.
|
|
120
|
-
5.
|
|
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
|
|
121
117
|
|
|
122
118
|
## License
|
|
123
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
|
|
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('
|
|
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 {
|
|
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.
|
|
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": "
|
|
20
|
-
"sharnix": "
|
|
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
|
}
|