tapimo 0.15.1 → 0.18.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 (709) hide show
  1. package/README.md +137 -0
  2. package/dist/ApiKey.d.ts +1 -0
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +4 -2
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +37 -11
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +163 -10
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +13085 -11974
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +46 -15
  13. package/dist/App.js.map +1 -1
  14. package/dist/Scope.d.ts +1 -1
  15. package/dist/Scope.d.ts.map +1 -1
  16. package/dist/Scope.js +1 -1
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/admin/App.d.ts +893 -191
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/App.js +5 -1
  21. package/dist/admin/App.js.map +1 -1
  22. package/dist/admin/apps/api-keys.d.ts +70 -70
  23. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.js +8 -3
  25. package/dist/admin/apps/api-keys.js.map +1 -1
  26. package/dist/admin/apps/earn-vaults.d.ts +66 -27
  27. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  28. package/dist/admin/apps/earn-vaults.js +36 -7
  29. package/dist/admin/apps/earn-vaults.js.map +1 -1
  30. package/dist/admin/apps/organizations.d.ts +25 -25
  31. package/dist/admin/apps/organizations.d.ts.map +1 -1
  32. package/dist/admin/apps/organizations.js +5 -4
  33. package/dist/admin/apps/organizations.js.map +1 -1
  34. package/dist/admin/apps/route-policies.d.ts +632 -0
  35. package/dist/admin/apps/route-policies.d.ts.map +1 -0
  36. package/dist/admin/apps/route-policies.js +257 -0
  37. package/dist/admin/apps/route-policies.js.map +1 -0
  38. package/dist/admin/apps/routes-support.js +39 -3
  39. package/dist/admin/apps/routes-support.js.map +1 -1
  40. package/dist/admin/apps/routes.d.ts +529 -76
  41. package/dist/admin/apps/routes.d.ts.map +1 -1
  42. package/dist/admin/apps/routes.js +82 -1
  43. package/dist/admin/apps/routes.js.map +1 -1
  44. package/dist/admin/apps/verified-tokens.d.ts +157 -157
  45. package/dist/admin/index.d.ts +0 -1
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +0 -1
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/admin/ui.generated.d.ts +1 -1
  50. package/dist/admin/ui.generated.d.ts.map +1 -1
  51. package/dist/admin/ui.generated.js +205 -201
  52. package/dist/admin/ui.generated.js.map +1 -1
  53. package/dist/analytics/Analytics.d.ts.map +1 -1
  54. package/dist/analytics/Analytics.js +65 -1
  55. package/dist/analytics/Analytics.js.map +1 -1
  56. package/dist/analytics/tables/requestEvents.d.ts +1 -1
  57. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  58. package/dist/analytics/tables/requestEvents.js +58 -59
  59. package/dist/analytics/tables/requestEvents.js.map +1 -1
  60. package/dist/apps/data/App.d.ts +2709 -2670
  61. package/dist/apps/data/App.d.ts.map +1 -1
  62. package/dist/apps/data/routes/activities.d.ts +357 -357
  63. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  64. package/dist/apps/data/routes/activities.js +50 -0
  65. package/dist/apps/data/routes/activities.js.map +1 -1
  66. package/dist/apps/data/routes/addresses.d.ts +248 -248
  67. package/dist/apps/data/routes/balances.d.ts +22 -22
  68. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  69. package/dist/apps/data/routes/balances.js +5 -7
  70. package/dist/apps/data/routes/balances.js.map +1 -1
  71. package/dist/apps/data/routes/blocks.d.ts +125 -125
  72. package/dist/apps/data/routes/coingecko.d.ts +54 -54
  73. package/dist/apps/data/routes/earn.d.ts +103 -12
  74. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  75. package/dist/apps/data/routes/earn.js +456 -220
  76. package/dist/apps/data/routes/earn.js.map +1 -1
  77. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  78. package/dist/apps/data/routes/exchanges.js +267 -97
  79. package/dist/apps/data/routes/exchanges.js.map +1 -1
  80. package/dist/apps/data/routes/fee-amm.d.ts +109 -127
  81. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  82. package/dist/apps/data/routes/fee-amm.js +83 -54
  83. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  84. package/dist/apps/data/routes/indexer.d.ts +43 -43
  85. package/dist/apps/data/routes/receipts.d.ts +235 -235
  86. package/dist/apps/data/routes/rpc.d.ts +30 -30
  87. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  88. package/dist/apps/data/routes/tokens.js +11 -6
  89. package/dist/apps/data/routes/tokens.js.map +1 -1
  90. package/dist/apps/data/routes/transactions.d.ts +2 -0
  91. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  92. package/dist/apps/data/routes/transactions.js +30 -22
  93. package/dist/apps/data/routes/transactions.js.map +1 -1
  94. package/dist/apps/data/routes/transfers.d.ts +77 -77
  95. package/dist/apps/data/routes/valuation.d.ts +32 -32
  96. package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
  97. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  98. package/dist/apps/data/routes/webhooks.js +1 -1
  99. package/dist/apps/data/routes/webhooks.js.map +1 -1
  100. package/dist/apps/data/routes/zones.d.ts +31 -31
  101. package/dist/apps/management/App.d.ts +2909 -2064
  102. package/dist/apps/management/App.d.ts.map +1 -1
  103. package/dist/apps/management/App.js +2 -0
  104. package/dist/apps/management/App.js.map +1 -1
  105. package/dist/apps/management/Billing.d.ts +2 -4
  106. package/dist/apps/management/Billing.d.ts.map +1 -1
  107. package/dist/apps/management/Billing.js +65 -26
  108. package/dist/apps/management/Billing.js.map +1 -1
  109. package/dist/apps/management/routes/api-keys.d.ts +257 -245
  110. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  111. package/dist/apps/management/routes/api-keys.js +70 -11
  112. package/dist/apps/management/routes/api-keys.js.map +1 -1
  113. package/dist/apps/management/routes/billing.d.ts +84 -84
  114. package/dist/apps/management/routes/cli.d.ts +912 -0
  115. package/dist/apps/management/routes/cli.d.ts.map +1 -0
  116. package/dist/apps/management/routes/cli.js +416 -0
  117. package/dist/apps/management/routes/cli.js.map +1 -0
  118. package/dist/apps/management/routes/faucet.d.ts +8 -8
  119. package/dist/apps/management/routes/invitations.d.ts +138 -138
  120. package/dist/apps/management/routes/invite-links.d.ts +172 -172
  121. package/dist/apps/management/routes/members.d.ts +16 -16
  122. package/dist/apps/management/routes/orgs.d.ts +104 -104
  123. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  124. package/dist/apps/management/routes/orgs.js +8 -2
  125. package/dist/apps/management/routes/orgs.js.map +1 -1
  126. package/dist/apps/management/routes/projects.d.ts +125 -125
  127. package/dist/apps/management/routes/usage.d.ts +8 -8
  128. package/dist/apps/management/routes/verified-token-requests.d.ts +86 -86
  129. package/dist/apps/management/routes/webhooks.d.ts +485 -485
  130. package/dist/apps/mpp/App.d.ts +44 -44
  131. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
  132. package/dist/apps/mpp/internal/Policy.js +4 -2
  133. package/dist/apps/mpp/internal/Policy.js.map +1 -1
  134. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -1
  135. package/dist/apps/mpp/internal/Sponsorship.js +6 -4
  136. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -1
  137. package/dist/apps/relay/App.d.ts +8 -0
  138. package/dist/apps/relay/App.d.ts.map +1 -1
  139. package/dist/apps/relay/App.js +16 -4
  140. package/dist/apps/relay/App.js.map +1 -1
  141. package/dist/apps/relay/Sponsorships.d.ts +4 -6
  142. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  143. package/dist/apps/relay/Sponsorships.js +71 -60
  144. package/dist/apps/relay/Sponsorships.js.map +1 -1
  145. package/dist/apps/routes/Access.d.ts +53 -0
  146. package/dist/apps/routes/Access.d.ts.map +1 -1
  147. package/dist/apps/routes/Access.js +121 -0
  148. package/dist/apps/routes/Access.js.map +1 -1
  149. package/dist/apps/routes/App.d.ts +397 -158
  150. package/dist/apps/routes/App.d.ts.map +1 -1
  151. package/dist/apps/routes/App.js.map +1 -1
  152. package/dist/apps/routes/routes/chains.d.ts +25 -25
  153. package/dist/apps/routes/routes/deposit-addresses.d.ts +169 -61
  154. package/dist/apps/routes/routes/deposit-addresses.d.ts.map +1 -1
  155. package/dist/apps/routes/routes/deposit-addresses.js +217 -32
  156. package/dist/apps/routes/routes/deposit-addresses.js.map +1 -1
  157. package/dist/apps/routes/routes/quotes.d.ts +171 -81
  158. package/dist/apps/routes/routes/quotes.d.ts.map +1 -1
  159. package/dist/apps/routes/routes/quotes.js +101 -27
  160. package/dist/apps/routes/routes/quotes.js.map +1 -1
  161. package/dist/apps/routes/routes/transfers.d.ts +532 -480
  162. package/dist/apps/routes/routes/transfers.d.ts.map +1 -1
  163. package/dist/apps/routes/routes/transfers.js +182 -37
  164. package/dist/apps/routes/routes/transfers.js.map +1 -1
  165. package/dist/cli/ApiKeys.d.ts +120 -0
  166. package/dist/cli/ApiKeys.d.ts.map +1 -0
  167. package/dist/cli/ApiKeys.js +138 -0
  168. package/dist/cli/ApiKeys.js.map +1 -0
  169. package/dist/cli/Cli.d.ts +92 -34
  170. package/dist/cli/Cli.d.ts.map +1 -1
  171. package/dist/cli/Cli.js +188 -11
  172. package/dist/cli/Cli.js.map +1 -1
  173. package/dist/cli/Credentials.d.ts +95 -0
  174. package/dist/cli/Credentials.d.ts.map +1 -0
  175. package/dist/cli/Credentials.js +110 -0
  176. package/dist/cli/Credentials.js.map +1 -0
  177. package/dist/cli/Spec.d.ts +59 -0
  178. package/dist/cli/Spec.d.ts.map +1 -0
  179. package/dist/cli/Spec.js +77 -0
  180. package/dist/cli/Spec.js.map +1 -0
  181. package/dist/cli/bin.js +5 -1
  182. package/dist/cli/bin.js.map +1 -1
  183. package/dist/cli/commands/admin.d.ts +5 -5
  184. package/dist/cli/commands/admin.d.ts.map +1 -1
  185. package/dist/cli/commands/auth.d.ts +73 -0
  186. package/dist/cli/commands/auth.d.ts.map +1 -0
  187. package/dist/cli/commands/auth.js +204 -0
  188. package/dist/cli/commands/auth.js.map +1 -0
  189. package/dist/cli/commands/keys.d.ts +17 -0
  190. package/dist/cli/commands/keys.d.ts.map +1 -0
  191. package/dist/cli/commands/keys.js +109 -0
  192. package/dist/cli/commands/keys.js.map +1 -0
  193. package/dist/cloudflare.d.ts +27 -2
  194. package/dist/cloudflare.d.ts.map +1 -1
  195. package/dist/cloudflare.js +144 -17
  196. package/dist/cloudflare.js.map +1 -1
  197. package/dist/db/Db.d.ts +23 -0
  198. package/dist/db/Db.d.ts.map +1 -1
  199. package/dist/db/Db.js +413 -1
  200. package/dist/db/Db.js.map +1 -1
  201. package/dist/db/Schema.d.ts +44 -1
  202. package/dist/db/Schema.d.ts.map +1 -1
  203. package/dist/db/Schema.js +56 -3
  204. package/dist/db/Schema.js.map +1 -1
  205. package/dist/db/tables/apiKeyAdmissions.d.ts +28 -2
  206. package/dist/db/tables/apiKeyAdmissions.d.ts.map +1 -1
  207. package/dist/db/tables/apiKeyAdmissions.js +65 -9
  208. package/dist/db/tables/apiKeyAdmissions.js.map +1 -1
  209. package/dist/db/tables/apiKeyOwnerTombstones.d.ts +2 -0
  210. package/dist/db/tables/apiKeyOwnerTombstones.d.ts.map +1 -1
  211. package/dist/db/tables/apiKeyOwnerTombstones.js +2 -2
  212. package/dist/db/tables/apiKeyOwnerTombstones.js.map +1 -1
  213. package/dist/db/tables/authAccounts.d.ts.map +1 -1
  214. package/dist/db/tables/authAccounts.js +1 -0
  215. package/dist/db/tables/authAccounts.js.map +1 -1
  216. package/dist/db/tables/earnVaults.d.ts +5 -1
  217. package/dist/db/tables/earnVaults.d.ts.map +1 -1
  218. package/dist/db/tables/earnVaults.js +12 -1
  219. package/dist/db/tables/earnVaults.js.map +1 -1
  220. package/dist/db/tables/organizations.d.ts +4 -2
  221. package/dist/db/tables/organizations.d.ts.map +1 -1
  222. package/dist/db/tables/organizations.js +8 -34
  223. package/dist/db/tables/organizations.js.map +1 -1
  224. package/dist/db/tables/requestUsage.d.ts +5 -1
  225. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  226. package/dist/db/tables/requestUsage.js +10 -2
  227. package/dist/db/tables/requestUsage.js.map +1 -1
  228. package/dist/db/tables/rewardEligibilityAssociations.d.ts +13 -0
  229. package/dist/db/tables/rewardEligibilityAssociations.d.ts.map +1 -1
  230. package/dist/db/tables/rewardEligibilityAssociations.js +11 -0
  231. package/dist/db/tables/rewardEligibilityAssociations.js.map +1 -1
  232. package/dist/db/tables/rewardRuns.d.ts.map +1 -1
  233. package/dist/db/tables/rewardRuns.js +4 -0
  234. package/dist/db/tables/rewardRuns.js.map +1 -1
  235. package/dist/db/tables/rewardTransactionAttempts.d.ts.map +1 -1
  236. package/dist/db/tables/rewardTransactionAttempts.js +2 -0
  237. package/dist/db/tables/rewardTransactionAttempts.js.map +1 -1
  238. package/dist/db/tables/routesDepositAddresses.d.ts +29 -0
  239. package/dist/db/tables/routesDepositAddresses.d.ts.map +1 -1
  240. package/dist/db/tables/routesDepositAddresses.js +84 -31
  241. package/dist/db/tables/routesDepositAddresses.js.map +1 -1
  242. package/dist/db/tables/routesDeposits.d.ts.map +1 -1
  243. package/dist/db/tables/routesDeposits.js +31 -21
  244. package/dist/db/tables/routesDeposits.js.map +1 -1
  245. package/dist/db/tables/routesIdempotency.d.ts.map +1 -1
  246. package/dist/db/tables/routesIdempotency.js +2 -0
  247. package/dist/db/tables/routesIdempotency.js.map +1 -1
  248. package/dist/db/tables/routesPolicies.d.ts +58 -0
  249. package/dist/db/tables/routesPolicies.d.ts.map +1 -0
  250. package/dist/db/tables/routesPolicies.js +198 -0
  251. package/dist/db/tables/routesPolicies.js.map +1 -0
  252. package/dist/db/tables/routesTransferSubsidies.d.ts +22 -0
  253. package/dist/db/tables/routesTransferSubsidies.d.ts.map +1 -1
  254. package/dist/db/tables/routesTransferSubsidies.js +41 -0
  255. package/dist/db/tables/routesTransferSubsidies.js.map +1 -1
  256. package/dist/db/tables/routesTransferSubsidyNonces.d.ts.map +1 -1
  257. package/dist/db/tables/routesTransferSubsidyNonces.js +12 -4
  258. package/dist/db/tables/routesTransferSubsidyNonces.js.map +1 -1
  259. package/dist/db/tables/routesTransfers.d.ts +26 -1
  260. package/dist/db/tables/routesTransfers.d.ts.map +1 -1
  261. package/dist/db/tables/routesTransfers.js +36 -6
  262. package/dist/db/tables/routesTransfers.js.map +1 -1
  263. package/dist/db/tables/sponsoredTransactions.d.ts +45 -13
  264. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  265. package/dist/db/tables/sponsoredTransactions.js +144 -33
  266. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  267. package/dist/db/tables/users.d.ts +2 -0
  268. package/dist/db/tables/users.d.ts.map +1 -1
  269. package/dist/db/tables/users.js +11 -0
  270. package/dist/db/tables/users.js.map +1 -1
  271. package/dist/handlers/internal/multisig.d.ts +1 -1
  272. package/dist/handlers/internal/multisig.d.ts.map +1 -1
  273. package/dist/handlers/internal/multisig.js +3 -2
  274. package/dist/handlers/internal/multisig.js.map +1 -1
  275. package/dist/handlers/relay.d.ts +2 -0
  276. package/dist/handlers/relay.d.ts.map +1 -1
  277. package/dist/handlers/relay.js +34 -15
  278. package/dist/handlers/relay.js.map +1 -1
  279. package/dist/internal/Auth.d.ts +57 -6
  280. package/dist/internal/Auth.d.ts.map +1 -1
  281. package/dist/internal/Auth.js +182 -78
  282. package/dist/internal/Auth.js.map +1 -1
  283. package/dist/internal/BetterAuth.d.ts +22 -0
  284. package/dist/internal/BetterAuth.d.ts.map +1 -1
  285. package/dist/internal/BetterAuth.js +17 -14
  286. package/dist/internal/BetterAuth.js.map +1 -1
  287. package/dist/internal/Cache.d.ts +5 -0
  288. package/dist/internal/Cache.d.ts.map +1 -1
  289. package/dist/internal/Cache.js +3 -1
  290. package/dist/internal/Cache.js.map +1 -1
  291. package/dist/internal/CliAuth.d.ts +243 -0
  292. package/dist/internal/CliAuth.d.ts.map +1 -0
  293. package/dist/internal/CliAuth.js +249 -0
  294. package/dist/internal/CliAuth.js.map +1 -0
  295. package/dist/internal/EarnSharePrices.d.ts +1 -1
  296. package/dist/internal/EarnSharePrices.d.ts.map +1 -1
  297. package/dist/internal/EarnSharePrices.js +7 -3
  298. package/dist/internal/EarnSharePrices.js.map +1 -1
  299. package/dist/internal/EarnVaults.d.ts +47 -0
  300. package/dist/internal/EarnVaults.d.ts.map +1 -1
  301. package/dist/internal/EarnVaults.js +188 -4
  302. package/dist/internal/EarnVaults.js.map +1 -1
  303. package/dist/internal/EarnWithdrawals.d.ts +73 -0
  304. package/dist/internal/EarnWithdrawals.d.ts.map +1 -0
  305. package/dist/internal/EarnWithdrawals.js +189 -0
  306. package/dist/internal/EarnWithdrawals.js.map +1 -0
  307. package/dist/internal/ExecutionContext.d.ts +21 -0
  308. package/dist/internal/ExecutionContext.d.ts.map +1 -0
  309. package/dist/internal/ExecutionContext.js +16 -0
  310. package/dist/internal/ExecutionContext.js.map +1 -0
  311. package/dist/internal/Log.d.ts +7 -3
  312. package/dist/internal/Log.d.ts.map +1 -1
  313. package/dist/internal/Log.js +163 -130
  314. package/dist/internal/Log.js.map +1 -1
  315. package/dist/internal/MetricSink.d.ts.map +1 -1
  316. package/dist/internal/MetricSink.js +26 -1
  317. package/dist/internal/MetricSink.js.map +1 -1
  318. package/dist/internal/RateLimit.d.ts +67 -0
  319. package/dist/internal/RateLimit.d.ts.map +1 -1
  320. package/dist/internal/RateLimit.js +174 -27
  321. package/dist/internal/RateLimit.js.map +1 -1
  322. package/dist/internal/Store.d.ts +6 -0
  323. package/dist/internal/Store.d.ts.map +1 -1
  324. package/dist/internal/Store.js +4 -5
  325. package/dist/internal/Store.js.map +1 -1
  326. package/dist/internal/Timing.d.ts +6 -0
  327. package/dist/internal/Timing.d.ts.map +1 -1
  328. package/dist/internal/Timing.js +21 -1
  329. package/dist/internal/Timing.js.map +1 -1
  330. package/dist/internal/Tron.d.ts +124 -0
  331. package/dist/internal/Tron.d.ts.map +1 -0
  332. package/dist/internal/Tron.js +202 -0
  333. package/dist/internal/Tron.js.map +1 -0
  334. package/dist/internal/Viem.d.ts +4 -0
  335. package/dist/internal/Viem.d.ts.map +1 -1
  336. package/dist/internal/Viem.js +25 -6
  337. package/dist/internal/Viem.js.map +1 -1
  338. package/dist/internal/rewards/Read.d.ts +2 -2
  339. package/dist/internal/rewards/Read.d.ts.map +1 -1
  340. package/dist/internal/rewards/Read.js +11 -2
  341. package/dist/internal/rewards/Read.js.map +1 -1
  342. package/dist/internal/routes/Action.d.ts +27 -0
  343. package/dist/internal/routes/Action.d.ts.map +1 -1
  344. package/dist/internal/routes/Action.js +49 -1
  345. package/dist/internal/routes/Action.js.map +1 -1
  346. package/dist/internal/routes/Chain.d.ts +2 -0
  347. package/dist/internal/routes/Chain.d.ts.map +1 -1
  348. package/dist/internal/routes/Chain.js +4 -0
  349. package/dist/internal/routes/Chain.js.map +1 -1
  350. package/dist/internal/routes/DepositAddress.d.ts.map +1 -1
  351. package/dist/internal/routes/DepositAddress.js +5 -0
  352. package/dist/internal/routes/DepositAddress.js.map +1 -1
  353. package/dist/internal/routes/Evidence.d.ts.map +1 -1
  354. package/dist/internal/routes/Evidence.js +6 -2
  355. package/dist/internal/routes/Evidence.js.map +1 -1
  356. package/dist/internal/routes/EvmTransferSettlement.d.ts +17 -0
  357. package/dist/internal/routes/EvmTransferSettlement.d.ts.map +1 -0
  358. package/dist/internal/routes/EvmTransferSettlement.js +196 -0
  359. package/dist/internal/routes/EvmTransferSettlement.js.map +1 -0
  360. package/dist/internal/routes/Policy.d.ts +161 -0
  361. package/dist/internal/routes/Policy.d.ts.map +1 -0
  362. package/dist/internal/routes/Policy.js +249 -0
  363. package/dist/internal/routes/Policy.js.map +1 -0
  364. package/dist/internal/routes/Provider.d.ts +66 -3
  365. package/dist/internal/routes/Provider.d.ts.map +1 -1
  366. package/dist/internal/routes/Provider.js +106 -27
  367. package/dist/internal/routes/Provider.js.map +1 -1
  368. package/dist/internal/routes/Quota.d.ts +57 -0
  369. package/dist/internal/routes/Quota.d.ts.map +1 -0
  370. package/dist/internal/routes/Quota.js +144 -0
  371. package/dist/internal/routes/Quota.js.map +1 -0
  372. package/dist/internal/routes/Reconciliation.d.ts.map +1 -1
  373. package/dist/internal/routes/Reconciliation.js +163 -47
  374. package/dist/internal/routes/Reconciliation.js.map +1 -1
  375. package/dist/internal/routes/SolanaTransferSettlement.d.ts +12 -0
  376. package/dist/internal/routes/SolanaTransferSettlement.d.ts.map +1 -0
  377. package/dist/internal/routes/SolanaTransferSettlement.js +220 -0
  378. package/dist/internal/routes/SolanaTransferSettlement.js.map +1 -0
  379. package/dist/internal/routes/SolanaTransferSubsidy.d.ts +172 -0
  380. package/dist/internal/routes/SolanaTransferSubsidy.d.ts.map +1 -0
  381. package/dist/internal/routes/SolanaTransferSubsidy.js +564 -0
  382. package/dist/internal/routes/SolanaTransferSubsidy.js.map +1 -0
  383. package/dist/internal/routes/Subsidy.d.ts +2 -2
  384. package/dist/internal/routes/Subsidy.d.ts.map +1 -1
  385. package/dist/internal/routes/Subsidy.js +2 -2
  386. package/dist/internal/routes/Subsidy.js.map +1 -1
  387. package/dist/internal/routes/Transfer.d.ts +229 -1
  388. package/dist/internal/routes/Transfer.d.ts.map +1 -1
  389. package/dist/internal/routes/Transfer.js +644 -7
  390. package/dist/internal/routes/Transfer.js.map +1 -1
  391. package/dist/internal/routes/TransferReconciliation.d.ts +6 -0
  392. package/dist/internal/routes/TransferReconciliation.d.ts.map +1 -1
  393. package/dist/internal/routes/TransferReconciliation.js +83 -159
  394. package/dist/internal/routes/TransferReconciliation.js.map +1 -1
  395. package/dist/internal/routes/TransferSettlement.d.ts +45 -0
  396. package/dist/internal/routes/TransferSettlement.d.ts.map +1 -0
  397. package/dist/internal/routes/TransferSettlement.js +2 -0
  398. package/dist/internal/routes/TransferSettlement.js.map +1 -0
  399. package/dist/internal/routes/TransferSubsidy.d.ts +23 -8
  400. package/dist/internal/routes/TransferSubsidy.d.ts.map +1 -1
  401. package/dist/internal/routes/TransferSubsidy.js +64 -5
  402. package/dist/internal/routes/TransferSubsidy.js.map +1 -1
  403. package/dist/internal/routes/TronTransferSettlement.d.ts +12 -0
  404. package/dist/internal/routes/TronTransferSettlement.d.ts.map +1 -0
  405. package/dist/internal/routes/TronTransferSettlement.js +201 -0
  406. package/dist/internal/routes/TronTransferSettlement.js.map +1 -0
  407. package/dist/internal/routes/TronTransferSubsidy.d.ts +174 -0
  408. package/dist/internal/routes/TronTransferSubsidy.d.ts.map +1 -0
  409. package/dist/internal/routes/TronTransferSubsidy.js +439 -0
  410. package/dist/internal/routes/TronTransferSubsidy.js.map +1 -0
  411. package/dist/internal/routes/index.d.ts +3 -0
  412. package/dist/internal/routes/index.d.ts.map +1 -1
  413. package/dist/internal/routes/index.js +3 -0
  414. package/dist/internal/routes/index.js.map +1 -1
  415. package/dist/internal/routes/providers/across.d.ts +3 -0
  416. package/dist/internal/routes/providers/across.d.ts.map +1 -1
  417. package/dist/internal/routes/providers/across.js +11 -0
  418. package/dist/internal/routes/providers/across.js.map +1 -1
  419. package/dist/internal/routes/providers/legacyMesh.d.ts +29 -0
  420. package/dist/internal/routes/providers/legacyMesh.d.ts.map +1 -0
  421. package/dist/internal/routes/providers/legacyMesh.js +474 -0
  422. package/dist/internal/routes/providers/legacyMesh.js.map +1 -0
  423. package/dist/internal/routes/providers/legacyMeshDelivery.d.ts +59 -0
  424. package/dist/internal/routes/providers/legacyMeshDelivery.d.ts.map +1 -0
  425. package/dist/internal/routes/providers/legacyMeshDelivery.js +229 -0
  426. package/dist/internal/routes/providers/legacyMeshDelivery.js.map +1 -0
  427. package/dist/internal/routes/providers/legacyMeshOutbound.d.ts +19 -0
  428. package/dist/internal/routes/providers/legacyMeshOutbound.d.ts.map +1 -0
  429. package/dist/internal/routes/providers/legacyMeshOutbound.js +457 -0
  430. package/dist/internal/routes/providers/legacyMeshOutbound.js.map +1 -0
  431. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts +123 -0
  432. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts.map +1 -0
  433. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js +333 -0
  434. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js.map +1 -0
  435. package/dist/internal/routes/providers/propAmm.d.ts +70 -0
  436. package/dist/internal/routes/providers/propAmm.d.ts.map +1 -0
  437. package/dist/internal/routes/providers/propAmm.js +524 -0
  438. package/dist/internal/routes/providers/propAmm.js.map +1 -0
  439. package/dist/internal/routes/providers/relay.d.ts +3 -0
  440. package/dist/internal/routes/providers/relay.d.ts.map +1 -1
  441. package/dist/internal/routes/providers/relay.js +352 -41
  442. package/dist/internal/routes/providers/relay.js.map +1 -1
  443. package/dist/internal/routes/providers/rhino.d.ts +3 -0
  444. package/dist/internal/routes/providers/rhino.d.ts.map +1 -1
  445. package/dist/internal/routes/providers/rhino.js +11 -0
  446. package/dist/internal/routes/providers/rhino.js.map +1 -1
  447. package/dist/internal/routes/providers/squid.d.ts +3 -0
  448. package/dist/internal/routes/providers/squid.d.ts.map +1 -1
  449. package/dist/internal/routes/providers/squid.js +19 -0
  450. package/dist/internal/routes/providers/squid.js.map +1 -1
  451. package/dist/internal/routes/providers/stargate.d.ts.map +1 -1
  452. package/dist/internal/routes/providers/stargate.js +22 -9
  453. package/dist/internal/routes/providers/stargate.js.map +1 -1
  454. package/dist/internal/routes/providers/symbiosis.d.ts.map +1 -1
  455. package/dist/internal/routes/providers/symbiosis.js +13 -17
  456. package/dist/internal/routes/providers/symbiosis.js.map +1 -1
  457. package/dist/providers/index.d.ts +14 -0
  458. package/dist/providers/index.d.ts.map +1 -1
  459. package/dist/providers/index.js +6 -0
  460. package/dist/providers/index.js.map +1 -1
  461. package/package.json +16 -6
  462. package/src/ApiKey.ts +7 -3
  463. package/src/ApiKeys.test.ts +652 -8
  464. package/src/ApiKeys.ts +191 -11
  465. package/src/App.test.ts +405 -18
  466. package/src/App.ts +51 -15
  467. package/src/Client.test-d.ts +157 -10
  468. package/src/Client.test.ts +4 -4
  469. package/src/Scope.ts +1 -2
  470. package/src/admin/App.ts +11 -5
  471. package/src/admin/apps/api-keys.test.ts +98 -2
  472. package/src/admin/apps/api-keys.ts +21 -12
  473. package/src/admin/apps/earn-vaults.test.ts +76 -7
  474. package/src/admin/apps/earn-vaults.ts +47 -8
  475. package/src/admin/apps/organizations.test.ts +147 -31
  476. package/src/admin/apps/organizations.ts +5 -4
  477. package/src/admin/apps/route-policies.test.ts +220 -0
  478. package/src/admin/apps/route-policies.ts +322 -0
  479. package/src/admin/apps/routes-support.test.ts +107 -2
  480. package/src/admin/apps/routes-support.ts +43 -3
  481. package/src/admin/apps/routes.test.ts +150 -0
  482. package/src/admin/apps/routes.ts +97 -1
  483. package/src/admin/apps/scopes.test.ts +1 -1
  484. package/src/admin/index.ts +0 -1
  485. package/src/admin/ui/plugin.ts +2 -1
  486. package/src/admin/ui/src/components/Dialog.tsx +1 -1
  487. package/src/admin/ui/src/components/EarnVaultForm.tsx +45 -0
  488. package/src/admin/ui/src/components/RoutePicker.tsx +79 -0
  489. package/src/admin/ui/src/lib/earn-vaults.ts +1 -1
  490. package/src/admin/ui/src/lib/route-policies.test.ts +452 -0
  491. package/src/admin/ui/src/lib/route-policies.ts +232 -0
  492. package/src/admin/ui/src/lib/routes.ts +34 -0
  493. package/src/admin/ui/src/routeTree.gen.ts +21 -0
  494. package/src/admin/ui/src/routes/api-keys.tsx +21 -2
  495. package/src/admin/ui/src/routes/early-access.tsx +1 -0
  496. package/src/admin/ui/src/routes/earn.vaults.tsx +1 -0
  497. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +22 -0
  498. package/src/admin/ui/src/routes/earn.vaults_.new.tsx +10 -0
  499. package/src/admin/ui/src/routes/organizations.tsx +1 -0
  500. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +18 -3
  501. package/src/admin/ui/src/routes/route-policies.tsx +678 -0
  502. package/src/admin/ui/src/routes/routes.tsx +85 -2
  503. package/src/admin/ui/src/routes/routes_.support.tsx +6 -22
  504. package/src/admin/ui/src/routes/subsidies.tsx +1 -0
  505. package/src/admin/ui/src/routes/verified-tokens.tsx +1 -0
  506. package/src/admin/ui.generated.ts +258 -202
  507. package/src/analytics/Analytics.test.ts +4 -50
  508. package/src/analytics/Analytics.ts +65 -1
  509. package/src/analytics/tables/requestEvents.test.ts +402 -1
  510. package/src/analytics/tables/requestEvents.ts +62 -93
  511. package/src/apps/data/routes/activities.test.ts +315 -14
  512. package/src/apps/data/routes/activities.ts +60 -0
  513. package/src/apps/data/routes/balances.ts +5 -7
  514. package/src/apps/data/routes/earn.bench.ts +18 -0
  515. package/src/apps/data/routes/earn.local.test.ts +507 -0
  516. package/src/apps/data/routes/earn.test.ts +405 -127
  517. package/src/apps/data/routes/earn.ts +660 -270
  518. package/src/apps/data/routes/exchanges.bench.ts +3 -1
  519. package/src/apps/data/routes/exchanges.test.ts +166 -2
  520. package/src/apps/data/routes/exchanges.ts +308 -101
  521. package/src/apps/data/routes/fee-amm.test.ts +134 -2
  522. package/src/apps/data/routes/fee-amm.ts +122 -60
  523. package/src/apps/data/routes/receipts.test.ts +21 -18
  524. package/src/apps/data/routes/rpc.test.ts +2 -2
  525. package/src/apps/data/routes/tokens.provenance.test.ts +157 -0
  526. package/src/apps/data/routes/tokens.test.ts +4 -4
  527. package/src/apps/data/routes/tokens.ts +11 -6
  528. package/src/apps/data/routes/transactions.test.ts +29 -0
  529. package/src/apps/data/routes/transactions.ts +33 -22
  530. package/src/apps/data/routes/webhooks.test.ts +12 -3
  531. package/src/apps/data/routes/webhooks.ts +2 -1
  532. package/src/apps/management/App.ts +4 -0
  533. package/src/apps/management/Billing.test.ts +253 -27
  534. package/src/apps/management/Billing.ts +83 -29
  535. package/src/apps/management/routes/api-keys.test.ts +1 -1
  536. package/src/apps/management/routes/api-keys.ts +85 -11
  537. package/src/apps/management/routes/billing.test.ts +68 -4
  538. package/src/apps/management/routes/cli.test.ts +370 -0
  539. package/src/apps/management/routes/cli.ts +533 -0
  540. package/src/apps/management/routes/me.test.ts +14 -4
  541. package/src/apps/management/routes/orgs.test.ts +108 -4
  542. package/src/apps/management/routes/orgs.ts +7 -2
  543. package/src/apps/management/routes/usage.test.ts +2 -2
  544. package/src/apps/mpp/internal/Policy.test.ts +51 -4
  545. package/src/apps/mpp/internal/Policy.ts +6 -2
  546. package/src/apps/mpp/internal/Sponsorship.test.ts +29 -0
  547. package/src/apps/mpp/internal/Sponsorship.ts +6 -4
  548. package/src/apps/relay/App.test.ts +85 -1
  549. package/src/apps/relay/App.ts +28 -4
  550. package/src/apps/relay/Sponsorships.test.ts +97 -1
  551. package/src/apps/relay/Sponsorships.ts +77 -66
  552. package/src/apps/routes/Access.test.ts +319 -0
  553. package/src/apps/routes/Access.ts +147 -0
  554. package/src/apps/routes/App.ts +10 -0
  555. package/src/apps/routes/routes/chains.test.ts +3 -2
  556. package/src/apps/routes/routes/deposit-addresses.test.ts +978 -34
  557. package/src/apps/routes/routes/deposit-addresses.ts +243 -32
  558. package/src/apps/routes/routes/propAmm.local.test.ts +951 -0
  559. package/src/apps/routes/routes/quotes.test.ts +81 -8
  560. package/src/apps/routes/routes/quotes.ts +109 -27
  561. package/src/apps/routes/routes/transfers.test.ts +252 -15
  562. package/src/apps/routes/routes/transfers.ts +212 -33
  563. package/src/cli/ApiKeys.test.ts +265 -0
  564. package/src/cli/ApiKeys.ts +189 -0
  565. package/src/cli/Cli.test.ts +188 -0
  566. package/src/cli/Cli.ts +280 -12
  567. package/src/cli/Credentials.test.ts +122 -0
  568. package/src/cli/Credentials.ts +144 -0
  569. package/src/cli/Spec.test.ts +133 -0
  570. package/src/cli/Spec.ts +132 -0
  571. package/src/cli/bin.test.ts +49 -0
  572. package/src/cli/bin.ts +5 -1
  573. package/src/cli/commands/auth.test.ts +138 -0
  574. package/src/cli/commands/auth.ts +254 -0
  575. package/src/cli/commands/keys.test.ts +68 -0
  576. package/src/cli/commands/keys.ts +125 -0
  577. package/src/cloudflare.ts +184 -36
  578. package/src/db/Db.test.ts +877 -0
  579. package/src/db/Db.ts +498 -1
  580. package/src/db/Schema.ts +75 -4
  581. package/src/db/tables/apiKeyAdmissions.test.ts +57 -0
  582. package/src/db/tables/apiKeyAdmissions.ts +101 -11
  583. package/src/db/tables/apiKeyOwnerTombstones.ts +2 -2
  584. package/src/db/tables/authAccounts.test.ts +30 -0
  585. package/src/db/tables/authAccounts.ts +1 -0
  586. package/src/db/tables/earnVaults.test.ts +34 -0
  587. package/src/db/tables/earnVaults.ts +17 -2
  588. package/src/db/tables/organizations.test.ts +148 -84
  589. package/src/db/tables/organizations.ts +11 -43
  590. package/src/db/tables/requestUsage.ts +13 -2
  591. package/src/db/tables/rewardCampaigns.test.ts +163 -0
  592. package/src/db/tables/rewardEligibilityAssociations.test.ts +14 -0
  593. package/src/db/tables/rewardEligibilityAssociations.ts +24 -0
  594. package/src/db/tables/rewardRuns.ts +4 -0
  595. package/src/db/tables/rewardTransactionAttempts.ts +2 -0
  596. package/src/db/tables/routesDepositAddresses.test.ts +263 -0
  597. package/src/db/tables/routesDepositAddresses.ts +118 -34
  598. package/src/db/tables/routesDeposits.test.ts +66 -5
  599. package/src/db/tables/routesDeposits.ts +47 -26
  600. package/src/db/tables/routesIdempotency.test.ts +80 -0
  601. package/src/db/tables/routesIdempotency.ts +2 -0
  602. package/src/db/tables/routesPolicies.test.ts +143 -0
  603. package/src/db/tables/routesPolicies.ts +251 -0
  604. package/src/db/tables/routesTransferSubsidies.ts +64 -0
  605. package/src/db/tables/routesTransferSubsidyNonces.ts +16 -4
  606. package/src/db/tables/routesTransfers.test.ts +183 -2
  607. package/src/db/tables/routesTransfers.ts +65 -6
  608. package/src/db/tables/sponsoredTransactions.test.ts +351 -76
  609. package/src/db/tables/sponsoredTransactions.ts +182 -38
  610. package/src/db/tables/users.test.ts +51 -0
  611. package/src/db/tables/users.ts +12 -0
  612. package/src/handlers/internal/multisig.store.test.ts +120 -0
  613. package/src/handlers/internal/multisig.test.ts +389 -0
  614. package/src/handlers/internal/multisig.ts +13 -10
  615. package/src/handlers/relay.test.ts +259 -83
  616. package/src/handlers/relay.ts +36 -17
  617. package/src/internal/Auth.test.ts +291 -8
  618. package/src/internal/Auth.ts +227 -96
  619. package/src/internal/BetterAuth.test.ts +58 -22
  620. package/src/internal/BetterAuth.ts +23 -17
  621. package/src/internal/Cache.ts +3 -1
  622. package/src/internal/CliAuth.test.ts +279 -0
  623. package/src/internal/CliAuth.ts +319 -0
  624. package/src/internal/EarnSharePrices.test.ts +25 -0
  625. package/src/internal/EarnSharePrices.ts +9 -2
  626. package/src/internal/EarnVaults.test.ts +67 -0
  627. package/src/internal/EarnVaults.ts +299 -4
  628. package/src/internal/EarnWithdrawals.test.ts +315 -0
  629. package/src/internal/EarnWithdrawals.ts +266 -0
  630. package/src/internal/ExecutionContext.ts +31 -0
  631. package/src/internal/Log.test.ts +210 -0
  632. package/src/internal/Log.ts +180 -142
  633. package/src/internal/MetricSink.test.ts +190 -15
  634. package/src/internal/MetricSink.ts +27 -1
  635. package/src/internal/RateLimit.test.ts +144 -8
  636. package/src/internal/RateLimit.ts +254 -26
  637. package/src/internal/Store.ts +4 -5
  638. package/src/internal/Timing.test.ts +32 -0
  639. package/src/internal/Timing.ts +20 -1
  640. package/src/internal/Tron.test-d.ts +22 -0
  641. package/src/internal/Tron.test.ts +94 -0
  642. package/src/internal/Tron.ts +289 -0
  643. package/src/internal/Viem.rpc.test.ts +76 -0
  644. package/src/internal/Viem.ts +29 -6
  645. package/src/internal/rewards/Read.test.ts +109 -0
  646. package/src/internal/rewards/Read.ts +13 -4
  647. package/src/internal/routes/Action.test.ts +70 -0
  648. package/src/internal/routes/Action.ts +76 -1
  649. package/src/internal/routes/Chain.test.ts +18 -0
  650. package/src/internal/routes/Chain.ts +5 -0
  651. package/src/internal/routes/DepositAddress.ts +5 -0
  652. package/src/internal/routes/Evidence.test.ts +64 -0
  653. package/src/internal/routes/Evidence.ts +11 -3
  654. package/src/internal/routes/EvmTransferSettlement.ts +213 -0
  655. package/src/internal/routes/Policy.test.ts +316 -0
  656. package/src/internal/routes/Policy.ts +399 -0
  657. package/src/internal/routes/Provider.test.ts +103 -2
  658. package/src/internal/routes/Provider.ts +149 -27
  659. package/src/internal/routes/Quota.test.ts +149 -0
  660. package/src/internal/routes/Quota.ts +226 -0
  661. package/src/internal/routes/Reconciliation.local.test.ts +285 -0
  662. package/src/internal/routes/Reconciliation.test.ts +371 -13
  663. package/src/internal/routes/Reconciliation.ts +193 -42
  664. package/src/internal/routes/SolanaTransferSettlement.ts +232 -0
  665. package/src/internal/routes/SolanaTransferSubsidy.test.ts +471 -0
  666. package/src/internal/routes/SolanaTransferSubsidy.ts +760 -0
  667. package/src/internal/routes/SourceObservation.test.ts +221 -0
  668. package/src/internal/routes/Subsidy.local.test.ts +46 -0
  669. package/src/internal/routes/Subsidy.ts +4 -2
  670. package/src/internal/routes/Transfer.solana.test.ts +389 -0
  671. package/src/internal/routes/Transfer.test.ts +130 -1
  672. package/src/internal/routes/Transfer.tron.test.ts +172 -0
  673. package/src/internal/routes/Transfer.ts +866 -8
  674. package/src/internal/routes/TransferReconciliation.test.ts +26 -4
  675. package/src/internal/routes/TransferReconciliation.ts +91 -166
  676. package/src/internal/routes/TransferSettlement.ts +48 -0
  677. package/src/internal/routes/TransferSubsidy.local.test.ts +143 -0
  678. package/src/internal/routes/TransferSubsidy.test.ts +34 -4
  679. package/src/internal/routes/TransferSubsidy.ts +87 -12
  680. package/src/internal/routes/TronTransferSettlement.ts +212 -0
  681. package/src/internal/routes/TronTransferSubsidy.test.ts +109 -0
  682. package/src/internal/routes/TronTransferSubsidy.ts +619 -0
  683. package/src/internal/routes/index.test.ts +3 -0
  684. package/src/internal/routes/index.ts +3 -0
  685. package/src/internal/routes/providers/across.ts +13 -0
  686. package/src/internal/routes/providers/index.test.ts +141 -0
  687. package/src/internal/routes/providers/legacyMesh.test.ts +484 -0
  688. package/src/internal/routes/providers/legacyMesh.ts +633 -0
  689. package/src/internal/routes/providers/legacyMeshDelivery.test.ts +306 -0
  690. package/src/internal/routes/providers/legacyMeshDelivery.ts +320 -0
  691. package/src/internal/routes/providers/legacyMeshOutbound.test.ts +401 -0
  692. package/src/internal/routes/providers/legacyMeshOutbound.ts +566 -0
  693. package/src/internal/routes/providers/legacyMeshOutboundDelivery.ts +473 -0
  694. package/src/internal/routes/providers/propAmm.ts +640 -0
  695. package/src/internal/routes/providers/relay.test.ts +1263 -41
  696. package/src/internal/routes/providers/relay.ts +423 -38
  697. package/src/internal/routes/providers/rhino.ts +14 -1
  698. package/src/internal/routes/providers/squid.ts +21 -0
  699. package/src/internal/routes/providers/stargate.test.ts +105 -1
  700. package/src/internal/routes/providers/stargate.ts +22 -9
  701. package/src/internal/routes/providers/symbiosis.ts +13 -47
  702. package/src/providers/index.test.ts +2 -0
  703. package/src/providers/index.ts +18 -0
  704. package/dist/admin/Access.d.ts +0 -39
  705. package/dist/admin/Access.d.ts.map +0 -1
  706. package/dist/admin/Access.js +0 -73
  707. package/dist/admin/Access.js.map +0 -1
  708. package/src/admin/Access.test.ts +0 -130
  709. package/src/admin/Access.ts +0 -85
@@ -0,0 +1,265 @@
1
+ import * as TestApp from '../../test/App.js'
2
+ import * as TestCli from '../../test/cli.js'
3
+ import * as core_ApiKeys from '../ApiKeys.js'
4
+ import * as Client from '../Client.js'
5
+ import * as Memberships from '../db/tables/memberships.js'
6
+ import * as CliAuth from '../internal/CliAuth.js'
7
+ import * as Store from '../internal/Store.js'
8
+ import * as ApiKeys from './ApiKeys.js'
9
+
10
+ describe('resolve', () => {
11
+ test('infers a project key, caches it privately, and expires it with the session', async () => {
12
+ const context = await TestCli.create()
13
+ const { cookie } = await TestCli.login(context)
14
+ const owner = await organization(context.app, cookie)
15
+ const request = auth(context)
16
+ const [credential, concurrent, separate] = await Promise.all([
17
+ ApiKeys.resolve(request, { scopes: ['routes:read'] }),
18
+ ApiKeys.resolve(auth(context), { scopes: ['routes:read'] }),
19
+ ApiKeys.resolve(request, { scopes: ['routes:read'] }),
20
+ ])
21
+ expect(typeof credential).toBe('string')
22
+ expect(concurrent).toBe(credential)
23
+ expect(separate).toBe(credential)
24
+ expect(await ApiKeys.resolve(auth(context), { scopes: ['routes:read'] })).toBe(credential)
25
+ const session = (await context.credentials.get(TestCli.origin))!
26
+ expect(session.apiKeys).toHaveLength(1)
27
+ expect(session.apiKeys![0]).toMatchObject({
28
+ ...owner,
29
+ environment: 'production',
30
+ expiresAt: session.expiresAt,
31
+ scopes: ['routes:read'],
32
+ })
33
+ const listed = await context.app.request(
34
+ `/v1/orgs/${owner.orgId}/projects/${owner.projectId}/api-keys?include=`,
35
+ { headers: { cookie } },
36
+ )
37
+ const { data } = await listed.json()
38
+ expect(data[0].expiresAt).toBe(session.expiresAt)
39
+ const { code, lines } = await TestCli.serve(context.cli, [
40
+ 'v1',
41
+ 'routes',
42
+ 'transfers',
43
+ 'get',
44
+ '--format',
45
+ 'json',
46
+ ])
47
+ expect(code).toBe(0)
48
+ expect(JSON.parse(lines.join('\n'))).toMatchObject({ data: [] })
49
+ await context.credentials.set(TestCli.origin, {
50
+ ...session,
51
+ apiKeys: session.apiKeys!.map((key) => ({ ...key, expiresAt: new Date(0).toISOString() })),
52
+ })
53
+ expect(await ApiKeys.resolve(auth(context), { scopes: ['routes:read'] })).not.toBe(credential)
54
+ })
55
+
56
+ test('requires fresh consent for legacy local and server sessions', async () => {
57
+ const store = Store.memory()
58
+ const context = await TestCli.create({ app: TestApp.create({ kv: { store } }) })
59
+ const { cookie } = await TestCli.login(context)
60
+ const owner = await organization(context.app, cookie)
61
+ const current = (await context.credentials.get(TestCli.origin))!
62
+ const { scopes: _scopes, ...legacy } = current
63
+ await context.credentials.set(TestCli.origin, legacy)
64
+ const denied = await ApiKeys.resolve(auth(context), { scopes: ['data:read'] })
65
+ expect(denied instanceof Response && (await denied.json())).toMatchObject({
66
+ error: { code: 'scope_not_approved' },
67
+ })
68
+ const { token } = await CliAuth.mint(store, { client: {}, userId: current.userId })
69
+ expect(
70
+ (
71
+ await context.app.request('/v1/me', {
72
+ headers: { authorization: `Bearer ${token}` },
73
+ })
74
+ ).status,
75
+ ).toBe(200)
76
+ const response = await context.app.request(
77
+ `/v1/orgs/${owner.orgId}/projects/${owner.projectId}/api-keys`,
78
+ {
79
+ body: JSON.stringify({ scopes: ['data:read'] }),
80
+ headers: { authorization: `Bearer ${token}`, 'content-type': 'application/json' },
81
+ method: 'POST',
82
+ },
83
+ )
84
+ expect(response.status).toBe(403)
85
+ expect(await response.json()).toMatchObject({ error: { code: 'scope_not_issuable' } })
86
+ })
87
+
88
+ test('requires owner membership to derive or rotate Routes write keys', async () => {
89
+ const db = TestApp.database()
90
+ const store = Store.memory()
91
+ const context = await TestCli.create({ app: TestApp.create({ db, kv: { store } }) })
92
+ const ownerCookie = await TestCli.consoleSession(context.app)
93
+ const owner = await organization(context.app, ownerCookie)
94
+ await TestCli.login(context)
95
+ const session = (await context.credentials.get(TestCli.origin))!
96
+ await Memberships.create(db, { orgId: owner.orgId, role: 'admin', userId: session.userId })
97
+ const { record } = await core_ApiKeys.mintBounded(db, store, {
98
+ ...owner,
99
+ environment: 'production',
100
+ scopes: ['routes:read', 'routes:write'],
101
+ })
102
+ const denied = await ApiKeys.resolve(auth(context), {
103
+ ...owner,
104
+ scopes: ['routes:write'],
105
+ sourceKeyId: record.id,
106
+ })
107
+ expect(denied instanceof Response && denied.status).toBe(403)
108
+ expect(denied instanceof Response && (await denied.json())).toMatchObject({
109
+ error: { code: 'scope_not_issuable' },
110
+ })
111
+ const rotated = await context.app.request(
112
+ `/v1/orgs/${owner.orgId}/projects/${owner.projectId}/api-keys/${record.id}/rotate`,
113
+ { headers: { authorization: `Bearer ${session.token}` }, method: 'POST' },
114
+ )
115
+ expect(rotated.status).toBe(403)
116
+ expect(await rotated.json()).toMatchObject({ error: { code: 'scope_not_issuable' } })
117
+ expect((await context.credentials.get(TestCli.origin))?.apiKeys).toBeUndefined()
118
+ expect(await core_ApiKeys.get(store, record.id)).not.toBeNull()
119
+ })
120
+
121
+ test('rejects operations outside approved scopes without minting a key', async () => {
122
+ const context = await TestCli.create()
123
+ const { cookie } = await TestCli.login(context, { scopes: [] })
124
+ const result = await ApiKeys.resolve(auth(context), { scopes: ['routes:write'] })
125
+ expect(result instanceof Response && (await result.json())).toMatchObject({
126
+ error: { code: 'scope_not_approved' },
127
+ })
128
+ expect((await context.credentials.get(TestCli.origin))?.apiKeys).toBeUndefined()
129
+ const owner = await organization(context.app, cookie)
130
+ const session = (await context.credentials.get(TestCli.origin))!
131
+ const denied = await context.app.request(
132
+ `/v1/orgs/${owner.orgId}/projects/${owner.projectId}/api-keys`,
133
+ {
134
+ body: JSON.stringify({ scopes: ['data:read'] }),
135
+ headers: { authorization: `Bearer ${session.token}`, 'content-type': 'application/json' },
136
+ method: 'POST',
137
+ },
138
+ )
139
+ expect(denied.status).toBe(403)
140
+ expect(await denied.json()).toMatchObject({ error: { code: 'scope_not_issuable' } })
141
+ })
142
+
143
+ test('requires selection when organization ownership is ambiguous', async () => {
144
+ const context = await TestCli.create()
145
+ const { cookie } = await TestCli.login(context)
146
+ const owner = await organization(context.app, cookie)
147
+ await organization(context.app, cookie)
148
+ const result = await ApiKeys.resolve(auth(context), { scopes: ['routes:read'] })
149
+ expect(result instanceof Response && (await result.json())).toMatchObject({
150
+ error: { code: 'organization_required' },
151
+ })
152
+ expect((await context.credentials.get(TestCli.origin))?.apiKeys).toBeUndefined()
153
+ await context.app.request(`/v1/orgs/${owner.orgId}/projects`, {
154
+ body: JSON.stringify({ name: 'Another project' }),
155
+ headers: { 'content-type': 'application/json', cookie },
156
+ method: 'POST',
157
+ })
158
+ const ambiguous = await ApiKeys.resolve(auth(context), {
159
+ orgId: owner.orgId,
160
+ scopes: ['routes:read'],
161
+ })
162
+ expect(ambiguous instanceof Response && (await ambiguous.json())).toMatchObject({
163
+ error: { code: 'project_required' },
164
+ })
165
+ expect(
166
+ typeof (await ApiKeys.resolve(auth(context), { ...owner, scopes: ['routes:read'] })),
167
+ ).toBe('string')
168
+ })
169
+
170
+ test.each([{ scopes: ['routes:read', 'routes:write'] }, { scopes: ['*'] }])(
171
+ 'derives Routes writes from approved scopes $scopes without rotating the source',
172
+ async ({ scopes }) => {
173
+ const db = TestApp.database()
174
+ const store = Store.memory()
175
+ const context = await TestCli.create({ app: TestApp.create({ db, kv: { store } }) })
176
+ const { cookie } = await TestCli.login(context)
177
+ const owner = await organization(context.app, cookie)
178
+ const denied = await ApiKeys.resolve(auth(context), { scopes: ['routes:write'] })
179
+ expect(denied instanceof Response && (await denied.json())).toMatchObject({
180
+ error: { code: 'api_key_required' },
181
+ })
182
+ const { record } = await core_ApiKeys.mintBounded(db, store, {
183
+ ...owner,
184
+ allowedIps: ['203.0.113.7'],
185
+ environment: 'production',
186
+ expiresAt: new Date(Date.now() + 60_000).toISOString(),
187
+ scopes,
188
+ })
189
+ expect(typeof (await ApiKeys.resolve(auth(context), { scopes: ['routes:write'] }))).toBe(
190
+ 'string',
191
+ )
192
+ const cached = (await context.credentials.get(TestCli.origin))!.apiKeys![0]!
193
+ const derived = await core_ApiKeys.get(store, cached.id)
194
+ expect(derived?.expiresAt).toBe(record.expiresAt)
195
+ expect(derived?.scopes).toEqual(['routes:write', 'routes:read'])
196
+ expect(derived?.allowedIps).toEqual(record.allowedIps)
197
+ expect(await core_ApiKeys.get(store, record.id)).not.toBeNull()
198
+ const first = await ApiKeys.resolve(auth(context), { scopes: ['routes:write'] })
199
+ expect(first).toBe(cached.token)
200
+ const second = await core_ApiKeys.mintBounded(db, store, {
201
+ ...owner,
202
+ environment: 'production',
203
+ scopes: ['routes:read', 'routes:write'],
204
+ })
205
+ const ambiguous = await ApiKeys.resolve(auth(context), { scopes: ['routes:write'] })
206
+ expect(ambiguous instanceof Response && (await ambiguous.json())).toMatchObject({
207
+ error: { code: 'api_key_required' },
208
+ })
209
+ expect(
210
+ await ApiKeys.resolve(auth(context), {
211
+ scopes: ['routes:write'],
212
+ sourceKeyId: record.id,
213
+ }),
214
+ ).toBe(cached.token)
215
+ expect((await context.credentials.get(TestCli.origin))?.apiKeys).toHaveLength(1)
216
+ expect(
217
+ await ApiKeys.resolve(auth(context), {
218
+ scopes: ['routes:write'],
219
+ sourceKeyId: second.record.id,
220
+ }),
221
+ ).not.toBe(cached.token)
222
+ const keys = (await context.credentials.get(TestCli.origin))!.apiKeys!
223
+ expect(keys).toHaveLength(2)
224
+ expect(keys[1]?.sourceKeyId).toBe(second.record.id)
225
+ expect(
226
+ await ApiKeys.revoke(auth(context), (await context.credentials.get(TestCli.origin))!),
227
+ ).toBe(true)
228
+ expect(await core_ApiKeys.get(store, cached.id)).toBeNull()
229
+ expect(await core_ApiKeys.get(store, keys[1]!.id)).toBeNull()
230
+ expect(await core_ApiKeys.get(store, record.id)).not.toBeNull()
231
+ },
232
+ )
233
+ })
234
+
235
+ function auth(context: Awaited<ReturnType<typeof TestCli.create>>) {
236
+ return {
237
+ api: Client.create({
238
+ fetch: async (input: Request | string | URL, init?: RequestInit) =>
239
+ context.app.fetch(new Request(input, init)),
240
+ url: TestCli.origin,
241
+ }),
242
+ apiUrl: new URL(TestCli.origin),
243
+ credentials: context.credentials,
244
+ fetch: async (request: Request) => context.app.fetch(request),
245
+ name: 'tapimo',
246
+ }
247
+ }
248
+
249
+ async function organization(app: ReturnType<typeof TestApp.create>, cookie: string) {
250
+ const headers = { 'content-type': 'application/json', cookie }
251
+ const created = await app.request('/v1/orgs', {
252
+ body: JSON.stringify({ name: 'CLI project' }),
253
+ headers,
254
+ method: 'POST',
255
+ })
256
+ const org = await created.json()
257
+ const project = await (
258
+ await app.request(`/v1/orgs/${org.id}/projects`, {
259
+ body: JSON.stringify({ name: 'CLI' }),
260
+ headers,
261
+ method: 'POST',
262
+ })
263
+ ).json()
264
+ return { orgId: org.id as string, projectId: project.id as string }
265
+ }
@@ -0,0 +1,189 @@
1
+ import * as Scope from '../Scope.js'
2
+ import type * as Auth from './commands/auth.js'
3
+ import type * as Credentials from './Credentials.js'
4
+
5
+ const resolutions = new WeakMap<Auth.Context, Promise<unknown>>()
6
+
7
+ /** Resolves a private, session-bound API key without replacing explicit credentials. */
8
+ export function resolve(context: Auth.Context, options: resolve.Options) {
9
+ const previous = resolutions.get(context) ?? Promise.resolve()
10
+ const pending = previous
11
+ .catch(() => undefined)
12
+ .then(() =>
13
+ context.credentials.withLock
14
+ ? context.credentials.withLock((credentials) =>
15
+ resolveKey({ ...context, credentials }, options),
16
+ )
17
+ : resolveKey(context, options),
18
+ )
19
+ resolutions.set(context, pending)
20
+ return pending.finally(() => {
21
+ if (resolutions.get(context) === pending) resolutions.delete(context)
22
+ })
23
+ }
24
+
25
+ async function resolveKey(context: Auth.Context, options: resolve.Options) {
26
+ const { api, apiUrl, credentials } = context
27
+ const session = await credentials.get(apiUrl)
28
+ if (!session) return undefined
29
+ const approved = session.scopes
30
+ if (!approved || !options.scopes.every((scope) => approved.includes(scope)))
31
+ return failure(
32
+ 'scope_not_approved',
33
+ 'Run login again and enable the required scopes under “Modify auth scopes”.',
34
+ )
35
+ const request = { headers: { authorization: `Bearer ${session.token}` } }
36
+ const me = await api.v1.me.$get(undefined, request)
37
+ if (me.status !== 200) return me
38
+ const orgs = await api.v1.orgs.$get(undefined, request)
39
+ if (orgs.status !== 200) return orgs
40
+ const organizations = (await orgs.json()).data
41
+ const orgId = options.orgId ?? (organizations.length === 1 ? organizations[0]!.id : undefined)
42
+ if (!orgId)
43
+ return failure(
44
+ 'organization_required',
45
+ `Set TEMPO_API_ORG to one of: ${describe(organizations)}.`,
46
+ )
47
+ const org = api.v1.orgs[':orgId{org_[A-Za-z0-9_-]+}']
48
+ const projects = await org.projects.$get({ param: { orgId } }, request)
49
+ if (projects.status !== 200) return projects
50
+ const choices = (await projects.json()).data
51
+ const projectId = options.projectId ?? (choices.length === 1 ? choices[0]!.id : undefined)
52
+ if (!projectId)
53
+ return failure('project_required', `Set TEMPO_API_PROJECT to one of: ${describe(choices)}.`)
54
+ if (!choices.some(({ id }) => id === projectId))
55
+ return failure(
56
+ 'project_not_found',
57
+ 'The selected project does not belong to this organization.',
58
+ )
59
+ const environment = options.environment ?? 'production'
60
+ const catalog = await api.v1.scopes.$get({}, request)
61
+ if (catalog.status !== 200) return catalog
62
+ const entries = (await catalog.json()).data
63
+ const selfServe = entries.filter(({ selfServe }) => selfServe).map(({ scope }) => scope)
64
+ const scopes = [...new Set(options.scopes)]
65
+ if (
66
+ scopes.includes('routes:write') &&
67
+ !scopes.includes('routes:read') &&
68
+ approved.includes('routes:read')
69
+ )
70
+ scopes.push('routes:read')
71
+ const project = org.projects[':projectId{prj_[A-Za-z0-9_-]+}']
72
+ const restricted = scopes.filter((scope) => !selfServe.includes(scope))
73
+ const sourceKeyId = await (async () => {
74
+ if (restricted.length === 0 && !options.sourceKeyId) return undefined
75
+ const listed = await project['api-keys'].$get(
76
+ { param: { orgId, projectId }, query: { environment, include: '' } },
77
+ request,
78
+ )
79
+ if (listed.status !== 200) return listed
80
+ // Locally inferred credentials are destinations, not additional provisioned source choices.
81
+ const inferredIds = new Set(session.apiKeys?.map(({ id }) => id))
82
+ const sources = (await listed.json()).data.filter(
83
+ (key) =>
84
+ !inferredIds.has(key.id) &&
85
+ restricted.every(
86
+ (scope) => key.scopes.includes(scope) || key.scopes.includes(Scope.wildcard),
87
+ ),
88
+ )
89
+ const source = options.sourceKeyId
90
+ ? sources.find(({ id }) => id === options.sourceKeyId)
91
+ : sources.length === 1
92
+ ? sources[0]
93
+ : undefined
94
+ if (!source)
95
+ return failure(
96
+ 'api_key_required',
97
+ sources.length === 0
98
+ ? 'This project needs a Tempo-approved key with the required scopes. Set TEMPO_API_KEY to an approved key, or ask Tempo to provision this project.'
99
+ : `Set TEMPO_API_SOURCE_KEY to one of: ${sources.map(({ id }) => id).join(', ')}.`,
100
+ )
101
+ return source.id
102
+ })()
103
+ if (sourceKeyId && typeof sourceKeyId !== 'string') return sourceKeyId
104
+ // Resolve the live source grant before reusing a key so caching never hides new ambiguity.
105
+ const cached = session.apiKeys?.find(
106
+ (key) =>
107
+ key.orgId === orgId &&
108
+ key.projectId === projectId &&
109
+ key.environment === environment &&
110
+ (!key.expiresAt || Date.parse(key.expiresAt) > Date.now()) &&
111
+ (!sourceKeyId || key.sourceKeyId === sourceKeyId) &&
112
+ options.scopes.every((scope) => key.scopes.includes(scope)),
113
+ )
114
+ if (cached) return cached.token
115
+ const minted = await project['api-keys'].$post(
116
+ {
117
+ json: { environment, name: 'Tempo CLI', scopes, ...(sourceKeyId ? { sourceKeyId } : {}) },
118
+ param: { orgId, projectId },
119
+ },
120
+ request,
121
+ )
122
+ if (minted.status !== 200) return minted
123
+ const key = await minted.json()
124
+ await credentials.set(apiUrl, {
125
+ ...session,
126
+ apiKeys: [
127
+ ...(session.apiKeys ?? []),
128
+ {
129
+ environment,
130
+ ...(key.expiresAt ? { expiresAt: key.expiresAt } : {}),
131
+ id: key.id,
132
+ orgId,
133
+ projectId,
134
+ scopes: key.scopes,
135
+ ...(sourceKeyId ? { sourceKeyId } : {}),
136
+ token: key.token,
137
+ },
138
+ ],
139
+ })
140
+ return key.token
141
+ }
142
+
143
+ export declare namespace resolve {
144
+ /** Context and permissions required by the generated operation. */
145
+ type Options = {
146
+ /** API-key environment. Defaults to production. */
147
+ environment?: 'production' | 'sandbox' | undefined
148
+ /** Owning organization; inferred only when unambiguous. */
149
+ orgId?: string | undefined
150
+ /** Attributed project; inferred only when unambiguous. */
151
+ projectId?: string | undefined
152
+ /** Scopes required by the operation. */
153
+ scopes: readonly string[]
154
+ /** Approved source key when more than one can delegate the required scopes. */
155
+ sourceKeyId?: string | undefined
156
+ }
157
+ }
158
+
159
+ /** Revokes inferred keys before forgetting or replacing a CLI session. */
160
+ export async function revoke(context: Auth.Context, session: Credentials.Session) {
161
+ const keys = session.apiKeys ?? []
162
+ const request = { headers: { authorization: `Bearer ${session.token}` } }
163
+ const results = await Promise.all(
164
+ keys.map(async (key) => {
165
+ const response = await context.api.v1.orgs[':orgId{org_[A-Za-z0-9_-]+}'].projects[
166
+ ':projectId{prj_[A-Za-z0-9_-]+}'
167
+ ]['api-keys'][':keyId{key_[A-Za-z0-9_-]+}']
168
+ .$delete(
169
+ {
170
+ param: { keyId: key.id, orgId: key.orgId, projectId: key.projectId },
171
+ },
172
+ request,
173
+ )
174
+ .catch(() => undefined)
175
+ return response?.status === 200 || response?.status === 404
176
+ }),
177
+ )
178
+ return results.every(Boolean)
179
+ }
180
+
181
+ function failure(code: string, message: string) {
182
+ return Response.json({ error: { code, message } }, { status: 403 })
183
+ }
184
+
185
+ function describe(choices: readonly { id: string; name: string }[]) {
186
+ return choices.length
187
+ ? choices.map(({ id, name }) => `${id} (${name})`).join(', ')
188
+ : 'none; create one in the Tempo console first'
189
+ }
@@ -1,7 +1,13 @@
1
+ import * as fs from 'node:fs/promises'
2
+ import * as http from 'node:http'
3
+ import type * as net from 'node:net'
4
+ import * as os from 'node:os'
5
+ import * as path from 'node:path'
1
6
  import { Cli as incur_Cli, z } from 'incur'
2
7
  import { Cli } from 'tapimo/server'
3
8
 
4
9
  import * as TestApp from '../../test/App.js'
10
+ import * as TestCli from '../../test/cli.js'
5
11
  import * as Runtime from '../../test/runtime.js'
6
12
 
7
13
  const apiUrl = 'https://api.tempo-api.test'
@@ -83,6 +89,188 @@ describe('from', () => {
83
89
  fetch.mockRestore()
84
90
  }
85
91
  })
92
+
93
+ test('generates commands for the v1 API only', async () => {
94
+ const context = await TestCli.create()
95
+ const spec = (await (await context.app.request('/openapi.json')).json()) as {
96
+ paths: Record<string, unknown>
97
+ }
98
+ const groups = new Set(Object.keys(spec.paths).map((path) => path.split('/')[1]))
99
+ expect(groups).toEqual(new Set(['gecko', 'rpc', 'v1']))
100
+
101
+ const { lines } = await TestCli.serve(context.cli, ['--help'])
102
+ const commands = lines
103
+ .slice(lines.indexOf('Commands:') + 1, lines.indexOf('Integrations:'))
104
+ .map((line) => line.trim())
105
+ expect(commands).toContain('v1 Call any Tempo API endpoint.')
106
+ for (const name of ['gecko', 'rpc'])
107
+ expect(commands.some((line) => line.startsWith(`${name} `))).toBe(false)
108
+ })
109
+
110
+ test('sends the CLI session to session operations and the API key elsewhere', async () => {
111
+ const context = await TestCli.create({ apiKey: TestApp.key.token })
112
+ await TestCli.login(context)
113
+ const { token } = (await context.credentials.get(TestCli.origin))!
114
+ const sent = (pathname: string) =>
115
+ context.requests.findLast((request) => new URL(request.url).pathname === pathname)!.headers
116
+
117
+ expect((await TestCli.serve(context.cli, ['v1', 'orgs', 'get', '--format', 'json'])).code).toBe(
118
+ 0,
119
+ )
120
+ expect(sent('/v1/orgs').get('authorization')).toBe(`Bearer ${token}`)
121
+ expect(sent('/v1/orgs').has('tempo-api-key')).toBe(false)
122
+
123
+ await TestCli.serve(context.cli, ['v1', 'tokens', 'get', '--format', 'json'])
124
+ expect(sent('/v1/tokens').get('tempo-api-key')).toBe(TestApp.key.token)
125
+ expect(sent('/v1/tokens').has('authorization')).toBe(false)
126
+
127
+ // Explicit credentials always win over stored ones.
128
+ await TestCli.serve(context.cli, ['v1', 'orgs', 'get', '--authorization', 'Bearer explicit'])
129
+ expect(sent('/v1/orgs').get('authorization')).toBe('Bearer explicit')
130
+
131
+ // Including the `key` query credential, which the API reads after `Authorization`.
132
+ await TestCli.serve(context.cli, ['/v1/orgs', '--key', TestApp.key.token])
133
+ const request = context.requests.at(-1)!
134
+ expect(new URL(request.url).searchParams.get('key')).toBe(TestApp.key.token)
135
+ expect(request.headers.has('authorization')).toBe(false)
136
+ expect(request.headers.has('tempo-api-key')).toBe(false)
137
+ })
138
+
139
+ test('preserves an explicit compatibility API key without inferring credentials', async () => {
140
+ const context = await TestCli.create({
141
+ request: { headers: { 'x-api-key': TestApp.key.token } },
142
+ })
143
+ await TestCli.login(context)
144
+ await TestCli.serve(context.cli, ['v1', 'routes', 'transfers', 'get', '--format', 'json'])
145
+ const request = context.requests.findLast(
146
+ (request) => new URL(request.url).pathname === '/v1/routes/transfers',
147
+ )!
148
+ expect(request.headers.get('x-api-key')).toBe(TestApp.key.token)
149
+ expect(request.headers.has('tempo-api-key')).toBe(false)
150
+ expect(request.headers.has('authorization')).toBe(false)
151
+ expect((await context.credentials.get(TestCli.origin))?.apiKeys).toBeUndefined()
152
+ expect(
153
+ context.requests.some(
154
+ (request) => request.method === 'POST' && request.url.endsWith('/api-keys'),
155
+ ),
156
+ ).toBe(false)
157
+ })
158
+
159
+ test('forwards gateway request defaults to login, inference, and revocation', async () => {
160
+ const context = await TestCli.create({
161
+ request: {
162
+ headers: {
163
+ 'cf-access-client-id': 'gateway-client',
164
+ 'cf-access-client-secret': 'gateway-secret',
165
+ },
166
+ redirect: 'manual',
167
+ },
168
+ })
169
+ const { cookie } = await TestCli.login(context)
170
+ const created = await context.app.request('/v1/orgs', {
171
+ body: JSON.stringify({ name: 'Gateway project' }),
172
+ headers: { 'content-type': 'application/json', cookie },
173
+ method: 'POST',
174
+ })
175
+ const org = await created.json()
176
+ await context.app.request(`/v1/orgs/${org.id}/projects`, {
177
+ body: JSON.stringify({ name: 'Gateway' }),
178
+ headers: { 'content-type': 'application/json', cookie },
179
+ method: 'POST',
180
+ })
181
+ const result = await TestCli.serve(context.cli, [
182
+ 'v1',
183
+ 'routes',
184
+ 'transfers',
185
+ 'get',
186
+ '--format',
187
+ 'json',
188
+ ])
189
+ expect(result.code).toBe(0)
190
+ expect((await context.credentials.get(TestCli.origin))?.apiKeys).toHaveLength(1)
191
+ expect((await TestCli.serve(context.cli, ['logout', '--format', 'json'])).code).toBe(0)
192
+ expect(context.requests.some((request) => new URL(request.url).pathname === '/v1/scopes')).toBe(
193
+ true,
194
+ )
195
+ expect(
196
+ context.requests.some(
197
+ (request) => request.method === 'POST' && request.url.endsWith('/api-keys'),
198
+ ),
199
+ ).toBe(true)
200
+ expect(context.requests.some((request) => request.method === 'DELETE')).toBe(true)
201
+ for (const request of context.requests) {
202
+ expect(request.headers.get('cf-access-client-id')).toBe('gateway-client')
203
+ expect(request.headers.get('cf-access-client-secret')).toBe('gateway-secret')
204
+ expect(request.redirect).toBe('manual')
205
+ }
206
+ })
207
+
208
+ test('sends the API key only to operations that accept one', async () => {
209
+ const context = await TestCli.create({ apiKey: TestApp.key.token })
210
+ const sent = (pathname: string) =>
211
+ context.requests.findLast((request) => new URL(request.url).pathname === pathname)
212
+
213
+ // Sign-in-only operations stop before sending, so an API key cannot earn a misleading 403.
214
+ const invitations = await TestCli.serve(context.cli, [
215
+ 'v1',
216
+ 'invitations',
217
+ 'get',
218
+ '--format',
219
+ 'json',
220
+ ])
221
+ expect(invitations.code).toBe(1)
222
+ expect(JSON.parse(invitations.lines.join('\n'))).toMatchObject({
223
+ code: 'not_signed_in',
224
+ message: 'Not signed in, or the session expired. Run `tapimo login`.',
225
+ })
226
+ expect(sent('/v1/invitations')).toBeUndefined()
227
+
228
+ // Public operations go out without credentials.
229
+ await TestCli.serve(context.cli, [
230
+ 'v1',
231
+ 'auth',
232
+ 'siwe',
233
+ 'challenge',
234
+ 'post',
235
+ '--format',
236
+ 'json',
237
+ ])
238
+ expect(sent('/v1/auth/siwe/challenge')?.headers.has('tempo-api-key')).toBe(false)
239
+ })
240
+ })
241
+
242
+ describe('fromEnv', () => {
243
+ test('keeps session commands usable when the API document cannot load', async () => {
244
+ const home = await fs.mkdtemp(path.join(os.tmpdir(), 'tapimo-home-'))
245
+ // Port 9 (discard) refuses connections, so the document fetch fails fast.
246
+ const cli = await Cli.fromEnv(
247
+ { TEMPO_API_URL: 'http://127.0.0.1:9', TEMPO_HOME: home },
248
+ { docs: false },
249
+ )
250
+ const { code, lines } = await TestCli.serve(cli, ['whoami', '--format', 'json'])
251
+ expect(code).toBe(1)
252
+ expect(JSON.parse(lines.join('\n')).code).toBe('not_signed_in')
253
+ })
254
+
255
+ test('skips fetching the API document when one is supplied', async () => {
256
+ const home = await fs.mkdtemp(path.join(os.tmpdir(), 'tapimo-home-'))
257
+ let requests = 0
258
+ const server = http.createServer((_, response) => {
259
+ requests += 1
260
+ response.end('{}')
261
+ })
262
+ await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve))
263
+ const { port } = server.address() as net.AddressInfo
264
+ try {
265
+ await Cli.fromEnv(
266
+ { TEMPO_API_URL: `http://127.0.0.1:${port}`, TEMPO_HOME: home },
267
+ { docs: false, openapi: { paths: {} } },
268
+ )
269
+ expect(requests).toBe(0)
270
+ } finally {
271
+ server.close()
272
+ }
273
+ })
86
274
  })
87
275
 
88
276
  function mockHostedApi(app = TestApp.create()) {