@tempoxyz/id 0.0.0-pr-187.sha-eed04d3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (712) hide show
  1. package/README.md +81 -0
  2. package/dist/App.d.ts +20 -0
  3. package/dist/App.d.ts.map +1 -0
  4. package/dist/App.js +26 -0
  5. package/dist/App.js.map +1 -0
  6. package/dist/app/client/.assetsignore +2 -0
  7. package/dist/app/client/assets/BRLA-CZvVDNYr.png +0 -0
  8. package/dist/app/client/assets/CHFAU-DCedc4aH.png +0 -0
  9. package/dist/app/client/assets/DLUSD-BnRXm3EI.png +0 -0
  10. package/dist/app/client/assets/PRIME-CiFp2-3e.svg +14 -0
  11. package/dist/app/client/assets/Pilat-Bold-C1t1eIrF.woff2 +0 -0
  12. package/dist/app/client/assets/Pilat-Book-CbS8ofT8.woff2 +0 -0
  13. package/dist/app/client/assets/Pilat-Demi-CADSbPAt.woff2 +0 -0
  14. package/dist/app/client/assets/Pilat-Regular-Bx8vzE7q.woff2 +0 -0
  15. package/dist/app/client/assets/USD1-COVcO_PB.svg +30 -0
  16. package/dist/app/client/assets/YLDS-CRh8Zw0g.svg +3 -0
  17. package/dist/app/client/assets/ccip-Cq1mMiVl.js +1 -0
  18. package/dist/app/client/assets/frxUSD-n9pTpinR.svg +1 -0
  19. package/dist/app/client/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  20. package/dist/app/client/assets/index-B7YJVP00.css +1 -0
  21. package/dist/app/client/assets/index-UXTxXCLk.js +55 -0
  22. package/dist/app/client/assets/pathUSD-BvaO6ooS.svg +25 -0
  23. package/dist/app/client/assets/reset-co-CHrff.css +1 -0
  24. package/dist/app/client/assets/wYLDS-CaCKDrO-.svg +10 -0
  25. package/dist/app/db/auth.d.ts +3207 -0
  26. package/dist/app/db/auth.d.ts.map +1 -0
  27. package/dist/app/db/auth.js +330 -0
  28. package/dist/app/db/auth.js.map +1 -0
  29. package/dist/app/db/schema.d.ts +932 -0
  30. package/dist/app/db/schema.d.ts.map +1 -0
  31. package/dist/app/db/schema.js +171 -0
  32. package/dist/app/db/schema.js.map +1 -0
  33. package/dist/app/server/.vite/manifest.json +489 -0
  34. package/dist/app/server/assets/BRLA-CZvVDNYr.png +0 -0
  35. package/dist/app/server/assets/CHFAU-DCedc4aH.png +0 -0
  36. package/dist/app/server/assets/DLUSD-BnRXm3EI.png +0 -0
  37. package/dist/app/server/assets/PRIME-CiFp2-3e.svg +14 -0
  38. package/dist/app/server/assets/Pilat-Bold-C1t1eIrF.woff2 +0 -0
  39. package/dist/app/server/assets/Pilat-Book-CbS8ofT8.woff2 +0 -0
  40. package/dist/app/server/assets/Pilat-Demi-CADSbPAt.woff2 +0 -0
  41. package/dist/app/server/assets/Pilat-Regular-Bx8vzE7q.woff2 +0 -0
  42. package/dist/app/server/assets/USD1-COVcO_PB.svg +30 -0
  43. package/dist/app/server/assets/YLDS-CRh8Zw0g.svg +3 -0
  44. package/dist/app/server/assets/_tanstack-start-manifest_v-DjQNeRZp.js +1 -0
  45. package/dist/app/server/assets/arktype-aI7TBD0R-D1R3Byo5.js +2 -0
  46. package/dist/app/server/assets/arktype-aI7TBD0R-D1R3Byo5.js.map +1 -0
  47. package/dist/app/server/assets/authorize-C95F-9E1-CbESJKGU.js +31 -0
  48. package/dist/app/server/assets/authorize-C95F-9E1-CbESJKGU.js.map +1 -0
  49. package/dist/app/server/assets/bun-sqlite-dialect-DoOVo4ja-CtyBkVMb.js +2 -0
  50. package/dist/app/server/assets/bun-sqlite-dialect-DoOVo4ja-CtyBkVMb.js.map +1 -0
  51. package/dist/app/server/assets/call-UQamaCKN.js +32 -0
  52. package/dist/app/server/assets/call-UQamaCKN.js.map +1 -0
  53. package/dist/app/server/assets/ccip-CbNKFO4n.js +2 -0
  54. package/dist/app/server/assets/ccip-CbNKFO4n.js.map +1 -0
  55. package/dist/app/server/assets/compiled-query-Ds2NVcFT.js +2 -0
  56. package/dist/app/server/assets/compiled-query-Ds2NVcFT.js.map +1 -0
  57. package/dist/app/server/assets/convert-BIC8n32x.js +2 -0
  58. package/dist/app/server/assets/convert-BIC8n32x.js.map +1 -0
  59. package/dist/app/server/assets/cookie-CS900nSP.css +1 -0
  60. package/dist/app/server/assets/cookie-Cce9CrIP.js +10 -0
  61. package/dist/app/server/assets/cookie-Cce9CrIP.js.map +1 -0
  62. package/dist/app/server/assets/core-B1HCXUmx.js +56 -0
  63. package/dist/app/server/assets/core-B1HCXUmx.js.map +1 -0
  64. package/dist/app/server/assets/d1-sqlite-dialect-m0f01-4z-Cv-csE1u.js +2 -0
  65. package/dist/app/server/assets/d1-sqlite-dialect-m0f01-4z-Cv-csE1u.js.map +1 -0
  66. package/dist/app/server/assets/default-u_dwuiYb-BJJ9PwCi.js +2 -0
  67. package/dist/app/server/assets/default-u_dwuiYb-BJJ9PwCi.js.map +1 -0
  68. package/dist/app/server/assets/dist-BxSwugSY.js +1 -0
  69. package/dist/app/server/assets/dist-CZGFhmQd.js +2 -0
  70. package/dist/app/server/assets/dist-CZGFhmQd.js.map +1 -0
  71. package/dist/app/server/assets/dist-Dg3PQqiW.js +15 -0
  72. package/dist/app/server/assets/dist-Dg3PQqiW.js.map +1 -0
  73. package/dist/app/server/assets/effect-QlVUlMFu-2tSPDT2b.js +2 -0
  74. package/dist/app/server/assets/effect-QlVUlMFu-2tSPDT2b.js.map +1 -0
  75. package/dist/app/server/assets/empty-plugin-adapters-BaGcmrjC.js +2 -0
  76. package/dist/app/server/assets/empty-plugin-adapters-BaGcmrjC.js.map +1 -0
  77. package/dist/app/server/assets/factory-ipHlJXZY.js +5 -0
  78. package/dist/app/server/assets/factory-ipHlJXZY.js.map +1 -0
  79. package/dist/app/server/assets/frxUSD-n9pTpinR.svg +1 -0
  80. package/dist/app/server/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  81. package/dist/app/server/assets/get-id-field-B0x109VU.js +6 -0
  82. package/dist/app/server/assets/get-id-field-B0x109VU.js.map +1 -0
  83. package/dist/app/server/assets/index-CLddUTqr-xpSuLpBt.js +2 -0
  84. package/dist/app/server/assets/index-CLddUTqr-xpSuLpBt.js.map +1 -0
  85. package/dist/app/server/assets/index-DZEfthgZ-8Uq5s5Pt.js +2 -0
  86. package/dist/app/server/assets/index-DZEfthgZ-8Uq5s5Pt.js.map +1 -0
  87. package/dist/app/server/assets/kysely-adapter-MkHAI9Jk.js +1 -0
  88. package/dist/app/server/assets/node-sqlite-dialect-BowWLXvK.js +2 -0
  89. package/dist/app/server/assets/node-sqlite-dialect-BowWLXvK.js.map +1 -0
  90. package/dist/app/server/assets/pathUSD-BvaO6ooS.svg +25 -0
  91. package/dist/app/server/assets/reset-co-CHrff.css +1 -0
  92. package/dist/app/server/assets/rolldown-runtime-B0Z9INg1.js +1 -0
  93. package/dist/app/server/assets/router-CcbyBCI4.css +1 -0
  94. package/dist/app/server/assets/router-xjZtEeaI.js +7 -0
  95. package/dist/app/server/assets/router-xjZtEeaI.js.map +1 -0
  96. package/dist/app/server/assets/schema-check-Cf7QOZZD.js +9 -0
  97. package/dist/app/server/assets/schema-check-Cf7QOZZD.js.map +1 -0
  98. package/dist/app/server/assets/schemas-C2lCYmR5.js +2 -0
  99. package/dist/app/server/assets/schemas-C2lCYmR5.js.map +1 -0
  100. package/dist/app/server/assets/secp256k1-buM5g4AL.js +2 -0
  101. package/dist/app/server/assets/secp256k1-buM5g4AL.js.map +1 -0
  102. package/dist/app/server/assets/sqlite-adapter-C_LAV4e3.js +2 -0
  103. package/dist/app/server/assets/sqlite-adapter-C_LAV4e3.js.map +1 -0
  104. package/dist/app/server/assets/sqlite-introspector-DSCAP82F-Crx7Ny14.js +6 -0
  105. package/dist/app/server/assets/sqlite-introspector-DSCAP82F-Crx7Ny14.js.map +1 -0
  106. package/dist/app/server/assets/standard-json-Cg1N07hM.js +2 -0
  107. package/dist/app/server/assets/standard-json-Cg1N07hM.js.map +1 -0
  108. package/dist/app/server/assets/standard-json-DY77efq0.js +2 -0
  109. package/dist/app/server/assets/standard-json-DY77efq0.js.map +1 -0
  110. package/dist/app/server/assets/standard-json-ig2t0wRt.js +2 -0
  111. package/dist/app/server/assets/standard-json-ig2t0wRt.js.map +1 -0
  112. package/dist/app/server/assets/standard-json-t-LNckA6.js +2 -0
  113. package/dist/app/server/assets/standard-json-t-LNckA6.js.map +1 -0
  114. package/dist/app/server/assets/standard-openapi-CONmVRl8.js +2 -0
  115. package/dist/app/server/assets/standard-openapi-CONmVRl8.js.map +1 -0
  116. package/dist/app/server/assets/start-C63VetBp.js +2 -0
  117. package/dist/app/server/assets/start-C63VetBp.js.map +1 -0
  118. package/dist/app/server/assets/sury-CWZTCd75-xt1mWc9f.js +2 -0
  119. package/dist/app/server/assets/sury-CWZTCd75-xt1mWc9f.js.map +1 -0
  120. package/dist/app/server/assets/typebox-Dei93FPO-D_lCVdAz.js +2 -0
  121. package/dist/app/server/assets/typebox-Dei93FPO-D_lCVdAz.js.map +1 -0
  122. package/dist/app/server/assets/utils-C4ZXZIZW.js +2 -0
  123. package/dist/app/server/assets/utils-C4ZXZIZW.js.map +1 -0
  124. package/dist/app/server/assets/valibot--1zFm7rT-NSoY2xTp.js +2 -0
  125. package/dist/app/server/assets/valibot--1zFm7rT-NSoY2xTp.js.map +1 -0
  126. package/dist/app/server/assets/valibot-D_HTw1Gn-CJwWeOUE.js +2 -0
  127. package/dist/app/server/assets/valibot-D_HTw1Gn-CJwWeOUE.js.map +1 -0
  128. package/dist/app/server/assets/wYLDS-CaCKDrO-.svg +10 -0
  129. package/dist/app/server/assets/zod-Bwrt9trS-CV38yPnQ.js +2 -0
  130. package/dist/app/server/assets/zod-Bwrt9trS-CV38yPnQ.js.map +1 -0
  131. package/dist/app/server/assets/zod-DSgpEGAE-BvlnBE2L.js +2 -0
  132. package/dist/app/server/assets/zod-DSgpEGAE-BvlnBE2L.js.map +1 -0
  133. package/dist/app/server/index.js +574 -0
  134. package/dist/app/server/index.js.map +1 -0
  135. package/dist/app/server/wrangler.json +1 -0
  136. package/dist/cli/Admin.d.ts +38 -0
  137. package/dist/cli/Admin.d.ts.map +1 -0
  138. package/dist/cli/Admin.js +62 -0
  139. package/dist/cli/Admin.js.map +1 -0
  140. package/dist/cli/Apps.d.ts +9 -0
  141. package/dist/cli/Apps.d.ts.map +1 -0
  142. package/dist/cli/Apps.js +36 -0
  143. package/dist/cli/Apps.js.map +1 -0
  144. package/dist/cli/Cli.d.ts +14 -0
  145. package/dist/cli/Cli.d.ts.map +1 -0
  146. package/dist/cli/Cli.js +27 -0
  147. package/dist/cli/Cli.js.map +1 -0
  148. package/dist/cli/Project.d.ts +20 -0
  149. package/dist/cli/Project.d.ts.map +1 -0
  150. package/dist/cli/Project.js +88 -0
  151. package/dist/cli/Project.js.map +1 -0
  152. package/dist/cli/Realms.d.ts +24 -0
  153. package/dist/cli/Realms.d.ts.map +1 -0
  154. package/dist/cli/Realms.js +49 -0
  155. package/dist/cli/Realms.js.map +1 -0
  156. package/dist/cli/Session.d.ts +85 -0
  157. package/dist/cli/Session.d.ts.map +1 -0
  158. package/dist/cli/Session.js +178 -0
  159. package/dist/cli/Session.js.map +1 -0
  160. package/dist/cli/User.d.ts +29 -0
  161. package/dist/cli/User.d.ts.map +1 -0
  162. package/dist/cli/User.js +39 -0
  163. package/dist/cli/User.js.map +1 -0
  164. package/dist/cli/V1.d.ts +35 -0
  165. package/dist/cli/V1.d.ts.map +1 -0
  166. package/dist/cli/V1.js +41 -0
  167. package/dist/cli/V1.js.map +1 -0
  168. package/dist/cli/bin.d.ts +3 -0
  169. package/dist/cli/bin.d.ts.map +1 -0
  170. package/dist/cli/bin.js +46 -0
  171. package/dist/cli/bin.js.map +1 -0
  172. package/dist/cli/commands/admin/apps/create.d.ts +23 -0
  173. package/dist/cli/commands/admin/apps/create.d.ts.map +1 -0
  174. package/dist/cli/commands/admin/apps/create.js +89 -0
  175. package/dist/cli/commands/admin/apps/create.js.map +1 -0
  176. package/dist/cli/commands/admin/apps/delete.d.ts +14 -0
  177. package/dist/cli/commands/admin/apps/delete.d.ts.map +1 -0
  178. package/dist/cli/commands/admin/apps/delete.js +41 -0
  179. package/dist/cli/commands/admin/apps/delete.js.map +1 -0
  180. package/dist/cli/commands/admin/apps/index.d.ts +5 -0
  181. package/dist/cli/commands/admin/apps/index.d.ts.map +1 -0
  182. package/dist/cli/commands/admin/apps/index.js +14 -0
  183. package/dist/cli/commands/admin/apps/index.js.map +1 -0
  184. package/dist/cli/commands/admin/apps/list.d.ts +9 -0
  185. package/dist/cli/commands/admin/apps/list.d.ts.map +1 -0
  186. package/dist/cli/commands/admin/apps/list.js +26 -0
  187. package/dist/cli/commands/admin/apps/list.js.map +1 -0
  188. package/dist/cli/commands/admin/apps/rotate-secret.d.ts +16 -0
  189. package/dist/cli/commands/admin/apps/rotate-secret.d.ts.map +1 -0
  190. package/dist/cli/commands/admin/apps/rotate-secret.js +47 -0
  191. package/dist/cli/commands/admin/apps/rotate-secret.js.map +1 -0
  192. package/dist/cli/commands/admin/apps/update.d.ts +20 -0
  193. package/dist/cli/commands/admin/apps/update.d.ts.map +1 -0
  194. package/dist/cli/commands/admin/apps/update.js +76 -0
  195. package/dist/cli/commands/admin/apps/update.js.map +1 -0
  196. package/dist/cli/commands/admin/index.d.ts +5 -0
  197. package/dist/cli/commands/admin/index.d.ts.map +1 -0
  198. package/dist/cli/commands/admin/index.js +13 -0
  199. package/dist/cli/commands/admin/index.js.map +1 -0
  200. package/dist/cli/commands/admin/migrate.d.ts +9 -0
  201. package/dist/cli/commands/admin/migrate.d.ts.map +1 -0
  202. package/dist/cli/commands/admin/migrate.js +17 -0
  203. package/dist/cli/commands/admin/migrate.js.map +1 -0
  204. package/dist/cli/commands/admin/realms/add.d.ts +12 -0
  205. package/dist/cli/commands/admin/realms/add.d.ts.map +1 -0
  206. package/dist/cli/commands/admin/realms/add.js +42 -0
  207. package/dist/cli/commands/admin/realms/add.js.map +1 -0
  208. package/dist/cli/commands/admin/realms/index.d.ts +5 -0
  209. package/dist/cli/commands/admin/realms/index.d.ts.map +1 -0
  210. package/dist/cli/commands/admin/realms/index.js +13 -0
  211. package/dist/cli/commands/admin/realms/index.js.map +1 -0
  212. package/dist/cli/commands/admin/realms/list.d.ts +13 -0
  213. package/dist/cli/commands/admin/realms/list.d.ts.map +1 -0
  214. package/dist/cli/commands/admin/realms/list.js +36 -0
  215. package/dist/cli/commands/admin/realms/list.js.map +1 -0
  216. package/dist/cli/commands/admin/realms/passkeys/index.d.ts +5 -0
  217. package/dist/cli/commands/admin/realms/passkeys/index.d.ts.map +1 -0
  218. package/dist/cli/commands/admin/realms/passkeys/index.js +13 -0
  219. package/dist/cli/commands/admin/realms/passkeys/index.js.map +1 -0
  220. package/dist/cli/commands/admin/realms/passkeys/set.d.ts +16 -0
  221. package/dist/cli/commands/admin/realms/passkeys/set.d.ts.map +1 -0
  222. package/dist/cli/commands/admin/realms/passkeys/set.js +46 -0
  223. package/dist/cli/commands/admin/realms/passkeys/set.js.map +1 -0
  224. package/dist/cli/commands/admin/realms/privy/index.d.ts +5 -0
  225. package/dist/cli/commands/admin/realms/privy/index.d.ts.map +1 -0
  226. package/dist/cli/commands/admin/realms/privy/index.js +13 -0
  227. package/dist/cli/commands/admin/realms/privy/index.js.map +1 -0
  228. package/dist/cli/commands/admin/realms/privy/set.d.ts +18 -0
  229. package/dist/cli/commands/admin/realms/privy/set.d.ts.map +1 -0
  230. package/dist/cli/commands/admin/realms/privy/set.js +66 -0
  231. package/dist/cli/commands/admin/realms/privy/set.js.map +1 -0
  232. package/dist/cli/commands/admin/realms/remove.d.ts +11 -0
  233. package/dist/cli/commands/admin/realms/remove.d.ts.map +1 -0
  234. package/dist/cli/commands/admin/realms/remove.js +35 -0
  235. package/dist/cli/commands/admin/realms/remove.js.map +1 -0
  236. package/dist/cli/commands/admin/realms/secp256k1/disable.d.ts +15 -0
  237. package/dist/cli/commands/admin/realms/secp256k1/disable.d.ts.map +1 -0
  238. package/dist/cli/commands/admin/realms/secp256k1/disable.js +42 -0
  239. package/dist/cli/commands/admin/realms/secp256k1/disable.js.map +1 -0
  240. package/dist/cli/commands/admin/realms/secp256k1/enable.d.ts +15 -0
  241. package/dist/cli/commands/admin/realms/secp256k1/enable.d.ts.map +1 -0
  242. package/dist/cli/commands/admin/realms/secp256k1/enable.js +42 -0
  243. package/dist/cli/commands/admin/realms/secp256k1/enable.js.map +1 -0
  244. package/dist/cli/commands/admin/realms/secp256k1/index.d.ts +9 -0
  245. package/dist/cli/commands/admin/realms/secp256k1/index.d.ts.map +1 -0
  246. package/dist/cli/commands/admin/realms/secp256k1/index.js +17 -0
  247. package/dist/cli/commands/admin/realms/secp256k1/index.js.map +1 -0
  248. package/dist/cli/commands/admin/realms/set.d.ts +16 -0
  249. package/dist/cli/commands/admin/realms/set.d.ts.map +1 -0
  250. package/dist/cli/commands/admin/realms/set.js +46 -0
  251. package/dist/cli/commands/admin/realms/set.js.map +1 -0
  252. package/dist/cli/commands/admin/rotate-key.d.ts +15 -0
  253. package/dist/cli/commands/admin/rotate-key.d.ts.map +1 -0
  254. package/dist/cli/commands/admin/rotate-key.js +46 -0
  255. package/dist/cli/commands/admin/rotate-key.js.map +1 -0
  256. package/dist/cli/commands/init.d.ts +11 -0
  257. package/dist/cli/commands/init.d.ts.map +1 -0
  258. package/dist/cli/commands/init.js +34 -0
  259. package/dist/cli/commands/init.js.map +1 -0
  260. package/dist/cli/commands/login.d.ts +12 -0
  261. package/dist/cli/commands/login.d.ts.map +1 -0
  262. package/dist/cli/commands/login.js +29 -0
  263. package/dist/cli/commands/login.js.map +1 -0
  264. package/dist/cli/commands/logout.d.ts +8 -0
  265. package/dist/cli/commands/logout.d.ts.map +1 -0
  266. package/dist/cli/commands/logout.js +19 -0
  267. package/dist/cli/commands/logout.js.map +1 -0
  268. package/dist/cli/commands/whoami.d.ts +12 -0
  269. package/dist/cli/commands/whoami.d.ts.map +1 -0
  270. package/dist/cli/commands/whoami.js +24 -0
  271. package/dist/cli/commands/whoami.js.map +1 -0
  272. package/dist/client/Actions.d.ts +101 -0
  273. package/dist/client/Actions.d.ts.map +1 -0
  274. package/dist/client/Actions.js +90 -0
  275. package/dist/client/Actions.js.map +1 -0
  276. package/dist/client/Auth.d.ts +161 -0
  277. package/dist/client/Auth.d.ts.map +1 -0
  278. package/dist/client/Auth.js +113 -0
  279. package/dist/client/Auth.js.map +1 -0
  280. package/dist/client/Authorization.d.ts +29 -0
  281. package/dist/client/Authorization.d.ts.map +1 -0
  282. package/dist/client/Authorization.js +12 -0
  283. package/dist/client/Authorization.js.map +1 -0
  284. package/dist/client/Decorator.d.ts +170 -0
  285. package/dist/client/Decorator.d.ts.map +1 -0
  286. package/dist/client/Decorator.js +227 -0
  287. package/dist/client/Decorator.js.map +1 -0
  288. package/dist/client/Key.d.ts +85 -0
  289. package/dist/client/Key.d.ts.map +1 -0
  290. package/dist/client/Key.js +83 -0
  291. package/dist/client/Key.js.map +1 -0
  292. package/dist/client/Pending.d.ts +39 -0
  293. package/dist/client/Pending.d.ts.map +1 -0
  294. package/dist/client/Pending.js +12 -0
  295. package/dist/client/Pending.js.map +1 -0
  296. package/dist/client/Permissions.d.ts +34 -0
  297. package/dist/client/Permissions.d.ts.map +1 -0
  298. package/dist/client/Permissions.js +16 -0
  299. package/dist/client/Permissions.js.map +1 -0
  300. package/dist/client/Provider.d.ts +16 -0
  301. package/dist/client/Provider.d.ts.map +1 -0
  302. package/dist/client/Provider.js +12 -0
  303. package/dist/client/Provider.js.map +1 -0
  304. package/dist/client/Step.d.ts +21 -0
  305. package/dist/client/Step.d.ts.map +1 -0
  306. package/dist/client/Step.js +16 -0
  307. package/dist/client/Step.js.map +1 -0
  308. package/dist/client/Storage.d.ts +27 -0
  309. package/dist/client/Storage.d.ts.map +1 -0
  310. package/dist/client/Storage.js +16 -0
  311. package/dist/client/Storage.js.map +1 -0
  312. package/dist/client/TempoAccount.d.ts +40 -0
  313. package/dist/client/TempoAccount.d.ts.map +1 -0
  314. package/dist/client/TempoAccount.js +16 -0
  315. package/dist/client/TempoAccount.js.map +1 -0
  316. package/dist/client/Tokens.d.ts +25 -0
  317. package/dist/client/Tokens.d.ts.map +1 -0
  318. package/dist/client/Tokens.js +12 -0
  319. package/dist/client/Tokens.js.map +1 -0
  320. package/dist/client/User.d.ts +21 -0
  321. package/dist/client/User.d.ts.map +1 -0
  322. package/dist/client/User.js +12 -0
  323. package/dist/client/User.js.map +1 -0
  324. package/dist/client/actions/account.d.ts +25 -0
  325. package/dist/client/actions/account.d.ts.map +1 -0
  326. package/dist/client/actions/account.js +34 -0
  327. package/dist/client/actions/account.js.map +1 -0
  328. package/dist/client/actions/device.d.ts +53 -0
  329. package/dist/client/actions/device.d.ts.map +1 -0
  330. package/dist/client/actions/device.js +79 -0
  331. package/dist/client/actions/device.js.map +1 -0
  332. package/dist/client/actions/email.d.ts +84 -0
  333. package/dist/client/actions/email.d.ts.map +1 -0
  334. package/dist/client/actions/email.js +63 -0
  335. package/dist/client/actions/email.js.map +1 -0
  336. package/dist/client/actions/oauth.d.ts +115 -0
  337. package/dist/client/actions/oauth.d.ts.map +1 -0
  338. package/dist/client/actions/oauth.js +105 -0
  339. package/dist/client/actions/oauth.js.map +1 -0
  340. package/dist/client/actions/passkey.d.ts +88 -0
  341. package/dist/client/actions/passkey.d.ts.map +1 -0
  342. package/dist/client/actions/passkey.js +60 -0
  343. package/dist/client/actions/passkey.js.map +1 -0
  344. package/dist/client/actions/provider.d.ts +49 -0
  345. package/dist/client/actions/provider.d.ts.map +1 -0
  346. package/dist/client/actions/provider.js +34 -0
  347. package/dist/client/actions/provider.js.map +1 -0
  348. package/dist/client/actions/realm.d.ts +24 -0
  349. package/dist/client/actions/realm.d.ts.map +1 -0
  350. package/dist/client/actions/realm.js +15 -0
  351. package/dist/client/actions/realm.js.map +1 -0
  352. package/dist/client/actions/redirect.d.ts +153 -0
  353. package/dist/client/actions/redirect.d.ts.map +1 -0
  354. package/dist/client/actions/redirect.js +236 -0
  355. package/dist/client/actions/redirect.js.map +1 -0
  356. package/dist/client/internal/accessKey.d.ts +21 -0
  357. package/dist/client/internal/accessKey.d.ts.map +1 -0
  358. package/dist/client/internal/accessKey.js +38 -0
  359. package/dist/client/internal/accessKey.js.map +1 -0
  360. package/dist/client/internal/account.d.ts +14 -0
  361. package/dist/client/internal/account.d.ts.map +1 -0
  362. package/dist/client/internal/account.js +3 -0
  363. package/dist/client/internal/account.js.map +1 -0
  364. package/dist/client/internal/api.d.ts +106 -0
  365. package/dist/client/internal/api.d.ts.map +1 -0
  366. package/dist/client/internal/api.js +129 -0
  367. package/dist/client/internal/api.js.map +1 -0
  368. package/dist/client/internal/headless.d.ts +33 -0
  369. package/dist/client/internal/headless.d.ts.map +1 -0
  370. package/dist/client/internal/headless.js +46 -0
  371. package/dist/client/internal/headless.js.map +1 -0
  372. package/dist/client/internal/indexedDb.d.ts +9 -0
  373. package/dist/client/internal/indexedDb.d.ts.map +1 -0
  374. package/dist/client/internal/indexedDb.js +32 -0
  375. package/dist/client/internal/indexedDb.js.map +1 -0
  376. package/dist/client/internal/request.d.ts +58 -0
  377. package/dist/client/internal/request.d.ts.map +1 -0
  378. package/dist/client/internal/request.js +45 -0
  379. package/dist/client/internal/request.js.map +1 -0
  380. package/dist/client/internal/store.d.ts +12 -0
  381. package/dist/client/internal/store.d.ts.map +1 -0
  382. package/dist/client/internal/store.js +15 -0
  383. package/dist/client/internal/store.js.map +1 -0
  384. package/dist/client.d.ts +20 -0
  385. package/dist/client.d.ts.map +1 -0
  386. package/dist/client.js +20 -0
  387. package/dist/client.js.map +1 -0
  388. package/dist/index.d.ts +7 -0
  389. package/dist/index.d.ts.map +1 -0
  390. package/dist/index.js +7 -0
  391. package/dist/index.js.map +1 -0
  392. package/dist/internal/Apps.d.ts +3051 -0
  393. package/dist/internal/Apps.d.ts.map +1 -0
  394. package/dist/internal/Apps.js +472 -0
  395. package/dist/internal/Apps.js.map +1 -0
  396. package/dist/internal/Auth.d.ts +4058 -0
  397. package/dist/internal/Auth.d.ts.map +1 -0
  398. package/dist/internal/Auth.js +137 -0
  399. package/dist/internal/Auth.js.map +1 -0
  400. package/dist/internal/Authorize.d.ts +532 -0
  401. package/dist/internal/Authorize.d.ts.map +1 -0
  402. package/dist/internal/Authorize.js +326 -0
  403. package/dist/internal/Authorize.js.map +1 -0
  404. package/dist/internal/Device.d.ts +371 -0
  405. package/dist/internal/Device.d.ts.map +1 -0
  406. package/dist/internal/Device.js +271 -0
  407. package/dist/internal/Device.js.map +1 -0
  408. package/dist/internal/Env.d.ts +57 -0
  409. package/dist/internal/Env.d.ts.map +1 -0
  410. package/dist/internal/Env.js +2 -0
  411. package/dist/internal/Env.js.map +1 -0
  412. package/dist/internal/ErrorResponse.d.ts +609 -0
  413. package/dist/internal/ErrorResponse.d.ts.map +1 -0
  414. package/dist/internal/ErrorResponse.js +679 -0
  415. package/dist/internal/ErrorResponse.js.map +1 -0
  416. package/dist/internal/Id.d.ts +10 -0
  417. package/dist/internal/Id.d.ts.map +1 -0
  418. package/dist/internal/Id.js +34 -0
  419. package/dist/internal/Id.js.map +1 -0
  420. package/dist/internal/KeyAuthorization.d.ts +1456 -0
  421. package/dist/internal/KeyAuthorization.d.ts.map +1 -0
  422. package/dist/internal/KeyAuthorization.js +1030 -0
  423. package/dist/internal/KeyAuthorization.js.map +1 -0
  424. package/dist/internal/Limits.d.ts +65 -0
  425. package/dist/internal/Limits.d.ts.map +1 -0
  426. package/dist/internal/Limits.js +35 -0
  427. package/dist/internal/Limits.js.map +1 -0
  428. package/dist/internal/Log.d.ts +49 -0
  429. package/dist/internal/Log.d.ts.map +1 -0
  430. package/dist/internal/Log.js +101 -0
  431. package/dist/internal/Log.js.map +1 -0
  432. package/dist/internal/LogLine.d.ts +33 -0
  433. package/dist/internal/LogLine.d.ts.map +1 -0
  434. package/dist/internal/LogLine.js +56 -0
  435. package/dist/internal/LogLine.js.map +1 -0
  436. package/dist/internal/Migrations.d.ts +19 -0
  437. package/dist/internal/Migrations.d.ts.map +1 -0
  438. package/dist/internal/Migrations.js +57 -0
  439. package/dist/internal/Migrations.js.map +1 -0
  440. package/dist/internal/Owner.d.ts +146 -0
  441. package/dist/internal/Owner.d.ts.map +1 -0
  442. package/dist/internal/Owner.js +65 -0
  443. package/dist/internal/Owner.js.map +1 -0
  444. package/dist/internal/Passkey.d.ts +528 -0
  445. package/dist/internal/Passkey.d.ts.map +1 -0
  446. package/dist/internal/Passkey.js +658 -0
  447. package/dist/internal/Passkey.js.map +1 -0
  448. package/dist/internal/PendingKey.d.ts +49 -0
  449. package/dist/internal/PendingKey.d.ts.map +1 -0
  450. package/dist/internal/PendingKey.js +58 -0
  451. package/dist/internal/PendingKey.js.map +1 -0
  452. package/dist/internal/Privy.d.ts +105 -0
  453. package/dist/internal/Privy.d.ts.map +1 -0
  454. package/dist/internal/Privy.js +224 -0
  455. package/dist/internal/Privy.js.map +1 -0
  456. package/dist/internal/RateLimit.d.ts +190 -0
  457. package/dist/internal/RateLimit.d.ts.map +1 -0
  458. package/dist/internal/RateLimit.js +148 -0
  459. package/dist/internal/RateLimit.js.map +1 -0
  460. package/dist/internal/Realm.d.ts +281 -0
  461. package/dist/internal/Realm.d.ts.map +1 -0
  462. package/dist/internal/Realm.js +477 -0
  463. package/dist/internal/Realm.js.map +1 -0
  464. package/dist/internal/RequestId.d.ts +16 -0
  465. package/dist/internal/RequestId.d.ts.map +1 -0
  466. package/dist/internal/RequestId.js +78 -0
  467. package/dist/internal/RequestId.js.map +1 -0
  468. package/dist/internal/SigningKey.d.ts +115 -0
  469. package/dist/internal/SigningKey.d.ts.map +1 -0
  470. package/dist/internal/SigningKey.js +197 -0
  471. package/dist/internal/SigningKey.js.map +1 -0
  472. package/dist/internal/TestInbox.d.ts +42 -0
  473. package/dist/internal/TestInbox.d.ts.map +1 -0
  474. package/dist/internal/TestInbox.js +20 -0
  475. package/dist/internal/TestInbox.js.map +1 -0
  476. package/dist/internal/Timing.d.ts +51 -0
  477. package/dist/internal/Timing.d.ts.map +1 -0
  478. package/dist/internal/Timing.js +103 -0
  479. package/dist/internal/Timing.js.map +1 -0
  480. package/dist/internal/Validation.d.ts +52 -0
  481. package/dist/internal/Validation.d.ts.map +1 -0
  482. package/dist/internal/Validation.js +22 -0
  483. package/dist/internal/Validation.js.map +1 -0
  484. package/dist/internal/Wallet.d.ts +37 -0
  485. package/dist/internal/Wallet.d.ts.map +1 -0
  486. package/dist/internal/Wallet.js +43 -0
  487. package/dist/internal/Wallet.js.map +1 -0
  488. package/dist/worker.d.ts +12 -0
  489. package/dist/worker.d.ts.map +1 -0
  490. package/dist/worker.js +12 -0
  491. package/dist/worker.js.map +1 -0
  492. package/package.json +82 -0
  493. package/src/Api.ts +151 -0
  494. package/src/App.ts +56 -0
  495. package/src/api/account.ts +311 -0
  496. package/src/api/authenticate.ts +1290 -0
  497. package/src/api/authorize.ts +1030 -0
  498. package/src/api/device.ts +874 -0
  499. package/src/api/health.ts +72 -0
  500. package/src/api/lib/AccountStep.ts +335 -0
  501. package/src/api/lib/Auth.ts +134 -0
  502. package/src/api/lib/Consent.ts +339 -0
  503. package/src/api/lib/Cors.ts +107 -0
  504. package/src/api/lib/Database.ts +10 -0
  505. package/src/api/lib/DeviceRequest.ts +265 -0
  506. package/src/api/lib/FirstAccount.ts +90 -0
  507. package/src/api/lib/KeySigner.ts +393 -0
  508. package/src/api/lib/PasskeyLink.ts +162 -0
  509. package/src/api/lib/Session.ts +34 -0
  510. package/src/api/lib/SignInConsent.ts +316 -0
  511. package/src/api/oauth.ts +1282 -0
  512. package/src/api/provider.ts +441 -0
  513. package/src/app/components/Button.tsx +128 -0
  514. package/src/app/components/CodeInput.tsx +186 -0
  515. package/src/app/components/ErrorMessage.tsx +66 -0
  516. package/src/app/components/Grant.tsx +323 -0
  517. package/src/app/components/Input.tsx +48 -0
  518. package/src/app/components/Tooltip.tsx +45 -0
  519. package/src/app/components/icons/BRLA.png +0 -0
  520. package/src/app/components/icons/BRZ.svg +1 -0
  521. package/src/app/components/icons/CHFAU.png +0 -0
  522. package/src/app/components/icons/DLUSD.png +0 -0
  523. package/src/app/components/icons/EURAU.svg +1 -0
  524. package/src/app/components/icons/EURC.e.svg +1 -0
  525. package/src/app/components/icons/GBPA.svg +4 -0
  526. package/src/app/components/icons/GUSD.svg +1 -0
  527. package/src/app/components/icons/MACH.svg +4 -0
  528. package/src/app/components/icons/OUSD.svg +5 -0
  529. package/src/app/components/icons/PRIME.svg +14 -0
  530. package/src/app/components/icons/SBC.svg +1 -0
  531. package/src/app/components/icons/SEKAU.svg +5 -0
  532. package/src/app/components/icons/USD1.svg +30 -0
  533. package/src/app/components/icons/USDB.svg +11 -0
  534. package/src/app/components/icons/USDC.e.svg +1 -0
  535. package/src/app/components/icons/USDT0.svg +1 -0
  536. package/src/app/components/icons/USDY.svg +16 -0
  537. package/src/app/components/icons/USDe.svg +1 -0
  538. package/src/app/components/icons/YLDS.svg +3 -0
  539. package/src/app/components/icons/alphaUSD.svg +1 -0
  540. package/src/app/components/icons/betaUSD.svg +1 -0
  541. package/src/app/components/icons/cUSD.svg +1 -0
  542. package/src/app/components/icons/cbBTC.svg +1 -0
  543. package/src/app/components/icons/frxUSD.svg +1 -0
  544. package/src/app/components/icons/goUSD.svg +5 -0
  545. package/src/app/components/icons/iUSD.svg +1 -0
  546. package/src/app/components/icons/pathUSD.svg +25 -0
  547. package/src/app/components/icons/rUSD.svg +1 -0
  548. package/src/app/components/icons/reUSD.svg +1 -0
  549. package/src/app/components/icons/sUSDe.svg +1 -0
  550. package/src/app/components/icons/siUSD.svg +1 -0
  551. package/src/app/components/icons/stcUSD.svg +1 -0
  552. package/src/app/components/icons/syrupUSDC.svg +5 -0
  553. package/src/app/components/icons/thetaUSD.svg +1 -0
  554. package/src/app/components/icons/wYLDS.svg +10 -0
  555. package/src/app/components/icons/wsrUSD.svg +1 -0
  556. package/src/app/components/logos/OUSD.dark.svg +17 -0
  557. package/src/app/components/logos/OUSD.light.svg +17 -0
  558. package/src/app/crons/cleanup.ts +42 -0
  559. package/src/app/db/auth.ts +416 -0
  560. package/src/app/db/migrations/0000_better_auth.sql +53 -0
  561. package/src/app/db/migrations/0001_oauth_provider.sql +162 -0
  562. package/src/app/db/migrations/0002_device_code.sql +17 -0
  563. package/src/app/db/migrations/0003_realms.sql +27 -0
  564. package/src/app/db/migrations/0004_default_realm.sql +2 -0
  565. package/src/app/db/migrations/0005_passkeys.sql +30 -0
  566. package/src/app/db/migrations/0006_first_accounts.sql +9 -0
  567. package/src/app/db/migrations/0007_pending_keys.sql +13 -0
  568. package/src/app/db/migrations/0008_secp256k1_owners.sql +18 -0
  569. package/src/app/db/migrations/0009_device_requests.sql +8 -0
  570. package/src/app/db/migrations/0010_device_keys.sql +4 -0
  571. package/src/app/db/migrations/meta/0000_snapshot.json +362 -0
  572. package/src/app/db/migrations/meta/0001_snapshot.json +1487 -0
  573. package/src/app/db/migrations/meta/0002_snapshot.json +1603 -0
  574. package/src/app/db/migrations/meta/0003_snapshot.json +1760 -0
  575. package/src/app/db/migrations/meta/0004_snapshot.json +1760 -0
  576. package/src/app/db/migrations/meta/0005_snapshot.json +1911 -0
  577. package/src/app/db/migrations/meta/0006_snapshot.json +1967 -0
  578. package/src/app/db/migrations/meta/0007_snapshot.json +2047 -0
  579. package/src/app/db/migrations/meta/0008_snapshot.json +2157 -0
  580. package/src/app/db/migrations/meta/0009_snapshot.json +2207 -0
  581. package/src/app/db/migrations/meta/0010_snapshot.json +2231 -0
  582. package/src/app/db/migrations/meta/_journal.json +83 -0
  583. package/src/app/db/schema.ts +218 -0
  584. package/src/app/env.ts +49 -0
  585. package/src/app/lib/Client.ts +82 -0
  586. package/src/app/lib/Loader.ts +24 -0
  587. package/src/app/package.json +8 -0
  588. package/src/app/routeTree.gen.ts +198 -0
  589. package/src/app/router.tsx +48 -0
  590. package/src/app/routes/[_].flows.tsx +3001 -0
  591. package/src/app/routes/__root.tsx +91 -0
  592. package/src/app/routes/authorize.tsx +197 -0
  593. package/src/app/routes/choose-account.tsx +111 -0
  594. package/src/app/routes/deposit.tsx +105 -0
  595. package/src/app/routes/device.tsx +227 -0
  596. package/src/app/routes/index.tsx +115 -0
  597. package/src/app/routes/login.tsx +506 -0
  598. package/src/app/screens/Account.tsx +347 -0
  599. package/src/app/screens/Approval.tsx +276 -0
  600. package/src/app/screens/ChooseAccount.tsx +240 -0
  601. package/src/app/screens/Deposit.tsx +762 -0
  602. package/src/app/screens/DeviceApproval.tsx +480 -0
  603. package/src/app/screens/SignIn.tsx +362 -0
  604. package/src/app/screens/chains/base.svg +3 -0
  605. package/src/app/screens/chains/ethereum.svg +11 -0
  606. package/src/app/screens/chains/solana.svg +4 -0
  607. package/src/app/screens/chains/tempo.svg +4 -0
  608. package/src/app/server.ts +204 -0
  609. package/src/app/vite.config.ts +95 -0
  610. package/src/app/void.config.ts +29 -0
  611. package/src/app/zyzz.config.ts +274 -0
  612. package/src/cli/Admin.ts +73 -0
  613. package/src/cli/Apps.ts +29 -0
  614. package/src/cli/Cli.ts +42 -0
  615. package/src/cli/Project.ts +117 -0
  616. package/src/cli/Realms.ts +50 -0
  617. package/src/cli/Session.ts +239 -0
  618. package/src/cli/User.ts +45 -0
  619. package/src/cli/V1.ts +57 -0
  620. package/src/cli/bin.ts +44 -0
  621. package/src/cli/commands/admin/apps/create.ts +101 -0
  622. package/src/cli/commands/admin/apps/delete.ts +38 -0
  623. package/src/cli/commands/admin/apps/index.ts +15 -0
  624. package/src/cli/commands/admin/apps/list.ts +25 -0
  625. package/src/cli/commands/admin/apps/rotate-secret.ts +47 -0
  626. package/src/cli/commands/admin/apps/update.ts +86 -0
  627. package/src/cli/commands/admin/index.ts +14 -0
  628. package/src/cli/commands/admin/migrate.ts +16 -0
  629. package/src/cli/commands/admin/realms/add.ts +40 -0
  630. package/src/cli/commands/admin/realms/index.ts +14 -0
  631. package/src/cli/commands/admin/realms/list.ts +38 -0
  632. package/src/cli/commands/admin/realms/passkeys/index.ts +15 -0
  633. package/src/cli/commands/admin/realms/passkeys/set.ts +44 -0
  634. package/src/cli/commands/admin/realms/privy/index.ts +14 -0
  635. package/src/cli/commands/admin/realms/privy/set.ts +69 -0
  636. package/src/cli/commands/admin/realms/remove.ts +33 -0
  637. package/src/cli/commands/admin/realms/secp256k1/disable.ts +40 -0
  638. package/src/cli/commands/admin/realms/secp256k1/enable.ts +40 -0
  639. package/src/cli/commands/admin/realms/secp256k1/index.ts +19 -0
  640. package/src/cli/commands/admin/realms/set.ts +46 -0
  641. package/src/cli/commands/admin/rotate-key.ts +47 -0
  642. package/src/cli/commands/init.ts +42 -0
  643. package/src/cli/commands/login.ts +32 -0
  644. package/src/cli/commands/logout.ts +19 -0
  645. package/src/cli/commands/whoami.ts +23 -0
  646. package/src/client/Actions.ts +168 -0
  647. package/src/client/Auth.ts +285 -0
  648. package/src/client/Authorization.ts +34 -0
  649. package/src/client/Decorator.ts +410 -0
  650. package/src/client/Key.ts +140 -0
  651. package/src/client/Pending.ts +46 -0
  652. package/src/client/Permissions.ts +39 -0
  653. package/src/client/Provider.ts +18 -0
  654. package/src/client/Step.ts +24 -0
  655. package/src/client/Storage.ts +29 -0
  656. package/src/client/TempoAccount.ts +42 -0
  657. package/src/client/Tokens.ts +27 -0
  658. package/src/client/User.ts +23 -0
  659. package/src/client/actions/account.ts +57 -0
  660. package/src/client/actions/device.ts +151 -0
  661. package/src/client/actions/email.ts +141 -0
  662. package/src/client/actions/oauth.ts +182 -0
  663. package/src/client/actions/passkey.ts +141 -0
  664. package/src/client/actions/provider.ts +70 -0
  665. package/src/client/actions/realm.ts +36 -0
  666. package/src/client/actions/redirect.ts +408 -0
  667. package/src/client/internal/accessKey.ts +54 -0
  668. package/src/client/internal/account.ts +15 -0
  669. package/src/client/internal/api.ts +224 -0
  670. package/src/client/internal/headless.ts +77 -0
  671. package/src/client/internal/indexedDb.ts +44 -0
  672. package/src/client/internal/request.ts +71 -0
  673. package/src/client/internal/store.ts +20 -0
  674. package/src/client.ts +19 -0
  675. package/src/index.ts +6 -0
  676. package/src/internal/Apps.ts +718 -0
  677. package/src/internal/Auth.ts +203 -0
  678. package/src/internal/Authorize.ts +424 -0
  679. package/src/internal/Balance.ts +168 -0
  680. package/src/internal/BodyLimit.ts +36 -0
  681. package/src/internal/Chain.ts +16 -0
  682. package/src/internal/Device.ts +469 -0
  683. package/src/internal/Env.ts +58 -0
  684. package/src/internal/ErrorResponse.ts +854 -0
  685. package/src/internal/Id.ts +41 -0
  686. package/src/internal/KeyAuthorization.ts +1339 -0
  687. package/src/internal/Limits.ts +39 -0
  688. package/src/internal/Log.ts +178 -0
  689. package/src/internal/LogLine.ts +87 -0
  690. package/src/internal/Logout.ts +336 -0
  691. package/src/internal/Migrations.ts +86 -0
  692. package/src/internal/OpenApi.ts +300 -0
  693. package/src/internal/Owner.ts +211 -0
  694. package/src/internal/Passkey.ts +1052 -0
  695. package/src/internal/PendingKey.ts +104 -0
  696. package/src/internal/Privy.ts +402 -0
  697. package/src/internal/Provider.ts +125 -0
  698. package/src/internal/RateLimit.ts +259 -0
  699. package/src/internal/Realm.ts +768 -0
  700. package/src/internal/RequestId.ts +118 -0
  701. package/src/internal/SignInGrant.ts +168 -0
  702. package/src/internal/SigningKey.ts +286 -0
  703. package/src/internal/TempoAccount.ts +342 -0
  704. package/src/internal/TestInbox.ts +51 -0
  705. package/src/internal/Timing.ts +158 -0
  706. package/src/internal/Validation.ts +52 -0
  707. package/src/internal/Wallet.ts +62 -0
  708. package/src/internal/owners/Passkey.ts +72 -0
  709. package/src/internal/owners/Privy.ts +81 -0
  710. package/src/internal/owners/Secp256k1.ts +143 -0
  711. package/src/types/app.d.ts +19 -0
  712. package/src/worker.ts +11 -0
@@ -0,0 +1,718 @@
1
+ /**
2
+ * OAuth apps: the Better Auth plugins that serve them, and the operations of `tempo-id admin apps`
3
+ * on the `oauth_client` table. Better Auth registers clients only for a signed-in owner, so the
4
+ * operations write the rows that it reads, with its client ID format and its secret hash. A client
5
+ * secret is stored only as its hash.
6
+ * @module
7
+ */
8
+ import { isLoopbackHost } from '@better-auth/core/utils/host'
9
+ import { isNativePrivateUseRedirectUri } from '@better-auth/core/utils/redirect-uri'
10
+ import {
11
+ getOAuthProviderState,
12
+ oauthProvider,
13
+ } from '@better-auth/oauth-provider'
14
+ import { generateRandomString } from 'better-auth/crypto'
15
+ import { jwt } from 'better-auth/plugins/jwt'
16
+ import { and, asc, eq, isNull, or } from 'drizzle-orm'
17
+ import { Base64 } from 'ox'
18
+ import * as Schema from '../app/db/schema.js'
19
+ import type * as PendingKey from './PendingKey.js'
20
+ import type * as Realm from './Realm.js'
21
+ import * as SigningKey from './SigningKey.js'
22
+
23
+ /** Another app already has the client ID. */
24
+ export class ExistsError extends Error {
25
+ override readonly name = 'Apps.ExistsError'
26
+
27
+ constructor(options: { clientId: string }) {
28
+ super(
29
+ `App ${options.clientId} already exists. Update it, or choose another client ID.`,
30
+ )
31
+ }
32
+ }
33
+
34
+ /** A name, a redirect URI, or another value of an app is not valid. */
35
+ export class InvalidError extends Error {
36
+ override readonly name = 'Apps.InvalidError'
37
+ }
38
+
39
+ /** No OAuth app has the client ID. */
40
+ export class NotFoundError extends Error {
41
+ override readonly name = 'Apps.NotFoundError'
42
+
43
+ constructor(options: { clientId: string }) {
44
+ super(`Unknown app ${options.clientId}. Name a registered OAuth app.`)
45
+ }
46
+ }
47
+
48
+ /** The app redeems codes with PKCE alone, so it has no client secret to rotate. */
49
+ export class PublicError extends Error {
50
+ override readonly name = 'Apps.PublicError'
51
+
52
+ constructor(options: { clientId: string }) {
53
+ super(
54
+ `App ${options.clientId} has no client secret. Rotate the secret of an app with a backend.`,
55
+ )
56
+ }
57
+ }
58
+
59
+ /** An OAuth app, as `tempo-id admin apps` returns it. */
60
+ export type App = {
61
+ /** The client ID, which the app sends as `client_id`. */
62
+ clientId: string
63
+ /** When the app was created. */
64
+ createdAt: Date | null
65
+ /** Whether the app signs in through the device grant, in place of a redirect, as a CLI does. */
66
+ device: boolean
67
+ /** The display name, which the approval page shows. */
68
+ name: string | null
69
+ /** Every URI that `GET /oauth2/end-session` may return to after it ends the session. */
70
+ postLogoutRedirectUris: readonly string[]
71
+ /** Every URI that the app returns to. */
72
+ redirectUris: readonly string[]
73
+ /** Whether the app holds a client secret, which its backend sends to the token endpoint. */
74
+ secret: boolean
75
+ /** Whether the app holds the `tempo-id:sign` scope, which permits a challenge. */
76
+ sign: boolean
77
+ /** Whether a request without a key skips the approval page. */
78
+ skipConsent: boolean
79
+ /** `web` for a browser app or an app with a backend, and `native` for a mobile app. */
80
+ type: 'native' | 'web'
81
+ }
82
+
83
+ /** The grant type of the device grant (RFC 8628 §3.4). */
84
+ export const deviceGrant = 'urn:ietf:params:oauth:grant-type:device_code'
85
+
86
+ /** The scope that lets an app bind its own challenge into a key authorization. */
87
+ export const signScope = 'tempo-id:sign'
88
+
89
+ /** The scopes that every app may request. */
90
+ const scopes = ['openid', 'profile', 'email', 'offline_access'] as const
91
+
92
+ /**
93
+ * Returns whether `clientSecret` is the client secret of the enabled app with `clientId`. An
94
+ * unknown app, a disabled app, and an app without a client secret return `false`. Better Auth still
95
+ * authenticates the request itself, so a match only decides which app a rate limit counts.
96
+ */
97
+ export async function authenticate(
98
+ db: Realm.Database,
99
+ options: authenticate.Options,
100
+ ) {
101
+ const [row] = await db
102
+ .select({
103
+ clientSecret: Schema.oauthClient.clientSecret,
104
+ disabled: Schema.oauthClient.disabled,
105
+ })
106
+ .from(Schema.oauthClient)
107
+ .where(eq(Schema.oauthClient.clientId, options.clientId))
108
+ .limit(1)
109
+ if (!row?.clientSecret || row.disabled) return false
110
+ return equal(await hashSecret(options.clientSecret), row.clientSecret)
111
+ }
112
+
113
+ export declare namespace authenticate {
114
+ type Options = {
115
+ /** The client ID that the request names. */
116
+ clientId: string
117
+ /** The client secret that the request sends. */
118
+ clientSecret: string
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Registers an app, and returns it with its client secret. The secret appears only in this result,
124
+ * since the row holds only its hash. A `clientId` or `clientSecret` keeps the values of an app that
125
+ * another deployment registered.
126
+ *
127
+ * Throws `InvalidError` for an invalid name, redirect URI, client ID, or client secret, or a device
128
+ * app with a secret, and `ExistsError` when another app has the client ID.
129
+ */
130
+ export async function create(db: Realm.Database, options: create.Options) {
131
+ const type = options.type ?? 'web'
132
+ const name = parseName(options.name)
133
+ const postLogoutRedirectUris = parsePostLogoutRedirectUris(
134
+ options.postLogoutRedirectUris ?? [],
135
+ { type },
136
+ )
137
+ const device = options.device ?? false
138
+ // A CLI cannot keep a secret, and the device grant's poll sends none, so a device app is public.
139
+ if (device && (options.secret || options.clientSecret !== undefined))
140
+ throw new InvalidError(
141
+ 'Invalid app: a device app has no client secret, since a CLI cannot keep one. Leave out the secret.',
142
+ )
143
+ // A device app redirects nowhere, so it needs no redirect URI.
144
+ const redirectUris =
145
+ device && (options.redirectUris ?? []).length === 0
146
+ ? []
147
+ : parseRedirectUris(options.redirectUris ?? [], { type })
148
+ const clientId =
149
+ options.clientId === undefined
150
+ ? // Better Auth's format: 32 random letters.
151
+ generateRandomString(32, 'a-z', 'A-Z')
152
+ : parseClientId(options.clientId)
153
+ const clientSecret = (() => {
154
+ if (options.clientSecret !== undefined)
155
+ return parseClientSecret(options.clientSecret)
156
+ return options.secret ? secret() : undefined
157
+ })()
158
+
159
+ const now = new Date()
160
+ const [row] = await db
161
+ .insert(Schema.oauthClient)
162
+ .values({
163
+ applicationType: type,
164
+ clientId,
165
+ clientSecret: clientSecret ? await hashSecret(clientSecret) : null,
166
+ createdAt: now,
167
+ // Lets the app end the session at `GET /oauth2/end-session`, and puts `sid` in its ID tokens.
168
+ enableEndSession: true,
169
+ // A device app has no authorization code grant, so `/oauth2/authorize` refuses it.
170
+ grantTypes: device
171
+ ? [deviceGrant, 'refresh_token']
172
+ : ['authorization_code', 'refresh_token'],
173
+ id: crypto.randomUUID(),
174
+ name,
175
+ postLogoutRedirectUris: [...postLogoutRedirectUris],
176
+ redirectUris: [...redirectUris],
177
+ responseTypes: ['code'],
178
+ scopes: scopesOf({ sign: options.sign ?? false }),
179
+ skipConsent: options.skipConsent ?? false,
180
+ // The client package sends the secret in the form body.
181
+ tokenEndpointAuthMethod: clientSecret ? 'client_secret_post' : 'none',
182
+ updatedAt: now,
183
+ })
184
+ .onConflictDoNothing({ target: Schema.oauthClient.clientId })
185
+ .returning()
186
+ if (!row) throw new ExistsError({ clientId })
187
+
188
+ return { app: toApp(row), ...(clientSecret ? { clientSecret } : {}) }
189
+ }
190
+
191
+ export declare namespace create {
192
+ type Options = {
193
+ /**
194
+ * The client ID, such as the one that another deployment issued. Defaults to 32 random letters,
195
+ * as Better Auth issues.
196
+ */
197
+ clientId?: string | undefined
198
+ /**
199
+ * The client secret, such as the one that another deployment issued. It gives the app a secret
200
+ * without `secret`. Defaults to a new secret when `secret` is set.
201
+ */
202
+ clientSecret?: string | undefined
203
+ /**
204
+ * Whether the app signs in through the device grant, in place of a redirect, as a CLI does.
205
+ * Defaults to `false`.
206
+ */
207
+ device?: boolean | undefined
208
+ /** The display name, which the approval page shows. */
209
+ name: string
210
+ /** Every URI that `GET /oauth2/end-session` may return to. Defaults to none. */
211
+ postLogoutRedirectUris?: readonly string[] | undefined
212
+ /** Every URI that the app returns to, in each environment. A device app may have none. */
213
+ redirectUris?: readonly string[] | undefined
214
+ /** Whether the app receives a client secret, for its backend. Defaults to `false`. */
215
+ secret?: boolean | undefined
216
+ /** Whether the app holds the `tempo-id:sign` scope. Defaults to `false`. */
217
+ sign?: boolean | undefined
218
+ /** Whether a request without a key skips the approval page. Defaults to `false`. */
219
+ skipConsent?: boolean | undefined
220
+ /** The application type. Defaults to `web`. */
221
+ type?: App['type'] | undefined
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Returns whether `origin` is the origin of a redirect URI of an enabled first-party app, one that
227
+ * skips consent. Pages on such an origin call the API with the session cookie. A disabled app,
228
+ * which Better Auth refuses, gives no origin. The registration rules keep production redirect URIs
229
+ * on `https`, so the check filters no scheme.
230
+ */
231
+ export async function firstPartyOrigin(
232
+ db: Realm.Database,
233
+ options: firstPartyOrigin.Options,
234
+ ) {
235
+ const rows = await db
236
+ .select({ redirectUris: Schema.oauthClient.redirectUris })
237
+ .from(Schema.oauthClient)
238
+ .where(
239
+ and(
240
+ eq(Schema.oauthClient.skipConsent, true),
241
+ or(
242
+ isNull(Schema.oauthClient.disabled),
243
+ eq(Schema.oauthClient.disabled, false),
244
+ ),
245
+ ),
246
+ )
247
+ return rows.some((row) =>
248
+ row.redirectUris.some((uri) => {
249
+ const url = URL.parse(uri)
250
+ return (
251
+ (url?.protocol === 'https:' || url?.protocol === 'http:') &&
252
+ url.origin === options.origin
253
+ )
254
+ }),
255
+ )
256
+ }
257
+
258
+ export declare namespace firstPartyOrigin {
259
+ type Options = {
260
+ /** The request's `Origin`. */
261
+ origin: string
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Returns the app with `clientId`. Throws `NotFoundError` when no app has it, or with `enabled`,
267
+ * when the app is disabled.
268
+ */
269
+ export async function get(db: Realm.Database, options: get.Options) {
270
+ const row = await find(db, options)
271
+ if (options.enabled && row.disabled)
272
+ throw new NotFoundError({ clientId: options.clientId })
273
+ return toApp(row)
274
+ }
275
+
276
+ export declare namespace get {
277
+ type Options = {
278
+ /** The app's client ID. */
279
+ clientId: string
280
+ /** Whether a disabled app counts as no app. Defaults to `false`. */
281
+ enabled?: boolean | undefined
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Returns the SHA-256 hash of a client secret, as base64url without padding, which the row holds.
287
+ * Better Auth verifies a client secret against it.
288
+ */
289
+ export async function hashSecret(secret: string) {
290
+ const digest = await crypto.subtle.digest(
291
+ 'SHA-256',
292
+ new TextEncoder().encode(secret),
293
+ )
294
+ return Base64.fromBytes(new Uint8Array(digest), { pad: false, url: true })
295
+ }
296
+
297
+ /**
298
+ * Compares two hashes from `hashSecret` in constant time. Node's `crypto.subtle` has no
299
+ * `timingSafeEqual`, and the CLI runs this module in Node, so the loop reads every byte of both.
300
+ */
301
+ function equal(a: string, b: string) {
302
+ const left = Base64.toBytes(a)
303
+ const right = Base64.toBytes(b)
304
+ if (left.length !== right.length) return false
305
+ let difference = 0
306
+ for (let index = 0; index < left.length; index++)
307
+ difference |= left[index]! ^ right[index]!
308
+ return difference === 0
309
+ }
310
+
311
+ /** Returns every app, oldest first. */
312
+ export async function list(db: Realm.Database): Promise<readonly App[]> {
313
+ const rows = await db
314
+ .select()
315
+ .from(Schema.oauthClient)
316
+ .orderBy(
317
+ asc(Schema.oauthClient.createdAt),
318
+ asc(Schema.oauthClient.clientId),
319
+ )
320
+ return rows.map(toApp)
321
+ }
322
+
323
+ /**
324
+ * Returns the Better Auth plugins that serve OAuth apps: the JWT plugin, which signs tokens with
325
+ * RS256, and the OAuth provider. `baseURL` is Tempo ID's origin, which is `iss` and the one resource.
326
+ */
327
+ export function plugins(options: plugins.Options) {
328
+ const { accountStep, baseURL, pendingKey } = options
329
+ return [
330
+ // `iss` is the configured origin, never the request's host.
331
+ jwt({
332
+ adapter: SigningKey.adapter,
333
+ jwks: SigningKey.jwks,
334
+ jwt: { issuer: baseURL },
335
+ }),
336
+ oauthProvider({
337
+ allowDynamicClientRegistration: false,
338
+ consentPage: '/authorize',
339
+ // Apps read the user's address from the ID token, so a grant of `email` puts it there as well
340
+ // as in userinfo, as OIDC Core §5.4 allows.
341
+ customIdTokenClaims: (info) =>
342
+ info.scopes.includes('email')
343
+ ? {
344
+ email: info.user.email,
345
+ email_verified: info.user.emailVerified,
346
+ }
347
+ : {},
348
+ // Every app may request the one resource.
349
+ enforcePerClientResources: false,
350
+ loginPage: '/login',
351
+ // The account step runs after sign-in and before consent, and `oauth2Continue` resumes the
352
+ // authorization with `postLogin`, which checks again.
353
+ ...(accountStep
354
+ ? {
355
+ postLogin: {
356
+ consentReferenceId: () => undefined,
357
+ page: '/choose-account',
358
+ shouldRedirect: async (context: {
359
+ headers: Headers
360
+ session: { id: string }
361
+ user: { id: string }
362
+ }) => {
363
+ // The authorization stores its query before it checks, so the hook reads the app.
364
+ const query = (await getOAuthProviderState())?.query
365
+ const clientId = query
366
+ ? new URLSearchParams(query).get('client_id')
367
+ : null
368
+ if (!clientId) return false
369
+ return await accountStep({
370
+ clientId,
371
+ headers: context.headers,
372
+ sessionId: context.session.id,
373
+ userId: context.user.id,
374
+ })
375
+ },
376
+ },
377
+ }
378
+ : {}),
379
+ // A code's redemption returns the key that its approval signed, once. Better Auth calls this
380
+ // after it checks the verifier against the code's challenge.
381
+ ...(pendingKey
382
+ ? {
383
+ customTokenResponseFields: async (info: {
384
+ grantType: string
385
+ user?: { id: string } | null | undefined
386
+ verificationValue?: {
387
+ query: {
388
+ client_id: string
389
+ code_challenge?: string | undefined
390
+ key_authorization?: unknown
391
+ }
392
+ }
393
+ }) => {
394
+ const query = info.verificationValue?.query
395
+ if (
396
+ info.grantType !== 'authorization_code' ||
397
+ !query?.code_challenge ||
398
+ // Only a code whose request carried the key takes it, so a keyless code for a reused
399
+ // challenge leaves it for the keyed one.
400
+ query.key_authorization === undefined ||
401
+ !info.user
402
+ )
403
+ return {}
404
+ const key = await pendingKey({
405
+ clientId: query.client_id,
406
+ codeChallenge: query.code_challenge,
407
+ userId: info.user.id,
408
+ })
409
+ if (!key) return {}
410
+ return {
411
+ account: key.account,
412
+ key_authorization: key.keyAuthorization,
413
+ }
414
+ },
415
+ }
416
+ : {}),
417
+ // Every access token names one audience, so each API verifies tokens for every app the same way.
418
+ resources: [
419
+ { accessTokenTtl: 300, identifier: baseURL, name: 'Tempo ID' },
420
+ ],
421
+ // Better Auth checks a registered app's scopes against its own row, so `tempo-id:sign` stays out
422
+ // of this list. A row without scopes falls back to this list, and never receives the scope.
423
+ scopes: [...scopes],
424
+ // `create` and `rotateSecret` store each secret with the same hash.
425
+ storeClientSecret: { hash: hashSecret },
426
+ }),
427
+ ]
428
+ }
429
+
430
+ export declare namespace plugins {
431
+ type Options = {
432
+ /**
433
+ * Returns whether the authorization of the app with `clientId` needs the account step, which
434
+ * the `/choose-account` page shows. Absent, no authorization shows it.
435
+ */
436
+ accountStep?:
437
+ | ((options: {
438
+ clientId: string
439
+ headers: Headers
440
+ sessionId: string
441
+ userId: string
442
+ }) => Promise<boolean>)
443
+ | undefined
444
+ /** Tempo ID's origin, such as `https://id.tempo.xyz`. */
445
+ baseURL: string
446
+ /**
447
+ * Takes the key authorization held for the app with `clientId`, the PKCE challenge
448
+ * `codeChallenge`, and the code's user, as `PendingKey.take` does. Absent, a code's redemption returns no key.
449
+ */
450
+ pendingKey?:
451
+ | ((options: {
452
+ clientId: string
453
+ codeChallenge: string
454
+ userId: string
455
+ }) => Promise<PendingKey.PendingKey | undefined>)
456
+ | undefined
457
+ }
458
+ }
459
+
460
+ /**
461
+ * Removes the app with `clientId`, with its consents, tokens, and realms. Throws `NotFoundError`
462
+ * when no app has it.
463
+ */
464
+ export async function remove(db: Realm.Database, options: remove.Options) {
465
+ const removed = await db
466
+ .delete(Schema.oauthClient)
467
+ .where(eq(Schema.oauthClient.clientId, options.clientId))
468
+ .returning()
469
+ const [row] = removed
470
+ if (!row) throw new NotFoundError({ clientId: options.clientId })
471
+ return toApp(row)
472
+ }
473
+
474
+ export declare namespace remove {
475
+ type Options = {
476
+ /** The app's client ID. */
477
+ clientId: string
478
+ }
479
+ }
480
+
481
+ /**
482
+ * Replaces the client secret of the app with `clientId`, and returns the app with the new secret.
483
+ * The earlier secret stops working at once.
484
+ *
485
+ * Throws `NotFoundError` when no app has the client ID, `PublicError` when the app has no client
486
+ * secret, and `InvalidError` for an invalid `clientSecret` or one that matches the current secret.
487
+ */
488
+ export async function rotateSecret(
489
+ db: Realm.Database,
490
+ options: rotateSecret.Options,
491
+ ) {
492
+ const clientSecret =
493
+ options.clientSecret === undefined
494
+ ? secret()
495
+ : parseClientSecret(options.clientSecret)
496
+ const current = await find(db, options)
497
+ if (!current.clientSecret) throw new PublicError(options)
498
+ // A rotation to the same secret would leave a leaked secret working while it reports success.
499
+ if (equal(current.clientSecret, await hashSecret(clientSecret)))
500
+ throw new InvalidError(
501
+ 'Invalid client secret: it matches the current secret. Use a new secret.',
502
+ )
503
+
504
+ const [row] = await db
505
+ .update(Schema.oauthClient)
506
+ .set({
507
+ clientSecret: await hashSecret(clientSecret),
508
+ updatedAt: new Date(),
509
+ })
510
+ .where(eq(Schema.oauthClient.clientId, options.clientId))
511
+ .returning()
512
+ // A concurrent `remove` deleted the app after the read.
513
+ if (!row) throw new NotFoundError(options)
514
+ // The row, not the earlier read, since a concurrent `update` can change the app between them.
515
+ return { app: toApp(row), clientSecret }
516
+ }
517
+
518
+ export declare namespace rotateSecret {
519
+ type Options = {
520
+ /** The app's client ID. */
521
+ clientId: string
522
+ /** The new client secret, such as the one that another deployment issued. Defaults to a new secret. */
523
+ clientSecret?: string | undefined
524
+ }
525
+ }
526
+
527
+ /**
528
+ * Updates the app with `clientId`, and returns it. A value left out stays.
529
+ *
530
+ * Throws `NotFoundError` when no app has the client ID, and `InvalidError` for an invalid name or
531
+ * redirect URI.
532
+ */
533
+ export async function update(db: Realm.Database, options: update.Options) {
534
+ const current = await find(db, options)
535
+ const app = toApp(current)
536
+ const name = options.name === undefined ? undefined : parseName(options.name)
537
+ const postLogoutRedirectUris =
538
+ options.postLogoutRedirectUris === undefined
539
+ ? undefined
540
+ : parsePostLogoutRedirectUris(options.postLogoutRedirectUris, {
541
+ type: app.type,
542
+ })
543
+ const redirectUris =
544
+ options.redirectUris === undefined
545
+ ? undefined
546
+ : parseRedirectUris(options.redirectUris, { type: app.type })
547
+
548
+ const [row] = await db
549
+ .update(Schema.oauthClient)
550
+ .set({
551
+ ...(name === undefined ? {} : { name }),
552
+ ...(postLogoutRedirectUris === undefined
553
+ ? {}
554
+ : { postLogoutRedirectUris: [...postLogoutRedirectUris] }),
555
+ // An app registered before logout existed gains it with its post-logout redirect URIs.
556
+ ...(postLogoutRedirectUris?.length ? { enableEndSession: true } : {}),
557
+ ...(redirectUris === undefined
558
+ ? {}
559
+ : { redirectUris: [...redirectUris] }),
560
+ ...(options.sign === undefined
561
+ ? {}
562
+ : {
563
+ scopes: scopesOf({
564
+ scopes: current.scopes ?? undefined,
565
+ sign: options.sign,
566
+ }),
567
+ }),
568
+ ...(options.skipConsent === undefined
569
+ ? {}
570
+ : { skipConsent: options.skipConsent }),
571
+ updatedAt: new Date(),
572
+ })
573
+ .where(eq(Schema.oauthClient.clientId, options.clientId))
574
+ .returning()
575
+ // A concurrent `remove` deleted the app after the read.
576
+ if (!row) throw new NotFoundError(options)
577
+ return toApp(row)
578
+ }
579
+
580
+ export declare namespace update {
581
+ type Options = {
582
+ /** The app's client ID. */
583
+ clientId: string
584
+ /** The display name. */
585
+ name?: string | undefined
586
+ /** Every URI that `GET /oauth2/end-session` may return to. They replace the earlier ones, and none clears them. */
587
+ postLogoutRedirectUris?: readonly string[] | undefined
588
+ /** Every URI that the app returns to. They replace the earlier ones. */
589
+ redirectUris?: readonly string[] | undefined
590
+ /** Whether the app holds the `tempo-id:sign` scope. */
591
+ sign?: boolean | undefined
592
+ /** Whether a request without a key skips the approval page. */
593
+ skipConsent?: boolean | undefined
594
+ }
595
+ }
596
+
597
+ /** Returns the `oauth_client` row with `clientId`. Throws `NotFoundError` when no app has it. */
598
+ async function find(db: Realm.Database, options: { clientId: string }) {
599
+ const [row] = await db
600
+ .select()
601
+ .from(Schema.oauthClient)
602
+ .where(eq(Schema.oauthClient.clientId, options.clientId))
603
+ if (!row) throw new NotFoundError({ clientId: options.clientId })
604
+ return row
605
+ }
606
+
607
+ /**
608
+ * Returns `clientId`. Throws `InvalidError` unless it holds 8 to 64 letters, digits, `-`, or `_`,
609
+ * which every URL and form carries unescaped.
610
+ */
611
+ function parseClientId(clientId: string) {
612
+ if (!/^[A-Za-z0-9_-]{8,64}$/.test(clientId))
613
+ throw new InvalidError(
614
+ `Invalid client ID: ${clientId}. Use 8 to 64 letters, digits, -, or _.`,
615
+ )
616
+ return clientId
617
+ }
618
+
619
+ /** Returns `clientSecret`. Throws `InvalidError` when it holds fewer than 32 characters. */
620
+ function parseClientSecret(clientSecret: string) {
621
+ // The message leaves the secret out, since errors never hold one.
622
+ if (clientSecret.length < 32)
623
+ throw new InvalidError(
624
+ 'Invalid client secret: fewer than 32 characters. Use a longer secret.',
625
+ )
626
+ return clientSecret
627
+ }
628
+
629
+ /** Returns `name` trimmed. Throws `InvalidError` when it is empty. */
630
+ function parseName(name: string) {
631
+ const trimmed = name.trim()
632
+ if (!trimmed)
633
+ throw new InvalidError('Invalid app: the name is empty. Set a name.')
634
+ return trimmed
635
+ }
636
+
637
+ /**
638
+ * Returns the post-logout redirect URIs `uris`, each named once. They follow the rules of
639
+ * `parseRedirectUris`, and may be empty. Throws `InvalidError` for an invalid URI.
640
+ */
641
+ function parsePostLogoutRedirectUris(
642
+ uris: readonly string[],
643
+ options: { type: App['type'] },
644
+ ): readonly string[] {
645
+ if (uris.length === 0) return []
646
+ return parseRedirectUris(uris, options)
647
+ }
648
+
649
+ /**
650
+ * Returns `uris`, each named once. A web app returns to `https` URIs, and a native app to `https` or
651
+ * a custom scheme, such as `com.example.app:/callback`. Loopback and other `http` redirects are
652
+ * refused, so a CLI uses the device grant. Throws `InvalidError` for an invalid URI.
653
+ */
654
+ function parseRedirectUris(
655
+ uris: readonly string[],
656
+ options: { type: App['type'] },
657
+ ): readonly string[] {
658
+ if (uris.length === 0)
659
+ throw new InvalidError(
660
+ 'Invalid app: no redirect URI. Set at least one redirect URI.',
661
+ )
662
+
663
+ for (const uri of uris) {
664
+ const url = URL.parse(uri)
665
+ const reason = (() => {
666
+ if (!url) return 'is not an absolute URI'
667
+ // RFC 6749 §3.1.2 bars a fragment from a redirect URI.
668
+ if (url.hash || uri.includes('#')) return 'has a fragment'
669
+ if (url.username || url.password) return 'holds credentials'
670
+ if (url.protocol === 'https:')
671
+ return isLoopbackHost(url.hostname) ? 'has a loopback host' : undefined
672
+ if (url.protocol === 'http:') return 'uses http'
673
+ if (options.type === 'web') return 'is not https'
674
+ // Refuses reserved schemes, such as `javascript:` and `file:`, as Better Auth's registration does.
675
+ if (!isNativePrivateUseRedirectUri(url))
676
+ return 'is not a valid custom scheme'
677
+ return undefined
678
+ })()
679
+ if (reason)
680
+ throw new InvalidError(
681
+ `Invalid redirect URI: ${uri} ${reason}. Use an https URI${options.type === 'native' ? ', or a custom scheme such as com.example.app:/callback' : ''}.`,
682
+ )
683
+ }
684
+ return [...new Set(uris)]
685
+ }
686
+
687
+ /**
688
+ * Returns `scopes`, or the scopes that every app may request, with `tempo-id:sign` only when `sign`
689
+ * is set. Every other scope stays as it is.
690
+ */
691
+ function scopesOf(options: {
692
+ scopes?: readonly string[] | undefined
693
+ sign: boolean
694
+ }): string[] {
695
+ const kept = (options.scopes ?? scopes).filter((scope) => scope !== signScope)
696
+ return [...kept, ...(options.sign ? [signScope] : [])]
697
+ }
698
+
699
+ /** Returns a new client secret: 32 random letters, as Better Auth creates by default. */
700
+ function secret() {
701
+ return generateRandomString(32, 'a-z', 'A-Z')
702
+ }
703
+
704
+ /** Returns the app of an `oauth_client` row. */
705
+ function toApp(row: typeof Schema.oauthClient.$inferSelect): App {
706
+ return {
707
+ clientId: row.clientId,
708
+ createdAt: row.createdAt,
709
+ device: (row.grantTypes ?? []).includes(deviceGrant),
710
+ name: row.name,
711
+ postLogoutRedirectUris: row.postLogoutRedirectUris ?? [],
712
+ redirectUris: row.redirectUris,
713
+ secret: Boolean(row.clientSecret),
714
+ sign: (row.scopes ?? []).includes(signScope),
715
+ skipConsent: row.skipConsent ?? false,
716
+ type: row.applicationType === 'native' ? 'native' : 'web',
717
+ }
718
+ }