@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,1904 @@
1
+ /**
2
+ * Passkeys: the WebAuthn credentials users sign in with, each a row of the `keys` table linked to a
3
+ * user. A linked wallet.tempo passkey, or one that a signed-in user registers, also owns Tempo
4
+ * Accounts, as the kind in `owners/Passkey.ts` lists, and signs their key authorizations over a
5
+ * signature challenge. A realm's `realm_passkeys` row names the relying party whose passkeys belong to it. Every
6
+ * challenge comes from Tempo ID, lives in Better Auth's `verification` table, and is spent once. The
7
+ * plugin's server-only endpoint creates a native Better Auth session once a route verifies an
8
+ * assertion.
9
+ * @module
10
+ */
11
+ import type { BetterAuthPlugin } from 'better-auth'
12
+ import { createAuthEndpoint } from 'better-auth/api'
13
+ import { setSessionCookie } from 'better-auth/cookies'
14
+ import { symmetricDecrypt, symmetricEncrypt } from 'better-auth/crypto'
15
+ import { and, asc, eq, gt, inArray, isNotNull, sql } from 'drizzle-orm'
16
+ import { Address, Base64, Hash, Hex, P256, PublicKey } from 'ox'
17
+ import { Authentication, Registration } from 'webauthx/server'
18
+ import { z } from 'zod'
19
+ import * as Schema from '../app/db/schema.js'
20
+ import type * as Apps from './Apps.js'
21
+ import * as Authorize from './Authorize.js'
22
+ import * as ErrorResponse from './ErrorResponse.js'
23
+ import * as KeyAuthorization from './KeyAuthorization.js'
24
+ import * as Owner from './Owner.js'
25
+ import type * as Realm from './Realm.js'
26
+ import * as Verification from './Verification.js'
27
+
28
+ /** The user holds {@link registrationLimit} registered passkeys, so Tempo ID registers no other. */
29
+ export class LimitError extends ErrorResponse.define('passkey_limit') {
30
+ override readonly name = 'Passkey.LimitError'
31
+
32
+ constructor() {
33
+ super({
34
+ error_description: `Passkey limit reached: the user holds ${registrationLimit} registered passkeys, the most that Tempo ID registers. Sign in with one of them.`,
35
+ meta: { limit: registrationLimit },
36
+ })
37
+ }
38
+ }
39
+
40
+ /**
41
+ * The email step's link to a wallet.tempo passkey expired, or the browser holds no link cookie for it.
42
+ * The refusal comes before the code is checked, so the code stays valid for a sign-in without the
43
+ * passkey.
44
+ */
45
+ export class LinkExpiredError extends ErrorResponse.define(
46
+ 'passkey_link_expired',
47
+ ) {
48
+ override readonly name = 'Passkey.LinkExpiredError'
49
+
50
+ constructor() {
51
+ super({
52
+ error_description:
53
+ 'Expired passkey sign-in: the link from the passkey step is no longer valid. Enter the code again to sign in with email only, or sign in with the passkey again.',
54
+ field: 'link',
55
+ })
56
+ }
57
+ }
58
+
59
+ /**
60
+ * A passkey sign-in names an app, or reaches a realm, that holds no passkeys for Tempo ID, or no
61
+ * passkeys whose relying party covers the app's page.
62
+ */
63
+ export class NotPermittedError extends ErrorResponse.define(
64
+ 'passkey_not_permitted',
65
+ ) {
66
+ override readonly name = 'Passkey.NotPermittedError'
67
+
68
+ constructor(options: NotPermittedError.Options = {}) {
69
+ const { clientId, origin } = options
70
+ super(
71
+ (() => {
72
+ if (clientId && origin)
73
+ return {
74
+ error_description: `Passkey not permitted: no realm of the app ${clientId} holds passkeys for ${origin}. Sign in with an emailed code.`,
75
+ meta: { client_id: clientId, origin },
76
+ }
77
+ if (clientId)
78
+ return {
79
+ error_description: `Passkey not permitted: the app ${clientId} holds no passkeys. Sign in with an emailed code.`,
80
+ meta: { client_id: clientId },
81
+ }
82
+ return {
83
+ error_description:
84
+ 'Passkey not permitted: no realm holds passkeys for this sign-in. Sign in with an emailed code.',
85
+ }
86
+ })(),
87
+ )
88
+ }
89
+ }
90
+
91
+ export declare namespace NotPermittedError {
92
+ type Options = {
93
+ /** The client ID of the app the sign-in names, if any. */
94
+ clientId?: string | undefined
95
+ /** The origin of the app's page that runs the ceremony, or absent for Tempo ID's own page. */
96
+ origin?: string | undefined
97
+ }
98
+ }
99
+
100
+ /**
101
+ * A passkey registration comes from a session that signed in more than {@link registrationFreshness}
102
+ * seconds before. A session alone, such as one left open in a shared browser, thus adds no passkey.
103
+ */
104
+ export class ReauthenticationRequiredError extends ErrorResponse.define(
105
+ 'reauthentication_required',
106
+ ) {
107
+ override readonly name = 'Passkey.ReauthenticationRequiredError'
108
+
109
+ constructor() {
110
+ super({
111
+ error_description: `Sign in again: adding a passkey needs a sign-in within the last ${registrationFreshness / 60} minutes.`,
112
+ })
113
+ }
114
+ }
115
+
116
+ /**
117
+ * A passkey ceremony failed: its challenge is unknown, spent, or expired, or the response does not
118
+ * verify. One refusal covers every case, so it reveals neither which check failed nor whether a
119
+ * credential exists.
120
+ */
121
+ export class WebAuthnRejectedError extends ErrorResponse.define(
122
+ 'webauthn_rejected',
123
+ ) {
124
+ override readonly name = 'Passkey.WebAuthnRejectedError'
125
+
126
+ constructor() {
127
+ super({
128
+ error_description:
129
+ 'Passkey rejected. Request new options, then try again with the same passkey or another one.',
130
+ })
131
+ }
132
+ }
133
+
134
+ /** A passkey assertion, as `webauthx/client`'s `Authentication.sign` serializes it. */
135
+ export type Assertion = z.output<typeof schema.assertion>
136
+
137
+ /** A challenge that Tempo ID issued, as `take` returns it once spent. */
138
+ export type Challenge = {
139
+ /**
140
+ * The headless authorization request of a sign-in with key signature on an app's page, as the
141
+ * page sent it with its key's expiry filled, or `undefined` for none. The sign-in runs it.
142
+ */
143
+ authorize: unknown
144
+ /** The challenge, as hex. */
145
+ challenge: Hex.Hex
146
+ /** The client ID of the app the sign-in named, or `null` for none. */
147
+ clientId: string | null
148
+ /**
149
+ * The SHA-256 digest of the email step's link that the challenge confirms, as hex, or `undefined`
150
+ * for a sign-in challenge.
151
+ */
152
+ link: string | undefined
153
+ /**
154
+ * The origin of the app's page that the ceremony runs at, or `undefined` for Tempo ID's own page.
155
+ */
156
+ origin: string | undefined
157
+ /**
158
+ * The realm whose relying party the challenge was issued for, or `undefined` when the stored
159
+ * challenge names none, which skips the wallet.tempo lookup.
160
+ */
161
+ realmId: string | undefined
162
+ /** The relying party the challenge was issued for. */
163
+ rpId: string
164
+ /**
165
+ * The witness that a key challenge's key authorization digest binds, or `undefined` for a
166
+ * random challenge.
167
+ */
168
+ witness: Hex.Hex | undefined
169
+ }
170
+
171
+ /** A registration credential, as `webauthx/client`'s `Registration.create` serializes it. */
172
+ export type Credential = z.output<typeof schema.credential>
173
+
174
+ /** A row of the `keys` table. */
175
+ export type Key = typeof Schema.keys.$inferSelect
176
+
177
+ /** A verified wallet.tempo passkey that waits for an emailed code to name its user. */
178
+ export type Link = z.output<typeof schema.link>
179
+
180
+ /**
181
+ * A challenge for the new passkey's proof that it holds its private key, as `takeProof` returns it
182
+ * once spent.
183
+ */
184
+ export type ProofChallenge = {
185
+ /** The challenge, as hex. */
186
+ challenge: Hex.Hex
187
+ /** The credential ID of the new passkey, base64url. */
188
+ id: string
189
+ /** The public key that the attestation holds, which the proof must verify against. */
190
+ publicKey: Hex.Hex
191
+ /** The relying party of the `default` realm, which the new passkey belongs to. */
192
+ rpId: string
193
+ }
194
+
195
+ /** A registration challenge that Tempo ID issued, as `takeRegistration` returns it once spent. */
196
+ export type RegistrationChallenge = {
197
+ /** The challenge, as hex. */
198
+ challenge: Hex.Hex
199
+ /** The relying party of the `default` realm, which the new passkey must belong to. */
200
+ rpId: string
201
+ }
202
+
203
+ /**
204
+ * A challenge for a passkey's signature of a key authorization, as `takeSignature` returns it once
205
+ * spent. The challenge is the key authorization's digest.
206
+ */
207
+ export type SignatureChallenge = {
208
+ /** The address of the Tempo Account that the key acts for, lowercase. */
209
+ account: string
210
+ /** The client ID of the app that requests the key. */
211
+ clientId: string
212
+ /** The passkey that must sign. */
213
+ credential: Owner.Credential
214
+ /** The digest of the key authorization, as hex. */
215
+ digest: Hex.Hex
216
+ }
217
+
218
+ /** Seconds a challenge lasts. */
219
+ export const lifetime = 5 * 60
220
+
221
+ /** Seconds a deferred link lasts. */
222
+ export const linkLifetime = 5 * 60
223
+
224
+ /** The prefix of a challenge's `verification` identifier, which its hex value follows. */
225
+ const prefix = 'passkey-challenge:'
226
+
227
+ /**
228
+ * The prefix of a proof challenge's `verification` identifier, which the user's ID and the
229
+ * challenge follow.
230
+ */
231
+ const proofPrefix = 'passkey-registration-proof:'
232
+
233
+ /**
234
+ * Seconds after its sign-in that a session can register a passkey. A later registration requires a
235
+ * new sign-in.
236
+ */
237
+ export const registrationFreshness = 10 * 60
238
+
239
+ /**
240
+ * The most passkeys that a user registers. Each owns an account that every account read lists, so
241
+ * the limit bounds the reads.
242
+ */
243
+ export const registrationLimit = 10
244
+
245
+ /**
246
+ * The prefix of a registration challenge's `verification` identifier, which the user's ID and the
247
+ * challenge follow. It differs from {@link prefix} and {@link proofPrefix}, so a sign-in or a proof
248
+ * never spends a registration challenge.
249
+ */
250
+ const registrationPrefix = 'passkey-registration:'
251
+
252
+ /**
253
+ * The prefix of a signature challenge's `verification` identifier, which {@link signatureIdentifier}
254
+ * completes. It differs from {@link prefix}, so a sign-in never spends a signature challenge.
255
+ */
256
+ const signaturePrefix = 'passkey-signature:'
257
+
258
+ /**
259
+ * The longest a spent signature's record lasts, in seconds: a year, the longest a headless key
260
+ * lasts. A redirect's key can name a much later expiry, so the record does not follow it, and each
261
+ * user's approvals add rows that the cleanup cron removes within the year.
262
+ */
263
+ const spentLifetime = KeyAuthorization.lifetime
264
+
265
+ /**
266
+ * The prefix of a spent signature's `verification` identifier, which the SHA-256 digest of the
267
+ * assertion's authenticator data and signature follows.
268
+ */
269
+ const spentPrefix = 'passkey-signature-spent:'
270
+
271
+ /**
272
+ * The prefix of the `verification` identifier of an assertion that a sign-in with key signature
273
+ * spent, which the same digest as {@link spentPrefix} follows.
274
+ */
275
+ const spentSignInPrefix = 'passkey-sign-in-spent:'
276
+
277
+ /** Whether the isolate built the curve's table of base point multiples, which {@link table} builds. */
278
+ let tabled = false
279
+
280
+ /** Zod schemas for passkey ceremonies. */
281
+ export namespace schema {
282
+ const base64url = z.string().regex(/^[A-Za-z0-9_-]+$/)
283
+ const hex = z.templateLiteral(['0x', z.string().regex(/^[0-9a-fA-F]*$/)])
284
+
285
+ /**
286
+ * A credential ID in canonical unpadded base64url, of at most 1,023 bytes, as WebAuthn bounds it:
287
+ * 1,364 characters.
288
+ */
289
+ export const credentialId = base64url.min(1).max(1364)
290
+
291
+ /** A passkey assertion, as `webauthx/client`'s `Authentication.sign` serializes it. */
292
+ export const assertion = z
293
+ .object({
294
+ id: credentialId.meta({
295
+ description: 'The credential ID of the passkey that signed, base64url.',
296
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
297
+ }),
298
+ metadata: z
299
+ .object({
300
+ authenticatorData: hex.meta({
301
+ description:
302
+ 'The authenticator data the passkey signed, as hex: the relying party ID hash, flags, and signature counter.',
303
+ examples: [
304
+ '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000',
305
+ ],
306
+ }),
307
+ challengeIndex: z
308
+ .number()
309
+ .int()
310
+ .nonnegative()
311
+ .optional()
312
+ .meta({
313
+ description:
314
+ 'The character offset of `"challenge"` in `clientDataJSON`. Absent, verification searches for it.',
315
+ examples: [23],
316
+ }),
317
+ clientDataJSON: z
318
+ .string()
319
+ .max(4096)
320
+ .meta({
321
+ description:
322
+ 'The client data the browser collected, as a JSON string, which holds the type, challenge, and origin.',
323
+ examples: [
324
+ '{"type":"webauthn.get","challenge":"9jEFijuhEWrM4SOW-tChJbUEHEP44VcjcJ-Bqo1fTM8","origin":"https://id.tempo.xyz","crossOrigin":false}',
325
+ ],
326
+ }),
327
+ typeIndex: z
328
+ .number()
329
+ .int()
330
+ .nonnegative()
331
+ .optional()
332
+ .meta({
333
+ description:
334
+ 'The character offset of `"type"` in `clientDataJSON`. Absent, verification searches for it.',
335
+ examples: [1],
336
+ }),
337
+ userVerificationRequired: z
338
+ .boolean()
339
+ .optional()
340
+ .meta({
341
+ description:
342
+ 'Whether the client required user verification. Verification ignores it and always requires user verification.',
343
+ examples: [true],
344
+ }),
345
+ })
346
+ .meta({
347
+ description:
348
+ 'The signed data that verification reads with `signature`, decoded from the browser response.',
349
+ }),
350
+ raw: z
351
+ .object({
352
+ authenticatorAttachment: z
353
+ .string()
354
+ .nullable()
355
+ .default(null)
356
+ .meta({
357
+ description:
358
+ 'How the authenticator attaches to the client, such as `platform` or `cross-platform`. Defaults to `null` when the browser reports none.',
359
+ examples: ['platform'],
360
+ }),
361
+ id: base64url.meta({
362
+ description:
363
+ 'The credential ID, base64url, as the browser returns it.',
364
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
365
+ }),
366
+ rawId: base64url.meta({
367
+ description: 'The bytes of the credential ID, base64url.',
368
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
369
+ }),
370
+ // Verification reads the top-level `metadata` and `signature`, so other fields are dropped.
371
+ response: z
372
+ .object({
373
+ clientDataJSON: base64url.meta({
374
+ description: 'The client data JSON, base64url.',
375
+ examples: [
376
+ 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiOWpFRmlqdWhFV3JNNFNPVy10Q2hKYlVFSEVQNDRWY2pjSi1CcW8xZlRNOCIsIm9yaWdpbiI6Imh0dHBzOi8vaWQudGVtcG8ueHl6IiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ',
377
+ ],
378
+ }),
379
+ })
380
+ .meta({
381
+ description:
382
+ "The authenticator's response. Verification keeps only `clientDataJSON` and drops other fields.",
383
+ }),
384
+ type: z.string().meta({
385
+ description: 'The credential type.',
386
+ examples: ['public-key'],
387
+ }),
388
+ })
389
+ .meta({
390
+ description:
391
+ 'The `PublicKeyCredential` that `navigator.credentials.get()` returns, serialized as JSON.',
392
+ }),
393
+ signature: hex.meta({
394
+ description:
395
+ 'The P-256 signature over the authenticator data and the client data hash, as 64-byte hex: `r` then `s`.',
396
+ examples: [
397
+ '0x6c3f1e0a9b7d24f58e1c3a6b9d0f2e4a7c5b8d1e3f6a9c2b4d7e0f1a3c5b8d9e1f2a7c4b6d8e0f3a5c7b9d1e4f6a8c0b2d5e7f9a1c3b6d8e0f2a4c7b9d1e3f5a',
398
+ ],
399
+ }),
400
+ })
401
+ .meta({
402
+ description: 'The assertion, serialized as `webauthx/client` returns it.',
403
+ id: 'PasskeyAssertion',
404
+ })
405
+
406
+ /** The client data fields that `take` and `verify` read. */
407
+ export const clientData = z.object({
408
+ challenge: base64url,
409
+ crossOrigin: z.boolean().optional(),
410
+ })
411
+
412
+ /** A registration credential, as `webauthx/client`'s `Registration.create` serializes it. */
413
+ export const credential = z
414
+ .object({
415
+ attestationObject: base64url.max(16384).meta({
416
+ description:
417
+ "The authenticator's attestation object, base64url, which holds the new public key.",
418
+ examples: ['o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjF'],
419
+ }),
420
+ clientDataJSON: base64url.max(4096).meta({
421
+ description:
422
+ 'The client data the browser collected, base64url, which holds the type, challenge, and origin.',
423
+ examples: [
424
+ 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiOWpFRmlqdWhFV3JNNFNPVy10Q2hKYlVFSEVQNDRWY2pjSi1CcW8xZlRNOCIsIm9yaWdpbiI6Imh0dHBzOi8vaWQudGVtcG8ueHl6IiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ',
425
+ ],
426
+ }),
427
+ id: credentialId.meta({
428
+ description: 'The credential ID of the new passkey, base64url.',
429
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
430
+ }),
431
+ // Verification reads the public key from the attestation object, never this copy.
432
+ publicKey: z
433
+ .templateLiteral(['0x', z.string().regex(/^04[0-9a-fA-F]{128}$/)])
434
+ .meta({
435
+ description:
436
+ "The new passkey's uncompressed P256 public key, as hex. Verification reads the key from `attestationObject` and ignores this copy.",
437
+ examples: [
438
+ '0x04f6310589abb21116acc6e123967ed0a125b5041c43f8e157237093e07eaa354c6c3f1e0a9b7d24f58e1c3a6b9d0f2e4a7c5b8d1e3f6a9c2b4d7e0f1a3c5b8d',
439
+ ],
440
+ }),
441
+ raw: z
442
+ .object({
443
+ authenticatorAttachment: z
444
+ .string()
445
+ .nullable()
446
+ .default(null)
447
+ .meta({
448
+ description:
449
+ 'How the authenticator attaches to the client, such as `platform` or `cross-platform`. Defaults to `null` when the browser reports none.',
450
+ examples: ['platform'],
451
+ }),
452
+ id: base64url.max(1364).meta({
453
+ description:
454
+ 'The credential ID, base64url, as the browser returns it.',
455
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
456
+ }),
457
+ rawId: base64url.max(1364).meta({
458
+ description: 'The bytes of the credential ID, base64url.',
459
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
460
+ }),
461
+ // Verification reads the top-level `attestationObject` and `clientDataJSON`, so the
462
+ // response's other fields are dropped.
463
+ response: z
464
+ .object({
465
+ clientDataJSON: base64url.max(4096).meta({
466
+ description: 'The client data JSON, base64url.',
467
+ examples: [
468
+ 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiOWpFRmlqdWhFV3JNNFNPVy10Q2hKYlVFSEVQNDRWY2pjSi1CcW8xZlRNOCIsIm9yaWdpbiI6Imh0dHBzOi8vaWQudGVtcG8ueHl6IiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ',
469
+ ],
470
+ }),
471
+ })
472
+ .meta({
473
+ description:
474
+ "The authenticator's response. Verification keeps only `clientDataJSON`, and reads the top-level `attestationObject`.",
475
+ }),
476
+ type: z
477
+ .string()
478
+ .max(32)
479
+ .meta({
480
+ description: 'The credential type.',
481
+ examples: ['public-key'],
482
+ }),
483
+ })
484
+ .meta({
485
+ description:
486
+ 'The `PublicKeyCredential` that `navigator.credentials.create()` returns, serialized as JSON.',
487
+ }),
488
+ })
489
+ .meta({
490
+ description:
491
+ 'The new passkey, serialized as `webauthx/client` returns it.',
492
+ id: 'PasskeyCredential',
493
+ })
494
+
495
+ /** A deferred link, as `seal` encrypts it. */
496
+ export const link = z.object({
497
+ address: z.string(),
498
+ createdAt: z.number().nullable(),
499
+ /** When the link expires, in seconds. */
500
+ expiresAt: z.number(),
501
+ /** The host that sealed it. Another host that shares the secret does not accept it. */
502
+ host: z.string(),
503
+ id: z.string(),
504
+ /** The value that the email step carries, which the emailed-code sign-in sends back. */
505
+ nonce: z.string(),
506
+ publicKey: z.templateLiteral(['0x', z.string()]),
507
+ rpId: z.string(),
508
+ })
509
+
510
+ /** A proof challenge's `verification` value. */
511
+ export const proof = z.object({
512
+ id: z.string(),
513
+ publicKey: hex,
514
+ rpId: z.string(),
515
+ })
516
+
517
+ /** A registration challenge's `verification` value. */
518
+ export const registration = z.object({
519
+ rpId: z.string(),
520
+ })
521
+
522
+ /** A signature challenge's `verification` value. */
523
+ export const signature = z.object({
524
+ account: z.string(),
525
+ clientId: z.string(),
526
+ credential: z.object({
527
+ id: z.string(),
528
+ publicKey: hex,
529
+ rpId: z.string(),
530
+ }),
531
+ })
532
+
533
+ /** The passkey step, which an approval of a key for a passkey-owned account returns. */
534
+ export const step = z
535
+ .object({
536
+ step: z
537
+ .object({
538
+ options: z
539
+ .object({
540
+ publicKey: z
541
+ .object({
542
+ allowCredentials: z
543
+ .array(
544
+ z
545
+ .object({
546
+ id: credentialId.meta({
547
+ description:
548
+ "The credential ID of the account's passkey, base64url.",
549
+ examples: ['KEbWNCc7NgaYnUyrNeFGX9_3Y-8'],
550
+ }),
551
+ type: z.literal('public-key').meta({
552
+ description: 'The credential type.',
553
+ }),
554
+ })
555
+ .meta({
556
+ description: 'The passkey that must sign.',
557
+ }),
558
+ )
559
+ .meta({
560
+ description:
561
+ "The account's passkey, the only one the browser offers.",
562
+ }),
563
+ challenge: z.templateLiteral(['0x', z.string()]).meta({
564
+ description:
565
+ "The key authorization's digest, as hex. It is single-use, and expires after 5 minutes.",
566
+ examples: [
567
+ '0xf6310589abb21116acc6e123967ed0a125b5041c43f8e157237093e07eaa354c',
568
+ ],
569
+ }),
570
+ rpId: z.string().meta({
571
+ description:
572
+ "The relying party ID of the account's passkey.",
573
+ examples: ['tempo.xyz'],
574
+ }),
575
+ userVerification: z.literal('required').meta({
576
+ description:
577
+ 'Every passkey signature requires user verification.',
578
+ }),
579
+ })
580
+ .meta({
581
+ description:
582
+ 'The `PublicKeyCredentialRequestOptions`, serialized with the challenge as hex.',
583
+ }),
584
+ })
585
+ .meta({
586
+ description: 'The options for `navigator.credentials.get()`.',
587
+ }),
588
+ type: z.literal('passkey').meta({
589
+ description:
590
+ 'Sign the options with the passkey, then repeat the approval with `passkey: { assertion }`.',
591
+ }),
592
+ })
593
+ .meta({
594
+ description:
595
+ "The next step: the passkey's signature over the key authorization's digest.",
596
+ }),
597
+ })
598
+ .meta({
599
+ description:
600
+ 'An approval that continues when the passkey signs the key authorization.',
601
+ id: 'PasskeyStep',
602
+ })
603
+
604
+ /** The passkey step of a headless authorization, which the app's page signs on its own origin. */
605
+ export const headlessStep = z
606
+ .object({
607
+ expiry: z
608
+ .number()
609
+ .int()
610
+ .meta({
611
+ description:
612
+ "The key's expiry in Unix seconds. The repeated request sends it as `key_authorization.expiry`, so the digest stays the same.",
613
+ examples: [1791869364],
614
+ }),
615
+ step: step.shape.step
616
+ .extend({
617
+ type: z.literal('passkey').meta({
618
+ description:
619
+ 'Sign the options with the passkey on the page, then repeat `POST /v1/authorize` with `passkey: { assertion }`.',
620
+ }),
621
+ })
622
+ .meta({
623
+ description:
624
+ "The next step: the passkey's signature over the key authorization's digest.",
625
+ }),
626
+ })
627
+ .meta({
628
+ description:
629
+ "A headless authorization that continues when the passkey that owns the account signs the key authorization on the app's page.",
630
+ id: 'HeadlessPasskeyStep',
631
+ })
632
+
633
+ /** A `user` row that the plugin's endpoint signs in, as `takeWithKey` reads it. */
634
+ export const user = z.object({
635
+ createdAt: z.date(),
636
+ email: z.string(),
637
+ emailVerified: z.boolean(),
638
+ id: z.string(),
639
+ image: z.string().nullable(),
640
+ name: z.string(),
641
+ updatedAt: z.date(),
642
+ })
643
+
644
+ /** A challenge's `verification` value. */
645
+ export const value = z.object({
646
+ // A key challenge of an app's page stores the request that its sign-in runs.
647
+ authorize: z.unknown().optional(),
648
+ clientId: z.string().nullable(),
649
+ link: z.string().optional(),
650
+ // A challenge without an origin runs at Tempo ID's own page.
651
+ origin: z.string().optional(),
652
+ // A stored challenge can name no realm. It verifies against stored passkeys only.
653
+ realmId: z.string().optional(),
654
+ rpId: z.string(),
655
+ // A key challenge is the digest of a key authorization with this witness.
656
+ witness: z.templateLiteral(['0x', z.string()]).optional(),
657
+ })
658
+ }
659
+
660
+ /**
661
+ * Issues a challenge for a sign-in at `rpId`, stores it until it expires, and returns it as hex.
662
+ * The challenge is random, or the digest of a key authorization for a sign-in with key signature,
663
+ * which stores its witness beside it. Returns `undefined` for a key challenge that a pending
664
+ * challenge already holds, since an app's challenge can repeat a digest, and one assertion must
665
+ * select exactly one request.
666
+ */
667
+ export async function challenge(
668
+ db: Realm.Database,
669
+ options: challenge.Options,
670
+ ) {
671
+ const value = (
672
+ options.keyChallenge?.digest ??
673
+ Hex.fromBytes(crypto.getRandomValues(new Uint8Array(32)))
674
+ ).toLowerCase() as Hex.Hex
675
+ const identifier = prefix + value
676
+ const row = {
677
+ expiresAt: new Date(Date.now() + lifetime * 1000),
678
+ id: crypto.randomUUID(),
679
+ identifier,
680
+ value: JSON.stringify(
681
+ schema.value.parse({
682
+ authorize: options.authorize,
683
+ clientId: options.clientId,
684
+ link: options.link,
685
+ origin: options.origin,
686
+ realmId: options.realmId,
687
+ rpId: options.rpId,
688
+ witness: options.keyChallenge?.witness,
689
+ }),
690
+ ),
691
+ }
692
+
693
+ // A random challenge never repeats, so only a key challenge needs the claim.
694
+ if (!options.keyChallenge) {
695
+ await db.insert(Schema.verification).values(row)
696
+ return value
697
+ }
698
+
699
+ // Concurrent requests for one digest claim one identifier, so only the first stores it.
700
+ const stored = await Verification.claim(db, row)
701
+ return stored ? value : undefined
702
+ }
703
+
704
+ export declare namespace challenge {
705
+ type Options = {
706
+ /**
707
+ * The headless authorization request that a sign-in with key signature on an app's page runs,
708
+ * as the page sent it with its key's expiry filled. Absent for any other sign-in.
709
+ */
710
+ authorize?: unknown
711
+ /** The client ID of the app the sign-in names, or `null` for none. */
712
+ clientId: string | null
713
+ /**
714
+ * The digest of the key authorization that a sign-in with key signature signs, and the witness
715
+ * that the digest binds. The digest takes the place of a random challenge. Absent for a plain
716
+ * sign-in.
717
+ */
718
+ keyChallenge?:
719
+ | {
720
+ /** The key authorization's digest, as hex. */
721
+ digest: Hex.Hex
722
+ /** The witness that the digest binds. */
723
+ witness: Hex.Hex
724
+ }
725
+ | undefined
726
+ /**
727
+ * The SHA-256 digest of the email step's link that the challenge confirms, as hex. Absent for a
728
+ * sign-in challenge.
729
+ */
730
+ link?: string | undefined
731
+ /**
732
+ * The origin of the app's page that the ceremony runs at. Absent for Tempo ID's own page. Only
733
+ * an assertion that reports it, from a request that page sends, spends the challenge.
734
+ */
735
+ origin?: string | undefined
736
+ /** The realm whose relying party the sign-in uses. */
737
+ realmId: string
738
+ /** The relying party ID the passkey must belong to. */
739
+ rpId: string
740
+ }
741
+ }
742
+
743
+ /**
744
+ * Returns why Tempo ID refuses a passkey ceremony on an app's page, or `undefined` when the page may
745
+ * run one. Tempo ID verifies the assertion for the page's origin, so only a first-party web app's
746
+ * page, at the origin of one of its redirect URIs, runs a ceremony:
747
+ *
748
+ * - A page sends the app's `client_id`, and the app must exist, be enabled, and be first-party.
749
+ * - A native app's request proves no app, so it signs in through an authentication sheet.
750
+ * - The request's `Origin` must be the origin of one of the app's redirect URIs.
751
+ */
752
+ export function checkPage(
753
+ options: checkPage.Options,
754
+ ): ErrorResponse.Instance<typeof checkPage.errors> | undefined {
755
+ const { app, clientId, origin } = options
756
+ if (!clientId)
757
+ return new Authorize.InvalidOriginError({
758
+ error_description: `Invalid \`Origin\`: ${origin ?? 'none'}. A passkey sign-in from an app's page sends the app's \`client_id\`.`,
759
+ field: 'Origin',
760
+ ...(origin ? { meta: { origin } } : {}),
761
+ })
762
+ if (!app || !app.firstParty)
763
+ return new Authorize.RejectedError({
764
+ description: `Passkey sign-in refused: ${clientId} is not a first-party app. Send the user to \`/oauth2/authorize\`, which offers passkey sign-in.`,
765
+ })
766
+ if (app.type === 'native')
767
+ return new Authorize.RejectedError({
768
+ description:
769
+ "Passkey sign-in refused: a native app's request does not prove which app sends it. Open `/oauth2/authorize` in an authentication sheet.",
770
+ })
771
+
772
+ const origins = app.redirectUris.flatMap((uri) => {
773
+ const url = URL.parse(uri)
774
+ return url?.protocol === 'https:' || url?.protocol === 'http:'
775
+ ? [url.origin]
776
+ : []
777
+ })
778
+ if (!origin || !origins.includes(origin))
779
+ return new Authorize.InvalidOriginError({
780
+ error_description: `Invalid \`Origin\`: ${origin ?? 'none'}. Passkey sign-in for ${clientId} must come from the origin of one of its redirect URIs.`,
781
+ field: 'Origin',
782
+ ...(origin ? { meta: { origin } } : {}),
783
+ })
784
+ return undefined
785
+ }
786
+
787
+ export namespace checkPage {
788
+ export type Options = {
789
+ /** The app that `clientId` names, or `undefined` when no enabled app has it. */
790
+ app: Pick<Apps.App, 'firstParty' | 'redirectUris' | 'type'> | undefined
791
+ /** The client ID that the request sends, if any. */
792
+ clientId: string | undefined
793
+ /** The request's `Origin`, if any. */
794
+ origin: string | undefined
795
+ }
796
+
797
+ /** The refusals `checkPage` returns. Its return type admits no other. */
798
+ export const errors = [
799
+ Authorize.InvalidOriginError,
800
+ Authorize.RejectedError,
801
+ ] as const
802
+ }
803
+
804
+ /** Returns the challenge of `clientDataJSON`, as hex, or `undefined` when it does not parse. */
805
+ function clientChallenge(options: take.Options) {
806
+ try {
807
+ const data = schema.clientData.parse(JSON.parse(options.clientDataJSON))
808
+ return Base64.toHex(data.challenge)
809
+ } catch {
810
+ return undefined
811
+ }
812
+ }
813
+
814
+ /**
815
+ * Returns the passkey with the credential `id` that belongs to `rpId`, or `undefined` when Tempo ID
816
+ * stores none.
817
+ */
818
+ export async function get(db: Realm.Database, options: get.Options) {
819
+ const [key] = await db
820
+ .select()
821
+ .from(Schema.keys)
822
+ .where(
823
+ and(eq(Schema.keys.id, options.id), eq(Schema.keys.rpId, options.rpId)),
824
+ )
825
+ return key
826
+ }
827
+
828
+ export declare namespace get {
829
+ type Options = {
830
+ /** The credential ID, base64url. */
831
+ id: string
832
+ /** The relying party ID the passkey must belong to. */
833
+ rpId: string
834
+ }
835
+ }
836
+
837
+ /**
838
+ * Stores a verified wallet.tempo passkey for `userId`, and returns the user the passkey's row names.
839
+ * A concurrent first sign-in of the same passkey can store the row first, so the row decides.
840
+ * Returns `undefined` when another passkey holds the address.
841
+ */
842
+ export async function link(db: Realm.Database, options: link.Options) {
843
+ const { credential, id, rpId, userId } = options
844
+ // `TempoAccount.create` takes the same lock to claim the realm of a first account, so a link
845
+ // either commits before the claim, and the claim gives way to it, or after it. A link after the
846
+ // claim adds the passkey's account beside the created one, as a link after its creation does.
847
+ return await db.transaction(async (tx) => {
848
+ await Owner.lock(tx, { userId })
849
+ // The `default` realm without a row signs in with a relying party that `Realm.withDefaults`
850
+ // derives. The first linked passkey stores it, so the unique `rp_id` keeps another realm from
851
+ // taking it, and a later change to `URL` keeps the passkeys that exist. A row already stored
852
+ // for `default`, or for this relying party, leaves the insert without effect.
853
+ await tx
854
+ .insert(Schema.realmPasskeys)
855
+ .values({ realmId: 'default', rpId })
856
+ .onConflictDoNothing()
857
+ const [inserted] = await tx
858
+ .insert(Schema.keys)
859
+ .values({
860
+ address: credential.address.toLowerCase(),
861
+ ...(credential.createdAt === null
862
+ ? {}
863
+ : { createdAt: new Date(credential.createdAt) }),
864
+ id,
865
+ publicKey: credential.publicKey,
866
+ rpId,
867
+ source: 'tempo-wallet',
868
+ type: 'passkey',
869
+ userId,
870
+ })
871
+ .onConflictDoNothing()
872
+ .returning({ userId: Schema.keys.userId })
873
+ if (inserted) return inserted.userId
874
+
875
+ const existing = await get(tx, { id, rpId })
876
+ return existing?.userId
877
+ })
878
+ }
879
+
880
+ export declare namespace link {
881
+ type Options = {
882
+ /** The passkey that wallet.tempo returned, which the assertion verified. */
883
+ credential: {
884
+ /** The address that the public key derives. */
885
+ address: string
886
+ /** When wallet.tempo created the passkey, in milliseconds, or `null` when it has no time. */
887
+ createdAt: number | null
888
+ /** The uncompressed P256 public key, hex. */
889
+ publicKey: Hex.Hex
890
+ }
891
+ /** The credential ID, base64url. */
892
+ id: string
893
+ /** The relying party of the passkey: the `default` realm's, which wallet.tempo shares. */
894
+ rpId: string
895
+ /** The user the passkey links to. */
896
+ userId: string
897
+ }
898
+ }
899
+
900
+ /**
901
+ * Derives the link cookie's own key from `secret` with HKDF-SHA256, as hex. The cookie thus shares
902
+ * no key with anything else that `SECRET` encrypts, such as the signing keys.
903
+ */
904
+ async function linkKey(secret: string) {
905
+ const encoder = new TextEncoder()
906
+ const material = await crypto.subtle.importKey(
907
+ 'raw',
908
+ encoder.encode(secret),
909
+ 'HKDF',
910
+ false,
911
+ ['deriveBits'],
912
+ )
913
+ const bits = await crypto.subtle.deriveBits(
914
+ {
915
+ hash: 'SHA-256',
916
+ info: encoder.encode('tempo-id:passkey-link:v1'),
917
+ name: 'HKDF',
918
+ salt: new Uint8Array(),
919
+ },
920
+ material,
921
+ 256,
922
+ )
923
+ return Hex.fromBytes(new Uint8Array(bits))
924
+ }
925
+
926
+ /**
927
+ * Returns the passkeys that the user with `userId` holds, of every relying party, oldest first. Each
928
+ * entry marks whether it counts toward {@link registrationLimit}, as {@link registered} counts it, so
929
+ * one read serves both the limit and the passkeys that a new registration excludes.
930
+ */
931
+ export async function list(db: Realm.Database, options: list.Options) {
932
+ return await db
933
+ .select({
934
+ id: Schema.keys.id,
935
+ registered: sql<boolean>`(${registeredKeys(options)})`,
936
+ rpId: Schema.keys.rpId,
937
+ })
938
+ .from(Schema.keys)
939
+ .where(eq(Schema.keys.userId, options.userId))
940
+ .orderBy(asc(Schema.keys.createdAt), asc(Schema.keys.id))
941
+ }
942
+
943
+ export declare namespace list {
944
+ type Options = {
945
+ /** The user's ID. */
946
+ userId: string
947
+ }
948
+ }
949
+
950
+ /**
951
+ * Instantiates a passkey sign-in plugin for Better Auth. Its server-only `signInPasskey` endpoint
952
+ * creates a session for a user whose assertion a route verified, and sets the session cookie. Like
953
+ * every sign-in, it continues an app's authorization that `oauth_query` names.
954
+ */
955
+ export function plugin() {
956
+ return {
957
+ endpoints: {
958
+ signInPasskey: createAuthEndpoint.serverOnly(
959
+ {
960
+ body: z.object({
961
+ oauth_query: z.string().optional(),
962
+ // The user row that the route already read with the passkey, which spares the read.
963
+ user: schema.user.optional(),
964
+ userId: z.string(),
965
+ }),
966
+ method: 'POST',
967
+ },
968
+ async (ctx) => {
969
+ const { user: read, userId } = ctx.body
970
+ const user =
971
+ read?.id === userId
972
+ ? read
973
+ : await ctx.context.internalAdapter.findUserById(userId)
974
+ if (!user) throw new Error('The passkey user is missing.')
975
+ const session = await ctx.context.internalAdapter.createSession(
976
+ user.id,
977
+ )
978
+ await setSessionCookie(ctx, { session, user })
979
+ return ctx.json({ user: { email: user.email, id: user.id } })
980
+ },
981
+ ),
982
+ },
983
+ id: 'tempo-id-passkey',
984
+ } satisfies BetterAuthPlugin
985
+ }
986
+
987
+ /**
988
+ * Returns how many passkeys the user with `userId` registered, of {@link registrationLimit} at most.
989
+ */
990
+ export async function registered(
991
+ db: Realm.Database,
992
+ options: registered.Options,
993
+ ) {
994
+ const [row] = await db
995
+ .select({ count: sql<number>`count(*)::int` })
996
+ .from(Schema.keys)
997
+ .where(registeredKeys(options))
998
+ return row?.count ?? 0
999
+ }
1000
+
1001
+ export declare namespace registered {
1002
+ type Options = {
1003
+ /** The user's ID. */
1004
+ userId: string
1005
+ }
1006
+ }
1007
+
1008
+ /**
1009
+ * Stores a passkey that the user with `userId` registered, once `verifyRegistration` accepted its
1010
+ * credential and `verify` its proof. Like a linked wallet.tempo passkey, it signs in, and owns the
1011
+ * Tempo Account at the address that its public key derives. It never replaces a stored row. Returns:
1012
+ *
1013
+ * - `stored` once it stores the passkey.
1014
+ * - `held` when Tempo ID already stores the credential ID or the address.
1015
+ * - `limit` when the user holds {@link registrationLimit} registered passkeys.
1016
+ * - `stale` when the `default` realm's relying party is no longer the challenge's.
1017
+ */
1018
+ export async function register(
1019
+ db: Realm.Database,
1020
+ options: register.Options,
1021
+ ): Promise<'held' | 'limit' | 'stale' | 'stored'> {
1022
+ const { id, publicKey, rpId, userId } = options
1023
+ return await db.transaction(async (tx) => {
1024
+ // The same lock as `link`, so a registration before the claim of a first account prevents the
1025
+ // Privy account, and one after it adds the passkey's account beside it. It also serializes the
1026
+ // count with the insert, so concurrent registrations stay within the limit.
1027
+ await Owner.lock(tx, { userId })
1028
+
1029
+ // As in `link`, the first stored passkey stores the relying party that `Realm.withDefaults`
1030
+ // derives for the `default` realm, so another realm cannot take it. A row that names another
1031
+ // relying party, set after the options, leaves the passkey outside the realm. One statement
1032
+ // counts the user's passkeys, and below the limit stores the relying party and locks its row.
1033
+ // The row lock holds until the insert commits, so a change of the relying party, such as
1034
+ // `Realm.setPasskeys`, waits for it and cannot land between the check and the insert.
1035
+ const counted = tx.$with('counted').as(
1036
+ tx
1037
+ .select({ count: sql<number>`count(*)::int`.as('count') })
1038
+ .from(Schema.keys)
1039
+ .where(registeredKeys({ userId })),
1040
+ )
1041
+ const stored = tx.$with('stored').as(
1042
+ tx
1043
+ .insert(Schema.realmPasskeys)
1044
+ // An insert from a query lists every column in the table's order.
1045
+ .select(
1046
+ sql`select now(), 'default', ${rpId} from ${counted} where ${counted.count} < ${registrationLimit}`,
1047
+ )
1048
+ .onConflictDoNothing()
1049
+ .returning({ rpId: Schema.realmPasskeys.rpId }),
1050
+ )
1051
+ const locked = tx
1052
+ .select({ rpId: Schema.realmPasskeys.rpId })
1053
+ .from(Schema.realmPasskeys)
1054
+ .where(eq(Schema.realmPasskeys.realmId, 'default'))
1055
+ .for('update')
1056
+ const [checked] = await tx
1057
+ .with(counted, stored)
1058
+ .select({
1059
+ count: counted.count,
1060
+ rpId: sql<
1061
+ string | null
1062
+ >`coalesce((select ${stored.rpId} from ${stored}), (${locked}))`,
1063
+ })
1064
+ .from(counted)
1065
+ if ((checked?.count ?? 0) >= registrationLimit) return 'limit'
1066
+
1067
+ // The statement reads only the rows that committed before it started, so it misses a `default`
1068
+ // row that another transaction stored during it. A second read returns that row.
1069
+ const realm = checked?.rpId ? { rpId: checked.rpId } : (await locked)[0]
1070
+ if (realm?.rpId !== rpId) return 'stale'
1071
+
1072
+ const [inserted] = await tx
1073
+ .insert(Schema.keys)
1074
+ .values({
1075
+ address: Address.fromPublicKey(
1076
+ PublicKey.fromHex(publicKey),
1077
+ ).toLowerCase(),
1078
+ id,
1079
+ publicKey,
1080
+ rpId,
1081
+ source: 'tempo-id',
1082
+ type: 'passkey',
1083
+ userId,
1084
+ })
1085
+ .onConflictDoNothing()
1086
+ .returning({ id: Schema.keys.id })
1087
+ return inserted ? 'stored' : 'held'
1088
+ })
1089
+ }
1090
+
1091
+ export declare namespace register {
1092
+ type Options = {
1093
+ /** The credential ID, base64url. */
1094
+ id: string
1095
+ /** The uncompressed P256 public key that the attestation holds, and the proof verified, hex. */
1096
+ publicKey: Hex.Hex
1097
+ /** The relying party of the `default` realm, which the challenge was issued for. */
1098
+ rpId: string
1099
+ /** The user who registers the passkey. */
1100
+ userId: string
1101
+ }
1102
+ }
1103
+
1104
+ /**
1105
+ * Returns the condition of the keys that count as passkeys that the user with `userId` registered.
1106
+ */
1107
+ function registeredKeys(options: registeredKeys.Options) {
1108
+ return and(
1109
+ // A registered passkey is Tempo ID's own and owns an account, so it holds an address.
1110
+ // `registered` is the earlier name of the same source, until a migration renames it.
1111
+ inArray(Schema.keys.source, ['registered', 'tempo-id']),
1112
+ isNotNull(Schema.keys.address),
1113
+ eq(Schema.keys.userId, options.userId),
1114
+ )
1115
+ }
1116
+
1117
+ declare namespace registeredKeys {
1118
+ type Options = {
1119
+ /** The user's ID. */
1120
+ userId: string
1121
+ }
1122
+ }
1123
+
1124
+ /**
1125
+ * Returns the first of `realms` that holds passkeys which can sign in at `origin`, and at `page`
1126
+ * when given, with its relying party ID, or `undefined` when none can. A WebAuthn ceremony runs
1127
+ * only at an origin whose host is the relying party ID or one of its subdomains.
1128
+ */
1129
+ export function relyingParty(
1130
+ realms: readonly Realm.Realm[],
1131
+ options: relyingParty.Options,
1132
+ ) {
1133
+ const hosts = [options.origin, options.page].flatMap((origin) =>
1134
+ origin ? [new URL(origin).hostname] : [],
1135
+ )
1136
+ for (const realm of realms) {
1137
+ const rpId = realm.passkeys?.rpId
1138
+ if (
1139
+ rpId !== undefined &&
1140
+ hosts.every((host) => host === rpId || host.endsWith(`.${rpId}`))
1141
+ )
1142
+ return { realmId: realm.id, rpId }
1143
+ }
1144
+ return undefined
1145
+ }
1146
+
1147
+ export declare namespace relyingParty {
1148
+ type Options = {
1149
+ /** Tempo ID's own origin. */
1150
+ origin: string
1151
+ /**
1152
+ * The origin of the app's page that runs the ceremony, if any. The relying party must cover it
1153
+ * and Tempo ID's origin both, so the page shares a site with Tempo ID, and the browser sends the
1154
+ * session cookie on the page's requests after the sign-in.
1155
+ */
1156
+ page?: string | undefined
1157
+ }
1158
+ }
1159
+
1160
+ /**
1161
+ * Issues a random challenge for the new passkey `credential` to sign, stores it with the passkey
1162
+ * until it expires, and returns it as hex. Only the user with `userId` spends it. The attestation
1163
+ * of format `none` carries no signature, so only this assertion proves that the user holds the
1164
+ * passkey's private key.
1165
+ */
1166
+ export async function requestProof(
1167
+ db: Realm.Database,
1168
+ options: requestProof.Options,
1169
+ ) {
1170
+ const { credential, rpId, userId } = options
1171
+ const challenge = Hex.fromBytes(crypto.getRandomValues(new Uint8Array(32)))
1172
+ await db.insert(Schema.verification).values({
1173
+ expiresAt: new Date(Date.now() + lifetime * 1000),
1174
+ id: crypto.randomUUID(),
1175
+ identifier: registrationIdentifier({
1176
+ challenge,
1177
+ prefix: proofPrefix,
1178
+ userId,
1179
+ }),
1180
+ value: JSON.stringify(schema.proof.parse({ ...credential, rpId })),
1181
+ })
1182
+ return challenge
1183
+ }
1184
+
1185
+ export declare namespace requestProof {
1186
+ type Options = {
1187
+ /** The new passkey, as `verifyRegistration` returned it. */
1188
+ credential: {
1189
+ /** The credential ID, base64url. */
1190
+ id: string
1191
+ /** The uncompressed P256 public key that the attestation holds, hex. */
1192
+ publicKey: Hex.Hex
1193
+ }
1194
+ /** The relying party of the `default` realm, which the new passkey belongs to. */
1195
+ rpId: string
1196
+ /** The signed-in user's ID. */
1197
+ userId: string
1198
+ }
1199
+ }
1200
+
1201
+ /**
1202
+ * Issues a random challenge for the registration of a passkey of `rpId` by the user with `userId`,
1203
+ * stores it until it expires, and returns it as hex. Only that user spends it.
1204
+ */
1205
+ export async function requestRegistration(
1206
+ db: Realm.Database,
1207
+ options: requestRegistration.Options,
1208
+ ) {
1209
+ const challenge = Hex.fromBytes(crypto.getRandomValues(new Uint8Array(32)))
1210
+ await db.insert(Schema.verification).values({
1211
+ expiresAt: new Date(Date.now() + lifetime * 1000),
1212
+ id: crypto.randomUUID(),
1213
+ identifier: registrationIdentifier({
1214
+ challenge,
1215
+ prefix: registrationPrefix,
1216
+ userId: options.userId,
1217
+ }),
1218
+ value: JSON.stringify(schema.registration.parse({ rpId: options.rpId })),
1219
+ })
1220
+ return challenge
1221
+ }
1222
+
1223
+ export declare namespace requestRegistration {
1224
+ type Options = {
1225
+ /** The relying party of the `default` realm, which the new passkey must belong to. */
1226
+ rpId: string
1227
+ /** The signed-in user's ID. */
1228
+ userId: string
1229
+ }
1230
+ }
1231
+
1232
+ /**
1233
+ * Returns the `verification` identifier of a registration or proof challenge, which names its step,
1234
+ * its user, and the challenge. JSON keeps each value apart, whatever characters it holds.
1235
+ */
1236
+ function registrationIdentifier(options: registrationIdentifier.Options) {
1237
+ return (
1238
+ options.prefix +
1239
+ JSON.stringify([options.userId, options.challenge.toLowerCase()])
1240
+ )
1241
+ }
1242
+
1243
+ declare namespace registrationIdentifier {
1244
+ type Options = {
1245
+ /** The challenge, as hex. */
1246
+ challenge: Hex.Hex
1247
+ /** The step's prefix: {@link registrationPrefix} or {@link proofPrefix}. */
1248
+ prefix: typeof proofPrefix | typeof registrationPrefix
1249
+ /** The user's ID. */
1250
+ userId: string
1251
+ }
1252
+ }
1253
+
1254
+ /**
1255
+ * Stores the digest of a key authorization as the challenge of a signature by `credential`, until it
1256
+ * expires. Only the user with `userId` spends it, for the same account, app, and passkey.
1257
+ */
1258
+ export async function requestSignature(
1259
+ db: Realm.Database,
1260
+ options: requestSignature.Options,
1261
+ ) {
1262
+ const { account, clientId, credential, digest, userId } = options
1263
+ await db.insert(Schema.verification).values({
1264
+ expiresAt: new Date(Date.now() + lifetime * 1000),
1265
+ id: crypto.randomUUID(),
1266
+ identifier: signatureIdentifier({
1267
+ account,
1268
+ clientId,
1269
+ credentialId: credential.id,
1270
+ digest,
1271
+ userId,
1272
+ }),
1273
+ value: JSON.stringify(
1274
+ schema.signature.parse({
1275
+ account: account.toLowerCase(),
1276
+ clientId,
1277
+ credential,
1278
+ }),
1279
+ ),
1280
+ })
1281
+ }
1282
+
1283
+ export declare namespace requestSignature {
1284
+ type Options = {
1285
+ /** The address of the Tempo Account that the key acts for. */
1286
+ account: string
1287
+ /** The client ID of the app that requests the key. */
1288
+ clientId: string
1289
+ /** The passkey that must sign: the account's owner. */
1290
+ credential: Owner.Credential
1291
+ /** The digest of the key authorization, as hex. */
1292
+ digest: Hex.Hex
1293
+ /** The signed-in user's ID. */
1294
+ userId: string
1295
+ }
1296
+ }
1297
+
1298
+ /**
1299
+ * Encrypts a deferred link with a key derived from `secret`, for the link cookie. The cookie cannot
1300
+ * be read, changed, or forged without the secret.
1301
+ */
1302
+ export async function seal(value: Link, options: seal.Options) {
1303
+ return await symmetricEncrypt({
1304
+ data: JSON.stringify(schema.link.parse(value)),
1305
+ key: await linkKey(options.secret),
1306
+ })
1307
+ }
1308
+
1309
+ export declare namespace seal {
1310
+ type Options = {
1311
+ /** The `SECRET` variable. */
1312
+ secret: string
1313
+ }
1314
+ }
1315
+
1316
+ /**
1317
+ * Spends the challenge that `clientDataJSON` names, and returns it, or `undefined` when it is
1318
+ * unknown, spent, or expired. One statement deletes and returns the row, so two concurrent
1319
+ * assertions over one challenge cannot both spend it.
1320
+ */
1321
+ export async function take(
1322
+ db: Realm.Database,
1323
+ options: take.Options,
1324
+ ): Promise<Challenge | undefined> {
1325
+ const challenge = clientChallenge(options)
1326
+ if (!challenge) return undefined
1327
+
1328
+ const [row] = await db
1329
+ .delete(Schema.verification)
1330
+ .where(
1331
+ and(
1332
+ eq(Schema.verification.identifier, prefix + challenge.toLowerCase()),
1333
+ gt(Schema.verification.expiresAt, new Date()),
1334
+ ),
1335
+ )
1336
+ .returning({ value: Schema.verification.value })
1337
+ if (!row) return undefined
1338
+ return toChallenge(row.value, { challenge })
1339
+ }
1340
+
1341
+ export declare namespace take {
1342
+ type Options = {
1343
+ /** The assertion's client data, as the JSON string the browser collected. */
1344
+ clientDataJSON: string
1345
+ }
1346
+ }
1347
+
1348
+ /** Returns the challenge that a stored `value` describes, once spent. */
1349
+ function toChallenge(value: string, options: toChallenge.Options): Challenge {
1350
+ const parsed = schema.value.parse(JSON.parse(value))
1351
+ return {
1352
+ authorize: parsed.authorize,
1353
+ challenge: options.challenge,
1354
+ clientId: parsed.clientId,
1355
+ link: parsed.link,
1356
+ origin: parsed.origin,
1357
+ realmId: parsed.realmId,
1358
+ rpId: parsed.rpId,
1359
+ witness: parsed.witness,
1360
+ }
1361
+ }
1362
+
1363
+ declare namespace toChallenge {
1364
+ type Options = {
1365
+ /** The challenge, as hex. */
1366
+ challenge: Hex.Hex
1367
+ }
1368
+ }
1369
+
1370
+ /**
1371
+ * Spends the challenge that `clientDataJSON` names, as {@link take} does, and returns it with the
1372
+ * passkey with the credential `id` at the challenge's relying party and that passkey's user, in one
1373
+ * statement. The challenge is spent whether or not the passkey exists. Returns `undefined` when the
1374
+ * challenge is unknown, spent, or expired, and no `key` when Tempo ID stores no such passkey.
1375
+ */
1376
+ export async function takeWithKey(
1377
+ db: Realm.Database,
1378
+ options: takeWithKey.Options,
1379
+ ): Promise<takeWithKey.ReturnType | undefined> {
1380
+ const challenge = clientChallenge(options)
1381
+ if (!challenge) return undefined
1382
+
1383
+ // A data-modifying CTE runs once, to completion, whatever the outer query reads, so the delete
1384
+ // spends the challenge even when no passkey matches.
1385
+ const spent = db.$with('spent').as(
1386
+ db
1387
+ .delete(Schema.verification)
1388
+ .where(
1389
+ and(
1390
+ eq(Schema.verification.identifier, prefix + challenge.toLowerCase()),
1391
+ gt(Schema.verification.expiresAt, new Date()),
1392
+ ),
1393
+ )
1394
+ .returning({ value: Schema.verification.value }),
1395
+ )
1396
+ const [row] = await db
1397
+ .with(spent)
1398
+ .select({
1399
+ // Drizzle reads a joined object as absent when its first column is null, and `address` is
1400
+ // null for a sign-in passkey, so the key selects only columns that are never null.
1401
+ key: {
1402
+ id: Schema.keys.id,
1403
+ publicKey: Schema.keys.publicKey,
1404
+ userId: Schema.keys.userId,
1405
+ },
1406
+ user: Schema.user,
1407
+ value: spent.value,
1408
+ })
1409
+ .from(spent)
1410
+ .leftJoin(
1411
+ Schema.keys,
1412
+ and(
1413
+ eq(Schema.keys.id, options.id),
1414
+ eq(Schema.keys.rpId, sql`(${spent.value})::jsonb ->> 'rpId'`),
1415
+ ),
1416
+ )
1417
+ .leftJoin(Schema.user, eq(Schema.user.id, Schema.keys.userId))
1418
+ if (!row) return undefined
1419
+ return {
1420
+ challenge: toChallenge(row.value, { challenge }),
1421
+ key: row.key && row.user ? { ...row.key, user: row.user } : undefined,
1422
+ }
1423
+ }
1424
+
1425
+ export declare namespace takeWithKey {
1426
+ type Options = take.Options & {
1427
+ /** The credential ID of the passkey that signed the assertion, base64url. */
1428
+ id: string
1429
+ }
1430
+
1431
+ type ReturnType = {
1432
+ /** The spent challenge. */
1433
+ challenge: Challenge
1434
+ /**
1435
+ * The passkey with the credential ID at the challenge's relying party, with its user, or
1436
+ * `undefined` when Tempo ID stores none.
1437
+ */
1438
+ key:
1439
+ | {
1440
+ /** The credential ID, base64url. */
1441
+ id: string
1442
+ /** The uncompressed P256 public key, hex. */
1443
+ publicKey: string
1444
+ /** The user that the passkey signs in. */
1445
+ user: typeof Schema.user.$inferSelect
1446
+ /** The ID of that user. */
1447
+ userId: string
1448
+ }
1449
+ | undefined
1450
+ }
1451
+ }
1452
+
1453
+ /**
1454
+ * Spends the proof challenge that `clientDataJSON` names for the user with `userId`, and returns it
1455
+ * with the new passkey, or `undefined` when it is unknown, spent, expired, or another user's. One
1456
+ * statement deletes and returns the row, so two concurrent proofs cannot both spend it.
1457
+ */
1458
+ export async function takeProof(
1459
+ db: Realm.Database,
1460
+ options: takeProof.Options,
1461
+ ): Promise<ProofChallenge | undefined> {
1462
+ const challenge = (() => {
1463
+ try {
1464
+ const data = schema.clientData.parse(JSON.parse(options.clientDataJSON))
1465
+ return Base64.toHex(data.challenge)
1466
+ } catch {
1467
+ return undefined
1468
+ }
1469
+ })()
1470
+ if (!challenge) return undefined
1471
+
1472
+ const [row] = await db
1473
+ .delete(Schema.verification)
1474
+ .where(
1475
+ and(
1476
+ eq(
1477
+ Schema.verification.identifier,
1478
+ registrationIdentifier({
1479
+ challenge,
1480
+ prefix: proofPrefix,
1481
+ userId: options.userId,
1482
+ }),
1483
+ ),
1484
+ gt(Schema.verification.expiresAt, new Date()),
1485
+ ),
1486
+ )
1487
+ .returning({ value: Schema.verification.value })
1488
+ if (!row) return undefined
1489
+
1490
+ return { ...schema.proof.parse(JSON.parse(row.value)), challenge }
1491
+ }
1492
+
1493
+ export declare namespace takeProof {
1494
+ type Options = {
1495
+ /** The assertion's client data, as the JSON string the browser collected. */
1496
+ clientDataJSON: string
1497
+ /** The signed-in user's ID. */
1498
+ userId: string
1499
+ }
1500
+ }
1501
+
1502
+ /**
1503
+ * Spends the registration challenge that `clientDataJSON` names for the user with `userId`, and
1504
+ * returns it, or `undefined` when it is unknown, spent, expired, or another user's. One statement
1505
+ * deletes and returns the row, so two concurrent registrations over one challenge cannot both
1506
+ * spend it.
1507
+ */
1508
+ export async function takeRegistration(
1509
+ db: Realm.Database,
1510
+ options: takeRegistration.Options,
1511
+ ): Promise<RegistrationChallenge | undefined> {
1512
+ const challenge = (() => {
1513
+ try {
1514
+ const data = schema.clientData.parse(
1515
+ JSON.parse(Base64.toString(options.clientDataJSON)),
1516
+ )
1517
+ return Base64.toHex(data.challenge)
1518
+ } catch {
1519
+ return undefined
1520
+ }
1521
+ })()
1522
+ if (!challenge) return undefined
1523
+
1524
+ const [row] = await db
1525
+ .delete(Schema.verification)
1526
+ .where(
1527
+ and(
1528
+ eq(
1529
+ Schema.verification.identifier,
1530
+ registrationIdentifier({
1531
+ challenge,
1532
+ prefix: registrationPrefix,
1533
+ userId: options.userId,
1534
+ }),
1535
+ ),
1536
+ gt(Schema.verification.expiresAt, new Date()),
1537
+ ),
1538
+ )
1539
+ .returning({ value: Schema.verification.value })
1540
+ if (!row) return undefined
1541
+
1542
+ const value = schema.registration.parse(JSON.parse(row.value))
1543
+ return { challenge, rpId: value.rpId }
1544
+ }
1545
+
1546
+ export declare namespace takeRegistration {
1547
+ type Options = {
1548
+ /** The credential's client data, base64url, as the browser collected it. */
1549
+ clientDataJSON: string
1550
+ /** The signed-in user's ID. */
1551
+ userId: string
1552
+ }
1553
+ }
1554
+
1555
+ /**
1556
+ * Records the assertion of a sign-in with key signature on an app's page as spent until `expiry`, once it
1557
+ * verified, and returns whether neither a sign-in nor a signature spent it before. The assertion
1558
+ * becomes public once its key reaches the chain, and an app's challenge can repeat its digest, so
1559
+ * the record holds whatever signs the key, and also when the authorization fails.
1560
+ */
1561
+ export async function spendSignIn(
1562
+ db: Realm.Database,
1563
+ options: spendSignIn.Options,
1564
+ ) {
1565
+ const signed = spentIdentifier(options)
1566
+ const signedIn = spentSignInPrefix + signed.slice(spentPrefix.length)
1567
+ return await db.transaction(async (tx) => {
1568
+ // The same lock as `takeSignature`, so a sign-in and a signature of one assertion serialize, and
1569
+ // the claim reads the record of a signature that committed while it waited.
1570
+ await tx.execute(
1571
+ sql`select pg_advisory_xact_lock(hashtextextended(${signed}, 0))`,
1572
+ )
1573
+ return await Verification.claim(tx, {
1574
+ expiresAt: new Date(
1575
+ Math.min(
1576
+ Math.max(options.expiry * 1000, Date.now() + lifetime * 1000),
1577
+ Date.now() + spentLifetime * 1000,
1578
+ ),
1579
+ ),
1580
+ identifier: signedIn,
1581
+ others: [signed],
1582
+ value: '{}',
1583
+ })
1584
+ })
1585
+ }
1586
+
1587
+ export declare namespace spendSignIn {
1588
+ type Options = {
1589
+ /** The assertion's authenticator data, as hex. */
1590
+ authenticatorData: Hex.Hex
1591
+ /**
1592
+ * When the key that the assertion signs expires, in Unix seconds. The record lasts until then,
1593
+ * for a year at most.
1594
+ */
1595
+ expiry: number
1596
+ /** The assertion's signature, as hex. */
1597
+ signature: Hex.Hex
1598
+ }
1599
+ }
1600
+
1601
+ /**
1602
+ * Records the assertion of a sign-in with key signature as a spent signature until `expiry`, for a year at
1603
+ * most, and returns whether no signature spent it before. The sign-in's challenge was the key's
1604
+ * digest, so no signature challenge precedes it, and the caller verifies the assertion over that
1605
+ * digest first. It takes the lock of {@link takeSignature}, so an approval that repeats the
1606
+ * assertion records it once.
1607
+ */
1608
+ export async function spendSignature(
1609
+ db: Realm.Database,
1610
+ options: spendSignature.Options,
1611
+ ) {
1612
+ const spentId = spentIdentifier(options)
1613
+ return await db.transaction(async (tx) => {
1614
+ await tx.execute(
1615
+ sql`select pg_advisory_xact_lock(hashtextextended(${spentId}, 0))`,
1616
+ )
1617
+ return await Verification.claim(tx, {
1618
+ expiresAt: new Date(
1619
+ Math.min(
1620
+ Math.max(options.expiry * 1000, Date.now() + lifetime * 1000),
1621
+ Date.now() + spentLifetime * 1000,
1622
+ ),
1623
+ ),
1624
+ identifier: spentId,
1625
+ value: '{}',
1626
+ })
1627
+ })
1628
+ }
1629
+
1630
+ export declare namespace spendSignature {
1631
+ type Options = spendSignIn.Options
1632
+ }
1633
+
1634
+ /**
1635
+ * Spends the signature challenge that `clientDataJSON` names, for the user, app, account, and
1636
+ * passkey of `options`, and returns it, or `undefined` when it is unknown, spent, or expired. One
1637
+ * statement deletes and returns the rows, so two concurrent assertions over one challenge cannot
1638
+ * both spend it, and an approval for another app, account, or passkey spends none of its rows.
1639
+ *
1640
+ * Returns the challenge only when `verify` accepts it with the assertion. Every step for the same
1641
+ * key issues the same digest, so the transaction then records the assertion as spent until
1642
+ * `expiry`, for a year at most, and returns `undefined` for an assertion that it recorded before. A captured assertion
1643
+ * thus signs no second approval, and an assertion that does not verify leaves no record.
1644
+ */
1645
+ export async function takeSignature(
1646
+ db: Realm.Database,
1647
+ options: takeSignature.Options,
1648
+ ): Promise<SignatureChallenge | undefined> {
1649
+ const digest = (() => {
1650
+ try {
1651
+ const data = schema.clientData.parse(JSON.parse(options.clientDataJSON))
1652
+ return Base64.toHex(data.challenge)
1653
+ } catch {
1654
+ return undefined
1655
+ }
1656
+ })()
1657
+ if (!digest) return undefined
1658
+
1659
+ const spentId = spentIdentifier(options)
1660
+
1661
+ return await db.transaction(async (tx) => {
1662
+ // The lock serializes requests with one assertion, so only the first records it.
1663
+ await tx.execute(
1664
+ sql`select pg_advisory_xact_lock(hashtextextended(${spentId}, 0))`,
1665
+ )
1666
+ const [used] = await tx
1667
+ .select({ id: Schema.verification.id })
1668
+ .from(Schema.verification)
1669
+ .where(
1670
+ and(
1671
+ eq(Schema.verification.identifier, spentId),
1672
+ gt(Schema.verification.expiresAt, new Date()),
1673
+ ),
1674
+ )
1675
+
1676
+ // Each approval of one request issues the same digest, so every row that it names is spent.
1677
+ // A replayed assertion spends the challenge too, so the step must run again.
1678
+ const [row] = await tx
1679
+ .delete(Schema.verification)
1680
+ .where(
1681
+ and(
1682
+ eq(
1683
+ Schema.verification.identifier,
1684
+ signatureIdentifier({ ...options, digest }),
1685
+ ),
1686
+ gt(Schema.verification.expiresAt, new Date()),
1687
+ ),
1688
+ )
1689
+ .returning({ value: Schema.verification.value })
1690
+ if (!row || used) return undefined
1691
+ const value = { ...schema.signature.parse(JSON.parse(row.value)), digest }
1692
+ if (!options.verify(value)) return undefined
1693
+
1694
+ // A signed request with the same key can reach a new step until the key expires.
1695
+ await tx.insert(Schema.verification).values({
1696
+ expiresAt: new Date(
1697
+ Math.min(
1698
+ Math.max(options.expiry * 1000, Date.now() + lifetime * 1000),
1699
+ Date.now() + spentLifetime * 1000,
1700
+ ),
1701
+ ),
1702
+ id: crypto.randomUUID(),
1703
+ identifier: spentId,
1704
+ value: '{}',
1705
+ })
1706
+ return value
1707
+ })
1708
+ }
1709
+
1710
+ export declare namespace takeSignature {
1711
+ type Options = {
1712
+ /** The address of the Tempo Account that the key acts for. */
1713
+ account: string
1714
+ /** The assertion's authenticator data, as hex. */
1715
+ authenticatorData: Hex.Hex
1716
+ /** The client ID of the app that requests the key. */
1717
+ clientId: string
1718
+ /** The assertion's client data, as the JSON string the browser collected. */
1719
+ clientDataJSON: string
1720
+ /** The credential ID of the passkey that signed, base64url. */
1721
+ credentialId: string
1722
+ /**
1723
+ * When the key expires, in Unix seconds. The spent assertion stays recorded until then, for a
1724
+ * year at most.
1725
+ */
1726
+ expiry: number
1727
+ /** The assertion's signature, as hex. */
1728
+ signature: Hex.Hex
1729
+ /** The signed-in user's ID. */
1730
+ userId: string
1731
+ /**
1732
+ * Returns whether the assertion verifies over the spent challenge, for the account, app, and
1733
+ * passkey that it names. It runs in the transaction, so it performs no I/O.
1734
+ */
1735
+ verify: (challenge: SignatureChallenge) => boolean
1736
+ }
1737
+ }
1738
+
1739
+ /**
1740
+ * Returns the `verification` identifier of a signature challenge, which names its user, app,
1741
+ * account, passkey, and digest. JSON keeps each value apart, whatever characters it holds.
1742
+ */
1743
+ function signatureIdentifier(options: signatureIdentifier.Options) {
1744
+ return (
1745
+ signaturePrefix +
1746
+ JSON.stringify([
1747
+ options.userId,
1748
+ options.clientId,
1749
+ options.account.toLowerCase(),
1750
+ options.credentialId,
1751
+ options.digest.toLowerCase(),
1752
+ ])
1753
+ )
1754
+ }
1755
+
1756
+ declare namespace signatureIdentifier {
1757
+ type Options = {
1758
+ /** The address of the Tempo Account that the key acts for. */
1759
+ account: string
1760
+ /** The client ID of the app that requests the key. */
1761
+ clientId: string
1762
+ /** The credential ID of the passkey that signs, base64url. */
1763
+ credentialId: string
1764
+ /** The digest of the key authorization, as hex. */
1765
+ digest: Hex.Hex
1766
+ /** The signed-in user's ID. */
1767
+ userId: string
1768
+ }
1769
+ }
1770
+
1771
+ /**
1772
+ * Returns the `verification` identifier of an assertion that a signature spent. Verification
1773
+ * refuses the high-`s` form of a P-256 signature, so each verified assertion has one identifier.
1774
+ */
1775
+ function spentIdentifier(options: Omit<spendSignIn.Options, 'expiry'>) {
1776
+ return (
1777
+ spentPrefix +
1778
+ Hash.sha256(Hex.concat(options.authenticatorData, options.signature))
1779
+ )
1780
+ }
1781
+
1782
+ /**
1783
+ * Decrypts the link cookie's value, and returns the deferred link, or `undefined` when the value
1784
+ * does not decrypt with `secret`, has another shape, came from another host, or expired.
1785
+ */
1786
+ export async function unseal(sealed: string, options: unseal.Options) {
1787
+ const value = await symmetricDecrypt({
1788
+ data: sealed,
1789
+ key: await linkKey(options.secret),
1790
+ })
1791
+ .then((data) => schema.link.safeParse(JSON.parse(data)))
1792
+ .catch(() => undefined)
1793
+ if (!value?.success) return undefined
1794
+ if (value.data.host !== options.host) return undefined
1795
+ if (value.data.expiresAt <= Date.now() / 1000) return undefined
1796
+ return value.data
1797
+ }
1798
+
1799
+ export declare namespace unseal {
1800
+ type Options = {
1801
+ /** The host that serves the request, which must be the one that sealed the link. */
1802
+ host: string
1803
+ /** The `SECRET` variable. */
1804
+ secret: string
1805
+ }
1806
+ }
1807
+
1808
+ /**
1809
+ * Builds the curve's table of base point multiples once for each isolate, at window 4. Otherwise
1810
+ * the first verification builds the table at window 8, which takes about six times the CPU, and
1811
+ * verifies at the same speed.
1812
+ */
1813
+ function table() {
1814
+ if (tabled) return
1815
+ P256.noble.utils.precompute(4)
1816
+ tabled = true
1817
+ }
1818
+
1819
+ /**
1820
+ * Returns whether `assertion` signs `challenge` with `publicKey`, at `origin`, for `rpId`, with the
1821
+ * user present and verified, outside a cross-origin iframe. The client cannot waive user
1822
+ * verification.
1823
+ */
1824
+ export function verify(assertion: Assertion, options: verify.Options) {
1825
+ table()
1826
+ try {
1827
+ // WebAuthn verification leaves `crossOrigin` to the relying party. A frame on another site
1828
+ // could otherwise run the ceremony for Tempo ID's origin.
1829
+ const data = schema.clientData.parse(
1830
+ JSON.parse(assertion.metadata.clientDataJSON),
1831
+ )
1832
+ if (data.crossOrigin) return false
1833
+
1834
+ return Authentication.verify(
1835
+ {
1836
+ ...assertion,
1837
+ metadata: { ...assertion.metadata, userVerificationRequired: true },
1838
+ },
1839
+ {
1840
+ challenge: options.challenge,
1841
+ origin: options.origin,
1842
+ publicKey: options.publicKey,
1843
+ rpId: options.rpId,
1844
+ },
1845
+ )
1846
+ } catch {
1847
+ return false
1848
+ }
1849
+ }
1850
+
1851
+ export declare namespace verify {
1852
+ type Options = {
1853
+ /** The challenge that Tempo ID issued, as hex. */
1854
+ challenge: Hex.Hex
1855
+ /** The origin the ceremony must report: Tempo ID's own, or the app's page that the challenge names. */
1856
+ origin: string
1857
+ /** The passkey's uncompressed P256 public key, hex. */
1858
+ publicKey: Hex.Hex
1859
+ /** The relying party ID the challenge was issued for. */
1860
+ rpId: string
1861
+ }
1862
+ }
1863
+
1864
+ /**
1865
+ * Returns the credential ID and public key of the passkey that `credential` creates, or `undefined`
1866
+ * when it does not create one over `challenge`, at `origin`, for `rpId`, with the user present and
1867
+ * verified, outside a cross-origin iframe. The public key comes from the attestation object. An
1868
+ * attestation of format `none` passes, as most authenticators return no other. It proves nothing
1869
+ * about the private key, so the passkey must then sign a proof challenge from `requestProof`.
1870
+ */
1871
+ export function verifyRegistration(
1872
+ credential: Credential,
1873
+ options: verifyRegistration.Options,
1874
+ ) {
1875
+ try {
1876
+ // As in `verify`, a frame on another site could otherwise run the ceremony for Tempo ID's origin.
1877
+ const data = schema.clientData.parse(
1878
+ JSON.parse(Base64.toString(credential.clientDataJSON)),
1879
+ )
1880
+ if (data.crossOrigin) return undefined
1881
+
1882
+ const result = Registration.verify(credential as Registration.Credential, {
1883
+ attestation: 'none',
1884
+ challenge: options.challenge,
1885
+ origin: options.origin,
1886
+ rpId: options.rpId,
1887
+ userVerification: 'required',
1888
+ })
1889
+ return { id: result.credential.id, publicKey: result.credential.publicKey }
1890
+ } catch {
1891
+ return undefined
1892
+ }
1893
+ }
1894
+
1895
+ export declare namespace verifyRegistration {
1896
+ type Options = {
1897
+ /** The registration challenge that Tempo ID issued, as hex. */
1898
+ challenge: Hex.Hex
1899
+ /** The origin the ceremony must report: Tempo ID's own. */
1900
+ origin: string
1901
+ /** The relying party ID the challenge was issued for. */
1902
+ rpId: string
1903
+ }
1904
+ }