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,361 @@
1
+ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
2
+
3
+ import * as App from '../App.js'
4
+ import * as TestApp from '../../../../test/App.js'
5
+ import * as Invitations from '../../../db/tables/invitations.js'
6
+ import * as InvitationsApp from './invitations.js'
7
+ import * as Memberships from '../../../db/tables/memberships.js'
8
+ import * as Orgs from './orgs.js'
9
+ import * as Users from '../../../db/tables/users.js'
10
+
11
+ /** Origin pinned for SIWE domain binding; Hono test requests use this host. */
12
+ const origin = 'http://localhost'
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
+ /** In-memory email sender capturing dispatched messages. */
24
+ function sender() {
25
+ const sent: App.Email.Message[] = []
26
+ const email = {
27
+ from: 'noreply@tempo.test',
28
+ send: (message: App.Email.Message) => {
29
+ sent.push(message)
30
+ return Promise.resolve()
31
+ },
32
+ } satisfies App.Email
33
+ return { email, sent }
34
+ }
35
+
36
+ /** Super admin secret configured on the test app. */
37
+ const secret = 'tempo:sk:d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3'
38
+
39
+ function createApp(options: { db?: ReturnType<typeof TestApp.database>; email?: App.Email } = {}) {
40
+ return TestApp.create({
41
+ auth: { superAdmin: { secret } },
42
+ db: options.db ?? TestApp.database(),
43
+ ...(options.email ? { email: options.email } : {}),
44
+ session: { wallet: { origin } },
45
+ })
46
+ }
47
+
48
+ /** Signs in a fresh scripted account; returns its cookie and user id. */
49
+ async function session(app: ReturnType<typeof createApp>) {
50
+ const account = privateKeyToAccount(generatePrivateKey())
51
+ const { cookie } = await TestApp.signIn(app, account)
52
+ const me = await app.request('/v1/me', { headers: { cookie: cookie! } })
53
+ const { id } = (await me.json()) as { id: string }
54
+ return { cookie: cookie!, userId: id }
55
+ }
56
+
57
+ describe('invitations', () => {
58
+ test('invites, surfaces, and accepts into membership', async () => {
59
+ const db = TestApp.database()
60
+ const { email, sent } = sender()
61
+ const app = createApp({ db, email })
62
+ const owner = await session(app)
63
+ const created = await app.request('/v1/orgs', json('POST', owner.cookie, { name: 'Acme' }))
64
+ const org = await TestApp.json(created, Orgs.schema.Organization)
65
+
66
+ const invited = await app.request(
67
+ `/v1/orgs/${org.id}/invitations`,
68
+ json('POST', owner.cookie, { email: 'Dev@Example.com', role: 'member' }),
69
+ )
70
+ expect(invited.status).toBe(200)
71
+ const invitation = await TestApp.json(invited, InvitationsApp.schema.Invitation)
72
+ expect(invitation.id).toMatch(/^inv_/)
73
+ expect(invitation.email).toBe('dev@example.com')
74
+
75
+ // The invitation email dispatched through the app's sender.
76
+ expect(sent).toHaveLength(1)
77
+ expect(sent[0]!.to).toBe('dev@example.com')
78
+ expect(sent[0]!.subject).toContain('Acme')
79
+ expect(sent[0]!.text).toMatchInlineSnapshot(`
80
+ "You've been invited to join Acme on the Tempo Developer Platform
81
+
82
+ Sign in at https://console.tempo.xyz/?email=dev%40example.com to accept. This invitation expires in 7 days."
83
+ `)
84
+ expect(sent[0]!.html).toContain('<strong>Acme</strong>')
85
+ expect(sent[0]!.html).toContain('https://console.tempo.xyz/?email=dev%40example.com')
86
+
87
+ // Invisible without a verified email; visible once it matches.
88
+ const invitee = await session(app)
89
+ const before = await app.request('/v1/invitations', { headers: { cookie: invitee.cookie } })
90
+ expect(
91
+ (await TestApp.json(before, InvitationsApp.schema.listMyInvitations.Response)).data,
92
+ ).toEqual([])
93
+ await Users.setEmail(db, invitee.userId, 'dev@example.com')
94
+ const after = await app.request('/v1/invitations', { headers: { cookie: invitee.cookie } })
95
+ const mine = await TestApp.json(after, InvitationsApp.schema.listMyInvitations.Response)
96
+ expect(mine.data.map(({ id, orgName }) => ({ id, orgName }))).toEqual([
97
+ { id: invitation.id, orgName: 'Acme' },
98
+ ])
99
+
100
+ const accepted = await app.request(`/v1/invitations/${invitation.id}/accept`, {
101
+ headers: { cookie: invitee.cookie },
102
+ method: 'POST',
103
+ })
104
+ expect(accepted.status).toBe(200)
105
+ const membership = await TestApp.json(accepted, InvitationsApp.schema.acceptInvitation.Response) // prettier-ignore
106
+ expect(membership).toEqual({ orgId: org.id, role: 'member', userId: invitee.userId })
107
+
108
+ // Membership grants access; the pending lists drain on both sides.
109
+ const read = await app.request(`/v1/orgs/${org.id}`, { headers: { cookie: invitee.cookie } })
110
+ expect(read.status).toBe(200)
111
+ const orgPending = await app.request(`/v1/orgs/${org.id}/invitations`, {
112
+ headers: { cookie: owner.cookie },
113
+ })
114
+ expect(
115
+ (await TestApp.json(orgPending, InvitationsApp.schema.listInvitations.Response)).data,
116
+ ).toEqual([])
117
+
118
+ // Accepting again fails: the invitation is settled.
119
+ const again = await app.request(`/v1/invitations/${invitation.id}/accept`, {
120
+ headers: { cookie: invitee.cookie },
121
+ method: 'POST',
122
+ })
123
+ expect(again.status).toBe(404)
124
+ })
125
+
126
+ test('accepting elevates an existing member but never demotes', async () => {
127
+ const db = TestApp.database()
128
+ const app = createApp({ db })
129
+ const owner = await session(app)
130
+ const created = await app.request('/v1/orgs', json('POST', owner.cookie, { name: 'Acme' }))
131
+ const org = await TestApp.json(created, Orgs.schema.Organization)
132
+
133
+ // A standing member accepts an admin invitation: the role is elevated.
134
+ const invitee = await session(app)
135
+ await Users.setEmail(db, invitee.userId, 'dev@example.com')
136
+ await Memberships.create(db, { orgId: org.id, role: 'member', userId: invitee.userId })
137
+ const promote = await app.request(
138
+ `/v1/orgs/${org.id}/invitations`,
139
+ json('POST', owner.cookie, { email: 'dev@example.com', role: 'admin' }),
140
+ )
141
+ const promoteInvite = await TestApp.json(promote, InvitationsApp.schema.Invitation)
142
+ const promoted = await app.request(`/v1/invitations/${promoteInvite.id}/accept`, {
143
+ headers: { cookie: invitee.cookie },
144
+ method: 'POST',
145
+ })
146
+ expect((await TestApp.json(promoted, InvitationsApp.schema.acceptInvitation.Response)).role).toBe('admin') // prettier-ignore
147
+ expect((await Memberships.get(db, org.id, invitee.userId))?.role).toBe('admin')
148
+
149
+ // A lower-role invitation to the same member is a no-op, never a demotion.
150
+ const demote = await app.request(
151
+ `/v1/orgs/${org.id}/invitations`,
152
+ json('POST', owner.cookie, { email: 'dev@example.com', role: 'member' }),
153
+ )
154
+ const demoteInvite = await TestApp.json(demote, InvitationsApp.schema.Invitation)
155
+ const demoted = await app.request(`/v1/invitations/${demoteInvite.id}/accept`, {
156
+ headers: { cookie: invitee.cookie },
157
+ method: 'POST',
158
+ })
159
+ expect((await TestApp.json(demoted, InvitationsApp.schema.acceptInvitation.Response)).role).toBe('admin') // prettier-ignore
160
+ expect((await Memberships.get(db, org.id, invitee.userId))?.role).toBe('admin')
161
+ })
162
+
163
+ test('re-inviting a pending email refreshes the invitation, not duplicates it', async () => {
164
+ const db = TestApp.database()
165
+ const app = createApp({ db })
166
+ const owner = await session(app)
167
+ const created = await app.request('/v1/orgs', json('POST', owner.cookie, { name: 'Acme' }))
168
+ const org = await TestApp.json(created, Orgs.schema.Organization)
169
+
170
+ const first = await app.request(
171
+ `/v1/orgs/${org.id}/invitations`,
172
+ json('POST', owner.cookie, { email: 'dev@example.com', role: 'member' }),
173
+ )
174
+ const firstInvite = await TestApp.json(first, InvitationsApp.schema.Invitation)
175
+ const second = await app.request(
176
+ `/v1/orgs/${org.id}/invitations`,
177
+ json('POST', owner.cookie, { email: 'dev@example.com', role: 'admin' }),
178
+ )
179
+ const secondInvite = await TestApp.json(second, InvitationsApp.schema.Invitation)
180
+
181
+ // Same row, refreshed role — a single pending invitation remains.
182
+ expect(secondInvite.id).toBe(firstInvite.id)
183
+ expect(secondInvite.role).toBe('admin')
184
+ const listed = await app.request(`/v1/orgs/${org.id}/invitations`, {
185
+ headers: { cookie: owner.cookie },
186
+ })
187
+ const pending = await TestApp.json(listed, InvitationsApp.schema.listInvitations.Response)
188
+ expect(pending.data).toHaveLength(1)
189
+ expect(pending.data[0]!.role).toBe('admin')
190
+ })
191
+
192
+ test('enforces the inviter role ladder', async () => {
193
+ const db = TestApp.database()
194
+ const app = createApp({ db })
195
+ const owner = await session(app)
196
+ const created = await app.request('/v1/orgs', json('POST', owner.cookie, { name: 'Acme' }))
197
+ const org = await TestApp.json(created, Orgs.schema.Organization)
198
+
199
+ const admin = await session(app)
200
+ await Memberships.create(db, { orgId: org.id, role: 'admin', userId: admin.userId })
201
+ const member = await session(app)
202
+ await Memberships.create(db, { orgId: org.id, role: 'member', userId: member.userId })
203
+
204
+ // Members cannot invite at all; admins cannot grant above their role.
205
+ const byMember = await app.request(`/v1/orgs/${org.id}/invitations`, json('POST', member.cookie, { email: 'a@example.com', role: 'member' })) // prettier-ignore
206
+ expect(byMember.status).toBe(403)
207
+ const escalated = await app.request(`/v1/orgs/${org.id}/invitations`, json('POST', admin.cookie, { email: 'a@example.com', role: 'owner' })) // prettier-ignore
208
+ expect(escalated.status).toBe(403)
209
+ // Admins cannot grant their own role either — only strictly below it.
210
+ const peer = await app.request(`/v1/orgs/${org.id}/invitations`, json('POST', admin.cookie, { email: 'a@example.com', role: 'admin' })) // prettier-ignore
211
+ expect(peer.status).toBe(403)
212
+ const byAdmin = await app.request(`/v1/orgs/${org.id}/invitations`, json('POST', admin.cookie, { email: 'a@example.com', role: 'member' })) // prettier-ignore
213
+ expect(byAdmin.status).toBe(200)
214
+ const byOwner = await app.request(`/v1/orgs/${org.id}/invitations`, json('POST', owner.cookie, { email: 'b@example.com', role: 'owner' })) // prettier-ignore
215
+ expect(byOwner.status).toBe(200)
216
+ })
217
+
218
+ test('revoked and expired invitations cannot be accepted', async () => {
219
+ const db = TestApp.database()
220
+ const app = createApp({ db })
221
+ const owner = await session(app)
222
+ const created = await app.request('/v1/orgs', json('POST', owner.cookie, { name: 'Acme' }))
223
+ const org = await TestApp.json(created, Orgs.schema.Organization)
224
+
225
+ const invitee = await session(app)
226
+ await Users.setEmail(db, invitee.userId, 'dev@example.com')
227
+
228
+ const invited = await app.request(
229
+ `/v1/orgs/${org.id}/invitations`,
230
+ json('POST', owner.cookie, { email: 'dev@example.com', role: 'member' }),
231
+ )
232
+ const invitation = await TestApp.json(invited, InvitationsApp.schema.Invitation)
233
+ const revoked = await app.request(`/v1/orgs/${org.id}/invitations/${invitation.id}`, {
234
+ headers: { cookie: owner.cookie },
235
+ method: 'DELETE',
236
+ })
237
+ expect(revoked.status).toBe(200)
238
+ const acceptRevoked = await app.request(`/v1/invitations/${invitation.id}/accept`, {
239
+ headers: { cookie: invitee.cookie },
240
+ method: 'POST',
241
+ })
242
+ expect(acceptRevoked.status).toBe(404)
243
+
244
+ // Expired: seeded directly with a past expiry through the table module.
245
+ const expired = await Invitations.create(db, {
246
+ email: 'dev@example.com',
247
+ expiresAt: '2020-01-01T00:00:00.000Z',
248
+ invitedBy: owner.userId,
249
+ orgId: org.id,
250
+ role: 'member',
251
+ })
252
+ const listed = await app.request('/v1/invitations', { headers: { cookie: invitee.cookie } })
253
+ expect(
254
+ (await TestApp.json(listed, InvitationsApp.schema.listMyInvitations.Response)).data,
255
+ ).toEqual([])
256
+ const acceptExpired = await app.request(`/v1/invitations/${expired.id}/accept`, {
257
+ headers: { cookie: invitee.cookie },
258
+ method: 'POST',
259
+ })
260
+ expect(acceptExpired.status).toBe(404)
261
+ })
262
+
263
+ test("hides invitations addressed to someone else's email", async () => {
264
+ const db = TestApp.database()
265
+ const app = createApp({ db })
266
+ const owner = await session(app)
267
+ const created = await app.request('/v1/orgs', json('POST', owner.cookie, { name: 'Acme' }))
268
+ const org = await TestApp.json(created, Orgs.schema.Organization)
269
+ const invited = await app.request(
270
+ `/v1/orgs/${org.id}/invitations`,
271
+ json('POST', owner.cookie, { email: 'dev@example.com', role: 'member' }),
272
+ )
273
+ const invitation = await TestApp.json(invited, InvitationsApp.schema.Invitation)
274
+
275
+ const other = await session(app)
276
+ await Users.setEmail(db, other.userId, 'other@example.com')
277
+ const accepted = await app.request(`/v1/invitations/${invitation.id}/accept`, {
278
+ headers: { cookie: other.cookie },
279
+ method: 'POST',
280
+ })
281
+ expect(accepted.status).toBe(404)
282
+ })
283
+
284
+ test('a failing email sender never fails the invite', async () => {
285
+ const app = createApp({
286
+ email: {
287
+ from: 'noreply@tempo.test',
288
+ send: () => Promise.reject(new Error('smtp down')),
289
+ },
290
+ })
291
+ const owner = await session(app)
292
+ const created = await app.request('/v1/orgs', json('POST', owner.cookie, { name: 'Acme' }))
293
+ const org = await TestApp.json(created, Orgs.schema.Organization)
294
+
295
+ const invited = await app.request(
296
+ `/v1/orgs/${org.id}/invitations`,
297
+ json('POST', owner.cookie, { email: 'dev@example.com', role: 'member' }),
298
+ )
299
+ expect(invited.status).toBe(200)
300
+ })
301
+
302
+ test('super admin provisions an org and seats its first owner', async () => {
303
+ const db = TestApp.database()
304
+ const app = createApp({ db })
305
+
306
+ // The super admin creates a memberless org and invites the first owner.
307
+ const created = await app.request('/v1/orgs', {
308
+ body: JSON.stringify({ name: 'Provisioned' }),
309
+ headers: { 'content-type': 'application/json', 'tempo-api-key': secret },
310
+ method: 'POST',
311
+ })
312
+ expect(created.status).toBe(200)
313
+ const org = await TestApp.json(created, Orgs.schema.Organization)
314
+ const invited = await app.request(`/v1/orgs/${org.id}/invitations`, {
315
+ body: JSON.stringify({ email: 'founder@example.com', role: 'owner' }),
316
+ headers: { 'content-type': 'application/json', 'tempo-api-key': secret },
317
+ method: 'POST',
318
+ })
319
+ expect(invited.status).toBe(200)
320
+ const invitation = await TestApp.json(invited, InvitationsApp.schema.Invitation)
321
+ expect(invitation.invitedBy).toBe('super_admin')
322
+
323
+ // The invitee accepts and holds owner powers.
324
+ const founder = await session(app)
325
+ await Users.setEmail(db, founder.userId, 'founder@example.com')
326
+ const accepted = await app.request(`/v1/invitations/${invitation.id}/accept`, {
327
+ headers: { cookie: founder.cookie },
328
+ method: 'POST',
329
+ })
330
+ expect(accepted.status).toBe(200)
331
+ const renamed = await app.request(
332
+ `/v1/orgs/${org.id}`,
333
+ json('PATCH', founder.cookie, { name: 'Founded' }),
334
+ )
335
+ expect(renamed.status).toBe(200)
336
+ })
337
+
338
+ test('embeds the configured console origin in the email link', async () => {
339
+ const sent: App.Email.Message[] = []
340
+ const app = createApp({
341
+ email: {
342
+ consoleUrl: 'https://portal.selfhost.example',
343
+ from: 'noreply@selfhost.example',
344
+ send: (message) => {
345
+ sent.push(message)
346
+ return Promise.resolve()
347
+ },
348
+ },
349
+ })
350
+ const owner = await session(app)
351
+ const created = await app.request('/v1/orgs', json('POST', owner.cookie, { name: 'Acme' }))
352
+ const org = await TestApp.json(created, Orgs.schema.Organization)
353
+
354
+ const invited = await app.request(
355
+ `/v1/orgs/${org.id}/invitations`,
356
+ json('POST', owner.cookie, { email: 'dev@example.com', role: 'member' }),
357
+ )
358
+ expect(invited.status).toBe(200)
359
+ expect(sent[0]!.text).toContain('https://portal.selfhost.example/?email=dev%40example.com')
360
+ })
361
+ })