tapimo 0.15.1 → 0.18.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 (709) hide show
  1. package/README.md +137 -0
  2. package/dist/ApiKey.d.ts +1 -0
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +4 -2
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +37 -11
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +163 -10
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +13085 -11974
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +46 -15
  13. package/dist/App.js.map +1 -1
  14. package/dist/Scope.d.ts +1 -1
  15. package/dist/Scope.d.ts.map +1 -1
  16. package/dist/Scope.js +1 -1
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/admin/App.d.ts +893 -191
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/App.js +5 -1
  21. package/dist/admin/App.js.map +1 -1
  22. package/dist/admin/apps/api-keys.d.ts +70 -70
  23. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.js +8 -3
  25. package/dist/admin/apps/api-keys.js.map +1 -1
  26. package/dist/admin/apps/earn-vaults.d.ts +66 -27
  27. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  28. package/dist/admin/apps/earn-vaults.js +36 -7
  29. package/dist/admin/apps/earn-vaults.js.map +1 -1
  30. package/dist/admin/apps/organizations.d.ts +25 -25
  31. package/dist/admin/apps/organizations.d.ts.map +1 -1
  32. package/dist/admin/apps/organizations.js +5 -4
  33. package/dist/admin/apps/organizations.js.map +1 -1
  34. package/dist/admin/apps/route-policies.d.ts +632 -0
  35. package/dist/admin/apps/route-policies.d.ts.map +1 -0
  36. package/dist/admin/apps/route-policies.js +257 -0
  37. package/dist/admin/apps/route-policies.js.map +1 -0
  38. package/dist/admin/apps/routes-support.js +39 -3
  39. package/dist/admin/apps/routes-support.js.map +1 -1
  40. package/dist/admin/apps/routes.d.ts +529 -76
  41. package/dist/admin/apps/routes.d.ts.map +1 -1
  42. package/dist/admin/apps/routes.js +82 -1
  43. package/dist/admin/apps/routes.js.map +1 -1
  44. package/dist/admin/apps/verified-tokens.d.ts +157 -157
  45. package/dist/admin/index.d.ts +0 -1
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +0 -1
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/admin/ui.generated.d.ts +1 -1
  50. package/dist/admin/ui.generated.d.ts.map +1 -1
  51. package/dist/admin/ui.generated.js +205 -201
  52. package/dist/admin/ui.generated.js.map +1 -1
  53. package/dist/analytics/Analytics.d.ts.map +1 -1
  54. package/dist/analytics/Analytics.js +65 -1
  55. package/dist/analytics/Analytics.js.map +1 -1
  56. package/dist/analytics/tables/requestEvents.d.ts +1 -1
  57. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  58. package/dist/analytics/tables/requestEvents.js +58 -59
  59. package/dist/analytics/tables/requestEvents.js.map +1 -1
  60. package/dist/apps/data/App.d.ts +2709 -2670
  61. package/dist/apps/data/App.d.ts.map +1 -1
  62. package/dist/apps/data/routes/activities.d.ts +357 -357
  63. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  64. package/dist/apps/data/routes/activities.js +50 -0
  65. package/dist/apps/data/routes/activities.js.map +1 -1
  66. package/dist/apps/data/routes/addresses.d.ts +248 -248
  67. package/dist/apps/data/routes/balances.d.ts +22 -22
  68. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  69. package/dist/apps/data/routes/balances.js +5 -7
  70. package/dist/apps/data/routes/balances.js.map +1 -1
  71. package/dist/apps/data/routes/blocks.d.ts +125 -125
  72. package/dist/apps/data/routes/coingecko.d.ts +54 -54
  73. package/dist/apps/data/routes/earn.d.ts +103 -12
  74. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  75. package/dist/apps/data/routes/earn.js +456 -220
  76. package/dist/apps/data/routes/earn.js.map +1 -1
  77. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  78. package/dist/apps/data/routes/exchanges.js +267 -97
  79. package/dist/apps/data/routes/exchanges.js.map +1 -1
  80. package/dist/apps/data/routes/fee-amm.d.ts +109 -127
  81. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  82. package/dist/apps/data/routes/fee-amm.js +83 -54
  83. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  84. package/dist/apps/data/routes/indexer.d.ts +43 -43
  85. package/dist/apps/data/routes/receipts.d.ts +235 -235
  86. package/dist/apps/data/routes/rpc.d.ts +30 -30
  87. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  88. package/dist/apps/data/routes/tokens.js +11 -6
  89. package/dist/apps/data/routes/tokens.js.map +1 -1
  90. package/dist/apps/data/routes/transactions.d.ts +2 -0
  91. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  92. package/dist/apps/data/routes/transactions.js +30 -22
  93. package/dist/apps/data/routes/transactions.js.map +1 -1
  94. package/dist/apps/data/routes/transfers.d.ts +77 -77
  95. package/dist/apps/data/routes/valuation.d.ts +32 -32
  96. package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
  97. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  98. package/dist/apps/data/routes/webhooks.js +1 -1
  99. package/dist/apps/data/routes/webhooks.js.map +1 -1
  100. package/dist/apps/data/routes/zones.d.ts +31 -31
  101. package/dist/apps/management/App.d.ts +2909 -2064
  102. package/dist/apps/management/App.d.ts.map +1 -1
  103. package/dist/apps/management/App.js +2 -0
  104. package/dist/apps/management/App.js.map +1 -1
  105. package/dist/apps/management/Billing.d.ts +2 -4
  106. package/dist/apps/management/Billing.d.ts.map +1 -1
  107. package/dist/apps/management/Billing.js +65 -26
  108. package/dist/apps/management/Billing.js.map +1 -1
  109. package/dist/apps/management/routes/api-keys.d.ts +257 -245
  110. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  111. package/dist/apps/management/routes/api-keys.js +70 -11
  112. package/dist/apps/management/routes/api-keys.js.map +1 -1
  113. package/dist/apps/management/routes/billing.d.ts +84 -84
  114. package/dist/apps/management/routes/cli.d.ts +912 -0
  115. package/dist/apps/management/routes/cli.d.ts.map +1 -0
  116. package/dist/apps/management/routes/cli.js +416 -0
  117. package/dist/apps/management/routes/cli.js.map +1 -0
  118. package/dist/apps/management/routes/faucet.d.ts +8 -8
  119. package/dist/apps/management/routes/invitations.d.ts +138 -138
  120. package/dist/apps/management/routes/invite-links.d.ts +172 -172
  121. package/dist/apps/management/routes/members.d.ts +16 -16
  122. package/dist/apps/management/routes/orgs.d.ts +104 -104
  123. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  124. package/dist/apps/management/routes/orgs.js +8 -2
  125. package/dist/apps/management/routes/orgs.js.map +1 -1
  126. package/dist/apps/management/routes/projects.d.ts +125 -125
  127. package/dist/apps/management/routes/usage.d.ts +8 -8
  128. package/dist/apps/management/routes/verified-token-requests.d.ts +86 -86
  129. package/dist/apps/management/routes/webhooks.d.ts +485 -485
  130. package/dist/apps/mpp/App.d.ts +44 -44
  131. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
  132. package/dist/apps/mpp/internal/Policy.js +4 -2
  133. package/dist/apps/mpp/internal/Policy.js.map +1 -1
  134. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -1
  135. package/dist/apps/mpp/internal/Sponsorship.js +6 -4
  136. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -1
  137. package/dist/apps/relay/App.d.ts +8 -0
  138. package/dist/apps/relay/App.d.ts.map +1 -1
  139. package/dist/apps/relay/App.js +16 -4
  140. package/dist/apps/relay/App.js.map +1 -1
  141. package/dist/apps/relay/Sponsorships.d.ts +4 -6
  142. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  143. package/dist/apps/relay/Sponsorships.js +71 -60
  144. package/dist/apps/relay/Sponsorships.js.map +1 -1
  145. package/dist/apps/routes/Access.d.ts +53 -0
  146. package/dist/apps/routes/Access.d.ts.map +1 -1
  147. package/dist/apps/routes/Access.js +121 -0
  148. package/dist/apps/routes/Access.js.map +1 -1
  149. package/dist/apps/routes/App.d.ts +397 -158
  150. package/dist/apps/routes/App.d.ts.map +1 -1
  151. package/dist/apps/routes/App.js.map +1 -1
  152. package/dist/apps/routes/routes/chains.d.ts +25 -25
  153. package/dist/apps/routes/routes/deposit-addresses.d.ts +169 -61
  154. package/dist/apps/routes/routes/deposit-addresses.d.ts.map +1 -1
  155. package/dist/apps/routes/routes/deposit-addresses.js +217 -32
  156. package/dist/apps/routes/routes/deposit-addresses.js.map +1 -1
  157. package/dist/apps/routes/routes/quotes.d.ts +171 -81
  158. package/dist/apps/routes/routes/quotes.d.ts.map +1 -1
  159. package/dist/apps/routes/routes/quotes.js +101 -27
  160. package/dist/apps/routes/routes/quotes.js.map +1 -1
  161. package/dist/apps/routes/routes/transfers.d.ts +532 -480
  162. package/dist/apps/routes/routes/transfers.d.ts.map +1 -1
  163. package/dist/apps/routes/routes/transfers.js +182 -37
  164. package/dist/apps/routes/routes/transfers.js.map +1 -1
  165. package/dist/cli/ApiKeys.d.ts +120 -0
  166. package/dist/cli/ApiKeys.d.ts.map +1 -0
  167. package/dist/cli/ApiKeys.js +138 -0
  168. package/dist/cli/ApiKeys.js.map +1 -0
  169. package/dist/cli/Cli.d.ts +92 -34
  170. package/dist/cli/Cli.d.ts.map +1 -1
  171. package/dist/cli/Cli.js +188 -11
  172. package/dist/cli/Cli.js.map +1 -1
  173. package/dist/cli/Credentials.d.ts +95 -0
  174. package/dist/cli/Credentials.d.ts.map +1 -0
  175. package/dist/cli/Credentials.js +110 -0
  176. package/dist/cli/Credentials.js.map +1 -0
  177. package/dist/cli/Spec.d.ts +59 -0
  178. package/dist/cli/Spec.d.ts.map +1 -0
  179. package/dist/cli/Spec.js +77 -0
  180. package/dist/cli/Spec.js.map +1 -0
  181. package/dist/cli/bin.js +5 -1
  182. package/dist/cli/bin.js.map +1 -1
  183. package/dist/cli/commands/admin.d.ts +5 -5
  184. package/dist/cli/commands/admin.d.ts.map +1 -1
  185. package/dist/cli/commands/auth.d.ts +73 -0
  186. package/dist/cli/commands/auth.d.ts.map +1 -0
  187. package/dist/cli/commands/auth.js +204 -0
  188. package/dist/cli/commands/auth.js.map +1 -0
  189. package/dist/cli/commands/keys.d.ts +17 -0
  190. package/dist/cli/commands/keys.d.ts.map +1 -0
  191. package/dist/cli/commands/keys.js +109 -0
  192. package/dist/cli/commands/keys.js.map +1 -0
  193. package/dist/cloudflare.d.ts +27 -2
  194. package/dist/cloudflare.d.ts.map +1 -1
  195. package/dist/cloudflare.js +144 -17
  196. package/dist/cloudflare.js.map +1 -1
  197. package/dist/db/Db.d.ts +23 -0
  198. package/dist/db/Db.d.ts.map +1 -1
  199. package/dist/db/Db.js +413 -1
  200. package/dist/db/Db.js.map +1 -1
  201. package/dist/db/Schema.d.ts +44 -1
  202. package/dist/db/Schema.d.ts.map +1 -1
  203. package/dist/db/Schema.js +56 -3
  204. package/dist/db/Schema.js.map +1 -1
  205. package/dist/db/tables/apiKeyAdmissions.d.ts +28 -2
  206. package/dist/db/tables/apiKeyAdmissions.d.ts.map +1 -1
  207. package/dist/db/tables/apiKeyAdmissions.js +65 -9
  208. package/dist/db/tables/apiKeyAdmissions.js.map +1 -1
  209. package/dist/db/tables/apiKeyOwnerTombstones.d.ts +2 -0
  210. package/dist/db/tables/apiKeyOwnerTombstones.d.ts.map +1 -1
  211. package/dist/db/tables/apiKeyOwnerTombstones.js +2 -2
  212. package/dist/db/tables/apiKeyOwnerTombstones.js.map +1 -1
  213. package/dist/db/tables/authAccounts.d.ts.map +1 -1
  214. package/dist/db/tables/authAccounts.js +1 -0
  215. package/dist/db/tables/authAccounts.js.map +1 -1
  216. package/dist/db/tables/earnVaults.d.ts +5 -1
  217. package/dist/db/tables/earnVaults.d.ts.map +1 -1
  218. package/dist/db/tables/earnVaults.js +12 -1
  219. package/dist/db/tables/earnVaults.js.map +1 -1
  220. package/dist/db/tables/organizations.d.ts +4 -2
  221. package/dist/db/tables/organizations.d.ts.map +1 -1
  222. package/dist/db/tables/organizations.js +8 -34
  223. package/dist/db/tables/organizations.js.map +1 -1
  224. package/dist/db/tables/requestUsage.d.ts +5 -1
  225. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  226. package/dist/db/tables/requestUsage.js +10 -2
  227. package/dist/db/tables/requestUsage.js.map +1 -1
  228. package/dist/db/tables/rewardEligibilityAssociations.d.ts +13 -0
  229. package/dist/db/tables/rewardEligibilityAssociations.d.ts.map +1 -1
  230. package/dist/db/tables/rewardEligibilityAssociations.js +11 -0
  231. package/dist/db/tables/rewardEligibilityAssociations.js.map +1 -1
  232. package/dist/db/tables/rewardRuns.d.ts.map +1 -1
  233. package/dist/db/tables/rewardRuns.js +4 -0
  234. package/dist/db/tables/rewardRuns.js.map +1 -1
  235. package/dist/db/tables/rewardTransactionAttempts.d.ts.map +1 -1
  236. package/dist/db/tables/rewardTransactionAttempts.js +2 -0
  237. package/dist/db/tables/rewardTransactionAttempts.js.map +1 -1
  238. package/dist/db/tables/routesDepositAddresses.d.ts +29 -0
  239. package/dist/db/tables/routesDepositAddresses.d.ts.map +1 -1
  240. package/dist/db/tables/routesDepositAddresses.js +84 -31
  241. package/dist/db/tables/routesDepositAddresses.js.map +1 -1
  242. package/dist/db/tables/routesDeposits.d.ts.map +1 -1
  243. package/dist/db/tables/routesDeposits.js +31 -21
  244. package/dist/db/tables/routesDeposits.js.map +1 -1
  245. package/dist/db/tables/routesIdempotency.d.ts.map +1 -1
  246. package/dist/db/tables/routesIdempotency.js +2 -0
  247. package/dist/db/tables/routesIdempotency.js.map +1 -1
  248. package/dist/db/tables/routesPolicies.d.ts +58 -0
  249. package/dist/db/tables/routesPolicies.d.ts.map +1 -0
  250. package/dist/db/tables/routesPolicies.js +198 -0
  251. package/dist/db/tables/routesPolicies.js.map +1 -0
  252. package/dist/db/tables/routesTransferSubsidies.d.ts +22 -0
  253. package/dist/db/tables/routesTransferSubsidies.d.ts.map +1 -1
  254. package/dist/db/tables/routesTransferSubsidies.js +41 -0
  255. package/dist/db/tables/routesTransferSubsidies.js.map +1 -1
  256. package/dist/db/tables/routesTransferSubsidyNonces.d.ts.map +1 -1
  257. package/dist/db/tables/routesTransferSubsidyNonces.js +12 -4
  258. package/dist/db/tables/routesTransferSubsidyNonces.js.map +1 -1
  259. package/dist/db/tables/routesTransfers.d.ts +26 -1
  260. package/dist/db/tables/routesTransfers.d.ts.map +1 -1
  261. package/dist/db/tables/routesTransfers.js +36 -6
  262. package/dist/db/tables/routesTransfers.js.map +1 -1
  263. package/dist/db/tables/sponsoredTransactions.d.ts +45 -13
  264. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  265. package/dist/db/tables/sponsoredTransactions.js +144 -33
  266. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  267. package/dist/db/tables/users.d.ts +2 -0
  268. package/dist/db/tables/users.d.ts.map +1 -1
  269. package/dist/db/tables/users.js +11 -0
  270. package/dist/db/tables/users.js.map +1 -1
  271. package/dist/handlers/internal/multisig.d.ts +1 -1
  272. package/dist/handlers/internal/multisig.d.ts.map +1 -1
  273. package/dist/handlers/internal/multisig.js +3 -2
  274. package/dist/handlers/internal/multisig.js.map +1 -1
  275. package/dist/handlers/relay.d.ts +2 -0
  276. package/dist/handlers/relay.d.ts.map +1 -1
  277. package/dist/handlers/relay.js +34 -15
  278. package/dist/handlers/relay.js.map +1 -1
  279. package/dist/internal/Auth.d.ts +57 -6
  280. package/dist/internal/Auth.d.ts.map +1 -1
  281. package/dist/internal/Auth.js +182 -78
  282. package/dist/internal/Auth.js.map +1 -1
  283. package/dist/internal/BetterAuth.d.ts +22 -0
  284. package/dist/internal/BetterAuth.d.ts.map +1 -1
  285. package/dist/internal/BetterAuth.js +17 -14
  286. package/dist/internal/BetterAuth.js.map +1 -1
  287. package/dist/internal/Cache.d.ts +5 -0
  288. package/dist/internal/Cache.d.ts.map +1 -1
  289. package/dist/internal/Cache.js +3 -1
  290. package/dist/internal/Cache.js.map +1 -1
  291. package/dist/internal/CliAuth.d.ts +243 -0
  292. package/dist/internal/CliAuth.d.ts.map +1 -0
  293. package/dist/internal/CliAuth.js +249 -0
  294. package/dist/internal/CliAuth.js.map +1 -0
  295. package/dist/internal/EarnSharePrices.d.ts +1 -1
  296. package/dist/internal/EarnSharePrices.d.ts.map +1 -1
  297. package/dist/internal/EarnSharePrices.js +7 -3
  298. package/dist/internal/EarnSharePrices.js.map +1 -1
  299. package/dist/internal/EarnVaults.d.ts +47 -0
  300. package/dist/internal/EarnVaults.d.ts.map +1 -1
  301. package/dist/internal/EarnVaults.js +188 -4
  302. package/dist/internal/EarnVaults.js.map +1 -1
  303. package/dist/internal/EarnWithdrawals.d.ts +73 -0
  304. package/dist/internal/EarnWithdrawals.d.ts.map +1 -0
  305. package/dist/internal/EarnWithdrawals.js +189 -0
  306. package/dist/internal/EarnWithdrawals.js.map +1 -0
  307. package/dist/internal/ExecutionContext.d.ts +21 -0
  308. package/dist/internal/ExecutionContext.d.ts.map +1 -0
  309. package/dist/internal/ExecutionContext.js +16 -0
  310. package/dist/internal/ExecutionContext.js.map +1 -0
  311. package/dist/internal/Log.d.ts +7 -3
  312. package/dist/internal/Log.d.ts.map +1 -1
  313. package/dist/internal/Log.js +163 -130
  314. package/dist/internal/Log.js.map +1 -1
  315. package/dist/internal/MetricSink.d.ts.map +1 -1
  316. package/dist/internal/MetricSink.js +26 -1
  317. package/dist/internal/MetricSink.js.map +1 -1
  318. package/dist/internal/RateLimit.d.ts +67 -0
  319. package/dist/internal/RateLimit.d.ts.map +1 -1
  320. package/dist/internal/RateLimit.js +174 -27
  321. package/dist/internal/RateLimit.js.map +1 -1
  322. package/dist/internal/Store.d.ts +6 -0
  323. package/dist/internal/Store.d.ts.map +1 -1
  324. package/dist/internal/Store.js +4 -5
  325. package/dist/internal/Store.js.map +1 -1
  326. package/dist/internal/Timing.d.ts +6 -0
  327. package/dist/internal/Timing.d.ts.map +1 -1
  328. package/dist/internal/Timing.js +21 -1
  329. package/dist/internal/Timing.js.map +1 -1
  330. package/dist/internal/Tron.d.ts +124 -0
  331. package/dist/internal/Tron.d.ts.map +1 -0
  332. package/dist/internal/Tron.js +202 -0
  333. package/dist/internal/Tron.js.map +1 -0
  334. package/dist/internal/Viem.d.ts +4 -0
  335. package/dist/internal/Viem.d.ts.map +1 -1
  336. package/dist/internal/Viem.js +25 -6
  337. package/dist/internal/Viem.js.map +1 -1
  338. package/dist/internal/rewards/Read.d.ts +2 -2
  339. package/dist/internal/rewards/Read.d.ts.map +1 -1
  340. package/dist/internal/rewards/Read.js +11 -2
  341. package/dist/internal/rewards/Read.js.map +1 -1
  342. package/dist/internal/routes/Action.d.ts +27 -0
  343. package/dist/internal/routes/Action.d.ts.map +1 -1
  344. package/dist/internal/routes/Action.js +49 -1
  345. package/dist/internal/routes/Action.js.map +1 -1
  346. package/dist/internal/routes/Chain.d.ts +2 -0
  347. package/dist/internal/routes/Chain.d.ts.map +1 -1
  348. package/dist/internal/routes/Chain.js +4 -0
  349. package/dist/internal/routes/Chain.js.map +1 -1
  350. package/dist/internal/routes/DepositAddress.d.ts.map +1 -1
  351. package/dist/internal/routes/DepositAddress.js +5 -0
  352. package/dist/internal/routes/DepositAddress.js.map +1 -1
  353. package/dist/internal/routes/Evidence.d.ts.map +1 -1
  354. package/dist/internal/routes/Evidence.js +6 -2
  355. package/dist/internal/routes/Evidence.js.map +1 -1
  356. package/dist/internal/routes/EvmTransferSettlement.d.ts +17 -0
  357. package/dist/internal/routes/EvmTransferSettlement.d.ts.map +1 -0
  358. package/dist/internal/routes/EvmTransferSettlement.js +196 -0
  359. package/dist/internal/routes/EvmTransferSettlement.js.map +1 -0
  360. package/dist/internal/routes/Policy.d.ts +161 -0
  361. package/dist/internal/routes/Policy.d.ts.map +1 -0
  362. package/dist/internal/routes/Policy.js +249 -0
  363. package/dist/internal/routes/Policy.js.map +1 -0
  364. package/dist/internal/routes/Provider.d.ts +66 -3
  365. package/dist/internal/routes/Provider.d.ts.map +1 -1
  366. package/dist/internal/routes/Provider.js +106 -27
  367. package/dist/internal/routes/Provider.js.map +1 -1
  368. package/dist/internal/routes/Quota.d.ts +57 -0
  369. package/dist/internal/routes/Quota.d.ts.map +1 -0
  370. package/dist/internal/routes/Quota.js +144 -0
  371. package/dist/internal/routes/Quota.js.map +1 -0
  372. package/dist/internal/routes/Reconciliation.d.ts.map +1 -1
  373. package/dist/internal/routes/Reconciliation.js +163 -47
  374. package/dist/internal/routes/Reconciliation.js.map +1 -1
  375. package/dist/internal/routes/SolanaTransferSettlement.d.ts +12 -0
  376. package/dist/internal/routes/SolanaTransferSettlement.d.ts.map +1 -0
  377. package/dist/internal/routes/SolanaTransferSettlement.js +220 -0
  378. package/dist/internal/routes/SolanaTransferSettlement.js.map +1 -0
  379. package/dist/internal/routes/SolanaTransferSubsidy.d.ts +172 -0
  380. package/dist/internal/routes/SolanaTransferSubsidy.d.ts.map +1 -0
  381. package/dist/internal/routes/SolanaTransferSubsidy.js +564 -0
  382. package/dist/internal/routes/SolanaTransferSubsidy.js.map +1 -0
  383. package/dist/internal/routes/Subsidy.d.ts +2 -2
  384. package/dist/internal/routes/Subsidy.d.ts.map +1 -1
  385. package/dist/internal/routes/Subsidy.js +2 -2
  386. package/dist/internal/routes/Subsidy.js.map +1 -1
  387. package/dist/internal/routes/Transfer.d.ts +229 -1
  388. package/dist/internal/routes/Transfer.d.ts.map +1 -1
  389. package/dist/internal/routes/Transfer.js +644 -7
  390. package/dist/internal/routes/Transfer.js.map +1 -1
  391. package/dist/internal/routes/TransferReconciliation.d.ts +6 -0
  392. package/dist/internal/routes/TransferReconciliation.d.ts.map +1 -1
  393. package/dist/internal/routes/TransferReconciliation.js +83 -159
  394. package/dist/internal/routes/TransferReconciliation.js.map +1 -1
  395. package/dist/internal/routes/TransferSettlement.d.ts +45 -0
  396. package/dist/internal/routes/TransferSettlement.d.ts.map +1 -0
  397. package/dist/internal/routes/TransferSettlement.js +2 -0
  398. package/dist/internal/routes/TransferSettlement.js.map +1 -0
  399. package/dist/internal/routes/TransferSubsidy.d.ts +23 -8
  400. package/dist/internal/routes/TransferSubsidy.d.ts.map +1 -1
  401. package/dist/internal/routes/TransferSubsidy.js +64 -5
  402. package/dist/internal/routes/TransferSubsidy.js.map +1 -1
  403. package/dist/internal/routes/TronTransferSettlement.d.ts +12 -0
  404. package/dist/internal/routes/TronTransferSettlement.d.ts.map +1 -0
  405. package/dist/internal/routes/TronTransferSettlement.js +201 -0
  406. package/dist/internal/routes/TronTransferSettlement.js.map +1 -0
  407. package/dist/internal/routes/TronTransferSubsidy.d.ts +174 -0
  408. package/dist/internal/routes/TronTransferSubsidy.d.ts.map +1 -0
  409. package/dist/internal/routes/TronTransferSubsidy.js +439 -0
  410. package/dist/internal/routes/TronTransferSubsidy.js.map +1 -0
  411. package/dist/internal/routes/index.d.ts +3 -0
  412. package/dist/internal/routes/index.d.ts.map +1 -1
  413. package/dist/internal/routes/index.js +3 -0
  414. package/dist/internal/routes/index.js.map +1 -1
  415. package/dist/internal/routes/providers/across.d.ts +3 -0
  416. package/dist/internal/routes/providers/across.d.ts.map +1 -1
  417. package/dist/internal/routes/providers/across.js +11 -0
  418. package/dist/internal/routes/providers/across.js.map +1 -1
  419. package/dist/internal/routes/providers/legacyMesh.d.ts +29 -0
  420. package/dist/internal/routes/providers/legacyMesh.d.ts.map +1 -0
  421. package/dist/internal/routes/providers/legacyMesh.js +474 -0
  422. package/dist/internal/routes/providers/legacyMesh.js.map +1 -0
  423. package/dist/internal/routes/providers/legacyMeshDelivery.d.ts +59 -0
  424. package/dist/internal/routes/providers/legacyMeshDelivery.d.ts.map +1 -0
  425. package/dist/internal/routes/providers/legacyMeshDelivery.js +229 -0
  426. package/dist/internal/routes/providers/legacyMeshDelivery.js.map +1 -0
  427. package/dist/internal/routes/providers/legacyMeshOutbound.d.ts +19 -0
  428. package/dist/internal/routes/providers/legacyMeshOutbound.d.ts.map +1 -0
  429. package/dist/internal/routes/providers/legacyMeshOutbound.js +457 -0
  430. package/dist/internal/routes/providers/legacyMeshOutbound.js.map +1 -0
  431. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts +123 -0
  432. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts.map +1 -0
  433. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js +333 -0
  434. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js.map +1 -0
  435. package/dist/internal/routes/providers/propAmm.d.ts +70 -0
  436. package/dist/internal/routes/providers/propAmm.d.ts.map +1 -0
  437. package/dist/internal/routes/providers/propAmm.js +524 -0
  438. package/dist/internal/routes/providers/propAmm.js.map +1 -0
  439. package/dist/internal/routes/providers/relay.d.ts +3 -0
  440. package/dist/internal/routes/providers/relay.d.ts.map +1 -1
  441. package/dist/internal/routes/providers/relay.js +352 -41
  442. package/dist/internal/routes/providers/relay.js.map +1 -1
  443. package/dist/internal/routes/providers/rhino.d.ts +3 -0
  444. package/dist/internal/routes/providers/rhino.d.ts.map +1 -1
  445. package/dist/internal/routes/providers/rhino.js +11 -0
  446. package/dist/internal/routes/providers/rhino.js.map +1 -1
  447. package/dist/internal/routes/providers/squid.d.ts +3 -0
  448. package/dist/internal/routes/providers/squid.d.ts.map +1 -1
  449. package/dist/internal/routes/providers/squid.js +19 -0
  450. package/dist/internal/routes/providers/squid.js.map +1 -1
  451. package/dist/internal/routes/providers/stargate.d.ts.map +1 -1
  452. package/dist/internal/routes/providers/stargate.js +22 -9
  453. package/dist/internal/routes/providers/stargate.js.map +1 -1
  454. package/dist/internal/routes/providers/symbiosis.d.ts.map +1 -1
  455. package/dist/internal/routes/providers/symbiosis.js +13 -17
  456. package/dist/internal/routes/providers/symbiosis.js.map +1 -1
  457. package/dist/providers/index.d.ts +14 -0
  458. package/dist/providers/index.d.ts.map +1 -1
  459. package/dist/providers/index.js +6 -0
  460. package/dist/providers/index.js.map +1 -1
  461. package/package.json +16 -6
  462. package/src/ApiKey.ts +7 -3
  463. package/src/ApiKeys.test.ts +652 -8
  464. package/src/ApiKeys.ts +191 -11
  465. package/src/App.test.ts +405 -18
  466. package/src/App.ts +51 -15
  467. package/src/Client.test-d.ts +157 -10
  468. package/src/Client.test.ts +4 -4
  469. package/src/Scope.ts +1 -2
  470. package/src/admin/App.ts +11 -5
  471. package/src/admin/apps/api-keys.test.ts +98 -2
  472. package/src/admin/apps/api-keys.ts +21 -12
  473. package/src/admin/apps/earn-vaults.test.ts +76 -7
  474. package/src/admin/apps/earn-vaults.ts +47 -8
  475. package/src/admin/apps/organizations.test.ts +147 -31
  476. package/src/admin/apps/organizations.ts +5 -4
  477. package/src/admin/apps/route-policies.test.ts +220 -0
  478. package/src/admin/apps/route-policies.ts +322 -0
  479. package/src/admin/apps/routes-support.test.ts +107 -2
  480. package/src/admin/apps/routes-support.ts +43 -3
  481. package/src/admin/apps/routes.test.ts +150 -0
  482. package/src/admin/apps/routes.ts +97 -1
  483. package/src/admin/apps/scopes.test.ts +1 -1
  484. package/src/admin/index.ts +0 -1
  485. package/src/admin/ui/plugin.ts +2 -1
  486. package/src/admin/ui/src/components/Dialog.tsx +1 -1
  487. package/src/admin/ui/src/components/EarnVaultForm.tsx +45 -0
  488. package/src/admin/ui/src/components/RoutePicker.tsx +79 -0
  489. package/src/admin/ui/src/lib/earn-vaults.ts +1 -1
  490. package/src/admin/ui/src/lib/route-policies.test.ts +452 -0
  491. package/src/admin/ui/src/lib/route-policies.ts +232 -0
  492. package/src/admin/ui/src/lib/routes.ts +34 -0
  493. package/src/admin/ui/src/routeTree.gen.ts +21 -0
  494. package/src/admin/ui/src/routes/api-keys.tsx +21 -2
  495. package/src/admin/ui/src/routes/early-access.tsx +1 -0
  496. package/src/admin/ui/src/routes/earn.vaults.tsx +1 -0
  497. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +22 -0
  498. package/src/admin/ui/src/routes/earn.vaults_.new.tsx +10 -0
  499. package/src/admin/ui/src/routes/organizations.tsx +1 -0
  500. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +18 -3
  501. package/src/admin/ui/src/routes/route-policies.tsx +678 -0
  502. package/src/admin/ui/src/routes/routes.tsx +85 -2
  503. package/src/admin/ui/src/routes/routes_.support.tsx +6 -22
  504. package/src/admin/ui/src/routes/subsidies.tsx +1 -0
  505. package/src/admin/ui/src/routes/verified-tokens.tsx +1 -0
  506. package/src/admin/ui.generated.ts +258 -202
  507. package/src/analytics/Analytics.test.ts +4 -50
  508. package/src/analytics/Analytics.ts +65 -1
  509. package/src/analytics/tables/requestEvents.test.ts +402 -1
  510. package/src/analytics/tables/requestEvents.ts +62 -93
  511. package/src/apps/data/routes/activities.test.ts +315 -14
  512. package/src/apps/data/routes/activities.ts +60 -0
  513. package/src/apps/data/routes/balances.ts +5 -7
  514. package/src/apps/data/routes/earn.bench.ts +18 -0
  515. package/src/apps/data/routes/earn.local.test.ts +507 -0
  516. package/src/apps/data/routes/earn.test.ts +405 -127
  517. package/src/apps/data/routes/earn.ts +660 -270
  518. package/src/apps/data/routes/exchanges.bench.ts +3 -1
  519. package/src/apps/data/routes/exchanges.test.ts +166 -2
  520. package/src/apps/data/routes/exchanges.ts +308 -101
  521. package/src/apps/data/routes/fee-amm.test.ts +134 -2
  522. package/src/apps/data/routes/fee-amm.ts +122 -60
  523. package/src/apps/data/routes/receipts.test.ts +21 -18
  524. package/src/apps/data/routes/rpc.test.ts +2 -2
  525. package/src/apps/data/routes/tokens.provenance.test.ts +157 -0
  526. package/src/apps/data/routes/tokens.test.ts +4 -4
  527. package/src/apps/data/routes/tokens.ts +11 -6
  528. package/src/apps/data/routes/transactions.test.ts +29 -0
  529. package/src/apps/data/routes/transactions.ts +33 -22
  530. package/src/apps/data/routes/webhooks.test.ts +12 -3
  531. package/src/apps/data/routes/webhooks.ts +2 -1
  532. package/src/apps/management/App.ts +4 -0
  533. package/src/apps/management/Billing.test.ts +253 -27
  534. package/src/apps/management/Billing.ts +83 -29
  535. package/src/apps/management/routes/api-keys.test.ts +1 -1
  536. package/src/apps/management/routes/api-keys.ts +85 -11
  537. package/src/apps/management/routes/billing.test.ts +68 -4
  538. package/src/apps/management/routes/cli.test.ts +370 -0
  539. package/src/apps/management/routes/cli.ts +533 -0
  540. package/src/apps/management/routes/me.test.ts +14 -4
  541. package/src/apps/management/routes/orgs.test.ts +108 -4
  542. package/src/apps/management/routes/orgs.ts +7 -2
  543. package/src/apps/management/routes/usage.test.ts +2 -2
  544. package/src/apps/mpp/internal/Policy.test.ts +51 -4
  545. package/src/apps/mpp/internal/Policy.ts +6 -2
  546. package/src/apps/mpp/internal/Sponsorship.test.ts +29 -0
  547. package/src/apps/mpp/internal/Sponsorship.ts +6 -4
  548. package/src/apps/relay/App.test.ts +85 -1
  549. package/src/apps/relay/App.ts +28 -4
  550. package/src/apps/relay/Sponsorships.test.ts +97 -1
  551. package/src/apps/relay/Sponsorships.ts +77 -66
  552. package/src/apps/routes/Access.test.ts +319 -0
  553. package/src/apps/routes/Access.ts +147 -0
  554. package/src/apps/routes/App.ts +10 -0
  555. package/src/apps/routes/routes/chains.test.ts +3 -2
  556. package/src/apps/routes/routes/deposit-addresses.test.ts +978 -34
  557. package/src/apps/routes/routes/deposit-addresses.ts +243 -32
  558. package/src/apps/routes/routes/propAmm.local.test.ts +951 -0
  559. package/src/apps/routes/routes/quotes.test.ts +81 -8
  560. package/src/apps/routes/routes/quotes.ts +109 -27
  561. package/src/apps/routes/routes/transfers.test.ts +252 -15
  562. package/src/apps/routes/routes/transfers.ts +212 -33
  563. package/src/cli/ApiKeys.test.ts +265 -0
  564. package/src/cli/ApiKeys.ts +189 -0
  565. package/src/cli/Cli.test.ts +188 -0
  566. package/src/cli/Cli.ts +280 -12
  567. package/src/cli/Credentials.test.ts +122 -0
  568. package/src/cli/Credentials.ts +144 -0
  569. package/src/cli/Spec.test.ts +133 -0
  570. package/src/cli/Spec.ts +132 -0
  571. package/src/cli/bin.test.ts +49 -0
  572. package/src/cli/bin.ts +5 -1
  573. package/src/cli/commands/auth.test.ts +138 -0
  574. package/src/cli/commands/auth.ts +254 -0
  575. package/src/cli/commands/keys.test.ts +68 -0
  576. package/src/cli/commands/keys.ts +125 -0
  577. package/src/cloudflare.ts +184 -36
  578. package/src/db/Db.test.ts +877 -0
  579. package/src/db/Db.ts +498 -1
  580. package/src/db/Schema.ts +75 -4
  581. package/src/db/tables/apiKeyAdmissions.test.ts +57 -0
  582. package/src/db/tables/apiKeyAdmissions.ts +101 -11
  583. package/src/db/tables/apiKeyOwnerTombstones.ts +2 -2
  584. package/src/db/tables/authAccounts.test.ts +30 -0
  585. package/src/db/tables/authAccounts.ts +1 -0
  586. package/src/db/tables/earnVaults.test.ts +34 -0
  587. package/src/db/tables/earnVaults.ts +17 -2
  588. package/src/db/tables/organizations.test.ts +148 -84
  589. package/src/db/tables/organizations.ts +11 -43
  590. package/src/db/tables/requestUsage.ts +13 -2
  591. package/src/db/tables/rewardCampaigns.test.ts +163 -0
  592. package/src/db/tables/rewardEligibilityAssociations.test.ts +14 -0
  593. package/src/db/tables/rewardEligibilityAssociations.ts +24 -0
  594. package/src/db/tables/rewardRuns.ts +4 -0
  595. package/src/db/tables/rewardTransactionAttempts.ts +2 -0
  596. package/src/db/tables/routesDepositAddresses.test.ts +263 -0
  597. package/src/db/tables/routesDepositAddresses.ts +118 -34
  598. package/src/db/tables/routesDeposits.test.ts +66 -5
  599. package/src/db/tables/routesDeposits.ts +47 -26
  600. package/src/db/tables/routesIdempotency.test.ts +80 -0
  601. package/src/db/tables/routesIdempotency.ts +2 -0
  602. package/src/db/tables/routesPolicies.test.ts +143 -0
  603. package/src/db/tables/routesPolicies.ts +251 -0
  604. package/src/db/tables/routesTransferSubsidies.ts +64 -0
  605. package/src/db/tables/routesTransferSubsidyNonces.ts +16 -4
  606. package/src/db/tables/routesTransfers.test.ts +183 -2
  607. package/src/db/tables/routesTransfers.ts +65 -6
  608. package/src/db/tables/sponsoredTransactions.test.ts +351 -76
  609. package/src/db/tables/sponsoredTransactions.ts +182 -38
  610. package/src/db/tables/users.test.ts +51 -0
  611. package/src/db/tables/users.ts +12 -0
  612. package/src/handlers/internal/multisig.store.test.ts +120 -0
  613. package/src/handlers/internal/multisig.test.ts +389 -0
  614. package/src/handlers/internal/multisig.ts +13 -10
  615. package/src/handlers/relay.test.ts +259 -83
  616. package/src/handlers/relay.ts +36 -17
  617. package/src/internal/Auth.test.ts +291 -8
  618. package/src/internal/Auth.ts +227 -96
  619. package/src/internal/BetterAuth.test.ts +58 -22
  620. package/src/internal/BetterAuth.ts +23 -17
  621. package/src/internal/Cache.ts +3 -1
  622. package/src/internal/CliAuth.test.ts +279 -0
  623. package/src/internal/CliAuth.ts +319 -0
  624. package/src/internal/EarnSharePrices.test.ts +25 -0
  625. package/src/internal/EarnSharePrices.ts +9 -2
  626. package/src/internal/EarnVaults.test.ts +67 -0
  627. package/src/internal/EarnVaults.ts +299 -4
  628. package/src/internal/EarnWithdrawals.test.ts +315 -0
  629. package/src/internal/EarnWithdrawals.ts +266 -0
  630. package/src/internal/ExecutionContext.ts +31 -0
  631. package/src/internal/Log.test.ts +210 -0
  632. package/src/internal/Log.ts +180 -142
  633. package/src/internal/MetricSink.test.ts +190 -15
  634. package/src/internal/MetricSink.ts +27 -1
  635. package/src/internal/RateLimit.test.ts +144 -8
  636. package/src/internal/RateLimit.ts +254 -26
  637. package/src/internal/Store.ts +4 -5
  638. package/src/internal/Timing.test.ts +32 -0
  639. package/src/internal/Timing.ts +20 -1
  640. package/src/internal/Tron.test-d.ts +22 -0
  641. package/src/internal/Tron.test.ts +94 -0
  642. package/src/internal/Tron.ts +289 -0
  643. package/src/internal/Viem.rpc.test.ts +76 -0
  644. package/src/internal/Viem.ts +29 -6
  645. package/src/internal/rewards/Read.test.ts +109 -0
  646. package/src/internal/rewards/Read.ts +13 -4
  647. package/src/internal/routes/Action.test.ts +70 -0
  648. package/src/internal/routes/Action.ts +76 -1
  649. package/src/internal/routes/Chain.test.ts +18 -0
  650. package/src/internal/routes/Chain.ts +5 -0
  651. package/src/internal/routes/DepositAddress.ts +5 -0
  652. package/src/internal/routes/Evidence.test.ts +64 -0
  653. package/src/internal/routes/Evidence.ts +11 -3
  654. package/src/internal/routes/EvmTransferSettlement.ts +213 -0
  655. package/src/internal/routes/Policy.test.ts +316 -0
  656. package/src/internal/routes/Policy.ts +399 -0
  657. package/src/internal/routes/Provider.test.ts +103 -2
  658. package/src/internal/routes/Provider.ts +149 -27
  659. package/src/internal/routes/Quota.test.ts +149 -0
  660. package/src/internal/routes/Quota.ts +226 -0
  661. package/src/internal/routes/Reconciliation.local.test.ts +285 -0
  662. package/src/internal/routes/Reconciliation.test.ts +371 -13
  663. package/src/internal/routes/Reconciliation.ts +193 -42
  664. package/src/internal/routes/SolanaTransferSettlement.ts +232 -0
  665. package/src/internal/routes/SolanaTransferSubsidy.test.ts +471 -0
  666. package/src/internal/routes/SolanaTransferSubsidy.ts +760 -0
  667. package/src/internal/routes/SourceObservation.test.ts +221 -0
  668. package/src/internal/routes/Subsidy.local.test.ts +46 -0
  669. package/src/internal/routes/Subsidy.ts +4 -2
  670. package/src/internal/routes/Transfer.solana.test.ts +389 -0
  671. package/src/internal/routes/Transfer.test.ts +130 -1
  672. package/src/internal/routes/Transfer.tron.test.ts +172 -0
  673. package/src/internal/routes/Transfer.ts +866 -8
  674. package/src/internal/routes/TransferReconciliation.test.ts +26 -4
  675. package/src/internal/routes/TransferReconciliation.ts +91 -166
  676. package/src/internal/routes/TransferSettlement.ts +48 -0
  677. package/src/internal/routes/TransferSubsidy.local.test.ts +143 -0
  678. package/src/internal/routes/TransferSubsidy.test.ts +34 -4
  679. package/src/internal/routes/TransferSubsidy.ts +87 -12
  680. package/src/internal/routes/TronTransferSettlement.ts +212 -0
  681. package/src/internal/routes/TronTransferSubsidy.test.ts +109 -0
  682. package/src/internal/routes/TronTransferSubsidy.ts +619 -0
  683. package/src/internal/routes/index.test.ts +3 -0
  684. package/src/internal/routes/index.ts +3 -0
  685. package/src/internal/routes/providers/across.ts +13 -0
  686. package/src/internal/routes/providers/index.test.ts +141 -0
  687. package/src/internal/routes/providers/legacyMesh.test.ts +484 -0
  688. package/src/internal/routes/providers/legacyMesh.ts +633 -0
  689. package/src/internal/routes/providers/legacyMeshDelivery.test.ts +306 -0
  690. package/src/internal/routes/providers/legacyMeshDelivery.ts +320 -0
  691. package/src/internal/routes/providers/legacyMeshOutbound.test.ts +401 -0
  692. package/src/internal/routes/providers/legacyMeshOutbound.ts +566 -0
  693. package/src/internal/routes/providers/legacyMeshOutboundDelivery.ts +473 -0
  694. package/src/internal/routes/providers/propAmm.ts +640 -0
  695. package/src/internal/routes/providers/relay.test.ts +1263 -41
  696. package/src/internal/routes/providers/relay.ts +423 -38
  697. package/src/internal/routes/providers/rhino.ts +14 -1
  698. package/src/internal/routes/providers/squid.ts +21 -0
  699. package/src/internal/routes/providers/stargate.test.ts +105 -1
  700. package/src/internal/routes/providers/stargate.ts +22 -9
  701. package/src/internal/routes/providers/symbiosis.ts +13 -47
  702. package/src/providers/index.test.ts +2 -0
  703. package/src/providers/index.ts +18 -0
  704. package/dist/admin/Access.d.ts +0 -39
  705. package/dist/admin/Access.d.ts.map +0 -1
  706. package/dist/admin/Access.js +0 -73
  707. package/dist/admin/Access.js.map +0 -1
  708. package/src/admin/Access.test.ts +0 -130
  709. package/src/admin/Access.ts +0 -85
@@ -53,7 +53,9 @@ export async function finalize(db: Db.Db, options: finalize.Options): Promise<fi
53
53
  // here only the TTL can settle them.
54
54
  if (row.transactionHash === null) {
55
55
  if (Date.parse(row.createdAt) + pendingTtlMs <= now().getTime()) {
56
- await SponsoredTransactions.fail(db, row.id, now().toISOString())
56
+ await SponsoredTransactions.fail(db, row.id, now().toISOString(), {
57
+ transactionHash: row.transactionHash,
58
+ })
57
59
  result.failed++
58
60
  } else result.pending++
59
61
  continue
@@ -70,7 +72,9 @@ export async function finalize(db: Db.Db, options: finalize.Options): Promise<fi
70
72
  else {
71
73
  result.errors++
72
74
  if (Date.parse(row.createdAt) + receiptErrorTtlMs <= now().getTime()) {
73
- await SponsoredTransactions.fail(db, row.id, now().toISOString())
75
+ await SponsoredTransactions.fail(db, row.id, now().toISOString(), {
76
+ transactionHash: row.transactionHash,
77
+ })
74
78
  result.failed++
75
79
  } else result.pending++
76
80
  continue
@@ -83,10 +87,13 @@ export async function finalize(db: Db.Db, options: finalize.Options): Promise<fi
83
87
  await SponsoredTransactions.finalize(db, row.id, {
84
88
  feeAmount: feeAmount.toString(),
85
89
  finalizedAt: now().toISOString(),
90
+ transactionHash: row.transactionHash,
86
91
  })
87
92
  result.finalized++
88
93
  } else if (Date.parse(row.createdAt) + pendingTtlMs <= now().getTime()) {
89
- await SponsoredTransactions.fail(db, row.id, now().toISOString())
94
+ await SponsoredTransactions.fail(db, row.id, now().toISOString(), {
95
+ transactionHash: row.transactionHash,
96
+ })
90
97
  result.failed++
91
98
  } else result.pending++
92
99
  }
@@ -123,11 +130,9 @@ export declare namespace finalize {
123
130
  }
124
131
 
125
132
  /**
126
- * Runs one reconciliation pass over pending fill intents (rows with no
127
- * transaction hash): fetches the fee payer's recent on-chain transactions
128
- * from TIDX, recomputes each candidate's fee-payer sign payload, and fills
129
- * matching intents' hashes so the receipt pass can finalize them. Query or
130
- * candidate errors leave intents for the next pass.
133
+ * Reconciles pending fill intents and recently failed sponsorships against
134
+ * on-chain fee-payer sign payloads. Matches update their transaction hashes;
135
+ * errors leave sponsorships for the next pass.
131
136
  *
132
137
  * @param db - The database holding `sponsored_transactions`.
133
138
  * @param options - Reconciliation options.
@@ -147,74 +152,80 @@ export async function reconcile(db: Db.Db, options: reconcile.Options): Promise<
147
152
  const failedSince = new Date(Date.now() - failedIntentTtlMs).toISOString()
148
153
  // Old failed intents must not move the active scan behind its candidate cap.
149
154
  const [intents, recoveryWindows] = await Promise.all([
150
- SponsoredTransactions.listIntents(db, { limit: batchSize }),
155
+ SponsoredTransactions.listReconciliationCandidates(db, { limit: batchSize }),
151
156
  SponsoredTransactions.listRecoveryWindows(db, { failedSince }),
152
157
  ])
153
158
  const result = { errors: 0, matched: 0, scanned: 0 }
154
159
  if (intents.length === 0 && recoveryWindows.length === 0) return result
155
160
 
156
- const groups = new Map<number, SponsoredTransactions.Record[]>()
157
- for (const intent of intents)
158
- groups.set(intent.chainId, [...(groups.get(intent.chainId) ?? []), intent])
161
+ const groups = [
162
+ new Map<number, SponsoredTransactions.Record[]>(),
163
+ new Map<number, SponsoredTransactions.Record[]>(),
164
+ ]
165
+ for (const intent of intents) {
166
+ const group = groups[intent.transactionHash === null ? 0 : 1]!
167
+ group.set(intent.chainId, [...(group.get(intent.chainId) ?? []), intent])
168
+ }
159
169
 
160
- for (const [chainId, rows] of groups) {
161
- if (candidateCap <= 0) continue
162
- const bySignPayload = new Map(rows.map((row) => [row.signPayload, row]))
163
- const since = formatTidxTimestamp(
164
- Math.min(...rows.map((row) => Date.parse(row.createdAt))) - skewMs,
165
- )
170
+ for (const group of groups)
171
+ for (const [chainId, rows] of group) {
172
+ if (candidateCap <= 0) continue
173
+ const bySignPayload = new Map(rows.map((row) => [row.signPayload, row]))
174
+ const since = formatTidxTimestamp(
175
+ Math.min(...rows.map((row) => Date.parse(row.createdAt))) - skewMs,
176
+ )
166
177
 
167
- let candidates: readonly globalThis.Record<string, unknown>[]
168
- try {
169
- // Dynamic filter values; the tidx client's query type wants literals.
170
- const fetched = await getTidx(chainId).fetch({
171
- chainId,
172
- query:
173
- `SELECT hash, "from" FROM txs WHERE fee_payer = '${feePayer.toLowerCase()}' AND block_timestamp >= '${since}' ORDER BY block_timestamp ASC LIMIT ${candidateCap}` as string,
174
- })
175
- candidates = fetched.rows
176
- } catch {
177
- // Indexer outage must not fail intents; retry on the next pass.
178
- result.errors++
179
- continue
180
- }
181
-
182
- for (const candidate of candidates) {
183
- if (bySignPayload.size === 0) break
184
- const hash = candidate['hash'] as Hex.Hex | undefined
185
- const sender = candidate['from'] as Address | undefined
186
- if (!hash || !sender) continue
187
- result.scanned++
178
+ let candidates: readonly globalThis.Record<string, unknown>[]
188
179
  try {
189
- const serialized = await getRawTransaction(getClient(chainId), hash)
190
- if (!serialized) {
191
- result.errors++
192
- continue
180
+ // Dynamic filter values; the tidx client's query type wants literals.
181
+ const fetched = await getTidx(chainId).fetch({
182
+ chainId,
183
+ query:
184
+ `SELECT hash, "from" FROM txs WHERE fee_payer = '${feePayer.toLowerCase()}' AND block_timestamp >= '${since}' ORDER BY block_timestamp ASC LIMIT ${candidateCap}` as string,
185
+ })
186
+ candidates = fetched.rows
187
+ } catch {
188
+ // Indexer outage must not fail sponsorships; retry on the next pass.
189
+ result.errors++
190
+ continue
191
+ }
192
+
193
+ for (const candidate of candidates) {
194
+ if (bySignPayload.size === 0) break
195
+ const hash = candidate['hash'] as Hex.Hex | undefined
196
+ const sender = candidate['from'] as Address | undefined
197
+ if (!hash || !sender) continue
198
+ result.scanned++
199
+ try {
200
+ const serialized = await getRawTransaction(getClient(chainId), hash)
201
+ if (!serialized) {
202
+ result.errors++
203
+ continue
204
+ }
205
+ if (!serialized.startsWith(TxEnvelopeTempo.serializedType)) continue
206
+ const signPayload = TxEnvelopeTempo.getFeePayerSignPayload(
207
+ TxEnvelopeTempo.deserialize(serialized as TxEnvelopeTempo.Serialized),
208
+ { sender },
209
+ )
210
+ const intent = bySignPayload.get(signPayload)
211
+ if (!intent) continue
212
+ await SponsoredTransactions.assignTransactionHash(
213
+ db,
214
+ intent.id,
215
+ hash,
216
+ await options.limitFor?.(intent),
217
+ )
218
+ bySignPayload.delete(signPayload)
219
+ result.matched++
220
+ } catch (error) {
221
+ // Spend-limit enforcement is an expected policy refusal; dependency,
222
+ // lookup, and malformed-envelope failures remain operational errors.
223
+ if (!(error instanceof SponsoredTransactions.PeriodSpendLimitError)) result.errors++
193
224
  }
194
- if (!serialized.startsWith(TxEnvelopeTempo.serializedType)) continue
195
- const signPayload = TxEnvelopeTempo.getFeePayerSignPayload(
196
- TxEnvelopeTempo.deserialize(serialized as TxEnvelopeTempo.Serialized),
197
- { sender },
198
- )
199
- const intent = bySignPayload.get(signPayload)
200
- if (!intent) continue
201
- await SponsoredTransactions.assignTransactionHash(
202
- db,
203
- intent.id,
204
- hash,
205
- await options.limitFor?.(intent),
206
- )
207
- bySignPayload.delete(signPayload)
208
- result.matched++
209
- } catch (error) {
210
- // Spend-limit enforcement is an expected policy refusal; dependency,
211
- // lookup, and malformed-envelope failures remain operational errors.
212
- if (!(error instanceof SponsoredTransactions.PeriodSpendLimitError)) result.errors++
213
225
  }
226
+ // A truncated active scan cannot prove that the remaining sponsorships were never mined.
227
+ if (candidates.length === candidateCap && bySignPayload.size > 0) result.errors++
214
228
  }
215
- // A truncated active scan cannot prove that the remaining intents were never mined.
216
- if (candidates.length === candidateCap && bySignPayload.size > 0) result.errors++
217
- }
218
229
 
219
230
  const feePayer_lower = feePayer.toLowerCase() as Address
220
231
  for (const window of recoveryWindows) {
@@ -353,7 +364,7 @@ export async function reconcile(db: Db.Db, options: reconcile.Options): Promise<
353
364
  export declare namespace reconcile {
354
365
  /** Options for {@link reconcile}. */
355
366
  type Options = {
356
- /** Maximum active intents considered per pass. @default 100 */
367
+ /** Maximum pending sponsorships per transaction-hash state considered per pass. @default 100 */
357
368
  batchSize?: number | undefined
358
369
  /** Maximum candidates per chain in each active or recovery scan. @default 500 */
359
370
  candidateCap?: number | undefined
@@ -0,0 +1,319 @@
1
+ import * as TestApp from '../../../test/App.js'
2
+ import * as TestRoutes from '../../../test/Routes.js'
3
+ import * as ApiKeys from '../../ApiKeys.js'
4
+ import * as Organizations from '../../db/tables/organizations.js'
5
+ import * as Projects from '../../db/tables/projects.js'
6
+ import * as RoutesPolicies from '../../db/tables/routesPolicies.js'
7
+ import * as StripeCustomers from '../../db/tables/stripeCustomers.js'
8
+ import * as Auth from '../../internal/Auth.js'
9
+ import * as OpenApi from '../../internal/OpenApi.js'
10
+ import * as Store from '../../internal/Store.js'
11
+ import * as Policy from '../../internal/routes/Policy.js'
12
+ import * as Relay from '../../internal/routes/providers/relay.js'
13
+ import * as Access from './Access.js'
14
+
15
+ const route = {
16
+ sourceChainId: 'eip155:8453',
17
+ sourceTokenId: 'USDC',
18
+ destinationChainId: 'eip155:4217',
19
+ destinationTokenId: 'USDC.e',
20
+ providerId: 'relay',
21
+ } satisfies Policy.Rule
22
+
23
+ describe('filterCatalog', () => {
24
+ test('allows a per-route enable through a disabled legacy gate', () => {
25
+ const catalogRoute = TestRoutes.snapshot.routes.find((item) => item.providerId === 'relay')!
26
+ const input = context({ terms: [{ ...Policy.fromRoute(catalogRoute), subsidyEnabled: true }] })
27
+ input.layers[0] = { access: null, subsidyRoutes: null }
28
+ const filtered = Access.filterCatalog(TestRoutes.snapshot, input, true)
29
+
30
+ expect(filtered.routes.map((item) => item.providerId)).toContain('relay')
31
+ })
32
+
33
+ test('keeps the legacy not-enabled error when no catalog route is enabled', () => {
34
+ const input = context({ subsidyEnabled: false })
35
+ expect(() => Access.filterCatalog(TestRoutes.snapshot, input, true)).toThrowError(
36
+ expect.objectContaining({
37
+ code: 'routes_subsidy_not_enabled',
38
+ message:
39
+ 'Route subsidies are not enabled for this request. Contact Tempo to enable them, or use an API key from an organization with subsidies enabled.',
40
+ }),
41
+ )
42
+ })
43
+ })
44
+
45
+ describe('commitment', () => {
46
+ test('allows Tempo-paid production without customer billing and clamps the expense cap', async () => {
47
+ const db = TestApp.database()
48
+ const result = await Access.commitment(
49
+ db,
50
+ context({ subsidyPayer: 'tempo', maxAmount: '12.345678' }),
51
+ route,
52
+ '10.25',
53
+ )
54
+
55
+ expect(result).toEqual({
56
+ maxAmount: '10.25',
57
+ scope: { apiKeyId: 'key_policy', environment: 'production', orgId: 'org_policy' },
58
+ subsidyPayer: 'tempo',
59
+ versions: [1, 2],
60
+ })
61
+ })
62
+
63
+ test('pins inherited terms for a route enabled over legacy false', async () => {
64
+ const input = context({
65
+ terms: [{ ...route, subsidyEnabled: true, subsidyPayer: 'tempo', maxAmount: '3' }],
66
+ })
67
+ input.layers[0] = { access: null, subsidyRoutes: null }
68
+
69
+ await expect(Access.commitment(TestApp.database(), input, route, '9')).resolves.toMatchObject({
70
+ maxAmount: '3',
71
+ subsidyPayer: 'tempo',
72
+ versions: [1, 2],
73
+ })
74
+ })
75
+
76
+ test('requires active billing for enterprise-paid production', async () => {
77
+ const db = TestApp.database()
78
+ await Organizations.create(db, { id: 'org_policy', name: 'Policy' })
79
+ const input = context({ subsidyPayer: 'enterprise', maxAmount: '5' })
80
+
81
+ await expect(Access.commitment(db, input, route, '9')).rejects.toMatchObject({
82
+ code: 'billing_required',
83
+ })
84
+ await StripeCustomers.create(db, { orgId: 'org_policy', stripeCustomerId: 'cus_policy' })
85
+ await StripeCustomers.setStatus(db, 'org_policy', 'active')
86
+ await expect(Access.commitment(db, input, route, '9')).resolves.toMatchObject({
87
+ maxAmount: '5',
88
+ subsidyPayer: 'enterprise',
89
+ })
90
+ })
91
+
92
+ test.each<[string, Policy.Overrides, Access.PolicyError['code']]>([
93
+ ['inaccessible', { access: [] }, 'routes_not_allowed'],
94
+ ['suspended', {}, 'routes_suspended'],
95
+ ['ineligible', { terms: [{ ...route, subsidyEligible: false }] }, 'routes_subsidy_not_allowed'],
96
+ ['globally disabled', { subsidyEnabled: false }, 'routes_subsidy_not_enabled'],
97
+ ])('rejects an %s route before creating a commitment', async (_name, policy, code) => {
98
+ const input = context(policy)
99
+ if (_name === 'suspended') input.layers[0] = { ...input.layers[0], suspended: true }
100
+ await expect(Access.commitment(TestApp.database(), input, route, '9')).rejects.toMatchObject({
101
+ code,
102
+ })
103
+ })
104
+ })
105
+
106
+ describe('assertPolicy', () => {
107
+ test.each(['organization', 'project'] as const)(
108
+ 'rejects inherited-policy acceptance after %s reassignment without a key override',
109
+ async (kind) => {
110
+ const db = TestApp.database()
111
+ const state = Store.memory()
112
+ const org = await Organizations.create(db, { name: 'Original owner' })
113
+ const project =
114
+ kind === 'project'
115
+ ? await Projects.create(db, { orgId: org.id, name: 'Original project' })
116
+ : undefined
117
+ const parent = {
118
+ environment: 'production',
119
+ orgId: org.id,
120
+ ...(project ? { projectId: project.id } : {}),
121
+ } as const
122
+ await RoutesPolicies.save(db, {
123
+ scope: parent,
124
+ version: 0,
125
+ policy: { access: null, subsidyEnabled: true, subsidyPayer: 'tempo', maxAmount: '1' },
126
+ })
127
+ const { record } = await ApiKeys.mintBounded(db, state, {
128
+ ...parent,
129
+ scopes: ['routes:write'],
130
+ })
131
+ const scope = { ...parent, apiKeyId: record.id }
132
+ const loaded = await RoutesPolicies.load(db, scope)
133
+ const pending = {
134
+ scope,
135
+ layers: loaded.layers.map((layer) => layer.policy),
136
+ legacy: loaded.legacy,
137
+ versions: loaded.layers.map((layer) => layer.version),
138
+ }
139
+ expect(await RoutesPolicies.get(db, scope)).toBeUndefined()
140
+ await expect(
141
+ db.transaction((tx) => Access.assertPolicy(tx, pending)),
142
+ ).resolves.toBeUndefined()
143
+
144
+ const destination =
145
+ kind === 'organization'
146
+ ? { orgId: (await Organizations.create(db, { name: 'New owner' })).id }
147
+ : { projectId: (await Projects.create(db, { orgId: org.id, name: 'New project' })).id }
148
+ const moved = await ApiKeys.updateBounded(db, state, record.id, destination)
149
+ expect(moved).toMatchObject({ ...destination, scopes: ['routes:write'] })
150
+ // No explicit key policy existed, so clearing it cannot invalidate these versions.
151
+ expect(await RoutesPolicies.load(db, scope)).toEqual(loaded)
152
+ await expect(db.transaction((tx) => Access.assertPolicy(tx, pending))).rejects.toMatchObject({
153
+ code: 'route_policy_changed',
154
+ })
155
+ },
156
+ )
157
+
158
+ test.each([
159
+ ['revision', { maxAmount: '2' }],
160
+ ['suspension', { maxAmount: '1', suspended: true }],
161
+ ] as const)(
162
+ 'detects a concurrent %s after taking the organization lock',
163
+ async (_name, policy) => {
164
+ const db = TestApp.database()
165
+ await Organizations.create(db, { id: 'org_assert', name: 'Assert' })
166
+ const scope = {
167
+ ...(_name === 'revision' ? { apiKeyId: 'key_assert' } : {}),
168
+ environment: 'production',
169
+ orgId: 'org_assert',
170
+ } as const
171
+ await RoutesPolicies.save(db, {
172
+ policy: { maxAmount: '1' },
173
+ scope,
174
+ version: 0,
175
+ })
176
+ const loaded = await RoutesPolicies.load(db, scope)
177
+ const stale = {
178
+ scope,
179
+ layers: loaded.layers.map((layer) => layer.policy),
180
+ legacy: loaded.legacy,
181
+ versions: loaded.layers.map((layer) => layer.version),
182
+ }
183
+ await RoutesPolicies.save(db, { policy, scope, version: 1 })
184
+
185
+ await expect(db.transaction((tx) => Access.assertPolicy(tx, stale))).rejects.toMatchObject({
186
+ code: 'route_policy_changed',
187
+ })
188
+ },
189
+ )
190
+ })
191
+
192
+ describe('loadPolicy', () => {
193
+ test('keeps missing organization policies in legacy mode until the first environment-specific save', async () => {
194
+ const db = TestApp.database()
195
+ const org = await Organizations.create(db, { name: 'Legacy policies' })
196
+ const keys = (['production', 'sandbox'] as const).map((environment) => ({
197
+ id: `key_legacy_${environment}`,
198
+ orgId: org.id,
199
+ environment,
200
+ token: `secret_legacy_${environment}`,
201
+ scopes: ['routes:read'],
202
+ }))
203
+ const app = TestApp.create({ db, auth: { keys } }).get(
204
+ '/policy',
205
+ Auth.policy({ apiKey: { scopes: ['routes:read'] } }),
206
+ OpenApi.describeRoute({ hide: true }),
207
+ async (c) => {
208
+ const loaded = (await Access.loadPolicy(c))!
209
+ return c.json({
210
+ access: Policy.resolve(loaded).access,
211
+ legacy: Access.isLegacy(loaded),
212
+ routes: Access.filterCatalog(TestRoutes.snapshot, loaded, false).routes.length,
213
+ })
214
+ },
215
+ )
216
+ const read = async (index: number) =>
217
+ (
218
+ await app.request('/policy', {
219
+ headers: { authorization: `Bearer ${keys[index]!.token}` },
220
+ })
221
+ ).json()
222
+ expect(await read(0)).toEqual({
223
+ access: null,
224
+ legacy: true,
225
+ routes: TestRoutes.snapshot.routes.length,
226
+ })
227
+ // A child can explicitly narrow legacy access without changing another key/environment.
228
+ await RoutesPolicies.save(db, {
229
+ scope: { orgId: org.id, environment: 'production', apiKeyId: keys[0]!.id },
230
+ policy: { access: [] },
231
+ version: 0,
232
+ })
233
+ expect(await read(0)).toEqual({ access: [], legacy: false, routes: 0 })
234
+ expect(await read(1)).toEqual({
235
+ access: null,
236
+ legacy: true,
237
+ routes: TestRoutes.snapshot.routes.length,
238
+ })
239
+ await RoutesPolicies.save(db, {
240
+ scope: { orgId: org.id, environment: 'sandbox' },
241
+ policy: {},
242
+ version: 0,
243
+ })
244
+ expect(await read(1)).toEqual({ access: [], legacy: false, routes: 0 })
245
+ })
246
+
247
+ test('enforces key access and organization suspension through composed creation and quote routes', async () => {
248
+ const db = TestApp.database()
249
+ const key = {
250
+ id: 'key_runtime_policy',
251
+ orgId: 'org_runtime_policy',
252
+ token: 'secret_runtime_policy',
253
+ scopes: ['routes:write', 'data:read'],
254
+ }
255
+ const scope = { apiKeyId: key.id, orgId: key.orgId, environment: 'production' } as const
256
+ await Organizations.create(db, { id: key.orgId, name: 'Policy runtime' })
257
+ await TestRoutes.publish(db)
258
+ const app = TestApp.create({
259
+ db,
260
+ defaultChainId: 4217,
261
+ auth: { keys: [key] },
262
+ providers: [Relay.relay()],
263
+ })
264
+ const headers = {
265
+ 'Tempo-API-Key': key.token,
266
+ 'Content-Type': 'application/json',
267
+ 'Idempotency-Key': 'policy-request',
268
+ }
269
+ const body = {
270
+ amount: '1000000',
271
+ sourceChain: 'eip155:8453',
272
+ sourceToken: 'usdc',
273
+ destinationToken: 'usdce',
274
+ recipient: `0x${'11'.repeat(20)}`,
275
+ }
276
+ await RoutesPolicies.save(db, { scope, version: 0, policy: { access: [] } })
277
+ const quote = await app.request(
278
+ '/v1/routes/quotes?sourceChain=base&sourceToken=usdc&destinationToken=usdce&sourceAmount=1000000',
279
+ { headers },
280
+ )
281
+ expect({ status: quote.status, body: await quote.json() }).toMatchObject({
282
+ status: 400,
283
+ body: { error: { code: 'route_unavailable' } },
284
+ })
285
+ const denied = await app.request('/v1/routes/deposit-addresses', {
286
+ method: 'POST',
287
+ headers,
288
+ body: JSON.stringify({ ...body, refundAddress: `0x${'22'.repeat(20)}` }),
289
+ })
290
+ expect({ status: denied.status, body: await denied.json() }).toMatchObject({
291
+ status: 403,
292
+ body: { error: { code: 'routes_not_allowed' } },
293
+ })
294
+ await RoutesPolicies.save(db, {
295
+ scope: { orgId: key.orgId, environment: 'production' },
296
+ version: 0,
297
+ policy: { suspended: true },
298
+ })
299
+ await RoutesPolicies.save(db, { scope, version: 1, policy: { access: null } })
300
+ const suspended = await app.request('/v1/routes/transfers', {
301
+ method: 'POST',
302
+ headers,
303
+ body: JSON.stringify({ ...body, mode: 'exactSource', sender: `0x${'22'.repeat(20)}` }),
304
+ })
305
+ expect({ status: suspended.status, body: await suspended.json() }).toMatchObject({
306
+ status: 403,
307
+ body: { error: { code: 'routes_suspended' } },
308
+ })
309
+ })
310
+ })
311
+
312
+ function context(keyPolicy: Policy.Overrides): Access.PolicyContext {
313
+ return {
314
+ scope: { apiKeyId: 'key_policy', environment: 'production', orgId: 'org_policy' },
315
+ layers: [{ access: null, subsidyEnabled: true, subsidyRoutes: null }, keyPolicy],
316
+ legacy: { subsidyEnabled: false, maxAmount: '0', subsidyPayer: 'enterprise' },
317
+ versions: [1, 2],
318
+ }
319
+ }
@@ -1,9 +1,17 @@
1
1
  import type { Context } from 'hono'
2
+ import { Value } from 'ox'
2
3
 
3
4
  import type * as App from '../../App.js'
5
+ import * as Db from '../../db/Db.js'
6
+ import * as ApiKeyAdmissions from '../../db/tables/apiKeyAdmissions.js'
7
+ import * as RoutesPolicies from '../../db/tables/routesPolicies.js'
8
+ import * as RoutesSubsidies from '../../db/tables/routesSubsidies.js'
9
+ import * as StripeCustomers from '../../db/tables/stripeCustomers.js'
4
10
  import type * as RoutesTransfers from '../../db/tables/routesTransfers.js'
5
11
  import * as Auth from '../../internal/Auth.js'
6
12
  import * as Response from '../../internal/Response.js'
13
+ import * as Policy from '../../internal/routes/Policy.js'
14
+ import type * as Catalog from '../../internal/routes/Catalog.js'
7
15
 
8
16
  /** Returns the routes owner encoded by an API-key principal. */
9
17
  export function owner(c: Context<App.Environment>): RoutesTransfers.Owner | null {
@@ -24,3 +32,142 @@ export function unauthorized(c: Context<App.Environment>) {
24
32
  status: 401,
25
33
  })
26
34
  }
35
+
36
+ /** Request-local authoritative policy context. Public quotes have no context. */
37
+ export type PolicyContext = {
38
+ scope: Policy.Scope
39
+ layers: Policy.Overrides[]
40
+ legacy: Policy.Legacy
41
+ defaultAccess?: null
42
+ versions: number[]
43
+ }
44
+
45
+ /** Reads grants from the primary database, never the API-key KV/cache. */
46
+ export async function loadPolicy(c: Context<App.Environment>): Promise<PolicyContext | undefined> {
47
+ const principal = Auth.getPrincipal(c)
48
+ if (principal?.type !== 'api_key') return undefined
49
+ const scope: Policy.Scope = {
50
+ apiKeyId: principal.id,
51
+ environment: principal.environment,
52
+ orgId: principal.orgId,
53
+ ...(principal.projectId === undefined ? {} : { projectId: principal.projectId }),
54
+ }
55
+ const loaded = await RoutesPolicies.load(Db.get(c.get('db')), scope)
56
+ return {
57
+ scope,
58
+ ...(loaded.layers[0]?.version === 0 ? { defaultAccess: null } : {}),
59
+ layers: loaded.layers.map((layer) => layer.policy),
60
+ legacy: loaded.legacy,
61
+ versions: loaded.layers.map((layer) => layer.version),
62
+ }
63
+ }
64
+
65
+ /** No saved policy in this scope chain: retain the original subsidy/provisioning contract. */
66
+ export function isLegacy(context: PolicyContext): boolean {
67
+ return context.versions.every((version) => version === 0)
68
+ }
69
+
70
+ /** Applies independent access and subsidy gates before provider selection. */
71
+ export function filterCatalog(
72
+ catalog: Catalog.Snapshot,
73
+ context: PolicyContext,
74
+ subsidize: boolean,
75
+ ): Catalog.Snapshot {
76
+ if (isLegacy(context)) return catalog
77
+ const effective = Policy.resolve(context)
78
+ if (effective.suspended) throw new PolicyError('routes_suspended')
79
+ if (
80
+ subsidize &&
81
+ !catalog.routes.some(
82
+ (route) => Policy.resolve({ ...context, route: Policy.fromRoute(route) }).subsidyEnabled,
83
+ )
84
+ )
85
+ throw new PolicyError('routes_subsidy_not_enabled')
86
+ return Policy.filter(catalog, { ...context, subsidize })
87
+ }
88
+
89
+ /** Checks financial eligibility and pins a platform-bounded expense ceiling. */
90
+ export async function commitment(
91
+ db: Db.Db,
92
+ context: PolicyContext,
93
+ route: Policy.Rule,
94
+ platformMaxAmount: string,
95
+ ): Promise<Policy.Commitment> {
96
+ const effective = Policy.resolve({ ...context, route })
97
+ if (effective.suspended) throw new PolicyError('routes_suspended')
98
+ if (!Policy.allows(effective.access, route)) throw new PolicyError('routes_not_allowed')
99
+ if (!effective.subsidyEnabled) throw new PolicyError('routes_subsidy_not_enabled')
100
+ if (!effective.subsidyEligible) throw new PolicyError('routes_subsidy_not_allowed')
101
+ if (context.scope.environment === 'production' && effective.subsidyPayer === 'enterprise') {
102
+ const billing = await StripeCustomers.get(db, context.scope.orgId)
103
+ if (billing?.status === 'past_due') throw new PolicyError('billing_past_due')
104
+ if (billing?.status !== 'active') throw new PolicyError('billing_required')
105
+ }
106
+ const limit = Value.from(effective.maxAmount, 6)
107
+ const platformLimit = Value.from(platformMaxAmount, 6)
108
+ return {
109
+ maxAmount: Value.format(limit < platformLimit ? limit : platformLimit, 6),
110
+ scope: context.scope,
111
+ subsidyPayer: effective.subsidyPayer,
112
+ versions: context.versions,
113
+ }
114
+ }
115
+
116
+ /** Serializes acceptance against admin changes; call inside the resource transaction. */
117
+ export async function assertPolicy(db: Db.Db, context: PolicyContext): Promise<void> {
118
+ await RoutesSubsidies.lockOrganization(db, context.scope.orgId)
119
+ // Reassignment takes this organization lock even when no key override exists.
120
+ // Policy versions alone cannot fence requests authenticated under the old owner.
121
+ if (
122
+ context.scope.apiKeyId !== undefined &&
123
+ !(await ApiKeyAdmissions.matches(db, {
124
+ id: context.scope.apiKeyId,
125
+ orgId: context.scope.orgId,
126
+ projectId: context.scope.projectId,
127
+ }))
128
+ )
129
+ throw new PolicyError('route_policy_changed')
130
+ const current = await RoutesPolicies.load(db, context.scope)
131
+ if (
132
+ JSON.stringify(current.layers.map((layer) => layer.version)) !==
133
+ JSON.stringify(context.versions) ||
134
+ JSON.stringify(current.legacy) !== JSON.stringify(context.legacy)
135
+ )
136
+ throw new PolicyError('route_policy_changed')
137
+ }
138
+
139
+ /** Emits a bounded denial metric and a customer-safe response. */
140
+ export function policyError(c: Context<App.Environment>, cause: PolicyError) {
141
+ c.get('metrics')?.count('routes_policy_denial_count', 1, { reason: cause.code })
142
+ if (cause.code === 'route_policy_changed')
143
+ return Response.error(c, {
144
+ code: cause.code,
145
+ message: messages[cause.code],
146
+ status: 409,
147
+ })
148
+ return Response.error(c, {
149
+ code: cause.code,
150
+ message: messages[cause.code],
151
+ status: 403,
152
+ })
153
+ }
154
+
155
+ const messages = {
156
+ billing_past_due: 'Billing past due.',
157
+ billing_required:
158
+ 'Active billing is required for enterprise-paid route subsidies. Set up billing for this organization, then retry.',
159
+ route_policy_changed: 'Route policy changed during creation. Retry the request.',
160
+ routes_not_allowed: 'This route is not permitted by your access policy.',
161
+ routes_subsidy_not_allowed: 'This route is not eligible for the requested subsidy.',
162
+ routes_subsidy_not_enabled:
163
+ 'Route subsidies are not enabled for this request. Contact Tempo to enable them, or use an API key from an organization with subsidies enabled.',
164
+ routes_suspended: 'New route instructions are suspended for this organization and environment.',
165
+ } as const
166
+
167
+ /** A policy denial, distinct from provider unavailability. */
168
+ export class PolicyError extends Error {
169
+ override name = 'Routes.Access.PolicyError'
170
+ constructor(public code: keyof typeof messages) {
171
+ super(messages[code])
172
+ }
173
+ }