33
44import { Data , type Effect } from "effect"
55
6+ import type * as Transaction from "../../core/Transaction.js"
67import type * as Address from "../Address.js"
78import type { ReadOnlyTransactionBuilder , ReadOnlyTransactionBuilderEffect } from "../builders/index.js"
89import type * as Delegation from "../Delegation.js"
@@ -12,7 +13,7 @@ import type * as RewardAddress from "../RewardAddress.js"
1213import type { EffectToPromiseAPI } from "../Type.js"
1314import type * as UTxO from "../UTxO.js"
1415// Type-only imports to avoid runtime circular dependency
15- import type { ReadOnlyWallet , SigningWallet , SigningWalletEffect } from "../wallet/WalletNew.js"
16+ import type { ApiWallet , ReadOnlyWallet , SigningWallet , SigningWalletEffect , WalletApi } from "../wallet/WalletNew.js"
1617
1718// ============================================================================
1819// Error Types
@@ -29,6 +30,43 @@ export class ProviderError extends Data.TaggedError("ProviderError")<{
2930 cause ?: unknown
3031} > { }
3132
33+ /**
34+ * Error class for multi-provider failover operations.
35+ *
36+ * @since 2.0.0
37+ * @category errors
38+ */
39+ export class MultiProviderError extends Data . TaggedError ( "MultiProviderError" ) < {
40+ message ?: string
41+ cause ?: unknown
42+ failedProviders ?: ReadonlyArray < {
43+ provider : string
44+ error : unknown
45+ } >
46+ allProvidersFailed ?: boolean
47+ } > { }
48+
49+ // ============================================================================
50+ // Provider Health Types
51+ // ============================================================================
52+
53+ export interface ProviderHealthStatus {
54+ readonly healthy : boolean
55+ readonly latency : number
56+ readonly lastCheck : Date
57+ readonly consecutiveFailures : number
58+ readonly lastError ?: unknown
59+ }
60+
61+ export interface MultiProviderState {
62+ readonly currentProvider : number
63+ readonly providers : ReadonlyArray < {
64+ config : KupmiosProviderConfig | BlockfrostProviderConfig
65+ health : ProviderHealthStatus
66+ } >
67+ readonly failoverStrategy : "round-robin" | "priority" | "random"
68+ }
69+
3270// ============================================================================
3371// Shared Types
3472// ============================================================================
@@ -63,6 +101,14 @@ export interface ClientEffect extends ReadOnlyClientEffect, SigningWalletEffect
63101
64102export interface MinimalClientEffect { }
65103
104+ // ============================================================================
105+ // Wallet-Only Client (for API wallets without provider)
106+ // ============================================================================
107+
108+ export interface WalletAPIClientEffect extends SigningWalletEffect {
109+ readonly newTx : ( utxos ?: ReadonlyArray < UTxO . UTxO > ) => ReadOnlyTransactionBuilderEffect
110+ }
111+
66112// ============================================================================
67113// Promise-based Client Interfaces
68114// ============================================================================
@@ -92,15 +138,38 @@ export type SigningClient = EffectToPromiseAPI<ClientEffect> & {
92138
93139export type Client = SigningClient
94140
141+ export type WalletAPIClient = EffectToPromiseAPI < WalletAPIClientEffect > & {
142+ readonly address : ( ) => Promise < Address . Address >
143+ readonly rewardAddress : ( ) => Promise < RewardAddress . RewardAddress | null >
144+ readonly newTx : ( utxos ?: ReadonlyArray < UTxO . UTxO > ) => ReadOnlyTransactionBuilder
145+ readonly submitTx : ( tx : Transaction . Transaction | string ) => Promise < string >
146+ readonly wallet : ApiWallet
147+ readonly attachProvider : {
148+ ( provider : Provider . Provider ) : SigningClient
149+ ( config : ProviderConfig ) : SigningClient
150+ }
151+ readonly Effect : WalletAPIClientEffect
152+ }
153+
95154export type ProviderOnlyClient = EffectToPromiseAPI < ProviderOnlyClientEffect > & {
96155 readonly attachWallet : {
97156 ( wallet : SigningWallet ) : SigningClient
98157 ( wallet : ReadOnlyWallet ) : ReadOnlyClient
99158 ( config : SeedWalletConfig ) : SigningClient
100159 ( config : ReadOnlyWalletConfig ) : ReadOnlyClient
160+ ( config : ApiWalletConfig ) : SigningClient
161+ ( api : WalletApi ) : SigningClient
101162 }
102163 readonly Effect : ProviderOnlyClientEffect
103164 readonly provider : Provider . Provider
165+ readonly isMultiProvider : boolean
166+ readonly getActiveProvider ?: ( ) => Provider . Provider
167+ readonly getProviderHealth ?: ( ) => Promise < ReadonlyArray < {
168+ provider : Provider . Provider
169+ healthy : boolean
170+ latency : number
171+ lastCheck : Date
172+ } > >
104173}
105174
106175export interface MinimalClient {
@@ -109,15 +178,23 @@ export interface MinimalClient {
109178 ( provider : Provider . Provider ) : ProviderOnlyClient
110179 ( config : ProviderConfig ) : ProviderOnlyClient
111180 }
181+ readonly attachMultiProvider : {
182+ ( config : MultiProviderConfig ) : ProviderOnlyClient
183+ }
112184 readonly attach : {
113185 ( provider : Provider . Provider , wallet : SigningWallet ) : SigningClient
114186 ( provider : Provider . Provider , wallet : ReadOnlyWallet ) : ReadOnlyClient
115187 ( provider : Provider . Provider , wallet : SeedWalletConfig ) : SigningClient
116188 ( provider : Provider . Provider , wallet : ReadOnlyWalletConfig ) : ReadOnlyClient
189+ ( provider : Provider . Provider , wallet : ApiWalletConfig ) : SigningClient
117190 ( config : ProviderConfig , wallet : SigningWallet ) : SigningClient
118191 ( config : ProviderConfig , wallet : ReadOnlyWallet ) : ReadOnlyClient
119192 ( config : ProviderConfig , wallet : SeedWalletConfig ) : SigningClient
120193 ( config : ProviderConfig , wallet : ReadOnlyWalletConfig ) : ReadOnlyClient
194+ ( config : ProviderConfig , wallet : ApiWalletConfig ) : SigningClient
195+ // API wallet can work without a separate provider (uses CIP-30 submitTx)
196+ ( wallet : ApiWalletConfig ) : WalletAPIClient
197+ ( api : WalletApi ) : WalletAPIClient
121198 }
122199 readonly Effect : MinimalClientEffect
123200}
@@ -134,15 +211,33 @@ export interface KupmiosProviderConfig {
134211 readonly apiKey : string
135212 readonly ogmiosUrl ?: string
136213 readonly kupoUrl ?: string
214+ readonly priority ?: number
137215}
138216
139217export interface BlockfrostProviderConfig {
140218 readonly type : "blockfrost"
141219 readonly apiKey : string
142220 readonly url ?: string
221+ readonly priority ?: number
222+ }
223+
224+ export interface MultiProviderConfig {
225+ readonly type : "multi"
226+ readonly providers : ReadonlyArray < KupmiosProviderConfig | BlockfrostProviderConfig >
227+ readonly failoverStrategy ?: "round-robin" | "priority" | "random"
228+ readonly healthCheck ?: {
229+ readonly enabled ?: boolean
230+ readonly intervalMs ?: number
231+ readonly timeoutMs ?: number
232+ }
233+ readonly retryConfig ?: {
234+ readonly maxRetries ?: number
235+ readonly retryDelayMs ?: number
236+ readonly backoffMultiplier ?: number
237+ }
143238}
144239
145- export type ProviderConfig = KupmiosProviderConfig | BlockfrostProviderConfig
240+ export type ProviderConfig = KupmiosProviderConfig | BlockfrostProviderConfig | MultiProviderConfig
146241
147242// Wallet Configs
148243export interface SeedWalletConfig {
@@ -159,7 +254,15 @@ export interface ReadOnlyWalletConfig {
159254 readonly rewardAddress ?: string
160255}
161256
162- export type WalletConfig = SeedWalletConfig | ReadOnlyWalletConfig
257+ export interface ApiWalletConfig {
258+ readonly type : "api"
259+ readonly api : WalletApi // CIP-30 wallet API interface
260+ // API wallets handle submission internally - no provider needed for transactions
261+ // Optional provider only for enhanced blockchain queries if needed
262+ readonly provider ?: ProviderConfig
263+ }
264+
265+ export type WalletConfig = SeedWalletConfig | ReadOnlyWalletConfig | ApiWalletConfig
163266
164267export type CreateClientConfig =
165268 | { network : NetworkId }
@@ -178,17 +281,112 @@ export declare function createClient(config: { network: NetworkId }): MinimalCli
178281export declare function createClient ( config : { network : NetworkId ; provider : ProviderConfig } ) : ProviderOnlyClient
179282export declare function createClient ( config : { network : NetworkId ; provider : ProviderConfig ; wallet : SeedWalletConfig } ) : SigningClient
180283export declare function createClient ( config : { network : NetworkId ; provider : ProviderConfig ; wallet : ReadOnlyWalletConfig } ) : ReadOnlyClient
284+ export declare function createClient ( config : { network : NetworkId ; provider : ProviderConfig ; wallet : ApiWalletConfig } ) : SigningClient
285+ export declare function createClient ( config : { network : NetworkId ; wallet : ApiWalletConfig } ) : WalletAPIClient // API wallet without separate provider
181286export declare function createClient (
182287 config ?: CreateClientConfig
183- ) : MinimalClient | ProviderOnlyClient | SigningClient | ReadOnlyClient
288+ ) : MinimalClient | ProviderOnlyClient | SigningClient | ReadOnlyClient | WalletAPIClient
184289
185290// Helper factory declarations (not yet implemented in this module)
186291export declare function providerFromConfig ( config : ProviderConfig , network : NetworkId ) : Provider . Provider
292+ export declare function multiProviderFromConfig ( config : MultiProviderConfig , network : NetworkId ) : Provider . Provider
187293export declare function seedWalletFromConfig ( config : SeedWalletConfig , network : NetworkId ) : SigningWallet
188294export declare function readOnlyWalletFromConfig ( config : ReadOnlyWalletConfig , network : NetworkId ) : ReadOnlyWallet
295+ export declare function apiWalletFromConfig ( config : ApiWalletConfig , network : NetworkId ) : ApiWallet
296+ export declare function walletFromCip30Api ( api : WalletApi ) : ApiWallet
189297
190298// Example (non-executable) usage:
191299const minimalClient = createClient ( )
192300const providerOnlyClient = minimalClient . attachProvider ( { type : "blockfrost" , apiKey : "xxx" } )
193- const readOnlyClient = providerOnlyClient . attachWallet ( { type : "read-only" , address : "test" } )
194- const signingClient = providerOnlyClient . attachWallet ( { type : "seed" , mnemonic : "..." } )
301+
302+ // API wallet client upgrade path:
303+ const apiWalletClient = createClient ( { network : "mainnet" , wallet : { type : "api" , api : { } as WalletApi } } )
304+ // apiWalletClient: WalletAPIClient (can sign/submit, but no blockchain queries)
305+
306+ const _fullSigningClient = apiWalletClient . attachProvider ( { type : "blockfrost" , apiKey : "xxx" } )
307+ // _fullSigningClient: SigningClient (full capabilities: query + sign + submit)
308+ const _readOnlyClient = providerOnlyClient . attachWallet ( { type : "read-only" , address : "test" } )
309+ const _signingClient = providerOnlyClient . attachWallet ( { type : "seed" , mnemonic : "..." } )
310+
311+ // Multi-provider examples:
312+ const _multiProviderClient = createClient ( {
313+ network : "mainnet" ,
314+ provider : {
315+ type : "multi" ,
316+ providers : [
317+ {
318+ type : "kupmios" ,
319+ apiKey : "primary-key" ,
320+ priority : 1
321+ } ,
322+ {
323+ type : "blockfrost" ,
324+ apiKey : "fallback-key" ,
325+ priority : 2
326+ }
327+ ] ,
328+ failoverStrategy : "priority" ,
329+ healthCheck : {
330+ enabled : true ,
331+ intervalMs : 30000 ,
332+ timeoutMs : 5000
333+ } ,
334+ retryConfig : {
335+ maxRetries : 3 ,
336+ retryDelayMs : 1000 ,
337+ backoffMultiplier : 2
338+ }
339+ }
340+ } )
341+
342+ const _roundRobinClient = createClient ( {
343+ network : "mainnet" ,
344+ provider : {
345+ type : "multi" ,
346+ providers : [
347+ { type : "kupmios" , apiKey : "key1" } ,
348+ { type : "kupmios" , apiKey : "key2" } ,
349+ { type : "blockfrost" , apiKey : "key3" }
350+ ] ,
351+ failoverStrategy : "round-robin"
352+ }
353+ } )
354+
355+ // Advanced multi-provider with wallet attachment:
356+ const _fullClient = createClient ( {
357+ network : "mainnet" ,
358+ provider : {
359+ type : "multi" ,
360+ providers : [
361+ {
362+ type : "kupmios" ,
363+ apiKey : "primary-key" ,
364+ ogmiosUrl : "wss://ogmios.example.com" ,
365+ kupoUrl : "https://kupo.example.com" ,
366+ priority : 1
367+ } ,
368+ {
369+ type : "blockfrost" ,
370+ apiKey : "backup-key" ,
371+ url : "https://blockfrost.example.com" ,
372+ priority : 2
373+ }
374+ ] ,
375+ failoverStrategy : "priority" ,
376+ healthCheck : {
377+ enabled : true ,
378+ intervalMs : 15000 , // Check every 15 seconds
379+ timeoutMs : 3000 // 3 second timeout
380+ } ,
381+ retryConfig : {
382+ maxRetries : 2 ,
383+ retryDelayMs : 500 ,
384+ backoffMultiplier : 1.5
385+ }
386+ } ,
387+ wallet : {
388+ type : "seed" ,
389+ mnemonic : "abandon abandon abandon..." ,
390+ accountIndex : 0
391+ }
392+ } )
0 commit comments