@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.
- package/README.md +70 -32
- package/index.js +25 -12
- 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
|
-
|
|
8
|
+
npx @sharnix/agent --port 3000
|
|
7
9
|
```
|
|
8
10
|
|
|
9
|
-
|
|
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
|
-
|
|
13
|
+
## First-time setup (automatic)
|
|
12
14
|
|
|
13
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
#
|
|
31
|
-
|
|
35
|
+
# With a label
|
|
36
|
+
npx @sharnix/agent --port 8080 --label "staging"
|
|
32
37
|
```
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
## Key resolution order
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
# ~/.bashrc or ~/.zshrc
|
|
38
|
-
export SHARNIX_API_KEY=shx_...
|
|
39
|
-
```
|
|
41
|
+
The CLI checks for a key in this order:
|
|
40
42
|
|
|
41
|
-
|
|
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
|
-
|
|
44
|
-
|
|
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
|
|
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` |
|
|
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
|
|
76
|
-
2.
|
|
77
|
-
3.
|
|
78
|
-
4.
|
|
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
|
|
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
|
}
|