blue-js-sdk 2.0.0
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/CHANGELOG.md +446 -0
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/ai-path/ADMIN-ELEVATION.md +116 -0
- package/ai-path/AI-MANIFESTO.md +185 -0
- package/ai-path/BREAKING.md +74 -0
- package/ai-path/CHECKLIST.md +619 -0
- package/ai-path/CONNECTION-STEPS.md +724 -0
- package/ai-path/DECISION-TREE.md +378 -0
- package/ai-path/DEPENDENCIES.md +459 -0
- package/ai-path/E2E-FLOW.md +1555 -0
- package/ai-path/FAILURES.md +403 -0
- package/ai-path/GUIDE.md +1217 -0
- package/ai-path/README.md +558 -0
- package/ai-path/SPLIT-TUNNEL.md +266 -0
- package/ai-path/cli.js +535 -0
- package/ai-path/connect.js +884 -0
- package/ai-path/discover.js +178 -0
- package/ai-path/environment.js +266 -0
- package/ai-path/errors.js +86 -0
- package/ai-path/examples/autonomous-agent.mjs +220 -0
- package/ai-path/examples/multi-region.mjs +174 -0
- package/ai-path/examples/one-shot.mjs +31 -0
- package/ai-path/index.js +60 -0
- package/ai-path/pricing.js +136 -0
- package/ai-path/recommend.js +413 -0
- package/ai-path/run-admin.vbs +25 -0
- package/ai-path/setup.js +291 -0
- package/ai-path/wallet.js +137 -0
- package/app-helpers.js +363 -0
- package/app-settings.js +95 -0
- package/app-types.js +267 -0
- package/audit.js +847 -0
- package/batch.js +293 -0
- package/bin/setup.js +376 -0
- package/chain/authz.js +109 -0
- package/chain/broadcast.js +472 -0
- package/chain/client.js +160 -0
- package/chain/fee-grants.js +305 -0
- package/chain/index.js +891 -0
- package/chain/lcd.js +313 -0
- package/chain/queries.js +547 -0
- package/chain/rpc.js +408 -0
- package/chain/wallet.js +141 -0
- package/cli/config.js +143 -0
- package/cli/index.js +463 -0
- package/cli/output.js +182 -0
- package/cli.js +491 -0
- package/client/index.js +251 -0
- package/client.js +271 -0
- package/config/index.js +255 -0
- package/connection/connect.js +849 -0
- package/connection/disconnect.js +180 -0
- package/connection/discovery.js +321 -0
- package/connection/index.js +76 -0
- package/connection/proxy.js +148 -0
- package/connection/resilience.js +428 -0
- package/connection/security.js +232 -0
- package/connection/state.js +369 -0
- package/connection/tunnel.js +691 -0
- package/consumer.js +132 -0
- package/cosmjs-setup.js +1884 -0
- package/defaults.js +366 -0
- package/disk-cache.js +107 -0
- package/dist/client.d.ts +108 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +400 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/errors/index.js +112 -0
- package/errors.js +218 -0
- package/examples/README.md +64 -0
- package/examples/connect-direct.mjs +106 -0
- package/examples/connect-plan.mjs +125 -0
- package/examples/error-handling.mjs +109 -0
- package/examples/query-nodes.mjs +94 -0
- package/examples/wallet-basics.mjs +61 -0
- package/generated/amino/amino.ts +9 -0
- package/generated/cosmos/base/v1beta1/coin.ts +365 -0
- package/generated/cosmos_proto/cosmos.ts +323 -0
- package/generated/gogoproto/gogo.ts +9 -0
- package/generated/google/protobuf/descriptor.ts +7601 -0
- package/generated/google/protobuf/duration.ts +208 -0
- package/generated/google/protobuf/timestamp.ts +238 -0
- package/generated/sentinel/lease/v1/events.ts +924 -0
- package/generated/sentinel/lease/v1/lease.ts +292 -0
- package/generated/sentinel/lease/v1/msg.ts +949 -0
- package/generated/sentinel/lease/v1/params.ts +164 -0
- package/generated/sentinel/node/v3/events.ts +881 -0
- package/generated/sentinel/node/v3/msg.ts +1002 -0
- package/generated/sentinel/node/v3/node.ts +263 -0
- package/generated/sentinel/node/v3/params.ts +183 -0
- package/generated/sentinel/plan/v3/events.ts +675 -0
- package/generated/sentinel/plan/v3/msg.ts +1191 -0
- package/generated/sentinel/plan/v3/plan.ts +283 -0
- package/generated/sentinel/provider/v2/events.ts +171 -0
- package/generated/sentinel/provider/v2/msg.ts +480 -0
- package/generated/sentinel/provider/v2/params.ts +131 -0
- package/generated/sentinel/provider/v2/provider.ts +246 -0
- package/generated/sentinel/session/v3/events.ts +480 -0
- package/generated/sentinel/session/v3/msg.ts +616 -0
- package/generated/sentinel/session/v3/params.ts +260 -0
- package/generated/sentinel/session/v3/proof.ts +180 -0
- package/generated/sentinel/session/v3/session.ts +384 -0
- package/generated/sentinel/subscription/v3/events.ts +1181 -0
- package/generated/sentinel/subscription/v3/msg.ts +1305 -0
- package/generated/sentinel/subscription/v3/params.ts +167 -0
- package/generated/sentinel/subscription/v3/subscription.ts +315 -0
- package/generated/sentinel/types/v1/bandwidth.ts +124 -0
- package/generated/sentinel/types/v1/price.ts +149 -0
- package/generated/sentinel/types/v1/renewal.ts +87 -0
- package/generated/sentinel/types/v1/status.ts +54 -0
- package/generated/typeRegistry.ts +27 -0
- package/index.js +486 -0
- package/node-connect.js +3015 -0
- package/operator.js +134 -0
- package/package.json +113 -0
- package/plan-operations.js +199 -0
- package/preflight.js +352 -0
- package/pricing/index.js +262 -0
- package/proto/amino/amino.proto +84 -0
- package/proto/cosmos/base/v1beta1/coin.proto +61 -0
- package/proto/cosmos_proto/cosmos.proto +112 -0
- package/proto/gogoproto/gogo.proto +145 -0
- package/proto/google/api/annotations.proto +31 -0
- package/proto/google/api/http.proto +370 -0
- package/proto/google/protobuf/any.proto +106 -0
- package/proto/google/protobuf/duration.proto +115 -0
- package/proto/google/protobuf/timestamp.proto +145 -0
- package/proto/sentinel/lease/v1/events.proto +52 -0
- package/proto/sentinel/lease/v1/genesis.proto +15 -0
- package/proto/sentinel/lease/v1/lease.proto +25 -0
- package/proto/sentinel/lease/v1/msg.proto +62 -0
- package/proto/sentinel/lease/v1/params.proto +17 -0
- package/proto/sentinel/node/v3/events.proto +50 -0
- package/proto/sentinel/node/v3/genesis.proto +15 -0
- package/proto/sentinel/node/v3/msg.proto +63 -0
- package/proto/sentinel/node/v3/node.proto +27 -0
- package/proto/sentinel/node/v3/params.proto +21 -0
- package/proto/sentinel/node/v3/querier.proto +63 -0
- package/proto/sentinel/plan/v3/events.proto +41 -0
- package/proto/sentinel/plan/v3/genesis.proto +21 -0
- package/proto/sentinel/plan/v3/msg.proto +83 -0
- package/proto/sentinel/plan/v3/plan.proto +32 -0
- package/proto/sentinel/plan/v3/querier.proto +53 -0
- package/proto/sentinel/provider/v2/events.proto +16 -0
- package/proto/sentinel/provider/v2/genesis.proto +15 -0
- package/proto/sentinel/provider/v2/msg.proto +35 -0
- package/proto/sentinel/provider/v2/params.proto +17 -0
- package/proto/sentinel/provider/v2/provider.proto +24 -0
- package/proto/sentinel/provider/v3/genesis.proto +15 -0
- package/proto/sentinel/provider/v3/params.proto +13 -0
- package/proto/sentinel/session/v3/events.proto +30 -0
- package/proto/sentinel/session/v3/genesis.proto +15 -0
- package/proto/sentinel/session/v3/msg.proto +50 -0
- package/proto/sentinel/session/v3/params.proto +25 -0
- package/proto/sentinel/session/v3/proof.proto +25 -0
- package/proto/sentinel/session/v3/querier.proto +100 -0
- package/proto/sentinel/session/v3/session.proto +50 -0
- package/proto/sentinel/subscription/v2/allocation.proto +21 -0
- package/proto/sentinel/subscription/v2/payout.proto +22 -0
- package/proto/sentinel/subscription/v3/events.proto +65 -0
- package/proto/sentinel/subscription/v3/genesis.proto +17 -0
- package/proto/sentinel/subscription/v3/msg.proto +83 -0
- package/proto/sentinel/subscription/v3/params.proto +21 -0
- package/proto/sentinel/subscription/v3/subscription.proto +33 -0
- package/proto/sentinel/types/v1/bandwidth.proto +19 -0
- package/proto/sentinel/types/v1/price.proto +21 -0
- package/proto/sentinel/types/v1/renewal.proto +21 -0
- package/proto/sentinel/types/v1/status.proto +16 -0
- package/protocol/encoding.js +341 -0
- package/protocol/events.js +361 -0
- package/protocol/handshake.js +297 -0
- package/protocol/index.js +15 -0
- package/protocol/messages.js +346 -0
- package/protocol/plans.js +199 -0
- package/protocol/v2ray.js +268 -0
- package/protocol/v3.js +723 -0
- package/protocol/wireguard.js +125 -0
- package/security/index.js +132 -0
- package/session-manager.js +329 -0
- package/session-tracker.js +80 -0
- package/setup.js +376 -0
- package/speedtest/index.js +528 -0
- package/speedtest.js +567 -0
- package/src/client.ts +502 -0
- package/src/index.ts +20 -0
- package/state/index.js +347 -0
- package/state.js +516 -0
- package/test-all-chain-ops.js +493 -0
- package/test-all-logic.js +199 -0
- package/test-all-msg-types.js +292 -0
- package/test-every-connection.js +208 -0
- package/test-feegrant-connect.js +98 -0
- package/test-logic.js +148 -0
- package/test-mainnet.js +176 -0
- package/test-plan-lifecycle.js +335 -0
- package/tls-trust.js +132 -0
- package/tsconfig.build.json +20 -0
- package/tsconfig.json +34 -0
- package/types/chain.d.ts +746 -0
- package/types/connection.d.ts +425 -0
- package/types/errors.d.ts +174 -0
- package/types/index.d.ts +1380 -0
- package/types/nodes.d.ts +187 -0
- package/types/pricing.d.ts +156 -0
- package/types/protocol.d.ts +332 -0
- package/types/session.d.ts +236 -0
- package/types/settings.d.ts +192 -0
- package/v3protocol.js +1053 -0
- package/wallet/index.js +153 -0
- package/wireguard.js +307 -0
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
# Connection Steps — Complete Technical Walkthrough
|
|
2
|
+
|
|
3
|
+
> **Purpose:** Show every step of a successful Sentinel dVPN connection with real output, so an AI agent building on this SDK can verify each phase against its own results and pinpoint exactly where a failure occurs.
|
|
4
|
+
|
|
5
|
+
## NON-NEGOTIABLE RULES — Read Before Writing ANY Code
|
|
6
|
+
|
|
7
|
+
These rules exist because every AI that has built on this SDK violated at least one of them. They are not suggestions. They are requirements.
|
|
8
|
+
|
|
9
|
+
1. **NEVER use native `fetch()` for V2Ray traffic.** Node.js `fetch()` silently ignores SOCKS5 proxy. Your IP check will show your real IP and you will think the VPN is working when it is not. Use `axios` with `SocksProxyAgent` for ALL traffic that must go through V2Ray.
|
|
10
|
+
|
|
11
|
+
2. **V2Ray is a SOCKS5 proxy, not a system tunnel.** Only traffic you explicitly route through `socks5://127.0.0.1:{port}` goes through the VPN. Everything else — your chain queries, your npm installs, your other HTTP calls — goes direct. This is by design. It is the split tunnel.
|
|
12
|
+
|
|
13
|
+
3. **WireGuard `splitIPs` takes IP addresses, not domain names.** `splitIPs: ['google.com']` does nothing. Domains resolve to many IPs via DNS/CDN. You must provide CIDR ranges like `splitIPs: ['10.0.0.0/8']`. For per-app routing, use V2Ray SOCKS5 instead.
|
|
14
|
+
|
|
15
|
+
4. **Use `axios` with `adapter: 'http'` for all SOCKS5 traffic.** Node.js 20+ defaults to the undici fetch adapter which silently fails with self-signed certificates and SOCKS5 proxies. Always set `adapter: 'http'` explicitly.
|
|
16
|
+
|
|
17
|
+
5. **After V2Ray connect, verify with `verify()` — not with `fetch()`.** The SDK's `verify()` function routes through SOCKS5 automatically. A raw `fetch()` call bypasses the proxy entirely.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Overview — The 9 Phases
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
Phase 1: Environment Check → Can I run?
|
|
25
|
+
Phase 2: Wallet Setup → Do I have keys?
|
|
26
|
+
Phase 3: Balance Check → Can I pay?
|
|
27
|
+
Phase 4: Node Discovery → Who can I connect to?
|
|
28
|
+
Phase 5: Cost Estimation → How much will it cost?
|
|
29
|
+
Phase 6: Session Creation → Pay the blockchain
|
|
30
|
+
Phase 7: Handshake → Exchange keys with the node
|
|
31
|
+
Phase 8: Tunnel Installation → Start encrypted tunnel
|
|
32
|
+
Phase 9: Verification → Confirm traffic flows
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Each phase below includes:
|
|
36
|
+
- **What happens** (technical)
|
|
37
|
+
- **Successful output** (real example)
|
|
38
|
+
- **Failure signatures** (what goes wrong and why)
|
|
39
|
+
- **Diagnostic check** (how to verify this phase independently)
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Phase 1: Environment Check
|
|
44
|
+
|
|
45
|
+
### What Happens
|
|
46
|
+
The SDK checks that all required binaries and permissions are available before any network calls.
|
|
47
|
+
|
|
48
|
+
### Code
|
|
49
|
+
```javascript
|
|
50
|
+
import { setup, getEnvironment } from 'sentinel-ai-connect';
|
|
51
|
+
|
|
52
|
+
// Quick synchronous check (no network calls)
|
|
53
|
+
const env = getEnvironment();
|
|
54
|
+
console.log(env);
|
|
55
|
+
|
|
56
|
+
// Full async check (includes chain reachability)
|
|
57
|
+
const check = await setup();
|
|
58
|
+
console.log(check);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Successful Output
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"os": "win32",
|
|
65
|
+
"arch": "x64",
|
|
66
|
+
"nodeVersion": "22.4.0",
|
|
67
|
+
"admin": true,
|
|
68
|
+
"v2ray": {
|
|
69
|
+
"available": true,
|
|
70
|
+
"path": "~/.sentinel-sdk/bin/v2ray.exe",
|
|
71
|
+
"version": "5.2.1"
|
|
72
|
+
},
|
|
73
|
+
"wireguard": {
|
|
74
|
+
"available": true,
|
|
75
|
+
"path": "C:\\Program Files\\WireGuard\\wireguard.exe"
|
|
76
|
+
},
|
|
77
|
+
"capabilities": ["v2ray", "wireguard"],
|
|
78
|
+
"recommendations": []
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Failure Signatures
|
|
83
|
+
|
|
84
|
+
| Symptom | Cause | Fix |
|
|
85
|
+
|---------|-------|-----|
|
|
86
|
+
| `v2ray.available: false` | V2Ray binary not downloaded | Run `npx sentinel-setup` or call `setup()` |
|
|
87
|
+
| `v2ray.version: "5.44.1"` | Wrong version — observatory bug breaks VMess | Delete and re-download v5.2.1 exactly |
|
|
88
|
+
| `wireguard.available: false` | WireGuard not installed | Install from wireguard.com |
|
|
89
|
+
| `admin: false` | Not elevated | WireGuard requires admin. Without it, only V2Ray works (~70% of network) |
|
|
90
|
+
| `capabilities: ["v2ray"]` | Admin false → WireGuard unavailable | Elevate with `run-admin.vbs` (Windows) or `sudo` (macOS/Linux) |
|
|
91
|
+
|
|
92
|
+
### Diagnostic Check
|
|
93
|
+
```bash
|
|
94
|
+
# V2Ray version (MUST be 5.2.1)
|
|
95
|
+
~/.sentinel-sdk/bin/v2ray version
|
|
96
|
+
|
|
97
|
+
# WireGuard available
|
|
98
|
+
wireguard.exe /version
|
|
99
|
+
|
|
100
|
+
# Admin check (Windows)
|
|
101
|
+
net session >nul 2>&1 && echo ADMIN || echo NOT ADMIN
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Phase 2: Wallet Setup
|
|
107
|
+
|
|
108
|
+
### What Happens
|
|
109
|
+
Creates or imports a BIP39 mnemonic, derives a Cosmos HD wallet (path `m/44'/118'/0'/0/0`), produces a `sent1...` address.
|
|
110
|
+
|
|
111
|
+
### Code
|
|
112
|
+
```javascript
|
|
113
|
+
import { createWallet, importWallet } from 'sentinel-ai-connect';
|
|
114
|
+
|
|
115
|
+
// Create new wallet
|
|
116
|
+
const wallet = await createWallet();
|
|
117
|
+
console.log(`Address: ${wallet.address}`);
|
|
118
|
+
console.log(`Mnemonic: ${wallet.mnemonic}`);
|
|
119
|
+
// ⚠ SAVE THE MNEMONIC. It cannot be recovered.
|
|
120
|
+
|
|
121
|
+
// OR import existing wallet
|
|
122
|
+
const imported = await importWallet('your twelve word mnemonic phrase goes right here in this string');
|
|
123
|
+
console.log(`Address: ${imported.address}`);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Successful Output
|
|
127
|
+
```
|
|
128
|
+
Address: sent1abc...xyz
|
|
129
|
+
Mnemonic: word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Failure Signatures
|
|
133
|
+
|
|
134
|
+
| Symptom | Cause | Fix |
|
|
135
|
+
|---------|-------|-----|
|
|
136
|
+
| `INVALID_MNEMONIC` | Not 12 or 24 words, or not valid BIP39 English words | Check for typos, extra spaces, wrong word count |
|
|
137
|
+
| `Cannot read properties of undefined (reading 'slice')` | Empty string or null passed as mnemonic | Ensure `.env` file exists and `MNEMONIC` is set |
|
|
138
|
+
| Address starts with `cosmos1` instead of `sent1` | Wrong bech32 prefix (using vanilla CosmJS without Sentinel prefix) | Use SDK's `generateWallet()`, not raw CosmJS |
|
|
139
|
+
|
|
140
|
+
### Diagnostic Check
|
|
141
|
+
```javascript
|
|
142
|
+
// Verify address format
|
|
143
|
+
const addr = imported.address;
|
|
144
|
+
console.assert(addr.startsWith('sent1'), 'Address must start with sent1');
|
|
145
|
+
console.assert(addr.length === 44, 'Address must be 44 characters');
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Phase 3: Balance Check
|
|
151
|
+
|
|
152
|
+
### What Happens
|
|
153
|
+
Queries the Sentinel blockchain (LCD REST API) for the wallet's `udvpn` balance. Tries 4 LCD endpoints with automatic failover.
|
|
154
|
+
|
|
155
|
+
### Code
|
|
156
|
+
```javascript
|
|
157
|
+
import { getBalance } from 'sentinel-ai-connect';
|
|
158
|
+
|
|
159
|
+
const bal = await getBalance('your twelve word mnemonic phrase...');
|
|
160
|
+
console.log(bal);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Successful Output
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"address": "sent1abc...xyz",
|
|
167
|
+
"udvpn": 47690000,
|
|
168
|
+
"p2p": "47.69",
|
|
169
|
+
"funded": true
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Failure Signatures
|
|
174
|
+
|
|
175
|
+
| Symptom | Cause | Fix |
|
|
176
|
+
|---------|-------|-----|
|
|
177
|
+
| `udvpn: 0, funded: false` | Wallet has no tokens | Send P2P tokens to the `sent1...` address |
|
|
178
|
+
| `ECONNREFUSED` or timeout on all 4 LCD endpoints | Network down or all LCD endpoints unreachable | Check internet connection. Verify manually: `curl https://lcd.sentinel.co/cosmos/bank/v1beta1/balances/sent1...` |
|
|
179
|
+
| `funded: false` but `udvpn > 0` | Balance below 1,000,000 udvpn (1.0 P2P) threshold | Fund wallet with at least 1.0 P2P to cover gas + cheapest node |
|
|
180
|
+
|
|
181
|
+
### Diagnostic Check
|
|
182
|
+
```bash
|
|
183
|
+
# Manual balance check (replace address)
|
|
184
|
+
curl -s "https://lcd.sentinel.co/cosmos/bank/v1beta1/balances/sent1abc...xyz" | jq '.balances[] | select(.denom=="udvpn")'
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Cost Reference
|
|
188
|
+
|
|
189
|
+
> Prices are set by independent node operators and vary. Use `estimateCost()` for live pricing.
|
|
190
|
+
|
|
191
|
+
| Action | Approximate Cost |
|
|
192
|
+
|--------|------|
|
|
193
|
+
| Gas per TX | ~0.04 P2P |
|
|
194
|
+
| 1 GB (cheapest nodes) | ~0.68 P2P (varies) |
|
|
195
|
+
| 1 GB (median node) | ~40 P2P (varies) |
|
|
196
|
+
| `funded: true` threshold | 1.0 P2P |
|
|
197
|
+
| Comfortable testing budget | 50 P2P |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Phase 4: Node Discovery
|
|
202
|
+
|
|
203
|
+
### What Happens
|
|
204
|
+
Queries the Sentinel LCD for all active nodes (`status=1`), fetches up to 5,000 nodes in a single request. Can optionally probe individual nodes for country, peers, and health.
|
|
205
|
+
|
|
206
|
+
### Code
|
|
207
|
+
```javascript
|
|
208
|
+
import { discoverNodes, getNetworkStats } from 'sentinel-ai-connect';
|
|
209
|
+
|
|
210
|
+
// Quick mode — chain data only, no probing (fast, < 3 seconds)
|
|
211
|
+
const nodes = await discoverNodes({ quick: true });
|
|
212
|
+
console.log(`Found ${nodes.length} active nodes`);
|
|
213
|
+
console.log('First node:', nodes[0]);
|
|
214
|
+
|
|
215
|
+
// Network overview
|
|
216
|
+
const stats = await getNetworkStats();
|
|
217
|
+
console.log(stats);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Successful Output
|
|
221
|
+
```
|
|
222
|
+
Found 1030 active nodes
|
|
223
|
+
First node: {
|
|
224
|
+
address: "sentnode1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5h38un",
|
|
225
|
+
country: "DE",
|
|
226
|
+
protocol: "wireguard",
|
|
227
|
+
pricePerGb: "4.22",
|
|
228
|
+
pricePerHour: null,
|
|
229
|
+
score: 85,
|
|
230
|
+
peers: 12,
|
|
231
|
+
remoteUrl: "https://45.76.32.100:8585"
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
{
|
|
235
|
+
totalNodes: 1030,
|
|
236
|
+
byCountry: { DE: 42, US: 38, SG: 35, ... },
|
|
237
|
+
byProtocol: { wireguard: 618, v2ray: 412 },
|
|
238
|
+
transportReliability: { "tcp": "100%", "grpc/none": "87%", "websocket": "75%", ... }
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Failure Signatures
|
|
243
|
+
|
|
244
|
+
| Symptom | Cause | Fix |
|
|
245
|
+
|---------|-------|-----|
|
|
246
|
+
| `Found 0 active nodes` | LCD endpoint returned empty, or using v2 path | Verify path is `/sentinel/node/v3/nodes?status=1` (NOT v2, NOT `STATUS_ACTIVE`) |
|
|
247
|
+
| Only ~400 nodes when 1000+ expected | Pagination truncated | Set `pagination.limit=5000` — SDK does this automatically |
|
|
248
|
+
| Country/protocol null on all nodes | Used `quick: true` mode (chain data only, no probing) | Use full mode (omit `quick`) for enriched data — takes 30-60s |
|
|
249
|
+
| `ECONNREFUSED` | LCD endpoints all down | Retry. Check manually: `curl https://lcd.sentinel.co/sentinel/node/v3/nodes?status=1&pagination.limit=5` |
|
|
250
|
+
|
|
251
|
+
### Diagnostic Check
|
|
252
|
+
```bash
|
|
253
|
+
# Count active nodes
|
|
254
|
+
curl -s "https://lcd.sentinel.co/sentinel/node/v3/nodes?status=1&pagination.limit=1&pagination.count_total=true" | jq '.pagination.total'
|
|
255
|
+
|
|
256
|
+
# Check single node
|
|
257
|
+
curl -s "https://lcd.sentinel.co/sentinel/node/v3/nodes/sentnode1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5h38un"
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Phase 5: Cost Estimation
|
|
263
|
+
|
|
264
|
+
### What Happens
|
|
265
|
+
Calculates how much a connection will cost before paying. Uses the node's on-chain price or network median if no specific node.
|
|
266
|
+
|
|
267
|
+
### Code
|
|
268
|
+
```javascript
|
|
269
|
+
import { estimateCost, recommend } from 'sentinel-ai-connect';
|
|
270
|
+
|
|
271
|
+
// Estimate for 1 GB
|
|
272
|
+
const cost = await estimateCost({ gigabytes: 1 });
|
|
273
|
+
console.log(cost);
|
|
274
|
+
|
|
275
|
+
// Or get a full recommendation
|
|
276
|
+
const rec = await recommend({
|
|
277
|
+
country: 'Germany',
|
|
278
|
+
priority: 'reliability',
|
|
279
|
+
gigabytes: 1,
|
|
280
|
+
});
|
|
281
|
+
console.log(rec);
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Successful Output — estimateCost
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"perGb": { "udvpn": 4220000, "p2p": "4.22" },
|
|
288
|
+
"total": { "udvpn": 4220000, "p2p": "4.22" },
|
|
289
|
+
"gas": { "udvpn": 40000, "p2p": "0.04" },
|
|
290
|
+
"grandTotal": { "udvpn": 4260000, "p2p": "4.26" },
|
|
291
|
+
"mode": "gigabyte"
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Successful Output — recommend
|
|
296
|
+
```json
|
|
297
|
+
{
|
|
298
|
+
"action": "connect",
|
|
299
|
+
"confidence": 0.9,
|
|
300
|
+
"primary": {
|
|
301
|
+
"address": "sentnode1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5h38un",
|
|
302
|
+
"country": "DE",
|
|
303
|
+
"protocol": "wireguard",
|
|
304
|
+
"score": 85,
|
|
305
|
+
"pricePerGb": "4.22",
|
|
306
|
+
"peers": 12,
|
|
307
|
+
"reason": "Exact country match, WireGuard available, low peer count"
|
|
308
|
+
},
|
|
309
|
+
"alternatives": [ /* 5 more nodes */ ],
|
|
310
|
+
"estimatedCost": { "udvpn": 4260000, "p2p": "4.26" },
|
|
311
|
+
"warnings": [],
|
|
312
|
+
"reasoning": [
|
|
313
|
+
"Checked capabilities: WireGuard available, admin elevated",
|
|
314
|
+
"Queried 1030 active nodes",
|
|
315
|
+
"Filtered to 42 nodes in Germany",
|
|
316
|
+
"Selected top node by reliability score"
|
|
317
|
+
],
|
|
318
|
+
"capabilities": { "wireguard": true, "v2ray": true, "admin": true }
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Failure Signatures
|
|
323
|
+
|
|
324
|
+
| Symptom | Cause | Fix |
|
|
325
|
+
|---------|-------|-----|
|
|
326
|
+
| `action: "cannot-connect"` | No nodes match filter (e.g. country with zero nodes) | Broaden filter, remove `strictCountry`, or use different country |
|
|
327
|
+
| `action: "connect-fallback"` | Exact country unavailable, using nearby country | Check `warnings` array for details |
|
|
328
|
+
| `pricePerGb` extremely high (>100 P2P) | Looking at `baseValue` instead of `quoteValue` | SDK handles this. If building manually: use `gigabyte_prices[0].amount` not `baseValue` |
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Phase 6: Session Creation (Payment)
|
|
333
|
+
|
|
334
|
+
### What Happens
|
|
335
|
+
Broadcasts a `MsgStartSession` transaction to the Sentinel blockchain. The node is notified on-chain that a session exists. Costs real P2P tokens.
|
|
336
|
+
|
|
337
|
+
**This is the point of no return — tokens are spent regardless of whether the connection succeeds.**
|
|
338
|
+
|
|
339
|
+
### Code (via connect — this happens automatically)
|
|
340
|
+
```javascript
|
|
341
|
+
// connect() handles this internally. The onProgress callback shows it:
|
|
342
|
+
const vpn = await connect({
|
|
343
|
+
mnemonic: process.env.MNEMONIC,
|
|
344
|
+
onProgress: (step, detail) => console.log(`[${step}] ${detail}`),
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Successful Progress Output
|
|
349
|
+
```
|
|
350
|
+
[wallet] Wallet ready: sent12e03...
|
|
351
|
+
[wallet] RPC connected: https://rpc.sentinel.co
|
|
352
|
+
[wallet] LCD connected: https://lcd.sentinel.co
|
|
353
|
+
[wallet] Balance: 47.69 P2P
|
|
354
|
+
[session] Found 1030 active nodes
|
|
355
|
+
[session] Selected node sentnode1qyp... (DE, WireGuard, 4.22 P2P/GB)
|
|
356
|
+
[session] Broadcasting MsgStartSession...
|
|
357
|
+
[session] TX broadcast: hash 7A3F...B21C
|
|
358
|
+
[session] Waiting for block confirmation...
|
|
359
|
+
[session] Session created: ID 485721
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
> **Progress tag reference:** The SDK emits these step names: `wallet`, `session`, `node-check`, `validate`, `handshake`, `tunnel`, `verify`, `proxy`, `recover`, `cache`, `dry-run`, `log`. Match against these when programmatically parsing progress output.
|
|
363
|
+
|
|
364
|
+
### Failure Signatures
|
|
365
|
+
|
|
366
|
+
| Symptom | Cause | Fix |
|
|
367
|
+
|---------|-------|-----|
|
|
368
|
+
| `INSUFFICIENT_BALANCE` | Not enough udvpn for session + gas | Fund wallet with more P2P tokens |
|
|
369
|
+
| `account sequence mismatch` | Previous TX still pending | SDK auto-retries up to 5 times with local sequence counter |
|
|
370
|
+
| `node does not exist` | Node went offline between query and TX | SDK retries once after 10s wait (chain lag). If persistent, try another node |
|
|
371
|
+
| `session already exists` | Active session with this node exists from a previous run | SDK detects and reuses the existing session |
|
|
372
|
+
| `BROADCAST_FAILED` after 5 retries | RPC endpoint congested | Wait 60s, then retry. Check RPC health: `curl https://rpc.sentinel.co/health` |
|
|
373
|
+
| `code 105: inactive` | Node just went inactive on-chain | SDK auto-retries with a different node |
|
|
374
|
+
| Progress stops at `[subscribe] Broadcasting...` | TX stuck in mempool | Wait up to 60s. Sentinel blocks are ~6s. If >60s, RPC may be congested |
|
|
375
|
+
|
|
376
|
+
### Diagnostic Check
|
|
377
|
+
```bash
|
|
378
|
+
# Check your sessions on-chain
|
|
379
|
+
curl -s "https://lcd.sentinel.co/sentinel/session/v3/accounts/sent1abc...xyz/sessions" | jq '.sessions | length'
|
|
380
|
+
|
|
381
|
+
# Check specific session
|
|
382
|
+
curl -s "https://lcd.sentinel.co/sentinel/session/v3/sessions/485721"
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Critical Timing
|
|
386
|
+
- After TX broadcast, the SDK waits for block confirmation (~6s)
|
|
387
|
+
- If session query returns "does not exist," the SDK waits 10s and retries (chain propagation lag)
|
|
388
|
+
- A new session may show `inactive_pending` status briefly — the SDK polls until `active`
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## Phase 7: Handshake
|
|
393
|
+
|
|
394
|
+
### What Happens
|
|
395
|
+
The SDK sends an authenticated POST request to the node's HTTPS API. The body contains the session ID, a public key (X25519 for WireGuard or UUID for V2Ray), and a cryptographic signature proving ownership of the wallet that paid for the session.
|
|
396
|
+
|
|
397
|
+
**Signature construction:** `secp256k1_sign(SHA256(BigEndian_uint64(sessionId) + raw_peer_data_json_bytes))`
|
|
398
|
+
|
|
399
|
+
### Successful Progress Output — WireGuard
|
|
400
|
+
```
|
|
401
|
+
[handshake] Handshaking with sentnode1qyp... (WireGuard)
|
|
402
|
+
[handshake] Generated X25519 key pair
|
|
403
|
+
[handshake] POST https://45.76.32.100:8585
|
|
404
|
+
[handshake] WireGuard config received
|
|
405
|
+
[log] Server public key: aB3x...kLm=
|
|
406
|
+
[log] Endpoint: 45.76.32.100:51820
|
|
407
|
+
[log] Tunnel IP: 10.8.0.2/32
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Successful Progress Output — V2Ray
|
|
411
|
+
```
|
|
412
|
+
[handshake] Handshaking with sentnode1abc... (V2Ray)
|
|
413
|
+
[handshake] Generated UUID: 7f3a...e2b1
|
|
414
|
+
[handshake] POST https://198.51.100.42:8585
|
|
415
|
+
[handshake] V2Ray config received
|
|
416
|
+
[log] Protocol: VLess, Transport: grpc/none
|
|
417
|
+
[log] Metadata entries: 3 outbounds available
|
|
418
|
+
[log] Ports: [8686, 8787, 7874]
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Failure Signatures
|
|
422
|
+
|
|
423
|
+
| Symptom | Cause | Fix |
|
|
424
|
+
|---------|-------|-----|
|
|
425
|
+
| `HANDSHAKE_FAILED` with timeout | Node API is unreachable (HTTPS port down) | Try a different node. SDK timeout is 90s |
|
|
426
|
+
| `409 Conflict` | Session exists but node has stale state | SDK retries at 15s, 20s, then 25s. Usually resolves |
|
|
427
|
+
| `session does not exist` (code 5) | Chain propagation lag — node hasn't seen the TX yet | SDK waits 10s and retries once |
|
|
428
|
+
| `ECONNRESET` or `EPROTO` | Node TLS certificate issue or network instability | SDK uses TOFU TLS (first cert is trusted, changes are rejected) |
|
|
429
|
+
| `already exists` | Re-handshaking for an already-used session | SDK creates a fresh session and retries |
|
|
430
|
+
| `certificate has changed` | Possible MITM attack OR node rotated its cert | SDK rejects. Skip this node (security) |
|
|
431
|
+
| Handshake succeeds but V2Ray tunnel hangs | VLess `flow` field set to `xtls-rprx-vision` instead of `''` | Must be empty string — V2Ray 5.x silently rejects Xray-only flows |
|
|
432
|
+
|
|
433
|
+
### Diagnostic Check
|
|
434
|
+
```bash
|
|
435
|
+
# Check if node is reachable (replace URL from node's remote_addrs)
|
|
436
|
+
curl -k -s -o /dev/null -w "%{http_code}" https://45.76.32.100:8585/status
|
|
437
|
+
|
|
438
|
+
# Expected: 200 (node alive) or 401 (alive but needs auth)
|
|
439
|
+
# If timeout or connection refused: node is down
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Phase 8: Tunnel Installation
|
|
445
|
+
|
|
446
|
+
### What Happens
|
|
447
|
+
|
|
448
|
+
**WireGuard path:**
|
|
449
|
+
1. Writes `wgsent0.conf` with: private key, server public key, endpoint, allowed IPs, DNS
|
|
450
|
+
2. Calls `wireguard.exe /installtunnelservice <path>/wgsent0.conf`
|
|
451
|
+
3. Windows creates a `WireGuardTunnel$wgsent0` service
|
|
452
|
+
4. Waits for the adapter to appear and traffic to flow
|
|
453
|
+
5. Config file must remain on disk — the service reads it at startup
|
|
454
|
+
|
|
455
|
+
**V2Ray path:**
|
|
456
|
+
1. Builds client config JSON with inbound (SOCKS5 proxy) and outbounds (one per transport)
|
|
457
|
+
2. Spawns `v2ray.exe run -config <path>/config.json`
|
|
458
|
+
3. Tests each outbound sequentially (TCP probe → SOCKS5 connectivity → traffic test)
|
|
459
|
+
4. First working outbound wins — remaining are skipped
|
|
460
|
+
5. SOCKS5 port: `10800 + random(1000)` — randomized to avoid TIME_WAIT collisions
|
|
461
|
+
|
|
462
|
+
### Successful Progress Output — WireGuard
|
|
463
|
+
```
|
|
464
|
+
[tunnel] Writing WireGuard config: wgsent0.conf
|
|
465
|
+
[tunnel] Config: MTU=1280, DNS=10.8.0.1, PersistentKeepalive=15
|
|
466
|
+
[tunnel] Installing tunnel service...
|
|
467
|
+
[tunnel] Service WireGuardTunnel$wgsent0 started
|
|
468
|
+
[tunnel] Adapter active: wgsent0
|
|
469
|
+
[tunnel] Waiting 3s for tunnel stabilization...
|
|
470
|
+
[tunnel] Tunnel ready
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Successful Progress Output — V2Ray
|
|
474
|
+
```
|
|
475
|
+
[tunnel] Building V2Ray config with 3 outbounds
|
|
476
|
+
[tunnel] SOCKS5 inbound on 127.0.0.1:11342
|
|
477
|
+
[tunnel] Starting V2Ray process (PID 14208)
|
|
478
|
+
[tunnel] Testing outbound 1/3: grpc/none on port 8686...
|
|
479
|
+
[tunnel] TCP probe: port 8686 open (142ms)
|
|
480
|
+
[tunnel] SOCKS5 test: connected (1.2s)
|
|
481
|
+
[tunnel] Outbound 1 works — using grpc/none
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Failure Signatures
|
|
485
|
+
|
|
486
|
+
| Symptom | Cause | Fix |
|
|
487
|
+
|---------|-------|-----|
|
|
488
|
+
| `WG_NOT_AVAILABLE` or `Access denied` | Not running as admin | Elevate: `run-admin.vbs` (Windows) or `sudo` |
|
|
489
|
+
| `Service failed to start` | Orphaned WireGuard tunnel from previous crash | Run `wireguard.exe /uninstalltunnelservice wgsent0` manually |
|
|
490
|
+
| `MTU errors` or `TLS handshake failure through tunnel` | MTU set to 1420 instead of 1280 | SDK uses 1280. If building manually: ALWAYS use 1280 |
|
|
491
|
+
| All 3 V2Ray outbounds fail TCP probe | Node's V2Ray ports are firewalled | Try a different node |
|
|
492
|
+
| V2Ray starts but SOCKS5 returns `connection refused` | Port collision — another process on the same port | SDK randomizes port. If persistent: kill orphaned V2Ray processes |
|
|
493
|
+
| `WG_NO_CONNECTIVITY` | WireGuard tunnel installed but no traffic flows | Node may be overloaded or routing broken. Disconnect and try another node |
|
|
494
|
+
| Internet dies completely for ~78 seconds | Full-tunnel WireGuard installed before verification | SDK uses verify-before-capture: tests with split IPs first, then switches to full tunnel |
|
|
495
|
+
| V2Ray tunnel works for 10-18s then hangs | VLess with wrong `flow` field, OR VMess with clock drift >120s | Check node's clock. Ensure `flow: ''` for VLess |
|
|
496
|
+
|
|
497
|
+
### Diagnostic Check — WireGuard
|
|
498
|
+
```bash
|
|
499
|
+
# Check if WireGuard service exists
|
|
500
|
+
sc query WireGuardTunnel$wgsent0
|
|
501
|
+
|
|
502
|
+
# Check if adapter exists
|
|
503
|
+
netsh interface show interface name="wgsent0"
|
|
504
|
+
|
|
505
|
+
# Check if traffic flows
|
|
506
|
+
ping -n 1 10.8.0.1
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Diagnostic Check — V2Ray
|
|
510
|
+
```bash
|
|
511
|
+
# Check if V2Ray process is running
|
|
512
|
+
tasklist | grep v2ray
|
|
513
|
+
|
|
514
|
+
# Test SOCKS5 proxy (replace port)
|
|
515
|
+
curl --socks5-hostname 127.0.0.1:11342 https://api.ipify.org
|
|
516
|
+
|
|
517
|
+
# IMPORTANT: Use axios with adapter:'http', NOT native fetch
|
|
518
|
+
# Native fetch silently ignores SOCKS5 proxy configuration
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## Phase 9: Verification
|
|
524
|
+
|
|
525
|
+
### What Happens
|
|
526
|
+
The SDK confirms the tunnel is actually working by checking the public IP through the tunnel. This verifies end-to-end connectivity.
|
|
527
|
+
|
|
528
|
+
### Code
|
|
529
|
+
```javascript
|
|
530
|
+
import { verify, status } from 'sentinel-ai-connect';
|
|
531
|
+
|
|
532
|
+
const v = await verify();
|
|
533
|
+
console.log(v);
|
|
534
|
+
|
|
535
|
+
const s = status();
|
|
536
|
+
console.log(s);
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### Successful Output
|
|
540
|
+
```json
|
|
541
|
+
// verify()
|
|
542
|
+
{
|
|
543
|
+
"connected": true,
|
|
544
|
+
"ip": "45.76.32.100",
|
|
545
|
+
"verified": true
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// status()
|
|
549
|
+
{
|
|
550
|
+
"connected": true,
|
|
551
|
+
"sessionId": "485721",
|
|
552
|
+
"protocol": "wireguard",
|
|
553
|
+
"nodeAddress": "sentnode1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5h38un",
|
|
554
|
+
"socksPort": null,
|
|
555
|
+
"uptimeMs": 12345,
|
|
556
|
+
"uptimeFormatted": "12s",
|
|
557
|
+
"ip": "45.76.32.100"
|
|
558
|
+
}
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Failure Signatures
|
|
562
|
+
|
|
563
|
+
| Symptom | Cause | Fix |
|
|
564
|
+
|---------|-------|-----|
|
|
565
|
+
| `verified: false`, `ip: null` | Tunnel is up but no traffic flows | Disconnect and try a different node |
|
|
566
|
+
| `ip` matches your real IP (not the node's) | Tunnel not actually routing traffic (split tunnel or DNS leak) | Check WireGuard AllowedIPs includes `0.0.0.0/0` |
|
|
567
|
+
| `connected: false` | Tunnel collapsed between installation and verification | Reconnect |
|
|
568
|
+
| Timeout on IP check | `api.ipify.org` blocked through this node | Non-critical — tunnel may still work. Try `curl https://ifconfig.me` manually |
|
|
569
|
+
|
|
570
|
+
### Diagnostic Check
|
|
571
|
+
```bash
|
|
572
|
+
# WireGuard: IP should match the node's IP
|
|
573
|
+
curl https://api.ipify.org
|
|
574
|
+
|
|
575
|
+
# V2Ray: IP should match the node's IP (must use SOCKS5)
|
|
576
|
+
curl --socks5-hostname 127.0.0.1:11342 https://api.ipify.org
|
|
577
|
+
|
|
578
|
+
# DNS leak check
|
|
579
|
+
nslookup whoami.akamai.net
|
|
580
|
+
# Should resolve through tunnel DNS, not your ISP's DNS
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## Complete Successful Connection — Full Log
|
|
586
|
+
|
|
587
|
+
This is the real output of a successful `connect()` call from start to finish:
|
|
588
|
+
|
|
589
|
+
```
|
|
590
|
+
[wallet] Deriving wallet from mnemonic...
|
|
591
|
+
[wallet] Wallet ready: sent1abc...xyz
|
|
592
|
+
[wallet] Connecting to RPC: https://rpc.sentinel.co
|
|
593
|
+
[wallet] RPC connected (chain: sentinelhub-2, height: 18,234,567)
|
|
594
|
+
[wallet] LCD available: https://lcd.sentinel.co
|
|
595
|
+
[wallet] Balance: 47.69 P2P (47,690,000 udvpn)
|
|
596
|
+
[session] Querying active nodes...
|
|
597
|
+
[session] Found 1,030 active nodes
|
|
598
|
+
[session] Filtering: WireGuard preferred, country: any
|
|
599
|
+
[session] Selected: sentnode1qyp... (DE, WireGuard, 4.22 P2P/GB, 12 peers)
|
|
600
|
+
[session] Broadcasting MsgStartSession (1 GB, ~4.26 P2P total)...
|
|
601
|
+
[session] TX hash: 7A3F8B2C...
|
|
602
|
+
[session] Confirmed in block 18,234,573 (6.2s)
|
|
603
|
+
[session] Session ID: 485721
|
|
604
|
+
[handshake] POST https://45.76.32.100:8585/handshake
|
|
605
|
+
[handshake] WireGuard keys exchanged successfully
|
|
606
|
+
[tunnel] Installing WireGuard tunnel (MTU=1280, DNS=10.8.0.1)
|
|
607
|
+
[tunnel] Service WireGuardTunnel$wgsent0 started
|
|
608
|
+
[tunnel] Tunnel active — verifying connectivity...
|
|
609
|
+
[verify] IP changed: 45.76.32.100 (was: 203.0.113.50)
|
|
610
|
+
[verify] Tunnel verified — traffic flowing through node
|
|
611
|
+
|
|
612
|
+
Result: {
|
|
613
|
+
sessionId: "485721",
|
|
614
|
+
protocol: "wireguard",
|
|
615
|
+
nodeAddress: "sentnode1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5h38un",
|
|
616
|
+
socksPort: null,
|
|
617
|
+
ip: "45.76.32.100"
|
|
618
|
+
}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
**Total time:** ~20-45 seconds (depends on node responsiveness and chain block time)
|
|
622
|
+
|
|
623
|
+
---
|
|
624
|
+
|
|
625
|
+
## Failure Diagnosis Flowchart
|
|
626
|
+
|
|
627
|
+
If `connect()` throws an error, match the error against this progression to identify the exact failing phase:
|
|
628
|
+
|
|
629
|
+
```
|
|
630
|
+
Error contains "mnemonic" or "wallet"?
|
|
631
|
+
→ Phase 2 failure. Check mnemonic format.
|
|
632
|
+
|
|
633
|
+
Error contains "balance" or "insufficient"?
|
|
634
|
+
→ Phase 3 failure. Fund wallet.
|
|
635
|
+
|
|
636
|
+
Error contains "0 nodes" or "no nodes"?
|
|
637
|
+
→ Phase 4 failure. Check LCD endpoint connectivity.
|
|
638
|
+
|
|
639
|
+
Error contains "broadcast" or "sequence"?
|
|
640
|
+
→ Phase 6 failure. Chain TX issue. Wait and retry.
|
|
641
|
+
|
|
642
|
+
Error contains "handshake" or "409" or "does not exist"?
|
|
643
|
+
→ Phase 7 failure. Node communication issue. Try different node.
|
|
644
|
+
|
|
645
|
+
Error contains "V2RAY_NOT_FOUND" or "WG_NOT_AVAILABLE"?
|
|
646
|
+
→ Phase 8 failure. Missing binary or admin rights.
|
|
647
|
+
|
|
648
|
+
Error contains "no connectivity" or "tunnel" or "timeout"?
|
|
649
|
+
→ Phase 8-9 failure. Tunnel installed but broken. Try different node.
|
|
650
|
+
|
|
651
|
+
Error contains "ABORTED"?
|
|
652
|
+
→ Timeout exceeded (default 120s). Increase timeout or check network.
|
|
653
|
+
|
|
654
|
+
None of the above?
|
|
655
|
+
→ Check err.code and err.details for SDK error code.
|
|
656
|
+
→ Report with full error output for diagnosis.
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
## The One-Shot Test
|
|
662
|
+
|
|
663
|
+
Run this to verify everything works end-to-end in your environment:
|
|
664
|
+
|
|
665
|
+
```javascript
|
|
666
|
+
import 'dotenv/config';
|
|
667
|
+
import { setup, getBalance, connect, verify, disconnect } from 'sentinel-ai-connect';
|
|
668
|
+
|
|
669
|
+
async function test() {
|
|
670
|
+
// Phase 1: Environment
|
|
671
|
+
console.log('--- Phase 1: Environment ---');
|
|
672
|
+
const env = await setup();
|
|
673
|
+
if (!env.ready) {
|
|
674
|
+
console.error('Environment not ready:', env.issues);
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
console.log('Environment OK:', env.environment.capabilities);
|
|
678
|
+
|
|
679
|
+
// Phase 2-3: Wallet + Balance
|
|
680
|
+
console.log('\n--- Phase 2-3: Wallet + Balance ---');
|
|
681
|
+
const bal = await getBalance(process.env.MNEMONIC);
|
|
682
|
+
console.log(`Balance: ${bal.p2p} P2P, funded: ${bal.funded}`);
|
|
683
|
+
if (!bal.funded) {
|
|
684
|
+
console.error(`Fund wallet: ${bal.address}`);
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Phase 4-9: Connect (handles discovery, payment, handshake, tunnel, verify)
|
|
689
|
+
console.log('\n--- Phase 4-9: Connect ---');
|
|
690
|
+
try {
|
|
691
|
+
const vpn = await connect({
|
|
692
|
+
mnemonic: process.env.MNEMONIC,
|
|
693
|
+
onProgress: (step, detail) => console.log(` [${step}] ${detail}`),
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
console.log('\n--- Result ---');
|
|
697
|
+
console.log(`Protocol: ${vpn.protocol}`);
|
|
698
|
+
console.log(`Node: ${vpn.nodeAddress}`);
|
|
699
|
+
console.log(`Session: ${vpn.sessionId}`);
|
|
700
|
+
console.log(`IP: ${vpn.ip}`);
|
|
701
|
+
|
|
702
|
+
// Extra verification
|
|
703
|
+
const v = await verify();
|
|
704
|
+
console.log(`Verified: ${v.verified}`);
|
|
705
|
+
|
|
706
|
+
// Disconnect
|
|
707
|
+
console.log('\n--- Disconnect ---');
|
|
708
|
+
await disconnect();
|
|
709
|
+
console.log('Disconnected successfully');
|
|
710
|
+
|
|
711
|
+
} catch (err) {
|
|
712
|
+
console.error(`FAILED: ${err.message}`);
|
|
713
|
+
console.error(`Code: ${err.code}`);
|
|
714
|
+
console.error(`Details: ${JSON.stringify(err.details)}`);
|
|
715
|
+
// Match against the Failure Diagnosis Flowchart above
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
test();
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
**Expected:** All phases complete, IP changes, `verified: true`, clean disconnect.
|
|
723
|
+
|
|
724
|
+
**If it fails:** The `onProgress` output shows exactly which phase succeeded before the failure. Match the last successful phase and the error against the tables above.
|