@sip-protocol/sdk 0.7.3 → 0.7.4

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 (264) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +267 -0
  3. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  4. package/dist/browser.d.mts +10 -4
  5. package/dist/browser.d.ts +10 -4
  6. package/dist/browser.js +47556 -19603
  7. package/dist/browser.mjs +628 -48
  8. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  9. package/dist/chunk-5D7A3L3W.mjs +717 -0
  10. package/dist/chunk-64AYA5F5.mjs +7834 -0
  11. package/dist/chunk-GMDGB22A.mjs +379 -0
  12. package/dist/chunk-I534WKN7.mjs +328 -0
  13. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  14. package/dist/chunk-PRRZAWJE.mjs +223 -0
  15. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  16. package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
  17. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  18. package/dist/constants-LHAAUC2T.mjs +51 -0
  19. package/dist/dist-2OGQ7FED.mjs +3957 -0
  20. package/dist/dist-IFHPYLDX.mjs +254 -0
  21. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  22. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  23. package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
  24. package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48396 -19623
  28. package/dist/index.mjs +537 -19
  29. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  30. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  31. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  32. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  33. package/dist/proofs/halo2.d.mts +151 -0
  34. package/dist/proofs/halo2.d.ts +151 -0
  35. package/dist/proofs/halo2.js +350 -0
  36. package/dist/proofs/halo2.mjs +11 -0
  37. package/dist/proofs/kimchi.d.mts +160 -0
  38. package/dist/proofs/kimchi.d.ts +160 -0
  39. package/dist/proofs/kimchi.js +431 -0
  40. package/dist/proofs/kimchi.mjs +13 -0
  41. package/dist/proofs/noir.d.mts +1 -1
  42. package/dist/proofs/noir.d.ts +1 -1
  43. package/dist/proofs/noir.js +74 -18
  44. package/dist/proofs/noir.mjs +84 -24
  45. package/dist/solana-U3MEGU7W.mjs +280 -0
  46. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  47. package/package.json +54 -21
  48. package/src/adapters/index.ts +41 -0
  49. package/src/adapters/jupiter.ts +571 -0
  50. package/src/adapters/near-intents.ts +135 -0
  51. package/src/advisor/advisor.ts +653 -0
  52. package/src/advisor/index.ts +54 -0
  53. package/src/advisor/tools.ts +303 -0
  54. package/src/advisor/types.ts +164 -0
  55. package/src/chains/ethereum/announcement.ts +536 -0
  56. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  57. package/src/chains/ethereum/commitment.ts +522 -0
  58. package/src/chains/ethereum/constants.ts +462 -0
  59. package/src/chains/ethereum/deployment.ts +596 -0
  60. package/src/chains/ethereum/gas-estimation.ts +538 -0
  61. package/src/chains/ethereum/index.ts +268 -0
  62. package/src/chains/ethereum/optimizations.ts +614 -0
  63. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  64. package/src/chains/ethereum/registry.ts +584 -0
  65. package/src/chains/ethereum/rpc.ts +905 -0
  66. package/src/chains/ethereum/stealth.ts +491 -0
  67. package/src/chains/ethereum/token.ts +790 -0
  68. package/src/chains/ethereum/transfer.ts +637 -0
  69. package/src/chains/ethereum/types.ts +456 -0
  70. package/src/chains/ethereum/viewing-key.ts +455 -0
  71. package/src/chains/near/commitment.ts +608 -0
  72. package/src/chains/near/constants.ts +284 -0
  73. package/src/chains/near/function-call.ts +871 -0
  74. package/src/chains/near/history.ts +654 -0
  75. package/src/chains/near/implicit-account.ts +840 -0
  76. package/src/chains/near/index.ts +393 -0
  77. package/src/chains/near/native-transfer.ts +658 -0
  78. package/src/chains/near/nep141.ts +775 -0
  79. package/src/chains/near/privacy-adapter.ts +889 -0
  80. package/src/chains/near/resolver.ts +971 -0
  81. package/src/chains/near/rpc.ts +1016 -0
  82. package/src/chains/near/stealth.ts +419 -0
  83. package/src/chains/near/types.ts +317 -0
  84. package/src/chains/near/viewing-key.ts +876 -0
  85. package/src/chains/solana/anchor-transfer.ts +386 -0
  86. package/src/chains/solana/commitment.ts +577 -0
  87. package/src/chains/solana/constants.ts +126 -12
  88. package/src/chains/solana/ephemeral-keys.ts +543 -0
  89. package/src/chains/solana/index.ts +252 -1
  90. package/src/chains/solana/key-derivation.ts +418 -0
  91. package/src/chains/solana/kit-compat.ts +334 -0
  92. package/src/chains/solana/optimizations.ts +560 -0
  93. package/src/chains/solana/privacy-adapter.ts +605 -0
  94. package/src/chains/solana/providers/generic.ts +47 -6
  95. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  96. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  97. package/src/chains/solana/providers/helius.ts +186 -33
  98. package/src/chains/solana/providers/index.ts +31 -0
  99. package/src/chains/solana/providers/interface.ts +61 -18
  100. package/src/chains/solana/providers/quicknode.ts +409 -0
  101. package/src/chains/solana/providers/triton.ts +426 -0
  102. package/src/chains/solana/providers/webhook.ts +338 -67
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +83 -66
  105. package/src/chains/solana/sol-transfer.ts +732 -0
  106. package/src/chains/solana/spl-transfer.ts +886 -0
  107. package/src/chains/solana/stealth-scanner.ts +703 -0
  108. package/src/chains/solana/sunspot-verifier.ts +453 -0
  109. package/src/chains/solana/transaction-builder.ts +755 -0
  110. package/src/chains/solana/transfer.ts +74 -5
  111. package/src/chains/solana/types.ts +57 -6
  112. package/src/chains/solana/utils.ts +110 -0
  113. package/src/chains/solana/viewing-key.ts +807 -0
  114. package/src/compliance/fireblocks.ts +921 -0
  115. package/src/compliance/index.ts +23 -0
  116. package/src/compliance/range-sas.ts +398 -33
  117. package/src/config/endpoints.ts +100 -0
  118. package/src/crypto.ts +11 -8
  119. package/src/errors.ts +82 -0
  120. package/src/evm/erc4337-relayer.ts +830 -0
  121. package/src/evm/index.ts +47 -0
  122. package/src/fees/calculator.ts +396 -0
  123. package/src/fees/index.ts +87 -0
  124. package/src/fees/near-contract.ts +429 -0
  125. package/src/fees/types.ts +268 -0
  126. package/src/index.ts +686 -1
  127. package/src/intent.ts +6 -3
  128. package/src/logger.ts +324 -0
  129. package/src/network/index.ts +80 -0
  130. package/src/network/proxy.ts +691 -0
  131. package/src/optimizations/index.ts +541 -0
  132. package/src/oracle/types.ts +1 -0
  133. package/src/privacy-backends/arcium-types.ts +727 -0
  134. package/src/privacy-backends/arcium.ts +719 -0
  135. package/src/privacy-backends/combined-privacy.ts +866 -0
  136. package/src/privacy-backends/cspl-token.ts +595 -0
  137. package/src/privacy-backends/cspl-types.ts +512 -0
  138. package/src/privacy-backends/cspl.ts +907 -0
  139. package/src/privacy-backends/health.ts +488 -0
  140. package/src/privacy-backends/inco-types.ts +323 -0
  141. package/src/privacy-backends/inco.ts +616 -0
  142. package/src/privacy-backends/index.ts +254 -4
  143. package/src/privacy-backends/interface.ts +649 -6
  144. package/src/privacy-backends/lru-cache.ts +343 -0
  145. package/src/privacy-backends/magicblock.ts +458 -0
  146. package/src/privacy-backends/mock.ts +258 -0
  147. package/src/privacy-backends/privacycash.ts +13 -17
  148. package/src/privacy-backends/private-swap.ts +570 -0
  149. package/src/privacy-backends/rate-limiter.ts +683 -0
  150. package/src/privacy-backends/registry.ts +414 -2
  151. package/src/privacy-backends/router.ts +283 -3
  152. package/src/privacy-backends/shadowwire.ts +449 -0
  153. package/src/privacy-backends/sip-native.ts +3 -0
  154. package/src/privacy-logger.ts +191 -0
  155. package/src/production-safety.ts +373 -0
  156. package/src/proofs/aggregator.ts +1029 -0
  157. package/src/proofs/browser-composer.ts +1150 -0
  158. package/src/proofs/browser.ts +113 -25
  159. package/src/proofs/cache/index.ts +127 -0
  160. package/src/proofs/cache/interface.ts +545 -0
  161. package/src/proofs/cache/key-generator.ts +188 -0
  162. package/src/proofs/cache/lru-cache.ts +481 -0
  163. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  164. package/src/proofs/cache/persistent-cache.ts +788 -0
  165. package/src/proofs/compliance-proof.ts +872 -0
  166. package/src/proofs/composer/base.ts +923 -0
  167. package/src/proofs/composer/index.ts +25 -0
  168. package/src/proofs/composer/interface.ts +518 -0
  169. package/src/proofs/composer/types.ts +383 -0
  170. package/src/proofs/converters/halo2.ts +452 -0
  171. package/src/proofs/converters/index.ts +208 -0
  172. package/src/proofs/converters/interface.ts +363 -0
  173. package/src/proofs/converters/kimchi.ts +462 -0
  174. package/src/proofs/converters/noir.ts +451 -0
  175. package/src/proofs/fallback.ts +888 -0
  176. package/src/proofs/halo2.ts +42 -0
  177. package/src/proofs/index.ts +471 -0
  178. package/src/proofs/interface.ts +13 -0
  179. package/src/proofs/kimchi.ts +42 -0
  180. package/src/proofs/lazy.ts +1004 -0
  181. package/src/proofs/mock.ts +25 -1
  182. package/src/proofs/noir.ts +110 -29
  183. package/src/proofs/orchestrator.ts +960 -0
  184. package/src/proofs/parallel/concurrency.ts +297 -0
  185. package/src/proofs/parallel/dependency-graph.ts +602 -0
  186. package/src/proofs/parallel/executor.ts +420 -0
  187. package/src/proofs/parallel/index.ts +131 -0
  188. package/src/proofs/parallel/interface.ts +685 -0
  189. package/src/proofs/parallel/worker-pool.ts +644 -0
  190. package/src/proofs/providers/halo2.ts +560 -0
  191. package/src/proofs/providers/index.ts +34 -0
  192. package/src/proofs/providers/kimchi.ts +641 -0
  193. package/src/proofs/validator.ts +881 -0
  194. package/src/proofs/verifier.ts +867 -0
  195. package/src/quantum/index.ts +112 -0
  196. package/src/quantum/winternitz-vault.ts +639 -0
  197. package/src/quantum/wots.ts +611 -0
  198. package/src/settlement/backends/direct-chain.ts +1 -0
  199. package/src/settlement/index.ts +9 -0
  200. package/src/settlement/router.ts +732 -46
  201. package/src/solana/index.ts +72 -0
  202. package/src/solana/jito-relayer.ts +687 -0
  203. package/src/solana/noir-verifier-types.ts +430 -0
  204. package/src/solana/noir-verifier.ts +816 -0
  205. package/src/stealth/address-derivation.ts +193 -0
  206. package/src/stealth/ed25519.ts +431 -0
  207. package/src/stealth/index.ts +233 -0
  208. package/src/stealth/meta-address.ts +221 -0
  209. package/src/stealth/secp256k1.ts +368 -0
  210. package/src/stealth/utils.ts +194 -0
  211. package/src/stealth.ts +50 -1504
  212. package/src/sync/index.ts +106 -0
  213. package/src/sync/manager.ts +504 -0
  214. package/src/sync/mock-provider.ts +318 -0
  215. package/src/sync/oblivious.ts +625 -0
  216. package/src/tokens/index.ts +15 -0
  217. package/src/tokens/registry.ts +301 -0
  218. package/src/utils/deprecation.ts +94 -0
  219. package/src/utils/index.ts +9 -0
  220. package/src/wallet/ethereum/index.ts +68 -0
  221. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  222. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  223. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  224. package/src/wallet/ethereum/types.ts +3 -1
  225. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  226. package/src/wallet/hardware/index.ts +10 -0
  227. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  228. package/src/wallet/index.ts +71 -0
  229. package/src/wallet/near/adapter.ts +626 -0
  230. package/src/wallet/near/index.ts +86 -0
  231. package/src/wallet/near/meteor-wallet.ts +1153 -0
  232. package/src/wallet/near/my-near-wallet.ts +790 -0
  233. package/src/wallet/near/wallet-selector.ts +702 -0
  234. package/src/wallet/solana/adapter.ts +6 -4
  235. package/src/wallet/solana/index.ts +13 -0
  236. package/src/wallet/solana/privacy-adapter.ts +567 -0
  237. package/src/wallet/sui/types.ts +6 -4
  238. package/src/zcash/rpc-client.ts +13 -6
  239. package/dist/chunk-2XIVXWHA.mjs +0 -1930
  240. package/dist/chunk-3INS3PR5.mjs +0 -884
  241. package/dist/chunk-3OVABDRH.mjs +0 -17096
  242. package/dist/chunk-7RFRWDCW.mjs +0 -1504
  243. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  244. package/dist/chunk-E6SZWREQ.mjs +0 -57
  245. package/dist/chunk-F6F73W35.mjs +0 -16166
  246. package/dist/chunk-G33LB27A.mjs +0 -16166
  247. package/dist/chunk-HGU6HZRC.mjs +0 -231
  248. package/dist/chunk-L2K34JCU.mjs +0 -1496
  249. package/dist/chunk-OFDBEIEK.mjs +0 -16166
  250. package/dist/chunk-SF7YSLF5.mjs +0 -1515
  251. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  252. package/dist/chunk-WWUSGOXE.mjs +0 -17129
  253. package/dist/constants-VOI7BSLK.mjs +0 -27
  254. package/dist/index-B71aXVzk.d.ts +0 -13264
  255. package/dist/index-BYZbDjal.d.ts +0 -11390
  256. package/dist/index-CHB3KuOB.d.mts +0 -11859
  257. package/dist/index-CzWPI6Le.d.ts +0 -11859
  258. package/dist/index-pOIIuwfV.d.mts +0 -13264
  259. package/dist/index-xbWjohNq.d.mts +0 -11390
  260. package/dist/solana-4O4K45VU.mjs +0 -46
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-NDABAZ6P.mjs +0 -56
  263. package/dist/solana-Q4NAVBTS.mjs +0 -46
  264. package/dist/solana-ZYO63LY5.mjs +0 -46
@@ -0,0 +1,691 @@
1
+ /**
2
+ * Network Privacy Layer - Proxy Support
3
+ *
4
+ * Provides Tor and SOCKS5/HTTP proxy support for routing RPC calls
5
+ * through privacy-preserving networks. Prevents IP address correlation
6
+ * with wallet activity.
7
+ *
8
+ * ## Features
9
+ *
10
+ * - Auto-detect Tor service (ports 9050, 9150)
11
+ * - SOCKS5 proxy support
12
+ * - HTTP/HTTPS proxy support
13
+ * - Environment variable configuration
14
+ * - Circuit rotation for unlinkability
15
+ *
16
+ * @example Using Tor
17
+ * ```typescript
18
+ * import { createProxyAgent, TOR_PORTS } from '@sip-protocol/sdk'
19
+ *
20
+ * // Auto-detect Tor
21
+ * const agent = await createProxyAgent('tor')
22
+ *
23
+ * // Or specify port
24
+ * const agent = await createProxyAgent('socks5://127.0.0.1:9050')
25
+ * ```
26
+ *
27
+ * @example Using custom SOCKS5 proxy
28
+ * ```typescript
29
+ * const agent = await createProxyAgent('socks5://myproxy.example.com:1080')
30
+ * ```
31
+ *
32
+ * @module network/proxy
33
+ * @see https://github.com/sip-protocol/sip-protocol/issues/489
34
+ */
35
+
36
+ import type { Agent } from 'http'
37
+
38
+ // ─── Types ───────────────────────────────────────────────────────────────────
39
+
40
+ /**
41
+ * Proxy configuration type
42
+ *
43
+ * - `'tor'`: Auto-detect local Tor service
44
+ * - `'socks5://...'`: SOCKS5 proxy URL
45
+ * - `'http://...'` or `'https://...'`: HTTP proxy URL
46
+ * - `undefined`: No proxy (direct connection)
47
+ */
48
+ export type ProxyConfig =
49
+ | 'tor'
50
+ | `socks5://${string}`
51
+ | `socks4://${string}`
52
+ | `http://${string}`
53
+ | `https://${string}`
54
+ | undefined
55
+
56
+ /**
57
+ * Proxy type classification
58
+ */
59
+ export type ProxyType = 'tor' | 'socks5' | 'socks4' | 'http' | 'https' | 'none'
60
+
61
+ /**
62
+ * Parsed proxy configuration
63
+ */
64
+ export interface ParsedProxyConfig {
65
+ /** Proxy type */
66
+ type: ProxyType
67
+ /** Proxy host */
68
+ host?: string
69
+ /** Proxy port */
70
+ port?: number
71
+ /** Full proxy URL */
72
+ url?: string
73
+ /** Authentication username (if any) */
74
+ username?: string
75
+ /** Authentication password (if any) */
76
+ password?: string
77
+ }
78
+
79
+ /**
80
+ * Proxy agent options
81
+ */
82
+ export interface ProxyAgentOptions {
83
+ /** Connection timeout in milliseconds */
84
+ timeout?: number
85
+ /** Whether to rotate circuits (Tor only) */
86
+ rotateCircuit?: boolean
87
+ /** Custom Tor control port for circuit rotation */
88
+ torControlPort?: number
89
+ /** Tor control password (for NEWNYM) */
90
+ torControlPassword?: string
91
+ }
92
+
93
+ /**
94
+ * Result of proxy availability check
95
+ */
96
+ export interface ProxyCheckResult {
97
+ /** Whether proxy is available */
98
+ available: boolean
99
+ /** Proxy type detected */
100
+ type: ProxyType
101
+ /** Proxy URL if available */
102
+ url?: string
103
+ /** Error message if not available */
104
+ error?: string
105
+ /** Response time in milliseconds */
106
+ responseTimeMs?: number
107
+ }
108
+
109
+ // ─── Constants ───────────────────────────────────────────────────────────────
110
+
111
+ /**
112
+ * Common Tor ports
113
+ *
114
+ * - 9050: Standalone Tor daemon
115
+ * - 9150: Tor Browser Bundle
116
+ */
117
+ export const TOR_PORTS = [9050, 9150] as const
118
+
119
+ /**
120
+ * Default Tor host
121
+ */
122
+ export const TOR_HOST = '127.0.0.1'
123
+
124
+ /**
125
+ * Default Tor control port (for NEWNYM signal)
126
+ */
127
+ export const TOR_CONTROL_PORT = 9051
128
+
129
+ /**
130
+ * Default connection timeout in milliseconds
131
+ */
132
+ export const DEFAULT_PROXY_TIMEOUT = 30000
133
+
134
+ /**
135
+ * Environment variable for proxy configuration
136
+ */
137
+ export const PROXY_ENV_VAR = 'SIP_PROXY'
138
+
139
+ /**
140
+ * Alternative environment variables to check
141
+ */
142
+ export const PROXY_ENV_VARS = [
143
+ 'SIP_PROXY',
144
+ 'ALL_PROXY',
145
+ 'HTTPS_PROXY',
146
+ 'HTTP_PROXY',
147
+ 'SOCKS_PROXY',
148
+ ] as const
149
+
150
+ // ─── Parsing ─────────────────────────────────────────────────────────────────
151
+
152
+ /**
153
+ * Parse a proxy configuration string into structured data
154
+ *
155
+ * @param config - Proxy configuration string
156
+ * @returns Parsed configuration
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * parseProxyConfig('tor')
161
+ * // { type: 'tor', host: '127.0.0.1', port: 9050 }
162
+ *
163
+ * parseProxyConfig('socks5://proxy.example.com:1080')
164
+ * // { type: 'socks5', host: 'proxy.example.com', port: 1080, url: '...' }
165
+ *
166
+ * parseProxyConfig('http://user:pass@proxy.com:8080')
167
+ * // { type: 'http', host: 'proxy.com', port: 8080, username: 'user', password: 'pass' }
168
+ * ```
169
+ */
170
+ export function parseProxyConfig(config: ProxyConfig): ParsedProxyConfig {
171
+ if (!config) {
172
+ return { type: 'none' }
173
+ }
174
+
175
+ if (config === 'tor') {
176
+ return {
177
+ type: 'tor',
178
+ host: TOR_HOST,
179
+ port: TOR_PORTS[0],
180
+ url: `socks5://${TOR_HOST}:${TOR_PORTS[0]}`,
181
+ }
182
+ }
183
+
184
+ // Parse URL
185
+ try {
186
+ const url = new URL(config)
187
+ const protocol = url.protocol.replace(':', '') as ProxyType
188
+
189
+ if (!['socks5', 'socks4', 'http', 'https'].includes(protocol)) {
190
+ throw new Error(`Unsupported proxy protocol: ${protocol}`)
191
+ }
192
+
193
+ return {
194
+ type: protocol,
195
+ host: url.hostname,
196
+ port: url.port ? parseInt(url.port, 10) : undefined,
197
+ url: config,
198
+ username: url.username || undefined,
199
+ password: url.password || undefined,
200
+ }
201
+ } catch {
202
+ throw new Error(
203
+ `Invalid proxy configuration: ${config}. ` +
204
+ `Expected 'tor', 'socks5://...', 'http://...', or 'https://...'`
205
+ )
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Get proxy configuration from environment variables
211
+ *
212
+ * Checks SIP_PROXY, ALL_PROXY, HTTPS_PROXY, HTTP_PROXY, SOCKS_PROXY
213
+ *
214
+ * @returns Proxy configuration or undefined
215
+ */
216
+ export function getProxyFromEnv(): ProxyConfig {
217
+ for (const envVar of PROXY_ENV_VARS) {
218
+ const value = process.env[envVar]
219
+ if (value) {
220
+ // Handle 'tor' shorthand
221
+ if (value.toLowerCase() === 'tor') {
222
+ return 'tor'
223
+ }
224
+ // Validate URL format
225
+ if (value.startsWith('socks') || value.startsWith('http')) {
226
+ return value as ProxyConfig
227
+ }
228
+ }
229
+ }
230
+ return undefined
231
+ }
232
+
233
+ // ─── Proxy Detection ─────────────────────────────────────────────────────────
234
+
235
+ /**
236
+ * Check if Tor is available on a specific port
237
+ *
238
+ * @param port - Port to check
239
+ * @param host - Host to check (default: 127.0.0.1)
240
+ * @param timeout - Connection timeout in ms
241
+ * @returns True if Tor is responding
242
+ */
243
+ export async function isTorAvailable(
244
+ port: number = TOR_PORTS[0],
245
+ host: string = TOR_HOST,
246
+ timeout: number = 5000
247
+ ): Promise<boolean> {
248
+ // In Node.js, we'd use net.connect to check
249
+ // For now, return a simple check
250
+ return new Promise((resolve) => {
251
+ if (typeof globalThis.process === 'undefined') {
252
+ // Browser environment - Tor not directly available
253
+ resolve(false)
254
+ return
255
+ }
256
+
257
+ try {
258
+ // Dynamic import to avoid bundling in browser
259
+ import('net').then(({ connect }) => {
260
+ const socket = connect({ host, port })
261
+
262
+ const timer = setTimeout(() => {
263
+ socket.destroy()
264
+ resolve(false)
265
+ }, timeout)
266
+
267
+ socket.on('connect', () => {
268
+ clearTimeout(timer)
269
+ socket.destroy()
270
+ resolve(true)
271
+ })
272
+
273
+ socket.on('error', () => {
274
+ clearTimeout(timer)
275
+ resolve(false)
276
+ })
277
+ }).catch(() => {
278
+ resolve(false)
279
+ })
280
+ } catch {
281
+ resolve(false)
282
+ }
283
+ })
284
+ }
285
+
286
+ /**
287
+ * Auto-detect Tor service on common ports
288
+ *
289
+ * @param timeout - Connection timeout per port
290
+ * @returns Port number if found, undefined otherwise
291
+ */
292
+ export async function detectTorPort(timeout: number = 5000): Promise<number | undefined> {
293
+ for (const port of TOR_PORTS) {
294
+ if (await isTorAvailable(port, TOR_HOST, timeout)) {
295
+ return port
296
+ }
297
+ }
298
+ return undefined
299
+ }
300
+
301
+ /**
302
+ * Check proxy availability and get connection info
303
+ *
304
+ * @param config - Proxy configuration
305
+ * @param timeout - Connection timeout
306
+ * @returns Availability result
307
+ */
308
+ export async function checkProxyAvailability(
309
+ config: ProxyConfig,
310
+ timeout: number = DEFAULT_PROXY_TIMEOUT
311
+ ): Promise<ProxyCheckResult> {
312
+ if (!config) {
313
+ return { available: true, type: 'none' }
314
+ }
315
+
316
+ const start = Date.now()
317
+
318
+ if (config === 'tor') {
319
+ const port = await detectTorPort(timeout)
320
+ if (port) {
321
+ return {
322
+ available: true,
323
+ type: 'tor',
324
+ url: `socks5://${TOR_HOST}:${port}`,
325
+ responseTimeMs: Date.now() - start,
326
+ }
327
+ }
328
+ return {
329
+ available: false,
330
+ type: 'tor',
331
+ error: `Tor not found on ports ${TOR_PORTS.join(', ')}. ` +
332
+ `Please start Tor or Tor Browser.`,
333
+ }
334
+ }
335
+
336
+ // For SOCKS5/HTTP proxies, parse and validate
337
+ try {
338
+ const parsed = parseProxyConfig(config)
339
+ // In production, we'd do a test connection here
340
+ return {
341
+ available: true,
342
+ type: parsed.type,
343
+ url: parsed.url,
344
+ responseTimeMs: Date.now() - start,
345
+ }
346
+ } catch (error) {
347
+ return {
348
+ available: false,
349
+ type: 'none',
350
+ error: error instanceof Error ? error.message : 'Unknown error',
351
+ }
352
+ }
353
+ }
354
+
355
+ // ─── Agent Creation ──────────────────────────────────────────────────────────
356
+
357
+ /**
358
+ * Create a proxy agent for HTTP requests
359
+ *
360
+ * **Note:** This requires optional dependencies:
361
+ * - `socks-proxy-agent` for SOCKS4/5 proxies
362
+ * - `https-proxy-agent` for HTTP/HTTPS proxies
363
+ *
364
+ * Install with: `npm install socks-proxy-agent https-proxy-agent`
365
+ *
366
+ * @param config - Proxy configuration
367
+ * @param options - Agent options
368
+ * @returns HTTP Agent configured for proxy, or undefined for direct connection
369
+ * @throws Error if proxy dependencies not installed
370
+ *
371
+ * @example
372
+ * ```typescript
373
+ * // Using Tor
374
+ * const agent = await createProxyAgent('tor')
375
+ *
376
+ * // Using custom SOCKS5
377
+ * const agent = await createProxyAgent('socks5://127.0.0.1:1080')
378
+ *
379
+ * // Use with fetch
380
+ * fetch(url, { agent })
381
+ * ```
382
+ */
383
+ export async function createProxyAgent(
384
+ config: ProxyConfig,
385
+ options: ProxyAgentOptions = {}
386
+ ): Promise<Agent | undefined> {
387
+ if (!config) {
388
+ return undefined
389
+ }
390
+
391
+ const { timeout = DEFAULT_PROXY_TIMEOUT } = options
392
+
393
+ // Handle Tor auto-detection
394
+ let proxyUrl: string
395
+ if (config === 'tor') {
396
+ const port = await detectTorPort(timeout)
397
+ if (!port) {
398
+ throw new Error(
399
+ `Tor not available on ports ${TOR_PORTS.join(', ')}. ` +
400
+ `Please start Tor (brew install tor && tor) or Tor Browser.`
401
+ )
402
+ }
403
+ proxyUrl = `socks5://${TOR_HOST}:${port}`
404
+ } else {
405
+ proxyUrl = config
406
+ }
407
+
408
+ // Parse to determine agent type
409
+ const parsed = parseProxyConfig(config === 'tor' ? `socks5://${TOR_HOST}:${TOR_PORTS[0]}` : config)
410
+
411
+ // Dynamic import of proxy agent libraries
412
+ try {
413
+ if (parsed.type === 'socks5' || parsed.type === 'socks4' || config === 'tor') {
414
+ // SOCKS proxy
415
+ const { SocksProxyAgent } = await import('socks-proxy-agent')
416
+ return new SocksProxyAgent(proxyUrl, { timeout })
417
+ }
418
+
419
+ if (parsed.type === 'http' || parsed.type === 'https') {
420
+ // HTTP proxy
421
+ const { HttpsProxyAgent } = await import('https-proxy-agent')
422
+ return new HttpsProxyAgent(proxyUrl, { timeout })
423
+ }
424
+ } catch (error) {
425
+ if ((error as NodeJS.ErrnoException).code === 'MODULE_NOT_FOUND') {
426
+ throw new Error(
427
+ `Proxy agent dependencies not installed. ` +
428
+ `Run: npm install socks-proxy-agent https-proxy-agent`
429
+ )
430
+ }
431
+ throw error
432
+ }
433
+
434
+ return undefined
435
+ }
436
+
437
+ // ─── Proxied Fetch ───────────────────────────────────────────────────────────
438
+
439
+ /**
440
+ * Fetch function type with optional agent
441
+ */
442
+ export type ProxiedFetch = (
443
+ url: string | URL,
444
+ options?: RequestInit & { agent?: Agent }
445
+ ) => Promise<Response>
446
+
447
+ /**
448
+ * Create a fetch function that uses a proxy agent
449
+ *
450
+ * @param agent - Proxy agent (from createProxyAgent)
451
+ * @returns Fetch function with proxy support
452
+ *
453
+ * @example
454
+ * ```typescript
455
+ * const agent = await createProxyAgent('tor')
456
+ * const proxiedFetch = createProxiedFetch(agent)
457
+ *
458
+ * // All requests go through Tor
459
+ * const response = await proxiedFetch('https://api.example.com/data')
460
+ * ```
461
+ */
462
+ export function createProxiedFetch(agent: Agent | undefined): ProxiedFetch {
463
+ return async (url: string | URL, options: RequestInit & { agent?: Agent } = {}) => {
464
+ // In Node.js, we can pass agent directly
465
+ // The global fetch in Node 18+ supports agent option
466
+ return fetch(url, {
467
+ ...options,
468
+ // @ts-expect-error - agent is valid for Node.js fetch
469
+ agent: agent ?? options.agent,
470
+ })
471
+ }
472
+ }
473
+
474
+ // ─── Tor Circuit Rotation ────────────────────────────────────────────────────
475
+
476
+ /**
477
+ * Request a new Tor circuit (NEWNYM)
478
+ *
479
+ * Requires Tor control port to be enabled with authentication.
480
+ * Configure in torrc:
481
+ * ```
482
+ * ControlPort 9051
483
+ * HashedControlPassword <your-hashed-password>
484
+ * ```
485
+ *
486
+ * @param controlPort - Tor control port (default: 9051)
487
+ * @param password - Control port password
488
+ * @returns True if circuit rotation succeeded
489
+ *
490
+ * @example
491
+ * ```typescript
492
+ * // Enable in torrc and set password
493
+ * const success = await rotateCircuit(9051, 'my-tor-password')
494
+ * if (success) {
495
+ * console.log('New Tor circuit established')
496
+ * }
497
+ * ```
498
+ */
499
+ export async function rotateCircuit(
500
+ controlPort: number = TOR_CONTROL_PORT,
501
+ password?: string
502
+ ): Promise<boolean> {
503
+ if (typeof globalThis.process === 'undefined') {
504
+ // Browser environment
505
+ console.warn('Circuit rotation not available in browser')
506
+ return false
507
+ }
508
+
509
+ try {
510
+ const { connect } = await import('net')
511
+
512
+ return new Promise((resolve) => {
513
+ const socket = connect({ host: TOR_HOST, port: controlPort })
514
+
515
+ let authenticated = false
516
+
517
+ socket.on('connect', () => {
518
+ if (password) {
519
+ socket.write(`AUTHENTICATE "${password}"\r\n`)
520
+ } else {
521
+ socket.write('AUTHENTICATE\r\n')
522
+ }
523
+ })
524
+
525
+ socket.on('data', (data) => {
526
+ const response = data.toString()
527
+
528
+ if (!authenticated && response.includes('250')) {
529
+ authenticated = true
530
+ socket.write('SIGNAL NEWNYM\r\n')
531
+ } else if (authenticated && response.includes('250')) {
532
+ socket.destroy()
533
+ resolve(true)
534
+ } else if (response.includes('515') || response.includes('5')) {
535
+ socket.destroy()
536
+ resolve(false)
537
+ }
538
+ })
539
+
540
+ socket.on('error', () => {
541
+ resolve(false)
542
+ })
543
+
544
+ // Timeout after 5 seconds
545
+ setTimeout(() => {
546
+ socket.destroy()
547
+ resolve(false)
548
+ }, 5000)
549
+ })
550
+ } catch {
551
+ return false
552
+ }
553
+ }
554
+
555
+ // ─── Network Privacy Config ──────────────────────────────────────────────────
556
+
557
+ /**
558
+ * Network privacy configuration for SDK clients
559
+ */
560
+ export interface NetworkPrivacyConfig {
561
+ /**
562
+ * Proxy configuration
563
+ *
564
+ * - `'tor'`: Auto-detect local Tor
565
+ * - `'socks5://...'`: SOCKS5 proxy
566
+ * - `'http://...'`: HTTP proxy
567
+ * - `undefined`: Direct connection
568
+ */
569
+ proxy?: ProxyConfig
570
+
571
+ /**
572
+ * Rotate Tor circuit per request
573
+ *
574
+ * Requires Tor control port. Provides unlinkability between requests.
575
+ *
576
+ * @default false
577
+ */
578
+ rotateCircuit?: boolean
579
+
580
+ /**
581
+ * Tor control port for circuit rotation
582
+ *
583
+ * @default 9051
584
+ */
585
+ torControlPort?: number
586
+
587
+ /**
588
+ * Tor control password
589
+ *
590
+ * Required for rotateCircuit if Tor is configured with password authentication.
591
+ */
592
+ torControlPassword?: string
593
+
594
+ /**
595
+ * Connection timeout in milliseconds
596
+ *
597
+ * @default 30000
598
+ */
599
+ timeout?: number
600
+
601
+ /**
602
+ * Fallback to direct connection if proxy unavailable
603
+ *
604
+ * If true, will use direct connection when proxy fails.
605
+ * If false, will throw error when proxy fails.
606
+ *
607
+ * @default false
608
+ */
609
+ fallbackToDirect?: boolean
610
+ }
611
+
612
+ /**
613
+ * Default network privacy configuration
614
+ */
615
+ export const DEFAULT_NETWORK_CONFIG: Required<Omit<NetworkPrivacyConfig, 'proxy' | 'torControlPassword'>> = {
616
+ rotateCircuit: false,
617
+ torControlPort: TOR_CONTROL_PORT,
618
+ timeout: DEFAULT_PROXY_TIMEOUT,
619
+ fallbackToDirect: false,
620
+ }
621
+
622
+ /**
623
+ * Create a network privacy client
624
+ *
625
+ * @param config - Network privacy configuration
626
+ * @returns Proxied fetch function and utilities
627
+ *
628
+ * @example
629
+ * ```typescript
630
+ * const network = await createNetworkPrivacyClient({
631
+ * proxy: 'tor',
632
+ * rotateCircuit: true,
633
+ * torControlPassword: 'my-password',
634
+ * })
635
+ *
636
+ * // Use proxied fetch
637
+ * const response = await network.fetch('https://api.example.com')
638
+ *
639
+ * // Rotate circuit manually
640
+ * await network.rotateCircuit()
641
+ *
642
+ * // Check status
643
+ * console.log(network.status) // { type: 'tor', connected: true, ... }
644
+ * ```
645
+ */
646
+ export async function createNetworkPrivacyClient(
647
+ config: NetworkPrivacyConfig = {}
648
+ ): Promise<{
649
+ fetch: ProxiedFetch
650
+ rotateCircuit: () => Promise<boolean>
651
+ status: ProxyCheckResult
652
+ agent: Agent | undefined
653
+ }> {
654
+ const {
655
+ proxy,
656
+ rotateCircuit: shouldRotate = DEFAULT_NETWORK_CONFIG.rotateCircuit,
657
+ torControlPort = DEFAULT_NETWORK_CONFIG.torControlPort,
658
+ torControlPassword,
659
+ timeout = DEFAULT_NETWORK_CONFIG.timeout,
660
+ fallbackToDirect = DEFAULT_NETWORK_CONFIG.fallbackToDirect,
661
+ } = config
662
+
663
+ // Check proxy availability
664
+ const status = await checkProxyAvailability(proxy, timeout)
665
+
666
+ let agent: Agent | undefined
667
+
668
+ if (!status.available) {
669
+ if (fallbackToDirect) {
670
+ console.warn(
671
+ `[SIP-SDK] Proxy unavailable: ${status.error}. Falling back to direct connection.`
672
+ )
673
+ } else {
674
+ throw new Error(`Proxy unavailable: ${status.error}`)
675
+ }
676
+ } else {
677
+ agent = await createProxyAgent(proxy, { timeout })
678
+ }
679
+
680
+ return {
681
+ fetch: createProxiedFetch(agent),
682
+ rotateCircuit: async () => {
683
+ if (shouldRotate && (status.type === 'tor' || proxy === 'tor')) {
684
+ return rotateCircuit(torControlPort, torControlPassword)
685
+ }
686
+ return false
687
+ },
688
+ status,
689
+ agent,
690
+ }
691
+ }