@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.
- package/README.md +121 -2
- package/dist/App.d.ts +121 -0
- package/dist/App.d.ts.map +1 -0
- package/dist/App.js +132 -0
- package/dist/App.js.map +1 -0
- package/dist/app/client/.assetsignore +2 -0
- package/dist/app/client/_headers +4 -0
- package/dist/app/client/assets/Account-BYLpNFf3.css +1 -0
- package/dist/app/client/assets/Account-BllJah07.js +1 -0
- package/dist/app/client/assets/Amount-E_7snI0-.js +1 -0
- package/dist/app/client/assets/Amount-ZdtluGf-.css +1 -0
- package/dist/app/client/assets/Approval-CgV5JHlb.css +1 -0
- package/dist/app/client/assets/Approval-yKflypU2.js +1 -0
- package/dist/app/client/assets/ArrowUp-CRvqfMNU.js +1 -0
- package/dist/app/client/assets/Authentication-BAXhOh_4.js +2 -0
- package/dist/app/client/assets/BRLA-CZvVDNYr.png +0 -0
- package/dist/app/client/assets/BRZ-Cn3jEi9t.svg +1 -0
- package/dist/app/client/assets/CHFAU-DCedc4aH.png +0 -0
- package/dist/app/client/assets/Callout-B736759d.js +1 -0
- package/dist/app/client/assets/Callout-DBfEmP7q.css +1 -0
- package/dist/app/client/assets/Check-DVgD8tDG.js +1 -0
- package/dist/app/client/assets/ChevronRight-CsXtIZCB.js +1 -0
- package/dist/app/client/assets/ChooseAccount-BjxfQjPK.js +1 -0
- package/dist/app/client/assets/ChooseAccount-DL3wgJhE.css +1 -0
- package/dist/app/client/assets/Client-JrABNovb.js +1 -0
- package/dist/app/client/assets/Close-CRvWlhqc.js +1 -0
- package/dist/app/client/assets/Cloud-DgJsrqpQ.js +1 -0
- package/dist/app/client/assets/CodeInput-79Ctx8ZA.js +1 -0
- package/dist/app/client/assets/CodeInput-BqRteSwD.css +1 -0
- package/dist/app/client/assets/DLUSD-BnRXm3EI.png +0 -0
- package/dist/app/client/assets/Deposit-CclrAoXL.css +1 -0
- package/dist/app/client/assets/Deposit-c7uYn2Eb.js +1 -0
- package/dist/app/client/assets/DevTools-BYkmtuV5.css +1 -0
- package/dist/app/client/assets/DevTools-BgnzDGo2.js +1 -0
- package/dist/app/client/assets/DeviceApproval-BBUVv58e.js +1 -0
- package/dist/app/client/assets/DeviceApproval-BffFLD8F.css +1 -0
- package/dist/app/client/assets/EURAU-sjieTTB9.svg +1 -0
- package/dist/app/client/assets/EURC.e-CxYiiwkz.svg +1 -0
- package/dist/app/client/assets/Fingerprint-BNCA6qOJ.js +1 -0
- package/dist/app/client/assets/GBPA-DI_25xSG.svg +4 -0
- package/dist/app/client/assets/GUSD-BDEP2Qb-.svg +1 -0
- package/dist/app/client/assets/GeistMono-Variable-BRXCGrxA.woff2 +0 -0
- package/dist/app/client/assets/Globe-f0eWzcEI.js +1 -0
- package/dist/app/client/assets/Grant-5a-n1gJH.css +1 -0
- package/dist/app/client/assets/Grant-Dp7mpcEi.js +1 -0
- package/dist/app/client/assets/Hex-C9KeV7_9.css +1 -0
- package/dist/app/client/assets/Hex-CSp2U46W.js +10 -0
- package/dist/app/client/assets/IconChip-DpZHa1JW.js +1 -0
- package/dist/app/client/assets/IconChip-yqaQ2y_d.css +1 -0
- package/dist/app/client/assets/InputGroup-BlZvt9In.css +1 -0
- package/dist/app/client/assets/InputGroup-CsOeBnpB.js +1 -0
- package/dist/app/client/assets/Inter-cyrillic-e3OmmzmJ.woff2 +0 -0
- package/dist/app/client/assets/Inter-cyrillic-ext-DOWZeO4Q.woff2 +0 -0
- package/dist/app/client/assets/Inter-greek-BD3ujQlX.woff2 +0 -0
- package/dist/app/client/assets/Inter-greek-ext-CXEwbus4.woff2 +0 -0
- package/dist/app/client/assets/Inter-latin-BDFm4vTb.woff2 +0 -0
- package/dist/app/client/assets/Inter-latin-ext-E7a9JEPe.woff2 +0 -0
- package/dist/app/client/assets/Inter-symbols-DEch7Rxr.woff2 +0 -0
- package/dist/app/client/assets/Inter-vietnamese-Bg9723vR.woff2 +0 -0
- package/dist/app/client/assets/Loader-Cm9YJNNJ.js +1 -0
- package/dist/app/client/assets/MACH-sK0r79kQ.svg +4 -0
- package/dist/app/client/assets/OUSD-BFXgVo-Z.svg +5 -0
- package/dist/app/client/assets/OUSD.dark-BbbjMvA1.svg +17 -0
- package/dist/app/client/assets/OUSD.light-B_zpSz_c.svg +17 -0
- package/dist/app/client/assets/PRIME-CiFp2-3e.svg +14 -0
- package/dist/app/client/assets/PopoverPopup-DprRXRQe.js +1 -0
- package/dist/app/client/assets/Rows-DPGTUdA8.css +1 -0
- package/dist/app/client/assets/Rows-Qqo3evtk.js +1 -0
- package/dist/app/client/assets/SBC-BTYkbkiD.svg +1 -0
- package/dist/app/client/assets/SEKAU-CB5Fc6o8.svg +5 -0
- package/dist/app/client/assets/Separator-CZUjVQOL.js +1 -0
- package/dist/app/client/assets/SignIn-HdaDzFmq.js +1 -0
- package/dist/app/client/assets/SignIn-mlBTwUq4.css +1 -0
- package/dist/app/client/assets/Stack-CkkvkOzj.js +1 -0
- package/dist/app/client/assets/Stack-D7Yt22Ed.css +1 -0
- package/dist/app/client/assets/Tag-BMh6ajrW.css +1 -0
- package/dist/app/client/assets/Tag-CLOVANTX.js +1 -0
- package/dist/app/client/assets/ToolbarRootContext-Zty_Dh3J.js +1 -0
- package/dist/app/client/assets/Tooltip-CLATV6YU.js +1 -0
- package/dist/app/client/assets/Tooltip-d3y9ESUJ.css +1 -0
- package/dist/app/client/assets/USD1-COVcO_PB.svg +30 -0
- package/dist/app/client/assets/USDB-Ckwb6UQw.svg +11 -0
- package/dist/app/client/assets/USDC.e-3nMsKAMC.svg +1 -0
- package/dist/app/client/assets/USDT0-ia60Dw0e.svg +1 -0
- package/dist/app/client/assets/USDY-CB4iet2q.svg +16 -0
- package/dist/app/client/assets/USDe-BXHQCd92.svg +1 -0
- package/dist/app/client/assets/Upgrade-D0_aO5AP.js +1 -0
- package/dist/app/client/assets/WalletUpgrade-BPsPNQsd.js +1 -0
- package/dist/app/client/assets/WalletUpgrade-C04kW0Jl.css +1 -0
- package/dist/app/client/assets/YLDS-CRh8Zw0g.svg +3 -0
- package/dist/app/client/assets/___-I98bns4o.css +1 -0
- package/dist/app/client/assets/___.flows-XOlLwMIy.js +5 -0
- package/dist/app/client/assets/alphaUSD-CpCFoVuh.svg +1 -0
- package/dist/app/client/assets/authorize-C-MlCyaM.js +1 -0
- package/dist/app/client/assets/betaUSD-9A8AjgYg.svg +1 -0
- package/dist/app/client/assets/cUSD-WsQfa-iC.svg +1 -0
- package/dist/app/client/assets/cbBTC-DvUDqrDi.svg +1 -0
- package/dist/app/client/assets/choose-account-nXR-SKa2.js +1 -0
- package/dist/app/client/assets/deposit-G8tiLPN4.js +1 -0
- package/dist/app/client/assets/device-BojBF7hZ.js +1 -0
- package/dist/app/client/assets/error-KiOpX7GD.js +1 -0
- package/dist/app/client/assets/frxUSD-n9pTpinR.svg +1 -0
- package/dist/app/client/assets/getPseudoElementBounds-BsLy4zf_.js +1 -0
- package/dist/app/client/assets/goUSD-D9kUvHsF.svg +5 -0
- package/dist/app/client/assets/iUSD-CWCJAq9X.svg +1 -0
- package/dist/app/client/assets/index-BZH0M7Nf.js +13 -0
- package/dist/app/client/assets/index-CIYxHmYA.css +1 -0
- package/dist/app/client/assets/login-DUjpk60p.js +1 -0
- package/dist/app/client/assets/pathUSD-BvaO6ooS.svg +25 -0
- package/dist/app/client/assets/preload-helper-Bs9KvdYl.js +1 -0
- package/dist/app/client/assets/rUSD-B-xuFS7T.svg +1 -0
- package/dist/app/client/assets/reUSD-CkIUs0Lx.svg +1 -0
- package/dist/app/client/assets/removable-DMiA3t_o.js +1 -0
- package/dist/app/client/assets/reset-co-CHrff.css +1 -0
- package/dist/app/client/assets/rolldown-runtime-WkwZ5CU-.js +1 -0
- package/dist/app/client/assets/routes-CK8cthzA.js +1 -0
- package/dist/app/client/assets/sUSDe-j9GOnH7I.svg +1 -0
- package/dist/app/client/assets/siUSD-C10QUNYS.svg +1 -0
- package/dist/app/client/assets/stcUSD-DIntDJeh.svg +1 -0
- package/dist/app/client/assets/syrupUSDC-DhYwZqdM.svg +5 -0
- package/dist/app/client/assets/thetaUSD-Dgmksf6G.svg +1 -0
- package/dist/app/client/assets/useNavigate-CB6S2u4J.js +1 -0
- package/dist/app/client/assets/useQuery-BpHfPhTT.js +1 -0
- package/dist/app/client/assets/useRegisterFieldControl-DsslqY-V.js +1 -0
- package/dist/app/client/assets/wYLDS-CaCKDrO-.svg +10 -0
- package/dist/app/client/assets/wsrUSD-B2Ey0bDQ.svg +1 -0
- package/dist/app/client/assets/zyzz-DYC-X0_B.css +1 -0
- package/dist/app/client/assets/zyzz.config-DX_D_7j3.js +2 -0
- package/dist/app/db/auth.d.ts +3412 -0
- package/dist/app/db/auth.d.ts.map +1 -0
- package/dist/app/db/auth.js +349 -0
- package/dist/app/db/auth.js.map +1 -0
- package/dist/app/db/schema.d.ts +1091 -0
- package/dist/app/db/schema.d.ts.map +1 -0
- package/dist/app/db/schema.js +183 -0
- package/dist/app/db/schema.js.map +1 -0
- package/dist/app/db/table.d.ts +8 -0
- package/dist/app/db/table.d.ts.map +1 -0
- package/dist/app/db/table.js +28 -0
- package/dist/app/db/table.js.map +1 -0
- package/dist/app/server/.vite/manifest.json +2093 -0
- package/dist/app/server/assets/Account-BYLpNFf3.css +1 -0
- package/dist/app/server/assets/Account-G_SUeRU3.js +2 -0
- package/dist/app/server/assets/Account-G_SUeRU3.js.map +1 -0
- package/dist/app/server/assets/Amount-Cgwdr3Xt.js +2 -0
- package/dist/app/server/assets/Amount-Cgwdr3Xt.js.map +1 -0
- package/dist/app/server/assets/Amount-ZdtluGf-.css +1 -0
- package/dist/app/server/assets/Approval-CgV5JHlb.css +1 -0
- package/dist/app/server/assets/Approval-DvkB9tWA.js +2 -0
- package/dist/app/server/assets/Approval-DvkB9tWA.js.map +1 -0
- package/dist/app/server/assets/ArrowUp-DpK_zNgZ.js +2 -0
- package/dist/app/server/assets/ArrowUp-DpK_zNgZ.js.map +1 -0
- package/dist/app/server/assets/Authentication-BOkhlNQu.js +2 -0
- package/dist/app/server/assets/Authentication-BOkhlNQu.js.map +1 -0
- package/dist/app/server/assets/Authentication-C3oNZAVX.js +2 -0
- package/dist/app/server/assets/Authentication-C3oNZAVX.js.map +1 -0
- package/dist/app/server/assets/BRLA-CZvVDNYr.png +0 -0
- package/dist/app/server/assets/BRZ-Cn3jEi9t.svg +1 -0
- package/dist/app/server/assets/Bytes-C7CRVS3J.js +4 -0
- package/dist/app/server/assets/Bytes-C7CRVS3J.js.map +1 -0
- package/dist/app/server/assets/CHFAU-DCedc4aH.png +0 -0
- package/dist/app/server/assets/Callout-DBfEmP7q.css +1 -0
- package/dist/app/server/assets/Callout-tQoAitWq.js +2 -0
- package/dist/app/server/assets/Callout-tQoAitWq.js.map +1 -0
- package/dist/app/server/assets/ChainList-C4A_7e-9.js +6 -0
- package/dist/app/server/assets/ChainList-C4A_7e-9.js.map +1 -0
- package/dist/app/server/assets/ChainName-BMnJyJrd.js +2 -0
- package/dist/app/server/assets/ChainName-BMnJyJrd.js.map +1 -0
- package/dist/app/server/assets/Check-DU_oR3Ev.js +2 -0
- package/dist/app/server/assets/Check-DU_oR3Ev.js.map +1 -0
- package/dist/app/server/assets/ChevronRight-DTBnw-W6.js +2 -0
- package/dist/app/server/assets/ChevronRight-DTBnw-W6.js.map +1 -0
- package/dist/app/server/assets/ChooseAccount-BizJvMrY.js +2 -0
- package/dist/app/server/assets/ChooseAccount-BizJvMrY.js.map +1 -0
- package/dist/app/server/assets/ChooseAccount-DL3wgJhE.css +1 -0
- package/dist/app/server/assets/Client-Dx3KrpJZ.js +2 -0
- package/dist/app/server/assets/Client-Dx3KrpJZ.js.map +1 -0
- package/dist/app/server/assets/ClientOnly-CKLiu67O.js +2 -0
- package/dist/app/server/assets/ClientOnly-CKLiu67O.js.map +1 -0
- package/dist/app/server/assets/Close-DUeE37ev.js +2 -0
- package/dist/app/server/assets/Close-DUeE37ev.js.map +1 -0
- package/dist/app/server/assets/Cloud-CLB3rTTy.js +2 -0
- package/dist/app/server/assets/Cloud-CLB3rTTy.js.map +1 -0
- package/dist/app/server/assets/CodeInput-BqRteSwD.css +1 -0
- package/dist/app/server/assets/CodeInput-FsPzVuLU.js +2 -0
- package/dist/app/server/assets/CodeInput-FsPzVuLU.js.map +1 -0
- package/dist/app/server/assets/Credential-DFjcrdyI.js +2 -0
- package/dist/app/server/assets/Credential-DFjcrdyI.js.map +1 -0
- package/dist/app/server/assets/DLUSD-BnRXm3EI.png +0 -0
- package/dist/app/server/assets/Deposit-CclrAoXL.css +1 -0
- package/dist/app/server/assets/Deposit-ChYGRfW2.js +2 -0
- package/dist/app/server/assets/Deposit-ChYGRfW2.js.map +1 -0
- package/dist/app/server/assets/DevTools-BYkmtuV5.css +1 -0
- package/dist/app/server/assets/DevTools-ZJVXqrIK.js +2 -0
- package/dist/app/server/assets/DevTools-ZJVXqrIK.js.map +1 -0
- package/dist/app/server/assets/DeviceApproval-BffFLD8F.css +1 -0
- package/dist/app/server/assets/DeviceApproval-Bqe3Mi78.js +2 -0
- package/dist/app/server/assets/DeviceApproval-Bqe3Mi78.js.map +1 -0
- package/dist/app/server/assets/EURAU-sjieTTB9.svg +1 -0
- package/dist/app/server/assets/EURC.e-CxYiiwkz.svg +1 -0
- package/dist/app/server/assets/ExecutionError-CDszGSF1.js +9 -0
- package/dist/app/server/assets/ExecutionError-CDszGSF1.js.map +1 -0
- package/dist/app/server/assets/Fingerprint-DhOPOdRr.js +2 -0
- package/dist/app/server/assets/Fingerprint-DhOPOdRr.js.map +1 -0
- package/dist/app/server/assets/GBPA-DI_25xSG.svg +4 -0
- package/dist/app/server/assets/GUSD-BDEP2Qb-.svg +1 -0
- package/dist/app/server/assets/GeistMono-Variable-BRXCGrxA.woff2 +0 -0
- package/dist/app/server/assets/Globe-2CxqxU-7.js +2 -0
- package/dist/app/server/assets/Globe-2CxqxU-7.js.map +1 -0
- package/dist/app/server/assets/Grant-5a-n1gJH.css +1 -0
- package/dist/app/server/assets/Grant-D_tun0mF.js +2 -0
- package/dist/app/server/assets/Grant-D_tun0mF.js.map +1 -0
- package/dist/app/server/assets/Hex-C9KeV7_9.css +1 -0
- package/dist/app/server/assets/Hex-Z6m_0Y0m.js +11 -0
- package/dist/app/server/assets/Hex-Z6m_0Y0m.js.map +1 -0
- package/dist/app/server/assets/IconChip-C9ZrmGB5.js +2 -0
- package/dist/app/server/assets/IconChip-C9ZrmGB5.js.map +1 -0
- package/dist/app/server/assets/IconChip-yqaQ2y_d.css +1 -0
- package/dist/app/server/assets/InputGroup-BlZvt9In.css +1 -0
- package/dist/app/server/assets/InputGroup-hpjuLuR7.js +2 -0
- package/dist/app/server/assets/InputGroup-hpjuLuR7.js.map +1 -0
- package/dist/app/server/assets/Inter-cyrillic-e3OmmzmJ.woff2 +0 -0
- package/dist/app/server/assets/Inter-cyrillic-ext-DOWZeO4Q.woff2 +0 -0
- package/dist/app/server/assets/Inter-greek-BD3ujQlX.woff2 +0 -0
- package/dist/app/server/assets/Inter-greek-ext-CXEwbus4.woff2 +0 -0
- package/dist/app/server/assets/Inter-latin-BDFm4vTb.woff2 +0 -0
- package/dist/app/server/assets/Inter-latin-ext-E7a9JEPe.woff2 +0 -0
- package/dist/app/server/assets/Inter-symbols-DEch7Rxr.woff2 +0 -0
- package/dist/app/server/assets/Inter-vietnamese-Bg9723vR.woff2 +0 -0
- package/dist/app/server/assets/Loader-DnKC9P5p.js +2 -0
- package/dist/app/server/assets/Loader-DnKC9P5p.js.map +1 -0
- package/dist/app/server/assets/MACH-sK0r79kQ.svg +4 -0
- package/dist/app/server/assets/Match-CyVdYcSf.js +2 -0
- package/dist/app/server/assets/Match-CyVdYcSf.js.map +1 -0
- package/dist/app/server/assets/OUSD-BFXgVo-Z.svg +5 -0
- package/dist/app/server/assets/OUSD.dark-BbbjMvA1.svg +17 -0
- package/dist/app/server/assets/OUSD.light-B_zpSz_c.svg +17 -0
- package/dist/app/server/assets/PRIME-CiFp2-3e.svg +14 -0
- package/dist/app/server/assets/PopoverPopup-CwqeQelI.js +2 -0
- package/dist/app/server/assets/PopoverPopup-CwqeQelI.js.map +1 -0
- package/dist/app/server/assets/Rows-CQKQwTI1.js +2 -0
- package/dist/app/server/assets/Rows-CQKQwTI1.js.map +1 -0
- package/dist/app/server/assets/Rows-DPGTUdA8.css +1 -0
- package/dist/app/server/assets/SBC-BTYkbkiD.svg +1 -0
- package/dist/app/server/assets/SEKAU-CB5Fc6o8.svg +5 -0
- package/dist/app/server/assets/Separator-DrI7KRAs.js +2 -0
- package/dist/app/server/assets/Separator-DrI7KRAs.js.map +1 -0
- package/dist/app/server/assets/SignIn-DfeeLEmN.js +2 -0
- package/dist/app/server/assets/SignIn-DfeeLEmN.js.map +1 -0
- package/dist/app/server/assets/SignIn-mlBTwUq4.css +1 -0
- package/dist/app/server/assets/Stack-D7Yt22Ed.css +1 -0
- package/dist/app/server/assets/Stack-DGktaLZc.js +2 -0
- package/dist/app/server/assets/Stack-DGktaLZc.js.map +1 -0
- package/dist/app/server/assets/Tag-9vSRBpph.js +2 -0
- package/dist/app/server/assets/Tag-9vSRBpph.js.map +1 -0
- package/dist/app/server/assets/Tag-BMh6ajrW.css +1 -0
- package/dist/app/server/assets/ToolbarRootContext-BH_CFSWd.js +2 -0
- package/dist/app/server/assets/ToolbarRootContext-BH_CFSWd.js.map +1 -0
- package/dist/app/server/assets/Tooltip-DLX41peb.js +2 -0
- package/dist/app/server/assets/Tooltip-DLX41peb.js.map +1 -0
- package/dist/app/server/assets/Tooltip-d3y9ESUJ.css +1 -0
- package/dist/app/server/assets/USD1-COVcO_PB.svg +30 -0
- package/dist/app/server/assets/USDB-Ckwb6UQw.svg +11 -0
- package/dist/app/server/assets/USDC.e-3nMsKAMC.svg +1 -0
- package/dist/app/server/assets/USDT0-ia60Dw0e.svg +1 -0
- package/dist/app/server/assets/USDY-CB4iet2q.svg +16 -0
- package/dist/app/server/assets/USDe-BXHQCd92.svg +1 -0
- package/dist/app/server/assets/Upgrade-Dbfm2nm0.js +2 -0
- package/dist/app/server/assets/Upgrade-Dbfm2nm0.js.map +1 -0
- package/dist/app/server/assets/WalletUpgrade-C04kW0Jl.css +1 -0
- package/dist/app/server/assets/WalletUpgrade-CWKc5fYt.js +2 -0
- package/dist/app/server/assets/WalletUpgrade-CWKc5fYt.js.map +1 -0
- package/dist/app/server/assets/YLDS-CRh8Zw0g.svg +3 -0
- package/dist/app/server/assets/___-I98bns4o.css +1 -0
- package/dist/app/server/assets/___.flows-Cc-awUoC.js +6 -0
- package/dist/app/server/assets/___.flows-Cc-awUoC.js.map +1 -0
- package/dist/app/server/assets/_tanstack-start-manifest_v-U7TrtUSA.js +1 -0
- package/dist/app/server/assets/_zyzz__2Fhome_2Frunner_2Fwork_2Fid_2Fid_2Fsrc_2Fapp_2Froutes_2F_5B__5D.flows-B1pPOqsM.css +1 -0
- package/dist/app/server/assets/_zyzz__2Fhome_2Frunner_2Fwork_2Fid_2Fid_2Fsrc_2Fapp_2Froutes_2F_5B__5D.flows.tsx-CKALi9oD.js +2 -0
- package/dist/app/server/assets/_zyzz__2Fhome_2Frunner_2Fwork_2Fid_2Fid_2Fsrc_2Fapp_2Froutes_2F_5B__5D.flows.tsx-CKALi9oD.js.map +1 -0
- package/dist/app/server/assets/_zyzz_shared-BbDIEd_j.css +1 -0
- package/dist/app/server/assets/alphaUSD-CpCFoVuh.svg +1 -0
- package/dist/app/server/assets/arktype-aI7TBD0R-D1R3Byo5.js +2 -0
- package/dist/app/server/assets/arktype-aI7TBD0R-D1R3Byo5.js.map +1 -0
- package/dist/app/server/assets/async-local-storage-DlOvwxXd.js +2 -0
- package/dist/app/server/assets/async-local-storage-DlOvwxXd.js.map +1 -0
- package/dist/app/server/assets/authorize-BXzTo2Pb.js +2 -0
- package/dist/app/server/assets/authorize-BXzTo2Pb.js.map +1 -0
- package/dist/app/server/assets/authorize-BzoUqOdA.js +2 -0
- package/dist/app/server/assets/authorize-BzoUqOdA.js.map +1 -0
- package/dist/app/server/assets/authorize-DXYo-K2n-rmQQ42x1.js +56 -0
- package/dist/app/server/assets/authorize-DXYo-K2n-rmQQ42x1.js.map +1 -0
- package/dist/app/server/assets/authorize-DfjPYJqS.css +1 -0
- package/dist/app/server/assets/betaUSD-9A8AjgYg.svg +1 -0
- package/dist/app/server/assets/bun-sqlite-dialect-DoOVo4ja-CtyBkVMb.js +2 -0
- package/dist/app/server/assets/bun-sqlite-dialect-DoOVo4ja-CtyBkVMb.js.map +1 -0
- package/dist/app/server/assets/cUSD-WsQfa-iC.svg +1 -0
- package/dist/app/server/assets/call-dzi0xjZd.js +31 -0
- package/dist/app/server/assets/call-dzi0xjZd.js.map +1 -0
- package/dist/app/server/assets/cbBTC-DvUDqrDi.svg +1 -0
- package/dist/app/server/assets/ccip-DjD8z_3B.js +2 -0
- package/dist/app/server/assets/ccip-DjD8z_3B.js.map +1 -0
- package/dist/app/server/assets/choose-account-_X7xq5am.js +2 -0
- package/dist/app/server/assets/choose-account-_X7xq5am.js.map +1 -0
- package/dist/app/server/assets/choose-account-lqA5SLx9.css +1 -0
- package/dist/app/server/assets/choose-account-zm-5Qs3e.js +2 -0
- package/dist/app/server/assets/choose-account-zm-5Qs3e.js.map +1 -0
- package/dist/app/server/assets/compiled-query-Ds2NVcFT.js +2 -0
- package/dist/app/server/assets/compiled-query-Ds2NVcFT.js.map +1 -0
- package/dist/app/server/assets/convert-BIC8n32x.js +2 -0
- package/dist/app/server/assets/convert-BIC8n32x.js.map +1 -0
- package/dist/app/server/assets/cookie-DxViaO10.js +2 -0
- package/dist/app/server/assets/cookie-DxViaO10.js.map +1 -0
- package/dist/app/server/assets/core-BBrZXfrB.js +56 -0
- package/dist/app/server/assets/core-BBrZXfrB.js.map +1 -0
- package/dist/app/server/assets/d1-sqlite-dialect-m0f01-4z-Cv-csE1u.js +2 -0
- package/dist/app/server/assets/d1-sqlite-dialect-m0f01-4z-Cv-csE1u.js.map +1 -0
- package/dist/app/server/assets/decodeFunctionData-bP6V2ai4.js +2 -0
- package/dist/app/server/assets/decodeFunctionData-bP6V2ai4.js.map +1 -0
- package/dist/app/server/assets/default-u_dwuiYb-DOrMMcg9.js +2 -0
- package/dist/app/server/assets/default-u_dwuiYb-DOrMMcg9.js.map +1 -0
- package/dist/app/server/assets/deposit-BBaNI01u.js +2 -0
- package/dist/app/server/assets/deposit-BBaNI01u.js.map +1 -0
- package/dist/app/server/assets/deposit-LWS6ZTuf.js +2 -0
- package/dist/app/server/assets/deposit-LWS6ZTuf.js.map +1 -0
- package/dist/app/server/assets/deposit-oFx15XCA.css +1 -0
- package/dist/app/server/assets/device-CrXlusjr.js +2 -0
- package/dist/app/server/assets/device-CrXlusjr.js.map +1 -0
- package/dist/app/server/assets/device-DdFMgYe2.js +2 -0
- package/dist/app/server/assets/device-DdFMgYe2.js.map +1 -0
- package/dist/app/server/assets/device-tMCpu5zk.css +1 -0
- package/dist/app/server/assets/dist-CR6FW-yS.js +1 -0
- package/dist/app/server/assets/dist-CoH0hD1s.js +15 -0
- package/dist/app/server/assets/dist-CoH0hD1s.js.map +1 -0
- package/dist/app/server/assets/dist-DcICI3fd.js +2 -0
- package/dist/app/server/assets/dist-DcICI3fd.js.map +1 -0
- package/dist/app/server/assets/effect-QlVUlMFu-mXPkuQTb.js +2 -0
- package/dist/app/server/assets/effect-QlVUlMFu-mXPkuQTb.js.map +1 -0
- package/dist/app/server/assets/empty-plugin-adapters-BaGcmrjC.js +2 -0
- package/dist/app/server/assets/empty-plugin-adapters-BaGcmrjC.js.map +1 -0
- package/dist/app/server/assets/error-CXy8gqdE.css +1 -0
- package/dist/app/server/assets/error-DXDT2AHy.js +2 -0
- package/dist/app/server/assets/error-DXDT2AHy.js.map +1 -0
- package/dist/app/server/assets/error-bnVzy9tx.js +2 -0
- package/dist/app/server/assets/error-bnVzy9tx.js.map +1 -0
- package/dist/app/server/assets/esm-C6SW--yt.js +4 -0
- package/dist/app/server/assets/esm-C6SW--yt.js.map +1 -0
- package/dist/app/server/assets/factory-dvoOlKer.js +5 -0
- package/dist/app/server/assets/factory-dvoOlKer.js.map +1 -0
- package/dist/app/server/assets/frxUSD-n9pTpinR.svg +1 -0
- package/dist/app/server/assets/get-id-field-OwLpfjj2.js +6 -0
- package/dist/app/server/assets/get-id-field-OwLpfjj2.js.map +1 -0
- package/dist/app/server/assets/getPseudoElementBounds-PkWU72kn.js +2 -0
- package/dist/app/server/assets/getPseudoElementBounds-PkWU72kn.js.map +1 -0
- package/dist/app/server/assets/goUSD-D9kUvHsF.svg +5 -0
- package/dist/app/server/assets/iUSD-CWCJAq9X.svg +1 -0
- package/dist/app/server/assets/index-CLddUTqr-CC33CMvS.js +2 -0
- package/dist/app/server/assets/index-CLddUTqr-CC33CMvS.js.map +1 -0
- package/dist/app/server/assets/index-DZEfthgZ-Ec2MMQ_e.js +2 -0
- package/dist/app/server/assets/index-DZEfthgZ-Ec2MMQ_e.js.map +1 -0
- package/dist/app/server/assets/kysely-adapter-B8tQwTcu.js +1 -0
- package/dist/app/server/assets/lazyRouteComponent-DPOOPZw_.js +2 -0
- package/dist/app/server/assets/lazyRouteComponent-DPOOPZw_.js.map +1 -0
- package/dist/app/server/assets/load-server-Dr0IlySo.js +3 -0
- package/dist/app/server/assets/load-server-Dr0IlySo.js.map +1 -0
- package/dist/app/server/assets/login-BLq3tEEr.js +2 -0
- package/dist/app/server/assets/login-BLq3tEEr.js.map +1 -0
- package/dist/app/server/assets/login-DCIrAbED.js +2 -0
- package/dist/app/server/assets/login-DCIrAbED.js.map +1 -0
- package/dist/app/server/assets/login-msDnt3yT.css +1 -0
- package/dist/app/server/assets/matchContext-ByrIUj4L.js +2 -0
- package/dist/app/server/assets/matchContext-ByrIUj4L.js.map +1 -0
- package/dist/app/server/assets/node-sqlite-dialect-BowWLXvK.js +2 -0
- package/dist/app/server/assets/node-sqlite-dialect-BowWLXvK.js.map +1 -0
- package/dist/app/server/assets/pathUSD-BvaO6ooS.svg +25 -0
- package/dist/app/server/assets/rUSD-B-xuFS7T.svg +1 -0
- package/dist/app/server/assets/reUSD-CkIUs0Lx.svg +1 -0
- package/dist/app/server/assets/react-dom-DYzj0HXX.js +2 -0
- package/dist/app/server/assets/react-dom-DYzj0HXX.js.map +1 -0
- package/dist/app/server/assets/removable-BCLTvPOx.js +2 -0
- package/dist/app/server/assets/removable-BCLTvPOx.js.map +1 -0
- package/dist/app/server/assets/reset-DZWeTZeQ.js +2 -0
- package/dist/app/server/assets/reset-DZWeTZeQ.js.map +1 -0
- package/dist/app/server/assets/reset-co-CHrff.css +1 -0
- package/dist/app/server/assets/resolveError-CZXXvCJR.js +2 -0
- package/dist/app/server/assets/resolveError-CZXXvCJR.js.map +1 -0
- package/dist/app/server/assets/rolldown-runtime-BWaJ3C7D.js +1 -0
- package/dist/app/server/assets/router-Bqz5X4Qw.js +2 -0
- package/dist/app/server/assets/router-Bqz5X4Qw.js.map +1 -0
- package/dist/app/server/assets/router-CclzitkY.css +1 -0
- package/dist/app/server/assets/routes-BLQdKqcZ.js +2 -0
- package/dist/app/server/assets/routes-BLQdKqcZ.js.map +1 -0
- package/dist/app/server/assets/routes-BgiIzrOt.css +1 -0
- package/dist/app/server/assets/routes-Bv6WzsSR.js +2 -0
- package/dist/app/server/assets/routes-Bv6WzsSR.js.map +1 -0
- package/dist/app/server/assets/sUSDe-j9GOnH7I.svg +1 -0
- package/dist/app/server/assets/schema-check-oLqvHR8y.js +9 -0
- package/dist/app/server/assets/schema-check-oLqvHR8y.js.map +1 -0
- package/dist/app/server/assets/secp256k1-yg8eeIYU.js +2 -0
- package/dist/app/server/assets/secp256k1-yg8eeIYU.js.map +1 -0
- package/dist/app/server/assets/server-RRUiOef2.js +76 -0
- package/dist/app/server/assets/server-RRUiOef2.js.map +1 -0
- package/dist/app/server/assets/siUSD-C10QUNYS.svg +1 -0
- package/dist/app/server/assets/sqlite-adapter-C_LAV4e3.js +2 -0
- package/dist/app/server/assets/sqlite-adapter-C_LAV4e3.js.map +1 -0
- package/dist/app/server/assets/sqlite-introspector-DSCAP82F-Crx7Ny14.js +6 -0
- package/dist/app/server/assets/sqlite-introspector-DSCAP82F-Crx7Ny14.js.map +1 -0
- package/dist/app/server/assets/standard-json-DY77efq0.js +2 -0
- package/dist/app/server/assets/standard-json-DY77efq0.js.map +1 -0
- package/dist/app/server/assets/standard-json-ig2t0wRt.js +2 -0
- package/dist/app/server/assets/standard-json-ig2t0wRt.js.map +1 -0
- package/dist/app/server/assets/standard-json-t-LNckA6.js +2 -0
- package/dist/app/server/assets/standard-json-t-LNckA6.js.map +1 -0
- package/dist/app/server/assets/standard-openapi-CONmVRl8.js +2 -0
- package/dist/app/server/assets/standard-openapi-CONmVRl8.js.map +1 -0
- package/dist/app/server/assets/start-C63VetBp.js +2 -0
- package/dist/app/server/assets/start-C63VetBp.js.map +1 -0
- package/dist/app/server/assets/stcUSD-DIntDJeh.svg +1 -0
- package/dist/app/server/assets/sury-CWZTCd75-CDaOS2oM.js +2 -0
- package/dist/app/server/assets/sury-CWZTCd75-CDaOS2oM.js.map +1 -0
- package/dist/app/server/assets/syrupUSDC-DhYwZqdM.svg +5 -0
- package/dist/app/server/assets/thetaUSD-Dgmksf6G.svg +1 -0
- package/dist/app/server/assets/typebox-Dei93FPO-D_lCVdAz.js +2 -0
- package/dist/app/server/assets/typebox-Dei93FPO-D_lCVdAz.js.map +1 -0
- package/dist/app/server/assets/useNavigate-D6d1w7KE.js +2 -0
- package/dist/app/server/assets/useNavigate-D6d1w7KE.js.map +1 -0
- package/dist/app/server/assets/useQuery-BRpCr5vj.js +2 -0
- package/dist/app/server/assets/useQuery-BRpCr5vj.js.map +1 -0
- package/dist/app/server/assets/useRegisterFieldControl-cJesrOWK.js +2 -0
- package/dist/app/server/assets/useRegisterFieldControl-cJesrOWK.js.map +1 -0
- package/dist/app/server/assets/utils-C4ZXZIZW.js +2 -0
- package/dist/app/server/assets/utils-C4ZXZIZW.js.map +1 -0
- package/dist/app/server/assets/utils-D57zfcg-.js +2 -0
- package/dist/app/server/assets/utils-D57zfcg-.js.map +1 -0
- package/dist/app/server/assets/valibot--1zFm7rT-CIKoH3MS.js +2 -0
- package/dist/app/server/assets/valibot--1zFm7rT-CIKoH3MS.js.map +1 -0
- package/dist/app/server/assets/valibot-D_HTw1Gn-BdPyLkXt.js +2 -0
- package/dist/app/server/assets/valibot-D_HTw1Gn-BdPyLkXt.js.map +1 -0
- package/dist/app/server/assets/wYLDS-CaCKDrO-.svg +10 -0
- package/dist/app/server/assets/wsrUSD-B2Ey0bDQ.svg +1 -0
- package/dist/app/server/assets/zod-Bwrt9trS-BezI5Gi1.js +2 -0
- package/dist/app/server/assets/zod-Bwrt9trS-BezI5Gi1.js.map +1 -0
- package/dist/app/server/assets/zod-DSgpEGAE-DZ7M_Q33.js +2 -0
- package/dist/app/server/assets/zod-DSgpEGAE-DZ7M_Q33.js.map +1 -0
- package/dist/app/server/assets/zyzz-6R2K52xP.css +1 -0
- package/dist/app/server/assets/zyzz.config-CJRpjn0E.js +3 -0
- package/dist/app/server/assets/zyzz.config-CJRpjn0E.js.map +1 -0
- package/dist/app/server/index.js +532 -0
- package/dist/app/server/index.js.map +1 -0
- package/dist/app/server/wrangler.json +1 -0
- package/dist/cli/Admin.d.ts +34 -0
- package/dist/cli/Admin.d.ts.map +1 -0
- package/dist/cli/Admin.js +61 -0
- package/dist/cli/Admin.js.map +1 -0
- package/dist/cli/Apps.d.ts +9 -0
- package/dist/cli/Apps.d.ts.map +1 -0
- package/dist/cli/Apps.js +34 -0
- package/dist/cli/Apps.js.map +1 -0
- package/dist/cli/Cli.d.ts +13 -0
- package/dist/cli/Cli.d.ts.map +1 -0
- package/dist/cli/Cli.js +26 -0
- package/dist/cli/Cli.js.map +1 -0
- package/dist/cli/Project.d.ts +17 -0
- package/dist/cli/Project.d.ts.map +1 -0
- package/dist/cli/Project.js +90 -0
- package/dist/cli/Project.js.map +1 -0
- package/dist/cli/Realms.d.ts +24 -0
- package/dist/cli/Realms.d.ts.map +1 -0
- package/dist/cli/Realms.js +48 -0
- package/dist/cli/Realms.js.map +1 -0
- package/dist/cli/Session.d.ts +79 -0
- package/dist/cli/Session.d.ts.map +1 -0
- package/dist/cli/Session.js +229 -0
- package/dist/cli/Session.js.map +1 -0
- package/dist/cli/User.d.ts +24 -0
- package/dist/cli/User.d.ts.map +1 -0
- package/dist/cli/User.js +34 -0
- package/dist/cli/User.js.map +1 -0
- package/dist/cli/V1.d.ts +32 -0
- package/dist/cli/V1.d.ts.map +1 -0
- package/dist/cli/V1.js +38 -0
- package/dist/cli/V1.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +46 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/commands/admin/apps/create.d.ts +23 -0
- package/dist/cli/commands/admin/apps/create.d.ts.map +1 -0
- package/dist/cli/commands/admin/apps/create.js +84 -0
- package/dist/cli/commands/admin/apps/create.js.map +1 -0
- package/dist/cli/commands/admin/apps/delete.d.ts +15 -0
- package/dist/cli/commands/admin/apps/delete.d.ts.map +1 -0
- package/dist/cli/commands/admin/apps/delete.js +41 -0
- package/dist/cli/commands/admin/apps/delete.js.map +1 -0
- package/dist/cli/commands/admin/apps/index.d.ts +5 -0
- package/dist/cli/commands/admin/apps/index.d.ts.map +1 -0
- package/dist/cli/commands/admin/apps/index.js +14 -0
- package/dist/cli/commands/admin/apps/index.js.map +1 -0
- package/dist/cli/commands/admin/apps/list.d.ts +10 -0
- package/dist/cli/commands/admin/apps/list.d.ts.map +1 -0
- package/dist/cli/commands/admin/apps/list.js +26 -0
- package/dist/cli/commands/admin/apps/list.js.map +1 -0
- package/dist/cli/commands/admin/apps/rotate-secret.d.ts +17 -0
- package/dist/cli/commands/admin/apps/rotate-secret.d.ts.map +1 -0
- package/dist/cli/commands/admin/apps/rotate-secret.js +47 -0
- package/dist/cli/commands/admin/apps/rotate-secret.js.map +1 -0
- package/dist/cli/commands/admin/apps/update.d.ts +20 -0
- package/dist/cli/commands/admin/apps/update.d.ts.map +1 -0
- package/dist/cli/commands/admin/apps/update.js +71 -0
- package/dist/cli/commands/admin/apps/update.js.map +1 -0
- package/dist/cli/commands/admin/index.d.ts +5 -0
- package/dist/cli/commands/admin/index.d.ts.map +1 -0
- package/dist/cli/commands/admin/index.js +13 -0
- package/dist/cli/commands/admin/index.js.map +1 -0
- package/dist/cli/commands/admin/migrate.d.ts +10 -0
- package/dist/cli/commands/admin/migrate.d.ts.map +1 -0
- package/dist/cli/commands/admin/migrate.js +20 -0
- package/dist/cli/commands/admin/migrate.js.map +1 -0
- package/dist/cli/commands/admin/realms/add.d.ts +13 -0
- package/dist/cli/commands/admin/realms/add.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/add.js +42 -0
- package/dist/cli/commands/admin/realms/add.js.map +1 -0
- package/dist/cli/commands/admin/realms/index.d.ts +5 -0
- package/dist/cli/commands/admin/realms/index.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/index.js +13 -0
- package/dist/cli/commands/admin/realms/index.js.map +1 -0
- package/dist/cli/commands/admin/realms/list.d.ts +14 -0
- package/dist/cli/commands/admin/realms/list.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/list.js +36 -0
- package/dist/cli/commands/admin/realms/list.js.map +1 -0
- package/dist/cli/commands/admin/realms/passkeys/index.d.ts +5 -0
- package/dist/cli/commands/admin/realms/passkeys/index.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/passkeys/index.js +13 -0
- package/dist/cli/commands/admin/realms/passkeys/index.js.map +1 -0
- package/dist/cli/commands/admin/realms/passkeys/set.d.ts +17 -0
- package/dist/cli/commands/admin/realms/passkeys/set.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/passkeys/set.js +46 -0
- package/dist/cli/commands/admin/realms/passkeys/set.js.map +1 -0
- package/dist/cli/commands/admin/realms/privy/index.d.ts +5 -0
- package/dist/cli/commands/admin/realms/privy/index.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/privy/index.js +13 -0
- package/dist/cli/commands/admin/realms/privy/index.js.map +1 -0
- package/dist/cli/commands/admin/realms/privy/set.d.ts +19 -0
- package/dist/cli/commands/admin/realms/privy/set.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/privy/set.js +66 -0
- package/dist/cli/commands/admin/realms/privy/set.js.map +1 -0
- package/dist/cli/commands/admin/realms/remove.d.ts +12 -0
- package/dist/cli/commands/admin/realms/remove.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/remove.js +35 -0
- package/dist/cli/commands/admin/realms/remove.js.map +1 -0
- package/dist/cli/commands/admin/realms/secp256k1/disable.d.ts +16 -0
- package/dist/cli/commands/admin/realms/secp256k1/disable.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/secp256k1/disable.js +42 -0
- package/dist/cli/commands/admin/realms/secp256k1/disable.js.map +1 -0
- package/dist/cli/commands/admin/realms/secp256k1/enable.d.ts +16 -0
- package/dist/cli/commands/admin/realms/secp256k1/enable.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/secp256k1/enable.js +42 -0
- package/dist/cli/commands/admin/realms/secp256k1/enable.js.map +1 -0
- package/dist/cli/commands/admin/realms/secp256k1/index.d.ts +9 -0
- package/dist/cli/commands/admin/realms/secp256k1/index.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/secp256k1/index.js +17 -0
- package/dist/cli/commands/admin/realms/secp256k1/index.js.map +1 -0
- package/dist/cli/commands/admin/realms/set.d.ts +17 -0
- package/dist/cli/commands/admin/realms/set.d.ts.map +1 -0
- package/dist/cli/commands/admin/realms/set.js +46 -0
- package/dist/cli/commands/admin/realms/set.js.map +1 -0
- package/dist/cli/commands/admin/rotate-key.d.ts +16 -0
- package/dist/cli/commands/admin/rotate-key.d.ts.map +1 -0
- package/dist/cli/commands/admin/rotate-key.js +46 -0
- package/dist/cli/commands/admin/rotate-key.js.map +1 -0
- package/dist/cli/commands/init.d.ts +11 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +34 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/login.d.ts +12 -0
- package/dist/cli/commands/login.d.ts.map +1 -0
- package/dist/cli/commands/login.js +29 -0
- package/dist/cli/commands/login.js.map +1 -0
- package/dist/cli/commands/logout.d.ts +8 -0
- package/dist/cli/commands/logout.d.ts.map +1 -0
- package/dist/cli/commands/logout.js +19 -0
- package/dist/cli/commands/logout.js.map +1 -0
- package/dist/cli/commands/whoami.d.ts +12 -0
- package/dist/cli/commands/whoami.d.ts.map +1 -0
- package/dist/cli/commands/whoami.js +24 -0
- package/dist/cli/commands/whoami.js.map +1 -0
- package/dist/client/Actions.d.ts +108 -0
- package/dist/client/Actions.d.ts.map +1 -0
- package/dist/client/Actions.js +94 -0
- package/dist/client/Actions.js.map +1 -0
- package/dist/client/Auth.d.ts +143 -0
- package/dist/client/Auth.d.ts.map +1 -0
- package/dist/client/Auth.js +106 -0
- package/dist/client/Auth.js.map +1 -0
- package/dist/client/Authorization.d.ts +29 -0
- package/dist/client/Authorization.d.ts.map +1 -0
- package/dist/client/Authorization.js +12 -0
- package/dist/client/Authorization.js.map +1 -0
- package/dist/client/Decorator.d.ts +172 -0
- package/dist/client/Decorator.d.ts.map +1 -0
- package/dist/client/Decorator.js +241 -0
- package/dist/client/Decorator.js.map +1 -0
- package/dist/client/Key.d.ts +82 -0
- package/dist/client/Key.d.ts.map +1 -0
- package/dist/client/Key.js +81 -0
- package/dist/client/Key.js.map +1 -0
- package/dist/client/Pending.d.ts +38 -0
- package/dist/client/Pending.d.ts.map +1 -0
- package/dist/client/Pending.js +12 -0
- package/dist/client/Pending.js.map +1 -0
- package/dist/client/Permissions.d.ts +36 -0
- package/dist/client/Permissions.d.ts.map +1 -0
- package/dist/client/Permissions.js +16 -0
- package/dist/client/Permissions.js.map +1 -0
- package/dist/client/Storage.d.ts +27 -0
- package/dist/client/Storage.d.ts.map +1 -0
- package/dist/client/Storage.js +16 -0
- package/dist/client/Storage.js.map +1 -0
- package/dist/client/TempoAccount.d.ts +52 -0
- package/dist/client/TempoAccount.d.ts.map +1 -0
- package/dist/client/TempoAccount.js +17 -0
- package/dist/client/TempoAccount.js.map +1 -0
- package/dist/client/Tokens.d.ts +25 -0
- package/dist/client/Tokens.d.ts.map +1 -0
- package/dist/client/Tokens.js +12 -0
- package/dist/client/Tokens.js.map +1 -0
- package/dist/client/User.d.ts +21 -0
- package/dist/client/User.d.ts.map +1 -0
- package/dist/client/User.js +12 -0
- package/dist/client/User.js.map +1 -0
- package/dist/client/actions/account.d.ts +75 -0
- package/dist/client/actions/account.d.ts.map +1 -0
- package/dist/client/actions/account.js +102 -0
- package/dist/client/actions/account.js.map +1 -0
- package/dist/client/actions/device.d.ts +52 -0
- package/dist/client/actions/device.d.ts.map +1 -0
- package/dist/client/actions/device.js +103 -0
- package/dist/client/actions/device.js.map +1 -0
- package/dist/client/actions/email.d.ts +89 -0
- package/dist/client/actions/email.d.ts.map +1 -0
- package/dist/client/actions/email.js +86 -0
- package/dist/client/actions/email.js.map +1 -0
- package/dist/client/actions/oauth.d.ts +112 -0
- package/dist/client/actions/oauth.d.ts.map +1 -0
- package/dist/client/actions/oauth.js +103 -0
- package/dist/client/actions/oauth.js.map +1 -0
- package/dist/client/actions/passkey.d.ts +140 -0
- package/dist/client/actions/passkey.d.ts.map +1 -0
- package/dist/client/actions/passkey.js +170 -0
- package/dist/client/actions/passkey.js.map +1 -0
- package/dist/client/actions/realm.d.ts +25 -0
- package/dist/client/actions/realm.d.ts.map +1 -0
- package/dist/client/actions/realm.js +16 -0
- package/dist/client/actions/realm.js.map +1 -0
- package/dist/client/actions/redirect.d.ts +152 -0
- package/dist/client/actions/redirect.d.ts.map +1 -0
- package/dist/client/actions/redirect.js +311 -0
- package/dist/client/actions/redirect.js.map +1 -0
- package/dist/client/internal/accessKey.d.ts +21 -0
- package/dist/client/internal/accessKey.d.ts.map +1 -0
- package/dist/client/internal/accessKey.js +38 -0
- package/dist/client/internal/accessKey.js.map +1 -0
- package/dist/client/internal/account.d.ts +17 -0
- package/dist/client/internal/account.d.ts.map +1 -0
- package/dist/client/internal/account.js +3 -0
- package/dist/client/internal/account.js.map +1 -0
- package/dist/client/internal/api.d.ts +110 -0
- package/dist/client/internal/api.d.ts.map +1 -0
- package/dist/client/internal/api.js +136 -0
- package/dist/client/internal/api.js.map +1 -0
- package/dist/client/internal/headless.d.ts +159 -0
- package/dist/client/internal/headless.d.ts.map +1 -0
- package/dist/client/internal/headless.js +196 -0
- package/dist/client/internal/headless.js.map +1 -0
- package/dist/client/internal/indexedDb.d.ts +8 -0
- package/dist/client/internal/indexedDb.d.ts.map +1 -0
- package/dist/client/internal/indexedDb.js +32 -0
- package/dist/client/internal/indexedDb.js.map +1 -0
- package/dist/client/internal/request.d.ts +56 -0
- package/dist/client/internal/request.d.ts.map +1 -0
- package/dist/client/internal/request.js +44 -0
- package/dist/client/internal/request.js.map +1 -0
- package/dist/client/internal/store.d.ts +12 -0
- package/dist/client/internal/store.d.ts.map +1 -0
- package/dist/client/internal/store.js +15 -0
- package/dist/client/internal/store.js.map +1 -0
- package/dist/client/internal/verifier.d.ts +25 -0
- package/dist/client/internal/verifier.d.ts.map +1 -0
- package/dist/client/internal/verifier.js +52 -0
- package/dist/client/internal/verifier.js.map +1 -0
- package/dist/client.d.ts +18 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +18 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/Apps.d.ts +3169 -0
- package/dist/internal/Apps.d.ts.map +1 -0
- package/dist/internal/Apps.js +948 -0
- package/dist/internal/Apps.js.map +1 -0
- package/dist/internal/Auth.d.ts +4287 -0
- package/dist/internal/Auth.d.ts.map +1 -0
- package/dist/internal/Auth.js +185 -0
- package/dist/internal/Auth.js.map +1 -0
- package/dist/internal/Authorize.d.ts +526 -0
- package/dist/internal/Authorize.d.ts.map +1 -0
- package/dist/internal/Authorize.js +330 -0
- package/dist/internal/Authorize.js.map +1 -0
- package/dist/internal/Cache.d.ts +56 -0
- package/dist/internal/Cache.d.ts.map +1 -0
- package/dist/internal/Cache.js +65 -0
- package/dist/internal/Cache.js.map +1 -0
- package/dist/internal/Chain.d.ts +738 -0
- package/dist/internal/Chain.d.ts.map +1 -0
- package/dist/internal/Chain.js +65 -0
- package/dist/internal/Chain.js.map +1 -0
- package/dist/internal/ChainList.d.ts +117 -0
- package/dist/internal/ChainList.d.ts.map +1 -0
- package/dist/internal/ChainList.js +148 -0
- package/dist/internal/ChainList.js.map +1 -0
- package/dist/internal/ChainName.d.ts +11 -0
- package/dist/internal/ChainName.d.ts.map +1 -0
- package/dist/internal/ChainName.js +13 -0
- package/dist/internal/ChainName.js.map +1 -0
- package/dist/internal/CodeEmail.d.ts +38 -0
- package/dist/internal/CodeEmail.d.ts.map +1 -0
- package/dist/internal/CodeEmail.js +85 -0
- package/dist/internal/CodeEmail.js.map +1 -0
- package/dist/internal/ConfigurableAccount.d.ts +600 -0
- package/dist/internal/ConfigurableAccount.d.ts.map +1 -0
- package/dist/internal/ConfigurableAccount.js +795 -0
- package/dist/internal/ConfigurableAccount.js.map +1 -0
- package/dist/internal/Device.d.ts +246 -0
- package/dist/internal/Device.d.ts.map +1 -0
- package/dist/internal/Device.js +257 -0
- package/dist/internal/Device.js.map +1 -0
- package/dist/internal/Env.d.ts +97 -0
- package/dist/internal/Env.d.ts.map +1 -0
- package/dist/internal/Env.js +2 -0
- package/dist/internal/Env.js.map +1 -0
- package/dist/internal/ErrorResponse.d.ts +608 -0
- package/dist/internal/ErrorResponse.d.ts.map +1 -0
- package/dist/internal/ErrorResponse.js +701 -0
- package/dist/internal/ErrorResponse.js.map +1 -0
- package/dist/internal/Id.d.ts +10 -0
- package/dist/internal/Id.d.ts.map +1 -0
- package/dist/internal/Id.js +34 -0
- package/dist/internal/Id.js.map +1 -0
- package/dist/internal/KeyAuthorization.d.ts +1650 -0
- package/dist/internal/KeyAuthorization.d.ts.map +1 -0
- package/dist/internal/KeyAuthorization.js +1187 -0
- package/dist/internal/KeyAuthorization.js.map +1 -0
- package/dist/internal/Limits.d.ts +70 -0
- package/dist/internal/Limits.d.ts.map +1 -0
- package/dist/internal/Limits.js +36 -0
- package/dist/internal/Limits.js.map +1 -0
- package/dist/internal/Log.d.ts +34 -0
- package/dist/internal/Log.d.ts.map +1 -0
- package/dist/internal/Log.js +99 -0
- package/dist/internal/Log.js.map +1 -0
- package/dist/internal/LogLine.d.ts +29 -0
- package/dist/internal/LogLine.d.ts.map +1 -0
- package/dist/internal/LogLine.js +50 -0
- package/dist/internal/LogLine.js.map +1 -0
- package/dist/internal/Migrations.d.ts +28 -0
- package/dist/internal/Migrations.d.ts.map +1 -0
- package/dist/internal/Migrations.js +82 -0
- package/dist/internal/Migrations.js.map +1 -0
- package/dist/internal/Owner.d.ts +230 -0
- package/dist/internal/Owner.d.ts.map +1 -0
- package/dist/internal/Owner.js +101 -0
- package/dist/internal/Owner.js.map +1 -0
- package/dist/internal/Passkey.d.ts +901 -0
- package/dist/internal/Passkey.d.ts.map +1 -0
- package/dist/internal/Passkey.js +1185 -0
- package/dist/internal/Passkey.js.map +1 -0
- package/dist/internal/PendingKey.d.ts +49 -0
- package/dist/internal/PendingKey.d.ts.map +1 -0
- package/dist/internal/PendingKey.js +58 -0
- package/dist/internal/PendingKey.js.map +1 -0
- package/dist/internal/Privy.d.ts +138 -0
- package/dist/internal/Privy.d.ts.map +1 -0
- package/dist/internal/Privy.js +285 -0
- package/dist/internal/Privy.js.map +1 -0
- package/dist/internal/RateLimit.d.ts +218 -0
- package/dist/internal/RateLimit.d.ts.map +1 -0
- package/dist/internal/RateLimit.js +209 -0
- package/dist/internal/RateLimit.js.map +1 -0
- package/dist/internal/Realm.d.ts +290 -0
- package/dist/internal/Realm.d.ts.map +1 -0
- package/dist/internal/Realm.js +502 -0
- package/dist/internal/Realm.js.map +1 -0
- package/dist/internal/RequestId.d.ts +16 -0
- package/dist/internal/RequestId.d.ts.map +1 -0
- package/dist/internal/RequestId.js +78 -0
- package/dist/internal/RequestId.js.map +1 -0
- package/dist/internal/SigningKey.d.ts +126 -0
- package/dist/internal/SigningKey.d.ts.map +1 -0
- package/dist/internal/SigningKey.js +221 -0
- package/dist/internal/SigningKey.js.map +1 -0
- package/dist/internal/TempoAccount.d.ts +181 -0
- package/dist/internal/TempoAccount.d.ts.map +1 -0
- package/dist/internal/TempoAccount.js +369 -0
- package/dist/internal/TempoAccount.js.map +1 -0
- package/dist/internal/TestInbox.d.ts +42 -0
- package/dist/internal/TestInbox.d.ts.map +1 -0
- package/dist/internal/TestInbox.js +20 -0
- package/dist/internal/TestInbox.js.map +1 -0
- package/dist/internal/Timing.d.ts +52 -0
- package/dist/internal/Timing.d.ts.map +1 -0
- package/dist/internal/Timing.js +116 -0
- package/dist/internal/Timing.js.map +1 -0
- package/dist/internal/Validation.d.ts +52 -0
- package/dist/internal/Validation.d.ts.map +1 -0
- package/dist/internal/Validation.js +22 -0
- package/dist/internal/Validation.js.map +1 -0
- package/dist/internal/Verification.d.ts +24 -0
- package/dist/internal/Verification.d.ts.map +1 -0
- package/dist/internal/Verification.js +37 -0
- package/dist/internal/Verification.js.map +1 -0
- package/dist/internal/Wallet.d.ts +66 -0
- package/dist/internal/Wallet.d.ts.map +1 -0
- package/dist/internal/Wallet.js +59 -0
- package/dist/internal/Wallet.js.map +1 -0
- package/dist/internal/owners/Passkey.d.ts +9 -0
- package/dist/internal/owners/Passkey.d.ts.map +1 -0
- package/dist/internal/owners/Passkey.js +58 -0
- package/dist/internal/owners/Passkey.js.map +1 -0
- package/dist/internal/owners/Privy.d.ts +13 -0
- package/dist/internal/owners/Privy.d.ts.map +1 -0
- package/dist/internal/owners/Privy.js +59 -0
- package/dist/internal/owners/Privy.js.map +1 -0
- package/dist/internal/owners/Secp256k1.d.ts +12 -0
- package/dist/internal/owners/Secp256k1.d.ts.map +1 -0
- package/dist/internal/owners/Secp256k1.js +99 -0
- package/dist/internal/owners/Secp256k1.js.map +1 -0
- package/dist/worker.d.ts +18 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +18 -0
- package/dist/worker.js.map +1 -0
- package/package.json +83 -3
- package/src/Api.ts +157 -0
- package/src/App.ts +316 -0
- package/src/api/account.ts +2266 -0
- package/src/api/authenticate.ts +1662 -0
- package/src/api/authorize.ts +1086 -0
- package/src/api/device.ts +516 -0
- package/src/api/health.ts +72 -0
- package/src/api/lib/AccountStep.ts +485 -0
- package/src/api/lib/Auth.ts +164 -0
- package/src/api/lib/Configure.ts +921 -0
- package/src/api/lib/Consent.ts +388 -0
- package/src/api/lib/Cors.ts +160 -0
- package/src/api/lib/Database.ts +10 -0
- package/src/api/lib/DeviceRequest.ts +244 -0
- package/src/api/lib/FirstAccount.ts +136 -0
- package/src/api/lib/Headless.ts +616 -0
- package/src/api/lib/IsolateCache.ts +28 -0
- package/src/api/lib/KeySigner.ts +690 -0
- package/src/api/lib/PasskeyLink.ts +162 -0
- package/src/api/lib/Session.ts +64 -0
- package/src/api/lib/SignInConsent.ts +393 -0
- package/src/api/oauth.ts +1796 -0
- package/src/app/components/CodeInput.tsx +153 -0
- package/src/app/components/DevTools.tsx +1071 -0
- package/src/app/components/Grant.tsx +476 -0
- package/src/app/components/icons/BRLA.png +0 -0
- package/src/app/components/icons/BRZ.svg +1 -0
- package/src/app/components/icons/CHFAU.png +0 -0
- package/src/app/components/icons/DLUSD.png +0 -0
- package/src/app/components/icons/EURAU.svg +1 -0
- package/src/app/components/icons/EURC.e.svg +1 -0
- package/src/app/components/icons/GBPA.svg +4 -0
- package/src/app/components/icons/GUSD.svg +1 -0
- package/src/app/components/icons/MACH.svg +4 -0
- package/src/app/components/icons/OUSD.svg +5 -0
- package/src/app/components/icons/PRIME.svg +14 -0
- package/src/app/components/icons/SBC.svg +1 -0
- package/src/app/components/icons/SEKAU.svg +5 -0
- package/src/app/components/icons/USD1.svg +30 -0
- package/src/app/components/icons/USDB.svg +11 -0
- package/src/app/components/icons/USDC.e.svg +1 -0
- package/src/app/components/icons/USDT0.svg +1 -0
- package/src/app/components/icons/USDY.svg +16 -0
- package/src/app/components/icons/USDe.svg +1 -0
- package/src/app/components/icons/YLDS.svg +3 -0
- package/src/app/components/icons/alphaUSD.svg +1 -0
- package/src/app/components/icons/betaUSD.svg +1 -0
- package/src/app/components/icons/cUSD.svg +1 -0
- package/src/app/components/icons/cbBTC.svg +1 -0
- package/src/app/components/icons/frxUSD.svg +1 -0
- package/src/app/components/icons/goUSD.svg +5 -0
- package/src/app/components/icons/iUSD.svg +1 -0
- package/src/app/components/icons/pathUSD.svg +25 -0
- package/src/app/components/icons/rUSD.svg +1 -0
- package/src/app/components/icons/reUSD.svg +1 -0
- package/src/app/components/icons/sUSDe.svg +1 -0
- package/src/app/components/icons/siUSD.svg +1 -0
- package/src/app/components/icons/stcUSD.svg +1 -0
- package/src/app/components/icons/syrupUSDC.svg +5 -0
- package/src/app/components/icons/thetaUSD.svg +1 -0
- package/src/app/components/icons/wYLDS.svg +10 -0
- package/src/app/components/icons/wsrUSD.svg +1 -0
- package/src/app/components/logos/OUSD.dark.svg +17 -0
- package/src/app/components/logos/OUSD.light.svg +17 -0
- package/src/app/coverage.server.ts +73 -0
- package/src/app/coverage.ts +69 -0
- package/src/app/crons/cleanup.ts +104 -0
- package/src/app/db/auth.ts +440 -0
- package/src/app/db/migrations/0000_better_auth.sql +53 -0
- package/src/app/db/migrations/0001_oauth_provider.sql +162 -0
- package/src/app/db/migrations/0002_device_code.sql +17 -0
- package/src/app/db/migrations/0003_realms.sql +27 -0
- package/src/app/db/migrations/0004_default_realm.sql +2 -0
- package/src/app/db/migrations/0005_passkeys.sql +30 -0
- package/src/app/db/migrations/0006_first_accounts.sql +9 -0
- package/src/app/db/migrations/0007_pending_keys.sql +13 -0
- package/src/app/db/migrations/0008_secp256k1_owners.sql +18 -0
- package/src/app/db/migrations/0009_device_requests.sql +8 -0
- package/src/app/db/migrations/0010_device_keys.sql +4 -0
- package/src/app/db/migrations/0011_registered_passkeys.sql +2 -0
- package/src/app/db/migrations/0012_passkey_accounts.sql +7 -0
- package/src/app/db/migrations/0013_first_party_apps.sql +4 -0
- package/src/app/db/migrations/0014_logout_revokes_tokens.sql +17 -0
- package/src/app/db/migrations/0015_expiry_indexes.sql +9 -0
- package/src/app/db/migrations/0016_configurable_accounts.sql +15 -0
- package/src/app/db/migrations/0017_account_config_keys.sql +3 -0
- package/src/app/db/migrations/0018_better_auth_1_8.sql +9 -0
- package/src/app/db/migrations/0019_drop_provider_account_index.sql +1 -0
- package/src/app/db/migrations/meta/0000_snapshot.json +362 -0
- package/src/app/db/migrations/meta/0001_snapshot.json +1487 -0
- package/src/app/db/migrations/meta/0002_snapshot.json +1603 -0
- package/src/app/db/migrations/meta/0003_snapshot.json +1760 -0
- package/src/app/db/migrations/meta/0004_snapshot.json +1760 -0
- package/src/app/db/migrations/meta/0005_snapshot.json +1911 -0
- package/src/app/db/migrations/meta/0006_snapshot.json +1967 -0
- package/src/app/db/migrations/meta/0007_snapshot.json +2047 -0
- package/src/app/db/migrations/meta/0008_snapshot.json +2157 -0
- package/src/app/db/migrations/meta/0009_snapshot.json +2207 -0
- package/src/app/db/migrations/meta/0010_snapshot.json +2231 -0
- package/src/app/db/migrations/meta/0011_snapshot.json +2231 -0
- package/src/app/db/migrations/meta/0012_snapshot.json +2231 -0
- package/src/app/db/migrations/meta/0013_snapshot.json +2231 -0
- package/src/app/db/migrations/meta/0014_snapshot.json +2231 -0
- package/src/app/db/migrations/meta/0015_snapshot.json +2375 -0
- package/src/app/db/migrations/meta/0016_snapshot.json +2475 -0
- package/src/app/db/migrations/meta/0017_snapshot.json +2481 -0
- package/src/app/db/migrations/meta/0018_snapshot.json +2535 -0
- package/src/app/db/migrations/meta/0019_snapshot.json +2514 -0
- package/src/app/db/migrations/meta/_journal.json +146 -0
- package/src/app/db/schema.ts +241 -0
- package/src/app/db/table.ts +31 -0
- package/src/app/env.ts +57 -0
- package/src/app/inbox.ts +190 -0
- package/src/app/lib/Client.ts +82 -0
- package/src/app/lib/Inbox.ts +11 -0
- package/src/app/lib/Loader.ts +21 -0
- package/src/app/lib/Upgrade.ts +221 -0
- package/src/app/package.json +8 -0
- package/src/app/public/_headers +4 -0
- package/src/app/routeTree.gen.ts +219 -0
- package/src/app/router.tsx +47 -0
- package/src/app/routes/[_].flows.tsx +4254 -0
- package/src/app/routes/__root.tsx +172 -0
- package/src/app/routes/authorize.tsx +379 -0
- package/src/app/routes/choose-account.tsx +144 -0
- package/src/app/routes/deposit.tsx +107 -0
- package/src/app/routes/device.tsx +273 -0
- package/src/app/routes/error.tsx +62 -0
- package/src/app/routes/index.tsx +511 -0
- package/src/app/routes/login.tsx +577 -0
- package/src/app/screens/Account.tsx +559 -0
- package/src/app/screens/Approval.tsx +444 -0
- package/src/app/screens/ChooseAccount.tsx +206 -0
- package/src/app/screens/Deposit.tsx +523 -0
- package/src/app/screens/DeviceApproval.tsx +500 -0
- package/src/app/screens/NotFound.tsx +62 -0
- package/src/app/screens/SignIn.tsx +372 -0
- package/src/app/screens/WalletUpgrade.tsx +121 -0
- package/src/app/screens/chains/base.svg +3 -0
- package/src/app/screens/chains/ethereum.svg +11 -0
- package/src/app/screens/chains/solana.svg +4 -0
- package/src/app/screens/chains/tempo.svg +4 -0
- package/src/app/server.ts +342 -0
- package/src/app/vite.config.ts +128 -0
- package/src/app/void.config.ts +36 -0
- package/src/app/wallet.ts +69 -0
- package/src/app/zyzz.config.ts +52 -0
- package/src/cli/Admin.ts +74 -0
- package/src/cli/Apps.ts +27 -0
- package/src/cli/Cli.ts +41 -0
- package/src/cli/Project.ts +119 -0
- package/src/cli/Realms.ts +49 -0
- package/src/cli/Session.ts +290 -0
- package/src/cli/User.ts +40 -0
- package/src/cli/V1.ts +54 -0
- package/src/cli/bin.ts +44 -0
- package/src/cli/commands/admin/apps/create.ts +96 -0
- package/src/cli/commands/admin/apps/delete.ts +38 -0
- package/src/cli/commands/admin/apps/index.ts +15 -0
- package/src/cli/commands/admin/apps/list.ts +25 -0
- package/src/cli/commands/admin/apps/rotate-secret.ts +47 -0
- package/src/cli/commands/admin/apps/update.ts +79 -0
- package/src/cli/commands/admin/index.ts +14 -0
- package/src/cli/commands/admin/migrate.ts +19 -0
- package/src/cli/commands/admin/realms/add.ts +40 -0
- package/src/cli/commands/admin/realms/index.ts +14 -0
- package/src/cli/commands/admin/realms/list.ts +38 -0
- package/src/cli/commands/admin/realms/passkeys/index.ts +15 -0
- package/src/cli/commands/admin/realms/passkeys/set.ts +44 -0
- package/src/cli/commands/admin/realms/privy/index.ts +14 -0
- package/src/cli/commands/admin/realms/privy/set.ts +69 -0
- package/src/cli/commands/admin/realms/remove.ts +33 -0
- package/src/cli/commands/admin/realms/secp256k1/disable.ts +40 -0
- package/src/cli/commands/admin/realms/secp256k1/enable.ts +40 -0
- package/src/cli/commands/admin/realms/secp256k1/index.ts +19 -0
- package/src/cli/commands/admin/realms/set.ts +46 -0
- package/src/cli/commands/admin/rotate-key.ts +47 -0
- package/src/cli/commands/init.ts +42 -0
- package/src/cli/commands/login.ts +32 -0
- package/src/cli/commands/logout.ts +19 -0
- package/src/cli/commands/whoami.ts +23 -0
- package/src/client/Actions.ts +180 -0
- package/src/client/Auth.ts +267 -0
- package/src/client/Authorization.ts +34 -0
- package/src/client/Decorator.ts +444 -0
- package/src/client/Key.ts +137 -0
- package/src/client/Pending.ts +45 -0
- package/src/client/Permissions.ts +41 -0
- package/src/client/Storage.ts +29 -0
- package/src/client/TempoAccount.ts +55 -0
- package/src/client/Tokens.ts +27 -0
- package/src/client/User.ts +23 -0
- package/src/client/actions/account.ts +171 -0
- package/src/client/actions/device.ts +166 -0
- package/src/client/actions/email.ts +164 -0
- package/src/client/actions/oauth.ts +179 -0
- package/src/client/actions/passkey.ts +333 -0
- package/src/client/actions/realm.ts +37 -0
- package/src/client/actions/redirect.ts +502 -0
- package/src/client/internal/accessKey.ts +54 -0
- package/src/client/internal/account.ts +18 -0
- package/src/client/internal/api.ts +242 -0
- package/src/client/internal/headless.ts +308 -0
- package/src/client/internal/indexedDb.ts +44 -0
- package/src/client/internal/request.ts +70 -0
- package/src/client/internal/store.ts +20 -0
- package/src/client/internal/verifier.ts +75 -0
- package/src/client.ts +17 -0
- package/src/index.ts +5 -0
- package/src/internal/Apps.ts +1283 -0
- package/src/internal/Auth.ts +273 -0
- package/src/internal/Authorize.ts +433 -0
- package/src/internal/Balance.ts +144 -0
- package/src/internal/BodyLimit.ts +31 -0
- package/src/internal/Cache.ts +119 -0
- package/src/internal/Chain.ts +99 -0
- package/src/internal/ChainList.ts +270 -0
- package/src/internal/ChainName.ts +14 -0
- package/src/internal/ChainStatus.ts +65 -0
- package/src/internal/CodeEmail.ts +138 -0
- package/src/internal/ConfigurableAccount.ts +1315 -0
- package/src/internal/Device.ts +471 -0
- package/src/internal/Env.ts +92 -0
- package/src/internal/ErrorResponse.ts +896 -0
- package/src/internal/Faucet.ts +43 -0
- package/src/internal/Id.ts +41 -0
- package/src/internal/KeyAuthorization.ts +1536 -0
- package/src/internal/Limits.ts +40 -0
- package/src/internal/Log.ts +166 -0
- package/src/internal/LogLine.ts +81 -0
- package/src/internal/Logout.ts +356 -0
- package/src/internal/Migrations.ts +120 -0
- package/src/internal/OpenApi.ts +300 -0
- package/src/internal/Owner.ts +310 -0
- package/src/internal/Passkey.ts +1904 -0
- package/src/internal/PendingKey.ts +104 -0
- package/src/internal/Privy.ts +536 -0
- package/src/internal/RateLimit.ts +346 -0
- package/src/internal/Realm.ts +814 -0
- package/src/internal/RequestId.ts +118 -0
- package/src/internal/SignInGrant.ts +175 -0
- package/src/internal/SigningKey.ts +319 -0
- package/src/internal/TempoAccount.ts +545 -0
- package/src/internal/TestInbox.ts +51 -0
- package/src/internal/Timing.ts +172 -0
- package/src/internal/Validation.ts +52 -0
- package/src/internal/Verification.ts +58 -0
- package/src/internal/Wallet.ts +101 -0
- package/src/internal/owners/Passkey.ts +76 -0
- package/src/internal/owners/Privy.ts +82 -0
- package/src/internal/owners/Secp256k1.ts +139 -0
- package/src/types/app.d.ts +39 -0
- package/src/worker.ts +17 -0
|
@@ -0,0 +1,1283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth apps: the Better Auth plugins that serve them, and the `tempo-id admin apps` operations on
|
|
3
|
+
* `oauth_client`. Every registered app is first-party. A third-party app's client ID is its
|
|
4
|
+
* metadata document's URL or its origin.
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
import {
|
|
8
|
+
createCimdClientDiscovery,
|
|
9
|
+
isCimdClientIdUrlCandidate,
|
|
10
|
+
} from '@better-auth/cimd'
|
|
11
|
+
import {
|
|
12
|
+
isLoopbackHost,
|
|
13
|
+
isPublicRoutableHost,
|
|
14
|
+
} from '@better-auth/core/utils/host'
|
|
15
|
+
import { isNativePrivateUseRedirectUri } from '@better-auth/core/utils/redirect-uri'
|
|
16
|
+
import type {
|
|
17
|
+
ClientDiscovery,
|
|
18
|
+
ClientMetadataResourceFetch,
|
|
19
|
+
} from '@better-auth/oauth-provider'
|
|
20
|
+
import {
|
|
21
|
+
getOAuthProviderApi,
|
|
22
|
+
getOAuthProviderState,
|
|
23
|
+
oauthProvider,
|
|
24
|
+
} from '@better-auth/oauth-provider'
|
|
25
|
+
import { registerClientMetadataDocument } from '@better-auth/oauth-provider/internal'
|
|
26
|
+
import type { BetterAuthPlugin } from 'better-auth'
|
|
27
|
+
import {
|
|
28
|
+
APIError,
|
|
29
|
+
createAuthEndpoint,
|
|
30
|
+
createAuthMiddleware,
|
|
31
|
+
getSessionFromCtx,
|
|
32
|
+
setShouldSkipSessionRefresh,
|
|
33
|
+
} from 'better-auth/api'
|
|
34
|
+
import { generateRandomString } from 'better-auth/crypto'
|
|
35
|
+
import { jwt } from 'better-auth/plugins/jwt'
|
|
36
|
+
import { and, asc, eq, inArray, isNull, or } from 'drizzle-orm'
|
|
37
|
+
import { Base64, Bytes } from 'ox'
|
|
38
|
+
import { z } from 'zod'
|
|
39
|
+
import * as Schema from '../app/db/schema.js'
|
|
40
|
+
import type * as Cache from './Cache.js'
|
|
41
|
+
import type * as PendingKey from './PendingKey.js'
|
|
42
|
+
import type * as Realm from './Realm.js'
|
|
43
|
+
import * as SigningKey from './SigningKey.js'
|
|
44
|
+
|
|
45
|
+
/** Another app already has the client ID. */
|
|
46
|
+
export class ExistsError extends Error {
|
|
47
|
+
override readonly name = 'Apps.ExistsError'
|
|
48
|
+
|
|
49
|
+
constructor(options: { clientId: string }) {
|
|
50
|
+
super(
|
|
51
|
+
`App ${options.clientId} already exists. Update it, or choose another client ID.`,
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** A name, a redirect URI, or another value of an app is not valid. */
|
|
57
|
+
export class InvalidError extends Error {
|
|
58
|
+
override readonly name = 'Apps.InvalidError'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** No OAuth app has the client ID. */
|
|
62
|
+
export class NotFoundError extends Error {
|
|
63
|
+
override readonly name = 'Apps.NotFoundError'
|
|
64
|
+
|
|
65
|
+
constructor(options: { clientId: string }) {
|
|
66
|
+
super(`Unknown app ${options.clientId}. Name a registered OAuth app.`)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The app redeems codes with PKCE alone, so it has no client secret to rotate. */
|
|
71
|
+
export class PublicError extends Error {
|
|
72
|
+
override readonly name = 'Apps.PublicError'
|
|
73
|
+
|
|
74
|
+
constructor(options: { clientId: string }) {
|
|
75
|
+
super(
|
|
76
|
+
`App ${options.clientId} has no client secret. Rotate the secret of an app with a backend.`,
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** An OAuth app, as `tempo-id admin apps` returns it. */
|
|
82
|
+
export type App = {
|
|
83
|
+
/** Sent as `client_id`. */
|
|
84
|
+
clientId: string
|
|
85
|
+
/** When the app was created. */
|
|
86
|
+
createdAt: Date | null
|
|
87
|
+
/** Whether the app signs in through the device grant, as a CLI does. */
|
|
88
|
+
device: boolean
|
|
89
|
+
/** Whether `tempo-id admin apps` registered the app, which then skips consent for keyless requests. */
|
|
90
|
+
firstParty: boolean
|
|
91
|
+
/** The logo as a `data:` URL. Only an app with an origin client ID has one. */
|
|
92
|
+
logo: string | null
|
|
93
|
+
/** The display name on the approval page. */
|
|
94
|
+
name: string | null
|
|
95
|
+
/** The URIs that `GET /oauth2/end-session` may return to. */
|
|
96
|
+
postLogoutRedirectUris: readonly string[]
|
|
97
|
+
/** The URIs that the app returns to. */
|
|
98
|
+
redirectUris: readonly string[]
|
|
99
|
+
/** Whether the app holds a client secret for its backend. */
|
|
100
|
+
secret: boolean
|
|
101
|
+
/** Whether the app holds the `tempo-id:sign` scope. */
|
|
102
|
+
sign: boolean
|
|
103
|
+
/** `web` for a browser app or a backend, and `native` for a mobile app. */
|
|
104
|
+
type: 'native' | 'web'
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** The grant type of the device grant (RFC 8628 §3.4). */
|
|
108
|
+
export const deviceGrant = 'urn:ietf:params:oauth:grant-type:device_code'
|
|
109
|
+
|
|
110
|
+
/** Lets an app bind its own challenge, and request unknown key calls headlessly. */
|
|
111
|
+
export const signScope = 'tempo-id:sign'
|
|
112
|
+
|
|
113
|
+
/** The scopes that every app may request. */
|
|
114
|
+
const scopes = ['openid', 'profile', 'email', 'offline_access'] as const
|
|
115
|
+
|
|
116
|
+
/** Returns whether `clientSecret` matches the enabled app, which selects a rate limit's app. */
|
|
117
|
+
export async function authenticate(
|
|
118
|
+
db: Realm.Database,
|
|
119
|
+
options: authenticate.Options,
|
|
120
|
+
) {
|
|
121
|
+
const [row] = await db
|
|
122
|
+
.select({
|
|
123
|
+
clientSecret: Schema.oauthClient.clientSecret,
|
|
124
|
+
disabled: Schema.oauthClient.disabled,
|
|
125
|
+
})
|
|
126
|
+
.from(Schema.oauthClient)
|
|
127
|
+
.where(eq(Schema.oauthClient.clientId, options.clientId))
|
|
128
|
+
.limit(1)
|
|
129
|
+
if (!row?.clientSecret || row.disabled) return false
|
|
130
|
+
return equal(await hashSecret(options.clientSecret), row.clientSecret)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export declare namespace authenticate {
|
|
134
|
+
type Options = {
|
|
135
|
+
/** The client ID that the request names. */
|
|
136
|
+
clientId: string
|
|
137
|
+
/** The client secret that the request sends. */
|
|
138
|
+
clientSecret: string
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Registers an app, and returns it with its client secret, which appears only here. Throws
|
|
144
|
+
* `InvalidError` for an invalid value, and `ExistsError` for a client ID in use.
|
|
145
|
+
*/
|
|
146
|
+
export async function create(db: Realm.Database, options: create.Options) {
|
|
147
|
+
const type = options.type ?? 'web'
|
|
148
|
+
const name = parseName(options.name)
|
|
149
|
+
const postLogoutRedirectUris = parsePostLogoutRedirectUris(
|
|
150
|
+
options.postLogoutRedirectUris ?? [],
|
|
151
|
+
{ type },
|
|
152
|
+
)
|
|
153
|
+
const device = options.device ?? false
|
|
154
|
+
// A CLI cannot keep a secret, and the device grant's poll sends none, so a device app is public.
|
|
155
|
+
if (device && (options.secret || options.clientSecret !== undefined))
|
|
156
|
+
throw new InvalidError(
|
|
157
|
+
'Invalid app: a device app has no client secret, since a CLI cannot keep one. Leave out the secret.',
|
|
158
|
+
)
|
|
159
|
+
// A device app redirects nowhere, so it needs no redirect URI.
|
|
160
|
+
const redirectUris =
|
|
161
|
+
device && (options.redirectUris ?? []).length === 0
|
|
162
|
+
? []
|
|
163
|
+
: parseRedirectUris(options.redirectUris ?? [], { type })
|
|
164
|
+
const clientId =
|
|
165
|
+
options.clientId === undefined
|
|
166
|
+
? // Better Auth's format: 32 random letters.
|
|
167
|
+
generateRandomString(32, 'a-z', 'A-Z')
|
|
168
|
+
: parseClientId(options.clientId)
|
|
169
|
+
const clientSecret = (() => {
|
|
170
|
+
if (options.clientSecret !== undefined)
|
|
171
|
+
return parseClientSecret(options.clientSecret)
|
|
172
|
+
return options.secret ? secret() : undefined
|
|
173
|
+
})()
|
|
174
|
+
|
|
175
|
+
const now = new Date()
|
|
176
|
+
const [row] = await db
|
|
177
|
+
.insert(Schema.oauthClient)
|
|
178
|
+
.values({
|
|
179
|
+
applicationType: type,
|
|
180
|
+
clientId,
|
|
181
|
+
clientSecret: clientSecret ? await hashSecret(clientSecret) : null,
|
|
182
|
+
createdAt: now,
|
|
183
|
+
// Lets the app end the session at `GET /oauth2/end-session`, and puts `sid` in its ID tokens.
|
|
184
|
+
enableEndSession: true,
|
|
185
|
+
// A device app has no authorization code grant, so `/oauth2/authorize` refuses it.
|
|
186
|
+
grantTypes: device
|
|
187
|
+
? [deviceGrant, 'refresh_token']
|
|
188
|
+
: ['authorization_code', 'refresh_token'],
|
|
189
|
+
id: crypto.randomUUID(),
|
|
190
|
+
name,
|
|
191
|
+
postLogoutRedirectUris: [...postLogoutRedirectUris],
|
|
192
|
+
redirectUris: [...redirectUris],
|
|
193
|
+
responseTypes: ['code'],
|
|
194
|
+
scopes: scopesOf({ sign: options.sign ?? false }),
|
|
195
|
+
// Every registered app is first-party.
|
|
196
|
+
skipConsent: true,
|
|
197
|
+
// The client package sends the secret in the form body.
|
|
198
|
+
tokenEndpointAuthMethod: clientSecret ? 'client_secret_post' : 'none',
|
|
199
|
+
updatedAt: now,
|
|
200
|
+
})
|
|
201
|
+
.onConflictDoNothing({ target: Schema.oauthClient.clientId })
|
|
202
|
+
.returning()
|
|
203
|
+
if (!row) throw new ExistsError({ clientId })
|
|
204
|
+
|
|
205
|
+
return { app: toApp(row), ...(clientSecret ? { clientSecret } : {}) }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export declare namespace create {
|
|
209
|
+
type Options = {
|
|
210
|
+
/** Another deployment's client ID to keep. Defaults to 32 random letters. */
|
|
211
|
+
clientId?: string | undefined
|
|
212
|
+
/** Another deployment's client secret to keep. Implies `secret`. */
|
|
213
|
+
clientSecret?: string | undefined
|
|
214
|
+
/** Whether the app signs in through the device grant. Defaults to `false`. */
|
|
215
|
+
device?: boolean | undefined
|
|
216
|
+
/** The display name on the approval page. */
|
|
217
|
+
name: string
|
|
218
|
+
/** The URIs that `GET /oauth2/end-session` may return to. Defaults to none. */
|
|
219
|
+
postLogoutRedirectUris?: readonly string[] | undefined
|
|
220
|
+
/** The URIs that the app returns to, in every environment. A device app may have none. */
|
|
221
|
+
redirectUris?: readonly string[] | undefined
|
|
222
|
+
/** Whether the app receives a new client secret. Defaults to `false`. */
|
|
223
|
+
secret?: boolean | undefined
|
|
224
|
+
/** Whether the app holds the `tempo-id:sign` scope. Defaults to `false`. */
|
|
225
|
+
sign?: boolean | undefined
|
|
226
|
+
/** The application type. Defaults to `web`. */
|
|
227
|
+
type?: App['type'] | undefined
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Returns the fetch of third-party apps' metadata documents, through `fetcher`. It refuses
|
|
233
|
+
* redirects, since a document must sit at its client ID's URL.
|
|
234
|
+
*/
|
|
235
|
+
export function fetchMetadata(
|
|
236
|
+
fetcher: fetchMetadata.Fetcher = globalThis,
|
|
237
|
+
): ClientMetadataResourceFetch {
|
|
238
|
+
return async (input, init) => {
|
|
239
|
+
// Workers support only `follow` and `manual`, so a redirect returns, and the transport refuses it.
|
|
240
|
+
const response = await fetcher.fetch(
|
|
241
|
+
new Request(input, { ...init, redirect: 'manual' }),
|
|
242
|
+
)
|
|
243
|
+
// A 304 answers the discovery's own conditional request, and moves nothing.
|
|
244
|
+
if (
|
|
245
|
+
response.status < 300 ||
|
|
246
|
+
response.status >= 400 ||
|
|
247
|
+
response.status === 304
|
|
248
|
+
)
|
|
249
|
+
return response
|
|
250
|
+
await response.body?.cancel()
|
|
251
|
+
throw new TypeError('The metadata document redirects.')
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export declare namespace fetchMetadata {
|
|
256
|
+
/** The global scope or a service binding. */
|
|
257
|
+
type Fetcher = {
|
|
258
|
+
/** Fetches the request. */
|
|
259
|
+
fetch: (request: Request) => Promise<Response>
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Returns the enabled first-party apps with a redirect URI at `origin`. */
|
|
264
|
+
export async function firstPartyOrigin(
|
|
265
|
+
db: Realm.Database,
|
|
266
|
+
options: firstPartyOrigin.Options,
|
|
267
|
+
): Promise<readonly App[]> {
|
|
268
|
+
const rows = await db
|
|
269
|
+
.select()
|
|
270
|
+
.from(Schema.oauthClient)
|
|
271
|
+
.where(
|
|
272
|
+
and(
|
|
273
|
+
isNull(Schema.oauthClient.clientDiscoveryId),
|
|
274
|
+
eq(Schema.oauthClient.skipConsent, true),
|
|
275
|
+
or(
|
|
276
|
+
isNull(Schema.oauthClient.disabled),
|
|
277
|
+
eq(Schema.oauthClient.disabled, false),
|
|
278
|
+
),
|
|
279
|
+
),
|
|
280
|
+
)
|
|
281
|
+
return rows
|
|
282
|
+
.filter((row) =>
|
|
283
|
+
row.redirectUris.some((uri) => {
|
|
284
|
+
const url = URL.parse(uri)
|
|
285
|
+
return (
|
|
286
|
+
(url?.protocol === 'https:' || url?.protocol === 'http:') &&
|
|
287
|
+
url.origin === options.origin
|
|
288
|
+
)
|
|
289
|
+
}),
|
|
290
|
+
)
|
|
291
|
+
.map(toApp)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export declare namespace firstPartyOrigin {
|
|
295
|
+
type Options = {
|
|
296
|
+
/** The request's `Origin`. */
|
|
297
|
+
origin: string
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Returns the app with `clientId`. Throws `NotFoundError` if it is unknown, or disabled with
|
|
303
|
+
* `enabled`.
|
|
304
|
+
*/
|
|
305
|
+
export async function get(db: Realm.Database, options: get.Options) {
|
|
306
|
+
const row = await find(db, options)
|
|
307
|
+
if (options.enabled && row.disabled)
|
|
308
|
+
throw new NotFoundError({ clientId: options.clientId })
|
|
309
|
+
return toApp(row)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export declare namespace get {
|
|
313
|
+
type Options = {
|
|
314
|
+
/** The app's client ID. */
|
|
315
|
+
clientId: string
|
|
316
|
+
/** Whether a disabled app counts as no app. Defaults to `false`. */
|
|
317
|
+
enabled?: boolean | undefined
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** Returns the SHA-256 hash of a client secret as unpadded base64url, as the row holds it. */
|
|
322
|
+
export async function hashSecret(secret: string) {
|
|
323
|
+
const digest = await crypto.subtle.digest(
|
|
324
|
+
'SHA-256',
|
|
325
|
+
new TextEncoder().encode(secret),
|
|
326
|
+
)
|
|
327
|
+
return Base64.fromBytes(new Uint8Array(digest), { pad: false, url: true })
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Compares two `hashSecret` hashes in constant time. The CLI runs this module in Node, whose
|
|
332
|
+
* `crypto.subtle` has no `timingSafeEqual`.
|
|
333
|
+
*/
|
|
334
|
+
function equal(a: string, b: string) {
|
|
335
|
+
const left = Base64.toBytes(a)
|
|
336
|
+
const right = Base64.toBytes(b)
|
|
337
|
+
if (left.length !== right.length) return false
|
|
338
|
+
let difference = 0
|
|
339
|
+
for (let index = 0; index < left.length; index++)
|
|
340
|
+
difference |= left[index]! ^ right[index]!
|
|
341
|
+
return difference === 0
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** Returns every registered app, oldest first, without third-party apps. */
|
|
345
|
+
export async function list(db: Realm.Database): Promise<readonly App[]> {
|
|
346
|
+
const rows = await db
|
|
347
|
+
.select()
|
|
348
|
+
.from(Schema.oauthClient)
|
|
349
|
+
.where(isNull(Schema.oauthClient.clientDiscoveryId))
|
|
350
|
+
.orderBy(
|
|
351
|
+
asc(Schema.oauthClient.createdAt),
|
|
352
|
+
asc(Schema.oauthClient.clientId),
|
|
353
|
+
)
|
|
354
|
+
return rows.map(toApp)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** The origins whose resource row this isolate read, so later instances skip the seed's read. */
|
|
358
|
+
const seeded = new Set<string>()
|
|
359
|
+
|
|
360
|
+
/** Returns the Better Auth plugins that serve OAuth apps: the JWT plugin and the OAuth provider. */
|
|
361
|
+
export function plugins(options: plugins.Options) {
|
|
362
|
+
const { accountStep, baseURL, cache, pendingKey } = options
|
|
363
|
+
const fetch = options.metadataFetch ?? fetchMetadata()
|
|
364
|
+
return [
|
|
365
|
+
// `iss` is the configured origin, never the request's host. No client reads the session's JWT
|
|
366
|
+
// header, and each session read would otherwise read the signing keys and sign one.
|
|
367
|
+
jwt({
|
|
368
|
+
adapter: SigningKey.adapter({ cache }),
|
|
369
|
+
disableSettingJwtHeader: true,
|
|
370
|
+
jwks: SigningKey.jwks,
|
|
371
|
+
jwt: { issuer: baseURL },
|
|
372
|
+
}),
|
|
373
|
+
oauthProvider({
|
|
374
|
+
allowDynamicClientRegistration: false,
|
|
375
|
+
// The resource's row holds only the values below, so the isolate reads it once.
|
|
376
|
+
cachedResources: new Set([baseURL]),
|
|
377
|
+
// The provider keeps each client row that it reads for the life of its options, which each
|
|
378
|
+
// request creates again, so a request reads each app once, and the next one reads it again.
|
|
379
|
+
// A cached client cannot change through the provider's client endpoints, which no route serves.
|
|
380
|
+
cachedTrustedClients: Object.assign(new Set<string>(), {
|
|
381
|
+
has: () => true,
|
|
382
|
+
}),
|
|
383
|
+
// A third-party app holds only the scopes that every app may request, never `tempo-id:sign`.
|
|
384
|
+
clientRegistrationDefaultScopes: [...scopes],
|
|
385
|
+
consentPage: '/authorize',
|
|
386
|
+
// Apps read the user's address from the ID token, so a grant of `email` puts it there as well
|
|
387
|
+
// as in userinfo, as OIDC Core §5.4 allows.
|
|
388
|
+
customIdTokenClaims: (info) =>
|
|
389
|
+
info.scopes.includes('email')
|
|
390
|
+
? {
|
|
391
|
+
email: info.user.email,
|
|
392
|
+
email_verified: info.user.emailVerified,
|
|
393
|
+
}
|
|
394
|
+
: {},
|
|
395
|
+
// Every app may request the one resource.
|
|
396
|
+
enforcePerClientResources: false,
|
|
397
|
+
// A third-party app names its metadata document's URL or its origin as its client ID, and
|
|
398
|
+
// registers no row.
|
|
399
|
+
extensions: [
|
|
400
|
+
{
|
|
401
|
+
clientDiscovery: [discovery({ fetch }), originDiscovery({ fetch })],
|
|
402
|
+
},
|
|
403
|
+
],
|
|
404
|
+
loginPage: '/login',
|
|
405
|
+
// The account step runs after sign-in and before consent, and `oauth2Continue` resumes the
|
|
406
|
+
// authorization with `postLogin`, which checks again.
|
|
407
|
+
...(accountStep
|
|
408
|
+
? {
|
|
409
|
+
postLogin: {
|
|
410
|
+
consentReferenceId: () => undefined,
|
|
411
|
+
page: '/choose-account',
|
|
412
|
+
shouldRedirect: async (context: {
|
|
413
|
+
headers: Headers
|
|
414
|
+
session: { id: string }
|
|
415
|
+
user: { id: string }
|
|
416
|
+
}) => {
|
|
417
|
+
// The authorization stores its query before it checks, so the hook reads the app.
|
|
418
|
+
const stored = (await getOAuthProviderState())?.query
|
|
419
|
+
const query = new URLSearchParams(stored ?? '')
|
|
420
|
+
const clientId = query.get('client_id')
|
|
421
|
+
if (!clientId) return false
|
|
422
|
+
return await accountStep({
|
|
423
|
+
clientId,
|
|
424
|
+
headers: context.headers,
|
|
425
|
+
query,
|
|
426
|
+
sessionId: context.session.id,
|
|
427
|
+
userId: context.user.id,
|
|
428
|
+
})
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
}
|
|
432
|
+
: {}),
|
|
433
|
+
// A code's redemption returns the key that its approval signed, once. Better Auth calls this
|
|
434
|
+
// after it checks the verifier against the code's challenge.
|
|
435
|
+
...(pendingKey
|
|
436
|
+
? {
|
|
437
|
+
customTokenResponseFields: async (info: {
|
|
438
|
+
grantType: string
|
|
439
|
+
user?: { id: string } | null | undefined
|
|
440
|
+
verificationValue?: {
|
|
441
|
+
query: {
|
|
442
|
+
client_id: string
|
|
443
|
+
code_challenge?: string | undefined
|
|
444
|
+
key_authorization?: unknown
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}) => {
|
|
448
|
+
const query = info.verificationValue?.query
|
|
449
|
+
if (
|
|
450
|
+
info.grantType !== 'authorization_code' ||
|
|
451
|
+
!query?.code_challenge ||
|
|
452
|
+
// Only a code whose request carried the key takes it, so a keyless code for a reused
|
|
453
|
+
// challenge leaves it for the keyed one.
|
|
454
|
+
query.key_authorization === undefined ||
|
|
455
|
+
!info.user
|
|
456
|
+
)
|
|
457
|
+
return {}
|
|
458
|
+
const key = await pendingKey({
|
|
459
|
+
clientId: query.client_id,
|
|
460
|
+
codeChallenge: query.code_challenge,
|
|
461
|
+
userId: info.user.id,
|
|
462
|
+
})
|
|
463
|
+
if (!key) return {}
|
|
464
|
+
return {
|
|
465
|
+
account: key.account,
|
|
466
|
+
key_authorization: key.keyAuthorization,
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
}
|
|
470
|
+
: {}),
|
|
471
|
+
// Every access token names one audience, so each API verifies tokens for every app the same way.
|
|
472
|
+
resources: seeded.has(baseURL)
|
|
473
|
+
? []
|
|
474
|
+
: [{ accessTokenTtl: 300, identifier: baseURL, name: 'Tempo ID' }],
|
|
475
|
+
// Better Auth checks a registered app's scopes against its own row, so `tempo-id:sign` stays out
|
|
476
|
+
// of this list. A row without scopes falls back to this list, and never receives the scope.
|
|
477
|
+
scopes: [...scopes],
|
|
478
|
+
// `create` and `rotateSecret` store each secret with the same hash.
|
|
479
|
+
storeClientSecret: { hash: hashSecret },
|
|
480
|
+
}),
|
|
481
|
+
// A session read inside the authorization extends no session, since the provider's after hook
|
|
482
|
+
// reads the session cookie of the extension as a sign-in, and authorizes again, with a second
|
|
483
|
+
// code. This hook runs after the provider's, so it extends a session that is due once the
|
|
484
|
+
// authorization returns. Better Auth's read extends it and sets the cookie.
|
|
485
|
+
{
|
|
486
|
+
hooks: {
|
|
487
|
+
after: [
|
|
488
|
+
{
|
|
489
|
+
handler: createAuthMiddleware(async (ctx) => {
|
|
490
|
+
await setShouldSkipSessionRefresh(false)
|
|
491
|
+
const session = ctx.context.session
|
|
492
|
+
if (!session) return
|
|
493
|
+
// Better Auth extends a session once `updateAge` of its lifetime passed.
|
|
494
|
+
const { expiresIn, updateAge } = ctx.context.sessionConfig
|
|
495
|
+
const due =
|
|
496
|
+
new Date(session.session.expiresAt).getTime() -
|
|
497
|
+
(expiresIn - updateAge) * 1000 <=
|
|
498
|
+
Date.now()
|
|
499
|
+
if (!due) return
|
|
500
|
+
ctx.context.session = null
|
|
501
|
+
await getSessionFromCtx(ctx)
|
|
502
|
+
}),
|
|
503
|
+
matcher: (ctx) => ctx.path === '/oauth2/authorize',
|
|
504
|
+
},
|
|
505
|
+
],
|
|
506
|
+
before: [
|
|
507
|
+
{
|
|
508
|
+
handler: createAuthMiddleware(async () => {
|
|
509
|
+
await setShouldSkipSessionRefresh(true)
|
|
510
|
+
}),
|
|
511
|
+
matcher: (ctx) => ctx.path === '/oauth2/authorize',
|
|
512
|
+
},
|
|
513
|
+
],
|
|
514
|
+
},
|
|
515
|
+
id: 'tempo-id-authorize-session',
|
|
516
|
+
} satisfies BetterAuthPlugin,
|
|
517
|
+
// Tempo ID's own checks read the `oauth_client` row, which only a resolution writes for a
|
|
518
|
+
// third-party app. Better Auth resolves a client only inside its endpoints, so a route resolves
|
|
519
|
+
// it here before the checks.
|
|
520
|
+
{
|
|
521
|
+
endpoints: {
|
|
522
|
+
resolveOAuthClient: createAuthEndpoint.serverOnly(
|
|
523
|
+
{ body: z.object({ client_id: z.string() }), method: 'POST' },
|
|
524
|
+
async (ctx) => {
|
|
525
|
+
const plugin = ctx.context.getPlugin('oauth-provider')
|
|
526
|
+
if (!plugin)
|
|
527
|
+
throw new Error('The OAuth provider plugin is missing.')
|
|
528
|
+
const client = await getOAuthProviderApi(
|
|
529
|
+
ctx,
|
|
530
|
+
plugin.options,
|
|
531
|
+
).getClient(ctx.body.client_id)
|
|
532
|
+
return ctx.json({ resolved: Boolean(client && !client.disabled) })
|
|
533
|
+
},
|
|
534
|
+
),
|
|
535
|
+
},
|
|
536
|
+
id: 'tempo-id-client-discovery',
|
|
537
|
+
} satisfies BetterAuthPlugin,
|
|
538
|
+
// Plugins run `init` in order, so this one runs after the provider's seed. A seed that failed
|
|
539
|
+
// logs and leaves no row, so the next instance seeds again.
|
|
540
|
+
{
|
|
541
|
+
id: 'tempo-id-resource-seed',
|
|
542
|
+
init: async (ctx) => {
|
|
543
|
+
if (seeded.has(baseURL)) return
|
|
544
|
+
const row = await ctx.adapter.findOne({
|
|
545
|
+
model: 'oauthResource',
|
|
546
|
+
where: [{ field: 'identifier', value: baseURL }],
|
|
547
|
+
})
|
|
548
|
+
if (row) seeded.add(baseURL)
|
|
549
|
+
},
|
|
550
|
+
} satisfies BetterAuthPlugin,
|
|
551
|
+
]
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
export declare namespace plugins {
|
|
555
|
+
type Options = {
|
|
556
|
+
/** Returns whether the app's authorization needs `/choose-account`. Absent, none does. */
|
|
557
|
+
accountStep?:
|
|
558
|
+
| ((options: {
|
|
559
|
+
clientId: string
|
|
560
|
+
headers: Headers
|
|
561
|
+
query: URLSearchParams
|
|
562
|
+
sessionId: string
|
|
563
|
+
userId: string
|
|
564
|
+
}) => Promise<boolean>)
|
|
565
|
+
| undefined
|
|
566
|
+
/** Tempo ID's origin, which is `iss` and the one resource. */
|
|
567
|
+
baseURL: string
|
|
568
|
+
/** The isolate's cache for the signing keys. Absent, nothing is cached. */
|
|
569
|
+
cache?: Cache.Cache | undefined
|
|
570
|
+
/** Fetches third-party apps' metadata documents. Defaults to `fetchMetadata()`. */
|
|
571
|
+
metadataFetch?: ClientMetadataResourceFetch | undefined
|
|
572
|
+
/** Takes a code's held key authorization, as `PendingKey.take` does. Absent, codes carry none. */
|
|
573
|
+
pendingKey?:
|
|
574
|
+
| ((options: {
|
|
575
|
+
clientId: string
|
|
576
|
+
codeChallenge: string
|
|
577
|
+
userId: string
|
|
578
|
+
}) => Promise<PendingKey.PendingKey | undefined>)
|
|
579
|
+
| undefined
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Removes the registered app with `clientId`, with its consents, tokens, and realms. Throws
|
|
585
|
+
* `NotFoundError` when no registered app has it.
|
|
586
|
+
*/
|
|
587
|
+
export async function remove(db: Realm.Database, options: remove.Options) {
|
|
588
|
+
const removed = await db
|
|
589
|
+
.delete(Schema.oauthClient)
|
|
590
|
+
.where(
|
|
591
|
+
and(
|
|
592
|
+
eq(Schema.oauthClient.clientId, options.clientId),
|
|
593
|
+
isNull(Schema.oauthClient.clientDiscoveryId),
|
|
594
|
+
),
|
|
595
|
+
)
|
|
596
|
+
.returning()
|
|
597
|
+
const [row] = removed
|
|
598
|
+
if (!row) throw new NotFoundError({ clientId: options.clientId })
|
|
599
|
+
return toApp(row)
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export declare namespace remove {
|
|
603
|
+
type Options = {
|
|
604
|
+
/** The app's client ID. */
|
|
605
|
+
clientId: string
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Replaces the client secret of the app with `clientId`, and returns the app with the new secret.
|
|
611
|
+
* The earlier secret stops working at once. Throws `NotFoundError` for an unknown app,
|
|
612
|
+
* `PublicError` for an app without a secret, and `InvalidError` for an invalid or unchanged secret.
|
|
613
|
+
*/
|
|
614
|
+
export async function rotateSecret(
|
|
615
|
+
db: Realm.Database,
|
|
616
|
+
options: rotateSecret.Options,
|
|
617
|
+
) {
|
|
618
|
+
const clientSecret =
|
|
619
|
+
options.clientSecret === undefined
|
|
620
|
+
? secret()
|
|
621
|
+
: parseClientSecret(options.clientSecret)
|
|
622
|
+
const current = await find(db, options)
|
|
623
|
+
if (!current.clientSecret) throw new PublicError(options)
|
|
624
|
+
// A rotation to the same secret would leave a leaked secret working while it reports success.
|
|
625
|
+
if (equal(current.clientSecret, await hashSecret(clientSecret)))
|
|
626
|
+
throw new InvalidError(
|
|
627
|
+
'Invalid client secret: it matches the current secret. Use a new secret.',
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
const [row] = await db
|
|
631
|
+
.update(Schema.oauthClient)
|
|
632
|
+
.set({
|
|
633
|
+
clientSecret: await hashSecret(clientSecret),
|
|
634
|
+
updatedAt: new Date(),
|
|
635
|
+
})
|
|
636
|
+
.where(eq(Schema.oauthClient.clientId, options.clientId))
|
|
637
|
+
.returning()
|
|
638
|
+
// A concurrent `remove` deleted the app after the read.
|
|
639
|
+
if (!row) throw new NotFoundError(options)
|
|
640
|
+
// The row, not the earlier read, since a concurrent `update` can change the app between them.
|
|
641
|
+
return { app: toApp(row), clientSecret }
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
export declare namespace rotateSecret {
|
|
645
|
+
type Options = {
|
|
646
|
+
/** The app's client ID. */
|
|
647
|
+
clientId: string
|
|
648
|
+
/** Another deployment's client secret to keep. Defaults to a new secret. */
|
|
649
|
+
clientSecret?: string | undefined
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/** Returns whether `clientId` is a canonical `https` origin, such as `https://app.example`. */
|
|
654
|
+
export function originId(clientId: string) {
|
|
655
|
+
const url = URL.parse(clientId)
|
|
656
|
+
return url?.protocol === 'https:' && url.origin === clientId
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/** Returns whether `clientId` names a third-party app: an `https` URL or origin. */
|
|
660
|
+
export function thirdParty(clientId: string) {
|
|
661
|
+
return isCimdClientIdUrlCandidate(clientId)
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/** Returns the third-party client IDs in `clientIds` without a row within `discoveryFreshness`. */
|
|
665
|
+
export async function stale(
|
|
666
|
+
db: Realm.Database,
|
|
667
|
+
options: stale.Options,
|
|
668
|
+
): Promise<readonly string[]> {
|
|
669
|
+
const candidates = [...new Set(options.clientIds.filter(thirdParty))]
|
|
670
|
+
if (candidates.length === 0) return []
|
|
671
|
+
const rows = await db
|
|
672
|
+
.select({
|
|
673
|
+
clientDiscoveryId: Schema.oauthClient.clientDiscoveryId,
|
|
674
|
+
clientId: Schema.oauthClient.clientId,
|
|
675
|
+
updatedAt: Schema.oauthClient.updatedAt,
|
|
676
|
+
})
|
|
677
|
+
.from(Schema.oauthClient)
|
|
678
|
+
.where(inArray(Schema.oauthClient.clientId, candidates))
|
|
679
|
+
const current = new Set(
|
|
680
|
+
rows.filter((row) => fresh(row)).map((row) => row.clientId),
|
|
681
|
+
)
|
|
682
|
+
return candidates.filter((clientId) => !current.has(clientId))
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
export declare namespace stale {
|
|
686
|
+
type Options = {
|
|
687
|
+
/** The client IDs in the request's parameters or Basic credentials. */
|
|
688
|
+
clientIds: readonly string[]
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Updates the registered app with `clientId`, and returns it. A value left out stays. Throws
|
|
694
|
+
* `NotFoundError` when no registered app has it, and `InvalidError` for an invalid value.
|
|
695
|
+
*/
|
|
696
|
+
export async function update(db: Realm.Database, options: update.Options) {
|
|
697
|
+
const current = await find(db, options)
|
|
698
|
+
// The discovery rewrites a third-party app's row from its document, so no update would hold.
|
|
699
|
+
if (current.clientDiscoveryId)
|
|
700
|
+
throw new NotFoundError({ clientId: options.clientId })
|
|
701
|
+
const app = toApp(current)
|
|
702
|
+
const name = options.name === undefined ? undefined : parseName(options.name)
|
|
703
|
+
const postLogoutRedirectUris =
|
|
704
|
+
options.postLogoutRedirectUris === undefined
|
|
705
|
+
? undefined
|
|
706
|
+
: parsePostLogoutRedirectUris(options.postLogoutRedirectUris, {
|
|
707
|
+
type: app.type,
|
|
708
|
+
})
|
|
709
|
+
const redirectUris =
|
|
710
|
+
options.redirectUris === undefined
|
|
711
|
+
? undefined
|
|
712
|
+
: parseRedirectUris(options.redirectUris, { type: app.type })
|
|
713
|
+
|
|
714
|
+
const [row] = await db
|
|
715
|
+
.update(Schema.oauthClient)
|
|
716
|
+
.set({
|
|
717
|
+
...(name === undefined ? {} : { name }),
|
|
718
|
+
...(postLogoutRedirectUris === undefined
|
|
719
|
+
? {}
|
|
720
|
+
: { postLogoutRedirectUris: [...postLogoutRedirectUris] }),
|
|
721
|
+
// An app registered before logout existed gains it with its post-logout redirect URIs.
|
|
722
|
+
...(postLogoutRedirectUris?.length ? { enableEndSession: true } : {}),
|
|
723
|
+
...(redirectUris === undefined
|
|
724
|
+
? {}
|
|
725
|
+
: { redirectUris: [...redirectUris] }),
|
|
726
|
+
...(options.sign === undefined
|
|
727
|
+
? {}
|
|
728
|
+
: {
|
|
729
|
+
scopes: scopesOf({
|
|
730
|
+
scopes: current.scopes ?? undefined,
|
|
731
|
+
sign: options.sign,
|
|
732
|
+
}),
|
|
733
|
+
}),
|
|
734
|
+
updatedAt: new Date(),
|
|
735
|
+
})
|
|
736
|
+
.where(eq(Schema.oauthClient.clientId, options.clientId))
|
|
737
|
+
.returning()
|
|
738
|
+
// A concurrent `remove` deleted the app after the read.
|
|
739
|
+
if (!row) throw new NotFoundError(options)
|
|
740
|
+
return toApp(row)
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
export declare namespace update {
|
|
744
|
+
type Options = {
|
|
745
|
+
/** The app's client ID. */
|
|
746
|
+
clientId: string
|
|
747
|
+
/** The display name. */
|
|
748
|
+
name?: string | undefined
|
|
749
|
+
/** Replaces the URIs that `GET /oauth2/end-session` may return to. An empty list clears them. */
|
|
750
|
+
postLogoutRedirectUris?: readonly string[] | undefined
|
|
751
|
+
/** Replaces the URIs that the app returns to. */
|
|
752
|
+
redirectUris?: readonly string[] | undefined
|
|
753
|
+
/** Whether the app holds the `tempo-id:sign` scope. */
|
|
754
|
+
sign?: boolean | undefined
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/** Milliseconds that a third-party app's row serves before the next fetch of its document. */
|
|
759
|
+
const discoveryFreshness = 5 * 60 * 1000
|
|
760
|
+
|
|
761
|
+
/** Returns whether `row` is a third-party app's row written within `discoveryFreshness`. */
|
|
762
|
+
function fresh(
|
|
763
|
+
row:
|
|
764
|
+
| { clientDiscoveryId?: string | null; updatedAt?: Date | null }
|
|
765
|
+
| null
|
|
766
|
+
| undefined,
|
|
767
|
+
): row is { clientDiscoveryId: string; updatedAt: Date } {
|
|
768
|
+
if (!row?.clientDiscoveryId || !row.updatedAt) return false
|
|
769
|
+
return Date.now() - row.updatedAt.getTime() < discoveryFreshness
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Returns the client discovery of apps whose client ID is a metadata document's URL. It binds every
|
|
774
|
+
* URL in the document to that origin. It refuses `http` or loopback URIs, grants other than
|
|
775
|
+
* `authorization_code` and `refresh_token`, and client authentication.
|
|
776
|
+
*/
|
|
777
|
+
function discovery(options: { fetch: ClientMetadataResourceFetch }) {
|
|
778
|
+
const cimd = createCimdClientDiscovery({
|
|
779
|
+
fetchClientMetadataResource: options.fetch,
|
|
780
|
+
originBoundFields: [
|
|
781
|
+
'client_uri',
|
|
782
|
+
'logo_uri',
|
|
783
|
+
'policy_uri',
|
|
784
|
+
'post_logout_redirect_uris',
|
|
785
|
+
'redirect_uris',
|
|
786
|
+
'tos_uri',
|
|
787
|
+
],
|
|
788
|
+
})
|
|
789
|
+
// An authorization with a key resolves the app before the issuer does. A failed fetch blocks the
|
|
790
|
+
// next fetch for the per-client interval, so the second resolve repeats the first one's result.
|
|
791
|
+
const resolutions = new Map<string, ReturnType<typeof cimd.resolve>>()
|
|
792
|
+
return {
|
|
793
|
+
...cimd,
|
|
794
|
+
// An origin client ID has no metadata document, and `originDiscovery` resolves it.
|
|
795
|
+
matches: (clientId) => cimd.matches(clientId) && !originId(clientId),
|
|
796
|
+
resolve: async (ctx, clientId, existing) => {
|
|
797
|
+
// The discovery's own cache lives in one Better Auth instance, which serves one request, so a
|
|
798
|
+
// fresh row serves as the cache. A row that the checks below refused stays refused.
|
|
799
|
+
const client = await (() => {
|
|
800
|
+
if (fresh(existing)) return existing
|
|
801
|
+
const resolution =
|
|
802
|
+
resolutions.get(clientId) ?? cimd.resolve(ctx, clientId, existing)
|
|
803
|
+
resolutions.set(clientId, resolution)
|
|
804
|
+
return resolution
|
|
805
|
+
})()
|
|
806
|
+
if (!client) return client
|
|
807
|
+
// The discovery admits loopback redirects, such as `http://localhost` and `https://x.localhost`,
|
|
808
|
+
// outside the origin binding. Tempo ID bans them, as `create` does.
|
|
809
|
+
// A custom scheme is refused too: any app on the device can claim it, so the key would reach an
|
|
810
|
+
// app other than the host that the approval page names. A mobile app uses a claimed https link.
|
|
811
|
+
const refused = [
|
|
812
|
+
...(client.redirectUris ?? []),
|
|
813
|
+
...(client.postLogoutRedirectUris ?? []),
|
|
814
|
+
].find((uri) => {
|
|
815
|
+
const url = URL.parse(uri)
|
|
816
|
+
if (!url || url.protocol !== 'https:') return true
|
|
817
|
+
return (
|
|
818
|
+
isLoopbackHost(url.hostname) || url.hostname.endsWith('.localhost')
|
|
819
|
+
)
|
|
820
|
+
})
|
|
821
|
+
if (refused)
|
|
822
|
+
throw new APIError('BAD_REQUEST', {
|
|
823
|
+
error: 'invalid_client',
|
|
824
|
+
error_description: `Invalid redirect URI in the metadata document: ${refused}. Use an https URI on the client ID's origin.`,
|
|
825
|
+
})
|
|
826
|
+
// A third-party app signs in through a redirect alone. The device grant would show its name on
|
|
827
|
+
// the device page, beside no host that proves it.
|
|
828
|
+
const grant = (client.grantTypes ?? []).find(
|
|
829
|
+
(type) => type !== 'authorization_code' && type !== 'refresh_token',
|
|
830
|
+
)
|
|
831
|
+
if (grant)
|
|
832
|
+
throw new APIError('BAD_REQUEST', {
|
|
833
|
+
error: 'invalid_client',
|
|
834
|
+
error_description: `Unsupported grant type in the metadata document: ${grant}. Use authorization_code and refresh_token.`,
|
|
835
|
+
})
|
|
836
|
+
// A third-party app is a public client that redeems codes with PKCE alone, so it holds no key
|
|
837
|
+
// that Tempo ID would fetch from a `jwks_uri`.
|
|
838
|
+
const method = client.tokenEndpointAuthMethod ?? 'none'
|
|
839
|
+
if (method !== 'none')
|
|
840
|
+
throw new APIError('BAD_REQUEST', {
|
|
841
|
+
error: 'invalid_client',
|
|
842
|
+
error_description: `Unsupported token_endpoint_auth_method in the metadata document: ${method}. Use none.`,
|
|
843
|
+
})
|
|
844
|
+
return client
|
|
845
|
+
},
|
|
846
|
+
} satisfies ClientDiscovery
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Returns the client discovery of apps whose client ID is their `https` origin. A failed `describe`
|
|
851
|
+
* falls back to the origin's root and host, so it never blocks a sign-in.
|
|
852
|
+
*/
|
|
853
|
+
function originDiscovery(options: { fetch: ClientMetadataResourceFetch }) {
|
|
854
|
+
// An authorization with a key resolves the app before the issuer does, so both read it once.
|
|
855
|
+
const resolutions = new Map<
|
|
856
|
+
string,
|
|
857
|
+
ReturnType<typeof registerClientMetadataDocument>
|
|
858
|
+
>()
|
|
859
|
+
return {
|
|
860
|
+
id: 'origin',
|
|
861
|
+
matches: originId,
|
|
862
|
+
resolve: async (ctx, clientId, existing) => {
|
|
863
|
+
// Tempo ID fetches the origin, so a private or reserved address is refused, as a metadata
|
|
864
|
+
// document's URL is.
|
|
865
|
+
const { host, hostname } = new URL(clientId)
|
|
866
|
+
if (!isPublicRoutableHost(hostname))
|
|
867
|
+
throw new APIError('BAD_REQUEST', {
|
|
868
|
+
error: 'invalid_client',
|
|
869
|
+
error_description: `Invalid client ID: ${clientId} is not a public host. Use the app's public https origin.`,
|
|
870
|
+
})
|
|
871
|
+
|
|
872
|
+
return await (async () => {
|
|
873
|
+
if (fresh(existing)) return existing
|
|
874
|
+
const plugin = ctx.context.getPlugin('oauth-provider')
|
|
875
|
+
if (!plugin) throw new Error('The OAuth provider plugin is missing.')
|
|
876
|
+
const resolution =
|
|
877
|
+
resolutions.get(clientId) ??
|
|
878
|
+
describe({ fetch: options.fetch, origin: clientId }).then((app) =>
|
|
879
|
+
registerClientMetadataDocument(ctx, plugin.options, {
|
|
880
|
+
clientDiscoveryId: 'origin',
|
|
881
|
+
clientId,
|
|
882
|
+
...(existing ? { existingClient: existing } : {}),
|
|
883
|
+
metadata: {
|
|
884
|
+
client_id: clientId,
|
|
885
|
+
client_name: app.name ?? host,
|
|
886
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
887
|
+
...(app.logo ? { logo_uri: app.logo } : {}),
|
|
888
|
+
// Better Auth matches each redirect URI exactly, so no other path on the origin, such as
|
|
889
|
+
// an open redirect, receives a code.
|
|
890
|
+
redirect_uris: app.redirectUris?.length
|
|
891
|
+
? [...app.redirectUris]
|
|
892
|
+
: [`${clientId}/`],
|
|
893
|
+
response_types: ['code'],
|
|
894
|
+
token_endpoint_auth_method: 'none',
|
|
895
|
+
},
|
|
896
|
+
}),
|
|
897
|
+
)
|
|
898
|
+
resolutions.set(clientId, resolution)
|
|
899
|
+
return (await resolution).client
|
|
900
|
+
})()
|
|
901
|
+
},
|
|
902
|
+
} satisfies ClientDiscovery
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/** The most that `describe` reads of the origin's page, and of its manifest, in bytes. */
|
|
906
|
+
const pageLimit = 64 * 1024
|
|
907
|
+
|
|
908
|
+
/** The largest logo that `describe` inlines, in bytes. */
|
|
909
|
+
const logoLimit = 32 * 1024
|
|
910
|
+
|
|
911
|
+
/** The image types that `describe` inlines as a logo. */
|
|
912
|
+
const logoTypes = new Set([
|
|
913
|
+
'image/gif',
|
|
914
|
+
'image/jpeg',
|
|
915
|
+
'image/png',
|
|
916
|
+
'image/svg+xml',
|
|
917
|
+
'image/webp',
|
|
918
|
+
])
|
|
919
|
+
|
|
920
|
+
/**
|
|
921
|
+
* Returns the name, logo, and redirect URIs of the app at `origin`, from its manifest, else from its
|
|
922
|
+
* page. The logo is a `data:` URL, so the approval page loads nothing from the app. The reads share
|
|
923
|
+
* a 5-second limit, and a failed read returns what it found.
|
|
924
|
+
*/
|
|
925
|
+
async function describe(options: {
|
|
926
|
+
fetch: ClientMetadataResourceFetch
|
|
927
|
+
origin: string
|
|
928
|
+
}): Promise<{
|
|
929
|
+
logo?: string | undefined
|
|
930
|
+
name?: string | undefined
|
|
931
|
+
redirectUris?: readonly string[] | undefined
|
|
932
|
+
}> {
|
|
933
|
+
const { origin } = options
|
|
934
|
+
const signal = AbortSignal.timeout(5000)
|
|
935
|
+
|
|
936
|
+
const read = async (url: string, accept: string) => {
|
|
937
|
+
const response = await options.fetch(url, {
|
|
938
|
+
headers: { accept },
|
|
939
|
+
redirect: 'error',
|
|
940
|
+
signal,
|
|
941
|
+
})
|
|
942
|
+
if (response.status !== 200 || !response.body) {
|
|
943
|
+
await response.body?.cancel()
|
|
944
|
+
throw new Error(`The read of ${url} responded with ${response.status}.`)
|
|
945
|
+
}
|
|
946
|
+
// The page's head comes first, so the read keeps only the start of a longer body. A chunk can
|
|
947
|
+
// be of any size, so each one is cut to the bytes left.
|
|
948
|
+
const reader = response.body.getReader()
|
|
949
|
+
const decoder = new TextDecoder()
|
|
950
|
+
// Each read has its own budget, so a long page leaves the manifest whole.
|
|
951
|
+
let remaining = pageLimit
|
|
952
|
+
let text = ''
|
|
953
|
+
while (remaining > 0) {
|
|
954
|
+
const { done, value } = await reader.read()
|
|
955
|
+
if (done) break
|
|
956
|
+
const chunk = value.subarray(0, remaining)
|
|
957
|
+
remaining -= chunk.byteLength
|
|
958
|
+
text += decoder.decode(chunk, { stream: true })
|
|
959
|
+
}
|
|
960
|
+
await reader.cancel()
|
|
961
|
+
return text
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// A URL on another origin, such as a CDN or a `data:` URL, is not the app's.
|
|
965
|
+
const own = (href: unknown, base: string) => {
|
|
966
|
+
if (typeof href !== 'string') return undefined
|
|
967
|
+
const url = URL.parse(href, base)
|
|
968
|
+
return url?.origin === origin ? url.href : undefined
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
const page = await read(`${origin}/`, 'text/html')
|
|
972
|
+
.then(parsePage)
|
|
973
|
+
.catch(() => undefined)
|
|
974
|
+
if (!page) return {}
|
|
975
|
+
|
|
976
|
+
// The page's links resolve against its `<base>`, as a browser resolves them.
|
|
977
|
+
const base = URL.parse(page.base ?? '', `${origin}/`)?.href ?? `${origin}/`
|
|
978
|
+
const manifestUrl = own(page.manifest, base)
|
|
979
|
+
const manifest = manifestUrl
|
|
980
|
+
? await read(manifestUrl, 'application/manifest+json, application/json')
|
|
981
|
+
.then((text): unknown => JSON.parse(text))
|
|
982
|
+
.catch(() => undefined)
|
|
983
|
+
: undefined
|
|
984
|
+
const fields =
|
|
985
|
+
typeof manifest === 'object' && manifest !== null
|
|
986
|
+
? (manifest as Record<string, unknown>)
|
|
987
|
+
: {}
|
|
988
|
+
const icons = Array.isArray(fields.icons)
|
|
989
|
+
? fields.icons.flatMap((icon: unknown) => {
|
|
990
|
+
if (typeof icon !== 'object' || icon === null) return []
|
|
991
|
+
const { purpose, sizes, src } = icon as Record<string, unknown>
|
|
992
|
+
// A monochrome icon is a mask, not a logo.
|
|
993
|
+
if (typeof purpose === 'string' && !/\b(any|maskable)\b/.test(purpose))
|
|
994
|
+
return []
|
|
995
|
+
const href = manifestUrl ? own(src, manifestUrl) : undefined
|
|
996
|
+
return href ? [{ href, size: iconSize(sizes, 0) }] : []
|
|
997
|
+
})
|
|
998
|
+
: []
|
|
999
|
+
// The page's icons apply only when the manifest names none. The page shows the logo at 48 pixels,
|
|
1000
|
+
// so the smallest icon of at least 96 pixels fills it on any screen, else the largest icon.
|
|
1001
|
+
const candidates =
|
|
1002
|
+
icons.length > 0
|
|
1003
|
+
? icons
|
|
1004
|
+
: page.icons.flatMap((icon) => {
|
|
1005
|
+
const href = own(icon.href, base)
|
|
1006
|
+
return href ? [{ href, size: icon.size }] : []
|
|
1007
|
+
})
|
|
1008
|
+
const icon = candidates.reduce<{ href: string; size: number } | undefined>(
|
|
1009
|
+
(best, icon) => {
|
|
1010
|
+
if (!best) return icon
|
|
1011
|
+
if (best.size >= 96 && icon.size >= 96)
|
|
1012
|
+
return icon.size < best.size ? icon : best
|
|
1013
|
+
return icon.size > best.size ? icon : best
|
|
1014
|
+
},
|
|
1015
|
+
undefined,
|
|
1016
|
+
)
|
|
1017
|
+
const logo = icon
|
|
1018
|
+
? await (async () => {
|
|
1019
|
+
const response = await options.fetch(icon.href, {
|
|
1020
|
+
headers: { accept: [...logoTypes].join(', ') },
|
|
1021
|
+
redirect: 'error',
|
|
1022
|
+
signal,
|
|
1023
|
+
})
|
|
1024
|
+
const type = response.headers
|
|
1025
|
+
.get('content-type')
|
|
1026
|
+
?.split(';')[0]
|
|
1027
|
+
?.trim()
|
|
1028
|
+
.toLowerCase()
|
|
1029
|
+
if (response.status !== 200 || !type || !logoTypes.has(type)) {
|
|
1030
|
+
await response.body?.cancel()
|
|
1031
|
+
return undefined
|
|
1032
|
+
}
|
|
1033
|
+
const reader = response.body?.getReader()
|
|
1034
|
+
if (!reader) return undefined
|
|
1035
|
+
const chunks: Uint8Array[] = []
|
|
1036
|
+
let size = 0
|
|
1037
|
+
while (true) {
|
|
1038
|
+
const { done, value } = await reader.read()
|
|
1039
|
+
if (done) break
|
|
1040
|
+
size += value.byteLength
|
|
1041
|
+
// A larger logo is refused whole, since a cut image does not render.
|
|
1042
|
+
if (size > logoLimit) {
|
|
1043
|
+
await reader.cancel()
|
|
1044
|
+
return undefined
|
|
1045
|
+
}
|
|
1046
|
+
chunks.push(value)
|
|
1047
|
+
}
|
|
1048
|
+
return `data:${type};base64,${Base64.fromBytes(Bytes.concat(...chunks))}`
|
|
1049
|
+
})().catch(() => undefined)
|
|
1050
|
+
: undefined
|
|
1051
|
+
|
|
1052
|
+
// Each redirect URI is an exact `https` URI on the origin, as a metadata document names one.
|
|
1053
|
+
const redirectUris = Array.isArray(fields.redirect_uris)
|
|
1054
|
+
? fields.redirect_uris
|
|
1055
|
+
.flatMap((uri: unknown) => {
|
|
1056
|
+
if (typeof uri !== 'string' || uri.includes('#')) return []
|
|
1057
|
+
const url = URL.parse(uri)
|
|
1058
|
+
if (url?.origin !== origin || url.username || url.password) return []
|
|
1059
|
+
return [url.href]
|
|
1060
|
+
})
|
|
1061
|
+
.slice(0, 10)
|
|
1062
|
+
: undefined
|
|
1063
|
+
|
|
1064
|
+
const name = [fields.name, fields.short_name, page.title]
|
|
1065
|
+
.map((value) =>
|
|
1066
|
+
typeof value === 'string'
|
|
1067
|
+
? // Control characters and runs of spaces would break the line that the page shows, and
|
|
1068
|
+
// format characters, such as bidi overrides, would reorder the host beside the name.
|
|
1069
|
+
value
|
|
1070
|
+
.replace(/[\p{Cc}\p{Cf}\s]+/gu, ' ')
|
|
1071
|
+
.trim()
|
|
1072
|
+
.slice(0, 64)
|
|
1073
|
+
: '',
|
|
1074
|
+
)
|
|
1075
|
+
.find(Boolean)
|
|
1076
|
+
return { logo, name, redirectUris }
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* Returns the largest dimension in an icon's `sizes`, such as 512 for `192x192 512x512`, and
|
|
1081
|
+
* infinity for `any`. Without sizes, returns `fallback`.
|
|
1082
|
+
*/
|
|
1083
|
+
function iconSize(sizes: unknown, fallback: number) {
|
|
1084
|
+
if (typeof sizes !== 'string' || !sizes.trim()) return fallback
|
|
1085
|
+
return Math.max(
|
|
1086
|
+
...sizes
|
|
1087
|
+
.toLowerCase()
|
|
1088
|
+
.split(/\s+/)
|
|
1089
|
+
.map((size) => {
|
|
1090
|
+
if (size === 'any') return Number.POSITIVE_INFINITY
|
|
1091
|
+
const [width, height] = size.split('x').map(Number)
|
|
1092
|
+
return Math.max(width || 0, height || 0)
|
|
1093
|
+
}),
|
|
1094
|
+
)
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Returns the `<base>` URL, `<title>`, manifest link, and icon links of an untrusted HTML page, with
|
|
1099
|
+
* patterns that each scan in linear time.
|
|
1100
|
+
*/
|
|
1101
|
+
function parsePage(html: string) {
|
|
1102
|
+
const source = html.replace(
|
|
1103
|
+
/<!--[\s\S]*?(?:-->|$)|<(script|style)\b[\s\S]*?(?:<\/\1\s*>|$)/gi,
|
|
1104
|
+
'',
|
|
1105
|
+
)
|
|
1106
|
+
const attributesOf = (tag: string) =>
|
|
1107
|
+
new Map(
|
|
1108
|
+
[
|
|
1109
|
+
...tag.matchAll(
|
|
1110
|
+
/([^\s"'=<>/]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]*)))?/g,
|
|
1111
|
+
),
|
|
1112
|
+
].map((entry) => [
|
|
1113
|
+
entry[1]!.toLowerCase(),
|
|
1114
|
+
decode(entry[2] ?? entry[3] ?? entry[4] ?? ''),
|
|
1115
|
+
]),
|
|
1116
|
+
)
|
|
1117
|
+
const links = [...source.matchAll(/<link\b([^>]*)(?:>|$)/gi)].map((match) => {
|
|
1118
|
+
const attributes = attributesOf(match[1] ?? '')
|
|
1119
|
+
const rel = (attributes.get('rel') ?? '').toLowerCase().split(/\s+/)
|
|
1120
|
+
return { attributes, rel }
|
|
1121
|
+
})
|
|
1122
|
+
const title = /<title\b[^>]*(?:>([^<]*)|$)/i.exec(source)?.[1]
|
|
1123
|
+
// A browser reads the first `<base>` with an `href`.
|
|
1124
|
+
const base = [...source.matchAll(/<base\b([^>]*)(?:>|$)/gi)]
|
|
1125
|
+
.map((match) => attributesOf(match[1] ?? '').get('href'))
|
|
1126
|
+
.find(Boolean)
|
|
1127
|
+
return {
|
|
1128
|
+
base,
|
|
1129
|
+
icons: links.flatMap((link) => {
|
|
1130
|
+
const href = link.attributes.get('href')
|
|
1131
|
+
if (!href) return []
|
|
1132
|
+
// An Apple touch icon without sizes is 180 pixels, larger than a favicon.
|
|
1133
|
+
if (link.rel.includes('apple-touch-icon'))
|
|
1134
|
+
return [{ href, size: iconSize(link.attributes.get('sizes'), 180) }]
|
|
1135
|
+
if (link.rel.includes('icon'))
|
|
1136
|
+
return [{ href, size: iconSize(link.attributes.get('sizes'), 0) }]
|
|
1137
|
+
return []
|
|
1138
|
+
}),
|
|
1139
|
+
manifest: links
|
|
1140
|
+
.find((link) => link.rel.includes('manifest'))
|
|
1141
|
+
?.attributes.get('href'),
|
|
1142
|
+
title: title === undefined ? undefined : decode(title),
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
/** Returns `text` with its HTML character references for markup and numbers replaced. */
|
|
1147
|
+
function decode(text: string) {
|
|
1148
|
+
const named: Record<string, string> = {
|
|
1149
|
+
amp: '&',
|
|
1150
|
+
apos: "'",
|
|
1151
|
+
gt: '>',
|
|
1152
|
+
lt: '<',
|
|
1153
|
+
nbsp: ' ',
|
|
1154
|
+
quot: '"',
|
|
1155
|
+
}
|
|
1156
|
+
return text.replace(
|
|
1157
|
+
/&(#x[0-9a-f]+|#[0-9]+|[a-z]+);/gi,
|
|
1158
|
+
(match, name: string) => {
|
|
1159
|
+
if (!name.startsWith('#')) return named[name.toLowerCase()] ?? match
|
|
1160
|
+
const code =
|
|
1161
|
+
name[1]?.toLowerCase() === 'x'
|
|
1162
|
+
? Number.parseInt(name.slice(2), 16)
|
|
1163
|
+
: Number.parseInt(name.slice(1), 10)
|
|
1164
|
+
return code > 0 && code <= 0x10ffff ? String.fromCodePoint(code) : match
|
|
1165
|
+
},
|
|
1166
|
+
)
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/** Returns the `oauth_client` row with `clientId`. Throws `NotFoundError` when no app has it. */
|
|
1170
|
+
async function find(db: Realm.Database, options: { clientId: string }) {
|
|
1171
|
+
const [row] = await db
|
|
1172
|
+
.select()
|
|
1173
|
+
.from(Schema.oauthClient)
|
|
1174
|
+
.where(eq(Schema.oauthClient.clientId, options.clientId))
|
|
1175
|
+
if (!row) throw new NotFoundError({ clientId: options.clientId })
|
|
1176
|
+
return row
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
/** Returns `clientId`. Throws `InvalidError` unless it is 8 to 64 letters, digits, `-`, or `_`. */
|
|
1180
|
+
function parseClientId(clientId: string) {
|
|
1181
|
+
if (!/^[A-Za-z0-9_-]{8,64}$/.test(clientId))
|
|
1182
|
+
throw new InvalidError(
|
|
1183
|
+
`Invalid client ID: ${clientId}. Use 8 to 64 letters, digits, -, or _.`,
|
|
1184
|
+
)
|
|
1185
|
+
return clientId
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
/** Returns `clientSecret`. Throws `InvalidError` when it holds fewer than 32 characters. */
|
|
1189
|
+
function parseClientSecret(clientSecret: string) {
|
|
1190
|
+
// The message leaves the secret out, since errors never hold one.
|
|
1191
|
+
if (clientSecret.length < 32)
|
|
1192
|
+
throw new InvalidError(
|
|
1193
|
+
'Invalid client secret: fewer than 32 characters. Use a longer secret.',
|
|
1194
|
+
)
|
|
1195
|
+
return clientSecret
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
/** Returns `name` trimmed. Throws `InvalidError` when it is empty. */
|
|
1199
|
+
function parseName(name: string) {
|
|
1200
|
+
const trimmed = name.trim()
|
|
1201
|
+
if (!trimmed)
|
|
1202
|
+
throw new InvalidError('Invalid app: the name is empty. Set a name.')
|
|
1203
|
+
return trimmed
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
/** Returns `uris` as `parseRedirectUris` does, but accepts an empty list. */
|
|
1207
|
+
function parsePostLogoutRedirectUris(
|
|
1208
|
+
uris: readonly string[],
|
|
1209
|
+
options: { type: App['type'] },
|
|
1210
|
+
): readonly string[] {
|
|
1211
|
+
if (uris.length === 0) return []
|
|
1212
|
+
return parseRedirectUris(uris, options)
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Returns `uris`, each named once. A web app takes `https` URIs, and a native app also a custom
|
|
1217
|
+
* scheme. Loopback and `http` URIs are refused. Throws `InvalidError` for an invalid URI or none.
|
|
1218
|
+
*/
|
|
1219
|
+
function parseRedirectUris(
|
|
1220
|
+
uris: readonly string[],
|
|
1221
|
+
options: { type: App['type'] },
|
|
1222
|
+
): readonly string[] {
|
|
1223
|
+
if (uris.length === 0)
|
|
1224
|
+
throw new InvalidError(
|
|
1225
|
+
'Invalid app: no redirect URI. Set at least one redirect URI.',
|
|
1226
|
+
)
|
|
1227
|
+
|
|
1228
|
+
for (const uri of uris) {
|
|
1229
|
+
const url = URL.parse(uri)
|
|
1230
|
+
const reason = (() => {
|
|
1231
|
+
if (!url) return 'is not an absolute URI'
|
|
1232
|
+
// RFC 6749 §3.1.2 bars a fragment from a redirect URI.
|
|
1233
|
+
if (url.hash || uri.includes('#')) return 'has a fragment'
|
|
1234
|
+
if (url.username || url.password) return 'holds credentials'
|
|
1235
|
+
if (url.protocol === 'https:')
|
|
1236
|
+
return isLoopbackHost(url.hostname) ? 'has a loopback host' : undefined
|
|
1237
|
+
if (url.protocol === 'http:') return 'uses http'
|
|
1238
|
+
if (options.type === 'web') return 'is not https'
|
|
1239
|
+
// Refuses reserved schemes, such as `javascript:` and `file:`, as Better Auth's registration does.
|
|
1240
|
+
if (!isNativePrivateUseRedirectUri(url))
|
|
1241
|
+
return 'is not a valid custom scheme'
|
|
1242
|
+
return undefined
|
|
1243
|
+
})()
|
|
1244
|
+
if (reason)
|
|
1245
|
+
throw new InvalidError(
|
|
1246
|
+
`Invalid redirect URI: ${uri} ${reason}. Use an https URI${options.type === 'native' ? ', or a custom scheme such as com.example.app:/callback' : ''}.`,
|
|
1247
|
+
)
|
|
1248
|
+
}
|
|
1249
|
+
return [...new Set(uris)]
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/** Returns `scopes`, or the default scopes, with `tempo-id:sign` only when `sign` is set. */
|
|
1253
|
+
function scopesOf(options: {
|
|
1254
|
+
scopes?: readonly string[] | undefined
|
|
1255
|
+
sign: boolean
|
|
1256
|
+
}): string[] {
|
|
1257
|
+
const kept = (options.scopes ?? scopes).filter((scope) => scope !== signScope)
|
|
1258
|
+
return [...kept, ...(options.sign ? [signScope] : [])]
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
/** Returns a new client secret: 32 random letters, as Better Auth creates. */
|
|
1262
|
+
function secret() {
|
|
1263
|
+
return generateRandomString(32, 'a-z', 'A-Z')
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
/** Returns the app of an `oauth_client` row. */
|
|
1267
|
+
function toApp(row: typeof Schema.oauthClient.$inferSelect): App {
|
|
1268
|
+
return {
|
|
1269
|
+
clientId: row.clientId,
|
|
1270
|
+
createdAt: row.createdAt,
|
|
1271
|
+
device: (row.grantTypes ?? []).includes(deviceGrant),
|
|
1272
|
+
// A metadata document cannot skip consent, so a discovered client is never first-party.
|
|
1273
|
+
firstParty: !row.clientDiscoveryId && row.skipConsent === true,
|
|
1274
|
+
// Only an inlined logo shows, so the approval page loads nothing from a third-party origin.
|
|
1275
|
+
logo: row.icon?.startsWith('data:image/') ? row.icon : null,
|
|
1276
|
+
name: row.name,
|
|
1277
|
+
postLogoutRedirectUris: row.postLogoutRedirectUris ?? [],
|
|
1278
|
+
redirectUris: row.redirectUris,
|
|
1279
|
+
secret: Boolean(row.clientSecret),
|
|
1280
|
+
sign: (row.scopes ?? []).includes(signScope),
|
|
1281
|
+
type: row.applicationType === 'native' ? 'native' : 'web',
|
|
1282
|
+
}
|
|
1283
|
+
}
|