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,425 @@
1
+ /**
2
+ * Sentinel SDK — Connection Types
3
+ *
4
+ * Types for connecting, disconnecting, and managing VPN connections.
5
+ * Covers: direct connect, plan connect, auto connect, reconnect,
6
+ * circuit breaker, kill switch, and connection state.
7
+ */
8
+
9
+ import type { EventEmitter } from 'events';
10
+ import type { ErrorCode, SentinelError } from './errors.js';
11
+
12
+ // ─── Connect Options ───────────────────────────────────────────────────────
13
+
14
+ /**
15
+ * Options for connectDirect() / connect().
16
+ * Only `mnemonic` and `nodeAddress` are required for basic usage.
17
+ */
18
+ export interface ConnectOptions {
19
+ /** BIP39 mnemonic phrase (12 or 24 words) */
20
+ mnemonic: string;
21
+ /** sentnode1... address of the node to connect to */
22
+ nodeAddress: string;
23
+ /** Chain RPC URL (default: cascading fallback across 5 endpoints) */
24
+ rpcUrl?: string;
25
+ /** Chain LCD URL (default: cascading fallback across 4 endpoints) */
26
+ lcdUrl?: string;
27
+ /** Bandwidth to purchase in GB (default: 1). Ignored when hours is set. */
28
+ gigabytes?: number;
29
+ /** Hours to purchase (e.g. 1, 4, 8, 24). When set, uses hourly pricing instead of per-GB. */
30
+ hours?: number;
31
+ /** Prefer hourly sessions when cheaper than per-GB (default: false). Ignored when hours is explicitly set. */
32
+ preferHourly?: boolean;
33
+ /** Path to v2ray binary (auto-detected if missing) */
34
+ v2rayExePath?: string;
35
+ /** Route ALL traffic through VPN (default: true). Set false for split tunnel/dev mode. */
36
+ fullTunnel?: boolean;
37
+ /** Specific IPs to route through VPN (overrides fullTunnel) */
38
+ splitIPs?: string[];
39
+ /** Set system SOCKS proxy (default: false -- explicit opt-in) */
40
+ systemProxy?: boolean;
41
+ /** Always pay for a new session, skip findExistingSession (default: false) */
42
+ forceNewSession?: boolean;
43
+ /**
44
+ * Progress callback. Called at each major step of connection.
45
+ * @param step - Step name (e.g. 'wallet', 'balance', 'subscribe', 'handshake', 'tunnel')
46
+ * @param detail - Human-readable description
47
+ * @param entry - Optional structured entry with extra fields
48
+ */
49
+ onProgress?: (step: string, detail: string, entry?: Record<string, unknown>) => void;
50
+ /** Logger function (default: console.log). Set to (() => {}) to suppress. */
51
+ log?: (msg: string) => void;
52
+ /** Override default timeouts (ms) for different operations */
53
+ timeouts?: ConnectionTimeouts;
54
+ /** AbortSignal for cancelling in-progress connections */
55
+ signal?: AbortSignal;
56
+ /** TLS trust mode: 'tofu' (default, pin on first use) | 'none' (insecure, for testing) */
57
+ tlsTrust?: 'tofu' | 'none';
58
+ /** If false, throw instead of auto-disconnecting when already connected (default: true) */
59
+ allowReconnect?: boolean;
60
+ /**
61
+ * Dry-run mode: runs wallet, LCD, node status checks but skips TX broadcast,
62
+ * handshake, and tunnel. For unfunded wallets / UI testing.
63
+ */
64
+ dryRun?: boolean;
65
+ /** Enable kill switch -- blocks all traffic if tunnel drops (default: false) */
66
+ killSwitch?: boolean;
67
+ /**
68
+ * DNS servers for WireGuard tunnel.
69
+ * - Preset name: 'handshake' (default), 'google', 'cloudflare'
70
+ * - Custom array: ['1.2.3.4', '5.6.7.8']
71
+ * Handshake DNS (103.196.38.38/39) is default -- decentralized, censorship-resistant.
72
+ */
73
+ dns?: 'handshake' | 'google' | 'cloudflare' | string[];
74
+ }
75
+
76
+ /** Timeout overrides for connection operations (all values in ms). */
77
+ export interface ConnectionTimeouts {
78
+ /** V2Ray SOCKS5 port readiness wait (default: 10000) */
79
+ v2rayReady?: number;
80
+ /** Handshake HTTP request timeout (default: 90000). Overloaded nodes need 60-90s. */
81
+ handshake?: number;
82
+ /** LCD query timeout (default: 15000) */
83
+ lcdQuery?: number;
84
+ /** Node status check timeout (default: 12000) */
85
+ nodeStatus?: number;
86
+ }
87
+
88
+ /**
89
+ * Options for connectViaPlan().
90
+ * Extends ConnectOptions but replaces gigabytes/forceNewSession with planId.
91
+ */
92
+ export interface ConnectViaPlanOptions extends Omit<ConnectOptions, 'gigabytes' | 'forceNewSession'> {
93
+ /** Plan ID to subscribe to */
94
+ planId: number | string | bigint;
95
+ /**
96
+ * Plan owner's address (sent1...) to use as fee granter.
97
+ * When set, the TX includes fee.granter so the plan operator pays gas.
98
+ * If the grant doesn't exist on-chain, falls back to user-paid gas.
99
+ */
100
+ feeGranter?: string;
101
+ }
102
+
103
+ /**
104
+ * Options for connectAuto().
105
+ * Extends ConnectOptions with filtering and retry configuration.
106
+ * nodeAddress is NOT required -- auto-connect picks the best node.
107
+ */
108
+ export interface ConnectAutoOptions extends Omit<ConnectOptions, 'nodeAddress'> {
109
+ /** sentnode1... address -- optional, overrides auto-selection */
110
+ nodeAddress?: string;
111
+ /** Maximum connection attempts across different nodes (default: 3) */
112
+ maxAttempts?: number;
113
+ /** Preferred service type filter */
114
+ serviceType?: 'wireguard' | 'v2ray';
115
+ /** Only try nodes in these countries (ISO codes, e.g. ['US', 'DE']) */
116
+ countries?: string[];
117
+ /** Skip nodes in these countries */
118
+ excludeCountries?: string[];
119
+ /** Max price in P2P per GB -- nodes above this are skipped */
120
+ maxPriceDvpn?: number;
121
+ /** Minimum quality score (0-100) for node selection */
122
+ minScore?: number;
123
+ /** Per-call circuit breaker config override */
124
+ circuitBreaker?: CircuitBreakerConfig;
125
+ /** Progress callback during node scan (before connection attempt) */
126
+ onNodeProbed?: (progress: { total: number; probed: number; online: number }) => void;
127
+ /** Restrict auto-connect to these specific node addresses (sentnode1...) */
128
+ nodePool?: string[];
129
+ }
130
+
131
+ // ─── Connect Results ───────────────────────────────────────────────────────
132
+
133
+ /** Result from connect(), connectDirect(), connectViaPlan(), connectAuto(). */
134
+ export interface ConnectResult {
135
+ /** Session ID as string (safe for JSON.stringify -- no BigInt serialization errors) */
136
+ sessionId: string;
137
+ /** Protocol used for this connection */
138
+ serviceType: 'wireguard' | 'v2ray';
139
+ /** sentnode1... address of the connected node */
140
+ nodeAddress: string;
141
+ /** SOCKS5 proxy port (V2Ray only). Use for HTTP requests through the tunnel. */
142
+ socksPort?: number;
143
+ /** WireGuard tunnel name (WireGuard only). Used for tunnel management. */
144
+ wgTunnelName?: string;
145
+ /** WireGuard config file path (WireGuard only) */
146
+ confPath?: string;
147
+ /** V2Ray process PID (V2Ray only). Can be used to monitor the process. */
148
+ v2rayPid?: number;
149
+ /** Whether system SOCKS proxy was configured */
150
+ systemProxySet?: boolean;
151
+ /** Disconnect and clean up all resources. Call this when done. */
152
+ cleanup: () => Promise<void>;
153
+ /** Present and true when dryRun was used -- no actual tunnel was created */
154
+ dryRun?: boolean;
155
+ /** Wallet address (dry-run only) */
156
+ walletAddress?: string;
157
+ /** Node moniker/name (dry-run only) */
158
+ nodeMoniker?: string;
159
+ /** Node location (dry-run only) */
160
+ nodeLocation?: { city: string; country: string };
161
+ /** RPC endpoint used (dry-run only) */
162
+ rpcUsed?: string;
163
+ /** LCD endpoint used (dry-run only) */
164
+ lcdUsed?: string;
165
+ }
166
+
167
+ /** Result from disconnect(). */
168
+ export interface DisconnectResult {
169
+ /** Whether a tunnel was actually cleaned up */
170
+ disconnected: boolean;
171
+ }
172
+
173
+ // ─── Connection Status ─────────────────────────────────────────────────────
174
+
175
+ /** Current connection status from getStatus(). null if not connected. */
176
+ export interface ConnectionStatus {
177
+ /** Whether a VPN tunnel is currently active */
178
+ connected: boolean;
179
+ /** Active session ID */
180
+ sessionId: bigint;
181
+ /** Protocol in use */
182
+ serviceType: 'wireguard' | 'v2ray';
183
+ /** Connected node address */
184
+ nodeAddress: string;
185
+ /** Timestamp when connection was established (Date.now()) */
186
+ connectedAt: number;
187
+ /** Connection uptime in milliseconds */
188
+ uptimeMs: number;
189
+ /** Human-readable uptime (e.g. "2h 15m 30s") */
190
+ uptimeFormatted: string;
191
+ /** SOCKS5 port (V2Ray only) */
192
+ socksPort?: number;
193
+ /** Health checks for tunnel/proxy liveness */
194
+ healthChecks: {
195
+ /** Whether the tunnel interface/process is alive */
196
+ tunnelActive: boolean;
197
+ /** Whether the SOCKS5 proxy port is listening (V2Ray only) */
198
+ proxyListening: boolean;
199
+ /** Whether system proxy settings are valid */
200
+ systemProxyValid: boolean;
201
+ };
202
+ }
203
+
204
+ // ─── Connection Verification ───────────────────────────────────────────────
205
+
206
+ /** Result from verifyConnection(). */
207
+ export interface VerifyResult {
208
+ /** Whether the VPN tunnel is working (IP changed from original) */
209
+ working: boolean;
210
+ /** Public IP address through the VPN tunnel (null if check failed) */
211
+ vpnIp: string | null;
212
+ /** Error message if verification failed */
213
+ error?: string;
214
+ }
215
+
216
+ // ─── Auto Reconnect ────────────────────────────────────────────────────────
217
+
218
+ /** Options for autoReconnect(). Returns a handle with stop(). */
219
+ export interface AutoReconnectOptions extends ConnectOptions {
220
+ /** How often to check connection health in ms (default: 5000) */
221
+ pollIntervalMs?: number;
222
+ /** Max reconnection attempts before giving up (default: 5) */
223
+ maxRetries?: number;
224
+ /** Backoff delays in ms between retries (default: [1000, 2000, 5000, 10000, 30000]) */
225
+ backoffMs?: number[];
226
+ /** Called when a reconnection attempt starts */
227
+ onReconnecting?: (attempt: number) => void;
228
+ /** Called when reconnection succeeds */
229
+ onReconnected?: (result: ConnectResult) => void;
230
+ /** Called when all retries exhausted */
231
+ onGaveUp?: (errors: Error[]) => void;
232
+ }
233
+
234
+ /** Handle returned by autoReconnect(). */
235
+ export interface AutoReconnectHandle {
236
+ /** Stop monitoring and reconnecting */
237
+ stop: () => void;
238
+ }
239
+
240
+ // ─── Circuit Breaker ───────────────────────────────────────────────────────
241
+
242
+ /** Configuration for the per-node circuit breaker. */
243
+ export interface CircuitBreakerConfig {
244
+ /**
245
+ * Number of consecutive failures before a node is "open" (skipped).
246
+ * Default: 3
247
+ */
248
+ threshold?: number;
249
+ /**
250
+ * Time in ms before a node's failure count resets (half-open).
251
+ * Default: 300000 (5 minutes)
252
+ */
253
+ ttlMs?: number;
254
+ }
255
+
256
+ /** Status of a circuit breaker for a single node. */
257
+ export interface CircuitBreakerStatus {
258
+ /** Number of consecutive failures */
259
+ count: number;
260
+ /** Timestamp of last failure */
261
+ lastFail: number;
262
+ /** Whether the circuit is open (node will be skipped) */
263
+ isOpen: boolean;
264
+ }
265
+
266
+ // ─── Connection Metrics ────────────────────────────────────────────────────
267
+
268
+ /** Connection metrics for observability (per node). */
269
+ export interface ConnectionMetric {
270
+ /** Total connection attempts */
271
+ attempts: number;
272
+ /** Successful connections */
273
+ successes: number;
274
+ /** Failed connections */
275
+ failures: number;
276
+ /** Success rate (0-1) */
277
+ successRate: number;
278
+ /** Average connection time in ms */
279
+ avgTimeMs: number;
280
+ /** Total connection time in ms */
281
+ totalTimeMs: number;
282
+ /** Timestamp of last attempt */
283
+ lastAttempt: number;
284
+ }
285
+
286
+ // ─── Connection State ──────────────────────────────────────────────────────
287
+
288
+ /**
289
+ * Per-instance tunnel state for SentinelClient.
290
+ * Each SentinelClient instance has its own ConnectionState.
291
+ * LIMITATION: WireGuard and V2Ray are OS-level singletons --
292
+ * only one active tunnel at a time system-wide.
293
+ */
294
+ export class ConnectionState {
295
+ /** Active V2Ray process reference (null if not running) */
296
+ v2rayProc: unknown;
297
+ /** Active WireGuard tunnel name (null if not running) */
298
+ wgTunnel: string | null;
299
+ /** Current connection info (null if disconnected) */
300
+ connection: ConnectResult | null;
301
+ /** Whether system SOCKS proxy was set */
302
+ systemProxy: boolean;
303
+ /** Saved proxy state for restoration on disconnect */
304
+ savedProxyState: unknown;
305
+ /** @internal Stored mnemonic for session-end TX on disconnect. Cleared after use. */
306
+ _mnemonic: string | null;
307
+ /** Whether a tunnel is currently active */
308
+ readonly isConnected: boolean;
309
+ /** Remove this state from the global cleanup registry */
310
+ destroy(): void;
311
+ }
312
+
313
+ // ─── SDK Events ────────────────────────────────────────────────────────────
314
+
315
+ /** Progress entry emitted during connection. */
316
+ export interface ProgressEntry {
317
+ /** Step/event name (e.g. 'wallet_created', 'handshake_started') */
318
+ event: string;
319
+ /** Human-readable detail string */
320
+ detail: string;
321
+ /** Timestamp (Date.now()) */
322
+ ts: number;
323
+ /** Additional structured fields vary by event */
324
+ [key: string]: unknown;
325
+ }
326
+
327
+ /** SDK lifecycle event emitter. Subscribe without polling. */
328
+ export interface SDKEvents extends EventEmitter {
329
+ on(event: 'connecting', listener: (data: { nodeAddress: string }) => void): this;
330
+ on(event: 'connected', listener: (data: { sessionId: bigint; serviceType: 'wireguard' | 'v2ray'; nodeAddress: string }) => void): this;
331
+ on(event: 'disconnected', listener: (data: { nodeAddress: string; serviceType: string; reason: string }) => void): this;
332
+ on(event: 'error', listener: (err: SentinelError | Error) => void): this;
333
+ on(event: 'progress', listener: (entry: ProgressEntry) => void): this;
334
+ emit(event: 'connecting', data: { nodeAddress: string }): boolean;
335
+ emit(event: 'connected', data: { sessionId: bigint; serviceType: string; nodeAddress: string }): boolean;
336
+ emit(event: 'disconnected', data: { nodeAddress: string; serviceType: string; reason: string }): boolean;
337
+ emit(event: 'error', err: SentinelError | Error): boolean;
338
+ emit(event: 'progress', entry: ProgressEntry): boolean;
339
+ }
340
+
341
+ // ─── Dependency Check ──────────────────────────────────────────────────────
342
+
343
+ /** Result from verifyDependencies(). Run at app startup. */
344
+ export interface DependencyCheck {
345
+ /** Overall pass: true if at least one protocol (WG or V2Ray) is available */
346
+ ok: boolean;
347
+ v2ray: {
348
+ /** Whether v2ray binary was found */
349
+ available: boolean;
350
+ /** Path to v2ray binary (null if not found) */
351
+ path: string | null;
352
+ /** Detected v2ray version string (null if not found) */
353
+ version: string | null;
354
+ /** Error message if detection failed */
355
+ error: string | null;
356
+ };
357
+ wireguard: {
358
+ /** Whether WireGuard tools are installed */
359
+ available: boolean;
360
+ /** Path to wireguard.exe / wg-quick (null if not found) */
361
+ path: string | null;
362
+ /** Whether process is running as admin/root (required for WG) */
363
+ isAdmin: boolean;
364
+ /** Error message if detection failed */
365
+ error: string | null;
366
+ };
367
+ /** Current OS platform */
368
+ platform: string;
369
+ /** CPU architecture */
370
+ arch: string;
371
+ /** Node.js version */
372
+ nodeVersion: string;
373
+ /** Summary of all errors found */
374
+ errors: string[];
375
+ }
376
+
377
+ // ─── Preflight Check ───────────────────────────────────────────────────────
378
+
379
+ /** Single issue found during preflight check. */
380
+ export interface PreflightIssue {
381
+ /** Severity: error = blocks connection, warning = may cause problems, info = informational */
382
+ severity: 'error' | 'warning' | 'info';
383
+ /** Which component has the issue */
384
+ component: 'wireguard' | 'v2ray' | 'protocols' | 'system';
385
+ /** Short description of the issue */
386
+ message: string;
387
+ /** Detailed explanation */
388
+ detail: string;
389
+ /** Suggested action to fix */
390
+ action: string;
391
+ /** Whether the SDK can auto-fix this issue */
392
+ autoFix: boolean;
393
+ }
394
+
395
+ /** Full preflight report from preflight(). */
396
+ export interface PreflightReport {
397
+ /** Overall pass: true if at least one protocol is ready */
398
+ ok: boolean;
399
+ /** Per-protocol readiness */
400
+ ready: {
401
+ wireguard: boolean;
402
+ v2ray: boolean;
403
+ /** True if at least WG or V2Ray is available */
404
+ anyProtocol: boolean;
405
+ };
406
+ /** All detected issues */
407
+ issues: PreflightIssue[];
408
+ /** One-line summary suitable for UI display */
409
+ summary: string;
410
+ }
411
+
412
+ // ─── Config Builder ────────────────────────────────────────────────────────
413
+
414
+ /**
415
+ * Reusable base config. Created by createConnectConfig().
416
+ * Override per-call with .with().
417
+ *
418
+ * @example
419
+ * const cfg = createConnectConfig({ mnemonic, rpcUrl });
420
+ * await connectDirect(cfg.with({ nodeAddress: 'sentnode1...' }));
421
+ */
422
+ export interface ConnectConfig extends Readonly<Partial<ConnectOptions>> {
423
+ /** Merge base config with per-call overrides */
424
+ with(overrides: Partial<ConnectOptions>): ConnectOptions;
425
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Sentinel SDK — Error Types
3
+ *
4
+ * Machine-readable error codes, typed error classes, and severity classification.
5
+ * All SDK errors extend SentinelError with a .code property matching ErrorCodes.
6
+ *
7
+ * Usage:
8
+ * import { SentinelError, ErrorCodes, isRetryable, userMessage } from 'sentinel-dvpn-sdk';
9
+ * try { await connect(opts); }
10
+ * catch (e) {
11
+ * if (e.code === ErrorCodes.V2RAY_ALL_FAILED) trySwitchNode();
12
+ * if (e instanceof ValidationError) showFormError(e.message);
13
+ * }
14
+ */
15
+
16
+ // ─── Error Code Constants ──────────────────────────────────────────────────
17
+
18
+ /**
19
+ * Machine-readable error code strings.
20
+ * These are a CONTRACT between all SDK languages (JS, C#, Rust, Swift).
21
+ * Use for switch/if checks instead of parsing error.message.
22
+ */
23
+ export type ErrorCode =
24
+ // Validation — bad input, user must fix before retrying
25
+ | 'INVALID_OPTIONS'
26
+ | 'INVALID_MNEMONIC'
27
+ | 'INVALID_NODE_ADDRESS'
28
+ | 'INVALID_GIGABYTES'
29
+ | 'INVALID_URL'
30
+ | 'INVALID_PLAN_ID'
31
+ // Node — node-level failures
32
+ | 'NODE_OFFLINE'
33
+ | 'NODE_NO_UDVPN'
34
+ | 'NODE_NOT_FOUND'
35
+ | 'NODE_CLOCK_DRIFT'
36
+ | 'NODE_INACTIVE'
37
+ | 'INVALID_ASSIGNED_IP'
38
+ | 'NODE_DATABASE_CORRUPT'
39
+ // Chain — transaction and query failures
40
+ | 'INSUFFICIENT_BALANCE'
41
+ | 'BROADCAST_FAILED'
42
+ | 'TX_FAILED'
43
+ | 'LCD_ERROR'
44
+ | 'UNKNOWN_MSG_TYPE'
45
+ | 'ALL_ENDPOINTS_FAILED'
46
+ | 'CHAIN_LAG'
47
+ // Session — session lifecycle issues
48
+ | 'SESSION_EXISTS'
49
+ | 'SESSION_EXTRACT_FAILED'
50
+ | 'SESSION_POISONED'
51
+ // Tunnel — VPN tunnel setup/operation failures
52
+ | 'V2RAY_NOT_FOUND'
53
+ | 'V2RAY_ALL_FAILED'
54
+ | 'WG_NOT_AVAILABLE'
55
+ | 'WG_NO_CONNECTIVITY'
56
+ | 'TUNNEL_SETUP_FAILED'
57
+ // Security — TLS and certificate issues
58
+ | 'TLS_CERT_CHANGED'
59
+ // Connection — high-level connection failures
60
+ | 'ABORTED'
61
+ | 'ALL_NODES_FAILED'
62
+ | 'ALREADY_CONNECTED'
63
+ | 'PARTIAL_CONNECTION_FAILED';
64
+
65
+ /** Frozen map of error code string constants. */
66
+ export const ErrorCodes: {
67
+ readonly INVALID_OPTIONS: 'INVALID_OPTIONS';
68
+ readonly INVALID_MNEMONIC: 'INVALID_MNEMONIC';
69
+ readonly INVALID_NODE_ADDRESS: 'INVALID_NODE_ADDRESS';
70
+ readonly INVALID_GIGABYTES: 'INVALID_GIGABYTES';
71
+ readonly INVALID_URL: 'INVALID_URL';
72
+ readonly INVALID_PLAN_ID: 'INVALID_PLAN_ID';
73
+ readonly NODE_OFFLINE: 'NODE_OFFLINE';
74
+ readonly NODE_NO_UDVPN: 'NODE_NO_UDVPN';
75
+ readonly NODE_NOT_FOUND: 'NODE_NOT_FOUND';
76
+ readonly NODE_CLOCK_DRIFT: 'NODE_CLOCK_DRIFT';
77
+ readonly NODE_INACTIVE: 'NODE_INACTIVE';
78
+ readonly INVALID_ASSIGNED_IP: 'INVALID_ASSIGNED_IP';
79
+ readonly NODE_DATABASE_CORRUPT: 'NODE_DATABASE_CORRUPT';
80
+ readonly INSUFFICIENT_BALANCE: 'INSUFFICIENT_BALANCE';
81
+ readonly BROADCAST_FAILED: 'BROADCAST_FAILED';
82
+ readonly TX_FAILED: 'TX_FAILED';
83
+ readonly LCD_ERROR: 'LCD_ERROR';
84
+ readonly UNKNOWN_MSG_TYPE: 'UNKNOWN_MSG_TYPE';
85
+ readonly ALL_ENDPOINTS_FAILED: 'ALL_ENDPOINTS_FAILED';
86
+ readonly CHAIN_LAG: 'CHAIN_LAG';
87
+ readonly SESSION_EXISTS: 'SESSION_EXISTS';
88
+ readonly SESSION_EXTRACT_FAILED: 'SESSION_EXTRACT_FAILED';
89
+ readonly SESSION_POISONED: 'SESSION_POISONED';
90
+ readonly V2RAY_NOT_FOUND: 'V2RAY_NOT_FOUND';
91
+ readonly V2RAY_ALL_FAILED: 'V2RAY_ALL_FAILED';
92
+ readonly WG_NOT_AVAILABLE: 'WG_NOT_AVAILABLE';
93
+ readonly WG_NO_CONNECTIVITY: 'WG_NO_CONNECTIVITY';
94
+ readonly TUNNEL_SETUP_FAILED: 'TUNNEL_SETUP_FAILED';
95
+ readonly TLS_CERT_CHANGED: 'TLS_CERT_CHANGED';
96
+ readonly ABORTED: 'ABORTED';
97
+ readonly ALL_NODES_FAILED: 'ALL_NODES_FAILED';
98
+ readonly ALREADY_CONNECTED: 'ALREADY_CONNECTED';
99
+ readonly PARTIAL_CONNECTION_FAILED: 'PARTIAL_CONNECTION_FAILED';
100
+ };
101
+
102
+ // ─── Error Severity ────────────────────────────────────────────────────────
103
+
104
+ /**
105
+ * Severity levels that determine retry/UX behavior:
106
+ * - fatal: Don't retry, user action needed (e.g. invalid mnemonic, insufficient balance)
107
+ * - retryable: Try again, possibly with a different node
108
+ * - recoverable: Can resume with recoverSession()
109
+ * - infrastructure: Check system state (e.g. missing binary, cert changed)
110
+ */
111
+ export type ErrorSeverity = 'fatal' | 'retryable' | 'recoverable' | 'infrastructure';
112
+
113
+ /** Map of error code to severity level. Apps use this for retry/UX logic. */
114
+ export const ERROR_SEVERITY: Readonly<Record<ErrorCode, ErrorSeverity>>;
115
+
116
+ // ─── Error Classes ─────────────────────────────────────────────────────────
117
+
118
+ /**
119
+ * Base error class for all SDK errors.
120
+ * Check .code (ErrorCode) for machine-readable error type.
121
+ * Check .details for structured context (node address, session ID, etc.).
122
+ */
123
+ export class SentinelError extends Error {
124
+ /** Machine-readable error code matching ErrorCodes constants */
125
+ readonly code: ErrorCode;
126
+ /** Structured context for programmatic handling (varies by error type) */
127
+ readonly details: Record<string, unknown>;
128
+ constructor(code: ErrorCode, message: string, details?: Record<string, unknown>);
129
+ /** Serialize to JSON-safe object */
130
+ toJSON(): { name: string; code: ErrorCode; message: string; details: Record<string, unknown> };
131
+ }
132
+
133
+ /** Input validation failures — bad mnemonic, invalid address, wrong option types */
134
+ export class ValidationError extends SentinelError {
135
+ constructor(code: ErrorCode, message: string, details?: Record<string, unknown>);
136
+ }
137
+
138
+ /** Node-level failures — offline, no udvpn pricing, clock drift, database corruption */
139
+ export class NodeError extends SentinelError {
140
+ constructor(code: ErrorCode, message: string, details?: Record<string, unknown>);
141
+ }
142
+
143
+ /** Chain/transaction failures — broadcast failed, extract failed, LCD errors */
144
+ export class ChainError extends SentinelError {
145
+ constructor(code: ErrorCode, message: string, details?: Record<string, unknown>);
146
+ }
147
+
148
+ /** Tunnel setup failures — V2Ray config errors, WG no connectivity */
149
+ export class TunnelError extends SentinelError {
150
+ constructor(code: ErrorCode, message: string, details?: Record<string, unknown>);
151
+ }
152
+
153
+ /** Security failures — TLS certificate changed (possible MITM) */
154
+ export class SecurityError extends SentinelError {
155
+ constructor(code: ErrorCode, message: string, details?: Record<string, unknown>);
156
+ }
157
+
158
+ // ─── Error Helper Functions ────────────────────────────────────────────────
159
+
160
+ /**
161
+ * Check if an error should be retried.
162
+ * Returns true for 'retryable' severity errors.
163
+ *
164
+ * @param error - SentinelError instance or object with .code, or just an error code string
165
+ */
166
+ export function isRetryable(error: SentinelError | { code: string } | string): boolean;
167
+
168
+ /**
169
+ * Map an SDK error to a user-friendly message suitable for UI display.
170
+ * Returns a plain English sentence. Falls back to error.message for unknown codes.
171
+ *
172
+ * @param error - SentinelError instance, object with .code, or just an error code string
173
+ */
174
+ export function userMessage(error: SentinelError | { code: string } | string): string;