@trustware/sdk-staging 1.1.11-staging.1 → 1.1.12-staging.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +54 -21
  2. package/dist/{blockchain-BxAFzp0s.d.cts → blockchain-DmCPxnxr.d.cts} +25 -1
  3. package/dist/{blockchain-BxAFzp0s.d.ts → blockchain-DmCPxnxr.d.ts} +25 -1
  4. package/dist/constants.cjs +1 -1
  5. package/dist/constants.mjs +1 -1
  6. package/dist/{core-BgYLe9Q7.d.ts → core-B4YDGtJT.d.ts} +3 -3
  7. package/dist/{core-fLSt4qD2.d.cts → core-Ck7dinYj.d.cts} +3 -3
  8. package/dist/core.cjs +141 -52
  9. package/dist/core.cjs.map +1 -1
  10. package/dist/core.d.cts +4 -4
  11. package/dist/core.d.ts +4 -4
  12. package/dist/core.mjs +139 -51
  13. package/dist/core.mjs.map +1 -1
  14. package/dist/index.cjs +166 -75
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +14 -8
  17. package/dist/index.d.ts +14 -8
  18. package/dist/index.mjs +164 -75
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/{manager-DT8enQbE.d.cts → manager-BZ8gyHGT.d.cts} +90 -23
  21. package/dist/{manager-BY3NHAks.d.ts → manager-D8nQsod2.d.ts} +90 -23
  22. package/dist/{metadata-DyxUcKHk.d.cts → metadata-B23D0oO9.d.cts} +1 -1
  23. package/dist/{metadata-BPvFYMlc.d.ts → metadata-BOjEF7oo.d.ts} +1 -1
  24. package/dist/smart-account.cjs +62 -47
  25. package/dist/smart-account.cjs.map +1 -1
  26. package/dist/smart-account.d.cts +6 -0
  27. package/dist/smart-account.d.ts +6 -0
  28. package/dist/smart-account.mjs +62 -47
  29. package/dist/smart-account.mjs.map +1 -1
  30. package/dist/{types-BJY9r-mz.d.ts → types-CMmx0S4U.d.ts} +1 -1
  31. package/dist/{types-DX3HtFcn.d.cts → types-DEUb5IZA.d.cts} +1 -1
  32. package/dist/wallet.cjs +51 -40
  33. package/dist/wallet.cjs.map +1 -1
  34. package/dist/wallet.d.cts +4 -4
  35. package/dist/wallet.d.ts +4 -4
  36. package/dist/wallet.mjs +51 -40
  37. package/dist/wallet.mjs.map +1 -1
  38. package/dist/widget.cjs +160 -75
  39. package/dist/widget.cjs.map +1 -1
  40. package/dist/widget.d.cts +2 -2
  41. package/dist/widget.d.ts +2 -2
  42. package/dist/widget.mjs +160 -75
  43. package/dist/widget.mjs.map +1 -1
  44. package/package.json +74 -5
@@ -1,4 +1,4 @@
1
- import { c as ChainType, C as ChainDef } from './blockchain-BxAFzp0s.cjs';
1
+ import { d as ChainType, C as ChainDef } from './blockchain-DmCPxnxr.cjs';
2
2
 
3
3
  declare enum TrustwareErrorCode {
4
4
  INVALID_CONFIG = "INVALID_CONFIG",
@@ -197,6 +197,13 @@ type BuildRouteBody = {
197
197
  postHook?: PostHookRequest;
198
198
  };
199
199
  };
200
+ /**
201
+ * Validates a `BuildRouteBody.hooks` value before it's sent, so a malformed
202
+ * postHook fails fast client-side instead of round-tripping to the backend.
203
+ * A no-op when `hooks`/`hooks.postHook` is omitted. Exported so callers can
204
+ * validate a postHook ahead of time (e.g. in their own form validation).
205
+ */
206
+ declare function assertValidPostHook(hooks: BuildRouteBody["hooks"]): void;
200
207
  type TxRequest = {
201
208
  to?: string;
202
209
  target?: string;
@@ -292,33 +299,73 @@ type RouteIntent = {
292
299
  fromAmountWei: string | number;
293
300
  quoteToAmountWei: string | number;
294
301
  minToAmountWei: string | number;
302
+ /** Trustware's own request ID (a UUID) for the call that created this
303
+ * intent — the same value the response carried in `X-Request-Id`, so it is
304
+ * the ID to quote in a Trustware support request. Wire field:
305
+ * `request_id`. Absent on intents created before it was split from
306
+ * `providerRequestId`. */
295
307
  requestId?: string;
308
+ /** The routing provider's own correlation ID: Squid `requestId`, LiFi/Relay
309
+ * route id, or Khalani's `{quoteId,routeId}` composite — the ID *that
310
+ * provider's* status API and support recognise. Wire field:
311
+ * `provider_request_id`. Absent when the winning provider returned none. */
312
+ providerRequestId?: string;
296
313
  routeRaw?: unknown;
297
314
  status: "created" | "submitted" | "bridging" | "success" | "failed";
298
315
  createdDate: Date | string;
299
316
  updatedDate: Date | string;
300
317
  };
318
+ /**
319
+ * A status payload from `getStatus`/`pollStatus`.
320
+ *
321
+ * Every field except `status` is optional, because a `"pending"` payload is a
322
+ * stub — the intent exists but no receipt has landed, so there is no
323
+ * transaction row to describe yet. Check `status` before reading anything
324
+ * else.
325
+ *
326
+ * The wire is snake_case (`source_tx_hash`, `intent_id`, ...) while this type
327
+ * is camelCase. `getStatus` maps one onto the other (see
328
+ * `normalizeStatusPayload` in core/routes.ts), so anything reaching you through
329
+ * `getStatus`/`pollStatus`/`runTopUp` has the camelCase names populated.
330
+ *
331
+ * The raw snake_case keys are still present **at runtime** — dropping them
332
+ * would break callers that already read them — but they are deliberately not
333
+ * declared here, because camelCase is the supported spelling and the raw ones
334
+ * are only kept for back-compat. Reading `tx.source_tx_hash` therefore needs a
335
+ * cast, and new code should not: use `tx.sourceTxHash`.
336
+ *
337
+ * `origin_eoa` and `landed_amount_verified` are the exception — the wire has no
338
+ * camelCase spelling for those two, so they are declared as-is below.
339
+ */
301
340
  type Transaction = {
302
- id: string;
303
- intentId: string;
304
- fromAddress: string;
305
- toAddress: string;
341
+ id?: string;
342
+ intentId?: string;
343
+ fromAddress?: string;
344
+ toAddress?: string;
306
345
  /** Connected wallet (EOA) that originated the payment when the sender is a
307
346
  * smart account. Wire field: `origin_eoa`. */
308
347
  origin_eoa?: string;
309
- fromChainId: string | number;
310
- toChainId: string | number;
311
- sourceTxHash: string;
312
- destTxHash: string;
313
- requestId: string;
314
- transactionRequest: unknown;
348
+ fromChainId?: string | number;
349
+ toChainId?: string | number;
350
+ sourceTxHash?: string;
351
+ destTxHash?: string;
352
+ /** Trustware's own request ID (a UUID), copied from the intent. Wire field:
353
+ * `request_id`. Optional: absent on a "pending" payload, and on rows
354
+ * created before it was split from `providerRequestId`. */
355
+ requestId?: string;
356
+ /** The routing provider's own correlation ID, copied from the intent — what
357
+ * that provider's status API polls with. Wire field:
358
+ * `provider_request_id`. See RouteIntent.providerRequestId. */
359
+ providerRequestId?: string;
360
+ transactionRequest?: unknown;
315
361
  /**
316
362
  * "pending" means the intent exists but no receipt has been submitted yet —
317
363
  * the backend returns it (HTTP 200) instead of the old 404 so pollers can
318
364
  * tell "not ready yet, keep polling" apart from "unknown intent" (a real
319
365
  * 404, which means stop polling). A pending response carries only
320
- * `intent_id`, `status`, `intent_status`, and `create_date`; the other
321
- * Transaction fields are absent until a receipt lands.
366
+ * `intent_id`, `status`, `intent_status`, `create_date` and — once the
367
+ * intent has an execution step plan — `steps`; every other field here is
368
+ * absent until a receipt lands.
322
369
  */
323
370
  status: "pending" | "submitted" | "bridging" | "success" | "failed";
324
371
  statusRaw?: unknown;
@@ -458,6 +505,11 @@ type RoutePlan = {
458
505
  };
459
506
  steps?: unknown[];
460
507
  provider?: string;
508
+ /** The winning provider's own correlation ID, not Trustware's — it is
509
+ * absent when that provider issued none, and it is what lands on the
510
+ * intent as `providerRequestId`. Trustware's request ID for the same call
511
+ * comes back in the `X-Request-Id` response header (the provider's is also
512
+ * mirrored there as `X-Provider-Request-Id`). */
461
513
  requestId?: string;
462
514
  reliabilityScore?: number;
463
515
  diagnostics?: {
@@ -676,13 +728,14 @@ type RateLimitInfo = {
676
728
  /** Seconds until rate limit resets (only present on 429 responses) */
677
729
  retryAfter?: number;
678
730
  };
731
+ /**
732
+ * Rate limit *observability*. Retry timing itself is not configurable: the
733
+ * limit is enforced server-side per API key, so the only retry schedule that
734
+ * can actually succeed is the one the server dictates through Retry-After.
735
+ * Tuning it client-side could only make requests fail sooner or hammer a
736
+ * limit that is already closed — see RETRY_POLICY.
737
+ */
679
738
  type RetryConfig = {
680
- /** Enable automatic retry on 429 responses (default: true). Note: This does NOT disable backend rate limits, only client-side retry behavior. */
681
- autoRetry?: boolean;
682
- /** Maximum number of retries on 429 (default: 3) */
683
- maxRetries?: number;
684
- /** Base delay in ms for exponential backoff (default: 1000) */
685
- baseDelayMs?: number;
686
739
  /** Callback when rate limit info is received from server */
687
740
  onRateLimitInfo?: (info: RateLimitInfo) => void;
688
741
  /** Callback when rate limit is hit (429 received) */
@@ -693,15 +746,29 @@ type RetryConfig = {
693
746
  approachingThreshold?: number;
694
747
  };
695
748
  type ResolvedRetryConfig = {
696
- autoRetry: boolean;
697
- maxRetries: number;
698
- baseDelayMs: number;
699
749
  approachingThreshold: number;
700
750
  onRateLimitInfo?: (info: RateLimitInfo) => void;
701
751
  onRateLimited?: (info: RateLimitInfo, retryCount: number) => void;
702
752
  onRateLimitApproaching?: (info: RateLimitInfo, threshold: number) => void;
703
753
  };
704
754
  declare const DEFAULT_RETRY_CONFIG: ResolvedRetryConfig;
755
+ /**
756
+ * The one retry number the SDK chooses for itself: the total time it will
757
+ * spend waiting out rate limits before handing the caller a RateLimitError.
758
+ *
759
+ * Everything else — how long to wait, and so whether to retry at all — is read
760
+ * off the response. The limit is per API key and settable per key server-side
761
+ * (rate_limit_per_min), and the backend reports the state of *that* key on
762
+ * every response: X-RateLimit-Limit / -Remaining / -Reset, plus Retry-After on
763
+ * a 429. A schedule hardcoded here could only disagree with it.
764
+ *
765
+ * This budget stays client-side because the server cannot know it: it is a
766
+ * property of the caller, not of the key. A payment widget cannot sit on a
767
+ * spinner for the minute a fresh window might be away, so past the budget the
768
+ * SDK stops and reports the wait (retriesExhausted: false, retryAfter set) for
769
+ * the app to render.
770
+ */
771
+ declare const RATE_LIMIT_WAIT_BUDGET_MS = 10000;
705
772
  declare const DEFAULT_FEATURE_FLAGS: ResolvedFeatureFlags;
706
773
 
707
774
  type WagmiConnector = {
@@ -841,4 +908,4 @@ declare function useWalletInfo(wagmi?: WagmiBridge): {
841
908
  };
842
909
  declare function useWalletExternalDisconnect(cb: () => void): void;
843
910
 
844
- export { type WalletConnectConfig as $, type ResolvedWalletConnectConfig as A, type BuildRouteBody as B, type RetryConfig as C, type DetectedWallet as D, type EIP1193 as E, type FeatureFlags as F, type RouteApproval as G, type RouteEstimate as H, IdentityStore as I, type RouteIntent as J, type RouteParams as K, type RoutePlan as L, type RouteSponsorship as M, type RoutesConfig as N, type SimpleWalletInterface as O, type PostHookRequest as P, type SponsorshipApproval as Q, type RateLimitInfo as R, type SolanaProviderLike as S, type TrustwareConfigOptions as T, type SwapTokenRef as U, type TrustwareTheme as V, type WalletMeta as W, type TrustwareWidgetMessages as X, type WalletAddressResolution as Y, type WalletAddressSource as Z, type WalletCategory as _, type WalletId as a, type WalletEcosystem as a0, type WalletIdentity as a1, type WalletIdentityAddress as a2, type WalletIdentityChainLike as a3, buildWalletIdentityAddress as a4, createWalletIdentity as a5, resolveWalletAddressForChain as a6, upsertWalletIdentityAddress as a7, buildRoute as a8, buildDepositAddress as a9, submitReceipt as aa, submitStepReceipt as ab, getStatus as ac, pollStatus as ad, type SolanaWalletInterface as b, type WagmiBridge as c, type WagmiConnector as d, type WalletSnapshot as e, useWalletExternalDisconnect as f, useWalletInfo as g, useWireDetectionIntoManager as h, type WalletInterFaceAPI as i, TrustwareError as j, type Transaction as k, type TrustwareEvent as l, type BuildRouteResponse as m, type BuildRouteResult as n, DEFAULT_AUTO_DETECT_PROVIDER as o, DEFAULT_FEATURE_FLAGS as p, DEFAULT_MESSAGES as q, DEFAULT_RETRY_CONFIG as r, DEFAULT_SLIPPAGE as s, type EIP6963ProviderDetail as t, useWalletConnectConnect as u, type EvmWalletInterface as v, walletManager as w, type ResolvedFeatureFlags as x, type ResolvedRetryConfig as y, type ResolvedTrustwareConfig as z };
911
+ export { type WalletCategory as $, type ResolvedTrustwareConfig as A, type BuildRouteBody as B, type ResolvedWalletConnectConfig as C, type DetectedWallet as D, type EIP1193 as E, type FeatureFlags as F, type RetryConfig as G, type RouteApproval as H, IdentityStore as I, type RouteEstimate as J, type RouteIntent as K, type RouteParams as L, type RoutePlan as M, type RouteSponsorship as N, type RoutesConfig as O, type PostHookRequest as P, type SimpleWalletInterface as Q, type RateLimitInfo as R, type SolanaProviderLike as S, type TrustwareConfigOptions as T, type SponsorshipApproval as U, type SwapTokenRef as V, type WalletMeta as W, type TrustwareTheme as X, type TrustwareWidgetMessages as Y, type WalletAddressResolution as Z, type WalletAddressSource as _, type WalletId as a, type WalletConnectConfig as a0, type WalletEcosystem as a1, type WalletIdentity as a2, type WalletIdentityAddress as a3, type WalletIdentityChainLike as a4, assertValidPostHook as a5, buildWalletIdentityAddress as a6, createWalletIdentity as a7, resolveWalletAddressForChain as a8, upsertWalletIdentityAddress as a9, buildRoute as aa, buildDepositAddress as ab, submitReceipt as ac, submitStepReceipt as ad, getStatus as ae, pollStatus as af, type SolanaWalletInterface as b, type WagmiBridge as c, type WagmiConnector as d, type WalletSnapshot as e, useWalletExternalDisconnect as f, useWalletInfo as g, useWireDetectionIntoManager as h, type WalletInterFaceAPI as i, TrustwareError as j, type Transaction as k, type TrustwareEvent as l, type BuildRouteResponse as m, type BuildRouteResult as n, DEFAULT_AUTO_DETECT_PROVIDER as o, DEFAULT_FEATURE_FLAGS as p, DEFAULT_MESSAGES as q, DEFAULT_RETRY_CONFIG as r, DEFAULT_SLIPPAGE as s, type EIP6963ProviderDetail as t, useWalletConnectConnect as u, type EvmWalletInterface as v, walletManager as w, RATE_LIMIT_WAIT_BUDGET_MS as x, type ResolvedFeatureFlags as y, type ResolvedRetryConfig as z };
@@ -1,4 +1,4 @@
1
- import { c as ChainType, C as ChainDef } from './blockchain-BxAFzp0s.js';
1
+ import { d as ChainType, C as ChainDef } from './blockchain-DmCPxnxr.js';
2
2
 
3
3
  declare enum TrustwareErrorCode {
4
4
  INVALID_CONFIG = "INVALID_CONFIG",
@@ -197,6 +197,13 @@ type BuildRouteBody = {
197
197
  postHook?: PostHookRequest;
198
198
  };
199
199
  };
200
+ /**
201
+ * Validates a `BuildRouteBody.hooks` value before it's sent, so a malformed
202
+ * postHook fails fast client-side instead of round-tripping to the backend.
203
+ * A no-op when `hooks`/`hooks.postHook` is omitted. Exported so callers can
204
+ * validate a postHook ahead of time (e.g. in their own form validation).
205
+ */
206
+ declare function assertValidPostHook(hooks: BuildRouteBody["hooks"]): void;
200
207
  type TxRequest = {
201
208
  to?: string;
202
209
  target?: string;
@@ -292,33 +299,73 @@ type RouteIntent = {
292
299
  fromAmountWei: string | number;
293
300
  quoteToAmountWei: string | number;
294
301
  minToAmountWei: string | number;
302
+ /** Trustware's own request ID (a UUID) for the call that created this
303
+ * intent — the same value the response carried in `X-Request-Id`, so it is
304
+ * the ID to quote in a Trustware support request. Wire field:
305
+ * `request_id`. Absent on intents created before it was split from
306
+ * `providerRequestId`. */
295
307
  requestId?: string;
308
+ /** The routing provider's own correlation ID: Squid `requestId`, LiFi/Relay
309
+ * route id, or Khalani's `{quoteId,routeId}` composite — the ID *that
310
+ * provider's* status API and support recognise. Wire field:
311
+ * `provider_request_id`. Absent when the winning provider returned none. */
312
+ providerRequestId?: string;
296
313
  routeRaw?: unknown;
297
314
  status: "created" | "submitted" | "bridging" | "success" | "failed";
298
315
  createdDate: Date | string;
299
316
  updatedDate: Date | string;
300
317
  };
318
+ /**
319
+ * A status payload from `getStatus`/`pollStatus`.
320
+ *
321
+ * Every field except `status` is optional, because a `"pending"` payload is a
322
+ * stub — the intent exists but no receipt has landed, so there is no
323
+ * transaction row to describe yet. Check `status` before reading anything
324
+ * else.
325
+ *
326
+ * The wire is snake_case (`source_tx_hash`, `intent_id`, ...) while this type
327
+ * is camelCase. `getStatus` maps one onto the other (see
328
+ * `normalizeStatusPayload` in core/routes.ts), so anything reaching you through
329
+ * `getStatus`/`pollStatus`/`runTopUp` has the camelCase names populated.
330
+ *
331
+ * The raw snake_case keys are still present **at runtime** — dropping them
332
+ * would break callers that already read them — but they are deliberately not
333
+ * declared here, because camelCase is the supported spelling and the raw ones
334
+ * are only kept for back-compat. Reading `tx.source_tx_hash` therefore needs a
335
+ * cast, and new code should not: use `tx.sourceTxHash`.
336
+ *
337
+ * `origin_eoa` and `landed_amount_verified` are the exception — the wire has no
338
+ * camelCase spelling for those two, so they are declared as-is below.
339
+ */
301
340
  type Transaction = {
302
- id: string;
303
- intentId: string;
304
- fromAddress: string;
305
- toAddress: string;
341
+ id?: string;
342
+ intentId?: string;
343
+ fromAddress?: string;
344
+ toAddress?: string;
306
345
  /** Connected wallet (EOA) that originated the payment when the sender is a
307
346
  * smart account. Wire field: `origin_eoa`. */
308
347
  origin_eoa?: string;
309
- fromChainId: string | number;
310
- toChainId: string | number;
311
- sourceTxHash: string;
312
- destTxHash: string;
313
- requestId: string;
314
- transactionRequest: unknown;
348
+ fromChainId?: string | number;
349
+ toChainId?: string | number;
350
+ sourceTxHash?: string;
351
+ destTxHash?: string;
352
+ /** Trustware's own request ID (a UUID), copied from the intent. Wire field:
353
+ * `request_id`. Optional: absent on a "pending" payload, and on rows
354
+ * created before it was split from `providerRequestId`. */
355
+ requestId?: string;
356
+ /** The routing provider's own correlation ID, copied from the intent — what
357
+ * that provider's status API polls with. Wire field:
358
+ * `provider_request_id`. See RouteIntent.providerRequestId. */
359
+ providerRequestId?: string;
360
+ transactionRequest?: unknown;
315
361
  /**
316
362
  * "pending" means the intent exists but no receipt has been submitted yet —
317
363
  * the backend returns it (HTTP 200) instead of the old 404 so pollers can
318
364
  * tell "not ready yet, keep polling" apart from "unknown intent" (a real
319
365
  * 404, which means stop polling). A pending response carries only
320
- * `intent_id`, `status`, `intent_status`, and `create_date`; the other
321
- * Transaction fields are absent until a receipt lands.
366
+ * `intent_id`, `status`, `intent_status`, `create_date` and — once the
367
+ * intent has an execution step plan — `steps`; every other field here is
368
+ * absent until a receipt lands.
322
369
  */
323
370
  status: "pending" | "submitted" | "bridging" | "success" | "failed";
324
371
  statusRaw?: unknown;
@@ -458,6 +505,11 @@ type RoutePlan = {
458
505
  };
459
506
  steps?: unknown[];
460
507
  provider?: string;
508
+ /** The winning provider's own correlation ID, not Trustware's — it is
509
+ * absent when that provider issued none, and it is what lands on the
510
+ * intent as `providerRequestId`. Trustware's request ID for the same call
511
+ * comes back in the `X-Request-Id` response header (the provider's is also
512
+ * mirrored there as `X-Provider-Request-Id`). */
461
513
  requestId?: string;
462
514
  reliabilityScore?: number;
463
515
  diagnostics?: {
@@ -676,13 +728,14 @@ type RateLimitInfo = {
676
728
  /** Seconds until rate limit resets (only present on 429 responses) */
677
729
  retryAfter?: number;
678
730
  };
731
+ /**
732
+ * Rate limit *observability*. Retry timing itself is not configurable: the
733
+ * limit is enforced server-side per API key, so the only retry schedule that
734
+ * can actually succeed is the one the server dictates through Retry-After.
735
+ * Tuning it client-side could only make requests fail sooner or hammer a
736
+ * limit that is already closed — see RETRY_POLICY.
737
+ */
679
738
  type RetryConfig = {
680
- /** Enable automatic retry on 429 responses (default: true). Note: This does NOT disable backend rate limits, only client-side retry behavior. */
681
- autoRetry?: boolean;
682
- /** Maximum number of retries on 429 (default: 3) */
683
- maxRetries?: number;
684
- /** Base delay in ms for exponential backoff (default: 1000) */
685
- baseDelayMs?: number;
686
739
  /** Callback when rate limit info is received from server */
687
740
  onRateLimitInfo?: (info: RateLimitInfo) => void;
688
741
  /** Callback when rate limit is hit (429 received) */
@@ -693,15 +746,29 @@ type RetryConfig = {
693
746
  approachingThreshold?: number;
694
747
  };
695
748
  type ResolvedRetryConfig = {
696
- autoRetry: boolean;
697
- maxRetries: number;
698
- baseDelayMs: number;
699
749
  approachingThreshold: number;
700
750
  onRateLimitInfo?: (info: RateLimitInfo) => void;
701
751
  onRateLimited?: (info: RateLimitInfo, retryCount: number) => void;
702
752
  onRateLimitApproaching?: (info: RateLimitInfo, threshold: number) => void;
703
753
  };
704
754
  declare const DEFAULT_RETRY_CONFIG: ResolvedRetryConfig;
755
+ /**
756
+ * The one retry number the SDK chooses for itself: the total time it will
757
+ * spend waiting out rate limits before handing the caller a RateLimitError.
758
+ *
759
+ * Everything else — how long to wait, and so whether to retry at all — is read
760
+ * off the response. The limit is per API key and settable per key server-side
761
+ * (rate_limit_per_min), and the backend reports the state of *that* key on
762
+ * every response: X-RateLimit-Limit / -Remaining / -Reset, plus Retry-After on
763
+ * a 429. A schedule hardcoded here could only disagree with it.
764
+ *
765
+ * This budget stays client-side because the server cannot know it: it is a
766
+ * property of the caller, not of the key. A payment widget cannot sit on a
767
+ * spinner for the minute a fresh window might be away, so past the budget the
768
+ * SDK stops and reports the wait (retriesExhausted: false, retryAfter set) for
769
+ * the app to render.
770
+ */
771
+ declare const RATE_LIMIT_WAIT_BUDGET_MS = 10000;
705
772
  declare const DEFAULT_FEATURE_FLAGS: ResolvedFeatureFlags;
706
773
 
707
774
  type WagmiConnector = {
@@ -841,4 +908,4 @@ declare function useWalletInfo(wagmi?: WagmiBridge): {
841
908
  };
842
909
  declare function useWalletExternalDisconnect(cb: () => void): void;
843
910
 
844
- export { type WalletConnectConfig as $, type ResolvedWalletConnectConfig as A, type BuildRouteBody as B, type RetryConfig as C, type DetectedWallet as D, type EIP1193 as E, type FeatureFlags as F, type RouteApproval as G, type RouteEstimate as H, IdentityStore as I, type RouteIntent as J, type RouteParams as K, type RoutePlan as L, type RouteSponsorship as M, type RoutesConfig as N, type SimpleWalletInterface as O, type PostHookRequest as P, type SponsorshipApproval as Q, type RateLimitInfo as R, type SolanaProviderLike as S, type TrustwareConfigOptions as T, type SwapTokenRef as U, type TrustwareTheme as V, type WalletMeta as W, type TrustwareWidgetMessages as X, type WalletAddressResolution as Y, type WalletAddressSource as Z, type WalletCategory as _, type WalletId as a, type WalletEcosystem as a0, type WalletIdentity as a1, type WalletIdentityAddress as a2, type WalletIdentityChainLike as a3, buildWalletIdentityAddress as a4, createWalletIdentity as a5, resolveWalletAddressForChain as a6, upsertWalletIdentityAddress as a7, buildRoute as a8, buildDepositAddress as a9, submitReceipt as aa, submitStepReceipt as ab, getStatus as ac, pollStatus as ad, type SolanaWalletInterface as b, type WagmiBridge as c, type WagmiConnector as d, type WalletSnapshot as e, useWalletExternalDisconnect as f, useWalletInfo as g, useWireDetectionIntoManager as h, type WalletInterFaceAPI as i, TrustwareError as j, type Transaction as k, type TrustwareEvent as l, type BuildRouteResponse as m, type BuildRouteResult as n, DEFAULT_AUTO_DETECT_PROVIDER as o, DEFAULT_FEATURE_FLAGS as p, DEFAULT_MESSAGES as q, DEFAULT_RETRY_CONFIG as r, DEFAULT_SLIPPAGE as s, type EIP6963ProviderDetail as t, useWalletConnectConnect as u, type EvmWalletInterface as v, walletManager as w, type ResolvedFeatureFlags as x, type ResolvedRetryConfig as y, type ResolvedTrustwareConfig as z };
911
+ export { type WalletCategory as $, type ResolvedTrustwareConfig as A, type BuildRouteBody as B, type ResolvedWalletConnectConfig as C, type DetectedWallet as D, type EIP1193 as E, type FeatureFlags as F, type RetryConfig as G, type RouteApproval as H, IdentityStore as I, type RouteEstimate as J, type RouteIntent as K, type RouteParams as L, type RoutePlan as M, type RouteSponsorship as N, type RoutesConfig as O, type PostHookRequest as P, type SimpleWalletInterface as Q, type RateLimitInfo as R, type SolanaProviderLike as S, type TrustwareConfigOptions as T, type SponsorshipApproval as U, type SwapTokenRef as V, type WalletMeta as W, type TrustwareTheme as X, type TrustwareWidgetMessages as Y, type WalletAddressResolution as Z, type WalletAddressSource as _, type WalletId as a, type WalletConnectConfig as a0, type WalletEcosystem as a1, type WalletIdentity as a2, type WalletIdentityAddress as a3, type WalletIdentityChainLike as a4, assertValidPostHook as a5, buildWalletIdentityAddress as a6, createWalletIdentity as a7, resolveWalletAddressForChain as a8, upsertWalletIdentityAddress as a9, buildRoute as aa, buildDepositAddress as ab, submitReceipt as ac, submitStepReceipt as ad, getStatus as ae, pollStatus as af, type SolanaWalletInterface as b, type WagmiBridge as c, type WagmiConnector as d, type WalletSnapshot as e, useWalletExternalDisconnect as f, useWalletInfo as g, useWireDetectionIntoManager as h, type WalletInterFaceAPI as i, TrustwareError as j, type Transaction as k, type TrustwareEvent as l, type BuildRouteResponse as m, type BuildRouteResult as n, DEFAULT_AUTO_DETECT_PROVIDER as o, DEFAULT_FEATURE_FLAGS as p, DEFAULT_MESSAGES as q, DEFAULT_RETRY_CONFIG as r, DEFAULT_SLIPPAGE as s, type EIP6963ProviderDetail as t, useWalletConnectConnect as u, type EvmWalletInterface as v, walletManager as w, RATE_LIMIT_WAIT_BUDGET_MS as x, type ResolvedFeatureFlags as y, type ResolvedRetryConfig as z };
@@ -1,4 +1,4 @@
1
- import { D as DetectedWallet, c as WagmiBridge, i as WalletInterFaceAPI, E as EIP1193, a as WalletId, t as EIP6963ProviderDetail, W as WalletMeta } from './manager-DT8enQbE.cjs';
1
+ import { D as DetectedWallet, c as WagmiBridge, i as WalletInterFaceAPI, E as EIP1193, a as WalletId, t as EIP6963ProviderDetail, W as WalletMeta } from './manager-BZ8gyHGT.cjs';
2
2
 
3
3
  /** Try wagmi bridge first (if provided), otherwise return EIP-1193 adapter. */
4
4
  declare function connectDetectedWallet(dw: DetectedWallet, opts?: {
@@ -1,4 +1,4 @@
1
- import { D as DetectedWallet, c as WagmiBridge, i as WalletInterFaceAPI, E as EIP1193, a as WalletId, t as EIP6963ProviderDetail, W as WalletMeta } from './manager-BY3NHAks.js';
1
+ import { D as DetectedWallet, c as WagmiBridge, i as WalletInterFaceAPI, E as EIP1193, a as WalletId, t as EIP6963ProviderDetail, W as WalletMeta } from './manager-D8nQsod2.js';
2
2
 
3
3
  /** Try wagmi bridge first (if provided), otherwise return EIP-1193 adapter. */
4
4
  declare function connectDetectedWallet(dw: DetectedWallet, opts?: {
@@ -2009,7 +2009,7 @@ var VERSION;
2009
2009
  var init_version = __esm({
2010
2010
  "node_modules/@aa-sdk/core/dist/esm/version.js"() {
2011
2011
  "use strict";
2012
- VERSION = "4.88.4";
2012
+ VERSION = "4.88.5";
2013
2013
  }
2014
2014
  });
2015
2015
 
@@ -10528,7 +10528,7 @@ var VERSION2;
10528
10528
  var init_version2 = __esm({
10529
10529
  "node_modules/@account-kit/infra/dist/esm/version.js"() {
10530
10530
  "use strict";
10531
- VERSION2 = "4.88.4";
10531
+ VERSION2 = "4.88.5";
10532
10532
  }
10533
10533
  });
10534
10534
 
@@ -12265,7 +12265,7 @@ var init_constants = __esm({
12265
12265
  "src/constants.ts"() {
12266
12266
  "use strict";
12267
12267
  SDK_NAME = "@trustware/sdk";
12268
- SDK_VERSION = "1.1.11-staging.1";
12268
+ SDK_VERSION = "1.1.12-staging.1";
12269
12269
  API_ROOT = "https://bv-staging-api.trustware.io";
12270
12270
  API_PREFIX = "/api";
12271
12271
  }
@@ -12286,19 +12286,27 @@ var init_defaults3 = __esm({
12286
12286
  });
12287
12287
 
12288
12288
  // src/types/config.ts
12289
- var DEFAULT_RETRY_CONFIG, DEFAULT_FEATURE_FLAGS;
12289
+ var DEFAULT_RETRY_CONFIG, RATE_LIMIT_WAIT_BUDGET_MS, DEFAULT_FEATURE_FLAGS;
12290
12290
  var init_config = __esm({
12291
12291
  "src/types/config.ts"() {
12292
12292
  "use strict";
12293
12293
  DEFAULT_RETRY_CONFIG = {
12294
- autoRetry: true,
12295
- maxRetries: 3,
12296
- baseDelayMs: 1e3,
12297
12294
  approachingThreshold: 5
12298
12295
  };
12296
+ RATE_LIMIT_WAIT_BUDGET_MS = 1e4;
12299
12297
  DEFAULT_FEATURE_FLAGS = {
12300
12298
  tokensPagination: true,
12301
- balanceStreaming: false,
12299
+ // On by default: an address scan covers every configured chain and takes
12300
+ // seconds end to end, so streaming turns one long wait into a wallet that
12301
+ // fills in as results land — first chunk in ~200ms against a ~2.3s buffered
12302
+ // response, measured on a live backend.
12303
+ //
12304
+ // Safe to default because the path degrades on its own: a backend with
12305
+ // BALANCE_STREAM_ENABLED off refuses the stream, and the SDK falls back to
12306
+ // the buffered endpoint (emitting balance_stream_fallback), as does any
12307
+ // runtime whose fetch has no readable body — React Native, most notably.
12308
+ // The cost of defaulting ahead of a backend is one refused request per scan.
12309
+ balanceStreaming: true,
12302
12310
  shouldAllowGA4: true,
12303
12311
  swapMode: false,
12304
12312
  swapDefaultDestToken: null,
@@ -13571,9 +13579,6 @@ function resolveConfig(input) {
13571
13579
  const theme = input.theme ?? "system";
13572
13580
  const messages = deepMerge(DEFAULT_MESSAGES, input.messages);
13573
13581
  const retry = {
13574
- autoRetry: input.retry?.autoRetry ?? DEFAULT_RETRY_CONFIG.autoRetry,
13575
- maxRetries: input.retry?.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries,
13576
- baseDelayMs: input.retry?.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs,
13577
13582
  approachingThreshold: input.retry?.approachingThreshold ?? DEFAULT_RETRY_CONFIG.approachingThreshold,
13578
13583
  onRateLimitInfo: input.retry?.onRateLimitInfo,
13579
13584
  onRateLimited: input.retry?.onRateLimited,
@@ -13684,60 +13689,66 @@ function notifyRateLimitCallbacks(info, isRateLimited, retryCount) {
13684
13689
  retry.onRateLimitApproaching(info, retry.approachingThreshold);
13685
13690
  }
13686
13691
  }
13687
- function calculateBackoffDelay(baseDelayMs, retryCount, retryAfter) {
13688
- if (retryAfter && retryAfter > 0) {
13689
- return retryAfter * 1e3;
13692
+ function serverDirectedWaitMs(info) {
13693
+ if (!info) return null;
13694
+ if (typeof info.retryAfter === "number" && info.retryAfter > 0) {
13695
+ return info.retryAfter * 1e3;
13690
13696
  }
13691
- return baseDelayMs * Math.pow(2, retryCount);
13697
+ if (typeof info.reset === "number" && info.reset > 0) {
13698
+ const untilReset = info.reset * 1e3 - Date.now();
13699
+ if (untilReset > 0) return untilReset;
13700
+ }
13701
+ return null;
13692
13702
  }
13693
13703
  function sleep(ms) {
13694
13704
  return new Promise((resolve) => setTimeout(resolve, ms));
13695
13705
  }
13696
- async function rateLimitedFetch(url, options = {}) {
13697
- const { skipRateLimit, ...fetchOptions } = options;
13698
- const cfg = TrustwareConfigStore.get();
13699
- if (!cfg.retry.autoRetry || skipRateLimit) {
13700
- return fetch(url, fetchOptions);
13701
- }
13702
- const { maxRetries, baseDelayMs } = cfg.retry;
13706
+ async function withRateLimitRetry(attempt) {
13707
+ let waitedMs = 0;
13703
13708
  let retryCount = 0;
13704
13709
  while (true) {
13705
- const response = await fetch(url, fetchOptions);
13710
+ const response = await attempt();
13706
13711
  const rateLimitInfo = parseRateLimitHeaders(response);
13707
- if (response.status === 429) {
13712
+ if (response.status !== 429) {
13708
13713
  if (rateLimitInfo) {
13709
- notifyRateLimitCallbacks(rateLimitInfo, true, retryCount);
13710
- }
13711
- if (retryCount >= maxRetries) {
13712
- throw new RateLimitError(
13713
- rateLimitInfo || { limit: 0, remaining: 0, reset: 0 },
13714
- true
13715
- );
13714
+ notifyRateLimitCallbacks(rateLimitInfo, false, 0);
13716
13715
  }
13717
- const delay = calculateBackoffDelay(
13718
- baseDelayMs,
13719
- retryCount,
13720
- rateLimitInfo?.retryAfter
13721
- );
13722
- await sleep(delay);
13723
- retryCount++;
13724
- continue;
13716
+ return response;
13725
13717
  }
13726
13718
  if (rateLimitInfo) {
13727
- notifyRateLimitCallbacks(rateLimitInfo, false, 0);
13719
+ notifyRateLimitCallbacks(rateLimitInfo, true, retryCount);
13720
+ }
13721
+ const waitMs = serverDirectedWaitMs(rateLimitInfo);
13722
+ const info = rateLimitInfo || { limit: 0, remaining: 0, reset: 0 };
13723
+ if (waitMs === null) {
13724
+ throw new RateLimitError(info, true);
13725
+ }
13726
+ if (waitedMs + waitMs > RATE_LIMIT_WAIT_BUDGET_MS) {
13727
+ throw new RateLimitError(info, false);
13728
13728
  }
13729
- return response;
13729
+ await sleep(waitMs);
13730
+ waitedMs += waitMs;
13731
+ retryCount++;
13730
13732
  }
13731
13733
  }
13734
+ async function rateLimitedFetch(url, options = {}) {
13735
+ const { skipRateLimit, ...fetchOptions } = options;
13736
+ if (skipRateLimit) {
13737
+ return fetch(url, fetchOptions);
13738
+ }
13739
+ return withRateLimitRetry(() => fetch(url, fetchOptions));
13740
+ }
13732
13741
  var RateLimitError;
13733
13742
  var init_http = __esm({
13734
13743
  "src/core/http.ts"() {
13735
13744
  "use strict";
13736
13745
  init_constants();
13737
13746
  init_config2();
13747
+ init_config();
13738
13748
  RateLimitError = class extends Error {
13739
13749
  constructor(info, retriesExhausted) {
13740
- const message = retriesExhausted ? `Rate limit exceeded after max retries. Try again in ${info.retryAfter ?? Math.ceil((info.reset * 1e3 - Date.now()) / 1e3)} seconds.` : `Rate limit exceeded. Try again in ${info.retryAfter} seconds.`;
13750
+ const seconds = info.retryAfter ?? (info.reset > 0 ? Math.max(0, Math.ceil((info.reset * 1e3 - Date.now()) / 1e3)) : null);
13751
+ const message = seconds === null ? "Rate limit exceeded. The server did not say when to retry." : `Rate limit exceeded. Try again in ${seconds} seconds.`;
13741
13752
  super(message);
13742
13753
  this.name = "RateLimitError";
13743
13754
  this.rateLimitInfo = info;
@@ -13748,7 +13759,7 @@ var init_http = __esm({
13748
13759
  });
13749
13760
 
13750
13761
  // src/smart-account/client.ts
13751
- async function fetchWithTimeout(url, init) {
13762
+ async function fetchOnceWithTimeout(url, init) {
13752
13763
  const controller = new AbortController();
13753
13764
  const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
13754
13765
  try {
@@ -13769,6 +13780,9 @@ async function fetchWithTimeout(url, init) {
13769
13780
  clearTimeout(timer);
13770
13781
  }
13771
13782
  }
13783
+ async function fetchWithTimeout(url, init) {
13784
+ return withRateLimitRetry(() => fetchOnceWithTimeout(url, init));
13785
+ }
13772
13786
  function extractRevertHex(err) {
13773
13787
  if (typeof err.data === "string" && err.data.startsWith("0x"))
13774
13788
  return err.data;
@@ -14261,7 +14275,7 @@ async function estimateRelayFeeInToken(valueWei, fromAmountWei, fromAmountUSD, c
14261
14275
  tokenUnitsPerDollar = Number(fromAmountWei) / fromUSD;
14262
14276
  } else if (fromToken && fromDecimals !== void 0) {
14263
14277
  try {
14264
- const resp = await fetch(
14278
+ const resp = await rateLimitedFetch(
14265
14279
  `${apiBase()}/v1/price/token?chainId=${cid}&address=${fromToken}`,
14266
14280
  { headers: jsonHeaders() }
14267
14281
  );
@@ -14277,9 +14291,10 @@ async function estimateRelayFeeInToken(valueWei, fromAmountWei, fromAmountUSD, c
14277
14291
  return 0n;
14278
14292
  }
14279
14293
  try {
14280
- const resp = await fetch(`${apiBase()}/v1/price/native?chainId=${cid}`, {
14281
- headers: jsonHeaders()
14282
- });
14294
+ const resp = await rateLimitedFetch(
14295
+ `${apiBase()}/v1/price/native?chainId=${cid}`,
14296
+ { headers: jsonHeaders() }
14297
+ );
14283
14298
  if (!resp.ok) throw new Error(`native price HTTP ${resp.status}`);
14284
14299
  const json = await resp.json();
14285
14300
  const ethPriceUSD = parseFloat(json.data?.priceUSD ?? "0");