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
@@ -1,4 +1,4 @@
1
- import { sql, type JSONColumnType, type Selectable } from 'kysely'
1
+ import { type ExpressionBuilder, type JSONColumnType, type Selectable, sql } from 'kysely'
2
2
 
3
3
  import * as Fees from '../../internal/Fees.js'
4
4
  import type * as Db from '../Db.js'
@@ -810,6 +810,27 @@ export function subsidies(record: Record) {
810
810
  ]
811
811
  }
812
812
 
813
+ function subsidyFinalized(eb: ExpressionBuilder<Db.Database, 'routes_deposits'>) {
814
+ return eb.or([
815
+ eb('status', '=', 'completed'),
816
+ eb.and([
817
+ eb('status', 'in', ['action-required', 'settling']),
818
+ eb('tempoGasPaid', 'is not', null),
819
+ ]),
820
+ // Fixed-rate shortfalls never create a later Tempo top-up, so provider expense is final.
821
+ eb.and([
822
+ eb('status', '=', 'action-required'),
823
+ eb.exists(
824
+ eb
825
+ .selectFrom('routes_deposit_addresses')
826
+ .select('routes_deposit_addresses.id')
827
+ .whereRef('routes_deposit_addresses.id', '=', 'routes_deposits.depositAddressId')
828
+ .where(sql<boolean>`routes_deposit_addresses.provider_state->>'fixedRate' = '1:1'`),
829
+ ),
830
+ ]),
831
+ ])
832
+ }
833
+
813
834
  /** Lists verified production subsidies awaiting a Stripe acknowledgement. */
814
835
  export function listUnreportedSubsidies(
815
836
  db: Db.Db,
@@ -819,15 +840,7 @@ export function listUnreportedSubsidies(
819
840
  .selectFrom('routes_deposits')
820
841
  .selectAll()
821
842
  .where('environment', '=', 'production')
822
- .where((eb) =>
823
- eb.or([
824
- eb('status', '=', 'completed'),
825
- eb.and([
826
- eb('status', 'in', ['action-required', 'settling']),
827
- eb('tempoGasPaid', 'is not', null),
828
- ]),
829
- ]),
830
- )
843
+ .where(subsidyFinalized)
831
844
  .where((eb) =>
832
845
  eb.or([
833
846
  sql<boolean>`(provider_subsidy->'amount'->>'baseUnits')::numeric > 0`,
@@ -839,6 +852,17 @@ export function listUnreportedSubsidies(
839
852
  ]),
840
853
  )
841
854
  .where('subsidyMeterReportedAt', 'is', null)
855
+ .where((eb) =>
856
+ eb.exists(
857
+ eb
858
+ .selectFrom('routes_deposit_addresses')
859
+ .select('routes_deposit_addresses.id')
860
+ .whereRef('routes_deposit_addresses.id', '=', 'routes_deposits.depositAddressId')
861
+ .where(
862
+ sql<boolean>`coalesce(routes_deposit_addresses.provider_state->'routePolicy'->>'subsidyPayer', 'enterprise') <> 'tempo'`,
863
+ ),
864
+ ),
865
+ )
842
866
  .orderBy('statusUpdatedAt', 'asc')
843
867
  .orderBy('id', 'asc')
844
868
  if (options.limit !== undefined) query = query.limit(options.limit)
@@ -878,17 +902,22 @@ export async function hasUnreportedSubsidies(
878
902
  .where('environment', '=', 'production')
879
903
  .where('orgId', '=', options.orgId)
880
904
  .where('status', 'in', ['action-required', 'settling', 'completed'])
905
+ .where((eb) =>
906
+ eb.exists(
907
+ eb
908
+ .selectFrom('routes_deposit_addresses')
909
+ .select('routes_deposit_addresses.id')
910
+ .whereRef('routes_deposit_addresses.id', '=', 'routes_deposits.depositAddressId')
911
+ .where(
912
+ sql<boolean>`coalesce(routes_deposit_addresses.provider_state->'routePolicy'->>'subsidyPayer', 'enterprise') <> 'tempo'`,
913
+ ),
914
+ ),
915
+ )
881
916
  .where((eb) =>
882
917
  eb.or([
883
918
  eb.and([
884
919
  sql<boolean>`(provider_subsidy->'amount'->>'baseUnits')::numeric > 0`,
885
- eb.or([
886
- eb('status', '=', 'completed'),
887
- eb.and([
888
- eb('status', 'in', ['action-required', 'settling']),
889
- eb('tempoGasPaid', 'is not', null),
890
- ]),
891
- ]),
920
+ subsidyFinalized(eb),
892
921
  ]),
893
922
  eb.and([
894
923
  eb('settlementTransactionHash', 'is not', null),
@@ -929,15 +958,7 @@ export async function subsidyUsage(
929
958
  ])
930
959
  .where('orgId', '=', options.orgId)
931
960
  .where('environment', '=', options.environment)
932
- .where((eb) =>
933
- eb.or([
934
- eb('status', '=', 'completed'),
935
- eb.and([
936
- eb('status', 'in', ['action-required', 'settling']),
937
- eb('tempoGasPaid', 'is not', null),
938
- ]),
939
- ]),
940
- )
961
+ .where(subsidyFinalized)
941
962
  .where((eb) =>
942
963
  eb.or([
943
964
  sql<boolean>`(provider_subsidy->'amount'->>'baseUnits')::numeric > 0`,
@@ -317,6 +317,86 @@ describe('claim', () => {
317
317
  ])
318
318
  })
319
319
 
320
+ test('resumes the oldest of several shared provider checkpoints', async () => {
321
+ const claims: RoutesIdempotency.release.Input[] = []
322
+ for (const [index, name] of ['older', 'newer'].entries()) {
323
+ vi.setSystemTime(new Date(now.getTime() + index * 1_000))
324
+ const request = input({
325
+ apiKeyId: `key_${name}`,
326
+ keyHash: `hash_${name}`,
327
+ operation: RoutesIdempotency.operations.depositAddress,
328
+ })
329
+ const claimed = await RoutesIdempotency.claim(db, request)
330
+ if (claimed.type !== 'claimed') throw new Error('Expected a fresh claim.')
331
+ claims.push({ ...request, createdAt: claimed.createdAt })
332
+ }
333
+ const [older, newer] = claims
334
+ if (!older || !newer) throw new Error('Expected two claims.')
335
+ for (const [claimed, response] of [
336
+ [older, '{"requestId":"relay_older"}'],
337
+ [newer, '{"requestId":"relay_newer"}'],
338
+ ] as const)
339
+ await RoutesIdempotency.checkpoint(db, { ...claimed, replayTtlMs, response })
340
+
341
+ await expect(
342
+ RoutesIdempotency.claim(
343
+ db,
344
+ input({
345
+ apiKeyId: 'key_rotated',
346
+ keyHash: 'hash_rotated',
347
+ operation: RoutesIdempotency.operations.depositAddress,
348
+ }),
349
+ ),
350
+ ).resolves.toMatchObject({
351
+ recoveredClaim: { apiKeyId: older.apiKeyId, createdAt: older.createdAt },
352
+ response: '{"requestId":"relay_older"}',
353
+ type: 'resume',
354
+ })
355
+ })
356
+
357
+ test('resumes the oldest of several provisioned match checkpoints', async () => {
358
+ const claims: RoutesIdempotency.release.Input[] = []
359
+ for (const [index, name] of ['older', 'newer', 'retry'].entries()) {
360
+ vi.setSystemTime(new Date(now.getTime() + index * 1_000))
361
+ const request = input({
362
+ apiKeyId: `key_${name}`,
363
+ keyHash: `hash_${name}`,
364
+ operation: RoutesIdempotency.operations.depositAddress,
365
+ requestHash: `req_${name}`,
366
+ })
367
+ const claimed = await RoutesIdempotency.claim(db, request)
368
+ if (claimed.type !== 'claimed') throw new Error('Expected a fresh claim.')
369
+ claims.push({ ...request, createdAt: claimed.createdAt })
370
+ }
371
+ const [older, newer, retry] = claims
372
+ if (!older || !newer || !retry) throw new Error('Expected three claims.')
373
+ const reserve = (claimed: RoutesIdempotency.release.Input) =>
374
+ RoutesIdempotency.reserveDepositAddressMatch(db, {
375
+ ...claimed,
376
+ matchHash: 'match_shared',
377
+ orgId: 'org_test',
378
+ ttlMs,
379
+ })
380
+ await expect(reserve(older)).resolves.toEqual({ type: 'reserved' })
381
+ await RoutesIdempotency.checkpoint(db, {
382
+ ...older,
383
+ replayTtlMs,
384
+ response: '{"requestId":"relay_older"}',
385
+ })
386
+ await expect(reserve(newer)).resolves.toMatchObject({ type: 'resume' })
387
+ await RoutesIdempotency.checkpoint(db, {
388
+ ...newer,
389
+ replayTtlMs,
390
+ response: '{"requestId":"relay_newer"}',
391
+ })
392
+
393
+ await expect(reserve(retry)).resolves.toMatchObject({
394
+ claim: { apiKeyId: older.apiKeyId, createdAt: older.createdAt },
395
+ response: '{"requestId":"relay_older"}',
396
+ type: 'resume',
397
+ })
398
+ })
399
+
320
400
  test('attributes an equivalent rolling-worker checkpoint for the same API key', async () => {
321
401
  const original = input({ operation: RoutesIdempotency.operations.depositAddress })
322
402
  const claimed = await RoutesIdempotency.claim(db, original)
@@ -70,6 +70,7 @@ export async function claim(db: Db.Db, input: claim.Input): Promise<claim.Result
70
70
  .where('status', '=', 'provisioned')
71
71
  .where((eb) => eb.or([eb('expiresAt', '>', now.toISOString()), eb('irrevocable', '=', true)]))
72
72
  .orderBy('createdAt', 'asc')
73
+ .limit(1)
73
74
  .forUpdate()
74
75
  .executeTakeFirst()
75
76
  if (!recoverable) return { createdAt: inserted.createdAt, type: 'claimed' }
@@ -311,6 +312,7 @@ export async function reserveDepositAddressMatch(
311
312
  .where('status', '=', 'provisioned')
312
313
  .where((eb) => eb.or([eb('expiresAt', '>', now.toISOString()), eb('irrevocable', '=', true)]))
313
314
  .orderBy('createdAt', 'asc')
315
+ .limit(1)
314
316
  .forUpdate()
315
317
  .executeTakeFirst()
316
318
  if (provisioned && claimed.status === 'pending') {
@@ -0,0 +1,143 @@
1
+ import * as TestApp from '../../../test/App.js'
2
+ import * as Organizations from './organizations.js'
3
+ import * as RoutesPolicies from './routesPolicies.js'
4
+
5
+ describe('save', () => {
6
+ test('serializes competing version-zero writes as a domain conflict', async () => {
7
+ const db = TestApp.database()
8
+ await Organizations.create(db, { id: 'org_policy', name: 'Policy' })
9
+ const scope = { environment: 'production', orgId: 'org_policy' } as const
10
+ const results = await Promise.allSettled([
11
+ RoutesPolicies.save(db, { policy: { maxAmount: '1' }, scope, version: 0 }),
12
+ RoutesPolicies.save(db, { policy: { maxAmount: '2' }, scope, version: 0 }),
13
+ ])
14
+ expect(
15
+ results
16
+ .map((result) =>
17
+ result.status === 'fulfilled' ? result.value.version : result.reason?.name,
18
+ )
19
+ .sort((a, b) => String(a).localeCompare(String(b))),
20
+ ).toMatchInlineSnapshot(`
21
+ [
22
+ 1,
23
+ "RoutesPolicies.ConflictError",
24
+ ]
25
+ `)
26
+ })
27
+ })
28
+
29
+ describe('load', () => {
30
+ test('preserves missing positional layers', async () => {
31
+ const db = TestApp.database()
32
+ await Organizations.create(db, { id: 'org_layers', name: 'Layers' })
33
+ const loaded = await RoutesPolicies.load(db, {
34
+ apiKeyId: 'key_1',
35
+ environment: 'sandbox',
36
+ orgId: 'org_layers',
37
+ })
38
+ expect(loaded.layers).toMatchInlineSnapshot(`
39
+ [
40
+ {
41
+ "policy": {},
42
+ "scope": {
43
+ "environment": "sandbox",
44
+ "orgId": "org_layers",
45
+ },
46
+ "version": 0,
47
+ },
48
+ {
49
+ "policy": {},
50
+ "scope": {
51
+ "apiKeyId": "key_1",
52
+ "environment": "sandbox",
53
+ "orgId": "org_layers",
54
+ },
55
+ "version": 0,
56
+ },
57
+ ]
58
+ `)
59
+ })
60
+ })
61
+
62
+ describe('clearKey', () => {
63
+ test('clears every matching scope, increments revisions, and ignores an absent key', async () => {
64
+ const db = TestApp.database()
65
+ await Organizations.create(db, { id: 'org_clear', name: 'Clear' })
66
+ for (const environment of ['production', 'sandbox'] as const)
67
+ await RoutesPolicies.save(db, {
68
+ policy: { maxAmount: environment === 'production' ? '1' : '2' },
69
+ scope: { apiKeyId: 'key_clear', environment, orgId: 'org_clear' },
70
+ version: 0,
71
+ })
72
+
73
+ const cleared = await RoutesPolicies.clearKey(db, { apiKeyId: 'key_clear' })
74
+
75
+ expect(cleared.map(({ policy, version }) => ({ policy, version }))).toEqual([
76
+ { policy: {}, version: 2 },
77
+ { policy: {}, version: 2 },
78
+ ])
79
+ await expect(
80
+ RoutesPolicies.save(db, {
81
+ policy: { maxAmount: '3' },
82
+ scope: { apiKeyId: 'key_clear', environment: 'production', orgId: 'org_clear' },
83
+ version: 1,
84
+ }),
85
+ ).rejects.toBeInstanceOf(RoutesPolicies.ConflictError)
86
+ await expect(RoutesPolicies.clearKey(db, { apiKeyId: 'key_missing' })).resolves.toEqual([])
87
+ for (const environment of ['production', 'sandbox'] as const)
88
+ expect(
89
+ await RoutesPolicies.get(db, {
90
+ apiKeyId: 'key_clear',
91
+ environment,
92
+ orgId: 'org_clear',
93
+ }),
94
+ ).toMatchObject({ policy: {}, version: 2 })
95
+ })
96
+ })
97
+
98
+ describe('copyKey', () => {
99
+ test('copies independently, no-ops when absent, rejects cross-scope, and rolls back', async () => {
100
+ const db = TestApp.database()
101
+ await Organizations.create(db, { id: 'org_copy', name: 'Copy' })
102
+ const source = { apiKeyId: 'key_source', environment: 'production', orgId: 'org_copy' } as const
103
+ const destination = { ...source, apiKeyId: 'key_destination' }
104
+ await RoutesPolicies.save(db, {
105
+ policy: { maxAmount: '7' },
106
+ scope: source,
107
+ version: 0,
108
+ })
109
+
110
+ await RoutesPolicies.copyKey(db, { destination, source })
111
+ await RoutesPolicies.save(db, {
112
+ policy: { maxAmount: '9' },
113
+ scope: source,
114
+ version: 1,
115
+ })
116
+ expect((await RoutesPolicies.get(db, destination))?.policy).toEqual({ maxAmount: '7' })
117
+ await expect(
118
+ RoutesPolicies.copyKey(db, {
119
+ destination: { ...destination, apiKeyId: 'key_absent_destination' },
120
+ source: { ...source, apiKeyId: 'key_absent' },
121
+ }),
122
+ ).resolves.toBeUndefined()
123
+ await expect(
124
+ RoutesPolicies.copyKey(db, {
125
+ destination: { ...destination, environment: 'sandbox' },
126
+ source,
127
+ }),
128
+ ).rejects.toThrow(RoutesPolicies.InvalidScopeError)
129
+
130
+ await expect(
131
+ db.transaction(async (tx) => {
132
+ await RoutesPolicies.copyKeyIn(tx, {
133
+ destination: { ...destination, apiKeyId: 'key_rollback' },
134
+ source,
135
+ })
136
+ throw new Error('rollback')
137
+ }),
138
+ ).rejects.toThrow('rollback')
139
+ expect(
140
+ await RoutesPolicies.get(db, { ...destination, apiKeyId: 'key_rollback' }),
141
+ ).toBeUndefined()
142
+ })
143
+ })
@@ -0,0 +1,251 @@
1
+ import { sql, type Selectable } from 'kysely'
2
+
3
+ import type * as Db from '../Db.js'
4
+ import type * as Schema from '../Schema.js'
5
+ import type * as Policy from '../../internal/routes/Policy.js'
6
+ import * as RoutesSubsidies from './routesSubsidies.js'
7
+
8
+ export type Table = Schema.RoutesPolicy
9
+ export type Record = Omit<Selectable<Table>, 'apiKeyId' | 'projectId'> & Policy.Scope
10
+ export type Layer = { scope: Policy.Scope; version: number; policy: Policy.Overrides }
11
+ export class ConflictError extends Error {
12
+ override name = 'RoutesPolicies.ConflictError'
13
+ }
14
+ export class InvalidScopeError extends Error {
15
+ override name = 'RoutesPolicies.InvalidScopeError'
16
+ }
17
+
18
+ export async function get(db: Db.Db, scope: Policy.Scope): Promise<Record | undefined> {
19
+ const row = await scoped(db, scope).selectAll().executeTakeFirst()
20
+ return row && domain(row)
21
+ }
22
+
23
+ export async function load(
24
+ db: Db.Db,
25
+ scope: Policy.Scope,
26
+ ): Promise<{ layers: Layer[]; legacy: Policy.Legacy }> {
27
+ const scopes: Policy.Scope[] = [
28
+ { orgId: scope.orgId, environment: scope.environment },
29
+ ...(scope.projectId
30
+ ? [{ orgId: scope.orgId, environment: scope.environment, projectId: scope.projectId }]
31
+ : []),
32
+ ...(scope.apiKeyId ? [scope] : []),
33
+ ]
34
+ const records = await Promise.all(scopes.map((item) => get(db, item)))
35
+ const legacy = await RoutesSubsidies.getOrganization(db, scope.orgId)
36
+ return {
37
+ layers: records.map((record, index) =>
38
+ record
39
+ ? { scope: pickScope(record), version: record.version, policy: record.policy }
40
+ : { scope: scopes[index]!, version: 0, policy: {} },
41
+ ),
42
+ legacy: {
43
+ subsidyEnabled: legacy?.enabled ?? false,
44
+ maxAmount: legacy?.maxAmount ?? '0',
45
+ subsidyPayer: 'enterprise',
46
+ },
47
+ }
48
+ }
49
+
50
+ export function save(
51
+ db: Db.Db,
52
+ input: {
53
+ scope: Policy.Scope
54
+ version: number
55
+ policy: Policy.Overrides
56
+ /** Revalidates external key ownership under the policy lock. */
57
+ validateScope?: (() => Promise<boolean>) | undefined
58
+ },
59
+ ): Promise<Record> {
60
+ return db.transaction(async (tx) => {
61
+ await RoutesSubsidies.lockOrganization(tx, input.scope.orgId)
62
+ if (input.validateScope && !(await input.validateScope())) throw new InvalidScopeError()
63
+ return saveIn(tx, input)
64
+ })
65
+ }
66
+
67
+ export function clearKey(db: Db.Db, input: clearKey.Input): Promise<readonly Record[]> {
68
+ return db.transaction((tx) => clearKeyIn(tx, input))
69
+ }
70
+
71
+ /** Locks current, destination, and historical key policy owners before owner or admission locks. */
72
+ export async function lockKeyOrganizations(
73
+ db: Db.Db,
74
+ input: lockKeyOrganizations.Input,
75
+ ): Promise<void> {
76
+ const rows = await db.kysely
77
+ .selectFrom('routes_policies')
78
+ .select('orgId')
79
+ .where('apiKeyId', '=', input.apiKeyId)
80
+ .distinct()
81
+ .execute()
82
+ for (const orgId of [...new Set([...input.orgIds, ...rows.map((row) => row.orgId)])].sort())
83
+ await RoutesSubsidies.lockOrganization(db, orgId)
84
+ }
85
+
86
+ export declare namespace lockKeyOrganizations {
87
+ /** Key being reassigned and its current and destination owners. */
88
+ type Input = {
89
+ /** API key identifier. */
90
+ apiKeyId: string
91
+ /** Current and destination organization identifiers. */
92
+ orgIds: readonly string[]
93
+ }
94
+ }
95
+
96
+ /** Clears key overrides inside a caller-owned transaction. */
97
+ export async function clearKeyIn(db: Db.Db, input: clearKey.Input): Promise<readonly Record[]> {
98
+ const rows = await db.kysely
99
+ .selectFrom('routes_policies')
100
+ .selectAll()
101
+ .where('apiKeyId', '=', input.apiKeyId)
102
+ .orderBy('orgId')
103
+ .orderBy('environment')
104
+ .orderBy('projectId')
105
+ .execute()
106
+ const records: Record[] = []
107
+ for (const row of rows) {
108
+ await RoutesSubsidies.lockOrganization(db, row.orgId)
109
+ // Former projects may be deleted; retain monotonic revisions without revalidating their existence.
110
+ const updated = await db.kysely
111
+ .updateTable('routes_policies')
112
+ .set({ policy: {}, updatedAt: new Date().toISOString(), version: sql`version + 1` })
113
+ .where('orgId', '=', row.orgId)
114
+ .where('environment', '=', row.environment)
115
+ .where('projectId', '=', row.projectId)
116
+ .where('apiKeyId', '=', row.apiKeyId)
117
+ .returningAll()
118
+ .executeTakeFirst()
119
+ if (updated) records.push(domain(updated))
120
+ }
121
+ return records
122
+ }
123
+
124
+ export namespace clearKey {
125
+ export type Input = { apiKeyId: string }
126
+ }
127
+
128
+ export function copyKey(db: Db.Db, input: copyKey.Input): Promise<Record | undefined> {
129
+ if (
130
+ input.source.environment !== input.destination.environment ||
131
+ input.source.orgId !== input.destination.orgId ||
132
+ input.source.projectId !== input.destination.projectId
133
+ )
134
+ return Promise.reject(new InvalidScopeError())
135
+ return db.transaction((tx) => copyKeyIn(tx, input))
136
+ }
137
+
138
+ /** Copies key overrides inside a caller-owned transaction. */
139
+ export async function copyKeyIn(db: Db.Db, input: copyKey.Input): Promise<Record | undefined> {
140
+ if (
141
+ input.source.environment !== input.destination.environment ||
142
+ input.source.orgId !== input.destination.orgId ||
143
+ input.source.projectId !== input.destination.projectId
144
+ )
145
+ throw new InvalidScopeError()
146
+ await RoutesSubsidies.lockOrganization(db, input.destination.orgId)
147
+ const source = await get(db, input.source)
148
+ if (!input.source.apiKeyId || !input.destination.apiKeyId) throw new InvalidScopeError()
149
+ if (!source) return undefined
150
+ const destination = await get(db, input.destination)
151
+ return saveIn(db, {
152
+ policy: source.policy,
153
+ scope: input.destination,
154
+ version: destination?.version ?? 0,
155
+ })
156
+ }
157
+
158
+ export namespace copyKey {
159
+ export type Input = { destination: Policy.Scope; source: Policy.Scope }
160
+ }
161
+
162
+ async function saveIn(
163
+ db: Db.Db,
164
+ input: { scope: Policy.Scope; version: number; policy: Policy.Overrides },
165
+ ): Promise<Record> {
166
+ await validateScope(db, input.scope)
167
+ if (
168
+ (input.scope.projectId !== undefined || input.scope.apiKeyId !== undefined) &&
169
+ input.policy.suspended !== undefined
170
+ )
171
+ throw new InvalidScopeError()
172
+ const before = await get(db, input.scope)
173
+ if ((before?.version ?? 0) !== input.version) throw new ConflictError()
174
+ const now = new Date().toISOString()
175
+ const keys = storage(input.scope)
176
+ const row =
177
+ input.version === 0
178
+ ? await db.kysely
179
+ .insertInto('routes_policies')
180
+ .values({ ...keys, version: 1, policy: input.policy, createdAt: now, updatedAt: now })
181
+ .returningAll()
182
+ .executeTakeFirstOrThrow()
183
+ : await db.kysely
184
+ .updateTable('routes_policies')
185
+ .set({ version: input.version + 1, policy: input.policy, updatedAt: now })
186
+ .where('orgId', '=', keys.orgId)
187
+ .where('environment', '=', keys.environment)
188
+ .where('projectId', '=', keys.projectId)
189
+ .where('apiKeyId', '=', keys.apiKeyId)
190
+ .where('version', '=', input.version)
191
+ .returningAll()
192
+ .executeTakeFirst()
193
+ if (!row) throw new ConflictError()
194
+ return domain(row)
195
+ }
196
+
197
+ function scoped(db: Db.Db, scope: Policy.Scope) {
198
+ const key = storage(scope)
199
+ return db.kysely
200
+ .selectFrom('routes_policies')
201
+ .where('orgId', '=', key.orgId)
202
+ .where('environment', '=', key.environment)
203
+ .where('projectId', '=', key.projectId)
204
+ .where('apiKeyId', '=', key.apiKeyId)
205
+ }
206
+ function storage(scope: Policy.Scope) {
207
+ return {
208
+ orgId: scope.orgId,
209
+ environment: scope.environment,
210
+ projectId: scope.projectId ?? '',
211
+ apiKeyId: scope.apiKeyId ?? '',
212
+ }
213
+ }
214
+ function domain(row: Selectable<Table>): Record {
215
+ return {
216
+ orgId: row.orgId,
217
+ environment: row.environment,
218
+ ...(row.projectId ? { projectId: row.projectId } : {}),
219
+ ...(row.apiKeyId ? { apiKeyId: row.apiKeyId } : {}),
220
+ version: row.version,
221
+ policy: row.policy,
222
+ createdAt: row.createdAt,
223
+ updatedAt: row.updatedAt,
224
+ }
225
+ }
226
+ function pickScope(value: Policy.Scope): Policy.Scope {
227
+ return {
228
+ orgId: value.orgId,
229
+ environment: value.environment,
230
+ ...(value.projectId ? { projectId: value.projectId } : {}),
231
+ ...(value.apiKeyId ? { apiKeyId: value.apiKeyId } : {}),
232
+ }
233
+ }
234
+ async function validateScope(db: Db.Db, scope: Policy.Scope) {
235
+ if (scope.projectId) {
236
+ const project = await db.kysely
237
+ .selectFrom('projects')
238
+ .select('id')
239
+ .where('id', '=', scope.projectId)
240
+ .where('orgId', '=', scope.orgId)
241
+ .executeTakeFirst()
242
+ if (!project) throw new InvalidScopeError()
243
+ } else {
244
+ const org = await db.kysely
245
+ .selectFrom('organizations')
246
+ .select('id')
247
+ .where('id', '=', scope.orgId)
248
+ .executeTakeFirst()
249
+ if (!org) throw new InvalidScopeError()
250
+ }
251
+ }
@@ -7,6 +7,8 @@ import type * as Schema from '../Schema.js'
7
7
  export type Table = Schema.RoutesTransferSubsidy
8
8
  /** A shared subsidy transaction and its billing owner. */
9
9
  export type Record = Selectable<Table>
10
+ /** Immutable evidence for an expired signed Solana attempt. */
11
+ export type ExpiredAttemptTable = Schema.RoutesTransferSubsidyExpiredAttempt
10
12
 
11
13
  /** Serializes subsidy preparation for a source payment and returns its persisted settlement. */
12
14
  export async function getForUpdateIn(
@@ -36,3 +38,65 @@ export declare namespace getForUpdateIn {
36
38
  transactionRef: string
37
39
  }
38
40
  }
41
+
42
+ /** Archives an expired Solana signature under the canonical source lock. */
43
+ export async function markExpiredIn(
44
+ db: Db.Db,
45
+ options: markExpiredIn.Options,
46
+ ): Promise<markExpiredIn.Result> {
47
+ const settlement = await getForUpdateIn(db, options)
48
+ if (!settlement) return { type: 'not_found' }
49
+ if (settlement.transferId !== options.transferId) return { settlement, type: 'shared' }
50
+ if (
51
+ settlement.status !== 'active' ||
52
+ !settlement.destinationChainId.startsWith('solana:') ||
53
+ settlement.transaction !== options.signedTransaction
54
+ )
55
+ return { settlement, type: 'stale' }
56
+ const signed: unknown = JSON.parse(options.signedTransaction)
57
+ if (
58
+ !signed ||
59
+ typeof signed !== 'object' ||
60
+ !('hash' in signed) ||
61
+ signed.hash !== options.signedHash
62
+ )
63
+ return { settlement, type: 'stale' }
64
+
65
+ // The caller proves final expiry before entering this transaction. Exact transaction
66
+ // comparison prevents a late recovery worker from replacing a newer signature.
67
+ const expiredAt = new Date().toISOString()
68
+ await db.kysely
69
+ .insertInto('routes_transfer_subsidy_expired_attempts')
70
+ .values({
71
+ createdAt: settlement.createdAt,
72
+ expiredAt,
73
+ sourceChainId: settlement.sourceChainId,
74
+ transaction: JSON.stringify(settlement.transaction),
75
+ transactionHash: options.signedHash,
76
+ transactionRef: settlement.transactionRef,
77
+ transferId: settlement.transferId,
78
+ })
79
+ .execute()
80
+ await db.kysely
81
+ .updateTable('routes_transfer_subsidies')
82
+ .set({ status: 'expired' })
83
+ .where('sourceChainId', '=', options.sourceChainId)
84
+ .where('transactionRef', '=', options.transactionRef)
85
+ .where('status', '=', 'active')
86
+ .executeTakeFirstOrThrow()
87
+ return { settlement: { ...settlement, status: 'expired' }, type: 'expired' }
88
+ }
89
+
90
+ export declare namespace markExpiredIn {
91
+ /** Expected canonical signed Solana attempt and its original billing owner. */
92
+ type Options = getForUpdateIn.Options & {
93
+ /** Signature of the signed attempt being retired. */
94
+ signedHash: string
95
+ /** Exact serialized signed transaction persisted in the settlement row. */
96
+ signedTransaction: string
97
+ /** Original subsidy billing owner. */
98
+ transferId: string
99
+ }
100
+ /** Outcome of the source-keyed expiry compare and swap. */
101
+ type Result = { type: 'not_found' } | { settlement: Record; type: 'expired' | 'shared' | 'stale' }
102
+ }