tapimo 0.0.2 → 0.2.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 (517) hide show
  1. package/README.md +38 -16
  2. package/dist/ApiKey.d.ts +14 -11
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +11 -12
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +207 -0
  7. package/dist/ApiKeys.d.ts.map +1 -0
  8. package/dist/ApiKeys.js +282 -0
  9. package/dist/ApiKeys.js.map +1 -0
  10. package/dist/App.d.ts +6771 -3819
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +145 -317
  13. package/dist/App.js.map +1 -1
  14. package/dist/Handler.d.ts +86 -0
  15. package/dist/Handler.d.ts.map +1 -0
  16. package/dist/Handler.js +83 -0
  17. package/dist/Handler.js.map +1 -0
  18. package/dist/Scope.d.ts +14 -4
  19. package/dist/Scope.d.ts.map +1 -1
  20. package/dist/Scope.js +16 -4
  21. package/dist/Scope.js.map +1 -1
  22. package/dist/Webhooks.d.ts +5 -7
  23. package/dist/Webhooks.d.ts.map +1 -1
  24. package/dist/Webhooks.js +11 -4
  25. package/dist/Webhooks.js.map +1 -1
  26. package/dist/admin/Access.d.ts +1 -3
  27. package/dist/admin/Access.d.ts.map +1 -1
  28. package/dist/admin/Access.js +1 -3
  29. package/dist/admin/Access.js.map +1 -1
  30. package/dist/admin/App.d.ts +167 -205
  31. package/dist/admin/App.d.ts.map +1 -1
  32. package/dist/admin/App.js +2 -4
  33. package/dist/admin/App.js.map +1 -1
  34. package/dist/admin/apps/api-keys.d.ts +105 -5
  35. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  36. package/dist/admin/apps/api-keys.js +75 -9
  37. package/dist/admin/apps/api-keys.js.map +1 -1
  38. package/dist/admin/apps/scopes.d.ts +6 -0
  39. package/dist/admin/apps/scopes.d.ts.map +1 -1
  40. package/dist/admin/apps/verified-tokens.d.ts +35 -149
  41. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  42. package/dist/admin/apps/verified-tokens.js +18 -39
  43. package/dist/admin/apps/verified-tokens.js.map +1 -1
  44. package/dist/admin/ui.generated.d.ts +1 -1
  45. package/dist/admin/ui.generated.js +1 -1
  46. package/dist/apps/data/App.d.ts +19176 -0
  47. package/dist/apps/data/App.d.ts.map +1 -0
  48. package/dist/apps/data/App.js +236 -0
  49. package/dist/apps/data/App.js.map +1 -0
  50. package/dist/apps/data/index.d.ts +3 -0
  51. package/dist/apps/data/index.d.ts.map +1 -0
  52. package/dist/apps/data/index.js +3 -0
  53. package/dist/apps/data/index.js.map +1 -0
  54. package/dist/apps/{activities.d.ts → data/routes/activities.d.ts} +32 -32
  55. package/dist/apps/{activities.d.ts.map → data/routes/activities.d.ts.map} +1 -1
  56. package/dist/apps/{activities.js → data/routes/activities.js} +13 -13
  57. package/dist/apps/data/routes/activities.js.map +1 -0
  58. package/dist/apps/{addresses.d.ts → data/routes/addresses.d.ts} +22 -22
  59. package/dist/apps/{addresses.d.ts.map → data/routes/addresses.d.ts.map} +1 -1
  60. package/dist/apps/{addresses.js → data/routes/addresses.js} +5 -5
  61. package/dist/apps/data/routes/addresses.js.map +1 -0
  62. package/dist/apps/{balances.d.ts → data/routes/balances.d.ts} +49 -49
  63. package/dist/apps/data/routes/balances.d.ts.map +1 -0
  64. package/dist/apps/{balances.js → data/routes/balances.js} +42 -11
  65. package/dist/apps/data/routes/balances.js.map +1 -0
  66. package/dist/apps/{blocks.d.ts → data/routes/blocks.d.ts} +47 -47
  67. package/dist/apps/data/routes/blocks.d.ts.map +1 -0
  68. package/dist/apps/{blocks.js → data/routes/blocks.js} +13 -13
  69. package/dist/apps/data/routes/blocks.js.map +1 -0
  70. package/dist/apps/{coingecko.d.ts → data/routes/coingecko.d.ts} +183 -183
  71. package/dist/apps/data/routes/coingecko.d.ts.map +1 -0
  72. package/dist/apps/{coingecko.js → data/routes/coingecko.js} +13 -13
  73. package/dist/apps/data/routes/coingecko.js.map +1 -0
  74. package/dist/apps/{exchanges.d.ts → data/routes/exchanges.d.ts} +460 -460
  75. package/dist/apps/data/routes/exchanges.d.ts.map +1 -0
  76. package/dist/apps/{exchanges.js → data/routes/exchanges.js} +19 -19
  77. package/dist/apps/data/routes/exchanges.js.map +1 -0
  78. package/dist/apps/{fee-amm.d.ts → data/routes/fee-amm.d.ts} +94 -94
  79. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -0
  80. package/dist/apps/{fee-amm.js → data/routes/fee-amm.js} +17 -17
  81. package/dist/apps/data/routes/fee-amm.js.map +1 -0
  82. package/dist/apps/{indexer.d.ts → data/routes/indexer.d.ts} +4 -4
  83. package/dist/apps/data/routes/indexer.d.ts.map +1 -0
  84. package/dist/apps/{indexer.js → data/routes/indexer.js} +13 -9
  85. package/dist/apps/data/routes/indexer.js.map +1 -0
  86. package/dist/apps/{receipts.d.ts → data/routes/receipts.d.ts} +6 -6
  87. package/dist/apps/data/routes/receipts.d.ts.map +1 -0
  88. package/dist/apps/{receipts.js → data/routes/receipts.js} +12 -12
  89. package/dist/apps/data/routes/receipts.js.map +1 -0
  90. package/dist/apps/{rpc.d.ts → data/routes/rpc.d.ts} +4 -4
  91. package/dist/apps/data/routes/rpc.d.ts.map +1 -0
  92. package/dist/apps/{rpc.js → data/routes/rpc.js} +6 -6
  93. package/dist/apps/data/routes/rpc.js.map +1 -0
  94. package/dist/apps/{tokenlist.d.ts → data/routes/tokenlist.d.ts} +4 -4
  95. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -0
  96. package/dist/apps/{tokenlist.js → data/routes/tokenlist.js} +8 -8
  97. package/dist/apps/data/routes/tokenlist.js.map +1 -0
  98. package/dist/apps/{tokens.d.ts → data/routes/tokens.d.ts} +11 -11
  99. package/dist/apps/data/routes/tokens.d.ts.map +1 -0
  100. package/dist/apps/{tokens.js → data/routes/tokens.js} +19 -19
  101. package/dist/apps/data/routes/tokens.js.map +1 -0
  102. package/dist/apps/{transactions.d.ts → data/routes/transactions.d.ts} +288 -288
  103. package/dist/apps/data/routes/transactions.d.ts.map +1 -0
  104. package/dist/apps/{transactions.js → data/routes/transactions.js} +13 -13
  105. package/dist/apps/data/routes/transactions.js.map +1 -0
  106. package/dist/apps/{transfers.d.ts → data/routes/transfers.d.ts} +35 -35
  107. package/dist/apps/data/routes/transfers.d.ts.map +1 -0
  108. package/dist/apps/{transfers.js → data/routes/transfers.js} +13 -13
  109. package/dist/apps/data/routes/transfers.js.map +1 -0
  110. package/dist/apps/{verified-tokens.d.ts → data/routes/verified-tokens.d.ts} +42 -42
  111. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -0
  112. package/dist/apps/{verified-tokens.js → data/routes/verified-tokens.js} +9 -9
  113. package/dist/apps/data/routes/verified-tokens.js.map +1 -0
  114. package/dist/apps/{webhooks.d.ts → data/routes/webhooks.d.ts} +66 -63
  115. package/dist/apps/{webhooks.d.ts.map → data/routes/webhooks.d.ts.map} +1 -1
  116. package/dist/apps/{webhooks.js → data/routes/webhooks.js} +67 -59
  117. package/dist/apps/data/routes/webhooks.js.map +1 -0
  118. package/dist/apps/docs/App.d.ts +27 -0
  119. package/dist/apps/docs/App.d.ts.map +1 -0
  120. package/dist/apps/docs/App.js +122 -0
  121. package/dist/apps/docs/App.js.map +1 -0
  122. package/dist/{internal/OpenApi.fonts.d.ts → apps/docs/fonts.d.ts} +1 -1
  123. package/dist/apps/docs/fonts.d.ts.map +1 -0
  124. package/dist/{internal/OpenApi.fonts.js → apps/docs/fonts.js} +1 -1
  125. package/dist/apps/docs/fonts.js.map +1 -0
  126. package/dist/apps/docs/index.d.ts +2 -0
  127. package/dist/apps/docs/index.d.ts.map +1 -0
  128. package/dist/apps/docs/index.js +2 -0
  129. package/dist/apps/docs/index.js.map +1 -0
  130. package/dist/{internal/OpenApi.logo.d.ts → apps/docs/logo.d.ts} +1 -1
  131. package/dist/apps/docs/logo.d.ts.map +1 -0
  132. package/dist/{internal/OpenApi.logo.js → apps/docs/logo.js} +1 -1
  133. package/dist/apps/docs/logo.js.map +1 -0
  134. package/dist/apps/index.d.ts +4 -0
  135. package/dist/apps/index.d.ts.map +1 -0
  136. package/dist/apps/index.js +4 -0
  137. package/dist/apps/index.js.map +1 -0
  138. package/dist/apps/metadata.d.ts +7 -0
  139. package/dist/apps/metadata.d.ts.map +1 -0
  140. package/dist/apps/metadata.js +15 -0
  141. package/dist/apps/metadata.js.map +1 -0
  142. package/dist/apps/platform/App.d.ts +2985 -0
  143. package/dist/apps/platform/App.d.ts.map +1 -0
  144. package/dist/apps/platform/App.js +74 -0
  145. package/dist/apps/platform/App.js.map +1 -0
  146. package/dist/apps/platform/index.d.ts +2 -0
  147. package/dist/apps/platform/index.d.ts.map +1 -0
  148. package/dist/apps/platform/index.js +2 -0
  149. package/dist/apps/platform/index.js.map +1 -0
  150. package/dist/apps/platform/routes/api-keys.d.ts +681 -0
  151. package/dist/apps/platform/routes/api-keys.d.ts.map +1 -0
  152. package/dist/apps/platform/routes/api-keys.js +328 -0
  153. package/dist/apps/platform/routes/api-keys.js.map +1 -0
  154. package/dist/apps/platform/routes/invitations.d.ts +733 -0
  155. package/dist/apps/platform/routes/invitations.d.ts.map +1 -0
  156. package/dist/apps/platform/routes/invitations.js +413 -0
  157. package/dist/apps/platform/routes/invitations.js.map +1 -0
  158. package/dist/apps/platform/routes/me.d.ts +95 -0
  159. package/dist/apps/platform/routes/me.d.ts.map +1 -0
  160. package/dist/apps/platform/routes/me.js +81 -0
  161. package/dist/apps/platform/routes/me.js.map +1 -0
  162. package/dist/apps/platform/routes/members.d.ts +554 -0
  163. package/dist/apps/platform/routes/members.d.ts.map +1 -0
  164. package/dist/apps/platform/routes/members.js +251 -0
  165. package/dist/apps/platform/routes/members.js.map +1 -0
  166. package/dist/apps/platform/routes/orgs.d.ts +582 -0
  167. package/dist/apps/platform/routes/orgs.d.ts.map +1 -0
  168. package/dist/apps/platform/routes/orgs.js +265 -0
  169. package/dist/apps/platform/routes/orgs.js.map +1 -0
  170. package/dist/apps/platform/routes/projects.d.ts +740 -0
  171. package/dist/apps/platform/routes/projects.d.ts.map +1 -0
  172. package/dist/apps/platform/routes/projects.js +286 -0
  173. package/dist/apps/platform/routes/projects.js.map +1 -0
  174. package/dist/apps/relay/App.d.ts +41 -0
  175. package/dist/apps/relay/App.d.ts.map +1 -0
  176. package/dist/apps/relay/App.js +103 -0
  177. package/dist/apps/relay/App.js.map +1 -0
  178. package/dist/apps/relay/Sponsorships.d.ts +107 -0
  179. package/dist/apps/relay/Sponsorships.d.ts.map +1 -0
  180. package/dist/apps/relay/Sponsorships.js +193 -0
  181. package/dist/apps/relay/Sponsorships.js.map +1 -0
  182. package/dist/apps/relay/index.d.ts +3 -0
  183. package/dist/apps/relay/index.d.ts.map +1 -0
  184. package/dist/apps/relay/index.js +3 -0
  185. package/dist/apps/relay/index.js.map +1 -0
  186. package/dist/{Cli.d.ts → cli/Cli.d.ts} +13 -2
  187. package/dist/cli/Cli.d.ts.map +1 -0
  188. package/dist/cli/Cli.js +19 -0
  189. package/dist/cli/Cli.js.map +1 -0
  190. package/dist/cli/bin.d.ts +3 -0
  191. package/dist/cli/bin.d.ts.map +1 -0
  192. package/dist/cli/bin.js +4 -0
  193. package/dist/cli/bin.js.map +1 -0
  194. package/dist/cli/commands/admin.d.ts +15 -0
  195. package/dist/cli/commands/admin.d.ts.map +1 -0
  196. package/dist/cli/commands/admin.js +60 -0
  197. package/dist/cli/commands/admin.js.map +1 -0
  198. package/dist/cloudflare.d.ts +7 -0
  199. package/dist/cloudflare.d.ts.map +1 -1
  200. package/dist/cloudflare.js +9 -0
  201. package/dist/cloudflare.js.map +1 -1
  202. package/dist/db/Db.d.ts +113 -0
  203. package/dist/db/Db.d.ts.map +1 -0
  204. package/dist/db/Db.js +402 -0
  205. package/dist/db/Db.js.map +1 -0
  206. package/dist/db/Schema.d.ts +168 -0
  207. package/dist/db/Schema.d.ts.map +1 -0
  208. package/dist/db/Schema.js +229 -0
  209. package/dist/db/Schema.js.map +1 -0
  210. package/dist/db/tables/invitations.d.ts +84 -0
  211. package/dist/db/tables/invitations.d.ts.map +1 -0
  212. package/dist/db/tables/invitations.js +165 -0
  213. package/dist/db/tables/invitations.js.map +1 -0
  214. package/dist/db/tables/memberships.d.ts +108 -0
  215. package/dist/db/tables/memberships.d.ts.map +1 -0
  216. package/dist/db/tables/memberships.js +153 -0
  217. package/dist/db/tables/memberships.js.map +1 -0
  218. package/dist/db/tables/organizations.d.ts +123 -0
  219. package/dist/db/tables/organizations.d.ts.map +1 -0
  220. package/dist/db/tables/organizations.js +170 -0
  221. package/dist/db/tables/organizations.js.map +1 -0
  222. package/dist/db/tables/projects.d.ts +65 -0
  223. package/dist/db/tables/projects.d.ts.map +1 -0
  224. package/dist/db/tables/projects.js +75 -0
  225. package/dist/db/tables/projects.js.map +1 -0
  226. package/dist/db/tables/sponsoredTransactions.d.ts +120 -0
  227. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -0
  228. package/dist/db/tables/sponsoredTransactions.js +161 -0
  229. package/dist/db/tables/sponsoredTransactions.js.map +1 -0
  230. package/dist/db/tables/users.d.ts +48 -0
  231. package/dist/db/tables/users.d.ts.map +1 -0
  232. package/dist/db/tables/users.js +65 -0
  233. package/dist/db/tables/users.js.map +1 -0
  234. package/dist/db/tables/verifiedTokens.d.ts +53 -0
  235. package/dist/db/tables/verifiedTokens.d.ts.map +1 -0
  236. package/dist/db/tables/verifiedTokens.js +74 -0
  237. package/dist/db/tables/verifiedTokens.js.map +1 -0
  238. package/dist/db/tables/webhookDeliveries.d.ts +71 -0
  239. package/dist/db/tables/webhookDeliveries.d.ts.map +1 -0
  240. package/dist/db/tables/webhookDeliveries.js +119 -0
  241. package/dist/db/tables/webhookDeliveries.js.map +1 -0
  242. package/dist/db/tables/webhookSubscriptions.d.ts +158 -0
  243. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -0
  244. package/dist/db/tables/webhookSubscriptions.js +272 -0
  245. package/dist/db/tables/webhookSubscriptions.js.map +1 -0
  246. package/dist/handlers/internal/executionError.d.ts +25 -0
  247. package/dist/handlers/internal/executionError.d.ts.map +1 -0
  248. package/dist/handlers/internal/executionError.js +186 -0
  249. package/dist/handlers/internal/executionError.js.map +1 -0
  250. package/dist/handlers/internal/multisig.d.ts +233 -0
  251. package/dist/handlers/internal/multisig.d.ts.map +1 -0
  252. package/dist/handlers/internal/multisig.js +542 -0
  253. package/dist/handlers/internal/multisig.js.map +1 -0
  254. package/dist/handlers/internal/requestListener.d.ts +124 -0
  255. package/dist/handlers/internal/requestListener.d.ts.map +1 -0
  256. package/dist/handlers/internal/requestListener.js +173 -0
  257. package/dist/handlers/internal/requestListener.js.map +1 -0
  258. package/dist/handlers/internal/sponsorship.d.ts +113 -0
  259. package/dist/handlers/internal/sponsorship.d.ts.map +1 -0
  260. package/dist/handlers/internal/sponsorship.js +128 -0
  261. package/dist/handlers/internal/sponsorship.js.map +1 -0
  262. package/dist/handlers/internal/types.d.ts +284 -0
  263. package/dist/handlers/internal/types.d.ts.map +1 -0
  264. package/dist/handlers/internal/types.js +2 -0
  265. package/dist/handlers/internal/types.js.map +1 -0
  266. package/dist/handlers/internal/utils.d.ts +34 -0
  267. package/dist/handlers/internal/utils.d.ts.map +1 -0
  268. package/dist/handlers/internal/utils.js +131 -0
  269. package/dist/handlers/internal/utils.js.map +1 -0
  270. package/dist/handlers/relay.d.ts +123 -0
  271. package/dist/handlers/relay.d.ts.map +1 -0
  272. package/dist/handlers/relay.js +1278 -0
  273. package/dist/handlers/relay.js.map +1 -0
  274. package/dist/index.d.ts +4 -2
  275. package/dist/index.d.ts.map +1 -1
  276. package/dist/index.js +4 -2
  277. package/dist/index.js.map +1 -1
  278. package/dist/internal/Auth.d.ts +224 -16
  279. package/dist/internal/Auth.d.ts.map +1 -1
  280. package/dist/internal/Auth.js +572 -33
  281. package/dist/internal/Auth.js.map +1 -1
  282. package/dist/internal/Log.d.ts +7 -3
  283. package/dist/internal/Log.d.ts.map +1 -1
  284. package/dist/internal/Log.js +4 -0
  285. package/dist/internal/Log.js.map +1 -1
  286. package/dist/internal/OpenApi.d.ts +0 -19
  287. package/dist/internal/OpenApi.d.ts.map +1 -1
  288. package/dist/internal/OpenApi.js +0 -57
  289. package/dist/internal/OpenApi.js.map +1 -1
  290. package/dist/internal/RpcSchema.d.ts +10 -0
  291. package/dist/internal/RpcSchema.d.ts.map +1 -0
  292. package/dist/internal/RpcSchema.js +2 -0
  293. package/dist/internal/RpcSchema.js.map +1 -0
  294. package/dist/internal/Store.d.ts +49 -4
  295. package/dist/internal/Store.d.ts.map +1 -1
  296. package/dist/internal/Store.js +81 -5
  297. package/dist/internal/Store.js.map +1 -1
  298. package/dist/internal/VerifiedTokens.d.ts +15 -34
  299. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  300. package/dist/internal/VerifiedTokens.js +115 -159
  301. package/dist/internal/VerifiedTokens.js.map +1 -1
  302. package/dist/internal/Viem.d.ts +84 -0
  303. package/dist/internal/Viem.d.ts.map +1 -1
  304. package/dist/internal/Webhooks.d.ts +50 -36
  305. package/dist/internal/Webhooks.d.ts.map +1 -1
  306. package/dist/internal/Webhooks.js +92 -205
  307. package/dist/internal/Webhooks.js.map +1 -1
  308. package/package.json +37 -6
  309. package/src/ApiKey.test.ts +3 -3
  310. package/src/ApiKey.ts +11 -12
  311. package/src/ApiKeys.test.ts +278 -0
  312. package/src/ApiKeys.ts +358 -0
  313. package/src/App.test-d.ts +1 -1
  314. package/src/App.test.ts +40508 -19083
  315. package/src/App.ts +239 -416
  316. package/src/Client.test-d.ts +307 -16
  317. package/src/Handler.ts +154 -0
  318. package/src/Scope.ts +17 -4
  319. package/src/Webhooks.test.ts +8 -7
  320. package/src/Webhooks.ts +13 -7
  321. package/src/admin/Access.ts +1 -3
  322. package/src/admin/App.ts +19 -24
  323. package/src/admin/apps/api-keys.test.ts +70 -18
  324. package/src/admin/apps/api-keys.ts +92 -9
  325. package/src/admin/apps/scopes.test.ts +8 -0
  326. package/src/admin/apps/verified-tokens.test.ts +3 -30
  327. package/src/admin/apps/verified-tokens.ts +18 -37
  328. package/src/admin/ui.generated.ts +1 -1
  329. package/src/apps/composition.test.ts +66 -0
  330. package/src/apps/data/App.ts +295 -0
  331. package/src/apps/data/index.ts +2 -0
  332. package/src/apps/{activities.test.ts → data/routes/activities.test.ts} +3 -3
  333. package/src/apps/{activities.ts → data/routes/activities.ts} +15 -15
  334. package/src/apps/{addresses.ts → data/routes/addresses.ts} +6 -6
  335. package/src/apps/{balances.test.ts → data/routes/balances.test.ts} +6 -5
  336. package/src/apps/{balances.ts → data/routes/balances.ts} +46 -12
  337. package/src/apps/{blocks.test.ts → data/routes/blocks.test.ts} +4 -4
  338. package/src/apps/{blocks.ts → data/routes/blocks.ts} +14 -14
  339. package/src/apps/{coingecko.test.ts → data/routes/coingecko.test.ts} +2 -2
  340. package/src/apps/{coingecko.ts → data/routes/coingecko.ts} +14 -14
  341. package/src/apps/{exchanges.test.ts → data/routes/exchanges.test.ts} +2 -2
  342. package/src/apps/{exchanges.ts → data/routes/exchanges.ts} +20 -20
  343. package/src/apps/{fee-amm.test.ts → data/routes/fee-amm.test.ts} +3 -3
  344. package/src/apps/{fee-amm.ts → data/routes/fee-amm.ts} +18 -18
  345. package/src/apps/{indexer.test.ts → data/routes/indexer.test.ts} +27 -6
  346. package/src/apps/{indexer.ts → data/routes/indexer.ts} +13 -10
  347. package/src/apps/{receipts.test.ts → data/routes/receipts.test.ts} +4 -4
  348. package/src/apps/{receipts.ts → data/routes/receipts.ts} +13 -13
  349. package/src/apps/{rpc.test.ts → data/routes/rpc.test.ts} +142 -13
  350. package/src/apps/{rpc.ts → data/routes/rpc.ts} +7 -7
  351. package/src/apps/{tokenlist.test.ts → data/routes/tokenlist.test.ts} +8 -10
  352. package/src/apps/{tokenlist.ts → data/routes/tokenlist.ts} +9 -9
  353. package/src/apps/{tokens.test.ts → data/routes/tokens.test.ts} +6 -5
  354. package/src/apps/{tokens.ts → data/routes/tokens.ts} +20 -20
  355. package/src/apps/{transactions.test.ts → data/routes/transactions.test.ts} +4 -4
  356. package/src/apps/{transactions.ts → data/routes/transactions.ts} +15 -15
  357. package/src/apps/{transfers.test.ts → data/routes/transfers.test.ts} +3 -3
  358. package/src/apps/{transfers.ts → data/routes/transfers.ts} +15 -15
  359. package/src/apps/{verified-tokens.test.ts → data/routes/verified-tokens.test.ts} +27 -15
  360. package/src/apps/{verified-tokens.ts → data/routes/verified-tokens.ts} +10 -10
  361. package/src/apps/{webhooks.test.ts → data/routes/webhooks.test.ts} +137 -150
  362. package/src/apps/{webhooks.ts → data/routes/webhooks.ts} +83 -81
  363. package/src/apps/docs/App.ts +136 -0
  364. package/src/apps/docs/index.ts +1 -0
  365. package/src/apps/index.ts +3 -0
  366. package/src/apps/metadata.ts +23 -0
  367. package/src/apps/platform/App.ts +130 -0
  368. package/src/apps/platform/index.ts +1 -0
  369. package/src/apps/platform/routes/api-keys.test.ts +330 -0
  370. package/src/apps/platform/routes/api-keys.ts +427 -0
  371. package/src/apps/platform/routes/invitations.test.ts +361 -0
  372. package/src/apps/platform/routes/invitations.ts +519 -0
  373. package/src/apps/platform/routes/me.test.ts +121 -0
  374. package/src/apps/platform/routes/me.ts +106 -0
  375. package/src/apps/platform/routes/members.test.ts +195 -0
  376. package/src/apps/platform/routes/members.ts +313 -0
  377. package/src/apps/platform/routes/orgs.test.ts +313 -0
  378. package/src/apps/platform/routes/orgs.ts +343 -0
  379. package/src/apps/platform/routes/projects.test.ts +181 -0
  380. package/src/apps/platform/routes/projects.ts +367 -0
  381. package/src/apps/relay/App.test.ts +484 -0
  382. package/src/apps/relay/App.ts +128 -0
  383. package/src/apps/relay/Sponsorships.test.ts +375 -0
  384. package/src/apps/relay/Sponsorships.ts +305 -0
  385. package/src/apps/relay/index.ts +2 -0
  386. package/src/{Cli.test.ts → cli/Cli.test.ts} +10 -9
  387. package/src/{Cli.ts → cli/Cli.ts} +16 -9
  388. package/src/cli/bin.ts +4 -0
  389. package/src/cli/commands/admin.test.ts +71 -0
  390. package/src/cli/commands/admin.ts +60 -0
  391. package/src/cloudflare.ts +10 -0
  392. package/src/db/Db.test.ts +84 -0
  393. package/src/db/Db.ts +542 -0
  394. package/src/db/Schema.ts +301 -0
  395. package/src/db/tables/invitations.ts +198 -0
  396. package/src/db/tables/memberships.ts +208 -0
  397. package/src/db/tables/organizations.test.ts +160 -0
  398. package/src/db/tables/organizations.ts +232 -0
  399. package/src/db/tables/projects.ts +107 -0
  400. package/src/db/tables/sponsoredTransactions.test.ts +218 -0
  401. package/src/db/tables/sponsoredTransactions.ts +236 -0
  402. package/src/db/tables/users.ts +85 -0
  403. package/src/db/tables/verifiedTokens.ts +111 -0
  404. package/src/db/tables/webhookDeliveries.ts +159 -0
  405. package/src/db/tables/webhookSubscriptions.ts +358 -0
  406. package/src/handlers/internal/executionError.ts +207 -0
  407. package/src/handlers/internal/multisig.test.ts +818 -0
  408. package/src/handlers/internal/multisig.ts +823 -0
  409. package/src/handlers/internal/requestListener.ts +273 -0
  410. package/src/handlers/internal/sponsorship.ts +245 -0
  411. package/src/handlers/internal/types.ts +378 -0
  412. package/src/handlers/internal/utils.ts +153 -0
  413. package/src/handlers/relay.test.ts +2035 -0
  414. package/src/handlers/relay.ts +1623 -0
  415. package/src/index.ts +4 -2
  416. package/src/internal/Auth.test.ts +337 -21
  417. package/src/internal/Auth.ts +783 -44
  418. package/src/internal/Cursor.test.ts +3 -2
  419. package/src/internal/Log.test.ts +1 -1
  420. package/src/internal/Log.ts +11 -3
  421. package/src/internal/MetricSink.ts +1 -1
  422. package/src/internal/OpenApi.ts +0 -59
  423. package/src/internal/RateLimit.test.ts +1 -1
  424. package/src/internal/RpcSchema.ts +10 -0
  425. package/src/internal/Store.test.ts +150 -10
  426. package/src/internal/Store.ts +136 -11
  427. package/src/internal/Tidx.local.test.ts +1 -1
  428. package/src/internal/VerifiedTokens.test.ts +99 -115
  429. package/src/internal/VerifiedTokens.ts +123 -175
  430. package/src/internal/WebhookDestination.test.ts +1 -1
  431. package/src/internal/Webhooks.test.ts +111 -111
  432. package/src/internal/Webhooks.ts +103 -221
  433. package/dist/ApiKeySource.d.ts +0 -166
  434. package/dist/ApiKeySource.d.ts.map +0 -1
  435. package/dist/ApiKeySource.js +0 -234
  436. package/dist/ApiKeySource.js.map +0 -1
  437. package/dist/Cli.d.ts.map +0 -1
  438. package/dist/Cli.js +0 -13
  439. package/dist/Cli.js.map +0 -1
  440. package/dist/apps/activities.js.map +0 -1
  441. package/dist/apps/addresses.js.map +0 -1
  442. package/dist/apps/balances.d.ts.map +0 -1
  443. package/dist/apps/balances.js.map +0 -1
  444. package/dist/apps/blocks.d.ts.map +0 -1
  445. package/dist/apps/blocks.js.map +0 -1
  446. package/dist/apps/coingecko.d.ts.map +0 -1
  447. package/dist/apps/coingecko.js.map +0 -1
  448. package/dist/apps/exchanges.d.ts.map +0 -1
  449. package/dist/apps/exchanges.js.map +0 -1
  450. package/dist/apps/fee-amm.d.ts.map +0 -1
  451. package/dist/apps/fee-amm.js.map +0 -1
  452. package/dist/apps/indexer.d.ts.map +0 -1
  453. package/dist/apps/indexer.js.map +0 -1
  454. package/dist/apps/receipts.d.ts.map +0 -1
  455. package/dist/apps/receipts.js.map +0 -1
  456. package/dist/apps/rpc.d.ts.map +0 -1
  457. package/dist/apps/rpc.js.map +0 -1
  458. package/dist/apps/tokenlist.d.ts.map +0 -1
  459. package/dist/apps/tokenlist.js.map +0 -1
  460. package/dist/apps/tokens.d.ts.map +0 -1
  461. package/dist/apps/tokens.js.map +0 -1
  462. package/dist/apps/transactions.d.ts.map +0 -1
  463. package/dist/apps/transactions.js.map +0 -1
  464. package/dist/apps/transfers.d.ts.map +0 -1
  465. package/dist/apps/transfers.js.map +0 -1
  466. package/dist/apps/verified-tokens.d.ts.map +0 -1
  467. package/dist/apps/verified-tokens.js.map +0 -1
  468. package/dist/apps/webhooks.js.map +0 -1
  469. package/dist/internal/OpenApi.fonts.d.ts.map +0 -1
  470. package/dist/internal/OpenApi.fonts.js.map +0 -1
  471. package/dist/internal/OpenApi.logo.d.ts.map +0 -1
  472. package/dist/internal/OpenApi.logo.js.map +0 -1
  473. package/seeds/31318/icons/0x20c0000000000000000000000000000000000000.svg +0 -1
  474. package/seeds/31318/icons/0x20c0000000000000000000000000000000000001.svg +0 -1
  475. package/seeds/31318/icons/0x20c0000000000000000000000000000000000002.svg +0 -1
  476. package/seeds/31318/icons/0x20c0000000000000000000000000000000000003.svg +0 -1
  477. package/seeds/31318/verified-tokens.json +0 -30
  478. package/seeds/4217/icons/0x20c0000000000000000000000000000000000000.svg +0 -25
  479. package/seeds/4217/icons/0x20c000000000000000000000048c8f36df1c9a4a.svg +0 -1
  480. package/seeds/4217/icons/0x20c0000000000000000000000520792dcccccccc.svg +0 -1
  481. package/seeds/4217/icons/0x20c0000000000000000000000a6da882d075a4c3.svg +0 -4
  482. package/seeds/4217/icons/0x20c000000000000000000000111111111e910f0f.svg +0 -30
  483. package/seeds/4217/icons/0x20c00000000000000000000014f22ca97301eb73.svg +0 -1
  484. package/seeds/4217/icons/0x20c0000000000000000000001621e21f71cf12fb.svg +0 -1
  485. package/seeds/4217/icons/0x20c0000000000000000000002f52d5cc21a3207b.svg +0 -1
  486. package/seeds/4217/icons/0x20c0000000000000000000003158081efd85bfc2.svg +0 -11
  487. package/seeds/4217/icons/0x20c0000000000000000000003554d28269e0f3c2.svg +0 -1
  488. package/seeds/4217/icons/0x20c000000000000000000000383a23bacb546ab9.svg +0 -1
  489. package/seeds/4217/icons/0x20c00000000000000000000042109aef2f8b28e1.png +0 -0
  490. package/seeds/4217/icons/0x20c0000000000000000000005c0bac7cef389a11.svg +0 -1
  491. package/seeds/4217/icons/0x20c0000000000000000000006fd9a167923ba194.png +0 -0
  492. package/seeds/4217/icons/0x20c0000000000000000000007f7ba549dd0251b9.svg +0 -1
  493. package/seeds/4217/icons/0x20c0000000000000000000008191667423f70e67.svg +0 -5
  494. package/seeds/4217/icons/0x20c0000000000000000000008ee4fcff88888888.svg +0 -1
  495. package/seeds/4217/icons/0x20c0000000000000000000009a4a4b17e0dc6651.svg +0 -1
  496. package/seeds/4217/icons/0x20c000000000000000000000ab02d39df30bd17e.svg +0 -1
  497. package/seeds/4217/icons/0x20c000000000000000000000ae247a1130450f09.svg +0 -1
  498. package/seeds/4217/icons/0x20c000000000000000000000aeed2ec36a54d0e5.svg +0 -1
  499. package/seeds/4217/icons/0x20c000000000000000000000b9537d11c60e8b50.svg +0 -1
  500. package/seeds/4217/icons/0x20c000000000000000000000bd95bfb69fbe6ce3.svg +0 -1
  501. package/seeds/4217/icons/0x20c000000000000000000000c412ec89d0c08be5.svg +0 -1
  502. package/seeds/4217/icons/0x20c000000000000000000000f047dd7018e50367.png +0 -0
  503. package/seeds/4217/verified-tokens.json +0 -177
  504. package/seeds/42431/icons/0x20c0000000000000000000000000000000000000.svg +0 -25
  505. package/seeds/42431/icons/0x20c0000000000000000000000000000000000001.svg +0 -1
  506. package/seeds/42431/icons/0x20c0000000000000000000000000000000000002.svg +0 -1
  507. package/seeds/42431/icons/0x20c0000000000000000000000000000000000003.svg +0 -1
  508. package/seeds/42431/icons/0x20c0000000000000000000009e8d7eb59b783726.svg +0 -1
  509. package/seeds/42431/icons/0x20c000000000000000000000d72572838bbee59c.svg +0 -1
  510. package/seeds/42431/verified-tokens.json +0 -44
  511. package/seeds/openrpc/README.md +0 -27
  512. package/seeds/openrpc/execution-apis.json +0 -8989
  513. package/src/ApiKeySource.test-d.ts +0 -11
  514. package/src/ApiKeySource.test.ts +0 -295
  515. package/src/ApiKeySource.ts +0 -303
  516. /package/src/{internal/OpenApi.fonts.ts → apps/docs/fonts.ts} +0 -0
  517. /package/src/{internal/OpenApi.logo.ts → apps/docs/logo.ts} +0 -0
@@ -0,0 +1,130 @@
1
+ import { Hono } from 'hono'
2
+
3
+ import type * as App from '../../App.js'
4
+ import * as Metadata from '../metadata.js'
5
+
6
+ import { apiKeys } from './routes/api-keys.js'
7
+ import { invitations } from './routes/invitations.js'
8
+ import { me } from './routes/me.js'
9
+ import { members } from './routes/members.js'
10
+ import { orgs } from './routes/orgs.js'
11
+ import { projects } from './routes/projects.js'
12
+
13
+ /**
14
+ * Minimal transactional email sender. Cloudflare deployments wrap the Email
15
+ * Service binding (`{ from, send: (m) => env.EMAIL.send(m) }`); other hosts
16
+ * pass any compatible sender. Dispatch is always best-effort.
17
+ */
18
+ export type Email = {
19
+ /** Console URL embedded in email links (e.g. sign-in URLs). Defaults to the hosted console; self-hosts point it at their own. */
20
+ consoleUrl?: string | undefined
21
+ /** Sender address for platform emails (e.g. `noreply@tempo.xyz`). */
22
+ from: string
23
+ /** Sends one message. */
24
+ send: (message: Email.Message) => Promise<unknown>
25
+ }
26
+
27
+ export declare namespace Email {
28
+ /** One transactional message. */
29
+ type Message = {
30
+ /** Sender address. */
31
+ from: string
32
+ /** HTML body. */
33
+ html?: string | undefined
34
+ /** Subject line. */
35
+ subject: string
36
+ /** Plain-text body. */
37
+ text: string
38
+ /** Recipient address. */
39
+ to: string
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Request environment for platform routes: the shared app environment plus the
45
+ * `email` sender this group publishes on context. Owned here, not in core
46
+ * `App.Environment`, since email is a platform concern.
47
+ */
48
+ export type Environment = {
49
+ Variables: App.Environment['Variables'] & {
50
+ /** Transactional email sender for platform emails; undefined when dispatch is disabled. */
51
+ email: Email | undefined
52
+ }
53
+ }
54
+
55
+ /**
56
+ * The tenant-platform route group: the current user, orgs, projects, members,
57
+ * invitations, and API-key management. Every route reads its dependencies from
58
+ * request context set by {@link App.create}.
59
+ *
60
+ * The session-auth surface (`/v1/auth/siwe` + `session` capability) is owned by
61
+ * {@link App.create}, so platform routes gate on a session without owning it.
62
+ *
63
+ * ```ts
64
+ * App.create(options).route('/', platform())
65
+ * ```
66
+ */
67
+ export function platform(options: platform.Options = {}) {
68
+ const app = new Hono<Environment>()
69
+ // Publish the transactional email sender for this group's handlers
70
+ // (invitations read it off context); undefined disables dispatch.
71
+ .use('*', async (c, next) => {
72
+ c.set('email', options.email)
73
+ await next()
74
+ })
75
+ .route('/', apiKeys({ enabled: options.apiKeys !== false }))
76
+ .route('/', invitations())
77
+ .route('/', me())
78
+ .route('/', members())
79
+ .route('/', orgs())
80
+ .route('/', projects())
81
+ return Metadata.attach(app, openapi)
82
+ }
83
+
84
+ export declare namespace platform {
85
+ /** Options for the platform route group. */
86
+ type Options = {
87
+ /** Expose the API-key management routes in the OpenAPI document. @default true */
88
+ apiKeys?: boolean | undefined
89
+ /** Transactional email sender for platform emails (e.g. invitations); omit to disable dispatch — notified flows still work in-product. */
90
+ email?: Email | undefined
91
+ }
92
+ }
93
+
94
+ /**
95
+ * The OpenAPI metadata this group owns: platform operation tags and the
96
+ * `session` security scheme. Tagged onto the {@link platform} instance so
97
+ * `App.create` collects it.
98
+ */
99
+ const openapi = {
100
+ securitySchemes: {
101
+ session: {
102
+ description: 'Cookie session established by sign-in (`POST /v1/auth/siwe`). Clients may also send the session token as `Authorization: Bearer <token>`.', // prettier-ignore
103
+ in: 'cookie',
104
+ name: 'accounts_auth',
105
+ type: 'apiKey',
106
+ },
107
+ },
108
+ tags: [
109
+ { name: 'API Keys', description: 'Credentials for accessing the Tempo API.' },
110
+ { name: 'Invitations', description: 'Pending organization invitations.' },
111
+ { name: 'Members', description: 'Organization team membership.' },
112
+ { name: 'Organizations', description: 'Teams that own application workspaces and members.' },
113
+ { name: 'Projects', description: 'Application workspaces within an organization.' },
114
+ { name: 'Users', description: 'Users on the Tempo Platform.' },
115
+ ],
116
+ 'x-tagGroups': [
117
+ {
118
+ name: 'Platform API',
119
+ tags: [
120
+ 'API Keys',
121
+ 'Authentication',
122
+ 'Invitations',
123
+ 'Members',
124
+ 'Organizations',
125
+ 'Projects',
126
+ 'Users',
127
+ ],
128
+ },
129
+ ],
130
+ } satisfies App.create.Metadata
@@ -0,0 +1 @@
1
+ export { platform } from './App.js'
@@ -0,0 +1,330 @@
1
+ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
2
+
3
+ import * as TestApp from '../../../../test/App.js'
4
+ import * as Keys from './api-keys.js'
5
+ import * as Orgs from './orgs.js'
6
+ import * as Projects from './projects.js'
7
+
8
+ /** Origin pinned for SIWE domain binding; Hono test requests use this host. */
9
+ const origin = 'http://localhost'
10
+
11
+ /** Super admin secret configured on the test app. */
12
+ const secret = 'tempo:sk:c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2'
13
+
14
+ /** RequestInit for a JSON mutation carrying the session cookie. */
15
+ function json(method: 'PATCH' | 'POST', cookie: string, body: unknown) {
16
+ return {
17
+ body: JSON.stringify(body),
18
+ headers: { 'content-type': 'application/json', cookie },
19
+ method,
20
+ }
21
+ }
22
+
23
+ /** RequestInit for a JSON mutation authenticated as the super admin. */
24
+ function superAdminJson(method: 'PATCH' | 'POST', body: unknown) {
25
+ return {
26
+ body: JSON.stringify(body),
27
+ headers: { 'content-type': 'application/json', 'tempo-api-key': secret },
28
+ method,
29
+ }
30
+ }
31
+
32
+ // Resolve-cache disabled so revocation assertions observe the store directly.
33
+ type State = ReturnType<typeof TestApp.kvStore>
34
+
35
+ function createApp(options: { kv?: { store: State } } = {}) {
36
+ return TestApp.create({
37
+ auth: { cache: false, superAdmin: { secret } },
38
+ ...(options.kv ? { kv: options.kv } : {}),
39
+ session: { wallet: { origin } },
40
+ })
41
+ }
42
+
43
+ function failRecordDeletes(store: State) {
44
+ const delete_ = store.delete.bind(store)
45
+ store.delete = async (key) => {
46
+ if (key.startsWith('apikey:')) throw new Error('KV delete failed.')
47
+ await delete_(key)
48
+ }
49
+ }
50
+
51
+ /** Signs in a fresh scripted account; returns its session cookie. */
52
+ async function session(app: TestApp.signIn.App) {
53
+ const account = privateKeyToAccount(generatePrivateKey())
54
+ const { cookie } = await TestApp.signIn(app, account)
55
+ return cookie!
56
+ }
57
+
58
+ /** Creates an org and a project owned by the session. */
59
+ async function fixture(app: ReturnType<typeof createApp>, cookie: string) {
60
+ const org = await TestApp.json(
61
+ await app.request('/v1/orgs', json('POST', cookie, { name: 'Acme' })),
62
+ Orgs.schema.Organization,
63
+ )
64
+ const project = await TestApp.json(
65
+ await app.request(`/v1/orgs/${org.id}/projects`, json('POST', cookie, { name: 'Checkout' })),
66
+ Projects.schema.Project,
67
+ )
68
+ return { org, project }
69
+ }
70
+
71
+ describe('keys', () => {
72
+ test('mints, lists, authenticates, and revokes a project key', async () => {
73
+ const app = createApp()
74
+ const cookie = await session(app)
75
+ const { org, project } = await fixture(app, cookie)
76
+ const base = `/v1/orgs/${org.id}/projects/${project.id}/api-keys`
77
+
78
+ // Scoped keys mint through the super admin: no scope is self-issuable.
79
+ const minted = await app.request(
80
+ base,
81
+ superAdminJson('POST', { environment: 'sandbox', name: 'CI', scopes: ['data:read'] }),
82
+ )
83
+ expect(minted.status).toBe(200)
84
+ const created = await TestApp.json(minted, Keys.schema.createApiKey.Response)
85
+ expect(created.id).toMatch(/^key_/)
86
+ expect(created.token).toMatch(/^tempo_sandbox:sk:[a-f0-9]{48}$/)
87
+ expect(created.orgId).toBe(org.id)
88
+ expect(created.projectId).toBe(project.id)
89
+ expect(created.createdBy).toBe('super_admin')
90
+
91
+ // The minted key authenticates data API requests. `no-store` forces an
92
+ // origin pass — an edge-cache hit would skip auth and mask the assertion.
93
+ const data = await app.request('/v1/tokens', {
94
+ headers: { 'cache-control': 'no-store', 'tempo-api-key': created.token },
95
+ })
96
+ expect(data.status).toBe(200)
97
+
98
+ // Listing exposes metadata only — never the token.
99
+ const listed = await app.request(base, { headers: { cookie } })
100
+ expect(listed.status).toBe(200)
101
+ const list = await TestApp.json(listed, Keys.schema.listApiKeys.Response)
102
+ expect(list.data.map(({ id }) => id)).toEqual([created.id])
103
+ expect(JSON.stringify(list)).not.toContain(created.token)
104
+ expect(list.data[0]!.tokenLast4).toBe(created.token.slice(-4))
105
+
106
+ const revoked = await app.request(`${base}/${created.id}`, {
107
+ headers: { cookie },
108
+ method: 'DELETE',
109
+ })
110
+ expect(revoked.status).toBe(200)
111
+ expect(await TestApp.json(revoked, Keys.schema.revokeApiKey.Response)).toEqual({
112
+ id: created.id,
113
+ })
114
+
115
+ // With the resolve cache disabled, revocation is immediate.
116
+ const after = await app.request('/v1/tokens', {
117
+ headers: { 'cache-control': 'no-store', 'tempo-api-key': created.token },
118
+ })
119
+ expect(after.status).toBe(401)
120
+ const empty = await TestApp.json(
121
+ await app.request(base, { headers: { cookie } }),
122
+ Keys.schema.listApiKeys.Response,
123
+ )
124
+ expect(empty).toEqual({ data: [] })
125
+ })
126
+
127
+ test('rejects the wildcard scope at mint', async () => {
128
+ const app = createApp()
129
+ const cookie = await session(app)
130
+ const { org, project } = await fixture(app, cookie)
131
+
132
+ const response = await app.request(
133
+ `/v1/orgs/${org.id}/projects/${project.id}/api-keys`,
134
+ json('POST', cookie, { scopes: ['*'] }),
135
+ )
136
+ expect(response.status).toBe(400)
137
+ })
138
+
139
+ test('rejects session mints while no scope is self-issuable', async () => {
140
+ const app = createApp()
141
+ const cookie = await session(app)
142
+ const { org, project } = await fixture(app, cookie)
143
+
144
+ const response = await app.request(
145
+ `/v1/orgs/${org.id}/projects/${project.id}/api-keys`,
146
+ json('POST', cookie, { scopes: ['data:read'] }),
147
+ )
148
+ expect(response.status).toBe(403)
149
+ const { requestId, ...body } = (await response.json()) as { requestId?: string }
150
+ expect(requestId).toBeDefined()
151
+ expect(body).toMatchInlineSnapshot(`
152
+ {
153
+ "error": {
154
+ "code": "scope_not_issuable",
155
+ "message": "The requested scopes are not issuable.",
156
+ },
157
+ }
158
+ `)
159
+ })
160
+
161
+ test('binds keys to their project on every verb', async () => {
162
+ const app = createApp()
163
+ const owner = await session(app)
164
+ const { org, project } = await fixture(app, owner)
165
+ const other = await TestApp.json(
166
+ await app.request(`/v1/orgs/${org.id}/projects`, json('POST', owner, { name: 'Payments' })),
167
+ Projects.schema.Project,
168
+ )
169
+ const minted = await TestApp.json(
170
+ await app.request(
171
+ `/v1/orgs/${org.id}/projects/${project.id}/api-keys`,
172
+ superAdminJson('POST', { scopes: ['data:read'] }),
173
+ ),
174
+ Keys.schema.createApiKey.Response,
175
+ )
176
+
177
+ // Same org, sibling project: the key id must not resolve through it.
178
+ const crossList = await app.request(`/v1/orgs/${org.id}/projects/${other.id}/api-keys`, {
179
+ headers: { cookie: owner },
180
+ })
181
+ expect((await TestApp.json(crossList, Keys.schema.listApiKeys.Response)).data).toEqual([])
182
+ const crossRevoke = await app.request(
183
+ `/v1/orgs/${org.id}/projects/${other.id}/api-keys/${minted.id}`,
184
+ { headers: { cookie: owner }, method: 'DELETE' },
185
+ )
186
+ expect(crossRevoke.status).toBe(404)
187
+
188
+ // Foreign session: the whole surface 404s at the org-ownership link.
189
+ const stranger = await session(app)
190
+ const foreignMint = await app.request(
191
+ `/v1/orgs/${org.id}/projects/${project.id}/api-keys`,
192
+ json('POST', stranger, { scopes: ['data:read'] }),
193
+ )
194
+ expect(foreignMint.status).toBe(404)
195
+ const foreignRevoke = await app.request(
196
+ `/v1/orgs/${org.id}/projects/${project.id}/api-keys/${minted.id}`,
197
+ { headers: { cookie: stranger }, method: 'DELETE' },
198
+ )
199
+ expect(foreignRevoke.status).toBe(404)
200
+
201
+ // The key survives every attempt, still listed for the owner.
202
+ const listed = await app.request(`/v1/orgs/${org.id}/projects/${project.id}/api-keys`, {
203
+ headers: { cookie: owner },
204
+ })
205
+ const list = await TestApp.json(listed, Keys.schema.listApiKeys.Response)
206
+ expect(list.data.map(({ id }) => id)).toEqual([minted.id])
207
+ })
208
+
209
+ test('revokes keys when their project or organization is deleted', async () => {
210
+ const app = createApp()
211
+ const cookie = await session(app)
212
+ const { org, project } = await fixture(app, cookie)
213
+ const minted = await TestApp.json(
214
+ await app.request(
215
+ `/v1/orgs/${org.id}/projects/${project.id}/api-keys`,
216
+ superAdminJson('POST', { scopes: ['data:read'] }),
217
+ ),
218
+ Keys.schema.createApiKey.Response,
219
+ )
220
+
221
+ const deletedProject = await app.request(`/v1/orgs/${org.id}/projects/${project.id}`, {
222
+ headers: { cookie },
223
+ method: 'DELETE',
224
+ })
225
+ expect(deletedProject.status).toBe(200)
226
+ const afterProject = await app.request('/v1/tokens', {
227
+ headers: { 'cache-control': 'no-store', 'tempo-api-key': minted.token },
228
+ })
229
+ expect(afterProject.status).toBe(401)
230
+
231
+ // Org deletion revokes keys of every remaining project.
232
+ const other = await TestApp.json(
233
+ await app.request(`/v1/orgs/${org.id}/projects`, json('POST', cookie, { name: 'Payments' })),
234
+ Projects.schema.Project,
235
+ )
236
+ const survivor = await TestApp.json(
237
+ await app.request(
238
+ `/v1/orgs/${org.id}/projects/${other.id}/api-keys`,
239
+ superAdminJson('POST', { scopes: ['data:read'] }),
240
+ ),
241
+ Keys.schema.createApiKey.Response,
242
+ )
243
+ const deletedOrg = await app.request(`/v1/orgs/${org.id}`, {
244
+ headers: { cookie },
245
+ method: 'DELETE',
246
+ })
247
+ expect(deletedOrg.status).toBe(200)
248
+ const afterOrg = await app.request('/v1/tokens', {
249
+ headers: { 'cache-control': 'no-store', 'tempo-api-key': survivor.token },
250
+ })
251
+ expect(afterOrg.status).toBe(401)
252
+ })
253
+
254
+ test('keeps the project when key revocation fails during project deletion', async () => {
255
+ const store = TestApp.kvStore({ keys: [] })
256
+ const app = createApp({ kv: { store } })
257
+ const cookie = await session(app)
258
+ const { org, project } = await fixture(app, cookie)
259
+ await TestApp.json(
260
+ await app.request(
261
+ `/v1/orgs/${org.id}/projects/${project.id}/api-keys`,
262
+ superAdminJson('POST', { scopes: ['data:read'] }),
263
+ ),
264
+ Keys.schema.createApiKey.Response,
265
+ )
266
+ failRecordDeletes(store)
267
+
268
+ const deletedProject = await app.request(`/v1/orgs/${org.id}/projects/${project.id}`, {
269
+ headers: { cookie },
270
+ method: 'DELETE',
271
+ })
272
+ expect(deletedProject.status).toBe(502)
273
+
274
+ const projectStill = await app.request(`/v1/orgs/${org.id}/projects/${project.id}`, {
275
+ headers: { cookie },
276
+ })
277
+ expect(projectStill.status).toBe(200)
278
+ })
279
+
280
+ test('keeps the organization when key revocation fails during organization deletion', async () => {
281
+ const store = TestApp.kvStore({ keys: [] })
282
+ const app = createApp({ kv: { store } })
283
+ const cookie = await session(app)
284
+ const { org, project } = await fixture(app, cookie)
285
+ await TestApp.json(
286
+ await app.request(
287
+ `/v1/orgs/${org.id}/projects/${project.id}/api-keys`,
288
+ superAdminJson('POST', { scopes: ['data:read'] }),
289
+ ),
290
+ Keys.schema.createApiKey.Response,
291
+ )
292
+ failRecordDeletes(store)
293
+
294
+ const deletedOrg = await app.request(`/v1/orgs/${org.id}`, {
295
+ headers: { cookie },
296
+ method: 'DELETE',
297
+ })
298
+ expect(deletedOrg.status).toBe(502)
299
+
300
+ const orgStill = await app.request(`/v1/orgs/${org.id}`, { headers: { cookie } })
301
+ expect(orgStill.status).toBe(200)
302
+ })
303
+
304
+ test('mints as the super admin with super admin attribution', async () => {
305
+ const app = createApp()
306
+ const cookie = await session(app)
307
+ const { org, project } = await fixture(app, cookie)
308
+
309
+ const minted = await app.request(`/v1/orgs/${org.id}/projects/${project.id}/api-keys`, {
310
+ body: JSON.stringify({ scopes: ['data:read'] }),
311
+ headers: { 'content-type': 'application/json', 'tempo-api-key': secret },
312
+ method: 'POST',
313
+ })
314
+ expect(minted.status).toBe(200)
315
+ const created = await TestApp.json(minted, Keys.schema.createApiKey.Response)
316
+ expect(created.createdBy).toBe('super_admin')
317
+ expect(created.environment).toBe('production')
318
+ })
319
+
320
+ test('rejects API keys on the keys surface', async () => {
321
+ const app = createApp()
322
+ const cookie = await session(app)
323
+ const { org, project } = await fixture(app, cookie)
324
+
325
+ const response = await app.request(`/v1/orgs/${org.id}/projects/${project.id}/api-keys`, {
326
+ headers: { 'tempo-api-key': TestApp.key.token },
327
+ })
328
+ expect(response.status).toBe(403)
329
+ })
330
+ })