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.
Files changed (215) hide show
  1. package/CHANGELOG.md +446 -0
  2. package/LICENSE +21 -0
  3. package/README.md +75 -0
  4. package/ai-path/ADMIN-ELEVATION.md +116 -0
  5. package/ai-path/AI-MANIFESTO.md +185 -0
  6. package/ai-path/BREAKING.md +74 -0
  7. package/ai-path/CHECKLIST.md +619 -0
  8. package/ai-path/CONNECTION-STEPS.md +724 -0
  9. package/ai-path/DECISION-TREE.md +378 -0
  10. package/ai-path/DEPENDENCIES.md +459 -0
  11. package/ai-path/E2E-FLOW.md +1555 -0
  12. package/ai-path/FAILURES.md +403 -0
  13. package/ai-path/GUIDE.md +1217 -0
  14. package/ai-path/README.md +558 -0
  15. package/ai-path/SPLIT-TUNNEL.md +266 -0
  16. package/ai-path/cli.js +535 -0
  17. package/ai-path/connect.js +884 -0
  18. package/ai-path/discover.js +178 -0
  19. package/ai-path/environment.js +266 -0
  20. package/ai-path/errors.js +86 -0
  21. package/ai-path/examples/autonomous-agent.mjs +220 -0
  22. package/ai-path/examples/multi-region.mjs +174 -0
  23. package/ai-path/examples/one-shot.mjs +31 -0
  24. package/ai-path/index.js +60 -0
  25. package/ai-path/pricing.js +136 -0
  26. package/ai-path/recommend.js +413 -0
  27. package/ai-path/run-admin.vbs +25 -0
  28. package/ai-path/setup.js +291 -0
  29. package/ai-path/wallet.js +137 -0
  30. package/app-helpers.js +363 -0
  31. package/app-settings.js +95 -0
  32. package/app-types.js +267 -0
  33. package/audit.js +847 -0
  34. package/batch.js +293 -0
  35. package/bin/setup.js +376 -0
  36. package/chain/authz.js +109 -0
  37. package/chain/broadcast.js +472 -0
  38. package/chain/client.js +160 -0
  39. package/chain/fee-grants.js +305 -0
  40. package/chain/index.js +891 -0
  41. package/chain/lcd.js +313 -0
  42. package/chain/queries.js +547 -0
  43. package/chain/rpc.js +408 -0
  44. package/chain/wallet.js +141 -0
  45. package/cli/config.js +143 -0
  46. package/cli/index.js +463 -0
  47. package/cli/output.js +182 -0
  48. package/cli.js +491 -0
  49. package/client/index.js +251 -0
  50. package/client.js +271 -0
  51. package/config/index.js +255 -0
  52. package/connection/connect.js +849 -0
  53. package/connection/disconnect.js +180 -0
  54. package/connection/discovery.js +321 -0
  55. package/connection/index.js +76 -0
  56. package/connection/proxy.js +148 -0
  57. package/connection/resilience.js +428 -0
  58. package/connection/security.js +232 -0
  59. package/connection/state.js +369 -0
  60. package/connection/tunnel.js +691 -0
  61. package/consumer.js +132 -0
  62. package/cosmjs-setup.js +1884 -0
  63. package/defaults.js +366 -0
  64. package/disk-cache.js +107 -0
  65. package/dist/client.d.ts +108 -0
  66. package/dist/client.d.ts.map +1 -0
  67. package/dist/client.js +400 -0
  68. package/dist/client.js.map +1 -0
  69. package/dist/index.d.ts +8 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +8 -0
  72. package/dist/index.js.map +1 -0
  73. package/errors/index.js +112 -0
  74. package/errors.js +218 -0
  75. package/examples/README.md +64 -0
  76. package/examples/connect-direct.mjs +106 -0
  77. package/examples/connect-plan.mjs +125 -0
  78. package/examples/error-handling.mjs +109 -0
  79. package/examples/query-nodes.mjs +94 -0
  80. package/examples/wallet-basics.mjs +61 -0
  81. package/generated/amino/amino.ts +9 -0
  82. package/generated/cosmos/base/v1beta1/coin.ts +365 -0
  83. package/generated/cosmos_proto/cosmos.ts +323 -0
  84. package/generated/gogoproto/gogo.ts +9 -0
  85. package/generated/google/protobuf/descriptor.ts +7601 -0
  86. package/generated/google/protobuf/duration.ts +208 -0
  87. package/generated/google/protobuf/timestamp.ts +238 -0
  88. package/generated/sentinel/lease/v1/events.ts +924 -0
  89. package/generated/sentinel/lease/v1/lease.ts +292 -0
  90. package/generated/sentinel/lease/v1/msg.ts +949 -0
  91. package/generated/sentinel/lease/v1/params.ts +164 -0
  92. package/generated/sentinel/node/v3/events.ts +881 -0
  93. package/generated/sentinel/node/v3/msg.ts +1002 -0
  94. package/generated/sentinel/node/v3/node.ts +263 -0
  95. package/generated/sentinel/node/v3/params.ts +183 -0
  96. package/generated/sentinel/plan/v3/events.ts +675 -0
  97. package/generated/sentinel/plan/v3/msg.ts +1191 -0
  98. package/generated/sentinel/plan/v3/plan.ts +283 -0
  99. package/generated/sentinel/provider/v2/events.ts +171 -0
  100. package/generated/sentinel/provider/v2/msg.ts +480 -0
  101. package/generated/sentinel/provider/v2/params.ts +131 -0
  102. package/generated/sentinel/provider/v2/provider.ts +246 -0
  103. package/generated/sentinel/session/v3/events.ts +480 -0
  104. package/generated/sentinel/session/v3/msg.ts +616 -0
  105. package/generated/sentinel/session/v3/params.ts +260 -0
  106. package/generated/sentinel/session/v3/proof.ts +180 -0
  107. package/generated/sentinel/session/v3/session.ts +384 -0
  108. package/generated/sentinel/subscription/v3/events.ts +1181 -0
  109. package/generated/sentinel/subscription/v3/msg.ts +1305 -0
  110. package/generated/sentinel/subscription/v3/params.ts +167 -0
  111. package/generated/sentinel/subscription/v3/subscription.ts +315 -0
  112. package/generated/sentinel/types/v1/bandwidth.ts +124 -0
  113. package/generated/sentinel/types/v1/price.ts +149 -0
  114. package/generated/sentinel/types/v1/renewal.ts +87 -0
  115. package/generated/sentinel/types/v1/status.ts +54 -0
  116. package/generated/typeRegistry.ts +27 -0
  117. package/index.js +486 -0
  118. package/node-connect.js +3015 -0
  119. package/operator.js +134 -0
  120. package/package.json +113 -0
  121. package/plan-operations.js +199 -0
  122. package/preflight.js +352 -0
  123. package/pricing/index.js +262 -0
  124. package/proto/amino/amino.proto +84 -0
  125. package/proto/cosmos/base/v1beta1/coin.proto +61 -0
  126. package/proto/cosmos_proto/cosmos.proto +112 -0
  127. package/proto/gogoproto/gogo.proto +145 -0
  128. package/proto/google/api/annotations.proto +31 -0
  129. package/proto/google/api/http.proto +370 -0
  130. package/proto/google/protobuf/any.proto +106 -0
  131. package/proto/google/protobuf/duration.proto +115 -0
  132. package/proto/google/protobuf/timestamp.proto +145 -0
  133. package/proto/sentinel/lease/v1/events.proto +52 -0
  134. package/proto/sentinel/lease/v1/genesis.proto +15 -0
  135. package/proto/sentinel/lease/v1/lease.proto +25 -0
  136. package/proto/sentinel/lease/v1/msg.proto +62 -0
  137. package/proto/sentinel/lease/v1/params.proto +17 -0
  138. package/proto/sentinel/node/v3/events.proto +50 -0
  139. package/proto/sentinel/node/v3/genesis.proto +15 -0
  140. package/proto/sentinel/node/v3/msg.proto +63 -0
  141. package/proto/sentinel/node/v3/node.proto +27 -0
  142. package/proto/sentinel/node/v3/params.proto +21 -0
  143. package/proto/sentinel/node/v3/querier.proto +63 -0
  144. package/proto/sentinel/plan/v3/events.proto +41 -0
  145. package/proto/sentinel/plan/v3/genesis.proto +21 -0
  146. package/proto/sentinel/plan/v3/msg.proto +83 -0
  147. package/proto/sentinel/plan/v3/plan.proto +32 -0
  148. package/proto/sentinel/plan/v3/querier.proto +53 -0
  149. package/proto/sentinel/provider/v2/events.proto +16 -0
  150. package/proto/sentinel/provider/v2/genesis.proto +15 -0
  151. package/proto/sentinel/provider/v2/msg.proto +35 -0
  152. package/proto/sentinel/provider/v2/params.proto +17 -0
  153. package/proto/sentinel/provider/v2/provider.proto +24 -0
  154. package/proto/sentinel/provider/v3/genesis.proto +15 -0
  155. package/proto/sentinel/provider/v3/params.proto +13 -0
  156. package/proto/sentinel/session/v3/events.proto +30 -0
  157. package/proto/sentinel/session/v3/genesis.proto +15 -0
  158. package/proto/sentinel/session/v3/msg.proto +50 -0
  159. package/proto/sentinel/session/v3/params.proto +25 -0
  160. package/proto/sentinel/session/v3/proof.proto +25 -0
  161. package/proto/sentinel/session/v3/querier.proto +100 -0
  162. package/proto/sentinel/session/v3/session.proto +50 -0
  163. package/proto/sentinel/subscription/v2/allocation.proto +21 -0
  164. package/proto/sentinel/subscription/v2/payout.proto +22 -0
  165. package/proto/sentinel/subscription/v3/events.proto +65 -0
  166. package/proto/sentinel/subscription/v3/genesis.proto +17 -0
  167. package/proto/sentinel/subscription/v3/msg.proto +83 -0
  168. package/proto/sentinel/subscription/v3/params.proto +21 -0
  169. package/proto/sentinel/subscription/v3/subscription.proto +33 -0
  170. package/proto/sentinel/types/v1/bandwidth.proto +19 -0
  171. package/proto/sentinel/types/v1/price.proto +21 -0
  172. package/proto/sentinel/types/v1/renewal.proto +21 -0
  173. package/proto/sentinel/types/v1/status.proto +16 -0
  174. package/protocol/encoding.js +341 -0
  175. package/protocol/events.js +361 -0
  176. package/protocol/handshake.js +297 -0
  177. package/protocol/index.js +15 -0
  178. package/protocol/messages.js +346 -0
  179. package/protocol/plans.js +199 -0
  180. package/protocol/v2ray.js +268 -0
  181. package/protocol/v3.js +723 -0
  182. package/protocol/wireguard.js +125 -0
  183. package/security/index.js +132 -0
  184. package/session-manager.js +329 -0
  185. package/session-tracker.js +80 -0
  186. package/setup.js +376 -0
  187. package/speedtest/index.js +528 -0
  188. package/speedtest.js +567 -0
  189. package/src/client.ts +502 -0
  190. package/src/index.ts +20 -0
  191. package/state/index.js +347 -0
  192. package/state.js +516 -0
  193. package/test-all-chain-ops.js +493 -0
  194. package/test-all-logic.js +199 -0
  195. package/test-all-msg-types.js +292 -0
  196. package/test-every-connection.js +208 -0
  197. package/test-feegrant-connect.js +98 -0
  198. package/test-logic.js +148 -0
  199. package/test-mainnet.js +176 -0
  200. package/test-plan-lifecycle.js +335 -0
  201. package/tls-trust.js +132 -0
  202. package/tsconfig.build.json +20 -0
  203. package/tsconfig.json +34 -0
  204. package/types/chain.d.ts +746 -0
  205. package/types/connection.d.ts +425 -0
  206. package/types/errors.d.ts +174 -0
  207. package/types/index.d.ts +1380 -0
  208. package/types/nodes.d.ts +187 -0
  209. package/types/pricing.d.ts +156 -0
  210. package/types/protocol.d.ts +332 -0
  211. package/types/session.d.ts +236 -0
  212. package/types/settings.d.ts +192 -0
  213. package/v3protocol.js +1053 -0
  214. package/wallet/index.js +153 -0
  215. package/wireguard.js +307 -0
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Autonomous Agent — Production VPN Pattern
3
+ *
4
+ * A complete autonomous AI agent that:
5
+ * 1. Creates or loads a wallet
6
+ * 2. Checks balance, warns if low
7
+ * 3. Connects to VPN with retry logic
8
+ * 4. Performs work (HTTP requests through the tunnel)
9
+ * 5. Monitors connection health
10
+ * 6. Auto-reconnects on failure
11
+ * 7. Gracefully disconnects when done
12
+ *
13
+ * Run: node examples/autonomous-agent.mjs
14
+ */
15
+
16
+ import 'dotenv/config';
17
+ import { connect, disconnect, status, isVpnActive, createWallet, getBalance } from '../index.js';
18
+
19
+ // ─── Configuration ──────────────────────────────────────────────────────────
20
+
21
+ const MAX_RETRIES = 3;
22
+ const RETRY_DELAY_MS = 5000;
23
+ const HEALTH_CHECK_INTERVAL_MS = 30000;
24
+ const WORK_CYCLES = 5;
25
+
26
+ // ─── Helpers ────────────────────────────────────────────────────────────────
27
+
28
+ function log(level, msg) {
29
+ const ts = new Date().toISOString().slice(11, 19);
30
+ const prefix = { info: '\x1b[36m[INFO]\x1b[0m', warn: '\x1b[33m[WARN]\x1b[0m', err: '\x1b[31m[ERR]\x1b[0m', ok: '\x1b[32m[ OK ]\x1b[0m' };
31
+ console.log(`${ts} ${prefix[level] || prefix.info} ${msg}`);
32
+ }
33
+
34
+ function sleep(ms) {
35
+ return new Promise((resolve) => setTimeout(resolve, ms));
36
+ }
37
+
38
+ // ─── Step 1: Wallet Setup ───────────────────────────────────────────────────
39
+
40
+ async function ensureWallet() {
41
+ let mnemonic = process.env.MNEMONIC;
42
+
43
+ if (!mnemonic) {
44
+ log('warn', 'No MNEMONIC in .env — generating a new wallet');
45
+ const wallet = await createWallet();
46
+ mnemonic = wallet.mnemonic;
47
+ log('ok', `Wallet created: ${wallet.address}`);
48
+ log('warn', 'SAVE YOUR MNEMONIC — it will not be shown again.');
49
+ log('warn', `Add to .env: MNEMONIC=<your ${mnemonic.split(' ').length} words>`);
50
+ // SECURITY: Never log the full mnemonic. Write directly to .env file instead.
51
+ const { writeFileSync } = await import('fs');
52
+ writeFileSync('.env', `MNEMONIC=${mnemonic}\n`, { mode: 0o600 });
53
+ }
54
+
55
+ return mnemonic;
56
+ }
57
+
58
+ // ─── Step 2: Balance Check ──────────────────────────────────────────────────
59
+
60
+ async function checkFunds(mnemonic) {
61
+ log('info', 'Checking wallet balance...');
62
+ const bal = await getBalance(mnemonic);
63
+ log('info', `Address: ${bal.address}`);
64
+ log('info', `Balance: ${bal.p2p} (${bal.udvpn.toLocaleString()} udvpn)`);
65
+
66
+ if (!bal.funded) {
67
+ log('err', 'Insufficient balance. Fund your wallet with P2P tokens.');
68
+ log('info', `Send tokens to: ${bal.address}`);
69
+ process.exit(1);
70
+ }
71
+
72
+ log('ok', 'Wallet funded and ready');
73
+ return bal;
74
+ }
75
+
76
+ // ─── Step 3: Connect with Retries ───────────────────────────────────────────
77
+
78
+ async function connectWithRetry(mnemonic) {
79
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
80
+ log('info', `Connection attempt ${attempt}/${MAX_RETRIES}...`);
81
+
82
+ try {
83
+ const vpn = await connect({
84
+ mnemonic,
85
+ protocol: 'v2ray',
86
+ onProgress: (stage, detail) => log('info', ` [${stage}] ${detail}`),
87
+ });
88
+
89
+ log('ok', `Connected via ${vpn.protocol} to ${vpn.nodeAddress}`);
90
+ if (vpn.ip) log('ok', `Public IP: ${vpn.ip}`);
91
+ return vpn;
92
+ } catch (err) {
93
+ log('err', `Attempt ${attempt} failed: ${err.message}`);
94
+
95
+ if (attempt < MAX_RETRIES) {
96
+ const delay = RETRY_DELAY_MS * attempt;
97
+ log('info', `Retrying in ${delay / 1000}s...`);
98
+ await sleep(delay);
99
+ }
100
+ }
101
+ }
102
+
103
+ log('err', `Failed after ${MAX_RETRIES} attempts`);
104
+ process.exit(1);
105
+ }
106
+
107
+ // ─── Step 4: Perform Work ───────────────────────────────────────────────────
108
+
109
+ async function doWork(cycleNum) {
110
+ // Simulated work — replace with your actual task
111
+ // (web scraping, API calls, data collection, etc.)
112
+ log('info', `Work cycle ${cycleNum}: making request through VPN tunnel...`);
113
+
114
+ try {
115
+ // Use dynamic import so this example works without axios installed
116
+ const { default: axios } = await import('axios');
117
+ const res = await axios.get('https://api.ipify.org?format=json', {
118
+ timeout: 15000,
119
+ adapter: 'http',
120
+ });
121
+ log('ok', `Work cycle ${cycleNum}: response from IP ${res.data.ip}`);
122
+ } catch (err) {
123
+ log('warn', `Work cycle ${cycleNum}: request failed — ${err.message}`);
124
+ return false;
125
+ }
126
+
127
+ return true;
128
+ }
129
+
130
+ // ─── Step 5: Health Monitor ─────────────────────────────────────────────────
131
+
132
+ function startHealthMonitor(mnemonic) {
133
+ const intervalId = setInterval(async () => {
134
+ if (!isVpnActive()) {
135
+ log('warn', 'VPN connection lost — reconnecting...');
136
+ clearInterval(intervalId);
137
+
138
+ try {
139
+ await connectWithRetry(mnemonic);
140
+ startHealthMonitor(mnemonic);
141
+ } catch (err) {
142
+ log('err', `Auto-reconnect failed: ${err.message}`);
143
+ }
144
+ } else {
145
+ const s = status();
146
+ log('info', `Health check: connected, uptime ${s.uptimeFormatted || 'unknown'}`);
147
+ }
148
+ }, HEALTH_CHECK_INTERVAL_MS);
149
+
150
+ return intervalId;
151
+ }
152
+
153
+ // ─── Main Agent Loop ────────────────────────────────────────────────────────
154
+
155
+ async function main() {
156
+ log('info', 'Autonomous agent starting...');
157
+ console.log('');
158
+
159
+ // 1. Wallet
160
+ const mnemonic = await ensureWallet();
161
+
162
+ // 2. Funds
163
+ await checkFunds(mnemonic);
164
+ console.log('');
165
+
166
+ // 3. Connect
167
+ await connectWithRetry(mnemonic);
168
+ console.log('');
169
+
170
+ // 4. Health monitor
171
+ const monitorId = startHealthMonitor(mnemonic);
172
+
173
+ // 5. Work loop
174
+ let failures = 0;
175
+ for (let i = 1; i <= WORK_CYCLES; i++) {
176
+ const success = await doWork(i);
177
+ if (!success) failures++;
178
+
179
+ // If too many consecutive failures, reconnect
180
+ if (failures >= 2) {
181
+ log('warn', 'Multiple work failures — reconnecting...');
182
+ await disconnect().catch(() => {});
183
+ await connectWithRetry(mnemonic);
184
+ failures = 0;
185
+ }
186
+
187
+ // Pause between work cycles
188
+ if (i < WORK_CYCLES) {
189
+ await sleep(3000);
190
+ }
191
+ }
192
+
193
+ // 6. Cleanup
194
+ console.log('');
195
+ log('info', 'Work complete. Disconnecting...');
196
+ clearInterval(monitorId);
197
+
198
+ try {
199
+ await disconnect();
200
+ log('ok', 'Disconnected. Agent finished.');
201
+ } catch (err) {
202
+ log('warn', `Disconnect error: ${err.message}`);
203
+ }
204
+
205
+ process.exit(0);
206
+ }
207
+
208
+ // ─── Graceful Shutdown ──────────────────────────────────────────────────────
209
+
210
+ process.on('SIGINT', async () => {
211
+ console.log('');
212
+ log('info', 'Interrupted — shutting down...');
213
+ try { await disconnect(); } catch { /* best effort */ }
214
+ process.exit(0);
215
+ });
216
+
217
+ main().catch((err) => {
218
+ log('err', `Fatal: ${err.message}`);
219
+ process.exit(1);
220
+ });
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Multi-Region Rotation
3
+ *
4
+ * Connect to VPN nodes in different countries sequentially.
5
+ * Each hop: connect -> perform work -> disconnect -> next country.
6
+ *
7
+ * Use cases:
8
+ * - Data collection from different geographic perspectives
9
+ * - Verifying geo-restricted content availability
10
+ * - Testing regional API responses
11
+ * - Distributing requests across exit regions
12
+ *
13
+ * Run: node examples/multi-region.mjs
14
+ */
15
+
16
+ import 'dotenv/config';
17
+ import { connect, disconnect, isVpnActive } from '../index.js';
18
+
19
+ // ─── Configuration ──────────────────────────────────────────────────────────
20
+
21
+ const REGIONS = [
22
+ { country: 'DE', label: 'Germany' },
23
+ { country: 'JP', label: 'Japan' },
24
+ { country: 'US', label: 'United States' },
25
+ ];
26
+
27
+ const SETTLE_DELAY_MS = 3000;
28
+
29
+ // ─── Helpers ────────────────────────────────────────────────────────────────
30
+
31
+ function log(level, msg) {
32
+ const ts = new Date().toISOString().slice(11, 19);
33
+ const prefix = { info: '\x1b[36m[INFO]\x1b[0m', warn: '\x1b[33m[WARN]\x1b[0m', err: '\x1b[31m[ERR]\x1b[0m', ok: '\x1b[32m[ OK ]\x1b[0m' };
34
+ console.log(`${ts} ${prefix[level] || prefix.info} ${msg}`);
35
+ }
36
+
37
+ function sleep(ms) {
38
+ return new Promise((resolve) => setTimeout(resolve, ms));
39
+ }
40
+
41
+ // ─── Work Function ──────────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * Perform work through the VPN tunnel.
45
+ * Replace this with your actual task (scraping, API calls, etc.).
46
+ */
47
+ async function doWork(region) {
48
+ log('info', `[${region.label}] Performing work through tunnel...`);
49
+
50
+ try {
51
+ const { default: axios } = await import('axios');
52
+
53
+ // Verify we have a new IP
54
+ const ipRes = await axios.get('https://api.ipify.org?format=json', {
55
+ timeout: 15000,
56
+ adapter: 'http',
57
+ });
58
+ log('ok', `[${region.label}] Exit IP: ${ipRes.data.ip}`);
59
+
60
+ // Example: fetch region-specific data
61
+ const geoRes = await axios.get(`https://ipapi.co/${ipRes.data.ip}/json/`, {
62
+ timeout: 15000,
63
+ adapter: 'http',
64
+ });
65
+ const geo = geoRes.data;
66
+ log('ok', `[${region.label}] Geo: ${geo.country_name || '?'}, ${geo.city || '?'}, ${geo.org || '?'}`);
67
+
68
+ return {
69
+ region: region.label,
70
+ ip: ipRes.data.ip,
71
+ country: geo.country_name || null,
72
+ city: geo.city || null,
73
+ org: geo.org || null,
74
+ };
75
+ } catch (err) {
76
+ log('warn', `[${region.label}] Work failed: ${err.message}`);
77
+ return { region: region.label, ip: null, error: err.message };
78
+ }
79
+ }
80
+
81
+ // ─── Main Loop ──────────────────────────────────────────────────────────────
82
+
83
+ async function main() {
84
+ const mnemonic = process.env.MNEMONIC;
85
+ if (!mnemonic) {
86
+ log('err', 'No MNEMONIC in .env file. Run: sentinel-ai wallet create');
87
+ process.exit(1);
88
+ }
89
+
90
+ log('info', `Multi-region rotation: ${REGIONS.map(r => r.label).join(' -> ')}`);
91
+ console.log('');
92
+
93
+ const results = [];
94
+
95
+ for (let i = 0; i < REGIONS.length; i++) {
96
+ const region = REGIONS[i];
97
+ const step = `[${i + 1}/${REGIONS.length}]`;
98
+
99
+ // ── Connect ──
100
+ log('info', `${step} Connecting to ${region.label} (${region.country})...`);
101
+
102
+ try {
103
+ const vpn = await connect({
104
+ mnemonic,
105
+ country: region.country,
106
+ protocol: 'v2ray',
107
+ onProgress: (stage, detail) => log('info', ` [${stage}] ${detail}`),
108
+ });
109
+
110
+ log('ok', `${step} Connected via ${vpn.protocol}, IP: ${vpn.ip || 'checking...'}`);
111
+
112
+ // Let the tunnel settle
113
+ await sleep(SETTLE_DELAY_MS);
114
+
115
+ // ── Work ──
116
+ const result = await doWork(region);
117
+ results.push(result);
118
+
119
+ } catch (err) {
120
+ log('err', `${step} Failed to connect to ${region.label}: ${err.message}`);
121
+ results.push({ region: region.label, ip: null, error: err.message });
122
+ }
123
+
124
+ // ── Disconnect ──
125
+ if (isVpnActive()) {
126
+ log('info', `${step} Disconnecting from ${region.label}...`);
127
+ try {
128
+ await disconnect();
129
+ log('ok', `${step} Disconnected`);
130
+ } catch (err) {
131
+ log('warn', `${step} Disconnect error: ${err.message}`);
132
+ }
133
+ }
134
+
135
+ // Pause between regions (let chain state settle)
136
+ if (i < REGIONS.length - 1) {
137
+ log('info', 'Waiting before next region...');
138
+ await sleep(SETTLE_DELAY_MS);
139
+ }
140
+
141
+ console.log('');
142
+ }
143
+
144
+ // ─── Summary ────────────────────────────────────────────────────────────
145
+
146
+ console.log('\x1b[1m Region Rotation Summary\x1b[0m');
147
+ console.log(` ${'─'.repeat(60)}`);
148
+
149
+ for (const r of results) {
150
+ if (r.error) {
151
+ console.log(` \x1b[31mx\x1b[0m ${r.region.padEnd(20)} Failed: ${r.error}`);
152
+ } else {
153
+ console.log(` \x1b[32m+\x1b[0m ${r.region.padEnd(20)} IP: ${r.ip} (${r.country || '?'}, ${r.city || '?'})`);
154
+ }
155
+ }
156
+
157
+ console.log('');
158
+ const ok = results.filter(r => !r.error).length;
159
+ log('info', `Done. ${ok}/${results.length} regions connected successfully.`);
160
+ }
161
+
162
+ // ─── Graceful Shutdown ──────────────────────────────────────────────────────
163
+
164
+ process.on('SIGINT', async () => {
165
+ console.log('');
166
+ log('info', 'Interrupted — disconnecting...');
167
+ try { await disconnect(); } catch { /* best effort */ }
168
+ process.exit(0);
169
+ });
170
+
171
+ main().catch((err) => {
172
+ log('err', `Fatal: ${err.message}`);
173
+ process.exit(1);
174
+ });
@@ -0,0 +1,31 @@
1
+ /**
2
+ * One-Shot VPN Connection
3
+ *
4
+ * The absolute minimum code to connect to Sentinel dVPN.
5
+ * 10 lines. That's it.
6
+ *
7
+ * Prerequisites:
8
+ * 1. .env file with MNEMONIC=<your 24-word phrase>
9
+ * 2. Funded wallet (P2P tokens)
10
+ * 3. V2Ray or WireGuard installed (run: sentinel-ai setup)
11
+ *
12
+ * Run: node examples/one-shot.mjs
13
+ */
14
+
15
+ import 'dotenv/config';
16
+ import { connect, disconnect } from '../index.js';
17
+
18
+ const vpn = await connect({
19
+ mnemonic: process.env.MNEMONIC,
20
+ onProgress: (step, detail) => console.log(`[${step}] ${detail}`),
21
+ });
22
+
23
+ console.log(`Connected! Protocol: ${vpn.protocol}, IP: ${vpn.ip}`);
24
+ console.log('Press Ctrl+C to disconnect.');
25
+
26
+ process.on('SIGINT', async () => {
27
+ await disconnect();
28
+ process.exit(0);
29
+ });
30
+
31
+ await new Promise(() => {});
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Sentinel AI Path — Decentralized VPN for AI Agents
3
+ *
4
+ * Complete agent flow:
5
+ *
6
+ * 1. Setup: await setup() → { os, node, v2ray, wireguard, admin }
7
+ * 2. Wallet: await createWallet() → { mnemonic, address }
8
+ * 3. Fund: await getBalance(m) → { p2p, funded }
9
+ * 4. Discover: await discoverNodes() → [{ address, country, protocol, price, score }]
10
+ * 5. Estimate: await estimateCost(opts) → { perGb, perHour, forBudget }
11
+ * 6. Connect: await connect(opts) → { sessionId, protocol, ip, socksPort }
12
+ * 7. Verify: await verify() → { connected, ip, latency }
13
+ * 8. Monitor: onEvent(callback) → unsubscribe function
14
+ * 9. Disconnect: await disconnect() → { disconnected: true }
15
+ */
16
+
17
+ // ─── Phase 1: Setup & Environment ────────────────────────────────────────────
18
+
19
+ export { setup, getEnvironment } from './environment.js';
20
+
21
+ // ─── Phase 2-3: Wallet & Funding ─────────────────────────────────────────────
22
+
23
+ export { createWallet, importWallet, getBalance } from './wallet.js';
24
+
25
+ // ─── Phase 4: Node Discovery ─────────────────────────────────────────────────
26
+
27
+ export { discoverNodes, getNodeInfo, getNetworkStats } from './discover.js';
28
+
29
+ // ─── Phase 5: Cost Estimation ────────────────────────────────────────────────
30
+
31
+ export { estimateCost, PRICING } from './pricing.js';
32
+
33
+ // ─── Phase 5.5: Decision Engine ───────────────────────────────────────────────
34
+
35
+ export { recommend } from './recommend.js';
36
+
37
+ // ─── Phase 6-7: Connect, Verify, Monitor ─────────────────────────────────────
38
+
39
+ export { connect, disconnect, status, isVpnActive, verify, verifySplitTunnel, onEvent } from './connect.js';
40
+
41
+ // ─── Error Handling ─────────────────────────────────────────────────────────
42
+
43
+ export { AiPathError, AiPathErrorCodes } from './errors.js';
44
+
45
+ // ─── SDK Internals (advanced — for agents that need typed access) ───────────
46
+
47
+ export {
48
+ // v1.5.0: Typed event parsers (structured TX event handling)
49
+ extractSessionIdTyped,
50
+ NodeEventCreateSession,
51
+ SubscriptionEventCreateSession,
52
+ searchEvent,
53
+ // v1.5.0: TYPE_URLS constants (canonical Sentinel message type URLs)
54
+ TYPE_URLS,
55
+ // v1.5.0: RPC queries (protobuf, ~10x faster than LCD)
56
+ createRpcQueryClientWithFallback,
57
+ rpcQueryNodes,
58
+ rpcQueryBalance,
59
+ rpcQueryNode,
60
+ } from '../index.js';
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Sentinel AI Path — Cost Estimation & Budget Planning
3
+ *
4
+ * An AI agent uses these to estimate costs before committing tokens.
5
+ */
6
+
7
+ import {
8
+ estimateSessionCost,
9
+ estimateSessionPrice,
10
+ formatP2P,
11
+ PRICING_REFERENCE,
12
+ DENOM,
13
+ } from '../index.js';
14
+
15
+ // ─── Constants ───────────────────────────────────────────────────────────────
16
+
17
+ /**
18
+ * Reference pricing from the SDK. Based on network-wide observations.
19
+ *
20
+ * @type {{
21
+ * typicalPerGb: { udvpn: number, p2p: string },
22
+ * minBalance: { udvpn: number, p2p: string },
23
+ * gasCost: { udvpn: number, p2p: string },
24
+ * denom: string,
25
+ * }}
26
+ */
27
+ /**
28
+ * Reference pricing sampled from chain data (2026-03-26, 1030 nodes).
29
+ * THESE ARE APPROXIMATE — node operators set their own prices and can change
30
+ * them at any time. Use estimateCost({ nodeAddress }) for live per-node pricing.
31
+ * Median: ~40 P2P/GB (40152030 udvpn at sample time)
32
+ * Cheapest: ~0.68 P2P/GB (680000 udvpn at sample time)
33
+ */
34
+ export const PRICING = {
35
+ medianPerGb: {
36
+ udvpn: 40152030,
37
+ p2p: formatP2P(40152030),
38
+ },
39
+ cheapestPerGb: {
40
+ udvpn: 680000,
41
+ p2p: formatP2P(680000),
42
+ },
43
+ typicalPerGb: {
44
+ udvpn: 40152030,
45
+ p2p: formatP2P(40152030),
46
+ },
47
+ minBalance: {
48
+ udvpn: 50000000, // 50 P2P — enough for 1 GB on median node + gas
49
+ p2p: formatP2P(50000000),
50
+ },
51
+ gasCost: {
52
+ udvpn: 40000,
53
+ p2p: formatP2P(40000),
54
+ },
55
+ denom: DENOM || 'udvpn',
56
+ };
57
+
58
+ // ─── estimateCost() ──────────────────────────────────────────────────────────
59
+
60
+ /**
61
+ * Estimate connection cost before committing tokens.
62
+ *
63
+ * @param {object} opts
64
+ * @param {number} [opts.gigabytes=1] - Planned data usage in GB
65
+ * @param {number} [opts.hours] - Planned session duration in hours (alternative to GB)
66
+ * @param {number} [opts.budget] - Available budget in udvpn — calculates how much you can get
67
+ * @param {string} [opts.nodeAddress] - Specific node for exact pricing (queries chain)
68
+ * @returns {Promise<{
69
+ * perGb: { udvpn: number, p2p: string },
70
+ * total: { udvpn: number, p2p: string },
71
+ * gas: { udvpn: number, p2p: string },
72
+ * grandTotal: { udvpn: number, p2p: string },
73
+ * forBudget?: { gigabytes: number, hours: number|null },
74
+ * mode: 'per-gb'|'hourly'|'estimate',
75
+ * }>}
76
+ */
77
+ export async function estimateCost(opts = {}) {
78
+ if (opts && typeof opts !== 'object') {
79
+ throw new Error('estimateCost(): opts must be an object or undefined');
80
+ }
81
+ const gb = opts.gigabytes || 1;
82
+ const gasCost = 40000; // ~0.04 P2P per TX
83
+
84
+ // If specific node given, get exact price
85
+ if (opts.nodeAddress) {
86
+ try {
87
+ const price = await estimateSessionPrice(opts.nodeAddress, gb);
88
+ const total = price.udvpn || price.amount || 0;
89
+ const grandTotal = total + gasCost;
90
+
91
+ const result = {
92
+ perGb: { udvpn: Math.round(total / gb), p2p: formatP2P(Math.round(total / gb)) },
93
+ total: { udvpn: total, p2p: formatP2P(total) },
94
+ gas: { udvpn: gasCost, p2p: formatP2P(gasCost) },
95
+ grandTotal: { udvpn: grandTotal, p2p: formatP2P(grandTotal) },
96
+ mode: opts.hours ? 'hourly' : 'per-gb',
97
+ };
98
+
99
+ if (opts.budget) {
100
+ const usable = opts.budget - gasCost;
101
+ const pricePerGb = Math.round(total / gb);
102
+ result.forBudget = {
103
+ gigabytes: pricePerGb > 0 ? Math.floor(usable / pricePerGb) : 0,
104
+ hours: null,
105
+ };
106
+ }
107
+
108
+ return result;
109
+ } catch {
110
+ // Fall through to estimate
111
+ }
112
+ }
113
+
114
+ // Network-wide estimate based on real chain pricing (median across 1030 nodes)
115
+ const typicalPerGb = PRICING.typicalPerGb.udvpn;
116
+ const total = typicalPerGb * gb;
117
+ const grandTotal = total + gasCost;
118
+
119
+ const result = {
120
+ perGb: { udvpn: typicalPerGb, p2p: formatP2P(typicalPerGb) },
121
+ total: { udvpn: total, p2p: formatP2P(total) },
122
+ gas: { udvpn: gasCost, p2p: formatP2P(gasCost) },
123
+ grandTotal: { udvpn: grandTotal, p2p: formatP2P(grandTotal) },
124
+ mode: 'estimate',
125
+ };
126
+
127
+ if (opts.budget) {
128
+ const usable = opts.budget - gasCost;
129
+ result.forBudget = {
130
+ gigabytes: typicalPerGb > 0 ? Math.floor(usable / typicalPerGb) : 0,
131
+ hours: null,
132
+ };
133
+ }
134
+
135
+ return result;
136
+ }