@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
package/README.md CHANGED
@@ -37,8 +37,6 @@ The current widget flow is:
37
37
 
38
38
  `Home -> Select Token -> Confirm Deposit -> Processing -> Success/Error`
39
39
 
40
- The refactored widget keeps the same behavior, but the configuration surface is now documented around the actual `TrustwareConfigOptions` shape and the current widget step model.
41
-
42
40
  ## Installation
43
41
 
44
42
  Supports React `18.2+` and `19`.
@@ -115,7 +113,7 @@ type TrustwareConfigOptions = {
115
113
  };
116
114
  };
117
115
  autoDetectProvider?: boolean;
118
- theme?: TrustwareWidgetTheme;
116
+ theme?: "light" | "dark" | "system"; // TrustwareTheme
119
117
  messages?: Partial<TrustwareWidgetMessages>;
120
118
  retry?: RetryConfig;
121
119
  walletConnect?: WalletConnectConfig;
@@ -172,7 +170,8 @@ type TrustwareConfigOptions = {
172
170
  ### Other Config Groups
173
171
 
174
172
  - `autoDetectProvider`: enables Trustware-managed wallet discovery.
175
- - `theme`: widget color and radius customization.
173
+ - `theme`: widget color mode — `"light" | "dark" | "system"` (default
174
+ `"system"`). Switch it at runtime with `Trustware.setTheme("dark")`.
176
175
  - `messages`: top-level copy overrides.
177
176
  - `retry`: API retry and rate-limit behavior.
178
177
  - `walletConnect`: WalletConnect overrides.
@@ -232,6 +231,13 @@ export function DepositPanel() {
232
231
  }
233
232
  ```
234
233
 
234
+ `useWagmi` (like `useEIP1193`) is a plain adapter factory, not a React hook,
235
+ despite the `use` prefix. If your ESLint setup runs `react-hooks/rules-of-hooks`
236
+ it will flag the call inside the `useMemo` callback above; silence it with an
237
+ `eslint-disable-next-line react-hooks/rules-of-hooks` comment — the call is
238
+ safe. See [docs.trustware.io](https://docs.trustware.io/guides/embedded-wallets#adapt-the-embedded-wallet)
239
+ for the same pattern with embedded wallets.
240
+
235
241
  Use this mode when:
236
242
 
237
243
  - your app already owns wallet state
@@ -285,19 +291,28 @@ Use this when you want Trustware’s routing and wallet plumbing without the wid
285
291
  ```ts
286
292
  import { Trustware } from "@trustware/sdk";
287
293
 
294
+ // buildRoute states both sides explicitly. fromAmount is in the source token's
295
+ // smallest unit, and the estimate comes back on the route — there is no
296
+ // separate quote call.
288
297
  const route = await Trustware.buildRoute({
289
- amount: "0.1",
298
+ fromChain: "1",
299
+ fromToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
300
+ toChain: "8453",
301
+ toToken: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // native on Base
302
+ fromAmount: "25000000", // 25 USDC (6 decimals)
290
303
  fromAddress: await Trustware.getAddress(),
304
+ toAddress: "0xDestination...",
291
305
  });
306
+ console.log(route.route?.estimate, route.finalExchangeRate);
292
307
 
293
- const quote = await Trustware.getQuote(route);
294
-
295
- const result = await Trustware.runTopUp({
296
- amount: "0.1",
297
- fromAddress: await Trustware.getAddress(),
298
- });
308
+ // Or let the SDK own route + submit + receipt + polling. Missing route fields
309
+ // come from the provider config; the sender comes from the attached wallet.
310
+ const tx = await Trustware.runTopUp({ fromAmount: "25000000" });
311
+ console.log(tx.status, tx.destTxHash);
299
312
  ```
300
313
 
314
+ See [docs.trustware.io](https://docs.trustware.io) for the full headless flow.
315
+
301
316
  ## Common Config Examples
302
317
 
303
318
  ### Fixed Amount Deposit
@@ -347,26 +362,44 @@ Trustware.setDestinationAddress("0xDestination...");
347
362
 
348
363
  ## Rate Limiting
349
364
 
350
- Client retry behavior is configured through `retry`.
365
+ The API is rate limited per API key, and that limit is shared by everyone using
366
+ your key — not per end user. Your key's limit, its remaining requests and the
367
+ window boundary come back on every response (`X-RateLimit-Limit`, `-Remaining`,
368
+ `-Reset`, plus `Retry-After` on a 429).
369
+
370
+ The SDK retries 429s on the schedule those headers state — it keeps no schedule
371
+ of its own to disagree with them. It waits exactly as long as the server asks,
372
+ for as long as the total stays under 10 seconds. Past that it stops and throws,
373
+ because how long your app can afford to block is the one thing the server can't
374
+ know. If a response carries no timing at all, the SDK stops rather than
375
+ guessing: the limit is a fixed window, so an invented delay either lands inside
376
+ the same closed window or overshoots one it could have read exactly.
377
+
378
+ None of that is configurable — the limit is enforced server-side, so no client
379
+ setting can widen it. If you need more headroom, ask us to raise the limit on
380
+ your key. `retry` configures observability only:
351
381
 
352
382
  ```ts
353
383
  const config = {
354
384
  ...trustwareConfig,
355
385
  retry: {
356
- autoRetry: true,
357
- maxRetries: 3,
358
- baseDelayMs: 1000,
386
+ onRateLimitInfo: (info) => console.debug(info.remaining, "requests left"),
387
+ onRateLimited: (info, attempt) => console.warn("429", attempt, info),
388
+ onRateLimitApproaching: (info) => showSoftWarning(info),
359
389
  approachingThreshold: 5,
360
390
  },
361
391
  } satisfies TrustwareConfigOptions;
362
392
  ```
363
393
 
364
- If retries are exhausted, the SDK throws `RateLimitError`.
394
+ `RateLimitError` distinguishes the two ways the SDK gives up:
395
+
396
+ - `retriesExhausted: false` — the wait is known and simply longer than the SDK
397
+ will block for. `rateLimitInfo.retryAfter` holds it, so show the user when to
398
+ come back instead of leaving them on a spinner.
399
+ - `retriesExhausted: true` — the response carried no usable timing, so there was
400
+ nothing to retry against.
365
401
 
366
402
  ## Docs
367
403
 
368
- - [Integration Guide](docs/intergrationGuide.md)
369
- - [Core Guide](docs/coreGuide.md)
370
- - [Backend RPC Offload PDR](docs/backend-rpc-offload-pdr.md)
371
- - [Widget Architecture Boundaries](docs/widget-architecture-boundaries.md)
372
- - [Widget Refactor Baseline](docs/widget-refactor-baseline.md)
404
+ Full API reference, integration guides, and examples live at
405
+ [docs.trustware.io](https://docs.trustware.io).
@@ -47,10 +47,34 @@ type TokenPageResult = {
47
47
  data: TokenDef[];
48
48
  pageInfo: TokenPageInfo;
49
49
  };
50
+ /**
51
+ * Terminal state of an address balance scan.
52
+ *
53
+ * `partial` is the one field a caller cannot reconstruct from the chunks: the
54
+ * backend scans every configured chain and reports `partial: true` when any of
55
+ * them failed, so "no balance on chain X" and "we could not reach chain X" look
56
+ * identical in the rows themselves. Rendering an empty wallet off a partial
57
+ * scan is the failure this exists to prevent.
58
+ */
59
+ type BalanceStreamSummary = {
60
+ address: string;
61
+ partial: boolean;
62
+ /** Chains that reported a result — equal to `total` on a complete scan. */
63
+ completed: number;
64
+ total: number;
65
+ /** Server-side scan duration. Absent on the buffered path, which does not report it. */
66
+ elapsedMs?: number;
67
+ };
50
68
  type BalanceStreamOptions = {
51
69
  stream?: boolean;
52
70
  signal?: AbortSignal;
53
71
  strict?: boolean;
72
+ /**
73
+ * Called once per scan with its terminal state, on the streamed and buffered
74
+ * paths alike — including when a stream fails and falls back — so a consumer
75
+ * can trust `partial` without knowing which path served it.
76
+ */
77
+ onSummary?: (summary: BalanceStreamSummary) => void;
54
78
  };
55
79
  type GetBalancesOptions = {
56
80
  /** Bypass the in-memory balance cache and re-fetch fresh data from the network. */
@@ -111,4 +135,4 @@ type TokenWithBalance = TokenDef & {
111
135
  balance?: bigint;
112
136
  };
113
137
 
114
- export type { BalanceRow as B, ChainDef as C, GetBalancesOptions as G, NativeCurrency as N, TokenDef as T, WalletAddressBalanceWrapper as W, BalanceStreamOptions as a, ChainMeta as b, ChainType as c, TokenMeta as d, TokenPageInfo as e, TokenPageOptions as f, TokenPageResult as g, TokenType as h, TokenWithBalance as i };
138
+ export type { BalanceRow as B, ChainDef as C, GetBalancesOptions as G, NativeCurrency as N, TokenDef as T, WalletAddressBalanceWrapper as W, BalanceStreamOptions as a, BalanceStreamSummary as b, ChainMeta as c, ChainType as d, TokenMeta as e, TokenPageInfo as f, TokenPageOptions as g, TokenPageResult as h, TokenType as i, TokenWithBalance as j };
@@ -47,10 +47,34 @@ type TokenPageResult = {
47
47
  data: TokenDef[];
48
48
  pageInfo: TokenPageInfo;
49
49
  };
50
+ /**
51
+ * Terminal state of an address balance scan.
52
+ *
53
+ * `partial` is the one field a caller cannot reconstruct from the chunks: the
54
+ * backend scans every configured chain and reports `partial: true` when any of
55
+ * them failed, so "no balance on chain X" and "we could not reach chain X" look
56
+ * identical in the rows themselves. Rendering an empty wallet off a partial
57
+ * scan is the failure this exists to prevent.
58
+ */
59
+ type BalanceStreamSummary = {
60
+ address: string;
61
+ partial: boolean;
62
+ /** Chains that reported a result — equal to `total` on a complete scan. */
63
+ completed: number;
64
+ total: number;
65
+ /** Server-side scan duration. Absent on the buffered path, which does not report it. */
66
+ elapsedMs?: number;
67
+ };
50
68
  type BalanceStreamOptions = {
51
69
  stream?: boolean;
52
70
  signal?: AbortSignal;
53
71
  strict?: boolean;
72
+ /**
73
+ * Called once per scan with its terminal state, on the streamed and buffered
74
+ * paths alike — including when a stream fails and falls back — so a consumer
75
+ * can trust `partial` without knowing which path served it.
76
+ */
77
+ onSummary?: (summary: BalanceStreamSummary) => void;
54
78
  };
55
79
  type GetBalancesOptions = {
56
80
  /** Bypass the in-memory balance cache and re-fetch fresh data from the network. */
@@ -111,4 +135,4 @@ type TokenWithBalance = TokenDef & {
111
135
  balance?: bigint;
112
136
  };
113
137
 
114
- export type { BalanceRow as B, ChainDef as C, GetBalancesOptions as G, NativeCurrency as N, TokenDef as T, WalletAddressBalanceWrapper as W, BalanceStreamOptions as a, ChainMeta as b, ChainType as c, TokenMeta as d, TokenPageInfo as e, TokenPageOptions as f, TokenPageResult as g, TokenType as h, TokenWithBalance as i };
138
+ export type { BalanceRow as B, ChainDef as C, GetBalancesOptions as G, NativeCurrency as N, TokenDef as T, WalletAddressBalanceWrapper as W, BalanceStreamOptions as a, BalanceStreamSummary as b, ChainMeta as c, ChainType as d, TokenMeta as e, TokenPageInfo as f, TokenPageOptions as g, TokenPageResult as h, TokenType as i, TokenWithBalance as j };
@@ -30,7 +30,7 @@ __export(constants_exports, {
30
30
  });
31
31
  module.exports = __toCommonJS(constants_exports);
32
32
  var SDK_NAME = "@trustware/sdk";
33
- var SDK_VERSION = "1.1.11-staging.1";
33
+ var SDK_VERSION = "1.1.12-staging.1";
34
34
  var API_ROOT = "https://bv-staging-api.trustware.io";
35
35
  var GTM_ID = "GTM-TZDGNCXB";
36
36
  var API_PREFIX = "/api";
@@ -1,6 +1,6 @@
1
1
  // src/constants.ts
2
2
  var SDK_NAME = "@trustware/sdk";
3
- var SDK_VERSION = "1.1.11-staging.1";
3
+ var SDK_VERSION = "1.1.12-staging.1";
4
4
  var API_ROOT = "https://bv-staging-api.trustware.io";
5
5
  var GTM_ID = "GTM-TZDGNCXB";
6
6
  var API_PREFIX = "/api";
@@ -1,6 +1,6 @@
1
- import { n as BuildRouteResult, k as Transaction, T as TrustwareConfigOptions, i as WalletInterFaceAPI, z as ResolvedTrustwareConfig, V as TrustwareTheme, a1 as WalletIdentity, w as walletManager, Y as WalletAddressResolution, a8 as buildRoute, a9 as buildDepositAddress, aa as submitReceipt, ab as submitStepReceipt, ac as getStatus, ad as pollStatus } from './manager-BY3NHAks.js';
2
- import { C as ChainDef, c as ChainType, G as GetBalancesOptions, B as BalanceRow, a as BalanceStreamOptions, W as WalletAddressBalanceWrapper } from './blockchain-BxAFzp0s.js';
3
- import { T as Token } from './types-BJY9r-mz.js';
1
+ import { n as BuildRouteResult, k as Transaction, T as TrustwareConfigOptions, i as WalletInterFaceAPI, A as ResolvedTrustwareConfig, X as TrustwareTheme, a2 as WalletIdentity, w as walletManager, Z as WalletAddressResolution, aa as buildRoute, ab as buildDepositAddress, ac as submitReceipt, ad as submitStepReceipt, ae as getStatus, af as pollStatus } from './manager-D8nQsod2.js';
2
+ import { C as ChainDef, d as ChainType, G as GetBalancesOptions, B as BalanceRow, a as BalanceStreamOptions, W as WalletAddressBalanceWrapper } from './blockchain-DmCPxnxr.js';
3
+ import { T as Token } from './types-CMmx0S4U.js';
4
4
 
5
5
  type AddressValidationResult = {
6
6
  isValid: boolean;
@@ -1,6 +1,6 @@
1
- import { n as BuildRouteResult, k as Transaction, T as TrustwareConfigOptions, i as WalletInterFaceAPI, z as ResolvedTrustwareConfig, V as TrustwareTheme, a1 as WalletIdentity, w as walletManager, Y as WalletAddressResolution, a8 as buildRoute, a9 as buildDepositAddress, aa as submitReceipt, ab as submitStepReceipt, ac as getStatus, ad as pollStatus } from './manager-DT8enQbE.cjs';
2
- import { C as ChainDef, c as ChainType, G as GetBalancesOptions, B as BalanceRow, a as BalanceStreamOptions, W as WalletAddressBalanceWrapper } from './blockchain-BxAFzp0s.cjs';
3
- import { T as Token } from './types-DX3HtFcn.cjs';
1
+ import { n as BuildRouteResult, k as Transaction, T as TrustwareConfigOptions, i as WalletInterFaceAPI, A as ResolvedTrustwareConfig, X as TrustwareTheme, a2 as WalletIdentity, w as walletManager, Z as WalletAddressResolution, aa as buildRoute, ab as buildDepositAddress, ac as submitReceipt, ad as submitStepReceipt, ae as getStatus, af as pollStatus } from './manager-BZ8gyHGT.cjs';
2
+ import { C as ChainDef, d as ChainType, G as GetBalancesOptions, B as BalanceRow, a as BalanceStreamOptions, W as WalletAddressBalanceWrapper } from './blockchain-DmCPxnxr.cjs';
3
+ import { T as Token } from './types-DEUb5IZA.cjs';
4
4
 
5
5
  type AddressValidationResult = {
6
6
  isValid: boolean;
package/dist/core.cjs CHANGED
@@ -47,19 +47,27 @@ var init_defaults = __esm({
47
47
  });
48
48
 
49
49
  // src/types/config.ts
50
- var DEFAULT_RETRY_CONFIG, DEFAULT_FEATURE_FLAGS;
50
+ var DEFAULT_RETRY_CONFIG, RATE_LIMIT_WAIT_BUDGET_MS, DEFAULT_FEATURE_FLAGS;
51
51
  var init_config = __esm({
52
52
  "src/types/config.ts"() {
53
53
  "use strict";
54
54
  DEFAULT_RETRY_CONFIG = {
55
- autoRetry: true,
56
- maxRetries: 3,
57
- baseDelayMs: 1e3,
58
55
  approachingThreshold: 5
59
56
  };
57
+ RATE_LIMIT_WAIT_BUDGET_MS = 1e4;
60
58
  DEFAULT_FEATURE_FLAGS = {
61
59
  tokensPagination: true,
62
- balanceStreaming: false,
60
+ // On by default: an address scan covers every configured chain and takes
61
+ // seconds end to end, so streaming turns one long wait into a wallet that
62
+ // fills in as results land — first chunk in ~200ms against a ~2.3s buffered
63
+ // response, measured on a live backend.
64
+ //
65
+ // Safe to default because the path degrades on its own: a backend with
66
+ // BALANCE_STREAM_ENABLED off refuses the stream, and the SDK falls back to
67
+ // the buffered endpoint (emitting balance_stream_fallback), as does any
68
+ // runtime whose fetch has no readable body — React Native, most notably.
69
+ // The cost of defaulting ahead of a backend is one refused request per scan.
70
+ balanceStreaming: true,
63
71
  shouldAllowGA4: true,
64
72
  swapMode: false,
65
73
  swapDefaultDestToken: null,
@@ -75,7 +83,7 @@ var init_constants = __esm({
75
83
  "src/constants.ts"() {
76
84
  "use strict";
77
85
  SDK_NAME = "@trustware/sdk";
78
- SDK_VERSION = "1.1.11-staging.1";
86
+ SDK_VERSION = "1.1.12-staging.1";
79
87
  API_ROOT = "https://bv-staging-api.trustware.io";
80
88
  API_PREFIX = "/api";
81
89
  WALLETCONNECT_PROJECT_ID = "72ea74c400f5111d43aea638d7d83a24";
@@ -118,7 +126,7 @@ async function assertOK(r) {
118
126
  throw new Error(`HTTP ${r.status}: ${msg}`);
119
127
  }
120
128
  async function validateSdkAccess() {
121
- const r = await fetch(`${apiBase()}/sdk/validate`, {
129
+ const r = await fetch(`${apiBase()}/v1/sdk/validate`, {
122
130
  method: "GET",
123
131
  headers: jsonHeaders()
124
132
  });
@@ -157,50 +165,54 @@ function notifyRateLimitCallbacks(info, isRateLimited, retryCount) {
157
165
  retry.onRateLimitApproaching(info, retry.approachingThreshold);
158
166
  }
159
167
  }
160
- function calculateBackoffDelay(baseDelayMs, retryCount, retryAfter) {
161
- if (retryAfter && retryAfter > 0) {
162
- return retryAfter * 1e3;
168
+ function serverDirectedWaitMs(info) {
169
+ if (!info) return null;
170
+ if (typeof info.retryAfter === "number" && info.retryAfter > 0) {
171
+ return info.retryAfter * 1e3;
163
172
  }
164
- return baseDelayMs * Math.pow(2, retryCount);
173
+ if (typeof info.reset === "number" && info.reset > 0) {
174
+ const untilReset = info.reset * 1e3 - Date.now();
175
+ if (untilReset > 0) return untilReset;
176
+ }
177
+ return null;
165
178
  }
166
179
  function sleep(ms) {
167
180
  return new Promise((resolve) => setTimeout(resolve, ms));
168
181
  }
169
- async function rateLimitedFetch(url, options = {}) {
170
- const { skipRateLimit, ...fetchOptions } = options;
171
- const cfg = TrustwareConfigStore.get();
172
- if (!cfg.retry.autoRetry || skipRateLimit) {
173
- return fetch(url, fetchOptions);
174
- }
175
- const { maxRetries, baseDelayMs } = cfg.retry;
182
+ async function withRateLimitRetry(attempt) {
183
+ let waitedMs = 0;
176
184
  let retryCount = 0;
177
185
  while (true) {
178
- const response = await fetch(url, fetchOptions);
186
+ const response = await attempt();
179
187
  const rateLimitInfo = parseRateLimitHeaders(response);
180
- if (response.status === 429) {
188
+ if (response.status !== 429) {
181
189
  if (rateLimitInfo) {
182
- notifyRateLimitCallbacks(rateLimitInfo, true, retryCount);
183
- }
184
- if (retryCount >= maxRetries) {
185
- throw new RateLimitError(
186
- rateLimitInfo || { limit: 0, remaining: 0, reset: 0 },
187
- true
188
- );
190
+ notifyRateLimitCallbacks(rateLimitInfo, false, 0);
189
191
  }
190
- const delay = calculateBackoffDelay(
191
- baseDelayMs,
192
- retryCount,
193
- rateLimitInfo?.retryAfter
194
- );
195
- await sleep(delay);
196
- retryCount++;
197
- continue;
192
+ return response;
198
193
  }
199
194
  if (rateLimitInfo) {
200
- notifyRateLimitCallbacks(rateLimitInfo, false, 0);
195
+ notifyRateLimitCallbacks(rateLimitInfo, true, retryCount);
196
+ }
197
+ const waitMs = serverDirectedWaitMs(rateLimitInfo);
198
+ const info = rateLimitInfo || { limit: 0, remaining: 0, reset: 0 };
199
+ if (waitMs === null) {
200
+ throw new RateLimitError(info, true);
201
201
  }
202
- return response;
202
+ if (waitedMs + waitMs > RATE_LIMIT_WAIT_BUDGET_MS) {
203
+ throw new RateLimitError(info, false);
204
+ }
205
+ await sleep(waitMs);
206
+ waitedMs += waitMs;
207
+ retryCount++;
208
+ }
209
+ }
210
+ async function rateLimitedFetch(url, options = {}) {
211
+ const { skipRateLimit, ...fetchOptions } = options;
212
+ if (skipRateLimit) {
213
+ return fetch(url, fetchOptions);
203
214
  }
215
+ return withRateLimitRetry(() => fetch(url, fetchOptions));
204
216
  }
205
217
  var RateLimitError;
206
218
  var init_http = __esm({
@@ -208,9 +220,11 @@ var init_http = __esm({
208
220
  "use strict";
209
221
  init_constants();
210
222
  init_config2();
223
+ init_config();
211
224
  RateLimitError = class extends Error {
212
225
  constructor(info, retriesExhausted) {
213
- 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.`;
226
+ const seconds = info.retryAfter ?? (info.reset > 0 ? Math.max(0, Math.ceil((info.reset * 1e3 - Date.now()) / 1e3)) : null);
227
+ const message = seconds === null ? "Rate limit exceeded. The server did not say when to retry." : `Rate limit exceeded. Try again in ${seconds} seconds.`;
214
228
  super(message);
215
229
  this.name = "RateLimitError";
216
230
  this.rateLimitInfo = info;
@@ -1795,6 +1809,16 @@ function mergeBalanceWrappers(current, incoming) {
1795
1809
  }
1796
1810
  return Array.from(merged.values());
1797
1811
  }
1812
+ function toSummary(frame, address) {
1813
+ const total = toNumberOrUndefined(frame.total) ?? 0;
1814
+ return {
1815
+ address: toStringOrUndefined(frame.address) ?? address,
1816
+ partial: Boolean(frame.partial),
1817
+ completed: toNumberOrUndefined(frame.completed) ?? 0,
1818
+ total,
1819
+ elapsedMs: toNumberOrUndefined(frame.elapsed)
1820
+ };
1821
+ }
1798
1822
  async function parseStreamingBalances(response, address, options = {}) {
1799
1823
  if (!response.body) {
1800
1824
  throw new Error("balances stream: empty response body");
@@ -1815,7 +1839,12 @@ async function parseStreamingBalances(response, address, options = {}) {
1815
1839
  if (!trimmed) continue;
1816
1840
  try {
1817
1841
  const parsed = JSON.parse(trimmed);
1818
- if (!parsed.chain_id) continue;
1842
+ if (!parsed.chain_id) {
1843
+ if (parsed.type === "summary") {
1844
+ options.onSummary?.(toSummary(parsed, address));
1845
+ }
1846
+ continue;
1847
+ }
1819
1848
  const chunk = normalizeStreamChunk(parsed);
1820
1849
  emitBalanceStreamChunk(address, chunk.length);
1821
1850
  yield chunk;
@@ -1834,6 +1863,8 @@ async function parseStreamingBalances(response, address, options = {}) {
1834
1863
  const chunk = normalizeStreamChunk(parsed);
1835
1864
  emitBalanceStreamChunk(address, chunk.length);
1836
1865
  yield chunk;
1866
+ } else if (parsed.type === "summary") {
1867
+ options.onSummary?.(toSummary(parsed, address));
1837
1868
  }
1838
1869
  } catch (error) {
1839
1870
  if (options.strict) {
@@ -1867,7 +1898,7 @@ async function getBalances(chainRef, address, opts) {
1867
1898
  if (cached) return cached;
1868
1899
  }
1869
1900
  const url = `${apiBase()}/v1/data/wallets/${encodeURIComponent(chainKey)}/${trimmedAddress}/balances`;
1870
- const response = await fetch(url, {
1901
+ const response = await rateLimitedFetch(url, {
1871
1902
  method: "GET",
1872
1903
  credentials: "omit",
1873
1904
  headers: jsonHeaders()
@@ -1888,7 +1919,7 @@ async function getBalancesByAddress(address, opts) {
1888
1919
  }
1889
1920
  return merged;
1890
1921
  }
1891
- const url = `${apiBase()}/data/balances/${address}`;
1922
+ const url = `${apiBase()}/v1/data/balances/${address}`;
1892
1923
  const r = await rateLimitedFetch(url, {
1893
1924
  method: "GET",
1894
1925
  credentials: "omit",
@@ -1896,14 +1927,27 @@ async function getBalancesByAddress(address, opts) {
1896
1927
  });
1897
1928
  if (!r.ok) throw new Error(`balances: HTTP ${r.status}`);
1898
1929
  const j = await r.json();
1899
- return Array.isArray(j) ? j : j.results ?? [];
1930
+ const results = Array.isArray(j) ? j : j.results ?? [];
1931
+ if (opts?.onSummary) {
1932
+ const completed = results.length;
1933
+ opts.onSummary({
1934
+ address,
1935
+ partial: Array.isArray(j) ? false : Boolean(j.partial),
1936
+ completed,
1937
+ total: completed
1938
+ });
1939
+ }
1940
+ return results;
1941
+ }
1942
+ function bufferedOptions(opts) {
1943
+ return { ...opts, stream: false };
1900
1944
  }
1901
1945
  async function* getBalancesByAddressStream(address, opts = {}) {
1902
1946
  if (!TrustwareConfigStore.get().features.balanceStreaming) {
1903
- yield await getBalancesByAddress(address);
1947
+ yield await getBalancesByAddress(address, bufferedOptions(opts));
1904
1948
  return;
1905
1949
  }
1906
- const url = `${apiBase()}/data/balances/${address}?stream=1`;
1950
+ const url = `${apiBase()}/v1/data/balances/${address}?stream=1`;
1907
1951
  try {
1908
1952
  const response = await rateLimitedFetch(url, {
1909
1953
  method: "GET",
@@ -1919,7 +1963,14 @@ async function* getBalancesByAddressStream(address, opts = {}) {
1919
1963
  const contentType = response.headers.get("content-type") ?? "";
1920
1964
  if (contentType.includes("application/json")) {
1921
1965
  const payload = await response.json();
1922
- yield Array.isArray(payload) ? payload : payload.results ?? [];
1966
+ const results = Array.isArray(payload) ? payload : payload.results ?? [];
1967
+ opts.onSummary?.({
1968
+ address,
1969
+ partial: Array.isArray(payload) ? false : Boolean(payload.partial),
1970
+ completed: results.length,
1971
+ total: results.length
1972
+ });
1973
+ yield results;
1923
1974
  return;
1924
1975
  }
1925
1976
  const stream = await parseStreamingBalances(response, address, opts);
@@ -1928,7 +1979,7 @@ async function* getBalancesByAddressStream(address, opts = {}) {
1928
1979
  }
1929
1980
  } catch (error) {
1930
1981
  emitBalanceStreamFallback(address, error);
1931
- yield await getBalancesByAddress(address);
1982
+ yield await getBalancesByAddress(address, bufferedOptions(opts));
1932
1983
  }
1933
1984
  }
1934
1985
  async function ensureRegistry() {
@@ -4115,7 +4166,18 @@ async function getStatus(intentId) {
4115
4166
  );
4116
4167
  await assertOK(r);
4117
4168
  const j = await r.json();
4118
- return j.data;
4169
+ return normalizeStatusPayload(j.data);
4170
+ }
4171
+ function normalizeStatusPayload(raw) {
4172
+ if (!raw || typeof raw !== "object") return raw;
4173
+ const wire = raw;
4174
+ const out = { ...wire };
4175
+ for (const [snake, camel] of Object.entries(STATUS_WIRE_TO_CAMEL)) {
4176
+ if (out[camel] !== void 0) continue;
4177
+ if (!(snake in wire)) continue;
4178
+ out[camel] = wire[snake];
4179
+ }
4180
+ return out;
4119
4181
  }
4120
4182
  async function pollStatus(intentId, { intervalMs = 2e3, timeoutMs = 5 * 6e4 } = {}) {
4121
4183
  const t0 = Date.now();
@@ -4126,12 +4188,39 @@ async function pollStatus(intentId, { intervalMs = 2e3, timeoutMs = 5 * 6e4 } =
4126
4188
  await new Promise((r) => setTimeout(r, intervalMs));
4127
4189
  }
4128
4190
  }
4191
+ var STATUS_WIRE_TO_CAMEL;
4129
4192
  var init_routes = __esm({
4130
4193
  "src/core/routes.ts"() {
4131
4194
  "use strict";
4132
4195
  init_http();
4133
4196
  init_store();
4134
4197
  init_address();
4198
+ STATUS_WIRE_TO_CAMEL = {
4199
+ intent_id: "intentId",
4200
+ from_address: "fromAddress",
4201
+ to_address: "toAddress",
4202
+ from_chain_id: "fromChainId",
4203
+ to_chain_id: "toChainId",
4204
+ source_tx_hash: "sourceTxHash",
4205
+ dest_tx_hash: "destTxHash",
4206
+ request_id: "requestId",
4207
+ provider_request_id: "providerRequestId",
4208
+ transaction_request: "transactionRequest",
4209
+ status_raw: "statusRaw",
4210
+ route_path: "routePath",
4211
+ route_status: "routeStatus",
4212
+ to_amount_wei: "toAmountWei",
4213
+ from_chain_block: "fromChainBlock",
4214
+ to_chain_block: "toChainBlock",
4215
+ from_chain_tx_url: "fromChainTxUrl",
4216
+ to_chain_tx_url: "toChainTxUrl",
4217
+ gas_status: "gasStatus",
4218
+ is_gmp_transaction: "isGMPTransaction",
4219
+ axelar_transaction_url: "axelarTransactionUrl",
4220
+ create_date: "createdDate",
4221
+ update_date: "updatedDate",
4222
+ time_spent_ms: "timeSpentMs"
4223
+ };
4135
4224
  }
4136
4225
  });
4137
4226
 
@@ -6604,9 +6693,6 @@ function resolveConfig(input) {
6604
6693
  const theme = input.theme ?? "system";
6605
6694
  const messages = deepMerge(DEFAULT_MESSAGES, input.messages);
6606
6695
  const retry = {
6607
- autoRetry: input.retry?.autoRetry ?? DEFAULT_RETRY_CONFIG.autoRetry,
6608
- maxRetries: input.retry?.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries,
6609
- baseDelayMs: input.retry?.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs,
6610
6696
  approachingThreshold: input.retry?.approachingThreshold ?? DEFAULT_RETRY_CONFIG.approachingThreshold,
6611
6697
  onRateLimitInfo: input.retry?.onRateLimitInfo,
6612
6698
  onRateLimited: input.retry?.onRateLimited,
@@ -6739,6 +6825,7 @@ var init_core = __esm({
6739
6825
  init_store();
6740
6826
  init_wallets();
6741
6827
  init_routes();
6828
+ init_routes();
6742
6829
  init_balances();
6743
6830
  init_tx();
6744
6831
  init_http();
@@ -6893,7 +6980,8 @@ var init_core = __esm({
6893
6980
  // src/core.ts
6894
6981
  var core_exports = {};
6895
6982
  __export(core_exports, {
6896
- Trustware: () => Trustware
6983
+ Trustware: () => Trustware,
6984
+ assertValidPostHook: () => assertValidPostHook
6897
6985
  });
6898
6986
  module.exports = __toCommonJS(core_exports);
6899
6987
  var init_core2 = __esm({
@@ -6904,6 +6992,7 @@ var init_core2 = __esm({
6904
6992
  init_core2();
6905
6993
  // Annotate the CommonJS export names for ESM import in node:
6906
6994
  0 && (module.exports = {
6907
- Trustware
6995
+ Trustware,
6996
+ assertValidPostHook
6908
6997
  });
6909
6998
  //# sourceMappingURL=core.cjs.map