@baseplate-dev/plugin-auth 0.6.17 → 0.6.19

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 (294) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/admin-crud-manage-roles-action.generator.d.ts +74 -0
  3. package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/generated/index.d.ts +74 -0
  4. package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/generated/template-renderers.d.ts +37 -0
  5. package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/generated/typed-templates.d.ts +37 -0
  6. package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/templates/routes/-components/role-manager-dialog.js +1 -2
  7. package/dist/better-auth/admin/generators/admin-crud-manage-roles-action/templates/routes/-components/role-manager-dialog.tsx +1 -1
  8. package/dist/better-auth/admin/generators/admin-crud-reset-password-action/admin-crud-reset-password-action.generator.d.ts +74 -0
  9. package/dist/better-auth/admin/generators/admin-crud-reset-password-action/generated/index.d.ts +74 -0
  10. package/dist/better-auth/admin/generators/admin-crud-reset-password-action/generated/template-renderers.d.ts +37 -0
  11. package/dist/better-auth/admin/generators/admin-crud-reset-password-action/generated/typed-templates.d.ts +74 -0
  12. package/dist/better-auth/admin/generators/admin-crud-reset-password-action/templates/routes/-components/password-reset-dialog.js +1 -2
  13. package/dist/better-auth/admin/generators/admin-crud-reset-password-action/templates/routes/-components/password-reset-dialog.tsx +1 -1
  14. package/dist/better-auth/admin/generators/admin-crud-roles-column/admin-crud-roles-column.generator.d.ts +37 -0
  15. package/dist/better-auth/core/node.js +7 -8
  16. package/dist/better-auth/generators/fastify/better-auth-admin-module/generated/index.d.ts +1 -0
  17. package/dist/better-auth/generators/fastify/better-auth-admin-module/generated/ts-import-providers.d.ts +1 -0
  18. package/dist/better-auth/generators/fastify/better-auth-admin-module/generated/ts-import-providers.js +1 -0
  19. package/dist/better-auth/generators/fastify/better-auth-module/better-auth-module.generator.d.ts +20 -3
  20. package/dist/better-auth/generators/fastify/better-auth-module/better-auth-module.generator.js +5 -24
  21. package/dist/better-auth/generators/fastify/better-auth-module/generated/index.d.ts +40 -2
  22. package/dist/better-auth/generators/fastify/better-auth-module/generated/template-renderers.d.ts +19 -1
  23. package/dist/better-auth/generators/fastify/better-auth-module/generated/template-renderers.js +6 -2
  24. package/dist/better-auth/generators/fastify/better-auth-module/generated/ts-import-providers.d.ts +1 -0
  25. package/dist/better-auth/generators/fastify/better-auth-module/generated/ts-import-providers.js +1 -0
  26. package/dist/better-auth/generators/fastify/better-auth-module/generated/typed-templates.d.ts +20 -1
  27. package/dist/better-auth/generators/fastify/better-auth-module/generated/typed-templates.js +4 -1
  28. package/dist/better-auth/generators/fastify/better-auth-module/templates/module/services/auth.ts +16 -8
  29. package/dist/better-auth/generators/react/better-auth-hooks/better-auth-hooks.generator.d.ts +1 -1
  30. package/dist/better-auth/generators/react/better-auth-hooks/generated/index.d.ts +5 -4
  31. package/dist/better-auth/generators/react/better-auth-hooks/generated/template-paths.d.ts +1 -1
  32. package/dist/better-auth/generators/react/better-auth-hooks/generated/template-paths.js +1 -1
  33. package/dist/better-auth/generators/react/better-auth-hooks/generated/ts-import-providers.d.ts +2 -1
  34. package/dist/better-auth/generators/react/better-auth-hooks/generated/ts-import-providers.js +2 -1
  35. package/dist/better-auth/generators/react/better-auth-hooks/generated/typed-templates.d.ts +6 -6
  36. package/dist/better-auth/generators/react/better-auth-hooks/generated/typed-templates.js +13 -13
  37. package/dist/better-auth/generators/react/better-auth-hooks/templates/src/hooks/{use-required-user-id.ts → use-user-id-or-throw.ts} +1 -1
  38. package/dist/better-auth/generators/react/better-auth-pages/better-auth-pages.generator.d.ts +37 -0
  39. package/dist/better-auth/generators/react/better-auth-pages/generated/index.d.ts +222 -0
  40. package/dist/better-auth/generators/react/better-auth-pages/generated/template-renderers.d.ts +37 -0
  41. package/dist/better-auth/generators/react/better-auth-pages/generated/typed-templates.d.ts +370 -0
  42. package/dist/better-auth/generators/react/better-auth-pages/templates/routes/forgot-password.tsx +1 -4
  43. package/dist/better-auth/generators/react/react-better-auth/generated/index.d.ts +77 -2
  44. package/dist/better-auth/generators/react/react-better-auth/generated/template-renderers.d.ts +38 -1
  45. package/dist/better-auth/generators/react/react-better-auth/generated/ts-import-providers.d.ts +1 -0
  46. package/dist/better-auth/generators/react/react-better-auth/generated/ts-import-providers.js +1 -0
  47. package/dist/better-auth/generators/react/react-better-auth/generated/typed-templates.d.ts +38 -1
  48. package/dist/better-auth/generators/react/react-better-auth/react-better-auth.generator.d.ts +38 -1
  49. package/dist/better-auth/generators/react/react-better-auth/templates/src/app/auth-loaded-gate.tsx +12 -3
  50. package/dist/local-auth/admin/common.js +6 -0
  51. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/admin-crud-invite-user-action.generator.d.ts +593 -0
  52. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/admin-crud-invite-user-action.generator.js +119 -0
  53. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/index.d.ts +602 -0
  54. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/index.js +11 -0
  55. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/template-paths.d.ts +12 -0
  56. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/template-paths.js +24 -0
  57. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/template-renderers.d.ts +307 -0
  58. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/template-renderers.js +45 -0
  59. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/typed-templates.d.ts +294 -0
  60. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/generated/typed-templates.js +21 -0
  61. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/index.d.ts +2 -0
  62. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/index.js +2 -0
  63. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/templates/routes/-components/invite-user-dialog.d.ts +21 -0
  64. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/templates/routes/-components/invite-user-dialog.js +68 -0
  65. package/dist/local-auth/admin/generators/admin-crud-invite-user-action/templates/routes/-components/invite-user-dialog.tsx +122 -0
  66. package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/admin-crud-manage-roles-action.generator.d.ts +74 -0
  67. package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/generated/index.d.ts +74 -0
  68. package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/generated/template-renderers.d.ts +37 -0
  69. package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/generated/typed-templates.d.ts +37 -0
  70. package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/templates/routes/-components/role-manager-dialog.js +1 -2
  71. package/dist/local-auth/admin/generators/admin-crud-manage-roles-action/templates/routes/-components/role-manager-dialog.tsx +1 -1
  72. package/dist/local-auth/admin/generators/admin-crud-reset-password-action/admin-crud-reset-password-action.generator.d.ts +74 -0
  73. package/dist/local-auth/admin/generators/admin-crud-reset-password-action/generated/index.d.ts +74 -0
  74. package/dist/local-auth/admin/generators/admin-crud-reset-password-action/generated/template-renderers.d.ts +37 -0
  75. package/dist/local-auth/admin/generators/admin-crud-reset-password-action/generated/typed-templates.d.ts +74 -0
  76. package/dist/local-auth/admin/generators/admin-crud-reset-password-action/templates/routes/-components/password-reset-dialog.js +1 -2
  77. package/dist/local-auth/admin/generators/admin-crud-reset-password-action/templates/routes/-components/password-reset-dialog.tsx +1 -1
  78. package/dist/local-auth/admin/generators/admin-crud-roles-column/admin-crud-roles-column.generator.d.ts +37 -0
  79. package/dist/local-auth/admin/node.js +13 -0
  80. package/dist/local-auth/admin/schema/invite-user-action.d.ts +12 -0
  81. package/dist/local-auth/admin/schema/invite-user-action.js +6 -0
  82. package/dist/local-auth/admin/web.js +8 -0
  83. package/dist/local-auth/core/common.js +7 -2
  84. package/dist/local-auth/core/components/local-auth-definition-editor.js +2 -1
  85. package/dist/local-auth/core/components/local-auth-web-app-settings-form.d.ts +9 -0
  86. package/dist/local-auth/core/components/local-auth-web-app-settings-form.js +11 -0
  87. package/dist/local-auth/core/generators/auth-email-password/auth-email-password.generator.d.ts +16 -7
  88. package/dist/local-auth/core/generators/auth-email-password/auth-email-password.generator.js +73 -16
  89. package/dist/local-auth/core/generators/auth-email-password/generated/index.d.ts +222 -7
  90. package/dist/local-auth/core/generators/auth-email-password/generated/template-paths.d.ts +5 -0
  91. package/dist/local-auth/core/generators/auth-email-password/generated/template-paths.js +5 -0
  92. package/dist/local-auth/core/generators/auth-email-password/generated/template-renderers.d.ts +27 -0
  93. package/dist/local-auth/core/generators/auth-email-password/generated/template-renderers.js +71 -4
  94. package/dist/local-auth/core/generators/auth-email-password/generated/ts-import-providers.d.ts +1 -3
  95. package/dist/local-auth/core/generators/auth-email-password/generated/ts-import-providers.js +1 -2
  96. package/dist/local-auth/core/generators/auth-email-password/generated/typed-templates.d.ts +226 -10
  97. package/dist/local-auth/core/generators/auth-email-password/generated/typed-templates.js +91 -7
  98. package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/otp.constants.d.ts +19 -0
  99. package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/otp.constants.js +20 -0
  100. package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/otp.constants.ts +22 -0
  101. package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/password.constants.d.ts +12 -0
  102. package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/password.constants.js +12 -0
  103. package/dist/local-auth/core/generators/auth-email-password/templates/module/constants/password.constants.ts +14 -0
  104. package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/email-otp.mutations.d.ts +2 -0
  105. package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/email-otp.mutations.js +30 -0
  106. package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/email-otp.mutations.ts +38 -0
  107. package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/invite.mutations.d.ts +2 -0
  108. package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/invite.mutations.js +42 -0
  109. package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/invite.mutations.ts +54 -0
  110. package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/user-password.mutations.js +2 -19
  111. package/dist/local-auth/core/generators/auth-email-password/templates/module/schema/user-password.mutations.ts +1 -22
  112. package/dist/local-auth/core/generators/auth-email-password/templates/module/services/email-otp.service.d.ts +37 -0
  113. package/dist/local-auth/core/generators/auth-email-password/templates/module/services/email-otp.service.js +225 -0
  114. package/dist/local-auth/core/generators/auth-email-password/templates/module/services/email-otp.service.ts +333 -0
  115. package/dist/local-auth/core/generators/auth-email-password/templates/module/services/email-verification.service.js +2 -3
  116. package/dist/local-auth/core/generators/auth-email-password/templates/module/services/email-verification.service.ts +5 -3
  117. package/dist/local-auth/core/generators/auth-email-password/templates/module/services/invite.service.d.ts +39 -0
  118. package/dist/local-auth/core/generators/auth-email-password/templates/module/services/invite.service.js +142 -0
  119. package/dist/local-auth/core/generators/auth-email-password/templates/module/services/invite.service.ts +221 -0
  120. package/dist/local-auth/core/generators/auth-email-password/templates/module/services/password-reset.service.js +5 -6
  121. package/dist/local-auth/core/generators/auth-email-password/templates/module/services/password-reset.service.ts +8 -5
  122. package/dist/local-auth/core/generators/auth-email-templates/auth-email-templates.generator.d.ts +3 -1
  123. package/dist/local-auth/core/generators/auth-email-templates/auth-email-templates.generator.js +18 -3
  124. package/dist/local-auth/core/generators/auth-email-templates/generated/index.d.ts +40 -0
  125. package/dist/local-auth/core/generators/auth-email-templates/generated/template-paths.d.ts +2 -0
  126. package/dist/local-auth/core/generators/auth-email-templates/generated/template-paths.js +2 -0
  127. package/dist/local-auth/core/generators/auth-email-templates/generated/template-renderers.d.ts +6 -0
  128. package/dist/local-auth/core/generators/auth-email-templates/generated/template-renderers.js +20 -0
  129. package/dist/local-auth/core/generators/auth-email-templates/generated/typed-templates.d.ts +40 -0
  130. package/dist/local-auth/core/generators/auth-email-templates/generated/typed-templates.js +24 -0
  131. package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/email-otp.email.d.ts +3 -0
  132. package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/email-otp.email.js +18 -0
  133. package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/email-otp.email.tsx +57 -0
  134. package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/invite.email.d.ts +3 -0
  135. package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/invite.email.js +14 -0
  136. package/dist/local-auth/core/generators/auth-email-templates/templates/src/emails/auth/invite.email.tsx +47 -0
  137. package/dist/local-auth/core/generators/auth-hooks/auth-hooks.generator.d.ts +272 -1
  138. package/dist/local-auth/core/generators/auth-hooks/generated/index.d.ts +547 -4
  139. package/dist/local-auth/core/generators/auth-hooks/generated/template-paths.d.ts +1 -1
  140. package/dist/local-auth/core/generators/auth-hooks/generated/template-paths.js +1 -1
  141. package/dist/local-auth/core/generators/auth-hooks/generated/template-renderers.d.ts +271 -0
  142. package/dist/local-auth/core/generators/auth-hooks/generated/template-renderers.js +4 -2
  143. package/dist/local-auth/core/generators/auth-hooks/generated/ts-import-providers.d.ts +2 -1
  144. package/dist/local-auth/core/generators/auth-hooks/generated/ts-import-providers.js +2 -1
  145. package/dist/local-auth/core/generators/auth-hooks/generated/typed-templates.d.ts +548 -6
  146. package/dist/local-auth/core/generators/auth-hooks/generated/typed-templates.js +15 -14
  147. package/dist/local-auth/core/generators/auth-hooks/templates/src/hooks/use-log-out.js +1 -1
  148. package/dist/local-auth/core/generators/auth-hooks/templates/src/hooks/use-log-out.ts +1 -1
  149. package/dist/local-auth/core/generators/auth-hooks/templates/src/hooks/use-session.d.ts +7 -0
  150. package/dist/local-auth/core/generators/auth-hooks/templates/src/hooks/use-session.ts +7 -0
  151. package/dist/local-auth/core/generators/auth-module/auth-module.generator.d.ts +23 -7
  152. package/dist/local-auth/core/generators/auth-module/auth-module.generator.js +7 -26
  153. package/dist/local-auth/core/generators/auth-module/generated/index.d.ts +65 -4
  154. package/dist/local-auth/core/generators/auth-module/generated/template-paths.d.ts +1 -1
  155. package/dist/local-auth/core/generators/auth-module/generated/template-paths.js +1 -1
  156. package/dist/local-auth/core/generators/auth-module/generated/template-renderers.d.ts +22 -1
  157. package/dist/local-auth/core/generators/auth-module/generated/template-renderers.js +19 -2
  158. package/dist/local-auth/core/generators/auth-module/generated/ts-import-providers.d.ts +10 -0
  159. package/dist/local-auth/core/generators/auth-module/generated/ts-import-providers.js +7 -0
  160. package/dist/local-auth/core/generators/auth-module/generated/typed-templates.d.ts +42 -4
  161. package/dist/local-auth/core/generators/auth-module/generated/typed-templates.js +24 -13
  162. package/dist/local-auth/core/generators/auth-module/templates/module/services/auth-verification.service.d.ts +4 -0
  163. package/dist/local-auth/core/generators/auth-module/templates/module/services/auth-verification.service.js +1 -1
  164. package/dist/local-auth/core/generators/auth-module/templates/module/services/auth-verification.service.ts +1 -1
  165. package/dist/local-auth/core/generators/auth-module/templates/module/services/code-verification.service.d.ts +67 -0
  166. package/dist/local-auth/core/generators/auth-module/templates/module/services/code-verification.service.js +140 -0
  167. package/dist/local-auth/core/generators/auth-module/templates/module/services/code-verification.service.ts +191 -0
  168. package/dist/local-auth/core/generators/auth-module/templates/module/services/user-session.service.js +8 -9
  169. package/dist/local-auth/core/generators/auth-module/templates/module/services/user-session.service.ts +10 -11
  170. package/dist/local-auth/core/generators/auth-routes/auth-routes.generator.d.ts +39 -0
  171. package/dist/local-auth/core/generators/auth-routes/auth-routes.generator.js +38 -5
  172. package/dist/local-auth/core/generators/auth-routes/generated/index.d.ts +1089 -268
  173. package/dist/local-auth/core/generators/auth-routes/generated/template-paths.d.ts +3 -0
  174. package/dist/local-auth/core/generators/auth-routes/generated/template-paths.js +3 -0
  175. package/dist/local-auth/core/generators/auth-routes/generated/template-renderers.d.ts +49 -0
  176. package/dist/local-auth/core/generators/auth-routes/generated/template-renderers.js +51 -0
  177. package/dist/local-auth/core/generators/auth-routes/generated/ts-import-providers.d.ts +1 -0
  178. package/dist/local-auth/core/generators/auth-routes/generated/ts-import-providers.js +1 -0
  179. package/dist/local-auth/core/generators/auth-routes/generated/typed-templates.d.ts +918 -283
  180. package/dist/local-auth/core/generators/auth-routes/generated/typed-templates.js +69 -23
  181. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/-otp-constants.d.ts +9 -0
  182. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/-otp-constants.js +10 -0
  183. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/-otp-constants.ts +11 -0
  184. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/accept-invite.d.ts +7 -0
  185. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/accept-invite.js +155 -0
  186. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/accept-invite.tsx +274 -0
  187. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/forgot-password.js +1 -2
  188. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/forgot-password.tsx +1 -1
  189. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/login-otp.d.ts +7 -0
  190. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/login-otp.js +184 -0
  191. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/login-otp.tsx +312 -0
  192. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/login.js +5 -5
  193. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/login.tsx +6 -12
  194. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/register.js +4 -4
  195. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/register.tsx +4 -3
  196. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/reset-password.js +1 -2
  197. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/reset-password.tsx +1 -1
  198. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/verify-email.js +1 -2
  199. package/dist/local-auth/core/generators/auth-routes/templates/routes/auth_/verify-email.tsx +1 -1
  200. package/dist/local-auth/core/generators/react-session/generated/index.d.ts +90 -7
  201. package/dist/local-auth/core/generators/react-session/generated/template-renderers.d.ts +38 -1
  202. package/dist/local-auth/core/generators/react-session/generated/ts-import-providers.d.ts +1 -0
  203. package/dist/local-auth/core/generators/react-session/generated/ts-import-providers.js +1 -0
  204. package/dist/local-auth/core/generators/react-session/generated/typed-templates.d.ts +102 -12
  205. package/dist/local-auth/core/generators/react-session/generated/typed-templates.js +5 -2
  206. package/dist/local-auth/core/generators/react-session/react-session.generator.d.ts +54 -1
  207. package/dist/local-auth/core/generators/react-session/react-session.generator.js +35 -1
  208. package/dist/local-auth/core/generators/react-session/templates/src/app/user-session-provider.js +17 -44
  209. package/dist/local-auth/core/generators/react-session/templates/src/app/user-session-provider.tsx +21 -49
  210. package/dist/local-auth/core/generators/react-session/templates/src/services/user-session-client.d.ts +43 -34
  211. package/dist/local-auth/core/generators/react-session/templates/src/services/user-session-client.js +96 -80
  212. package/dist/local-auth/core/generators/react-session/templates/src/services/user-session-client.ts +148 -82
  213. package/dist/local-auth/core/generators/seed-initial-user/generated/index.d.ts +0 -2
  214. package/dist/local-auth/core/generators/seed-initial-user/generated/template-renderers.d.ts +0 -1
  215. package/dist/local-auth/core/generators/seed-initial-user/generated/typed-templates.d.ts +0 -1
  216. package/dist/local-auth/core/generators/seed-initial-user/seed-initial-user.generator.d.ts +0 -1
  217. package/dist/local-auth/core/node.js +30 -12
  218. package/dist/local-auth/core/schema/migrations.d.ts +3 -0
  219. package/dist/local-auth/core/schema/migrations.js +36 -0
  220. package/dist/local-auth/core/schema/models.js +8 -0
  221. package/dist/local-auth/core/schema/plugin-definition.d.ts +1 -0
  222. package/dist/local-auth/core/schema/plugin-definition.js +1 -0
  223. package/dist/local-auth/core/schema/web-app-schema.d.ts +15 -0
  224. package/dist/local-auth/core/schema/web-app-schema.js +16 -0
  225. package/dist/local-auth/core/web.js +8 -1
  226. package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/index.d.ts +4 -3
  227. package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/template-paths.d.ts +1 -1
  228. package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/template-paths.js +1 -1
  229. package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/ts-import-providers.d.ts +2 -1
  230. package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/ts-import-providers.js +2 -1
  231. package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/typed-templates.d.ts +4 -4
  232. package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/generated/typed-templates.js +13 -13
  233. package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/placeholder-auth-hooks.generator.d.ts +1 -1
  234. package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/templates/src/hooks/use-session.d.ts +1 -0
  235. package/dist/placeholder-auth/core/generators/placeholder-auth-hooks/templates/src/hooks/use-session.ts +2 -0
  236. package/dist/placeholder-auth/core/generators/placeholder-auth-module/generated/index.d.ts +1 -2
  237. package/dist/placeholder-auth/core/generators/placeholder-auth-module/generated/template-renderers.d.ts +0 -1
  238. package/dist/placeholder-auth/core/generators/placeholder-auth-module/generated/ts-import-providers.d.ts +1 -0
  239. package/dist/placeholder-auth/core/generators/placeholder-auth-module/generated/ts-import-providers.js +1 -0
  240. package/dist/placeholder-auth/core/generators/placeholder-auth-module/generated/typed-templates.d.ts +0 -1
  241. package/dist/placeholder-auth/core/generators/placeholder-auth-module/placeholder-auth-module.generator.d.ts +0 -1
  242. package/dist/web/assets/{_virtual_mf-localSharedImportMap___mfe_internal__plugin_mf_2_auth-ChkXxpXe.js → _virtual_mf-localSharedImportMap___mfe_internal__plugin_mf_2_auth__mf_owner__1-DUupKqD4.js} +42 -34
  243. package/dist/web/assets/{dist-DY7ZXvq4.js → _virtual_mf___mfe_internal__plugin_mf_2_auth__mf_owner__1__loadShare___mf_0_baseplate_mf_2_dev_mf_1_project_mf_2_builder_mf_2_lib__loadShare__.js-DE4rTqEA.js} +16857 -381
  244. package/dist/web/assets/{_virtual_mf___mfe_internal__plugin_mf_2_auth__loadShare___mf_0_baseplate_mf_2_dev_mf_1_project_mf_2_builder_mf_2_lib_mf_1_web__loadShare__.js-37vlYRxk.js → _virtual_mf___mfe_internal__plugin_mf_2_auth__mf_owner__1__loadShare___mf_0_baseplate_mf_2_dev_mf_1_project_mf_2_builder_mf_2_lib_mf_1_web__loadShare__.js-mszeXpf-.js} +90 -38
  245. package/dist/web/assets/{_virtual_mf___mfe_internal__plugin_mf_2_auth__loadShare___mf_0_baseplate_mf_2_dev_mf_1_ui_mf_2_components__loadShare__.js-DRSNXPPo.js → _virtual_mf___mfe_internal__plugin_mf_2_auth__mf_owner__1__loadShare___mf_0_baseplate_mf_2_dev_mf_1_ui_mf_2_components__loadShare__.js-CtIleM_e.js} +4095 -2399
  246. package/dist/web/assets/{_virtual_mf___mfe_internal__plugin_mf_2_auth__loadShare___mf_0_tanstack_mf_1_react_mf_2_router__loadShare__.js-DfiQqvVC.js → _virtual_mf___mfe_internal__plugin_mf_2_auth__mf_owner__1__loadShare___mf_0_tanstack_mf_1_react_mf_2_router__loadShare__.js-BckLhSjF.js} +212 -57
  247. package/dist/web/assets/auth-DR6QxrAW.js +1 -0
  248. package/dist/web/assets/{common-iHaemino.js → common-BsyRiQi3.js} +6 -6
  249. package/dist/web/assets/{common-TDf_PrjX.js → common-CRwNlCMn.js} +10 -10
  250. package/dist/web/assets/{common-ByxS61u8.js → common-CvqlRZC9.js} +12 -12
  251. package/dist/web/assets/common-D3atSs7O.js +70 -0
  252. package/dist/web/assets/common-DuFyXa6l.js +36 -0
  253. package/dist/web/assets/common-islduJTj.js +43 -0
  254. package/dist/web/assets/{dist-CrLSslv6.js → dist-DQd1TAJX.js} +273 -132
  255. package/dist/web/assets/{get-auth-plugin-definition-kDCtXq_6.js → get-auth-plugin-definition-BgWWHl_Y.js} +3 -3
  256. package/dist/web/assets/{hostInit-Cruek6c6.js → hostInit-DNA4kLRY.js} +32 -5
  257. package/dist/web/assets/{mf-entry-bootstrap-0-dfed0275.js → mf-entry-bootstrap-0-ea77c09b.js} +2 -1
  258. package/dist/web/assets/{mf-entry-bootstrap-1-5275674a.js → mf-entry-bootstrap-1-9dee3d8d.js} +3 -2
  259. package/dist/web/assets/{mf-entry-bootstrap-2-39fb9255.js → mf-entry-bootstrap-2-3179040b.js} +3 -2
  260. package/dist/web/assets/{mf-entry-bootstrap-3-49e64336.js → mf-entry-bootstrap-3-370d200d.js} +3 -2
  261. package/dist/web/assets/{models-DSvs_3bA.js → models-BOeSYfRn.js} +4 -5
  262. package/dist/web/assets/{models-BZmCbizK.js → models-DF6DoXt6.js} +11 -6
  263. package/dist/web/assets/{plugin-definition-CYj29S3q.js → plugin-definition--k0VAeK3.js} +9 -10
  264. package/dist/web/assets/plugin-definition-CMwSlxsJ.js +10 -0
  265. package/dist/web/assets/{styles-yjbHBTlw.js → styles-BQEcQHoR.js} +9 -10
  266. package/dist/web/assets/{virtualExposes-CbPBmicF.js → virtualExposes-C7fDiAmS.js} +1 -1
  267. package/dist/web/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__plugin-auth__remoteEntry_js-BZBRyml2.js +747 -0
  268. package/dist/web/assets/{virtual_mf-exposes___mfe_internal__plugin-auth__remoteEntry_js-B6BXIeF1.js → virtual_mf-exposes___mfe_internal__plugin-auth__remoteEntry_js-6SjVUCs8.js} +13 -13
  269. package/dist/web/assets/web-8wz0ad-V.js +59 -0
  270. package/dist/web/assets/{web-CXAHKjIY.js → web-BGixH_gT.js} +27 -27
  271. package/dist/web/assets/{web-1eTcxMhf.js → web-BxIwkN3O.js} +6 -6
  272. package/dist/web/assets/{web-VqBA3jxZ.js → web-CQMfABjr.js} +24 -24
  273. package/dist/web/assets/{web-CDAKPPK9.js → web-CcNpItSu.js} +22 -22
  274. package/dist/web/assets/web-CypPeiVv.js +148 -0
  275. package/dist/web/assets/{web-D0MSKfyv.js → web-CzK_la2_.js} +53 -53
  276. package/dist/web/index.html +5 -5
  277. package/dist/web/remoteEntry.js +1 -1
  278. package/package.json +14 -14
  279. package/dist/local-auth/core/generators/auth-module/templates/module/utils/cookie-signer.d.ts +0 -38
  280. package/dist/local-auth/core/generators/auth-module/templates/module/utils/cookie-signer.js +0 -71
  281. package/dist/local-auth/core/generators/auth-module/templates/module/utils/cookie-signer.ts +0 -77
  282. package/dist/web/assets/_virtual_mf___mfe_internal__plugin_mf_2_auth__loadShare___mf_0_baseplate_mf_2_dev_mf_1_project_mf_2_builder_mf_2_lib__loadShare__.js-CO5Pvo0y.js +0 -384
  283. package/dist/web/assets/_virtual_mf___mfe_internal__plugin_mf_2_auth__loadShare__zod__loadShare__.js-BEZ7A-cz.js +0 -13566
  284. package/dist/web/assets/auth-BxAE0rgh.js +0 -1
  285. package/dist/web/assets/common-CKl_XlvH.js +0 -37
  286. package/dist/web/assets/common-UpVCKZeW.js +0 -41
  287. package/dist/web/assets/common-crSwCD36.js +0 -37
  288. package/dist/web/assets/model-utils-C0WDb_Ec.js +0 -1599
  289. package/dist/web/assets/plugin-definition-DOMmPL2Z.js +0 -11
  290. package/dist/web/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__plugin-auth__remoteEntry_js-XM6iYVxf.js +0 -259
  291. package/dist/web/assets/virtual_mf-exposes-ssr___mfe_internal__plugin-auth__remoteEntry_js-DGjg7Brm.js +0 -129
  292. package/dist/web/assets/web-DbeAaDTV.js +0 -118
  293. package/dist/web/assets/web-miDovYk_.js +0 -46
  294. package/dist/web/remoteEntry.ssr.js +0 -43
@@ -0,0 +1,225 @@
1
+ // @ts-nocheck
2
+ import { EMAIL_OTP_EXPIRY_SEC, EMAIL_OTP_LENGTH, EMAIL_OTP_MAX_ATTEMPTS, } from '$constantsOtp';
3
+ import { PASSWORD_MAX_LENGTH } from '$constantsPassword';
4
+ import { consumeCodeVerification, createCodeVerification, validateCodeVerification, } from '%authModuleImports';
5
+ import { isDevelopment } from '%configServiceImports';
6
+ import { BadRequestError, handleZodRequestValidationError, } from '%errorHandlerServiceImports';
7
+ import { prisma } from '%prismaImports';
8
+ import { memoizeRateLimiter } from '%rateLimitImports';
9
+ import * as crypto from 'node:crypto';
10
+ import z from 'zod';
11
+ const PROVIDER_ID = 'email-otp';
12
+ const EMAIL_OTP_TYPE = 'email-otp';
13
+ /**
14
+ * Rate limiters for emailed sign-in codes.
15
+ */
16
+ // Per-email burst limit: 3 codes / 15 minutes
17
+ const getEmailOtpRequestEmailLimiter = memoizeRateLimiter('email-otp-email', {
18
+ points: 3,
19
+ duration: 60 * 15, // 15 minutes
20
+ });
21
+ // Per-email daily cap. Each new code resets that code's attempt budget, so
22
+ // this is what actually bounds guesses per day: 10 codes x 5 attempts.
23
+ const getEmailOtpRequestEmailDailyLimiter = memoizeRateLimiter('email-otp-email-daily', {
24
+ points: 10,
25
+ duration: 60 * 60 * 24, // 1 day
26
+ });
27
+ // Per-IP rate limit: 10 codes/hour (prevents email scanning)
28
+ const getEmailOtpRequestIpLimiter = memoizeRateLimiter('email-otp-ip', {
29
+ points: 10,
30
+ duration: 60 * 60, // 1 hour
31
+ });
32
+ // Deliberately no global limiter here. A shared counter would let anyone who
33
+ // exhausts it lock every user out of signing in, and accounts created through
34
+ // this flow have no password to fall back on. Distributed abuse is bounded by
35
+ // the per-IP limit above; protecting the email provider from a cost or
36
+ // reputation spike belongs in its own quotas and alerting, not in the login
37
+ // path.
38
+ // Per-address verification limit. Unlike the per-code attempt budget this
39
+ // survives the code being reissued, and unlike the per-IP limit it survives
40
+ // the attacker rotating IPs.
41
+ const getEmailOtpVerifyEmailLimiter = memoizeRateLimiter('email-otp-verify-email', {
42
+ points: 10,
43
+ duration: 60 * 60, // 1 hour
44
+ blockDuration: 60 * 60, // Block for 1 hour if exceeded
45
+ });
46
+ // Per-IP verification limit, on top of each code's own attempt budget
47
+ const getEmailOtpVerifyIpLimiter = memoizeRateLimiter('email-otp-verify-ip', {
48
+ points: 20,
49
+ duration: 60 * 60, // 1 hour
50
+ blockDuration: 60 * 60, // Block for 1 hour if exceeded
51
+ });
52
+ /**
53
+ * Cookie holding the id of the pending verification.
54
+ *
55
+ * Requiring it at verification binds a code to the browser that asked for it,
56
+ * so a code read over someone's shoulder or talked out of them over the phone
57
+ * cannot be redeemed elsewhere.
58
+ */
59
+ const EMAIL_OTP_COOKIE_NAME = 'email-otp-verification';
60
+ function getEmailOtpCookieOptions() {
61
+ return {
62
+ httpOnly: true,
63
+ sameSite: 'lax',
64
+ secure: !isDevelopment(),
65
+ maxAge: EMAIL_OTP_EXPIRY_SEC,
66
+ path: '/',
67
+ };
68
+ }
69
+ const emailSchema = z.object({
70
+ email: z
71
+ .email()
72
+ .max(PASSWORD_MAX_LENGTH)
73
+ .transform((value) => value.toLowerCase()),
74
+ });
75
+ /**
76
+ * Generates a numeric code using rejection sampling so every digit is equally
77
+ * likely. 250 is the largest multiple of 10 within a byte, so values above it
78
+ * are discarded rather than folded back and over-weighting digits 0-5.
79
+ */
80
+ function generateNumericCode(length) {
81
+ const digits = Array.from({ length }, () => {
82
+ let value = 256;
83
+ while (value >= 250) {
84
+ value = crypto.randomBytes(1).readUInt8(0);
85
+ }
86
+ return String(value % 10);
87
+ });
88
+ return digits.join('');
89
+ }
90
+ /**
91
+ * Emails a single-use sign-in code to the given address.
92
+ *
93
+ * A code is sent whether or not an account exists — verifying one signs the
94
+ * user in, creating the account on first use — so this endpoint reveals
95
+ * nothing about which addresses are registered.
96
+ */
97
+ export async function requestEmailOtp({ email: rawEmail, context, }) {
98
+ const { services } = context;
99
+ const { email } = await emailSchema
100
+ .parseAsync({ email: rawEmail })
101
+ .catch(handleZodRequestValidationError);
102
+ await Promise.all([
103
+ getEmailOtpRequestIpLimiter().consumeOrThrow(context.reqInfo.ip, 'Too many sign-in code requests. Please try again later.', 'too-many-requests'),
104
+ getEmailOtpRequestEmailLimiter().consumeOrThrow(email, 'Too many sign-in code requests. Please try again later.', 'too-many-requests'),
105
+ getEmailOtpRequestEmailDailyLimiter().consumeOrThrow(email, 'Too many sign-in code requests. Please try again later.', 'too-many-requests'),
106
+ ]);
107
+ const code = generateNumericCode(EMAIL_OTP_LENGTH);
108
+ const { id: verificationId } = await createCodeVerification({
109
+ type: EMAIL_OTP_TYPE,
110
+ identifier: email,
111
+ code,
112
+ expiresInSec: EMAIL_OTP_EXPIRY_SEC,
113
+ });
114
+ context.cookieStore.set(EMAIL_OTP_COOKIE_NAME, verificationId, getEmailOtpCookieOptions());
115
+ await services.email.send(TPL_EMAIL_OTP_EMAIL, {
116
+ to: email,
117
+ data: { code, expiryMinutes: Math.floor(EMAIL_OTP_EXPIRY_SEC / 60) },
118
+ });
119
+ return { success: true };
120
+ }
121
+ const verifyEmailOtpSchema = z.object({
122
+ email: z
123
+ .email()
124
+ .max(PASSWORD_MAX_LENGTH)
125
+ .transform((value) => value.toLowerCase()),
126
+ code: z.string().length(EMAIL_OTP_LENGTH),
127
+ // Blank and whitespace-only names are normalized to absent rather than
128
+ // rejected, so a client that always sends the field still gets the
129
+ // `name-required` response rather than a generic validation failure.
130
+ name: z
131
+ .string()
132
+ .max(100)
133
+ .optional()
134
+ .transform((value) => {
135
+ const trimmed = value?.trim();
136
+ return trimmed ? trimmed : undefined;
137
+ }),
138
+ });
139
+ /**
140
+ * Signs a user in with an emailed code, creating the account on first use.
141
+ *
142
+ * A verified code proves control of the inbox, so the account it creates (or
143
+ * signs in to) is marked as having a verified email. Accounts created this way
144
+ * have no password until the user goes through the password reset flow.
145
+ *
146
+ * @throws BadRequestError `name-required` when the code is valid but the
147
+ * address has no account yet and no name was supplied. The code is left intact
148
+ * so the client can collect a name and retry with it.
149
+ */
150
+ export async function signInWithEmailOtp({ input, context, }) {
151
+ const { email, code, name } = await verifyEmailOtpSchema
152
+ .parseAsync(input)
153
+ .catch(handleZodRequestValidationError);
154
+ await getEmailOtpVerifyIpLimiter().consumeOrThrow(context.reqInfo.ip, 'Too many sign-in attempts. Please try again later.', 'too-many-requests');
155
+ // A code is only redeemable in the browser that requested it.
156
+ const verificationId = context.cookieStore.get(EMAIL_OTP_COOKIE_NAME);
157
+ if (!verificationId) {
158
+ throw new BadRequestError('This code must be entered in the browser that requested it', 'verification-context-missing');
159
+ }
160
+ // Establish that this browser owns the outstanding code before spending any
161
+ // of the address's budget. Charging first would let anyone lock a chosen
162
+ // address out of signing in just by posting its email with a junk code —
163
+ // which is worse than it sounds, because an account created through this
164
+ // flow has no password to fall back on.
165
+ const challenge = await prisma.authVerification.findUnique({
166
+ where: { type_identifier: { type: EMAIL_OTP_TYPE, identifier: email } },
167
+ select: { id: true },
168
+ });
169
+ if (challenge?.id !== verificationId) {
170
+ throw new BadRequestError('Invalid or expired code', 'invalid-code');
171
+ }
172
+ await getEmailOtpVerifyEmailLimiter().consumeOrThrow(email, 'Too many sign-in attempts. Please try again later.', 'too-many-requests');
173
+ const record = await validateCodeVerification({
174
+ type: EMAIL_OTP_TYPE,
175
+ identifier: email,
176
+ code,
177
+ maxAttempts: EMAIL_OTP_MAX_ATTEMPTS,
178
+ });
179
+ if (!record) {
180
+ throw new BadRequestError('Invalid or expired code', 'invalid-code');
181
+ }
182
+ // Re-checked because a fresh code may have been issued since the lookup
183
+ // above, which would have replaced the id this browser is holding.
184
+ if (record.id !== verificationId) {
185
+ throw new BadRequestError('Invalid or expired code', 'invalid-code');
186
+ }
187
+ // Asking for a name only when the address is new would normally leak whether
188
+ // an account exists. Gating it behind a valid code keeps that safe: only
189
+ // someone who controls the mailbox reaches this point.
190
+ TPL_NAME_REQUIRED_CHECK;
191
+ // Spending the code and settling the account commit together, so a failure
192
+ // partway through leaves the code still usable rather than burning it and
193
+ // forcing the user to request another.
194
+ const userId = await prisma.$transaction(async (tx) => {
195
+ if (!(await consumeCodeVerification({ id: record.id, client: tx }))) {
196
+ throw new BadRequestError('Invalid or expired code', 'invalid-code');
197
+ }
198
+ // Receiving the code proves control of the address, so the account is
199
+ // created (or marked) as verified. An existing user's name is left alone.
200
+ const { id } = await tx.user.upsert({
201
+ where: { email },
202
+ create: {
203
+ email,
204
+ name,
205
+ emailVerified: true,
206
+ accounts: {
207
+ create: {
208
+ accountId: email,
209
+ providerId: PROVIDER_ID,
210
+ },
211
+ },
212
+ },
213
+ update: { emailVerified: true },
214
+ select: { id: true },
215
+ });
216
+ return id;
217
+ });
218
+ context.cookieStore.clear(EMAIL_OTP_COOKIE_NAME, getEmailOtpCookieOptions());
219
+ // Outside the transaction: session creation manages its own storage through
220
+ // the request context. If it fails the code is spent, but the account now
221
+ // exists, so retrying signs the user in without asking for a name again.
222
+ const session = await context.services.userSession.createSession(userId, context);
223
+ return { session };
224
+ }
225
+ //# sourceMappingURL=email-otp.service.js.map
@@ -0,0 +1,333 @@
1
+ // @ts-nocheck
2
+
3
+ import type {
4
+ RequestServiceContext,
5
+ RequestServiceContextWith,
6
+ } from '%requestServiceContextImports';
7
+ import type { UserSessionPayload } from '%userSessionTypesImports';
8
+ import type { CookieSerializeOptions } from '@fastify/cookie';
9
+
10
+ import {
11
+ EMAIL_OTP_EXPIRY_SEC,
12
+ EMAIL_OTP_LENGTH,
13
+ EMAIL_OTP_MAX_ATTEMPTS,
14
+ } from '$constantsOtp';
15
+ import { PASSWORD_MAX_LENGTH } from '$constantsPassword';
16
+ import {
17
+ consumeCodeVerification,
18
+ createCodeVerification,
19
+ validateCodeVerification,
20
+ } from '%authModuleImports';
21
+ import { isDevelopment } from '%configServiceImports';
22
+ import {
23
+ BadRequestError,
24
+ handleZodRequestValidationError,
25
+ } from '%errorHandlerServiceImports';
26
+ import { prisma } from '%prismaImports';
27
+ import { memoizeRateLimiter } from '%rateLimitImports';
28
+ import * as crypto from 'node:crypto';
29
+ import z from 'zod';
30
+
31
+ const PROVIDER_ID = 'email-otp';
32
+ const EMAIL_OTP_TYPE = 'email-otp';
33
+
34
+ /**
35
+ * Rate limiters for emailed sign-in codes.
36
+ */
37
+
38
+ // Per-email burst limit: 3 codes / 15 minutes
39
+ const getEmailOtpRequestEmailLimiter = memoizeRateLimiter('email-otp-email', {
40
+ points: 3,
41
+ duration: 60 * 15, // 15 minutes
42
+ });
43
+
44
+ // Per-email daily cap. Each new code resets that code's attempt budget, so
45
+ // this is what actually bounds guesses per day: 10 codes x 5 attempts.
46
+ const getEmailOtpRequestEmailDailyLimiter = memoizeRateLimiter(
47
+ 'email-otp-email-daily',
48
+ {
49
+ points: 10,
50
+ duration: 60 * 60 * 24, // 1 day
51
+ },
52
+ );
53
+
54
+ // Per-IP rate limit: 10 codes/hour (prevents email scanning)
55
+ const getEmailOtpRequestIpLimiter = memoizeRateLimiter('email-otp-ip', {
56
+ points: 10,
57
+ duration: 60 * 60, // 1 hour
58
+ });
59
+
60
+ // Deliberately no global limiter here. A shared counter would let anyone who
61
+ // exhausts it lock every user out of signing in, and accounts created through
62
+ // this flow have no password to fall back on. Distributed abuse is bounded by
63
+ // the per-IP limit above; protecting the email provider from a cost or
64
+ // reputation spike belongs in its own quotas and alerting, not in the login
65
+ // path.
66
+
67
+ // Per-address verification limit. Unlike the per-code attempt budget this
68
+ // survives the code being reissued, and unlike the per-IP limit it survives
69
+ // the attacker rotating IPs.
70
+ const getEmailOtpVerifyEmailLimiter = memoizeRateLimiter(
71
+ 'email-otp-verify-email',
72
+ {
73
+ points: 10,
74
+ duration: 60 * 60, // 1 hour
75
+ blockDuration: 60 * 60, // Block for 1 hour if exceeded
76
+ },
77
+ );
78
+
79
+ // Per-IP verification limit, on top of each code's own attempt budget
80
+ const getEmailOtpVerifyIpLimiter = memoizeRateLimiter('email-otp-verify-ip', {
81
+ points: 20,
82
+ duration: 60 * 60, // 1 hour
83
+ blockDuration: 60 * 60, // Block for 1 hour if exceeded
84
+ });
85
+
86
+ /**
87
+ * Cookie holding the id of the pending verification.
88
+ *
89
+ * Requiring it at verification binds a code to the browser that asked for it,
90
+ * so a code read over someone's shoulder or talked out of them over the phone
91
+ * cannot be redeemed elsewhere.
92
+ */
93
+ const EMAIL_OTP_COOKIE_NAME = 'email-otp-verification';
94
+
95
+ function getEmailOtpCookieOptions(): CookieSerializeOptions {
96
+ return {
97
+ httpOnly: true,
98
+ sameSite: 'lax',
99
+ secure: !isDevelopment(),
100
+ maxAge: EMAIL_OTP_EXPIRY_SEC,
101
+ path: '/',
102
+ };
103
+ }
104
+
105
+ const emailSchema = z.object({
106
+ email: z
107
+ .email()
108
+ .max(PASSWORD_MAX_LENGTH)
109
+ .transform((value) => value.toLowerCase()),
110
+ });
111
+
112
+ /**
113
+ * Generates a numeric code using rejection sampling so every digit is equally
114
+ * likely. 250 is the largest multiple of 10 within a byte, so values above it
115
+ * are discarded rather than folded back and over-weighting digits 0-5.
116
+ */
117
+ function generateNumericCode(length: number): string {
118
+ const digits = Array.from({ length }, () => {
119
+ let value = 256;
120
+ while (value >= 250) {
121
+ value = crypto.randomBytes(1).readUInt8(0);
122
+ }
123
+ return String(value % 10);
124
+ });
125
+ return digits.join('');
126
+ }
127
+
128
+ /**
129
+ * Emails a single-use sign-in code to the given address.
130
+ *
131
+ * A code is sent whether or not an account exists — verifying one signs the
132
+ * user in, creating the account on first use — so this endpoint reveals
133
+ * nothing about which addresses are registered.
134
+ */
135
+ export async function requestEmailOtp({
136
+ email: rawEmail,
137
+ context,
138
+ }: {
139
+ email: string;
140
+ context: RequestServiceContextWith<'email'>;
141
+ }): Promise<{ success: true }> {
142
+ const { services } = context;
143
+
144
+ const { email } = await emailSchema
145
+ .parseAsync({ email: rawEmail })
146
+ .catch(handleZodRequestValidationError);
147
+
148
+ await Promise.all([
149
+ getEmailOtpRequestIpLimiter().consumeOrThrow(
150
+ context.reqInfo.ip,
151
+ 'Too many sign-in code requests. Please try again later.',
152
+ 'too-many-requests',
153
+ ),
154
+ getEmailOtpRequestEmailLimiter().consumeOrThrow(
155
+ email,
156
+ 'Too many sign-in code requests. Please try again later.',
157
+ 'too-many-requests',
158
+ ),
159
+ getEmailOtpRequestEmailDailyLimiter().consumeOrThrow(
160
+ email,
161
+ 'Too many sign-in code requests. Please try again later.',
162
+ 'too-many-requests',
163
+ ),
164
+ ]);
165
+
166
+ const code = generateNumericCode(EMAIL_OTP_LENGTH);
167
+
168
+ const { id: verificationId } = await createCodeVerification({
169
+ type: EMAIL_OTP_TYPE,
170
+ identifier: email,
171
+ code,
172
+ expiresInSec: EMAIL_OTP_EXPIRY_SEC,
173
+ });
174
+
175
+ context.cookieStore.set(
176
+ EMAIL_OTP_COOKIE_NAME,
177
+ verificationId,
178
+ getEmailOtpCookieOptions(),
179
+ );
180
+
181
+ await services.email.send(TPL_EMAIL_OTP_EMAIL, {
182
+ to: email,
183
+ data: { code, expiryMinutes: Math.floor(EMAIL_OTP_EXPIRY_SEC / 60) },
184
+ });
185
+
186
+ return { success: true };
187
+ }
188
+
189
+ const verifyEmailOtpSchema = z.object({
190
+ email: z
191
+ .email()
192
+ .max(PASSWORD_MAX_LENGTH)
193
+ .transform((value) => value.toLowerCase()),
194
+ code: z.string().length(EMAIL_OTP_LENGTH),
195
+ // Blank and whitespace-only names are normalized to absent rather than
196
+ // rejected, so a client that always sends the field still gets the
197
+ // `name-required` response rather than a generic validation failure.
198
+ name: z
199
+ .string()
200
+ .max(100)
201
+ .optional()
202
+ .transform((value) => {
203
+ const trimmed = value?.trim();
204
+ return trimmed ? trimmed : undefined;
205
+ }),
206
+ });
207
+
208
+ /**
209
+ * Signs a user in with an emailed code, creating the account on first use.
210
+ *
211
+ * A verified code proves control of the inbox, so the account it creates (or
212
+ * signs in to) is marked as having a verified email. Accounts created this way
213
+ * have no password until the user goes through the password reset flow.
214
+ *
215
+ * @throws BadRequestError `name-required` when the code is valid but the
216
+ * address has no account yet and no name was supplied. The code is left intact
217
+ * so the client can collect a name and retry with it.
218
+ */
219
+ export async function signInWithEmailOtp({
220
+ input,
221
+ context,
222
+ }: {
223
+ input: {
224
+ email: string;
225
+ code: string;
226
+ name?: string;
227
+ };
228
+ context: RequestServiceContext;
229
+ }): Promise<{ session: UserSessionPayload }> {
230
+ const { email, code, name } = await verifyEmailOtpSchema
231
+ .parseAsync(input)
232
+ .catch(handleZodRequestValidationError);
233
+
234
+ await getEmailOtpVerifyIpLimiter().consumeOrThrow(
235
+ context.reqInfo.ip,
236
+ 'Too many sign-in attempts. Please try again later.',
237
+ 'too-many-requests',
238
+ );
239
+
240
+ // A code is only redeemable in the browser that requested it.
241
+ const verificationId = context.cookieStore.get(EMAIL_OTP_COOKIE_NAME);
242
+
243
+ if (!verificationId) {
244
+ throw new BadRequestError(
245
+ 'This code must be entered in the browser that requested it',
246
+ 'verification-context-missing',
247
+ );
248
+ }
249
+
250
+ // Establish that this browser owns the outstanding code before spending any
251
+ // of the address's budget. Charging first would let anyone lock a chosen
252
+ // address out of signing in just by posting its email with a junk code —
253
+ // which is worse than it sounds, because an account created through this
254
+ // flow has no password to fall back on.
255
+ const challenge = await prisma.authVerification.findUnique({
256
+ where: { type_identifier: { type: EMAIL_OTP_TYPE, identifier: email } },
257
+ select: { id: true },
258
+ });
259
+
260
+ if (challenge?.id !== verificationId) {
261
+ throw new BadRequestError('Invalid or expired code', 'invalid-code');
262
+ }
263
+
264
+ await getEmailOtpVerifyEmailLimiter().consumeOrThrow(
265
+ email,
266
+ 'Too many sign-in attempts. Please try again later.',
267
+ 'too-many-requests',
268
+ );
269
+
270
+ const record = await validateCodeVerification({
271
+ type: EMAIL_OTP_TYPE,
272
+ identifier: email,
273
+ code,
274
+ maxAttempts: EMAIL_OTP_MAX_ATTEMPTS,
275
+ });
276
+
277
+ if (!record) {
278
+ throw new BadRequestError('Invalid or expired code', 'invalid-code');
279
+ }
280
+
281
+ // Re-checked because a fresh code may have been issued since the lookup
282
+ // above, which would have replaced the id this browser is holding.
283
+ if (record.id !== verificationId) {
284
+ throw new BadRequestError('Invalid or expired code', 'invalid-code');
285
+ }
286
+
287
+ // Asking for a name only when the address is new would normally leak whether
288
+ // an account exists. Gating it behind a valid code keeps that safe: only
289
+ // someone who controls the mailbox reaches this point.
290
+ TPL_NAME_REQUIRED_CHECK;
291
+
292
+ // Spending the code and settling the account commit together, so a failure
293
+ // partway through leaves the code still usable rather than burning it and
294
+ // forcing the user to request another.
295
+ const userId = await prisma.$transaction(async (tx) => {
296
+ if (!(await consumeCodeVerification({ id: record.id, client: tx }))) {
297
+ throw new BadRequestError('Invalid or expired code', 'invalid-code');
298
+ }
299
+
300
+ // Receiving the code proves control of the address, so the account is
301
+ // created (or marked) as verified. An existing user's name is left alone.
302
+ const { id } = await tx.user.upsert({
303
+ where: { email },
304
+ create: {
305
+ email,
306
+ name,
307
+ emailVerified: true,
308
+ accounts: {
309
+ create: {
310
+ accountId: email,
311
+ providerId: PROVIDER_ID,
312
+ },
313
+ },
314
+ },
315
+ update: { emailVerified: true },
316
+ select: { id: true },
317
+ });
318
+
319
+ return id;
320
+ });
321
+
322
+ context.cookieStore.clear(EMAIL_OTP_COOKIE_NAME, getEmailOtpCookieOptions());
323
+
324
+ // Outside the transaction: session creation manages its own storage through
325
+ // the request context. If it fails the code is spent, but the account now
326
+ // exists, so retrying signs the user in without asking for a name again.
327
+ const session = await context.services.userSession.createSession(
328
+ userId,
329
+ context,
330
+ );
331
+
332
+ return { session };
333
+ }
@@ -1,7 +1,7 @@
1
1
  // @ts-nocheck
2
2
  import { EMAIL_VERIFICATION_TOKEN_EXPIRY_SEC } from '$constantsPassword';
3
+ import { getWebAppForUrl, getWebUrl } from '%appUrlsImports';
3
4
  import { createAuthVerification, validateAuthVerification, } from '%authModuleImports';
4
- import { getConfig } from '%configServiceImports';
5
5
  import { BadRequestError } from '%errorHandlerServiceImports';
6
6
  import { prisma } from '%prismaImports';
7
7
  import { memoizeRateLimiter } from '%rateLimitImports';
@@ -49,8 +49,7 @@ export async function requestEmailVerification({ userId, context, }) {
49
49
  userId: user.id,
50
50
  expiresInSec: EMAIL_VERIFICATION_TOKEN_EXPIRY_SEC,
51
51
  });
52
- // Construct verification URL using configured domain
53
- const verifyLink = `${getConfig().AUTH_FRONTEND_URL}/auth/verify-email?token=${encodeURIComponent(token)}`;
52
+ const verifyLink = getWebUrl(getWebAppForUrl(context.reqInfo.headers.origin) ?? TPL_AUTH_WEB_APP, `/auth/verify-email?token=${encodeURIComponent(token)}`);
54
53
  await services.email.send(TPL_ACCOUNT_VERIFICATION_EMAIL, {
55
54
  to: user.email,
56
55
  data: { verifyLink },
@@ -6,11 +6,11 @@ import type {
6
6
  } from '%requestServiceContextImports';
7
7
 
8
8
  import { EMAIL_VERIFICATION_TOKEN_EXPIRY_SEC } from '$constantsPassword';
9
+ import { getWebAppForUrl, getWebUrl } from '%appUrlsImports';
9
10
  import {
10
11
  createAuthVerification,
11
12
  validateAuthVerification,
12
13
  } from '%authModuleImports';
13
- import { getConfig } from '%configServiceImports';
14
14
  import { BadRequestError } from '%errorHandlerServiceImports';
15
15
  import { prisma } from '%prismaImports';
16
16
  import { memoizeRateLimiter } from '%rateLimitImports';
@@ -90,8 +90,10 @@ export async function requestEmailVerification({
90
90
  expiresInSec: EMAIL_VERIFICATION_TOKEN_EXPIRY_SEC,
91
91
  });
92
92
 
93
- // Construct verification URL using configured domain
94
- const verifyLink = `${getConfig().AUTH_FRONTEND_URL}/auth/verify-email?token=${encodeURIComponent(token)}`;
93
+ const verifyLink = getWebUrl(
94
+ getWebAppForUrl(context.reqInfo.headers.origin) ?? TPL_AUTH_WEB_APP,
95
+ `/auth/verify-email?token=${encodeURIComponent(token)}`,
96
+ );
95
97
 
96
98
  await services.email.send(TPL_ACCOUNT_VERIFICATION_EMAIL, {
97
99
  to: user.email,
@@ -0,0 +1,39 @@
1
+ import type { User } from '%prismaGeneratedImports';
2
+ import type { RequestServiceContext, RequestServiceContextWith } from '%requestServiceContextImports';
3
+ import type { UserSessionPayload } from '%userSessionTypesImports';
4
+ /**
5
+ * Sends an invite email so a user can set their password and sign in.
6
+ * Admin-triggered, so unlike password reset requests, it does not need
7
+ * anti-enumeration rate limiting.
8
+ */
9
+ export declare function inviteUser({ userId, context, }: {
10
+ userId: string;
11
+ context: RequestServiceContextWith<'email'>;
12
+ }): Promise<{
13
+ user: User;
14
+ }>;
15
+ /**
16
+ * Validates an invite token without consuming it.
17
+ * Used by the frontend to verify the token is valid and to show the
18
+ * invited email before displaying the set-password form.
19
+ *
20
+ * @throws BadRequestError with code 'invalid-token' if the token is invalid or expired
21
+ */
22
+ export declare function validateInviteToken({ token: rawToken, }: {
23
+ token: string;
24
+ }): Promise<{
25
+ email: string;
26
+ }>;
27
+ /**
28
+ * Completes the invite flow by setting the invited user's password and
29
+ * signing them in. Token is single-use (deleted after acceptance, along
30
+ * with any other pending invite tokens for the user).
31
+ */
32
+ export declare function acceptInvite({ token: rawToken, newPassword: rawNewPassword, context, }: {
33
+ token: string;
34
+ newPassword: string;
35
+ context: RequestServiceContext;
36
+ }): Promise<{
37
+ session: UserSessionPayload;
38
+ }>;
39
+ //# sourceMappingURL=invite.service.d.ts.map