tapimo 0.4.0 → 0.4.3

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 (255) hide show
  1. package/README.md +1 -1
  2. package/dist/ApiKey.d.ts +1 -9
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +2 -3
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +53 -27
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +32 -17
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +2451 -1533
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +23 -9
  13. package/dist/App.js.map +1 -1
  14. package/dist/Assets.d.ts +10 -0
  15. package/dist/Assets.d.ts.map +1 -1
  16. package/dist/Assets.js +4 -0
  17. package/dist/Assets.js.map +1 -1
  18. package/dist/Auth.d.ts +2 -1
  19. package/dist/Auth.d.ts.map +1 -1
  20. package/dist/Auth.js +2 -1
  21. package/dist/Auth.js.map +1 -1
  22. package/dist/Scope.d.ts +40 -15
  23. package/dist/Scope.d.ts.map +1 -1
  24. package/dist/Scope.js +44 -13
  25. package/dist/Scope.js.map +1 -1
  26. package/dist/admin/App.d.ts +560 -9
  27. package/dist/admin/App.d.ts.map +1 -1
  28. package/dist/admin/App.js +38 -6
  29. package/dist/admin/App.js.map +1 -1
  30. package/dist/admin/apps/api-keys.d.ts +10 -24
  31. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  32. package/dist/admin/apps/api-keys.js +10 -3
  33. package/dist/admin/apps/api-keys.js.map +1 -1
  34. package/dist/admin/apps/organizations.d.ts +833 -0
  35. package/dist/admin/apps/organizations.d.ts.map +1 -0
  36. package/dist/admin/apps/organizations.js +733 -0
  37. package/dist/admin/apps/organizations.js.map +1 -0
  38. package/dist/admin/apps/scopes.d.ts +8 -0
  39. package/dist/admin/apps/scopes.d.ts.map +1 -1
  40. package/dist/admin/ui.generated.d.ts +1 -1
  41. package/dist/admin/ui.generated.d.ts.map +1 -1
  42. package/dist/admin/ui.generated.js +53 -13
  43. package/dist/admin/ui.generated.js.map +1 -1
  44. package/dist/analytics/Analytics.d.ts +10 -0
  45. package/dist/analytics/Analytics.d.ts.map +1 -1
  46. package/dist/analytics/Analytics.js +8 -0
  47. package/dist/analytics/Analytics.js.map +1 -1
  48. package/dist/analytics/tables/requestEvents.d.ts +9 -0
  49. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  50. package/dist/analytics/tables/requestEvents.js +14 -0
  51. package/dist/analytics/tables/requestEvents.js.map +1 -1
  52. package/dist/apps/data/App.d.ts +1354 -984
  53. package/dist/apps/data/App.d.ts.map +1 -1
  54. package/dist/apps/data/App.js +20 -3
  55. package/dist/apps/data/App.js.map +1 -1
  56. package/dist/apps/data/FundingRouteProviders.d.ts +94 -5
  57. package/dist/apps/data/FundingRouteProviders.d.ts.map +1 -1
  58. package/dist/apps/data/FundingRouteProviders.js +196 -5
  59. package/dist/apps/data/FundingRouteProviders.js.map +1 -1
  60. package/dist/apps/data/routes/activities.d.ts +38 -38
  61. package/dist/apps/data/routes/addresses.d.ts +24 -24
  62. package/dist/apps/data/routes/balances.d.ts +45 -45
  63. package/dist/apps/data/routes/blocks.d.ts +39 -39
  64. package/dist/apps/data/routes/coingecko.d.ts +176 -176
  65. package/dist/apps/data/routes/exchanges.d.ts +453 -453
  66. package/dist/apps/data/routes/fee-amm.d.ts +101 -101
  67. package/dist/apps/data/routes/funding.d.ts +730 -138
  68. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  69. package/dist/apps/data/routes/funding.js +234 -0
  70. package/dist/apps/data/routes/funding.js.map +1 -1
  71. package/dist/apps/data/routes/indexer.d.ts +5 -5
  72. package/dist/apps/data/routes/rpc.d.ts +31 -31
  73. package/dist/apps/data/routes/verified-tokens.d.ts +81 -81
  74. package/dist/apps/management/App.d.ts +1156 -615
  75. package/dist/apps/management/App.d.ts.map +1 -1
  76. package/dist/apps/management/App.js +2 -2
  77. package/dist/apps/management/Billing.d.ts +3 -0
  78. package/dist/apps/management/Billing.d.ts.map +1 -1
  79. package/dist/apps/management/Billing.js +7 -2
  80. package/dist/apps/management/Billing.js.map +1 -1
  81. package/dist/apps/management/routes/api-keys.d.ts +106 -90
  82. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  83. package/dist/apps/management/routes/api-keys.js +41 -30
  84. package/dist/apps/management/routes/api-keys.js.map +1 -1
  85. package/dist/apps/management/routes/billing.d.ts +278 -146
  86. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  87. package/dist/apps/management/routes/billing.js +14 -14
  88. package/dist/apps/management/routes/billing.js.map +1 -1
  89. package/dist/apps/management/routes/invitations.d.ts +93 -20
  90. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  91. package/dist/apps/management/routes/invitations.js +12 -15
  92. package/dist/apps/management/routes/invitations.js.map +1 -1
  93. package/dist/apps/management/routes/me.d.ts +13 -13
  94. package/dist/apps/management/routes/members.d.ts +89 -18
  95. package/dist/apps/management/routes/members.d.ts.map +1 -1
  96. package/dist/apps/management/routes/members.js +10 -10
  97. package/dist/apps/management/routes/members.js.map +1 -1
  98. package/dist/apps/management/routes/orgs.d.ts +130 -70
  99. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  100. package/dist/apps/management/routes/orgs.js +19 -19
  101. package/dist/apps/management/routes/orgs.js.map +1 -1
  102. package/dist/apps/management/routes/projects.d.ts +137 -48
  103. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  104. package/dist/apps/management/routes/projects.js +12 -13
  105. package/dist/apps/management/routes/projects.js.map +1 -1
  106. package/dist/apps/management/routes/scopes.d.ts +14 -28
  107. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  108. package/dist/apps/management/routes/scopes.js +6 -7
  109. package/dist/apps/management/routes/scopes.js.map +1 -1
  110. package/dist/apps/management/routes/usage.d.ts +63 -19
  111. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  112. package/dist/apps/management/routes/usage.js +9 -10
  113. package/dist/apps/management/routes/usage.js.map +1 -1
  114. package/dist/apps/mcp.d.ts.map +1 -1
  115. package/dist/apps/mcp.js +35 -3
  116. package/dist/apps/mcp.js.map +1 -1
  117. package/dist/apps/relay/App.d.ts +26 -4
  118. package/dist/apps/relay/App.d.ts.map +1 -1
  119. package/dist/apps/relay/App.js +17 -14
  120. package/dist/apps/relay/App.js.map +1 -1
  121. package/dist/db/Db.d.ts +5 -3
  122. package/dist/db/Db.d.ts.map +1 -1
  123. package/dist/db/Db.js +52 -0
  124. package/dist/db/Db.js.map +1 -1
  125. package/dist/db/Schema.d.ts +13 -0
  126. package/dist/db/Schema.d.ts.map +1 -1
  127. package/dist/db/Schema.js +16 -1
  128. package/dist/db/Schema.js.map +1 -1
  129. package/dist/db/tables/adminAuditLogs.d.ts +27 -0
  130. package/dist/db/tables/adminAuditLogs.d.ts.map +1 -0
  131. package/dist/db/tables/adminAuditLogs.js +19 -0
  132. package/dist/db/tables/adminAuditLogs.js.map +1 -0
  133. package/dist/db/tables/invitations.d.ts +1 -1
  134. package/dist/db/tables/invitations.d.ts.map +1 -1
  135. package/dist/db/tables/memberships.d.ts +32 -4
  136. package/dist/db/tables/memberships.d.ts.map +1 -1
  137. package/dist/db/tables/memberships.js +31 -0
  138. package/dist/db/tables/memberships.js.map +1 -1
  139. package/dist/db/tables/organizations.d.ts +43 -1
  140. package/dist/db/tables/organizations.d.ts.map +1 -1
  141. package/dist/db/tables/organizations.js +103 -0
  142. package/dist/db/tables/organizations.js.map +1 -1
  143. package/dist/db/tables/projects.d.ts +25 -0
  144. package/dist/db/tables/projects.d.ts.map +1 -1
  145. package/dist/db/tables/projects.js +22 -0
  146. package/dist/db/tables/projects.js.map +1 -1
  147. package/dist/db/tables/webhookDeliveries.d.ts +26 -0
  148. package/dist/db/tables/webhookDeliveries.d.ts.map +1 -1
  149. package/dist/db/tables/webhookDeliveries.js +37 -0
  150. package/dist/db/tables/webhookDeliveries.js.map +1 -1
  151. package/dist/handlers/relay.d.ts +13 -10
  152. package/dist/handlers/relay.d.ts.map +1 -1
  153. package/dist/handlers/relay.js +46 -16
  154. package/dist/handlers/relay.js.map +1 -1
  155. package/dist/internal/Auth.d.ts +13 -18
  156. package/dist/internal/Auth.d.ts.map +1 -1
  157. package/dist/internal/Auth.js +78 -58
  158. package/dist/internal/Auth.js.map +1 -1
  159. package/dist/internal/Cursor.d.ts +1 -1
  160. package/dist/internal/Cursor.d.ts.map +1 -1
  161. package/dist/internal/Cursor.js +4 -0
  162. package/dist/internal/Cursor.js.map +1 -1
  163. package/dist/internal/EdgeCache.d.ts.map +1 -1
  164. package/dist/internal/EdgeCache.js +2 -0
  165. package/dist/internal/EdgeCache.js.map +1 -1
  166. package/dist/internal/FundingRoutes.d.ts +170 -0
  167. package/dist/internal/FundingRoutes.d.ts.map +1 -1
  168. package/dist/internal/FundingRoutes.js +68 -6
  169. package/dist/internal/FundingRoutes.js.map +1 -1
  170. package/dist/internal/Log.d.ts +16 -1
  171. package/dist/internal/Log.d.ts.map +1 -1
  172. package/dist/internal/Log.js +5 -3
  173. package/dist/internal/Log.js.map +1 -1
  174. package/package.json +2 -2
  175. package/src/ApiKey.ts +2 -3
  176. package/src/ApiKeys.ts +95 -17
  177. package/src/App.test.ts +44 -2
  178. package/src/App.ts +29 -9
  179. package/src/Assets.ts +8 -0
  180. package/src/Auth.test-d.ts +36 -0
  181. package/src/Auth.ts +20 -1
  182. package/src/Client.test-d.ts +64 -17
  183. package/src/Scope.test.ts +34 -0
  184. package/src/Scope.ts +53 -17
  185. package/src/admin/App.test.ts +33 -3
  186. package/src/admin/App.ts +49 -14
  187. package/src/admin/apps/api-keys.ts +10 -3
  188. package/src/admin/apps/organizations.test.ts +455 -0
  189. package/src/admin/apps/organizations.ts +953 -0
  190. package/src/admin/apps/scopes.test.ts +10 -0
  191. package/src/admin/ui/plugin.ts +1 -1
  192. package/src/admin/ui/src/components/MobileProfile.tsx +2 -0
  193. package/src/admin/ui/src/components/ThemeToggle.tsx +20 -0
  194. package/src/admin/ui/src/lib/api-keys.ts +36 -19
  195. package/src/admin/ui/src/lib/config.ts +2 -3
  196. package/src/admin/ui/src/lib/organizations.test.ts +89 -0
  197. package/src/admin/ui/src/lib/organizations.ts +262 -0
  198. package/src/admin/ui/src/lib/query-client.ts +3 -1
  199. package/src/admin/ui/src/lib/theme.ts +57 -0
  200. package/src/admin/ui/src/routeTree.gen.ts +47 -4
  201. package/src/admin/ui/src/routes/__root.tsx +18 -3
  202. package/src/admin/ui/src/routes/api-keys.tsx +52 -7
  203. package/src/admin/ui/src/routes/index.tsx +1 -1
  204. package/src/admin/ui/src/routes/organizations.tsx +158 -0
  205. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +710 -0
  206. package/src/admin/ui/src/start.ts +6 -0
  207. package/src/admin/ui.generated.ts +63 -13
  208. package/src/analytics/Analytics.ts +25 -0
  209. package/src/analytics/tables/requestEvents.ts +33 -0
  210. package/src/apps/composition.test.ts +82 -2
  211. package/src/apps/data/App.ts +24 -3
  212. package/src/apps/data/FundingRouteProviders.test.ts +204 -0
  213. package/src/apps/data/FundingRouteProviders.ts +294 -9
  214. package/src/apps/data/routes/funding.test.ts +90 -23
  215. package/src/apps/data/routes/funding.ts +315 -0
  216. package/src/apps/data/routes/rpc.test.ts +33 -0
  217. package/src/apps/management/App.ts +2 -2
  218. package/src/apps/management/Billing.ts +10 -2
  219. package/src/apps/management/routes/api-keys.test.ts +137 -1
  220. package/src/apps/management/routes/api-keys.ts +63 -38
  221. package/src/apps/management/routes/billing.ts +14 -14
  222. package/src/apps/management/routes/invitations.test.ts +102 -1
  223. package/src/apps/management/routes/invitations.ts +13 -15
  224. package/src/apps/management/routes/members.ts +10 -10
  225. package/src/apps/management/routes/orgs.test.ts +78 -16
  226. package/src/apps/management/routes/orgs.ts +21 -20
  227. package/src/apps/management/routes/projects.ts +12 -13
  228. package/src/apps/management/routes/scopes.test.ts +16 -0
  229. package/src/apps/management/routes/scopes.ts +6 -7
  230. package/src/apps/management/routes/usage.ts +9 -14
  231. package/src/apps/mcp.test.ts +25 -1
  232. package/src/apps/mcp.ts +43 -3
  233. package/src/apps/relay/App.test.ts +23 -18
  234. package/src/apps/relay/App.ts +35 -14
  235. package/src/db/Db.ts +59 -3
  236. package/src/db/Schema.ts +20 -1
  237. package/src/db/tables/adminAuditLogs.ts +47 -0
  238. package/src/db/tables/invitations.ts +1 -1
  239. package/src/db/tables/memberships.ts +59 -3
  240. package/src/db/tables/organizations.ts +148 -1
  241. package/src/db/tables/projects.ts +47 -0
  242. package/src/db/tables/webhookDeliveries.ts +83 -0
  243. package/src/handlers/relay.test-d.ts +8 -0
  244. package/src/handlers/relay.test.ts +2 -2
  245. package/src/handlers/relay.ts +62 -22
  246. package/src/internal/Auth.test.ts +174 -7
  247. package/src/internal/Auth.ts +90 -62
  248. package/src/internal/Cursor.test.ts +10 -0
  249. package/src/internal/Cursor.ts +5 -1
  250. package/src/internal/EdgeCache.test.ts +11 -0
  251. package/src/internal/EdgeCache.ts +2 -0
  252. package/src/internal/FundingRoutes.test.ts +26 -0
  253. package/src/internal/FundingRoutes.ts +187 -18
  254. package/src/internal/Log.test.ts +41 -3
  255. package/src/internal/Log.ts +23 -4
@@ -307,7 +307,9 @@ export type ChainRef = ReturnType<typeof formatChain> | typeof destinationChain
307
307
  export type TokenAmount = ReturnType<typeof resolveSourceAmount>
308
308
 
309
309
  /** Normalized token reference passed to provider adapters. */
310
- export type TokenRef = ReturnType<typeof formatDestinationToken> | ReturnType<typeof formatSourceToken>
310
+ export type TokenRef =
311
+ | ReturnType<typeof formatDestinationToken>
312
+ | ReturnType<typeof formatSourceToken>
311
313
 
312
314
  /** A normalized funding route candidate returned by route discovery. */
313
315
  export type RouteCandidate = ReturnType<typeof formatRouteCandidate>
@@ -411,6 +413,64 @@ export type QuoteProbeResult = {
411
413
  }
412
414
  }
413
415
 
416
+ /** Token reference attached to a normalized provider fee. */
417
+ export type ProviderQuoteFeeToken = {
418
+ /** Token contract address on its chain. */
419
+ address: string
420
+ /** CAIP-2 chain id for the fee token. */
421
+ chainId: string
422
+ /** Number of decimal places used by the fee token. */
423
+ decimals: number
424
+ /** Fee token ticker symbol. */
425
+ symbol: string
426
+ }
427
+
428
+ /** Normalized fee amount returned by a provider quote. */
429
+ export type ProviderQuoteFee = {
430
+ /** Fee amount in the fee token's base units. */
431
+ amount: string
432
+ /** Provider-estimated USD value of the fee. */
433
+ amountUsd: string | null
434
+ /** Fee as basis points of the quoted input, when available. */
435
+ bps: number | null
436
+ /** Token in which the fee amount is denominated. */
437
+ token: ProviderQuoteFeeToken
438
+ }
439
+
440
+ /** Input passed to a provider for one explicit, depositor-specific quote. */
441
+ export type ProviderQuoteInput = {
442
+ /** Address that would submit the funding transaction. */
443
+ depositor: string
444
+ /** Optional destination recipient; providers default it to the depositor. */
445
+ recipient?: string | undefined
446
+ /** Curated route selected by the caller. */
447
+ route: RouteCandidate
448
+ }
449
+
450
+ /** Dynamic data returned by an explicit provider quote. */
451
+ export type ProviderQuoteResult = {
452
+ /** Estimated settlement time in seconds. */
453
+ estimatedSeconds: number | null
454
+ /** Provider quote expiry timestamp. */
455
+ expiresAt: string
456
+ /** Current and maximum fee summaries. */
457
+ fees: {
458
+ /** Current estimated total fee. */
459
+ total: ProviderQuoteFee
460
+ /** Maximum total fee allowed by the quote. */
461
+ totalMax: ProviderQuoteFee
462
+ }
463
+ /** Slippage-adjusted minimum destination amount in base units. */
464
+ minimumOutputAmount: string
465
+ /** Expected destination amount in base units. */
466
+ outputAmount: string
467
+ /** Timestamp when Tempo sampled the quote. */
468
+ sampledAt: string
469
+ }
470
+
471
+ /** A normalized explicit funding quote returned to callers. */
472
+ export type FundingQuote = ReturnType<typeof formatFundingQuote>
473
+
414
474
  /** Adapter used to enrich a static route candidate with live provider information. */
415
475
  export type ProviderAdapter = {
416
476
  /** Probes provider-backed quote information for one static candidate. */
@@ -420,6 +480,12 @@ export type ProviderAdapter = {
420
480
  /** Provider adapter registry, keyed by provider id. Missing adapters leave routes static. */
421
481
  export type ProviderAdapters = Partial<Record<ProviderId, ProviderAdapter>>
422
482
 
483
+ /** Gets a depositor-specific quote without exposing provider execution payloads. */
484
+ export type ProviderQuote = (
485
+ input: ProviderQuoteInput,
486
+ signal: AbortSignal,
487
+ ) => Promise<ProviderQuoteResult>
488
+
423
489
  /** Static provider support rows used until live quote adapters are configured. */
424
490
  const inventory: readonly InventoryEntry[] = [
425
491
  { destinationToken: 'usdce', provider: 'across', sourceChains: ['ethereum', 'base', 'bnb'], sourceTokens: ['USDC'] }, // prettier-ignore
@@ -437,6 +503,7 @@ type InventoryEntry = {
437
503
  }
438
504
 
439
505
  const defaultAdapterTimeoutMs = 750
506
+ const defaultQuoteTimeoutMs = 5_000
440
507
  const includes = ['quotes'] as const
441
508
 
442
509
  /** Lists normalized chains and source tokens that can fund Tempo. */
@@ -455,7 +522,10 @@ export function listProviders(options: listProviders.Options = {}) {
455
522
  )
456
523
  .map((provider) => ({
457
524
  ...formatProvider(provider),
458
- status: options.adapters?.[provider.id] ? ('configured' as const) : provider.status,
525
+ status:
526
+ options.adapters?.[provider.id] || options.configuredProviders?.includes(provider.id)
527
+ ? ('configured' as const)
528
+ : provider.status,
459
529
  }))
460
530
  }
461
531
 
@@ -464,6 +534,8 @@ export declare namespace listProviders {
464
534
  type Options = {
465
535
  /** Provider adapters configured for this deployment. */
466
536
  adapters?: ProviderAdapters | undefined
537
+ /** Providers configured through capabilities outside discovery adapters. */
538
+ configuredProviders?: readonly ProviderId[] | undefined
467
539
  /** Provider capability to require. */
468
540
  capability?: Capability | undefined
469
541
  }
@@ -472,7 +544,10 @@ export declare namespace listProviders {
472
544
  /** Parses the comma-separated `include` query parameter. */
473
545
  export function parseInclude(input: string | undefined) {
474
546
  if (input === undefined || input.trim() === '') return []
475
- const parsed = input.split(',').map((part) => part.trim()).filter(Boolean)
547
+ const parsed = input
548
+ .split(',')
549
+ .map((part) => part.trim())
550
+ .filter(Boolean)
476
551
  for (const include of parsed)
477
552
  if (!(includes as readonly string[]).includes(include)) throw new UnsupportedIncludeError()
478
553
  return [...new Set(parsed)] as readonly Include[]
@@ -506,6 +581,55 @@ export async function listRoutes(options: listRoutes.Options) {
506
581
  )
507
582
  }
508
583
 
584
+ /** Gets a depositor-specific quote for one curated funding route. */
585
+ export async function quoteRoute(options: quoteRoute.Options): Promise<FundingQuote> {
586
+ const [route] = listStaticRoutes({
587
+ destinationToken: options.destinationToken,
588
+ limit: 1,
589
+ provider: options.provider,
590
+ sourceAmount: options.sourceAmount,
591
+ sourceAmountUnits: options.sourceAmountUnits,
592
+ sourceChain: options.sourceChain,
593
+ sourceToken: options.sourceToken,
594
+ })
595
+ if (!route) throw new FundingRouteNotFoundError()
596
+
597
+ const quote = options.quote
598
+ if (!quote) throw new ProviderNotConfiguredError()
599
+
600
+ return formatFundingQuote(
601
+ route,
602
+ await runWithTimeout(
603
+ (signal) =>
604
+ quote(
605
+ {
606
+ depositor: options.depositor,
607
+ ...(options.recipient === undefined ? {} : { recipient: options.recipient }),
608
+ route,
609
+ },
610
+ signal,
611
+ ),
612
+ options.quoteTimeoutMs ?? defaultQuoteTimeoutMs,
613
+ ),
614
+ )
615
+ }
616
+
617
+ export declare namespace quoteRoute {
618
+ /** Options for resolving and quoting one curated funding route. */
619
+ type Options = Omit<listStaticRoutes.Options, 'limit' | 'provider'> & {
620
+ /** Address that would submit the funding transaction. */
621
+ depositor: string
622
+ /** Configured provider quote capability. */
623
+ quote?: ProviderQuote | undefined
624
+ /** Provider selected for the quote. */
625
+ provider: 'across'
626
+ /** Maximum time allowed for the live provider request. */
627
+ quoteTimeoutMs?: number | undefined
628
+ /** Optional destination recipient; defaults to the depositor. */
629
+ recipient?: string | undefined
630
+ }
631
+ }
632
+
509
633
  /** Lists static funding route candidates for a normalized caller request. */
510
634
  export function listStaticRoutes(options: listStaticRoutes.Options) {
511
635
  const sourceChain = resolveSourceChain(options.sourceChain)
@@ -608,19 +732,22 @@ async function enrichRoute(
608
732
  if (!adapter) return route
609
733
 
610
734
  try {
611
- const quote = await quoteWithTimeout(
612
- adapter,
613
- {
614
- cache: options.cache,
615
- destinationChain: route.destinationChain,
616
- destinationToken: route.destinationToken,
617
- include: options.include,
618
- request: options.request,
619
- route,
620
- sourceAmount: route.sourceAmount,
621
- sourceChain: route.sourceChain,
622
- sourceToken: route.sourceToken,
623
- },
735
+ const quote = await runWithTimeout(
736
+ (signal) =>
737
+ adapter.probeQuote(
738
+ {
739
+ cache: options.cache,
740
+ destinationChain: route.destinationChain,
741
+ destinationToken: route.destinationToken,
742
+ include: options.include,
743
+ request: options.request,
744
+ route,
745
+ sourceAmount: route.sourceAmount,
746
+ sourceChain: route.sourceChain,
747
+ sourceToken: route.sourceToken,
748
+ },
749
+ signal,
750
+ ),
624
751
  options.timeoutMs,
625
752
  )
626
753
  return {
@@ -754,6 +881,28 @@ function formatRouteQuote(route: RouteCandidate, quote: QuoteProbeResult) {
754
881
  } as const
755
882
  }
756
883
 
884
+ function formatFundingQuote(route: RouteCandidate, quote: ProviderQuoteResult) {
885
+ return {
886
+ destinationChain: route.destinationChain,
887
+ destinationToken: route.destinationToken,
888
+ estimatedSeconds: quote.estimatedSeconds,
889
+ expiresAt: quote.expiresAt,
890
+ fees: quote.fees,
891
+ inputAmount: route.sourceAmount.amount,
892
+ minimumOutputAmount: quote.minimumOutputAmount,
893
+ outputAmount: quote.outputAmount,
894
+ outputAmountFormatted: decimalFromBaseUnits(
895
+ quote.outputAmount,
896
+ route.destinationToken.decimals,
897
+ ),
898
+ provider: route.provider,
899
+ routeId: route.id,
900
+ sampledAt: quote.sampledAt,
901
+ sourceChain: route.sourceChain,
902
+ sourceToken: route.sourceToken,
903
+ } as const
904
+ }
905
+
757
906
  function markRouteError(route: RouteCandidate, errorCode: string) {
758
907
  return {
759
908
  ...route,
@@ -770,11 +919,11 @@ function markRouteError(route: RouteCandidate, errorCode: string) {
770
919
  }
771
920
  }
772
921
 
773
- function quoteWithTimeout(adapter: ProviderAdapter, input: QuoteProbeInput, timeoutMs: number) {
922
+ function runWithTimeout<result>(fn: (signal: AbortSignal) => Promise<result>, timeoutMs: number) {
774
923
  const controller = new AbortController()
775
924
  const timeout = setTimeout(() => controller.abort(), timeoutMs)
776
925
  return Promise.race([
777
- adapter.probeQuote(input, controller.signal),
926
+ fn(controller.signal),
778
927
  new Promise<never>((_, reject) => {
779
928
  if (controller.signal.aborted) {
780
929
  reject(new ProviderAdapterTimeoutError())
@@ -877,11 +1026,31 @@ export class InvalidAmountError extends Error {
877
1026
  override name = 'FundingRoutes.InvalidAmountError'
878
1027
  }
879
1028
 
1029
+ /** Error thrown when no curated route matches an explicit quote request. */
1030
+ export class FundingRouteNotFoundError extends Error {
1031
+ override name = 'FundingRoutes.FundingRouteNotFoundError'
1032
+ }
1033
+
880
1034
  /** Error thrown internally when a provider adapter exceeds its route quote timeout. */
881
1035
  export class ProviderAdapterTimeoutError extends Error {
882
1036
  override name = 'FundingRoutes.ProviderAdapterTimeoutError'
883
1037
  }
884
1038
 
1039
+ /** Error thrown when a requested provider quote is temporarily unavailable. */
1040
+ export class ProviderQuoteUnavailableError extends Error {
1041
+ override name = 'FundingRoutes.ProviderQuoteUnavailableError'
1042
+ }
1043
+
1044
+ /** Error thrown when a provider rate-limits a quote request. */
1045
+ export class ProviderRateLimitError extends Error {
1046
+ override name = 'FundingRoutes.ProviderRateLimitError'
1047
+ }
1048
+
1049
+ /** Error thrown when a route provider lacks explicit quote capability. */
1050
+ export class ProviderNotConfiguredError extends Error {
1051
+ override name = 'FundingRoutes.ProviderNotConfiguredError'
1052
+ }
1053
+
885
1054
  /** Error thrown when the caller filters to an unknown provider. */
886
1055
  export class UnsupportedProviderError extends Error {
887
1056
  override name = 'FundingRoutes.UnsupportedProviderError'
@@ -65,8 +65,7 @@ describe('middleware', () => {
65
65
  })
66
66
  api.get('/secure', (c) => c.json({ ok: true }, 200))
67
67
 
68
- const token = `tempo:sk:${'a'.repeat(48)}`
69
- await api.request(`/secure?apiKey=${token}`)
68
+ await api.request('/secure?key=opaque-secret&chainId=mainnet')
70
69
 
71
70
  expect(stable(entries[0]!)).toMatchInlineSnapshot(`
72
71
  {
@@ -80,7 +79,7 @@ describe('middleware', () => {
80
79
  "orgId": "org_1",
81
80
  "type": "api_key",
82
81
  },
83
- "query": "apiKey=tempo:sk:…",
82
+ "query": "chainId=mainnet",
84
83
  "route": "/secure",
85
84
  "status": 200,
86
85
  }
@@ -139,6 +138,45 @@ describe('middleware', () => {
139
138
  `)
140
139
  })
141
140
 
141
+ test('includes redacted provider failure details', async () => {
142
+ const entries: Log.Entry[] = []
143
+ const api = app({ emit: (entry) => void entries.push(entry) })
144
+ api.get('/provider', (c) => {
145
+ c.set('providerFailure', {
146
+ code: 'UNAUTHORIZED',
147
+ failure: 'http',
148
+ id: 'across',
149
+ operation: 'swap/approval',
150
+ status: 401,
151
+ })
152
+ return Response.error(c, {
153
+ code: 'provider_error',
154
+ message: 'Provider request failed',
155
+ status: 502,
156
+ })
157
+ })
158
+
159
+ await api.request('/provider')
160
+
161
+ expect(stable(entries[0]!)).toMatchInlineSnapshot(`
162
+ {
163
+ "errorCode": "provider_error",
164
+ "level": "error",
165
+ "method": "GET",
166
+ "path": "/provider",
167
+ "provider": {
168
+ "code": "UNAUTHORIZED",
169
+ "failure": "http",
170
+ "id": "across",
171
+ "operation": "swap/approval",
172
+ "status": 401,
173
+ },
174
+ "route": "/provider",
175
+ "status": 502,
176
+ }
177
+ `)
178
+ })
179
+
142
180
  test('logs thrown errors at error level', async () => {
143
181
  const entries: Log.Entry[] = []
144
182
  const api = app({ emit: (entry) => void entries.push(entry) })
@@ -10,6 +10,8 @@ import type * as Timing from './Timing.js'
10
10
  export type Variables = {
11
11
  /** Stable error code recorded by `Response.error` for the request log entry. */
12
12
  errorCode?: string | undefined
13
+ /** Redacted provider failure details recorded by an upstream adapter. */
14
+ providerFailure?: Entry['provider'] | undefined
13
15
  }
14
16
 
15
17
  /** Hono environment shape used by the request logger. */
@@ -55,12 +57,27 @@ export type Entry = {
55
57
  id: string
56
58
  /** Owning organization id for API-key callers. */
57
59
  orgId?: string | undefined
58
- /** Owning project id for project-attributed API-key callers. */
60
+ /** Attributed project id for API-key callers. */
59
61
  projectId?: string | undefined
60
62
  /** Principal kind. */
61
63
  type: 'api_key' | 'public' | 'session' | 'super_admin'
62
64
  }
63
65
  | undefined
66
+ /** Redacted upstream provider failure details, when an adapter request fails. */
67
+ provider?:
68
+ | {
69
+ /** Stable provider error code, when one is safe to retain. */
70
+ code?: string | undefined
71
+ /** Failure boundary that rejected the provider request. */
72
+ failure: 'http' | 'network' | 'payload' | 'unknown'
73
+ /** Provider identifier. */
74
+ id: string
75
+ /** Provider operation identifier. */
76
+ operation: string
77
+ /** Upstream HTTP status, when a response was received. */
78
+ status?: number | undefined
79
+ }
80
+ | undefined
64
81
  /** Raw query string (no leading `?`) with API-key tokens redacted, when present. */
65
82
  query?: string | undefined
66
83
  /** Rate limit state from the `RateLimit-*` response headers, when enforced. */
@@ -110,12 +127,15 @@ export function middleware<environment extends Environment = Environment>(
110
127
  const duration = performance.now() - start
111
128
 
112
129
  const url = new URL(c.req.url)
130
+ url.searchParams.delete('key')
131
+ const query = ApiKey.redact(url.search.slice(1))
113
132
  const status = c.res.status
114
133
  // Hono cannot resolve variable types through the generic `environment`,
115
134
  // so shared-variable reads are cast from the environment contract above
116
135
  // (the same pattern EdgeCache uses for its cross-layer reads).
117
136
  const principal = c.get('principal' as never) as Auth.Principal | undefined
118
137
  const errorCode = c.get('errorCode' as never) as string | undefined
138
+ const provider = c.get('providerFailure' as never) as Entry['provider']
119
139
 
120
140
  // The `request` total metric duplicates `duration` (measured here, one
121
141
  // layer further out), so only operation timings are kept.
@@ -165,9 +185,8 @@ export function middleware<environment extends Environment = Environment>(
165
185
  type: principal.type,
166
186
  },
167
187
  }),
168
- // Keys belong in headers, but a confused client may pass one in the
169
- // query string; redact defensively before it reaches a log store.
170
- ...(url.search.length > 1 ? { query: ApiKey.redact(url.search.slice(1)) } : {}),
188
+ ...(provider === undefined ? {} : { provider }),
189
+ ...(query ? { query } : {}),
171
190
  ...(rateLimit === undefined ? {} : { rateLimit }),
172
191
  requestId: c.get('requestId' as never) as string,
173
192
  route: c.req.routePath,