tapimo 0.13.0 → 0.15.0

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 (1143) hide show
  1. package/README.md +7 -4
  2. package/dist/ApiKey.js +1 -1
  3. package/dist/ApiKey.js.map +1 -1
  4. package/dist/ApiKeys.d.ts +95 -14
  5. package/dist/ApiKeys.d.ts.map +1 -1
  6. package/dist/ApiKeys.js +360 -49
  7. package/dist/ApiKeys.js.map +1 -1
  8. package/dist/App.d.ts +21383 -18056
  9. package/dist/App.d.ts.map +1 -1
  10. package/dist/App.js +301 -22
  11. package/dist/App.js.map +1 -1
  12. package/dist/Assets.d.ts.map +1 -1
  13. package/dist/Assets.js +2 -1
  14. package/dist/Assets.js.map +1 -1
  15. package/dist/Handler.d.ts +0 -1
  16. package/dist/Handler.d.ts.map +1 -1
  17. package/dist/Handler.js +0 -1
  18. package/dist/Handler.js.map +1 -1
  19. package/dist/Scope.d.ts +13 -5
  20. package/dist/Scope.d.ts.map +1 -1
  21. package/dist/Scope.js +16 -5
  22. package/dist/Scope.js.map +1 -1
  23. package/dist/Webhooks.js +2 -2
  24. package/dist/Webhooks.js.map +1 -1
  25. package/dist/admin/App.d.ts +3936 -1337
  26. package/dist/admin/App.d.ts.map +1 -1
  27. package/dist/admin/App.js +26 -5
  28. package/dist/admin/App.js.map +1 -1
  29. package/dist/admin/apps/api-keys.d.ts +159 -7
  30. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  31. package/dist/admin/apps/api-keys.js +95 -43
  32. package/dist/admin/apps/api-keys.js.map +1 -1
  33. package/dist/admin/apps/earn-vaults.d.ts +1446 -0
  34. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  35. package/dist/admin/apps/earn-vaults.js +465 -8
  36. package/dist/admin/apps/earn-vaults.js.map +1 -1
  37. package/dist/admin/apps/organizations.d.ts +344 -3
  38. package/dist/admin/apps/organizations.d.ts.map +1 -1
  39. package/dist/admin/apps/organizations.js +288 -10
  40. package/dist/admin/apps/organizations.js.map +1 -1
  41. package/dist/admin/apps/routes-support.d.ts +95 -0
  42. package/dist/admin/apps/routes-support.d.ts.map +1 -0
  43. package/dist/admin/apps/routes-support.js +151 -0
  44. package/dist/admin/apps/routes-support.js.map +1 -0
  45. package/dist/admin/apps/routes.d.ts +2764 -0
  46. package/dist/admin/apps/routes.d.ts.map +1 -0
  47. package/dist/admin/apps/routes.js +728 -0
  48. package/dist/admin/apps/routes.js.map +1 -0
  49. package/dist/admin/apps/subsidies.d.ts +501 -0
  50. package/dist/admin/apps/subsidies.d.ts.map +1 -0
  51. package/dist/admin/apps/subsidies.js +384 -0
  52. package/dist/admin/apps/subsidies.js.map +1 -0
  53. package/dist/admin/apps/verified-tokens.d.ts +16 -16
  54. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  55. package/dist/admin/apps/verified-tokens.js +3 -3
  56. package/dist/admin/apps/verified-tokens.js.map +1 -1
  57. package/dist/admin/ui.generated.d.ts +1 -1
  58. package/dist/admin/ui.generated.d.ts.map +1 -1
  59. package/dist/admin/ui.generated.js +129 -69
  60. package/dist/admin/ui.generated.js.map +1 -1
  61. package/dist/analytics/Analytics.d.ts +5 -2
  62. package/dist/analytics/Analytics.d.ts.map +1 -1
  63. package/dist/analytics/Analytics.js +31 -1
  64. package/dist/analytics/Analytics.js.map +1 -1
  65. package/dist/analytics/tables/requestEvents.d.ts +2 -1
  66. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  67. package/dist/analytics/tables/requestEvents.js +10 -1
  68. package/dist/analytics/tables/requestEvents.js.map +1 -1
  69. package/dist/analytics/tables/routesLifecycleIntervals.d.ts +72 -0
  70. package/dist/analytics/tables/routesLifecycleIntervals.d.ts.map +1 -0
  71. package/dist/analytics/tables/routesLifecycleIntervals.js +56 -0
  72. package/dist/analytics/tables/routesLifecycleIntervals.js.map +1 -0
  73. package/dist/apps/Zones.d.ts +21 -12526
  74. package/dist/apps/Zones.d.ts.map +1 -1
  75. package/dist/apps/Zones.js +40 -8
  76. package/dist/apps/Zones.js.map +1 -1
  77. package/dist/apps/data/App.d.ts +4310 -2548
  78. package/dist/apps/data/App.d.ts.map +1 -1
  79. package/dist/apps/data/App.js +86 -26
  80. package/dist/apps/data/App.js.map +1 -1
  81. package/dist/apps/data/routes/activities.d.ts +364 -34
  82. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  83. package/dist/apps/data/routes/activities.js +495 -190
  84. package/dist/apps/data/routes/activities.js.map +1 -1
  85. package/dist/apps/data/routes/addresses.d.ts +94 -22
  86. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  87. package/dist/apps/data/routes/blocks.d.ts +37 -37
  88. package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
  89. package/dist/apps/data/routes/coingecko.js +47 -21
  90. package/dist/apps/data/routes/coingecko.js.map +1 -1
  91. package/dist/apps/data/routes/earn.d.ts +1641 -352
  92. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  93. package/dist/apps/data/routes/earn.js +1561 -120
  94. package/dist/apps/data/routes/earn.js.map +1 -1
  95. package/dist/apps/data/routes/exchanges.d.ts +15 -0
  96. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  97. package/dist/apps/data/routes/exchanges.js +180 -114
  98. package/dist/apps/data/routes/exchanges.js.map +1 -1
  99. package/dist/apps/data/routes/fee-amm.d.ts +5 -0
  100. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  101. package/dist/apps/data/routes/fee-amm.js +49 -38
  102. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  103. package/dist/apps/data/routes/indexer.d.ts +125 -0
  104. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  105. package/dist/apps/data/routes/indexer.js +83 -27
  106. package/dist/apps/data/routes/indexer.js.map +1 -1
  107. package/dist/apps/data/routes/rpc.d.ts +507 -33
  108. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  109. package/dist/apps/data/routes/rpc.js +266 -156
  110. package/dist/apps/data/routes/rpc.js.map +1 -1
  111. package/dist/apps/data/routes/tokenlist.d.ts +47 -15
  112. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  113. package/dist/apps/data/routes/tokenlist.js +68 -11
  114. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  115. package/dist/apps/data/routes/tokens.d.ts +95 -93
  116. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  117. package/dist/apps/data/routes/tokens.js +26 -14
  118. package/dist/apps/data/routes/tokens.js.map +1 -1
  119. package/dist/apps/data/routes/transfers.d.ts +16 -0
  120. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  121. package/dist/apps/data/routes/transfers.js +9 -7
  122. package/dist/apps/data/routes/transfers.js.map +1 -1
  123. package/dist/apps/data/routes/verified-tokens.d.ts +4 -4
  124. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
  125. package/dist/apps/data/routes/verified-tokens.js +64 -20
  126. package/dist/apps/data/routes/verified-tokens.js.map +1 -1
  127. package/dist/apps/data/routes/webhooks.d.ts +1210 -70
  128. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  129. package/dist/apps/data/routes/webhooks.js +301 -163
  130. package/dist/apps/data/routes/webhooks.js.map +1 -1
  131. package/dist/apps/data/routes/zones.d.ts.map +1 -1
  132. package/dist/apps/data/routes/zones.js +20 -12
  133. package/dist/apps/data/routes/zones.js.map +1 -1
  134. package/dist/apps/docs/reference.js +2 -2
  135. package/dist/apps/docs/reference.js.map +1 -1
  136. package/dist/apps/index.d.ts +1 -1
  137. package/dist/apps/index.d.ts.map +1 -1
  138. package/dist/apps/index.js +1 -1
  139. package/dist/apps/index.js.map +1 -1
  140. package/dist/apps/management/App.d.ts +4119 -3297
  141. package/dist/apps/management/App.d.ts.map +1 -1
  142. package/dist/apps/management/App.js +5 -14
  143. package/dist/apps/management/App.js.map +1 -1
  144. package/dist/apps/management/Billing.d.ts +49 -8
  145. package/dist/apps/management/Billing.d.ts.map +1 -1
  146. package/dist/apps/management/Billing.js +221 -26
  147. package/dist/apps/management/Billing.js.map +1 -1
  148. package/dist/apps/management/routes/api-keys.d.ts +174 -72
  149. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  150. package/dist/apps/management/routes/api-keys.js +43 -15
  151. package/dist/apps/management/routes/api-keys.js.map +1 -1
  152. package/dist/apps/management/routes/billing.d.ts +364 -78
  153. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  154. package/dist/apps/management/routes/billing.js +274 -49
  155. package/dist/apps/management/routes/billing.js.map +1 -1
  156. package/dist/apps/management/routes/faucet.d.ts +6 -6
  157. package/dist/apps/management/routes/faucet.js +1 -1
  158. package/dist/apps/management/routes/faucet.js.map +1 -1
  159. package/dist/apps/management/routes/invitations.d.ts +99 -24
  160. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  161. package/dist/apps/management/routes/invitations.js +117 -13
  162. package/dist/apps/management/routes/invitations.js.map +1 -1
  163. package/dist/apps/management/routes/invite-links.d.ts +42 -42
  164. package/dist/apps/management/routes/me.d.ts.map +1 -1
  165. package/dist/apps/management/routes/me.js +6 -2
  166. package/dist/apps/management/routes/me.js.map +1 -1
  167. package/dist/apps/management/routes/members.d.ts +16 -16
  168. package/dist/apps/management/routes/orgs.d.ts +36 -20
  169. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  170. package/dist/apps/management/routes/orgs.js +52 -12
  171. package/dist/apps/management/routes/orgs.js.map +1 -1
  172. package/dist/apps/management/routes/projects.d.ts +40 -40
  173. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  174. package/dist/apps/management/routes/projects.js +6 -1
  175. package/dist/apps/management/routes/projects.js.map +1 -1
  176. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  177. package/dist/apps/management/routes/scopes.js +4 -1
  178. package/dist/apps/management/routes/scopes.js.map +1 -1
  179. package/dist/apps/management/routes/usage.d.ts +8 -8
  180. package/dist/apps/management/routes/usage.js +21 -4
  181. package/dist/apps/management/routes/usage.js.map +1 -1
  182. package/dist/apps/management/routes/verified-token-requests.d.ts +16 -16
  183. package/dist/apps/management/routes/webhooks.d.ts +931 -215
  184. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  185. package/dist/apps/management/routes/webhooks.js +71 -25
  186. package/dist/apps/management/routes/webhooks.js.map +1 -1
  187. package/dist/apps/mcp.d.ts +1 -1
  188. package/dist/apps/mcp.js +7 -7
  189. package/dist/apps/mcp.js.map +1 -1
  190. package/dist/apps/mpp/App.d.ts.map +1 -1
  191. package/dist/apps/mpp/App.js +35 -7
  192. package/dist/apps/mpp/App.js.map +1 -1
  193. package/dist/apps/mpp/internal/Adapter.d.ts +2 -0
  194. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
  195. package/dist/apps/mpp/internal/Adapter.js +30 -1
  196. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  197. package/dist/apps/mpp/internal/Policy.d.ts +22 -4
  198. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
  199. package/dist/apps/mpp/internal/Policy.js +24 -6
  200. package/dist/apps/mpp/internal/Policy.js.map +1 -1
  201. package/dist/apps/mpp/internal/Sponsorship.d.ts +3 -0
  202. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -1
  203. package/dist/apps/mpp/internal/Sponsorship.js +6 -3
  204. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -1
  205. package/dist/apps/relay/App.d.ts +2 -0
  206. package/dist/apps/relay/App.d.ts.map +1 -1
  207. package/dist/apps/relay/App.js +177 -26
  208. package/dist/apps/relay/App.js.map +1 -1
  209. package/dist/apps/relay/Sponsorships.d.ts +5 -3
  210. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  211. package/dist/apps/relay/Sponsorships.js +232 -25
  212. package/dist/apps/relay/Sponsorships.js.map +1 -1
  213. package/dist/apps/{funding → routes}/Access.d.ts +4 -4
  214. package/dist/apps/routes/Access.d.ts.map +1 -0
  215. package/dist/apps/{funding → routes}/Access.js +4 -4
  216. package/dist/apps/routes/Access.js.map +1 -0
  217. package/dist/apps/{funding → routes}/App.d.ts +841 -136
  218. package/dist/apps/{funding → routes}/App.d.ts.map +1 -1
  219. package/dist/apps/{funding → routes}/App.js +17 -17
  220. package/dist/apps/routes/App.js.map +1 -0
  221. package/dist/apps/routes/Inventory.d.ts.map +1 -0
  222. package/dist/apps/{funding → routes}/Inventory.js +2 -2
  223. package/dist/apps/routes/Inventory.js.map +1 -0
  224. package/dist/apps/routes/index.d.ts +2 -0
  225. package/dist/apps/routes/index.d.ts.map +1 -0
  226. package/dist/apps/routes/index.js +2 -0
  227. package/dist/apps/routes/index.js.map +1 -0
  228. package/dist/apps/{funding → routes}/routes/chains.d.ts +7 -7
  229. package/dist/apps/routes/routes/chains.d.ts.map +1 -0
  230. package/dist/apps/{funding → routes}/routes/chains.js +25 -25
  231. package/dist/apps/routes/routes/chains.js.map +1 -0
  232. package/dist/apps/{funding → routes}/routes/deposit-addresses.d.ts +123 -59
  233. package/dist/apps/routes/routes/deposit-addresses.d.ts.map +1 -0
  234. package/dist/apps/{funding → routes}/routes/deposit-addresses.js +498 -223
  235. package/dist/apps/routes/routes/deposit-addresses.js.map +1 -0
  236. package/dist/apps/{funding → routes}/routes/providers.d.ts +8 -8
  237. package/dist/apps/routes/routes/providers.d.ts.map +1 -0
  238. package/dist/apps/routes/routes/providers.js +57 -0
  239. package/dist/apps/routes/routes/providers.js.map +1 -0
  240. package/dist/apps/{funding → routes}/routes/quotes.d.ts +19 -16
  241. package/dist/apps/routes/routes/quotes.d.ts.map +1 -0
  242. package/dist/apps/{funding → routes}/routes/quotes.js +55 -38
  243. package/dist/apps/routes/routes/quotes.js.map +1 -0
  244. package/dist/apps/{funding → routes}/routes/transfers.d.ts +957 -71
  245. package/dist/apps/routes/routes/transfers.d.ts.map +1 -0
  246. package/dist/apps/routes/routes/transfers.js +1140 -0
  247. package/dist/apps/routes/routes/transfers.js.map +1 -0
  248. package/dist/cli/Cli.d.ts +30 -0
  249. package/dist/cli/Cli.d.ts.map +1 -1
  250. package/dist/cli/commands/admin.d.ts +36 -0
  251. package/dist/cli/commands/admin.d.ts.map +1 -1
  252. package/dist/cli/commands/admin.js +273 -0
  253. package/dist/cli/commands/admin.js.map +1 -1
  254. package/dist/cloudflare.d.ts +16 -14
  255. package/dist/cloudflare.d.ts.map +1 -1
  256. package/dist/cloudflare.js +26 -21
  257. package/dist/cloudflare.js.map +1 -1
  258. package/dist/db/Db.d.ts +63 -21
  259. package/dist/db/Db.d.ts.map +1 -1
  260. package/dist/db/Db.js +1052 -15
  261. package/dist/db/Db.js.map +1 -1
  262. package/dist/db/Schema.d.ts +785 -133
  263. package/dist/db/Schema.d.ts.map +1 -1
  264. package/dist/db/Schema.js +590 -162
  265. package/dist/db/Schema.js.map +1 -1
  266. package/dist/db/tables/apiKeyAdmissionBootstraps.d.ts +4 -0
  267. package/dist/db/tables/apiKeyAdmissionBootstraps.d.ts.map +1 -0
  268. package/dist/db/tables/apiKeyAdmissionBootstraps.js +2 -0
  269. package/dist/db/tables/apiKeyAdmissionBootstraps.js.map +1 -0
  270. package/dist/db/tables/apiKeyAdmissions.d.ts +73 -0
  271. package/dist/db/tables/apiKeyAdmissions.d.ts.map +1 -0
  272. package/dist/db/tables/apiKeyAdmissions.js +142 -0
  273. package/dist/db/tables/apiKeyAdmissions.js.map +1 -0
  274. package/dist/db/tables/apiKeyOwnerAdmissions.d.ts +4 -0
  275. package/dist/db/tables/apiKeyOwnerAdmissions.d.ts.map +1 -0
  276. package/dist/db/tables/apiKeyOwnerAdmissions.js +2 -0
  277. package/dist/db/tables/apiKeyOwnerAdmissions.js.map +1 -0
  278. package/dist/db/tables/apiKeyOwnerTombstones.d.ts +20 -0
  279. package/dist/db/tables/apiKeyOwnerTombstones.d.ts.map +1 -0
  280. package/dist/db/tables/apiKeyOwnerTombstones.js +57 -0
  281. package/dist/db/tables/apiKeyOwnerTombstones.js.map +1 -0
  282. package/dist/db/tables/apiKeyRevocations.d.ts +21 -0
  283. package/dist/db/tables/apiKeyRevocations.d.ts.map +1 -0
  284. package/dist/db/tables/apiKeyRevocations.js +98 -0
  285. package/dist/db/tables/apiKeyRevocations.js.map +1 -0
  286. package/dist/db/tables/authAccounts.d.ts +47 -0
  287. package/dist/db/tables/authAccounts.d.ts.map +1 -0
  288. package/dist/db/tables/authAccounts.js +72 -0
  289. package/dist/db/tables/authAccounts.js.map +1 -0
  290. package/dist/db/tables/authSessions.d.ts +12 -0
  291. package/dist/db/tables/authSessions.d.ts.map +1 -0
  292. package/dist/db/tables/authSessions.js +2 -0
  293. package/dist/db/tables/authSessions.js.map +1 -0
  294. package/dist/db/tables/authVerifications.d.ts +12 -0
  295. package/dist/db/tables/authVerifications.d.ts.map +1 -0
  296. package/dist/db/tables/authVerifications.js +2 -0
  297. package/dist/db/tables/authVerifications.js.map +1 -0
  298. package/dist/db/tables/invitations.d.ts +17 -1
  299. package/dist/db/tables/invitations.d.ts.map +1 -1
  300. package/dist/db/tables/invitations.js +123 -43
  301. package/dist/db/tables/invitations.js.map +1 -1
  302. package/dist/db/tables/memberships.d.ts +8 -0
  303. package/dist/db/tables/memberships.d.ts.map +1 -1
  304. package/dist/db/tables/memberships.js +51 -2
  305. package/dist/db/tables/memberships.js.map +1 -1
  306. package/dist/db/tables/organizations.d.ts +51 -5
  307. package/dist/db/tables/organizations.d.ts.map +1 -1
  308. package/dist/db/tables/organizations.js +135 -47
  309. package/dist/db/tables/organizations.js.map +1 -1
  310. package/dist/db/tables/projects.d.ts +27 -1
  311. package/dist/db/tables/projects.d.ts.map +1 -1
  312. package/dist/db/tables/projects.js +38 -3
  313. package/dist/db/tables/projects.js.map +1 -1
  314. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  315. package/dist/db/tables/requestUsage.js.map +1 -1
  316. package/dist/db/tables/rewardAccounts.d.ts +86 -0
  317. package/dist/db/tables/rewardAccounts.d.ts.map +1 -0
  318. package/dist/db/tables/rewardAccounts.js +88 -0
  319. package/dist/db/tables/rewardAccounts.js.map +1 -0
  320. package/dist/db/tables/rewardCampaignDistributors.d.ts +36 -0
  321. package/dist/db/tables/rewardCampaignDistributors.d.ts.map +1 -0
  322. package/dist/db/tables/rewardCampaignDistributors.js +30 -0
  323. package/dist/db/tables/rewardCampaignDistributors.js.map +1 -0
  324. package/dist/db/tables/rewardCampaigns.d.ts +171 -0
  325. package/dist/db/tables/rewardCampaigns.d.ts.map +1 -0
  326. package/dist/db/tables/rewardCampaigns.js +392 -0
  327. package/dist/db/tables/rewardCampaigns.js.map +1 -0
  328. package/dist/db/tables/rewardCredits.d.ts +53 -0
  329. package/dist/db/tables/rewardCredits.d.ts.map +1 -0
  330. package/dist/db/tables/rewardCredits.js +63 -0
  331. package/dist/db/tables/rewardCredits.js.map +1 -0
  332. package/dist/db/tables/rewardEligibilityAssociations.d.ts +61 -0
  333. package/dist/db/tables/rewardEligibilityAssociations.d.ts.map +1 -0
  334. package/dist/db/tables/rewardEligibilityAssociations.js +103 -0
  335. package/dist/db/tables/rewardEligibilityAssociations.js.map +1 -0
  336. package/dist/db/tables/rewardRuns.d.ts +188 -0
  337. package/dist/db/tables/rewardRuns.d.ts.map +1 -0
  338. package/dist/db/tables/rewardRuns.js +278 -0
  339. package/dist/db/tables/rewardRuns.js.map +1 -0
  340. package/dist/db/tables/rewardTransactionAttempts.d.ts +100 -0
  341. package/dist/db/tables/rewardTransactionAttempts.d.ts.map +1 -0
  342. package/dist/db/tables/rewardTransactionAttempts.js +163 -0
  343. package/dist/db/tables/rewardTransactionAttempts.js.map +1 -0
  344. package/dist/db/tables/routesCatalog.d.ts +58 -0
  345. package/dist/db/tables/routesCatalog.d.ts.map +1 -0
  346. package/dist/db/tables/{fundingCatalog.js → routesCatalog.js} +19 -19
  347. package/dist/db/tables/routesCatalog.js.map +1 -0
  348. package/dist/db/tables/routesDepositAddresses.d.ts +476 -0
  349. package/dist/db/tables/routesDepositAddresses.d.ts.map +1 -0
  350. package/dist/db/tables/routesDepositAddresses.js +587 -0
  351. package/dist/db/tables/routesDepositAddresses.js.map +1 -0
  352. package/dist/db/tables/{fundingDepositRequestObservations.d.ts → routesDepositRequestObservations.d.ts} +6 -6
  353. package/dist/db/tables/routesDepositRequestObservations.d.ts.map +1 -0
  354. package/dist/db/tables/{fundingDepositRequestObservations.js → routesDepositRequestObservations.js} +6 -6
  355. package/dist/db/tables/routesDepositRequestObservations.js.map +1 -0
  356. package/dist/db/tables/{fundingDeposits.d.ts → routesDeposits.d.ts} +210 -22
  357. package/dist/db/tables/routesDeposits.d.ts.map +1 -0
  358. package/dist/db/tables/routesDeposits.js +576 -0
  359. package/dist/db/tables/routesDeposits.js.map +1 -0
  360. package/dist/db/tables/routesIdempotency.d.ts +166 -0
  361. package/dist/db/tables/routesIdempotency.d.ts.map +1 -0
  362. package/dist/db/tables/routesIdempotency.js +330 -0
  363. package/dist/db/tables/routesIdempotency.js.map +1 -0
  364. package/dist/db/tables/routesSubsidies.d.ts +27 -0
  365. package/dist/db/tables/routesSubsidies.d.ts.map +1 -0
  366. package/dist/db/tables/routesSubsidies.js +45 -0
  367. package/dist/db/tables/routesSubsidies.js.map +1 -0
  368. package/dist/db/tables/{fundingTransferEvents.d.ts → routesTransferEvents.d.ts} +3 -3
  369. package/dist/db/tables/routesTransferEvents.d.ts.map +1 -0
  370. package/dist/db/tables/{fundingTransferEvents.js → routesTransferEvents.js} +3 -3
  371. package/dist/db/tables/routesTransferEvents.js.map +1 -0
  372. package/dist/db/tables/routesTransferSubsidies.d.ts +19 -0
  373. package/dist/db/tables/routesTransferSubsidies.d.ts.map +1 -0
  374. package/dist/db/tables/routesTransferSubsidies.js +17 -0
  375. package/dist/db/tables/routesTransferSubsidies.js.map +1 -0
  376. package/dist/db/tables/routesTransferSubsidyNonces.d.ts +51 -0
  377. package/dist/db/tables/routesTransferSubsidyNonces.d.ts.map +1 -0
  378. package/dist/db/tables/routesTransferSubsidyNonces.js +82 -0
  379. package/dist/db/tables/routesTransferSubsidyNonces.js.map +1 -0
  380. package/dist/db/tables/routesTransferTransactions.d.ts +77 -0
  381. package/dist/db/tables/routesTransferTransactions.d.ts.map +1 -0
  382. package/dist/db/tables/routesTransferTransactions.js +86 -0
  383. package/dist/db/tables/routesTransferTransactions.js.map +1 -0
  384. package/dist/db/tables/routesTransfers.d.ts +319 -0
  385. package/dist/db/tables/routesTransfers.d.ts.map +1 -0
  386. package/dist/db/tables/routesTransfers.js +372 -0
  387. package/dist/db/tables/routesTransfers.js.map +1 -0
  388. package/dist/db/tables/sponsoredTransactions.d.ts +112 -13
  389. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  390. package/dist/db/tables/sponsoredTransactions.js +241 -38
  391. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  392. package/dist/db/tables/sponsorshipAttributions.d.ts +69 -0
  393. package/dist/db/tables/sponsorshipAttributions.d.ts.map +1 -0
  394. package/dist/db/tables/sponsorshipAttributions.js +77 -0
  395. package/dist/db/tables/sponsorshipAttributions.js.map +1 -0
  396. package/dist/db/tables/sponsorshipReconciliationCursors.d.ts +22 -0
  397. package/dist/db/tables/sponsorshipReconciliationCursors.d.ts.map +1 -0
  398. package/dist/db/tables/sponsorshipReconciliationCursors.js +45 -0
  399. package/dist/db/tables/sponsorshipReconciliationCursors.js.map +1 -0
  400. package/dist/db/tables/stripeCustomers.d.ts +11 -0
  401. package/dist/db/tables/stripeCustomers.d.ts.map +1 -1
  402. package/dist/db/tables/stripeCustomers.js +13 -0
  403. package/dist/db/tables/stripeCustomers.js.map +1 -1
  404. package/dist/db/tables/users.d.ts +17 -1
  405. package/dist/db/tables/users.d.ts.map +1 -1
  406. package/dist/db/tables/users.js +47 -2
  407. package/dist/db/tables/users.js.map +1 -1
  408. package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -1
  409. package/dist/db/tables/webhookQueueEvents.js +5 -1
  410. package/dist/db/tables/webhookQueueEvents.js.map +1 -1
  411. package/dist/db/tables/webhookSubscriptions.d.ts +22 -10
  412. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  413. package/dist/db/tables/webhookSubscriptions.js +50 -15
  414. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  415. package/dist/handlers/internal/executionError.d.ts +2 -2
  416. package/dist/handlers/internal/executionError.d.ts.map +1 -1
  417. package/dist/handlers/internal/executionError.js +1 -2
  418. package/dist/handlers/internal/executionError.js.map +1 -1
  419. package/dist/handlers/internal/multisig.d.ts +4 -232
  420. package/dist/handlers/internal/multisig.d.ts.map +1 -1
  421. package/dist/handlers/internal/multisig.js +11 -537
  422. package/dist/handlers/internal/multisig.js.map +1 -1
  423. package/dist/handlers/internal/sponsorship.d.ts +19 -8
  424. package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
  425. package/dist/handlers/internal/sponsorship.js +13 -9
  426. package/dist/handlers/internal/sponsorship.js.map +1 -1
  427. package/dist/handlers/relay.d.ts +9 -12
  428. package/dist/handlers/relay.d.ts.map +1 -1
  429. package/dist/handlers/relay.js +81 -85
  430. package/dist/handlers/relay.js.map +1 -1
  431. package/dist/index.d.ts +0 -17
  432. package/dist/index.d.ts.map +1 -1
  433. package/dist/index.js +0 -17
  434. package/dist/index.js.map +1 -1
  435. package/dist/internal/AssetResponse.d.ts +12 -0
  436. package/dist/internal/AssetResponse.d.ts.map +1 -0
  437. package/dist/internal/AssetResponse.js +21 -0
  438. package/dist/internal/AssetResponse.js.map +1 -0
  439. package/dist/internal/Auth.d.ts +48 -12
  440. package/dist/internal/Auth.d.ts.map +1 -1
  441. package/dist/internal/Auth.js +603 -175
  442. package/dist/internal/Auth.js.map +1 -1
  443. package/dist/internal/BetterAuth.d.ts +1488 -0
  444. package/dist/internal/BetterAuth.d.ts.map +1 -0
  445. package/dist/internal/BetterAuth.js +253 -0
  446. package/dist/internal/BetterAuth.js.map +1 -0
  447. package/dist/internal/Cache.d.ts +2 -0
  448. package/dist/internal/Cache.d.ts.map +1 -1
  449. package/dist/internal/Cache.js +2 -0
  450. package/dist/internal/Cache.js.map +1 -1
  451. package/dist/internal/EarnRates.d.ts +26 -3
  452. package/dist/internal/EarnRates.d.ts.map +1 -1
  453. package/dist/internal/EarnRates.js +84 -19
  454. package/dist/internal/EarnRates.js.map +1 -1
  455. package/dist/internal/EarnSharePrices.d.ts +120 -0
  456. package/dist/internal/EarnSharePrices.d.ts.map +1 -0
  457. package/dist/internal/EarnSharePrices.js +179 -0
  458. package/dist/internal/EarnSharePrices.js.map +1 -0
  459. package/dist/internal/EarnVaults.d.ts +4 -0
  460. package/dist/internal/EarnVaults.d.ts.map +1 -1
  461. package/dist/internal/EarnVaults.js +31 -14
  462. package/dist/internal/EarnVaults.js.map +1 -1
  463. package/dist/internal/Email.d.ts +37 -0
  464. package/dist/internal/Email.d.ts.map +1 -0
  465. package/dist/internal/Email.js +16 -0
  466. package/dist/internal/Email.js.map +1 -0
  467. package/dist/internal/Log.d.ts +32 -28
  468. package/dist/internal/Log.d.ts.map +1 -1
  469. package/dist/internal/Log.js +18 -11
  470. package/dist/internal/Log.js.map +1 -1
  471. package/dist/internal/MetricSink.d.ts +3 -0
  472. package/dist/internal/MetricSink.d.ts.map +1 -1
  473. package/dist/internal/MetricSink.js +67 -8
  474. package/dist/internal/MetricSink.js.map +1 -1
  475. package/dist/internal/Mpp.d.ts.map +1 -1
  476. package/dist/internal/Mpp.js +20 -25
  477. package/dist/internal/Mpp.js.map +1 -1
  478. package/dist/internal/OpenApi.d.ts +26 -3
  479. package/dist/internal/OpenApi.d.ts.map +1 -1
  480. package/dist/internal/OpenApi.js +25 -10
  481. package/dist/internal/OpenApi.js.map +1 -1
  482. package/dist/internal/Provider.d.ts +1 -1
  483. package/dist/internal/Provider.d.ts.map +1 -1
  484. package/dist/internal/RateLimit.d.ts.map +1 -1
  485. package/dist/internal/RateLimit.js +13 -1
  486. package/dist/internal/RateLimit.js.map +1 -1
  487. package/dist/internal/Store.d.ts +16 -0
  488. package/dist/internal/Store.d.ts.map +1 -1
  489. package/dist/internal/Store.js +59 -8
  490. package/dist/internal/Store.js.map +1 -1
  491. package/dist/internal/Tidx.d.ts +9 -2
  492. package/dist/internal/Tidx.d.ts.map +1 -1
  493. package/dist/internal/Tidx.js +78 -11
  494. package/dist/internal/Tidx.js.map +1 -1
  495. package/dist/internal/Timing.d.ts +26 -0
  496. package/dist/internal/Timing.d.ts.map +1 -1
  497. package/dist/internal/Timing.js +63 -5
  498. package/dist/internal/Timing.js.map +1 -1
  499. package/dist/internal/VercelOidc.d.ts +94 -0
  500. package/dist/internal/VercelOidc.d.ts.map +1 -0
  501. package/dist/internal/VercelOidc.js +128 -0
  502. package/dist/internal/VercelOidc.js.map +1 -0
  503. package/dist/internal/VerifiedTokens.d.ts +2 -8
  504. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  505. package/dist/internal/VerifiedTokens.js +24 -24
  506. package/dist/internal/VerifiedTokens.js.map +1 -1
  507. package/dist/internal/Viem.d.ts +46 -2068
  508. package/dist/internal/Viem.d.ts.map +1 -1
  509. package/dist/internal/Viem.js +171 -11
  510. package/dist/internal/Viem.js.map +1 -1
  511. package/dist/internal/Webhooks.d.ts +12 -4
  512. package/dist/internal/Webhooks.d.ts.map +1 -1
  513. package/dist/internal/Webhooks.js +9 -3
  514. package/dist/internal/Webhooks.js.map +1 -1
  515. package/dist/internal/ZoneRpc.d.ts +7 -0
  516. package/dist/internal/ZoneRpc.d.ts.map +1 -0
  517. package/dist/internal/ZoneRpc.js +49 -0
  518. package/dist/internal/ZoneRpc.js.map +1 -0
  519. package/dist/internal/index.d.ts +3 -1
  520. package/dist/internal/index.d.ts.map +1 -1
  521. package/dist/internal/index.js +3 -1
  522. package/dist/internal/index.js.map +1 -1
  523. package/dist/internal/rewards/Audit.d.ts +88 -0
  524. package/dist/internal/rewards/Audit.d.ts.map +1 -0
  525. package/dist/internal/rewards/Audit.js +134 -0
  526. package/dist/internal/rewards/Audit.js.map +1 -0
  527. package/dist/internal/rewards/Campaigns.d.ts +572 -0
  528. package/dist/internal/rewards/Campaigns.d.ts.map +1 -0
  529. package/dist/internal/rewards/Campaigns.js +531 -0
  530. package/dist/internal/rewards/Campaigns.js.map +1 -0
  531. package/dist/internal/rewards/Credits.d.ts +76 -0
  532. package/dist/internal/rewards/Credits.d.ts.map +1 -0
  533. package/dist/internal/rewards/Credits.js +95 -0
  534. package/dist/internal/rewards/Credits.js.map +1 -0
  535. package/dist/internal/rewards/Events.d.ts +100 -0
  536. package/dist/internal/rewards/Events.d.ts.map +1 -0
  537. package/dist/internal/rewards/Events.js +340 -0
  538. package/dist/internal/rewards/Events.js.map +1 -0
  539. package/dist/internal/rewards/Projection.d.ts +237 -0
  540. package/dist/internal/rewards/Projection.d.ts.map +1 -0
  541. package/dist/internal/rewards/Projection.js +616 -0
  542. package/dist/internal/rewards/Projection.js.map +1 -0
  543. package/dist/internal/rewards/Rates.d.ts +44 -0
  544. package/dist/internal/rewards/Rates.d.ts.map +1 -0
  545. package/dist/internal/rewards/Rates.js +60 -0
  546. package/dist/internal/rewards/Rates.js.map +1 -0
  547. package/dist/internal/rewards/Read.d.ts +158 -0
  548. package/dist/internal/rewards/Read.d.ts.map +1 -0
  549. package/dist/internal/rewards/Read.js +292 -0
  550. package/dist/internal/rewards/Read.js.map +1 -0
  551. package/dist/internal/rewards/Runner.d.ts +164 -0
  552. package/dist/internal/rewards/Runner.d.ts.map +1 -0
  553. package/dist/internal/rewards/Runner.js +1778 -0
  554. package/dist/internal/rewards/Runner.js.map +1 -0
  555. package/dist/internal/rewards/Signer.d.ts +224 -0
  556. package/dist/internal/rewards/Signer.d.ts.map +1 -0
  557. package/dist/internal/rewards/Signer.js +135 -0
  558. package/dist/internal/rewards/Signer.js.map +1 -0
  559. package/dist/internal/rewards/index.d.ts +15 -0
  560. package/dist/internal/rewards/index.d.ts.map +1 -0
  561. package/dist/internal/rewards/index.js +15 -0
  562. package/dist/internal/rewards/index.js.map +1 -0
  563. package/dist/internal/{funding → routes}/Action.d.ts +12 -1
  564. package/dist/internal/routes/Action.d.ts.map +1 -0
  565. package/dist/internal/{funding → routes}/Action.js +17 -9
  566. package/dist/internal/routes/Action.js.map +1 -0
  567. package/dist/internal/{funding → routes}/Catalog.d.ts +20 -20
  568. package/dist/internal/routes/Catalog.d.ts.map +1 -0
  569. package/dist/internal/{funding → routes}/Catalog.js +29 -29
  570. package/dist/internal/routes/Catalog.js.map +1 -0
  571. package/dist/internal/{funding → routes}/Chain.d.ts +10 -10
  572. package/dist/internal/routes/Chain.d.ts.map +1 -0
  573. package/dist/internal/{funding → routes}/Chain.js +3 -3
  574. package/dist/internal/routes/Chain.js.map +1 -0
  575. package/dist/internal/{funding → routes}/Deposit.d.ts +45 -23
  576. package/dist/internal/routes/Deposit.d.ts.map +1 -0
  577. package/dist/internal/{funding → routes}/Deposit.js +60 -27
  578. package/dist/internal/routes/Deposit.js.map +1 -0
  579. package/dist/internal/{funding → routes}/DepositAddress.d.ts +56 -27
  580. package/dist/internal/routes/DepositAddress.d.ts.map +1 -0
  581. package/dist/internal/{funding → routes}/DepositAddress.js +95 -33
  582. package/dist/internal/routes/DepositAddress.js.map +1 -0
  583. package/dist/internal/{funding → routes}/DepositWebhook.d.ts +4 -4
  584. package/dist/internal/routes/DepositWebhook.d.ts.map +1 -0
  585. package/dist/internal/{funding → routes}/DepositWebhook.js +4 -3
  586. package/dist/internal/routes/DepositWebhook.js.map +1 -0
  587. package/dist/internal/routes/Economics.d.ts +25 -0
  588. package/dist/internal/routes/Economics.d.ts.map +1 -0
  589. package/dist/internal/routes/Economics.js +28 -0
  590. package/dist/internal/routes/Economics.js.map +1 -0
  591. package/dist/internal/{funding → routes}/Evidence.d.ts +3 -3
  592. package/dist/internal/routes/Evidence.d.ts.map +1 -0
  593. package/dist/internal/{funding → routes}/Evidence.js +9 -17
  594. package/dist/internal/routes/Evidence.js.map +1 -0
  595. package/dist/internal/routes/Observability.d.ts +154 -0
  596. package/dist/internal/routes/Observability.d.ts.map +1 -0
  597. package/dist/internal/routes/Observability.js +389 -0
  598. package/dist/internal/routes/Observability.js.map +1 -0
  599. package/dist/internal/{funding → routes}/Provider.d.ts +350 -104
  600. package/dist/internal/routes/Provider.d.ts.map +1 -0
  601. package/dist/internal/{funding → routes}/Provider.js +233 -97
  602. package/dist/internal/routes/Provider.js.map +1 -0
  603. package/dist/internal/{funding → routes}/Reconciliation.d.ts +11 -6
  604. package/dist/internal/routes/Reconciliation.d.ts.map +1 -0
  605. package/dist/internal/{funding → routes}/Reconciliation.js +408 -158
  606. package/dist/internal/routes/Reconciliation.js.map +1 -0
  607. package/dist/internal/routes/Route.d.ts +21 -0
  608. package/dist/internal/routes/Route.d.ts.map +1 -0
  609. package/dist/internal/{funding → routes}/Route.js +1 -1
  610. package/dist/internal/routes/Route.js.map +1 -0
  611. package/dist/internal/{funding → routes}/SourceObservation.d.ts +6 -6
  612. package/dist/internal/routes/SourceObservation.d.ts.map +1 -0
  613. package/dist/internal/{funding → routes}/SourceObservation.js +13 -15
  614. package/dist/internal/routes/SourceObservation.js.map +1 -0
  615. package/dist/internal/{funding → routes}/Subsidy.d.ts +48 -3
  616. package/dist/internal/routes/Subsidy.d.ts.map +1 -0
  617. package/dist/internal/{funding → routes}/Subsidy.js +43 -3
  618. package/dist/internal/routes/Subsidy.js.map +1 -0
  619. package/dist/internal/{funding → routes}/Token.d.ts +4 -4
  620. package/dist/internal/routes/Token.d.ts.map +1 -0
  621. package/dist/internal/{funding → routes}/Token.js +3 -3
  622. package/dist/internal/routes/Token.js.map +1 -0
  623. package/dist/internal/{funding → routes}/Transfer.d.ts +324 -34
  624. package/dist/internal/routes/Transfer.d.ts.map +1 -0
  625. package/dist/internal/routes/Transfer.js +728 -0
  626. package/dist/internal/routes/Transfer.js.map +1 -0
  627. package/dist/internal/routes/TransferReconciliation.d.ts +55 -0
  628. package/dist/internal/routes/TransferReconciliation.d.ts.map +1 -0
  629. package/dist/internal/routes/TransferReconciliation.js +422 -0
  630. package/dist/internal/routes/TransferReconciliation.js.map +1 -0
  631. package/dist/internal/routes/TransferSubsidy.d.ts +201 -0
  632. package/dist/internal/routes/TransferSubsidy.d.ts.map +1 -0
  633. package/dist/internal/routes/TransferSubsidy.js +256 -0
  634. package/dist/internal/routes/TransferSubsidy.js.map +1 -0
  635. package/dist/internal/routes/TransferWebhook.d.ts +21 -0
  636. package/dist/internal/routes/TransferWebhook.d.ts.map +1 -0
  637. package/dist/internal/routes/TransferWebhook.js +43 -0
  638. package/dist/internal/routes/TransferWebhook.js.map +1 -0
  639. package/dist/internal/{funding → routes}/index.d.ts +3 -0
  640. package/dist/internal/routes/index.d.ts.map +1 -0
  641. package/dist/internal/{funding → routes}/index.js +3 -0
  642. package/dist/internal/routes/index.js.map +1 -0
  643. package/dist/internal/{funding → routes}/providers/across.d.ts +4 -4
  644. package/dist/internal/routes/providers/across.d.ts.map +1 -0
  645. package/dist/internal/{funding → routes}/providers/across.js +13 -13
  646. package/dist/internal/routes/providers/across.js.map +1 -0
  647. package/dist/internal/{funding → routes}/providers/relay.d.ts +21 -12
  648. package/dist/internal/routes/providers/relay.d.ts.map +1 -0
  649. package/dist/internal/{funding → routes}/providers/relay.js +197 -122
  650. package/dist/internal/routes/providers/relay.js.map +1 -0
  651. package/dist/internal/{funding → routes}/providers/rhino.d.ts +4 -4
  652. package/dist/internal/routes/providers/rhino.d.ts.map +1 -0
  653. package/dist/internal/{funding → routes}/providers/rhino.js +10 -10
  654. package/dist/internal/routes/providers/rhino.js.map +1 -0
  655. package/dist/internal/{funding → routes}/providers/squid.d.ts +4 -4
  656. package/dist/internal/routes/providers/squid.d.ts.map +1 -0
  657. package/dist/internal/{funding → routes}/providers/squid.js +14 -14
  658. package/dist/internal/routes/providers/squid.js.map +1 -0
  659. package/dist/internal/routes/providers/stargate.d.ts +165 -0
  660. package/dist/internal/routes/providers/stargate.d.ts.map +1 -0
  661. package/dist/internal/routes/providers/stargate.js +898 -0
  662. package/dist/internal/routes/providers/stargate.js.map +1 -0
  663. package/dist/internal/{funding → routes}/providers/symbiosis.d.ts +4 -4
  664. package/dist/internal/routes/providers/symbiosis.d.ts.map +1 -0
  665. package/dist/internal/{funding → routes}/providers/symbiosis.js +30 -20
  666. package/dist/internal/routes/providers/symbiosis.js.map +1 -0
  667. package/dist/internal/webhookDestinations/slack.d.ts.map +1 -1
  668. package/dist/internal/webhookDestinations/slack.js +22 -6
  669. package/dist/internal/webhookDestinations/slack.js.map +1 -1
  670. package/dist/providers/index.d.ts +12 -12
  671. package/dist/providers/index.d.ts.map +1 -1
  672. package/dist/providers/index.js +12 -12
  673. package/dist/providers/index.js.map +1 -1
  674. package/dist/server.d.ts +19 -0
  675. package/dist/server.d.ts.map +1 -0
  676. package/dist/server.js +19 -0
  677. package/dist/server.js.map +1 -0
  678. package/package.json +15 -4
  679. package/src/ApiKey.ts +1 -1
  680. package/src/ApiKeys.test.ts +1033 -3
  681. package/src/ApiKeys.ts +489 -48
  682. package/src/App.test-d.ts +1 -1
  683. package/src/App.test.ts +216 -25
  684. package/src/App.ts +335 -31
  685. package/src/Assets.test.ts +2 -2
  686. package/src/Assets.ts +3 -1
  687. package/src/Auth.test-d.ts +1 -1
  688. package/src/Client.test-d.ts +611 -101
  689. package/src/Handler.ts +0 -1
  690. package/src/OpenApi.contract.test.ts +195 -0
  691. package/src/Scope.ts +17 -5
  692. package/src/Webhooks.ts +2 -2
  693. package/src/admin/App.test.ts +30 -2
  694. package/src/admin/App.ts +42 -6
  695. package/src/admin/apps/api-keys.test.ts +267 -5
  696. package/src/admin/apps/api-keys.ts +100 -50
  697. package/src/admin/apps/earn-vaults.test.ts +158 -0
  698. package/src/admin/apps/earn-vaults.ts +681 -7
  699. package/src/admin/apps/organizations.test.ts +342 -1
  700. package/src/admin/apps/organizations.ts +368 -8
  701. package/src/admin/apps/routes-support.test.ts +200 -0
  702. package/src/admin/apps/routes-support.ts +201 -0
  703. package/src/admin/apps/routes.test.ts +450 -0
  704. package/src/admin/apps/routes.ts +896 -0
  705. package/src/admin/apps/scopes.test.ts +15 -5
  706. package/src/admin/apps/subsidies.test.ts +306 -0
  707. package/src/admin/apps/subsidies.ts +457 -0
  708. package/src/admin/apps/verified-tokens.test.ts +8 -3
  709. package/src/admin/apps/verified-tokens.ts +3 -3
  710. package/src/admin/ui/plugin.ts +1 -2
  711. package/src/admin/ui/src/components/RewardCampaignForm.tsx +1009 -0
  712. package/src/admin/ui/src/lib/config.ts +11 -2
  713. package/src/admin/ui/src/lib/earn-vaults.ts +2 -2
  714. package/src/admin/ui/src/lib/organizations.test.ts +147 -3
  715. package/src/admin/ui/src/lib/organizations.ts +136 -0
  716. package/src/admin/ui/src/lib/query-client.ts +1 -1
  717. package/src/admin/ui/src/lib/reward-campaigns.ts +136 -0
  718. package/src/admin/ui/src/lib/routes.test.ts +88 -0
  719. package/src/admin/ui/src/lib/routes.ts +304 -0
  720. package/src/admin/ui/src/lib/subsidies.ts +75 -0
  721. package/src/admin/ui/src/routeTree.gen.ts +63 -0
  722. package/src/admin/ui/src/routes/__root.tsx +12 -1
  723. package/src/admin/ui/src/routes/api-keys.tsx +196 -84
  724. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +105 -70
  725. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +334 -2
  726. package/src/admin/ui/src/routes/routes.tsx +1615 -0
  727. package/src/admin/ui/src/routes/routes_.support.tsx +248 -0
  728. package/src/admin/ui/src/routes/subsidies.tsx +799 -0
  729. package/src/admin/ui.generated.ts +144 -69
  730. package/src/analytics/Analytics.test.ts +108 -18
  731. package/src/analytics/Analytics.ts +38 -6
  732. package/src/analytics/tables/requestEvents.test.ts +100 -0
  733. package/src/analytics/tables/requestEvents.ts +10 -1
  734. package/src/analytics/tables/routesLifecycleIntervals.ts +140 -0
  735. package/src/apps/Zones.test.ts +18 -3
  736. package/src/apps/Zones.ts +55 -8
  737. package/src/apps/composition.test.ts +68 -59
  738. package/src/apps/data/App.test.ts +154 -2
  739. package/src/apps/data/App.ts +102 -33
  740. package/src/apps/data/routes/activities.test.ts +419 -7
  741. package/src/apps/data/routes/activities.ts +683 -216
  742. package/src/apps/data/routes/balances.test.ts +2 -2
  743. package/src/apps/data/routes/blocks.test.ts +46 -1
  744. package/src/apps/data/routes/coingecko.test.ts +419 -1
  745. package/src/apps/data/routes/coingecko.ts +309 -253
  746. package/src/apps/data/routes/earn.discovery.test.ts +274 -0
  747. package/src/apps/data/routes/earn.test.ts +1661 -29
  748. package/src/apps/data/routes/earn.ts +2314 -328
  749. package/src/apps/data/routes/exchanges.test.ts +752 -30
  750. package/src/apps/data/routes/exchanges.ts +954 -753
  751. package/src/apps/data/routes/fee-amm.test.ts +224 -0
  752. package/src/apps/data/routes/fee-amm.ts +208 -178
  753. package/src/apps/data/routes/indexer.test.ts +389 -0
  754. package/src/apps/data/routes/indexer.ts +165 -69
  755. package/src/apps/data/routes/receipts.test.ts +1 -1
  756. package/src/apps/data/routes/rpc.test.ts +352 -8
  757. package/src/apps/data/routes/rpc.ts +407 -219
  758. package/src/apps/data/routes/rpc.zone.test.ts +340 -0
  759. package/src/apps/data/routes/tokenlist.test.ts +285 -0
  760. package/src/apps/data/routes/tokenlist.ts +173 -88
  761. package/src/apps/data/routes/tokens.test.ts +93 -3
  762. package/src/apps/data/routes/tokens.ts +39 -23
  763. package/src/apps/data/routes/transactions.test.ts +1 -1
  764. package/src/apps/data/routes/transfers.test.ts +56 -24
  765. package/src/apps/data/routes/transfers.ts +19 -8
  766. package/src/apps/data/routes/valuation.test.ts +1 -1
  767. package/src/apps/data/routes/verified-tokens.test.ts +345 -0
  768. package/src/apps/data/routes/verified-tokens.ts +99 -29
  769. package/src/apps/data/routes/webhooks.test.ts +659 -81
  770. package/src/apps/data/routes/webhooks.ts +1104 -817
  771. package/src/apps/data/routes/zones.test.ts +148 -71
  772. package/src/apps/data/routes/zones.ts +71 -55
  773. package/src/apps/docs/reference.ts +2 -2
  774. package/src/apps/index.ts +1 -1
  775. package/src/apps/management/App.ts +9 -51
  776. package/src/apps/management/Billing.test.ts +375 -14
  777. package/src/apps/management/Billing.ts +283 -34
  778. package/src/apps/management/routes/api-keys.test.ts +269 -7
  779. package/src/apps/management/routes/api-keys.ts +61 -20
  780. package/src/apps/management/routes/billing.test.ts +477 -15
  781. package/src/apps/management/routes/billing.ts +377 -50
  782. package/src/apps/management/routes/faucet.test.ts +1 -1
  783. package/src/apps/management/routes/faucet.ts +1 -1
  784. package/src/apps/management/routes/invitations.test.ts +270 -3
  785. package/src/apps/management/routes/invitations.ts +185 -15
  786. package/src/apps/management/routes/invoicePreview.test.ts +549 -0
  787. package/src/apps/management/routes/me.test.ts +246 -5
  788. package/src/apps/management/routes/me.ts +7 -2
  789. package/src/apps/management/routes/members.test.ts +108 -0
  790. package/src/apps/management/routes/orgs.test.ts +191 -3
  791. package/src/apps/management/routes/orgs.ts +58 -11
  792. package/src/apps/management/routes/projects.test.ts +33 -3
  793. package/src/apps/management/routes/projects.ts +6 -1
  794. package/src/apps/management/routes/scopes.test.ts +30 -2
  795. package/src/apps/management/routes/scopes.ts +4 -1
  796. package/src/apps/management/routes/usage.test.ts +32 -0
  797. package/src/apps/management/routes/usage.ts +22 -4
  798. package/src/apps/management/routes/webhooks.test.ts +49 -26
  799. package/src/apps/management/routes/webhooks.ts +93 -38
  800. package/src/apps/mcp.test.ts +6 -6
  801. package/src/apps/mcp.ts +7 -7
  802. package/src/apps/mpp/App.ts +37 -7
  803. package/src/apps/mpp/Mpp.test.ts +49 -8
  804. package/src/apps/mpp/Mpp.zone.test.ts +219 -0
  805. package/src/apps/mpp/internal/Adapter.ts +34 -0
  806. package/src/apps/mpp/internal/Policy.test.ts +86 -31
  807. package/src/apps/mpp/internal/Policy.ts +49 -7
  808. package/src/apps/mpp/internal/Sponsorship.test.ts +207 -0
  809. package/src/apps/mpp/internal/Sponsorship.ts +9 -3
  810. package/src/apps/relay/App.test.ts +1024 -38
  811. package/src/apps/relay/App.ts +228 -32
  812. package/src/apps/relay/App.zone-billing.test.ts +257 -0
  813. package/src/apps/relay/Sponsorships.test.ts +67 -4
  814. package/src/apps/relay/Sponsorships.ts +253 -29
  815. package/src/apps/relay/Sponsorships.zone.test.ts +102 -0
  816. package/src/apps/{funding → routes}/Access.ts +6 -6
  817. package/src/apps/routes/App.test.ts +165 -0
  818. package/src/apps/routes/App.ts +96 -0
  819. package/src/apps/{funding → routes}/Inventory.ts +2 -2
  820. package/src/apps/routes/index.ts +1 -0
  821. package/src/apps/{funding → routes}/routes/chains.test.ts +66 -66
  822. package/src/apps/{funding → routes}/routes/chains.ts +23 -23
  823. package/src/apps/{funding → routes}/routes/deposit-addresses.test.ts +1362 -462
  824. package/src/apps/{funding → routes}/routes/deposit-addresses.ts +568 -248
  825. package/src/apps/{funding → routes}/routes/providers.test.ts +27 -33
  826. package/src/apps/{funding → routes}/routes/providers.ts +23 -23
  827. package/src/apps/{funding → routes}/routes/quotes.test.ts +298 -41
  828. package/src/apps/{funding → routes}/routes/quotes.ts +57 -40
  829. package/src/apps/routes/routes/transfers.test.ts +2876 -0
  830. package/src/apps/routes/routes/transfers.ts +1332 -0
  831. package/src/cli/Cli.test.ts +1 -1
  832. package/src/cli/commands/admin.test.ts +748 -1
  833. package/src/cli/commands/admin.ts +278 -0
  834. package/src/cloudflare.ts +52 -47
  835. package/src/db/Db.test.ts +245 -2
  836. package/src/db/Db.ts +1511 -34
  837. package/src/db/Schema.ts +744 -228
  838. package/src/db/tables/apiKeyAdmissionBootstraps.ts +4 -0
  839. package/src/db/tables/apiKeyAdmissions.ts +218 -0
  840. package/src/db/tables/apiKeyOwnerAdmissions.ts +4 -0
  841. package/src/db/tables/apiKeyOwnerTombstones.ts +81 -0
  842. package/src/db/tables/apiKeyRevocations.test.ts +74 -0
  843. package/src/db/tables/apiKeyRevocations.ts +121 -0
  844. package/src/db/tables/authAccounts.ts +105 -0
  845. package/src/db/tables/authSessions.ts +13 -0
  846. package/src/db/tables/authVerifications.ts +13 -0
  847. package/src/db/tables/invitations.ts +142 -45
  848. package/src/db/tables/memberships.ts +79 -3
  849. package/src/db/tables/organizations.test.ts +725 -7
  850. package/src/db/tables/organizations.ts +182 -49
  851. package/src/db/tables/projects.test.ts +71 -0
  852. package/src/db/tables/projects.ts +59 -4
  853. package/src/db/tables/requestUsage.ts +4 -1
  854. package/src/db/tables/rewardAccounts.ts +178 -0
  855. package/src/db/tables/rewardCampaignDistributors.ts +68 -0
  856. package/src/db/tables/rewardCampaigns.test.ts +1388 -0
  857. package/src/db/tables/rewardCampaigns.ts +647 -0
  858. package/src/db/tables/rewardCredits.ts +110 -0
  859. package/src/db/tables/rewardEligibilityAssociations.test.ts +271 -0
  860. package/src/db/tables/rewardEligibilityAssociations.ts +184 -0
  861. package/src/db/tables/rewardRuns.ts +514 -0
  862. package/src/db/tables/rewardTransactionAttempts.ts +272 -0
  863. package/src/db/tables/routesCatalog.test.ts +185 -0
  864. package/src/db/tables/routesCatalog.ts +163 -0
  865. package/src/db/tables/routesDepositAddresses.test.ts +1048 -0
  866. package/src/db/tables/routesDepositAddresses.ts +1008 -0
  867. package/src/db/tables/{fundingDepositRequestObservations.test.ts → routesDepositRequestObservations.test.ts} +13 -14
  868. package/src/db/tables/{fundingDepositRequestObservations.ts → routesDepositRequestObservations.ts} +10 -10
  869. package/src/db/tables/{fundingDeposits.test.ts → routesDeposits.test.ts} +316 -46
  870. package/src/db/tables/routesDeposits.ts +1062 -0
  871. package/src/db/tables/routesIdempotency.test.ts +796 -0
  872. package/src/db/tables/routesIdempotency.ts +496 -0
  873. package/src/db/tables/routesSubsidies.test.ts +120 -0
  874. package/src/db/tables/routesSubsidies.ts +71 -0
  875. package/src/db/tables/{fundingTransferEvents.ts → routesTransferEvents.ts} +4 -4
  876. package/src/db/tables/routesTransferSubsidies.ts +38 -0
  877. package/src/db/tables/routesTransferSubsidyNonces.ts +124 -0
  878. package/src/db/tables/routesTransferTransactions.test.ts +195 -0
  879. package/src/db/tables/routesTransferTransactions.ts +158 -0
  880. package/src/db/tables/routesTransfers.test.ts +338 -0
  881. package/src/db/tables/routesTransfers.ts +662 -0
  882. package/src/db/tables/sponsoredTransactions.test.ts +563 -1
  883. package/src/db/tables/sponsoredTransactions.ts +386 -42
  884. package/src/db/tables/sponsorshipAttributions.test.ts +160 -0
  885. package/src/db/tables/sponsorshipAttributions.ts +168 -0
  886. package/src/db/tables/sponsorshipReconciliationCursors.test.ts +115 -0
  887. package/src/db/tables/sponsorshipReconciliationCursors.ts +67 -0
  888. package/src/db/tables/stripeCustomers.test.ts +85 -0
  889. package/src/db/tables/stripeCustomers.ts +24 -0
  890. package/src/db/tables/users.test.ts +129 -0
  891. package/src/db/tables/users.ts +49 -3
  892. package/src/db/tables/webhookQueueEvents.ts +8 -1
  893. package/src/db/tables/webhookSubscriptions.ts +103 -21
  894. package/src/handlers/internal/executionError.ts +3 -4
  895. package/src/handlers/internal/multisig.ts +13 -816
  896. package/src/handlers/internal/sponsorship.ts +26 -10
  897. package/src/handlers/relay.test-d.ts +9 -1
  898. package/src/handlers/relay.test.ts +823 -3
  899. package/src/handlers/relay.ts +127 -107
  900. package/src/index.test-d.ts +7 -0
  901. package/src/index.ts +0 -17
  902. package/src/internal/AssetResponse.ts +26 -0
  903. package/src/internal/Auth.test.ts +1564 -9
  904. package/src/internal/Auth.ts +833 -239
  905. package/src/internal/BetterAuth.test.ts +242 -0
  906. package/src/internal/BetterAuth.ts +349 -0
  907. package/src/internal/Cache.ts +2 -0
  908. package/src/internal/EarnRates.test.ts +17 -0
  909. package/src/internal/EarnRates.ts +124 -31
  910. package/src/internal/EarnSharePrices.test.ts +182 -0
  911. package/src/internal/EarnSharePrices.ts +313 -0
  912. package/src/internal/EarnVaults.test.ts +21 -0
  913. package/src/internal/EarnVaults.ts +37 -15
  914. package/src/internal/Email.ts +54 -0
  915. package/src/internal/Idempotency.test.ts +2 -2
  916. package/src/internal/Log.test-d.ts +10 -7
  917. package/src/internal/Log.test.ts +114 -16
  918. package/src/internal/Log.ts +55 -40
  919. package/src/internal/MetricSink.test.ts +313 -26
  920. package/src/internal/MetricSink.ts +73 -8
  921. package/src/internal/Mpp.test.ts +31 -0
  922. package/src/internal/Mpp.ts +21 -24
  923. package/src/internal/OpenApi.ts +45 -12
  924. package/src/internal/Provider.test.ts +1 -1
  925. package/src/internal/Provider.ts +1 -1
  926. package/src/internal/RateLimit.test.ts +21 -3
  927. package/src/internal/RateLimit.ts +12 -1
  928. package/src/internal/Store.test-d.ts +1 -1
  929. package/src/internal/Store.test.ts +151 -8
  930. package/src/internal/Store.ts +76 -9
  931. package/src/internal/Tidx.test.ts +59 -8
  932. package/src/internal/Tidx.ts +86 -14
  933. package/src/internal/Timing.test.ts +77 -0
  934. package/src/internal/Timing.ts +83 -6
  935. package/src/internal/VercelOidc.test.ts +188 -0
  936. package/src/internal/VercelOidc.ts +193 -0
  937. package/src/internal/VerifiedTokens.test.ts +60 -6
  938. package/src/internal/VerifiedTokens.ts +21 -24
  939. package/src/internal/Viem.batch.test.ts +80 -0
  940. package/src/internal/Viem.test.ts +201 -2
  941. package/src/internal/Viem.ts +249 -17
  942. package/src/internal/Webhooks.test.ts +125 -1
  943. package/src/internal/Webhooks.ts +22 -4
  944. package/src/internal/ZoneRpc.ts +50 -0
  945. package/src/internal/exchange/Provider.test.ts +2 -2
  946. package/src/internal/index.test.ts +3 -1
  947. package/src/internal/index.ts +3 -1
  948. package/src/internal/rewards/Audit.ts +231 -0
  949. package/src/internal/rewards/Campaigns.test.ts +1234 -0
  950. package/src/internal/rewards/Campaigns.ts +1205 -0
  951. package/src/internal/rewards/Credits.ts +165 -0
  952. package/src/internal/rewards/Events.local.test.ts +113 -0
  953. package/src/internal/rewards/Events.test.ts +152 -0
  954. package/src/internal/rewards/Events.ts +468 -0
  955. package/src/internal/rewards/Projection.test.ts +681 -0
  956. package/src/internal/rewards/Projection.ts +987 -0
  957. package/src/internal/rewards/Rates.test.ts +171 -0
  958. package/src/internal/rewards/Rates.ts +110 -0
  959. package/src/internal/rewards/Read.test.ts +501 -0
  960. package/src/internal/rewards/Read.ts +476 -0
  961. package/src/internal/rewards/Runner.checkpoint.test.ts +80 -0
  962. package/src/internal/rewards/Runner.states.test.ts +188 -0
  963. package/src/internal/rewards/Runner.test.ts +90 -0
  964. package/src/internal/rewards/Runner.ts +2229 -0
  965. package/src/internal/rewards/Signer.test.ts +79 -0
  966. package/src/internal/rewards/Signer.ts +180 -0
  967. package/src/internal/rewards/index.ts +14 -0
  968. package/src/internal/{funding → routes}/Action.test.ts +63 -14
  969. package/src/internal/{funding → routes}/Action.ts +35 -8
  970. package/src/internal/{funding → routes}/Catalog.test.ts +3 -3
  971. package/src/internal/{funding → routes}/Catalog.ts +39 -39
  972. package/src/internal/{funding → routes}/Chain.test.ts +1 -1
  973. package/src/internal/{funding → routes}/Chain.ts +11 -11
  974. package/src/internal/{funding → routes}/Deposit.test.ts +1 -1
  975. package/src/internal/{funding → routes}/Deposit.ts +93 -45
  976. package/src/internal/{funding → routes}/DepositAddress.test.ts +11 -3
  977. package/src/internal/{funding → routes}/DepositAddress.ts +132 -53
  978. package/src/internal/{funding → routes}/DepositWebhook.test.ts +61 -18
  979. package/src/internal/{funding → routes}/DepositWebhook.ts +9 -8
  980. package/src/internal/routes/Economics.test.ts +42 -0
  981. package/src/internal/routes/Economics.ts +47 -0
  982. package/src/internal/{funding → routes}/Evidence.test.ts +6 -6
  983. package/src/internal/{funding → routes}/Evidence.ts +11 -22
  984. package/src/internal/routes/Observability.test.ts +636 -0
  985. package/src/internal/routes/Observability.ts +668 -0
  986. package/src/internal/{funding → routes}/Provider.test.ts +489 -153
  987. package/src/internal/{funding → routes}/Provider.ts +531 -185
  988. package/src/internal/{funding → routes}/Reconciliation.local.test.ts +84 -12
  989. package/src/internal/{funding → routes}/Reconciliation.test.ts +1213 -279
  990. package/src/internal/{funding → routes}/Reconciliation.ts +501 -203
  991. package/src/internal/routes/Reconciliation.unattributed.test.ts +250 -0
  992. package/src/internal/{funding → routes}/Route.ts +7 -7
  993. package/src/internal/{funding → routes}/SourceObservation.test.ts +13 -14
  994. package/src/internal/{funding → routes}/SourceObservation.ts +18 -22
  995. package/src/internal/{funding → routes}/Subsidy.local.test.ts +7 -7
  996. package/src/internal/routes/Subsidy.test.ts +169 -0
  997. package/src/internal/{funding → routes}/Subsidy.ts +86 -6
  998. package/src/internal/{funding → routes}/Token.test.ts +1 -1
  999. package/src/internal/{funding → routes}/Token.ts +5 -5
  1000. package/src/internal/routes/Transfer.test.ts +1199 -0
  1001. package/src/internal/routes/Transfer.ts +1206 -0
  1002. package/src/internal/routes/TransferReconciliation.test.ts +731 -0
  1003. package/src/internal/routes/TransferReconciliation.ts +527 -0
  1004. package/src/internal/routes/TransferSubsidy.test.ts +172 -0
  1005. package/src/internal/routes/TransferSubsidy.ts +447 -0
  1006. package/src/internal/routes/TransferWebhook.test.ts +128 -0
  1007. package/src/internal/routes/TransferWebhook.ts +67 -0
  1008. package/src/internal/{funding → routes}/index.test.ts +6 -3
  1009. package/src/internal/{funding → routes}/index.ts +3 -0
  1010. package/src/internal/{funding → routes}/providers/across.ts +16 -16
  1011. package/src/internal/{funding → routes}/providers/index.test.ts +157 -44
  1012. package/src/internal/{funding → routes}/providers/relay.test.ts +165 -32
  1013. package/src/internal/{funding → routes}/providers/relay.ts +231 -136
  1014. package/src/internal/{funding → routes}/providers/rhino.ts +16 -16
  1015. package/src/internal/{funding → routes}/providers/squid.ts +17 -17
  1016. package/src/internal/routes/providers/stargate.test.ts +728 -0
  1017. package/src/internal/routes/providers/stargate.ts +1276 -0
  1018. package/src/internal/{funding → routes}/providers/symbiosis.ts +64 -24
  1019. package/src/internal/webhookDestinations/slack.ts +20 -5
  1020. package/src/providers/index.ts +13 -13
  1021. package/src/server.ts +18 -0
  1022. package/dist/apps/funding/Access.d.ts.map +0 -1
  1023. package/dist/apps/funding/Access.js.map +0 -1
  1024. package/dist/apps/funding/App.js.map +0 -1
  1025. package/dist/apps/funding/Inventory.d.ts.map +0 -1
  1026. package/dist/apps/funding/Inventory.js.map +0 -1
  1027. package/dist/apps/funding/ProviderAttempts.d.ts +0 -5
  1028. package/dist/apps/funding/ProviderAttempts.d.ts.map +0 -1
  1029. package/dist/apps/funding/ProviderAttempts.js +0 -24
  1030. package/dist/apps/funding/ProviderAttempts.js.map +0 -1
  1031. package/dist/apps/funding/index.d.ts +0 -2
  1032. package/dist/apps/funding/index.d.ts.map +0 -1
  1033. package/dist/apps/funding/index.js +0 -2
  1034. package/dist/apps/funding/index.js.map +0 -1
  1035. package/dist/apps/funding/routes/chains.d.ts.map +0 -1
  1036. package/dist/apps/funding/routes/chains.js.map +0 -1
  1037. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +0 -1
  1038. package/dist/apps/funding/routes/deposit-addresses.js.map +0 -1
  1039. package/dist/apps/funding/routes/providers.d.ts.map +0 -1
  1040. package/dist/apps/funding/routes/providers.js +0 -57
  1041. package/dist/apps/funding/routes/providers.js.map +0 -1
  1042. package/dist/apps/funding/routes/quotes.d.ts.map +0 -1
  1043. package/dist/apps/funding/routes/quotes.js.map +0 -1
  1044. package/dist/apps/funding/routes/transfers.d.ts.map +0 -1
  1045. package/dist/apps/funding/routes/transfers.js +0 -622
  1046. package/dist/apps/funding/routes/transfers.js.map +0 -1
  1047. package/dist/db/tables/fundingCatalog.d.ts +0 -58
  1048. package/dist/db/tables/fundingCatalog.d.ts.map +0 -1
  1049. package/dist/db/tables/fundingCatalog.js.map +0 -1
  1050. package/dist/db/tables/fundingDepositAddresses.d.ts +0 -192
  1051. package/dist/db/tables/fundingDepositAddresses.d.ts.map +0 -1
  1052. package/dist/db/tables/fundingDepositAddresses.js +0 -235
  1053. package/dist/db/tables/fundingDepositAddresses.js.map +0 -1
  1054. package/dist/db/tables/fundingDepositRequestObservations.d.ts.map +0 -1
  1055. package/dist/db/tables/fundingDepositRequestObservations.js.map +0 -1
  1056. package/dist/db/tables/fundingDeposits.d.ts.map +0 -1
  1057. package/dist/db/tables/fundingDeposits.js +0 -295
  1058. package/dist/db/tables/fundingDeposits.js.map +0 -1
  1059. package/dist/db/tables/fundingIdempotency.d.ts +0 -91
  1060. package/dist/db/tables/fundingIdempotency.d.ts.map +0 -1
  1061. package/dist/db/tables/fundingIdempotency.js +0 -103
  1062. package/dist/db/tables/fundingIdempotency.js.map +0 -1
  1063. package/dist/db/tables/fundingTransferEvents.d.ts.map +0 -1
  1064. package/dist/db/tables/fundingTransferEvents.js.map +0 -1
  1065. package/dist/db/tables/fundingTransferTransactions.d.ts +0 -15
  1066. package/dist/db/tables/fundingTransferTransactions.d.ts.map +0 -1
  1067. package/dist/db/tables/fundingTransferTransactions.js +0 -27
  1068. package/dist/db/tables/fundingTransferTransactions.js.map +0 -1
  1069. package/dist/db/tables/fundingTransfers.d.ts +0 -82
  1070. package/dist/db/tables/fundingTransfers.d.ts.map +0 -1
  1071. package/dist/db/tables/fundingTransfers.js +0 -89
  1072. package/dist/db/tables/fundingTransfers.js.map +0 -1
  1073. package/dist/internal/funding/Action.d.ts.map +0 -1
  1074. package/dist/internal/funding/Action.js.map +0 -1
  1075. package/dist/internal/funding/Catalog.d.ts.map +0 -1
  1076. package/dist/internal/funding/Catalog.js.map +0 -1
  1077. package/dist/internal/funding/Chain.d.ts.map +0 -1
  1078. package/dist/internal/funding/Chain.js.map +0 -1
  1079. package/dist/internal/funding/Deposit.d.ts.map +0 -1
  1080. package/dist/internal/funding/Deposit.js.map +0 -1
  1081. package/dist/internal/funding/DepositAddress.d.ts.map +0 -1
  1082. package/dist/internal/funding/DepositAddress.js.map +0 -1
  1083. package/dist/internal/funding/DepositWebhook.d.ts.map +0 -1
  1084. package/dist/internal/funding/DepositWebhook.js.map +0 -1
  1085. package/dist/internal/funding/Evidence.d.ts.map +0 -1
  1086. package/dist/internal/funding/Evidence.js.map +0 -1
  1087. package/dist/internal/funding/Provider.d.ts.map +0 -1
  1088. package/dist/internal/funding/Provider.js.map +0 -1
  1089. package/dist/internal/funding/Reconciliation.d.ts.map +0 -1
  1090. package/dist/internal/funding/Reconciliation.js.map +0 -1
  1091. package/dist/internal/funding/Route.d.ts +0 -21
  1092. package/dist/internal/funding/Route.d.ts.map +0 -1
  1093. package/dist/internal/funding/Route.js.map +0 -1
  1094. package/dist/internal/funding/SourceObservation.d.ts.map +0 -1
  1095. package/dist/internal/funding/SourceObservation.js.map +0 -1
  1096. package/dist/internal/funding/Subsidy.d.ts.map +0 -1
  1097. package/dist/internal/funding/Subsidy.js.map +0 -1
  1098. package/dist/internal/funding/Token.d.ts.map +0 -1
  1099. package/dist/internal/funding/Token.js.map +0 -1
  1100. package/dist/internal/funding/Transfer.d.ts.map +0 -1
  1101. package/dist/internal/funding/Transfer.js +0 -334
  1102. package/dist/internal/funding/Transfer.js.map +0 -1
  1103. package/dist/internal/funding/index.d.ts.map +0 -1
  1104. package/dist/internal/funding/index.js.map +0 -1
  1105. package/dist/internal/funding/providers/across.d.ts.map +0 -1
  1106. package/dist/internal/funding/providers/across.js.map +0 -1
  1107. package/dist/internal/funding/providers/relay.d.ts.map +0 -1
  1108. package/dist/internal/funding/providers/relay.js.map +0 -1
  1109. package/dist/internal/funding/providers/rhino.d.ts.map +0 -1
  1110. package/dist/internal/funding/providers/rhino.js.map +0 -1
  1111. package/dist/internal/funding/providers/squid.d.ts.map +0 -1
  1112. package/dist/internal/funding/providers/squid.js.map +0 -1
  1113. package/dist/internal/funding/providers/stargate.d.ts +0 -38
  1114. package/dist/internal/funding/providers/stargate.d.ts.map +0 -1
  1115. package/dist/internal/funding/providers/stargate.js +0 -277
  1116. package/dist/internal/funding/providers/stargate.js.map +0 -1
  1117. package/dist/internal/funding/providers/symbiosis.d.ts.map +0 -1
  1118. package/dist/internal/funding/providers/symbiosis.js.map +0 -1
  1119. package/src/apps/funding/App.test.ts +0 -78
  1120. package/src/apps/funding/App.ts +0 -78
  1121. package/src/apps/funding/ProviderAttempts.ts +0 -26
  1122. package/src/apps/funding/index.ts +0 -1
  1123. package/src/apps/funding/routes/transfers.test.ts +0 -1638
  1124. package/src/apps/funding/routes/transfers.ts +0 -721
  1125. package/src/db/tables/fundingCatalog.test.ts +0 -122
  1126. package/src/db/tables/fundingCatalog.ts +0 -163
  1127. package/src/db/tables/fundingDepositAddresses.test.ts +0 -608
  1128. package/src/db/tables/fundingDepositAddresses.ts +0 -443
  1129. package/src/db/tables/fundingDeposits.ts +0 -572
  1130. package/src/db/tables/fundingIdempotency.test.ts +0 -182
  1131. package/src/db/tables/fundingIdempotency.ts +0 -180
  1132. package/src/db/tables/fundingTransferTransactions.test.ts +0 -69
  1133. package/src/db/tables/fundingTransferTransactions.ts +0 -37
  1134. package/src/db/tables/fundingTransfers.test.ts +0 -89
  1135. package/src/db/tables/fundingTransfers.ts +0 -153
  1136. package/src/handlers/internal/multisig.test.ts +0 -818
  1137. package/src/internal/funding/Subsidy.test.ts +0 -75
  1138. package/src/internal/funding/Transfer.test.ts +0 -369
  1139. package/src/internal/funding/Transfer.ts +0 -545
  1140. package/src/internal/funding/providers/stargate.test.ts +0 -163
  1141. package/src/internal/funding/providers/stargate.ts +0 -409
  1142. /package/dist/apps/{funding → routes}/Inventory.d.ts +0 -0
  1143. /package/src/internal/{funding → routes}/Route.test.ts +0 -0
@@ -1,5 +1,11 @@
1
1
  import * as ApiKeys from './ApiKeys.js'
2
+ import * as ApiKeyAdmissions from './db/tables/apiKeyAdmissions.js'
3
+ import * as ApiKeyOwnerTombstones from './db/tables/apiKeyOwnerTombstones.js'
4
+ import * as ApiKeyRevocations from './db/tables/apiKeyRevocations.js'
5
+ import * as Organizations from './db/tables/organizations.js'
6
+ import * as Projects from './db/tables/projects.js'
2
7
  import * as Store from './internal/Store.js'
8
+ import * as TestApp from '../test/App.js'
3
9
 
4
10
  describe('resolve', () => {
5
11
  test('resolves an unknown token to null', async () => {
@@ -52,6 +58,16 @@ describe('resolve', () => {
52
58
  expect(await ApiKeys.resolve(state, token)).toBeNull()
53
59
  })
54
60
 
61
+ test('continues resolving stored records with redundant scopes', async () => {
62
+ const state = Store.memory()
63
+ const { token } = await ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })
64
+ const { keys } = await state.list({ prefix: 'apikey:' })
65
+ const value = JSON.parse((await state.get(keys[0]!.name))!) as Record<string, unknown>
66
+ await state.put(keys[0]!.name, JSON.stringify({ ...value, scopes: ['data:read', 'data:read'] }))
67
+
68
+ expect((await ApiKeys.resolve(state, token))?.scopes).toEqual(['data:read', 'data:read'])
69
+ })
70
+
55
71
  test('normalizes persisted per-minute rate limits', async () => {
56
72
  const state = Store.memory()
57
73
  const { token } = await ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })
@@ -119,6 +135,15 @@ describe('mint', () => {
119
135
  ).rejects.toThrowError(/invalid API key input/)
120
136
  })
121
137
 
138
+ test('rejects duplicate scope vectors', async () => {
139
+ await expect(
140
+ ApiKeys.mint(Store.memory(), {
141
+ orgId: 'org_a',
142
+ scopes: ['data:read', 'data:read'],
143
+ }),
144
+ ).rejects.toThrowError(/invalid API key input/)
145
+ })
146
+
122
147
  test('mints per-zone read and write scopes', async () => {
123
148
  const state = Store.memory()
124
149
  const { token } = await ApiKeys.mint(state, {
@@ -146,6 +171,789 @@ describe('mint', () => {
146
171
  })
147
172
  })
148
173
 
174
+ describe('markOwnerDeleting', () => {
175
+ test('idempotently retains the fence across concurrent deletion attempts', async () => {
176
+ const state = Store.memory()
177
+ const organization = await ApiKeys.mint(state, {
178
+ orgId: 'org_a',
179
+ scopes: ['data:read'],
180
+ })
181
+
182
+ await ApiKeys.markOwnerDeleting(state, { orgId: 'org_a' })
183
+ await ApiKeys.markOwnerDeleting(state, { orgId: 'org_a' })
184
+
185
+ expect(await ApiKeys.resolve(state, organization.token)).toBeNull()
186
+ await expect(ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })).rejects.toThrow(
187
+ ApiKeys.OwnerDeletedError,
188
+ )
189
+ })
190
+ test('project fences leave sibling keys active', async () => {
191
+ const state = Store.memory()
192
+ const project = await ApiKeys.mint(state, {
193
+ orgId: 'org_a',
194
+ projectId: 'prj_deleted',
195
+ scopes: ['data:read'],
196
+ })
197
+ const sibling = await ApiKeys.mint(state, {
198
+ orgId: 'org_a',
199
+ projectId: 'prj_active',
200
+ scopes: ['data:read'],
201
+ })
202
+ await ApiKeys.markOwnerDeleting(state, { orgId: 'org_a', projectId: 'prj_deleted' })
203
+
204
+ expect(await ApiKeys.resolve(state, project.token)).toBeNull()
205
+ expect(await ApiKeys.resolve(state, sibling.token)).not.toBeNull()
206
+ await expect(
207
+ ApiKeys.mint(state, {
208
+ orgId: 'org_a',
209
+ projectId: 'prj_deleted',
210
+ scopes: ['data:read'],
211
+ }),
212
+ ).rejects.toThrow(ApiKeys.OwnerDeletedError)
213
+ })
214
+ })
215
+
216
+ describe('mintBounded', () => {
217
+ test('rejects an authoritative owner tombstone absent from KV', async () => {
218
+ const db = TestApp.database()
219
+ const state = Store.memory()
220
+ await db.transaction((tx) => ApiKeyOwnerTombstones.markDeleted(tx, { orgId: 'org_a' }))
221
+
222
+ await expect(
223
+ ApiKeys.mintBounded(db, state, { orgId: 'org_a', scopes: ['data:read'] }),
224
+ ).rejects.toThrow(ApiKeys.OwnerDeletedError)
225
+ })
226
+
227
+ test('atomically caps organization keys and releases revoked slots', async () => {
228
+ const db = TestApp.database()
229
+ const state = Store.memory()
230
+ const attempts = await Promise.allSettled(
231
+ Array.from({ length: ApiKeys.maxLiveKeysPerOrganization + 1 }, () =>
232
+ ApiKeys.mintBounded(db, state, { orgId: 'org_a', scopes: ['data:read'] }),
233
+ ),
234
+ )
235
+
236
+ const minted = attempts.flatMap((attempt) =>
237
+ attempt.status === 'fulfilled' ? [attempt.value] : [],
238
+ )
239
+ expect(minted).toHaveLength(ApiKeys.maxLiveKeysPerOrganization)
240
+ expect(attempts.filter((attempt) => attempt.status === 'rejected')).toHaveLength(1)
241
+
242
+ const revocations = await Promise.all([
243
+ ApiKeys.revokeBounded(db, state, minted[0]!.record.id),
244
+ ApiKeys.revokeBounded(db, state, minted[0]!.record.id),
245
+ ])
246
+ expect(revocations).toContain(true)
247
+ const replacements = await Promise.allSettled([
248
+ ApiKeys.mintBounded(db, state, { orgId: 'org_a', scopes: ['data:read'] }),
249
+ ApiKeys.mintBounded(db, state, { orgId: 'org_a', scopes: ['data:read'] }),
250
+ ])
251
+ expect(replacements.filter(({ status }) => status === 'fulfilled')).toHaveLength(1)
252
+ })
253
+
254
+ test('rejects a legacy key revoked before bootstrap despite a stale listing', async () => {
255
+ vi.useFakeTimers({ now: new Date('2026-01-01T00:00:00.000Z'), toFake: ['Date'] })
256
+ try {
257
+ const db = TestApp.database()
258
+ const state = Store.memory()
259
+ const minted = await Promise.all(
260
+ Array.from({ length: ApiKeys.maxLiveKeysPerOrganization }, () =>
261
+ ApiKeys.mint(state, { orgId: 'org_revoked', scopes: ['data:read'] }),
262
+ ),
263
+ )
264
+ const revoked = minted[0]!
265
+ const recordKey = (await state.get(`apikey_id:${revoked.record.id}`))!
266
+ const raw = (await state.get(recordKey))!
267
+
268
+ await ApiKeys.revokeBounded(db, state, revoked.record.id)
269
+ await state.put(recordKey, raw)
270
+ await state.put(`apikey_org:${revoked.record.orgId}:${revoked.record.id}`, recordKey)
271
+
272
+ const stale = await ApiKeys.resolve(state, revoked.token)
273
+ expect(stale).not.toBeNull()
274
+ await expect(ApiKeyAdmissions.matches(db, stale!)).resolves.toBe(false)
275
+ await ApiKeys.mintBounded(db, state, {
276
+ orgId: revoked.record.orgId,
277
+ scopes: ['data:read'],
278
+ })
279
+
280
+ vi.advanceTimersByTime(ApiKeyRevocations.retentionMs + 1)
281
+ await ApiKeyRevocations.prune(db)
282
+ expect(
283
+ await db.kysely
284
+ .selectFrom('api_key_admissions')
285
+ .select('id')
286
+ .where('id', '=', revoked.record.id)
287
+ .executeTakeFirst(),
288
+ ).toBeUndefined()
289
+ await expect(ApiKeyAdmissions.matches(db, stale!)).resolves.toBe(false)
290
+
291
+ await ApiKeys.revokeBounded(db, state, minted[1]!.record.id)
292
+ const replacements = await Promise.allSettled([
293
+ ApiKeys.mintBounded(db, state, {
294
+ orgId: revoked.record.orgId,
295
+ scopes: ['data:read'],
296
+ }),
297
+ ApiKeys.mintBounded(db, state, {
298
+ orgId: revoked.record.orgId,
299
+ scopes: ['data:read'],
300
+ }),
301
+ ])
302
+ expect(replacements.filter(({ status }) => status === 'fulfilled')).toHaveLength(1)
303
+ } finally {
304
+ vi.useRealTimers()
305
+ }
306
+ })
307
+
308
+ test('revokes without scanning a hostile legacy organization index', async () => {
309
+ const db = TestApp.database()
310
+ const state = Store.memory()
311
+ await Promise.all(
312
+ Array.from({ length: ApiKeys.maxLegacyAdmissionIndexes + 1 }, (_, index) =>
313
+ state.put(`apikey_org:org_hostile:!${String(index).padStart(4, '0')}`, `missing:${index}`),
314
+ ),
315
+ )
316
+ const target = await ApiKeys.mint(state, {
317
+ orgId: 'org_hostile',
318
+ scopes: ['data:read'],
319
+ })
320
+ const recordKey = (await state.get(`apikey_id:${target.record.id}`))!
321
+ const raw = (await state.get(recordKey))!
322
+
323
+ await expect(ApiKeys.revokeBounded(db, state, target.record.id)).resolves.toBe(true)
324
+ await state.put(recordKey, raw)
325
+ await state.put(`apikey_org:${target.record.orgId}:${target.record.id}`, recordKey)
326
+
327
+ const stale = await ApiKeys.resolve(state, target.token)
328
+ expect(stale).not.toBeNull()
329
+ await expect(ApiKeyAdmissions.matches(db, stale!)).resolves.toBe(false)
330
+ })
331
+
332
+ test('keeps a missing-index revocation fenced and admitted until KV deletion succeeds', async () => {
333
+ vi.useFakeTimers({ now: new Date('2026-01-01T00:00:00.000Z'), toFake: ['Date'] })
334
+ try {
335
+ const db = TestApp.database()
336
+ const state = Store.memory()
337
+ const minted = await Promise.all(
338
+ Array.from({ length: ApiKeys.maxLiveKeysPerOrganization + 1 }, () =>
339
+ ApiKeys.mint(state, { orgId: 'org_incomplete', scopes: ['data:read'] }),
340
+ ),
341
+ )
342
+ await expect(
343
+ ApiKeys.mintBounded(db, state, {
344
+ orgId: 'org_incomplete',
345
+ scopes: ['data:read'],
346
+ }),
347
+ ).rejects.toThrow(ApiKeys.LiveKeyLimitError)
348
+ const admitted = await db.kysely
349
+ .selectFrom('api_key_admissions')
350
+ .select('id')
351
+ .where('orgId', '=', 'org_incomplete')
352
+ .executeTakeFirstOrThrow()
353
+ const target = minted.find(({ record }) => record.id === admitted.id)!
354
+ await state.delete(`apikey_id:${target.record.id}`)
355
+
356
+ await expect(ApiKeys.revokeBounded(db, state, target.record.id)).resolves.toBe(true)
357
+ const stale = await ApiKeys.resolve(state, target.token)
358
+ expect(stale).not.toBeNull()
359
+ await expect(ApiKeyAdmissions.matches(db, stale!)).resolves.toBe(false)
360
+ vi.advanceTimersByTime(ApiKeyRevocations.retentionMs + 1)
361
+ await expect(ApiKeyRevocations.prune(db)).resolves.toBe(0)
362
+ await expect(ApiKeyAdmissions.matches(db, stale!)).resolves.toBe(false)
363
+ await expect(ApiKeyAdmissions.exists(db, target.record.id)).resolves.toBe(true)
364
+ await expect(
365
+ ApiKeys.mintBounded(db, state, {
366
+ orgId: 'org_incomplete',
367
+ scopes: ['data:read'],
368
+ }),
369
+ ).rejects.toThrow(ApiKeys.LiveKeyLimitError)
370
+ } finally {
371
+ vi.useRealTimers()
372
+ }
373
+ })
374
+
375
+ test('expires and prunes revocation fences after KV becomes fresh', async () => {
376
+ vi.useFakeTimers({ now: new Date('2026-01-01T00:00:00.000Z'), toFake: ['Date'] })
377
+ try {
378
+ const db = TestApp.database()
379
+ const state = Store.memory()
380
+ const revoked = await ApiKeys.mint(state, {
381
+ orgId: 'org_churn',
382
+ scopes: ['data:read'],
383
+ })
384
+ await ApiKeys.revokeBounded(db, state, revoked.record.id)
385
+
386
+ vi.advanceTimersByTime(ApiKeyRevocations.retentionMs + 1)
387
+ expect(await ApiKeyRevocations.prune(db)).toBe(1)
388
+ expect(await ApiKeyAdmissions.matches(db, revoked.record)).toBe(true)
389
+ expect(await ApiKeys.resolve(state, revoked.token)).toBeNull()
390
+ } finally {
391
+ vi.useRealTimers()
392
+ }
393
+ })
394
+
395
+ test('cascades organization-attributed revocation fences on deletion', async () => {
396
+ const db = TestApp.database()
397
+ const state = Store.memory()
398
+ const organization = await Organizations.create(db, { name: 'Fence owner' })
399
+ const revoked = await ApiKeys.mintBounded(db, state, {
400
+ orgId: organization.id,
401
+ scopes: ['data:read'],
402
+ })
403
+ await state.delete(`apikey_id:${revoked.record.id}`)
404
+ await ApiKeys.revokeBounded(db, state, revoked.record.id)
405
+
406
+ expect(
407
+ await db.kysely
408
+ .selectFrom('api_key_revocations')
409
+ .select('orgId')
410
+ .where('id', '=', revoked.record.id)
411
+ .executeTakeFirst(),
412
+ ).toEqual({ orgId: organization.id })
413
+ await Organizations.deleteOrganization(db, organization.id)
414
+ expect(
415
+ await db.kysely
416
+ .selectFrom('api_key_revocations')
417
+ .select('id')
418
+ .where('id', '=', revoked.record.id)
419
+ .executeTakeFirst(),
420
+ ).toBeUndefined()
421
+ await expect(ApiKeyAdmissions.exists(db, revoked.record.id)).resolves.toBe(false)
422
+ })
423
+
424
+ test('attributes a confirmed fence from admission when the first KV read misses', async () => {
425
+ const db = TestApp.database()
426
+ const inner = Store.memory()
427
+ const organization = await Organizations.create(db, { name: 'Admission owner' })
428
+ const revoked = await ApiKeys.mintBounded(db, inner, {
429
+ orgId: organization.id,
430
+ scopes: ['data:read'],
431
+ })
432
+ const idKey = `apikey_id:${revoked.record.id}`
433
+ let idReads = 0
434
+ const state = Store.from({
435
+ ...inner,
436
+ get(key) {
437
+ if (key === idKey && idReads++ === 0) return Promise.resolve(null)
438
+ return inner.get(key)
439
+ },
440
+ })
441
+
442
+ await expect(ApiKeys.revokeBounded(db, state, revoked.record.id)).resolves.toBe(true)
443
+ expect(
444
+ await db.kysely
445
+ .selectFrom('api_key_revocations')
446
+ .select('orgId')
447
+ .where('id', '=', revoked.record.id)
448
+ .executeTakeFirst(),
449
+ ).toEqual({ orgId: organization.id })
450
+ })
451
+
452
+ test('removes pending project revocations before releasing owner admissions', async () => {
453
+ const db = TestApp.database()
454
+ const state = Store.memory()
455
+ const organization = await Organizations.create(db, { name: 'Project fence owner' })
456
+ const project = await Projects.create(db, { name: 'Project fence', orgId: organization.id })
457
+ const revoked = await ApiKeys.mintBounded(db, state, {
458
+ orgId: organization.id,
459
+ projectId: project.id,
460
+ scopes: ['data:read'],
461
+ })
462
+ await state.delete(`apikey_id:${revoked.record.id}`)
463
+ await ApiKeys.revokeBounded(db, state, revoked.record.id)
464
+
465
+ await Projects.deleteProject(db, project.id)
466
+
467
+ expect(
468
+ await db.kysely
469
+ .selectFrom('api_key_revocations')
470
+ .select('id')
471
+ .where('id', '=', revoked.record.id)
472
+ .executeTakeFirst(),
473
+ ).toBeUndefined()
474
+ await expect(ApiKeyAdmissions.exists(db, revoked.record.id)).resolves.toBe(false)
475
+ })
476
+
477
+ test('does not regress a confirmed fence when another location reads stale KV', async () => {
478
+ vi.useFakeTimers({ now: new Date('2026-01-01T00:00:00.000Z'), toFake: ['Date'] })
479
+ try {
480
+ const database = TestApp.databaseFactory()
481
+ const inner = Store.memory()
482
+ const revoked = await ApiKeys.mintBounded(database(), inner, {
483
+ orgId: 'org_stale_revoke',
484
+ scopes: ['data:read'],
485
+ })
486
+ const idKey = `apikey_id:${revoked.record.id}`
487
+ const recordKey = (await inner.get(idKey))!
488
+ const raw = (await inner.get(recordKey))!
489
+ await ApiKeys.revokeBounded(database(), inner, revoked.record.id)
490
+ let idReads = 0
491
+ const stale = Store.from({
492
+ ...inner,
493
+ async get(key) {
494
+ if (key === idKey) return idReads++ === 0 ? recordKey : null
495
+ if (key === recordKey) return raw
496
+ return inner.get(key)
497
+ },
498
+ })
499
+
500
+ await expect(ApiKeys.revokeBounded(database(), stale, revoked.record.id)).resolves.toBe(true)
501
+ expect(
502
+ await database()
503
+ .kysely.selectFrom('api_key_revocations')
504
+ .select('expiresAt')
505
+ .where('id', '=', revoked.record.id)
506
+ .executeTakeFirst(),
507
+ ).not.toEqual({ expiresAt: ApiKeyRevocations.pendingExpiresAt })
508
+ vi.advanceTimersByTime(ApiKeyRevocations.retentionMs + 1)
509
+ await expect(ApiKeyRevocations.prune(database())).resolves.toBe(1)
510
+ await expect(ApiKeyAdmissions.exists(database(), revoked.record.id)).resolves.toBe(false)
511
+ await expect(ApiKeyRevocations.exists(database(), revoked.record.id)).resolves.toBe(false)
512
+ } finally {
513
+ vi.useRealTimers()
514
+ }
515
+ })
516
+
517
+ test('does not leave pending fences when owner deletion wins a concurrent revoke', async () => {
518
+ const database = TestApp.databaseFactory()
519
+ for (const ownerType of ['organization', 'project'] as const) {
520
+ const state = Store.memory()
521
+ const organization = await Organizations.create(database(), { name: `${ownerType} race` })
522
+ const project =
523
+ ownerType === 'project'
524
+ ? await Projects.create(database(), { name: 'Revoke race', orgId: organization.id })
525
+ : undefined
526
+ const revoked = await ApiKeys.mintBounded(database(), state, {
527
+ orgId: organization.id,
528
+ ...(project === undefined ? {} : { projectId: project.id }),
529
+ scopes: ['data:read'],
530
+ })
531
+ const idKey = `apikey_id:${revoked.record.id}`
532
+ await state.delete(idKey)
533
+ const reading = Promise.withResolvers<void>()
534
+ const deleted = Promise.withResolvers<void>()
535
+ const delayed = Store.from({
536
+ ...state,
537
+ async get(key) {
538
+ if (key !== idKey) return state.get(key)
539
+ reading.resolve()
540
+ await deleted.promise
541
+ return null
542
+ },
543
+ })
544
+ const revocation = ApiKeys.revokeBounded(database(), delayed, revoked.record.id)
545
+ await reading.promise
546
+
547
+ if (project === undefined) await Organizations.deleteOrganization(database(), organization.id)
548
+ else await Projects.deleteProject(database(), project.id)
549
+ deleted.resolve()
550
+ await expect(revocation).resolves.toBe(true)
551
+ await expect(ApiKeyAdmissions.exists(database(), revoked.record.id)).resolves.toBe(false)
552
+ await expect(ApiKeyRevocations.exists(database(), revoked.record.id)).resolves.toBe(false)
553
+ }
554
+ })
555
+
556
+ test('bootstraps the cap from bounded legacy KV records', async () => {
557
+ const db = TestApp.database()
558
+ const state = Store.memory()
559
+ await Promise.all(
560
+ Array.from({ length: ApiKeys.maxLiveKeysPerOrganization }, () =>
561
+ ApiKeys.mint(state, { orgId: 'org_legacy', scopes: ['data:read'] }),
562
+ ),
563
+ )
564
+
565
+ await expect(
566
+ ApiKeys.mintBounded(db, state, { orgId: 'org_legacy', scopes: ['data:read'] }),
567
+ ).rejects.toThrow(ApiKeys.LiveKeyLimitError)
568
+ const count = await db.kysely
569
+ .selectFrom('api_key_admissions')
570
+ .select((eb) => eb.fn.countAll<number>().as('count'))
571
+ .where('orgId', '=', 'org_legacy')
572
+ .executeTakeFirstOrThrow()
573
+ expect(Number(count.count)).toBe(ApiKeys.maxLiveKeysPerOrganization)
574
+ })
575
+
576
+ test('keeps omitted over-cap legacy keys valid without completing bootstrap', async () => {
577
+ const db = TestApp.database()
578
+ const state = Store.memory()
579
+ const legacy = await Promise.all(
580
+ Array.from({ length: ApiKeys.maxLiveKeysPerOrganization + 1 }, () =>
581
+ ApiKeys.mint(state, { orgId: 'org_over_cap', scopes: ['data:read'] }),
582
+ ),
583
+ )
584
+
585
+ await expect(
586
+ ApiKeys.mintBounded(db, state, { orgId: 'org_over_cap', scopes: ['data:read'] }),
587
+ ).rejects.toThrow(ApiKeys.LiveKeyLimitError)
588
+ const admissions = await db.kysely
589
+ .selectFrom('api_key_admissions')
590
+ .select('id')
591
+ .where('orgId', '=', 'org_over_cap')
592
+ .execute()
593
+ const admitted = new Set(admissions.map(({ id }) => id))
594
+ const omitted = legacy.find(({ record }) => !admitted.has(record.id))
595
+ expect(omitted).toBeDefined()
596
+ const resolved = await ApiKeys.resolve(state, omitted!.token)
597
+ expect(resolved).not.toBeNull()
598
+ await expect(ApiKeyAdmissions.matches(db, resolved!)).resolves.toBe(true)
599
+ expect(
600
+ await db.kysely
601
+ .selectFrom('api_key_admission_bootstraps')
602
+ .select('orgId')
603
+ .where('orgId', '=', 'org_over_cap')
604
+ .executeTakeFirst(),
605
+ ).toBeUndefined()
606
+ })
607
+
608
+ test('scans beyond stale legacy index pages', async () => {
609
+ const db = TestApp.database()
610
+ const state = Store.memory()
611
+ await Promise.all(
612
+ Array.from({ length: ApiKeys.maxLiveKeysPerOrganization }, (_, index) =>
613
+ state.put(`apikey_org:org_stale:!${String(index).padStart(3, '0')}`, `missing:${index}`),
614
+ ),
615
+ )
616
+ const { record: legacy } = await ApiKeys.mint(state, {
617
+ orgId: 'org_stale',
618
+ scopes: ['data:read'],
619
+ })
620
+
621
+ await ApiKeys.mintBounded(db, state, { orgId: 'org_stale', scopes: ['data:read'] })
622
+ expect(
623
+ await db.kysely
624
+ .selectFrom('api_key_admissions')
625
+ .select('id')
626
+ .where('id', '=', legacy.id)
627
+ .executeTakeFirst(),
628
+ ).toEqual({ id: legacy.id })
629
+ })
630
+
631
+ test('fails closed when stale indexes exhaust the reconciliation budget', async () => {
632
+ const db = TestApp.database()
633
+ const state = Store.memory()
634
+ await Promise.all(
635
+ Array.from({ length: ApiKeys.maxLegacyAdmissionIndexes + 1 }, (_, index) =>
636
+ state.put(
637
+ `apikey_org:org_exhausted:!${String(index).padStart(4, '0')}`,
638
+ `missing:${index}`,
639
+ ),
640
+ ),
641
+ )
642
+
643
+ for (let attempt = 0; attempt < 2; attempt++)
644
+ await expect(
645
+ ApiKeys.mintBounded(db, state, {
646
+ orgId: 'org_exhausted',
647
+ scopes: ['data:read'],
648
+ }),
649
+ ).rejects.toThrow(ApiKeys.LiveKeyLimitError)
650
+ expect(await state.get('apikey_org:org_exhausted:!0000')).toBe('missing:0')
651
+ })
652
+
653
+ test('expired keys no longer consume admission slots', async () => {
654
+ vi.useFakeTimers({ now: new Date('2026-01-01T00:00:00.000Z'), toFake: ['Date'] })
655
+ try {
656
+ const db = TestApp.database()
657
+ const state = Store.memory()
658
+ const expiresAt = '2026-01-01T00:01:00.000Z'
659
+ await Promise.all(
660
+ Array.from({ length: ApiKeys.maxLiveKeysPerOrganization }, () =>
661
+ ApiKeys.mintBounded(db, state, {
662
+ expiresAt,
663
+ orgId: 'org_expiring',
664
+ scopes: ['data:read'],
665
+ }),
666
+ ),
667
+ )
668
+
669
+ vi.setSystemTime(new Date('2026-01-01T00:02:00.000Z'))
670
+ await expect(
671
+ ApiKeys.mintBounded(db, state, {
672
+ orgId: 'org_expiring',
673
+ scopes: ['data:read'],
674
+ }),
675
+ ).resolves.toBeDefined()
676
+ } finally {
677
+ vi.useRealTimers()
678
+ }
679
+ })
680
+
681
+ test('normalizes offset expiries before admission', async () => {
682
+ const db = TestApp.database()
683
+ const state = Store.memory()
684
+ const { record } = await ApiKeys.mintBounded(db, state, {
685
+ expiresAt: '2030-09-04T00:00:00-08:00',
686
+ orgId: 'org_offset',
687
+ scopes: ['data:read'],
688
+ })
689
+
690
+ expect(record.expiresAt).toBe('2030-09-04T08:00:00.000Z')
691
+ expect(
692
+ await db.kysely
693
+ .selectFrom('api_key_admissions')
694
+ .select('expiresAt')
695
+ .where('id', '=', record.id)
696
+ .executeTakeFirst(),
697
+ ).toEqual({ expiresAt: '2030-09-04T08:00:00.000Z' })
698
+ })
699
+
700
+ test('counts a malformed legacy expiry as non-expiring', async () => {
701
+ const db = TestApp.database()
702
+ const state = Store.memory()
703
+ const { record } = await ApiKeys.mint(state, {
704
+ orgId: 'org_malformed_expiry',
705
+ scopes: ['data:read'],
706
+ })
707
+ const recordKey = (await state.get(`apikey_id:${record.id}`))!
708
+ const raw = JSON.parse((await state.get(recordKey))!) as ApiKeys.Record
709
+ await state.put(recordKey, JSON.stringify({ ...raw, expiresAt: 'not-a-date' }))
710
+
711
+ await expect(
712
+ ApiKeys.mintBounded(db, state, {
713
+ orgId: record.orgId,
714
+ scopes: ['data:read'],
715
+ }),
716
+ ).resolves.toBeDefined()
717
+ expect(
718
+ await db.kysely
719
+ .selectFrom('api_key_admissions')
720
+ .select('expiresAt')
721
+ .where('id', '=', record.id)
722
+ .executeTakeFirst(),
723
+ ).toEqual({ expiresAt: null })
724
+ })
725
+ })
726
+
727
+ describe('updateBounded', () => {
728
+ test('rejects an update when the locked key no longer has the expected owner', async () => {
729
+ const db = TestApp.database()
730
+ const state = Store.memory()
731
+ const { record } = await ApiKeys.mintBounded(db, state, {
732
+ orgId: 'org_source',
733
+ projectId: 'prj_source',
734
+ scopes: ['data:read'],
735
+ })
736
+ await ApiKeys.updateBounded(db, state, record.id, {
737
+ orgId: 'org_destination',
738
+ projectId: 'prj_destination',
739
+ })
740
+
741
+ await expect(
742
+ ApiKeys.updateBounded(
743
+ db,
744
+ state,
745
+ record.id,
746
+ { name: 'stale admin update' },
747
+ { expectedOwner: { orgId: 'org_source', projectId: 'prj_source' } },
748
+ ),
749
+ ).resolves.toBeNull()
750
+ const updated = await ApiKeys.get(state, record.id)
751
+ expect(updated).toMatchObject({
752
+ orgId: 'org_destination',
753
+ projectId: 'prj_destination',
754
+ })
755
+ expect(updated).not.toHaveProperty('name')
756
+ })
757
+
758
+ test('rejects an authoritative destination tombstone absent from KV', async () => {
759
+ const db = TestApp.database()
760
+ const state = Store.memory()
761
+ const { record } = await ApiKeys.mint(state, { scopes: ['data:read'] })
762
+ await db.transaction((tx) => ApiKeyOwnerTombstones.markDeleted(tx, { orgId: 'org_a' }))
763
+
764
+ await expect(ApiKeys.updateBounded(db, state, record.id, { orgId: 'org_a' })).rejects.toThrow(
765
+ ApiKeys.OwnerDeletedError,
766
+ )
767
+ expect((await ApiKeys.get(state, record.id))?.orgId).toBe(record.id)
768
+ })
769
+
770
+ test('rolls back admission when the KV attribution update is rejected', async () => {
771
+ const db = TestApp.database()
772
+ const state = Store.memory()
773
+ const { record } = await ApiKeys.mintBounded(db, state, {
774
+ orgId: 'org_source',
775
+ scopes: ['data:read'],
776
+ })
777
+ await ApiKeys.markOwnerDeleting(state, { orgId: 'org_target' })
778
+
779
+ await expect(
780
+ ApiKeys.updateBounded(db, state, record.id, { orgId: 'org_target' }),
781
+ ).rejects.toThrow(ApiKeys.OwnerDeletedError)
782
+ expect((await ApiKeys.get(state, record.id))?.orgId).toBe('org_source')
783
+ expect(
784
+ await db.kysely
785
+ .selectFrom('api_key_admissions')
786
+ .select(['id', 'orgId'])
787
+ .where('id', '=', record.id)
788
+ .executeTakeFirst(),
789
+ ).toEqual({ id: record.id, orgId: 'org_source' })
790
+ })
791
+
792
+ test('enforces the destination cap after a partial KV attribution write', async () => {
793
+ const db = TestApp.database()
794
+ const inner = Store.memory()
795
+ await Promise.all(
796
+ Array.from({ length: ApiKeys.maxLiveKeysPerOrganization - 1 }, () =>
797
+ ApiKeys.mintBounded(db, inner, {
798
+ orgId: 'org_full',
799
+ scopes: ['data:read'],
800
+ }),
801
+ ),
802
+ )
803
+ const { record } = await ApiKeys.mintBounded(db, inner, {
804
+ orgId: 'org_source',
805
+ scopes: ['data:read'],
806
+ })
807
+ let primaryWritten = false
808
+ let rejected = false
809
+ const state = Store.from({
810
+ ...inner,
811
+ async delete(key) {
812
+ if (primaryWritten && !rejected) {
813
+ rejected = true
814
+ throw new Error('index write rejected')
815
+ }
816
+ await inner.delete(key)
817
+ },
818
+ async put(key, value, options = {}) {
819
+ await inner.put(key, value, options)
820
+ if (!key.startsWith('apikey:')) return
821
+ const updated = JSON.parse(value) as { id?: string; orgId?: string }
822
+ if (updated.id === record.id && updated.orgId === 'org_full') primaryWritten = true
823
+ },
824
+ })
825
+
826
+ await expect(
827
+ ApiKeys.updateBounded(db, state, record.id, { orgId: 'org_full' }),
828
+ ).rejects.toThrow('index write rejected')
829
+ expect((await ApiKeys.get(inner, record.id))?.orgId).toBe('org_full')
830
+ expect(
831
+ await db.kysely
832
+ .selectFrom('api_key_admissions')
833
+ .select(['id', 'orgId'])
834
+ .where('id', '=', record.id)
835
+ .executeTakeFirst(),
836
+ ).toEqual({ id: record.id, orgId: 'org_source' })
837
+ await ApiKeys.mintBounded(db, inner, { orgId: 'org_full', scopes: ['data:read'] })
838
+ await expect(
839
+ ApiKeys.updateBounded(db, inner, record.id, { orgId: 'org_full' }),
840
+ ).rejects.toThrow(ApiKeys.LiveKeyLimitError)
841
+ const count = await db.kysely
842
+ .selectFrom('api_key_admissions')
843
+ .select((eb) => eb.fn.countAll<number>().as('count'))
844
+ .where('orgId', '=', 'org_full')
845
+ .executeTakeFirstOrThrow()
846
+ expect(Number(count.count)).toBe(ApiKeys.maxLiveKeysPerOrganization)
847
+ const stale = await ApiKeys.get(inner, record.id)
848
+ expect(stale).not.toBeNull()
849
+ await expect(ApiKeyAdmissions.matches(db, stale!)).resolves.toBe(false)
850
+ })
851
+
852
+ test('serializes admission moves through their KV attribution writes', async () => {
853
+ const database = TestApp.databaseFactory()
854
+ const inner = Store.memory()
855
+ const firstWrite = Promise.withResolvers<void>()
856
+ const secondWrite = Promise.withResolvers<void>()
857
+ const state = Store.from({
858
+ ...inner,
859
+ async put(key, value, options = {}) {
860
+ const record = (() => {
861
+ try {
862
+ return JSON.parse(value) as { orgId?: string; projectId?: string }
863
+ } catch {
864
+ return undefined
865
+ }
866
+ })()
867
+ if (key.startsWith('apikey:') && record?.orgId === 'org_first') {
868
+ firstWrite.resolve()
869
+ // The old lock boundary let the second KV write complete before this delayed write.
870
+ await Promise.race([
871
+ secondWrite.promise,
872
+ new Promise<void>((resolve) => setTimeout(resolve, 1_000)),
873
+ ])
874
+ }
875
+ if (key.startsWith('apikey:') && record?.projectId === 'prj_second') secondWrite.resolve()
876
+ await inner.put(key, value, options)
877
+ },
878
+ })
879
+ const { record } = await ApiKeys.mintBounded(database(), state, {
880
+ orgId: 'org_source',
881
+ scopes: ['data:read'],
882
+ })
883
+
884
+ const first = ApiKeys.updateBounded(database(), state, record.id, { orgId: 'org_first' })
885
+ await firstWrite.promise
886
+ const second = ApiKeys.updateBounded(database(), state, record.id, {
887
+ projectId: 'prj_second',
888
+ })
889
+ await Promise.all([first, second])
890
+
891
+ expect(await ApiKeys.get(state, record.id)).toMatchObject({
892
+ orgId: 'org_first',
893
+ projectId: 'prj_second',
894
+ })
895
+ expect(
896
+ await database()
897
+ .kysely.selectFrom('api_key_admissions')
898
+ .select(['id', 'orgId', 'projectId'])
899
+ .where('id', '=', record.id)
900
+ .executeTakeFirst(),
901
+ ).toEqual({ id: record.id, orgId: 'org_first', projectId: 'prj_second' })
902
+ })
903
+
904
+ test('serializes metadata writes with attribution moves', async () => {
905
+ const database = TestApp.databaseFactory()
906
+ const inner = Store.memory()
907
+ const attributionWrite = Promise.withResolvers<void>()
908
+ const metadataWrite = Promise.withResolvers<void>()
909
+ const state = Store.from({
910
+ ...inner,
911
+ async put(key, value, options = {}) {
912
+ const record = (() => {
913
+ try {
914
+ return JSON.parse(value) as { name?: string; orgId?: string }
915
+ } catch {
916
+ return undefined
917
+ }
918
+ })()
919
+ if (key.startsWith('apikey:') && record?.name === 'renamed') {
920
+ metadataWrite.resolve()
921
+ // The old metadata path could overwrite an attribution written while this write waited.
922
+ await Promise.race([
923
+ attributionWrite.promise,
924
+ new Promise<void>((resolve) => setTimeout(resolve, 1_000)),
925
+ ])
926
+ }
927
+ if (key.startsWith('apikey:') && record?.orgId === 'org_first') attributionWrite.resolve()
928
+ await inner.put(key, value, options)
929
+ },
930
+ })
931
+ const { record } = await ApiKeys.mintBounded(database(), state, {
932
+ orgId: 'org_source',
933
+ scopes: ['data:read'],
934
+ })
935
+
936
+ const metadata = ApiKeys.updateBounded(database(), state, record.id, { name: 'renamed' })
937
+ await metadataWrite.promise
938
+ const attribution = ApiKeys.updateBounded(database(), state, record.id, {
939
+ orgId: 'org_first',
940
+ })
941
+ await Promise.all([metadata, attribution])
942
+
943
+ expect(await ApiKeys.get(state, record.id)).toMatchObject({
944
+ name: 'renamed',
945
+ orgId: 'org_first',
946
+ })
947
+ expect(
948
+ await database()
949
+ .kysely.selectFrom('api_key_admissions')
950
+ .select(['id', 'orgId'])
951
+ .where('id', '=', record.id)
952
+ .executeTakeFirst(),
953
+ ).toEqual({ id: record.id, orgId: 'org_first' })
954
+ })
955
+ })
956
+
149
957
  describe('list', () => {
150
958
  beforeEach(() => vi.useFakeTimers({ now: new Date('2026-01-01T00:00:00.000Z') }))
151
959
  afterEach(() => vi.useRealTimers())
@@ -211,7 +1019,16 @@ describe('revoke', () => {
211
1019
  test('revoke is O(1): deletes the record without scanning the prefix', async () => {
212
1020
  const state = Store.memory()
213
1021
 
214
- const { record } = await ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })
1022
+ const { record } = await ApiKeys.mint(state, {
1023
+ environment: 'sandbox',
1024
+ orgId: 'org_a',
1025
+ scopes: ['data:read'],
1026
+ })
1027
+ await ApiKeys.setBillingActive(state, {
1028
+ active: true,
1029
+ environment: 'sandbox',
1030
+ orgId: 'org_a',
1031
+ })
215
1032
 
216
1033
  // The id index entry maps id -> record key; revoke uses it directly.
217
1034
  expect(await ApiKeys.revoke(state, record.id)).toBe(true)
@@ -265,6 +1082,14 @@ describe('listByOrg', () => {
265
1082
  `)
266
1083
  })
267
1084
 
1085
+ test('bounds legacy owner indexes', async () => {
1086
+ const state = Store.memory()
1087
+ for (let index = 0; index <= ApiKeys.maxLiveKeysPerOrganization; index++)
1088
+ await ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })
1089
+
1090
+ expect(await ApiKeys.listByOrg(state, 'org_a')).toHaveLength(ApiKeys.maxLiveKeysPerOrganization)
1091
+ })
1092
+
268
1093
  test('skips and lazily cleans dangling index entries', async () => {
269
1094
  const state = Store.memory()
270
1095
  await ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })
@@ -277,12 +1102,44 @@ describe('listByOrg', () => {
277
1102
  expect(await ApiKeys.listByOrg(state, 'org_a')).toEqual([])
278
1103
  expect((await state.list({ prefix: 'apikey_org:' })).keys).toMatchInlineSnapshot(`[]`)
279
1104
  })
1105
+
1106
+ test('lazily cleans index entries whose record has another owner', async () => {
1107
+ const state = Store.memory()
1108
+ const { record } = await ApiKeys.mint(state, {
1109
+ orgId: 'org_a',
1110
+ scopes: ['data:read'],
1111
+ })
1112
+ const recordKey = (await state.list({ prefix: 'apikey:' })).keys[0]!.name
1113
+ await state.put(`apikey_org:org_b:${record.id}`, recordKey)
1114
+
1115
+ expect(await ApiKeys.listByOrg(state, 'org_b')).toEqual([])
1116
+ expect((await state.list({ prefix: 'apikey_org:org_b:' })).keys).toEqual([])
1117
+ })
280
1118
  })
281
1119
 
282
1120
  describe('update', () => {
1121
+ test('rejects duplicate scopes and fenced owner attribution', async () => {
1122
+ const state = Store.memory()
1123
+ const { record } = await ApiKeys.mint(state, { scopes: ['data:read'] })
1124
+
1125
+ await expect(
1126
+ ApiKeys.update(state, record.id, { scopes: ['data:read', 'data:read'] }),
1127
+ ).rejects.toThrowError(/invalid scopes/)
1128
+ await ApiKeys.markOwnerDeleting(state, { orgId: 'org_deleted' })
1129
+ await expect(ApiKeys.update(state, record.id, { orgId: 'org_deleted' })).rejects.toThrow(
1130
+ ApiKeys.OwnerDeletedError,
1131
+ )
1132
+ })
1133
+
283
1134
  test('updates the name, org, and project while moving the org index', async () => {
284
1135
  const state = Store.memory()
285
1136
  const { record, token } = await ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })
1137
+ await ApiKeys.setBillingActive(state, {
1138
+ active: true,
1139
+ environment: 'production',
1140
+ orgId: 'org_a',
1141
+ })
1142
+ expect((await ApiKeys.resolve(state, token))?.billingActive).toBe(true)
286
1143
 
287
1144
  const updated = await ApiKeys.update(state, record.id, {
288
1145
  name: 'Explorer',
@@ -297,6 +1154,7 @@ describe('update', () => {
297
1154
  const resolved = await ApiKeys.resolve(state, token)
298
1155
  expect(resolved?.orgId).toBe('org_b')
299
1156
  expect(resolved?.projectId).toBe('prj_b')
1157
+ expect(resolved?.billingActive).toBeUndefined()
300
1158
 
301
1159
  expect(await ApiKeys.listByOrg(state, 'org_a')).toEqual([])
302
1160
  expect((await ApiKeys.listByOrg(state, 'org_b')).map(({ id }) => id)).toEqual([record.id])
@@ -305,6 +1163,23 @@ describe('update', () => {
305
1163
  expect(await ApiKeys.attribute(state, 'key_missing', { projectId: 'prj_x' })).toBeNull()
306
1164
  })
307
1165
 
1166
+ test('does not list a concurrent reassignment under its stale owner', async () => {
1167
+ const state = Store.memory()
1168
+ const { record } = await ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })
1169
+
1170
+ await Promise.all([
1171
+ ApiKeys.update(state, record.id, { orgId: 'org_b' }),
1172
+ ApiKeys.update(state, record.id, { orgId: 'org_c' }),
1173
+ ])
1174
+
1175
+ const updated = await ApiKeys.get(state, record.id)
1176
+ if (!updated) throw new Error('API key missing after reassignment.')
1177
+ const staleOrgId = updated.orgId === 'org_b' ? 'org_c' : 'org_b'
1178
+ expect((await state.list({ prefix: `apikey_org:${staleOrgId}:` })).keys).toHaveLength(1)
1179
+ expect(await ApiKeys.listByOrg(state, staleOrgId)).toEqual([])
1180
+ expect((await ApiKeys.listByOrg(state, updated.orgId)).map(({ id }) => id)).toEqual([record.id])
1181
+ })
1182
+
308
1183
  test('replaces and clears the IP allowlist without changing the token', async () => {
309
1184
  const state = Store.memory()
310
1185
  const { record, token } = await ApiKeys.mint(state, {
@@ -324,6 +1199,93 @@ describe('update', () => {
324
1199
  expect((await ApiKeys.resolve(state, token))?.allowedIps).toEqual([])
325
1200
  })
326
1201
 
1202
+ test('replaces scopes without changing the token', async () => {
1203
+ const state = Store.memory()
1204
+ const { record, token } = await ApiKeys.mint(state, {
1205
+ orgId: 'org_a',
1206
+ scopes: ['data:read'],
1207
+ })
1208
+
1209
+ const updated = await ApiKeys.update(state, record.id, {
1210
+ scopes: ['management:read', 'zone:421700001:write'],
1211
+ })
1212
+
1213
+ expect(updated?.scopes).toEqual(['management:read', 'zone:421700001:write'])
1214
+ expect((await ApiKeys.resolve(state, token))?.scopes).toEqual([
1215
+ 'management:read',
1216
+ 'zone:421700001:write',
1217
+ ])
1218
+ })
1219
+
1220
+ test('replaces rate limits without changing the token', async () => {
1221
+ const state = Store.memory()
1222
+ const { record, token } = await ApiKeys.mint(state, {
1223
+ orgId: 'org_a',
1224
+ rateLimits: { '*': { limit: 10_000, period: 'minute' } },
1225
+ scopes: ['data:read'],
1226
+ })
1227
+
1228
+ const updated = await ApiKeys.update(state, record.id, {
1229
+ rateLimits: { '*': { limit: 25_000, period: 'minute' } },
1230
+ })
1231
+
1232
+ expect(updated?.rateLimits).toEqual({ '*': { limit: 25_000, period: 'minute' } })
1233
+ expect((await ApiKeys.resolve(state, token))?.rateLimits).toEqual({
1234
+ '*': { limit: 25_000, period: 'minute' },
1235
+ })
1236
+ })
1237
+
1238
+ test('keeps replaced scopes while the billing snapshot changes', async () => {
1239
+ const state = Store.memory()
1240
+ const { record, token } = await ApiKeys.mint(state, {
1241
+ environment: 'sandbox',
1242
+ orgId: 'org_a',
1243
+ scopes: ['data:read'],
1244
+ })
1245
+ const recordKey = (await state.list({ prefix: 'apikey:' })).keys[0]!.name
1246
+ await ApiKeys.update(state, record.id, { scopes: ['management:read'] })
1247
+ const stored = await state.get(recordKey)
1248
+ await ApiKeys.setBillingActive(state, {
1249
+ active: true,
1250
+ environment: 'sandbox',
1251
+ orgId: 'org_a',
1252
+ })
1253
+
1254
+ expect(await state.get(recordKey)).toBe(stored)
1255
+ expect(await ApiKeys.resolve(state, token)).toMatchObject({
1256
+ billingActive: true,
1257
+ scopes: ['management:read'],
1258
+ })
1259
+ })
1260
+
1261
+ test('rejects invalid scopes at the write boundary', async () => {
1262
+ const state = Store.memory()
1263
+ const { record } = await ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })
1264
+
1265
+ await expect(
1266
+ ApiKeys.update(state, record.id, { scopes: ['not-a-scope'] }),
1267
+ ).rejects.toThrowError(/invalid API key input/)
1268
+ })
1269
+
1270
+ test('fails closed when a persisted billing snapshot is corrupt', async () => {
1271
+ const state = Store.memory()
1272
+ const { token } = await ApiKeys.mint(state, {
1273
+ environment: 'sandbox',
1274
+ orgId: 'org_a',
1275
+ scopes: ['data:read'],
1276
+ })
1277
+ await ApiKeys.setBillingActive(state, {
1278
+ active: true,
1279
+ environment: 'sandbox',
1280
+ orgId: 'org_a',
1281
+ })
1282
+ const snapshotKey = (await state.list({ prefix: 'apikey_billing:' })).keys[0]!.name
1283
+
1284
+ await state.put(snapshotKey, 'not json')
1285
+
1286
+ expect(await ApiKeys.resolve(state, token)).toBeNull()
1287
+ })
1288
+
327
1289
  test('rejects invalid IP allowlist rules at the write boundary', async () => {
328
1290
  const state = Store.memory()
329
1291
  const { record } = await ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })
@@ -335,6 +1297,39 @@ describe('update', () => {
335
1297
  })
336
1298
 
337
1299
  describe('setBillingActive', () => {
1300
+ test('stamps production billing snapshots', async () => {
1301
+ const state = Store.memory()
1302
+ const { token } = await ApiKeys.mint(state, {
1303
+ environment: 'production',
1304
+ orgId: 'org_a',
1305
+ scopes: ['data:read'],
1306
+ })
1307
+
1308
+ expect(
1309
+ await ApiKeys.setBillingActive(state, {
1310
+ active: true,
1311
+ environment: 'production',
1312
+ orgId: 'org_a',
1313
+ }),
1314
+ ).toBe(1)
1315
+ expect((await ApiKeys.resolve(state, token))?.billingActive).toBe(true)
1316
+ })
1317
+
1318
+ test('ignores a billing snapshot produced for a previous owner', async () => {
1319
+ const state = Store.memory()
1320
+ const { record, token } = await ApiKeys.mint(state, {
1321
+ environment: 'sandbox',
1322
+ orgId: 'org_a',
1323
+ scopes: ['data:read'],
1324
+ })
1325
+ const recordKey = (await state.list({ prefix: 'apikey:' })).keys[0]!.name
1326
+ await ApiKeys.update(state, record.id, { orgId: 'org_b' })
1327
+
1328
+ await state.put(`apikey_billing:${recordKey}`, JSON.stringify({ active: true, orgId: 'org_a' }))
1329
+
1330
+ expect((await ApiKeys.resolve(state, token))?.billingActive).toBeUndefined()
1331
+ })
1332
+
338
1333
  test('stamps billingActive onto the org keys in the target environment only', async () => {
339
1334
  const state = Store.memory()
340
1335
  const { token: sandboxToken } = await ApiKeys.mint(state, {
@@ -366,6 +1361,28 @@ describe('setBillingActive', () => {
366
1361
  expect((await ApiKeys.resolve(state, otherToken))?.billingActive).toBeUndefined()
367
1362
  })
368
1363
 
1364
+ test('paginates beyond the user-facing organization list bound', async () => {
1365
+ const state = Store.memory()
1366
+ const keys = await Promise.all(
1367
+ Array.from({ length: ApiKeys.maxLiveKeysPerOrganization + 1 }, () =>
1368
+ ApiKeys.mint(state, {
1369
+ environment: 'sandbox',
1370
+ orgId: 'org_legacy',
1371
+ scopes: ['data:read'],
1372
+ }),
1373
+ ),
1374
+ )
1375
+
1376
+ expect(
1377
+ await ApiKeys.setBillingActive(state, {
1378
+ active: true,
1379
+ environment: 'sandbox',
1380
+ orgId: 'org_legacy',
1381
+ }),
1382
+ ).toBe(ApiKeys.maxLiveKeysPerOrganization + 1)
1383
+ expect((await ApiKeys.resolve(state, keys.at(-1)!.token))?.billingActive).toBe(true)
1384
+ })
1385
+
369
1386
  test('skips records already carrying the target value', async () => {
370
1387
  const state = Store.memory()
371
1388
  await ApiKeys.mint(state, {
@@ -388,7 +1405,17 @@ describe('setBillingActive', () => {
388
1405
  describe('backfill', () => {
389
1406
  test('rebuilds index entries for legacy records', async () => {
390
1407
  const state = Store.memory()
391
- const { record, token } = await ApiKeys.mint(state, { orgId: 'org_a', scopes: ['data:read'] })
1408
+ const { record, token } = await ApiKeys.mint(state, {
1409
+ environment: 'sandbox',
1410
+ orgId: 'org_a',
1411
+ scopes: ['data:read'],
1412
+ })
1413
+ await ApiKeys.update(state, record.id, { scopes: ['management:read'] })
1414
+ await ApiKeys.setBillingActive(state, {
1415
+ active: true,
1416
+ environment: 'sandbox',
1417
+ orgId: 'org_a',
1418
+ })
392
1419
 
393
1420
  // Legacy state: records exist, index entries do not.
394
1421
  for (const { name } of (await state.list({ prefix: 'apikey_id:' })).keys)
@@ -400,7 +1427,10 @@ describe('backfill', () => {
400
1427
  expect(await ApiKeys.backfill(state)).toEqual({ indexed: 1, scanned: 1 })
401
1428
 
402
1429
  expect((await ApiKeys.listByOrg(state, 'org_a')).map(({ id }) => id)).toEqual([record.id])
403
- expect(await ApiKeys.resolve(state, token)).not.toBeNull()
1430
+ expect(await ApiKeys.resolve(state, token)).toMatchObject({
1431
+ billingActive: true,
1432
+ scopes: ['management:read'],
1433
+ })
404
1434
  // The id index is restored, so revoke-by-id works again.
405
1435
  expect(await ApiKeys.revoke(state, record.id)).toBe(true)
406
1436
  })