@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.
- package/LICENSE +21 -0
- package/README.md +267 -0
- package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
- package/dist/browser.d.mts +10 -4
- package/dist/browser.d.ts +10 -4
- package/dist/browser.js +48874 -18336
- package/dist/browser.mjs +674 -48
- package/dist/chunk-4GRJ5MAW.mjs +152 -0
- package/dist/chunk-5D7A3L3W.mjs +717 -0
- package/dist/chunk-64AYA5F5.mjs +7834 -0
- package/dist/chunk-GMDGB22A.mjs +379 -0
- package/dist/chunk-I534WKN7.mjs +328 -0
- package/dist/chunk-IBZVA5Y7.mjs +1003 -0
- package/dist/chunk-PRRZAWJE.mjs +223 -0
- package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
- package/dist/chunk-YWGJ77A2.mjs +33806 -0
- package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
- package/dist/constants-LHAAUC2T.mjs +51 -0
- package/dist/dist-2OGQ7FED.mjs +3957 -0
- package/dist/dist-IFHPYLDX.mjs +254 -0
- package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
- package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
- package/dist/index-DXh2IGkz.d.ts +24681 -0
- package/dist/index-DeE1ZzA4.d.mts +24681 -0
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48676 -17318
- package/dist/index.mjs +583 -19
- package/dist/interface-Bf7w1PLW.d.mts +679 -0
- package/dist/interface-Bf7w1PLW.d.ts +679 -0
- package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
- package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
- package/dist/proofs/halo2.d.mts +151 -0
- package/dist/proofs/halo2.d.ts +151 -0
- package/dist/proofs/halo2.js +350 -0
- package/dist/proofs/halo2.mjs +11 -0
- package/dist/proofs/kimchi.d.mts +160 -0
- package/dist/proofs/kimchi.d.ts +160 -0
- package/dist/proofs/kimchi.js +431 -0
- package/dist/proofs/kimchi.mjs +13 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +74 -18
- package/dist/proofs/noir.mjs +84 -24
- package/dist/solana-U3MEGU7W.mjs +280 -0
- package/dist/validity_proof-3POXLPNY.mjs +21 -0
- package/package.json +54 -21
- package/src/adapters/index.ts +41 -0
- package/src/adapters/jupiter.ts +571 -0
- package/src/adapters/near-intents.ts +135 -0
- package/src/advisor/advisor.ts +653 -0
- package/src/advisor/index.ts +54 -0
- package/src/advisor/tools.ts +303 -0
- package/src/advisor/types.ts +164 -0
- package/src/chains/ethereum/announcement.ts +536 -0
- package/src/chains/ethereum/bnb-optimizations.ts +474 -0
- package/src/chains/ethereum/commitment.ts +522 -0
- package/src/chains/ethereum/constants.ts +462 -0
- package/src/chains/ethereum/deployment.ts +596 -0
- package/src/chains/ethereum/gas-estimation.ts +538 -0
- package/src/chains/ethereum/index.ts +268 -0
- package/src/chains/ethereum/optimizations.ts +614 -0
- package/src/chains/ethereum/privacy-adapter.ts +855 -0
- package/src/chains/ethereum/registry.ts +584 -0
- package/src/chains/ethereum/rpc.ts +905 -0
- package/src/chains/ethereum/stealth.ts +491 -0
- package/src/chains/ethereum/token.ts +790 -0
- package/src/chains/ethereum/transfer.ts +637 -0
- package/src/chains/ethereum/types.ts +456 -0
- package/src/chains/ethereum/viewing-key.ts +455 -0
- package/src/chains/near/commitment.ts +608 -0
- package/src/chains/near/constants.ts +284 -0
- package/src/chains/near/function-call.ts +871 -0
- package/src/chains/near/history.ts +654 -0
- package/src/chains/near/implicit-account.ts +840 -0
- package/src/chains/near/index.ts +393 -0
- package/src/chains/near/native-transfer.ts +658 -0
- package/src/chains/near/nep141.ts +775 -0
- package/src/chains/near/privacy-adapter.ts +889 -0
- package/src/chains/near/resolver.ts +971 -0
- package/src/chains/near/rpc.ts +1016 -0
- package/src/chains/near/stealth.ts +419 -0
- package/src/chains/near/types.ts +317 -0
- package/src/chains/near/viewing-key.ts +876 -0
- package/src/chains/solana/anchor-transfer.ts +386 -0
- package/src/chains/solana/commitment.ts +577 -0
- package/src/chains/solana/constants.ts +126 -12
- package/src/chains/solana/ephemeral-keys.ts +543 -0
- package/src/chains/solana/index.ts +276 -1
- package/src/chains/solana/key-derivation.ts +418 -0
- package/src/chains/solana/kit-compat.ts +334 -0
- package/src/chains/solana/optimizations.ts +560 -0
- package/src/chains/solana/privacy-adapter.ts +605 -0
- package/src/chains/solana/providers/generic.ts +201 -0
- package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
- package/src/chains/solana/providers/helius-enhanced.ts +623 -0
- package/src/chains/solana/providers/helius.ts +402 -0
- package/src/chains/solana/providers/index.ts +85 -0
- package/src/chains/solana/providers/interface.ts +221 -0
- package/src/chains/solana/providers/quicknode.ts +409 -0
- package/src/chains/solana/providers/triton.ts +426 -0
- package/src/chains/solana/providers/webhook.ts +790 -0
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +170 -73
- package/src/chains/solana/sol-transfer.ts +732 -0
- package/src/chains/solana/spl-transfer.ts +886 -0
- package/src/chains/solana/stealth-scanner.ts +703 -0
- package/src/chains/solana/sunspot-verifier.ts +453 -0
- package/src/chains/solana/transaction-builder.ts +755 -0
- package/src/chains/solana/transfer.ts +74 -5
- package/src/chains/solana/types.ts +77 -7
- package/src/chains/solana/utils.ts +110 -0
- package/src/chains/solana/viewing-key.ts +807 -0
- package/src/compliance/fireblocks.ts +921 -0
- package/src/compliance/index.ts +37 -0
- package/src/compliance/range-sas.ts +956 -0
- package/src/config/endpoints.ts +100 -0
- package/src/crypto.ts +11 -8
- package/src/errors.ts +82 -0
- package/src/evm/erc4337-relayer.ts +830 -0
- package/src/evm/index.ts +47 -0
- package/src/fees/calculator.ts +396 -0
- package/src/fees/index.ts +87 -0
- package/src/fees/near-contract.ts +429 -0
- package/src/fees/types.ts +268 -0
- package/src/index.ts +785 -1
- package/src/intent.ts +6 -3
- package/src/logger.ts +324 -0
- package/src/network/index.ts +80 -0
- package/src/network/proxy.ts +691 -0
- package/src/optimizations/index.ts +541 -0
- package/src/oracle/types.ts +1 -0
- package/src/privacy-backends/arcium-types.ts +727 -0
- package/src/privacy-backends/arcium.ts +719 -0
- package/src/privacy-backends/combined-privacy.ts +866 -0
- package/src/privacy-backends/cspl-token.ts +595 -0
- package/src/privacy-backends/cspl-types.ts +512 -0
- package/src/privacy-backends/cspl.ts +907 -0
- package/src/privacy-backends/health.ts +488 -0
- package/src/privacy-backends/inco-types.ts +323 -0
- package/src/privacy-backends/inco.ts +616 -0
- package/src/privacy-backends/index.ts +336 -0
- package/src/privacy-backends/interface.ts +906 -0
- package/src/privacy-backends/lru-cache.ts +343 -0
- package/src/privacy-backends/magicblock.ts +458 -0
- package/src/privacy-backends/mock.ts +258 -0
- package/src/privacy-backends/privacycash-types.ts +278 -0
- package/src/privacy-backends/privacycash.ts +456 -0
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +690 -0
- package/src/privacy-backends/router.ts +626 -0
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +256 -0
- package/src/privacy-logger.ts +191 -0
- package/src/production-safety.ts +373 -0
- package/src/proofs/aggregator.ts +1029 -0
- package/src/proofs/browser-composer.ts +1150 -0
- package/src/proofs/browser.ts +113 -25
- package/src/proofs/cache/index.ts +127 -0
- package/src/proofs/cache/interface.ts +545 -0
- package/src/proofs/cache/key-generator.ts +188 -0
- package/src/proofs/cache/lru-cache.ts +481 -0
- package/src/proofs/cache/multi-tier-cache.ts +575 -0
- package/src/proofs/cache/persistent-cache.ts +788 -0
- package/src/proofs/compliance-proof.ts +872 -0
- package/src/proofs/composer/base.ts +923 -0
- package/src/proofs/composer/index.ts +25 -0
- package/src/proofs/composer/interface.ts +518 -0
- package/src/proofs/composer/types.ts +383 -0
- package/src/proofs/converters/halo2.ts +452 -0
- package/src/proofs/converters/index.ts +208 -0
- package/src/proofs/converters/interface.ts +363 -0
- package/src/proofs/converters/kimchi.ts +462 -0
- package/src/proofs/converters/noir.ts +451 -0
- package/src/proofs/fallback.ts +888 -0
- package/src/proofs/halo2.ts +42 -0
- package/src/proofs/index.ts +471 -0
- package/src/proofs/interface.ts +13 -0
- package/src/proofs/kimchi.ts +42 -0
- package/src/proofs/lazy.ts +1004 -0
- package/src/proofs/mock.ts +25 -1
- package/src/proofs/noir.ts +111 -30
- package/src/proofs/orchestrator.ts +960 -0
- package/src/proofs/parallel/concurrency.ts +297 -0
- package/src/proofs/parallel/dependency-graph.ts +602 -0
- package/src/proofs/parallel/executor.ts +420 -0
- package/src/proofs/parallel/index.ts +131 -0
- package/src/proofs/parallel/interface.ts +685 -0
- package/src/proofs/parallel/worker-pool.ts +644 -0
- package/src/proofs/providers/halo2.ts +560 -0
- package/src/proofs/providers/index.ts +34 -0
- package/src/proofs/providers/kimchi.ts +641 -0
- package/src/proofs/validator.ts +881 -0
- package/src/proofs/verifier.ts +867 -0
- package/src/quantum/index.ts +112 -0
- package/src/quantum/winternitz-vault.ts +639 -0
- package/src/quantum/wots.ts +611 -0
- package/src/settlement/backends/direct-chain.ts +1 -0
- package/src/settlement/index.ts +9 -0
- package/src/settlement/router.ts +732 -46
- package/src/solana/index.ts +72 -0
- package/src/solana/jito-relayer.ts +687 -0
- package/src/solana/noir-verifier-types.ts +430 -0
- package/src/solana/noir-verifier.ts +816 -0
- package/src/stealth/address-derivation.ts +193 -0
- package/src/stealth/ed25519.ts +431 -0
- package/src/stealth/index.ts +233 -0
- package/src/stealth/meta-address.ts +221 -0
- package/src/stealth/secp256k1.ts +368 -0
- package/src/stealth/utils.ts +194 -0
- package/src/stealth.ts +50 -1504
- package/src/surveillance/algorithms/address-reuse.ts +143 -0
- package/src/surveillance/algorithms/cluster.ts +247 -0
- package/src/surveillance/algorithms/exchange.ts +295 -0
- package/src/surveillance/algorithms/temporal.ts +337 -0
- package/src/surveillance/analyzer.ts +442 -0
- package/src/surveillance/index.ts +64 -0
- package/src/surveillance/scoring.ts +372 -0
- package/src/surveillance/types.ts +264 -0
- package/src/sync/index.ts +106 -0
- package/src/sync/manager.ts +504 -0
- package/src/sync/mock-provider.ts +318 -0
- package/src/sync/oblivious.ts +625 -0
- package/src/tokens/index.ts +15 -0
- package/src/tokens/registry.ts +301 -0
- package/src/utils/deprecation.ts +94 -0
- package/src/utils/index.ts +9 -0
- package/src/wallet/ethereum/index.ts +68 -0
- package/src/wallet/ethereum/metamask-privacy.ts +420 -0
- package/src/wallet/ethereum/multi-wallet.ts +646 -0
- package/src/wallet/ethereum/privacy-adapter.ts +700 -0
- package/src/wallet/ethereum/types.ts +3 -1
- package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
- package/src/wallet/hardware/index.ts +10 -0
- package/src/wallet/hardware/ledger-privacy.ts +414 -0
- package/src/wallet/index.ts +71 -0
- package/src/wallet/near/adapter.ts +626 -0
- package/src/wallet/near/index.ts +86 -0
- package/src/wallet/near/meteor-wallet.ts +1153 -0
- package/src/wallet/near/my-near-wallet.ts +790 -0
- package/src/wallet/near/wallet-selector.ts +702 -0
- package/src/wallet/solana/adapter.ts +6 -4
- package/src/wallet/solana/index.ts +13 -0
- package/src/wallet/solana/privacy-adapter.ts +567 -0
- package/src/wallet/sui/types.ts +6 -4
- package/src/zcash/rpc-client.ts +13 -6
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-BYZbDjal.d.ts +0 -11390
- package/dist/index-CHB3KuOB.d.mts +0 -11859
- package/dist/index-CzWPI6Le.d.ts +0 -11859
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-5EMCTPTS.mjs +0 -46
- package/dist/solana-Q4NAVBTS.mjs +0 -46
|
@@ -0,0 +1,906 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privacy Backend Interface
|
|
3
|
+
*
|
|
4
|
+
* Unified interface for all privacy approaches in SIP Protocol.
|
|
5
|
+
* Enables SIP as a Privacy Aggregator across different backends.
|
|
6
|
+
*
|
|
7
|
+
* ## Architecture
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* TRANSACTION PRIVACY (Who sends what to whom):
|
|
11
|
+
* • SIP Native — Stealth addresses + Pedersen commitments
|
|
12
|
+
* • PrivacyCash — Pool mixing (integrated as backend)
|
|
13
|
+
*
|
|
14
|
+
* COMPUTE PRIVACY (What happens inside contracts):
|
|
15
|
+
* • Arcium — MPC (Multi-Party Computation)
|
|
16
|
+
* • Inco — FHE (Fully Homomorphic Encryption)
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { PrivacyBackendRegistry, SIPNativeBackend } from '@sip-protocol/sdk'
|
|
22
|
+
*
|
|
23
|
+
* // Register backends
|
|
24
|
+
* const registry = new PrivacyBackendRegistry()
|
|
25
|
+
* registry.register(new SIPNativeBackend())
|
|
26
|
+
*
|
|
27
|
+
* // Use SmartRouter for auto-selection
|
|
28
|
+
* const router = new SmartRouter(registry)
|
|
29
|
+
* const result = await router.execute(params, {
|
|
30
|
+
* prioritize: 'compliance',
|
|
31
|
+
* requireViewingKeys: true,
|
|
32
|
+
* })
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @packageDocumentation
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import type { ChainType, HexString, ViewingKey } from '@sip-protocol/types'
|
|
39
|
+
|
|
40
|
+
// ─── Core Types ──────────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Privacy backend type classification
|
|
44
|
+
*
|
|
45
|
+
* - `transaction`: Hides sender, recipient, amount (SIP Native, PrivacyCash)
|
|
46
|
+
* - `compute`: Hides computation logic (Arcium, Inco)
|
|
47
|
+
* - `both`: Full privacy stack
|
|
48
|
+
*/
|
|
49
|
+
export type BackendType = 'transaction' | 'compute' | 'both'
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Latency estimate for backend operations
|
|
53
|
+
*/
|
|
54
|
+
export type LatencyEstimate = 'fast' | 'medium' | 'slow'
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Backend capabilities describing what privacy features are supported
|
|
58
|
+
*/
|
|
59
|
+
export interface BackendCapabilities {
|
|
60
|
+
/** Whether transaction amounts are hidden */
|
|
61
|
+
hiddenAmount: boolean
|
|
62
|
+
/** Whether sender address is hidden */
|
|
63
|
+
hiddenSender: boolean
|
|
64
|
+
/** Whether recipient address is hidden */
|
|
65
|
+
hiddenRecipient: boolean
|
|
66
|
+
/** Whether smart contract computation is private */
|
|
67
|
+
hiddenCompute: boolean
|
|
68
|
+
/** Whether viewing keys are supported for compliance */
|
|
69
|
+
complianceSupport: boolean
|
|
70
|
+
/** Size of anonymity set (for pool-based mixers) */
|
|
71
|
+
anonymitySet?: number
|
|
72
|
+
/** Whether setup is required before use (FHE, MPC coordination) */
|
|
73
|
+
setupRequired: boolean
|
|
74
|
+
/** Estimated latency for operations */
|
|
75
|
+
latencyEstimate: LatencyEstimate
|
|
76
|
+
/** Supported token types */
|
|
77
|
+
supportedTokens: 'native' | 'spl' | 'all'
|
|
78
|
+
/** Minimum transfer amount (if any) */
|
|
79
|
+
minAmount?: bigint
|
|
80
|
+
/** Maximum transfer amount (if any) */
|
|
81
|
+
maxAmount?: bigint
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Parameters for a privacy-preserving transfer
|
|
86
|
+
*/
|
|
87
|
+
export interface TransferParams {
|
|
88
|
+
/** Source chain */
|
|
89
|
+
chain: ChainType
|
|
90
|
+
/** Sender address (may be hidden by backend) */
|
|
91
|
+
sender: string
|
|
92
|
+
/** Recipient address or stealth address */
|
|
93
|
+
recipient: string
|
|
94
|
+
/** Token mint address (null for native token) */
|
|
95
|
+
mint: string | null
|
|
96
|
+
/** Transfer amount in smallest units */
|
|
97
|
+
amount: bigint
|
|
98
|
+
/** Token decimals */
|
|
99
|
+
decimals: number
|
|
100
|
+
/** Viewing key for compliance (optional) */
|
|
101
|
+
viewingKey?: ViewingKey
|
|
102
|
+
/** Additional backend-specific options */
|
|
103
|
+
options?: Record<string, unknown>
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Result of a privacy-preserving transfer
|
|
108
|
+
*/
|
|
109
|
+
export interface TransactionResult {
|
|
110
|
+
/** Whether the transaction was successful */
|
|
111
|
+
success: boolean
|
|
112
|
+
/** Transaction signature/hash */
|
|
113
|
+
signature?: string
|
|
114
|
+
/** Error message if failed */
|
|
115
|
+
error?: string
|
|
116
|
+
/** Backend that executed the transaction */
|
|
117
|
+
backend: string
|
|
118
|
+
/** Encrypted transaction data (for viewing key holders) */
|
|
119
|
+
encryptedData?: HexString
|
|
120
|
+
/** Proof data (for ZK backends) */
|
|
121
|
+
proof?: HexString
|
|
122
|
+
/** Additional metadata */
|
|
123
|
+
metadata?: Record<string, unknown>
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Backend availability check result
|
|
128
|
+
*/
|
|
129
|
+
export interface AvailabilityResult {
|
|
130
|
+
/** Whether the backend can handle this transfer */
|
|
131
|
+
available: boolean
|
|
132
|
+
/** Reason if not available */
|
|
133
|
+
reason?: string
|
|
134
|
+
/** Estimated cost (in lamports/gas) */
|
|
135
|
+
estimatedCost?: bigint
|
|
136
|
+
/** Estimated time in milliseconds */
|
|
137
|
+
estimatedTime?: number
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ─── Compute Privacy Types ───────────────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Supported cipher types for encrypted computation
|
|
144
|
+
*/
|
|
145
|
+
export type CipherType = 'aes128' | 'aes192' | 'aes256' | 'rescue'
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Computation status for tracking MPC/FHE operations
|
|
149
|
+
*/
|
|
150
|
+
export type ComputationStatus =
|
|
151
|
+
| 'submitted'
|
|
152
|
+
| 'encrypting'
|
|
153
|
+
| 'processing'
|
|
154
|
+
| 'finalizing'
|
|
155
|
+
| 'completed'
|
|
156
|
+
| 'failed'
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Parameters for a privacy-preserving computation
|
|
160
|
+
*
|
|
161
|
+
* Used by compute backends (Arcium, Inco) for MPC/FHE operations.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const params: ComputationParams = {
|
|
166
|
+
* chain: 'solana',
|
|
167
|
+
* circuitId: 'private-swap',
|
|
168
|
+
* encryptedInputs: [encryptedAmount, encryptedPrice],
|
|
169
|
+
* cluster: 'mainnet-cluster-1',
|
|
170
|
+
* }
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export interface ComputationParams {
|
|
174
|
+
/** Target blockchain */
|
|
175
|
+
chain: ChainType
|
|
176
|
+
/** Circuit or program identifier for the computation */
|
|
177
|
+
circuitId: string
|
|
178
|
+
/** Encrypted inputs for the MPC/FHE computation */
|
|
179
|
+
encryptedInputs: Uint8Array[]
|
|
180
|
+
/** MPC cluster or FHE node to use */
|
|
181
|
+
cluster?: string
|
|
182
|
+
/** Callback address for computation results */
|
|
183
|
+
callbackAddress?: string
|
|
184
|
+
/** Cipher type for input encryption */
|
|
185
|
+
cipher?: CipherType
|
|
186
|
+
/** Timeout in milliseconds */
|
|
187
|
+
timeout?: number
|
|
188
|
+
/** Additional backend-specific options */
|
|
189
|
+
options?: Record<string, unknown>
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Result of a privacy-preserving computation
|
|
194
|
+
*
|
|
195
|
+
* Returned by compute backends after MPC/FHE execution.
|
|
196
|
+
*/
|
|
197
|
+
export interface ComputationResult {
|
|
198
|
+
/** Whether the computation was successful */
|
|
199
|
+
success: boolean
|
|
200
|
+
/** Unique computation identifier for tracking */
|
|
201
|
+
computationId?: string
|
|
202
|
+
/** Decrypted output data (if available and authorized) */
|
|
203
|
+
output?: Uint8Array
|
|
204
|
+
/** Error message if failed */
|
|
205
|
+
error?: string
|
|
206
|
+
/** Backend that executed the computation */
|
|
207
|
+
backend: string
|
|
208
|
+
/** Current computation status */
|
|
209
|
+
status?: ComputationStatus
|
|
210
|
+
/** Cryptographic proof of correct computation */
|
|
211
|
+
proof?: HexString
|
|
212
|
+
/** Timestamp when computation completed */
|
|
213
|
+
completedAt?: number
|
|
214
|
+
/** Additional metadata */
|
|
215
|
+
metadata?: Record<string, unknown>
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Union type for backend operation parameters
|
|
220
|
+
*
|
|
221
|
+
* Backends accept either transfer params (transaction privacy)
|
|
222
|
+
* or computation params (compute privacy).
|
|
223
|
+
*/
|
|
224
|
+
export type BackendParams = TransferParams | ComputationParams
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Type guard to check if params are for computation
|
|
228
|
+
*/
|
|
229
|
+
export function isComputationParams(
|
|
230
|
+
params: BackendParams
|
|
231
|
+
): params is ComputationParams {
|
|
232
|
+
return 'circuitId' in params && 'encryptedInputs' in params
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Type guard to check if params are for transfer
|
|
237
|
+
*/
|
|
238
|
+
export function isTransferParams(
|
|
239
|
+
params: BackendParams
|
|
240
|
+
): params is TransferParams {
|
|
241
|
+
return 'sender' in params && 'recipient' in params && 'amount' in params
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ─── Interface Versioning ────────────────────────────────────────────────────
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* PrivacyBackend interface version
|
|
248
|
+
*
|
|
249
|
+
* ## Version History
|
|
250
|
+
*
|
|
251
|
+
* - **v1** (initial): Basic backend interface with execute/checkAvailability
|
|
252
|
+
* - **v2** (current): Added version field, compute privacy support, circuit breaker integration
|
|
253
|
+
*
|
|
254
|
+
* ## Migration Guide
|
|
255
|
+
*
|
|
256
|
+
* ### v1 → v2
|
|
257
|
+
*
|
|
258
|
+
* 1. Add `version` property (set to 2)
|
|
259
|
+
* 2. Optional: Implement `executeComputation()` for compute backends
|
|
260
|
+
* 3. Optional: Add circuit breaker integration via `onHealthChange` callback
|
|
261
|
+
*
|
|
262
|
+
* ```typescript
|
|
263
|
+
* // v1 backend (deprecated)
|
|
264
|
+
* class MyBackendV1 implements PrivacyBackend {
|
|
265
|
+
* name = 'my-backend'
|
|
266
|
+
* type = 'transaction'
|
|
267
|
+
* chains = ['solana']
|
|
268
|
+
* // ... no version field
|
|
269
|
+
* }
|
|
270
|
+
*
|
|
271
|
+
* // v2 backend (current)
|
|
272
|
+
* class MyBackendV2 implements PrivacyBackend {
|
|
273
|
+
* version = 2
|
|
274
|
+
* name = 'my-backend'
|
|
275
|
+
* type = 'transaction'
|
|
276
|
+
* chains = ['solana']
|
|
277
|
+
* // ...
|
|
278
|
+
* }
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
export type PrivacyBackendVersion = 1 | 2
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Current interface version
|
|
285
|
+
*/
|
|
286
|
+
export const CURRENT_BACKEND_VERSION: PrivacyBackendVersion = 2
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Minimum supported version (backends below this will be rejected)
|
|
290
|
+
*/
|
|
291
|
+
export const MIN_SUPPORTED_VERSION: PrivacyBackendVersion = 1
|
|
292
|
+
|
|
293
|
+
// ─── Privacy Backend Interface ───────────────────────────────────────────────
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Core interface for all privacy backends
|
|
297
|
+
*
|
|
298
|
+
* All privacy implementations (SIP Native, PrivacyCash, Arcium, Inco)
|
|
299
|
+
* must implement this interface for unified access.
|
|
300
|
+
*
|
|
301
|
+
* ## Interface Version
|
|
302
|
+
*
|
|
303
|
+
* The current interface version is **v2**. Backends should set `version: 2`.
|
|
304
|
+
* v1 backends without a version field are still supported but deprecated.
|
|
305
|
+
*
|
|
306
|
+
* ## Backend Types
|
|
307
|
+
*
|
|
308
|
+
* - **Transaction backends** (type: 'transaction'): Implement `execute()` for transfers
|
|
309
|
+
* - **Compute backends** (type: 'compute'): Implement `executeComputation()` for MPC/FHE
|
|
310
|
+
* - **Hybrid backends** (type: 'both'): Implement both methods
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```typescript
|
|
314
|
+
* // Transaction backend usage
|
|
315
|
+
* const sipNative = new SIPNativeBackend()
|
|
316
|
+
* await sipNative.execute({ chain: 'solana', sender, recipient, amount, ... })
|
|
317
|
+
*
|
|
318
|
+
* // Compute backend usage
|
|
319
|
+
* const arcium = new ArciumBackend()
|
|
320
|
+
* await arcium.executeComputation({ chain: 'solana', circuitId, encryptedInputs, ... })
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
323
|
+
export interface PrivacyBackend {
|
|
324
|
+
/**
|
|
325
|
+
* Interface version implemented by this backend
|
|
326
|
+
*
|
|
327
|
+
* - v1: Initial interface (deprecated, no version field)
|
|
328
|
+
* - v2: Current interface with versioning support
|
|
329
|
+
*
|
|
330
|
+
* Backends without a version field are treated as v1 with deprecation warning.
|
|
331
|
+
*
|
|
332
|
+
* @default 1 (for backwards compatibility)
|
|
333
|
+
*/
|
|
334
|
+
readonly version?: PrivacyBackendVersion
|
|
335
|
+
|
|
336
|
+
/** Unique backend identifier */
|
|
337
|
+
readonly name: string
|
|
338
|
+
|
|
339
|
+
/** Backend type classification */
|
|
340
|
+
readonly type: BackendType
|
|
341
|
+
|
|
342
|
+
/** Supported blockchain networks */
|
|
343
|
+
readonly chains: string[]
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Check if backend is available for given parameters
|
|
347
|
+
*
|
|
348
|
+
* Accepts either TransferParams (for transaction backends) or
|
|
349
|
+
* ComputationParams (for compute backends).
|
|
350
|
+
*
|
|
351
|
+
* @param params - Transfer or computation parameters
|
|
352
|
+
* @returns Availability result with cost/time estimates
|
|
353
|
+
*/
|
|
354
|
+
checkAvailability(params: BackendParams): Promise<AvailabilityResult>
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Get backend capabilities and trade-offs
|
|
358
|
+
*
|
|
359
|
+
* @returns Static capability description
|
|
360
|
+
*/
|
|
361
|
+
getCapabilities(): BackendCapabilities
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Execute a privacy-preserving transfer
|
|
365
|
+
*
|
|
366
|
+
* Implemented by transaction backends (SIP Native, PrivacyCash).
|
|
367
|
+
* Compute backends should return an error directing users to executeComputation().
|
|
368
|
+
*
|
|
369
|
+
* @param params - Transfer parameters
|
|
370
|
+
* @returns Transaction result
|
|
371
|
+
*/
|
|
372
|
+
execute(params: TransferParams): Promise<TransactionResult>
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Execute a privacy-preserving computation
|
|
376
|
+
*
|
|
377
|
+
* Implemented by compute backends (Arcium, Inco).
|
|
378
|
+
* Transaction backends do not implement this method.
|
|
379
|
+
*
|
|
380
|
+
* @param params - Computation parameters
|
|
381
|
+
* @returns Computation result with status and output
|
|
382
|
+
*/
|
|
383
|
+
executeComputation?(params: ComputationParams): Promise<ComputationResult>
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Estimate cost for an operation (without executing)
|
|
387
|
+
*
|
|
388
|
+
* Accepts either TransferParams or ComputationParams.
|
|
389
|
+
*
|
|
390
|
+
* @param params - Transfer or computation parameters
|
|
391
|
+
* @returns Estimated cost in native token smallest units
|
|
392
|
+
*/
|
|
393
|
+
estimateCost(params: BackendParams): Promise<bigint>
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// ─── SmartRouter Types ───────────────────────────────────────────────────────
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Priority for backend selection
|
|
400
|
+
*/
|
|
401
|
+
export type RouterPriority = 'privacy' | 'speed' | 'cost' | 'compliance'
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Configuration for SmartRouter backend selection
|
|
405
|
+
*/
|
|
406
|
+
export interface SmartRouterConfig {
|
|
407
|
+
/** What to prioritize when selecting backend */
|
|
408
|
+
prioritize: RouterPriority
|
|
409
|
+
/** Minimum anonymity set size (for pool mixers) */
|
|
410
|
+
minAnonymitySet?: number
|
|
411
|
+
/** Require viewing key support */
|
|
412
|
+
requireViewingKeys?: boolean
|
|
413
|
+
/** Allow compute privacy backends */
|
|
414
|
+
allowComputePrivacy?: boolean
|
|
415
|
+
/** Preferred backend name (hint, not requirement) */
|
|
416
|
+
preferredBackend?: string
|
|
417
|
+
/** Excluded backend names */
|
|
418
|
+
excludeBackends?: string[]
|
|
419
|
+
/** Maximum acceptable cost */
|
|
420
|
+
maxCost?: bigint
|
|
421
|
+
/** Maximum acceptable latency in ms */
|
|
422
|
+
maxLatency?: number
|
|
423
|
+
/**
|
|
424
|
+
* Enable automatic fallback to alternative backends on failure
|
|
425
|
+
* @default true
|
|
426
|
+
*/
|
|
427
|
+
enableFallback?: boolean
|
|
428
|
+
/**
|
|
429
|
+
* Include unhealthy backends (circuit open) in selection
|
|
430
|
+
* @default false
|
|
431
|
+
*/
|
|
432
|
+
includeUnhealthy?: boolean
|
|
433
|
+
/**
|
|
434
|
+
* Maximum number of fallback attempts
|
|
435
|
+
* @default 3
|
|
436
|
+
*/
|
|
437
|
+
maxFallbackAttempts?: number
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Result of backend selection
|
|
442
|
+
*/
|
|
443
|
+
export interface BackendSelectionResult {
|
|
444
|
+
/** Selected backend */
|
|
445
|
+
backend: PrivacyBackend
|
|
446
|
+
/** Why this backend was selected */
|
|
447
|
+
reason: string
|
|
448
|
+
/** Other considered backends */
|
|
449
|
+
alternatives: Array<{
|
|
450
|
+
backend: PrivacyBackend
|
|
451
|
+
score: number
|
|
452
|
+
reason: string
|
|
453
|
+
}>
|
|
454
|
+
/** Selection score (0-100) */
|
|
455
|
+
score: number
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// ─── Registry Types ──────────────────────────────────────────────────────────
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Backend registration options
|
|
462
|
+
*/
|
|
463
|
+
export interface BackendRegistrationOptions {
|
|
464
|
+
/** Override existing backend with same name */
|
|
465
|
+
override?: boolean
|
|
466
|
+
/** Backend priority (higher = preferred) */
|
|
467
|
+
priority?: number
|
|
468
|
+
/** Whether backend is enabled by default */
|
|
469
|
+
enabled?: boolean
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Registered backend entry
|
|
474
|
+
*/
|
|
475
|
+
export interface RegisteredBackend {
|
|
476
|
+
/** The backend instance */
|
|
477
|
+
backend: PrivacyBackend
|
|
478
|
+
/** Registration priority */
|
|
479
|
+
priority: number
|
|
480
|
+
/** Whether backend is enabled */
|
|
481
|
+
enabled: boolean
|
|
482
|
+
/** Registration timestamp */
|
|
483
|
+
registeredAt: number
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// ─── Health & Circuit Breaker Types ─────────────────────────────────────────
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Circuit breaker state
|
|
490
|
+
*
|
|
491
|
+
* - `closed`: Backend is healthy, requests flow normally
|
|
492
|
+
* - `open`: Backend is failing, requests are blocked
|
|
493
|
+
* - `half-open`: Testing if backend recovered, limited requests allowed
|
|
494
|
+
*/
|
|
495
|
+
export type CircuitState = 'closed' | 'open' | 'half-open'
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Health state tracking for circuit breaker pattern
|
|
499
|
+
*
|
|
500
|
+
* Tracks backend health to automatically disable failing backends
|
|
501
|
+
* and re-enable them after recovery.
|
|
502
|
+
*/
|
|
503
|
+
export interface BackendHealthState {
|
|
504
|
+
/** Current circuit state */
|
|
505
|
+
circuitState: CircuitState
|
|
506
|
+
/** Whether backend is considered healthy (circuit closed or half-open) */
|
|
507
|
+
isHealthy: boolean
|
|
508
|
+
/** Last health check timestamp */
|
|
509
|
+
lastChecked: number
|
|
510
|
+
/** Number of consecutive failures */
|
|
511
|
+
consecutiveFailures: number
|
|
512
|
+
/** Number of consecutive successes (for half-open recovery) */
|
|
513
|
+
consecutiveSuccesses: number
|
|
514
|
+
/** Last failure reason */
|
|
515
|
+
lastFailureReason?: string
|
|
516
|
+
/** Last failure timestamp */
|
|
517
|
+
lastFailureTime?: number
|
|
518
|
+
/** Timestamp when circuit opened */
|
|
519
|
+
circuitOpenedAt?: number
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Metrics for backend observability
|
|
524
|
+
*
|
|
525
|
+
* Tracks request counts and latency for monitoring and debugging.
|
|
526
|
+
*/
|
|
527
|
+
export interface BackendMetrics {
|
|
528
|
+
/** Total requests made to this backend */
|
|
529
|
+
totalRequests: number
|
|
530
|
+
/** Successful requests */
|
|
531
|
+
successfulRequests: number
|
|
532
|
+
/** Failed requests */
|
|
533
|
+
failedRequests: number
|
|
534
|
+
/** Total latency in milliseconds (for average calculation) */
|
|
535
|
+
totalLatencyMs: number
|
|
536
|
+
/** Average latency in milliseconds */
|
|
537
|
+
averageLatencyMs: number
|
|
538
|
+
/** Last request timestamp */
|
|
539
|
+
lastRequestTime: number
|
|
540
|
+
/** Last successful request timestamp */
|
|
541
|
+
lastSuccessTime?: number
|
|
542
|
+
/** Minimum latency observed */
|
|
543
|
+
minLatencyMs?: number
|
|
544
|
+
/** Maximum latency observed */
|
|
545
|
+
maxLatencyMs?: number
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Circuit breaker configuration
|
|
550
|
+
*
|
|
551
|
+
* Controls when backends are disabled and re-enabled.
|
|
552
|
+
*/
|
|
553
|
+
export interface CircuitBreakerConfig {
|
|
554
|
+
/**
|
|
555
|
+
* Number of consecutive failures before opening circuit
|
|
556
|
+
* @default 3
|
|
557
|
+
*/
|
|
558
|
+
failureThreshold: number
|
|
559
|
+
/**
|
|
560
|
+
* Time in ms before attempting to close circuit (half-open state)
|
|
561
|
+
* @default 30000 (30 seconds)
|
|
562
|
+
*/
|
|
563
|
+
resetTimeoutMs: number
|
|
564
|
+
/**
|
|
565
|
+
* Number of successful requests in half-open state before closing circuit
|
|
566
|
+
* @default 2
|
|
567
|
+
*/
|
|
568
|
+
successThreshold: number
|
|
569
|
+
/**
|
|
570
|
+
* Whether to track metrics
|
|
571
|
+
* @default true
|
|
572
|
+
*/
|
|
573
|
+
enableMetrics: boolean
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Default circuit breaker configuration
|
|
578
|
+
*/
|
|
579
|
+
export const DEFAULT_CIRCUIT_BREAKER_CONFIG: CircuitBreakerConfig = {
|
|
580
|
+
failureThreshold: 3,
|
|
581
|
+
resetTimeoutMs: 30000,
|
|
582
|
+
successThreshold: 2,
|
|
583
|
+
enableMetrics: true,
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// ─── Error Types ────────────────────────────────────────────────────────────
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Error thrown when all backends fail during execution
|
|
590
|
+
*
|
|
591
|
+
* Contains details about which backends were attempted and why they failed.
|
|
592
|
+
*/
|
|
593
|
+
export class AllBackendsFailedError extends Error {
|
|
594
|
+
readonly name = 'AllBackendsFailedError'
|
|
595
|
+
|
|
596
|
+
constructor(
|
|
597
|
+
/** Backends that were attempted */
|
|
598
|
+
public readonly attemptedBackends: string[],
|
|
599
|
+
/** Map of backend name to error message */
|
|
600
|
+
public readonly errors: Map<string, string>,
|
|
601
|
+
/** Original transfer parameters */
|
|
602
|
+
public readonly params?: TransferParams
|
|
603
|
+
) {
|
|
604
|
+
const backendList = attemptedBackends.join(', ')
|
|
605
|
+
super(
|
|
606
|
+
`All ${attemptedBackends.length} backend(s) failed: [${backendList}]. ` +
|
|
607
|
+
`Check errors map for details.`
|
|
608
|
+
)
|
|
609
|
+
// Fix prototype chain for instanceof in transpiled code
|
|
610
|
+
Object.setPrototypeOf(this, AllBackendsFailedError.prototype)
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Get formatted error summary
|
|
615
|
+
*/
|
|
616
|
+
getSummary(): string {
|
|
617
|
+
const lines = [`All backends failed (${this.attemptedBackends.length} attempted):`]
|
|
618
|
+
for (const [backend, error] of this.errors) {
|
|
619
|
+
lines.push(` • ${backend}: ${error}`)
|
|
620
|
+
}
|
|
621
|
+
return lines.join('\n')
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Error thrown when circuit breaker is open
|
|
627
|
+
*/
|
|
628
|
+
export class CircuitOpenError extends Error {
|
|
629
|
+
readonly name = 'CircuitOpenError'
|
|
630
|
+
|
|
631
|
+
constructor(
|
|
632
|
+
/** Backend name with open circuit */
|
|
633
|
+
public readonly backendName: string,
|
|
634
|
+
/** Time when circuit opened */
|
|
635
|
+
public readonly openedAt: number,
|
|
636
|
+
/** Time until reset attempt */
|
|
637
|
+
public readonly resetTimeoutMs: number
|
|
638
|
+
) {
|
|
639
|
+
const remainingMs = Math.max(0, (openedAt + resetTimeoutMs) - Date.now())
|
|
640
|
+
const remainingSec = Math.ceil(remainingMs / 1000)
|
|
641
|
+
super(
|
|
642
|
+
`Circuit breaker open for '${backendName}'. ` +
|
|
643
|
+
`Will attempt reset in ${remainingSec}s.`
|
|
644
|
+
)
|
|
645
|
+
// Fix prototype chain for instanceof in transpiled code
|
|
646
|
+
Object.setPrototypeOf(this, CircuitOpenError.prototype)
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Error thrown when a computation times out
|
|
652
|
+
*/
|
|
653
|
+
export class ComputationTimeoutError extends Error {
|
|
654
|
+
readonly name = 'ComputationTimeoutError'
|
|
655
|
+
|
|
656
|
+
constructor(
|
|
657
|
+
/** Computation identifier */
|
|
658
|
+
public readonly computationId: string,
|
|
659
|
+
/** Timeout duration in milliseconds */
|
|
660
|
+
public readonly timeoutMs: number,
|
|
661
|
+
/** Backend name where timeout occurred */
|
|
662
|
+
public readonly backendName: string
|
|
663
|
+
) {
|
|
664
|
+
super(
|
|
665
|
+
`Computation '${computationId}' timed out after ${timeoutMs}ms ` +
|
|
666
|
+
`on backend '${backendName}'`
|
|
667
|
+
)
|
|
668
|
+
// Fix prototype chain for instanceof in transpiled code
|
|
669
|
+
Object.setPrototypeOf(this, ComputationTimeoutError.prototype)
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// ─── Timeout Utilities ────────────────────────────────────────────────────────
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Wrap a promise with a timeout
|
|
677
|
+
*
|
|
678
|
+
* @param promise - The promise to wrap
|
|
679
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
680
|
+
* @param onTimeout - Function to call when timeout occurs, should throw an error
|
|
681
|
+
* @returns The promise result or throws the timeout error
|
|
682
|
+
*
|
|
683
|
+
* @example
|
|
684
|
+
* ```typescript
|
|
685
|
+
* const result = await withTimeout(
|
|
686
|
+
* fetchData(),
|
|
687
|
+
* 5000,
|
|
688
|
+
* () => { throw new Error('Request timed out') }
|
|
689
|
+
* )
|
|
690
|
+
* ```
|
|
691
|
+
*/
|
|
692
|
+
export async function withTimeout<T>(
|
|
693
|
+
promise: Promise<T>,
|
|
694
|
+
timeoutMs: number,
|
|
695
|
+
onTimeout: () => never
|
|
696
|
+
): Promise<T> {
|
|
697
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined
|
|
698
|
+
|
|
699
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
700
|
+
timeoutId = setTimeout(() => {
|
|
701
|
+
try {
|
|
702
|
+
onTimeout()
|
|
703
|
+
} catch (error) {
|
|
704
|
+
reject(error)
|
|
705
|
+
}
|
|
706
|
+
}, timeoutMs)
|
|
707
|
+
})
|
|
708
|
+
|
|
709
|
+
try {
|
|
710
|
+
return await Promise.race([promise, timeoutPromise])
|
|
711
|
+
} finally {
|
|
712
|
+
if (timeoutId !== undefined) {
|
|
713
|
+
clearTimeout(timeoutId)
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// ─── Utility Functions ────────────────────────────────────────────────────────
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Deep freeze an object to make it truly immutable
|
|
722
|
+
*
|
|
723
|
+
* Unlike Object.freeze() which only freezes the top level,
|
|
724
|
+
* this recursively freezes all nested objects and arrays.
|
|
725
|
+
*
|
|
726
|
+
* @param obj - Object to freeze
|
|
727
|
+
* @returns The same object, deeply frozen
|
|
728
|
+
*
|
|
729
|
+
* @example
|
|
730
|
+
* ```typescript
|
|
731
|
+
* const config = deepFreeze({ network: 'devnet', options: { timeout: 5000 } })
|
|
732
|
+
* config.options.timeout = 10000 // Error in strict mode, silently ignored otherwise
|
|
733
|
+
* ```
|
|
734
|
+
*/
|
|
735
|
+
export function deepFreeze<T extends object>(obj: T): Readonly<T> {
|
|
736
|
+
// Get all properties including non-enumerable
|
|
737
|
+
const propNames = Object.getOwnPropertyNames(obj) as (keyof T)[]
|
|
738
|
+
|
|
739
|
+
// Freeze nested objects first (depth-first)
|
|
740
|
+
for (const name of propNames) {
|
|
741
|
+
const value = obj[name]
|
|
742
|
+
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
743
|
+
deepFreeze(value as object)
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// Freeze the object itself
|
|
748
|
+
return Object.freeze(obj)
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// ─── Version Migration Helpers ───────────────────────────────────────────────
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Result of version validation
|
|
755
|
+
*/
|
|
756
|
+
export interface VersionValidationResult {
|
|
757
|
+
/** Whether the backend version is valid */
|
|
758
|
+
valid: boolean
|
|
759
|
+
/** Current version of the backend */
|
|
760
|
+
version: PrivacyBackendVersion
|
|
761
|
+
/** Whether the backend is using a deprecated version */
|
|
762
|
+
deprecated: boolean
|
|
763
|
+
/** Warning message if deprecated */
|
|
764
|
+
warning?: string
|
|
765
|
+
/** Error message if invalid */
|
|
766
|
+
error?: string
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Validate a backend's interface version
|
|
771
|
+
*
|
|
772
|
+
* @param backend - The backend to validate
|
|
773
|
+
* @returns Validation result with version info and any warnings/errors
|
|
774
|
+
*
|
|
775
|
+
* @example
|
|
776
|
+
* ```typescript
|
|
777
|
+
* const result = validateBackendVersion(myBackend)
|
|
778
|
+
* if (result.deprecated) {
|
|
779
|
+
* console.warn(result.warning)
|
|
780
|
+
* }
|
|
781
|
+
* if (!result.valid) {
|
|
782
|
+
* throw new Error(result.error)
|
|
783
|
+
* }
|
|
784
|
+
* ```
|
|
785
|
+
*/
|
|
786
|
+
export function validateBackendVersion(
|
|
787
|
+
backend: PrivacyBackend
|
|
788
|
+
): VersionValidationResult {
|
|
789
|
+
const version = backend.version ?? 1
|
|
790
|
+
|
|
791
|
+
// Check if version is below minimum supported
|
|
792
|
+
if (version < MIN_SUPPORTED_VERSION) {
|
|
793
|
+
return {
|
|
794
|
+
valid: false,
|
|
795
|
+
version,
|
|
796
|
+
deprecated: true,
|
|
797
|
+
error: `Backend '${backend.name}' uses unsupported version ${version}. ` +
|
|
798
|
+
`Minimum supported version is ${MIN_SUPPORTED_VERSION}.`,
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// Check if version is deprecated (v1 without explicit version field)
|
|
803
|
+
if (backend.version === undefined) {
|
|
804
|
+
return {
|
|
805
|
+
valid: true,
|
|
806
|
+
version: 1,
|
|
807
|
+
deprecated: true,
|
|
808
|
+
warning: `Backend '${backend.name}' does not specify a version field. ` +
|
|
809
|
+
`It is treated as v1 which is deprecated. ` +
|
|
810
|
+
`Please update to v${CURRENT_BACKEND_VERSION} by adding 'version: ${CURRENT_BACKEND_VERSION}'.`,
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// Check if version is older than current
|
|
815
|
+
if (version < CURRENT_BACKEND_VERSION) {
|
|
816
|
+
return {
|
|
817
|
+
valid: true,
|
|
818
|
+
version,
|
|
819
|
+
deprecated: true,
|
|
820
|
+
warning: `Backend '${backend.name}' uses version ${version}. ` +
|
|
821
|
+
`Consider upgrading to v${CURRENT_BACKEND_VERSION} for latest features.`,
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Version is current
|
|
826
|
+
return {
|
|
827
|
+
valid: true,
|
|
828
|
+
version,
|
|
829
|
+
deprecated: false,
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* Get the effective version of a backend
|
|
835
|
+
*
|
|
836
|
+
* Returns 1 for backends without an explicit version field (v1 legacy).
|
|
837
|
+
*
|
|
838
|
+
* @param backend - The backend to check
|
|
839
|
+
* @returns The backend's interface version
|
|
840
|
+
*/
|
|
841
|
+
export function getBackendVersion(backend: PrivacyBackend): PrivacyBackendVersion {
|
|
842
|
+
return backend.version ?? 1
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* Check if a backend supports a specific interface version
|
|
847
|
+
*
|
|
848
|
+
* @param backend - The backend to check
|
|
849
|
+
* @param minVersion - Minimum version required
|
|
850
|
+
* @returns True if backend version >= minVersion
|
|
851
|
+
*/
|
|
852
|
+
export function backendSupportsVersion(
|
|
853
|
+
backend: PrivacyBackend,
|
|
854
|
+
minVersion: PrivacyBackendVersion
|
|
855
|
+
): boolean {
|
|
856
|
+
return getBackendVersion(backend) >= minVersion
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* Type guard to check if backend is v2 or higher
|
|
861
|
+
*
|
|
862
|
+
* V2 backends have explicit version field and may have additional features.
|
|
863
|
+
*/
|
|
864
|
+
export function isV2Backend(backend: PrivacyBackend): backend is PrivacyBackend & { version: 2 } {
|
|
865
|
+
return backend.version === 2
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Log deprecation warning for v1 backends
|
|
870
|
+
*
|
|
871
|
+
* Call this when registering backends to warn about deprecated versions.
|
|
872
|
+
*
|
|
873
|
+
* @param backend - The backend to check
|
|
874
|
+
* @param logger - Optional custom logger (defaults to console.warn)
|
|
875
|
+
*/
|
|
876
|
+
export function warnIfDeprecatedVersion(
|
|
877
|
+
backend: PrivacyBackend,
|
|
878
|
+
logger: (message: string) => void = console.warn
|
|
879
|
+
): void {
|
|
880
|
+
const result = validateBackendVersion(backend)
|
|
881
|
+
if (result.deprecated && result.warning) {
|
|
882
|
+
logger(`[SIP-SDK] DEPRECATION WARNING: ${result.warning}`)
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Error thrown when a backend version is not supported
|
|
888
|
+
*/
|
|
889
|
+
export class UnsupportedVersionError extends Error {
|
|
890
|
+
readonly name = 'UnsupportedVersionError'
|
|
891
|
+
|
|
892
|
+
constructor(
|
|
893
|
+
/** Backend name */
|
|
894
|
+
public readonly backendName: string,
|
|
895
|
+
/** Backend version */
|
|
896
|
+
public readonly backendVersion: PrivacyBackendVersion,
|
|
897
|
+
/** Minimum supported version */
|
|
898
|
+
public readonly minSupported: PrivacyBackendVersion
|
|
899
|
+
) {
|
|
900
|
+
super(
|
|
901
|
+
`Backend '${backendName}' uses version ${backendVersion}, ` +
|
|
902
|
+
`but minimum supported version is ${minSupported}.`
|
|
903
|
+
)
|
|
904
|
+
Object.setPrototypeOf(this, UnsupportedVersionError.prototype)
|
|
905
|
+
}
|
|
906
|
+
}
|