@tempoxyz/id 0.0.0-stage → 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -2
- package/dist/App.d.ts +20 -0
- package/dist/App.d.ts.map +1 -0
- package/dist/App.js +26 -0
- package/dist/App.js.map +1 -0
- package/dist/app/client/.assetsignore +2 -0
- package/dist/app/client/assets/BRLA-CZvVDNYr.png +0 -0
- package/dist/app/client/assets/CHFAU-DCedc4aH.png +0 -0
- package/dist/app/client/assets/DLUSD-BnRXm3EI.png +0 -0
- package/dist/app/client/assets/PRIME-CiFp2-3e.svg +14 -0
- package/dist/app/client/assets/Pilat-Bold-C1t1eIrF.woff2 +0 -0
- package/dist/app/client/assets/Pilat-Book-CbS8ofT8.woff2 +0 -0
- package/dist/app/client/assets/Pilat-Demi-CADSbPAt.woff2 +0 -0
- package/dist/app/client/assets/Pilat-Regular-Bx8vzE7q.woff2 +0 -0
- package/dist/app/client/assets/USD1-COVcO_PB.svg +30 -0
- package/dist/app/client/assets/YLDS-CRh8Zw0g.svg +3 -0
- package/dist/app/client/assets/ccip-Cq1mMiVl.js +1 -0
- package/dist/app/client/assets/frxUSD-n9pTpinR.svg +1 -0
- package/dist/app/client/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
- package/dist/app/client/assets/index-B7YJVP00.css +1 -0
- package/dist/app/client/assets/index-UXTxXCLk.js +55 -0
- package/dist/app/client/assets/pathUSD-BvaO6ooS.svg +25 -0
- package/dist/app/client/assets/reset-co-CHrff.css +1 -0
- package/dist/app/client/assets/wYLDS-CaCKDrO-.svg +10 -0
- package/dist/app/db/auth.d.ts +3207 -0
- package/dist/app/db/auth.d.ts.map +1 -0
- package/dist/app/db/auth.js +330 -0
- package/dist/app/db/auth.js.map +1 -0
- package/dist/app/db/schema.d.ts +932 -0
- package/dist/app/db/schema.d.ts.map +1 -0
- package/dist/app/db/schema.js +171 -0
- package/dist/app/db/schema.js.map +1 -0
- package/dist/app/server/.vite/manifest.json +489 -0
- package/dist/app/server/assets/BRLA-CZvVDNYr.png +0 -0
- package/dist/app/server/assets/CHFAU-DCedc4aH.png +0 -0
- package/dist/app/server/assets/DLUSD-BnRXm3EI.png +0 -0
- package/dist/app/server/assets/PRIME-CiFp2-3e.svg +14 -0
- package/dist/app/server/assets/Pilat-Bold-C1t1eIrF.woff2 +0 -0
- package/dist/app/server/assets/Pilat-Book-CbS8ofT8.woff2 +0 -0
- package/dist/app/server/assets/Pilat-Demi-CADSbPAt.woff2 +0 -0
- package/dist/app/server/assets/Pilat-Regular-Bx8vzE7q.woff2 +0 -0
- package/dist/app/server/assets/USD1-COVcO_PB.svg +30 -0
- package/dist/app/server/assets/YLDS-CRh8Zw0g.svg +3 -0
- package/dist/app/server/assets/_tanstack-start-manifest_v-11GtFGrq.js +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/authorize-C95F-9E1-CbESJKGU.js +31 -0
- package/dist/app/server/assets/authorize-C95F-9E1-CbESJKGU.js.map +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/call-UQamaCKN.js +32 -0
- package/dist/app/server/assets/call-UQamaCKN.js.map +1 -0
- package/dist/app/server/assets/ccip-CbNKFO4n.js +2 -0
- package/dist/app/server/assets/ccip-CbNKFO4n.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-CS900nSP.css +1 -0
- package/dist/app/server/assets/cookie-Cce9CrIP.js +10 -0
- package/dist/app/server/assets/cookie-Cce9CrIP.js.map +1 -0
- package/dist/app/server/assets/core-B1HCXUmx.js +56 -0
- package/dist/app/server/assets/core-B1HCXUmx.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/default-u_dwuiYb-BJJ9PwCi.js +2 -0
- package/dist/app/server/assets/default-u_dwuiYb-BJJ9PwCi.js.map +1 -0
- package/dist/app/server/assets/dist-BxSwugSY.js +1 -0
- package/dist/app/server/assets/dist-CZGFhmQd.js +2 -0
- package/dist/app/server/assets/dist-CZGFhmQd.js.map +1 -0
- package/dist/app/server/assets/dist-Dg3PQqiW.js +15 -0
- package/dist/app/server/assets/dist-Dg3PQqiW.js.map +1 -0
- package/dist/app/server/assets/effect-QlVUlMFu-2tSPDT2b.js +2 -0
- package/dist/app/server/assets/effect-QlVUlMFu-2tSPDT2b.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/factory-ipHlJXZY.js +5 -0
- package/dist/app/server/assets/factory-ipHlJXZY.js.map +1 -0
- package/dist/app/server/assets/frxUSD-n9pTpinR.svg +1 -0
- package/dist/app/server/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
- package/dist/app/server/assets/get-id-field-B0x109VU.js +6 -0
- package/dist/app/server/assets/get-id-field-B0x109VU.js.map +1 -0
- package/dist/app/server/assets/index-CLddUTqr-xpSuLpBt.js +2 -0
- package/dist/app/server/assets/index-CLddUTqr-xpSuLpBt.js.map +1 -0
- package/dist/app/server/assets/index-DZEfthgZ-8Uq5s5Pt.js +2 -0
- package/dist/app/server/assets/index-DZEfthgZ-8Uq5s5Pt.js.map +1 -0
- package/dist/app/server/assets/kysely-adapter-MkHAI9Jk.js +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/reset-co-CHrff.css +1 -0
- package/dist/app/server/assets/rolldown-runtime-B0Z9INg1.js +1 -0
- package/dist/app/server/assets/router-CcbyBCI4.css +1 -0
- package/dist/app/server/assets/router-xjZtEeaI.js +7 -0
- package/dist/app/server/assets/router-xjZtEeaI.js.map +1 -0
- package/dist/app/server/assets/schema-check-Cf7QOZZD.js +9 -0
- package/dist/app/server/assets/schema-check-Cf7QOZZD.js.map +1 -0
- package/dist/app/server/assets/schemas-C2lCYmR5.js +2 -0
- package/dist/app/server/assets/schemas-C2lCYmR5.js.map +1 -0
- package/dist/app/server/assets/secp256k1-buM5g4AL.js +2 -0
- package/dist/app/server/assets/secp256k1-buM5g4AL.js.map +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-Cg1N07hM.js +2 -0
- package/dist/app/server/assets/standard-json-Cg1N07hM.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/sury-CWZTCd75-xt1mWc9f.js +2 -0
- package/dist/app/server/assets/sury-CWZTCd75-xt1mWc9f.js.map +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/utils-C4ZXZIZW.js +2 -0
- package/dist/app/server/assets/utils-C4ZXZIZW.js.map +1 -0
- package/dist/app/server/assets/valibot--1zFm7rT-NSoY2xTp.js +2 -0
- package/dist/app/server/assets/valibot--1zFm7rT-NSoY2xTp.js.map +1 -0
- package/dist/app/server/assets/valibot-D_HTw1Gn-CJwWeOUE.js +2 -0
- package/dist/app/server/assets/valibot-D_HTw1Gn-CJwWeOUE.js.map +1 -0
- package/dist/app/server/assets/wYLDS-CaCKDrO-.svg +10 -0
- package/dist/app/server/assets/zod-Bwrt9trS-CV38yPnQ.js +2 -0
- package/dist/app/server/assets/zod-Bwrt9trS-CV38yPnQ.js.map +1 -0
- package/dist/app/server/assets/zod-DSgpEGAE-BvlnBE2L.js +2 -0
- package/dist/app/server/assets/zod-DSgpEGAE-BvlnBE2L.js.map +1 -0
- package/dist/app/server/index.js +574 -0
- package/dist/app/server/index.js.map +1 -0
- package/dist/app/server/wrangler.json +1 -0
- package/dist/cli/Admin.d.ts +38 -0
- package/dist/cli/Admin.d.ts.map +1 -0
- package/dist/cli/Admin.js +62 -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 +36 -0
- package/dist/cli/Apps.js.map +1 -0
- package/dist/cli/Cli.d.ts +14 -0
- package/dist/cli/Cli.d.ts.map +1 -0
- package/dist/cli/Cli.js +27 -0
- package/dist/cli/Cli.js.map +1 -0
- package/dist/cli/Project.d.ts +20 -0
- package/dist/cli/Project.d.ts.map +1 -0
- package/dist/cli/Project.js +88 -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 +49 -0
- package/dist/cli/Realms.js.map +1 -0
- package/dist/cli/Session.d.ts +85 -0
- package/dist/cli/Session.d.ts.map +1 -0
- package/dist/cli/Session.js +178 -0
- package/dist/cli/Session.js.map +1 -0
- package/dist/cli/User.d.ts +29 -0
- package/dist/cli/User.d.ts.map +1 -0
- package/dist/cli/User.js +39 -0
- package/dist/cli/User.js.map +1 -0
- package/dist/cli/V1.d.ts +35 -0
- package/dist/cli/V1.d.ts.map +1 -0
- package/dist/cli/V1.js +41 -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 +89 -0
- package/dist/cli/commands/admin/apps/create.js.map +1 -0
- package/dist/cli/commands/admin/apps/delete.d.ts +14 -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 +9 -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 +16 -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 +76 -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 +9 -0
- package/dist/cli/commands/admin/migrate.d.ts.map +1 -0
- package/dist/cli/commands/admin/migrate.js +17 -0
- package/dist/cli/commands/admin/migrate.js.map +1 -0
- package/dist/cli/commands/admin/realms/add.d.ts +12 -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 +13 -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 +16 -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 +18 -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 +11 -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 +15 -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 +15 -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 +16 -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 +15 -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 +101 -0
- package/dist/client/Actions.d.ts.map +1 -0
- package/dist/client/Actions.js +90 -0
- package/dist/client/Actions.js.map +1 -0
- package/dist/client/Auth.d.ts +161 -0
- package/dist/client/Auth.d.ts.map +1 -0
- package/dist/client/Auth.js +113 -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 +170 -0
- package/dist/client/Decorator.d.ts.map +1 -0
- package/dist/client/Decorator.js +227 -0
- package/dist/client/Decorator.js.map +1 -0
- package/dist/client/Key.d.ts +85 -0
- package/dist/client/Key.d.ts.map +1 -0
- package/dist/client/Key.js +83 -0
- package/dist/client/Key.js.map +1 -0
- package/dist/client/Pending.d.ts +39 -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 +34 -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/Provider.d.ts +16 -0
- package/dist/client/Provider.d.ts.map +1 -0
- package/dist/client/Provider.js +12 -0
- package/dist/client/Provider.js.map +1 -0
- package/dist/client/Step.d.ts +21 -0
- package/dist/client/Step.d.ts.map +1 -0
- package/dist/client/Step.js +16 -0
- package/dist/client/Step.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 +40 -0
- package/dist/client/TempoAccount.d.ts.map +1 -0
- package/dist/client/TempoAccount.js +16 -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 +25 -0
- package/dist/client/actions/account.d.ts.map +1 -0
- package/dist/client/actions/account.js +34 -0
- package/dist/client/actions/account.js.map +1 -0
- package/dist/client/actions/device.d.ts +53 -0
- package/dist/client/actions/device.d.ts.map +1 -0
- package/dist/client/actions/device.js +79 -0
- package/dist/client/actions/device.js.map +1 -0
- package/dist/client/actions/email.d.ts +84 -0
- package/dist/client/actions/email.d.ts.map +1 -0
- package/dist/client/actions/email.js +63 -0
- package/dist/client/actions/email.js.map +1 -0
- package/dist/client/actions/oauth.d.ts +115 -0
- package/dist/client/actions/oauth.d.ts.map +1 -0
- package/dist/client/actions/oauth.js +105 -0
- package/dist/client/actions/oauth.js.map +1 -0
- package/dist/client/actions/passkey.d.ts +88 -0
- package/dist/client/actions/passkey.d.ts.map +1 -0
- package/dist/client/actions/passkey.js +60 -0
- package/dist/client/actions/passkey.js.map +1 -0
- package/dist/client/actions/provider.d.ts +49 -0
- package/dist/client/actions/provider.d.ts.map +1 -0
- package/dist/client/actions/provider.js +34 -0
- package/dist/client/actions/provider.js.map +1 -0
- package/dist/client/actions/realm.d.ts +24 -0
- package/dist/client/actions/realm.d.ts.map +1 -0
- package/dist/client/actions/realm.js +15 -0
- package/dist/client/actions/realm.js.map +1 -0
- package/dist/client/actions/redirect.d.ts +153 -0
- package/dist/client/actions/redirect.d.ts.map +1 -0
- package/dist/client/actions/redirect.js +236 -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 +14 -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 +106 -0
- package/dist/client/internal/api.d.ts.map +1 -0
- package/dist/client/internal/api.js +129 -0
- package/dist/client/internal/api.js.map +1 -0
- package/dist/client/internal/headless.d.ts +33 -0
- package/dist/client/internal/headless.d.ts.map +1 -0
- package/dist/client/internal/headless.js +46 -0
- package/dist/client/internal/headless.js.map +1 -0
- package/dist/client/internal/indexedDb.d.ts +9 -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 +58 -0
- package/dist/client/internal/request.d.ts.map +1 -0
- package/dist/client/internal/request.js +45 -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.d.ts +20 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +20 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/Apps.d.ts +3051 -0
- package/dist/internal/Apps.d.ts.map +1 -0
- package/dist/internal/Apps.js +472 -0
- package/dist/internal/Apps.js.map +1 -0
- package/dist/internal/Auth.d.ts +4058 -0
- package/dist/internal/Auth.d.ts.map +1 -0
- package/dist/internal/Auth.js +137 -0
- package/dist/internal/Auth.js.map +1 -0
- package/dist/internal/Authorize.d.ts +532 -0
- package/dist/internal/Authorize.d.ts.map +1 -0
- package/dist/internal/Authorize.js +326 -0
- package/dist/internal/Authorize.js.map +1 -0
- package/dist/internal/Device.d.ts +371 -0
- package/dist/internal/Device.d.ts.map +1 -0
- package/dist/internal/Device.js +271 -0
- package/dist/internal/Device.js.map +1 -0
- package/dist/internal/Env.d.ts +57 -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 +609 -0
- package/dist/internal/ErrorResponse.d.ts.map +1 -0
- package/dist/internal/ErrorResponse.js +679 -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 +1456 -0
- package/dist/internal/KeyAuthorization.d.ts.map +1 -0
- package/dist/internal/KeyAuthorization.js +1030 -0
- package/dist/internal/KeyAuthorization.js.map +1 -0
- package/dist/internal/Limits.d.ts +65 -0
- package/dist/internal/Limits.d.ts.map +1 -0
- package/dist/internal/Limits.js +35 -0
- package/dist/internal/Limits.js.map +1 -0
- package/dist/internal/Log.d.ts +49 -0
- package/dist/internal/Log.d.ts.map +1 -0
- package/dist/internal/Log.js +101 -0
- package/dist/internal/Log.js.map +1 -0
- package/dist/internal/LogLine.d.ts +33 -0
- package/dist/internal/LogLine.d.ts.map +1 -0
- package/dist/internal/LogLine.js +56 -0
- package/dist/internal/LogLine.js.map +1 -0
- package/dist/internal/Migrations.d.ts +19 -0
- package/dist/internal/Migrations.d.ts.map +1 -0
- package/dist/internal/Migrations.js +57 -0
- package/dist/internal/Migrations.js.map +1 -0
- package/dist/internal/Owner.d.ts +146 -0
- package/dist/internal/Owner.d.ts.map +1 -0
- package/dist/internal/Owner.js +65 -0
- package/dist/internal/Owner.js.map +1 -0
- package/dist/internal/Passkey.d.ts +528 -0
- package/dist/internal/Passkey.d.ts.map +1 -0
- package/dist/internal/Passkey.js +658 -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 +105 -0
- package/dist/internal/Privy.d.ts.map +1 -0
- package/dist/internal/Privy.js +224 -0
- package/dist/internal/Privy.js.map +1 -0
- package/dist/internal/RateLimit.d.ts +190 -0
- package/dist/internal/RateLimit.d.ts.map +1 -0
- package/dist/internal/RateLimit.js +148 -0
- package/dist/internal/RateLimit.js.map +1 -0
- package/dist/internal/Realm.d.ts +281 -0
- package/dist/internal/Realm.d.ts.map +1 -0
- package/dist/internal/Realm.js +477 -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 +115 -0
- package/dist/internal/SigningKey.d.ts.map +1 -0
- package/dist/internal/SigningKey.js +197 -0
- package/dist/internal/SigningKey.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 +51 -0
- package/dist/internal/Timing.d.ts.map +1 -0
- package/dist/internal/Timing.js +103 -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/Wallet.d.ts +37 -0
- package/dist/internal/Wallet.d.ts.map +1 -0
- package/dist/internal/Wallet.js +43 -0
- package/dist/internal/Wallet.js.map +1 -0
- package/dist/worker.d.ts +12 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +12 -0
- package/dist/worker.js.map +1 -0
- package/package.json +79 -3
- package/src/Api.ts +151 -0
- package/src/App.ts +56 -0
- package/src/api/account.ts +311 -0
- package/src/api/authenticate.ts +1290 -0
- package/src/api/authorize.ts +1030 -0
- package/src/api/device.ts +874 -0
- package/src/api/health.ts +72 -0
- package/src/api/lib/AccountStep.ts +335 -0
- package/src/api/lib/Auth.ts +134 -0
- package/src/api/lib/Consent.ts +339 -0
- package/src/api/lib/Cors.ts +107 -0
- package/src/api/lib/Database.ts +10 -0
- package/src/api/lib/DeviceRequest.ts +265 -0
- package/src/api/lib/FirstAccount.ts +90 -0
- package/src/api/lib/KeySigner.ts +393 -0
- package/src/api/lib/PasskeyLink.ts +162 -0
- package/src/api/lib/Session.ts +34 -0
- package/src/api/lib/SignInConsent.ts +316 -0
- package/src/api/oauth.ts +1282 -0
- package/src/api/provider.ts +441 -0
- package/src/app/components/Button.tsx +128 -0
- package/src/app/components/CodeInput.tsx +186 -0
- package/src/app/components/ErrorMessage.tsx +66 -0
- package/src/app/components/Grant.tsx +323 -0
- package/src/app/components/Input.tsx +48 -0
- package/src/app/components/Tooltip.tsx +45 -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/crons/cleanup.ts +42 -0
- package/src/app/db/auth.ts +416 -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/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/_journal.json +83 -0
- package/src/app/db/schema.ts +218 -0
- package/src/app/env.ts +49 -0
- package/src/app/lib/Client.ts +82 -0
- package/src/app/lib/Loader.ts +24 -0
- package/src/app/package.json +8 -0
- package/src/app/routeTree.gen.ts +198 -0
- package/src/app/router.tsx +48 -0
- package/src/app/routes/[_].flows.tsx +3001 -0
- package/src/app/routes/__root.tsx +91 -0
- package/src/app/routes/authorize.tsx +197 -0
- package/src/app/routes/choose-account.tsx +111 -0
- package/src/app/routes/deposit.tsx +105 -0
- package/src/app/routes/device.tsx +227 -0
- package/src/app/routes/index.tsx +115 -0
- package/src/app/routes/login.tsx +506 -0
- package/src/app/screens/Account.tsx +347 -0
- package/src/app/screens/Approval.tsx +276 -0
- package/src/app/screens/ChooseAccount.tsx +240 -0
- package/src/app/screens/Deposit.tsx +762 -0
- package/src/app/screens/DeviceApproval.tsx +480 -0
- package/src/app/screens/SignIn.tsx +362 -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 +204 -0
- package/src/app/vite.config.ts +95 -0
- package/src/app/void.config.ts +29 -0
- package/src/app/zyzz.config.ts +274 -0
- package/src/cli/Admin.ts +73 -0
- package/src/cli/Apps.ts +29 -0
- package/src/cli/Cli.ts +42 -0
- package/src/cli/Project.ts +117 -0
- package/src/cli/Realms.ts +50 -0
- package/src/cli/Session.ts +239 -0
- package/src/cli/User.ts +45 -0
- package/src/cli/V1.ts +57 -0
- package/src/cli/bin.ts +44 -0
- package/src/cli/commands/admin/apps/create.ts +101 -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 +86 -0
- package/src/cli/commands/admin/index.ts +14 -0
- package/src/cli/commands/admin/migrate.ts +16 -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 +168 -0
- package/src/client/Auth.ts +285 -0
- package/src/client/Authorization.ts +34 -0
- package/src/client/Decorator.ts +410 -0
- package/src/client/Key.ts +140 -0
- package/src/client/Pending.ts +46 -0
- package/src/client/Permissions.ts +39 -0
- package/src/client/Provider.ts +18 -0
- package/src/client/Step.ts +24 -0
- package/src/client/Storage.ts +29 -0
- package/src/client/TempoAccount.ts +42 -0
- package/src/client/Tokens.ts +27 -0
- package/src/client/User.ts +23 -0
- package/src/client/actions/account.ts +57 -0
- package/src/client/actions/device.ts +151 -0
- package/src/client/actions/email.ts +141 -0
- package/src/client/actions/oauth.ts +182 -0
- package/src/client/actions/passkey.ts +141 -0
- package/src/client/actions/provider.ts +70 -0
- package/src/client/actions/realm.ts +36 -0
- package/src/client/actions/redirect.ts +408 -0
- package/src/client/internal/accessKey.ts +54 -0
- package/src/client/internal/account.ts +15 -0
- package/src/client/internal/api.ts +224 -0
- package/src/client/internal/headless.ts +77 -0
- package/src/client/internal/indexedDb.ts +44 -0
- package/src/client/internal/request.ts +71 -0
- package/src/client/internal/store.ts +20 -0
- package/src/client.ts +19 -0
- package/src/index.ts +6 -0
- package/src/internal/Apps.ts +718 -0
- package/src/internal/Auth.ts +203 -0
- package/src/internal/Authorize.ts +424 -0
- package/src/internal/Balance.ts +168 -0
- package/src/internal/BodyLimit.ts +36 -0
- package/src/internal/Chain.ts +16 -0
- package/src/internal/Device.ts +469 -0
- package/src/internal/Env.ts +58 -0
- package/src/internal/ErrorResponse.ts +854 -0
- package/src/internal/Id.ts +41 -0
- package/src/internal/KeyAuthorization.ts +1339 -0
- package/src/internal/Limits.ts +39 -0
- package/src/internal/Log.ts +178 -0
- package/src/internal/LogLine.ts +87 -0
- package/src/internal/Logout.ts +336 -0
- package/src/internal/Migrations.ts +86 -0
- package/src/internal/OpenApi.ts +300 -0
- package/src/internal/Owner.ts +211 -0
- package/src/internal/Passkey.ts +1052 -0
- package/src/internal/PendingKey.ts +104 -0
- package/src/internal/Privy.ts +402 -0
- package/src/internal/Provider.ts +125 -0
- package/src/internal/RateLimit.ts +259 -0
- package/src/internal/Realm.ts +768 -0
- package/src/internal/RequestId.ts +118 -0
- package/src/internal/SignInGrant.ts +168 -0
- package/src/internal/SigningKey.ts +286 -0
- package/src/internal/TempoAccount.ts +342 -0
- package/src/internal/TestInbox.ts +51 -0
- package/src/internal/Timing.ts +158 -0
- package/src/internal/Validation.ts +52 -0
- package/src/internal/Wallet.ts +62 -0
- package/src/internal/owners/Passkey.ts +72 -0
- package/src/internal/owners/Privy.ts +81 -0
- package/src/internal/owners/Secp256k1.ts +143 -0
- package/src/types/app.d.ts +19 -0
- package/src/worker.ts +11 -0
|
@@ -0,0 +1,768 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Realms: the sets of Tempo Accounts that apps reach. The `realms` table holds each realm, and its
|
|
3
|
+
* owner configurations live in their own tables: `realm_passkeys` for its passkey relying party,
|
|
4
|
+
* `realm_privy` for its Privy app, and `realm_secp256k1` for the secp256k1 owners that Tempo ID
|
|
5
|
+
* holds. The `app_realms` table maps each OAuth app to its realms, in order. An app without rows
|
|
6
|
+
* reaches the `default` realm.
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import type { PgDatabase, PgQueryResultHKT } from 'drizzle-orm/pg-core'
|
|
10
|
+
import { symmetricDecrypt, symmetricEncrypt } from 'better-auth/crypto'
|
|
11
|
+
import { and, asc, eq, inArray, or } from 'drizzle-orm'
|
|
12
|
+
import * as Tldts from 'tldts'
|
|
13
|
+
import { z } from 'zod'
|
|
14
|
+
import * as Schema from '../app/db/schema.js'
|
|
15
|
+
import type * as Privy from './Privy.js'
|
|
16
|
+
|
|
17
|
+
/** An app names the realm, so the realm cannot be removed. */
|
|
18
|
+
export class InUseError extends Error {
|
|
19
|
+
override readonly name = 'Realm.InUseError'
|
|
20
|
+
|
|
21
|
+
constructor(options: { id: string }) {
|
|
22
|
+
super(
|
|
23
|
+
`Realm ${options.id} is in use. Remove it from the realms of each app first.`,
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** A realm ID, a name, a Privy app, or a list of realms is not valid. */
|
|
29
|
+
export class InvalidError extends Error {
|
|
30
|
+
override readonly name = 'Realm.InvalidError'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** No OAuth app has the client ID. */
|
|
34
|
+
export class NotFoundAppError extends Error {
|
|
35
|
+
override readonly name = 'Realm.NotFoundAppError'
|
|
36
|
+
|
|
37
|
+
constructor(options: { clientId: string }) {
|
|
38
|
+
super(`Unknown app ${options.clientId}. Name a registered OAuth app.`)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** No realm has the ID. */
|
|
43
|
+
export class NotFoundError extends Error {
|
|
44
|
+
override readonly name = 'Realm.NotFoundError'
|
|
45
|
+
|
|
46
|
+
constructor(options: { id: string }) {
|
|
47
|
+
super(`Unknown realm ${options.id}. Add it first.`)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** A realm with the ID exists. */
|
|
52
|
+
export class TakenError extends Error {
|
|
53
|
+
override readonly name = 'Realm.TakenError'
|
|
54
|
+
|
|
55
|
+
constructor(options: { id: string }) {
|
|
56
|
+
super(`Realm ${options.id} exists. Choose another ID.`)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Another realm holds the passkey relying party. A passkey belongs to exactly one relying party. */
|
|
61
|
+
export class TakenPasskeysError extends Error {
|
|
62
|
+
override readonly name = 'Realm.TakenPasskeysError'
|
|
63
|
+
|
|
64
|
+
constructor(options: { rpId: string }) {
|
|
65
|
+
super(
|
|
66
|
+
`Relying party ${options.rpId} belongs to another realm. Give each realm its own relying party.`,
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Another realm holds the Privy app. Realms that shared one would list the same accounts. */
|
|
72
|
+
export class TakenPrivyAppError extends Error {
|
|
73
|
+
override readonly name = 'Realm.TakenPrivyAppError'
|
|
74
|
+
|
|
75
|
+
constructor(options: { appId: string }) {
|
|
76
|
+
super(
|
|
77
|
+
`Privy app ${options.appId} belongs to another realm. Give each realm its own Privy app.`,
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** A database with Tempo ID's tables, through any Postgres driver. */
|
|
83
|
+
export type Database = PgDatabase<PgQueryResultHKT, typeof Schema>
|
|
84
|
+
|
|
85
|
+
/** One set of Tempo Accounts, which only the apps that name it reach. */
|
|
86
|
+
export type Realm = {
|
|
87
|
+
/** The realm ID, such as `default` or `tempo-cash`. */
|
|
88
|
+
id: string
|
|
89
|
+
/** The display name, which labels the realm's accounts, such as `Tempo Cash`. */
|
|
90
|
+
name: string
|
|
91
|
+
/** The passkey relying party whose passkeys own accounts in the realm. `undefined` when the realm has none. */
|
|
92
|
+
passkeys:
|
|
93
|
+
| {
|
|
94
|
+
/** The relying party ID, a registrable domain such as `tempo.xyz`. */
|
|
95
|
+
rpId: string
|
|
96
|
+
}
|
|
97
|
+
| undefined
|
|
98
|
+
/** The Privy app that holds the realm's Privy owners. `undefined` when the realm has none. */
|
|
99
|
+
privy:
|
|
100
|
+
| {
|
|
101
|
+
/** The Privy app ID. */
|
|
102
|
+
appId: string
|
|
103
|
+
}
|
|
104
|
+
| undefined
|
|
105
|
+
/** Whether Tempo ID holds the realm's secp256k1 owners itself, as in the suites and local development. */
|
|
106
|
+
secp256k1: boolean
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** The ID of the realm that every app without rows in `app_realms` reaches. */
|
|
110
|
+
export const defaultId = 'default'
|
|
111
|
+
|
|
112
|
+
/** Zod schemas for the values that define realms. */
|
|
113
|
+
export namespace schema {
|
|
114
|
+
/** A realm ID, in lowercase kebab case. */
|
|
115
|
+
export const id = z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, {
|
|
116
|
+
message: 'Use lowercase kebab case, such as tempo-cash.',
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
/** A realm, as `add` receives it. */
|
|
120
|
+
export const realm = z.object({
|
|
121
|
+
id,
|
|
122
|
+
name: z.string().trim().min(1, { message: 'Set a name.' }),
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
/** A realm's passkey relying party, as `setPasskeys` receives it. */
|
|
126
|
+
export const passkeys = z.object({
|
|
127
|
+
realmId: id,
|
|
128
|
+
rpId: z
|
|
129
|
+
.string()
|
|
130
|
+
.regex(
|
|
131
|
+
/^(?=.{1,253}$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/,
|
|
132
|
+
{
|
|
133
|
+
message: 'Use a lowercase domain, such as tempo.xyz.',
|
|
134
|
+
},
|
|
135
|
+
),
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
/** A realm's Privy app, as `setPrivy` receives it. */
|
|
139
|
+
export const privy = z.object({
|
|
140
|
+
appId: z.string().trim().min(1, { message: 'Set a Privy app ID.' }),
|
|
141
|
+
appSecret: z.string().min(1, { message: 'Set a Privy app secret.' }),
|
|
142
|
+
realmId: id,
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
/** An app's realms, in order, each named once. */
|
|
146
|
+
export const realms = z
|
|
147
|
+
.array(id)
|
|
148
|
+
.refine((ids) => new Set(ids).size === ids.length, {
|
|
149
|
+
message: 'Name each realm once.',
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Adds a realm without owner configurations, and returns it.
|
|
155
|
+
*
|
|
156
|
+
* Throws `InvalidError` for an invalid value, and `TakenError` when the ID exists.
|
|
157
|
+
*/
|
|
158
|
+
export async function add(db: Database, options: add.Options) {
|
|
159
|
+
const value = parse(options, { schema: schema.realm })
|
|
160
|
+
|
|
161
|
+
const inserted = await db
|
|
162
|
+
.insert(Schema.realms)
|
|
163
|
+
.values(value)
|
|
164
|
+
.onConflictDoNothing()
|
|
165
|
+
.returning({ id: Schema.realms.id })
|
|
166
|
+
if (inserted.length === 0) throw new TakenError({ id: value.id })
|
|
167
|
+
|
|
168
|
+
return from({
|
|
169
|
+
id: value.id,
|
|
170
|
+
name: value.name,
|
|
171
|
+
passkeys: undefined,
|
|
172
|
+
privy: undefined,
|
|
173
|
+
secp256k1: false,
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export declare namespace add {
|
|
178
|
+
type Options = {
|
|
179
|
+
/** The realm ID, in lowercase kebab case, such as `tempo-cash`. */
|
|
180
|
+
id: string
|
|
181
|
+
/** The display name, such as `Tempo Cash`. */
|
|
182
|
+
name: string
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Returns the realms of the app with `clientId`, in order, in one query. The first realm holds a
|
|
188
|
+
* user's first account. An app without rows, or an unknown client ID, reaches the `default` realm.
|
|
189
|
+
*/
|
|
190
|
+
export async function forApp(
|
|
191
|
+
db: Database,
|
|
192
|
+
options: forApp.Options,
|
|
193
|
+
): Promise<readonly Realm[]> {
|
|
194
|
+
// The query returns the app's realms and the `default` realm. `position` is `null` on `default`
|
|
195
|
+
// when the app does not name it.
|
|
196
|
+
const rows = await db
|
|
197
|
+
.select({
|
|
198
|
+
appId: Schema.realmPrivy.appId,
|
|
199
|
+
id: Schema.realms.id,
|
|
200
|
+
name: Schema.realms.name,
|
|
201
|
+
position: Schema.appRealms.position,
|
|
202
|
+
rpId: Schema.realmPasskeys.rpId,
|
|
203
|
+
secp256k1: Schema.realmSecp256k1.realmId,
|
|
204
|
+
})
|
|
205
|
+
.from(Schema.realms)
|
|
206
|
+
.leftJoin(
|
|
207
|
+
Schema.appRealms,
|
|
208
|
+
and(
|
|
209
|
+
eq(Schema.appRealms.realmId, Schema.realms.id),
|
|
210
|
+
eq(Schema.appRealms.clientId, options.clientId),
|
|
211
|
+
),
|
|
212
|
+
)
|
|
213
|
+
.leftJoin(
|
|
214
|
+
Schema.realmPasskeys,
|
|
215
|
+
eq(Schema.realmPasskeys.realmId, Schema.realms.id),
|
|
216
|
+
)
|
|
217
|
+
.leftJoin(
|
|
218
|
+
Schema.realmPrivy,
|
|
219
|
+
eq(Schema.realmPrivy.realmId, Schema.realms.id),
|
|
220
|
+
)
|
|
221
|
+
.leftJoin(
|
|
222
|
+
Schema.realmSecp256k1,
|
|
223
|
+
eq(Schema.realmSecp256k1.realmId, Schema.realms.id),
|
|
224
|
+
)
|
|
225
|
+
.where(
|
|
226
|
+
or(
|
|
227
|
+
eq(Schema.appRealms.clientId, options.clientId),
|
|
228
|
+
eq(Schema.realms.id, defaultId),
|
|
229
|
+
),
|
|
230
|
+
)
|
|
231
|
+
.orderBy(asc(Schema.appRealms.position))
|
|
232
|
+
|
|
233
|
+
const named = rows.filter((row) => row.position !== null)
|
|
234
|
+
return (named.length > 0 ? named : rows).map(toRealm)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export declare namespace forApp {
|
|
238
|
+
type Options = {
|
|
239
|
+
/** The OAuth app's client ID. */
|
|
240
|
+
clientId: string
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Returns the realms that a request reaches for the app with `clientId`, in order. A request that
|
|
246
|
+
* names no app reaches the `default` realm. So does a browser page that names an app from an origin
|
|
247
|
+
* none of the app's redirect URIs has, since a page cannot read another app's accounts. A native app
|
|
248
|
+
* sends no `Origin`, and Tempo ID's own pages send `own`.
|
|
249
|
+
*/
|
|
250
|
+
export async function forRequest(
|
|
251
|
+
db: Database,
|
|
252
|
+
options: forRequest.Options,
|
|
253
|
+
): Promise<readonly Realm[]> {
|
|
254
|
+
const { clientId, origin, own } = options
|
|
255
|
+
if (!clientId) return [await get(db, { id: defaultId })]
|
|
256
|
+
|
|
257
|
+
if (origin && origin !== own) {
|
|
258
|
+
const [app] = await db
|
|
259
|
+
.select({ redirectUris: Schema.oauthClient.redirectUris })
|
|
260
|
+
.from(Schema.oauthClient)
|
|
261
|
+
.where(eq(Schema.oauthClient.clientId, clientId))
|
|
262
|
+
const origins = (app?.redirectUris ?? []).flatMap((uri) => {
|
|
263
|
+
const url = URL.parse(uri)
|
|
264
|
+
return url && (url.protocol === 'https:' || url.protocol === 'http:')
|
|
265
|
+
? [url.origin]
|
|
266
|
+
: []
|
|
267
|
+
})
|
|
268
|
+
if (!origins.includes(origin)) return [await get(db, { id: defaultId })]
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return await forApp(db, { clientId })
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export declare namespace forRequest {
|
|
275
|
+
type Options = {
|
|
276
|
+
/** The client ID that the request names, if any. */
|
|
277
|
+
clientId?: string | undefined
|
|
278
|
+
/** The request's `Origin`, if any. */
|
|
279
|
+
origin?: string | undefined
|
|
280
|
+
/** Tempo ID's own origin. */
|
|
281
|
+
own: string
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Instantiates a {@link Realm}.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```ts
|
|
290
|
+
* const realm = Realm.from({
|
|
291
|
+
* id: 'tempo-cash',
|
|
292
|
+
* name: 'Tempo Cash',
|
|
293
|
+
* privy: { appId: 'cm…' },
|
|
294
|
+
* secp256k1: false,
|
|
295
|
+
* })
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
export function from(value: Realm): Realm {
|
|
299
|
+
return value
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Returns the realm with `id`. Throws `NotFoundError` when no realm has it. */
|
|
303
|
+
export async function get(db: Database, options: get.Options) {
|
|
304
|
+
const [row] = await db
|
|
305
|
+
.select({
|
|
306
|
+
appId: Schema.realmPrivy.appId,
|
|
307
|
+
id: Schema.realms.id,
|
|
308
|
+
name: Schema.realms.name,
|
|
309
|
+
rpId: Schema.realmPasskeys.rpId,
|
|
310
|
+
secp256k1: Schema.realmSecp256k1.realmId,
|
|
311
|
+
})
|
|
312
|
+
.from(Schema.realms)
|
|
313
|
+
.leftJoin(
|
|
314
|
+
Schema.realmPasskeys,
|
|
315
|
+
eq(Schema.realmPasskeys.realmId, Schema.realms.id),
|
|
316
|
+
)
|
|
317
|
+
.leftJoin(
|
|
318
|
+
Schema.realmPrivy,
|
|
319
|
+
eq(Schema.realmPrivy.realmId, Schema.realms.id),
|
|
320
|
+
)
|
|
321
|
+
.leftJoin(
|
|
322
|
+
Schema.realmSecp256k1,
|
|
323
|
+
eq(Schema.realmSecp256k1.realmId, Schema.realms.id),
|
|
324
|
+
)
|
|
325
|
+
.where(eq(Schema.realms.id, options.id))
|
|
326
|
+
if (!row) throw new NotFoundError({ id: options.id })
|
|
327
|
+
return toRealm(row)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export declare namespace get {
|
|
331
|
+
type Options = {
|
|
332
|
+
/** The realm ID, such as `tempo-cash`. */
|
|
333
|
+
id: string
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** Returns every realm: `default` first, then the others by ID. */
|
|
338
|
+
export async function list(db: Database): Promise<readonly Realm[]> {
|
|
339
|
+
const rows = await db
|
|
340
|
+
.select({
|
|
341
|
+
appId: Schema.realmPrivy.appId,
|
|
342
|
+
id: Schema.realms.id,
|
|
343
|
+
name: Schema.realms.name,
|
|
344
|
+
rpId: Schema.realmPasskeys.rpId,
|
|
345
|
+
secp256k1: Schema.realmSecp256k1.realmId,
|
|
346
|
+
})
|
|
347
|
+
.from(Schema.realms)
|
|
348
|
+
.leftJoin(
|
|
349
|
+
Schema.realmPasskeys,
|
|
350
|
+
eq(Schema.realmPasskeys.realmId, Schema.realms.id),
|
|
351
|
+
)
|
|
352
|
+
.leftJoin(
|
|
353
|
+
Schema.realmPrivy,
|
|
354
|
+
eq(Schema.realmPrivy.realmId, Schema.realms.id),
|
|
355
|
+
)
|
|
356
|
+
.leftJoin(
|
|
357
|
+
Schema.realmSecp256k1,
|
|
358
|
+
eq(Schema.realmSecp256k1.realmId, Schema.realms.id),
|
|
359
|
+
)
|
|
360
|
+
.orderBy(asc(Schema.realms.id))
|
|
361
|
+
|
|
362
|
+
return rows
|
|
363
|
+
.toSorted((a, b) => Number(b.id === defaultId) - Number(a.id === defaultId))
|
|
364
|
+
.map(toRealm)
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Returns the Privy apps of `realms`, by realm ID, with each app secret decrypted with `secret`. A
|
|
369
|
+
* realm without a Privy app has no entry. Reads every realm in one query.
|
|
370
|
+
*/
|
|
371
|
+
export async function privyApps(
|
|
372
|
+
db: Database,
|
|
373
|
+
options: privyApps.Options,
|
|
374
|
+
): Promise<ReadonlyMap<string, Privy.App>> {
|
|
375
|
+
const ids = options.realms.flatMap((realm) => (realm.privy ? [realm.id] : []))
|
|
376
|
+
if (ids.length === 0) return new Map()
|
|
377
|
+
|
|
378
|
+
const rows = await db
|
|
379
|
+
.select()
|
|
380
|
+
.from(Schema.realmPrivy)
|
|
381
|
+
.where(inArray(Schema.realmPrivy.realmId, ids))
|
|
382
|
+
return new Map(
|
|
383
|
+
await Promise.all(
|
|
384
|
+
rows.map(
|
|
385
|
+
async (row) =>
|
|
386
|
+
[
|
|
387
|
+
row.realmId,
|
|
388
|
+
{
|
|
389
|
+
appId: row.appId,
|
|
390
|
+
appSecret: await symmetricDecrypt({
|
|
391
|
+
data: row.appSecret,
|
|
392
|
+
key: options.secret,
|
|
393
|
+
}),
|
|
394
|
+
},
|
|
395
|
+
] as const,
|
|
396
|
+
),
|
|
397
|
+
),
|
|
398
|
+
)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export declare namespace privyApps {
|
|
402
|
+
type Options = {
|
|
403
|
+
/** The realms whose Privy apps to read. */
|
|
404
|
+
realms: readonly Realm[]
|
|
405
|
+
/** The `SECRET` variable, which encrypts each app secret. */
|
|
406
|
+
secret: string
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Removes the realm with `id`, with its owner configurations.
|
|
412
|
+
*
|
|
413
|
+
* Throws `InvalidError` for an invalid ID or `default`, `NotFoundError` when no realm has the ID,
|
|
414
|
+
* and `InUseError` while an app names the realm.
|
|
415
|
+
*/
|
|
416
|
+
export async function remove(db: Database, options: remove.Options) {
|
|
417
|
+
const id = parse(options.id, { schema: schema.id })
|
|
418
|
+
if (id === defaultId)
|
|
419
|
+
throw new InvalidError(
|
|
420
|
+
`Invalid id: apps without realms reach the ${defaultId} realm. Remove another realm.`,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
const deleted = await (async () => {
|
|
424
|
+
try {
|
|
425
|
+
return await db
|
|
426
|
+
.delete(Schema.realms)
|
|
427
|
+
.where(eq(Schema.realms.id, id))
|
|
428
|
+
.returning({ id: Schema.realms.id })
|
|
429
|
+
} catch (error) {
|
|
430
|
+
if (
|
|
431
|
+
violation(error, { code: '23503' }) ===
|
|
432
|
+
'app_realms_realm_id_realms_id_fk'
|
|
433
|
+
)
|
|
434
|
+
throw new InUseError({ id })
|
|
435
|
+
throw error
|
|
436
|
+
}
|
|
437
|
+
})()
|
|
438
|
+
if (deleted.length === 0) throw new NotFoundError({ id })
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export declare namespace remove {
|
|
442
|
+
type Options = {
|
|
443
|
+
/** The realm ID, such as `tempo-cash`. */
|
|
444
|
+
id: string
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Sets the realms of the app with `clientId`, in order, and returns them. An empty list removes the
|
|
450
|
+
* app's rows, so the app reaches the `default` realm.
|
|
451
|
+
*
|
|
452
|
+
* Throws `InvalidError` for an invalid ID or a repeated realm, `NotFoundAppError` when no OAuth app
|
|
453
|
+
* has the client ID, and `NotFoundError` when no realm has one of the IDs.
|
|
454
|
+
*/
|
|
455
|
+
export async function setForApp(db: Database, options: setForApp.Options) {
|
|
456
|
+
const { clientId } = options
|
|
457
|
+
const ids = parse(options.realms, { schema: schema.realms })
|
|
458
|
+
|
|
459
|
+
return await db.transaction(async (tx) => {
|
|
460
|
+
// The locks serialize concurrent changes to the app's realms, and hold each named realm until
|
|
461
|
+
// the transaction ends, so a concurrent `remove` waits and the result is this call's own.
|
|
462
|
+
const [app] = await tx
|
|
463
|
+
.select({ clientId: Schema.oauthClient.clientId })
|
|
464
|
+
.from(Schema.oauthClient)
|
|
465
|
+
.where(eq(Schema.oauthClient.clientId, clientId))
|
|
466
|
+
.for('update')
|
|
467
|
+
if (!app) throw new NotFoundAppError({ clientId })
|
|
468
|
+
|
|
469
|
+
const rows =
|
|
470
|
+
ids.length === 0
|
|
471
|
+
? []
|
|
472
|
+
: await tx
|
|
473
|
+
.select({ id: Schema.realms.id })
|
|
474
|
+
.from(Schema.realms)
|
|
475
|
+
.where(inArray(Schema.realms.id, ids))
|
|
476
|
+
.for('share')
|
|
477
|
+
const known = new Set(rows.map((row) => row.id))
|
|
478
|
+
const missing = ids.find((id) => !known.has(id))
|
|
479
|
+
if (missing) throw new NotFoundError({ id: missing })
|
|
480
|
+
|
|
481
|
+
await tx
|
|
482
|
+
.delete(Schema.appRealms)
|
|
483
|
+
.where(eq(Schema.appRealms.clientId, clientId))
|
|
484
|
+
if (ids.length > 0)
|
|
485
|
+
await tx
|
|
486
|
+
.insert(Schema.appRealms)
|
|
487
|
+
.values(
|
|
488
|
+
ids.map((realmId, position) => ({ clientId, position, realmId })),
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
return await forApp(tx, { clientId })
|
|
492
|
+
})
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export declare namespace setForApp {
|
|
496
|
+
type Options = {
|
|
497
|
+
/** The OAuth app's client ID. */
|
|
498
|
+
clientId: string
|
|
499
|
+
/** The realm IDs, in order, such as `['default', 'tempo-cash']`. Empty for the `default` realm alone. */
|
|
500
|
+
realms: readonly string[]
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Sets the passkey relying party of the realm with `realmId`, and returns the realm. It replaces an
|
|
506
|
+
* earlier relying party. Passkeys of that relying party then own accounts in the realm.
|
|
507
|
+
*
|
|
508
|
+
* Throws `InvalidError` for an invalid value, `NotFoundError` when no realm has the ID, and
|
|
509
|
+
* `TakenPasskeysError` when another realm holds the relying party.
|
|
510
|
+
*/
|
|
511
|
+
export async function setPasskeys(db: Database, options: setPasskeys.Options) {
|
|
512
|
+
const value = parse(options, { schema: schema.passkeys })
|
|
513
|
+
|
|
514
|
+
try {
|
|
515
|
+
await db
|
|
516
|
+
.insert(Schema.realmPasskeys)
|
|
517
|
+
.values({ realmId: value.realmId, rpId: value.rpId })
|
|
518
|
+
.onConflictDoUpdate({
|
|
519
|
+
set: { rpId: value.rpId },
|
|
520
|
+
target: Schema.realmPasskeys.realmId,
|
|
521
|
+
})
|
|
522
|
+
} catch (error) {
|
|
523
|
+
if (violation(error, { code: '23505' }) === 'realm_passkeys_rp_id_unique')
|
|
524
|
+
throw new TakenPasskeysError({ rpId: value.rpId })
|
|
525
|
+
if (violation(error, { code: '23503' }))
|
|
526
|
+
throw new NotFoundError({ id: value.realmId })
|
|
527
|
+
throw error
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return await get(db, { id: value.realmId })
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export declare namespace setPasskeys {
|
|
534
|
+
type Options = {
|
|
535
|
+
/** The realm ID, such as `default`. */
|
|
536
|
+
realmId: string
|
|
537
|
+
/** The relying party ID, a registrable domain such as `tempo.xyz`. */
|
|
538
|
+
rpId: string
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Sets the Privy app that holds the Privy owners of the realm with `realmId`, and returns the realm.
|
|
544
|
+
* It replaces an earlier Privy app. The row holds the app secret encrypted with `secret`.
|
|
545
|
+
*
|
|
546
|
+
* Throws `InvalidError` for an invalid value, `NotFoundError` when no realm has the ID, and
|
|
547
|
+
* `TakenPrivyAppError` when another realm holds the Privy app.
|
|
548
|
+
*/
|
|
549
|
+
export async function setPrivy(db: Database, options: setPrivy.Options) {
|
|
550
|
+
const value = parse(options, { schema: schema.privy })
|
|
551
|
+
const appSecret = await symmetricEncrypt({
|
|
552
|
+
data: value.appSecret,
|
|
553
|
+
key: options.secret,
|
|
554
|
+
})
|
|
555
|
+
|
|
556
|
+
const [realm] = await db
|
|
557
|
+
.select({ id: Schema.realms.id })
|
|
558
|
+
.from(Schema.realms)
|
|
559
|
+
.where(eq(Schema.realms.id, value.realmId))
|
|
560
|
+
if (!realm) throw new NotFoundError({ id: value.realmId })
|
|
561
|
+
|
|
562
|
+
try {
|
|
563
|
+
await db
|
|
564
|
+
.insert(Schema.realmPrivy)
|
|
565
|
+
.values({ appId: value.appId, appSecret, realmId: value.realmId })
|
|
566
|
+
.onConflictDoUpdate({
|
|
567
|
+
set: { appId: value.appId, appSecret },
|
|
568
|
+
target: Schema.realmPrivy.realmId,
|
|
569
|
+
})
|
|
570
|
+
} catch (error) {
|
|
571
|
+
if (violation(error, { code: '23505' }) === 'realm_privy_app_id_unique')
|
|
572
|
+
throw new TakenPrivyAppError({ appId: value.appId })
|
|
573
|
+
// A concurrent `remove` deleted the realm after the read.
|
|
574
|
+
if (violation(error, { code: '23503' }))
|
|
575
|
+
throw new NotFoundError({ id: value.realmId })
|
|
576
|
+
throw error
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
return await get(db, { id: value.realmId })
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
export declare namespace setPrivy {
|
|
583
|
+
type Options = {
|
|
584
|
+
/** The Privy app ID. */
|
|
585
|
+
appId: string
|
|
586
|
+
/** The Privy app secret, which the row holds only encrypted. */
|
|
587
|
+
appSecret: string
|
|
588
|
+
/** The realm ID, such as `tempo-cash`. */
|
|
589
|
+
realmId: string
|
|
590
|
+
/** The `SECRET` variable, which encrypts the app secret. */
|
|
591
|
+
secret: string
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Sets whether Tempo ID holds the secp256k1 owners of the realm with `realmId`, and returns the
|
|
597
|
+
* realm. The realm then creates a user's first account with a key that Tempo ID holds. Turning it
|
|
598
|
+
* off keeps the realm's stored keys, and lists none of them.
|
|
599
|
+
*
|
|
600
|
+
* Throws `InvalidError` for an invalid ID, and `NotFoundError` when no realm has the ID.
|
|
601
|
+
*/
|
|
602
|
+
export async function setSecp256k1(
|
|
603
|
+
db: Database,
|
|
604
|
+
options: setSecp256k1.Options,
|
|
605
|
+
) {
|
|
606
|
+
const realmId = parse(options.realmId, { schema: schema.id })
|
|
607
|
+
|
|
608
|
+
if (!options.enabled)
|
|
609
|
+
await db
|
|
610
|
+
.delete(Schema.realmSecp256k1)
|
|
611
|
+
.where(eq(Schema.realmSecp256k1.realmId, realmId))
|
|
612
|
+
else
|
|
613
|
+
try {
|
|
614
|
+
await db
|
|
615
|
+
.insert(Schema.realmSecp256k1)
|
|
616
|
+
.values({ realmId })
|
|
617
|
+
.onConflictDoNothing()
|
|
618
|
+
} catch (error) {
|
|
619
|
+
if (violation(error, { code: '23503' }))
|
|
620
|
+
throw new NotFoundError({ id: realmId })
|
|
621
|
+
throw error
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
return await get(db, { id: realmId })
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
export declare namespace setSecp256k1 {
|
|
628
|
+
type Options = {
|
|
629
|
+
/** Whether Tempo ID holds the realm's secp256k1 owners. */
|
|
630
|
+
enabled: boolean
|
|
631
|
+
/** The realm ID, such as `default`. */
|
|
632
|
+
realmId: string
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Returns `realms` with the relying party that each one signs in with. The `default` realm without a
|
|
638
|
+
* `realm_passkeys` row signs in with passkeys of the registrable domain of `origin`, such as
|
|
639
|
+
* `tempo.xyz` for `https://id.tempo.xyz`, so every deployment offers passkeys without configuration. A row replaces that relying party. When another realm's row holds
|
|
640
|
+
* the host or a parent domain of it, `default` has none, since that realm's passkeys sign in at the
|
|
641
|
+
* same origin.
|
|
642
|
+
*/
|
|
643
|
+
export async function withDefaults(
|
|
644
|
+
db: Database,
|
|
645
|
+
options: withDefaults.Options,
|
|
646
|
+
): Promise<readonly Realm[]> {
|
|
647
|
+
const { realms } = options
|
|
648
|
+
if (!realms.some((realm) => realm.id === defaultId && !realm.passkeys))
|
|
649
|
+
return realms
|
|
650
|
+
|
|
651
|
+
const host = new URL(options.origin).hostname
|
|
652
|
+
const parsed = Tldts.parse(host, { allowPrivateDomains: true })
|
|
653
|
+
// WebAuthn refuses an IP address as a relying party.
|
|
654
|
+
if (parsed.isIp) return realms
|
|
655
|
+
|
|
656
|
+
// A private suffix, such as `workers.dev`, is not a registrable domain, so the host keeps its own
|
|
657
|
+
// label there. `localhost` has no registrable domain, and keeps its host.
|
|
658
|
+
const rpId = parsed.domain ?? host
|
|
659
|
+
// A row for the host or a parent domain of it, such as `tempo.xyz` for `id.tempo.xyz`, signs in at
|
|
660
|
+
// the origin too, so the default would take that realm's sign-ins at an app that lists `default`
|
|
661
|
+
// first.
|
|
662
|
+
// A public suffix, such as `xyz`, is never a relying party, so the domains stop at `rpId`.
|
|
663
|
+
const labels = host.split('.')
|
|
664
|
+
const domains = labels
|
|
665
|
+
.map((_, index) => labels.slice(index).join('.'))
|
|
666
|
+
.filter((domain) => domain === rpId || domain.endsWith(`.${rpId}`))
|
|
667
|
+
// The realms come from an earlier read than the lookup below, so a change between the two reads
|
|
668
|
+
// could show the host as free while one of `realms` still holds it. Both checks together cover
|
|
669
|
+
// either order.
|
|
670
|
+
if (
|
|
671
|
+
realms.some(
|
|
672
|
+
(realm) => realm.passkeys && domains.includes(realm.passkeys.rpId),
|
|
673
|
+
)
|
|
674
|
+
)
|
|
675
|
+
return realms
|
|
676
|
+
|
|
677
|
+
const [taken] = await db
|
|
678
|
+
.select({ realmId: Schema.realmPasskeys.realmId })
|
|
679
|
+
.from(Schema.realmPasskeys)
|
|
680
|
+
.where(inArray(Schema.realmPasskeys.rpId, domains))
|
|
681
|
+
if (taken) return realms
|
|
682
|
+
|
|
683
|
+
return realms.map((realm) =>
|
|
684
|
+
realm.id === defaultId && !realm.passkeys
|
|
685
|
+
? from({ ...realm, passkeys: { rpId } })
|
|
686
|
+
: realm,
|
|
687
|
+
)
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
export declare namespace withDefaults {
|
|
691
|
+
type Options = {
|
|
692
|
+
/** Tempo ID's origin, such as `https://id.tempo.xyz`. */
|
|
693
|
+
origin: string
|
|
694
|
+
/** The realms that a request reaches, in order. */
|
|
695
|
+
realms: readonly Realm[]
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/** Parses `value` with `options.schema`, and throws `InvalidError` with the first issue's message. */
|
|
700
|
+
function parse<const type extends z.ZodType>(
|
|
701
|
+
value: unknown,
|
|
702
|
+
options: parse.Options<type>,
|
|
703
|
+
): z.output<type> {
|
|
704
|
+
const result = options.schema.safeParse(value)
|
|
705
|
+
if (result.success) return result.data
|
|
706
|
+
|
|
707
|
+
const issue = result.error.issues[0]!
|
|
708
|
+
const path = issue.path.join('.')
|
|
709
|
+
throw new InvalidError(
|
|
710
|
+
path
|
|
711
|
+
? `Invalid ${path}: ${issue.message}`
|
|
712
|
+
: `Invalid realm: ${issue.message}`,
|
|
713
|
+
)
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
declare namespace parse {
|
|
717
|
+
type Options<type extends z.ZodType> = {
|
|
718
|
+
/** The schema that `value` must pass. */
|
|
719
|
+
schema: type
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/** Returns a realm from a row of `realms` joined with its owner configurations. */
|
|
724
|
+
function toRealm(row: toRealm.Row) {
|
|
725
|
+
return from({
|
|
726
|
+
id: row.id,
|
|
727
|
+
name: row.name,
|
|
728
|
+
passkeys: row.rpId === null ? undefined : { rpId: row.rpId },
|
|
729
|
+
privy: row.appId === null ? undefined : { appId: row.appId },
|
|
730
|
+
secp256k1: row.secp256k1 !== null,
|
|
731
|
+
})
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
declare namespace toRealm {
|
|
735
|
+
type Row = {
|
|
736
|
+
/** The Privy app ID, or `null` when the realm has no Privy app. */
|
|
737
|
+
appId: string | null
|
|
738
|
+
/** The realm ID. */
|
|
739
|
+
id: string
|
|
740
|
+
/** The display name. */
|
|
741
|
+
name: string
|
|
742
|
+
/** The passkey relying party ID, or `null` when the realm has none. */
|
|
743
|
+
rpId: string | null
|
|
744
|
+
/** The realm ID again when the realm holds secp256k1 owners, or `null`. */
|
|
745
|
+
secp256k1: string | null
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Returns the constraint that a Postgres error with `code` names, such as `23505` for a unique
|
|
751
|
+
* violation, or `undefined` for any other error. Drizzle wraps the driver's error in `cause`.
|
|
752
|
+
*/
|
|
753
|
+
function violation(error: unknown, options: violation.Options) {
|
|
754
|
+
const { code } = options
|
|
755
|
+
const cause = error instanceof Error && error.cause ? error.cause : error
|
|
756
|
+
if (typeof cause !== 'object' || cause === null) return undefined
|
|
757
|
+
if (!('code' in cause) || cause.code !== code) return undefined
|
|
758
|
+
if (!('constraint' in cause) || typeof cause.constraint !== 'string')
|
|
759
|
+
return undefined
|
|
760
|
+
return cause.constraint
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
declare namespace violation {
|
|
764
|
+
type Options = {
|
|
765
|
+
/** The SQLSTATE code, such as `23503` for a foreign key violation. */
|
|
766
|
+
code: string
|
|
767
|
+
}
|
|
768
|
+
}
|