@unifold/core 0.1.70-beta.1 → 0.1.70

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/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- type ChainType = 'ethereum' | 'solana' | 'bitcoin' | 'algorand' | 'xrpl' | 'cardano' | 'n1';
1
+ type ChainType = 'ethereum' | 'solana' | 'bitcoin' | 'algorand' | 'xrpl' | 'cardano' | 'n1' | 'tron';
2
2
 
3
3
  declare function setApiConfig(config: {
4
4
  baseUrl?: string;
@@ -337,7 +337,13 @@ interface OnrampQuote {
337
337
  destination_currency: string;
338
338
  destination_network: string;
339
339
  exchange_rate: number;
340
- payment_method_type: string;
340
+ /**
341
+ * Unified payment method type (`card` / `apple_pay` / `sepa`). Provider-native
342
+ * values (e.g. Meld's `credit_debit_card`) are normalized to this vocabulary.
343
+ */
344
+ payment_method_type: OnrampSessionPaymentMethodType;
345
+ /** @deprecated Use `payment_method_type` instead (same value). */
346
+ payment_method: OnrampSessionPaymentMethodType;
341
347
  customer_score: number;
342
348
  service_provider: string;
343
349
  service_provider_display_name: string;
@@ -371,7 +377,12 @@ declare function getOnrampQuotes(request: OnrampQuotesRequest, publishableKey?:
371
377
  * (Coinbase only) — useful as a fallback when the headless Apple Pay flow
372
378
  * is unavailable.
373
379
  */
374
- type OnrampSessionPaymentMethod = 'card' | 'sepa' | 'apple_pay';
380
+ type OnrampSessionPaymentMethodType = 'card' | 'sepa' | 'apple_pay';
381
+ /**
382
+ * @deprecated Use `OnrampSessionPaymentMethodType` instead. Retained as an alias so
383
+ * previously-released SDK consumers keep compiling.
384
+ */
385
+ type OnrampSessionPaymentMethod = OnrampSessionPaymentMethodType;
375
386
  interface OnrampSessionRequest {
376
387
  service_provider: string;
377
388
  country_code: string;
@@ -384,7 +395,13 @@ interface OnrampSessionRequest {
384
395
  redirect_url?: string;
385
396
  external_id?: string;
386
397
  email?: string;
387
- payment_method?: OnrampSessionPaymentMethod;
398
+ /**
399
+ * Payment method type for the session (`card` / `sepa` / `apple_pay`).
400
+ * Defaults to `card`.
401
+ */
402
+ payment_method_type?: OnrampSessionPaymentMethodType;
403
+ /** @deprecated Use `payment_method_type` instead (same value). */
404
+ payment_method?: OnrampSessionPaymentMethodType;
388
405
  }
389
406
  interface OnrampSessionResponse {
390
407
  url: string;
@@ -418,7 +435,7 @@ interface BankTransferProvider {
418
435
  * a single provider can light up multiple rails (e.g. SEPA + ACH) without
419
436
  * forking the row.
420
437
  */
421
- payment_methods: OnrampSessionPaymentMethod[];
438
+ payment_methods: OnrampSessionPaymentMethodType[];
422
439
  /** All fiat currencies the rail accepts (e.g. ['eur', 'gbp']). */
423
440
  supported_currencies: string[];
424
441
  /**
@@ -1587,18 +1604,32 @@ interface StripeQuotesResponse {
1587
1604
  * Backend error_type values for headless Stripe onramp failures. The SDK can
1588
1605
  * branch on these instead of string-matching Stripe messages.
1589
1606
  */
1590
- type StripeOnrampErrorType = 'stripe_onramp_missing_minimum_identity_verification' | 'stripe_onramp_missing_identity_verification' | 'stripe_onramp_missing_document_verification' | 'stripe_onramp_purchase_limit_reached' | 'stripe_onramp_bad_request' | 'stripe_onramp_forbidden' | 'stripe_onramp_not_found' | 'stripe_onramp_upstream_error' | (string & NonNullable<unknown>);
1607
+ type StripeOnrampErrorType = 'stripe_onramp_missing_minimum_identity_verification' | 'stripe_onramp_missing_identity_verification' | 'stripe_onramp_missing_document_verification' | 'stripe_onramp_purchase_limit_reached' | 'stripe_onramp_payment_method_consumed' | 'stripe_onramp_bad_request' | 'stripe_onramp_forbidden' | 'stripe_onramp_not_found' | 'stripe_onramp_upstream_error' | (string & NonNullable<unknown>);
1591
1608
  declare class StripeApiResponseError extends Error {
1592
1609
  readonly statusCode: number;
1593
1610
  /** Underlying Stripe error code (e.g. `crypto_onramp_session_error`), when available */
1594
1611
  readonly stripeCode?: string | undefined;
1595
1612
  /** Unifold backend error_type (e.g. `stripe_onramp_missing_document_verification`) */
1596
1613
  readonly errorType?: StripeOnrampErrorType | undefined;
1614
+ /**
1615
+ * The raw Stripe error message (from `details.stripe_error.message`), without
1616
+ * the operation prefix baked into `message`. This is the human-readable text
1617
+ * Stripe returns (e.g. "Your card was declined.") and is safe to show to the
1618
+ * user directly when there's no more specific mapped message.
1619
+ */
1620
+ readonly stripeMessage?: string | undefined;
1597
1621
  constructor(message: string, statusCode: number,
1598
1622
  /** Underlying Stripe error code (e.g. `crypto_onramp_session_error`), when available */
1599
1623
  stripeCode?: string | undefined,
1600
1624
  /** Unifold backend error_type (e.g. `stripe_onramp_missing_document_verification`) */
1601
- errorType?: StripeOnrampErrorType | undefined);
1625
+ errorType?: StripeOnrampErrorType | undefined,
1626
+ /**
1627
+ * The raw Stripe error message (from `details.stripe_error.message`), without
1628
+ * the operation prefix baked into `message`. This is the human-readable text
1629
+ * Stripe returns (e.g. "Your card was declined.") and is safe to show to the
1630
+ * user directly when there's no more specific mapped message.
1631
+ */
1632
+ stripeMessage?: string | undefined);
1602
1633
  }
1603
1634
  /**
1604
1635
  * Fetch Stripe config (publishable key + merchant ID) for SDK initialization.
@@ -2277,7 +2308,16 @@ interface DepositSessionParams {
2277
2308
  interface DepositSessionConfig extends DepositSessionParams {
2278
2309
  publishableKey: string;
2279
2310
  }
2280
- type DepositSessionStatus = 'idle' | 'creating_addresses' | 'awaiting_funds' | 'processing' | 'succeeded' | 'failed' | 'error';
2311
+ /**
2312
+ * Session status is LIFECYCLE-ONLY. A DepositSession is an ongoing watcher
2313
+ * that can observe many executions, so execution outcomes deliberately never
2314
+ * appear here — a session-level "succeeded"/"failed" misleads the moment a
2315
+ * second deposit arrives (a failure right after a success would flip the
2316
+ * whole session to "failed"). Outcomes live on the executions themselves:
2317
+ * `snapshot.executions` / `latestExecution` statuses, the
2318
+ * `direct_execution.succeeded`/`.failed` events, and `waitForSuccess()`.
2319
+ */
2320
+ type DepositSessionStatus = 'idle' | 'creating_addresses' | 'ready' | 'processing' | 'error';
2281
2321
  interface DepositSessionSnapshot {
2282
2322
  status: DepositSessionStatus;
2283
2323
  /** Deposit addresses (one per chain type); empty until created. */
@@ -2350,6 +2390,9 @@ declare class DepositSession {
2350
2390
  private baselineMs;
2351
2391
  private tracked;
2352
2392
  private pollErrorLatched;
2393
+ private pollInFlight;
2394
+ /** First execution to succeed this run — waitForSuccess's one-shot answer. */
2395
+ private firstSuccess;
2353
2396
  private detectionTimer;
2354
2397
  private nudgeTimer;
2355
2398
  private armTimer;
@@ -2388,9 +2431,11 @@ declare class DepositSession {
2388
2431
  destroy(): void;
2389
2432
  /**
2390
2433
  * Resolve when the session reaches one of the given statuses (immediately
2391
- * if it's already there). Generic primitive over the status state machine:
2392
- * `waitForStatus('processing')` awaits detection; `waitForStatus(['succeeded',
2393
- * 'failed'])` awaits a terminal outcome.
2434
+ * if it's already there). Generic primitive over the lifecycle state
2435
+ * machine — e.g. `waitForStatus('processing')` awaits detection of live
2436
+ * activity, `waitForStatus('ready')` awaits readiness. Statuses
2437
+ * carry no outcomes; await those with {@link waitForSuccess} or the
2438
+ * `direct_execution.*` events.
2394
2439
  *
2395
2440
  * Rejects with {@link DepositSessionWaitError} on abort or destroy().
2396
2441
  * Does not start or stop the session — it only listens.
@@ -2404,14 +2449,15 @@ declare class DepositSession {
2404
2449
  * Multi-execution semantics (unlike quote-scoped models such as Privy's,
2405
2450
  * one session can observe many executions — a user may send twice, or on
2406
2451
  * two chains): this waiter is one-shot "first completion" detection. If an
2407
- * execution has already succeeded, it resolves immediately with that
2408
- * execution. The session keeps polling after success — to react to every
2409
- * settlement, subscribe to `direct_execution.succeeded` events or read
2410
- * `snapshot.executions` instead.
2452
+ * execution has already succeeded this run, it resolves immediately with
2453
+ * the FIRST one that did (not the newest). The session keeps polling after
2454
+ * success to react to every settlement, subscribe to
2455
+ * `direct_execution.succeeded` events or read `snapshot.executions`.
2411
2456
  *
2412
2457
  * Rejects with {@link DepositSessionWaitError}:
2413
- * - `DEPOSIT_FAILED` (cause: the failed execution) when a deposit fails
2414
- * before any succeeds,
2458
+ * - `DEPOSIT_FAILED` (cause: the failed execution) when a deposit fails and
2459
+ * NO other observed execution is still in flight — a failure while
2460
+ * another deposit is pending keeps waiting (that one may still succeed),
2415
2461
  * - `SESSION_ERROR` (cause: the fatal {@link DepositSessionError}) on fatal
2416
2462
  * session errors (e.g. address creation failed),
2417
2463
  * - `ABORTED` / `DESTROYED` per the wait options and session lifecycle.
@@ -2438,8 +2484,10 @@ declare class DepositSession {
2438
2484
  private runStartChecks;
2439
2485
  private startDetectionLoop;
2440
2486
  private pollExecutions;
2487
+ private pollExecutionsOnce;
2441
2488
  private processExecutionChange;
2442
2489
  private armConfirmation;
2490
+ private anyExecutionInFlight;
2443
2491
  private setStatus;
2444
2492
  private clearTimers;
2445
2493
  private buildSnapshot;
@@ -2646,4 +2694,4 @@ declare const i18n: {
2646
2694
  };
2647
2695
  type I18nStrings = typeof i18n;
2648
2696
 
2649
- export { ActionType, type AddressBalanceResponse, type AddressBalancesResponse, type AddressValidationFailureCode, type AddressValidationMetadata, type AddressVerification, type ApplePayLimitUpgradeStatus, type ApplePayProvider, type ApplePayProvidersResponse, type AuthenticateOAuthResult, type AutoSwapRequest, type AutoSwapResponse, type BankTransferConfig, type BankTransferProvider, type BankTransferProvidersResponse, type BlockedCountrySubdivision, type BuildHypercoreTransactionRequest, type BuildHypercoreTransactionResponse, type BuildSolanaTransactionRequest, type BuildSolanaTransactionResponse, type CashAppLimits, type CashAppSessionRequest, type CashAppSessionResponse, type CashAppSessionStatusResponse, type ChainType, type CheckoutEvent, CheckoutEventType, type CheckoutMethod, type CheckoutPaymentIntent, type CheckoutPaymentIntentData, type CheckoutPaymentIntentSucceededEvent, type CoinbaseApplePayLimit, type CoinbaseApplePayLimitUpgradeOption, type CoinbaseApplePayLimitsResponse, type CoinbaseApplePaySessionResponse, type CoinbaseLegalAgreement, type CoinbaseLegalAgreementsResponse, type ConfirmIntegrationTransferResult, type CreateCoinbaseApplePaySessionRequest, type CreateDepositAddressRequest, type CreateExchangeSessionRequest, type CreateExchangeSessionResponse, type CreateIntegrationTransferParams, type CreateIntegrationTransferResult, type CreateOnrampVerificationSessionRequest, DETECTION_ARM_DELAY_MS, DETECTION_POLL_INTERVAL_MS, type DefaultTokenChain, type DefaultTokenMetadata, type DefaultTokenResponse, type DepositAddress, type DepositAddressParams, type DepositAddressResponse, DepositAddressValidationError, type DepositEvent, DepositEventType, type DepositMethod, type DepositQuote, type DepositQuoteRequest, DepositSession, type DepositSessionConfig, type DepositSessionDestination, type DepositSessionError, type DepositSessionErrorCode, type DepositSessionEvent, type DepositSessionEventMap, DepositSessionEventType, type DepositSessionParams, type DepositSessionSnapshot, type DepositSessionStatus, DepositSessionWaitError, type DepositSessionWaitErrorCode, type DepositSessionWaitOptions, type DestinationToken, type DestinationTokenChain, type DirectExecution, type DirectExecutionResponse, type DirectExecutionSucceededEvent, type EvmContractCall, type ExchangeProviderInfo, type ExchangeProvidersResponse, type ExchangeSessionStartParams, type ExchangeWalletAddress, ExecutionStatus, type ExternalWalletChainType, type ExternalWalletInfo, type ExternalWalletsResponse, type FeaturedToken, type FeaturedWallet, type FiatCurrenciesResponse, type FiatCurrency, type GetBankTransferProvidersOptions, type GetExchangesQuery, type HypercoreActivationRequest, type HypercoreActivationResponse, type I18nStrings, type IconUrl, IneligibilityReason, type IntegrationAccount, type IntegrationExchangeInfo, type IntegrationExchangesResponse, type IntegrationFeeAmount, type IntegrationHoldingsResponse, IntegrationProvider, type IpAddressResponse, LOOKBACK_MS, type ListExecutionsParams, type LockedQuoteLimits, type LockedQuotePreview, type LockedQuotePreviewRequest, type OnrampQuote, type OnrampQuotesRequest, type OnrampQuotesResponse, type OnrampSessionCreatedData, type OnrampSessionCreatedEvent, type OnrampSessionPaymentMethod, type OnrampSessionRequest, type OnrampSessionResponse, type OnrampVerificationFactor, type OnrampVerificationFactorStatus, type OnrampVerificationSession, type OnrampVerificationStatus, type OnrampVerificationTokenResponse, type PaymentIntent, type PaymentIntentDepositAddress, type PaymentIntentExecutionsResponse, type PaymentIntentStatus, type PaymentIntentType, type PaymentNetwork, type PollExecutionsRequest, type PollExecutionsResponse, type ProductType, type ProjectConfigResponse, type PublicIncidentResponse, type QueryExecutionsRequest, type QueryExecutionsResponse, type RefreshIntegrationTokenResult, type RequestCoinbaseApplePayLimitUpgradeRequest, type RequestCoinbaseApplePayLimitUpgradeResponse, SCAN_NUDGE_INTERVAL_MS, SOLANA_USDC_ADDRESS, type SendHypercoreTransactionRequest, type SendHypercoreTransactionResponse, type SendSolanaTransactionRequest, type SendSolanaTransactionResponse, type SourceToken, type SourceTokenNetwork, type StartIntegrationOAuthResult, type StripeAccessTokenResponse, StripeApiResponseError, type StripeAuthIntentResponse, type StripeConfigResponse, type StripeConfirmRequest, type StripeConsumerWallet, type StripeCreateSessionRequest, type StripeCryptoCustomer, type StripeCustomerVerification, type StripeDefaultTokenResponse, type StripeListResponse, type StripeOnrampErrorType, type StripeOnrampSession, type StripeOnrampTransactionDetails, type StripePaymentToken, type StripeQuoteRequest, type StripeQuotesResponse, type StripeTransactionLimitEntry, type StripeTransactionLimitsResponse, type SupportedChain, type SupportedDepositTokensParams, type SupportedDepositTokensResponse, type SupportedDestinationTokensResponse, type SupportedSourceTokensQuery, type SupportedSourceTokensResponse, type SupportedToken, type TokenBalance, type TokenChain, type TokenChainIconUrl, type TokenChainsResponse, type TokenDisplayMetadata, type TokenIconUrl, type TokenInfo, type TokenMetadata, type TransferDefaultTokenParams, type TransferDefaultTokenResult, UnifoldClient, type UnifoldClientOptions, type UserIpInfo, type VerifyAddressParams, type VerifyAddressRequest, type VerifyAddressResponse, type Wallet, type WalletMobileDeepLinkDepositAddress, type WalletMobileDeepLinkResponse, type WalletMobileDeepLinkWallet, type WithdrawDirectExecutionSucceededEvent, type WithdrawEvent, WithdrawEventType, authenticateIntegrationOAuth, buildHypercoreTransaction, buildSolanaTransaction, checkHypercoreActivation, confirmIntegrationTransfer, createCashAppSession, createCoinbaseApplePaySession, createDepositAddress, createExchangeSession, createIntegrationTransfer, createOnrampSession, createOnrampVerificationSession, createUnifoldClient, exchangeOnrampVerificationToken, formatStablecoinAmount, generateKSUID, generatePrefixedKSUID, getAddressBalance, getAddressBalances, getApiBaseUrl, getApplePayLimitUpgradeStatus, getApplePayProviders, getBankTransferProviders, getCashAppLimits, getCashAppSessionStatus, getChainName, getCoinbaseApplePayLimits, getCoinbaseLegalAgreements, getDefaultOnrampToken, getDepositAddress, getDepositQuote, getExchangeSessionStartUrl, getExchanges, getExternalWallets, getFiatCurrencies, getFiatExchangeRates, getIconUrl, getIconUrlWithCdn, getIntegrationExchanges, getIntegrationHoldings, getIntegrationTransferDefaultToken, getIpAddress, getOnrampQuotes, getOnrampSessionStartUrl, getOnrampVerificationSession, getPreferredIconUrl, getProjectConfig, getPublicIncident, getSupportedDepositTokens, getSupportedDestinationTokens, getTokenChains, getTokenMetadata, getWalletByChainType, getWalletMobileDeepLink, i18n, isApplePayLimitReached, isDepositAddressValidationError, listPaymentIntentExecutions, mapDirectExecution, mapWalletToDepositAddress, pollDirectExecutions, queryExecutions, refreshIntegrationToken, requestCoinbaseApplePayLimitUpgrade, retrievePaymentIntent, revokeIntegrationToken, sendHypercoreTransaction, sendOnrampVerificationOtp, sendSolanaTransaction, setApiConfig, startIntegrationOAuth, stripeConfirmSession, stripeCreateAuthIntent, stripeCreateSession, stripeExchangeTokens, stripeGetConfig, stripeGetCustomer, stripeGetDefaultToken, stripeGetQuotes, stripeGetSession, stripeGetTransactionLimits, stripeListPaymentTokens, stripeListWallets, stripeRefreshQuote, stripeRefreshToken, useUserIp, verifyOnrampVerificationOtp, verifyRecipientAddress };
2697
+ export { ActionType, type AddressBalanceResponse, type AddressBalancesResponse, type AddressValidationFailureCode, type AddressValidationMetadata, type AddressVerification, type ApplePayLimitUpgradeStatus, type ApplePayProvider, type ApplePayProvidersResponse, type AuthenticateOAuthResult, type AutoSwapRequest, type AutoSwapResponse, type BankTransferConfig, type BankTransferProvider, type BankTransferProvidersResponse, type BlockedCountrySubdivision, type BuildHypercoreTransactionRequest, type BuildHypercoreTransactionResponse, type BuildSolanaTransactionRequest, type BuildSolanaTransactionResponse, type CashAppLimits, type CashAppSessionRequest, type CashAppSessionResponse, type CashAppSessionStatusResponse, type ChainType, type CheckoutEvent, CheckoutEventType, type CheckoutMethod, type CheckoutPaymentIntent, type CheckoutPaymentIntentData, type CheckoutPaymentIntentSucceededEvent, type CoinbaseApplePayLimit, type CoinbaseApplePayLimitUpgradeOption, type CoinbaseApplePayLimitsResponse, type CoinbaseApplePaySessionResponse, type CoinbaseLegalAgreement, type CoinbaseLegalAgreementsResponse, type ConfirmIntegrationTransferResult, type CreateCoinbaseApplePaySessionRequest, type CreateDepositAddressRequest, type CreateExchangeSessionRequest, type CreateExchangeSessionResponse, type CreateIntegrationTransferParams, type CreateIntegrationTransferResult, type CreateOnrampVerificationSessionRequest, DETECTION_ARM_DELAY_MS, DETECTION_POLL_INTERVAL_MS, type DefaultTokenChain, type DefaultTokenMetadata, type DefaultTokenResponse, type DepositAddress, type DepositAddressParams, type DepositAddressResponse, DepositAddressValidationError, type DepositEvent, DepositEventType, type DepositMethod, type DepositQuote, type DepositQuoteRequest, DepositSession, type DepositSessionConfig, type DepositSessionDestination, type DepositSessionError, type DepositSessionErrorCode, type DepositSessionEvent, type DepositSessionEventMap, DepositSessionEventType, type DepositSessionParams, type DepositSessionSnapshot, type DepositSessionStatus, DepositSessionWaitError, type DepositSessionWaitErrorCode, type DepositSessionWaitOptions, type DestinationToken, type DestinationTokenChain, type DirectExecution, type DirectExecutionResponse, type DirectExecutionSucceededEvent, type EvmContractCall, type ExchangeProviderInfo, type ExchangeProvidersResponse, type ExchangeSessionStartParams, type ExchangeWalletAddress, ExecutionStatus, type ExternalWalletChainType, type ExternalWalletInfo, type ExternalWalletsResponse, type FeaturedToken, type FeaturedWallet, type FiatCurrenciesResponse, type FiatCurrency, type GetBankTransferProvidersOptions, type GetExchangesQuery, type HypercoreActivationRequest, type HypercoreActivationResponse, type I18nStrings, type IconUrl, IneligibilityReason, type IntegrationAccount, type IntegrationExchangeInfo, type IntegrationExchangesResponse, type IntegrationFeeAmount, type IntegrationHoldingsResponse, IntegrationProvider, type IpAddressResponse, LOOKBACK_MS, type ListExecutionsParams, type LockedQuoteLimits, type LockedQuotePreview, type LockedQuotePreviewRequest, type OnrampQuote, type OnrampQuotesRequest, type OnrampQuotesResponse, type OnrampSessionCreatedData, type OnrampSessionCreatedEvent, type OnrampSessionPaymentMethod, type OnrampSessionPaymentMethodType, type OnrampSessionRequest, type OnrampSessionResponse, type OnrampVerificationFactor, type OnrampVerificationFactorStatus, type OnrampVerificationSession, type OnrampVerificationStatus, type OnrampVerificationTokenResponse, type PaymentIntent, type PaymentIntentDepositAddress, type PaymentIntentExecutionsResponse, type PaymentIntentStatus, type PaymentIntentType, type PaymentNetwork, type PollExecutionsRequest, type PollExecutionsResponse, type ProductType, type ProjectConfigResponse, type PublicIncidentResponse, type QueryExecutionsRequest, type QueryExecutionsResponse, type RefreshIntegrationTokenResult, type RequestCoinbaseApplePayLimitUpgradeRequest, type RequestCoinbaseApplePayLimitUpgradeResponse, SCAN_NUDGE_INTERVAL_MS, SOLANA_USDC_ADDRESS, type SendHypercoreTransactionRequest, type SendHypercoreTransactionResponse, type SendSolanaTransactionRequest, type SendSolanaTransactionResponse, type SourceToken, type SourceTokenNetwork, type StartIntegrationOAuthResult, type StripeAccessTokenResponse, StripeApiResponseError, type StripeAuthIntentResponse, type StripeConfigResponse, type StripeConfirmRequest, type StripeConsumerWallet, type StripeCreateSessionRequest, type StripeCryptoCustomer, type StripeCustomerVerification, type StripeDefaultTokenResponse, type StripeListResponse, type StripeOnrampErrorType, type StripeOnrampSession, type StripeOnrampTransactionDetails, type StripePaymentToken, type StripeQuoteRequest, type StripeQuotesResponse, type StripeTransactionLimitEntry, type StripeTransactionLimitsResponse, type SupportedChain, type SupportedDepositTokensParams, type SupportedDepositTokensResponse, type SupportedDestinationTokensResponse, type SupportedSourceTokensQuery, type SupportedSourceTokensResponse, type SupportedToken, type TokenBalance, type TokenChain, type TokenChainIconUrl, type TokenChainsResponse, type TokenDisplayMetadata, type TokenIconUrl, type TokenInfo, type TokenMetadata, type TransferDefaultTokenParams, type TransferDefaultTokenResult, UnifoldClient, type UnifoldClientOptions, type UserIpInfo, type VerifyAddressParams, type VerifyAddressRequest, type VerifyAddressResponse, type Wallet, type WalletMobileDeepLinkDepositAddress, type WalletMobileDeepLinkResponse, type WalletMobileDeepLinkWallet, type WithdrawDirectExecutionSucceededEvent, type WithdrawEvent, WithdrawEventType, authenticateIntegrationOAuth, buildHypercoreTransaction, buildSolanaTransaction, checkHypercoreActivation, confirmIntegrationTransfer, createCashAppSession, createCoinbaseApplePaySession, createDepositAddress, createExchangeSession, createIntegrationTransfer, createOnrampSession, createOnrampVerificationSession, createUnifoldClient, exchangeOnrampVerificationToken, formatStablecoinAmount, generateKSUID, generatePrefixedKSUID, getAddressBalance, getAddressBalances, getApiBaseUrl, getApplePayLimitUpgradeStatus, getApplePayProviders, getBankTransferProviders, getCashAppLimits, getCashAppSessionStatus, getChainName, getCoinbaseApplePayLimits, getCoinbaseLegalAgreements, getDefaultOnrampToken, getDepositAddress, getDepositQuote, getExchangeSessionStartUrl, getExchanges, getExternalWallets, getFiatCurrencies, getFiatExchangeRates, getIconUrl, getIconUrlWithCdn, getIntegrationExchanges, getIntegrationHoldings, getIntegrationTransferDefaultToken, getIpAddress, getOnrampQuotes, getOnrampSessionStartUrl, getOnrampVerificationSession, getPreferredIconUrl, getProjectConfig, getPublicIncident, getSupportedDepositTokens, getSupportedDestinationTokens, getTokenChains, getTokenMetadata, getWalletByChainType, getWalletMobileDeepLink, i18n, isApplePayLimitReached, isDepositAddressValidationError, listPaymentIntentExecutions, mapDirectExecution, mapWalletToDepositAddress, pollDirectExecutions, queryExecutions, refreshIntegrationToken, requestCoinbaseApplePayLimitUpgrade, retrievePaymentIntent, revokeIntegrationToken, sendHypercoreTransaction, sendOnrampVerificationOtp, sendSolanaTransaction, setApiConfig, startIntegrationOAuth, stripeConfirmSession, stripeCreateAuthIntent, stripeCreateSession, stripeExchangeTokens, stripeGetConfig, stripeGetCustomer, stripeGetDefaultToken, stripeGetQuotes, stripeGetSession, stripeGetTransactionLimits, stripeListPaymentTokens, stripeListWallets, stripeRefreshQuote, stripeRefreshToken, useUserIp, verifyOnrampVerificationOtp, verifyRecipientAddress };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- type ChainType = 'ethereum' | 'solana' | 'bitcoin' | 'algorand' | 'xrpl' | 'cardano' | 'n1';
1
+ type ChainType = 'ethereum' | 'solana' | 'bitcoin' | 'algorand' | 'xrpl' | 'cardano' | 'n1' | 'tron';
2
2
 
3
3
  declare function setApiConfig(config: {
4
4
  baseUrl?: string;
@@ -337,7 +337,13 @@ interface OnrampQuote {
337
337
  destination_currency: string;
338
338
  destination_network: string;
339
339
  exchange_rate: number;
340
- payment_method_type: string;
340
+ /**
341
+ * Unified payment method type (`card` / `apple_pay` / `sepa`). Provider-native
342
+ * values (e.g. Meld's `credit_debit_card`) are normalized to this vocabulary.
343
+ */
344
+ payment_method_type: OnrampSessionPaymentMethodType;
345
+ /** @deprecated Use `payment_method_type` instead (same value). */
346
+ payment_method: OnrampSessionPaymentMethodType;
341
347
  customer_score: number;
342
348
  service_provider: string;
343
349
  service_provider_display_name: string;
@@ -371,7 +377,12 @@ declare function getOnrampQuotes(request: OnrampQuotesRequest, publishableKey?:
371
377
  * (Coinbase only) — useful as a fallback when the headless Apple Pay flow
372
378
  * is unavailable.
373
379
  */
374
- type OnrampSessionPaymentMethod = 'card' | 'sepa' | 'apple_pay';
380
+ type OnrampSessionPaymentMethodType = 'card' | 'sepa' | 'apple_pay';
381
+ /**
382
+ * @deprecated Use `OnrampSessionPaymentMethodType` instead. Retained as an alias so
383
+ * previously-released SDK consumers keep compiling.
384
+ */
385
+ type OnrampSessionPaymentMethod = OnrampSessionPaymentMethodType;
375
386
  interface OnrampSessionRequest {
376
387
  service_provider: string;
377
388
  country_code: string;
@@ -384,7 +395,13 @@ interface OnrampSessionRequest {
384
395
  redirect_url?: string;
385
396
  external_id?: string;
386
397
  email?: string;
387
- payment_method?: OnrampSessionPaymentMethod;
398
+ /**
399
+ * Payment method type for the session (`card` / `sepa` / `apple_pay`).
400
+ * Defaults to `card`.
401
+ */
402
+ payment_method_type?: OnrampSessionPaymentMethodType;
403
+ /** @deprecated Use `payment_method_type` instead (same value). */
404
+ payment_method?: OnrampSessionPaymentMethodType;
388
405
  }
389
406
  interface OnrampSessionResponse {
390
407
  url: string;
@@ -418,7 +435,7 @@ interface BankTransferProvider {
418
435
  * a single provider can light up multiple rails (e.g. SEPA + ACH) without
419
436
  * forking the row.
420
437
  */
421
- payment_methods: OnrampSessionPaymentMethod[];
438
+ payment_methods: OnrampSessionPaymentMethodType[];
422
439
  /** All fiat currencies the rail accepts (e.g. ['eur', 'gbp']). */
423
440
  supported_currencies: string[];
424
441
  /**
@@ -1587,18 +1604,32 @@ interface StripeQuotesResponse {
1587
1604
  * Backend error_type values for headless Stripe onramp failures. The SDK can
1588
1605
  * branch on these instead of string-matching Stripe messages.
1589
1606
  */
1590
- type StripeOnrampErrorType = 'stripe_onramp_missing_minimum_identity_verification' | 'stripe_onramp_missing_identity_verification' | 'stripe_onramp_missing_document_verification' | 'stripe_onramp_purchase_limit_reached' | 'stripe_onramp_bad_request' | 'stripe_onramp_forbidden' | 'stripe_onramp_not_found' | 'stripe_onramp_upstream_error' | (string & NonNullable<unknown>);
1607
+ type StripeOnrampErrorType = 'stripe_onramp_missing_minimum_identity_verification' | 'stripe_onramp_missing_identity_verification' | 'stripe_onramp_missing_document_verification' | 'stripe_onramp_purchase_limit_reached' | 'stripe_onramp_payment_method_consumed' | 'stripe_onramp_bad_request' | 'stripe_onramp_forbidden' | 'stripe_onramp_not_found' | 'stripe_onramp_upstream_error' | (string & NonNullable<unknown>);
1591
1608
  declare class StripeApiResponseError extends Error {
1592
1609
  readonly statusCode: number;
1593
1610
  /** Underlying Stripe error code (e.g. `crypto_onramp_session_error`), when available */
1594
1611
  readonly stripeCode?: string | undefined;
1595
1612
  /** Unifold backend error_type (e.g. `stripe_onramp_missing_document_verification`) */
1596
1613
  readonly errorType?: StripeOnrampErrorType | undefined;
1614
+ /**
1615
+ * The raw Stripe error message (from `details.stripe_error.message`), without
1616
+ * the operation prefix baked into `message`. This is the human-readable text
1617
+ * Stripe returns (e.g. "Your card was declined.") and is safe to show to the
1618
+ * user directly when there's no more specific mapped message.
1619
+ */
1620
+ readonly stripeMessage?: string | undefined;
1597
1621
  constructor(message: string, statusCode: number,
1598
1622
  /** Underlying Stripe error code (e.g. `crypto_onramp_session_error`), when available */
1599
1623
  stripeCode?: string | undefined,
1600
1624
  /** Unifold backend error_type (e.g. `stripe_onramp_missing_document_verification`) */
1601
- errorType?: StripeOnrampErrorType | undefined);
1625
+ errorType?: StripeOnrampErrorType | undefined,
1626
+ /**
1627
+ * The raw Stripe error message (from `details.stripe_error.message`), without
1628
+ * the operation prefix baked into `message`. This is the human-readable text
1629
+ * Stripe returns (e.g. "Your card was declined.") and is safe to show to the
1630
+ * user directly when there's no more specific mapped message.
1631
+ */
1632
+ stripeMessage?: string | undefined);
1602
1633
  }
1603
1634
  /**
1604
1635
  * Fetch Stripe config (publishable key + merchant ID) for SDK initialization.
@@ -2277,7 +2308,16 @@ interface DepositSessionParams {
2277
2308
  interface DepositSessionConfig extends DepositSessionParams {
2278
2309
  publishableKey: string;
2279
2310
  }
2280
- type DepositSessionStatus = 'idle' | 'creating_addresses' | 'awaiting_funds' | 'processing' | 'succeeded' | 'failed' | 'error';
2311
+ /**
2312
+ * Session status is LIFECYCLE-ONLY. A DepositSession is an ongoing watcher
2313
+ * that can observe many executions, so execution outcomes deliberately never
2314
+ * appear here — a session-level "succeeded"/"failed" misleads the moment a
2315
+ * second deposit arrives (a failure right after a success would flip the
2316
+ * whole session to "failed"). Outcomes live on the executions themselves:
2317
+ * `snapshot.executions` / `latestExecution` statuses, the
2318
+ * `direct_execution.succeeded`/`.failed` events, and `waitForSuccess()`.
2319
+ */
2320
+ type DepositSessionStatus = 'idle' | 'creating_addresses' | 'ready' | 'processing' | 'error';
2281
2321
  interface DepositSessionSnapshot {
2282
2322
  status: DepositSessionStatus;
2283
2323
  /** Deposit addresses (one per chain type); empty until created. */
@@ -2350,6 +2390,9 @@ declare class DepositSession {
2350
2390
  private baselineMs;
2351
2391
  private tracked;
2352
2392
  private pollErrorLatched;
2393
+ private pollInFlight;
2394
+ /** First execution to succeed this run — waitForSuccess's one-shot answer. */
2395
+ private firstSuccess;
2353
2396
  private detectionTimer;
2354
2397
  private nudgeTimer;
2355
2398
  private armTimer;
@@ -2388,9 +2431,11 @@ declare class DepositSession {
2388
2431
  destroy(): void;
2389
2432
  /**
2390
2433
  * Resolve when the session reaches one of the given statuses (immediately
2391
- * if it's already there). Generic primitive over the status state machine:
2392
- * `waitForStatus('processing')` awaits detection; `waitForStatus(['succeeded',
2393
- * 'failed'])` awaits a terminal outcome.
2434
+ * if it's already there). Generic primitive over the lifecycle state
2435
+ * machine — e.g. `waitForStatus('processing')` awaits detection of live
2436
+ * activity, `waitForStatus('ready')` awaits readiness. Statuses
2437
+ * carry no outcomes; await those with {@link waitForSuccess} or the
2438
+ * `direct_execution.*` events.
2394
2439
  *
2395
2440
  * Rejects with {@link DepositSessionWaitError} on abort or destroy().
2396
2441
  * Does not start or stop the session — it only listens.
@@ -2404,14 +2449,15 @@ declare class DepositSession {
2404
2449
  * Multi-execution semantics (unlike quote-scoped models such as Privy's,
2405
2450
  * one session can observe many executions — a user may send twice, or on
2406
2451
  * two chains): this waiter is one-shot "first completion" detection. If an
2407
- * execution has already succeeded, it resolves immediately with that
2408
- * execution. The session keeps polling after success — to react to every
2409
- * settlement, subscribe to `direct_execution.succeeded` events or read
2410
- * `snapshot.executions` instead.
2452
+ * execution has already succeeded this run, it resolves immediately with
2453
+ * the FIRST one that did (not the newest). The session keeps polling after
2454
+ * success to react to every settlement, subscribe to
2455
+ * `direct_execution.succeeded` events or read `snapshot.executions`.
2411
2456
  *
2412
2457
  * Rejects with {@link DepositSessionWaitError}:
2413
- * - `DEPOSIT_FAILED` (cause: the failed execution) when a deposit fails
2414
- * before any succeeds,
2458
+ * - `DEPOSIT_FAILED` (cause: the failed execution) when a deposit fails and
2459
+ * NO other observed execution is still in flight — a failure while
2460
+ * another deposit is pending keeps waiting (that one may still succeed),
2415
2461
  * - `SESSION_ERROR` (cause: the fatal {@link DepositSessionError}) on fatal
2416
2462
  * session errors (e.g. address creation failed),
2417
2463
  * - `ABORTED` / `DESTROYED` per the wait options and session lifecycle.
@@ -2438,8 +2484,10 @@ declare class DepositSession {
2438
2484
  private runStartChecks;
2439
2485
  private startDetectionLoop;
2440
2486
  private pollExecutions;
2487
+ private pollExecutionsOnce;
2441
2488
  private processExecutionChange;
2442
2489
  private armConfirmation;
2490
+ private anyExecutionInFlight;
2443
2491
  private setStatus;
2444
2492
  private clearTimers;
2445
2493
  private buildSnapshot;
@@ -2646,4 +2694,4 @@ declare const i18n: {
2646
2694
  };
2647
2695
  type I18nStrings = typeof i18n;
2648
2696
 
2649
- export { ActionType, type AddressBalanceResponse, type AddressBalancesResponse, type AddressValidationFailureCode, type AddressValidationMetadata, type AddressVerification, type ApplePayLimitUpgradeStatus, type ApplePayProvider, type ApplePayProvidersResponse, type AuthenticateOAuthResult, type AutoSwapRequest, type AutoSwapResponse, type BankTransferConfig, type BankTransferProvider, type BankTransferProvidersResponse, type BlockedCountrySubdivision, type BuildHypercoreTransactionRequest, type BuildHypercoreTransactionResponse, type BuildSolanaTransactionRequest, type BuildSolanaTransactionResponse, type CashAppLimits, type CashAppSessionRequest, type CashAppSessionResponse, type CashAppSessionStatusResponse, type ChainType, type CheckoutEvent, CheckoutEventType, type CheckoutMethod, type CheckoutPaymentIntent, type CheckoutPaymentIntentData, type CheckoutPaymentIntentSucceededEvent, type CoinbaseApplePayLimit, type CoinbaseApplePayLimitUpgradeOption, type CoinbaseApplePayLimitsResponse, type CoinbaseApplePaySessionResponse, type CoinbaseLegalAgreement, type CoinbaseLegalAgreementsResponse, type ConfirmIntegrationTransferResult, type CreateCoinbaseApplePaySessionRequest, type CreateDepositAddressRequest, type CreateExchangeSessionRequest, type CreateExchangeSessionResponse, type CreateIntegrationTransferParams, type CreateIntegrationTransferResult, type CreateOnrampVerificationSessionRequest, DETECTION_ARM_DELAY_MS, DETECTION_POLL_INTERVAL_MS, type DefaultTokenChain, type DefaultTokenMetadata, type DefaultTokenResponse, type DepositAddress, type DepositAddressParams, type DepositAddressResponse, DepositAddressValidationError, type DepositEvent, DepositEventType, type DepositMethod, type DepositQuote, type DepositQuoteRequest, DepositSession, type DepositSessionConfig, type DepositSessionDestination, type DepositSessionError, type DepositSessionErrorCode, type DepositSessionEvent, type DepositSessionEventMap, DepositSessionEventType, type DepositSessionParams, type DepositSessionSnapshot, type DepositSessionStatus, DepositSessionWaitError, type DepositSessionWaitErrorCode, type DepositSessionWaitOptions, type DestinationToken, type DestinationTokenChain, type DirectExecution, type DirectExecutionResponse, type DirectExecutionSucceededEvent, type EvmContractCall, type ExchangeProviderInfo, type ExchangeProvidersResponse, type ExchangeSessionStartParams, type ExchangeWalletAddress, ExecutionStatus, type ExternalWalletChainType, type ExternalWalletInfo, type ExternalWalletsResponse, type FeaturedToken, type FeaturedWallet, type FiatCurrenciesResponse, type FiatCurrency, type GetBankTransferProvidersOptions, type GetExchangesQuery, type HypercoreActivationRequest, type HypercoreActivationResponse, type I18nStrings, type IconUrl, IneligibilityReason, type IntegrationAccount, type IntegrationExchangeInfo, type IntegrationExchangesResponse, type IntegrationFeeAmount, type IntegrationHoldingsResponse, IntegrationProvider, type IpAddressResponse, LOOKBACK_MS, type ListExecutionsParams, type LockedQuoteLimits, type LockedQuotePreview, type LockedQuotePreviewRequest, type OnrampQuote, type OnrampQuotesRequest, type OnrampQuotesResponse, type OnrampSessionCreatedData, type OnrampSessionCreatedEvent, type OnrampSessionPaymentMethod, type OnrampSessionRequest, type OnrampSessionResponse, type OnrampVerificationFactor, type OnrampVerificationFactorStatus, type OnrampVerificationSession, type OnrampVerificationStatus, type OnrampVerificationTokenResponse, type PaymentIntent, type PaymentIntentDepositAddress, type PaymentIntentExecutionsResponse, type PaymentIntentStatus, type PaymentIntentType, type PaymentNetwork, type PollExecutionsRequest, type PollExecutionsResponse, type ProductType, type ProjectConfigResponse, type PublicIncidentResponse, type QueryExecutionsRequest, type QueryExecutionsResponse, type RefreshIntegrationTokenResult, type RequestCoinbaseApplePayLimitUpgradeRequest, type RequestCoinbaseApplePayLimitUpgradeResponse, SCAN_NUDGE_INTERVAL_MS, SOLANA_USDC_ADDRESS, type SendHypercoreTransactionRequest, type SendHypercoreTransactionResponse, type SendSolanaTransactionRequest, type SendSolanaTransactionResponse, type SourceToken, type SourceTokenNetwork, type StartIntegrationOAuthResult, type StripeAccessTokenResponse, StripeApiResponseError, type StripeAuthIntentResponse, type StripeConfigResponse, type StripeConfirmRequest, type StripeConsumerWallet, type StripeCreateSessionRequest, type StripeCryptoCustomer, type StripeCustomerVerification, type StripeDefaultTokenResponse, type StripeListResponse, type StripeOnrampErrorType, type StripeOnrampSession, type StripeOnrampTransactionDetails, type StripePaymentToken, type StripeQuoteRequest, type StripeQuotesResponse, type StripeTransactionLimitEntry, type StripeTransactionLimitsResponse, type SupportedChain, type SupportedDepositTokensParams, type SupportedDepositTokensResponse, type SupportedDestinationTokensResponse, type SupportedSourceTokensQuery, type SupportedSourceTokensResponse, type SupportedToken, type TokenBalance, type TokenChain, type TokenChainIconUrl, type TokenChainsResponse, type TokenDisplayMetadata, type TokenIconUrl, type TokenInfo, type TokenMetadata, type TransferDefaultTokenParams, type TransferDefaultTokenResult, UnifoldClient, type UnifoldClientOptions, type UserIpInfo, type VerifyAddressParams, type VerifyAddressRequest, type VerifyAddressResponse, type Wallet, type WalletMobileDeepLinkDepositAddress, type WalletMobileDeepLinkResponse, type WalletMobileDeepLinkWallet, type WithdrawDirectExecutionSucceededEvent, type WithdrawEvent, WithdrawEventType, authenticateIntegrationOAuth, buildHypercoreTransaction, buildSolanaTransaction, checkHypercoreActivation, confirmIntegrationTransfer, createCashAppSession, createCoinbaseApplePaySession, createDepositAddress, createExchangeSession, createIntegrationTransfer, createOnrampSession, createOnrampVerificationSession, createUnifoldClient, exchangeOnrampVerificationToken, formatStablecoinAmount, generateKSUID, generatePrefixedKSUID, getAddressBalance, getAddressBalances, getApiBaseUrl, getApplePayLimitUpgradeStatus, getApplePayProviders, getBankTransferProviders, getCashAppLimits, getCashAppSessionStatus, getChainName, getCoinbaseApplePayLimits, getCoinbaseLegalAgreements, getDefaultOnrampToken, getDepositAddress, getDepositQuote, getExchangeSessionStartUrl, getExchanges, getExternalWallets, getFiatCurrencies, getFiatExchangeRates, getIconUrl, getIconUrlWithCdn, getIntegrationExchanges, getIntegrationHoldings, getIntegrationTransferDefaultToken, getIpAddress, getOnrampQuotes, getOnrampSessionStartUrl, getOnrampVerificationSession, getPreferredIconUrl, getProjectConfig, getPublicIncident, getSupportedDepositTokens, getSupportedDestinationTokens, getTokenChains, getTokenMetadata, getWalletByChainType, getWalletMobileDeepLink, i18n, isApplePayLimitReached, isDepositAddressValidationError, listPaymentIntentExecutions, mapDirectExecution, mapWalletToDepositAddress, pollDirectExecutions, queryExecutions, refreshIntegrationToken, requestCoinbaseApplePayLimitUpgrade, retrievePaymentIntent, revokeIntegrationToken, sendHypercoreTransaction, sendOnrampVerificationOtp, sendSolanaTransaction, setApiConfig, startIntegrationOAuth, stripeConfirmSession, stripeCreateAuthIntent, stripeCreateSession, stripeExchangeTokens, stripeGetConfig, stripeGetCustomer, stripeGetDefaultToken, stripeGetQuotes, stripeGetSession, stripeGetTransactionLimits, stripeListPaymentTokens, stripeListWallets, stripeRefreshQuote, stripeRefreshToken, useUserIp, verifyOnrampVerificationOtp, verifyRecipientAddress };
2697
+ export { ActionType, type AddressBalanceResponse, type AddressBalancesResponse, type AddressValidationFailureCode, type AddressValidationMetadata, type AddressVerification, type ApplePayLimitUpgradeStatus, type ApplePayProvider, type ApplePayProvidersResponse, type AuthenticateOAuthResult, type AutoSwapRequest, type AutoSwapResponse, type BankTransferConfig, type BankTransferProvider, type BankTransferProvidersResponse, type BlockedCountrySubdivision, type BuildHypercoreTransactionRequest, type BuildHypercoreTransactionResponse, type BuildSolanaTransactionRequest, type BuildSolanaTransactionResponse, type CashAppLimits, type CashAppSessionRequest, type CashAppSessionResponse, type CashAppSessionStatusResponse, type ChainType, type CheckoutEvent, CheckoutEventType, type CheckoutMethod, type CheckoutPaymentIntent, type CheckoutPaymentIntentData, type CheckoutPaymentIntentSucceededEvent, type CoinbaseApplePayLimit, type CoinbaseApplePayLimitUpgradeOption, type CoinbaseApplePayLimitsResponse, type CoinbaseApplePaySessionResponse, type CoinbaseLegalAgreement, type CoinbaseLegalAgreementsResponse, type ConfirmIntegrationTransferResult, type CreateCoinbaseApplePaySessionRequest, type CreateDepositAddressRequest, type CreateExchangeSessionRequest, type CreateExchangeSessionResponse, type CreateIntegrationTransferParams, type CreateIntegrationTransferResult, type CreateOnrampVerificationSessionRequest, DETECTION_ARM_DELAY_MS, DETECTION_POLL_INTERVAL_MS, type DefaultTokenChain, type DefaultTokenMetadata, type DefaultTokenResponse, type DepositAddress, type DepositAddressParams, type DepositAddressResponse, DepositAddressValidationError, type DepositEvent, DepositEventType, type DepositMethod, type DepositQuote, type DepositQuoteRequest, DepositSession, type DepositSessionConfig, type DepositSessionDestination, type DepositSessionError, type DepositSessionErrorCode, type DepositSessionEvent, type DepositSessionEventMap, DepositSessionEventType, type DepositSessionParams, type DepositSessionSnapshot, type DepositSessionStatus, DepositSessionWaitError, type DepositSessionWaitErrorCode, type DepositSessionWaitOptions, type DestinationToken, type DestinationTokenChain, type DirectExecution, type DirectExecutionResponse, type DirectExecutionSucceededEvent, type EvmContractCall, type ExchangeProviderInfo, type ExchangeProvidersResponse, type ExchangeSessionStartParams, type ExchangeWalletAddress, ExecutionStatus, type ExternalWalletChainType, type ExternalWalletInfo, type ExternalWalletsResponse, type FeaturedToken, type FeaturedWallet, type FiatCurrenciesResponse, type FiatCurrency, type GetBankTransferProvidersOptions, type GetExchangesQuery, type HypercoreActivationRequest, type HypercoreActivationResponse, type I18nStrings, type IconUrl, IneligibilityReason, type IntegrationAccount, type IntegrationExchangeInfo, type IntegrationExchangesResponse, type IntegrationFeeAmount, type IntegrationHoldingsResponse, IntegrationProvider, type IpAddressResponse, LOOKBACK_MS, type ListExecutionsParams, type LockedQuoteLimits, type LockedQuotePreview, type LockedQuotePreviewRequest, type OnrampQuote, type OnrampQuotesRequest, type OnrampQuotesResponse, type OnrampSessionCreatedData, type OnrampSessionCreatedEvent, type OnrampSessionPaymentMethod, type OnrampSessionPaymentMethodType, type OnrampSessionRequest, type OnrampSessionResponse, type OnrampVerificationFactor, type OnrampVerificationFactorStatus, type OnrampVerificationSession, type OnrampVerificationStatus, type OnrampVerificationTokenResponse, type PaymentIntent, type PaymentIntentDepositAddress, type PaymentIntentExecutionsResponse, type PaymentIntentStatus, type PaymentIntentType, type PaymentNetwork, type PollExecutionsRequest, type PollExecutionsResponse, type ProductType, type ProjectConfigResponse, type PublicIncidentResponse, type QueryExecutionsRequest, type QueryExecutionsResponse, type RefreshIntegrationTokenResult, type RequestCoinbaseApplePayLimitUpgradeRequest, type RequestCoinbaseApplePayLimitUpgradeResponse, SCAN_NUDGE_INTERVAL_MS, SOLANA_USDC_ADDRESS, type SendHypercoreTransactionRequest, type SendHypercoreTransactionResponse, type SendSolanaTransactionRequest, type SendSolanaTransactionResponse, type SourceToken, type SourceTokenNetwork, type StartIntegrationOAuthResult, type StripeAccessTokenResponse, StripeApiResponseError, type StripeAuthIntentResponse, type StripeConfigResponse, type StripeConfirmRequest, type StripeConsumerWallet, type StripeCreateSessionRequest, type StripeCryptoCustomer, type StripeCustomerVerification, type StripeDefaultTokenResponse, type StripeListResponse, type StripeOnrampErrorType, type StripeOnrampSession, type StripeOnrampTransactionDetails, type StripePaymentToken, type StripeQuoteRequest, type StripeQuotesResponse, type StripeTransactionLimitEntry, type StripeTransactionLimitsResponse, type SupportedChain, type SupportedDepositTokensParams, type SupportedDepositTokensResponse, type SupportedDestinationTokensResponse, type SupportedSourceTokensQuery, type SupportedSourceTokensResponse, type SupportedToken, type TokenBalance, type TokenChain, type TokenChainIconUrl, type TokenChainsResponse, type TokenDisplayMetadata, type TokenIconUrl, type TokenInfo, type TokenMetadata, type TransferDefaultTokenParams, type TransferDefaultTokenResult, UnifoldClient, type UnifoldClientOptions, type UserIpInfo, type VerifyAddressParams, type VerifyAddressRequest, type VerifyAddressResponse, type Wallet, type WalletMobileDeepLinkDepositAddress, type WalletMobileDeepLinkResponse, type WalletMobileDeepLinkWallet, type WithdrawDirectExecutionSucceededEvent, type WithdrawEvent, WithdrawEventType, authenticateIntegrationOAuth, buildHypercoreTransaction, buildSolanaTransaction, checkHypercoreActivation, confirmIntegrationTransfer, createCashAppSession, createCoinbaseApplePaySession, createDepositAddress, createExchangeSession, createIntegrationTransfer, createOnrampSession, createOnrampVerificationSession, createUnifoldClient, exchangeOnrampVerificationToken, formatStablecoinAmount, generateKSUID, generatePrefixedKSUID, getAddressBalance, getAddressBalances, getApiBaseUrl, getApplePayLimitUpgradeStatus, getApplePayProviders, getBankTransferProviders, getCashAppLimits, getCashAppSessionStatus, getChainName, getCoinbaseApplePayLimits, getCoinbaseLegalAgreements, getDefaultOnrampToken, getDepositAddress, getDepositQuote, getExchangeSessionStartUrl, getExchanges, getExternalWallets, getFiatCurrencies, getFiatExchangeRates, getIconUrl, getIconUrlWithCdn, getIntegrationExchanges, getIntegrationHoldings, getIntegrationTransferDefaultToken, getIpAddress, getOnrampQuotes, getOnrampSessionStartUrl, getOnrampVerificationSession, getPreferredIconUrl, getProjectConfig, getPublicIncident, getSupportedDepositTokens, getSupportedDestinationTokens, getTokenChains, getTokenMetadata, getWalletByChainType, getWalletMobileDeepLink, i18n, isApplePayLimitReached, isDepositAddressValidationError, listPaymentIntentExecutions, mapDirectExecution, mapWalletToDepositAddress, pollDirectExecutions, queryExecutions, refreshIntegrationToken, requestCoinbaseApplePayLimitUpgrade, retrievePaymentIntent, revokeIntegrationToken, sendHypercoreTransaction, sendOnrampVerificationOtp, sendSolanaTransaction, setApiConfig, startIntegrationOAuth, stripeConfirmSession, stripeCreateAuthIntent, stripeCreateSession, stripeExchangeTokens, stripeGetConfig, stripeGetCustomer, stripeGetDefaultToken, stripeGetQuotes, stripeGetSession, stripeGetTransactionLimits, stripeListPaymentTokens, stripeListWallets, stripeRefreshQuote, stripeRefreshToken, useUserIp, verifyOnrampVerificationOtp, verifyRecipientAddress };
package/dist/index.js CHANGED
@@ -550,6 +550,9 @@ function getOnrampSessionStartUrl(request, publishableKey) {
550
550
  if (request.email) {
551
551
  params.append("email", request.email);
552
552
  }
553
+ if (request.payment_method_type) {
554
+ params.append("payment_method_type", request.payment_method_type);
555
+ }
553
556
  if (request.payment_method) {
554
557
  params.append("payment_method", request.payment_method);
555
558
  }
@@ -1207,11 +1210,12 @@ async function stripeGetDefaultToken(params, publishableKey) {
1207
1210
  }
1208
1211
  var HEADLESS_STRIPE_BASE = "/v1/public/onramps/headless/stripe";
1209
1212
  var StripeApiResponseError = class extends Error {
1210
- constructor(message, statusCode, stripeCode, errorType) {
1213
+ constructor(message, statusCode, stripeCode, errorType, stripeMessage) {
1211
1214
  super(message);
1212
1215
  this.statusCode = statusCode;
1213
1216
  this.stripeCode = stripeCode;
1214
1217
  this.errorType = errorType;
1218
+ this.stripeMessage = stripeMessage;
1215
1219
  this.name = "StripeApiResponseError";
1216
1220
  }
1217
1221
  };
@@ -1222,7 +1226,8 @@ function throwStripeError(prefix, response, error) {
1222
1226
  `${prefix}: ${detailMessage}`,
1223
1227
  response.status,
1224
1228
  stripeError?.code,
1225
- error.error_type
1229
+ error.error_type,
1230
+ stripeError?.message
1226
1231
  );
1227
1232
  }
1228
1233
  async function stripeGetConfig(publishableKey) {
@@ -1858,6 +1863,9 @@ var DepositSession = class {
1858
1863
  __publicField(this, "baselineMs", 0);
1859
1864
  __publicField(this, "tracked", /* @__PURE__ */ new Map());
1860
1865
  __publicField(this, "pollErrorLatched", false);
1866
+ __publicField(this, "pollInFlight", false);
1867
+ /** First execution to succeed this run — waitForSuccess's one-shot answer. */
1868
+ __publicField(this, "firstSuccess", null);
1861
1869
  __publicField(this, "detectionTimer", null);
1862
1870
  __publicField(this, "nudgeTimer", null);
1863
1871
  __publicField(this, "armTimer", null);
@@ -1928,8 +1936,9 @@ var DepositSession = class {
1928
1936
  this.runToken += 1;
1929
1937
  this.clearTimers();
1930
1938
  this.startPromise = null;
1931
- if (this.checkingDeposit) {
1932
- this.checkingDeposit = false;
1939
+ this.checkingDeposit = false;
1940
+ if (this.status !== "idle" && this.status !== "error") {
1941
+ this.setStatus("idle");
1933
1942
  }
1934
1943
  if (wasActive && !this.destroyed) {
1935
1944
  this.commit();
@@ -1951,9 +1960,11 @@ var DepositSession = class {
1951
1960
  // -- Promise waiters (subscription sugar over the event stream) ------------
1952
1961
  /**
1953
1962
  * Resolve when the session reaches one of the given statuses (immediately
1954
- * if it's already there). Generic primitive over the status state machine:
1955
- * `waitForStatus('processing')` awaits detection; `waitForStatus(['succeeded',
1956
- * 'failed'])` awaits a terminal outcome.
1963
+ * if it's already there). Generic primitive over the lifecycle state
1964
+ * machine — e.g. `waitForStatus('processing')` awaits detection of live
1965
+ * activity, `waitForStatus('ready')` awaits readiness. Statuses
1966
+ * carry no outcomes; await those with {@link waitForSuccess} or the
1967
+ * `direct_execution.*` events.
1957
1968
  *
1958
1969
  * Rejects with {@link DepositSessionWaitError} on abort or destroy().
1959
1970
  * Does not start or stop the session — it only listens.
@@ -1982,14 +1993,15 @@ var DepositSession = class {
1982
1993
  * Multi-execution semantics (unlike quote-scoped models such as Privy's,
1983
1994
  * one session can observe many executions — a user may send twice, or on
1984
1995
  * two chains): this waiter is one-shot "first completion" detection. If an
1985
- * execution has already succeeded, it resolves immediately with that
1986
- * execution. The session keeps polling after success — to react to every
1987
- * settlement, subscribe to `direct_execution.succeeded` events or read
1988
- * `snapshot.executions` instead.
1996
+ * execution has already succeeded this run, it resolves immediately with
1997
+ * the FIRST one that did (not the newest). The session keeps polling after
1998
+ * success to react to every settlement, subscribe to
1999
+ * `direct_execution.succeeded` events or read `snapshot.executions`.
1989
2000
  *
1990
2001
  * Rejects with {@link DepositSessionWaitError}:
1991
- * - `DEPOSIT_FAILED` (cause: the failed execution) when a deposit fails
1992
- * before any succeeds,
2002
+ * - `DEPOSIT_FAILED` (cause: the failed execution) when a deposit fails and
2003
+ * NO other observed execution is still in flight — a failure while
2004
+ * another deposit is pending keeps waiting (that one may still succeed),
1993
2005
  * - `SESSION_ERROR` (cause: the fatal {@link DepositSessionError}) on fatal
1994
2006
  * session errors (e.g. address creation failed),
1995
2007
  * - `ABORTED` / `DESTROYED` per the wait options and session lifecycle.
@@ -2000,29 +2012,28 @@ var DepositSession = class {
2000
2012
  options,
2001
2013
  reject,
2002
2014
  subscribe: (settle) => {
2003
- const { executions, error } = this.snapshot;
2004
- const alreadySucceeded = executions.find(
2005
- (execution) => execution.status === "succeeded" /* SUCCEEDED */
2015
+ const rejectFailure = (failed) => settle(
2016
+ () => reject(new DepositSessionWaitError("DEPOSIT_FAILED", "Deposit failed", failed))
2006
2017
  );
2007
- if (alreadySucceeded) {
2008
- settle(() => resolve(alreadySucceeded));
2018
+ const { executions, error } = this.snapshot;
2019
+ if (this.firstSuccess) {
2020
+ const first = this.firstSuccess;
2021
+ settle(() => resolve(first));
2009
2022
  return () => {
2010
2023
  };
2011
2024
  }
2012
2025
  const alreadyFailed = executions.find(
2013
2026
  (execution) => FAILURE_STATUSES.includes(execution.status)
2014
2027
  );
2015
- if (alreadyFailed) {
2016
- settle(
2017
- () => reject(
2018
- new DepositSessionWaitError("DEPOSIT_FAILED", "Deposit failed", alreadyFailed)
2019
- )
2020
- );
2028
+ if (alreadyFailed && !this.anyExecutionInFlight()) {
2029
+ rejectFailure(alreadyFailed);
2021
2030
  return () => {
2022
2031
  };
2023
2032
  }
2024
2033
  if (error?.fatal) {
2025
- settle(() => reject(new DepositSessionWaitError("SESSION_ERROR", error.message, error)));
2034
+ settle(
2035
+ () => reject(new DepositSessionWaitError("SESSION_ERROR", error.message, error))
2036
+ );
2026
2037
  return () => {
2027
2038
  };
2028
2039
  }
@@ -2031,14 +2042,20 @@ var DepositSession = class {
2031
2042
  "direct_execution.succeeded" /* EXECUTION_SUCCEEDED */,
2032
2043
  (event) => settle(() => resolve(event.data.object))
2033
2044
  ),
2034
- this.on(
2035
- "direct_execution.failed" /* EXECUTION_FAILED */,
2036
- (event) => settle(
2037
- () => reject(
2038
- new DepositSessionWaitError("DEPOSIT_FAILED", "Deposit failed", event.data.object)
2039
- )
2040
- )
2041
- ),
2045
+ this.on("direct_execution.failed" /* EXECUTION_FAILED */, (event) => {
2046
+ if (this.anyExecutionInFlight()) return;
2047
+ rejectFailure(event.data.object);
2048
+ }),
2049
+ // A previously-failed wait condition can become settleable when
2050
+ // the last in-flight execution also fails (updated → failed is
2051
+ // covered above; updated → refunded transitions re-check here).
2052
+ this.on("direct_execution.updated" /* EXECUTION_UPDATED */, () => {
2053
+ if (this.anyExecutionInFlight() || this.firstSuccess) return;
2054
+ const failed = this.snapshot.executions.find(
2055
+ (execution) => FAILURE_STATUSES.includes(execution.status)
2056
+ );
2057
+ if (failed) rejectFailure(failed);
2058
+ }),
2042
2059
  this.on("deposit_session.errored" /* SESSION_ERRORED */, (event) => {
2043
2060
  if (!event.data.object.fatal) return;
2044
2061
  settle(
@@ -2092,7 +2109,9 @@ var DepositSession = class {
2092
2109
  () => reject(new DepositSessionWaitError("ABORTED", "Wait aborted", options.signal?.reason))
2093
2110
  );
2094
2111
  const onDestroy = () => settle(
2095
- () => reject(new DepositSessionWaitError("DESTROYED", "DepositSession was destroyed while waiting"))
2112
+ () => reject(
2113
+ new DepositSessionWaitError("DESTROYED", "DepositSession was destroyed while waiting")
2114
+ )
2096
2115
  );
2097
2116
  this.waiterDestroyCallbacks.add(onDestroy);
2098
2117
  options.signal?.addEventListener("abort", onAbort, { once: true });
@@ -2106,19 +2125,20 @@ var DepositSession = class {
2106
2125
  this.tracked.clear();
2107
2126
  this.pollErrorLatched = false;
2108
2127
  this.executions = [];
2128
+ this.firstSuccess = null;
2109
2129
  this.error = null;
2110
2130
  this.checkingDeposit = false;
2131
+ this.addresses = [];
2132
+ this.addressIds = [];
2111
2133
  this.setStatus("creating_addresses");
2134
+ this.commit();
2112
2135
  this.emitSessionEvent("deposit_session.started" /* SESSION_STARTED */, {
2113
2136
  sessionId: this.id
2114
2137
  });
2115
2138
  this.notify();
2116
2139
  let wallets;
2117
2140
  try {
2118
- [wallets] = await Promise.all([
2119
- this.createAddressesWithRetry(token),
2120
- this.runStartChecks()
2121
- ]);
2141
+ [wallets] = await Promise.all([this.createAddressesWithRetry(token), this.runStartChecks()]);
2122
2142
  } catch (cause) {
2123
2143
  if (token !== this.runToken) return;
2124
2144
  const isCheck = cause instanceof SessionCheckError;
@@ -2132,13 +2152,14 @@ var DepositSession = class {
2132
2152
  if (token !== this.runToken) return;
2133
2153
  this.addresses = wallets.map(mapWalletToDepositAddress);
2134
2154
  this.addressIds = wallets.map((w) => w.id).filter(Boolean);
2135
- this.setStatus("awaiting_funds");
2155
+ this.setStatus("ready");
2136
2156
  this.commit();
2137
2157
  this.emitSessionEvent("deposit_session.addresses_created" /* ADDRESSES_CREATED */, {
2138
2158
  sessionId: this.id,
2139
2159
  addresses: this.addresses
2140
2160
  });
2141
2161
  this.notify();
2162
+ if (token !== this.runToken) return;
2142
2163
  this.startDetectionLoop(token);
2143
2164
  if (this.confirmationMode === "auto") {
2144
2165
  this.armTimer = setTimeout(() => {
@@ -2214,11 +2235,29 @@ var DepositSession = class {
2214
2235
  }
2215
2236
  // -- Detection polling (port of useDepositPolling Effect 2) ----------------
2216
2237
  startDetectionLoop(token) {
2217
- const poll = () => void this.pollExecutions(token);
2238
+ const poll = () => {
2239
+ if (token !== this.runToken) {
2240
+ if (this.detectionTimer) {
2241
+ clearInterval(this.detectionTimer);
2242
+ this.detectionTimer = null;
2243
+ }
2244
+ return;
2245
+ }
2246
+ void this.pollExecutions(token);
2247
+ };
2218
2248
  poll();
2219
2249
  this.detectionTimer = setInterval(poll, DETECTION_POLL_INTERVAL_MS);
2220
2250
  }
2221
2251
  async pollExecutions(token) {
2252
+ if (this.pollInFlight) return;
2253
+ this.pollInFlight = true;
2254
+ try {
2255
+ await this.pollExecutionsOnce(token);
2256
+ } finally {
2257
+ this.pollInFlight = false;
2258
+ }
2259
+ }
2260
+ async pollExecutionsOnce(token) {
2222
2261
  try {
2223
2262
  const response = await queryExecutions(
2224
2263
  this.externalUserId,
@@ -2284,9 +2323,7 @@ var DepositSession = class {
2284
2323
  const execution = mapDirectExecution(wire);
2285
2324
  const existingIndex = this.executions.findIndex((e) => e.id === execution.id);
2286
2325
  if (existingIndex >= 0) {
2287
- this.executions = this.executions.map(
2288
- (e, i) => i === existingIndex ? execution : e
2289
- );
2326
+ this.executions = this.executions.map((e, i) => i === existingIndex ? execution : e);
2290
2327
  } else {
2291
2328
  this.executions = [...this.executions, execution].sort((a, b) => {
2292
2329
  const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
@@ -2294,21 +2331,15 @@ var DepositSession = class {
2294
2331
  return timeB - timeA;
2295
2332
  });
2296
2333
  }
2297
- if (wire.status === "succeeded" /* SUCCEEDED */) {
2298
- this.setStatus("succeeded");
2299
- } else if (FAILURE_STATUSES.includes(wire.status)) {
2300
- this.setStatus("failed");
2301
- } else if (IN_PROGRESS_STATUSES.includes(wire.status)) {
2302
- this.setStatus("processing");
2334
+ this.setStatus(this.anyExecutionInFlight() ? "processing" : "ready");
2335
+ const wasInProgressOrNew = previousStatus === null || IN_PROGRESS_STATUSES.includes(previousStatus);
2336
+ if (wire.status === "succeeded" /* SUCCEEDED */ && wasInProgressOrNew && !this.firstSuccess) {
2337
+ this.firstSuccess = execution;
2303
2338
  }
2304
2339
  this.commit();
2305
2340
  const eventCreated = this.executionEventTimestamp(wire);
2306
2341
  if (previousStatus === null) {
2307
- this.emitExecutionEvent(
2308
- "direct_execution.detected" /* EXECUTION_DETECTED */,
2309
- execution,
2310
- eventCreated
2311
- );
2342
+ this.emitExecutionEvent("direct_execution.detected" /* EXECUTION_DETECTED */, execution, eventCreated);
2312
2343
  } else {
2313
2344
  this.emitExecutionEvent(
2314
2345
  "direct_execution.updated" /* EXECUTION_UPDATED */,
@@ -2316,25 +2347,17 @@ var DepositSession = class {
2316
2347
  eventCreated
2317
2348
  );
2318
2349
  }
2319
- const wasInProgressOrNew = previousStatus === null || IN_PROGRESS_STATUSES.includes(previousStatus);
2320
2350
  if (wire.status === "succeeded" /* SUCCEEDED */ && wasInProgressOrNew) {
2321
- this.emitExecutionEvent(
2322
- "direct_execution.succeeded" /* EXECUTION_SUCCEEDED */,
2323
- execution,
2324
- eventCreated
2325
- );
2351
+ this.emitExecutionEvent("direct_execution.succeeded" /* EXECUTION_SUCCEEDED */, execution, eventCreated);
2326
2352
  } else if (FAILURE_STATUSES.includes(wire.status) && (previousStatus === null || !FAILURE_STATUSES.includes(previousStatus))) {
2327
- this.emitExecutionEvent(
2328
- "direct_execution.failed" /* EXECUTION_FAILED */,
2329
- execution,
2330
- eventCreated
2331
- );
2353
+ this.emitExecutionEvent("direct_execution.failed" /* EXECUTION_FAILED */, execution, eventCreated);
2332
2354
  }
2333
2355
  this.notify();
2334
2356
  }
2335
2357
  // -- Scan nudge (port of useDepositPolling Effects 1 + 3) ------------------
2336
2358
  armConfirmation(trigger) {
2337
2359
  if (this.checkingDeposit || this.destroyed) return;
2360
+ if (this.addressIds.length === 0) return;
2338
2361
  if (this.armTimer) {
2339
2362
  clearTimeout(this.armTimer);
2340
2363
  this.armTimer = null;
@@ -2351,10 +2374,8 @@ var DepositSession = class {
2351
2374
  if (token !== this.runToken) return;
2352
2375
  void Promise.all(
2353
2376
  this.addressIds.map(
2354
- (id) => pollDirectExecutions({ deposit_wallet_id: id }, this.publishableKey).catch(
2355
- () => {
2356
- }
2357
- )
2377
+ (id) => pollDirectExecutions({ deposit_wallet_id: id }, this.publishableKey).catch(() => {
2378
+ })
2358
2379
  )
2359
2380
  );
2360
2381
  };
@@ -2362,6 +2383,11 @@ var DepositSession = class {
2362
2383
  this.nudgeTimer = setInterval(nudge, SCAN_NUDGE_INTERVAL_MS);
2363
2384
  }
2364
2385
  // -- Internals --------------------------------------------------------------
2386
+ anyExecutionInFlight() {
2387
+ return Array.from(this.tracked.values()).some(
2388
+ (status) => IN_PROGRESS_STATUSES.includes(status)
2389
+ );
2390
+ }
2365
2391
  setStatus(status) {
2366
2392
  this.status = status;
2367
2393
  }
@@ -2436,9 +2462,7 @@ var UnifoldClient = class {
2436
2462
  throw new Error("Unifold: publishableKey is required");
2437
2463
  }
2438
2464
  if (!publishableKey.startsWith("pk_test_") && !publishableKey.startsWith("pk_live_")) {
2439
- console.warn(
2440
- 'Unifold: publishableKey should start with "pk_test_" or "pk_live_".'
2441
- );
2465
+ console.warn('Unifold: publishableKey should start with "pk_test_" or "pk_live_".');
2442
2466
  }
2443
2467
  this.publishableKey = publishableKey;
2444
2468
  }
package/dist/index.mjs CHANGED
@@ -421,6 +421,9 @@ function getOnrampSessionStartUrl(request, publishableKey) {
421
421
  if (request.email) {
422
422
  params.append("email", request.email);
423
423
  }
424
+ if (request.payment_method_type) {
425
+ params.append("payment_method_type", request.payment_method_type);
426
+ }
424
427
  if (request.payment_method) {
425
428
  params.append("payment_method", request.payment_method);
426
429
  }
@@ -1078,11 +1081,12 @@ async function stripeGetDefaultToken(params, publishableKey) {
1078
1081
  }
1079
1082
  var HEADLESS_STRIPE_BASE = "/v1/public/onramps/headless/stripe";
1080
1083
  var StripeApiResponseError = class extends Error {
1081
- constructor(message, statusCode, stripeCode, errorType) {
1084
+ constructor(message, statusCode, stripeCode, errorType, stripeMessage) {
1082
1085
  super(message);
1083
1086
  this.statusCode = statusCode;
1084
1087
  this.stripeCode = stripeCode;
1085
1088
  this.errorType = errorType;
1089
+ this.stripeMessage = stripeMessage;
1086
1090
  this.name = "StripeApiResponseError";
1087
1091
  }
1088
1092
  };
@@ -1093,7 +1097,8 @@ function throwStripeError(prefix, response, error) {
1093
1097
  `${prefix}: ${detailMessage}`,
1094
1098
  response.status,
1095
1099
  stripeError?.code,
1096
- error.error_type
1100
+ error.error_type,
1101
+ stripeError?.message
1097
1102
  );
1098
1103
  }
1099
1104
  async function stripeGetConfig(publishableKey) {
@@ -1729,6 +1734,9 @@ var DepositSession = class {
1729
1734
  __publicField(this, "baselineMs", 0);
1730
1735
  __publicField(this, "tracked", /* @__PURE__ */ new Map());
1731
1736
  __publicField(this, "pollErrorLatched", false);
1737
+ __publicField(this, "pollInFlight", false);
1738
+ /** First execution to succeed this run — waitForSuccess's one-shot answer. */
1739
+ __publicField(this, "firstSuccess", null);
1732
1740
  __publicField(this, "detectionTimer", null);
1733
1741
  __publicField(this, "nudgeTimer", null);
1734
1742
  __publicField(this, "armTimer", null);
@@ -1799,8 +1807,9 @@ var DepositSession = class {
1799
1807
  this.runToken += 1;
1800
1808
  this.clearTimers();
1801
1809
  this.startPromise = null;
1802
- if (this.checkingDeposit) {
1803
- this.checkingDeposit = false;
1810
+ this.checkingDeposit = false;
1811
+ if (this.status !== "idle" && this.status !== "error") {
1812
+ this.setStatus("idle");
1804
1813
  }
1805
1814
  if (wasActive && !this.destroyed) {
1806
1815
  this.commit();
@@ -1822,9 +1831,11 @@ var DepositSession = class {
1822
1831
  // -- Promise waiters (subscription sugar over the event stream) ------------
1823
1832
  /**
1824
1833
  * Resolve when the session reaches one of the given statuses (immediately
1825
- * if it's already there). Generic primitive over the status state machine:
1826
- * `waitForStatus('processing')` awaits detection; `waitForStatus(['succeeded',
1827
- * 'failed'])` awaits a terminal outcome.
1834
+ * if it's already there). Generic primitive over the lifecycle state
1835
+ * machine — e.g. `waitForStatus('processing')` awaits detection of live
1836
+ * activity, `waitForStatus('ready')` awaits readiness. Statuses
1837
+ * carry no outcomes; await those with {@link waitForSuccess} or the
1838
+ * `direct_execution.*` events.
1828
1839
  *
1829
1840
  * Rejects with {@link DepositSessionWaitError} on abort or destroy().
1830
1841
  * Does not start or stop the session — it only listens.
@@ -1853,14 +1864,15 @@ var DepositSession = class {
1853
1864
  * Multi-execution semantics (unlike quote-scoped models such as Privy's,
1854
1865
  * one session can observe many executions — a user may send twice, or on
1855
1866
  * two chains): this waiter is one-shot "first completion" detection. If an
1856
- * execution has already succeeded, it resolves immediately with that
1857
- * execution. The session keeps polling after success — to react to every
1858
- * settlement, subscribe to `direct_execution.succeeded` events or read
1859
- * `snapshot.executions` instead.
1867
+ * execution has already succeeded this run, it resolves immediately with
1868
+ * the FIRST one that did (not the newest). The session keeps polling after
1869
+ * success to react to every settlement, subscribe to
1870
+ * `direct_execution.succeeded` events or read `snapshot.executions`.
1860
1871
  *
1861
1872
  * Rejects with {@link DepositSessionWaitError}:
1862
- * - `DEPOSIT_FAILED` (cause: the failed execution) when a deposit fails
1863
- * before any succeeds,
1873
+ * - `DEPOSIT_FAILED` (cause: the failed execution) when a deposit fails and
1874
+ * NO other observed execution is still in flight — a failure while
1875
+ * another deposit is pending keeps waiting (that one may still succeed),
1864
1876
  * - `SESSION_ERROR` (cause: the fatal {@link DepositSessionError}) on fatal
1865
1877
  * session errors (e.g. address creation failed),
1866
1878
  * - `ABORTED` / `DESTROYED` per the wait options and session lifecycle.
@@ -1871,29 +1883,28 @@ var DepositSession = class {
1871
1883
  options,
1872
1884
  reject,
1873
1885
  subscribe: (settle) => {
1874
- const { executions, error } = this.snapshot;
1875
- const alreadySucceeded = executions.find(
1876
- (execution) => execution.status === "succeeded" /* SUCCEEDED */
1886
+ const rejectFailure = (failed) => settle(
1887
+ () => reject(new DepositSessionWaitError("DEPOSIT_FAILED", "Deposit failed", failed))
1877
1888
  );
1878
- if (alreadySucceeded) {
1879
- settle(() => resolve(alreadySucceeded));
1889
+ const { executions, error } = this.snapshot;
1890
+ if (this.firstSuccess) {
1891
+ const first = this.firstSuccess;
1892
+ settle(() => resolve(first));
1880
1893
  return () => {
1881
1894
  };
1882
1895
  }
1883
1896
  const alreadyFailed = executions.find(
1884
1897
  (execution) => FAILURE_STATUSES.includes(execution.status)
1885
1898
  );
1886
- if (alreadyFailed) {
1887
- settle(
1888
- () => reject(
1889
- new DepositSessionWaitError("DEPOSIT_FAILED", "Deposit failed", alreadyFailed)
1890
- )
1891
- );
1899
+ if (alreadyFailed && !this.anyExecutionInFlight()) {
1900
+ rejectFailure(alreadyFailed);
1892
1901
  return () => {
1893
1902
  };
1894
1903
  }
1895
1904
  if (error?.fatal) {
1896
- settle(() => reject(new DepositSessionWaitError("SESSION_ERROR", error.message, error)));
1905
+ settle(
1906
+ () => reject(new DepositSessionWaitError("SESSION_ERROR", error.message, error))
1907
+ );
1897
1908
  return () => {
1898
1909
  };
1899
1910
  }
@@ -1902,14 +1913,20 @@ var DepositSession = class {
1902
1913
  "direct_execution.succeeded" /* EXECUTION_SUCCEEDED */,
1903
1914
  (event) => settle(() => resolve(event.data.object))
1904
1915
  ),
1905
- this.on(
1906
- "direct_execution.failed" /* EXECUTION_FAILED */,
1907
- (event) => settle(
1908
- () => reject(
1909
- new DepositSessionWaitError("DEPOSIT_FAILED", "Deposit failed", event.data.object)
1910
- )
1911
- )
1912
- ),
1916
+ this.on("direct_execution.failed" /* EXECUTION_FAILED */, (event) => {
1917
+ if (this.anyExecutionInFlight()) return;
1918
+ rejectFailure(event.data.object);
1919
+ }),
1920
+ // A previously-failed wait condition can become settleable when
1921
+ // the last in-flight execution also fails (updated → failed is
1922
+ // covered above; updated → refunded transitions re-check here).
1923
+ this.on("direct_execution.updated" /* EXECUTION_UPDATED */, () => {
1924
+ if (this.anyExecutionInFlight() || this.firstSuccess) return;
1925
+ const failed = this.snapshot.executions.find(
1926
+ (execution) => FAILURE_STATUSES.includes(execution.status)
1927
+ );
1928
+ if (failed) rejectFailure(failed);
1929
+ }),
1913
1930
  this.on("deposit_session.errored" /* SESSION_ERRORED */, (event) => {
1914
1931
  if (!event.data.object.fatal) return;
1915
1932
  settle(
@@ -1963,7 +1980,9 @@ var DepositSession = class {
1963
1980
  () => reject(new DepositSessionWaitError("ABORTED", "Wait aborted", options.signal?.reason))
1964
1981
  );
1965
1982
  const onDestroy = () => settle(
1966
- () => reject(new DepositSessionWaitError("DESTROYED", "DepositSession was destroyed while waiting"))
1983
+ () => reject(
1984
+ new DepositSessionWaitError("DESTROYED", "DepositSession was destroyed while waiting")
1985
+ )
1967
1986
  );
1968
1987
  this.waiterDestroyCallbacks.add(onDestroy);
1969
1988
  options.signal?.addEventListener("abort", onAbort, { once: true });
@@ -1977,19 +1996,20 @@ var DepositSession = class {
1977
1996
  this.tracked.clear();
1978
1997
  this.pollErrorLatched = false;
1979
1998
  this.executions = [];
1999
+ this.firstSuccess = null;
1980
2000
  this.error = null;
1981
2001
  this.checkingDeposit = false;
2002
+ this.addresses = [];
2003
+ this.addressIds = [];
1982
2004
  this.setStatus("creating_addresses");
2005
+ this.commit();
1983
2006
  this.emitSessionEvent("deposit_session.started" /* SESSION_STARTED */, {
1984
2007
  sessionId: this.id
1985
2008
  });
1986
2009
  this.notify();
1987
2010
  let wallets;
1988
2011
  try {
1989
- [wallets] = await Promise.all([
1990
- this.createAddressesWithRetry(token),
1991
- this.runStartChecks()
1992
- ]);
2012
+ [wallets] = await Promise.all([this.createAddressesWithRetry(token), this.runStartChecks()]);
1993
2013
  } catch (cause) {
1994
2014
  if (token !== this.runToken) return;
1995
2015
  const isCheck = cause instanceof SessionCheckError;
@@ -2003,13 +2023,14 @@ var DepositSession = class {
2003
2023
  if (token !== this.runToken) return;
2004
2024
  this.addresses = wallets.map(mapWalletToDepositAddress);
2005
2025
  this.addressIds = wallets.map((w) => w.id).filter(Boolean);
2006
- this.setStatus("awaiting_funds");
2026
+ this.setStatus("ready");
2007
2027
  this.commit();
2008
2028
  this.emitSessionEvent("deposit_session.addresses_created" /* ADDRESSES_CREATED */, {
2009
2029
  sessionId: this.id,
2010
2030
  addresses: this.addresses
2011
2031
  });
2012
2032
  this.notify();
2033
+ if (token !== this.runToken) return;
2013
2034
  this.startDetectionLoop(token);
2014
2035
  if (this.confirmationMode === "auto") {
2015
2036
  this.armTimer = setTimeout(() => {
@@ -2085,11 +2106,29 @@ var DepositSession = class {
2085
2106
  }
2086
2107
  // -- Detection polling (port of useDepositPolling Effect 2) ----------------
2087
2108
  startDetectionLoop(token) {
2088
- const poll = () => void this.pollExecutions(token);
2109
+ const poll = () => {
2110
+ if (token !== this.runToken) {
2111
+ if (this.detectionTimer) {
2112
+ clearInterval(this.detectionTimer);
2113
+ this.detectionTimer = null;
2114
+ }
2115
+ return;
2116
+ }
2117
+ void this.pollExecutions(token);
2118
+ };
2089
2119
  poll();
2090
2120
  this.detectionTimer = setInterval(poll, DETECTION_POLL_INTERVAL_MS);
2091
2121
  }
2092
2122
  async pollExecutions(token) {
2123
+ if (this.pollInFlight) return;
2124
+ this.pollInFlight = true;
2125
+ try {
2126
+ await this.pollExecutionsOnce(token);
2127
+ } finally {
2128
+ this.pollInFlight = false;
2129
+ }
2130
+ }
2131
+ async pollExecutionsOnce(token) {
2093
2132
  try {
2094
2133
  const response = await queryExecutions(
2095
2134
  this.externalUserId,
@@ -2155,9 +2194,7 @@ var DepositSession = class {
2155
2194
  const execution = mapDirectExecution(wire);
2156
2195
  const existingIndex = this.executions.findIndex((e) => e.id === execution.id);
2157
2196
  if (existingIndex >= 0) {
2158
- this.executions = this.executions.map(
2159
- (e, i) => i === existingIndex ? execution : e
2160
- );
2197
+ this.executions = this.executions.map((e, i) => i === existingIndex ? execution : e);
2161
2198
  } else {
2162
2199
  this.executions = [...this.executions, execution].sort((a, b) => {
2163
2200
  const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
@@ -2165,21 +2202,15 @@ var DepositSession = class {
2165
2202
  return timeB - timeA;
2166
2203
  });
2167
2204
  }
2168
- if (wire.status === "succeeded" /* SUCCEEDED */) {
2169
- this.setStatus("succeeded");
2170
- } else if (FAILURE_STATUSES.includes(wire.status)) {
2171
- this.setStatus("failed");
2172
- } else if (IN_PROGRESS_STATUSES.includes(wire.status)) {
2173
- this.setStatus("processing");
2205
+ this.setStatus(this.anyExecutionInFlight() ? "processing" : "ready");
2206
+ const wasInProgressOrNew = previousStatus === null || IN_PROGRESS_STATUSES.includes(previousStatus);
2207
+ if (wire.status === "succeeded" /* SUCCEEDED */ && wasInProgressOrNew && !this.firstSuccess) {
2208
+ this.firstSuccess = execution;
2174
2209
  }
2175
2210
  this.commit();
2176
2211
  const eventCreated = this.executionEventTimestamp(wire);
2177
2212
  if (previousStatus === null) {
2178
- this.emitExecutionEvent(
2179
- "direct_execution.detected" /* EXECUTION_DETECTED */,
2180
- execution,
2181
- eventCreated
2182
- );
2213
+ this.emitExecutionEvent("direct_execution.detected" /* EXECUTION_DETECTED */, execution, eventCreated);
2183
2214
  } else {
2184
2215
  this.emitExecutionEvent(
2185
2216
  "direct_execution.updated" /* EXECUTION_UPDATED */,
@@ -2187,25 +2218,17 @@ var DepositSession = class {
2187
2218
  eventCreated
2188
2219
  );
2189
2220
  }
2190
- const wasInProgressOrNew = previousStatus === null || IN_PROGRESS_STATUSES.includes(previousStatus);
2191
2221
  if (wire.status === "succeeded" /* SUCCEEDED */ && wasInProgressOrNew) {
2192
- this.emitExecutionEvent(
2193
- "direct_execution.succeeded" /* EXECUTION_SUCCEEDED */,
2194
- execution,
2195
- eventCreated
2196
- );
2222
+ this.emitExecutionEvent("direct_execution.succeeded" /* EXECUTION_SUCCEEDED */, execution, eventCreated);
2197
2223
  } else if (FAILURE_STATUSES.includes(wire.status) && (previousStatus === null || !FAILURE_STATUSES.includes(previousStatus))) {
2198
- this.emitExecutionEvent(
2199
- "direct_execution.failed" /* EXECUTION_FAILED */,
2200
- execution,
2201
- eventCreated
2202
- );
2224
+ this.emitExecutionEvent("direct_execution.failed" /* EXECUTION_FAILED */, execution, eventCreated);
2203
2225
  }
2204
2226
  this.notify();
2205
2227
  }
2206
2228
  // -- Scan nudge (port of useDepositPolling Effects 1 + 3) ------------------
2207
2229
  armConfirmation(trigger) {
2208
2230
  if (this.checkingDeposit || this.destroyed) return;
2231
+ if (this.addressIds.length === 0) return;
2209
2232
  if (this.armTimer) {
2210
2233
  clearTimeout(this.armTimer);
2211
2234
  this.armTimer = null;
@@ -2222,10 +2245,8 @@ var DepositSession = class {
2222
2245
  if (token !== this.runToken) return;
2223
2246
  void Promise.all(
2224
2247
  this.addressIds.map(
2225
- (id) => pollDirectExecutions({ deposit_wallet_id: id }, this.publishableKey).catch(
2226
- () => {
2227
- }
2228
- )
2248
+ (id) => pollDirectExecutions({ deposit_wallet_id: id }, this.publishableKey).catch(() => {
2249
+ })
2229
2250
  )
2230
2251
  );
2231
2252
  };
@@ -2233,6 +2254,11 @@ var DepositSession = class {
2233
2254
  this.nudgeTimer = setInterval(nudge, SCAN_NUDGE_INTERVAL_MS);
2234
2255
  }
2235
2256
  // -- Internals --------------------------------------------------------------
2257
+ anyExecutionInFlight() {
2258
+ return Array.from(this.tracked.values()).some(
2259
+ (status) => IN_PROGRESS_STATUSES.includes(status)
2260
+ );
2261
+ }
2236
2262
  setStatus(status) {
2237
2263
  this.status = status;
2238
2264
  }
@@ -2307,9 +2333,7 @@ var UnifoldClient = class {
2307
2333
  throw new Error("Unifold: publishableKey is required");
2308
2334
  }
2309
2335
  if (!publishableKey.startsWith("pk_test_") && !publishableKey.startsWith("pk_live_")) {
2310
- console.warn(
2311
- 'Unifold: publishableKey should start with "pk_test_" or "pk_live_".'
2312
- );
2336
+ console.warn('Unifold: publishableKey should start with "pk_test_" or "pk_live_".');
2313
2337
  }
2314
2338
  this.publishableKey = publishableKey;
2315
2339
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unifold/core",
3
- "version": "0.1.70-beta.1",
3
+ "version": "0.1.70",
4
4
  "description": "Unifold Core SDK - Core types, API client, and business logic",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",