@gatwech/auth 1.0.0-beta.18

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 (422) hide show
  1. package/README.md +31 -0
  2. package/dist/access-BO2g7QVe.mjs +45 -0
  3. package/dist/access-C6O_osEz.mjs +79 -0
  4. package/dist/access-DT1f6l5k.mjs +51 -0
  5. package/dist/adapter-factory-BZ2Qiqpn.mjs +640 -0
  6. package/dist/adapters/drizzle-adapter/index.d.mts +47 -0
  7. package/dist/adapters/drizzle-adapter/index.mjs +208 -0
  8. package/dist/adapters/index.d.mts +132 -0
  9. package/dist/adapters/index.mjs +18 -0
  10. package/dist/adapters/kysely-adapter/index.d.mts +47 -0
  11. package/dist/adapters/kysely-adapter/index.mjs +11 -0
  12. package/dist/adapters/memory-adapter/index.d.mts +14 -0
  13. package/dist/adapters/memory-adapter/index.mjs +154 -0
  14. package/dist/adapters/mongodb-adapter/index.d.mts +35 -0
  15. package/dist/adapters/mongodb-adapter/index.mjs +315 -0
  16. package/dist/adapters/prisma-adapter/index.d.mts +34 -0
  17. package/dist/adapters/prisma-adapter/index.mjs +159 -0
  18. package/dist/adapters/test.d.mts +81 -0
  19. package/dist/adapters/test.mjs +793 -0
  20. package/dist/admin-Bcq53Nwj.mjs +743 -0
  21. package/dist/admin-DtfO1PLg.d.mts +1689 -0
  22. package/dist/anonymous-CRt1imBW.mjs +107 -0
  23. package/dist/api/index.d.mts +6 -0
  24. package/dist/api/index.mjs +17 -0
  25. package/dist/api-0pR_I-Nx.mjs +3139 -0
  26. package/dist/auth-CBUoBX6o.mjs +233 -0
  27. package/dist/bearer-Djf_awfo.mjs +63 -0
  28. package/dist/bun-sqlite-dialect-CeNvMaZz.mjs +155 -0
  29. package/dist/captcha-BqaMxlKC.mjs +178 -0
  30. package/dist/chunk-BK_LfMhE.mjs +40 -0
  31. package/dist/client/index.d.mts +186 -0
  32. package/dist/client/index.mjs +7 -0
  33. package/dist/client/plugins/index.d.mts +949 -0
  34. package/dist/client/plugins/index.mjs +539 -0
  35. package/dist/client/react/index.d.mts +179 -0
  36. package/dist/client/react/index.mjs +69 -0
  37. package/dist/client-BOX93C3d.d.mts +1250 -0
  38. package/dist/client-CNY0tn9g.d.mts +628 -0
  39. package/dist/client-CygJhqeB.mjs +29 -0
  40. package/dist/client-WiN43tAS.mjs +17 -0
  41. package/dist/client-aExCkfwm.mjs +30 -0
  42. package/dist/cookies/index.d.mts +7 -0
  43. package/dist/cookies/index.mjs +7 -0
  44. package/dist/cookies-cJObLwn1.mjs +597 -0
  45. package/dist/crypto/index.d.mts +44 -0
  46. package/dist/crypto/index.mjs +4 -0
  47. package/dist/crypto-Bb42eMrH.mjs +70 -0
  48. package/dist/custom-session-L3t7ecsd.mjs +67 -0
  49. package/dist/date-Cx2yCiC4.mjs +115 -0
  50. package/dist/db/index.d.mts +7 -0
  51. package/dist/db/index.mjs +15 -0
  52. package/dist/db-BrstmDhc.mjs +1124 -0
  53. package/dist/device-authorization-V4s3h4Mj.mjs +557 -0
  54. package/dist/dialect-CeddeGHf.mjs +72 -0
  55. package/dist/email-otp-BtDHSw14.mjs +592 -0
  56. package/dist/esm-C-QicDNz.mjs +4090 -0
  57. package/dist/generic-oauth-CL5X27ZI.mjs +445 -0
  58. package/dist/get-request-ip-DSjrEpGo.mjs +27 -0
  59. package/dist/get-tables-BQP7YW9c.mjs +249 -0
  60. package/dist/has-permission-BpAr7uCn.mjs +14 -0
  61. package/dist/haveibeenpwned-cMpJvmzI.mjs +43 -0
  62. package/dist/helper-tmxW3BHj.d.mts +21 -0
  63. package/dist/index-34ONrP8l.d.mts +503 -0
  64. package/dist/index-65G5U5DB-DSdjzreF.d.mts +2543 -0
  65. package/dist/index-B-XKqFvY.d.mts +30 -0
  66. package/dist/index-B3n8e37d.d.mts +165 -0
  67. package/dist/index-BBm8nQ9Q.d.mts +42 -0
  68. package/dist/index-BHoQlf7a.d.mts +7699 -0
  69. package/dist/index-BYMI9r_d.d.mts +257 -0
  70. package/dist/index-BqhKCbPH.d.mts +36 -0
  71. package/dist/index-Buhn3hkR.d.mts +433 -0
  72. package/dist/index-C-u1h_WX.d.mts +174 -0
  73. package/dist/index-C7fQuk-V.d.mts +41 -0
  74. package/dist/index-CM-CFWwr.d.mts +1919 -0
  75. package/dist/index-CuFzhoS6.d.mts +359 -0
  76. package/dist/index-Cxi7TbLE.d.mts +11347 -0
  77. package/dist/index-DB7t8whN.d.mts +1 -0
  78. package/dist/index-DKNNV1kb.d.mts +626 -0
  79. package/dist/index-DR0xXno9.d.mts +113 -0
  80. package/dist/index-D_k662QG.d.mts +833 -0
  81. package/dist/index-DaBcikv9.d.mts +118 -0
  82. package/dist/index-DlaMq1nb.d.mts +955 -0
  83. package/dist/index-DoXZYQpq.d.mts +290 -0
  84. package/dist/index-G6V0Z_Mn.d.mts +125 -0
  85. package/dist/index-z0KSvE5i.d.mts +246 -0
  86. package/dist/index-zjjNBRY2.d.mts +95 -0
  87. package/dist/index.d.mts +12 -0
  88. package/dist/index.mjs +33 -0
  89. package/dist/integrations/next-js.d.mts +21 -0
  90. package/dist/integrations/next-js.mjs +62 -0
  91. package/dist/integrations/node.d.mts +15 -0
  92. package/dist/integrations/node.mjs +15 -0
  93. package/dist/integrations/react-start.d.mts +15 -0
  94. package/dist/integrations/react-start.mjs +46 -0
  95. package/dist/json-D0TBLy4q.mjs +24 -0
  96. package/dist/jwt-CmxZAGe2.mjs +94 -0
  97. package/dist/jwt-lHV4QHpD.mjs +387 -0
  98. package/dist/kysely-adapter-DpzYO8Yf.mjs +181 -0
  99. package/dist/magic-link-Bk-ueorR.mjs +176 -0
  100. package/dist/misc-beA1w3XV.mjs +7 -0
  101. package/dist/multi-session-DRrLKrg9.mjs +144 -0
  102. package/dist/node-sqlite-dialect-BcKxBQnm.mjs +155 -0
  103. package/dist/oauth-proxy-D1sWh9B_.mjs +133 -0
  104. package/dist/oauth2/index.d.mts +60 -0
  105. package/dist/oauth2/index.mjs +19 -0
  106. package/dist/one-tap-DMswkTEc.mjs +113 -0
  107. package/dist/organization-BArHO_5v.mjs +3857 -0
  108. package/dist/parser-DcrIEuXE.mjs +73 -0
  109. package/dist/passkey-CcD4CnhM.mjs +558 -0
  110. package/dist/password-sVC4nePO.mjs +25 -0
  111. package/dist/permission-DLYUF3cW.mjs +15 -0
  112. package/dist/phone-number-rHDIlh-2.mjs +485 -0
  113. package/dist/plugin-helper-4L-lzsjZ.mjs +16 -0
  114. package/dist/plugins/access/index.d.mts +3 -0
  115. package/dist/plugins/access/index.mjs +3 -0
  116. package/dist/plugins/admin/access/index.d.mts +116 -0
  117. package/dist/plugins/admin/access/index.mjs +4 -0
  118. package/dist/plugins/admin/index.d.mts +9 -0
  119. package/dist/plugins/admin/index.mjs +22 -0
  120. package/dist/plugins/anonymous/index.d.mts +7 -0
  121. package/dist/plugins/anonymous/index.mjs +18 -0
  122. package/dist/plugins/bearer/index.d.mts +2 -0
  123. package/dist/plugins/bearer/index.mjs +8 -0
  124. package/dist/plugins/captcha/index.d.mts +2 -0
  125. package/dist/plugins/captcha/index.mjs +4 -0
  126. package/dist/plugins/custom-session/index.d.mts +7 -0
  127. package/dist/plugins/custom-session/index.mjs +19 -0
  128. package/dist/plugins/device-authorization/index.d.mts +4 -0
  129. package/dist/plugins/device-authorization/index.mjs +18 -0
  130. package/dist/plugins/email-otp/index.d.mts +3 -0
  131. package/dist/plugins/email-otp/index.mjs +19 -0
  132. package/dist/plugins/generic-oauth/index.d.mts +7 -0
  133. package/dist/plugins/generic-oauth/index.mjs +18 -0
  134. package/dist/plugins/haveibeenpwned/index.d.mts +2 -0
  135. package/dist/plugins/haveibeenpwned/index.mjs +18 -0
  136. package/dist/plugins/index.d.mts +139 -0
  137. package/dist/plugins/index.mjs +47 -0
  138. package/dist/plugins/jwt/index.d.mts +7 -0
  139. package/dist/plugins/jwt/index.mjs +18 -0
  140. package/dist/plugins/magic-link/index.d.mts +2 -0
  141. package/dist/plugins/magic-link/index.mjs +18 -0
  142. package/dist/plugins/multi-session/index.d.mts +3 -0
  143. package/dist/plugins/multi-session/index.mjs +18 -0
  144. package/dist/plugins/oauth-proxy/index.d.mts +2 -0
  145. package/dist/plugins/oauth-proxy/index.mjs +18 -0
  146. package/dist/plugins/one-tap/index.d.mts +2 -0
  147. package/dist/plugins/one-tap/index.mjs +18 -0
  148. package/dist/plugins/one-time-token/index.d.mts +7 -0
  149. package/dist/plugins/one-time-token/index.mjs +47 -0
  150. package/dist/plugins/organization/access/index.d.mts +4 -0
  151. package/dist/plugins/organization/access/index.mjs +4 -0
  152. package/dist/plugins/organization/index.d.mts +9 -0
  153. package/dist/plugins/organization/index.mjs +22 -0
  154. package/dist/plugins/passkey/index.d.mts +7 -0
  155. package/dist/plugins/passkey/index.mjs +18 -0
  156. package/dist/plugins/phone-number/index.d.mts +7 -0
  157. package/dist/plugins/phone-number/index.mjs +18 -0
  158. package/dist/plugins/two-factor/index.d.mts +7 -0
  159. package/dist/plugins/two-factor/index.mjs +20 -0
  160. package/dist/plugins/username/index.d.mts +4 -0
  161. package/dist/plugins/username/index.mjs +18 -0
  162. package/dist/plugins-3jfNste3.mjs +1544 -0
  163. package/dist/plugins-hFZT3hmK.d.mts +14 -0
  164. package/dist/promise-8rrEHRXd.mjs +23154 -0
  165. package/dist/proxy-CL9PZXJA.mjs +441 -0
  166. package/dist/session-Dgp133Yt.mjs +413 -0
  167. package/dist/social-providers/index.d.mts +1 -0
  168. package/dist/social-providers/index.mjs +3 -0
  169. package/dist/src/adapters/adapter-factory/index.d.ts +10 -0
  170. package/dist/src/adapters/adapter-factory/types.d.ts +124 -0
  171. package/dist/src/adapters/create-test-suite.d.ts +97 -0
  172. package/dist/src/adapters/drizzle-adapter/drizzle-adapter.d.ts +43 -0
  173. package/dist/src/adapters/drizzle-adapter/index.d.ts +1 -0
  174. package/dist/src/adapters/drizzle-adapter/test/generate-schema.d.ts +12 -0
  175. package/dist/src/adapters/index.d.ts +21 -0
  176. package/dist/src/adapters/kysely-adapter/bun-sqlite-dialect.d.ts +58 -0
  177. package/dist/src/adapters/kysely-adapter/dialect.d.ts +13 -0
  178. package/dist/src/adapters/kysely-adapter/index.d.ts +3 -0
  179. package/dist/src/adapters/kysely-adapter/kysely-adapter.d.ts +32 -0
  180. package/dist/src/adapters/kysely-adapter/node-sqlite-dialect.d.ts +58 -0
  181. package/dist/src/adapters/kysely-adapter/types.d.ts +1 -0
  182. package/dist/src/adapters/memory-adapter/index.d.ts +1 -0
  183. package/dist/src/adapters/memory-adapter/memory-adapter.d.ts +9 -0
  184. package/dist/src/adapters/mongodb-adapter/index.d.ts +1 -0
  185. package/dist/src/adapters/mongodb-adapter/mongodb-adapter.d.ts +31 -0
  186. package/dist/src/adapters/prisma-adapter/index.d.ts +1 -0
  187. package/dist/src/adapters/prisma-adapter/prisma-adapter.d.ts +32 -0
  188. package/dist/src/adapters/prisma-adapter/test/auth.d.ts +3 -0
  189. package/dist/src/adapters/prisma-adapter/test/generate-auth-config.d.ts +2 -0
  190. package/dist/src/adapters/prisma-adapter/test/generate-prisma-schema.d.ts +3 -0
  191. package/dist/src/adapters/prisma-adapter/test/get-prisma-client.d.ts +7 -0
  192. package/dist/src/adapters/prisma-adapter/test/push-prisma-schema.d.ts +1 -0
  193. package/dist/src/adapters/test-adapter.d.ts +61 -0
  194. package/dist/src/adapters/test.d.ts +78 -0
  195. package/dist/src/adapters/tests/auth-flow.d.ts +22 -0
  196. package/dist/src/adapters/tests/index.d.ts +5 -0
  197. package/dist/src/adapters/tests/normal.d.ts +87 -0
  198. package/dist/src/adapters/tests/number-id.d.ts +17 -0
  199. package/dist/src/adapters/tests/performance.d.ts +24 -0
  200. package/dist/src/adapters/tests/transactions.d.ts +20 -0
  201. package/dist/src/adapters/utils.d.ts +3 -0
  202. package/dist/src/api/index.d.ts +7150 -0
  203. package/dist/src/api/middlewares/index.d.ts +2 -0
  204. package/dist/src/api/middlewares/oauth.d.ts +15 -0
  205. package/dist/src/api/middlewares/origin-check.d.ts +8 -0
  206. package/dist/src/api/rate-limiter/index.d.ts +13 -0
  207. package/dist/src/api/routes/account.d.ts +623 -0
  208. package/dist/src/api/routes/callback.d.ts +68 -0
  209. package/dist/src/api/routes/email-verification.d.ts +266 -0
  210. package/dist/src/api/routes/error.d.ts +51 -0
  211. package/dist/src/api/routes/index.d.ts +11 -0
  212. package/dist/src/api/routes/ok.d.ts +61 -0
  213. package/dist/src/api/routes/reset-password.d.ts +203 -0
  214. package/dist/src/api/routes/session.d.ts +586 -0
  215. package/dist/src/api/routes/sign-in.d.ts +298 -0
  216. package/dist/src/api/routes/sign-out.d.ts +59 -0
  217. package/dist/src/api/routes/sign-up.d.ts +625 -0
  218. package/dist/src/api/routes/update-user.d.ts +862 -0
  219. package/dist/src/api/to-auth-endpoints.d.ts +3 -0
  220. package/dist/src/auth.d.ts +25 -0
  221. package/dist/src/client/broadcast-channel.d.ts +12 -0
  222. package/dist/src/client/config.d.ts +85 -0
  223. package/dist/src/client/fetch-plugins.d.ts +14 -0
  224. package/dist/src/client/index.d.ts +15 -0
  225. package/dist/src/client/parser.d.ts +12 -0
  226. package/dist/src/client/path-to-object.d.ts +63 -0
  227. package/dist/src/client/plugins/index.d.ts +21 -0
  228. package/dist/src/client/plugins/infer-plugin.d.ts +11 -0
  229. package/dist/src/client/proxy.d.ts +8 -0
  230. package/dist/src/client/query.d.ts +16 -0
  231. package/dist/src/client/react/index.d.ts +130 -0
  232. package/dist/src/client/react/react-store.d.ts +43 -0
  233. package/dist/src/client/session-atom.d.ts +18 -0
  234. package/dist/src/client/session-refresh.d.ts +17 -0
  235. package/dist/src/client/test-plugin.d.ts +147 -0
  236. package/dist/src/client/types.d.ts +49 -0
  237. package/dist/src/client/vanilla.d.ts +124 -0
  238. package/dist/src/cookies/check-cookies.d.ts +4 -0
  239. package/dist/src/cookies/cookie-utils.d.ts +16 -0
  240. package/dist/src/cookies/index.d.ts +56 -0
  241. package/dist/src/cookies/session-store.d.ts +43 -0
  242. package/dist/src/crypto/buffer.d.ts +4 -0
  243. package/dist/src/crypto/index.d.ts +14 -0
  244. package/dist/src/crypto/jwt.d.ts +4 -0
  245. package/dist/src/crypto/password.d.ts +5 -0
  246. package/dist/src/crypto/random.d.ts +1 -0
  247. package/dist/src/db/field.d.ts +97 -0
  248. package/dist/src/db/get-migration.d.ts +18 -0
  249. package/dist/src/db/get-schema.d.ts +6 -0
  250. package/dist/src/db/get-tables.d.ts +3 -0
  251. package/dist/src/db/index.d.ts +10 -0
  252. package/dist/src/db/internal-adapter.d.ts +9 -0
  253. package/dist/src/db/schema.d.ts +76 -0
  254. package/dist/src/db/to-zod.d.ts +31 -0
  255. package/dist/src/db/utils.d.ts +6 -0
  256. package/dist/src/db/with-hooks.d.ts +27 -0
  257. package/dist/src/index.d.ts +14 -0
  258. package/dist/src/init.d.ts +2 -0
  259. package/dist/src/integrations/next-js.d.ts +15 -0
  260. package/dist/src/integrations/node.d.ts +6 -0
  261. package/dist/src/integrations/react-start.d.ts +9 -0
  262. package/dist/src/oauth2/index.d.ts +4 -0
  263. package/dist/src/oauth2/link-account.d.ts +41 -0
  264. package/dist/src/oauth2/state.d.ts +21 -0
  265. package/dist/src/oauth2/utils.d.ts +3 -0
  266. package/dist/src/plugins/access/access.d.ts +25 -0
  267. package/dist/src/plugins/access/index.d.ts +2 -0
  268. package/dist/src/plugins/access/types.d.ts +14 -0
  269. package/dist/src/plugins/additional-fields/client.d.ts +91 -0
  270. package/dist/src/plugins/admin/access/index.d.ts +1 -0
  271. package/dist/src/plugins/admin/access/statement.d.ts +110 -0
  272. package/dist/src/plugins/admin/admin.d.ts +1570 -0
  273. package/dist/src/plugins/admin/client.d.ts +62 -0
  274. package/dist/src/plugins/admin/error-codes.d.ts +21 -0
  275. package/dist/src/plugins/admin/has-permission.d.ts +21 -0
  276. package/dist/src/plugins/admin/index.d.ts +2 -0
  277. package/dist/src/plugins/admin/schema.d.ts +36 -0
  278. package/dist/src/plugins/admin/types.d.ts +77 -0
  279. package/dist/src/plugins/anonymous/client.d.ts +8 -0
  280. package/dist/src/plugins/anonymous/index.d.ts +159 -0
  281. package/dist/src/plugins/api-key/client.d.ts +11 -0
  282. package/dist/src/plugins/api-key/index.d.ts +1431 -0
  283. package/dist/src/plugins/api-key/rate-limit.d.ts +20 -0
  284. package/dist/src/plugins/api-key/routes/create-api-key.d.ts +244 -0
  285. package/dist/src/plugins/api-key/routes/delete-all-expired-api-keys.d.ts +45 -0
  286. package/dist/src/plugins/api-key/routes/delete-api-key.d.ts +112 -0
  287. package/dist/src/plugins/api-key/routes/get-api-key.d.ts +234 -0
  288. package/dist/src/plugins/api-key/routes/index.d.ts +1136 -0
  289. package/dist/src/plugins/api-key/routes/list-api-keys.d.ts +231 -0
  290. package/dist/src/plugins/api-key/routes/update-api-key.d.ts +235 -0
  291. package/dist/src/plugins/api-key/routes/verify-api-key.d.ts +80 -0
  292. package/dist/src/plugins/api-key/schema.d.ts +188 -0
  293. package/dist/src/plugins/api-key/types.d.ts +285 -0
  294. package/dist/src/plugins/bearer/index.d.ts +31 -0
  295. package/dist/src/plugins/captcha/constants.d.ts +9 -0
  296. package/dist/src/plugins/captcha/error-codes.d.ts +9 -0
  297. package/dist/src/plugins/captcha/index.d.ts +7 -0
  298. package/dist/src/plugins/captcha/types.d.ts +23 -0
  299. package/dist/src/plugins/captcha/utils.d.ts +1 -0
  300. package/dist/src/plugins/captcha/verify-handlers/captchafox.d.ts +11 -0
  301. package/dist/src/plugins/captcha/verify-handlers/cloudflare-turnstile.d.ts +10 -0
  302. package/dist/src/plugins/captcha/verify-handlers/google-recaptcha.d.ts +11 -0
  303. package/dist/src/plugins/captcha/verify-handlers/h-captcha.d.ts +11 -0
  304. package/dist/src/plugins/captcha/verify-handlers/index.d.ts +4 -0
  305. package/dist/src/plugins/custom-session/client.d.ts +12 -0
  306. package/dist/src/plugins/custom-session/index.d.ts +89 -0
  307. package/dist/src/plugins/device-authorization/client.d.ts +12 -0
  308. package/dist/src/plugins/device-authorization/index.d.ts +568 -0
  309. package/dist/src/plugins/device-authorization/schema.d.ts +56 -0
  310. package/dist/src/plugins/email-otp/client.d.ts +9 -0
  311. package/dist/src/plugins/email-otp/index.d.ts +826 -0
  312. package/dist/src/plugins/email-otp/utils.d.ts +2 -0
  313. package/dist/src/plugins/generic-oauth/client.d.ts +5 -0
  314. package/dist/src/plugins/generic-oauth/index.d.ts +428 -0
  315. package/dist/src/plugins/haveibeenpwned/index.d.ts +25 -0
  316. package/dist/src/plugins/index.d.ts +28 -0
  317. package/dist/src/plugins/jwt/adapter.d.ts +8 -0
  318. package/dist/src/plugins/jwt/client.d.ts +5 -0
  319. package/dist/src/plugins/jwt/index.d.ts +276 -0
  320. package/dist/src/plugins/jwt/schema.d.ts +18 -0
  321. package/dist/src/plugins/jwt/sign.d.ts +8 -0
  322. package/dist/src/plugins/jwt/types.d.ts +175 -0
  323. package/dist/src/plugins/jwt/utils.d.ts +46 -0
  324. package/dist/src/plugins/last-login-method/client.d.ts +34 -0
  325. package/dist/src/plugins/last-login-method/index.d.ts +103 -0
  326. package/dist/src/plugins/magic-link/client.d.ts +5 -0
  327. package/dist/src/plugins/magic-link/index.d.ts +253 -0
  328. package/dist/src/plugins/magic-link/utils.d.ts +1 -0
  329. package/dist/src/plugins/multi-session/client.d.ts +9 -0
  330. package/dist/src/plugins/multi-session/index.d.ts +284 -0
  331. package/dist/src/plugins/oauth-proxy/index.d.ts +119 -0
  332. package/dist/src/plugins/one-tap/client.d.ts +81 -0
  333. package/dist/src/plugins/one-tap/index.d.ts +114 -0
  334. package/dist/src/plugins/one-time-token/client.d.ts +5 -0
  335. package/dist/src/plugins/one-time-token/index.d.ts +170 -0
  336. package/dist/src/plugins/one-time-token/utils.d.ts +1 -0
  337. package/dist/src/plugins/organization/access/index.d.ts +1 -0
  338. package/dist/src/plugins/organization/access/statement.d.ts +241 -0
  339. package/dist/src/plugins/organization/adapter.d.ts +685 -0
  340. package/dist/src/plugins/organization/call.d.ts +55 -0
  341. package/dist/src/plugins/organization/client.d.ts +344 -0
  342. package/dist/src/plugins/organization/error-codes.d.ts +58 -0
  343. package/dist/src/plugins/organization/has-permission.d.ts +13 -0
  344. package/dist/src/plugins/organization/index.d.ts +4 -0
  345. package/dist/src/plugins/organization/organization.d.ts +412 -0
  346. package/dist/src/plugins/organization/permission.d.ts +27 -0
  347. package/dist/src/plugins/organization/routes/crud-access-control.d.ts +701 -0
  348. package/dist/src/plugins/organization/routes/crud-invites.d.ts +1522 -0
  349. package/dist/src/plugins/organization/routes/crud-members.d.ts +1220 -0
  350. package/dist/src/plugins/organization/routes/crud-org.d.ts +1399 -0
  351. package/dist/src/plugins/organization/routes/crud-team.d.ts +1323 -0
  352. package/dist/src/plugins/organization/schema.d.ts +366 -0
  353. package/dist/src/plugins/organization/types.d.ts +737 -0
  354. package/dist/src/plugins/passkey/client.d.ts +190 -0
  355. package/dist/src/plugins/passkey/error-codes.d.ts +9 -0
  356. package/dist/src/plugins/passkey/index.d.ts +838 -0
  357. package/dist/src/plugins/passkey/schema.d.ts +50 -0
  358. package/dist/src/plugins/passkey/types.d.ts +69 -0
  359. package/dist/src/plugins/passkey/utils.d.ts +2 -0
  360. package/dist/src/plugins/phone-number/client.d.ts +9 -0
  361. package/dist/src/plugins/phone-number/index.d.ts +622 -0
  362. package/dist/src/plugins/phone-number/phone-number-error.d.ts +10 -0
  363. package/dist/src/plugins/two-factor/backup-codes/index.d.ts +387 -0
  364. package/dist/src/plugins/two-factor/client.d.ts +28 -0
  365. package/dist/src/plugins/two-factor/constant.d.ts +2 -0
  366. package/dist/src/plugins/two-factor/error-code.d.ts +11 -0
  367. package/dist/src/plugins/two-factor/index.d.ts +1014 -0
  368. package/dist/src/plugins/two-factor/otp/index.d.ts +282 -0
  369. package/dist/src/plugins/two-factor/schema.d.ts +35 -0
  370. package/dist/src/plugins/two-factor/totp/index.d.ts +298 -0
  371. package/dist/src/plugins/two-factor/types.d.ts +50 -0
  372. package/dist/src/plugins/two-factor/utils.d.ts +1 -0
  373. package/dist/src/plugins/two-factor/verify-two-factor.d.ts +59 -0
  374. package/dist/src/plugins/username/client.d.ts +5 -0
  375. package/dist/src/plugins/username/error-codes.d.ts +10 -0
  376. package/dist/src/plugins/username/index.d.ts +313 -0
  377. package/dist/src/plugins/username/schema.d.ts +27 -0
  378. package/dist/src/social-providers/index.d.ts +1 -0
  379. package/dist/src/test-utils/headers.d.ts +5 -0
  380. package/dist/src/test-utils/index.d.ts +2 -0
  381. package/dist/src/test-utils/test-instance.d.ts +17849 -0
  382. package/dist/src/types/adapter.d.ts +21 -0
  383. package/dist/src/types/api.d.ts +29 -0
  384. package/dist/src/types/helper.d.ts +32 -0
  385. package/dist/src/types/index.d.ts +7 -0
  386. package/dist/src/types/models.d.ts +13 -0
  387. package/dist/src/types/plugins.d.ts +14 -0
  388. package/dist/src/utils/await-object.d.ts +3 -0
  389. package/dist/src/utils/boolean.d.ts +1 -0
  390. package/dist/src/utils/clone.d.ts +1 -0
  391. package/dist/src/utils/constants.d.ts +1 -0
  392. package/dist/src/utils/date.d.ts +1 -0
  393. package/dist/src/utils/ensure-utc.d.ts +1 -0
  394. package/dist/src/utils/get-request-ip.d.ts +2 -0
  395. package/dist/src/utils/hashing.d.ts +6 -0
  396. package/dist/src/utils/hide-metadata.d.ts +3 -0
  397. package/dist/src/utils/id.d.ts +1 -0
  398. package/dist/src/utils/import-util.d.ts +1 -0
  399. package/dist/src/utils/index.d.ts +5 -0
  400. package/dist/src/utils/is-atom.d.ts +2 -0
  401. package/dist/src/utils/is-promise.d.ts +1 -0
  402. package/dist/src/utils/json.d.ts +1 -0
  403. package/dist/src/utils/merger.d.ts +1 -0
  404. package/dist/src/utils/middleware-response.d.ts +8 -0
  405. package/dist/src/utils/misc.d.ts +1 -0
  406. package/dist/src/utils/password.d.ts +6 -0
  407. package/dist/src/utils/plugin-helper.d.ts +5 -0
  408. package/dist/src/utils/shim.d.ts +3 -0
  409. package/dist/src/utils/time.d.ts +4 -0
  410. package/dist/src/utils/url.d.ts +4 -0
  411. package/dist/src/utils/wildcard.d.ts +45 -0
  412. package/dist/test-utils/index.d.mts +17870 -0
  413. package/dist/test-utils/index.mjs +272 -0
  414. package/dist/two-factor-ClUXxom2.mjs +914 -0
  415. package/dist/types/index.d.mts +6 -0
  416. package/dist/types/index.mjs +3 -0
  417. package/dist/types-B1OL7hyf.d.mts +4 -0
  418. package/dist/types-Bjn15Uy6.mjs +1 -0
  419. package/dist/url-VB2gAbTI.mjs +59 -0
  420. package/dist/username-DiGklOGl.mjs +278 -0
  421. package/dist/utils-SOMB4Px5.mjs +132 -0
  422. package/package.json +447 -0
@@ -0,0 +1,3139 @@
1
+ import { i as parseState, n as HIDE_METADATA, r as generateState, t as generateId } from "./utils-SOMB4Px5.mjs";
2
+ import { i as getProtocol, n as getHost, r as getOrigin } from "./url-VB2gAbTI.mjs";
3
+ import { t as getIp } from "./get-request-ip-DSjrEpGo.mjs";
4
+ import { t as safeJSONParse } from "./json-D0TBLy4q.mjs";
5
+ import { n as symmetricEncrypt, r as generateRandomString, t as symmetricDecrypt } from "./crypto-Bb42eMrH.mjs";
6
+ import { t as signJWT } from "./jwt-CmxZAGe2.mjs";
7
+ import { c as setSessionCookie, n as deleteSessionCookie } from "./cookies-cJObLwn1.mjs";
8
+ import { l as parseUserInput, t as getDate } from "./date-Cx2yCiC4.mjs";
9
+ import { c as revokeSessions, i as listSessions, l as sensitiveSessionMiddleware, n as getSession, o as revokeOtherSessions, r as getSessionFromCtx, s as revokeSession, t as freshSessionMiddleware, u as sessionMiddleware } from "./session-Dgp133Yt.mjs";
10
+ import { hasRequestState, runWithEndpointContext, runWithRequestState, runWithTransaction } from "@gatwech/core/context";
11
+ import { isDevelopment, isProduction, logger, shouldPublishLog } from "@gatwech/core/env";
12
+ import { BASE_ERROR_CODES } from "@gatwech/core/error";
13
+ import { APIError, APIError as APIError$1, createRouter, toResponse } from "better-call";
14
+ import { createAuthEndpoint, createAuthEndpoint as createAuthEndpoint$1, createAuthMiddleware, createAuthMiddleware as createAuthMiddleware$1, optionsMiddleware } from "@gatwech/core/api";
15
+ import * as z$1 from "zod";
16
+ import { SocialProviderListEnum } from "@gatwech/core/social-providers";
17
+ import { jwtVerify } from "jose";
18
+ import { JWTExpired } from "jose/errors";
19
+ import { createDefu } from "defu";
20
+
21
+ //#region src/utils/wildcard.ts
22
+ /**
23
+ * Escapes a character if it has a special meaning in regular expressions
24
+ * and returns the character as is if it doesn't
25
+ */
26
+ function escapeRegExpChar(char) {
27
+ if (char === "-" || char === "^" || char === "$" || char === "+" || char === "." || char === "(" || char === ")" || char === "|" || char === "[" || char === "]" || char === "{" || char === "}" || char === "*" || char === "?" || char === "\\") return `\\${char}`;
28
+ else return char;
29
+ }
30
+ /**
31
+ * Escapes all characters in a given string that have a special meaning in regular expressions
32
+ */
33
+ function escapeRegExpString(str) {
34
+ let result = "";
35
+ for (let i = 0; i < str.length; i++) result += escapeRegExpChar(str[i]);
36
+ return result;
37
+ }
38
+ /**
39
+ * Transforms one or more glob patterns into a RegExp pattern
40
+ */
41
+ function transform(pattern, separator = true) {
42
+ if (Array.isArray(pattern)) return `(?:${pattern.map((p) => `^${transform(p, separator)}$`).join("|")})`;
43
+ let separatorSplitter = "";
44
+ let separatorMatcher = "";
45
+ let wildcard = ".";
46
+ if (separator === true) {
47
+ separatorSplitter = "/";
48
+ separatorMatcher = "[/\\\\]";
49
+ wildcard = "[^/\\\\]";
50
+ } else if (separator) {
51
+ separatorSplitter = separator;
52
+ separatorMatcher = escapeRegExpString(separatorSplitter);
53
+ if (separatorMatcher.length > 1) {
54
+ separatorMatcher = `(?:${separatorMatcher})`;
55
+ wildcard = `((?!${separatorMatcher}).)`;
56
+ } else wildcard = `[^${separatorMatcher}]`;
57
+ }
58
+ let requiredSeparator = separator ? `${separatorMatcher}+?` : "";
59
+ let optionalSeparator = separator ? `${separatorMatcher}*?` : "";
60
+ let segments = separator ? pattern.split(separatorSplitter) : [pattern];
61
+ let result = "";
62
+ for (let s = 0; s < segments.length; s++) {
63
+ let segment = segments[s];
64
+ let nextSegment = segments[s + 1];
65
+ let currentSeparator = "";
66
+ if (!segment && s > 0) continue;
67
+ if (separator) if (s === segments.length - 1) currentSeparator = optionalSeparator;
68
+ else if (nextSegment !== "**") currentSeparator = requiredSeparator;
69
+ else currentSeparator = "";
70
+ if (separator && segment === "**") {
71
+ if (currentSeparator) {
72
+ result += s === 0 ? "" : currentSeparator;
73
+ result += `(?:${wildcard}*?${currentSeparator})*?`;
74
+ }
75
+ continue;
76
+ }
77
+ for (let c = 0; c < segment.length; c++) {
78
+ let char = segment[c];
79
+ if (char === "\\") {
80
+ if (c < segment.length - 1) {
81
+ result += escapeRegExpChar(segment[c + 1]);
82
+ c++;
83
+ }
84
+ } else if (char === "?") result += wildcard;
85
+ else if (char === "*") result += `${wildcard}*?`;
86
+ else result += escapeRegExpChar(char);
87
+ }
88
+ result += currentSeparator;
89
+ }
90
+ return result;
91
+ }
92
+ function isMatch(regexp, sample) {
93
+ if (typeof sample !== "string") throw new TypeError(`Sample must be a string, but ${typeof sample} given`);
94
+ return regexp.test(sample);
95
+ }
96
+ /**
97
+ * Compiles one or more glob patterns into a RegExp and returns an isMatch function.
98
+ * The isMatch function takes a sample string as its only argument and returns `true`
99
+ * if the string matches the pattern(s).
100
+ *
101
+ * ```js
102
+ * wildcardMatch('src/*.js')('src/index.js') //=> true
103
+ * ```
104
+ *
105
+ * ```js
106
+ * const isMatch = wildcardMatch('*.example.com', '.')
107
+ * isMatch('foo.example.com') //=> true
108
+ * isMatch('foo.bar.com') //=> false
109
+ * ```
110
+ */
111
+ function wildcardMatch(pattern, options) {
112
+ if (typeof pattern !== "string" && !Array.isArray(pattern)) throw new TypeError(`The first argument must be a single pattern string or an array of patterns, but ${typeof pattern} given`);
113
+ if (typeof options === "string" || typeof options === "boolean") options = { separator: options };
114
+ if (arguments.length === 2 && !(typeof options === "undefined" || typeof options === "object" && options !== null && !Array.isArray(options))) throw new TypeError(`The second argument must be an options object or a string/boolean separator, but ${typeof options} given`);
115
+ options = options || {};
116
+ if (options.separator === "\\") throw new Error("\\ is not a valid separator because it is used for escaping. Try setting the separator to `true` instead");
117
+ let regexpPattern = transform(pattern, options.separator);
118
+ let regexp = new RegExp(`^${regexpPattern}$`, options.flags);
119
+ let fn = isMatch.bind(null, regexp);
120
+ fn.options = options;
121
+ fn.pattern = pattern;
122
+ fn.regexp = regexp;
123
+ return fn;
124
+ }
125
+
126
+ //#endregion
127
+ //#region src/api/middlewares/origin-check.ts
128
+ /**
129
+ * A middleware to validate callbackURL and origin against
130
+ * trustedOrigins.
131
+ */
132
+ const originCheckMiddleware = createAuthMiddleware(async (ctx) => {
133
+ if (ctx.request?.method !== "POST" || !ctx.request) return;
134
+ const headers = ctx.request?.headers;
135
+ const request = ctx.request;
136
+ const { body, query, context } = ctx;
137
+ /**
138
+ * We only allow requests with the x-auth-request header set to
139
+ * true or application/json content type. This is to prevent
140
+ * simple requests from being processed
141
+ */
142
+ if (isSimpleRequest(headers) && !ctx.context.skipCSRFCheck) throw new APIError("FORBIDDEN", { message: "Invalid request" });
143
+ const originHeader = headers?.get("origin") || headers?.get("referer") || "";
144
+ const callbackURL = body?.callbackURL || query?.callbackURL;
145
+ const redirectURL = body?.redirectTo;
146
+ const errorCallbackURL = body?.errorCallbackURL;
147
+ const newUserCallbackURL = body?.newUserCallbackURL;
148
+ const trustedOrigins = Array.isArray(context.options.trustedOrigins) ? context.trustedOrigins : [...context.trustedOrigins, ...await context.options.trustedOrigins?.(request) || []];
149
+ const useCookies = headers?.has("cookie");
150
+ const matchesPattern = (url, pattern) => {
151
+ if (url.startsWith("/")) return false;
152
+ if (pattern.includes("*")) {
153
+ if (pattern.includes("://")) return wildcardMatch(pattern)(getOrigin(url) || url);
154
+ const host = getHost(url);
155
+ if (!host) return false;
156
+ return wildcardMatch(pattern)(host);
157
+ }
158
+ const protocol = getProtocol(url);
159
+ return protocol === "http:" || protocol === "https:" || !protocol ? pattern === getOrigin(url) : url.startsWith(pattern);
160
+ };
161
+ const validateURL = (url, label) => {
162
+ if (!url) return;
163
+ if (!trustedOrigins.some((origin) => matchesPattern(url, origin) || url?.startsWith("/") && label !== "origin" && /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/@]*(?:\?[\w\-.\+/=&%@]*)?$/.test(url))) {
164
+ ctx.context.logger.error(`Invalid ${label}: ${url}`);
165
+ ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\n`, `Current list of trustedOrigins: ${trustedOrigins}`);
166
+ throw new APIError("FORBIDDEN", { message: `Invalid ${label}` });
167
+ }
168
+ };
169
+ if (useCookies && !ctx.context.skipCSRFCheck && !ctx.context.skipOriginCheck) {
170
+ if (!originHeader || originHeader === "null") throw new APIError("FORBIDDEN", { message: "Missing or null Origin" });
171
+ validateURL(originHeader, "origin");
172
+ }
173
+ callbackURL && validateURL(callbackURL, "callbackURL");
174
+ redirectURL && validateURL(redirectURL, "redirectURL");
175
+ errorCallbackURL && validateURL(errorCallbackURL, "errorCallbackURL");
176
+ newUserCallbackURL && validateURL(newUserCallbackURL, "newUserCallbackURL");
177
+ });
178
+ const originCheck = (getValue) => createAuthMiddleware(async (ctx) => {
179
+ if (!ctx.request) return;
180
+ const { context } = ctx;
181
+ const callbackURL = getValue(ctx);
182
+ const trustedOrigins = Array.isArray(context.options.trustedOrigins) ? context.trustedOrigins : [...context.trustedOrigins, ...await context.options.trustedOrigins?.(ctx.request) || []];
183
+ const matchesPattern = (url, pattern) => {
184
+ if (url.startsWith("/")) return false;
185
+ if (pattern.includes("*")) {
186
+ if (pattern.includes("://")) return wildcardMatch(pattern)(getOrigin(url) || url);
187
+ const host = getHost(url);
188
+ if (!host) return false;
189
+ return wildcardMatch(pattern)(host);
190
+ }
191
+ const protocol = getProtocol(url);
192
+ return protocol === "http:" || protocol === "https:" || !protocol ? pattern === getOrigin(url) : url.startsWith(pattern);
193
+ };
194
+ const validateURL = (url, label) => {
195
+ if (!url) return;
196
+ if (!trustedOrigins.some((origin) => matchesPattern(url, origin) || url?.startsWith("/") && label !== "origin" && /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/@]*(?:\?[\w\-.\+/=&%@]*)?$/.test(url))) {
197
+ ctx.context.logger.error(`Invalid ${label}: ${url}`);
198
+ ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\n`, `Current list of trustedOrigins: ${trustedOrigins}`);
199
+ throw new APIError("FORBIDDEN", { message: `Invalid ${label}` });
200
+ }
201
+ };
202
+ const callbacks = Array.isArray(callbackURL) ? callbackURL : [callbackURL];
203
+ for (const url of callbacks) validateURL(url, "callbackURL");
204
+ });
205
+ function isSimpleRequest(headers) {
206
+ const SIMPLE_HEADERS = [
207
+ "accept",
208
+ "accept-language",
209
+ "content-language",
210
+ "content-type"
211
+ ];
212
+ const SIMPLE_CONTENT_TYPES = [
213
+ "application/x-www-form-urlencoded",
214
+ "multipart/form-data",
215
+ "text/plain"
216
+ ];
217
+ for (const [key, value] of headers.entries()) {
218
+ if (!SIMPLE_HEADERS.includes(key.toLowerCase())) return false;
219
+ if (key.toLowerCase() === "content-type" && !SIMPLE_CONTENT_TYPES.includes(value?.split(";")[0]?.trim()?.toLowerCase() || "")) return false;
220
+ }
221
+ return true;
222
+ }
223
+
224
+ //#endregion
225
+ //#region src/api/rate-limiter/index.ts
226
+ function shouldRateLimit(max, window, rateLimitData) {
227
+ const now = Date.now();
228
+ const windowInMs = window * 1e3;
229
+ return now - rateLimitData.lastRequest < windowInMs && rateLimitData.count >= max;
230
+ }
231
+ function rateLimitResponse(retryAfter) {
232
+ return new Response(JSON.stringify({ message: "Too many requests. Please try again later." }), {
233
+ status: 429,
234
+ statusText: "Too Many Requests",
235
+ headers: { "X-Retry-After": retryAfter.toString() }
236
+ });
237
+ }
238
+ function getRetryAfter(lastRequest, window) {
239
+ const now = Date.now();
240
+ const windowInMs = window * 1e3;
241
+ return Math.ceil((lastRequest + windowInMs - now) / 1e3);
242
+ }
243
+ function createDBStorage(ctx) {
244
+ const model = "rateLimit";
245
+ const db = ctx.adapter;
246
+ return {
247
+ get: async (key) => {
248
+ const data = (await db.findMany({
249
+ model,
250
+ where: [{
251
+ field: "key",
252
+ value: key
253
+ }]
254
+ }))[0];
255
+ if (typeof data?.lastRequest === "bigint") data.lastRequest = Number(data.lastRequest);
256
+ return data;
257
+ },
258
+ set: async (key, value, _update) => {
259
+ try {
260
+ if (_update) await db.updateMany({
261
+ model,
262
+ where: [{
263
+ field: "key",
264
+ value: key
265
+ }],
266
+ update: {
267
+ count: value.count,
268
+ lastRequest: value.lastRequest
269
+ }
270
+ });
271
+ else await db.create({
272
+ model,
273
+ data: {
274
+ key,
275
+ count: value.count,
276
+ lastRequest: value.lastRequest
277
+ }
278
+ });
279
+ } catch (e) {
280
+ ctx.logger.error("Error setting rate limit", e);
281
+ }
282
+ }
283
+ };
284
+ }
285
+ const memory = /* @__PURE__ */ new Map();
286
+ function getRateLimitStorage(ctx, rateLimitSettings) {
287
+ if (ctx.options.rateLimit?.customStorage) return ctx.options.rateLimit.customStorage;
288
+ const storage = ctx.rateLimit.storage;
289
+ if (storage === "secondary-storage") return {
290
+ get: async (key) => {
291
+ const data = await ctx.options.secondaryStorage?.get(key);
292
+ return data ? safeJSONParse(data) : void 0;
293
+ },
294
+ set: async (key, value, _update) => {
295
+ const ttl = rateLimitSettings?.window ?? ctx.options.rateLimit?.window ?? 10;
296
+ await ctx.options.secondaryStorage?.set?.(key, JSON.stringify(value), ttl);
297
+ }
298
+ };
299
+ else if (storage === "memory") return {
300
+ async get(key) {
301
+ return memory.get(key);
302
+ },
303
+ async set(key, value, _update) {
304
+ memory.set(key, value);
305
+ }
306
+ };
307
+ return createDBStorage(ctx);
308
+ }
309
+ async function onRequestRateLimit(req, ctx) {
310
+ if (!ctx.rateLimit.enabled) return;
311
+ const path = new URL(req.url).pathname.replace(ctx.options.basePath || "/api/auth", "");
312
+ let window = ctx.rateLimit.window;
313
+ let max = ctx.rateLimit.max;
314
+ const ip = getIp(req, ctx.options);
315
+ if (!ip) return;
316
+ const key = ip + path;
317
+ const specialRule = getDefaultSpecialRules().find((rule) => rule.pathMatcher(path));
318
+ if (specialRule) {
319
+ window = specialRule.window;
320
+ max = specialRule.max;
321
+ }
322
+ for (const plugin of ctx.options.plugins || []) if (plugin.rateLimit) {
323
+ const matchedRule = plugin.rateLimit.find((rule) => rule.pathMatcher(path));
324
+ if (matchedRule) {
325
+ window = matchedRule.window;
326
+ max = matchedRule.max;
327
+ break;
328
+ }
329
+ }
330
+ if (ctx.rateLimit.customRules) {
331
+ const _path = Object.keys(ctx.rateLimit.customRules).find((p) => {
332
+ if (p.includes("*")) return wildcardMatch(p)(path);
333
+ return p === path;
334
+ });
335
+ if (_path) {
336
+ const customRule = ctx.rateLimit.customRules[_path];
337
+ const resolved = typeof customRule === "function" ? await customRule(req) : customRule;
338
+ if (resolved) {
339
+ window = resolved.window;
340
+ max = resolved.max;
341
+ }
342
+ if (resolved === false) return;
343
+ }
344
+ }
345
+ const storage = getRateLimitStorage(ctx, { window });
346
+ const data = await storage.get(key);
347
+ const now = Date.now();
348
+ if (!data) await storage.set(key, {
349
+ key,
350
+ count: 1,
351
+ lastRequest: now
352
+ });
353
+ else {
354
+ const timeSinceLastRequest = now - data.lastRequest;
355
+ if (shouldRateLimit(max, window, data)) return rateLimitResponse(getRetryAfter(data.lastRequest, window));
356
+ else if (timeSinceLastRequest > window * 1e3) await storage.set(key, {
357
+ ...data,
358
+ count: 1,
359
+ lastRequest: now
360
+ }, true);
361
+ else await storage.set(key, {
362
+ ...data,
363
+ count: data.count + 1,
364
+ lastRequest: now
365
+ }, true);
366
+ }
367
+ }
368
+ function getDefaultSpecialRules() {
369
+ return [{
370
+ pathMatcher(path) {
371
+ return path.startsWith("/sign-in") || path.startsWith("/sign-up") || path.startsWith("/change-password") || path.startsWith("/change-email");
372
+ },
373
+ window: 10,
374
+ max: 3
375
+ }];
376
+ }
377
+
378
+ //#endregion
379
+ //#region src/oauth2/utils.ts
380
+ function decryptOAuthToken(token, ctx) {
381
+ if (!token) return token;
382
+ if (ctx.options.account?.encryptOAuthTokens) return symmetricDecrypt({
383
+ key: ctx.secret,
384
+ data: token
385
+ });
386
+ return token;
387
+ }
388
+ function setTokenUtil(token, ctx) {
389
+ if (ctx.options.account?.encryptOAuthTokens && token) return symmetricEncrypt({
390
+ key: ctx.secret,
391
+ data: token
392
+ });
393
+ return token;
394
+ }
395
+
396
+ //#endregion
397
+ //#region src/api/routes/account.ts
398
+ const listUserAccounts = createAuthEndpoint("/list-accounts", {
399
+ method: "GET",
400
+ use: [sessionMiddleware],
401
+ metadata: { openapi: {
402
+ description: "List all accounts linked to the user",
403
+ responses: { "200": {
404
+ description: "Success",
405
+ content: { "application/json": { schema: {
406
+ type: "array",
407
+ items: {
408
+ type: "object",
409
+ properties: {
410
+ id: { type: "string" },
411
+ providerId: { type: "string" },
412
+ createdAt: {
413
+ type: "string",
414
+ format: "date-time"
415
+ },
416
+ updatedAt: {
417
+ type: "string",
418
+ format: "date-time"
419
+ },
420
+ accountId: { type: "string" },
421
+ userId: { type: "string" },
422
+ scopes: {
423
+ type: "array",
424
+ items: { type: "string" }
425
+ }
426
+ },
427
+ required: [
428
+ "id",
429
+ "providerId",
430
+ "createdAt",
431
+ "updatedAt",
432
+ "accountId",
433
+ "userId",
434
+ "scopes"
435
+ ]
436
+ }
437
+ } } }
438
+ } }
439
+ } }
440
+ }, async (c) => {
441
+ const session = c.context.session;
442
+ const accounts = await c.context.internalAdapter.findAccounts(session.user.id);
443
+ return c.json(accounts.map((a) => ({
444
+ id: a.id,
445
+ providerId: a.providerId,
446
+ createdAt: a.createdAt,
447
+ updatedAt: a.updatedAt,
448
+ accountId: a.accountId,
449
+ userId: a.userId,
450
+ scopes: a.scope?.split(",") || []
451
+ })));
452
+ });
453
+ const linkSocialAccount = createAuthEndpoint("/link-social", {
454
+ method: "POST",
455
+ requireHeaders: true,
456
+ body: z$1.object({
457
+ callbackURL: z$1.string().meta({ description: "The URL to redirect to after the user has signed in" }).optional(),
458
+ provider: SocialProviderListEnum,
459
+ idToken: z$1.object({
460
+ token: z$1.string(),
461
+ nonce: z$1.string().optional(),
462
+ accessToken: z$1.string().optional(),
463
+ refreshToken: z$1.string().optional(),
464
+ scopes: z$1.array(z$1.string()).optional()
465
+ }).optional(),
466
+ requestSignUp: z$1.boolean().optional(),
467
+ scopes: z$1.array(z$1.string()).meta({ description: "Additional scopes to request from the provider" }).optional(),
468
+ errorCallbackURL: z$1.string().meta({ description: "The URL to redirect to if there is an error during the link process" }).optional(),
469
+ disableRedirect: z$1.boolean().meta({ description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself" }).optional(),
470
+ additionalData: z$1.record(z$1.string(), z$1.any()).optional()
471
+ }),
472
+ use: [sessionMiddleware],
473
+ metadata: { openapi: {
474
+ description: "Link a social account to the user",
475
+ responses: { "200": {
476
+ description: "Success",
477
+ content: { "application/json": { schema: {
478
+ type: "object",
479
+ properties: {
480
+ url: {
481
+ type: "string",
482
+ description: "The authorization URL to redirect the user to"
483
+ },
484
+ redirect: {
485
+ type: "boolean",
486
+ description: "Indicates if the user should be redirected to the authorization URL"
487
+ },
488
+ status: { type: "boolean" }
489
+ },
490
+ required: ["redirect"]
491
+ } } }
492
+ } }
493
+ } }
494
+ }, async (c) => {
495
+ const session = c.context.session;
496
+ const provider = c.context.socialProviders.find((p) => p.id === c.body.provider);
497
+ if (!provider) {
498
+ c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider });
499
+ throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND });
500
+ }
501
+ if (c.body.idToken) {
502
+ if (!provider.verifyIdToken) {
503
+ c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider });
504
+ throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED });
505
+ }
506
+ const { token, nonce } = c.body.idToken;
507
+ if (!await provider.verifyIdToken(token, nonce)) {
508
+ c.context.logger.error("Invalid id token", { provider: c.body.provider });
509
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_TOKEN });
510
+ }
511
+ const linkingUserInfo = await provider.getUserInfo({
512
+ idToken: token,
513
+ accessToken: c.body.idToken.accessToken,
514
+ refreshToken: c.body.idToken.refreshToken
515
+ });
516
+ if (!linkingUserInfo || !linkingUserInfo?.user) {
517
+ c.context.logger.error("Failed to get user info", { provider: c.body.provider });
518
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO });
519
+ }
520
+ const linkingUserId = String(linkingUserInfo.user.id);
521
+ if (!linkingUserInfo.user.email) {
522
+ c.context.logger.error("User email not found", { provider: c.body.provider });
523
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND });
524
+ }
525
+ if ((await c.context.internalAdapter.findAccounts(session.user.id)).find((a) => a.providerId === provider.id && a.accountId === linkingUserId)) return c.json({
526
+ url: "",
527
+ status: true,
528
+ redirect: false
529
+ });
530
+ if (!(c.context.options.account?.accountLinking?.trustedProviders)?.includes(provider.id) && !linkingUserInfo.user.emailVerified || c.context.options.account?.accountLinking?.enabled === false) throw new APIError("UNAUTHORIZED", { message: "Account not linked - linking not allowed" });
531
+ if (linkingUserInfo.user.email !== session.user.email && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) throw new APIError("UNAUTHORIZED", { message: "Account not linked - different emails not allowed" });
532
+ try {
533
+ await c.context.internalAdapter.createAccount({
534
+ userId: session.user.id,
535
+ providerId: provider.id,
536
+ accountId: linkingUserId,
537
+ accessToken: c.body.idToken.accessToken,
538
+ idToken: token,
539
+ refreshToken: c.body.idToken.refreshToken,
540
+ scope: c.body.idToken.scopes?.join(",")
541
+ });
542
+ } catch (e) {
543
+ throw new APIError("EXPECTATION_FAILED", { message: "Account not linked - unable to create account" });
544
+ }
545
+ if (c.context.options.account?.accountLinking?.updateUserInfoOnLink === true) try {
546
+ await c.context.internalAdapter.updateUser(session.user.id, {
547
+ name: linkingUserInfo.user?.name,
548
+ image: linkingUserInfo.user?.image
549
+ });
550
+ } catch (e) {
551
+ console.warn("Could not update user - " + e.toString());
552
+ }
553
+ return c.json({
554
+ url: "",
555
+ status: true,
556
+ redirect: false
557
+ });
558
+ }
559
+ const state = await generateState(c, {
560
+ userId: session.user.id,
561
+ email: session.user.email
562
+ }, c.body.additionalData);
563
+ const url = await provider.createAuthorizationURL({
564
+ state: state.state,
565
+ codeVerifier: state.codeVerifier,
566
+ redirectURI: `${c.context.baseURL}/callback/${provider.id}`,
567
+ scopes: c.body.scopes
568
+ });
569
+ return c.json({
570
+ url: url.toString(),
571
+ redirect: !c.body.disableRedirect
572
+ });
573
+ });
574
+ const unlinkAccount = createAuthEndpoint("/unlink-account", {
575
+ method: "POST",
576
+ body: z$1.object({
577
+ providerId: z$1.string(),
578
+ accountId: z$1.string().optional()
579
+ }),
580
+ use: [freshSessionMiddleware],
581
+ metadata: { openapi: {
582
+ description: "Unlink an account",
583
+ responses: { "200": {
584
+ description: "Success",
585
+ content: { "application/json": { schema: {
586
+ type: "object",
587
+ properties: { status: { type: "boolean" } }
588
+ } } }
589
+ } }
590
+ } }
591
+ }, async (ctx) => {
592
+ const { providerId, accountId } = ctx.body;
593
+ const accounts = await ctx.context.internalAdapter.findAccounts(ctx.context.session.user.id);
594
+ if (accounts.length === 1 && !ctx.context.options.account?.accountLinking?.allowUnlinkingAll) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT });
595
+ const accountExist = accounts.find((account) => accountId ? account.accountId === accountId && account.providerId === providerId : account.providerId === providerId);
596
+ if (!accountExist) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.ACCOUNT_NOT_FOUND });
597
+ await ctx.context.internalAdapter.deleteAccount(accountExist.id);
598
+ return ctx.json({ status: true });
599
+ });
600
+ const getAccessToken = createAuthEndpoint("/get-access-token", {
601
+ method: "POST",
602
+ body: z$1.object({
603
+ providerId: z$1.string().meta({ description: "The provider ID for the OAuth provider" }),
604
+ accountId: z$1.string().meta({ description: "The account ID associated with the refresh token" }).optional(),
605
+ userId: z$1.string().meta({ description: "The user ID associated with the account" }).optional()
606
+ }),
607
+ metadata: { openapi: {
608
+ description: "Get a valid access token, doing a refresh if needed",
609
+ responses: {
610
+ 200: {
611
+ description: "A Valid access token",
612
+ content: { "application/json": { schema: {
613
+ type: "object",
614
+ properties: {
615
+ tokenType: { type: "string" },
616
+ idToken: { type: "string" },
617
+ accessToken: { type: "string" },
618
+ refreshToken: { type: "string" },
619
+ accessTokenExpiresAt: {
620
+ type: "string",
621
+ format: "date-time"
622
+ },
623
+ refreshTokenExpiresAt: {
624
+ type: "string",
625
+ format: "date-time"
626
+ }
627
+ }
628
+ } } }
629
+ },
630
+ 400: { description: "Invalid refresh token or provider configuration" }
631
+ }
632
+ } }
633
+ }, async (ctx) => {
634
+ const { providerId, accountId, userId } = ctx.body;
635
+ const req = ctx.request;
636
+ const session = await getSessionFromCtx(ctx);
637
+ if (req && !session) throw ctx.error("UNAUTHORIZED");
638
+ let resolvedUserId = session?.user?.id || userId;
639
+ if (!resolvedUserId) throw new APIError("BAD_REQUEST", { message: `Either userId or session is required` });
640
+ if (!ctx.context.socialProviders.find((p) => p.id === providerId)) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} is not supported.` });
641
+ const account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.id === accountId && acc.providerId === providerId : acc.providerId === providerId);
642
+ if (!account) throw new APIError("BAD_REQUEST", { message: "Account not found" });
643
+ const provider = ctx.context.socialProviders.find((p) => p.id === providerId);
644
+ if (!provider) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} not found.` });
645
+ try {
646
+ let newTokens = null;
647
+ const accessTokenExpired = account.accessTokenExpiresAt && new Date(account.accessTokenExpiresAt).getTime() - Date.now() < 5e3;
648
+ if (account.refreshToken && accessTokenExpired && provider.refreshAccessToken) {
649
+ const refreshToken$1 = await decryptOAuthToken(account.refreshToken, ctx.context);
650
+ newTokens = await provider.refreshAccessToken(refreshToken$1);
651
+ await ctx.context.internalAdapter.updateAccount(account.id, {
652
+ accessToken: await setTokenUtil(newTokens.accessToken, ctx.context),
653
+ accessTokenExpiresAt: newTokens.accessTokenExpiresAt,
654
+ refreshToken: await setTokenUtil(newTokens.refreshToken, ctx.context),
655
+ refreshTokenExpiresAt: newTokens.refreshTokenExpiresAt
656
+ });
657
+ }
658
+ const tokens = {
659
+ accessToken: newTokens?.accessToken ?? await decryptOAuthToken(account.accessToken ?? "", ctx.context),
660
+ accessTokenExpiresAt: newTokens?.accessTokenExpiresAt ?? account.accessTokenExpiresAt ?? void 0,
661
+ scopes: account.scope?.split(",") ?? [],
662
+ idToken: newTokens?.idToken ?? account.idToken ?? void 0
663
+ };
664
+ return ctx.json(tokens);
665
+ } catch (error$1) {
666
+ throw new APIError("BAD_REQUEST", {
667
+ message: "Failed to get a valid access token",
668
+ cause: error$1
669
+ });
670
+ }
671
+ });
672
+ const refreshToken = createAuthEndpoint("/refresh-token", {
673
+ method: "POST",
674
+ body: z$1.object({
675
+ providerId: z$1.string().meta({ description: "The provider ID for the OAuth provider" }),
676
+ accountId: z$1.string().meta({ description: "The account ID associated with the refresh token" }).optional(),
677
+ userId: z$1.string().meta({ description: "The user ID associated with the account" }).optional()
678
+ }),
679
+ metadata: { openapi: {
680
+ description: "Refresh the access token using a refresh token",
681
+ responses: {
682
+ 200: {
683
+ description: "Access token refreshed successfully",
684
+ content: { "application/json": { schema: {
685
+ type: "object",
686
+ properties: {
687
+ tokenType: { type: "string" },
688
+ idToken: { type: "string" },
689
+ accessToken: { type: "string" },
690
+ refreshToken: { type: "string" },
691
+ accessTokenExpiresAt: {
692
+ type: "string",
693
+ format: "date-time"
694
+ },
695
+ refreshTokenExpiresAt: {
696
+ type: "string",
697
+ format: "date-time"
698
+ }
699
+ }
700
+ } } }
701
+ },
702
+ 400: { description: "Invalid refresh token or provider configuration" }
703
+ }
704
+ } }
705
+ }, async (ctx) => {
706
+ const { providerId, accountId, userId } = ctx.body;
707
+ const req = ctx.request;
708
+ const session = await getSessionFromCtx(ctx);
709
+ if (req && !session) throw ctx.error("UNAUTHORIZED");
710
+ let resolvedUserId = session?.user?.id || userId;
711
+ if (!resolvedUserId) throw new APIError("BAD_REQUEST", { message: `Either userId or session is required` });
712
+ const account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.id === accountId && acc.providerId === providerId : acc.providerId === providerId);
713
+ if (!account) throw new APIError("BAD_REQUEST", { message: "Account not found" });
714
+ const provider = ctx.context.socialProviders.find((p) => p.id === providerId);
715
+ if (!provider) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} not found.` });
716
+ if (!provider.refreshAccessToken) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} does not support token refreshing.` });
717
+ try {
718
+ const tokens = await provider.refreshAccessToken(account.refreshToken);
719
+ await ctx.context.internalAdapter.updateAccount(account.id, {
720
+ accessToken: await setTokenUtil(tokens.accessToken, ctx.context),
721
+ refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context),
722
+ accessTokenExpiresAt: tokens.accessTokenExpiresAt,
723
+ refreshTokenExpiresAt: tokens.refreshTokenExpiresAt
724
+ });
725
+ return ctx.json(tokens);
726
+ } catch (error$1) {
727
+ throw new APIError("BAD_REQUEST", {
728
+ message: "Failed to refresh access token",
729
+ cause: error$1
730
+ });
731
+ }
732
+ });
733
+ const accountInfo = createAuthEndpoint("/account-info", {
734
+ method: "POST",
735
+ use: [sessionMiddleware],
736
+ metadata: { openapi: {
737
+ description: "Get the account info provided by the provider",
738
+ responses: { "200": {
739
+ description: "Success",
740
+ content: { "application/json": { schema: {
741
+ type: "object",
742
+ properties: {
743
+ user: {
744
+ type: "object",
745
+ properties: {
746
+ id: { type: "string" },
747
+ name: { type: "string" },
748
+ email: { type: "string" },
749
+ image: { type: "string" },
750
+ emailVerified: { type: "boolean" }
751
+ },
752
+ required: ["id", "emailVerified"]
753
+ },
754
+ data: {
755
+ type: "object",
756
+ properties: {},
757
+ additionalProperties: true
758
+ }
759
+ },
760
+ required: ["user", "data"],
761
+ additionalProperties: false
762
+ } } }
763
+ } }
764
+ } },
765
+ body: z$1.object({ accountId: z$1.string().meta({ description: "The provider given account id for which to get the account info" }) })
766
+ }, async (ctx) => {
767
+ const account = await ctx.context.internalAdapter.findAccount(ctx.body.accountId);
768
+ if (!account || account.userId !== ctx.context.session.user.id) throw new APIError("BAD_REQUEST", { message: "Account not found" });
769
+ const provider = ctx.context.socialProviders.find((p) => p.id === account.providerId);
770
+ if (!provider) throw new APIError("INTERNAL_SERVER_ERROR", { message: `Provider account provider is ${account.providerId} but it is not configured` });
771
+ const tokens = await getAccessToken({
772
+ ...ctx,
773
+ body: {
774
+ accountId: account.id,
775
+ providerId: account.providerId
776
+ },
777
+ returnHeaders: false
778
+ });
779
+ if (!tokens.accessToken) throw new APIError("BAD_REQUEST", { message: "Access token not found" });
780
+ const info = await provider.getUserInfo({
781
+ ...tokens,
782
+ accessToken: tokens.accessToken
783
+ });
784
+ return ctx.json(info);
785
+ });
786
+
787
+ //#endregion
788
+ //#region src/oauth2/link-account.ts
789
+ async function handleOAuthUserInfo(c, { userInfo, account, callbackURL, disableSignUp, overrideUserInfo }) {
790
+ const dbUser = await c.context.internalAdapter.findOAuthUser(userInfo.email.toLowerCase(), account.accountId, account.providerId).catch((e) => {
791
+ logger.error("Payvo Auth was unable to query your database.\nError: ", e);
792
+ const errorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`;
793
+ throw c.redirect(`${errorURL}?error=internal_server_error`);
794
+ });
795
+ let user = dbUser?.user;
796
+ let isRegister = !user;
797
+ if (dbUser) {
798
+ const hasBeenLinked = dbUser.accounts.find((a) => a.providerId === account.providerId && a.accountId === account.accountId);
799
+ if (!hasBeenLinked) {
800
+ if (!(c.context.options.account?.accountLinking?.trustedProviders)?.includes(account.providerId) && !userInfo.emailVerified || c.context.options.account?.accountLinking?.enabled === false) {
801
+ if (isDevelopment()) logger.warn(`User already exist but account isn't linked to ${account.providerId}. To read more about how account linking works in Payvo Auth see https://www.payvopayvo.com/docs/concepts/users-accounts#account-linking.`);
802
+ return {
803
+ error: "account not linked",
804
+ data: null
805
+ };
806
+ }
807
+ try {
808
+ await c.context.internalAdapter.linkAccount({
809
+ providerId: account.providerId,
810
+ accountId: userInfo.id.toString(),
811
+ userId: dbUser.user.id,
812
+ accessToken: await setTokenUtil(account.accessToken, c.context),
813
+ refreshToken: await setTokenUtil(account.refreshToken, c.context),
814
+ idToken: account.idToken,
815
+ accessTokenExpiresAt: account.accessTokenExpiresAt,
816
+ refreshTokenExpiresAt: account.refreshTokenExpiresAt,
817
+ scope: account.scope
818
+ });
819
+ } catch (e) {
820
+ logger.error("Unable to link account", e);
821
+ return {
822
+ error: "unable to link account",
823
+ data: null
824
+ };
825
+ }
826
+ if (userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await c.context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true });
827
+ } else {
828
+ if (c.context.options.account?.updateAccountOnSignIn !== false) {
829
+ const updateData = Object.fromEntries(Object.entries({
830
+ idToken: account.idToken,
831
+ accessToken: await setTokenUtil(account.accessToken, c.context),
832
+ refreshToken: await setTokenUtil(account.refreshToken, c.context),
833
+ accessTokenExpiresAt: account.accessTokenExpiresAt,
834
+ refreshTokenExpiresAt: account.refreshTokenExpiresAt,
835
+ scope: account.scope
836
+ }).filter(([_, value]) => value !== void 0));
837
+ if (Object.keys(updateData).length > 0) await c.context.internalAdapter.updateAccount(hasBeenLinked.id, updateData);
838
+ }
839
+ if (userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await c.context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true });
840
+ }
841
+ if (overrideUserInfo) {
842
+ const { id: _,...restUserInfo } = userInfo;
843
+ await c.context.internalAdapter.updateUser(dbUser.user.id, {
844
+ ...restUserInfo,
845
+ email: userInfo.email.toLowerCase(),
846
+ emailVerified: userInfo.email.toLowerCase() === dbUser.user.email ? dbUser.user.emailVerified || userInfo.emailVerified : userInfo.emailVerified
847
+ });
848
+ }
849
+ } else {
850
+ if (disableSignUp) return {
851
+ error: "signup disabled",
852
+ data: null,
853
+ isRegister: false
854
+ };
855
+ try {
856
+ const { id: _,...restUserInfo } = userInfo;
857
+ user = await c.context.internalAdapter.createOAuthUser({
858
+ ...restUserInfo,
859
+ email: userInfo.email.toLowerCase()
860
+ }, {
861
+ accessToken: await setTokenUtil(account.accessToken, c.context),
862
+ refreshToken: await setTokenUtil(account.refreshToken, c.context),
863
+ idToken: account.idToken,
864
+ accessTokenExpiresAt: account.accessTokenExpiresAt,
865
+ refreshTokenExpiresAt: account.refreshTokenExpiresAt,
866
+ scope: account.scope,
867
+ providerId: account.providerId,
868
+ accountId: userInfo.id.toString()
869
+ }).then((res) => res?.user);
870
+ if (!userInfo.emailVerified && user && c.context.options.emailVerification?.sendOnSignUp) {
871
+ const token = await createEmailVerificationToken(c.context.secret, user.email, void 0, c.context.options.emailVerification?.expiresIn);
872
+ const url = `${c.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`;
873
+ await c.context.options.emailVerification?.sendVerificationEmail?.({
874
+ user,
875
+ url,
876
+ token
877
+ }, c.request);
878
+ }
879
+ } catch (e) {
880
+ logger.error(e);
881
+ if (e instanceof APIError$1) return {
882
+ error: e.message,
883
+ data: null,
884
+ isRegister: false
885
+ };
886
+ return {
887
+ error: "unable to create user",
888
+ data: null,
889
+ isRegister: false
890
+ };
891
+ }
892
+ }
893
+ if (!user) return {
894
+ error: "unable to create user",
895
+ data: null,
896
+ isRegister: false
897
+ };
898
+ const session = await c.context.internalAdapter.createSession(user.id);
899
+ if (!session) return {
900
+ error: "unable to create session",
901
+ data: null,
902
+ isRegister: false
903
+ };
904
+ return {
905
+ data: {
906
+ session,
907
+ user
908
+ },
909
+ error: null,
910
+ isRegister
911
+ };
912
+ }
913
+
914
+ //#endregion
915
+ //#region src/api/routes/callback.ts
916
+ const schema = z$1.object({
917
+ code: z$1.string().optional(),
918
+ error: z$1.string().optional(),
919
+ device_id: z$1.string().optional(),
920
+ error_description: z$1.string().optional(),
921
+ state: z$1.string().optional(),
922
+ user: z$1.string().optional()
923
+ });
924
+ const callbackOAuth = createAuthEndpoint("/callback/:id", {
925
+ method: ["GET", "POST"],
926
+ body: schema.optional(),
927
+ query: schema.optional(),
928
+ metadata: HIDE_METADATA
929
+ }, async (c) => {
930
+ let queryOrBody;
931
+ const defaultErrorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`;
932
+ if (c.method === "POST") {
933
+ const postData = c.body ? schema.parse(c.body) : {};
934
+ const queryData = c.query ? schema.parse(c.query) : {};
935
+ const mergedData = schema.parse({
936
+ ...postData,
937
+ ...queryData
938
+ });
939
+ const params = new URLSearchParams();
940
+ for (const [key, value] of Object.entries(mergedData)) if (value !== void 0 && value !== null) params.set(key, String(value));
941
+ const redirectURL = `${c.context.baseURL}/callback/${c.params.id}?${params.toString()}`;
942
+ throw c.redirect(redirectURL);
943
+ }
944
+ try {
945
+ if (c.method === "GET") queryOrBody = schema.parse(c.query);
946
+ else if (c.method === "POST") queryOrBody = schema.parse(c.body);
947
+ else throw new Error("Unsupported method");
948
+ } catch (e) {
949
+ c.context.logger.error("INVALID_CALLBACK_REQUEST", e);
950
+ throw c.redirect(`${defaultErrorURL}?error=invalid_callback_request`);
951
+ }
952
+ const { code, error: error$1, state, error_description, device_id } = queryOrBody;
953
+ if (!state) {
954
+ c.context.logger.error("State not found", error$1);
955
+ const url = `${defaultErrorURL}${defaultErrorURL.includes("?") ? "&" : "?"}state=state_not_found`;
956
+ throw c.redirect(url);
957
+ }
958
+ const { codeVerifier, callbackURL, link, errorURL, newUserURL, requestSignUp } = await parseState(c);
959
+ function redirectOnError(error$2, description) {
960
+ const baseURL = errorURL ?? defaultErrorURL;
961
+ const params = new URLSearchParams({ error: error$2 });
962
+ if (description) params.set("error_description", description);
963
+ const url = `${baseURL}${baseURL.includes("?") ? "&" : "?"}${params.toString()}`;
964
+ throw c.redirect(url);
965
+ }
966
+ if (error$1) redirectOnError(error$1, error_description);
967
+ if (!code) {
968
+ c.context.logger.error("Code not found");
969
+ throw redirectOnError("no_code");
970
+ }
971
+ const provider = c.context.socialProviders.find((p) => p.id === c.params.id);
972
+ if (!provider) {
973
+ c.context.logger.error("Oauth provider with id", c.params.id, "not found");
974
+ throw redirectOnError("oauth_provider_not_found");
975
+ }
976
+ let tokens;
977
+ try {
978
+ tokens = await provider.validateAuthorizationCode({
979
+ code,
980
+ codeVerifier,
981
+ deviceId: device_id,
982
+ redirectURI: `${c.context.baseURL}/callback/${provider.id}`
983
+ });
984
+ } catch (e) {
985
+ c.context.logger.error("", e);
986
+ throw redirectOnError("invalid_code");
987
+ }
988
+ const userInfo = await provider.getUserInfo({
989
+ ...tokens,
990
+ user: c.body?.user ? safeJSONParse(c.body.user) : void 0
991
+ }).then((res) => res?.user);
992
+ if (!userInfo) {
993
+ c.context.logger.error("Unable to get user info");
994
+ return redirectOnError("unable_to_get_user_info");
995
+ }
996
+ if (!callbackURL) {
997
+ c.context.logger.error("No callback URL found");
998
+ throw redirectOnError("no_callback_url");
999
+ }
1000
+ if (link) {
1001
+ if (!(c.context.options.account?.accountLinking?.trustedProviders)?.includes(provider.id) && !userInfo.emailVerified || c.context.options.account?.accountLinking?.enabled === false) {
1002
+ c.context.logger.error("Unable to link account - untrusted provider");
1003
+ return redirectOnError("unable_to_link_account");
1004
+ }
1005
+ if (userInfo.email !== link.email && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) return redirectOnError("email_doesn't_match");
1006
+ const existingAccount = await c.context.internalAdapter.findAccount(String(userInfo.id));
1007
+ if (existingAccount) {
1008
+ if (existingAccount.userId.toString() !== link.userId.toString()) return redirectOnError("account_already_linked_to_different_user");
1009
+ const updateData = Object.fromEntries(Object.entries({
1010
+ accessToken: await setTokenUtil(tokens.accessToken, c.context),
1011
+ refreshToken: await setTokenUtil(tokens.refreshToken, c.context),
1012
+ idToken: tokens.idToken,
1013
+ accessTokenExpiresAt: tokens.accessTokenExpiresAt,
1014
+ refreshTokenExpiresAt: tokens.refreshTokenExpiresAt,
1015
+ scope: tokens.scopes?.join(",")
1016
+ }).filter(([_, value]) => value !== void 0));
1017
+ await c.context.internalAdapter.updateAccount(existingAccount.id, updateData);
1018
+ } else if (!await c.context.internalAdapter.createAccount({
1019
+ userId: link.userId,
1020
+ providerId: provider.id,
1021
+ accountId: String(userInfo.id),
1022
+ ...tokens,
1023
+ accessToken: await setTokenUtil(tokens.accessToken, c.context),
1024
+ refreshToken: await setTokenUtil(tokens.refreshToken, c.context),
1025
+ scope: tokens.scopes?.join(",")
1026
+ })) return redirectOnError("unable_to_link_account");
1027
+ let toRedirectTo$1;
1028
+ try {
1029
+ toRedirectTo$1 = callbackURL.toString();
1030
+ } catch {
1031
+ toRedirectTo$1 = callbackURL;
1032
+ }
1033
+ throw c.redirect(toRedirectTo$1);
1034
+ }
1035
+ if (!userInfo.email) {
1036
+ c.context.logger.error("Provider did not return email. This could be due to misconfiguration in the provider settings.");
1037
+ return redirectOnError("email_not_found");
1038
+ }
1039
+ const result = await handleOAuthUserInfo(c, {
1040
+ userInfo: {
1041
+ ...userInfo,
1042
+ id: String(userInfo.id),
1043
+ email: userInfo.email,
1044
+ name: userInfo.name || userInfo.email
1045
+ },
1046
+ account: {
1047
+ providerId: provider.id,
1048
+ accountId: String(userInfo.id),
1049
+ ...tokens,
1050
+ scope: tokens.scopes?.join(",")
1051
+ },
1052
+ callbackURL,
1053
+ disableSignUp: provider.disableImplicitSignUp && !requestSignUp || provider.options?.disableSignUp,
1054
+ overrideUserInfo: provider.options?.overrideUserInfoOnSignIn
1055
+ });
1056
+ if (result.error) {
1057
+ c.context.logger.error(result.error.split(" ").join("_"));
1058
+ return redirectOnError(result.error.split(" ").join("_"));
1059
+ }
1060
+ const { session, user } = result.data;
1061
+ await setSessionCookie(c, {
1062
+ session,
1063
+ user
1064
+ });
1065
+ let toRedirectTo;
1066
+ try {
1067
+ toRedirectTo = (result.isRegister ? newUserURL || callbackURL : callbackURL).toString();
1068
+ } catch {
1069
+ toRedirectTo = result.isRegister ? newUserURL || callbackURL : callbackURL;
1070
+ }
1071
+ throw c.redirect(toRedirectTo);
1072
+ });
1073
+
1074
+ //#endregion
1075
+ //#region src/api/routes/email-verification.ts
1076
+ async function createEmailVerificationToken(secret, email, updateTo, expiresIn = 3600) {
1077
+ return await signJWT({
1078
+ email: email.toLowerCase(),
1079
+ updateTo
1080
+ }, secret, expiresIn);
1081
+ }
1082
+ /**
1083
+ * A function to send a verification email to the user
1084
+ */
1085
+ async function sendVerificationEmailFn(ctx, user) {
1086
+ if (!ctx.context.options.emailVerification?.sendVerificationEmail) {
1087
+ ctx.context.logger.error("Verification email isn't enabled.");
1088
+ throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" });
1089
+ }
1090
+ const token = await createEmailVerificationToken(ctx.context.secret, user.email, void 0, ctx.context.options.emailVerification?.expiresIn);
1091
+ const callbackURL = ctx.body.callbackURL ? encodeURIComponent(ctx.body.callbackURL) : encodeURIComponent("/");
1092
+ const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`;
1093
+ await ctx.context.options.emailVerification.sendVerificationEmail({
1094
+ user,
1095
+ url,
1096
+ token
1097
+ }, ctx.request);
1098
+ }
1099
+ const sendVerificationEmail = createAuthEndpoint("/send-verification-email", {
1100
+ method: "POST",
1101
+ body: z$1.object({
1102
+ email: z$1.email().meta({ description: "The email to send the verification email to" }),
1103
+ callbackURL: z$1.string().meta({ description: "The URL to use for email verification callback" }).optional()
1104
+ }),
1105
+ metadata: { openapi: {
1106
+ description: "Send a verification email to the user",
1107
+ requestBody: { content: { "application/json": { schema: {
1108
+ type: "object",
1109
+ properties: {
1110
+ email: {
1111
+ type: "string",
1112
+ description: "The email to send the verification email to",
1113
+ example: "user@example.com"
1114
+ },
1115
+ callbackURL: {
1116
+ type: "string",
1117
+ description: "The URL to use for email verification callback",
1118
+ example: "https://example.com/callback",
1119
+ nullable: true
1120
+ }
1121
+ },
1122
+ required: ["email"]
1123
+ } } } },
1124
+ responses: {
1125
+ "200": {
1126
+ description: "Success",
1127
+ content: { "application/json": { schema: {
1128
+ type: "object",
1129
+ properties: { status: {
1130
+ type: "boolean",
1131
+ description: "Indicates if the email was sent successfully",
1132
+ example: true
1133
+ } }
1134
+ } } }
1135
+ },
1136
+ "400": {
1137
+ description: "Bad Request",
1138
+ content: { "application/json": { schema: {
1139
+ type: "object",
1140
+ properties: { message: {
1141
+ type: "string",
1142
+ description: "Error message",
1143
+ example: "Verification email isn't enabled"
1144
+ } }
1145
+ } } }
1146
+ }
1147
+ }
1148
+ } }
1149
+ }, async (ctx) => {
1150
+ if (!ctx.context.options.emailVerification?.sendVerificationEmail) {
1151
+ ctx.context.logger.error("Verification email isn't enabled.");
1152
+ throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" });
1153
+ }
1154
+ const { email } = ctx.body;
1155
+ const session = await getSessionFromCtx(ctx);
1156
+ if (!session) {
1157
+ const user = await ctx.context.internalAdapter.findUserByEmail(email);
1158
+ if (!user) return ctx.json({ status: true });
1159
+ await sendVerificationEmailFn(ctx, user.user);
1160
+ return ctx.json({ status: true });
1161
+ }
1162
+ if (session?.user.emailVerified) throw new APIError("BAD_REQUEST", { message: "You can only send a verification email to an unverified email" });
1163
+ if (session?.user.email !== email) throw new APIError("BAD_REQUEST", { message: "You can only send a verification email to your own email" });
1164
+ await sendVerificationEmailFn(ctx, session.user);
1165
+ return ctx.json({ status: true });
1166
+ });
1167
+ const verifyEmail = createAuthEndpoint("/verify-email", {
1168
+ method: "GET",
1169
+ query: z$1.object({
1170
+ token: z$1.string().meta({ description: "The token to verify the email" }),
1171
+ callbackURL: z$1.string().meta({ description: "The URL to redirect to after email verification" }).optional()
1172
+ }),
1173
+ use: [originCheck((ctx) => ctx.query.callbackURL)],
1174
+ metadata: { openapi: {
1175
+ description: "Verify the email of the user",
1176
+ parameters: [{
1177
+ name: "token",
1178
+ in: "query",
1179
+ description: "The token to verify the email",
1180
+ required: true,
1181
+ schema: { type: "string" }
1182
+ }, {
1183
+ name: "callbackURL",
1184
+ in: "query",
1185
+ description: "The URL to redirect to after email verification",
1186
+ required: false,
1187
+ schema: { type: "string" }
1188
+ }],
1189
+ responses: { "200": {
1190
+ description: "Success",
1191
+ content: { "application/json": { schema: {
1192
+ type: "object",
1193
+ properties: {
1194
+ user: {
1195
+ type: "object",
1196
+ properties: {
1197
+ id: {
1198
+ type: "string",
1199
+ description: "User ID"
1200
+ },
1201
+ email: {
1202
+ type: "string",
1203
+ description: "User email"
1204
+ },
1205
+ name: {
1206
+ type: "string",
1207
+ description: "User name"
1208
+ },
1209
+ image: {
1210
+ type: "string",
1211
+ description: "User image URL"
1212
+ },
1213
+ emailVerified: {
1214
+ type: "boolean",
1215
+ description: "Indicates if the user email is verified"
1216
+ },
1217
+ createdAt: {
1218
+ type: "string",
1219
+ description: "User creation date"
1220
+ },
1221
+ updatedAt: {
1222
+ type: "string",
1223
+ description: "User update date"
1224
+ }
1225
+ },
1226
+ required: [
1227
+ "id",
1228
+ "email",
1229
+ "name",
1230
+ "image",
1231
+ "emailVerified",
1232
+ "createdAt",
1233
+ "updatedAt"
1234
+ ]
1235
+ },
1236
+ status: {
1237
+ type: "boolean",
1238
+ description: "Indicates if the email was verified successfully"
1239
+ }
1240
+ },
1241
+ required: ["user", "status"]
1242
+ } } }
1243
+ } }
1244
+ } }
1245
+ }, async (ctx) => {
1246
+ function redirectOnError(error$1) {
1247
+ if (ctx.query.callbackURL) {
1248
+ if (ctx.query.callbackURL.includes("?")) throw ctx.redirect(`${ctx.query.callbackURL}&error=${error$1}`);
1249
+ throw ctx.redirect(`${ctx.query.callbackURL}?error=${error$1}`);
1250
+ }
1251
+ throw new APIError("UNAUTHORIZED", { message: error$1 });
1252
+ }
1253
+ const { token } = ctx.query;
1254
+ let jwt;
1255
+ try {
1256
+ jwt = await jwtVerify(token, new TextEncoder().encode(ctx.context.secret), { algorithms: ["HS256"] });
1257
+ } catch (e) {
1258
+ if (e instanceof JWTExpired) return redirectOnError("token_expired");
1259
+ return redirectOnError("invalid_token");
1260
+ }
1261
+ const parsed = z$1.object({
1262
+ email: z$1.string().email(),
1263
+ updateTo: z$1.string().optional()
1264
+ }).parse(jwt.payload);
1265
+ const user = await ctx.context.internalAdapter.findUserByEmail(parsed.email);
1266
+ if (!user) return redirectOnError("user_not_found");
1267
+ if (parsed.updateTo) {
1268
+ const session = await getSessionFromCtx(ctx);
1269
+ if (!session) {
1270
+ if (ctx.query.callbackURL) throw ctx.redirect(`${ctx.query.callbackURL}?error=unauthorized`);
1271
+ return redirectOnError("unauthorized");
1272
+ }
1273
+ if (session.user.email !== parsed.email) {
1274
+ if (ctx.query.callbackURL) throw ctx.redirect(`${ctx.query.callbackURL}?error=unauthorized`);
1275
+ return redirectOnError("unauthorized");
1276
+ }
1277
+ const updatedUser$1 = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, {
1278
+ email: parsed.updateTo,
1279
+ emailVerified: false
1280
+ });
1281
+ const newToken = await createEmailVerificationToken(ctx.context.secret, parsed.updateTo);
1282
+ const updateCallbackURL = ctx.query.callbackURL ? encodeURIComponent(ctx.query.callbackURL) : encodeURIComponent("/");
1283
+ await ctx.context.options.emailVerification?.sendVerificationEmail?.({
1284
+ user: updatedUser$1,
1285
+ url: `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`,
1286
+ token: newToken
1287
+ }, ctx.request);
1288
+ await setSessionCookie(ctx, {
1289
+ session: session.session,
1290
+ user: {
1291
+ ...session.user,
1292
+ email: parsed.updateTo,
1293
+ emailVerified: false
1294
+ }
1295
+ });
1296
+ if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL);
1297
+ return ctx.json({
1298
+ status: true,
1299
+ user: {
1300
+ id: updatedUser$1.id,
1301
+ email: updatedUser$1.email,
1302
+ name: updatedUser$1.name,
1303
+ image: updatedUser$1.image,
1304
+ emailVerified: updatedUser$1.emailVerified,
1305
+ createdAt: updatedUser$1.createdAt,
1306
+ updatedAt: updatedUser$1.updatedAt
1307
+ }
1308
+ });
1309
+ }
1310
+ if (ctx.context.options.emailVerification?.onEmailVerification) await ctx.context.options.emailVerification.onEmailVerification(user.user, ctx.request);
1311
+ const updatedUser = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, { emailVerified: true });
1312
+ if (ctx.context.options.emailVerification?.afterEmailVerification) await ctx.context.options.emailVerification.afterEmailVerification(updatedUser, ctx.request);
1313
+ if (ctx.context.options.emailVerification?.autoSignInAfterVerification) {
1314
+ const currentSession = await getSessionFromCtx(ctx);
1315
+ if (!currentSession || currentSession.user.email !== parsed.email) {
1316
+ const session = await ctx.context.internalAdapter.createSession(user.user.id);
1317
+ if (!session) throw new APIError("INTERNAL_SERVER_ERROR", { message: "Failed to create session" });
1318
+ await setSessionCookie(ctx, {
1319
+ session,
1320
+ user: {
1321
+ ...user.user,
1322
+ emailVerified: true
1323
+ }
1324
+ });
1325
+ } else await setSessionCookie(ctx, {
1326
+ session: currentSession.session,
1327
+ user: {
1328
+ ...currentSession.user,
1329
+ emailVerified: true
1330
+ }
1331
+ });
1332
+ }
1333
+ if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL);
1334
+ return ctx.json({
1335
+ status: true,
1336
+ user: null
1337
+ });
1338
+ });
1339
+
1340
+ //#endregion
1341
+ //#region src/api/routes/error.ts
1342
+ function sanitize(input) {
1343
+ return input.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/&(?!amp;|lt;|gt;|quot;|#39;|#x[0-9a-fA-F]+;|#[0-9]+;)/g, "&amp;");
1344
+ }
1345
+ const html = (options, code = "Unknown", description = null) => {
1346
+ const custom = options.onAPIError?.customizeDefaultErrorPage;
1347
+ return `<!DOCTYPE html>
1348
+ <html lang="en">
1349
+ <head>
1350
+ <meta charset="UTF-8" />
1351
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
1352
+ <title>Error</title>
1353
+ <style>
1354
+ body {
1355
+ font-family: ${custom?.font?.defaultFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"};
1356
+ background: ${custom?.colors?.background || "var(--background)"};
1357
+ color: var(--foreground);
1358
+ margin: 0;
1359
+ }
1360
+ :root,
1361
+ :host {
1362
+ --spacing: 0.25rem;
1363
+ --container-md: 28rem;
1364
+ --text-sm: ${custom?.size?.textSm || "0.875rem"};
1365
+ --text-sm--line-height: calc(1.25 / 0.875);
1366
+ --text-2xl: ${custom?.size?.text2xl || "1.5rem"};
1367
+ --text-2xl--line-height: calc(2 / 1.5);
1368
+ --text-4xl: ${custom?.size?.text4xl || "2.25rem"};
1369
+ --text-4xl--line-height: calc(2.5 / 2.25);
1370
+ --text-6xl: ${custom?.size?.text6xl || "3.75rem"};
1371
+ --text-6xl--line-height: 1;
1372
+ --font-weight-medium: 500;
1373
+ --font-weight-semibold: 600;
1374
+ --font-weight-bold: 700;
1375
+ --default-transition-duration: 150ms;
1376
+ --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1377
+ --radius: ${custom?.size?.radiusSm || "0.625rem"};
1378
+ --default-mono-font-family: ${custom?.font?.monoFamily || "var(--font-geist-mono)"};
1379
+ --primary: ${custom?.colors?.primary || "black"};
1380
+ --primary-foreground: ${custom?.colors?.primaryForeground || "white"};
1381
+ --background: ${custom?.colors?.background || "white"};
1382
+ --foreground: ${custom?.colors?.foreground || "oklch(0.271 0 0)"};
1383
+ --border: ${custom?.colors?.border || "oklch(0.89 0 0)"};
1384
+ --destructive: ${custom?.colors?.destructive || "oklch(0.55 0.15 25.723)"};
1385
+ --muted-foreground: ${custom?.colors?.mutedForeground || "oklch(0.545 0 0)"};
1386
+ --corner-border: ${custom?.colors?.cornerBorder || "#404040"};
1387
+ }
1388
+
1389
+ button, .btn {
1390
+ cursor: pointer;
1391
+ background: none;
1392
+ border: none;
1393
+ color: inherit;
1394
+ font: inherit;
1395
+ transition: all var(--default-transition-duration)
1396
+ var(--default-transition-timing-function);
1397
+ }
1398
+ button:hover, .btn:hover {
1399
+ opacity: 0.8;
1400
+ }
1401
+ </style>
1402
+ </head>
1403
+ <body style="width: 100vw; height: 100vh; overflow: hidden;">
1404
+ <div
1405
+ style="
1406
+ display: flex;
1407
+ flex-direction: column;
1408
+ align-items: center;
1409
+ justify-content: center;
1410
+ gap: 1.5rem;
1411
+ position: relative;
1412
+ width: 100vw;
1413
+ height: 100vh;
1414
+ "
1415
+ >
1416
+ ${custom?.disableBackgroundGrid ? "" : `
1417
+ <div
1418
+ style="
1419
+ position: absolute;
1420
+ inset: 0;
1421
+ background-image: linear-gradient(to right, ${custom?.colors?.gridColor || "var(--border)"} 1px, transparent 1px),
1422
+ linear-gradient(to bottom, ${custom?.colors?.gridColor || "var(--border)"} 1px, transparent 1px);
1423
+ opacity: 0.5;
1424
+ background-size: 24px 24px;
1425
+ pointer-events: none;
1426
+ width: 100vw;
1427
+ height: 100vh;
1428
+ "
1429
+ ></div>
1430
+ `}
1431
+
1432
+ <div
1433
+ style="
1434
+ position: relative;
1435
+ z-index: 10;
1436
+ border: 2px solid var(--border);
1437
+ background: ${custom?.colors?.cardBackground || "var(--background)"};
1438
+ padding: 3rem;
1439
+ max-width: 42rem;
1440
+ min-width: 297px;
1441
+ width: 100%;
1442
+ "
1443
+ >
1444
+ ${custom?.disableCornerDecorations ? "" : `
1445
+ <!-- Corner decorations -->
1446
+ <div
1447
+ style="
1448
+ position: absolute;
1449
+ top: -2px;
1450
+ left: -2px;
1451
+ width: 3rem;
1452
+ height: 3rem;
1453
+ border-top: 4px solid var(--corner-border);
1454
+ border-left: 4px solid var(--corner-border);
1455
+ "
1456
+ ></div>
1457
+ <div
1458
+ style="
1459
+ position: absolute;
1460
+ top: -2px;
1461
+ right: -2px;
1462
+ width: 3rem;
1463
+ height: 3rem;
1464
+ border-top: 4px solid var(--corner-border);
1465
+ border-right: 4px solid var(--corner-border);
1466
+ "
1467
+ ></div>
1468
+
1469
+ <div
1470
+ style="
1471
+ position: absolute;
1472
+ bottom: -2px;
1473
+ left: -2px;
1474
+ width: 3rem;
1475
+ height: 3rem;
1476
+ border-bottom: 4px solid var(--corner-border);
1477
+ border-left: 4px solid var(--corner-border);
1478
+ "
1479
+ ></div>
1480
+ <div
1481
+ style="
1482
+ position: absolute;
1483
+ bottom: -2px;
1484
+ right: -2px;
1485
+ width: 3rem;
1486
+ height: 3rem;
1487
+ border-bottom: 4px solid var(--corner-border);
1488
+ border-right: 4px solid var(--corner-border);
1489
+ "
1490
+ ></div>`}
1491
+
1492
+ <div style="text-align: center; margin-bottom: 2rem;">
1493
+ <div style="margin-bottom: 1.5rem;">
1494
+ <div
1495
+ style="
1496
+ display: inline-block;
1497
+ border: 2px solid ${custom?.disableTitleBorder ? "transparent" : custom?.colors?.titleBorder || "var(--destructive)"};
1498
+ padding: 0.5rem 1.5rem;
1499
+ "
1500
+ >
1501
+ <h1
1502
+ style="
1503
+ font-size: var(--text-6xl);
1504
+ font-weight: var(--font-weight-bold);
1505
+ color: ${custom?.colors?.titleColor || "var(--foreground)"};
1506
+ letter-spacing: -0.02em;
1507
+ margin: 0;
1508
+ "
1509
+ >
1510
+ ERROR
1511
+ </h1>
1512
+ </div>
1513
+ <div
1514
+ style="
1515
+ height: 1px;
1516
+ background-color: var(--border);
1517
+ width: 100%;
1518
+ margin-top: 1rem;
1519
+ "
1520
+ ></div>
1521
+ </div>
1522
+
1523
+ <h2
1524
+ style="
1525
+ font-size: var(--text-2xl);
1526
+ font-weight: var(--font-weight-semibold);
1527
+ color: var(--foreground);
1528
+ margin: 0 0 1.5rem;
1529
+ "
1530
+ >
1531
+ Something went wrong
1532
+ </h2>
1533
+
1534
+ <div
1535
+ style="
1536
+ display: inline-flex;
1537
+ align-items: center;
1538
+ gap: 0.5rem;
1539
+ border: 2px solid var(--border);
1540
+ background-color: var(--muted);
1541
+ padding: 0.5rem 1rem;
1542
+ margin: 0 0 1.5rem;
1543
+ "
1544
+ >
1545
+ <span
1546
+ style="
1547
+ font-size: 0.75rem;
1548
+ color: var(--muted-foreground);
1549
+ font-weight: var(--font-weight-semibold);
1550
+ "
1551
+ >
1552
+ CODE:
1553
+ </span>
1554
+ <span
1555
+ style="
1556
+ font-size: var(--text-sm);
1557
+ font-family: var(--default-mono-font-family, monospace);
1558
+ color: var(--foreground);
1559
+ "
1560
+ >
1561
+ ${sanitize(code)}
1562
+ </span>
1563
+ </div>
1564
+
1565
+ <p
1566
+ style="
1567
+ color: var(--muted-foreground);
1568
+ max-width: 28rem;
1569
+ margin: 0 auto;
1570
+ border-left: 2px solid var(--border);
1571
+ padding-left: 1rem;
1572
+ "
1573
+ >
1574
+ ${!description ? `We encountered an unexpected error. Please try again or return to the home page. If you're a developer, you can find more information about the error <a href='https://payvopayvo.com/docs/errors/${encodeURIComponent(code)}' target='_blank' rel="noopener noreferrer" style='color: var(--foreground); text-decoration: underline;'>here</a>.` : description}
1575
+ </p>
1576
+ </div>
1577
+
1578
+ <div
1579
+ style="
1580
+ display: flex;
1581
+ gap: 1rem;
1582
+ margin-top: 2rem;
1583
+ justify-content: center;
1584
+ "
1585
+ >
1586
+ <a
1587
+ href="/"
1588
+ style="
1589
+ text-decoration: none;
1590
+ "
1591
+ >
1592
+ <div
1593
+ style="
1594
+ border: 2px solid var(--border);
1595
+ background: var(--primary);
1596
+ color: var(--primary-foreground);
1597
+ padding: 0.5rem 1.25rem;
1598
+ border-radius: 0;
1599
+ "
1600
+ class="btn"
1601
+ >
1602
+ Go Home
1603
+ </div>
1604
+ </a>
1605
+ <a
1606
+ href="https://payvopayvo.com/docs/errors/${encodeURIComponent(code)}?askai=${encodeURIComponent(`What does the error code ${code} mean?`)}"
1607
+ target="_blank"
1608
+ rel="noopener noreferrer"
1609
+ style="
1610
+ text-decoration: none;
1611
+ "
1612
+ >
1613
+ <div
1614
+ style="
1615
+ border: 2px solid var(--border);
1616
+ background: transparent;
1617
+ color: var(--foreground);
1618
+ padding: 0.5rem 1.25rem;
1619
+ border-radius: 0;
1620
+ "
1621
+ class="btn"
1622
+ >
1623
+ Ask AI
1624
+ </div>
1625
+ </a>
1626
+ </div>
1627
+ </div>
1628
+ </div>
1629
+ </body>
1630
+ </html>`;
1631
+ };
1632
+ const error = createAuthEndpoint("/error", {
1633
+ method: "GET",
1634
+ metadata: {
1635
+ ...HIDE_METADATA,
1636
+ openapi: {
1637
+ description: "Displays an error page",
1638
+ responses: { "200": {
1639
+ description: "Success",
1640
+ content: { "text/html": { schema: {
1641
+ type: "string",
1642
+ description: "The HTML content of the error page"
1643
+ } } }
1644
+ } }
1645
+ }
1646
+ }
1647
+ }, async (c) => {
1648
+ const url = new URL(c.request?.url || "");
1649
+ const unsanitizedCode = url.searchParams.get("error") || "UNKNOWN";
1650
+ const unsanitizedDescription = url.searchParams.get("error_description") || null;
1651
+ const safeCode = /^[\'A-Za-z0-9_-]+$/.test(unsanitizedCode || "") ? unsanitizedCode : "UNKNOWN";
1652
+ const safeDescription = unsanitizedDescription ? sanitize(unsanitizedDescription) : null;
1653
+ const queryParams = new URLSearchParams();
1654
+ queryParams.set("error", safeCode);
1655
+ if (unsanitizedDescription) queryParams.set("error_description", unsanitizedDescription);
1656
+ const options = c.context.options;
1657
+ const errorURL = options.onAPIError?.errorURL;
1658
+ if (errorURL) return new Response(null, {
1659
+ status: 302,
1660
+ headers: { Location: `${errorURL}${errorURL.includes("?") ? "&" : "?"}${queryParams.toString()}` }
1661
+ });
1662
+ if (isProduction && !options.onAPIError?.customizeDefaultErrorPage) return new Response(null, {
1663
+ status: 302,
1664
+ headers: { Location: `/?${queryParams.toString()}` }
1665
+ });
1666
+ return new Response(html(c.context.options, safeCode, safeDescription), { headers: { "Content-Type": "text/html" } });
1667
+ });
1668
+
1669
+ //#endregion
1670
+ //#region src/api/routes/ok.ts
1671
+ const ok = createAuthEndpoint("/ok", {
1672
+ method: "GET",
1673
+ metadata: {
1674
+ ...HIDE_METADATA,
1675
+ openapi: {
1676
+ description: "Check if the API is working",
1677
+ responses: { "200": {
1678
+ description: "API is working",
1679
+ content: { "application/json": { schema: {
1680
+ type: "object",
1681
+ properties: { ok: {
1682
+ type: "boolean",
1683
+ description: "Indicates if the API is working"
1684
+ } },
1685
+ required: ["ok"]
1686
+ } } }
1687
+ } }
1688
+ }
1689
+ }
1690
+ }, async (ctx) => {
1691
+ return ctx.json({ ok: true });
1692
+ });
1693
+
1694
+ //#endregion
1695
+ //#region src/api/routes/reset-password.ts
1696
+ function redirectError(ctx, callbackURL, query) {
1697
+ const url = callbackURL ? new URL(callbackURL, ctx.baseURL) : new URL(`${ctx.baseURL}/error`);
1698
+ if (query) Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));
1699
+ return url.href;
1700
+ }
1701
+ function redirectCallback(ctx, callbackURL, query) {
1702
+ const url = new URL(callbackURL, ctx.baseURL);
1703
+ if (query) Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));
1704
+ return url.href;
1705
+ }
1706
+ const requestPasswordReset = createAuthEndpoint("/request-password-reset", {
1707
+ method: "POST",
1708
+ body: z$1.object({
1709
+ email: z$1.email().meta({ description: "The email address of the user to send a password reset email to" }),
1710
+ redirectTo: z$1.string().meta({ description: "The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter `?error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN" }).optional()
1711
+ }),
1712
+ metadata: { openapi: {
1713
+ description: "Send a password reset email to the user",
1714
+ responses: { "200": {
1715
+ description: "Success",
1716
+ content: { "application/json": { schema: {
1717
+ type: "object",
1718
+ properties: {
1719
+ status: { type: "boolean" },
1720
+ message: { type: "string" }
1721
+ }
1722
+ } } }
1723
+ } }
1724
+ } }
1725
+ }, async (ctx) => {
1726
+ if (!ctx.context.options.emailAndPassword?.sendResetPassword) {
1727
+ ctx.context.logger.error("Reset password isn't enabled.Please pass an emailAndPassword.sendResetPassword function in your auth config!");
1728
+ throw new APIError("BAD_REQUEST", { message: "Reset password isn't enabled" });
1729
+ }
1730
+ const { email, redirectTo } = ctx.body;
1731
+ const user = await ctx.context.internalAdapter.findUserByEmail(email, { includeAccounts: true });
1732
+ if (!user) {
1733
+ ctx.context.logger.error("Reset Password: User not found", { email });
1734
+ return ctx.json({
1735
+ status: true,
1736
+ message: "If this email exists in our system, check your email for the reset link"
1737
+ });
1738
+ }
1739
+ const expiresAt = getDate(ctx.context.options.emailAndPassword.resetPasswordTokenExpiresIn || 3600 * 1, "sec");
1740
+ const verificationToken = generateId(24);
1741
+ await ctx.context.internalAdapter.createVerificationValue({
1742
+ value: user.user.id,
1743
+ identifier: `reset-password:${verificationToken}`,
1744
+ expiresAt
1745
+ });
1746
+ const callbackURL = redirectTo ? encodeURIComponent(redirectTo) : "";
1747
+ const url = `${ctx.context.baseURL}/reset-password/${verificationToken}?callbackURL=${callbackURL}`;
1748
+ await ctx.context.options.emailAndPassword.sendResetPassword({
1749
+ user: user.user,
1750
+ url,
1751
+ token: verificationToken
1752
+ }, ctx.request);
1753
+ return ctx.json({
1754
+ status: true,
1755
+ message: "If this email exists in our system, check your email for the reset link"
1756
+ });
1757
+ });
1758
+ const requestPasswordResetCallback = createAuthEndpoint("/reset-password/:token", {
1759
+ method: "GET",
1760
+ query: z$1.object({ callbackURL: z$1.string().meta({ description: "The URL to redirect the user to reset their password" }) }),
1761
+ use: [originCheck((ctx) => ctx.query.callbackURL)],
1762
+ metadata: { openapi: {
1763
+ description: "Redirects the user to the callback URL with the token",
1764
+ responses: { "200": {
1765
+ description: "Success",
1766
+ content: { "application/json": { schema: {
1767
+ type: "object",
1768
+ properties: { token: { type: "string" } }
1769
+ } } }
1770
+ } }
1771
+ } }
1772
+ }, async (ctx) => {
1773
+ const { token } = ctx.params;
1774
+ const { callbackURL } = ctx.query;
1775
+ if (!token || !callbackURL) throw ctx.redirect(redirectError(ctx.context, callbackURL, { error: "INVALID_TOKEN" }));
1776
+ const verification = await ctx.context.internalAdapter.findVerificationValue(`reset-password:${token}`);
1777
+ if (!verification || verification.expiresAt < /* @__PURE__ */ new Date()) throw ctx.redirect(redirectError(ctx.context, callbackURL, { error: "INVALID_TOKEN" }));
1778
+ throw ctx.redirect(redirectCallback(ctx.context, callbackURL, { token }));
1779
+ });
1780
+ const resetPassword = createAuthEndpoint("/reset-password", {
1781
+ method: "POST",
1782
+ query: z$1.object({ token: z$1.string().optional() }).optional(),
1783
+ body: z$1.object({
1784
+ newPassword: z$1.string().meta({ description: "The new password to set" }),
1785
+ token: z$1.string().meta({ description: "The token to reset the password" }).optional()
1786
+ }),
1787
+ metadata: { openapi: {
1788
+ description: "Reset the password for a user",
1789
+ responses: { "200": {
1790
+ description: "Success",
1791
+ content: { "application/json": { schema: {
1792
+ type: "object",
1793
+ properties: { status: { type: "boolean" } }
1794
+ } } }
1795
+ } }
1796
+ } }
1797
+ }, async (ctx) => {
1798
+ const token = ctx.body.token || ctx.query?.token;
1799
+ if (!token) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_TOKEN });
1800
+ const { newPassword } = ctx.body;
1801
+ const minLength = ctx.context.password?.config.minPasswordLength;
1802
+ const maxLength = ctx.context.password?.config.maxPasswordLength;
1803
+ if (newPassword.length < minLength) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT });
1804
+ if (newPassword.length > maxLength) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG });
1805
+ const id = `reset-password:${token}`;
1806
+ const verification = await ctx.context.internalAdapter.findVerificationValue(id);
1807
+ if (!verification || verification.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_TOKEN });
1808
+ const userId = verification.value;
1809
+ const hashedPassword = await ctx.context.password.hash(newPassword);
1810
+ if (!(await ctx.context.internalAdapter.findAccounts(userId)).find((ac) => ac.providerId === "credential")) await ctx.context.internalAdapter.createAccount({
1811
+ userId,
1812
+ providerId: "credential",
1813
+ password: hashedPassword,
1814
+ accountId: userId
1815
+ });
1816
+ else await ctx.context.internalAdapter.updatePassword(userId, hashedPassword);
1817
+ await ctx.context.internalAdapter.deleteVerificationValue(verification.id);
1818
+ if (ctx.context.options.emailAndPassword?.onPasswordReset) {
1819
+ const user = await ctx.context.internalAdapter.findUserById(userId);
1820
+ if (user) await ctx.context.options.emailAndPassword.onPasswordReset({ user }, ctx.request);
1821
+ }
1822
+ if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) await ctx.context.internalAdapter.deleteSessions(userId);
1823
+ return ctx.json({ status: true });
1824
+ });
1825
+
1826
+ //#endregion
1827
+ //#region src/api/routes/sign-in.ts
1828
+ const signInSocial = createAuthEndpoint("/sign-in/social", {
1829
+ method: "POST",
1830
+ body: z$1.object({
1831
+ callbackURL: z$1.string().meta({ description: "Callback URL to redirect to after the user has signed in" }).optional(),
1832
+ newUserCallbackURL: z$1.string().optional(),
1833
+ errorCallbackURL: z$1.string().meta({ description: "Callback URL to redirect to if an error happens" }).optional(),
1834
+ provider: SocialProviderListEnum,
1835
+ disableRedirect: z$1.boolean().meta({ description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself" }).optional(),
1836
+ idToken: z$1.optional(z$1.object({
1837
+ token: z$1.string().meta({ description: "ID token from the provider" }),
1838
+ nonce: z$1.string().meta({ description: "Nonce used to generate the token" }).optional(),
1839
+ accessToken: z$1.string().meta({ description: "Access token from the provider" }).optional(),
1840
+ refreshToken: z$1.string().meta({ description: "Refresh token from the provider" }).optional(),
1841
+ expiresAt: z$1.number().meta({ description: "Expiry date of the token" }).optional()
1842
+ })),
1843
+ scopes: z$1.array(z$1.string()).meta({ description: "Array of scopes to request from the provider. This will override the default scopes passed." }).optional(),
1844
+ requestSignUp: z$1.boolean().meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider" }).optional(),
1845
+ loginHint: z$1.string().meta({ description: "The login hint to use for the authorization code request" }).optional(),
1846
+ additionalData: z$1.record(z$1.string(), z$1.any()).optional().meta({ description: "Additional data to be passed through the OAuth flow" })
1847
+ }),
1848
+ metadata: { openapi: {
1849
+ description: "Sign in with a social provider",
1850
+ operationId: "socialSignIn",
1851
+ responses: { "200": {
1852
+ description: "Success - Returns either session details or redirect URL",
1853
+ content: { "application/json": { schema: {
1854
+ type: "object",
1855
+ description: "Session response when idToken is provided",
1856
+ properties: {
1857
+ redirect: {
1858
+ type: "boolean",
1859
+ enum: [false]
1860
+ },
1861
+ token: {
1862
+ type: "string",
1863
+ description: "Session token",
1864
+ url: {
1865
+ type: "null",
1866
+ nullable: true
1867
+ },
1868
+ user: {
1869
+ type: "object",
1870
+ properties: {
1871
+ id: { type: "string" },
1872
+ email: { type: "string" },
1873
+ name: {
1874
+ type: "string",
1875
+ nullable: true
1876
+ },
1877
+ image: {
1878
+ type: "string",
1879
+ nullable: true
1880
+ },
1881
+ emailVerified: { type: "boolean" },
1882
+ createdAt: {
1883
+ type: "string",
1884
+ format: "date-time"
1885
+ },
1886
+ updatedAt: {
1887
+ type: "string",
1888
+ format: "date-time"
1889
+ }
1890
+ },
1891
+ required: [
1892
+ "id",
1893
+ "email",
1894
+ "emailVerified",
1895
+ "createdAt",
1896
+ "updatedAt"
1897
+ ]
1898
+ }
1899
+ }
1900
+ },
1901
+ required: [
1902
+ "redirect",
1903
+ "token",
1904
+ "user"
1905
+ ]
1906
+ } } }
1907
+ } }
1908
+ } }
1909
+ }, async (c) => {
1910
+ const provider = c.context.socialProviders.find((p) => p.id === c.body.provider);
1911
+ if (!provider) {
1912
+ c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider });
1913
+ throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND });
1914
+ }
1915
+ if (c.body.idToken) {
1916
+ if (!provider.verifyIdToken) {
1917
+ c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider });
1918
+ throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED });
1919
+ }
1920
+ const { token, nonce } = c.body.idToken;
1921
+ if (!await provider.verifyIdToken(token, nonce)) {
1922
+ c.context.logger.error("Invalid id token", { provider: c.body.provider });
1923
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_TOKEN });
1924
+ }
1925
+ const userInfo = await provider.getUserInfo({
1926
+ idToken: token,
1927
+ accessToken: c.body.idToken.accessToken,
1928
+ refreshToken: c.body.idToken.refreshToken
1929
+ });
1930
+ if (!userInfo || !userInfo?.user) {
1931
+ c.context.logger.error("Failed to get user info", { provider: c.body.provider });
1932
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO });
1933
+ }
1934
+ if (!userInfo.user.email) {
1935
+ c.context.logger.error("User email not found", { provider: c.body.provider });
1936
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND });
1937
+ }
1938
+ const data = await handleOAuthUserInfo(c, {
1939
+ userInfo: {
1940
+ ...userInfo.user,
1941
+ email: userInfo.user.email,
1942
+ id: String(userInfo.user.id),
1943
+ name: userInfo.user.name || "",
1944
+ image: userInfo.user.image,
1945
+ emailVerified: userInfo.user.emailVerified || false
1946
+ },
1947
+ account: {
1948
+ providerId: provider.id,
1949
+ accountId: String(userInfo.user.id),
1950
+ accessToken: c.body.idToken.accessToken
1951
+ },
1952
+ callbackURL: c.body.callbackURL,
1953
+ disableSignUp: provider.disableImplicitSignUp && !c.body.requestSignUp || provider.disableSignUp
1954
+ });
1955
+ if (data.error) throw new APIError("UNAUTHORIZED", { message: data.error });
1956
+ await setSessionCookie(c, data.data);
1957
+ return c.json({
1958
+ redirect: false,
1959
+ token: data.data.session.token,
1960
+ url: void 0,
1961
+ user: {
1962
+ id: data.data.user.id,
1963
+ email: data.data.user.email,
1964
+ name: data.data.user.name,
1965
+ image: data.data.user.image,
1966
+ emailVerified: data.data.user.emailVerified,
1967
+ createdAt: data.data.user.createdAt,
1968
+ updatedAt: data.data.user.updatedAt
1969
+ }
1970
+ });
1971
+ }
1972
+ const { codeVerifier, state } = await generateState(c, void 0, c.body.additionalData);
1973
+ const url = await provider.createAuthorizationURL({
1974
+ state,
1975
+ codeVerifier,
1976
+ redirectURI: `${c.context.baseURL}/callback/${provider.id}`,
1977
+ scopes: c.body.scopes,
1978
+ loginHint: c.body.loginHint
1979
+ });
1980
+ return c.json({
1981
+ url: url.toString(),
1982
+ redirect: !c.body.disableRedirect
1983
+ });
1984
+ });
1985
+ const signInEmail = createAuthEndpoint("/sign-in/email", {
1986
+ method: "POST",
1987
+ body: z$1.object({
1988
+ email: z$1.string().meta({ description: "Email of the user" }),
1989
+ password: z$1.string().meta({ description: "Password of the user" }),
1990
+ callbackURL: z$1.string().meta({ description: "Callback URL to use as a redirect for email verification" }).optional(),
1991
+ rememberMe: z$1.boolean().meta({ description: "If this is false, the session will not be remembered. Default is `true`." }).default(true).optional()
1992
+ }),
1993
+ metadata: { openapi: {
1994
+ description: "Sign in with email and password",
1995
+ responses: { "200": {
1996
+ description: "Success - Returns either session details or redirect URL",
1997
+ content: { "application/json": { schema: {
1998
+ type: "object",
1999
+ description: "Session response when idToken is provided",
2000
+ properties: {
2001
+ redirect: {
2002
+ type: "boolean",
2003
+ enum: [false]
2004
+ },
2005
+ token: {
2006
+ type: "string",
2007
+ description: "Session token"
2008
+ },
2009
+ url: {
2010
+ type: "null",
2011
+ nullable: true
2012
+ },
2013
+ user: {
2014
+ type: "object",
2015
+ properties: {
2016
+ id: { type: "string" },
2017
+ email: { type: "string" },
2018
+ name: {
2019
+ type: "string",
2020
+ nullable: true
2021
+ },
2022
+ image: {
2023
+ type: "string",
2024
+ nullable: true
2025
+ },
2026
+ emailVerified: { type: "boolean" },
2027
+ createdAt: {
2028
+ type: "string",
2029
+ format: "date-time"
2030
+ },
2031
+ updatedAt: {
2032
+ type: "string",
2033
+ format: "date-time"
2034
+ }
2035
+ },
2036
+ required: [
2037
+ "id",
2038
+ "email",
2039
+ "emailVerified",
2040
+ "createdAt",
2041
+ "updatedAt"
2042
+ ]
2043
+ }
2044
+ },
2045
+ required: [
2046
+ "redirect",
2047
+ "token",
2048
+ "user"
2049
+ ]
2050
+ } } }
2051
+ } }
2052
+ } }
2053
+ }, async (ctx) => {
2054
+ if (!ctx.context.options?.emailAndPassword?.enabled) {
2055
+ ctx.context.logger.error("Email and password is not enabled. Make sure to enable it in the options on you `auth.ts` file. Check `https://payvopayvo.com/docs/authentication/email-password` for more!");
2056
+ throw new APIError("BAD_REQUEST", { message: "Email and password is not enabled" });
2057
+ }
2058
+ const { email, password } = ctx.body;
2059
+ if (!z$1.string().email().safeParse(email).success) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_EMAIL });
2060
+ const user = await ctx.context.internalAdapter.findUserByEmail(email, { includeAccounts: true });
2061
+ if (!user) {
2062
+ await ctx.context.password.hash(password);
2063
+ ctx.context.logger.error("User not found", { email });
2064
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD });
2065
+ }
2066
+ const credentialAccount = user.accounts.find((a) => a.providerId === "credential");
2067
+ if (!credentialAccount) {
2068
+ ctx.context.logger.error("Credential account not found", { email });
2069
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD });
2070
+ }
2071
+ const currentPassword = credentialAccount?.password;
2072
+ if (!currentPassword) {
2073
+ ctx.context.logger.error("Password not found", { email });
2074
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD });
2075
+ }
2076
+ if (!await ctx.context.password.verify({
2077
+ hash: currentPassword,
2078
+ password
2079
+ })) {
2080
+ ctx.context.logger.error("Invalid password");
2081
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD });
2082
+ }
2083
+ if (ctx.context.options?.emailAndPassword?.requireEmailVerification && !user.user.emailVerified) {
2084
+ if (!ctx.context.options?.emailVerification?.sendVerificationEmail) throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.EMAIL_NOT_VERIFIED });
2085
+ if (ctx.context.options?.emailVerification?.sendOnSignIn) {
2086
+ const token = await createEmailVerificationToken(ctx.context.secret, user.user.email, void 0, ctx.context.options.emailVerification?.expiresIn);
2087
+ const callbackURL = ctx.body.callbackURL ? encodeURIComponent(ctx.body.callbackURL) : encodeURIComponent("/");
2088
+ const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`;
2089
+ await ctx.context.options.emailVerification.sendVerificationEmail({
2090
+ user: user.user,
2091
+ url,
2092
+ token
2093
+ }, ctx.request);
2094
+ }
2095
+ throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.EMAIL_NOT_VERIFIED });
2096
+ }
2097
+ const session = await ctx.context.internalAdapter.createSession(user.user.id, ctx.body.rememberMe === false);
2098
+ if (!session) {
2099
+ ctx.context.logger.error("Failed to create session");
2100
+ throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION });
2101
+ }
2102
+ await setSessionCookie(ctx, {
2103
+ session,
2104
+ user: user.user
2105
+ }, ctx.body.rememberMe === false);
2106
+ return ctx.json({
2107
+ redirect: !!ctx.body.callbackURL,
2108
+ token: session.token,
2109
+ url: ctx.body.callbackURL,
2110
+ user: {
2111
+ id: user.user.id,
2112
+ email: user.user.email,
2113
+ name: user.user.name,
2114
+ image: user.user.image,
2115
+ emailVerified: user.user.emailVerified,
2116
+ createdAt: user.user.createdAt,
2117
+ updatedAt: user.user.updatedAt
2118
+ }
2119
+ });
2120
+ });
2121
+
2122
+ //#endregion
2123
+ //#region src/api/routes/sign-out.ts
2124
+ const signOut = createAuthEndpoint("/sign-out", {
2125
+ method: "POST",
2126
+ requireHeaders: true,
2127
+ metadata: { openapi: {
2128
+ description: "Sign out the current user",
2129
+ responses: { "200": {
2130
+ description: "Success",
2131
+ content: { "application/json": { schema: {
2132
+ type: "object",
2133
+ properties: { success: { type: "boolean" } }
2134
+ } } }
2135
+ } }
2136
+ } }
2137
+ }, async (ctx) => {
2138
+ const sessionCookieToken = await ctx.getSignedCookie(ctx.context.authCookies.sessionToken.name, ctx.context.secret);
2139
+ if (!sessionCookieToken) {
2140
+ deleteSessionCookie(ctx);
2141
+ throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION });
2142
+ }
2143
+ await ctx.context.internalAdapter.deleteSession(sessionCookieToken);
2144
+ deleteSessionCookie(ctx);
2145
+ return ctx.json({ success: true });
2146
+ });
2147
+
2148
+ //#endregion
2149
+ //#region src/api/routes/sign-up.ts
2150
+ const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
2151
+ method: "POST",
2152
+ body: z$1.record(z$1.string(), z$1.any()),
2153
+ metadata: {
2154
+ $Infer: { body: {} },
2155
+ openapi: {
2156
+ description: "Sign up a user using email and password",
2157
+ requestBody: { content: { "application/json": { schema: {
2158
+ type: "object",
2159
+ properties: {
2160
+ name: {
2161
+ type: "string",
2162
+ description: "The name of the user"
2163
+ },
2164
+ email: {
2165
+ type: "string",
2166
+ description: "The email of the user"
2167
+ },
2168
+ password: {
2169
+ type: "string",
2170
+ description: "The password of the user"
2171
+ },
2172
+ image: {
2173
+ type: "string",
2174
+ description: "The profile image URL of the user"
2175
+ },
2176
+ callbackURL: {
2177
+ type: "string",
2178
+ description: "The URL to use for email verification callback"
2179
+ },
2180
+ rememberMe: {
2181
+ type: "boolean",
2182
+ description: "If this is false, the session will not be remembered. Default is `true`."
2183
+ }
2184
+ },
2185
+ required: [
2186
+ "name",
2187
+ "email",
2188
+ "password"
2189
+ ]
2190
+ } } } },
2191
+ responses: {
2192
+ "200": {
2193
+ description: "Successfully created user",
2194
+ content: { "application/json": { schema: {
2195
+ type: "object",
2196
+ properties: {
2197
+ token: {
2198
+ type: "string",
2199
+ nullable: true,
2200
+ description: "Authentication token for the session"
2201
+ },
2202
+ user: {
2203
+ type: "object",
2204
+ properties: {
2205
+ id: {
2206
+ type: "string",
2207
+ description: "The unique identifier of the user"
2208
+ },
2209
+ email: {
2210
+ type: "string",
2211
+ format: "email",
2212
+ description: "The email address of the user"
2213
+ },
2214
+ name: {
2215
+ type: "string",
2216
+ description: "The name of the user"
2217
+ },
2218
+ image: {
2219
+ type: "string",
2220
+ format: "uri",
2221
+ nullable: true,
2222
+ description: "The profile image URL of the user"
2223
+ },
2224
+ emailVerified: {
2225
+ type: "boolean",
2226
+ description: "Whether the email has been verified"
2227
+ },
2228
+ createdAt: {
2229
+ type: "string",
2230
+ format: "date-time",
2231
+ description: "When the user was created"
2232
+ },
2233
+ updatedAt: {
2234
+ type: "string",
2235
+ format: "date-time",
2236
+ description: "When the user was last updated"
2237
+ }
2238
+ },
2239
+ required: [
2240
+ "id",
2241
+ "email",
2242
+ "name",
2243
+ "emailVerified",
2244
+ "createdAt",
2245
+ "updatedAt"
2246
+ ]
2247
+ }
2248
+ },
2249
+ required: ["user"]
2250
+ } } }
2251
+ },
2252
+ "422": {
2253
+ description: "Unprocessable Entity. User already exists or failed to create user.",
2254
+ content: { "application/json": { schema: {
2255
+ type: "object",
2256
+ properties: { message: { type: "string" } }
2257
+ } } }
2258
+ }
2259
+ }
2260
+ }
2261
+ }
2262
+ }, async (ctx) => {
2263
+ return runWithTransaction(ctx.context.adapter, async () => {
2264
+ if (!ctx.context.options.emailAndPassword?.enabled || ctx.context.options.emailAndPassword?.disableSignUp) throw new APIError("BAD_REQUEST", { message: "Email and password sign up is not enabled" });
2265
+ const body = ctx.body;
2266
+ const { name, email, password, image, callbackURL, rememberMe,...rest } = body;
2267
+ if (!z$1.email().safeParse(email).success) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_EMAIL });
2268
+ const minPasswordLength = ctx.context.password.config.minPasswordLength;
2269
+ if (password.length < minPasswordLength) {
2270
+ ctx.context.logger.error("Password is too short");
2271
+ throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT });
2272
+ }
2273
+ const maxPasswordLength = ctx.context.password.config.maxPasswordLength;
2274
+ if (password.length > maxPasswordLength) {
2275
+ ctx.context.logger.error("Password is too long");
2276
+ throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG });
2277
+ }
2278
+ if ((await ctx.context.internalAdapter.findUserByEmail(email))?.user) {
2279
+ ctx.context.logger.info(`Sign-up attempt for existing email: ${email}`);
2280
+ throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL });
2281
+ }
2282
+ /**
2283
+ * Hash the password
2284
+ *
2285
+ * This is done prior to creating the user
2286
+ * to ensure that any plugin that
2287
+ * may break the hashing should break
2288
+ * before the user is created.
2289
+ */
2290
+ const hash = await ctx.context.password.hash(password);
2291
+ let createdUser;
2292
+ try {
2293
+ const data = parseUserInput(ctx.context.options, rest, "create");
2294
+ createdUser = await ctx.context.internalAdapter.createUser({
2295
+ email: email.toLowerCase(),
2296
+ name,
2297
+ image,
2298
+ ...data,
2299
+ emailVerified: false
2300
+ });
2301
+ if (!createdUser) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER });
2302
+ } catch (e) {
2303
+ if (isDevelopment()) ctx.context.logger.error("Failed to create user", e);
2304
+ if (e instanceof APIError) throw e;
2305
+ ctx.context.logger?.error("Failed to create user", e);
2306
+ throw new APIError("UNPROCESSABLE_ENTITY", {
2307
+ message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER,
2308
+ details: e
2309
+ });
2310
+ }
2311
+ if (!createdUser) throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER });
2312
+ await ctx.context.internalAdapter.linkAccount({
2313
+ userId: createdUser.id,
2314
+ providerId: "credential",
2315
+ accountId: createdUser.id,
2316
+ password: hash
2317
+ });
2318
+ if (ctx.context.options.emailVerification?.sendOnSignUp || ctx.context.options.emailAndPassword.requireEmailVerification) {
2319
+ const token = await createEmailVerificationToken(ctx.context.secret, createdUser.email, void 0, ctx.context.options.emailVerification?.expiresIn);
2320
+ const callbackURL$1 = body.callbackURL ? encodeURIComponent(body.callbackURL) : encodeURIComponent("/");
2321
+ const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL$1}`;
2322
+ const args = ctx.request ? [{
2323
+ user: createdUser,
2324
+ url,
2325
+ token
2326
+ }, ctx.request] : [{
2327
+ user: createdUser,
2328
+ url,
2329
+ token
2330
+ }];
2331
+ await ctx.context.options.emailVerification?.sendVerificationEmail?.(...args);
2332
+ }
2333
+ if (ctx.context.options.emailAndPassword.autoSignIn === false || ctx.context.options.emailAndPassword.requireEmailVerification) return ctx.json({
2334
+ token: null,
2335
+ user: {
2336
+ id: createdUser.id,
2337
+ email: createdUser.email,
2338
+ name: createdUser.name,
2339
+ image: createdUser.image,
2340
+ emailVerified: createdUser.emailVerified,
2341
+ createdAt: createdUser.createdAt,
2342
+ updatedAt: createdUser.updatedAt
2343
+ }
2344
+ });
2345
+ const session = await ctx.context.internalAdapter.createSession(createdUser.id, rememberMe === false);
2346
+ if (!session) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION });
2347
+ await setSessionCookie(ctx, {
2348
+ session,
2349
+ user: createdUser
2350
+ }, rememberMe === false);
2351
+ return ctx.json({
2352
+ token: session.token,
2353
+ user: {
2354
+ id: createdUser.id,
2355
+ email: createdUser.email,
2356
+ name: createdUser.name,
2357
+ image: createdUser.image,
2358
+ emailVerified: createdUser.emailVerified,
2359
+ createdAt: createdUser.createdAt,
2360
+ updatedAt: createdUser.updatedAt
2361
+ }
2362
+ });
2363
+ });
2364
+ });
2365
+
2366
+ //#endregion
2367
+ //#region src/api/routes/update-user.ts
2368
+ const updateUser = () => createAuthEndpoint("/update-user", {
2369
+ method: "POST",
2370
+ body: z$1.record(z$1.string().meta({ description: "Field name must be a string" }), z$1.any()),
2371
+ use: [sessionMiddleware],
2372
+ metadata: {
2373
+ $Infer: { body: {} },
2374
+ openapi: {
2375
+ description: "Update the current user",
2376
+ requestBody: { content: { "application/json": { schema: {
2377
+ type: "object",
2378
+ properties: {
2379
+ name: {
2380
+ type: "string",
2381
+ description: "The name of the user"
2382
+ },
2383
+ image: {
2384
+ type: "string",
2385
+ description: "The image of the user"
2386
+ }
2387
+ }
2388
+ } } } },
2389
+ responses: { "200": {
2390
+ description: "Success",
2391
+ content: { "application/json": { schema: {
2392
+ type: "object",
2393
+ properties: { status: {
2394
+ type: "boolean",
2395
+ description: "Indicates if the update was successful"
2396
+ } }
2397
+ } } }
2398
+ } }
2399
+ }
2400
+ }
2401
+ }, async (ctx) => {
2402
+ const body = ctx.body;
2403
+ if (body.email) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.EMAIL_CAN_NOT_BE_UPDATED });
2404
+ const { name, image,...rest } = body;
2405
+ const session = ctx.context.session;
2406
+ const additionalFields = parseUserInput(ctx.context.options, rest, "update");
2407
+ if (image === void 0 && name === void 0 && Object.keys(additionalFields).length === 0) throw new APIError("BAD_REQUEST", { message: "No fields to update" });
2408
+ const user = await ctx.context.internalAdapter.updateUser(session.user.id, {
2409
+ name,
2410
+ image,
2411
+ ...additionalFields
2412
+ });
2413
+ /**
2414
+ * Update the session cookie with the new user data
2415
+ */
2416
+ await setSessionCookie(ctx, {
2417
+ session: session.session,
2418
+ user
2419
+ });
2420
+ return ctx.json({ status: true });
2421
+ });
2422
+ const changePassword = createAuthEndpoint("/change-password", {
2423
+ method: "POST",
2424
+ body: z$1.object({
2425
+ newPassword: z$1.string().meta({ description: "The new password to set" }),
2426
+ currentPassword: z$1.string().meta({ description: "The current password is required" }),
2427
+ revokeOtherSessions: z$1.boolean().meta({ description: "Must be a boolean value" }).optional()
2428
+ }),
2429
+ use: [sensitiveSessionMiddleware],
2430
+ metadata: { openapi: {
2431
+ description: "Change the password of the user",
2432
+ responses: { "200": {
2433
+ description: "Password successfully changed",
2434
+ content: { "application/json": { schema: {
2435
+ type: "object",
2436
+ properties: {
2437
+ token: {
2438
+ type: "string",
2439
+ nullable: true,
2440
+ description: "New session token if other sessions were revoked"
2441
+ },
2442
+ user: {
2443
+ type: "object",
2444
+ properties: {
2445
+ id: {
2446
+ type: "string",
2447
+ description: "The unique identifier of the user"
2448
+ },
2449
+ email: {
2450
+ type: "string",
2451
+ format: "email",
2452
+ description: "The email address of the user"
2453
+ },
2454
+ name: {
2455
+ type: "string",
2456
+ description: "The name of the user"
2457
+ },
2458
+ image: {
2459
+ type: "string",
2460
+ format: "uri",
2461
+ nullable: true,
2462
+ description: "The profile image URL of the user"
2463
+ },
2464
+ emailVerified: {
2465
+ type: "boolean",
2466
+ description: "Whether the email has been verified"
2467
+ },
2468
+ createdAt: {
2469
+ type: "string",
2470
+ format: "date-time",
2471
+ description: "When the user was created"
2472
+ },
2473
+ updatedAt: {
2474
+ type: "string",
2475
+ format: "date-time",
2476
+ description: "When the user was last updated"
2477
+ }
2478
+ },
2479
+ required: [
2480
+ "id",
2481
+ "email",
2482
+ "name",
2483
+ "emailVerified",
2484
+ "createdAt",
2485
+ "updatedAt"
2486
+ ]
2487
+ }
2488
+ },
2489
+ required: ["user"]
2490
+ } } }
2491
+ } }
2492
+ } }
2493
+ }, async (ctx) => {
2494
+ const { newPassword, currentPassword, revokeOtherSessions: revokeOtherSessions$1 } = ctx.body;
2495
+ const session = ctx.context.session;
2496
+ const minPasswordLength = ctx.context.password.config.minPasswordLength;
2497
+ if (newPassword.length < minPasswordLength) {
2498
+ ctx.context.logger.error("Password is too short");
2499
+ throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT });
2500
+ }
2501
+ const maxPasswordLength = ctx.context.password.config.maxPasswordLength;
2502
+ if (newPassword.length > maxPasswordLength) {
2503
+ ctx.context.logger.error("Password is too long");
2504
+ throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG });
2505
+ }
2506
+ const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password);
2507
+ if (!account || !account.password) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND });
2508
+ const passwordHash = await ctx.context.password.hash(newPassword);
2509
+ if (!await ctx.context.password.verify({
2510
+ hash: account.password,
2511
+ password: currentPassword
2512
+ })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD });
2513
+ await ctx.context.internalAdapter.updateAccount(account.id, { password: passwordHash });
2514
+ let token = null;
2515
+ if (revokeOtherSessions$1) {
2516
+ await ctx.context.internalAdapter.deleteSessions(session.user.id);
2517
+ const newSession = await ctx.context.internalAdapter.createSession(session.user.id);
2518
+ if (!newSession) throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION });
2519
+ await setSessionCookie(ctx, {
2520
+ session: newSession,
2521
+ user: session.user
2522
+ });
2523
+ token = newSession.token;
2524
+ }
2525
+ return ctx.json({
2526
+ token,
2527
+ user: {
2528
+ id: session.user.id,
2529
+ email: session.user.email,
2530
+ name: session.user.name,
2531
+ image: session.user.image,
2532
+ emailVerified: session.user.emailVerified,
2533
+ createdAt: session.user.createdAt,
2534
+ updatedAt: session.user.updatedAt
2535
+ }
2536
+ });
2537
+ });
2538
+ const setPassword = createAuthEndpoint("/set-password", {
2539
+ method: "POST",
2540
+ body: z$1.object({ newPassword: z$1.string().meta({ description: "The new password to set is required" }) }),
2541
+ metadata: { SERVER_ONLY: true },
2542
+ use: [sensitiveSessionMiddleware]
2543
+ }, async (ctx) => {
2544
+ const { newPassword } = ctx.body;
2545
+ const session = ctx.context.session;
2546
+ const minPasswordLength = ctx.context.password.config.minPasswordLength;
2547
+ if (newPassword.length < minPasswordLength) {
2548
+ ctx.context.logger.error("Password is too short");
2549
+ throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT });
2550
+ }
2551
+ const maxPasswordLength = ctx.context.password.config.maxPasswordLength;
2552
+ if (newPassword.length > maxPasswordLength) {
2553
+ ctx.context.logger.error("Password is too long");
2554
+ throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG });
2555
+ }
2556
+ const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password);
2557
+ const passwordHash = await ctx.context.password.hash(newPassword);
2558
+ if (!account) {
2559
+ await ctx.context.internalAdapter.linkAccount({
2560
+ userId: session.user.id,
2561
+ providerId: "credential",
2562
+ accountId: session.user.id,
2563
+ password: passwordHash
2564
+ });
2565
+ return ctx.json({ status: true });
2566
+ }
2567
+ throw new APIError("BAD_REQUEST", { message: "user already has a password" });
2568
+ });
2569
+ const deleteUser = createAuthEndpoint("/delete-user", {
2570
+ method: "POST",
2571
+ use: [sensitiveSessionMiddleware],
2572
+ body: z$1.object({
2573
+ callbackURL: z$1.string().meta({ description: "The callback URL to redirect to after the user is deleted" }).optional(),
2574
+ password: z$1.string().meta({ description: "The password of the user is required to delete the user" }).optional(),
2575
+ token: z$1.string().meta({ description: "The token to delete the user is required" }).optional()
2576
+ }),
2577
+ metadata: { openapi: {
2578
+ description: "Delete the user",
2579
+ responses: { "200": {
2580
+ description: "User deletion processed successfully",
2581
+ content: { "application/json": { schema: {
2582
+ type: "object",
2583
+ properties: {
2584
+ success: {
2585
+ type: "boolean",
2586
+ description: "Indicates if the operation was successful"
2587
+ },
2588
+ message: {
2589
+ type: "string",
2590
+ enum: ["User deleted", "Verification email sent"],
2591
+ description: "Status message of the deletion process"
2592
+ }
2593
+ },
2594
+ required: ["success", "message"]
2595
+ } } }
2596
+ } }
2597
+ } }
2598
+ }, async (ctx) => {
2599
+ if (!ctx.context.options.user?.deleteUser?.enabled) {
2600
+ ctx.context.logger.error("Delete user is disabled. Enable it in the options");
2601
+ throw new APIError("NOT_FOUND");
2602
+ }
2603
+ const session = ctx.context.session;
2604
+ if (ctx.body.password) {
2605
+ const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password);
2606
+ if (!account || !account.password) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND });
2607
+ if (!await ctx.context.password.verify({
2608
+ hash: account.password,
2609
+ password: ctx.body.password
2610
+ })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD });
2611
+ }
2612
+ if (ctx.body.token) {
2613
+ await deleteUserCallback({
2614
+ ...ctx,
2615
+ query: { token: ctx.body.token }
2616
+ });
2617
+ return ctx.json({
2618
+ success: true,
2619
+ message: "User deleted"
2620
+ });
2621
+ }
2622
+ if (ctx.context.options.user.deleteUser?.sendDeleteAccountVerification) {
2623
+ const token = generateRandomString(32, "0-9", "a-z");
2624
+ await ctx.context.internalAdapter.createVerificationValue({
2625
+ value: session.user.id,
2626
+ identifier: `delete-account-${token}`,
2627
+ expiresAt: new Date(Date.now() + (ctx.context.options.user.deleteUser?.deleteTokenExpiresIn || 3600 * 24) * 1e3)
2628
+ });
2629
+ const url = `${ctx.context.baseURL}/delete-user/callback?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`;
2630
+ await ctx.context.options.user.deleteUser.sendDeleteAccountVerification({
2631
+ user: session.user,
2632
+ url,
2633
+ token
2634
+ }, ctx.request);
2635
+ return ctx.json({
2636
+ success: true,
2637
+ message: "Verification email sent"
2638
+ });
2639
+ }
2640
+ if (!ctx.body.password && ctx.context.sessionConfig.freshAge !== 0) {
2641
+ const currentAge = new Date(session.session.createdAt).getTime();
2642
+ const freshAge = ctx.context.sessionConfig.freshAge * 1e3;
2643
+ if (Date.now() - currentAge > freshAge * 1e3) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.SESSION_EXPIRED });
2644
+ }
2645
+ const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;
2646
+ if (beforeDelete) await beforeDelete(session.user, ctx.request);
2647
+ await ctx.context.internalAdapter.deleteUser(session.user.id);
2648
+ await ctx.context.internalAdapter.deleteSessions(session.user.id);
2649
+ deleteSessionCookie(ctx);
2650
+ const afterDelete = ctx.context.options.user.deleteUser?.afterDelete;
2651
+ if (afterDelete) await afterDelete(session.user, ctx.request);
2652
+ return ctx.json({
2653
+ success: true,
2654
+ message: "User deleted"
2655
+ });
2656
+ });
2657
+ const deleteUserCallback = createAuthEndpoint("/delete-user/callback", {
2658
+ method: "GET",
2659
+ query: z$1.object({
2660
+ token: z$1.string().meta({ description: "The token to verify the deletion request" }),
2661
+ callbackURL: z$1.string().meta({ description: "The URL to redirect to after deletion" }).optional()
2662
+ }),
2663
+ use: [originCheck((ctx) => ctx.query.callbackURL)],
2664
+ metadata: { openapi: {
2665
+ description: "Callback to complete user deletion with verification token",
2666
+ responses: { "200": {
2667
+ description: "User successfully deleted",
2668
+ content: { "application/json": { schema: {
2669
+ type: "object",
2670
+ properties: {
2671
+ success: {
2672
+ type: "boolean",
2673
+ description: "Indicates if the deletion was successful"
2674
+ },
2675
+ message: {
2676
+ type: "string",
2677
+ enum: ["User deleted"],
2678
+ description: "Confirmation message"
2679
+ }
2680
+ },
2681
+ required: ["success", "message"]
2682
+ } } }
2683
+ } }
2684
+ } }
2685
+ }, async (ctx) => {
2686
+ if (!ctx.context.options.user?.deleteUser?.enabled) {
2687
+ ctx.context.logger.error("Delete user is disabled. Enable it in the options");
2688
+ throw new APIError("NOT_FOUND");
2689
+ }
2690
+ const session = await getSessionFromCtx(ctx);
2691
+ if (!session) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO });
2692
+ const token = await ctx.context.internalAdapter.findVerificationValue(`delete-account-${ctx.query.token}`);
2693
+ if (!token || token.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.INVALID_TOKEN });
2694
+ if (token.value !== session.user.id) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.INVALID_TOKEN });
2695
+ const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;
2696
+ if (beforeDelete) await beforeDelete(session.user, ctx.request);
2697
+ await ctx.context.internalAdapter.deleteUser(session.user.id);
2698
+ await ctx.context.internalAdapter.deleteSessions(session.user.id);
2699
+ await ctx.context.internalAdapter.deleteAccounts(session.user.id);
2700
+ await ctx.context.internalAdapter.deleteVerificationValue(token.id);
2701
+ deleteSessionCookie(ctx);
2702
+ const afterDelete = ctx.context.options.user.deleteUser?.afterDelete;
2703
+ if (afterDelete) await afterDelete(session.user, ctx.request);
2704
+ if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL || "/");
2705
+ return ctx.json({
2706
+ success: true,
2707
+ message: "User deleted"
2708
+ });
2709
+ });
2710
+ const changeEmail = createAuthEndpoint("/change-email", {
2711
+ method: "POST",
2712
+ body: z$1.object({
2713
+ newEmail: z$1.email().meta({ description: "The new email address to set must be a valid email address" }),
2714
+ callbackURL: z$1.string().meta({ description: "The URL to redirect to after email verification" }).optional()
2715
+ }),
2716
+ use: [sensitiveSessionMiddleware],
2717
+ metadata: { openapi: { responses: {
2718
+ "200": {
2719
+ description: "Email change request processed successfully",
2720
+ content: { "application/json": { schema: {
2721
+ type: "object",
2722
+ properties: {
2723
+ status: {
2724
+ type: "boolean",
2725
+ description: "Indicates if the request was successful"
2726
+ },
2727
+ message: {
2728
+ type: "string",
2729
+ enum: ["Email updated", "Verification email sent"],
2730
+ description: "Status message of the email change process",
2731
+ nullable: true
2732
+ }
2733
+ },
2734
+ required: ["status"]
2735
+ } } }
2736
+ },
2737
+ "422": {
2738
+ description: "Unprocessable Entity. Email already exists",
2739
+ content: { "application/json": { schema: {
2740
+ type: "object",
2741
+ properties: { message: { type: "string" } }
2742
+ } } }
2743
+ }
2744
+ } } }
2745
+ }, async (ctx) => {
2746
+ if (!ctx.context.options.user?.changeEmail?.enabled) {
2747
+ ctx.context.logger.error("Change email is disabled.");
2748
+ throw new APIError("BAD_REQUEST", { message: "Change email is disabled" });
2749
+ }
2750
+ const newEmail = ctx.body.newEmail.toLowerCase();
2751
+ if (newEmail === ctx.context.session.user.email) {
2752
+ ctx.context.logger.error("Email is the same");
2753
+ throw new APIError("BAD_REQUEST", { message: "Email is the same" });
2754
+ }
2755
+ if (await ctx.context.internalAdapter.findUserByEmail(newEmail)) {
2756
+ ctx.context.logger.error("Email already exists");
2757
+ throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL });
2758
+ }
2759
+ /**
2760
+ * If the email is not verified, we can update the email
2761
+ */
2762
+ if (ctx.context.session.user.emailVerified !== true) {
2763
+ await ctx.context.internalAdapter.updateUserByEmail(ctx.context.session.user.email, { email: newEmail });
2764
+ await setSessionCookie(ctx, {
2765
+ session: ctx.context.session.session,
2766
+ user: {
2767
+ ...ctx.context.session.user,
2768
+ email: newEmail
2769
+ }
2770
+ });
2771
+ if (ctx.context.options.emailVerification?.sendVerificationEmail) {
2772
+ const token$1 = await createEmailVerificationToken(ctx.context.secret, newEmail, void 0, ctx.context.options.emailVerification?.expiresIn);
2773
+ const url$1 = `${ctx.context.baseURL}/verify-email?token=${token$1}&callbackURL=${ctx.body.callbackURL || "/"}`;
2774
+ await ctx.context.options.emailVerification.sendVerificationEmail({
2775
+ user: {
2776
+ ...ctx.context.session.user,
2777
+ email: newEmail
2778
+ },
2779
+ url: url$1,
2780
+ token: token$1
2781
+ }, ctx.request);
2782
+ }
2783
+ return ctx.json({ status: true });
2784
+ }
2785
+ /**
2786
+ * If the email is verified, we need to send a verification email
2787
+ */
2788
+ if (!ctx.context.options.user.changeEmail.sendChangeEmailVerification) {
2789
+ ctx.context.logger.error("Verification email isn't enabled.");
2790
+ throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" });
2791
+ }
2792
+ const token = await createEmailVerificationToken(ctx.context.secret, ctx.context.session.user.email, newEmail, ctx.context.options.emailVerification?.expiresIn);
2793
+ const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`;
2794
+ await ctx.context.options.user.changeEmail.sendChangeEmailVerification({
2795
+ user: ctx.context.session.user,
2796
+ newEmail,
2797
+ url,
2798
+ token
2799
+ }, ctx.request);
2800
+ return ctx.json({ status: true });
2801
+ });
2802
+
2803
+ //#endregion
2804
+ //#region src/api/to-auth-endpoints.ts
2805
+ const defuReplaceArrays = createDefu((obj, key, value) => {
2806
+ if (Array.isArray(obj[key]) && Array.isArray(value)) {
2807
+ obj[key] = value;
2808
+ return true;
2809
+ }
2810
+ });
2811
+ function toAuthEndpoints(endpoints, ctx) {
2812
+ const api = {};
2813
+ for (const [key, endpoint] of Object.entries(endpoints)) {
2814
+ api[key] = async (context) => {
2815
+ const run = async () => {
2816
+ const authContext = await ctx;
2817
+ let internalContext = {
2818
+ ...context,
2819
+ context: {
2820
+ ...authContext,
2821
+ returned: void 0,
2822
+ responseHeaders: void 0,
2823
+ session: null
2824
+ },
2825
+ path: endpoint.path,
2826
+ headers: context?.headers ? new Headers(context?.headers) : void 0
2827
+ };
2828
+ return runWithEndpointContext(internalContext, async () => {
2829
+ const { beforeHooks, afterHooks } = getHooks(authContext);
2830
+ const before = await runBeforeHooks(internalContext, beforeHooks);
2831
+ /**
2832
+ * If `before.context` is returned, it should
2833
+ * get merged with the original context
2834
+ */
2835
+ if ("context" in before && before.context && typeof before.context === "object") {
2836
+ const { headers,...rest } = before.context;
2837
+ /**
2838
+ * Headers should be merged differently
2839
+ * so the hook doesn't override the whole
2840
+ * header
2841
+ */
2842
+ if (headers) headers.forEach((value, key$1) => {
2843
+ internalContext.headers.set(key$1, value);
2844
+ });
2845
+ internalContext = defuReplaceArrays(rest, internalContext);
2846
+ } else if (before) return context?.asResponse ? toResponse(before, { headers: context?.headers }) : context?.returnHeaders ? {
2847
+ headers: context?.headers,
2848
+ response: before
2849
+ } : before;
2850
+ internalContext.asResponse = false;
2851
+ internalContext.returnHeaders = true;
2852
+ const result = await runWithEndpointContext(internalContext, () => endpoint(internalContext)).catch((e) => {
2853
+ if (e instanceof APIError)
2854
+ /**
2855
+ * API Errors from response are caught
2856
+ * and returned to hooks
2857
+ */
2858
+ return {
2859
+ response: e,
2860
+ headers: e.headers ? new Headers(e.headers) : null
2861
+ };
2862
+ throw e;
2863
+ });
2864
+ if (result && result instanceof Response) return result;
2865
+ internalContext.context.returned = result.response;
2866
+ internalContext.context.responseHeaders = result.headers;
2867
+ const after = await runAfterHooks(internalContext, afterHooks);
2868
+ if (after.response) result.response = after.response;
2869
+ if (result.response instanceof APIError && shouldPublishLog(authContext.logger.level, "debug")) result.response.stack = result.response.errorStack;
2870
+ if (result.response instanceof APIError && !context?.asResponse) throw result.response;
2871
+ return context?.asResponse ? toResponse(result.response, { headers: result.headers }) : context?.returnHeaders ? {
2872
+ headers: result.headers,
2873
+ response: result.response
2874
+ } : result.response;
2875
+ });
2876
+ };
2877
+ if (await hasRequestState()) return run();
2878
+ else return runWithRequestState(/* @__PURE__ */ new WeakMap(), run);
2879
+ };
2880
+ api[key].path = endpoint.path;
2881
+ api[key].options = endpoint.options;
2882
+ }
2883
+ return api;
2884
+ }
2885
+ async function runBeforeHooks(context, hooks) {
2886
+ let modifiedContext = {};
2887
+ for (const hook of hooks) if (hook.matcher(context)) {
2888
+ const result = await hook.handler({
2889
+ ...context,
2890
+ returnHeaders: false
2891
+ }).catch((e) => {
2892
+ if (e instanceof APIError && shouldPublishLog(context.context.logger.level, "debug")) e.stack = e.errorStack;
2893
+ throw e;
2894
+ });
2895
+ if (result && typeof result === "object") {
2896
+ if ("context" in result && typeof result.context === "object") {
2897
+ const { headers,...rest } = result.context;
2898
+ if (headers instanceof Headers) if (modifiedContext.headers) headers.forEach((value, key) => {
2899
+ modifiedContext.headers?.set(key, value);
2900
+ });
2901
+ else modifiedContext.headers = headers;
2902
+ modifiedContext = defuReplaceArrays(rest, modifiedContext);
2903
+ continue;
2904
+ }
2905
+ return result;
2906
+ }
2907
+ }
2908
+ return { context: modifiedContext };
2909
+ }
2910
+ async function runAfterHooks(context, hooks) {
2911
+ for (const hook of hooks) if (hook.matcher(context)) {
2912
+ const result = await hook.handler(context).catch((e) => {
2913
+ if (e instanceof APIError) {
2914
+ if (shouldPublishLog(context.context.logger.level, "debug")) e.stack = e.errorStack;
2915
+ return {
2916
+ response: e,
2917
+ headers: e.headers ? new Headers(e.headers) : null
2918
+ };
2919
+ }
2920
+ throw e;
2921
+ });
2922
+ if (result.headers) result.headers.forEach((value, key) => {
2923
+ if (!context.context.responseHeaders) context.context.responseHeaders = new Headers({ [key]: value });
2924
+ else if (key.toLowerCase() === "set-cookie") context.context.responseHeaders.append(key, value);
2925
+ else context.context.responseHeaders.set(key, value);
2926
+ });
2927
+ if (result.response) context.context.returned = result.response;
2928
+ }
2929
+ return {
2930
+ response: context.context.returned,
2931
+ headers: context.context.responseHeaders
2932
+ };
2933
+ }
2934
+ function getHooks(authContext) {
2935
+ const plugins = authContext.options.plugins || [];
2936
+ const beforeHooks = [];
2937
+ const afterHooks = [];
2938
+ if (authContext.options.hooks?.before) beforeHooks.push({
2939
+ matcher: () => true,
2940
+ handler: authContext.options.hooks.before
2941
+ });
2942
+ if (authContext.options.hooks?.after) afterHooks.push({
2943
+ matcher: () => true,
2944
+ handler: authContext.options.hooks.after
2945
+ });
2946
+ const pluginBeforeHooks = plugins.map((plugin) => {
2947
+ if (plugin.hooks?.before) return plugin.hooks.before;
2948
+ }).filter((plugin) => plugin !== void 0).flat();
2949
+ const pluginAfterHooks = plugins.map((plugin) => {
2950
+ if (plugin.hooks?.after) return plugin.hooks.after;
2951
+ }).filter((plugin) => plugin !== void 0).flat();
2952
+ /**
2953
+ * Add plugin added hooks at last
2954
+ */
2955
+ if (pluginBeforeHooks.length) beforeHooks.push(...pluginBeforeHooks);
2956
+ if (pluginAfterHooks.length) afterHooks.push(...pluginAfterHooks);
2957
+ return {
2958
+ beforeHooks,
2959
+ afterHooks
2960
+ };
2961
+ }
2962
+
2963
+ //#endregion
2964
+ //#region src/api/index.ts
2965
+ function checkEndpointConflicts(options, logger$1) {
2966
+ const endpointRegistry = /* @__PURE__ */ new Map();
2967
+ options.plugins?.forEach((plugin) => {
2968
+ if (plugin.endpoints) {
2969
+ for (const [key, endpoint] of Object.entries(plugin.endpoints)) if (endpoint && "path" in endpoint) {
2970
+ const path = endpoint.path;
2971
+ let methods = [];
2972
+ if (endpoint.options && "method" in endpoint.options) {
2973
+ if (Array.isArray(endpoint.options.method)) methods = endpoint.options.method;
2974
+ else if (typeof endpoint.options.method === "string") methods = [endpoint.options.method];
2975
+ }
2976
+ if (methods.length === 0) methods = ["*"];
2977
+ if (!endpointRegistry.has(path)) endpointRegistry.set(path, []);
2978
+ endpointRegistry.get(path).push({
2979
+ pluginId: plugin.id,
2980
+ endpointKey: key,
2981
+ methods
2982
+ });
2983
+ }
2984
+ }
2985
+ });
2986
+ const conflicts = [];
2987
+ for (const [path, entries] of endpointRegistry.entries()) if (entries.length > 1) {
2988
+ const methodMap = /* @__PURE__ */ new Map();
2989
+ let hasConflict = false;
2990
+ for (const entry of entries) for (const method of entry.methods) {
2991
+ if (!methodMap.has(method)) methodMap.set(method, []);
2992
+ methodMap.get(method).push(entry.pluginId);
2993
+ if (methodMap.get(method).length > 1) hasConflict = true;
2994
+ if (method === "*" && entries.length > 1) hasConflict = true;
2995
+ else if (method !== "*" && methodMap.has("*")) hasConflict = true;
2996
+ }
2997
+ if (hasConflict) {
2998
+ const uniquePlugins = [...new Set(entries.map((e) => e.pluginId))];
2999
+ const conflictingMethods = [];
3000
+ for (const [method, plugins] of methodMap.entries()) if (plugins.length > 1 || method === "*" && entries.length > 1 || method !== "*" && methodMap.has("*")) conflictingMethods.push(method);
3001
+ conflicts.push({
3002
+ path,
3003
+ plugins: uniquePlugins,
3004
+ conflictingMethods
3005
+ });
3006
+ }
3007
+ }
3008
+ if (conflicts.length > 0) {
3009
+ const conflictMessages = conflicts.map((conflict) => ` - "${conflict.path}" [${conflict.conflictingMethods.join(", ")}] used by plugins: ${conflict.plugins.join(", ")}`).join("\n");
3010
+ logger$1.error(`Endpoint path conflicts detected! Multiple plugins are trying to use the same endpoint paths with conflicting HTTP methods:
3011
+ ${conflictMessages}
3012
+
3013
+ To resolve this, you can:
3014
+ 1. Use only one of the conflicting plugins
3015
+ 2. Configure the plugins to use different paths (if supported)
3016
+ 3. Ensure plugins use different HTTP methods for the same path
3017
+ `);
3018
+ }
3019
+ }
3020
+ function getEndpoints(ctx, options) {
3021
+ const pluginEndpoints = options.plugins?.reduce((acc, plugin) => {
3022
+ return {
3023
+ ...acc,
3024
+ ...plugin.endpoints
3025
+ };
3026
+ }, {}) ?? {};
3027
+ const middlewares = options.plugins?.map((plugin) => plugin.middlewares?.map((m) => {
3028
+ const middleware = (async (context) => {
3029
+ const authContext = await ctx;
3030
+ return m.middleware({
3031
+ ...context,
3032
+ context: {
3033
+ ...authContext,
3034
+ ...context.context
3035
+ }
3036
+ });
3037
+ });
3038
+ middleware.options = m.middleware.options;
3039
+ return {
3040
+ path: m.path,
3041
+ middleware
3042
+ };
3043
+ })).filter((plugin) => plugin !== void 0).flat() || [];
3044
+ return {
3045
+ api: toAuthEndpoints({
3046
+ signInSocial,
3047
+ callbackOAuth,
3048
+ getSession: getSession(),
3049
+ signOut,
3050
+ signUpEmail: signUpEmail(),
3051
+ signInEmail,
3052
+ resetPassword,
3053
+ verifyEmail,
3054
+ sendVerificationEmail,
3055
+ changeEmail,
3056
+ changePassword,
3057
+ setPassword,
3058
+ updateUser: updateUser(),
3059
+ deleteUser,
3060
+ requestPasswordReset,
3061
+ requestPasswordResetCallback,
3062
+ listSessions: listSessions(),
3063
+ revokeSession,
3064
+ revokeSessions,
3065
+ revokeOtherSessions,
3066
+ linkSocialAccount,
3067
+ listUserAccounts,
3068
+ deleteUserCallback,
3069
+ unlinkAccount,
3070
+ refreshToken,
3071
+ getAccessToken,
3072
+ accountInfo,
3073
+ ...pluginEndpoints,
3074
+ ok,
3075
+ error
3076
+ }, ctx),
3077
+ middlewares
3078
+ };
3079
+ }
3080
+ const router = (ctx, options) => {
3081
+ const { api, middlewares } = getEndpoints(ctx, options);
3082
+ const basePath = new URL(ctx.baseURL).pathname;
3083
+ return createRouter(api, {
3084
+ routerContext: ctx,
3085
+ openapi: { disabled: true },
3086
+ basePath,
3087
+ routerMiddleware: [{
3088
+ path: "/**",
3089
+ middleware: originCheckMiddleware
3090
+ }, ...middlewares],
3091
+ async onRequest(req) {
3092
+ const disabledPaths = ctx.options.disabledPaths || [];
3093
+ const path = new URL(req.url).pathname.replace(basePath, "");
3094
+ if (disabledPaths.includes(path)) return new Response("Not Found", { status: 404 });
3095
+ for (const plugin of ctx.options.plugins || []) if (plugin.onRequest) {
3096
+ const response = await plugin.onRequest(req, ctx);
3097
+ if (response && "response" in response) return response.response;
3098
+ if (response && "request" in response) {
3099
+ const rateLimitResponse$1 = await onRequestRateLimit(response.request, ctx);
3100
+ if (rateLimitResponse$1) return rateLimitResponse$1;
3101
+ return response.request;
3102
+ }
3103
+ }
3104
+ return onRequestRateLimit(req, ctx);
3105
+ },
3106
+ async onResponse(res) {
3107
+ for (const plugin of ctx.options.plugins || []) if (plugin.onResponse) {
3108
+ const response = await plugin.onResponse(res, ctx);
3109
+ if (response) return response.response;
3110
+ }
3111
+ return res;
3112
+ },
3113
+ onError(e) {
3114
+ if (e instanceof APIError && e.status === "FOUND") return;
3115
+ if (options.onAPIError?.throw) throw e;
3116
+ if (options.onAPIError?.onError) {
3117
+ options.onAPIError.onError(e, ctx);
3118
+ return;
3119
+ }
3120
+ const optLogLevel = options.logger?.level;
3121
+ const log = optLogLevel === "error" || optLogLevel === "warn" || optLogLevel === "debug" ? logger : void 0;
3122
+ if (options.logger?.disabled !== true) {
3123
+ if (e && typeof e === "object" && "message" in e && typeof e.message === "string") {
3124
+ if (e.message.includes("no column") || e.message.includes("column") || e.message.includes("relation") || e.message.includes("table") || e.message.includes("does not exist")) {
3125
+ ctx.logger?.error(e.message);
3126
+ return;
3127
+ }
3128
+ }
3129
+ if (e instanceof APIError) {
3130
+ if (e.status === "INTERNAL_SERVER_ERROR") ctx.logger.error(e.status, e);
3131
+ log?.error(e.message);
3132
+ } else ctx.logger?.error(e && typeof e === "object" && "name" in e ? e.name : "", e);
3133
+ }
3134
+ }
3135
+ });
3136
+ };
3137
+
3138
+ //#endregion
3139
+ export { getAccessToken as A, createEmailVerificationToken as C, callbackOAuth as D, verifyEmail as E, decryptOAuthToken as F, setTokenUtil as I, isSimpleRequest as L, listUserAccounts as M, refreshToken as N, handleOAuthUserInfo as O, unlinkAccount as P, originCheck as R, error as S, sendVerificationEmailFn as T, signInSocial as _, getEndpoints as a, resetPassword as b, changeEmail as c, deleteUserCallback as d, setPassword as f, signInEmail as g, signOut as h, createAuthMiddleware$1 as i, linkSocialAccount as j, accountInfo as k, changePassword as l, signUpEmail as m, checkEndpointConflicts as n, optionsMiddleware as o, updateUser as p, createAuthEndpoint$1 as r, router as s, APIError$1 as t, deleteUser as u, requestPasswordReset as v, sendVerificationEmail as w, ok as x, requestPasswordResetCallback as y, originCheckMiddleware as z };