@sip-protocol/sdk 0.7.2 → 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 (262) 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 +48874 -18336
  7. package/dist/browser.mjs +674 -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-YWGJ77A2.mjs +33806 -0
  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-DXh2IGkz.d.ts +24681 -0
  24. package/dist/index-DeE1ZzA4.d.mts +24681 -0
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48676 -17318
  28. package/dist/index.mjs +583 -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 +276 -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 +201 -0
  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 +402 -0
  98. package/src/chains/solana/providers/index.ts +85 -0
  99. package/src/chains/solana/providers/interface.ts +221 -0
  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 +790 -0
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +170 -73
  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 +77 -7
  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 +37 -0
  116. package/src/compliance/range-sas.ts +956 -0
  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 +785 -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 +336 -0
  143. package/src/privacy-backends/interface.ts +906 -0
  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-types.ts +278 -0
  148. package/src/privacy-backends/privacycash.ts +456 -0
  149. package/src/privacy-backends/private-swap.ts +570 -0
  150. package/src/privacy-backends/rate-limiter.ts +683 -0
  151. package/src/privacy-backends/registry.ts +690 -0
  152. package/src/privacy-backends/router.ts +626 -0
  153. package/src/privacy-backends/shadowwire.ts +449 -0
  154. package/src/privacy-backends/sip-native.ts +256 -0
  155. package/src/privacy-logger.ts +191 -0
  156. package/src/production-safety.ts +373 -0
  157. package/src/proofs/aggregator.ts +1029 -0
  158. package/src/proofs/browser-composer.ts +1150 -0
  159. package/src/proofs/browser.ts +113 -25
  160. package/src/proofs/cache/index.ts +127 -0
  161. package/src/proofs/cache/interface.ts +545 -0
  162. package/src/proofs/cache/key-generator.ts +188 -0
  163. package/src/proofs/cache/lru-cache.ts +481 -0
  164. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  165. package/src/proofs/cache/persistent-cache.ts +788 -0
  166. package/src/proofs/compliance-proof.ts +872 -0
  167. package/src/proofs/composer/base.ts +923 -0
  168. package/src/proofs/composer/index.ts +25 -0
  169. package/src/proofs/composer/interface.ts +518 -0
  170. package/src/proofs/composer/types.ts +383 -0
  171. package/src/proofs/converters/halo2.ts +452 -0
  172. package/src/proofs/converters/index.ts +208 -0
  173. package/src/proofs/converters/interface.ts +363 -0
  174. package/src/proofs/converters/kimchi.ts +462 -0
  175. package/src/proofs/converters/noir.ts +451 -0
  176. package/src/proofs/fallback.ts +888 -0
  177. package/src/proofs/halo2.ts +42 -0
  178. package/src/proofs/index.ts +471 -0
  179. package/src/proofs/interface.ts +13 -0
  180. package/src/proofs/kimchi.ts +42 -0
  181. package/src/proofs/lazy.ts +1004 -0
  182. package/src/proofs/mock.ts +25 -1
  183. package/src/proofs/noir.ts +111 -30
  184. package/src/proofs/orchestrator.ts +960 -0
  185. package/src/proofs/parallel/concurrency.ts +297 -0
  186. package/src/proofs/parallel/dependency-graph.ts +602 -0
  187. package/src/proofs/parallel/executor.ts +420 -0
  188. package/src/proofs/parallel/index.ts +131 -0
  189. package/src/proofs/parallel/interface.ts +685 -0
  190. package/src/proofs/parallel/worker-pool.ts +644 -0
  191. package/src/proofs/providers/halo2.ts +560 -0
  192. package/src/proofs/providers/index.ts +34 -0
  193. package/src/proofs/providers/kimchi.ts +641 -0
  194. package/src/proofs/validator.ts +881 -0
  195. package/src/proofs/verifier.ts +867 -0
  196. package/src/quantum/index.ts +112 -0
  197. package/src/quantum/winternitz-vault.ts +639 -0
  198. package/src/quantum/wots.ts +611 -0
  199. package/src/settlement/backends/direct-chain.ts +1 -0
  200. package/src/settlement/index.ts +9 -0
  201. package/src/settlement/router.ts +732 -46
  202. package/src/solana/index.ts +72 -0
  203. package/src/solana/jito-relayer.ts +687 -0
  204. package/src/solana/noir-verifier-types.ts +430 -0
  205. package/src/solana/noir-verifier.ts +816 -0
  206. package/src/stealth/address-derivation.ts +193 -0
  207. package/src/stealth/ed25519.ts +431 -0
  208. package/src/stealth/index.ts +233 -0
  209. package/src/stealth/meta-address.ts +221 -0
  210. package/src/stealth/secp256k1.ts +368 -0
  211. package/src/stealth/utils.ts +194 -0
  212. package/src/stealth.ts +50 -1504
  213. package/src/surveillance/algorithms/address-reuse.ts +143 -0
  214. package/src/surveillance/algorithms/cluster.ts +247 -0
  215. package/src/surveillance/algorithms/exchange.ts +295 -0
  216. package/src/surveillance/algorithms/temporal.ts +337 -0
  217. package/src/surveillance/analyzer.ts +442 -0
  218. package/src/surveillance/index.ts +64 -0
  219. package/src/surveillance/scoring.ts +372 -0
  220. package/src/surveillance/types.ts +264 -0
  221. package/src/sync/index.ts +106 -0
  222. package/src/sync/manager.ts +504 -0
  223. package/src/sync/mock-provider.ts +318 -0
  224. package/src/sync/oblivious.ts +625 -0
  225. package/src/tokens/index.ts +15 -0
  226. package/src/tokens/registry.ts +301 -0
  227. package/src/utils/deprecation.ts +94 -0
  228. package/src/utils/index.ts +9 -0
  229. package/src/wallet/ethereum/index.ts +68 -0
  230. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  231. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  232. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  233. package/src/wallet/ethereum/types.ts +3 -1
  234. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  235. package/src/wallet/hardware/index.ts +10 -0
  236. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  237. package/src/wallet/index.ts +71 -0
  238. package/src/wallet/near/adapter.ts +626 -0
  239. package/src/wallet/near/index.ts +86 -0
  240. package/src/wallet/near/meteor-wallet.ts +1153 -0
  241. package/src/wallet/near/my-near-wallet.ts +790 -0
  242. package/src/wallet/near/wallet-selector.ts +702 -0
  243. package/src/wallet/solana/adapter.ts +6 -4
  244. package/src/wallet/solana/index.ts +13 -0
  245. package/src/wallet/solana/privacy-adapter.ts +567 -0
  246. package/src/wallet/sui/types.ts +6 -4
  247. package/src/zcash/rpc-client.ts +13 -6
  248. package/dist/chunk-3INS3PR5.mjs +0 -884
  249. package/dist/chunk-3OVABDRH.mjs +0 -17096
  250. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  251. package/dist/chunk-E6SZWREQ.mjs +0 -57
  252. package/dist/chunk-G33LB27A.mjs +0 -16166
  253. package/dist/chunk-HGU6HZRC.mjs +0 -231
  254. package/dist/chunk-L2K34JCU.mjs +0 -1496
  255. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  256. package/dist/constants-VOI7BSLK.mjs +0 -27
  257. package/dist/index-BYZbDjal.d.ts +0 -11390
  258. package/dist/index-CHB3KuOB.d.mts +0 -11859
  259. package/dist/index-CzWPI6Le.d.ts +0 -11859
  260. package/dist/index-xbWjohNq.d.mts +0 -11390
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
@@ -0,0 +1,690 @@
1
+ /**
2
+ * Privacy Backend Registry
3
+ *
4
+ * Manages registration and discovery of privacy backends.
5
+ * Optionally integrates with BackendHealthTracker for circuit breaker support.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const registry = new PrivacyBackendRegistry()
10
+ *
11
+ * // Register backends
12
+ * registry.register(new SIPNativeBackend())
13
+ * registry.register(new PrivacyCashBackend(), { priority: 10 })
14
+ *
15
+ * // Get backends
16
+ * const all = registry.getAll()
17
+ * const byName = registry.get('sip-native')
18
+ * const forChain = registry.getByChain('solana')
19
+ * const forType = registry.getByType('transaction')
20
+ *
21
+ * // Health-aware operations (when health tracker is attached)
22
+ * const healthy = registry.getHealthy()
23
+ * const health = registry.getHealthState('sip-native')
24
+ * ```
25
+ */
26
+
27
+ import type { ChainType } from '@sip-protocol/types'
28
+ import type {
29
+ PrivacyBackend,
30
+ BackendType,
31
+ BackendRegistrationOptions,
32
+ RegisteredBackend,
33
+ TransferParams,
34
+ AvailabilityResult,
35
+ BackendHealthState,
36
+ BackendMetrics,
37
+ CircuitBreakerConfig,
38
+ } from './interface'
39
+ import { warnIfDeprecatedVersion } from './interface'
40
+ import { BackendHealthTracker } from './health'
41
+ import { RateLimiter, type RateLimiterConfig, type RateLimitStats, type AcquireOptions } from './rate-limiter'
42
+
43
+ /**
44
+ * Default priority for registered backends
45
+ */
46
+ const DEFAULT_PRIORITY = 50
47
+
48
+ /**
49
+ * Registry configuration options
50
+ */
51
+ export interface PrivacyBackendRegistryConfig {
52
+ /**
53
+ * Enable health tracking with circuit breaker
54
+ * @default true
55
+ */
56
+ enableHealthTracking?: boolean
57
+ /**
58
+ * Circuit breaker configuration (when health tracking is enabled)
59
+ */
60
+ circuitBreakerConfig?: Partial<CircuitBreakerConfig>
61
+ /**
62
+ * Enable rate limiting for backends
63
+ * @default false
64
+ */
65
+ enableRateLimiting?: boolean
66
+ /**
67
+ * Rate limiter configuration (when rate limiting is enabled)
68
+ */
69
+ rateLimiterConfig?: RateLimiterConfig
70
+ }
71
+
72
+ /**
73
+ * Registry for managing privacy backends
74
+ *
75
+ * Provides a centralized way to register, discover, and manage
76
+ * different privacy backend implementations. Optionally integrates
77
+ * with BackendHealthTracker for circuit breaker support.
78
+ */
79
+ export class PrivacyBackendRegistry {
80
+ private backends: Map<string, RegisteredBackend> = new Map()
81
+ private healthTracker: BackendHealthTracker | null = null
82
+ private rateLimiter: RateLimiter | null = null
83
+
84
+ /**
85
+ * Create a new registry
86
+ *
87
+ * @param config - Registry configuration
88
+ */
89
+ constructor(config: PrivacyBackendRegistryConfig = {}) {
90
+ const {
91
+ enableHealthTracking = true,
92
+ circuitBreakerConfig,
93
+ enableRateLimiting = false,
94
+ rateLimiterConfig,
95
+ } = config
96
+
97
+ if (enableHealthTracking) {
98
+ this.healthTracker = new BackendHealthTracker(circuitBreakerConfig)
99
+ }
100
+
101
+ if (enableRateLimiting) {
102
+ this.rateLimiter = new RateLimiter(rateLimiterConfig)
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Get the health tracker instance
108
+ *
109
+ * @returns Health tracker or null if not enabled
110
+ */
111
+ getHealthTracker(): BackendHealthTracker | null {
112
+ return this.healthTracker
113
+ }
114
+
115
+ /**
116
+ * Attach an external health tracker
117
+ *
118
+ * Useful for sharing a health tracker between multiple registries
119
+ * or for testing.
120
+ *
121
+ * @param tracker - Health tracker to attach
122
+ */
123
+ setHealthTracker(tracker: BackendHealthTracker | null): void {
124
+ this.healthTracker = tracker
125
+ }
126
+
127
+ /**
128
+ * Get the rate limiter instance
129
+ *
130
+ * @returns Rate limiter or null if not enabled
131
+ */
132
+ getRateLimiter(): RateLimiter | null {
133
+ return this.rateLimiter
134
+ }
135
+
136
+ /**
137
+ * Attach an external rate limiter
138
+ *
139
+ * Useful for sharing a rate limiter between multiple registries
140
+ * or for testing.
141
+ *
142
+ * @param limiter - Rate limiter to attach
143
+ */
144
+ setRateLimiter(limiter: RateLimiter | null): void {
145
+ this.rateLimiter = limiter
146
+ }
147
+
148
+ /**
149
+ * Register a privacy backend
150
+ *
151
+ * @param backend - Backend instance to register
152
+ * @param options - Registration options
153
+ * @throws Error if backend with same name exists and override is false
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * registry.register(new SIPNativeBackend())
158
+ * registry.register(new PrivacyCashBackend(), { priority: 100 })
159
+ * ```
160
+ */
161
+ register(
162
+ backend: PrivacyBackend,
163
+ options: BackendRegistrationOptions = {}
164
+ ): void {
165
+ const { override = false, priority = DEFAULT_PRIORITY, enabled = true } = options
166
+
167
+ if (this.backends.has(backend.name) && !override) {
168
+ throw new Error(
169
+ `Backend '${backend.name}' is already registered. ` +
170
+ `Use { override: true } to replace it.`
171
+ )
172
+ }
173
+
174
+ // Warn about deprecated interface versions
175
+ warnIfDeprecatedVersion(backend)
176
+
177
+ this.backends.set(backend.name, {
178
+ backend,
179
+ priority,
180
+ enabled,
181
+ registeredAt: Date.now(),
182
+ })
183
+
184
+ // Register with health tracker if enabled
185
+ if (this.healthTracker) {
186
+ this.healthTracker.register(backend.name)
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Unregister a backend by name
192
+ *
193
+ * @param name - Backend name to unregister
194
+ * @returns true if backend was removed, false if not found
195
+ */
196
+ unregister(name: string): boolean {
197
+ const removed = this.backends.delete(name)
198
+ if (removed && this.healthTracker) {
199
+ this.healthTracker.unregister(name)
200
+ }
201
+ return removed
202
+ }
203
+
204
+ /**
205
+ * Get a backend by name
206
+ *
207
+ * @param name - Backend name
208
+ * @returns Backend instance or undefined if not found
209
+ */
210
+ get(name: string): PrivacyBackend | undefined {
211
+ const entry = this.backends.get(name)
212
+ return entry?.enabled ? entry.backend : undefined
213
+ }
214
+
215
+ /**
216
+ * Check if a backend is registered
217
+ *
218
+ * @param name - Backend name
219
+ * @returns true if registered (regardless of enabled state)
220
+ */
221
+ has(name: string): boolean {
222
+ return this.backends.has(name)
223
+ }
224
+
225
+ /**
226
+ * Get all enabled backends sorted by priority
227
+ *
228
+ * @returns Array of backends (highest priority first)
229
+ */
230
+ getAll(): PrivacyBackend[] {
231
+ return Array.from(this.backends.values())
232
+ .filter(entry => entry.enabled)
233
+ .sort((a, b) => b.priority - a.priority)
234
+ .map(entry => entry.backend)
235
+ }
236
+
237
+ /**
238
+ * Get all registered entries (including disabled)
239
+ *
240
+ * @returns Array of registered backend entries
241
+ */
242
+ getAllEntries(): RegisteredBackend[] {
243
+ return Array.from(this.backends.values())
244
+ .sort((a, b) => b.priority - a.priority)
245
+ }
246
+
247
+ /**
248
+ * Get backends supporting a specific chain
249
+ *
250
+ * @param chain - Chain type to filter by
251
+ * @returns Array of backends supporting the chain
252
+ */
253
+ getByChain(chain: ChainType): PrivacyBackend[] {
254
+ return this.getAll().filter(backend =>
255
+ backend.chains.includes(chain)
256
+ )
257
+ }
258
+
259
+ /**
260
+ * Get backends of a specific type
261
+ *
262
+ * @param type - Backend type to filter by
263
+ * @returns Array of backends of the specified type
264
+ */
265
+ getByType(type: BackendType): PrivacyBackend[] {
266
+ return this.getAll().filter(backend =>
267
+ backend.type === type || backend.type === 'both'
268
+ )
269
+ }
270
+
271
+ /**
272
+ * Get backends that support compliance (viewing keys)
273
+ *
274
+ * @returns Array of compliance-supporting backends
275
+ */
276
+ getCompliant(): PrivacyBackend[] {
277
+ return this.getAll().filter(backend =>
278
+ backend.getCapabilities().complianceSupport
279
+ )
280
+ }
281
+
282
+ /**
283
+ * Find available backends for a transfer
284
+ *
285
+ * @param params - Transfer parameters
286
+ * @returns Array of available backends with availability info
287
+ */
288
+ async findAvailable(
289
+ params: TransferParams
290
+ ): Promise<Array<{ backend: PrivacyBackend; availability: AvailabilityResult }>> {
291
+ const chainBackends = this.getByChain(params.chain)
292
+ const results: Array<{ backend: PrivacyBackend; availability: AvailabilityResult }> = []
293
+
294
+ for (const backend of chainBackends) {
295
+ const availability = await backend.checkAvailability(params)
296
+ if (availability.available) {
297
+ results.push({ backend, availability })
298
+ }
299
+ }
300
+
301
+ return results
302
+ }
303
+
304
+ /**
305
+ * Enable a backend
306
+ *
307
+ * @param name - Backend name
308
+ * @returns true if backend was enabled, false if not found
309
+ */
310
+ enable(name: string): boolean {
311
+ const entry = this.backends.get(name)
312
+ if (entry) {
313
+ entry.enabled = true
314
+ return true
315
+ }
316
+ return false
317
+ }
318
+
319
+ /**
320
+ * Disable a backend
321
+ *
322
+ * @param name - Backend name
323
+ * @returns true if backend was disabled, false if not found
324
+ */
325
+ disable(name: string): boolean {
326
+ const entry = this.backends.get(name)
327
+ if (entry) {
328
+ entry.enabled = false
329
+ return true
330
+ }
331
+ return false
332
+ }
333
+
334
+ /**
335
+ * Set backend priority
336
+ *
337
+ * @param name - Backend name
338
+ * @param priority - New priority value
339
+ * @returns true if priority was set, false if not found
340
+ */
341
+ setPriority(name: string, priority: number): boolean {
342
+ const entry = this.backends.get(name)
343
+ if (entry) {
344
+ entry.priority = priority
345
+ return true
346
+ }
347
+ return false
348
+ }
349
+
350
+ /**
351
+ * Get count of registered backends
352
+ *
353
+ * @param enabledOnly - If true, only count enabled backends
354
+ * @returns Number of backends
355
+ */
356
+ count(enabledOnly: boolean = false): number {
357
+ if (enabledOnly) {
358
+ return Array.from(this.backends.values()).filter(e => e.enabled).length
359
+ }
360
+ return this.backends.size
361
+ }
362
+
363
+ /**
364
+ * Clear all registered backends
365
+ */
366
+ clear(): void {
367
+ this.backends.clear()
368
+ if (this.healthTracker) {
369
+ this.healthTracker.clear()
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Get backend names
375
+ *
376
+ * @param enabledOnly - If true, only return enabled backend names
377
+ * @returns Array of backend names
378
+ */
379
+ getNames(enabledOnly: boolean = false): string[] {
380
+ if (enabledOnly) {
381
+ return Array.from(this.backends.entries())
382
+ .filter(([, entry]) => entry.enabled)
383
+ .map(([name]) => name)
384
+ }
385
+ return Array.from(this.backends.keys())
386
+ }
387
+
388
+ // ─── Health-Aware Methods ───────────────────────────────────────────────────
389
+
390
+ /**
391
+ * Get all healthy backends (circuit not open)
392
+ *
393
+ * Filters out backends where the circuit breaker is open.
394
+ * Falls back to getAll() if health tracking is disabled.
395
+ *
396
+ * @returns Array of healthy backends
397
+ */
398
+ getHealthy(): PrivacyBackend[] {
399
+ const all = this.getAll()
400
+ if (!this.healthTracker) {
401
+ return all
402
+ }
403
+ return all.filter(backend => this.healthTracker!.isHealthy(backend.name))
404
+ }
405
+
406
+ /**
407
+ * Get healthy backends supporting a specific chain
408
+ *
409
+ * @param chain - Chain type to filter by
410
+ * @returns Array of healthy backends supporting the chain
411
+ */
412
+ getHealthyByChain(chain: ChainType): PrivacyBackend[] {
413
+ return this.getHealthy().filter(backend => backend.chains.includes(chain))
414
+ }
415
+
416
+ /**
417
+ * Get health state for a backend
418
+ *
419
+ * @param name - Backend name
420
+ * @returns Health state or undefined if not tracked
421
+ */
422
+ getHealthState(name: string): BackendHealthState | undefined {
423
+ return this.healthTracker?.getHealth(name)
424
+ }
425
+
426
+ /**
427
+ * Get metrics for a backend
428
+ *
429
+ * @param name - Backend name
430
+ * @returns Metrics or undefined if not tracked
431
+ */
432
+ getMetrics(name: string): BackendMetrics | undefined {
433
+ return this.healthTracker?.getMetrics(name)
434
+ }
435
+
436
+ /**
437
+ * Get summary of all backend health
438
+ *
439
+ * @returns Object with backend names as keys and health info as values
440
+ */
441
+ getHealthSummary(): Record<string, {
442
+ healthy: boolean
443
+ state: string
444
+ failures: number
445
+ lastError?: string
446
+ }> {
447
+ if (!this.healthTracker) {
448
+ // Return all backends as healthy when tracking is disabled
449
+ const summary: Record<string, {
450
+ healthy: boolean
451
+ state: string
452
+ failures: number
453
+ }> = {}
454
+ for (const name of this.getNames()) {
455
+ summary[name] = { healthy: true, state: 'closed', failures: 0 }
456
+ }
457
+ return summary
458
+ }
459
+ return this.healthTracker.getHealthSummary()
460
+ }
461
+
462
+ /**
463
+ * Check if a backend is healthy
464
+ *
465
+ * @param name - Backend name
466
+ * @returns true if healthy or health tracking is disabled
467
+ */
468
+ isHealthy(name: string): boolean {
469
+ if (!this.healthTracker) {
470
+ return true
471
+ }
472
+ return this.healthTracker.isHealthy(name)
473
+ }
474
+
475
+ /**
476
+ * Manually open circuit for a backend
477
+ *
478
+ * Useful for maintenance or known issues.
479
+ *
480
+ * @param name - Backend name
481
+ * @returns true if circuit was opened, false if not found or tracking disabled
482
+ */
483
+ openCircuit(name: string): boolean {
484
+ if (!this.healthTracker || !this.backends.has(name)) {
485
+ return false
486
+ }
487
+ this.healthTracker.forceOpen(name)
488
+ return true
489
+ }
490
+
491
+ /**
492
+ * Manually close circuit for a backend
493
+ *
494
+ * Use with caution - may route requests to failing backend.
495
+ *
496
+ * @param name - Backend name
497
+ * @returns true if circuit was closed, false if not found or tracking disabled
498
+ */
499
+ closeCircuit(name: string): boolean {
500
+ if (!this.healthTracker || !this.backends.has(name)) {
501
+ return false
502
+ }
503
+ this.healthTracker.forceClose(name)
504
+ return true
505
+ }
506
+
507
+ /**
508
+ * Reset health state for a backend
509
+ *
510
+ * Clears failure count and closes circuit.
511
+ *
512
+ * @param name - Backend name
513
+ * @returns true if reset, false if not found or tracking disabled
514
+ */
515
+ resetHealth(name: string): boolean {
516
+ if (!this.healthTracker || !this.backends.has(name)) {
517
+ return false
518
+ }
519
+ this.healthTracker.reset(name)
520
+ return true
521
+ }
522
+
523
+ /**
524
+ * Record a successful execution for a backend
525
+ *
526
+ * @param name - Backend name
527
+ * @param latencyMs - Request latency in milliseconds
528
+ */
529
+ recordSuccess(name: string, latencyMs: number): void {
530
+ if (this.healthTracker) {
531
+ this.healthTracker.recordSuccess(name, latencyMs)
532
+ }
533
+ }
534
+
535
+ /**
536
+ * Record a failed execution for a backend
537
+ *
538
+ * @param name - Backend name
539
+ * @param reason - Failure reason
540
+ */
541
+ recordFailure(name: string, reason: string): void {
542
+ if (this.healthTracker) {
543
+ this.healthTracker.recordFailure(name, reason)
544
+ }
545
+ }
546
+
547
+ // ─── Rate Limiting Methods ─────────────────────────────────────────────────
548
+
549
+ /**
550
+ * Try to acquire rate limit tokens for a backend (non-blocking)
551
+ *
552
+ * @param name - Backend name
553
+ * @param tokens - Number of tokens to acquire (default: 1)
554
+ * @returns true if tokens were acquired, false if rate limited or limiter disabled
555
+ */
556
+ tryAcquire(name: string, tokens: number = 1): boolean {
557
+ if (!this.rateLimiter) {
558
+ return true // No rate limiting enabled
559
+ }
560
+ return this.rateLimiter.tryAcquire(name, tokens)
561
+ }
562
+
563
+ /**
564
+ * Acquire rate limit tokens for a backend (async with queueing)
565
+ *
566
+ * @param name - Backend name
567
+ * @param options - Acquire options (tokens, timeout)
568
+ * @returns Promise resolving when tokens are acquired
569
+ * @throws RateLimitExceededError, QueueFullError, or AcquireTimeoutError
570
+ */
571
+ async acquire(name: string, options?: AcquireOptions): Promise<void> {
572
+ if (!this.rateLimiter) {
573
+ return // No rate limiting enabled
574
+ }
575
+ await this.rateLimiter.acquire(name, options)
576
+ }
577
+
578
+ /**
579
+ * Check if tokens can be acquired without consuming them
580
+ *
581
+ * @param name - Backend name
582
+ * @param tokens - Number of tokens to check (default: 1)
583
+ * @returns true if tokens are available
584
+ */
585
+ canAcquire(name: string, tokens: number = 1): boolean {
586
+ if (!this.rateLimiter) {
587
+ return true // No rate limiting enabled
588
+ }
589
+ return this.rateLimiter.canAcquire(name, tokens)
590
+ }
591
+
592
+ /**
593
+ * Get rate limit statistics for a backend
594
+ *
595
+ * @param name - Backend name
596
+ * @returns Rate limit stats or undefined if limiter disabled
597
+ */
598
+ getRateLimitStats(name: string): RateLimitStats | undefined {
599
+ return this.rateLimiter?.getStats(name)
600
+ }
601
+
602
+ /**
603
+ * Check if a backend is rate limited (no tokens available)
604
+ *
605
+ * @param name - Backend name
606
+ * @returns true if rate limited, false if available or limiter disabled
607
+ */
608
+ isRateLimited(name: string): boolean {
609
+ if (!this.rateLimiter) {
610
+ return false
611
+ }
612
+ return !this.rateLimiter.canAcquire(name)
613
+ }
614
+
615
+ /**
616
+ * Get all backends that are NOT rate limited
617
+ *
618
+ * @returns Array of backends with available rate limit tokens
619
+ */
620
+ getAvailable(): PrivacyBackend[] {
621
+ const all = this.getAll()
622
+ if (!this.rateLimiter) {
623
+ return all
624
+ }
625
+ return all.filter(backend => this.rateLimiter!.canAcquire(backend.name))
626
+ }
627
+
628
+ /**
629
+ * Get available backends for a specific chain
630
+ *
631
+ * Filters by both chain support and rate limit availability.
632
+ *
633
+ * @param chain - Chain type to filter by
634
+ * @returns Array of available backends supporting the chain
635
+ */
636
+ getAvailableByChain(chain: ChainType): PrivacyBackend[] {
637
+ return this.getAvailable().filter(backend => backend.chains.includes(chain))
638
+ }
639
+
640
+ /**
641
+ * Get backends that are both healthy AND not rate limited
642
+ *
643
+ * @returns Array of backends ready for use
644
+ */
645
+ getReady(): PrivacyBackend[] {
646
+ const healthy = this.getHealthy()
647
+ if (!this.rateLimiter) {
648
+ return healthy
649
+ }
650
+ return healthy.filter(backend => this.rateLimiter!.canAcquire(backend.name))
651
+ }
652
+
653
+ /**
654
+ * Get ready backends for a specific chain
655
+ *
656
+ * @param chain - Chain type to filter by
657
+ * @returns Array of ready backends supporting the chain
658
+ */
659
+ getReadyByChain(chain: ChainType): PrivacyBackend[] {
660
+ return this.getReady().filter(backend => backend.chains.includes(chain))
661
+ }
662
+
663
+ /**
664
+ * Reset rate limit state for a backend
665
+ *
666
+ * Refills bucket to max tokens and clears stats.
667
+ *
668
+ * @param name - Backend name
669
+ */
670
+ resetRateLimit(name: string): void {
671
+ this.rateLimiter?.reset(name)
672
+ }
673
+
674
+ /**
675
+ * Dispose rate limiter resources
676
+ *
677
+ * Call when shutting down to clean up queue processing intervals.
678
+ */
679
+ disposeRateLimiter(): void {
680
+ this.rateLimiter?.dispose()
681
+ }
682
+ }
683
+
684
+ /**
685
+ * Global default registry instance
686
+ *
687
+ * Use this for simple applications, or create your own instance
688
+ * for more control.
689
+ */
690
+ export const defaultRegistry = new PrivacyBackendRegistry()