tapimo 0.2.0 → 0.4.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 (362) hide show
  1. package/README.md +36 -8
  2. package/dist/ApiKey.d.ts +1 -0
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +5 -2
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +28 -1
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +34 -1
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +7532 -4850
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +11 -3
  13. package/dist/App.js.map +1 -1
  14. package/dist/Scope.d.ts +11 -2
  15. package/dist/Scope.d.ts.map +1 -1
  16. package/dist/Scope.js +14 -3
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/admin/App.d.ts +63 -53
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/apps/api-keys.d.ts +7 -0
  21. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  22. package/dist/admin/apps/scopes.d.ts +8 -0
  23. package/dist/admin/apps/scopes.d.ts.map +1 -1
  24. package/dist/admin/apps/scopes.js +3 -0
  25. package/dist/admin/apps/scopes.js.map +1 -1
  26. package/dist/admin/apps/verified-tokens.d.ts +57 -57
  27. package/dist/admin/ui.generated.d.ts +1 -1
  28. package/dist/admin/ui.generated.js +13 -13
  29. package/dist/admin/ui.generated.js.map +1 -1
  30. package/dist/analytics/Analytics.d.ts +151 -0
  31. package/dist/analytics/Analytics.d.ts.map +1 -0
  32. package/dist/analytics/Analytics.js +212 -0
  33. package/dist/analytics/Analytics.js.map +1 -0
  34. package/dist/analytics/tables/requestEvents.d.ts +215 -0
  35. package/dist/analytics/tables/requestEvents.d.ts.map +1 -0
  36. package/dist/analytics/tables/requestEvents.js +264 -0
  37. package/dist/analytics/tables/requestEvents.js.map +1 -0
  38. package/dist/apps/data/App.d.ts +1049 -624
  39. package/dist/apps/data/App.d.ts.map +1 -1
  40. package/dist/apps/data/App.js +36 -0
  41. package/dist/apps/data/App.js.map +1 -1
  42. package/dist/apps/data/FundingRouteProviders.d.ts +54 -0
  43. package/dist/apps/data/FundingRouteProviders.d.ts.map +1 -0
  44. package/dist/apps/data/FundingRouteProviders.js +355 -0
  45. package/dist/apps/data/FundingRouteProviders.js.map +1 -0
  46. package/dist/apps/data/index.d.ts +1 -0
  47. package/dist/apps/data/index.d.ts.map +1 -1
  48. package/dist/apps/data/index.js +1 -0
  49. package/dist/apps/data/index.js.map +1 -1
  50. package/dist/apps/data/routes/balances.d.ts +45 -45
  51. package/dist/apps/data/routes/coingecko.d.ts +176 -176
  52. package/dist/apps/data/routes/exchanges.d.ts +455 -455
  53. package/dist/apps/data/routes/fee-amm.d.ts +101 -101
  54. package/dist/apps/data/routes/funding.d.ts +843 -0
  55. package/dist/apps/data/routes/funding.d.ts.map +1 -0
  56. package/dist/apps/data/routes/funding.js +443 -0
  57. package/dist/apps/data/routes/funding.js.map +1 -0
  58. package/dist/apps/data/routes/indexer.d.ts +5 -5
  59. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  60. package/dist/apps/data/routes/receipts.js +2 -8
  61. package/dist/apps/data/routes/receipts.js.map +1 -1
  62. package/dist/apps/data/routes/rpc.d.ts +29 -36
  63. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  64. package/dist/apps/data/routes/rpc.js +29 -1
  65. package/dist/apps/data/routes/rpc.js.map +1 -1
  66. package/dist/apps/data/routes/tokenlist.d.ts +36 -36
  67. package/dist/apps/data/routes/transfers.d.ts +56 -56
  68. package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
  69. package/dist/apps/data/routes/webhooks.d.ts +45 -45
  70. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  71. package/dist/apps/data/routes/webhooks.js +8 -8
  72. package/dist/apps/data/routes/webhooks.js.map +1 -1
  73. package/dist/apps/docs/App.d.ts +5 -3
  74. package/dist/apps/docs/App.d.ts.map +1 -1
  75. package/dist/apps/docs/App.js +28 -96
  76. package/dist/apps/docs/App.js.map +1 -1
  77. package/dist/apps/docs/reference.d.ts +21 -0
  78. package/dist/apps/docs/reference.d.ts.map +1 -0
  79. package/dist/apps/docs/reference.js +112 -0
  80. package/dist/apps/docs/reference.js.map +1 -0
  81. package/dist/apps/index.d.ts +3 -2
  82. package/dist/apps/index.d.ts.map +1 -1
  83. package/dist/apps/index.js +3 -2
  84. package/dist/apps/index.js.map +1 -1
  85. package/dist/apps/{platform → management}/App.d.ts +3015 -738
  86. package/dist/apps/management/App.d.ts.map +1 -0
  87. package/dist/apps/{platform → management}/App.js +20 -10
  88. package/dist/apps/management/App.js.map +1 -0
  89. package/dist/apps/management/Billing.d.ts +279 -0
  90. package/dist/apps/management/Billing.d.ts.map +1 -0
  91. package/dist/apps/management/Billing.js +477 -0
  92. package/dist/apps/management/Billing.js.map +1 -0
  93. package/dist/apps/management/index.d.ts +3 -0
  94. package/dist/apps/management/index.d.ts.map +1 -0
  95. package/dist/apps/management/index.js +3 -0
  96. package/dist/apps/management/index.js.map +1 -0
  97. package/dist/apps/{platform → management}/routes/api-keys.d.ts +341 -49
  98. package/dist/apps/management/routes/api-keys.d.ts.map +1 -0
  99. package/dist/apps/{platform → management}/routes/api-keys.js +116 -14
  100. package/dist/apps/management/routes/api-keys.js.map +1 -0
  101. package/dist/apps/management/routes/billing.d.ts +1520 -0
  102. package/dist/apps/management/routes/billing.d.ts.map +1 -0
  103. package/dist/apps/management/routes/billing.js +795 -0
  104. package/dist/apps/management/routes/billing.js.map +1 -0
  105. package/dist/apps/{platform → management}/routes/invitations.d.ts +202 -84
  106. package/dist/apps/management/routes/invitations.d.ts.map +1 -0
  107. package/dist/apps/{platform → management}/routes/invitations.js +59 -1
  108. package/dist/apps/management/routes/invitations.js.map +1 -0
  109. package/dist/apps/{platform → management}/routes/me.d.ts +17 -17
  110. package/dist/apps/management/routes/me.d.ts.map +1 -0
  111. package/dist/apps/management/routes/me.js.map +1 -0
  112. package/dist/apps/management/routes/members.d.ts.map +1 -0
  113. package/dist/apps/management/routes/members.js.map +1 -0
  114. package/dist/apps/{platform → management}/routes/orgs.d.ts +50 -36
  115. package/dist/apps/management/routes/orgs.d.ts.map +1 -0
  116. package/dist/apps/{platform → management}/routes/orgs.js +14 -3
  117. package/dist/apps/management/routes/orgs.js.map +1 -0
  118. package/dist/apps/{platform → management}/routes/projects.d.ts +97 -97
  119. package/dist/apps/{platform → management}/routes/projects.d.ts.map +1 -1
  120. package/dist/apps/management/routes/projects.js.map +1 -0
  121. package/dist/apps/management/routes/scopes.d.ts +107 -0
  122. package/dist/apps/management/routes/scopes.d.ts.map +1 -0
  123. package/dist/apps/management/routes/scopes.js +66 -0
  124. package/dist/apps/management/routes/scopes.js.map +1 -0
  125. package/dist/apps/management/routes/usage.d.ts +588 -0
  126. package/dist/apps/management/routes/usage.d.ts.map +1 -0
  127. package/dist/apps/management/routes/usage.js +391 -0
  128. package/dist/apps/management/routes/usage.js.map +1 -0
  129. package/dist/apps/mcp.d.ts +76 -0
  130. package/dist/apps/mcp.d.ts.map +1 -0
  131. package/dist/apps/mcp.js +188 -0
  132. package/dist/apps/mcp.js.map +1 -0
  133. package/dist/apps/relay/App.d.ts +4 -1
  134. package/dist/apps/relay/App.d.ts.map +1 -1
  135. package/dist/apps/relay/App.js +118 -10
  136. package/dist/apps/relay/App.js.map +1 -1
  137. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  138. package/dist/apps/relay/Sponsorships.js +2 -1
  139. package/dist/apps/relay/Sponsorships.js.map +1 -1
  140. package/dist/cli/Cli.d.ts +8 -1
  141. package/dist/cli/Cli.d.ts.map +1 -1
  142. package/dist/cli/Cli.js +11 -3
  143. package/dist/cli/Cli.js.map +1 -1
  144. package/dist/cli/commands/admin.d.ts +4 -0
  145. package/dist/cli/commands/admin.d.ts.map +1 -1
  146. package/dist/cli/commands/admin.js +80 -1
  147. package/dist/cli/commands/admin.js.map +1 -1
  148. package/dist/db/Db.d.ts +7 -0
  149. package/dist/db/Db.d.ts.map +1 -1
  150. package/dist/db/Db.js +126 -0
  151. package/dist/db/Db.js.map +1 -1
  152. package/dist/db/Schema.d.ts +79 -0
  153. package/dist/db/Schema.d.ts.map +1 -1
  154. package/dist/db/Schema.js +88 -2
  155. package/dist/db/Schema.js.map +1 -1
  156. package/dist/db/tables/billingSettings.d.ts +55 -0
  157. package/dist/db/tables/billingSettings.d.ts.map +1 -0
  158. package/dist/db/tables/billingSettings.js +70 -0
  159. package/dist/db/tables/billingSettings.js.map +1 -0
  160. package/dist/db/tables/invitations.js +2 -2
  161. package/dist/db/tables/invitations.js.map +1 -1
  162. package/dist/db/tables/organizations.d.ts +6 -2
  163. package/dist/db/tables/organizations.d.ts.map +1 -1
  164. package/dist/db/tables/organizations.js +10 -4
  165. package/dist/db/tables/organizations.js.map +1 -1
  166. package/dist/db/tables/projects.js +2 -2
  167. package/dist/db/tables/projects.js.map +1 -1
  168. package/dist/db/tables/requestUsage.d.ts +121 -0
  169. package/dist/db/tables/requestUsage.d.ts.map +1 -0
  170. package/dist/db/tables/requestUsage.js +150 -0
  171. package/dist/db/tables/requestUsage.js.map +1 -0
  172. package/dist/db/tables/sponsoredTransactions.d.ts +119 -0
  173. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  174. package/dist/db/tables/sponsoredTransactions.js +155 -2
  175. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  176. package/dist/db/tables/stripeCustomers.d.ts +81 -0
  177. package/dist/db/tables/stripeCustomers.d.ts.map +1 -0
  178. package/dist/db/tables/stripeCustomers.js +120 -0
  179. package/dist/db/tables/stripeCustomers.js.map +1 -0
  180. package/dist/db/tables/users.js +2 -2
  181. package/dist/db/tables/users.js.map +1 -1
  182. package/dist/handlers/internal/sponsorship.d.ts +5 -2
  183. package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
  184. package/dist/handlers/internal/sponsorship.js +19 -5
  185. package/dist/handlers/internal/sponsorship.js.map +1 -1
  186. package/dist/handlers/internal/utils.d.ts +10 -3
  187. package/dist/handlers/internal/utils.d.ts.map +1 -1
  188. package/dist/handlers/internal/utils.js +14 -6
  189. package/dist/handlers/internal/utils.js.map +1 -1
  190. package/dist/index.d.ts +1 -0
  191. package/dist/index.d.ts.map +1 -1
  192. package/dist/index.js +1 -0
  193. package/dist/index.js.map +1 -1
  194. package/dist/internal/Auth.d.ts +18 -4
  195. package/dist/internal/Auth.d.ts.map +1 -1
  196. package/dist/internal/Auth.js +149 -77
  197. package/dist/internal/Auth.js.map +1 -1
  198. package/dist/internal/Cache.d.ts.map +1 -1
  199. package/dist/internal/Cache.js +4 -1
  200. package/dist/internal/Cache.js.map +1 -1
  201. package/dist/internal/EdgeCache.d.ts +10 -0
  202. package/dist/internal/EdgeCache.d.ts.map +1 -1
  203. package/dist/internal/EdgeCache.js +39 -8
  204. package/dist/internal/EdgeCache.js.map +1 -1
  205. package/dist/internal/Fees.d.ts +27 -0
  206. package/dist/internal/Fees.d.ts.map +1 -0
  207. package/dist/internal/Fees.js +48 -0
  208. package/dist/internal/Fees.js.map +1 -0
  209. package/dist/internal/FundingRoutes.d.ts +915 -0
  210. package/dist/internal/FundingRoutes.d.ts.map +1 -0
  211. package/dist/internal/FundingRoutes.js +625 -0
  212. package/dist/internal/FundingRoutes.js.map +1 -0
  213. package/dist/internal/Id.d.ts +15 -0
  214. package/dist/internal/Id.d.ts.map +1 -0
  215. package/dist/internal/Id.js +22 -0
  216. package/dist/internal/Id.js.map +1 -0
  217. package/dist/internal/Log.d.ts +2 -0
  218. package/dist/internal/Log.d.ts.map +1 -1
  219. package/dist/internal/Log.js +3 -0
  220. package/dist/internal/Log.js.map +1 -1
  221. package/dist/internal/OpenApi.d.ts +10 -1
  222. package/dist/internal/OpenApi.d.ts.map +1 -1
  223. package/dist/internal/OpenApi.js +8 -1
  224. package/dist/internal/OpenApi.js.map +1 -1
  225. package/dist/internal/RateLimit.d.ts +25 -0
  226. package/dist/internal/RateLimit.d.ts.map +1 -1
  227. package/dist/internal/RateLimit.js +51 -0
  228. package/dist/internal/RateLimit.js.map +1 -1
  229. package/dist/internal/Response.d.ts +1 -1
  230. package/dist/internal/Response.d.ts.map +1 -1
  231. package/dist/internal/Schema.d.ts +8 -0
  232. package/dist/internal/Schema.d.ts.map +1 -1
  233. package/dist/internal/Schema.js +7 -0
  234. package/dist/internal/Schema.js.map +1 -1
  235. package/dist/internal/Webhooks.d.ts.map +1 -1
  236. package/dist/internal/Webhooks.js +3 -3
  237. package/dist/internal/Webhooks.js.map +1 -1
  238. package/package.json +8 -7
  239. package/src/ApiKey.ts +9 -2
  240. package/src/ApiKeys.test.ts +51 -0
  241. package/src/ApiKeys.ts +50 -1
  242. package/src/App.test.ts +33 -86718
  243. package/src/App.ts +26 -8
  244. package/src/Client.test-d.ts +353 -2
  245. package/src/Scope.ts +16 -3
  246. package/src/admin/apps/scopes.test.ts +6 -0
  247. package/src/admin/apps/scopes.ts +3 -0
  248. package/src/admin/ui/src/components/Page.tsx +2 -3
  249. package/src/admin/ui/src/routes/__root.tsx +2 -2
  250. package/src/admin/ui/src/routes/api-keys.tsx +2 -2
  251. package/src/admin/ui.generated.ts +13 -13
  252. package/src/analytics/Analytics.test.ts +527 -0
  253. package/src/analytics/Analytics.ts +318 -0
  254. package/src/analytics/tables/requestEvents.ts +523 -0
  255. package/src/apps/composition.test.ts +26 -13
  256. package/src/apps/data/App.test.ts +72 -0
  257. package/src/apps/data/App.ts +37 -0
  258. package/src/apps/data/FundingRouteProviders.test.ts +281 -0
  259. package/src/apps/data/FundingRouteProviders.ts +459 -0
  260. package/src/apps/data/index.ts +1 -0
  261. package/src/apps/data/routes/funding.test.ts +314 -0
  262. package/src/apps/data/routes/funding.ts +698 -0
  263. package/src/apps/data/routes/receipts.ts +2 -9
  264. package/src/apps/data/routes/rpc.test.ts +78 -2
  265. package/src/apps/data/routes/rpc.ts +31 -1
  266. package/src/apps/data/routes/webhooks.test.ts +1 -1
  267. package/src/apps/data/routes/webhooks.ts +11 -8
  268. package/src/apps/docs/App.ts +30 -101
  269. package/src/apps/docs/reference.ts +132 -0
  270. package/src/apps/index.ts +3 -2
  271. package/src/apps/{platform → management}/App.ts +56 -17
  272. package/src/apps/management/Billing.test.ts +530 -0
  273. package/src/apps/management/Billing.ts +682 -0
  274. package/src/apps/management/index.ts +2 -0
  275. package/src/apps/{platform → management}/routes/api-keys.test.ts +172 -9
  276. package/src/apps/{platform → management}/routes/api-keys.ts +137 -21
  277. package/src/apps/management/routes/billing.test.ts +1100 -0
  278. package/src/apps/management/routes/billing.ts +966 -0
  279. package/src/apps/{platform → management}/routes/invitations.test.ts +55 -7
  280. package/src/apps/{platform → management}/routes/invitations.ts +69 -1
  281. package/src/apps/management/routes/me.test.ts +351 -0
  282. package/src/apps/{platform → management}/routes/orgs.ts +26 -4
  283. package/src/apps/management/routes/scopes.test.ts +29 -0
  284. package/src/apps/management/routes/scopes.ts +85 -0
  285. package/src/apps/management/routes/usage.test.ts +422 -0
  286. package/src/apps/management/routes/usage.ts +527 -0
  287. package/src/apps/mcp.test.ts +206 -0
  288. package/src/apps/mcp.ts +250 -0
  289. package/src/apps/relay/App.test.ts +457 -8
  290. package/src/apps/relay/App.ts +120 -12
  291. package/src/apps/relay/Sponsorships.test.ts +1 -1
  292. package/src/apps/relay/Sponsorships.ts +2 -1
  293. package/src/cli/Cli.test.ts +25 -2
  294. package/src/cli/Cli.ts +17 -2
  295. package/src/cli/commands/admin.test.ts +83 -0
  296. package/src/cli/commands/admin.ts +89 -1
  297. package/src/db/Db.ts +137 -0
  298. package/src/db/Schema.ts +104 -2
  299. package/src/db/tables/billingSettings.test.ts +87 -0
  300. package/src/db/tables/billingSettings.ts +108 -0
  301. package/src/db/tables/invitations.ts +2 -2
  302. package/src/db/tables/organizations.test.ts +1 -1
  303. package/src/db/tables/organizations.ts +15 -5
  304. package/src/db/tables/projects.ts +2 -2
  305. package/src/db/tables/requestUsage.ts +231 -0
  306. package/src/db/tables/sponsoredTransactions.test.ts +108 -1
  307. package/src/db/tables/sponsoredTransactions.ts +230 -2
  308. package/src/db/tables/stripeCustomers.test.ts +109 -0
  309. package/src/db/tables/stripeCustomers.ts +162 -0
  310. package/src/db/tables/users.ts +2 -2
  311. package/src/handlers/internal/sponsorship.ts +34 -7
  312. package/src/handlers/internal/utils.ts +19 -7
  313. package/src/index.ts +1 -0
  314. package/src/internal/Auth.test.ts +175 -25
  315. package/src/internal/Auth.ts +176 -87
  316. package/src/internal/Cache.ts +5 -1
  317. package/src/internal/EdgeCache.test.ts +27 -4
  318. package/src/internal/EdgeCache.ts +47 -9
  319. package/src/internal/Fees.test.ts +32 -0
  320. package/src/internal/Fees.ts +51 -0
  321. package/src/internal/FundingRoutes.test.ts +213 -0
  322. package/src/internal/FundingRoutes.ts +898 -0
  323. package/src/internal/Id.test.ts +17 -0
  324. package/src/internal/Id.ts +24 -0
  325. package/src/internal/Log.test.ts +1 -0
  326. package/src/internal/Log.ts +5 -0
  327. package/src/internal/OpenApi.ts +12 -1
  328. package/src/internal/RateLimit.test.ts +84 -0
  329. package/src/internal/RateLimit.ts +70 -0
  330. package/src/internal/Response.ts +1 -1
  331. package/src/internal/Schema.ts +8 -0
  332. package/src/internal/Webhooks.test.ts +3 -3
  333. package/src/internal/Webhooks.ts +3 -3
  334. package/dist/apps/platform/App.d.ts.map +0 -1
  335. package/dist/apps/platform/App.js.map +0 -1
  336. package/dist/apps/platform/index.d.ts +0 -2
  337. package/dist/apps/platform/index.d.ts.map +0 -1
  338. package/dist/apps/platform/index.js +0 -2
  339. package/dist/apps/platform/index.js.map +0 -1
  340. package/dist/apps/platform/routes/api-keys.d.ts.map +0 -1
  341. package/dist/apps/platform/routes/api-keys.js.map +0 -1
  342. package/dist/apps/platform/routes/invitations.d.ts.map +0 -1
  343. package/dist/apps/platform/routes/invitations.js.map +0 -1
  344. package/dist/apps/platform/routes/me.d.ts.map +0 -1
  345. package/dist/apps/platform/routes/me.js.map +0 -1
  346. package/dist/apps/platform/routes/members.d.ts.map +0 -1
  347. package/dist/apps/platform/routes/members.js.map +0 -1
  348. package/dist/apps/platform/routes/orgs.d.ts.map +0 -1
  349. package/dist/apps/platform/routes/orgs.js.map +0 -1
  350. package/dist/apps/platform/routes/projects.js.map +0 -1
  351. package/src/apps/platform/index.ts +0 -1
  352. package/src/apps/platform/routes/me.test.ts +0 -121
  353. /package/dist/apps/{platform → management}/routes/me.js +0 -0
  354. /package/dist/apps/{platform → management}/routes/members.d.ts +0 -0
  355. /package/dist/apps/{platform → management}/routes/members.js +0 -0
  356. /package/dist/apps/{platform → management}/routes/projects.js +0 -0
  357. /package/src/apps/{platform → management}/routes/me.ts +0 -0
  358. /package/src/apps/{platform → management}/routes/members.test.ts +0 -0
  359. /package/src/apps/{platform → management}/routes/members.ts +0 -0
  360. /package/src/apps/{platform → management}/routes/orgs.test.ts +0 -0
  361. /package/src/apps/{platform → management}/routes/projects.test.ts +0 -0
  362. /package/src/apps/{platform → management}/routes/projects.ts +0 -0
@@ -175,6 +175,7 @@ describe('require', () => {
175
175
  expect(entries[0]?.errorCode).toMatchInlineSnapshot(`"api_key_forbidden"`)
176
176
  expect(entries[0]?.principal).toMatchInlineSnapshot(`
177
177
  {
178
+ "billingActive": false,
178
179
  "environment": "production",
179
180
  "id": "key_test",
180
181
  "orgId": "org_test",
@@ -499,7 +500,15 @@ describe('require', () => {
499
500
  describe('environment', () => {
500
501
  const sandboxToken = 'secret_sandbox'
501
502
 
502
- function createChainApp(options: { public?: boolean } = {}) {
503
+ function createChainApp(
504
+ options: {
505
+ public?: boolean
506
+ publicRateLimit?: RateLimit.Limit
507
+ rateLimit?: RateLimit.Store
508
+ sandboxBillingActive?: boolean
509
+ mpp?: Auth.Context['mpp']
510
+ } = {},
511
+ ) {
503
512
  const auth: Auth.Context = {
504
513
  apiKey: {
505
514
  resolve: TestApp.resolver({
@@ -511,27 +520,33 @@ describe('require', () => {
511
520
  orgId: 'org_test',
512
521
  scopes: [Scope.wildcard],
513
522
  token: sandboxToken,
523
+ ...(options.sandboxBillingActive === undefined
524
+ ? {}
525
+ : { billingActive: options.sandboxBillingActive }),
514
526
  },
515
527
  ],
516
528
  }),
517
529
  },
518
- rateLimit: RateLimit.memory(),
530
+ rateLimit: options.rateLimit ?? RateLimit.memory(),
531
+ ...(options.publicRateLimit ? { publicRateLimit: options.publicRateLimit } : {}),
532
+ ...(options.mpp ? { mpp: options.mpp } : {}),
519
533
  }
520
534
  const policy: Auth.require.Policy = {
521
535
  apiKey: { scopes: [Scope.wildcard] },
522
536
  ...(options.public === false ? {} : { public: { rateLimit: { perMinute: 60 } } }),
537
+ ...(options.mpp ? { mpp: { charge: { amount: '1' } } } : {}),
523
538
  }
524
539
  const app = new Hono<Auth.Environment>()
525
540
  app.use('*', async (c, next) => {
526
541
  c.set('auth', auth)
527
- // Mirror the app default so sandbox steering toward testnet is observable.
542
+ // Mirror the app default (mainnet) so the effective chain is observable.
528
543
  c.set('chainId' as never, Viem.defaultChainId as never)
529
544
  await next()
530
545
  })
531
546
  app.use('/protected', Auth.require(policy))
532
547
  app.get('/protected', (c) => {
533
548
  // Mirror how real handlers resolve the effective chain: explicit query
534
- // wins, else the context default (which auth may steer to testnet).
549
+ // wins, else the context default. Auth no longer steers this value.
535
550
  const raw = c.req.query('chainId')
536
551
  const chainId = raw ? Number(raw) : ((c.get('chainId' as never) as number | null) ?? null)
537
552
  return c.json({ chainId, principal: Auth.getPrincipal(c)?.type ?? null })
@@ -539,45 +554,39 @@ describe('require', () => {
539
554
  return app
540
555
  }
541
556
 
542
- test('falls through to the public policy for a sandbox key on explicit mainnet', async () => {
557
+ test('rejects a sandbox key on explicit mainnet', async () => {
543
558
  const app = createChainApp()
544
559
  const response = await app.request('/protected?chainId=4217', {
545
560
  headers: { 'tempo-api-key': sandboxToken },
546
561
  })
547
- expect(response.status).toMatchInlineSnapshot(`200`)
548
- // Treated as anonymous (public) rather than rejected; chain stays mainnet.
562
+ expect(response.status).toMatchInlineSnapshot(`403`)
549
563
  expect(await response.json()).toMatchInlineSnapshot(`
550
564
  {
551
- "chainId": 4217,
552
- "principal": "public",
565
+ "error": {
566
+ "code": "api_key_forbidden",
567
+ "message": "Sandbox API keys only support testnet. Pass a testnet \`chainId\`.",
568
+ },
553
569
  }
554
570
  `)
555
571
  })
556
572
 
557
- test('falls through to the public policy for a sandbox key on the mainnet alias', async () => {
573
+ test('rejects a sandbox key on the mainnet alias', async () => {
558
574
  const app = createChainApp()
559
575
  const response = await app.request('/protected?chainId=mainnet', {
560
576
  headers: { 'tempo-api-key': sandboxToken },
561
577
  })
562
- expect(response.status).toMatchInlineSnapshot(`200`)
563
- expect((await response.json()).principal).toMatchInlineSnapshot(`"public"`)
578
+ expect(response.status).toMatchInlineSnapshot(`403`)
579
+ expect((await response.json()).error.code).toMatchInlineSnapshot(`"api_key_forbidden"`)
564
580
  })
565
581
 
566
- test('a sandbox key on mainnet with no public lane is rejected as missing', async () => {
582
+ test('rejects a sandbox key on explicit mainnet even with no public lane', async () => {
567
583
  const app = createChainApp({ public: false })
568
584
  const response = await app.request('/protected?chainId=4217', {
569
585
  headers: { 'tempo-api-key': sandboxToken },
570
586
  })
571
- // With no public lane, the public policy closes to "missing API key".
572
- expect(response.status).toMatchInlineSnapshot(`401`)
573
- expect(await response.json()).toMatchInlineSnapshot(`
574
- {
575
- "error": {
576
- "code": "api_key_missing",
577
- "message": "Missing API key",
578
- },
579
- }
580
- `)
587
+ // A resolved-but-forbidden key is a 403, not anonymous fall-through.
588
+ expect(response.status).toMatchInlineSnapshot(`403`)
589
+ expect((await response.json()).error.code).toMatchInlineSnapshot(`"api_key_forbidden"`)
581
590
  })
582
591
 
583
592
  test('uses a sandbox key on an explicit non-mainnet chain', async () => {
@@ -594,15 +603,17 @@ describe('require', () => {
594
603
  `)
595
604
  })
596
605
 
597
- test('defaults a sandbox key with no chain to testnet', async () => {
606
+ test('authenticates a sandbox key with no query chain without steering', async () => {
598
607
  const app = createChainApp()
599
608
  const response = await app.request('/protected', {
600
609
  headers: { 'tempo-api-key': sandboxToken },
601
610
  })
611
+ // Auth no longer mutates `chainId`; the mainnet default is left for the
612
+ // data group's own sandbox chain guard to reject.
602
613
  expect(response.status).toMatchInlineSnapshot(`200`)
603
614
  expect(await response.json()).toMatchInlineSnapshot(`
604
615
  {
605
- "chainId": 42431,
616
+ "chainId": 4217,
606
617
  "principal": "api_key",
607
618
  }
608
619
  `)
@@ -621,6 +632,85 @@ describe('require', () => {
621
632
  }
622
633
  `)
623
634
  })
635
+
636
+ test('throttles a sandbox key to the public quota when billing is inactive', async () => {
637
+ const app = createChainApp({
638
+ public: true, // policy.public.rateLimit is { perMinute: 60 }
639
+ sandboxBillingActive: false,
640
+ })
641
+ const response = await app.request('/protected?chainId=42431', {
642
+ headers: { 'tempo-api-key': sandboxToken },
643
+ })
644
+ expect(response.status).toBe(200)
645
+ // The public ceiling (60), not the API-key default (100).
646
+ expect(response.headers.get('RateLimit-Limit')).toMatchInlineSnapshot(`"60"`)
647
+ })
648
+
649
+ test('grants a sandbox key the full API-key quota when billing is active', async () => {
650
+ const app = createChainApp({
651
+ public: true,
652
+ sandboxBillingActive: true,
653
+ })
654
+ const response = await app.request('/protected?chainId=42431', {
655
+ headers: { 'tempo-api-key': sandboxToken },
656
+ })
657
+ expect(response.status).toBe(200)
658
+ // The API-key default (100), not the public ceiling (60).
659
+ expect(response.headers.get('RateLimit-Limit')).toMatchInlineSnapshot(`"100"`)
660
+ })
661
+
662
+ test('throttles a sandbox key to the public quota when billing is unknown', async () => {
663
+ // A sandbox key minted before billing was ever active carries no
664
+ // `billingActive` flag; it falls back to the public quota.
665
+ const app = createChainApp({ public: true })
666
+ const response = await app.request('/protected?chainId=42431', {
667
+ headers: { 'tempo-api-key': sandboxToken },
668
+ })
669
+ expect(response.status).toBe(200)
670
+ expect(response.headers.get('RateLimit-Limit')).toMatchInlineSnapshot(`"60"`)
671
+ })
672
+
673
+ test('throttles to the configured public default on API-key-only routes', async () => {
674
+ const app = createChainApp({
675
+ public: false, // no per-route public lane
676
+ publicRateLimit: { perMinute: 7 },
677
+ sandboxBillingActive: false,
678
+ })
679
+ const response = await app.request('/protected?chainId=42431', {
680
+ headers: { 'tempo-api-key': sandboxToken },
681
+ })
682
+ expect(response.status).toBe(200)
683
+ expect(response.headers.get('RateLimit-Limit')).toMatchInlineSnapshot(`"7"`)
684
+ })
685
+
686
+ test('returns 429 (never a payment challenge) for a throttled sandbox key over quota', async () => {
687
+ const app = createChainApp({
688
+ mpp: createMppServer(),
689
+ rateLimit: overQuota(),
690
+ sandboxBillingActive: false,
691
+ })
692
+ const response = await app.request('/protected?chainId=42431', {
693
+ headers: { 'tempo-api-key': sandboxToken },
694
+ })
695
+ // A throttled sandbox key must activate billing, not pay per request, so
696
+ // the over-quota response is a plain 429 rather than a 402 MPP challenge.
697
+ expect(response.status).toMatchInlineSnapshot(`429`)
698
+ expect((await response.json()).error.code).toMatchInlineSnapshot(`"rate_limit_exceeded"`)
699
+ })
700
+
701
+ test('ignores a payment credential for a throttled sandbox key under quota', async () => {
702
+ const app = createChainApp({
703
+ mpp: createMppServer(),
704
+ sandboxBillingActive: false,
705
+ })
706
+ const response = await app.request('/protected?chainId=42431', {
707
+ headers: { 'tempo-api-key': sandboxToken, authorization: 'Payment paid' },
708
+ })
709
+ // The payment lane can't buy past the throttle; the request runs on the
710
+ // public quota instead of being charged.
711
+ expect(response.status).toBe(200)
712
+ expect(response.headers.get('RateLimit-Limit')).toMatchInlineSnapshot(`"60"`)
713
+ })
624
714
  })
625
715
 
626
716
  describe('mpp', () => {
@@ -921,6 +1011,65 @@ describe('require', () => {
921
1011
  error.mockRestore()
922
1012
  }
923
1013
  })
1014
+
1015
+ test('fails open (at warn) when the rate-limit Durable Object errors retryably', async () => {
1016
+ const error = vi.spyOn(console, 'error').mockImplementation(() => {})
1017
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
1018
+ try {
1019
+ const app = createApp({
1020
+ auth: {
1021
+ apiKey: { resolve: TestApp.resolver({ keys: [{ ...key, token }] }) },
1022
+ rateLimit: {
1023
+ async consume() {
1024
+ // A transient transport fault whose single retry also failed.
1025
+ throw Object.assign(new Error('Network connection lost.'), { retryable: true })
1026
+ },
1027
+ },
1028
+ },
1029
+ policy: { public: { rateLimit: { perMinute: 1 } } },
1030
+ })
1031
+ const response = await app.request('/protected', {
1032
+ headers: { 'x-forwarded-for': '203.0.113.10' },
1033
+ })
1034
+
1035
+ expect(response.status).toMatchInlineSnapshot(`200`)
1036
+ expect(response.headers.has('ratelimit-limit')).toMatchInlineSnapshot(`false`)
1037
+ expect(warn.mock.calls.length).toMatchInlineSnapshot(`1`)
1038
+ expect(error.mock.calls.length).toMatchInlineSnapshot(`0`)
1039
+ } finally {
1040
+ warn.mockRestore()
1041
+ error.mockRestore()
1042
+ }
1043
+ })
1044
+
1045
+ test('fails open (at warn) on a redacted Durable Object internal error', async () => {
1046
+ const error = vi.spyOn(console, 'error').mockImplementation(() => {})
1047
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
1048
+ try {
1049
+ const app = createApp({
1050
+ auth: {
1051
+ apiKey: { resolve: TestApp.resolver({ keys: [{ ...key, token }] }) },
1052
+ rateLimit: {
1053
+ async consume() {
1054
+ throw new Error(`internal error; reference = ${'ab12'.repeat(6)}`)
1055
+ },
1056
+ },
1057
+ },
1058
+ policy: { public: { rateLimit: { perMinute: 1 } } },
1059
+ })
1060
+ const response = await app.request('/protected', {
1061
+ headers: { 'x-forwarded-for': '203.0.113.10' },
1062
+ })
1063
+
1064
+ expect(response.status).toMatchInlineSnapshot(`200`)
1065
+ expect(response.headers.has('ratelimit-limit')).toMatchInlineSnapshot(`false`)
1066
+ expect(warn.mock.calls.length).toMatchInlineSnapshot(`1`)
1067
+ expect(error.mock.calls.length).toMatchInlineSnapshot(`0`)
1068
+ } finally {
1069
+ warn.mockRestore()
1070
+ error.mockRestore()
1071
+ }
1072
+ })
924
1073
  })
925
1074
 
926
1075
  describe('rateLimit per-scope', () => {
@@ -1113,6 +1262,7 @@ describe('require', () => {
1113
1262
  expect(response.headers.get('ratelimit-limit')).toMatchInlineSnapshot(`"1"`)
1114
1263
  expect(entries[0]?.principal).toMatchInlineSnapshot(`
1115
1264
  {
1265
+ "billingActive": false,
1116
1266
  "environment": "production",
1117
1267
  "id": "key_test",
1118
1268
  "orgId": "org_test",