@tempoxyz/id 0.0.0-stage → 0.0.1

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 (1096) hide show
  1. package/README.md +121 -2
  2. package/dist/App.d.ts +121 -0
  3. package/dist/App.d.ts.map +1 -0
  4. package/dist/App.js +132 -0
  5. package/dist/App.js.map +1 -0
  6. package/dist/app/client/.assetsignore +2 -0
  7. package/dist/app/client/_headers +4 -0
  8. package/dist/app/client/assets/Account-BYLpNFf3.css +1 -0
  9. package/dist/app/client/assets/Account-BllJah07.js +1 -0
  10. package/dist/app/client/assets/Amount-E_7snI0-.js +1 -0
  11. package/dist/app/client/assets/Amount-ZdtluGf-.css +1 -0
  12. package/dist/app/client/assets/Approval-CgV5JHlb.css +1 -0
  13. package/dist/app/client/assets/Approval-yKflypU2.js +1 -0
  14. package/dist/app/client/assets/ArrowUp-CRvqfMNU.js +1 -0
  15. package/dist/app/client/assets/Authentication-BAXhOh_4.js +2 -0
  16. package/dist/app/client/assets/BRLA-CZvVDNYr.png +0 -0
  17. package/dist/app/client/assets/BRZ-Cn3jEi9t.svg +1 -0
  18. package/dist/app/client/assets/CHFAU-DCedc4aH.png +0 -0
  19. package/dist/app/client/assets/Callout-B736759d.js +1 -0
  20. package/dist/app/client/assets/Callout-DBfEmP7q.css +1 -0
  21. package/dist/app/client/assets/Check-DVgD8tDG.js +1 -0
  22. package/dist/app/client/assets/ChevronRight-CsXtIZCB.js +1 -0
  23. package/dist/app/client/assets/ChooseAccount-BjxfQjPK.js +1 -0
  24. package/dist/app/client/assets/ChooseAccount-DL3wgJhE.css +1 -0
  25. package/dist/app/client/assets/Client-JrABNovb.js +1 -0
  26. package/dist/app/client/assets/Close-CRvWlhqc.js +1 -0
  27. package/dist/app/client/assets/Cloud-DgJsrqpQ.js +1 -0
  28. package/dist/app/client/assets/CodeInput-79Ctx8ZA.js +1 -0
  29. package/dist/app/client/assets/CodeInput-BqRteSwD.css +1 -0
  30. package/dist/app/client/assets/DLUSD-BnRXm3EI.png +0 -0
  31. package/dist/app/client/assets/Deposit-CclrAoXL.css +1 -0
  32. package/dist/app/client/assets/Deposit-c7uYn2Eb.js +1 -0
  33. package/dist/app/client/assets/DevTools-BYkmtuV5.css +1 -0
  34. package/dist/app/client/assets/DevTools-BgnzDGo2.js +1 -0
  35. package/dist/app/client/assets/DeviceApproval-BBUVv58e.js +1 -0
  36. package/dist/app/client/assets/DeviceApproval-BffFLD8F.css +1 -0
  37. package/dist/app/client/assets/EURAU-sjieTTB9.svg +1 -0
  38. package/dist/app/client/assets/EURC.e-CxYiiwkz.svg +1 -0
  39. package/dist/app/client/assets/Fingerprint-BNCA6qOJ.js +1 -0
  40. package/dist/app/client/assets/GBPA-DI_25xSG.svg +4 -0
  41. package/dist/app/client/assets/GUSD-BDEP2Qb-.svg +1 -0
  42. package/dist/app/client/assets/GeistMono-Variable-BRXCGrxA.woff2 +0 -0
  43. package/dist/app/client/assets/Globe-f0eWzcEI.js +1 -0
  44. package/dist/app/client/assets/Grant-5a-n1gJH.css +1 -0
  45. package/dist/app/client/assets/Grant-Dp7mpcEi.js +1 -0
  46. package/dist/app/client/assets/Hex-C9KeV7_9.css +1 -0
  47. package/dist/app/client/assets/Hex-CSp2U46W.js +10 -0
  48. package/dist/app/client/assets/IconChip-DpZHa1JW.js +1 -0
  49. package/dist/app/client/assets/IconChip-yqaQ2y_d.css +1 -0
  50. package/dist/app/client/assets/InputGroup-BlZvt9In.css +1 -0
  51. package/dist/app/client/assets/InputGroup-CsOeBnpB.js +1 -0
  52. package/dist/app/client/assets/Inter-cyrillic-e3OmmzmJ.woff2 +0 -0
  53. package/dist/app/client/assets/Inter-cyrillic-ext-DOWZeO4Q.woff2 +0 -0
  54. package/dist/app/client/assets/Inter-greek-BD3ujQlX.woff2 +0 -0
  55. package/dist/app/client/assets/Inter-greek-ext-CXEwbus4.woff2 +0 -0
  56. package/dist/app/client/assets/Inter-latin-BDFm4vTb.woff2 +0 -0
  57. package/dist/app/client/assets/Inter-latin-ext-E7a9JEPe.woff2 +0 -0
  58. package/dist/app/client/assets/Inter-symbols-DEch7Rxr.woff2 +0 -0
  59. package/dist/app/client/assets/Inter-vietnamese-Bg9723vR.woff2 +0 -0
  60. package/dist/app/client/assets/Loader-Cm9YJNNJ.js +1 -0
  61. package/dist/app/client/assets/MACH-sK0r79kQ.svg +4 -0
  62. package/dist/app/client/assets/OUSD-BFXgVo-Z.svg +5 -0
  63. package/dist/app/client/assets/OUSD.dark-BbbjMvA1.svg +17 -0
  64. package/dist/app/client/assets/OUSD.light-B_zpSz_c.svg +17 -0
  65. package/dist/app/client/assets/PRIME-CiFp2-3e.svg +14 -0
  66. package/dist/app/client/assets/PopoverPopup-DprRXRQe.js +1 -0
  67. package/dist/app/client/assets/Rows-DPGTUdA8.css +1 -0
  68. package/dist/app/client/assets/Rows-Qqo3evtk.js +1 -0
  69. package/dist/app/client/assets/SBC-BTYkbkiD.svg +1 -0
  70. package/dist/app/client/assets/SEKAU-CB5Fc6o8.svg +5 -0
  71. package/dist/app/client/assets/Separator-CZUjVQOL.js +1 -0
  72. package/dist/app/client/assets/SignIn-HdaDzFmq.js +1 -0
  73. package/dist/app/client/assets/SignIn-mlBTwUq4.css +1 -0
  74. package/dist/app/client/assets/Stack-CkkvkOzj.js +1 -0
  75. package/dist/app/client/assets/Stack-D7Yt22Ed.css +1 -0
  76. package/dist/app/client/assets/Tag-BMh6ajrW.css +1 -0
  77. package/dist/app/client/assets/Tag-CLOVANTX.js +1 -0
  78. package/dist/app/client/assets/ToolbarRootContext-Zty_Dh3J.js +1 -0
  79. package/dist/app/client/assets/Tooltip-CLATV6YU.js +1 -0
  80. package/dist/app/client/assets/Tooltip-d3y9ESUJ.css +1 -0
  81. package/dist/app/client/assets/USD1-COVcO_PB.svg +30 -0
  82. package/dist/app/client/assets/USDB-Ckwb6UQw.svg +11 -0
  83. package/dist/app/client/assets/USDC.e-3nMsKAMC.svg +1 -0
  84. package/dist/app/client/assets/USDT0-ia60Dw0e.svg +1 -0
  85. package/dist/app/client/assets/USDY-CB4iet2q.svg +16 -0
  86. package/dist/app/client/assets/USDe-BXHQCd92.svg +1 -0
  87. package/dist/app/client/assets/Upgrade-D0_aO5AP.js +1 -0
  88. package/dist/app/client/assets/WalletUpgrade-BPsPNQsd.js +1 -0
  89. package/dist/app/client/assets/WalletUpgrade-C04kW0Jl.css +1 -0
  90. package/dist/app/client/assets/YLDS-CRh8Zw0g.svg +3 -0
  91. package/dist/app/client/assets/___-I98bns4o.css +1 -0
  92. package/dist/app/client/assets/___.flows-XOlLwMIy.js +5 -0
  93. package/dist/app/client/assets/alphaUSD-CpCFoVuh.svg +1 -0
  94. package/dist/app/client/assets/authorize-C-MlCyaM.js +1 -0
  95. package/dist/app/client/assets/betaUSD-9A8AjgYg.svg +1 -0
  96. package/dist/app/client/assets/cUSD-WsQfa-iC.svg +1 -0
  97. package/dist/app/client/assets/cbBTC-DvUDqrDi.svg +1 -0
  98. package/dist/app/client/assets/choose-account-nXR-SKa2.js +1 -0
  99. package/dist/app/client/assets/deposit-G8tiLPN4.js +1 -0
  100. package/dist/app/client/assets/device-BojBF7hZ.js +1 -0
  101. package/dist/app/client/assets/error-KiOpX7GD.js +1 -0
  102. package/dist/app/client/assets/frxUSD-n9pTpinR.svg +1 -0
  103. package/dist/app/client/assets/getPseudoElementBounds-BsLy4zf_.js +1 -0
  104. package/dist/app/client/assets/goUSD-D9kUvHsF.svg +5 -0
  105. package/dist/app/client/assets/iUSD-CWCJAq9X.svg +1 -0
  106. package/dist/app/client/assets/index-BZH0M7Nf.js +13 -0
  107. package/dist/app/client/assets/index-CIYxHmYA.css +1 -0
  108. package/dist/app/client/assets/login-DUjpk60p.js +1 -0
  109. package/dist/app/client/assets/pathUSD-BvaO6ooS.svg +25 -0
  110. package/dist/app/client/assets/preload-helper-Bs9KvdYl.js +1 -0
  111. package/dist/app/client/assets/rUSD-B-xuFS7T.svg +1 -0
  112. package/dist/app/client/assets/reUSD-CkIUs0Lx.svg +1 -0
  113. package/dist/app/client/assets/removable-DMiA3t_o.js +1 -0
  114. package/dist/app/client/assets/reset-co-CHrff.css +1 -0
  115. package/dist/app/client/assets/rolldown-runtime-WkwZ5CU-.js +1 -0
  116. package/dist/app/client/assets/routes-CK8cthzA.js +1 -0
  117. package/dist/app/client/assets/sUSDe-j9GOnH7I.svg +1 -0
  118. package/dist/app/client/assets/siUSD-C10QUNYS.svg +1 -0
  119. package/dist/app/client/assets/stcUSD-DIntDJeh.svg +1 -0
  120. package/dist/app/client/assets/syrupUSDC-DhYwZqdM.svg +5 -0
  121. package/dist/app/client/assets/thetaUSD-Dgmksf6G.svg +1 -0
  122. package/dist/app/client/assets/useNavigate-CB6S2u4J.js +1 -0
  123. package/dist/app/client/assets/useQuery-BpHfPhTT.js +1 -0
  124. package/dist/app/client/assets/useRegisterFieldControl-DsslqY-V.js +1 -0
  125. package/dist/app/client/assets/wYLDS-CaCKDrO-.svg +10 -0
  126. package/dist/app/client/assets/wsrUSD-B2Ey0bDQ.svg +1 -0
  127. package/dist/app/client/assets/zyzz-DYC-X0_B.css +1 -0
  128. package/dist/app/client/assets/zyzz.config-DX_D_7j3.js +2 -0
  129. package/dist/app/db/auth.d.ts +3412 -0
  130. package/dist/app/db/auth.d.ts.map +1 -0
  131. package/dist/app/db/auth.js +349 -0
  132. package/dist/app/db/auth.js.map +1 -0
  133. package/dist/app/db/schema.d.ts +1091 -0
  134. package/dist/app/db/schema.d.ts.map +1 -0
  135. package/dist/app/db/schema.js +183 -0
  136. package/dist/app/db/schema.js.map +1 -0
  137. package/dist/app/db/table.d.ts +8 -0
  138. package/dist/app/db/table.d.ts.map +1 -0
  139. package/dist/app/db/table.js +28 -0
  140. package/dist/app/db/table.js.map +1 -0
  141. package/dist/app/server/.vite/manifest.json +2093 -0
  142. package/dist/app/server/assets/Account-BYLpNFf3.css +1 -0
  143. package/dist/app/server/assets/Account-G_SUeRU3.js +2 -0
  144. package/dist/app/server/assets/Account-G_SUeRU3.js.map +1 -0
  145. package/dist/app/server/assets/Amount-Cgwdr3Xt.js +2 -0
  146. package/dist/app/server/assets/Amount-Cgwdr3Xt.js.map +1 -0
  147. package/dist/app/server/assets/Amount-ZdtluGf-.css +1 -0
  148. package/dist/app/server/assets/Approval-CgV5JHlb.css +1 -0
  149. package/dist/app/server/assets/Approval-DvkB9tWA.js +2 -0
  150. package/dist/app/server/assets/Approval-DvkB9tWA.js.map +1 -0
  151. package/dist/app/server/assets/ArrowUp-DpK_zNgZ.js +2 -0
  152. package/dist/app/server/assets/ArrowUp-DpK_zNgZ.js.map +1 -0
  153. package/dist/app/server/assets/Authentication-BOkhlNQu.js +2 -0
  154. package/dist/app/server/assets/Authentication-BOkhlNQu.js.map +1 -0
  155. package/dist/app/server/assets/Authentication-C3oNZAVX.js +2 -0
  156. package/dist/app/server/assets/Authentication-C3oNZAVX.js.map +1 -0
  157. package/dist/app/server/assets/BRLA-CZvVDNYr.png +0 -0
  158. package/dist/app/server/assets/BRZ-Cn3jEi9t.svg +1 -0
  159. package/dist/app/server/assets/Bytes-C7CRVS3J.js +4 -0
  160. package/dist/app/server/assets/Bytes-C7CRVS3J.js.map +1 -0
  161. package/dist/app/server/assets/CHFAU-DCedc4aH.png +0 -0
  162. package/dist/app/server/assets/Callout-DBfEmP7q.css +1 -0
  163. package/dist/app/server/assets/Callout-tQoAitWq.js +2 -0
  164. package/dist/app/server/assets/Callout-tQoAitWq.js.map +1 -0
  165. package/dist/app/server/assets/ChainList-C4A_7e-9.js +6 -0
  166. package/dist/app/server/assets/ChainList-C4A_7e-9.js.map +1 -0
  167. package/dist/app/server/assets/ChainName-BMnJyJrd.js +2 -0
  168. package/dist/app/server/assets/ChainName-BMnJyJrd.js.map +1 -0
  169. package/dist/app/server/assets/Check-DU_oR3Ev.js +2 -0
  170. package/dist/app/server/assets/Check-DU_oR3Ev.js.map +1 -0
  171. package/dist/app/server/assets/ChevronRight-DTBnw-W6.js +2 -0
  172. package/dist/app/server/assets/ChevronRight-DTBnw-W6.js.map +1 -0
  173. package/dist/app/server/assets/ChooseAccount-BizJvMrY.js +2 -0
  174. package/dist/app/server/assets/ChooseAccount-BizJvMrY.js.map +1 -0
  175. package/dist/app/server/assets/ChooseAccount-DL3wgJhE.css +1 -0
  176. package/dist/app/server/assets/Client-Dx3KrpJZ.js +2 -0
  177. package/dist/app/server/assets/Client-Dx3KrpJZ.js.map +1 -0
  178. package/dist/app/server/assets/ClientOnly-CKLiu67O.js +2 -0
  179. package/dist/app/server/assets/ClientOnly-CKLiu67O.js.map +1 -0
  180. package/dist/app/server/assets/Close-DUeE37ev.js +2 -0
  181. package/dist/app/server/assets/Close-DUeE37ev.js.map +1 -0
  182. package/dist/app/server/assets/Cloud-CLB3rTTy.js +2 -0
  183. package/dist/app/server/assets/Cloud-CLB3rTTy.js.map +1 -0
  184. package/dist/app/server/assets/CodeInput-BqRteSwD.css +1 -0
  185. package/dist/app/server/assets/CodeInput-FsPzVuLU.js +2 -0
  186. package/dist/app/server/assets/CodeInput-FsPzVuLU.js.map +1 -0
  187. package/dist/app/server/assets/Credential-DFjcrdyI.js +2 -0
  188. package/dist/app/server/assets/Credential-DFjcrdyI.js.map +1 -0
  189. package/dist/app/server/assets/DLUSD-BnRXm3EI.png +0 -0
  190. package/dist/app/server/assets/Deposit-CclrAoXL.css +1 -0
  191. package/dist/app/server/assets/Deposit-ChYGRfW2.js +2 -0
  192. package/dist/app/server/assets/Deposit-ChYGRfW2.js.map +1 -0
  193. package/dist/app/server/assets/DevTools-BYkmtuV5.css +1 -0
  194. package/dist/app/server/assets/DevTools-ZJVXqrIK.js +2 -0
  195. package/dist/app/server/assets/DevTools-ZJVXqrIK.js.map +1 -0
  196. package/dist/app/server/assets/DeviceApproval-BffFLD8F.css +1 -0
  197. package/dist/app/server/assets/DeviceApproval-Bqe3Mi78.js +2 -0
  198. package/dist/app/server/assets/DeviceApproval-Bqe3Mi78.js.map +1 -0
  199. package/dist/app/server/assets/EURAU-sjieTTB9.svg +1 -0
  200. package/dist/app/server/assets/EURC.e-CxYiiwkz.svg +1 -0
  201. package/dist/app/server/assets/ExecutionError-CDszGSF1.js +9 -0
  202. package/dist/app/server/assets/ExecutionError-CDszGSF1.js.map +1 -0
  203. package/dist/app/server/assets/Fingerprint-DhOPOdRr.js +2 -0
  204. package/dist/app/server/assets/Fingerprint-DhOPOdRr.js.map +1 -0
  205. package/dist/app/server/assets/GBPA-DI_25xSG.svg +4 -0
  206. package/dist/app/server/assets/GUSD-BDEP2Qb-.svg +1 -0
  207. package/dist/app/server/assets/GeistMono-Variable-BRXCGrxA.woff2 +0 -0
  208. package/dist/app/server/assets/Globe-2CxqxU-7.js +2 -0
  209. package/dist/app/server/assets/Globe-2CxqxU-7.js.map +1 -0
  210. package/dist/app/server/assets/Grant-5a-n1gJH.css +1 -0
  211. package/dist/app/server/assets/Grant-D_tun0mF.js +2 -0
  212. package/dist/app/server/assets/Grant-D_tun0mF.js.map +1 -0
  213. package/dist/app/server/assets/Hex-C9KeV7_9.css +1 -0
  214. package/dist/app/server/assets/Hex-Z6m_0Y0m.js +11 -0
  215. package/dist/app/server/assets/Hex-Z6m_0Y0m.js.map +1 -0
  216. package/dist/app/server/assets/IconChip-C9ZrmGB5.js +2 -0
  217. package/dist/app/server/assets/IconChip-C9ZrmGB5.js.map +1 -0
  218. package/dist/app/server/assets/IconChip-yqaQ2y_d.css +1 -0
  219. package/dist/app/server/assets/InputGroup-BlZvt9In.css +1 -0
  220. package/dist/app/server/assets/InputGroup-hpjuLuR7.js +2 -0
  221. package/dist/app/server/assets/InputGroup-hpjuLuR7.js.map +1 -0
  222. package/dist/app/server/assets/Inter-cyrillic-e3OmmzmJ.woff2 +0 -0
  223. package/dist/app/server/assets/Inter-cyrillic-ext-DOWZeO4Q.woff2 +0 -0
  224. package/dist/app/server/assets/Inter-greek-BD3ujQlX.woff2 +0 -0
  225. package/dist/app/server/assets/Inter-greek-ext-CXEwbus4.woff2 +0 -0
  226. package/dist/app/server/assets/Inter-latin-BDFm4vTb.woff2 +0 -0
  227. package/dist/app/server/assets/Inter-latin-ext-E7a9JEPe.woff2 +0 -0
  228. package/dist/app/server/assets/Inter-symbols-DEch7Rxr.woff2 +0 -0
  229. package/dist/app/server/assets/Inter-vietnamese-Bg9723vR.woff2 +0 -0
  230. package/dist/app/server/assets/Loader-DnKC9P5p.js +2 -0
  231. package/dist/app/server/assets/Loader-DnKC9P5p.js.map +1 -0
  232. package/dist/app/server/assets/MACH-sK0r79kQ.svg +4 -0
  233. package/dist/app/server/assets/Match-CyVdYcSf.js +2 -0
  234. package/dist/app/server/assets/Match-CyVdYcSf.js.map +1 -0
  235. package/dist/app/server/assets/OUSD-BFXgVo-Z.svg +5 -0
  236. package/dist/app/server/assets/OUSD.dark-BbbjMvA1.svg +17 -0
  237. package/dist/app/server/assets/OUSD.light-B_zpSz_c.svg +17 -0
  238. package/dist/app/server/assets/PRIME-CiFp2-3e.svg +14 -0
  239. package/dist/app/server/assets/PopoverPopup-CwqeQelI.js +2 -0
  240. package/dist/app/server/assets/PopoverPopup-CwqeQelI.js.map +1 -0
  241. package/dist/app/server/assets/Rows-CQKQwTI1.js +2 -0
  242. package/dist/app/server/assets/Rows-CQKQwTI1.js.map +1 -0
  243. package/dist/app/server/assets/Rows-DPGTUdA8.css +1 -0
  244. package/dist/app/server/assets/SBC-BTYkbkiD.svg +1 -0
  245. package/dist/app/server/assets/SEKAU-CB5Fc6o8.svg +5 -0
  246. package/dist/app/server/assets/Separator-DrI7KRAs.js +2 -0
  247. package/dist/app/server/assets/Separator-DrI7KRAs.js.map +1 -0
  248. package/dist/app/server/assets/SignIn-DfeeLEmN.js +2 -0
  249. package/dist/app/server/assets/SignIn-DfeeLEmN.js.map +1 -0
  250. package/dist/app/server/assets/SignIn-mlBTwUq4.css +1 -0
  251. package/dist/app/server/assets/Stack-D7Yt22Ed.css +1 -0
  252. package/dist/app/server/assets/Stack-DGktaLZc.js +2 -0
  253. package/dist/app/server/assets/Stack-DGktaLZc.js.map +1 -0
  254. package/dist/app/server/assets/Tag-9vSRBpph.js +2 -0
  255. package/dist/app/server/assets/Tag-9vSRBpph.js.map +1 -0
  256. package/dist/app/server/assets/Tag-BMh6ajrW.css +1 -0
  257. package/dist/app/server/assets/ToolbarRootContext-BH_CFSWd.js +2 -0
  258. package/dist/app/server/assets/ToolbarRootContext-BH_CFSWd.js.map +1 -0
  259. package/dist/app/server/assets/Tooltip-DLX41peb.js +2 -0
  260. package/dist/app/server/assets/Tooltip-DLX41peb.js.map +1 -0
  261. package/dist/app/server/assets/Tooltip-d3y9ESUJ.css +1 -0
  262. package/dist/app/server/assets/USD1-COVcO_PB.svg +30 -0
  263. package/dist/app/server/assets/USDB-Ckwb6UQw.svg +11 -0
  264. package/dist/app/server/assets/USDC.e-3nMsKAMC.svg +1 -0
  265. package/dist/app/server/assets/USDT0-ia60Dw0e.svg +1 -0
  266. package/dist/app/server/assets/USDY-CB4iet2q.svg +16 -0
  267. package/dist/app/server/assets/USDe-BXHQCd92.svg +1 -0
  268. package/dist/app/server/assets/Upgrade-Dbfm2nm0.js +2 -0
  269. package/dist/app/server/assets/Upgrade-Dbfm2nm0.js.map +1 -0
  270. package/dist/app/server/assets/WalletUpgrade-C04kW0Jl.css +1 -0
  271. package/dist/app/server/assets/WalletUpgrade-CWKc5fYt.js +2 -0
  272. package/dist/app/server/assets/WalletUpgrade-CWKc5fYt.js.map +1 -0
  273. package/dist/app/server/assets/YLDS-CRh8Zw0g.svg +3 -0
  274. package/dist/app/server/assets/___-I98bns4o.css +1 -0
  275. package/dist/app/server/assets/___.flows-Cc-awUoC.js +6 -0
  276. package/dist/app/server/assets/___.flows-Cc-awUoC.js.map +1 -0
  277. package/dist/app/server/assets/_tanstack-start-manifest_v-U7TrtUSA.js +1 -0
  278. package/dist/app/server/assets/_zyzz__2Fhome_2Frunner_2Fwork_2Fid_2Fid_2Fsrc_2Fapp_2Froutes_2F_5B__5D.flows-B1pPOqsM.css +1 -0
  279. package/dist/app/server/assets/_zyzz__2Fhome_2Frunner_2Fwork_2Fid_2Fid_2Fsrc_2Fapp_2Froutes_2F_5B__5D.flows.tsx-CKALi9oD.js +2 -0
  280. package/dist/app/server/assets/_zyzz__2Fhome_2Frunner_2Fwork_2Fid_2Fid_2Fsrc_2Fapp_2Froutes_2F_5B__5D.flows.tsx-CKALi9oD.js.map +1 -0
  281. package/dist/app/server/assets/_zyzz_shared-BbDIEd_j.css +1 -0
  282. package/dist/app/server/assets/alphaUSD-CpCFoVuh.svg +1 -0
  283. package/dist/app/server/assets/arktype-aI7TBD0R-D1R3Byo5.js +2 -0
  284. package/dist/app/server/assets/arktype-aI7TBD0R-D1R3Byo5.js.map +1 -0
  285. package/dist/app/server/assets/async-local-storage-DlOvwxXd.js +2 -0
  286. package/dist/app/server/assets/async-local-storage-DlOvwxXd.js.map +1 -0
  287. package/dist/app/server/assets/authorize-BXzTo2Pb.js +2 -0
  288. package/dist/app/server/assets/authorize-BXzTo2Pb.js.map +1 -0
  289. package/dist/app/server/assets/authorize-BzoUqOdA.js +2 -0
  290. package/dist/app/server/assets/authorize-BzoUqOdA.js.map +1 -0
  291. package/dist/app/server/assets/authorize-DXYo-K2n-rmQQ42x1.js +56 -0
  292. package/dist/app/server/assets/authorize-DXYo-K2n-rmQQ42x1.js.map +1 -0
  293. package/dist/app/server/assets/authorize-DfjPYJqS.css +1 -0
  294. package/dist/app/server/assets/betaUSD-9A8AjgYg.svg +1 -0
  295. package/dist/app/server/assets/bun-sqlite-dialect-DoOVo4ja-CtyBkVMb.js +2 -0
  296. package/dist/app/server/assets/bun-sqlite-dialect-DoOVo4ja-CtyBkVMb.js.map +1 -0
  297. package/dist/app/server/assets/cUSD-WsQfa-iC.svg +1 -0
  298. package/dist/app/server/assets/call-dzi0xjZd.js +31 -0
  299. package/dist/app/server/assets/call-dzi0xjZd.js.map +1 -0
  300. package/dist/app/server/assets/cbBTC-DvUDqrDi.svg +1 -0
  301. package/dist/app/server/assets/ccip-DjD8z_3B.js +2 -0
  302. package/dist/app/server/assets/ccip-DjD8z_3B.js.map +1 -0
  303. package/dist/app/server/assets/choose-account-_X7xq5am.js +2 -0
  304. package/dist/app/server/assets/choose-account-_X7xq5am.js.map +1 -0
  305. package/dist/app/server/assets/choose-account-lqA5SLx9.css +1 -0
  306. package/dist/app/server/assets/choose-account-zm-5Qs3e.js +2 -0
  307. package/dist/app/server/assets/choose-account-zm-5Qs3e.js.map +1 -0
  308. package/dist/app/server/assets/compiled-query-Ds2NVcFT.js +2 -0
  309. package/dist/app/server/assets/compiled-query-Ds2NVcFT.js.map +1 -0
  310. package/dist/app/server/assets/convert-BIC8n32x.js +2 -0
  311. package/dist/app/server/assets/convert-BIC8n32x.js.map +1 -0
  312. package/dist/app/server/assets/cookie-DxViaO10.js +2 -0
  313. package/dist/app/server/assets/cookie-DxViaO10.js.map +1 -0
  314. package/dist/app/server/assets/core-BBrZXfrB.js +56 -0
  315. package/dist/app/server/assets/core-BBrZXfrB.js.map +1 -0
  316. package/dist/app/server/assets/d1-sqlite-dialect-m0f01-4z-Cv-csE1u.js +2 -0
  317. package/dist/app/server/assets/d1-sqlite-dialect-m0f01-4z-Cv-csE1u.js.map +1 -0
  318. package/dist/app/server/assets/decodeFunctionData-bP6V2ai4.js +2 -0
  319. package/dist/app/server/assets/decodeFunctionData-bP6V2ai4.js.map +1 -0
  320. package/dist/app/server/assets/default-u_dwuiYb-DOrMMcg9.js +2 -0
  321. package/dist/app/server/assets/default-u_dwuiYb-DOrMMcg9.js.map +1 -0
  322. package/dist/app/server/assets/deposit-BBaNI01u.js +2 -0
  323. package/dist/app/server/assets/deposit-BBaNI01u.js.map +1 -0
  324. package/dist/app/server/assets/deposit-LWS6ZTuf.js +2 -0
  325. package/dist/app/server/assets/deposit-LWS6ZTuf.js.map +1 -0
  326. package/dist/app/server/assets/deposit-oFx15XCA.css +1 -0
  327. package/dist/app/server/assets/device-CrXlusjr.js +2 -0
  328. package/dist/app/server/assets/device-CrXlusjr.js.map +1 -0
  329. package/dist/app/server/assets/device-DdFMgYe2.js +2 -0
  330. package/dist/app/server/assets/device-DdFMgYe2.js.map +1 -0
  331. package/dist/app/server/assets/device-tMCpu5zk.css +1 -0
  332. package/dist/app/server/assets/dist-CR6FW-yS.js +1 -0
  333. package/dist/app/server/assets/dist-CoH0hD1s.js +15 -0
  334. package/dist/app/server/assets/dist-CoH0hD1s.js.map +1 -0
  335. package/dist/app/server/assets/dist-DcICI3fd.js +2 -0
  336. package/dist/app/server/assets/dist-DcICI3fd.js.map +1 -0
  337. package/dist/app/server/assets/effect-QlVUlMFu-mXPkuQTb.js +2 -0
  338. package/dist/app/server/assets/effect-QlVUlMFu-mXPkuQTb.js.map +1 -0
  339. package/dist/app/server/assets/empty-plugin-adapters-BaGcmrjC.js +2 -0
  340. package/dist/app/server/assets/empty-plugin-adapters-BaGcmrjC.js.map +1 -0
  341. package/dist/app/server/assets/error-CXy8gqdE.css +1 -0
  342. package/dist/app/server/assets/error-DXDT2AHy.js +2 -0
  343. package/dist/app/server/assets/error-DXDT2AHy.js.map +1 -0
  344. package/dist/app/server/assets/error-bnVzy9tx.js +2 -0
  345. package/dist/app/server/assets/error-bnVzy9tx.js.map +1 -0
  346. package/dist/app/server/assets/esm-C6SW--yt.js +4 -0
  347. package/dist/app/server/assets/esm-C6SW--yt.js.map +1 -0
  348. package/dist/app/server/assets/factory-dvoOlKer.js +5 -0
  349. package/dist/app/server/assets/factory-dvoOlKer.js.map +1 -0
  350. package/dist/app/server/assets/frxUSD-n9pTpinR.svg +1 -0
  351. package/dist/app/server/assets/get-id-field-OwLpfjj2.js +6 -0
  352. package/dist/app/server/assets/get-id-field-OwLpfjj2.js.map +1 -0
  353. package/dist/app/server/assets/getPseudoElementBounds-PkWU72kn.js +2 -0
  354. package/dist/app/server/assets/getPseudoElementBounds-PkWU72kn.js.map +1 -0
  355. package/dist/app/server/assets/goUSD-D9kUvHsF.svg +5 -0
  356. package/dist/app/server/assets/iUSD-CWCJAq9X.svg +1 -0
  357. package/dist/app/server/assets/index-CLddUTqr-CC33CMvS.js +2 -0
  358. package/dist/app/server/assets/index-CLddUTqr-CC33CMvS.js.map +1 -0
  359. package/dist/app/server/assets/index-DZEfthgZ-Ec2MMQ_e.js +2 -0
  360. package/dist/app/server/assets/index-DZEfthgZ-Ec2MMQ_e.js.map +1 -0
  361. package/dist/app/server/assets/kysely-adapter-B8tQwTcu.js +1 -0
  362. package/dist/app/server/assets/lazyRouteComponent-DPOOPZw_.js +2 -0
  363. package/dist/app/server/assets/lazyRouteComponent-DPOOPZw_.js.map +1 -0
  364. package/dist/app/server/assets/load-server-Dr0IlySo.js +3 -0
  365. package/dist/app/server/assets/load-server-Dr0IlySo.js.map +1 -0
  366. package/dist/app/server/assets/login-BLq3tEEr.js +2 -0
  367. package/dist/app/server/assets/login-BLq3tEEr.js.map +1 -0
  368. package/dist/app/server/assets/login-DCIrAbED.js +2 -0
  369. package/dist/app/server/assets/login-DCIrAbED.js.map +1 -0
  370. package/dist/app/server/assets/login-msDnt3yT.css +1 -0
  371. package/dist/app/server/assets/matchContext-ByrIUj4L.js +2 -0
  372. package/dist/app/server/assets/matchContext-ByrIUj4L.js.map +1 -0
  373. package/dist/app/server/assets/node-sqlite-dialect-BowWLXvK.js +2 -0
  374. package/dist/app/server/assets/node-sqlite-dialect-BowWLXvK.js.map +1 -0
  375. package/dist/app/server/assets/pathUSD-BvaO6ooS.svg +25 -0
  376. package/dist/app/server/assets/rUSD-B-xuFS7T.svg +1 -0
  377. package/dist/app/server/assets/reUSD-CkIUs0Lx.svg +1 -0
  378. package/dist/app/server/assets/react-dom-DYzj0HXX.js +2 -0
  379. package/dist/app/server/assets/react-dom-DYzj0HXX.js.map +1 -0
  380. package/dist/app/server/assets/removable-BCLTvPOx.js +2 -0
  381. package/dist/app/server/assets/removable-BCLTvPOx.js.map +1 -0
  382. package/dist/app/server/assets/reset-DZWeTZeQ.js +2 -0
  383. package/dist/app/server/assets/reset-DZWeTZeQ.js.map +1 -0
  384. package/dist/app/server/assets/reset-co-CHrff.css +1 -0
  385. package/dist/app/server/assets/resolveError-CZXXvCJR.js +2 -0
  386. package/dist/app/server/assets/resolveError-CZXXvCJR.js.map +1 -0
  387. package/dist/app/server/assets/rolldown-runtime-BWaJ3C7D.js +1 -0
  388. package/dist/app/server/assets/router-Bqz5X4Qw.js +2 -0
  389. package/dist/app/server/assets/router-Bqz5X4Qw.js.map +1 -0
  390. package/dist/app/server/assets/router-CclzitkY.css +1 -0
  391. package/dist/app/server/assets/routes-BLQdKqcZ.js +2 -0
  392. package/dist/app/server/assets/routes-BLQdKqcZ.js.map +1 -0
  393. package/dist/app/server/assets/routes-BgiIzrOt.css +1 -0
  394. package/dist/app/server/assets/routes-Bv6WzsSR.js +2 -0
  395. package/dist/app/server/assets/routes-Bv6WzsSR.js.map +1 -0
  396. package/dist/app/server/assets/sUSDe-j9GOnH7I.svg +1 -0
  397. package/dist/app/server/assets/schema-check-oLqvHR8y.js +9 -0
  398. package/dist/app/server/assets/schema-check-oLqvHR8y.js.map +1 -0
  399. package/dist/app/server/assets/secp256k1-yg8eeIYU.js +2 -0
  400. package/dist/app/server/assets/secp256k1-yg8eeIYU.js.map +1 -0
  401. package/dist/app/server/assets/server-RRUiOef2.js +76 -0
  402. package/dist/app/server/assets/server-RRUiOef2.js.map +1 -0
  403. package/dist/app/server/assets/siUSD-C10QUNYS.svg +1 -0
  404. package/dist/app/server/assets/sqlite-adapter-C_LAV4e3.js +2 -0
  405. package/dist/app/server/assets/sqlite-adapter-C_LAV4e3.js.map +1 -0
  406. package/dist/app/server/assets/sqlite-introspector-DSCAP82F-Crx7Ny14.js +6 -0
  407. package/dist/app/server/assets/sqlite-introspector-DSCAP82F-Crx7Ny14.js.map +1 -0
  408. package/dist/app/server/assets/standard-json-DY77efq0.js +2 -0
  409. package/dist/app/server/assets/standard-json-DY77efq0.js.map +1 -0
  410. package/dist/app/server/assets/standard-json-ig2t0wRt.js +2 -0
  411. package/dist/app/server/assets/standard-json-ig2t0wRt.js.map +1 -0
  412. package/dist/app/server/assets/standard-json-t-LNckA6.js +2 -0
  413. package/dist/app/server/assets/standard-json-t-LNckA6.js.map +1 -0
  414. package/dist/app/server/assets/standard-openapi-CONmVRl8.js +2 -0
  415. package/dist/app/server/assets/standard-openapi-CONmVRl8.js.map +1 -0
  416. package/dist/app/server/assets/start-C63VetBp.js +2 -0
  417. package/dist/app/server/assets/start-C63VetBp.js.map +1 -0
  418. package/dist/app/server/assets/stcUSD-DIntDJeh.svg +1 -0
  419. package/dist/app/server/assets/sury-CWZTCd75-CDaOS2oM.js +2 -0
  420. package/dist/app/server/assets/sury-CWZTCd75-CDaOS2oM.js.map +1 -0
  421. package/dist/app/server/assets/syrupUSDC-DhYwZqdM.svg +5 -0
  422. package/dist/app/server/assets/thetaUSD-Dgmksf6G.svg +1 -0
  423. package/dist/app/server/assets/typebox-Dei93FPO-D_lCVdAz.js +2 -0
  424. package/dist/app/server/assets/typebox-Dei93FPO-D_lCVdAz.js.map +1 -0
  425. package/dist/app/server/assets/useNavigate-D6d1w7KE.js +2 -0
  426. package/dist/app/server/assets/useNavigate-D6d1w7KE.js.map +1 -0
  427. package/dist/app/server/assets/useQuery-BRpCr5vj.js +2 -0
  428. package/dist/app/server/assets/useQuery-BRpCr5vj.js.map +1 -0
  429. package/dist/app/server/assets/useRegisterFieldControl-cJesrOWK.js +2 -0
  430. package/dist/app/server/assets/useRegisterFieldControl-cJesrOWK.js.map +1 -0
  431. package/dist/app/server/assets/utils-C4ZXZIZW.js +2 -0
  432. package/dist/app/server/assets/utils-C4ZXZIZW.js.map +1 -0
  433. package/dist/app/server/assets/utils-D57zfcg-.js +2 -0
  434. package/dist/app/server/assets/utils-D57zfcg-.js.map +1 -0
  435. package/dist/app/server/assets/valibot--1zFm7rT-CIKoH3MS.js +2 -0
  436. package/dist/app/server/assets/valibot--1zFm7rT-CIKoH3MS.js.map +1 -0
  437. package/dist/app/server/assets/valibot-D_HTw1Gn-BdPyLkXt.js +2 -0
  438. package/dist/app/server/assets/valibot-D_HTw1Gn-BdPyLkXt.js.map +1 -0
  439. package/dist/app/server/assets/wYLDS-CaCKDrO-.svg +10 -0
  440. package/dist/app/server/assets/wsrUSD-B2Ey0bDQ.svg +1 -0
  441. package/dist/app/server/assets/zod-Bwrt9trS-BezI5Gi1.js +2 -0
  442. package/dist/app/server/assets/zod-Bwrt9trS-BezI5Gi1.js.map +1 -0
  443. package/dist/app/server/assets/zod-DSgpEGAE-DZ7M_Q33.js +2 -0
  444. package/dist/app/server/assets/zod-DSgpEGAE-DZ7M_Q33.js.map +1 -0
  445. package/dist/app/server/assets/zyzz-6R2K52xP.css +1 -0
  446. package/dist/app/server/assets/zyzz.config-CJRpjn0E.js +3 -0
  447. package/dist/app/server/assets/zyzz.config-CJRpjn0E.js.map +1 -0
  448. package/dist/app/server/index.js +532 -0
  449. package/dist/app/server/index.js.map +1 -0
  450. package/dist/app/server/wrangler.json +1 -0
  451. package/dist/cli/Admin.d.ts +34 -0
  452. package/dist/cli/Admin.d.ts.map +1 -0
  453. package/dist/cli/Admin.js +61 -0
  454. package/dist/cli/Admin.js.map +1 -0
  455. package/dist/cli/Apps.d.ts +9 -0
  456. package/dist/cli/Apps.d.ts.map +1 -0
  457. package/dist/cli/Apps.js +34 -0
  458. package/dist/cli/Apps.js.map +1 -0
  459. package/dist/cli/Cli.d.ts +13 -0
  460. package/dist/cli/Cli.d.ts.map +1 -0
  461. package/dist/cli/Cli.js +26 -0
  462. package/dist/cli/Cli.js.map +1 -0
  463. package/dist/cli/Project.d.ts +17 -0
  464. package/dist/cli/Project.d.ts.map +1 -0
  465. package/dist/cli/Project.js +90 -0
  466. package/dist/cli/Project.js.map +1 -0
  467. package/dist/cli/Realms.d.ts +24 -0
  468. package/dist/cli/Realms.d.ts.map +1 -0
  469. package/dist/cli/Realms.js +48 -0
  470. package/dist/cli/Realms.js.map +1 -0
  471. package/dist/cli/Session.d.ts +79 -0
  472. package/dist/cli/Session.d.ts.map +1 -0
  473. package/dist/cli/Session.js +229 -0
  474. package/dist/cli/Session.js.map +1 -0
  475. package/dist/cli/User.d.ts +24 -0
  476. package/dist/cli/User.d.ts.map +1 -0
  477. package/dist/cli/User.js +34 -0
  478. package/dist/cli/User.js.map +1 -0
  479. package/dist/cli/V1.d.ts +32 -0
  480. package/dist/cli/V1.d.ts.map +1 -0
  481. package/dist/cli/V1.js +38 -0
  482. package/dist/cli/V1.js.map +1 -0
  483. package/dist/cli/bin.d.ts +3 -0
  484. package/dist/cli/bin.d.ts.map +1 -0
  485. package/dist/cli/bin.js +46 -0
  486. package/dist/cli/bin.js.map +1 -0
  487. package/dist/cli/commands/admin/apps/create.d.ts +23 -0
  488. package/dist/cli/commands/admin/apps/create.d.ts.map +1 -0
  489. package/dist/cli/commands/admin/apps/create.js +84 -0
  490. package/dist/cli/commands/admin/apps/create.js.map +1 -0
  491. package/dist/cli/commands/admin/apps/delete.d.ts +15 -0
  492. package/dist/cli/commands/admin/apps/delete.d.ts.map +1 -0
  493. package/dist/cli/commands/admin/apps/delete.js +41 -0
  494. package/dist/cli/commands/admin/apps/delete.js.map +1 -0
  495. package/dist/cli/commands/admin/apps/index.d.ts +5 -0
  496. package/dist/cli/commands/admin/apps/index.d.ts.map +1 -0
  497. package/dist/cli/commands/admin/apps/index.js +14 -0
  498. package/dist/cli/commands/admin/apps/index.js.map +1 -0
  499. package/dist/cli/commands/admin/apps/list.d.ts +10 -0
  500. package/dist/cli/commands/admin/apps/list.d.ts.map +1 -0
  501. package/dist/cli/commands/admin/apps/list.js +26 -0
  502. package/dist/cli/commands/admin/apps/list.js.map +1 -0
  503. package/dist/cli/commands/admin/apps/rotate-secret.d.ts +17 -0
  504. package/dist/cli/commands/admin/apps/rotate-secret.d.ts.map +1 -0
  505. package/dist/cli/commands/admin/apps/rotate-secret.js +47 -0
  506. package/dist/cli/commands/admin/apps/rotate-secret.js.map +1 -0
  507. package/dist/cli/commands/admin/apps/update.d.ts +20 -0
  508. package/dist/cli/commands/admin/apps/update.d.ts.map +1 -0
  509. package/dist/cli/commands/admin/apps/update.js +71 -0
  510. package/dist/cli/commands/admin/apps/update.js.map +1 -0
  511. package/dist/cli/commands/admin/index.d.ts +5 -0
  512. package/dist/cli/commands/admin/index.d.ts.map +1 -0
  513. package/dist/cli/commands/admin/index.js +13 -0
  514. package/dist/cli/commands/admin/index.js.map +1 -0
  515. package/dist/cli/commands/admin/migrate.d.ts +10 -0
  516. package/dist/cli/commands/admin/migrate.d.ts.map +1 -0
  517. package/dist/cli/commands/admin/migrate.js +20 -0
  518. package/dist/cli/commands/admin/migrate.js.map +1 -0
  519. package/dist/cli/commands/admin/realms/add.d.ts +13 -0
  520. package/dist/cli/commands/admin/realms/add.d.ts.map +1 -0
  521. package/dist/cli/commands/admin/realms/add.js +42 -0
  522. package/dist/cli/commands/admin/realms/add.js.map +1 -0
  523. package/dist/cli/commands/admin/realms/index.d.ts +5 -0
  524. package/dist/cli/commands/admin/realms/index.d.ts.map +1 -0
  525. package/dist/cli/commands/admin/realms/index.js +13 -0
  526. package/dist/cli/commands/admin/realms/index.js.map +1 -0
  527. package/dist/cli/commands/admin/realms/list.d.ts +14 -0
  528. package/dist/cli/commands/admin/realms/list.d.ts.map +1 -0
  529. package/dist/cli/commands/admin/realms/list.js +36 -0
  530. package/dist/cli/commands/admin/realms/list.js.map +1 -0
  531. package/dist/cli/commands/admin/realms/passkeys/index.d.ts +5 -0
  532. package/dist/cli/commands/admin/realms/passkeys/index.d.ts.map +1 -0
  533. package/dist/cli/commands/admin/realms/passkeys/index.js +13 -0
  534. package/dist/cli/commands/admin/realms/passkeys/index.js.map +1 -0
  535. package/dist/cli/commands/admin/realms/passkeys/set.d.ts +17 -0
  536. package/dist/cli/commands/admin/realms/passkeys/set.d.ts.map +1 -0
  537. package/dist/cli/commands/admin/realms/passkeys/set.js +46 -0
  538. package/dist/cli/commands/admin/realms/passkeys/set.js.map +1 -0
  539. package/dist/cli/commands/admin/realms/privy/index.d.ts +5 -0
  540. package/dist/cli/commands/admin/realms/privy/index.d.ts.map +1 -0
  541. package/dist/cli/commands/admin/realms/privy/index.js +13 -0
  542. package/dist/cli/commands/admin/realms/privy/index.js.map +1 -0
  543. package/dist/cli/commands/admin/realms/privy/set.d.ts +19 -0
  544. package/dist/cli/commands/admin/realms/privy/set.d.ts.map +1 -0
  545. package/dist/cli/commands/admin/realms/privy/set.js +66 -0
  546. package/dist/cli/commands/admin/realms/privy/set.js.map +1 -0
  547. package/dist/cli/commands/admin/realms/remove.d.ts +12 -0
  548. package/dist/cli/commands/admin/realms/remove.d.ts.map +1 -0
  549. package/dist/cli/commands/admin/realms/remove.js +35 -0
  550. package/dist/cli/commands/admin/realms/remove.js.map +1 -0
  551. package/dist/cli/commands/admin/realms/secp256k1/disable.d.ts +16 -0
  552. package/dist/cli/commands/admin/realms/secp256k1/disable.d.ts.map +1 -0
  553. package/dist/cli/commands/admin/realms/secp256k1/disable.js +42 -0
  554. package/dist/cli/commands/admin/realms/secp256k1/disable.js.map +1 -0
  555. package/dist/cli/commands/admin/realms/secp256k1/enable.d.ts +16 -0
  556. package/dist/cli/commands/admin/realms/secp256k1/enable.d.ts.map +1 -0
  557. package/dist/cli/commands/admin/realms/secp256k1/enable.js +42 -0
  558. package/dist/cli/commands/admin/realms/secp256k1/enable.js.map +1 -0
  559. package/dist/cli/commands/admin/realms/secp256k1/index.d.ts +9 -0
  560. package/dist/cli/commands/admin/realms/secp256k1/index.d.ts.map +1 -0
  561. package/dist/cli/commands/admin/realms/secp256k1/index.js +17 -0
  562. package/dist/cli/commands/admin/realms/secp256k1/index.js.map +1 -0
  563. package/dist/cli/commands/admin/realms/set.d.ts +17 -0
  564. package/dist/cli/commands/admin/realms/set.d.ts.map +1 -0
  565. package/dist/cli/commands/admin/realms/set.js +46 -0
  566. package/dist/cli/commands/admin/realms/set.js.map +1 -0
  567. package/dist/cli/commands/admin/rotate-key.d.ts +16 -0
  568. package/dist/cli/commands/admin/rotate-key.d.ts.map +1 -0
  569. package/dist/cli/commands/admin/rotate-key.js +46 -0
  570. package/dist/cli/commands/admin/rotate-key.js.map +1 -0
  571. package/dist/cli/commands/init.d.ts +11 -0
  572. package/dist/cli/commands/init.d.ts.map +1 -0
  573. package/dist/cli/commands/init.js +34 -0
  574. package/dist/cli/commands/init.js.map +1 -0
  575. package/dist/cli/commands/login.d.ts +12 -0
  576. package/dist/cli/commands/login.d.ts.map +1 -0
  577. package/dist/cli/commands/login.js +29 -0
  578. package/dist/cli/commands/login.js.map +1 -0
  579. package/dist/cli/commands/logout.d.ts +8 -0
  580. package/dist/cli/commands/logout.d.ts.map +1 -0
  581. package/dist/cli/commands/logout.js +19 -0
  582. package/dist/cli/commands/logout.js.map +1 -0
  583. package/dist/cli/commands/whoami.d.ts +12 -0
  584. package/dist/cli/commands/whoami.d.ts.map +1 -0
  585. package/dist/cli/commands/whoami.js +24 -0
  586. package/dist/cli/commands/whoami.js.map +1 -0
  587. package/dist/client/Actions.d.ts +108 -0
  588. package/dist/client/Actions.d.ts.map +1 -0
  589. package/dist/client/Actions.js +94 -0
  590. package/dist/client/Actions.js.map +1 -0
  591. package/dist/client/Auth.d.ts +143 -0
  592. package/dist/client/Auth.d.ts.map +1 -0
  593. package/dist/client/Auth.js +106 -0
  594. package/dist/client/Auth.js.map +1 -0
  595. package/dist/client/Authorization.d.ts +29 -0
  596. package/dist/client/Authorization.d.ts.map +1 -0
  597. package/dist/client/Authorization.js +12 -0
  598. package/dist/client/Authorization.js.map +1 -0
  599. package/dist/client/Decorator.d.ts +172 -0
  600. package/dist/client/Decorator.d.ts.map +1 -0
  601. package/dist/client/Decorator.js +241 -0
  602. package/dist/client/Decorator.js.map +1 -0
  603. package/dist/client/Key.d.ts +82 -0
  604. package/dist/client/Key.d.ts.map +1 -0
  605. package/dist/client/Key.js +81 -0
  606. package/dist/client/Key.js.map +1 -0
  607. package/dist/client/Pending.d.ts +38 -0
  608. package/dist/client/Pending.d.ts.map +1 -0
  609. package/dist/client/Pending.js +12 -0
  610. package/dist/client/Pending.js.map +1 -0
  611. package/dist/client/Permissions.d.ts +36 -0
  612. package/dist/client/Permissions.d.ts.map +1 -0
  613. package/dist/client/Permissions.js +16 -0
  614. package/dist/client/Permissions.js.map +1 -0
  615. package/dist/client/Storage.d.ts +27 -0
  616. package/dist/client/Storage.d.ts.map +1 -0
  617. package/dist/client/Storage.js +16 -0
  618. package/dist/client/Storage.js.map +1 -0
  619. package/dist/client/TempoAccount.d.ts +52 -0
  620. package/dist/client/TempoAccount.d.ts.map +1 -0
  621. package/dist/client/TempoAccount.js +17 -0
  622. package/dist/client/TempoAccount.js.map +1 -0
  623. package/dist/client/Tokens.d.ts +25 -0
  624. package/dist/client/Tokens.d.ts.map +1 -0
  625. package/dist/client/Tokens.js +12 -0
  626. package/dist/client/Tokens.js.map +1 -0
  627. package/dist/client/User.d.ts +21 -0
  628. package/dist/client/User.d.ts.map +1 -0
  629. package/dist/client/User.js +12 -0
  630. package/dist/client/User.js.map +1 -0
  631. package/dist/client/actions/account.d.ts +75 -0
  632. package/dist/client/actions/account.d.ts.map +1 -0
  633. package/dist/client/actions/account.js +102 -0
  634. package/dist/client/actions/account.js.map +1 -0
  635. package/dist/client/actions/device.d.ts +52 -0
  636. package/dist/client/actions/device.d.ts.map +1 -0
  637. package/dist/client/actions/device.js +103 -0
  638. package/dist/client/actions/device.js.map +1 -0
  639. package/dist/client/actions/email.d.ts +89 -0
  640. package/dist/client/actions/email.d.ts.map +1 -0
  641. package/dist/client/actions/email.js +86 -0
  642. package/dist/client/actions/email.js.map +1 -0
  643. package/dist/client/actions/oauth.d.ts +112 -0
  644. package/dist/client/actions/oauth.d.ts.map +1 -0
  645. package/dist/client/actions/oauth.js +103 -0
  646. package/dist/client/actions/oauth.js.map +1 -0
  647. package/dist/client/actions/passkey.d.ts +140 -0
  648. package/dist/client/actions/passkey.d.ts.map +1 -0
  649. package/dist/client/actions/passkey.js +170 -0
  650. package/dist/client/actions/passkey.js.map +1 -0
  651. package/dist/client/actions/realm.d.ts +25 -0
  652. package/dist/client/actions/realm.d.ts.map +1 -0
  653. package/dist/client/actions/realm.js +16 -0
  654. package/dist/client/actions/realm.js.map +1 -0
  655. package/dist/client/actions/redirect.d.ts +152 -0
  656. package/dist/client/actions/redirect.d.ts.map +1 -0
  657. package/dist/client/actions/redirect.js +311 -0
  658. package/dist/client/actions/redirect.js.map +1 -0
  659. package/dist/client/internal/accessKey.d.ts +21 -0
  660. package/dist/client/internal/accessKey.d.ts.map +1 -0
  661. package/dist/client/internal/accessKey.js +38 -0
  662. package/dist/client/internal/accessKey.js.map +1 -0
  663. package/dist/client/internal/account.d.ts +17 -0
  664. package/dist/client/internal/account.d.ts.map +1 -0
  665. package/dist/client/internal/account.js +3 -0
  666. package/dist/client/internal/account.js.map +1 -0
  667. package/dist/client/internal/api.d.ts +110 -0
  668. package/dist/client/internal/api.d.ts.map +1 -0
  669. package/dist/client/internal/api.js +136 -0
  670. package/dist/client/internal/api.js.map +1 -0
  671. package/dist/client/internal/headless.d.ts +159 -0
  672. package/dist/client/internal/headless.d.ts.map +1 -0
  673. package/dist/client/internal/headless.js +196 -0
  674. package/dist/client/internal/headless.js.map +1 -0
  675. package/dist/client/internal/indexedDb.d.ts +8 -0
  676. package/dist/client/internal/indexedDb.d.ts.map +1 -0
  677. package/dist/client/internal/indexedDb.js +32 -0
  678. package/dist/client/internal/indexedDb.js.map +1 -0
  679. package/dist/client/internal/request.d.ts +56 -0
  680. package/dist/client/internal/request.d.ts.map +1 -0
  681. package/dist/client/internal/request.js +44 -0
  682. package/dist/client/internal/request.js.map +1 -0
  683. package/dist/client/internal/store.d.ts +12 -0
  684. package/dist/client/internal/store.d.ts.map +1 -0
  685. package/dist/client/internal/store.js +15 -0
  686. package/dist/client/internal/store.js.map +1 -0
  687. package/dist/client/internal/verifier.d.ts +25 -0
  688. package/dist/client/internal/verifier.d.ts.map +1 -0
  689. package/dist/client/internal/verifier.js +52 -0
  690. package/dist/client/internal/verifier.js.map +1 -0
  691. package/dist/client.d.ts +18 -0
  692. package/dist/client.d.ts.map +1 -0
  693. package/dist/client.js +18 -0
  694. package/dist/client.js.map +1 -0
  695. package/dist/index.d.ts +6 -0
  696. package/dist/index.d.ts.map +1 -0
  697. package/dist/index.js +6 -0
  698. package/dist/index.js.map +1 -0
  699. package/dist/internal/Apps.d.ts +3169 -0
  700. package/dist/internal/Apps.d.ts.map +1 -0
  701. package/dist/internal/Apps.js +948 -0
  702. package/dist/internal/Apps.js.map +1 -0
  703. package/dist/internal/Auth.d.ts +4287 -0
  704. package/dist/internal/Auth.d.ts.map +1 -0
  705. package/dist/internal/Auth.js +185 -0
  706. package/dist/internal/Auth.js.map +1 -0
  707. package/dist/internal/Authorize.d.ts +526 -0
  708. package/dist/internal/Authorize.d.ts.map +1 -0
  709. package/dist/internal/Authorize.js +330 -0
  710. package/dist/internal/Authorize.js.map +1 -0
  711. package/dist/internal/Cache.d.ts +56 -0
  712. package/dist/internal/Cache.d.ts.map +1 -0
  713. package/dist/internal/Cache.js +65 -0
  714. package/dist/internal/Cache.js.map +1 -0
  715. package/dist/internal/Chain.d.ts +738 -0
  716. package/dist/internal/Chain.d.ts.map +1 -0
  717. package/dist/internal/Chain.js +65 -0
  718. package/dist/internal/Chain.js.map +1 -0
  719. package/dist/internal/ChainList.d.ts +117 -0
  720. package/dist/internal/ChainList.d.ts.map +1 -0
  721. package/dist/internal/ChainList.js +148 -0
  722. package/dist/internal/ChainList.js.map +1 -0
  723. package/dist/internal/ChainName.d.ts +11 -0
  724. package/dist/internal/ChainName.d.ts.map +1 -0
  725. package/dist/internal/ChainName.js +13 -0
  726. package/dist/internal/ChainName.js.map +1 -0
  727. package/dist/internal/CodeEmail.d.ts +38 -0
  728. package/dist/internal/CodeEmail.d.ts.map +1 -0
  729. package/dist/internal/CodeEmail.js +85 -0
  730. package/dist/internal/CodeEmail.js.map +1 -0
  731. package/dist/internal/ConfigurableAccount.d.ts +600 -0
  732. package/dist/internal/ConfigurableAccount.d.ts.map +1 -0
  733. package/dist/internal/ConfigurableAccount.js +795 -0
  734. package/dist/internal/ConfigurableAccount.js.map +1 -0
  735. package/dist/internal/Device.d.ts +246 -0
  736. package/dist/internal/Device.d.ts.map +1 -0
  737. package/dist/internal/Device.js +257 -0
  738. package/dist/internal/Device.js.map +1 -0
  739. package/dist/internal/Env.d.ts +97 -0
  740. package/dist/internal/Env.d.ts.map +1 -0
  741. package/dist/internal/Env.js +2 -0
  742. package/dist/internal/Env.js.map +1 -0
  743. package/dist/internal/ErrorResponse.d.ts +608 -0
  744. package/dist/internal/ErrorResponse.d.ts.map +1 -0
  745. package/dist/internal/ErrorResponse.js +701 -0
  746. package/dist/internal/ErrorResponse.js.map +1 -0
  747. package/dist/internal/Id.d.ts +10 -0
  748. package/dist/internal/Id.d.ts.map +1 -0
  749. package/dist/internal/Id.js +34 -0
  750. package/dist/internal/Id.js.map +1 -0
  751. package/dist/internal/KeyAuthorization.d.ts +1650 -0
  752. package/dist/internal/KeyAuthorization.d.ts.map +1 -0
  753. package/dist/internal/KeyAuthorization.js +1187 -0
  754. package/dist/internal/KeyAuthorization.js.map +1 -0
  755. package/dist/internal/Limits.d.ts +70 -0
  756. package/dist/internal/Limits.d.ts.map +1 -0
  757. package/dist/internal/Limits.js +36 -0
  758. package/dist/internal/Limits.js.map +1 -0
  759. package/dist/internal/Log.d.ts +34 -0
  760. package/dist/internal/Log.d.ts.map +1 -0
  761. package/dist/internal/Log.js +99 -0
  762. package/dist/internal/Log.js.map +1 -0
  763. package/dist/internal/LogLine.d.ts +29 -0
  764. package/dist/internal/LogLine.d.ts.map +1 -0
  765. package/dist/internal/LogLine.js +50 -0
  766. package/dist/internal/LogLine.js.map +1 -0
  767. package/dist/internal/Migrations.d.ts +28 -0
  768. package/dist/internal/Migrations.d.ts.map +1 -0
  769. package/dist/internal/Migrations.js +82 -0
  770. package/dist/internal/Migrations.js.map +1 -0
  771. package/dist/internal/Owner.d.ts +230 -0
  772. package/dist/internal/Owner.d.ts.map +1 -0
  773. package/dist/internal/Owner.js +101 -0
  774. package/dist/internal/Owner.js.map +1 -0
  775. package/dist/internal/Passkey.d.ts +901 -0
  776. package/dist/internal/Passkey.d.ts.map +1 -0
  777. package/dist/internal/Passkey.js +1185 -0
  778. package/dist/internal/Passkey.js.map +1 -0
  779. package/dist/internal/PendingKey.d.ts +49 -0
  780. package/dist/internal/PendingKey.d.ts.map +1 -0
  781. package/dist/internal/PendingKey.js +58 -0
  782. package/dist/internal/PendingKey.js.map +1 -0
  783. package/dist/internal/Privy.d.ts +138 -0
  784. package/dist/internal/Privy.d.ts.map +1 -0
  785. package/dist/internal/Privy.js +285 -0
  786. package/dist/internal/Privy.js.map +1 -0
  787. package/dist/internal/RateLimit.d.ts +218 -0
  788. package/dist/internal/RateLimit.d.ts.map +1 -0
  789. package/dist/internal/RateLimit.js +209 -0
  790. package/dist/internal/RateLimit.js.map +1 -0
  791. package/dist/internal/Realm.d.ts +290 -0
  792. package/dist/internal/Realm.d.ts.map +1 -0
  793. package/dist/internal/Realm.js +502 -0
  794. package/dist/internal/Realm.js.map +1 -0
  795. package/dist/internal/RequestId.d.ts +16 -0
  796. package/dist/internal/RequestId.d.ts.map +1 -0
  797. package/dist/internal/RequestId.js +78 -0
  798. package/dist/internal/RequestId.js.map +1 -0
  799. package/dist/internal/SigningKey.d.ts +126 -0
  800. package/dist/internal/SigningKey.d.ts.map +1 -0
  801. package/dist/internal/SigningKey.js +221 -0
  802. package/dist/internal/SigningKey.js.map +1 -0
  803. package/dist/internal/TempoAccount.d.ts +181 -0
  804. package/dist/internal/TempoAccount.d.ts.map +1 -0
  805. package/dist/internal/TempoAccount.js +369 -0
  806. package/dist/internal/TempoAccount.js.map +1 -0
  807. package/dist/internal/TestInbox.d.ts +42 -0
  808. package/dist/internal/TestInbox.d.ts.map +1 -0
  809. package/dist/internal/TestInbox.js +20 -0
  810. package/dist/internal/TestInbox.js.map +1 -0
  811. package/dist/internal/Timing.d.ts +52 -0
  812. package/dist/internal/Timing.d.ts.map +1 -0
  813. package/dist/internal/Timing.js +116 -0
  814. package/dist/internal/Timing.js.map +1 -0
  815. package/dist/internal/Validation.d.ts +52 -0
  816. package/dist/internal/Validation.d.ts.map +1 -0
  817. package/dist/internal/Validation.js +22 -0
  818. package/dist/internal/Validation.js.map +1 -0
  819. package/dist/internal/Verification.d.ts +24 -0
  820. package/dist/internal/Verification.d.ts.map +1 -0
  821. package/dist/internal/Verification.js +37 -0
  822. package/dist/internal/Verification.js.map +1 -0
  823. package/dist/internal/Wallet.d.ts +66 -0
  824. package/dist/internal/Wallet.d.ts.map +1 -0
  825. package/dist/internal/Wallet.js +59 -0
  826. package/dist/internal/Wallet.js.map +1 -0
  827. package/dist/internal/owners/Passkey.d.ts +9 -0
  828. package/dist/internal/owners/Passkey.d.ts.map +1 -0
  829. package/dist/internal/owners/Passkey.js +58 -0
  830. package/dist/internal/owners/Passkey.js.map +1 -0
  831. package/dist/internal/owners/Privy.d.ts +13 -0
  832. package/dist/internal/owners/Privy.d.ts.map +1 -0
  833. package/dist/internal/owners/Privy.js +59 -0
  834. package/dist/internal/owners/Privy.js.map +1 -0
  835. package/dist/internal/owners/Secp256k1.d.ts +12 -0
  836. package/dist/internal/owners/Secp256k1.d.ts.map +1 -0
  837. package/dist/internal/owners/Secp256k1.js +99 -0
  838. package/dist/internal/owners/Secp256k1.js.map +1 -0
  839. package/dist/worker.d.ts +18 -0
  840. package/dist/worker.d.ts.map +1 -0
  841. package/dist/worker.js +18 -0
  842. package/dist/worker.js.map +1 -0
  843. package/package.json +83 -3
  844. package/src/Api.ts +157 -0
  845. package/src/App.ts +316 -0
  846. package/src/api/account.ts +2266 -0
  847. package/src/api/authenticate.ts +1662 -0
  848. package/src/api/authorize.ts +1086 -0
  849. package/src/api/device.ts +516 -0
  850. package/src/api/health.ts +72 -0
  851. package/src/api/lib/AccountStep.ts +485 -0
  852. package/src/api/lib/Auth.ts +164 -0
  853. package/src/api/lib/Configure.ts +921 -0
  854. package/src/api/lib/Consent.ts +388 -0
  855. package/src/api/lib/Cors.ts +160 -0
  856. package/src/api/lib/Database.ts +10 -0
  857. package/src/api/lib/DeviceRequest.ts +244 -0
  858. package/src/api/lib/FirstAccount.ts +136 -0
  859. package/src/api/lib/Headless.ts +616 -0
  860. package/src/api/lib/IsolateCache.ts +28 -0
  861. package/src/api/lib/KeySigner.ts +690 -0
  862. package/src/api/lib/PasskeyLink.ts +162 -0
  863. package/src/api/lib/Session.ts +64 -0
  864. package/src/api/lib/SignInConsent.ts +393 -0
  865. package/src/api/oauth.ts +1796 -0
  866. package/src/app/components/CodeInput.tsx +153 -0
  867. package/src/app/components/DevTools.tsx +1071 -0
  868. package/src/app/components/Grant.tsx +476 -0
  869. package/src/app/components/icons/BRLA.png +0 -0
  870. package/src/app/components/icons/BRZ.svg +1 -0
  871. package/src/app/components/icons/CHFAU.png +0 -0
  872. package/src/app/components/icons/DLUSD.png +0 -0
  873. package/src/app/components/icons/EURAU.svg +1 -0
  874. package/src/app/components/icons/EURC.e.svg +1 -0
  875. package/src/app/components/icons/GBPA.svg +4 -0
  876. package/src/app/components/icons/GUSD.svg +1 -0
  877. package/src/app/components/icons/MACH.svg +4 -0
  878. package/src/app/components/icons/OUSD.svg +5 -0
  879. package/src/app/components/icons/PRIME.svg +14 -0
  880. package/src/app/components/icons/SBC.svg +1 -0
  881. package/src/app/components/icons/SEKAU.svg +5 -0
  882. package/src/app/components/icons/USD1.svg +30 -0
  883. package/src/app/components/icons/USDB.svg +11 -0
  884. package/src/app/components/icons/USDC.e.svg +1 -0
  885. package/src/app/components/icons/USDT0.svg +1 -0
  886. package/src/app/components/icons/USDY.svg +16 -0
  887. package/src/app/components/icons/USDe.svg +1 -0
  888. package/src/app/components/icons/YLDS.svg +3 -0
  889. package/src/app/components/icons/alphaUSD.svg +1 -0
  890. package/src/app/components/icons/betaUSD.svg +1 -0
  891. package/src/app/components/icons/cUSD.svg +1 -0
  892. package/src/app/components/icons/cbBTC.svg +1 -0
  893. package/src/app/components/icons/frxUSD.svg +1 -0
  894. package/src/app/components/icons/goUSD.svg +5 -0
  895. package/src/app/components/icons/iUSD.svg +1 -0
  896. package/src/app/components/icons/pathUSD.svg +25 -0
  897. package/src/app/components/icons/rUSD.svg +1 -0
  898. package/src/app/components/icons/reUSD.svg +1 -0
  899. package/src/app/components/icons/sUSDe.svg +1 -0
  900. package/src/app/components/icons/siUSD.svg +1 -0
  901. package/src/app/components/icons/stcUSD.svg +1 -0
  902. package/src/app/components/icons/syrupUSDC.svg +5 -0
  903. package/src/app/components/icons/thetaUSD.svg +1 -0
  904. package/src/app/components/icons/wYLDS.svg +10 -0
  905. package/src/app/components/icons/wsrUSD.svg +1 -0
  906. package/src/app/components/logos/OUSD.dark.svg +17 -0
  907. package/src/app/components/logos/OUSD.light.svg +17 -0
  908. package/src/app/coverage.server.ts +73 -0
  909. package/src/app/coverage.ts +69 -0
  910. package/src/app/crons/cleanup.ts +104 -0
  911. package/src/app/db/auth.ts +440 -0
  912. package/src/app/db/migrations/0000_better_auth.sql +53 -0
  913. package/src/app/db/migrations/0001_oauth_provider.sql +162 -0
  914. package/src/app/db/migrations/0002_device_code.sql +17 -0
  915. package/src/app/db/migrations/0003_realms.sql +27 -0
  916. package/src/app/db/migrations/0004_default_realm.sql +2 -0
  917. package/src/app/db/migrations/0005_passkeys.sql +30 -0
  918. package/src/app/db/migrations/0006_first_accounts.sql +9 -0
  919. package/src/app/db/migrations/0007_pending_keys.sql +13 -0
  920. package/src/app/db/migrations/0008_secp256k1_owners.sql +18 -0
  921. package/src/app/db/migrations/0009_device_requests.sql +8 -0
  922. package/src/app/db/migrations/0010_device_keys.sql +4 -0
  923. package/src/app/db/migrations/0011_registered_passkeys.sql +2 -0
  924. package/src/app/db/migrations/0012_passkey_accounts.sql +7 -0
  925. package/src/app/db/migrations/0013_first_party_apps.sql +4 -0
  926. package/src/app/db/migrations/0014_logout_revokes_tokens.sql +17 -0
  927. package/src/app/db/migrations/0015_expiry_indexes.sql +9 -0
  928. package/src/app/db/migrations/0016_configurable_accounts.sql +15 -0
  929. package/src/app/db/migrations/0017_account_config_keys.sql +3 -0
  930. package/src/app/db/migrations/0018_better_auth_1_8.sql +9 -0
  931. package/src/app/db/migrations/0019_drop_provider_account_index.sql +1 -0
  932. package/src/app/db/migrations/meta/0000_snapshot.json +362 -0
  933. package/src/app/db/migrations/meta/0001_snapshot.json +1487 -0
  934. package/src/app/db/migrations/meta/0002_snapshot.json +1603 -0
  935. package/src/app/db/migrations/meta/0003_snapshot.json +1760 -0
  936. package/src/app/db/migrations/meta/0004_snapshot.json +1760 -0
  937. package/src/app/db/migrations/meta/0005_snapshot.json +1911 -0
  938. package/src/app/db/migrations/meta/0006_snapshot.json +1967 -0
  939. package/src/app/db/migrations/meta/0007_snapshot.json +2047 -0
  940. package/src/app/db/migrations/meta/0008_snapshot.json +2157 -0
  941. package/src/app/db/migrations/meta/0009_snapshot.json +2207 -0
  942. package/src/app/db/migrations/meta/0010_snapshot.json +2231 -0
  943. package/src/app/db/migrations/meta/0011_snapshot.json +2231 -0
  944. package/src/app/db/migrations/meta/0012_snapshot.json +2231 -0
  945. package/src/app/db/migrations/meta/0013_snapshot.json +2231 -0
  946. package/src/app/db/migrations/meta/0014_snapshot.json +2231 -0
  947. package/src/app/db/migrations/meta/0015_snapshot.json +2375 -0
  948. package/src/app/db/migrations/meta/0016_snapshot.json +2475 -0
  949. package/src/app/db/migrations/meta/0017_snapshot.json +2481 -0
  950. package/src/app/db/migrations/meta/0018_snapshot.json +2535 -0
  951. package/src/app/db/migrations/meta/0019_snapshot.json +2514 -0
  952. package/src/app/db/migrations/meta/_journal.json +146 -0
  953. package/src/app/db/schema.ts +241 -0
  954. package/src/app/db/table.ts +31 -0
  955. package/src/app/env.ts +57 -0
  956. package/src/app/inbox.ts +190 -0
  957. package/src/app/lib/Client.ts +82 -0
  958. package/src/app/lib/Inbox.ts +11 -0
  959. package/src/app/lib/Loader.ts +21 -0
  960. package/src/app/lib/Upgrade.ts +221 -0
  961. package/src/app/package.json +8 -0
  962. package/src/app/public/_headers +4 -0
  963. package/src/app/routeTree.gen.ts +219 -0
  964. package/src/app/router.tsx +47 -0
  965. package/src/app/routes/[_].flows.tsx +4254 -0
  966. package/src/app/routes/__root.tsx +172 -0
  967. package/src/app/routes/authorize.tsx +379 -0
  968. package/src/app/routes/choose-account.tsx +144 -0
  969. package/src/app/routes/deposit.tsx +107 -0
  970. package/src/app/routes/device.tsx +273 -0
  971. package/src/app/routes/error.tsx +62 -0
  972. package/src/app/routes/index.tsx +511 -0
  973. package/src/app/routes/login.tsx +577 -0
  974. package/src/app/screens/Account.tsx +559 -0
  975. package/src/app/screens/Approval.tsx +444 -0
  976. package/src/app/screens/ChooseAccount.tsx +206 -0
  977. package/src/app/screens/Deposit.tsx +523 -0
  978. package/src/app/screens/DeviceApproval.tsx +500 -0
  979. package/src/app/screens/NotFound.tsx +62 -0
  980. package/src/app/screens/SignIn.tsx +372 -0
  981. package/src/app/screens/WalletUpgrade.tsx +121 -0
  982. package/src/app/screens/chains/base.svg +3 -0
  983. package/src/app/screens/chains/ethereum.svg +11 -0
  984. package/src/app/screens/chains/solana.svg +4 -0
  985. package/src/app/screens/chains/tempo.svg +4 -0
  986. package/src/app/server.ts +342 -0
  987. package/src/app/vite.config.ts +128 -0
  988. package/src/app/void.config.ts +36 -0
  989. package/src/app/wallet.ts +69 -0
  990. package/src/app/zyzz.config.ts +52 -0
  991. package/src/cli/Admin.ts +74 -0
  992. package/src/cli/Apps.ts +27 -0
  993. package/src/cli/Cli.ts +41 -0
  994. package/src/cli/Project.ts +119 -0
  995. package/src/cli/Realms.ts +49 -0
  996. package/src/cli/Session.ts +290 -0
  997. package/src/cli/User.ts +40 -0
  998. package/src/cli/V1.ts +54 -0
  999. package/src/cli/bin.ts +44 -0
  1000. package/src/cli/commands/admin/apps/create.ts +96 -0
  1001. package/src/cli/commands/admin/apps/delete.ts +38 -0
  1002. package/src/cli/commands/admin/apps/index.ts +15 -0
  1003. package/src/cli/commands/admin/apps/list.ts +25 -0
  1004. package/src/cli/commands/admin/apps/rotate-secret.ts +47 -0
  1005. package/src/cli/commands/admin/apps/update.ts +79 -0
  1006. package/src/cli/commands/admin/index.ts +14 -0
  1007. package/src/cli/commands/admin/migrate.ts +19 -0
  1008. package/src/cli/commands/admin/realms/add.ts +40 -0
  1009. package/src/cli/commands/admin/realms/index.ts +14 -0
  1010. package/src/cli/commands/admin/realms/list.ts +38 -0
  1011. package/src/cli/commands/admin/realms/passkeys/index.ts +15 -0
  1012. package/src/cli/commands/admin/realms/passkeys/set.ts +44 -0
  1013. package/src/cli/commands/admin/realms/privy/index.ts +14 -0
  1014. package/src/cli/commands/admin/realms/privy/set.ts +69 -0
  1015. package/src/cli/commands/admin/realms/remove.ts +33 -0
  1016. package/src/cli/commands/admin/realms/secp256k1/disable.ts +40 -0
  1017. package/src/cli/commands/admin/realms/secp256k1/enable.ts +40 -0
  1018. package/src/cli/commands/admin/realms/secp256k1/index.ts +19 -0
  1019. package/src/cli/commands/admin/realms/set.ts +46 -0
  1020. package/src/cli/commands/admin/rotate-key.ts +47 -0
  1021. package/src/cli/commands/init.ts +42 -0
  1022. package/src/cli/commands/login.ts +32 -0
  1023. package/src/cli/commands/logout.ts +19 -0
  1024. package/src/cli/commands/whoami.ts +23 -0
  1025. package/src/client/Actions.ts +180 -0
  1026. package/src/client/Auth.ts +267 -0
  1027. package/src/client/Authorization.ts +34 -0
  1028. package/src/client/Decorator.ts +444 -0
  1029. package/src/client/Key.ts +137 -0
  1030. package/src/client/Pending.ts +45 -0
  1031. package/src/client/Permissions.ts +41 -0
  1032. package/src/client/Storage.ts +29 -0
  1033. package/src/client/TempoAccount.ts +55 -0
  1034. package/src/client/Tokens.ts +27 -0
  1035. package/src/client/User.ts +23 -0
  1036. package/src/client/actions/account.ts +171 -0
  1037. package/src/client/actions/device.ts +166 -0
  1038. package/src/client/actions/email.ts +164 -0
  1039. package/src/client/actions/oauth.ts +179 -0
  1040. package/src/client/actions/passkey.ts +333 -0
  1041. package/src/client/actions/realm.ts +37 -0
  1042. package/src/client/actions/redirect.ts +502 -0
  1043. package/src/client/internal/accessKey.ts +54 -0
  1044. package/src/client/internal/account.ts +18 -0
  1045. package/src/client/internal/api.ts +242 -0
  1046. package/src/client/internal/headless.ts +308 -0
  1047. package/src/client/internal/indexedDb.ts +44 -0
  1048. package/src/client/internal/request.ts +70 -0
  1049. package/src/client/internal/store.ts +20 -0
  1050. package/src/client/internal/verifier.ts +75 -0
  1051. package/src/client.ts +17 -0
  1052. package/src/index.ts +5 -0
  1053. package/src/internal/Apps.ts +1283 -0
  1054. package/src/internal/Auth.ts +273 -0
  1055. package/src/internal/Authorize.ts +433 -0
  1056. package/src/internal/Balance.ts +144 -0
  1057. package/src/internal/BodyLimit.ts +31 -0
  1058. package/src/internal/Cache.ts +119 -0
  1059. package/src/internal/Chain.ts +99 -0
  1060. package/src/internal/ChainList.ts +270 -0
  1061. package/src/internal/ChainName.ts +14 -0
  1062. package/src/internal/ChainStatus.ts +65 -0
  1063. package/src/internal/CodeEmail.ts +138 -0
  1064. package/src/internal/ConfigurableAccount.ts +1315 -0
  1065. package/src/internal/Device.ts +471 -0
  1066. package/src/internal/Env.ts +92 -0
  1067. package/src/internal/ErrorResponse.ts +896 -0
  1068. package/src/internal/Faucet.ts +43 -0
  1069. package/src/internal/Id.ts +41 -0
  1070. package/src/internal/KeyAuthorization.ts +1536 -0
  1071. package/src/internal/Limits.ts +40 -0
  1072. package/src/internal/Log.ts +166 -0
  1073. package/src/internal/LogLine.ts +81 -0
  1074. package/src/internal/Logout.ts +356 -0
  1075. package/src/internal/Migrations.ts +120 -0
  1076. package/src/internal/OpenApi.ts +300 -0
  1077. package/src/internal/Owner.ts +310 -0
  1078. package/src/internal/Passkey.ts +1904 -0
  1079. package/src/internal/PendingKey.ts +104 -0
  1080. package/src/internal/Privy.ts +536 -0
  1081. package/src/internal/RateLimit.ts +346 -0
  1082. package/src/internal/Realm.ts +814 -0
  1083. package/src/internal/RequestId.ts +118 -0
  1084. package/src/internal/SignInGrant.ts +175 -0
  1085. package/src/internal/SigningKey.ts +319 -0
  1086. package/src/internal/TempoAccount.ts +545 -0
  1087. package/src/internal/TestInbox.ts +51 -0
  1088. package/src/internal/Timing.ts +172 -0
  1089. package/src/internal/Validation.ts +52 -0
  1090. package/src/internal/Verification.ts +58 -0
  1091. package/src/internal/Wallet.ts +101 -0
  1092. package/src/internal/owners/Passkey.ts +76 -0
  1093. package/src/internal/owners/Privy.ts +82 -0
  1094. package/src/internal/owners/Secp256k1.ts +139 -0
  1095. package/src/types/app.d.ts +39 -0
  1096. package/src/worker.ts +17 -0
@@ -0,0 +1,2266 @@
1
+ /**
2
+ * The signed-in user's Tempo Accounts, the creation of the first one, the registration of a passkey
3
+ * that owns another, and the realms an app reaches, under `/v1/account` and `/v1/realms`. The
4
+ * chains, their status, and the faucet that only Tempo ID's own pages call are under `/i`.
5
+ * @module
6
+ */
7
+ import { type Context, Hono } from 'hono'
8
+ import { Address, PublicKey } from 'ox'
9
+ import {
10
+ KeyAuthorization as ox_KeyAuthorization,
11
+ SignatureEnvelope,
12
+ } from 'ox/tempo'
13
+ import { env } from 'void/env'
14
+ import { Authentication, Registration } from 'webauthx/server'
15
+ import * as z from 'zod'
16
+ import * as core_Auth from '../internal/Auth.js'
17
+ import * as Balance from '../internal/Balance.js'
18
+ import * as BodyLimit from '../internal/BodyLimit.js'
19
+ import * as Cache from '../internal/Cache.js'
20
+ import * as Chain from '../internal/Chain.js'
21
+ import * as ChainList from '../internal/ChainList.js'
22
+ import * as ChainStatus from '../internal/ChainStatus.js'
23
+ import * as ConfigurableAccount from '../internal/ConfigurableAccount.js'
24
+ import type { Env } from '../internal/Env.js'
25
+ import * as ErrorResponse from '../internal/ErrorResponse.js'
26
+ import * as Faucet from '../internal/Faucet.js'
27
+ import * as KeyAuthorization from '../internal/KeyAuthorization.js'
28
+ import * as Log from '../internal/Log.js'
29
+ import * as OpenApi from '../internal/OpenApi.js'
30
+ import * as Owner from '../internal/Owner.js'
31
+ import * as Passkey from '../internal/Passkey.js'
32
+ import * as RateLimit from '../internal/RateLimit.js'
33
+ import * as Realm from '../internal/Realm.js'
34
+ import * as TempoAccount from '../internal/TempoAccount.js'
35
+ import * as Timing from '../internal/Timing.js'
36
+ import * as Validation from '../internal/Validation.js'
37
+ import * as Wallet from '../internal/Wallet.js'
38
+ import * as AccountStep from './lib/AccountStep.js'
39
+ import * as Configure from './lib/Configure.js'
40
+ import * as Cors from './lib/Cors.js'
41
+ import { db } from './lib/Database.js'
42
+ import * as Headless from './lib/Headless.js'
43
+ import * as Session from './lib/Session.js'
44
+
45
+ namespace schema {
46
+ const address = z.templateLiteral([
47
+ '0x',
48
+ z.string().regex(/^[0-9a-fA-F]{40}$/),
49
+ ])
50
+
51
+ export namespace account {
52
+ export const query = z.object({
53
+ chain: Chain.schema.optional().meta({
54
+ description:
55
+ 'The chain whose balance each account carries: `mainnet`, `testnet`, or another chain that the deployment lists. Without it, the accounts carry no balance.',
56
+ examples: ['testnet'],
57
+ }),
58
+ client_id: z
59
+ .string()
60
+ .min(1)
61
+ .max(255)
62
+ .optional()
63
+ .meta({
64
+ description:
65
+ "The app's client ID, whose realms select the accounts. A browser page from an origin that none of the app's redirect URIs has receives the `default` realm, as does a request without one.",
66
+ examples: ['client_01JZ8Q6W3N1R5B4V7C2X9K0M3T'],
67
+ }),
68
+ })
69
+
70
+ export const response = z
71
+ .object({
72
+ email: z.email().meta({
73
+ description: "The user's email address.",
74
+ examples: ['ada@example.com'],
75
+ }),
76
+ id: z.string().meta({
77
+ description:
78
+ "The user's ID, which is the `sub` of every token Tempo ID issues for the user.",
79
+ examples: ['user_01JZ8Q6W3N1R5B4V7C2X9K0M3T'],
80
+ }),
81
+ name: z
82
+ .string()
83
+ .nullable()
84
+ .meta({
85
+ description:
86
+ "The user's name, or `null` for a user who signed up without one.",
87
+ examples: ['Ada Lovelace'],
88
+ }),
89
+ passkeys: z.boolean().meta({
90
+ description:
91
+ "Whether the realms the request reaches hold passkeys that sign in at Tempo ID's origin. Without `client_id`, the `default` realm's, where `POST /v1/account/passkey/options` registers a passkey.",
92
+ examples: [true],
93
+ }),
94
+ tempo: z
95
+ .array(
96
+ TempoAccount.schema.tempoAccount.extend({
97
+ balance: Balance.schema.balance.nullable().optional().meta({
98
+ description:
99
+ "The USD value of the account's verified holdings on the chain that `chain` names, or absent without `chain`. `null` when the chain has no Tempo API URL, or the read fails or takes longer than 3 seconds.",
100
+ }),
101
+ }),
102
+ )
103
+ .readonly()
104
+ .meta({
105
+ description:
106
+ "The user's Tempo Accounts in the realms the request reaches: the account that the user selected for the app first, then oldest first.",
107
+ }),
108
+ })
109
+ .meta({ id: 'Account' })
110
+ }
111
+
112
+ export namespace create {
113
+ export const json = account.query
114
+
115
+ export const response = account.response
116
+ }
117
+
118
+ export namespace passkeyOptions {
119
+ // A JSON body, since `csrf()` refuses a body-less write, and the body requires a CORS preflight.
120
+ export const json = z.object({})
121
+
122
+ export const response = z.object({
123
+ options: z
124
+ .object({
125
+ publicKey: z
126
+ .object({
127
+ attestation: z.literal('none').meta({
128
+ description:
129
+ 'Tempo ID requests no attestation statement from the authenticator.',
130
+ }),
131
+ authenticatorSelection: z
132
+ .object({
133
+ requireResidentKey: z.literal(true).meta({
134
+ description:
135
+ 'The passkey must be discoverable, so it signs in without an email.',
136
+ }),
137
+ residentKey: z.literal('required').meta({
138
+ description:
139
+ 'The passkey must be discoverable, so it signs in without an email.',
140
+ }),
141
+ userVerification: z.literal('required').meta({
142
+ description:
143
+ 'Every passkey registration requires user verification.',
144
+ }),
145
+ })
146
+ .meta({
147
+ description: 'The authenticator that the passkey requires.',
148
+ }),
149
+ challenge: z.templateLiteral(['0x', z.string()]).meta({
150
+ description:
151
+ 'The single-use challenge, as hex. It expires after 5 minutes, and only the same user spends it.',
152
+ examples: [
153
+ '0xf6310589abb21116acc6e123967ed0a125b5041c43f8e157237093e07eaa354c',
154
+ ],
155
+ }),
156
+ excludeCredentials: z
157
+ .array(
158
+ z
159
+ .object({
160
+ id: z.string().meta({
161
+ description: 'A credential ID, base64url.',
162
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
163
+ }),
164
+ type: z.literal('public-key').meta({
165
+ description: 'The credential type.',
166
+ }),
167
+ })
168
+ .meta({
169
+ description: 'A passkey that the user holds already.',
170
+ }),
171
+ )
172
+ .optional()
173
+ .meta({
174
+ description:
175
+ "The user's passkeys of the relying party, which an authenticator that holds one of them refuses to replace. Absent for a user with none.",
176
+ }),
177
+ pubKeyCredParams: z
178
+ .array(
179
+ z
180
+ .object({
181
+ alg: z.literal(-7).meta({
182
+ description: 'ES256: ECDSA over P-256 with SHA-256.',
183
+ }),
184
+ type: z.literal('public-key').meta({
185
+ description: 'The credential type.',
186
+ }),
187
+ })
188
+ .meta({
189
+ description:
190
+ 'The only key type that a Tempo Account accepts.',
191
+ }),
192
+ )
193
+ .meta({
194
+ description:
195
+ 'The key types the passkey may use: P-256 alone, which a Tempo Account verifies.',
196
+ }),
197
+ rp: z
198
+ .object({
199
+ id: z.string().meta({
200
+ description: 'The relying party ID of the `default` realm.',
201
+ examples: ['tempo.xyz'],
202
+ }),
203
+ name: z.string().meta({
204
+ description: "The `default` realm's display name.",
205
+ examples: ['Tempo'],
206
+ }),
207
+ })
208
+ .meta({ description: 'The relying party.' }),
209
+ user: z
210
+ .object({
211
+ displayName: z.string().meta({
212
+ description:
213
+ "The user's name, or the email address for a user without one.",
214
+ examples: ['Ada Lovelace'],
215
+ }),
216
+ id: z.string().meta({
217
+ description:
218
+ 'A random user handle for this passkey, base64url, so a new passkey never replaces another in the authenticator.',
219
+ examples: ['3q2-7wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'],
220
+ }),
221
+ name: z.email().meta({
222
+ description: "The user's email address.",
223
+ examples: ['ada@example.com'],
224
+ }),
225
+ })
226
+ .meta({
227
+ description:
228
+ 'The user, as the authenticator labels the passkey.',
229
+ }),
230
+ })
231
+ .meta({
232
+ description:
233
+ 'The `PublicKeyCredentialCreationOptions`, serialized with the challenge as hex.',
234
+ }),
235
+ })
236
+ .meta({
237
+ description: 'The options for `navigator.credentials.create()`.',
238
+ }),
239
+ })
240
+ }
241
+
242
+ export namespace passkey {
243
+ export const json = z.object({
244
+ credential: Passkey.schema.credential,
245
+ })
246
+
247
+ export const response = z.object({
248
+ step: z
249
+ .object({
250
+ options: z
251
+ .object({
252
+ publicKey: z
253
+ .object({
254
+ allowCredentials: z
255
+ .array(
256
+ z
257
+ .object({
258
+ id: Passkey.schema.credentialId.meta({
259
+ description:
260
+ 'The credential ID of the new passkey, base64url.',
261
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
262
+ }),
263
+ type: z.literal('public-key').meta({
264
+ description: 'The credential type.',
265
+ }),
266
+ })
267
+ .meta({ description: 'The new passkey.' }),
268
+ )
269
+ .meta({
270
+ description:
271
+ 'The new passkey, the only one the browser offers.',
272
+ }),
273
+ challenge: z.templateLiteral(['0x', z.string()]).meta({
274
+ description:
275
+ 'The single-use proof challenge, as hex. It expires after 5 minutes, and only the same user spends it.',
276
+ examples: [
277
+ '0xf6310589abb21116acc6e123967ed0a125b5041c43f8e157237093e07eaa354c',
278
+ ],
279
+ }),
280
+ rpId: z.string().meta({
281
+ description: 'The relying party ID of the `default` realm.',
282
+ examples: ['tempo.xyz'],
283
+ }),
284
+ userVerification: z.literal('required').meta({
285
+ description:
286
+ 'Every passkey signature requires user verification.',
287
+ }),
288
+ })
289
+ .meta({
290
+ description:
291
+ 'The `PublicKeyCredentialRequestOptions`, serialized with the challenge as hex.',
292
+ }),
293
+ })
294
+ .meta({
295
+ description: 'The options for `navigator.credentials.get()`.',
296
+ }),
297
+ type: z.literal('passkey').meta({
298
+ description:
299
+ 'Sign the options with the new passkey, then send the assertion to `POST /v1/account/passkey/verify`.',
300
+ }),
301
+ })
302
+ .meta({
303
+ description:
304
+ "The next step: the new passkey's signature, which proves that the authenticator holds its private key.",
305
+ }),
306
+ })
307
+ }
308
+
309
+ export namespace passkeyVerify {
310
+ export const json = z.object({
311
+ account: address.optional().meta({
312
+ description:
313
+ "A configurable Tempo Account that the user's cloud wallet owns in the `default` realm, which the passkey joins as a second owner on `chain`. Absent, the passkey owns an account of its own.",
314
+ examples: ['0x7a3f9c2b1e5d8a4f6c0b3e7d9a2f5c8b1e4d7a0f'],
315
+ }),
316
+ assertion: Passkey.schema.assertion,
317
+ chain: Chain.schema.optional().meta({
318
+ description:
319
+ "The chain whose accounts are configurable, where `account` is, and whose address of the passkey's own account the response returns. Without it, the first such chain for `account`, and the passkey's own address otherwise.",
320
+ examples: ['local'],
321
+ }),
322
+ })
323
+
324
+ export const response = z.object({
325
+ address: z.string().meta({
326
+ description:
327
+ "The address of the Tempo Account that the passkey owns: `account`, or the passkey's own account on `chain`.",
328
+ examples: ['0x7a3f9c2b1e5d8a4f6c0b3e7d9a2f5c8b1e4d7a0f'],
329
+ }),
330
+ id: Passkey.schema.credentialId.meta({
331
+ description: 'The credential ID of the passkey, base64url.',
332
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
333
+ }),
334
+ })
335
+ }
336
+
337
+ export namespace realms {
338
+ export const query = account.query.omit({ chain: true })
339
+
340
+ export const response = z.object({
341
+ passkeys: z.boolean().meta({
342
+ description:
343
+ "Whether a passkey sign-in for the app runs on the page that sends the request, at a relying party of the app's realms. `false` without `client_id`, or for Tempo ID's own page.",
344
+ examples: [true],
345
+ }),
346
+ realms: z.array(TempoAccount.schema.realm).readonly().meta({
347
+ description:
348
+ "The realms the app reaches, never empty. The first holds a user's first account.",
349
+ }),
350
+ })
351
+ }
352
+
353
+ export namespace chains {
354
+ export const entry = z
355
+ .object({
356
+ chainId: z
357
+ .number()
358
+ .int()
359
+ .meta({
360
+ description: 'The ID of the Tempo chain that serves the name.',
361
+ examples: [42431],
362
+ }),
363
+ configurable: z.boolean().meta({
364
+ description:
365
+ 'Whether Tempo Accounts can be upgraded to configurable accounts (TIP-1107) on the chain, as the deployment sets.',
366
+ examples: [false],
367
+ }),
368
+ name: Chain.schema.meta({
369
+ description: 'The name that the `chain` parameter carries.',
370
+ examples: ['testnet'],
371
+ }),
372
+ })
373
+ .meta({ description: 'A chain that a page can select.' })
374
+
375
+ export const response = z.object({
376
+ chains: z.array(entry).readonly().meta({
377
+ description:
378
+ "The chains in order: `mainnet`, `testnet`, then the deployment's listed chains.",
379
+ }),
380
+ })
381
+ }
382
+
383
+ export namespace pageChains {
384
+ export const response = z.object({
385
+ chains: z
386
+ .array(
387
+ chains.entry
388
+ .extend({
389
+ faucet: z.boolean().meta({
390
+ description:
391
+ 'Whether `POST /i/account/fund` funds an account on the chain, which every Tempo chain but mainnet offers.',
392
+ examples: [true],
393
+ }),
394
+ })
395
+ .meta({ description: 'A chain that a page can select.' }),
396
+ )
397
+ .readonly()
398
+ .meta({
399
+ description:
400
+ "The chains in order: `mainnet`, `testnet`, then the deployment's listed chains.",
401
+ }),
402
+ })
403
+ }
404
+
405
+ export namespace chainStatus {
406
+ export const response = z.object({
407
+ chains: z
408
+ .array(
409
+ z
410
+ .object({
411
+ api: z.enum(['down', 'none', 'up']).meta({
412
+ description:
413
+ "Whether the chain's Tempo API responds on `/health`: `up`, `down`, or `none` when `TEMPO_API_URLS` lists none for the chain.",
414
+ examples: ['up'],
415
+ }),
416
+ chainId: z
417
+ .number()
418
+ .int()
419
+ .meta({
420
+ description:
421
+ 'The ID of the Tempo chain that serves the name.',
422
+ examples: [1337],
423
+ }),
424
+ name: Chain.schema.meta({
425
+ description: 'The name that the `chain` parameter carries.',
426
+ examples: ['local'],
427
+ }),
428
+ node: z.enum(['down', 'up']).meta({
429
+ description:
430
+ "Whether the chain's node serves the chain ID: `up`, or `down` when it does not respond or serves another.",
431
+ examples: ['up'],
432
+ }),
433
+ })
434
+ .meta({ description: 'The status of a listed chain.' }),
435
+ )
436
+ .readonly()
437
+ .meta({
438
+ description:
439
+ "The deployment's listed chains in order, apart from `mainnet` and `testnet`.",
440
+ }),
441
+ })
442
+ }
443
+
444
+ export namespace fund {
445
+ export const json = z.object({
446
+ address: z
447
+ .templateLiteral(['0x', z.string().regex(/^[0-9a-fA-F]{40}$/)])
448
+ .meta({
449
+ description:
450
+ "The Tempo Account that receives the tokens, one of the user's accounts in the `default` realm.",
451
+ examples: ['0x7a3f9c2b1e5d8a4f6c0b3e7d9a2f5c8b1e4d7a0f'],
452
+ pattern: '^0x[0-9a-fA-F]{40}$',
453
+ }),
454
+ chain: Chain.schema.meta({
455
+ description:
456
+ 'The test chain whose faucet drips the tokens: `testnet`, or a name that `GET /i/chains` lists. Tempo mainnet has no faucet.',
457
+ examples: ['testnet'],
458
+ }),
459
+ })
460
+
461
+ export const response = z.object({
462
+ transactions: z
463
+ .array(
464
+ z.templateLiteral(['0x', z.string().regex(/^[0-9a-f]{64}$/)]).meta({
465
+ description: 'The hash of one transfer from the faucet.',
466
+ examples: [
467
+ '0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060',
468
+ ],
469
+ }),
470
+ )
471
+ .readonly()
472
+ .meta({
473
+ description:
474
+ 'The hashes of the transfers, one for each token that the faucet drips, each one landed.',
475
+ examples: [
476
+ [
477
+ '0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060',
478
+ ],
479
+ ],
480
+ }),
481
+ })
482
+ }
483
+
484
+ export namespace upgrade {
485
+ export const json = z
486
+ .object({
487
+ account: address.optional().meta({
488
+ description:
489
+ "One of the user's Tempo Accounts in the app's realms on `chain`, which a linked wallet.tempo passkey owns and the upgrade makes configurable. Absent with `credentialId`.",
490
+ examples: ['0x7a3f9c2b1e5d8a4f6c0b3e7d9a2f5c8b1e4d7a0f'],
491
+ }),
492
+ chain: Chain.schema.optional().meta({
493
+ description:
494
+ 'The chain whose accounts are configurable, where the upgrade runs. Defaults to the first such chain that the deployment names.',
495
+ examples: ['local'],
496
+ }),
497
+ client_id: z
498
+ .string()
499
+ .min(1)
500
+ .max(255)
501
+ .optional()
502
+ .meta({
503
+ description:
504
+ 'The app whose realms hold the account. Without it, the `default` realm.',
505
+ examples: ['client_01JZ8Q6W3N1R5B4V7C2X9K0M3T'],
506
+ }),
507
+ credentialId: Passkey.schema.credentialId.optional().meta({
508
+ description:
509
+ "A wallet.tempo passkey of the user's email that has not linked to the user yet, as `GET /i/account/passkeys` lists it. Its assertion over the upgrade links it. Absent with `account`. Only Tempo ID's own page sends it.",
510
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
511
+ }),
512
+ key: z
513
+ .object({
514
+ // A malformed signature is refused here, before the repeated request spends the step.
515
+ signature: z
516
+ .templateLiteral(['0x', z.string().regex(/^[0-9a-fA-F]*$/)])
517
+ .refine(primitive, {
518
+ message:
519
+ 'Expected the serialized signature envelope of a secp256k1, P256, or WebAuthn access key',
520
+ })
521
+ .meta({
522
+ description:
523
+ "The access key's raw signature over `step.key.digest`, as a serialized signature envelope.",
524
+ examples: [
525
+ '0x997c61aa10e2330c076d6ba7abca1e71703a8f039291db103a62e085c9b2cf0d3f7e31ec9028229acc83093fbb722fa700fd6e4ea15d584df1bf384eb0051e0d1c',
526
+ ],
527
+ }),
528
+ })
529
+ .optional()
530
+ .meta({
531
+ description:
532
+ "The access key's signature of its registration, on the repeated request of a step with `key`.",
533
+ }),
534
+ key_authorization: KeyAuthorization.schema.rpc.optional().meta({
535
+ description:
536
+ "A key that the passkey signed as the account's own key, such as with `skip_upgrade`, on the first request. The chain registers it before the upgrade, so it keeps working after. Its chain is the upgrade's when `chain` is absent.",
537
+ }),
538
+ passkey: z
539
+ .object({
540
+ assertion: Passkey.schema.assertion,
541
+ })
542
+ .optional()
543
+ .meta({
544
+ description:
545
+ "The passkey step's result: the passkey's assertion over the step's challenge. Absent on the first request.",
546
+ }),
547
+ })
548
+ .refine(
549
+ (value) =>
550
+ (value.account === undefined) !== (value.credentialId === undefined),
551
+ {
552
+ message: 'Name exactly one of `account` or `credentialId`.',
553
+ path: ['account'],
554
+ },
555
+ )
556
+
557
+ export const response = z.union([
558
+ z
559
+ .object({
560
+ account: TempoAccount.schema.tempoAccount,
561
+ })
562
+ .meta({ description: 'The installed configuration.' }),
563
+ z
564
+ .object({
565
+ step: z
566
+ .object({
567
+ options: z
568
+ .object({
569
+ publicKey: z
570
+ .object({
571
+ allowCredentials: z
572
+ .array(
573
+ z
574
+ .object({
575
+ id: Passkey.schema.credentialId.meta({
576
+ description:
577
+ "The credential ID of the account's passkey, base64url.",
578
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
579
+ }),
580
+ type: z.literal('public-key').meta({
581
+ description: 'The credential type.',
582
+ }),
583
+ })
584
+ .meta({ description: "The account's passkey." }),
585
+ )
586
+ .meta({
587
+ description:
588
+ "The account's passkey, the only one the browser offers.",
589
+ }),
590
+ challenge: z.templateLiteral(['0x', z.string()]).meta({
591
+ description:
592
+ 'The digest of the transaction that installs the configuration, as hex. It expires after 5 minutes, and only the same user spends it.',
593
+ examples: [
594
+ '0xf6310589abb21116acc6e123967ed0a125b5041c43f8e157237093e07eaa354c',
595
+ ],
596
+ }),
597
+ rpId: z.string().meta({
598
+ description: "The passkey's relying party ID.",
599
+ examples: ['tempo.xyz'],
600
+ }),
601
+ userVerification: z.literal('required').meta({
602
+ description:
603
+ 'Every passkey signature requires user verification.',
604
+ }),
605
+ })
606
+ .meta({
607
+ description:
608
+ 'The `PublicKeyCredentialRequestOptions`, serialized with the challenge as hex.',
609
+ }),
610
+ })
611
+ .meta({
612
+ description: 'The options for `navigator.credentials.get()`.',
613
+ }),
614
+ key: z
615
+ .object({
616
+ digest: z.templateLiteral(['0x', z.string()]).meta({
617
+ description:
618
+ 'The digest of the transaction that registers the key, which the access key signs raw. Tempo ID sponsors the transaction.',
619
+ examples: [
620
+ '0x3c8a5e1f0b7d2c946a1e8f3b5d7c9a2e4f6b8d0c1e3a5f7b9d2c4e6a8f0b1d3c',
621
+ ],
622
+ }),
623
+ })
624
+ .optional()
625
+ .meta({
626
+ description:
627
+ "The key's registration, for a request with `key_authorization` whose key the chain does not hold yet. Repeat the request with `key.signature` too.",
628
+ }),
629
+ type: z.literal('passkey').meta({
630
+ description:
631
+ 'Sign the options with the passkey, then repeat the request with `passkey.assertion`.',
632
+ }),
633
+ })
634
+ .meta({
635
+ description:
636
+ "The next step: the passkey's signature of the transaction, since only the passkey signs for the account.",
637
+ }),
638
+ })
639
+ .meta({ description: 'The passkey step.' }),
640
+ ])
641
+ }
642
+
643
+ export namespace passkeys {
644
+ export const response = z.object({
645
+ passkeys: z
646
+ .array(
647
+ z
648
+ .object({
649
+ address: address.meta({
650
+ description:
651
+ "The address of the passkey's Tempo Account, which its public key derives.",
652
+ examples: ['0x7a3f9c2b1e5d8a4f6c0b3e7d9a2f5c8b1e4d7a0f'],
653
+ }),
654
+ credentialId: Passkey.schema.credentialId.meta({
655
+ description: 'The credential ID of the passkey, base64url.',
656
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
657
+ }),
658
+ })
659
+ .meta({ description: 'A wallet.tempo passkey of the email.' }),
660
+ )
661
+ .readonly()
662
+ .meta({
663
+ description:
664
+ "The passkeys that wallet.tempo stores for the user's email and that link to no user yet, oldest first. Empty without the wallet service.",
665
+ }),
666
+ })
667
+ }
668
+
669
+ export namespace upgrades {
670
+ export const query = z.object({
671
+ chain: Chain.schema.meta({
672
+ description:
673
+ 'The chain to list upgrades on, such as the chain that the sign-in page shows. A chain whose accounts are not configurable lists none.',
674
+ examples: ['t14'],
675
+ }),
676
+ })
677
+
678
+ /** The name of the chain where an upgrade applies. */
679
+ const chain = Chain.schema.meta({
680
+ description:
681
+ 'The name of the chain where the upgrade applies, which `CONFIGURABLE_ACCOUNTS` names.',
682
+ examples: ['t14'],
683
+ })
684
+
685
+ export const response = z.object({
686
+ upgrades: z
687
+ .array(
688
+ z.union([
689
+ z
690
+ .object({
691
+ account: address.meta({
692
+ description:
693
+ "The linked wallet.tempo passkey's account, which `POST /v1/account/upgrade` takes as `account`.",
694
+ examples: ['0x7a3f9c2b1e5d8a4f6c0b3e7d9a2f5c8b1e4d7a0f'],
695
+ }),
696
+ chain,
697
+ })
698
+ .meta({
699
+ description:
700
+ "A linked wallet.tempo passkey's account that is not configurable on the chain.",
701
+ }),
702
+ z
703
+ .object({
704
+ chain,
705
+ credentialId: Passkey.schema.credentialId.meta({
706
+ description:
707
+ 'The credential ID of the wallet.tempo passkey, which `POST /v1/account/upgrade` takes as `credentialId`.',
708
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
709
+ }),
710
+ })
711
+ .meta({
712
+ description:
713
+ 'A wallet.tempo passkey of the email that links to no user, whose upgrade links it.',
714
+ }),
715
+ ]),
716
+ )
717
+ .readonly()
718
+ .meta({
719
+ description:
720
+ 'The upgrades, linked accounts first, in the order of the chains. Empty without a chain whose accounts are configurable.',
721
+ }),
722
+ })
723
+ }
724
+ }
725
+
726
+ /**
727
+ * How long the isolate keeps a listed chain's status, in milliseconds. However often the route is
728
+ * called, each isolate probes each chain at most once in this time.
729
+ */
730
+ const statusTtl = 2_000
731
+
732
+ /** The account routes. */
733
+ export const account = new Hono<Env>()
734
+ .get(
735
+ '/v1/account',
736
+ OpenApi.describeRoute({
737
+ description:
738
+ 'Reads the signed-in user and their Tempo Accounts in the realms of the app that `client_id` names, or of the `default` realm. The account that the user selected for the app comes first, then the oldest.',
739
+ responses: OpenApi.responses({
740
+ errors: [
741
+ ...OpenApi.validate.errors,
742
+ ...RateLimit.check.errors,
743
+ ...TempoAccount.list.errors,
744
+ core_Auth.SessionRequiredError,
745
+ ErrorResponse.CrossSiteRequestError,
746
+ ],
747
+ success: {
748
+ description: 'The user and their Tempo Accounts.',
749
+ schema: schema.account.response,
750
+ },
751
+ }),
752
+ security: [{ sessionCookie: [] }],
753
+ tags: ['Account'],
754
+ }),
755
+ OpenApi.validate('query', schema.account.query),
756
+ async (c) => {
757
+ // The session cookie is `Lax`, so the only cross-site request that carries it is a top-level
758
+ // navigation. No app reads accounts that way, and a page on another site could otherwise spend
759
+ // the user's `ACCOUNT_LIMIT` by navigating a window here.
760
+ if (c.req.header('sec-fetch-site') === 'cross-site')
761
+ return ErrorResponse.json(c, new ErrorResponse.CrossSiteRequestError())
762
+
763
+ const session = await Timing.measure(c, Session.get(c), 'Session.get')
764
+ if (!session)
765
+ return ErrorResponse.json(c, new core_Auth.SessionRequiredError())
766
+
767
+ // An unknown name is refused before it spends a read of the limit.
768
+ const { chain } = c.req.valid('query')
769
+ const target = chain
770
+ ? ChainList.resolve({
771
+ name: chain,
772
+ rpcUrl: env.TEMPO_RPC_URL,
773
+ rpcUrls: env.RPC_URLS,
774
+ })
775
+ : undefined
776
+ if (chain && !target)
777
+ return ErrorResponse.json(c, unknownChain({ chain }))
778
+
779
+ // Each read can call the Privy app of every realm with that app's secret, so one user's reads
780
+ // are limited before they spend the Privy quota that every user shares.
781
+ const refused = await Timing.measure(
782
+ c,
783
+ RateLimit.check(c, {
784
+ limits: [{ binding: 'ACCOUNT_LIMIT', key: session.user.id }],
785
+ }),
786
+ 'RateLimit.check',
787
+ )
788
+ if (refused) return refused
789
+
790
+ const stored = await Timing.measure(
791
+ c,
792
+ Realm.forRequest(c, {
793
+ clientId: c.req.valid('query').client_id,
794
+ db,
795
+ origin: c.req.header('origin'),
796
+ own: new URL(env.URL).origin,
797
+ }),
798
+ 'Realm.forRequest',
799
+ )
800
+ const realms = await Timing.measure(
801
+ c,
802
+ Realm.withDefaults(c, { db, origin: env.URL, realms: stored }),
803
+ 'Realm.withDefaults',
804
+ )
805
+ const tempo = await Timing.measure(
806
+ c,
807
+ TempoAccount.list(c, {
808
+ chainId: target?.chainId,
809
+ db,
810
+ env,
811
+ realms,
812
+ userId: session.user.id,
813
+ }),
814
+ 'TempoAccount.list',
815
+ )
816
+ // The account that the user selected for the app comes first.
817
+ const { client_id: clientId } = c.req.valid('query')
818
+ const ordered = clientId
819
+ ? AccountStep.order(tempo, {
820
+ clientId,
821
+ cookie: c.req.header('cookie'),
822
+ sessionId: session.session.id,
823
+ })
824
+ : tempo
825
+ const balances = target
826
+ ? await Timing.measure(
827
+ c,
828
+ Balance.list(c, {
829
+ accounts: ordered,
830
+ apiUrl: Chain.apiUrl({
831
+ apiUrls: env.TEMPO_API_URLS,
832
+ chainId: target.chainId,
833
+ }),
834
+ chainId: target.chainId,
835
+ }),
836
+ 'Balance.list',
837
+ )
838
+ : undefined
839
+ c.header('cache-control', 'private, no-store')
840
+ return c.json(
841
+ {
842
+ email: session.user.email,
843
+ id: session.user.id,
844
+ // Better Auth stores an empty name for a user who signed up without one.
845
+ name: session.user.name || null,
846
+ passkeys: Boolean(Passkey.relyingParty(realms, { origin: env.URL })),
847
+ tempo: ordered.map((account, index) =>
848
+ balances
849
+ ? { ...account, balance: balances[index] ?? null }
850
+ : account,
851
+ ),
852
+ },
853
+ 200,
854
+ )
855
+ },
856
+ )
857
+ .post(
858
+ '/v1/account',
859
+ OpenApi.describeRoute({
860
+ description:
861
+ 'Returns the signed-in user and their Tempo Accounts, as `GET /v1/account` does. For a user with no account or passkey, it also creates a Privy-owned account in the first realm, when that realm has a Privy app. The JSON body needs a CORS preflight, which Tempo ID grants only to the origins of first-party apps.',
862
+ responses: OpenApi.responses({
863
+ errors: [
864
+ ...BodyLimit.errors,
865
+ ...OpenApi.validate.errors,
866
+ ...RateLimit.check.errors,
867
+ ...TempoAccount.create.errors,
868
+ core_Auth.SessionRequiredError,
869
+ ErrorResponse.CrossSiteRequestError,
870
+ ],
871
+ success: {
872
+ description: 'The user and their Tempo Accounts.',
873
+ schema: schema.create.response,
874
+ },
875
+ }),
876
+ security: [{ sessionCookie: [] }],
877
+ tags: ['Account'],
878
+ }),
879
+ OpenApi.validate('json', schema.create.json),
880
+ async (c) => {
881
+ const session = await Timing.measure(c, Session.get(c), 'Session.get')
882
+ if (!session)
883
+ return ErrorResponse.json(c, new core_Auth.SessionRequiredError())
884
+
885
+ // An unknown name is refused before any work, so `POST` creates no account for it.
886
+ const { chain } = c.req.valid('json')
887
+ const target = chain
888
+ ? ChainList.resolve({
889
+ name: chain,
890
+ rpcUrl: env.TEMPO_RPC_URL,
891
+ rpcUrls: env.RPC_URLS,
892
+ })
893
+ : undefined
894
+ if (chain && !target)
895
+ return ErrorResponse.json(c, unknownChain({ chain }))
896
+
897
+ // The request reads every realm's Privy app as `GET /v1/account` does, so it counts against
898
+ // the same limit.
899
+ const refused = await Timing.measure(
900
+ c,
901
+ RateLimit.check(c, {
902
+ limits: [{ binding: 'ACCOUNT_LIMIT', key: session.user.id }],
903
+ }),
904
+ 'RateLimit.check',
905
+ )
906
+ if (refused) return refused
907
+
908
+ const stored = await Timing.measure(
909
+ c,
910
+ Realm.forRequest(c, {
911
+ clientId: c.req.valid('json').client_id,
912
+ db,
913
+ origin: c.req.header('origin'),
914
+ own: new URL(env.URL).origin,
915
+ }),
916
+ 'Realm.forRequest',
917
+ )
918
+ const realms = await Timing.measure(
919
+ c,
920
+ Realm.withDefaults(c, { db, origin: env.URL, realms: stored }),
921
+ 'Realm.withDefaults',
922
+ )
923
+ // A wallet.tempo passkey of the user's email becomes their account through its upgrade, so the
924
+ // request creates no cloud wallet beside it, as a sign-in does.
925
+ const waits = await Timing.measure(
926
+ c,
927
+ Configure.awaitsUpgrade(c, {
928
+ email: session.user.email,
929
+ realms,
930
+ userId: session.user.id,
931
+ }),
932
+ 'Configure.awaitsUpgrade',
933
+ )
934
+ const options = {
935
+ chainId: target?.chainId,
936
+ db,
937
+ env,
938
+ realms,
939
+ userId: session.user.id,
940
+ }
941
+ const owners = await Timing.measure(
942
+ c,
943
+ waits ? TempoAccount.held(c, options) : TempoAccount.create(c, options),
944
+ 'TempoAccount.create',
945
+ )
946
+ const tempo = owners.map(TempoAccount.serialize)
947
+ // The account that the user selected for the app comes first, as `GET /v1/account` lists it.
948
+ const { client_id: clientId } = c.req.valid('json')
949
+ const ordered = clientId
950
+ ? AccountStep.order(tempo, {
951
+ clientId,
952
+ cookie: c.req.header('cookie'),
953
+ sessionId: session.session.id,
954
+ })
955
+ : tempo
956
+ const balances = target
957
+ ? await Timing.measure(
958
+ c,
959
+ Balance.list(c, {
960
+ accounts: ordered,
961
+ apiUrl: Chain.apiUrl({
962
+ apiUrls: env.TEMPO_API_URLS,
963
+ chainId: target.chainId,
964
+ }),
965
+ chainId: target.chainId,
966
+ }),
967
+ 'Balance.list',
968
+ )
969
+ : undefined
970
+ c.header('cache-control', 'private, no-store')
971
+ return c.json(
972
+ {
973
+ email: session.user.email,
974
+ id: session.user.id,
975
+ name: session.user.name || null,
976
+ passkeys: Boolean(Passkey.relyingParty(realms, { origin: env.URL })),
977
+ tempo: ordered.map((account, index) =>
978
+ balances
979
+ ? { ...account, balance: balances[index] ?? null }
980
+ : account,
981
+ ),
982
+ },
983
+ 200,
984
+ )
985
+ },
986
+ )
987
+ .post(
988
+ '/v1/account/passkey/options',
989
+ OpenApi.describeRoute({
990
+ description:
991
+ "Issues a single-use registration challenge for the signed-in user, and returns creation options for a passkey of the `default` realm. Requires a sign-in within the last 10 minutes and fewer than 10 passkeys. Only Tempo ID's own page sends the request.",
992
+ responses: OpenApi.responses({
993
+ errors: [
994
+ ...BodyLimit.errors,
995
+ ...OpenApi.validate.errors,
996
+ ...RateLimit.check.errors,
997
+ core_Auth.SessionRequiredError,
998
+ ErrorResponse.CrossSiteRequestError,
999
+ Passkey.LimitError,
1000
+ Passkey.NotPermittedError,
1001
+ Passkey.ReauthenticationRequiredError,
1002
+ ],
1003
+ success: {
1004
+ description: 'The creation options.',
1005
+ schema: schema.passkeyOptions.response,
1006
+ },
1007
+ }),
1008
+ security: [{ sessionCookie: [] }],
1009
+ tags: ['Account'],
1010
+ }),
1011
+ OpenApi.validate('json', schema.passkeyOptions.json),
1012
+ async (c) => {
1013
+ // The ceremony runs at Tempo ID's origin, so only its own page registers a passkey.
1014
+ if (Cors.appOrigin(c))
1015
+ return ErrorResponse.json(c, new ErrorResponse.CrossSiteRequestError())
1016
+
1017
+ const session = await Timing.measure(c, Session.get(c), 'Session.get')
1018
+ if (!session)
1019
+ return ErrorResponse.json(c, new core_Auth.SessionRequiredError())
1020
+ if (!fresh(session))
1021
+ return ErrorResponse.json(
1022
+ c,
1023
+ new Passkey.ReauthenticationRequiredError(),
1024
+ )
1025
+
1026
+ const refused = await Timing.measure(
1027
+ c,
1028
+ RateLimit.check(c, {
1029
+ limits: [{ binding: 'ACCOUNT_LIMIT', key: session.user.id }],
1030
+ }),
1031
+ 'RateLimit.check',
1032
+ )
1033
+ if (refused) return refused
1034
+
1035
+ // One read returns the passkeys that the limit counts and the ones that the options exclude.
1036
+ const userId = session.user.id
1037
+ const held = await Timing.measure(
1038
+ c,
1039
+ Passkey.list(db, { userId }),
1040
+ 'Passkey.list',
1041
+ )
1042
+ if (
1043
+ held.filter((key) => key.registered).length >= Passkey.registrationLimit
1044
+ )
1045
+ return ErrorResponse.json(c, new Passkey.LimitError())
1046
+
1047
+ const realms = await Timing.measure(
1048
+ c,
1049
+ Realm.withDefaults(c, {
1050
+ db,
1051
+ origin: env.URL,
1052
+ realms: [
1053
+ await Timing.measure(
1054
+ c,
1055
+ Cache.read(c, () => Realm.get(db, { id: Realm.defaultId }), [
1056
+ 'realm.get',
1057
+ Realm.defaultId,
1058
+ ]),
1059
+ 'Realm.get',
1060
+ ),
1061
+ ],
1062
+ }),
1063
+ 'Realm.withDefaults',
1064
+ )
1065
+ const relyingParty = Passkey.relyingParty(realms, { origin: env.URL })
1066
+ const realm = realms.find((entry) => entry.id === relyingParty?.realmId)
1067
+ if (!relyingParty || !realm)
1068
+ return ErrorResponse.json(c, new Passkey.NotPermittedError())
1069
+
1070
+ const challenge = await Timing.measure(
1071
+ c,
1072
+ Passkey.requestRegistration(db, { rpId: relyingParty.rpId, userId }),
1073
+ 'Passkey.requestRegistration',
1074
+ )
1075
+ const excluded = held.flatMap((key) =>
1076
+ key.rpId === relyingParty.rpId ? [key.id] : [],
1077
+ )
1078
+ const options = schema.passkeyOptions.response.shape.options.parse(
1079
+ Registration.getOptions({
1080
+ authenticatorSelection: {
1081
+ requireResidentKey: true,
1082
+ residentKey: 'required',
1083
+ userVerification: 'required',
1084
+ },
1085
+ challenge,
1086
+ ...(excluded.length > 0 ? { excludeCredentialIds: excluded } : {}),
1087
+ rp: { id: relyingParty.rpId, name: realm.name },
1088
+ // A random handle per passkey, since an authenticator replaces the passkey of the same
1089
+ // relying party and handle, and with it the only key of that passkey's account.
1090
+ user: {
1091
+ displayName: session.user.name || session.user.email,
1092
+ id: crypto.getRandomValues(new Uint8Array(32)),
1093
+ name: session.user.email,
1094
+ },
1095
+ }).options,
1096
+ )
1097
+ c.header('cache-control', 'private, no-store')
1098
+ return c.json({ options }, 200)
1099
+ },
1100
+ )
1101
+ .post(
1102
+ '/v1/account/passkey',
1103
+ OpenApi.describeRoute({
1104
+ description:
1105
+ "Verifies a new passkey's credential over a challenge from `POST /v1/account/passkey/options`, and returns a proof challenge for the passkey to sign. The attestation carries no signature, so only `POST /v1/account/passkey/verify` stores the passkey. Requires a sign-in within the last 10 minutes. Only Tempo ID's own page sends the request.",
1106
+ responses: OpenApi.responses({
1107
+ errors: [
1108
+ ...BodyLimit.errors,
1109
+ ...ErrorResponse.fromUpstream.errors,
1110
+ ...OpenApi.validate.errors,
1111
+ ...RateLimit.check.errors,
1112
+ core_Auth.SessionRequiredError,
1113
+ ErrorResponse.CrossSiteRequestError,
1114
+ Passkey.LimitError,
1115
+ Passkey.ReauthenticationRequiredError,
1116
+ Passkey.WebAuthnRejectedError,
1117
+ ],
1118
+ success: {
1119
+ description: 'The proof step.',
1120
+ schema: schema.passkey.response,
1121
+ },
1122
+ }),
1123
+ security: [{ sessionCookie: [] }],
1124
+ tags: ['Account'],
1125
+ }),
1126
+ OpenApi.validate('json', schema.passkey.json),
1127
+ async (c) => {
1128
+ if (Cors.appOrigin(c))
1129
+ return ErrorResponse.json(c, new ErrorResponse.CrossSiteRequestError())
1130
+
1131
+ const session = await Timing.measure(c, Session.get(c), 'Session.get')
1132
+ if (!session)
1133
+ return ErrorResponse.json(c, new core_Auth.SessionRequiredError())
1134
+ if (!fresh(session))
1135
+ return ErrorResponse.json(
1136
+ c,
1137
+ new Passkey.ReauthenticationRequiredError(),
1138
+ )
1139
+
1140
+ const refused = await Timing.measure(
1141
+ c,
1142
+ RateLimit.check(c, {
1143
+ limits: [{ binding: 'ACCOUNT_LIMIT', key: session.user.id }],
1144
+ }),
1145
+ 'RateLimit.check',
1146
+ )
1147
+ if (refused) return refused
1148
+
1149
+ // The challenge is spent before any other check, so a failed attempt cannot be retried.
1150
+ const { credential } = c.req.valid('json')
1151
+ const userId = session.user.id
1152
+ const challenge = await Timing.measure(
1153
+ c,
1154
+ Passkey.takeRegistration(db, {
1155
+ clientDataJSON: credential.clientDataJSON,
1156
+ userId,
1157
+ }),
1158
+ 'Passkey.takeRegistration',
1159
+ )
1160
+ const verified = challenge
1161
+ ? Passkey.verifyRegistration(credential, {
1162
+ challenge: challenge.challenge,
1163
+ origin: new URL(env.URL).origin,
1164
+ rpId: challenge.rpId,
1165
+ })
1166
+ : undefined
1167
+ if (!challenge || !verified)
1168
+ return ErrorResponse.json(c, new Passkey.WebAuthnRejectedError())
1169
+
1170
+ // A credential ID that wallet.tempo stores belongs to its passkey, which links at its first
1171
+ // sign-in. A registration of it would take the ID with another key. The lookup and the count
1172
+ // run together, and their refusals keep this order.
1173
+ const [wallet, count] = await Promise.all([
1174
+ (async () => {
1175
+ if (!c.env.WALLET) return undefined
1176
+ try {
1177
+ return await Timing.measure(
1178
+ c,
1179
+ Wallet.credential(c.env.WALLET, { id: verified.id }),
1180
+ 'Wallet.credential',
1181
+ )
1182
+ } catch (error) {
1183
+ // Only the binding call throws, so the failure is wallet.tempo's.
1184
+ Log.warn(c, {
1185
+ error,
1186
+ message: 'The wallet service failed a passkey lookup.',
1187
+ })
1188
+ return (
1189
+ (error instanceof Error && ErrorResponse.fromUpstream(error)) ||
1190
+ new ErrorResponse.UpstreamUnavailableError()
1191
+ )
1192
+ }
1193
+ })(),
1194
+ Timing.measure(
1195
+ c,
1196
+ Passkey.registered(db, { userId }),
1197
+ 'Passkey.registered',
1198
+ ),
1199
+ ])
1200
+ if (wallet instanceof ErrorResponse.ResponseError)
1201
+ return ErrorResponse.json(c, wallet)
1202
+ if (wallet)
1203
+ return ErrorResponse.json(c, new Passkey.WebAuthnRejectedError())
1204
+
1205
+ if (count >= Passkey.registrationLimit)
1206
+ return ErrorResponse.json(c, new Passkey.LimitError())
1207
+
1208
+ const proof = await Timing.measure(
1209
+ c,
1210
+ Passkey.requestProof(db, {
1211
+ credential: verified,
1212
+ rpId: challenge.rpId,
1213
+ userId,
1214
+ }),
1215
+ 'Passkey.requestProof',
1216
+ )
1217
+ const options = schema.passkey.response.shape.step.shape.options.parse(
1218
+ Authentication.getOptions({
1219
+ challenge: proof,
1220
+ credentialId: [verified.id],
1221
+ rpId: challenge.rpId,
1222
+ userVerification: 'required',
1223
+ }).options,
1224
+ )
1225
+ c.header('cache-control', 'private, no-store')
1226
+ return c.json({ step: { options, type: 'passkey' as const } }, 200)
1227
+ },
1228
+ )
1229
+ .post(
1230
+ '/v1/account/passkey/verify',
1231
+ OpenApi.describeRoute({
1232
+ description:
1233
+ "Registers a passkey for the signed-in user with its assertion over the proof challenge. The passkey owns its own Tempo Account in the `default` realm, or joins `account` as a second owner. Requires a sign-in within the last 10 minutes. Only Tempo ID's own page sends the request.",
1234
+ responses: OpenApi.responses({
1235
+ errors: [
1236
+ ...BodyLimit.errors,
1237
+ ...Configure.find.errors,
1238
+ ...Configure.send.errors,
1239
+ ...OpenApi.validate.errors,
1240
+ ...RateLimit.check.errors,
1241
+ ConfigurableAccount.NotConfigurableError,
1242
+ ConfigurableAccount.OwnerExistsError,
1243
+ core_Auth.SessionRequiredError,
1244
+ ErrorResponse.CrossSiteRequestError,
1245
+ Passkey.LimitError,
1246
+ Passkey.ReauthenticationRequiredError,
1247
+ Passkey.WebAuthnRejectedError,
1248
+ ],
1249
+ success: {
1250
+ description: 'The passkey and the address of the account it owns.',
1251
+ schema: schema.passkeyVerify.response,
1252
+ },
1253
+ }),
1254
+ security: [{ sessionCookie: [] }],
1255
+ tags: ['Account'],
1256
+ }),
1257
+ OpenApi.validate('json', schema.passkeyVerify.json),
1258
+ async (c) => {
1259
+ if (Cors.appOrigin(c))
1260
+ return ErrorResponse.json(c, new ErrorResponse.CrossSiteRequestError())
1261
+
1262
+ const session = await Timing.measure(c, Session.get(c), 'Session.get')
1263
+ if (!session)
1264
+ return ErrorResponse.json(c, new core_Auth.SessionRequiredError())
1265
+ if (!fresh(session))
1266
+ return ErrorResponse.json(
1267
+ c,
1268
+ new Passkey.ReauthenticationRequiredError(),
1269
+ )
1270
+
1271
+ const refused = await Timing.measure(
1272
+ c,
1273
+ RateLimit.check(c, {
1274
+ limits: [{ binding: 'ACCOUNT_LIMIT', key: session.user.id }],
1275
+ }),
1276
+ 'RateLimit.check',
1277
+ )
1278
+ if (refused) return refused
1279
+
1280
+ // The challenge is spent before any other check, so a failed attempt cannot be retried.
1281
+ const { assertion } = c.req.valid('json')
1282
+ const userId = session.user.id
1283
+ const proof = await Timing.measure(
1284
+ c,
1285
+ Passkey.takeProof(db, {
1286
+ clientDataJSON: assertion.metadata.clientDataJSON,
1287
+ userId,
1288
+ }),
1289
+ 'Passkey.takeProof',
1290
+ )
1291
+ // Only the attested public key verifies the proof, so the user holds its private key.
1292
+ if (
1293
+ !proof ||
1294
+ assertion.id !== proof.id ||
1295
+ !Passkey.verify(assertion, {
1296
+ challenge: proof.challenge,
1297
+ origin: new URL(env.URL).origin,
1298
+ publicKey: proof.publicKey,
1299
+ rpId: proof.rpId,
1300
+ })
1301
+ )
1302
+ return ErrorResponse.json(c, new Passkey.WebAuthnRejectedError())
1303
+
1304
+ // A passkey that joins an account is checked before it is stored, so a refusal stores none.
1305
+ const { account, chain } = c.req.valid('json')
1306
+ const joined = account
1307
+ ? await Timing.measure(
1308
+ c,
1309
+ Configure.find(c, { account, chain, userId }),
1310
+ 'Configure.find',
1311
+ )
1312
+ : undefined
1313
+ if (joined instanceof ErrorResponse.ResponseError)
1314
+ return ErrorResponse.json(c, joined)
1315
+ // A passkey joins only an account that is configurable already.
1316
+ if (joined && !joined.current)
1317
+ return ErrorResponse.json(
1318
+ c,
1319
+ new ConfigurableAccount.NotConfigurableError({
1320
+ account: Owner.address(joined.owner),
1321
+ reason: 'upgrade',
1322
+ }),
1323
+ )
1324
+ if (
1325
+ joined &&
1326
+ (joined.owner.type === 'webAuthn' ||
1327
+ joined.current?.owners.some((entry) => entry.type === 'webAuthn'))
1328
+ )
1329
+ return ErrorResponse.json(
1330
+ c,
1331
+ new ConfigurableAccount.OwnerExistsError({
1332
+ account: Owner.address(joined.owner),
1333
+ owner: 'passkey',
1334
+ }),
1335
+ )
1336
+
1337
+ const stored = await Timing.measure(
1338
+ c,
1339
+ Passkey.register(db, {
1340
+ id: proof.id,
1341
+ publicKey: proof.publicKey,
1342
+ rpId: proof.rpId,
1343
+ userId,
1344
+ }),
1345
+ 'Passkey.register',
1346
+ )
1347
+ TempoAccount.forget(c)
1348
+ if (stored === 'limit')
1349
+ return ErrorResponse.json(c, new Passkey.LimitError())
1350
+ // Another row holds the credential ID or the address, or the realm's relying party changed.
1351
+ if (stored !== 'stored')
1352
+ return ErrorResponse.json(c, new Passkey.WebAuthnRejectedError())
1353
+
1354
+ const address = Address.checksum(
1355
+ Address.fromPublicKey(PublicKey.fromHex(proof.publicKey)),
1356
+ )
1357
+ c.header('cache-control', 'private, no-store')
1358
+ if (!joined) {
1359
+ // On a chain whose accounts are configurable, the passkey owns the account that its initial
1360
+ // configuration derives there, which no row stores.
1361
+ const configurable = chain
1362
+ ? ConfigurableAccount.chains({
1363
+ rpcUrl: env.TEMPO_RPC_URL,
1364
+ rpcUrls: env.RPC_URLS,
1365
+ value: env.CONFIGURABLE_ACCOUNTS,
1366
+ }).find((entry) => entry.name === chain)
1367
+ : undefined
1368
+ if (!configurable) return c.json({ address, id: proof.id }, 200)
1369
+ const config = ConfigurableAccount.created({
1370
+ chainId: configurable.chainId,
1371
+ key: address,
1372
+ type: 'webAuthn',
1373
+ })
1374
+ return c.json({ address: config.address, id: proof.id }, 200)
1375
+ }
1376
+
1377
+ // The account's cloud wallet signs the change on the server: no passkey owns the account, so
1378
+ // its key, or an owner of its configuration, is a kind that signs there. A failed change
1379
+ // leaves the passkey stored, as the owner of its own account.
1380
+ const { client, current, owner } = joined
1381
+ const target = ConfigurableAccount.next({
1382
+ add: [{ address, type: 'webAuthn', weight: 1 }],
1383
+ address: Owner.address(owner),
1384
+ chainId: joined.chain.chainId,
1385
+ current,
1386
+ type: owner.type,
1387
+ })
1388
+ await Configure.send(c, {
1389
+ client,
1390
+ current,
1391
+ signing: Configure.signer(owner, { current }),
1392
+ target,
1393
+ userId,
1394
+ })
1395
+ return c.json({ address: target.address, id: proof.id }, 200)
1396
+ },
1397
+ )
1398
+ .get(
1399
+ '/v1/realms',
1400
+ OpenApi.describeRoute({
1401
+ description:
1402
+ 'Lists the realms of the app that `client_id` names, in order, and whether its passkey sign-in runs on the page that sends the request. An app without realms reaches the `default` realm alone.',
1403
+ responses: OpenApi.responses({
1404
+ errors: [...OpenApi.validate.errors],
1405
+ success: {
1406
+ description: 'The realms.',
1407
+ schema: schema.realms.response,
1408
+ },
1409
+ }),
1410
+ tags: ['Account'],
1411
+ }),
1412
+ OpenApi.validate('query', schema.realms.query),
1413
+ async (c) => {
1414
+ const clientId = c.req.valid('query').client_id
1415
+ const realms = await Timing.measure(
1416
+ c,
1417
+ Realm.forRequest(c, {
1418
+ clientId,
1419
+ db,
1420
+ origin: c.req.header('origin'),
1421
+ own: new URL(env.URL).origin,
1422
+ }),
1423
+ 'Realm.forRequest',
1424
+ )
1425
+ // The checks are those of `POST /v1/auth/passkey/options` from an app's page, so a page that
1426
+ // reads `true` requests options that the route issues.
1427
+ const page = Cors.appOrigin(c)
1428
+ const passkeys = await (async () => {
1429
+ if (!page || !clientId) return false
1430
+ const app = await Timing.measure(
1431
+ c,
1432
+ Headless.app(c, { clientId }),
1433
+ 'Headless.app',
1434
+ )
1435
+ if (Passkey.checkPage({ app, clientId, origin: page })) return false
1436
+ const reached = await Timing.measure(
1437
+ c,
1438
+ Realm.withDefaults(c, { db, origin: env.URL, realms }),
1439
+ 'Realm.withDefaults',
1440
+ )
1441
+ return (
1442
+ Passkey.relyingParty(reached, { origin: env.URL, page }) !== undefined
1443
+ )
1444
+ })()
1445
+ // The response follows the request's `Origin`, so no shared cache keeps it.
1446
+ c.header('cache-control', 'private, no-store')
1447
+ return c.json(
1448
+ {
1449
+ passkeys,
1450
+ realms: realms.map((realm) => ({ id: realm.id, name: realm.name })),
1451
+ },
1452
+ 200,
1453
+ )
1454
+ },
1455
+ )
1456
+ // The response names no RPC URL, since a listed URL can hold an RPC provider's key. Every app's
1457
+ // page reads it, so it grants CORS to any origin.
1458
+ .get(
1459
+ '/v1/chains',
1460
+ OpenApi.describeRoute({
1461
+ description:
1462
+ 'Lists the chains that the `chain` parameter selects, each with its chain ID: `mainnet`, `testnet`, then the chains that the deployment lists.',
1463
+ responses: OpenApi.responses({
1464
+ success: {
1465
+ description: 'The chains.',
1466
+ schema: schema.chains.response,
1467
+ },
1468
+ }),
1469
+ tags: ['Account'],
1470
+ }),
1471
+ (c) => c.json({ chains: chains() }, 200),
1472
+ )
1473
+ .get(
1474
+ '/i/chains',
1475
+ OpenApi.describeRoute({
1476
+ description:
1477
+ "Lists the chains that the `chain` parameter of `GET /v1/account` and `POST /v1/account` selects, as `GET /v1/chains` does, each with whether its faucet funds accounts. Internal: only Tempo ID's own pages send the request, so the public document leaves it out.",
1478
+ // Internal routes stay out of `/openapi.json` and `/docs`.
1479
+ hide: true,
1480
+ responses: OpenApi.responses({
1481
+ success: {
1482
+ description: 'The chains.',
1483
+ schema: schema.pageChains.response,
1484
+ },
1485
+ }),
1486
+ tags: ['Account'],
1487
+ }),
1488
+ // Pages read the faucet here, so no page bundles the chain definitions that `Faucet` reads.
1489
+ (c) =>
1490
+ c.json(
1491
+ {
1492
+ chains: chains().map((entry) => ({
1493
+ ...entry,
1494
+ faucet: Faucet.chains.some((chain) => chain.id === entry.chainId),
1495
+ })),
1496
+ },
1497
+ 200,
1498
+ ),
1499
+ )
1500
+ // The route probes the nodes and Tempo APIs that the deployment lists, so only Tempo ID's own
1501
+ // page sends it, and the isolate keeps each status for `statusTtl`. The built-in chains are never
1502
+ // probed, so a deployment that lists no other chain sends no probe.
1503
+ .get(
1504
+ '/i/chains/status',
1505
+ OpenApi.describeRoute({
1506
+ description:
1507
+ "Returns whether the node and the Tempo API of each chain that the deployment lists respond, apart from `mainnet` and `testnet`. A probe that fails or takes longer than a second reads as `down`, and a status can be up to 2 seconds old. Internal: only Tempo ID's own page sends the request, so the public document leaves it out.",
1508
+ // Internal routes stay out of `/openapi.json` and `/docs`.
1509
+ hide: true,
1510
+ responses: OpenApi.responses({
1511
+ errors: [...Cors.internal.errors],
1512
+ success: {
1513
+ description: 'The status of each listed chain.',
1514
+ schema: schema.chainStatus.response,
1515
+ },
1516
+ }),
1517
+ tags: ['Account'],
1518
+ }),
1519
+ async (c) => {
1520
+ const crossSite = Cors.internal(c)
1521
+ if (crossSite) return ErrorResponse.json(c, crossSite)
1522
+
1523
+ const entries = ChainList.list({ value: env.RPC_URLS }).filter(
1524
+ (entry) => !(entry.name in ChainList.ids),
1525
+ )
1526
+ const statuses = await Promise.all(
1527
+ entries.map(async (entry) => {
1528
+ const status = await Timing.measure(
1529
+ c,
1530
+ Cache.read(
1531
+ c,
1532
+ () =>
1533
+ ChainStatus.get({
1534
+ apiUrl: Chain.apiUrl({
1535
+ apiUrls: env.TEMPO_API_URLS,
1536
+ chainId: entry.chainId,
1537
+ }),
1538
+ chainId: entry.chainId,
1539
+ rpcUrl: entry.url,
1540
+ }),
1541
+ ['ChainStatus.get', entry.name],
1542
+ { ttl: statusTtl },
1543
+ ),
1544
+ 'ChainStatus.get',
1545
+ )
1546
+ return { ...status, chainId: entry.chainId, name: entry.name }
1547
+ }),
1548
+ )
1549
+
1550
+ c.header('cache-control', 'no-store')
1551
+ return c.json({ chains: statuses }, 200)
1552
+ },
1553
+ )
1554
+ .post(
1555
+ '/i/account/fund',
1556
+ OpenApi.describeRoute({
1557
+ description:
1558
+ "Funds one of the signed-in user's Tempo Accounts in the `default` realm from the faucet of the test chain that `chain` names, and waits until each transfer lands. Tempo mainnet has no faucet. Internal: only Tempo ID's own page sends the request, so the public document leaves it out.",
1559
+ // Internal routes stay out of `/openapi.json` and `/docs`.
1560
+ hide: true,
1561
+ responses: OpenApi.responses({
1562
+ errors: [
1563
+ ...BodyLimit.errors,
1564
+ ...Cors.internal.errors,
1565
+ ...OpenApi.validate.errors,
1566
+ ...ErrorResponse.fromUpstream.errors,
1567
+ ...RateLimit.check.errors,
1568
+ ...TempoAccount.list.errors,
1569
+ core_Auth.SessionRequiredError,
1570
+ ErrorResponse.CrossSiteRequestError,
1571
+ ],
1572
+ success: {
1573
+ description: 'The transfers from the faucet.',
1574
+ schema: schema.fund.response,
1575
+ },
1576
+ }),
1577
+ security: [{ sessionCookie: [] }],
1578
+ tags: ['Account'],
1579
+ }),
1580
+ OpenApi.validate('json', schema.fund.json),
1581
+ async (c) => {
1582
+ const crossSite = Cors.internal(c)
1583
+ if (crossSite) return ErrorResponse.json(c, crossSite)
1584
+
1585
+ const session = await Timing.measure(c, Session.get(c), 'Session.get')
1586
+ if (!session)
1587
+ return ErrorResponse.json(c, new core_Auth.SessionRequiredError())
1588
+
1589
+ // A chain without a faucet is refused before the request spends a read of the limit.
1590
+ const { address, chain } = c.req.valid('json')
1591
+ const target = ChainList.resolve({
1592
+ name: chain,
1593
+ rpcUrl: env.TEMPO_RPC_URL,
1594
+ rpcUrls: env.RPC_URLS,
1595
+ })
1596
+ if (!target) return ErrorResponse.json(c, unknownChain({ chain }))
1597
+ const faucet = Faucet.chains.find((entry) => entry.id === target.chainId)
1598
+ if (!faucet) return ErrorResponse.json(c, noFaucet({ chain }))
1599
+
1600
+ // The account check reads every realm's Privy app as `GET /v1/account` does, so it counts
1601
+ // against the same limit.
1602
+ const refused = await Timing.measure(
1603
+ c,
1604
+ RateLimit.check(c, {
1605
+ limits: [{ binding: 'ACCOUNT_LIMIT', key: session.user.id }],
1606
+ }),
1607
+ 'RateLimit.check',
1608
+ )
1609
+ if (refused) return refused
1610
+
1611
+ const stored = await Timing.measure(
1612
+ c,
1613
+ Realm.forRequest(c, {
1614
+ clientId: undefined,
1615
+ db,
1616
+ origin: c.req.header('origin'),
1617
+ own: new URL(env.URL).origin,
1618
+ }),
1619
+ 'Realm.forRequest',
1620
+ )
1621
+ const realms = await Timing.measure(
1622
+ c,
1623
+ Realm.withDefaults(c, { db, origin: env.URL, realms: stored }),
1624
+ 'Realm.withDefaults',
1625
+ )
1626
+ const tempo = await Timing.measure(
1627
+ c,
1628
+ TempoAccount.list(c, {
1629
+ chainId: target.chainId,
1630
+ db,
1631
+ env,
1632
+ realms,
1633
+ userId: session.user.id,
1634
+ }),
1635
+ 'TempoAccount.list',
1636
+ )
1637
+ // Only the user's own accounts receive tokens, so the faucet is no open relay.
1638
+ const found = tempo.find(
1639
+ (entry) => entry.address.toLowerCase() === address.toLowerCase(),
1640
+ )
1641
+ if (!found) return ErrorResponse.json(c, unknownAccount({ address }))
1642
+
1643
+ const transactions = await (async () => {
1644
+ try {
1645
+ return await Timing.measure(
1646
+ c,
1647
+ Faucet.fund({
1648
+ address: found.address,
1649
+ chain: faucet,
1650
+ rpcUrl: target.rpcUrl,
1651
+ }),
1652
+ 'Faucet.fund',
1653
+ )
1654
+ } catch (error) {
1655
+ // `ErrorResponse.handle` maps and logs a 429, a 5xx, or no response. A JSON-RPC refusal or a
1656
+ // transfer that never lands is the node's failure too, so it maps the same way.
1657
+ if (!(error instanceof Error) || ErrorResponse.fromUpstream(error))
1658
+ throw error
1659
+ Log.warn(c, {
1660
+ error,
1661
+ message: 'The faucet did not fund the account.',
1662
+ })
1663
+ throw new ErrorResponse.UpstreamUnavailableError()
1664
+ }
1665
+ })()
1666
+ return c.json({ transactions }, 200)
1667
+ },
1668
+ )
1669
+ .post(
1670
+ '/v1/account/upgrade',
1671
+ OpenApi.describeRoute({
1672
+ description:
1673
+ "Upgrades a wallet.tempo passkey's Tempo Account of the signed-in user in place to a configurable account (TIP-1113), on a chain whose accounts are configurable. The account keeps its address, and the passkey stays its only owner. The first request returns the passkey step, and the repeat with `passkey.assertion` sends the upgrade. With `key_authorization`, Tempo ID first registers that key, sponsored, so it keeps working. Requires a sign-in within the last 10 minutes.",
1674
+ responses: OpenApi.responses({
1675
+ errors: [
1676
+ ...BodyLimit.errors,
1677
+ ...Configure.confirm.errors,
1678
+ ...Configure.root.errors,
1679
+ ...Cors.internal.errors,
1680
+ ...OpenApi.validate.errors,
1681
+ ...RateLimit.check.errors,
1682
+ core_Auth.SessionRequiredError,
1683
+ KeyAuthorization.WebAuthnRequiredError,
1684
+ Passkey.ReauthenticationRequiredError,
1685
+ Validation.InvalidFieldError,
1686
+ ],
1687
+ success: {
1688
+ description: 'The upgraded account, or the passkey step.',
1689
+ schema: schema.upgrade.response,
1690
+ },
1691
+ }),
1692
+ security: [{ sessionCookie: [] }],
1693
+ tags: ['Account'],
1694
+ }),
1695
+ OpenApi.validate('json', schema.upgrade.json),
1696
+ async (c) => {
1697
+ const {
1698
+ account,
1699
+ client_id: clientId,
1700
+ credentialId,
1701
+ key,
1702
+ key_authorization: keyAuthorization,
1703
+ passkey,
1704
+ } = c.req.valid('json')
1705
+ // Only Tempo ID's own page lists the passkeys of the email that have not linked, so only it
1706
+ // links one.
1707
+ const session = await owned(c, { internal: credentialId !== undefined })
1708
+ if (session instanceof Response) return session
1709
+ const userId = session.user.id
1710
+
1711
+ const requested = keyAuthorization
1712
+ ? ox_KeyAuthorization.fromRpc(keyAuthorization as never)
1713
+ : undefined
1714
+ const chain =
1715
+ c.req.valid('json').chain ??
1716
+ (requested
1717
+ ? ConfigurableAccount.on({ chainId: Number(requested.chainId), env })
1718
+ ?.name
1719
+ : undefined)
1720
+ const root = await Timing.measure(
1721
+ c,
1722
+ Configure.root(c, {
1723
+ account,
1724
+ chain,
1725
+ clientId,
1726
+ credentialId,
1727
+ email: session.user.email,
1728
+ userId,
1729
+ }),
1730
+ 'Configure.root',
1731
+ )
1732
+ if (root instanceof ErrorResponse.ResponseError)
1733
+ return ErrorResponse.json(c, root)
1734
+ c.header('cache-control', 'private, no-store')
1735
+
1736
+ // A first-party app's page runs the ceremony at its own origin, which the passkey's relying
1737
+ // party must cover beside Tempo ID's.
1738
+ const page = Cors.appOrigin(c)
1739
+ const origin = page ?? new URL(env.URL).origin
1740
+
1741
+ // The repeated request sends the upgrade that the passkey step prepared, whose challenge it
1742
+ // spends before any other check, so a refused assertion cannot be tried again.
1743
+ if (passkey) {
1744
+ const installed = await Timing.measure(
1745
+ c,
1746
+ Configure.confirm(c, {
1747
+ account: root.account,
1748
+ assertion: passkey.assertion,
1749
+ client: root.client,
1750
+ credential: root.credential,
1751
+ keySignature: key?.signature,
1752
+ link: root.link,
1753
+ origin,
1754
+ userId,
1755
+ }),
1756
+ 'Configure.confirm',
1757
+ )
1758
+ if (installed instanceof ErrorResponse.ResponseError)
1759
+ return ErrorResponse.json(c, installed)
1760
+ const upgraded = await Timing.measure(
1761
+ c,
1762
+ reread(c, {
1763
+ account: root.account,
1764
+ chain: root.chain,
1765
+ clientId,
1766
+ userId,
1767
+ }),
1768
+ 'reread',
1769
+ )
1770
+ return c.json({ account: upgraded }, 200)
1771
+ }
1772
+
1773
+ // A passkey signs only at its relying party, which must cover Tempo ID's origin, and the app's.
1774
+ if (
1775
+ Passkey.relyingParty([root.realm], { origin: env.URL, page })?.rpId !==
1776
+ root.credential.rpId
1777
+ )
1778
+ return ErrorResponse.json(
1779
+ c,
1780
+ passkeyElsewhere({ account: root.account }),
1781
+ )
1782
+
1783
+ const target = ConfigurableAccount.next({
1784
+ add: [],
1785
+ address: root.account,
1786
+ chainId: root.chain.chainId,
1787
+ current: undefined,
1788
+ type: 'webAuthn',
1789
+ })
1790
+
1791
+ const refused = requested
1792
+ ? unsignedKey(requested, {
1793
+ chainId: root.chain.chainId,
1794
+ publicKey: root.credential.publicKey,
1795
+ })
1796
+ : undefined
1797
+ if (refused) return ErrorResponse.json(c, refused)
1798
+ // A key that the chain holds already needs no registration, such as after an upgrade that failed.
1799
+ // A revoked key cannot sign after the upgrade, and no registration replaces it.
1800
+ const status = requested
1801
+ ? await Configure.submit(c, () =>
1802
+ ConfigurableAccount.keyStatus({
1803
+ account: root.account,
1804
+ client: root.client,
1805
+ key: requested.address,
1806
+ }),
1807
+ )
1808
+ : 'active'
1809
+ if (status === 'revoked') return ErrorResponse.json(c, revokedKey())
1810
+ const held = status === 'active'
1811
+ // An upgrade that the chain accepted, and whose save failed, leaves the chain at the target. The
1812
+ // repeated request saves it, since a new upgrade would conflict with the chain.
1813
+ const done = await Timing.measure(
1814
+ c,
1815
+ ConfigurableAccount.installed({ client: root.client, target }),
1816
+ 'ConfigurableAccount.installed',
1817
+ )
1818
+ if (done) {
1819
+ const refused = root.link
1820
+ ? await Timing.measure(c, root.link(), 'Configure.link')
1821
+ : undefined
1822
+ if (refused) return ErrorResponse.json(c, refused)
1823
+ await Timing.measure(
1824
+ c,
1825
+ ConfigurableAccount.save(db, { config: target, userId }),
1826
+ 'db.accountConfig.save',
1827
+ )
1828
+ const upgraded = await Timing.measure(
1829
+ c,
1830
+ reread(c, {
1831
+ account: root.account,
1832
+ chain: root.chain,
1833
+ clientId,
1834
+ userId,
1835
+ }),
1836
+ 'reread',
1837
+ )
1838
+ // The upgrade retired the signature of the key that the passkey signed as the account's own,
1839
+ // so the chain can no longer register it.
1840
+ if (!held) return ErrorResponse.json(c, retiredKey())
1841
+ return c.json({ account: upgraded }, 200)
1842
+ }
1843
+
1844
+ const registration = held
1845
+ ? undefined
1846
+ : await Configure.submit(c, () =>
1847
+ ConfigurableAccount.requestRegistration({
1848
+ account: root.account,
1849
+ client: root.client,
1850
+ key: requested!,
1851
+ }),
1852
+ )
1853
+ if (!held && !registration) return ErrorResponse.json(c, unregistrable())
1854
+
1855
+ const options =
1856
+ schema.upgrade.response.options[1].shape.step.shape.options.parse(
1857
+ await Timing.measure(
1858
+ c,
1859
+ Configure.request(c, {
1860
+ account: root.account,
1861
+ client: root.client,
1862
+ credential: root.credential,
1863
+ current: undefined,
1864
+ registration,
1865
+ target,
1866
+ userId,
1867
+ }),
1868
+ 'Configure.request',
1869
+ ),
1870
+ )
1871
+ return c.json(
1872
+ {
1873
+ step: {
1874
+ options,
1875
+ ...(registration ? { key: { digest: registration.digest } } : {}),
1876
+ type: 'passkey' as const,
1877
+ },
1878
+ },
1879
+ 200,
1880
+ )
1881
+ },
1882
+ )
1883
+ .get(
1884
+ '/i/account/passkeys',
1885
+ OpenApi.describeRoute({
1886
+ description:
1887
+ "Lists the wallet.tempo passkeys of the signed-in user's email that link to no user yet, which `POST /v1/account/upgrade` takes as `credentialId`. The sign-in proved the email, so the list reveals nothing to another person. Counts against the user's `ACCOUNT_LIMIT`. Refuses a cross-site navigation with `cross_site_request`. Internal: only Tempo ID's own page sends the request, so the public document leaves it out.",
1888
+ // Internal routes stay out of `/openapi.json` and `/docs`.
1889
+ hide: true,
1890
+ responses: OpenApi.responses({
1891
+ errors: [
1892
+ ...ErrorResponse.fromUpstream.errors,
1893
+ ...RateLimit.check.errors,
1894
+ core_Auth.SessionRequiredError,
1895
+ ErrorResponse.CrossSiteRequestError,
1896
+ ],
1897
+ success: {
1898
+ description: 'The passkeys.',
1899
+ schema: schema.passkeys.response,
1900
+ },
1901
+ }),
1902
+ security: [{ sessionCookie: [] }],
1903
+ tags: ['Account'],
1904
+ }),
1905
+ async (c) => {
1906
+ // The session cookie is `Lax`, so the only cross-site request that carries it is a top-level
1907
+ // navigation, which could otherwise spend the user's `ACCOUNT_LIMIT` and call wallet.tempo.
1908
+ // The page's loader calls the route in process, without `Sec-Fetch-Site`.
1909
+ if (c.req.header('sec-fetch-site') === 'cross-site')
1910
+ return ErrorResponse.json(c, new ErrorResponse.CrossSiteRequestError())
1911
+
1912
+ const session = await Timing.measure(c, Session.get(c), 'Session.get')
1913
+ if (!session)
1914
+ return ErrorResponse.json(c, new core_Auth.SessionRequiredError())
1915
+ const refused = await Timing.measure(
1916
+ c,
1917
+ RateLimit.check(c, {
1918
+ limits: [{ binding: 'ACCOUNT_LIMIT', key: session.user.id }],
1919
+ }),
1920
+ 'RateLimit.check',
1921
+ )
1922
+ if (refused) return refused
1923
+
1924
+ const listed = await Timing.measure(
1925
+ c,
1926
+ Configure.unlinked(c, { email: session.user.email }),
1927
+ 'Configure.unlinked',
1928
+ )
1929
+ c.header('cache-control', 'private, no-store')
1930
+ return c.json(
1931
+ {
1932
+ passkeys: listed.map((entry) => ({
1933
+ address: Address.checksum(entry.address as `0x${string}`),
1934
+ credentialId: entry.credentialId,
1935
+ })),
1936
+ },
1937
+ 200,
1938
+ )
1939
+ },
1940
+ )
1941
+ .get(
1942
+ '/i/account/upgrades',
1943
+ OpenApi.describeRoute({
1944
+ description:
1945
+ "Lists the upgrades that wait for the signed-in user on `chain`, which the sign-in page offers, when `CONFIGURABLE_ACCOUNTS` names it. Each linked wallet.tempo passkey's account without a configuration on the chain comes first. For a user who holds no account, each wallet.tempo passkey of the email that links to no user follows. `POST /v1/account/upgrade` takes either. Reads stored rows and wallet.tempo, never a chain. Counts against the user's `ACCOUNT_LIMIT`. Refuses a cross-site navigation with `cross_site_request`. Internal: only Tempo ID's own page sends the request, so the public document leaves it out.",
1946
+ // Internal routes stay out of `/openapi.json` and `/docs`.
1947
+ hide: true,
1948
+ responses: OpenApi.responses({
1949
+ errors: [
1950
+ ...ErrorResponse.fromUpstream.errors,
1951
+ ...OpenApi.validate.errors,
1952
+ ...RateLimit.check.errors,
1953
+ core_Auth.SessionRequiredError,
1954
+ ErrorResponse.CrossSiteRequestError,
1955
+ ],
1956
+ success: {
1957
+ description: 'The upgrades.',
1958
+ schema: schema.upgrades.response,
1959
+ },
1960
+ }),
1961
+ security: [{ sessionCookie: [] }],
1962
+ tags: ['Account'],
1963
+ }),
1964
+ OpenApi.validate('query', schema.upgrades.query),
1965
+ async (c) => {
1966
+ // A cross-site navigation carries the `Lax` cookie, and could spend the user's `ACCOUNT_LIMIT`,
1967
+ // as on `GET /i/account/passkeys`.
1968
+ if (c.req.header('sec-fetch-site') === 'cross-site')
1969
+ return ErrorResponse.json(c, new ErrorResponse.CrossSiteRequestError())
1970
+
1971
+ const session = await Timing.measure(c, Session.get(c), 'Session.get')
1972
+ if (!session)
1973
+ return ErrorResponse.json(c, new core_Auth.SessionRequiredError())
1974
+ const refused = await Timing.measure(
1975
+ c,
1976
+ RateLimit.check(c, {
1977
+ limits: [{ binding: 'ACCOUNT_LIMIT', key: session.user.id }],
1978
+ }),
1979
+ 'RateLimit.check',
1980
+ )
1981
+ if (refused) return refused
1982
+
1983
+ const upgrades = await Timing.measure(
1984
+ c,
1985
+ Configure.upgrades(c, {
1986
+ chain: c.req.valid('query').chain,
1987
+ email: session.user.email,
1988
+ userId: session.user.id,
1989
+ }),
1990
+ 'Configure.upgrades',
1991
+ )
1992
+ c.header('cache-control', 'private, no-store')
1993
+ return c.json({ upgrades }, 200)
1994
+ },
1995
+ )
1996
+
1997
+ /**
1998
+ * Checks an owner change's request: it comes from Tempo ID's own page, from a session that signed in
1999
+ * within the last 10 minutes, within the user's `ACCOUNT_LIMIT`. Returns the session, or the refusal
2000
+ * as a response.
2001
+ */
2002
+ async function owned(c: Context<Env>, options: owned.Options = {}) {
2003
+ const { internal = true } = options
2004
+ const crossSite = internal ? Cors.internal(c) : undefined
2005
+ if (crossSite) return ErrorResponse.json(c, crossSite)
2006
+
2007
+ const session = await Timing.measure(c, Session.get(c), 'Session.get')
2008
+ if (!session)
2009
+ return ErrorResponse.json(c, new core_Auth.SessionRequiredError())
2010
+ // A new owner can sign for the account, so an open session alone adds none.
2011
+ if (!fresh(session))
2012
+ return ErrorResponse.json(c, new Passkey.ReauthenticationRequiredError())
2013
+
2014
+ const refused = await Timing.measure(
2015
+ c,
2016
+ RateLimit.check(c, {
2017
+ limits: [{ binding: 'ACCOUNT_LIMIT', key: session.user.id }],
2018
+ }),
2019
+ 'RateLimit.check',
2020
+ )
2021
+ if (refused) return refused
2022
+ return session
2023
+ }
2024
+
2025
+ declare namespace owned {
2026
+ type Options = {
2027
+ /** Whether only Tempo ID's own page sends the request. Defaults to `true`. */
2028
+ internal?: boolean | undefined
2029
+ }
2030
+ }
2031
+
2032
+ /**
2033
+ * Returns the refusal of `key` when the account's passkey, `publicKey`, did not sign it as the
2034
+ * account's own key on the chain `chainId`, or it expired, or `undefined`. The chain verifies the
2035
+ * signature itself when it registers the key.
2036
+ */
2037
+ function unsignedKey(
2038
+ key: ox_KeyAuthorization.Signed,
2039
+ options: unsignedKey.Options,
2040
+ ) {
2041
+ const refuse = (message: string, field: string) =>
2042
+ new Validation.InvalidFieldError({
2043
+ issues: [{ message, path: ['key_authorization', field] }],
2044
+ })
2045
+ const { signature } = key
2046
+ if (
2047
+ signature.type !== 'webAuthn' ||
2048
+ PublicKey.toHex(signature.publicKey, { includePrefix: false }) !==
2049
+ PublicKey.toHex(PublicKey.fromHex(options.publicKey), {
2050
+ includePrefix: false,
2051
+ })
2052
+ )
2053
+ return refuse(
2054
+ "The account's passkey did not sign the key. Send a key that the passkey signed as the account's own key, such as with `skip_upgrade`",
2055
+ 'signature',
2056
+ )
2057
+ if (Number(key.chainId) !== options.chainId)
2058
+ return refuse(
2059
+ `The key acts on chain ${Number(key.chainId)}, not the upgrade's chain ${options.chainId}. Send a key of the upgrade's chain`,
2060
+ 'chainId',
2061
+ )
2062
+ if (key.expiry && key.expiry * 1000 <= Date.now())
2063
+ return refuse('The key expired. Authorize a new key', 'expiry')
2064
+ return undefined
2065
+ }
2066
+
2067
+ declare namespace unsignedKey {
2068
+ type Options = {
2069
+ /** The ID of the upgrade's chain. */
2070
+ chainId: number
2071
+ /** The account's passkey, an uncompressed P256 public key, hex. */
2072
+ publicKey: `0x${string}`
2073
+ }
2074
+ }
2075
+
2076
+ /** Whether `value` is the serialized signature envelope of a key that signs alone, as an access key does. */
2077
+ function primitive(value: `0x${string}`) {
2078
+ try {
2079
+ return ['p256', 'secp256k1', 'webAuthn'].includes(
2080
+ SignatureEnvelope.deserialize(value).type,
2081
+ )
2082
+ } catch {
2083
+ // A value that does not deserialize is no envelope.
2084
+ return false
2085
+ }
2086
+ }
2087
+
2088
+ /** Returns the refusal of a key that the chain holds as revoked. */
2089
+ function revokedKey() {
2090
+ return new Validation.InvalidFieldError({
2091
+ issues: [
2092
+ {
2093
+ message:
2094
+ 'The chain holds the key as revoked, so it signs nothing after the upgrade. Authorize a new key, then upgrade with it',
2095
+ path: ['key_authorization'],
2096
+ },
2097
+ ],
2098
+ })
2099
+ }
2100
+
2101
+ /** Returns the refusal of a key that the chain did not register before the account upgraded. */
2102
+ function retiredKey() {
2103
+ return new Validation.InvalidFieldError({
2104
+ issues: [
2105
+ {
2106
+ message:
2107
+ 'The account upgraded before the chain registered the key, so the chain refuses its signature. The account is configurable now. Authorize a new key',
2108
+ path: ['key_authorization'],
2109
+ },
2110
+ ],
2111
+ })
2112
+ }
2113
+
2114
+ /** Returns the refusal of a key whose scopes allow no TIP-20 transfer of 0, which its registration sends. */
2115
+ function unregistrable() {
2116
+ return new Validation.InvalidFieldError({
2117
+ issues: [
2118
+ {
2119
+ message:
2120
+ 'No scope of the key allows a TIP-20 `transfer` or `transferWithMemo`, so no transaction registers it before the upgrade. Authorize a key that allows one, or upgrade without `key_authorization`',
2121
+ path: ['key_authorization', 'allowedCalls'],
2122
+ },
2123
+ ],
2124
+ })
2125
+ }
2126
+
2127
+ /** Returns the refusal of a passkey whose relying party does not cover Tempo ID's origin. */
2128
+ function passkeyElsewhere(options: passkeyElsewhere.Options) {
2129
+ return new KeyAuthorization.WebAuthnRequiredError({
2130
+ account: options.account,
2131
+ description: `Passkey required: the passkey of Tempo Account ${options.account} signs only at its own relying party, which this page is not part of. Change the account there.`,
2132
+ })
2133
+ }
2134
+
2135
+ declare namespace passkeyElsewhere {
2136
+ type Options = {
2137
+ /** The account's address. */
2138
+ account: `0x${string}`
2139
+ }
2140
+ }
2141
+
2142
+ /** Reads the user's account at `account` on `chain` again, after a change, as the API returns it. */
2143
+ async function reread(c: Context<Env>, options: reread.Options) {
2144
+ const { account, chain, clientId, userId } = options
2145
+ const realms = await Timing.measure(
2146
+ c,
2147
+ Configure.reach(c, { clientId }),
2148
+ 'Configure.reach',
2149
+ )
2150
+ const owners = await Timing.measure(
2151
+ c,
2152
+ TempoAccount.held(c, { chainId: chain.chainId, db, env, realms, userId }),
2153
+ 'TempoAccount.held',
2154
+ )
2155
+ const owner = owners.find(
2156
+ (entry) => Owner.address(entry).toLowerCase() === account.toLowerCase(),
2157
+ )
2158
+ // The change stored the configuration first, so the account is listed. A concurrent change of
2159
+ // the realms could still drop it, which the caller sees as a missing account.
2160
+ if (!owner) throw new TempoAccount.ForeignAccountError({ account })
2161
+ return TempoAccount.serialize(owner)
2162
+ }
2163
+
2164
+ declare namespace reread {
2165
+ type Options = {
2166
+ /** The account's address. */
2167
+ account: `0x${string}`
2168
+ /** The chain of the change. */
2169
+ chain: ConfigurableAccount.Entry
2170
+ /** The app whose realms hold the account, if any. */
2171
+ clientId?: string | undefined
2172
+ /** The signed-in user's ID. */
2173
+ userId: string
2174
+ }
2175
+ }
2176
+
2177
+ /** Returns the refusal of an `address` that is not one of the user's accounts. */
2178
+ function unknownAccount(options: unknownAccount.Options) {
2179
+ return new Validation.InvalidFieldError({
2180
+ issues: [
2181
+ {
2182
+ message: `The signed-in user has no Tempo Account at ${options.address}. Use an address that \`GET /v1/account\` lists`,
2183
+ path: ['address'],
2184
+ },
2185
+ ],
2186
+ })
2187
+ }
2188
+
2189
+ declare namespace unknownAccount {
2190
+ type Options = {
2191
+ /** The address that the request sent. */
2192
+ address: string
2193
+ }
2194
+ }
2195
+
2196
+ /** Returns the refusal of a `chain` whose node serves no faucet, such as Tempo mainnet. */
2197
+ function noFaucet(options: noFaucet.Options) {
2198
+ return new Validation.InvalidFieldError({
2199
+ issues: [
2200
+ {
2201
+ message: `The chain "${options.chain}" has no faucet. Use \`testnet\`, or a test chain that the deployment lists`,
2202
+ path: ['chain'],
2203
+ },
2204
+ ],
2205
+ })
2206
+ }
2207
+
2208
+ declare namespace noFaucet {
2209
+ type Options = {
2210
+ /** The name that the request sent. */
2211
+ chain: string
2212
+ }
2213
+ }
2214
+
2215
+ /**
2216
+ * Returns whether `session` signed in within the last {@link Passkey.registrationFreshness} seconds,
2217
+ * so it can register a passkey. Better Auth extends a session's expiry, never its creation time.
2218
+ */
2219
+ /** Returns the refusal of a `chain` that names neither a built-in chain nor a listed one. */
2220
+ function unknownChain(options: unknownChain.Options) {
2221
+ return new Validation.InvalidFieldError({
2222
+ issues: [
2223
+ {
2224
+ message: `No chain is named "${options.chain}". Use \`mainnet\`, \`testnet\`, or another chain that the deployment lists`,
2225
+ path: ['chain'],
2226
+ },
2227
+ ],
2228
+ })
2229
+ }
2230
+
2231
+ declare namespace unknownChain {
2232
+ type Options = {
2233
+ /** The name that the request sent. */
2234
+ chain: string
2235
+ }
2236
+ }
2237
+
2238
+ function fresh(session: { session: { createdAt: Date } }) {
2239
+ return (
2240
+ Date.now() - session.session.createdAt.getTime() <
2241
+ Passkey.registrationFreshness * 1000
2242
+ )
2243
+ }
2244
+
2245
+ /**
2246
+ * The chains that `chain` selects: `mainnet`, `testnet`, then each other chain of `RPC_URLS`. Those
2247
+ * that `CONFIGURABLE_ACCOUNTS` names are configurable.
2248
+ */
2249
+ function chains() {
2250
+ const configurable = ConfigurableAccount.chains({
2251
+ rpcUrl: env.TEMPO_RPC_URL,
2252
+ rpcUrls: env.RPC_URLS,
2253
+ value: env.CONFIGURABLE_ACCOUNTS,
2254
+ }).map((entry) => entry.chainId)
2255
+ return [
2256
+ { chainId: ChainList.ids.mainnet, name: 'mainnet' },
2257
+ { chainId: ChainList.ids.testnet, name: 'testnet' },
2258
+ // An entry for a built-in chain replaces its RPC URL, so the chain stays listed once.
2259
+ ...ChainList.list({ value: env.RPC_URLS })
2260
+ .filter((entry) => !(entry.name in ChainList.ids))
2261
+ .map((entry) => ({ chainId: entry.chainId, name: entry.name })),
2262
+ ].map((entry) => ({
2263
+ ...entry,
2264
+ configurable: configurable.includes(entry.chainId),
2265
+ }))
2266
+ }