@lastshotlabs/bunshot 0.0.27 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (742) hide show
  1. package/.oclif.manifest.json +39 -0
  2. package/README.md +8282 -2147
  3. package/dist/cli/commands/init.js +690 -0
  4. package/dist/cli/index.js +6 -0
  5. package/dist/cli.js +4 -4
  6. package/dist/packages/bunshot-admin/src/index.d.ts +15 -0
  7. package/dist/packages/bunshot-admin/src/index.js +11 -0
  8. package/dist/packages/bunshot-admin/src/lib/resourceTypes.d.ts +8 -0
  9. package/dist/packages/bunshot-admin/src/lib/resourceTypes.js +33 -0
  10. package/dist/packages/bunshot-admin/src/lib/typedRoute.d.ts +14 -0
  11. package/dist/packages/bunshot-admin/src/lib/typedRoute.js +17 -0
  12. package/dist/packages/bunshot-admin/src/plugin.d.ts +4 -0
  13. package/dist/packages/bunshot-admin/src/plugin.js +46 -0
  14. package/dist/packages/bunshot-admin/src/providers/auth0Access.d.ts +6 -0
  15. package/dist/packages/bunshot-admin/src/providers/auth0Access.js +32 -0
  16. package/dist/packages/bunshot-admin/src/routes/admin.d.ts +10 -0
  17. package/dist/packages/bunshot-admin/src/routes/admin.js +923 -0
  18. package/dist/packages/bunshot-admin/src/routes/mail.d.ts +6 -0
  19. package/dist/packages/bunshot-admin/src/routes/mail.js +114 -0
  20. package/dist/packages/bunshot-admin/src/routes/permissions.d.ts +8 -0
  21. package/dist/packages/bunshot-admin/src/routes/permissions.js +315 -0
  22. package/dist/packages/bunshot-admin/src/types/config.d.ts +16 -0
  23. package/dist/packages/bunshot-admin/src/types/config.js +37 -0
  24. package/dist/packages/bunshot-admin/src/types/env.d.ts +14 -0
  25. package/dist/packages/bunshot-admin/src/types/provider.d.ts +1 -0
  26. package/dist/packages/bunshot-admin/src/types/provider.js +4 -0
  27. package/dist/packages/bunshot-auth/src/adapters/memoryAuth.d.ts +66 -0
  28. package/dist/packages/bunshot-auth/src/adapters/memoryAuth.js +1063 -0
  29. package/dist/packages/bunshot-auth/src/adapters/mongoAuth.d.ts +2 -0
  30. package/dist/packages/bunshot-auth/src/adapters/mongoAuth.js +536 -0
  31. package/dist/packages/bunshot-auth/src/adapters/sqliteAuth.d.ts +88 -0
  32. package/dist/packages/bunshot-auth/src/adapters/sqliteAuth.js +1366 -0
  33. package/dist/packages/bunshot-auth/src/admin/bunshotAccess.d.ts +2 -0
  34. package/dist/packages/bunshot-auth/src/admin/bunshotAccess.js +23 -0
  35. package/dist/packages/bunshot-auth/src/admin/bunshotUsers.d.ts +5 -0
  36. package/dist/packages/bunshot-auth/src/admin/bunshotUsers.js +131 -0
  37. package/dist/packages/bunshot-auth/src/bootstrap.d.ts +38 -0
  38. package/dist/packages/bunshot-auth/src/bootstrap.js +384 -0
  39. package/dist/packages/bunshot-auth/src/config/appConfig.d.ts +3 -0
  40. package/dist/packages/bunshot-auth/src/config/appConfig.js +4 -0
  41. package/dist/packages/bunshot-auth/src/config/authConfig.d.ts +478 -0
  42. package/dist/packages/bunshot-auth/src/config/authConfig.js +46 -0
  43. package/dist/packages/bunshot-auth/src/config/configLock.d.ts +2 -0
  44. package/dist/packages/bunshot-auth/src/config/configLock.js +10 -0
  45. package/dist/packages/bunshot-auth/src/index.d.ts +25 -0
  46. package/dist/packages/bunshot-auth/src/index.js +23 -0
  47. package/dist/packages/bunshot-auth/src/infra/mongo.d.ts +15 -0
  48. package/dist/packages/bunshot-auth/src/infra/mongo.js +44 -0
  49. package/dist/packages/bunshot-auth/src/infra/queue.d.ts +14 -0
  50. package/dist/packages/bunshot-auth/src/infra/queue.js +27 -0
  51. package/dist/packages/bunshot-auth/src/infra/redis.d.ts +5 -0
  52. package/dist/packages/bunshot-auth/src/infra/redis.js +15 -0
  53. package/dist/packages/bunshot-auth/src/infra/signing.d.ts +7 -0
  54. package/dist/packages/bunshot-auth/src/infra/signing.js +8 -0
  55. package/dist/packages/bunshot-auth/src/lib/accountLockout.d.ts +34 -0
  56. package/dist/packages/bunshot-auth/src/lib/accountLockout.js +244 -0
  57. package/dist/packages/bunshot-auth/src/lib/adapterTiers.d.ts +1 -0
  58. package/dist/packages/bunshot-auth/src/lib/adapterTiers.js +1 -0
  59. package/dist/packages/bunshot-auth/src/lib/authAdapter.d.ts +1 -0
  60. package/dist/packages/bunshot-auth/src/lib/authAdapter.js +1 -0
  61. package/dist/packages/bunshot-auth/src/lib/authContext.d.ts +15 -0
  62. package/dist/packages/bunshot-auth/src/lib/authContext.js +1 -0
  63. package/dist/packages/bunshot-auth/src/lib/authEventBus.d.ts +4 -0
  64. package/dist/packages/bunshot-auth/src/lib/authEventBus.js +15 -0
  65. package/dist/packages/bunshot-auth/src/lib/authRateLimit.d.ts +28 -0
  66. package/dist/packages/bunshot-auth/src/lib/authRateLimit.js +205 -0
  67. package/dist/{lib → packages/bunshot-auth/src/lib}/breachedPassword.d.ts +8 -2
  68. package/dist/{lib → packages/bunshot-auth/src/lib}/breachedPassword.js +22 -9
  69. package/dist/packages/bunshot-auth/src/lib/cache.d.ts +12 -0
  70. package/dist/packages/bunshot-auth/src/lib/cache.js +120 -0
  71. package/dist/packages/bunshot-auth/src/lib/clientIp.d.ts +4 -0
  72. package/dist/{lib → packages/bunshot-auth/src/lib}/clientIp.js +14 -7
  73. package/dist/packages/bunshot-auth/src/lib/cookieOptions.d.ts +27 -0
  74. package/dist/packages/bunshot-auth/src/lib/cookieOptions.js +33 -0
  75. package/dist/packages/bunshot-auth/src/lib/credentialStuffing.d.ts +40 -0
  76. package/dist/packages/bunshot-auth/src/lib/credentialStuffing.js +211 -0
  77. package/dist/packages/bunshot-auth/src/lib/deletionCancelToken.d.ts +19 -0
  78. package/dist/packages/bunshot-auth/src/lib/deletionCancelToken.js +148 -0
  79. package/dist/packages/bunshot-auth/src/lib/emailTemplates.d.ts +23 -0
  80. package/dist/packages/bunshot-auth/src/lib/emailTemplates.js +265 -0
  81. package/dist/packages/bunshot-auth/src/lib/emailVerification.d.ts +30 -0
  82. package/dist/packages/bunshot-auth/src/lib/emailVerification.js +200 -0
  83. package/dist/packages/bunshot-auth/src/lib/env.d.ts +1 -0
  84. package/dist/packages/bunshot-auth/src/lib/env.js +3 -0
  85. package/dist/packages/bunshot-auth/src/lib/fingerprint.js +36 -0
  86. package/dist/{lib → packages/bunshot-auth/src/lib}/groups.d.ts +15 -16
  87. package/dist/{lib → packages/bunshot-auth/src/lib}/groups.js +22 -34
  88. package/dist/packages/bunshot-auth/src/lib/jwks.d.ts +28 -0
  89. package/dist/packages/bunshot-auth/src/lib/jwks.js +79 -0
  90. package/dist/packages/bunshot-auth/src/lib/jwt.d.ts +12 -0
  91. package/dist/packages/bunshot-auth/src/lib/jwt.js +86 -0
  92. package/dist/{lib → packages/bunshot-auth/src/lib}/logger.js +3 -3
  93. package/dist/{lib → packages/bunshot-auth/src/lib}/m2m.d.ts +5 -4
  94. package/dist/{lib → packages/bunshot-auth/src/lib}/m2m.js +6 -10
  95. package/dist/packages/bunshot-auth/src/lib/magicLink.d.ts +13 -0
  96. package/dist/packages/bunshot-auth/src/lib/magicLink.js +145 -0
  97. package/dist/packages/bunshot-auth/src/lib/mfaChallenge.d.ts +60 -0
  98. package/dist/packages/bunshot-auth/src/lib/mfaChallenge.js +419 -0
  99. package/dist/packages/bunshot-auth/src/lib/oauth.d.ts +82 -0
  100. package/dist/packages/bunshot-auth/src/lib/oauth.js +177 -0
  101. package/dist/packages/bunshot-auth/src/lib/oauthCode.d.ts +19 -0
  102. package/dist/packages/bunshot-auth/src/lib/oauthCode.js +182 -0
  103. package/dist/packages/bunshot-auth/src/lib/oauthReauth.d.ts +19 -0
  104. package/dist/packages/bunshot-auth/src/lib/oauthReauth.js +255 -0
  105. package/dist/packages/bunshot-auth/src/lib/organization.d.ts +66 -0
  106. package/dist/packages/bunshot-auth/src/lib/organization.js +225 -0
  107. package/dist/packages/bunshot-auth/src/lib/passwordHistory.d.ts +12 -0
  108. package/dist/packages/bunshot-auth/src/lib/passwordHistory.js +31 -0
  109. package/dist/packages/bunshot-auth/src/lib/resetPassword.d.ts +20 -0
  110. package/dist/packages/bunshot-auth/src/lib/resetPassword.js +148 -0
  111. package/dist/packages/bunshot-auth/src/lib/roles.d.ts +9 -0
  112. package/dist/packages/bunshot-auth/src/lib/roles.js +93 -0
  113. package/dist/packages/bunshot-auth/src/lib/saml.d.ts +29 -0
  114. package/dist/packages/bunshot-auth/src/lib/saml.js +73 -0
  115. package/dist/packages/bunshot-auth/src/lib/samlRequestId.d.ts +13 -0
  116. package/dist/packages/bunshot-auth/src/lib/samlRequestId.js +129 -0
  117. package/dist/{lib → packages/bunshot-auth/src/lib}/scim.d.ts +7 -7
  118. package/dist/{lib → packages/bunshot-auth/src/lib}/scim.js +15 -13
  119. package/dist/packages/bunshot-auth/src/lib/securityEventWiring.d.ts +22 -0
  120. package/dist/packages/bunshot-auth/src/lib/securityEventWiring.js +65 -0
  121. package/dist/packages/bunshot-auth/src/lib/session.d.ts +45 -0
  122. package/dist/packages/bunshot-auth/src/lib/session.js +1211 -0
  123. package/dist/packages/bunshot-auth/src/lib/storeInfra.d.ts +26 -0
  124. package/dist/packages/bunshot-auth/src/lib/storeInfra.js +18 -0
  125. package/dist/{lib → packages/bunshot-auth/src/lib}/suspension.d.ts +3 -2
  126. package/dist/{lib → packages/bunshot-auth/src/lib}/suspension.js +2 -5
  127. package/dist/packages/bunshot-auth/src/lib/validateAdapter.d.ts +16 -0
  128. package/dist/packages/bunshot-auth/src/lib/validateAdapter.js +161 -0
  129. package/dist/packages/bunshot-auth/src/middleware/bearerAuth.d.ts +13 -0
  130. package/dist/packages/bunshot-auth/src/middleware/bearerAuth.js +58 -0
  131. package/dist/{middleware → packages/bunshot-auth/src/middleware}/csrf.d.ts +5 -4
  132. package/dist/packages/bunshot-auth/src/middleware/csrf.js +138 -0
  133. package/dist/packages/bunshot-auth/src/middleware/identify.d.ts +4 -0
  134. package/dist/packages/bunshot-auth/src/middleware/identify.js +124 -0
  135. package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireMfaSetup.d.ts +2 -2
  136. package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireMfaSetup.js +10 -8
  137. package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireRole.d.ts +2 -2
  138. package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireRole.js +20 -16
  139. package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireScope.d.ts +2 -2
  140. package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireScope.js +6 -6
  141. package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireStepUp.d.ts +2 -2
  142. package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireStepUp.js +8 -7
  143. package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireVerifiedEmail.d.ts +2 -2
  144. package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireVerifiedEmail.js +7 -6
  145. package/dist/packages/bunshot-auth/src/middleware/scimAuth.d.ts +8 -0
  146. package/dist/packages/bunshot-auth/src/middleware/scimAuth.js +29 -0
  147. package/dist/packages/bunshot-auth/src/middleware/userAuth.d.ts +3 -0
  148. package/dist/packages/bunshot-auth/src/middleware/userAuth.js +6 -0
  149. package/dist/{models → packages/bunshot-auth/src/models}/AuthUser.d.ts +12 -8
  150. package/dist/packages/bunshot-auth/src/models/AuthUser.js +53 -0
  151. package/dist/packages/bunshot-auth/src/models/Group.d.ts +19 -0
  152. package/dist/packages/bunshot-auth/src/models/Group.js +22 -0
  153. package/dist/{models → packages/bunshot-auth/src/models}/GroupMembership.d.ts +6 -8
  154. package/dist/packages/bunshot-auth/src/models/GroupMembership.js +19 -0
  155. package/dist/{models → packages/bunshot-auth/src/models}/M2MClient.d.ts +1 -1
  156. package/dist/{models → packages/bunshot-auth/src/models}/M2MClient.js +5 -5
  157. package/dist/packages/bunshot-auth/src/models/TenantRole.d.ts +13 -0
  158. package/dist/packages/bunshot-auth/src/models/TenantRole.js +17 -0
  159. package/dist/packages/bunshot-auth/src/plugin.d.ts +4 -0
  160. package/dist/packages/bunshot-auth/src/plugin.js +277 -0
  161. package/dist/packages/bunshot-auth/src/routes/auth.d.ts +15 -0
  162. package/dist/packages/bunshot-auth/src/routes/auth.js +1624 -0
  163. package/dist/packages/bunshot-auth/src/routes/groups.d.ts +4 -0
  164. package/dist/packages/bunshot-auth/src/routes/groups.js +481 -0
  165. package/dist/packages/bunshot-auth/src/routes/m2m.d.ts +2 -0
  166. package/dist/packages/bunshot-auth/src/routes/m2m.js +145 -0
  167. package/dist/packages/bunshot-auth/src/routes/mfa.d.ts +6 -0
  168. package/dist/packages/bunshot-auth/src/routes/mfa.js +991 -0
  169. package/dist/packages/bunshot-auth/src/routes/oauth.d.ts +3 -0
  170. package/dist/packages/bunshot-auth/src/routes/oauth.js +1727 -0
  171. package/dist/packages/bunshot-auth/src/routes/oidc.d.ts +2 -0
  172. package/dist/packages/bunshot-auth/src/routes/oidc.js +84 -0
  173. package/dist/packages/bunshot-auth/src/routes/organizations.d.ts +3 -0
  174. package/dist/packages/bunshot-auth/src/routes/organizations.js +741 -0
  175. package/dist/packages/bunshot-auth/src/routes/passkey.d.ts +2 -0
  176. package/dist/packages/bunshot-auth/src/routes/passkey.js +199 -0
  177. package/dist/packages/bunshot-auth/src/routes/saml.d.ts +2 -0
  178. package/dist/packages/bunshot-auth/src/routes/saml.js +226 -0
  179. package/dist/packages/bunshot-auth/src/routes/scim.d.ts +3 -0
  180. package/dist/packages/bunshot-auth/src/routes/scim.js +588 -0
  181. package/dist/packages/bunshot-auth/src/runtime.d.ts +52 -0
  182. package/dist/packages/bunshot-auth/src/runtime.js +11 -0
  183. package/dist/{schemas → packages/bunshot-auth/src/schemas}/auth.d.ts +4 -5
  184. package/dist/packages/bunshot-auth/src/schemas/auth.js +24 -0
  185. package/dist/packages/bunshot-auth/src/schemas/error.d.ts +10 -0
  186. package/dist/packages/bunshot-auth/src/schemas/error.js +10 -0
  187. package/dist/packages/bunshot-auth/src/schemas/success.d.ts +10 -0
  188. package/dist/packages/bunshot-auth/src/schemas/success.js +10 -0
  189. package/dist/packages/bunshot-auth/src/services/auth.d.ts +39 -0
  190. package/dist/packages/bunshot-auth/src/services/auth.js +378 -0
  191. package/dist/{services → packages/bunshot-auth/src/services}/mfa.d.ts +41 -17
  192. package/dist/{services → packages/bunshot-auth/src/services}/mfa.js +259 -183
  193. package/dist/packages/bunshot-auth/src/testing.d.ts +31 -0
  194. package/dist/packages/bunshot-auth/src/testing.js +23 -0
  195. package/dist/packages/bunshot-auth/src/types/adapter.d.ts +1 -0
  196. package/dist/packages/bunshot-auth/src/types/adapter.js +1 -0
  197. package/dist/packages/bunshot-auth/src/types/config.d.ts +152 -0
  198. package/dist/packages/bunshot-auth/src/types/config.js +179 -0
  199. package/dist/{routes → packages/bunshot-auth/src/types}/groups.d.ts +2 -3
  200. package/dist/packages/bunshot-auth/src/types/groups.js +1 -0
  201. package/dist/packages/bunshot-auth/src/types/oauthCode.d.ts +6 -0
  202. package/dist/packages/bunshot-auth/src/types/oauthCode.js +1 -0
  203. package/dist/packages/bunshot-auth/src/types/oauthReauth.d.ts +13 -0
  204. package/dist/packages/bunshot-auth/src/types/oauthReauth.js +1 -0
  205. package/dist/packages/bunshot-auth/src/types/redis.d.ts +1 -0
  206. package/dist/packages/bunshot-auth/src/types/redis.js +1 -0
  207. package/dist/packages/bunshot-auth/src/types/saml.d.ts +10 -0
  208. package/dist/packages/bunshot-auth/src/types/saml.js +1 -0
  209. package/dist/packages/bunshot-auth/src/types/session.d.ts +18 -0
  210. package/dist/packages/bunshot-auth/src/types/session.js +1 -0
  211. package/dist/packages/bunshot-auth/src/types/store.d.ts +1 -0
  212. package/dist/packages/bunshot-auth/src/types/store.js +1 -0
  213. package/dist/packages/bunshot-core/src/adminProvider.d.ts +95 -0
  214. package/dist/packages/bunshot-core/src/adminProvider.js +1 -0
  215. package/dist/packages/bunshot-core/src/auditLog.d.ts +34 -0
  216. package/dist/packages/bunshot-core/src/auditLog.js +1 -0
  217. package/dist/packages/bunshot-core/src/auth-adapter.d.ts +227 -0
  218. package/dist/packages/bunshot-core/src/auth-adapter.js +4 -0
  219. package/dist/packages/bunshot-core/src/authVariables.d.ts +14 -0
  220. package/dist/packages/bunshot-core/src/authVariables.js +4 -0
  221. package/dist/packages/bunshot-core/src/cache.d.ts +12 -0
  222. package/dist/packages/bunshot-core/src/cache.js +21 -0
  223. package/dist/{lib → packages/bunshot-core/src}/captcha.d.ts +1 -10
  224. package/dist/packages/bunshot-core/src/captcha.js +1 -0
  225. package/dist/packages/bunshot-core/src/clearRegistry.d.ts +6 -0
  226. package/dist/packages/bunshot-core/src/clearRegistry.js +17 -0
  227. package/dist/packages/bunshot-core/src/clientIp.d.ts +3 -0
  228. package/dist/packages/bunshot-core/src/clientIp.js +45 -0
  229. package/dist/packages/bunshot-core/src/configLock.d.ts +4 -0
  230. package/dist/packages/bunshot-core/src/configLock.js +7 -0
  231. package/dist/packages/bunshot-core/src/configValidation.d.ts +22 -0
  232. package/dist/packages/bunshot-core/src/configValidation.js +39 -0
  233. package/dist/packages/bunshot-core/src/constants.js +10 -0
  234. package/dist/packages/bunshot-core/src/context/bunshotContext.d.ts +232 -0
  235. package/dist/packages/bunshot-core/src/context/bunshotContext.js +1 -0
  236. package/dist/packages/bunshot-core/src/context/contextAccess.d.ts +3 -0
  237. package/dist/packages/bunshot-core/src/context/contextAccess.js +16 -0
  238. package/dist/packages/bunshot-core/src/context/contextStore.d.ts +16 -0
  239. package/dist/packages/bunshot-core/src/context/contextStore.js +31 -0
  240. package/dist/packages/bunshot-core/src/context/frameworkConfig.d.ts +38 -0
  241. package/dist/packages/bunshot-core/src/context/frameworkConfig.js +1 -0
  242. package/dist/packages/bunshot-core/src/context/index.d.ts +4 -0
  243. package/dist/packages/bunshot-core/src/context/index.js +2 -0
  244. package/dist/packages/bunshot-core/src/context.d.ts +40 -0
  245. package/dist/packages/bunshot-core/src/context.js +35 -0
  246. package/dist/packages/bunshot-core/src/coreContracts.d.ts +47 -0
  247. package/dist/packages/bunshot-core/src/coreContracts.js +1 -0
  248. package/dist/packages/bunshot-core/src/coreRegistrar.d.ts +6 -0
  249. package/dist/packages/bunshot-core/src/coreRegistrar.js +42 -0
  250. package/dist/{lib → packages/bunshot-core/src}/createRoute.d.ts +4 -30
  251. package/dist/{lib → packages/bunshot-core/src}/createRoute.js +39 -88
  252. package/dist/packages/bunshot-core/src/cronRegistry.d.ts +11 -0
  253. package/dist/packages/bunshot-core/src/cronRegistry.js +1 -0
  254. package/dist/packages/bunshot-core/src/crypto.d.ts +43 -0
  255. package/dist/packages/bunshot-core/src/crypto.js +74 -0
  256. package/dist/packages/bunshot-core/src/csrf.d.ts +8 -0
  257. package/dist/packages/bunshot-core/src/csrf.js +1 -0
  258. package/dist/packages/bunshot-core/src/defaults/defaultFingerprint.d.ts +7 -0
  259. package/dist/packages/bunshot-core/src/defaults/defaultFingerprint.js +19 -0
  260. package/dist/packages/bunshot-core/src/defaults/memoryCacheAdapter.d.ts +6 -0
  261. package/dist/packages/bunshot-core/src/defaults/memoryCacheAdapter.js +40 -0
  262. package/dist/packages/bunshot-core/src/defaults/memoryRateLimit.d.ts +6 -0
  263. package/dist/packages/bunshot-core/src/defaults/memoryRateLimit.js +24 -0
  264. package/dist/packages/bunshot-core/src/emailTemplates.d.ts +5 -0
  265. package/dist/packages/bunshot-core/src/emailTemplates.js +10 -0
  266. package/dist/{lib/HttpError.d.ts → packages/bunshot-core/src/errors.d.ts} +4 -1
  267. package/dist/{lib/HttpError.js → packages/bunshot-core/src/errors.js} +7 -1
  268. package/dist/packages/bunshot-core/src/eventBus.d.ts +270 -0
  269. package/dist/packages/bunshot-core/src/eventBus.js +143 -0
  270. package/dist/packages/bunshot-core/src/idempotency.d.ts +18 -0
  271. package/dist/packages/bunshot-core/src/idempotency.js +1 -0
  272. package/dist/packages/bunshot-core/src/index.d.ts +60 -0
  273. package/dist/packages/bunshot-core/src/index.js +34 -0
  274. package/dist/packages/bunshot-core/src/mail.d.ts +14 -0
  275. package/dist/packages/bunshot-core/src/mail.js +8 -0
  276. package/dist/packages/bunshot-core/src/memoryEviction.d.ts +24 -0
  277. package/dist/packages/bunshot-core/src/memoryEviction.js +52 -0
  278. package/dist/packages/bunshot-core/src/pagination.d.ts +45 -0
  279. package/dist/packages/bunshot-core/src/pagination.js +61 -0
  280. package/dist/packages/bunshot-core/src/permissions.d.ts +64 -0
  281. package/dist/packages/bunshot-core/src/permissions.js +27 -0
  282. package/dist/packages/bunshot-core/src/plugin.d.ts +44 -0
  283. package/dist/packages/bunshot-core/src/plugin.js +1 -0
  284. package/dist/packages/bunshot-core/src/rateLimit.d.ts +5 -0
  285. package/dist/packages/bunshot-core/src/rateLimit.js +18 -0
  286. package/dist/packages/bunshot-core/src/redis.d.ts +21 -0
  287. package/dist/packages/bunshot-core/src/redis.js +1 -0
  288. package/dist/packages/bunshot-core/src/routeAuth.d.ts +5 -0
  289. package/dist/packages/bunshot-core/src/routeAuth.js +11 -0
  290. package/dist/packages/bunshot-core/src/routeOverrides.d.ts +24 -0
  291. package/dist/packages/bunshot-core/src/routeOverrides.js +25 -0
  292. package/dist/packages/bunshot-core/src/routerAdapter.d.ts +6 -0
  293. package/dist/packages/bunshot-core/src/routerAdapter.js +56 -0
  294. package/dist/packages/bunshot-core/src/secrets.d.ts +48 -0
  295. package/dist/packages/bunshot-core/src/secrets.js +8 -0
  296. package/dist/packages/bunshot-core/src/signing.d.ts +41 -0
  297. package/dist/packages/bunshot-core/src/signing.js +1 -0
  298. package/dist/packages/bunshot-core/src/sse.d.ts +36 -0
  299. package/dist/packages/bunshot-core/src/sse.js +1 -0
  300. package/dist/packages/bunshot-core/src/storageAdapter.js +1 -0
  301. package/dist/packages/bunshot-core/src/storeInfra.d.ts +44 -0
  302. package/dist/packages/bunshot-core/src/storeInfra.js +18 -0
  303. package/dist/packages/bunshot-core/src/storeType.d.ts +7 -0
  304. package/dist/packages/bunshot-core/src/storeType.js +1 -0
  305. package/dist/packages/bunshot-core/src/testing.d.ts +1 -0
  306. package/dist/packages/bunshot-core/src/testing.js +1 -0
  307. package/dist/packages/bunshot-core/src/uploadRegistry.d.ts +23 -0
  308. package/dist/packages/bunshot-core/src/uploadRegistry.js +4 -0
  309. package/dist/packages/bunshot-core/src/userResolver.d.ts +5 -0
  310. package/dist/packages/bunshot-core/src/userResolver.js +14 -0
  311. package/dist/packages/bunshot-core/src/wsMessages.d.ts +42 -0
  312. package/dist/packages/bunshot-core/src/wsMessages.js +4 -0
  313. package/dist/packages/bunshot-permissions/src/adapters/memory.d.ts +7 -0
  314. package/dist/packages/bunshot-permissions/src/adapters/memory.js +73 -0
  315. package/dist/packages/bunshot-permissions/src/index.d.ts +10 -0
  316. package/dist/packages/bunshot-permissions/src/index.js +5 -0
  317. package/dist/packages/bunshot-permissions/src/lib/bootstrap.d.ts +7 -0
  318. package/dist/packages/bunshot-permissions/src/lib/bootstrap.js +12 -0
  319. package/dist/packages/bunshot-permissions/src/lib/evaluator.d.ts +10 -0
  320. package/dist/packages/bunshot-permissions/src/lib/evaluator.js +165 -0
  321. package/dist/packages/bunshot-permissions/src/lib/registry.d.ts +2 -0
  322. package/dist/packages/bunshot-permissions/src/lib/registry.js +31 -0
  323. package/dist/packages/bunshot-permissions/src/lib/validation.d.ts +1 -0
  324. package/dist/packages/bunshot-permissions/src/lib/validation.js +1 -0
  325. package/dist/packages/bunshot-permissions/src/types/adapter.d.ts +1 -0
  326. package/dist/packages/bunshot-permissions/src/types/adapter.js +1 -0
  327. package/dist/packages/bunshot-permissions/src/types/evaluator.d.ts +1 -0
  328. package/dist/packages/bunshot-permissions/src/types/evaluator.js +1 -0
  329. package/dist/packages/bunshot-permissions/src/types/models.d.ts +1 -0
  330. package/dist/packages/bunshot-permissions/src/types/models.js +1 -0
  331. package/dist/packages/bunshot-permissions/src/types/registry.d.ts +1 -0
  332. package/dist/packages/bunshot-permissions/src/types/registry.js +1 -0
  333. package/dist/packages/bunshot-postgres/src/adapter.d.ts +6 -0
  334. package/dist/packages/bunshot-postgres/src/adapter.js +794 -0
  335. package/dist/packages/bunshot-postgres/src/connection.d.ts +15 -0
  336. package/dist/packages/bunshot-postgres/src/connection.js +16 -0
  337. package/dist/packages/bunshot-postgres/src/index.d.ts +4 -0
  338. package/dist/packages/bunshot-postgres/src/index.js +2 -0
  339. package/dist/packages/bunshot-postgres/src/schema.d.ts +997 -0
  340. package/dist/packages/bunshot-postgres/src/schema.js +105 -0
  341. package/dist/src/app.d.ts +230 -0
  342. package/dist/src/app.js +182 -0
  343. package/dist/src/cli/commands/init.d.ts +10 -0
  344. package/dist/src/cli/commands/init.js +709 -0
  345. package/dist/src/cli/index.d.ts +1 -0
  346. package/dist/src/cli/index.js +3 -0
  347. package/dist/src/entrypoints/mongo.d.ts +6 -0
  348. package/dist/src/entrypoints/mongo.js +4 -0
  349. package/dist/src/entrypoints/queue.d.ts +2 -0
  350. package/dist/src/entrypoints/queue.js +1 -0
  351. package/dist/src/entrypoints/redis.d.ts +1 -0
  352. package/dist/src/entrypoints/redis.js +1 -0
  353. package/dist/{adapters → src/framework/adapters}/localStorage.d.ts +1 -1
  354. package/dist/{adapters → src/framework/adapters}/localStorage.js +10 -10
  355. package/dist/src/framework/adapters/memoryStorage.d.ts +2 -0
  356. package/dist/src/framework/adapters/memoryStorage.js +45 -0
  357. package/dist/{adapters → src/framework/adapters}/s3Storage.d.ts +1 -1
  358. package/dist/{adapters → src/framework/adapters}/s3Storage.js +12 -12
  359. package/dist/src/framework/admin/bunshotAccess.d.ts +2 -0
  360. package/dist/src/framework/admin/bunshotAccess.js +23 -0
  361. package/dist/src/framework/admin/bunshotUsers.d.ts +2 -0
  362. package/dist/src/framework/admin/bunshotUsers.js +103 -0
  363. package/dist/src/framework/admin/index.d.ts +7 -0
  364. package/dist/src/framework/admin/index.js +21 -0
  365. package/dist/src/framework/boundaryAdapters/cacheFactories.d.ts +13 -0
  366. package/dist/src/framework/boundaryAdapters/cacheFactories.js +86 -0
  367. package/dist/src/framework/boundaryAdapters/index.d.ts +2 -0
  368. package/dist/src/framework/boundaryAdapters/index.js +1 -0
  369. package/dist/src/framework/boundaryAdapters.d.ts +17 -0
  370. package/dist/src/framework/boundaryAdapters.js +62 -0
  371. package/dist/src/framework/buildContext.d.ts +33 -0
  372. package/dist/src/framework/buildContext.js +119 -0
  373. package/dist/src/framework/config/schema.d.ts +447 -0
  374. package/dist/src/framework/config/schema.js +528 -0
  375. package/dist/src/framework/createInfrastructure.d.ts +76 -0
  376. package/dist/src/framework/createInfrastructure.js +221 -0
  377. package/dist/src/framework/lib/auditLog.d.ts +23 -0
  378. package/dist/src/framework/lib/auditLog.js +416 -0
  379. package/dist/src/framework/lib/captcha.d.ts +11 -0
  380. package/dist/{lib → src/framework/lib}/captcha.js +13 -10
  381. package/dist/{lib → src/framework/lib}/createDtoMapper.js +4 -4
  382. package/dist/src/framework/lib/createRoute.d.ts +1 -0
  383. package/dist/src/framework/lib/createRoute.js +2 -0
  384. package/dist/{lib → src/framework/lib}/idempotency.d.ts +2 -6
  385. package/dist/src/framework/lib/idempotency.js +74 -0
  386. package/dist/src/framework/lib/logger.d.ts +3 -0
  387. package/dist/src/framework/lib/logger.js +14 -0
  388. package/dist/src/framework/lib/metrics.d.ts +34 -0
  389. package/dist/{lib → src/framework/lib}/metrics.js +49 -57
  390. package/dist/src/framework/lib/pagination.d.ts +42 -0
  391. package/dist/src/framework/lib/pagination.js +51 -0
  392. package/dist/src/framework/lib/redisTransport.d.ts +38 -0
  393. package/dist/src/framework/lib/redisTransport.js +107 -0
  394. package/dist/src/framework/lib/resolveUserId.d.ts +2 -0
  395. package/dist/src/framework/lib/resolveUserId.js +5 -0
  396. package/dist/src/framework/lib/sseCollision.d.ts +6 -0
  397. package/dist/src/framework/lib/sseCollision.js +26 -0
  398. package/dist/src/framework/lib/storageAdapter.d.ts +1 -0
  399. package/dist/src/framework/lib/storageAdapter.js +1 -0
  400. package/dist/{lib → src/framework/lib}/stripUnreferencedSchemas.js +4 -4
  401. package/dist/src/framework/lib/tenant.d.ts +21 -0
  402. package/dist/src/framework/lib/tenant.js +70 -0
  403. package/dist/{lib → src/framework/lib}/upload.d.ts +11 -10
  404. package/dist/src/framework/lib/upload.js +132 -0
  405. package/dist/src/framework/lib/uploadRegistry.d.ts +23 -0
  406. package/dist/src/framework/lib/uploadRegistry.js +34 -0
  407. package/dist/{lib → src/framework/lib}/validate.d.ts +1 -1
  408. package/dist/{lib → src/framework/lib}/validate.js +2 -2
  409. package/dist/src/framework/lib/ws.d.ts +19 -0
  410. package/dist/src/framework/lib/ws.js +130 -0
  411. package/dist/src/framework/lib/wsHeartbeat.d.ts +12 -0
  412. package/dist/src/framework/lib/wsHeartbeat.js +53 -0
  413. package/dist/src/framework/lib/wsMessages.d.ts +25 -0
  414. package/dist/src/framework/lib/wsMessages.js +45 -0
  415. package/dist/src/framework/lib/wsNamespace.d.ts +17 -0
  416. package/dist/src/framework/lib/wsNamespace.js +19 -0
  417. package/dist/src/framework/lib/wsPresence.d.ts +17 -0
  418. package/dist/src/framework/lib/wsPresence.js +84 -0
  419. package/dist/src/framework/lib/wsTransport.d.ts +38 -0
  420. package/dist/src/framework/lib/wsTransport.js +9 -0
  421. package/dist/{lib → src/framework/lib}/zodToMongoose.d.ts +1 -1
  422. package/dist/{lib → src/framework/lib}/zodToMongoose.js +11 -11
  423. package/dist/{middleware → src/framework/middleware}/auditLog.d.ts +4 -3
  424. package/dist/src/framework/middleware/auditLog.js +42 -0
  425. package/dist/{middleware → src/framework/middleware}/botProtection.d.ts +2 -2
  426. package/dist/{middleware → src/framework/middleware}/botProtection.js +8 -9
  427. package/dist/src/framework/middleware/cacheResponse.d.ts +35 -0
  428. package/dist/src/framework/middleware/cacheResponse.js +126 -0
  429. package/dist/{middleware → src/framework/middleware}/captcha.d.ts +2 -3
  430. package/dist/src/framework/middleware/captcha.js +37 -0
  431. package/dist/{middleware → src/framework/middleware}/errorHandler.d.ts +1 -1
  432. package/dist/{middleware → src/framework/middleware}/errorHandler.js +2 -2
  433. package/dist/src/framework/middleware/index.js +1 -0
  434. package/dist/{middleware → src/framework/middleware}/logger.d.ts +1 -1
  435. package/dist/src/framework/middleware/metrics.d.ts +12 -0
  436. package/dist/src/framework/middleware/metrics.js +26 -0
  437. package/dist/{middleware → src/framework/middleware}/rateLimit.d.ts +2 -2
  438. package/dist/src/framework/middleware/rateLimit.js +22 -0
  439. package/dist/src/framework/middleware/requestId.d.ts +3 -0
  440. package/dist/{middleware → src/framework/middleware}/requestId.js +2 -2
  441. package/dist/{middleware → src/framework/middleware}/requestLogger.d.ts +3 -3
  442. package/dist/{middleware → src/framework/middleware}/requestLogger.js +17 -12
  443. package/dist/{middleware → src/framework/middleware}/requestSigning.d.ts +2 -2
  444. package/dist/{middleware → src/framework/middleware}/requestSigning.js +18 -20
  445. package/dist/src/framework/middleware/tenant.d.ts +14 -0
  446. package/dist/{middleware → src/framework/middleware}/tenant.js +31 -27
  447. package/dist/src/framework/middleware/upload.d.ts +5 -0
  448. package/dist/{middleware → src/framework/middleware}/upload.js +4 -4
  449. package/dist/{middleware → src/framework/middleware}/webhookAuth.d.ts +3 -3
  450. package/dist/{middleware → src/framework/middleware}/webhookAuth.js +11 -12
  451. package/dist/src/framework/models/AuditLog.d.ts +21 -0
  452. package/dist/src/framework/models/AuditLog.js +31 -0
  453. package/dist/src/framework/mountMiddleware.d.ts +91 -0
  454. package/dist/src/framework/mountMiddleware.js +128 -0
  455. package/dist/src/framework/mountOptionalEndpoints.d.ts +103 -0
  456. package/dist/src/framework/mountOptionalEndpoints.js +64 -0
  457. package/dist/src/framework/mountRoutes.d.ts +21 -0
  458. package/dist/src/framework/mountRoutes.js +144 -0
  459. package/dist/src/framework/persistence/cronRegistry.d.ts +28 -0
  460. package/dist/src/framework/persistence/cronRegistry.js +139 -0
  461. package/dist/src/framework/persistence/idempotency.d.ts +26 -0
  462. package/dist/src/framework/persistence/idempotency.js +178 -0
  463. package/dist/src/framework/persistence/index.d.ts +6 -0
  464. package/dist/src/framework/persistence/index.js +8 -0
  465. package/dist/src/framework/persistence/storeInfra.d.ts +9 -0
  466. package/dist/src/framework/persistence/storeInfra.js +1 -0
  467. package/dist/src/framework/persistence/uploadRegistry.d.ts +35 -0
  468. package/dist/src/framework/persistence/uploadRegistry.js +235 -0
  469. package/dist/src/framework/persistence/wsMessages.d.ts +22 -0
  470. package/dist/src/framework/persistence/wsMessages.js +296 -0
  471. package/dist/src/framework/preloadSchemas.d.ts +24 -0
  472. package/dist/src/framework/preloadSchemas.js +42 -0
  473. package/dist/src/framework/registerBoundaryAdapters.d.ts +23 -0
  474. package/dist/src/framework/registerBoundaryAdapters.js +46 -0
  475. package/dist/src/framework/routes/admin.d.ts +9 -0
  476. package/dist/src/framework/routes/admin.js +361 -0
  477. package/dist/src/framework/routes/health.d.ts +1 -0
  478. package/dist/src/framework/routes/health.js +21 -0
  479. package/dist/src/framework/routes/home.d.ts +1 -0
  480. package/dist/src/framework/routes/home.js +18 -0
  481. package/dist/src/framework/routes/jobs.d.ts +3 -0
  482. package/dist/{routes → src/framework/routes}/jobs.js +128 -103
  483. package/dist/src/framework/routes/metrics.d.ts +10 -0
  484. package/dist/src/framework/routes/metrics.js +57 -0
  485. package/dist/{routes → src/framework/routes}/uploads.d.ts +3 -3
  486. package/dist/src/framework/routes/uploads.js +262 -0
  487. package/dist/src/framework/runPluginLifecycle.d.ts +27 -0
  488. package/dist/src/framework/runPluginLifecycle.js +121 -0
  489. package/dist/src/framework/secrets/frameworkSecretSchema.d.ts +58 -0
  490. package/dist/src/framework/secrets/frameworkSecretSchema.js +20 -0
  491. package/dist/src/framework/secrets/index.d.ts +9 -0
  492. package/dist/src/framework/secrets/index.js +7 -0
  493. package/dist/src/framework/secrets/providers/envProvider.d.ts +15 -0
  494. package/dist/src/framework/secrets/providers/envProvider.js +18 -0
  495. package/dist/src/framework/secrets/providers/fileProvider.d.ts +8 -0
  496. package/dist/src/framework/secrets/providers/fileProvider.js +82 -0
  497. package/dist/src/framework/secrets/providers/ssmProvider.d.ts +20 -0
  498. package/dist/src/framework/secrets/providers/ssmProvider.js +127 -0
  499. package/dist/src/framework/secrets/resolveSecretBundle.d.ts +53 -0
  500. package/dist/src/framework/secrets/resolveSecretBundle.js +84 -0
  501. package/dist/src/framework/secrets/resolveSecrets.d.ts +18 -0
  502. package/dist/src/framework/secrets/resolveSecrets.js +34 -0
  503. package/dist/src/framework/sse/index.d.ts +21 -0
  504. package/dist/src/framework/sse/index.js +109 -0
  505. package/dist/src/framework/ws/index.d.ts +11 -0
  506. package/dist/src/framework/ws/index.js +8 -0
  507. package/dist/src/index.d.ts +87 -0
  508. package/dist/src/index.js +58 -0
  509. package/dist/src/lib/appConfig.d.ts +7 -0
  510. package/dist/src/lib/appConfig.js +27 -0
  511. package/dist/src/lib/appMeta.d.ts +7 -0
  512. package/dist/src/lib/appMeta.js +3 -0
  513. package/dist/src/lib/authConfig.d.ts +532 -0
  514. package/dist/{lib/appConfig.js → src/lib/authConfig.js} +75 -17
  515. package/dist/{lib → src/lib}/context.d.ts +6 -12
  516. package/dist/{lib → src/lib}/context.js +5 -5
  517. package/dist/src/lib/logger.d.ts +1 -0
  518. package/dist/src/lib/logger.js +1 -0
  519. package/dist/src/lib/mongo.d.ts +58 -0
  520. package/dist/src/lib/mongo.js +96 -0
  521. package/dist/src/lib/queue.d.ts +72 -0
  522. package/dist/src/lib/queue.js +152 -0
  523. package/dist/src/lib/redis.d.ts +28 -0
  524. package/dist/src/lib/redis.js +72 -0
  525. package/dist/{lib → src/lib}/signing.d.ts +2 -2
  526. package/dist/src/lib/signing.js +210 -0
  527. package/dist/src/lib/signingConfig.d.ts +40 -0
  528. package/dist/src/lib/signingConfig.js +28 -0
  529. package/dist/src/server.d.ts +146 -0
  530. package/dist/src/server.js +469 -0
  531. package/dist/src/shared/lib/HttpError.d.ts +1 -0
  532. package/dist/src/shared/lib/HttpError.js +2 -0
  533. package/dist/src/shared/lib/constants.d.ts +10 -0
  534. package/dist/src/shared/lib/crypto.d.ts +43 -0
  535. package/dist/src/shared/lib/crypto.js +74 -0
  536. package/dist/src/shared/lib/signing.d.ts +52 -0
  537. package/dist/{lib → src/shared/lib}/signing.js +35 -8
  538. package/dist/src/testing.d.ts +34 -0
  539. package/dist/src/testing.js +93 -0
  540. package/package.json +100 -26
  541. package/dist/adapters/memoryAuth.d.ts +0 -52
  542. package/dist/adapters/memoryAuth.js +0 -749
  543. package/dist/adapters/memoryStorage.d.ts +0 -3
  544. package/dist/adapters/memoryStorage.js +0 -44
  545. package/dist/adapters/mongoAuth.d.ts +0 -2
  546. package/dist/adapters/mongoAuth.js +0 -403
  547. package/dist/adapters/sqliteAuth.d.ts +0 -72
  548. package/dist/adapters/sqliteAuth.js +0 -858
  549. package/dist/app.d.ts +0 -559
  550. package/dist/app.js +0 -651
  551. package/dist/entrypoints/mongo.d.ts +0 -5
  552. package/dist/entrypoints/mongo.js +0 -4
  553. package/dist/entrypoints/queue.d.ts +0 -2
  554. package/dist/entrypoints/queue.js +0 -1
  555. package/dist/entrypoints/redis.d.ts +0 -1
  556. package/dist/entrypoints/redis.js +0 -1
  557. package/dist/index.d.ts +0 -117
  558. package/dist/index.js +0 -88
  559. package/dist/lib/appConfig.d.ts +0 -275
  560. package/dist/lib/auditLog.d.ts +0 -58
  561. package/dist/lib/auditLog.js +0 -218
  562. package/dist/lib/authAdapter.d.ts +0 -246
  563. package/dist/lib/authAdapter.js +0 -7
  564. package/dist/lib/authRateLimit.d.ts +0 -13
  565. package/dist/lib/authRateLimit.js +0 -117
  566. package/dist/lib/clientIp.d.ts +0 -14
  567. package/dist/lib/credentialStuffing.d.ts +0 -31
  568. package/dist/lib/credentialStuffing.js +0 -77
  569. package/dist/lib/crypto.d.ts +0 -11
  570. package/dist/lib/crypto.js +0 -22
  571. package/dist/lib/deletionCancelToken.d.ts +0 -12
  572. package/dist/lib/deletionCancelToken.js +0 -88
  573. package/dist/lib/emailVerification.d.ts +0 -19
  574. package/dist/lib/emailVerification.js +0 -129
  575. package/dist/lib/fingerprint.js +0 -36
  576. package/dist/lib/idempotency.js +0 -182
  577. package/dist/lib/jwks.d.ts +0 -25
  578. package/dist/lib/jwks.js +0 -51
  579. package/dist/lib/jwt.d.ts +0 -15
  580. package/dist/lib/jwt.js +0 -111
  581. package/dist/lib/metrics.d.ts +0 -14
  582. package/dist/lib/mfaChallenge.d.ts +0 -55
  583. package/dist/lib/mfaChallenge.js +0 -398
  584. package/dist/lib/mongo.d.ts +0 -39
  585. package/dist/lib/mongo.js +0 -124
  586. package/dist/lib/oauth.d.ts +0 -40
  587. package/dist/lib/oauth.js +0 -101
  588. package/dist/lib/oauthCode.d.ts +0 -15
  589. package/dist/lib/oauthCode.js +0 -95
  590. package/dist/lib/pagination.d.ts +0 -119
  591. package/dist/lib/pagination.js +0 -166
  592. package/dist/lib/queue.d.ts +0 -37
  593. package/dist/lib/queue.js +0 -117
  594. package/dist/lib/redis.d.ts +0 -9
  595. package/dist/lib/redis.js +0 -61
  596. package/dist/lib/resetPassword.d.ts +0 -12
  597. package/dist/lib/resetPassword.js +0 -93
  598. package/dist/lib/roles.d.ts +0 -7
  599. package/dist/lib/roles.js +0 -49
  600. package/dist/lib/saml.d.ts +0 -25
  601. package/dist/lib/saml.js +0 -64
  602. package/dist/lib/securityEvents.d.ts +0 -28
  603. package/dist/lib/securityEvents.js +0 -26
  604. package/dist/lib/session.d.ts +0 -49
  605. package/dist/lib/session.js +0 -597
  606. package/dist/lib/tenant.d.ts +0 -15
  607. package/dist/lib/tenant.js +0 -65
  608. package/dist/lib/upload.js +0 -112
  609. package/dist/lib/uploadRegistry.d.ts +0 -18
  610. package/dist/lib/uploadRegistry.js +0 -83
  611. package/dist/lib/ws.d.ts +0 -22
  612. package/dist/lib/ws.js +0 -96
  613. package/dist/lib/wsHeartbeat.d.ts +0 -12
  614. package/dist/lib/wsHeartbeat.js +0 -57
  615. package/dist/lib/wsMessages.d.ts +0 -40
  616. package/dist/lib/wsMessages.js +0 -330
  617. package/dist/lib/wsPresence.d.ts +0 -25
  618. package/dist/lib/wsPresence.js +0 -99
  619. package/dist/middleware/auditLog.js +0 -39
  620. package/dist/middleware/bearerAuth.d.ts +0 -2
  621. package/dist/middleware/bearerAuth.js +0 -11
  622. package/dist/middleware/cacheResponse.d.ts +0 -15
  623. package/dist/middleware/cacheResponse.js +0 -178
  624. package/dist/middleware/captcha.js +0 -36
  625. package/dist/middleware/csrf.js +0 -129
  626. package/dist/middleware/identify.d.ts +0 -3
  627. package/dist/middleware/identify.js +0 -122
  628. package/dist/middleware/index.js +0 -1
  629. package/dist/middleware/metrics.d.ts +0 -9
  630. package/dist/middleware/metrics.js +0 -26
  631. package/dist/middleware/rateLimit.js +0 -22
  632. package/dist/middleware/requestId.d.ts +0 -3
  633. package/dist/middleware/scimAuth.d.ts +0 -8
  634. package/dist/middleware/scimAuth.js +0 -29
  635. package/dist/middleware/tenant.d.ts +0 -5
  636. package/dist/middleware/upload.d.ts +0 -5
  637. package/dist/middleware/userAuth.d.ts +0 -3
  638. package/dist/middleware/userAuth.js +0 -6
  639. package/dist/models/AuditLog.d.ts +0 -30
  640. package/dist/models/AuditLog.js +0 -39
  641. package/dist/models/AuthUser.js +0 -55
  642. package/dist/models/Group.d.ts +0 -21
  643. package/dist/models/Group.js +0 -28
  644. package/dist/models/GroupMembership.js +0 -25
  645. package/dist/models/TenantRole.d.ts +0 -15
  646. package/dist/models/TenantRole.js +0 -23
  647. package/dist/routes/auth.d.ts +0 -12
  648. package/dist/routes/auth.js +0 -744
  649. package/dist/routes/groups.js +0 -346
  650. package/dist/routes/health.d.ts +0 -1
  651. package/dist/routes/health.js +0 -22
  652. package/dist/routes/home.d.ts +0 -1
  653. package/dist/routes/home.js +0 -16
  654. package/dist/routes/jobs.d.ts +0 -2
  655. package/dist/routes/m2m.d.ts +0 -2
  656. package/dist/routes/m2m.js +0 -72
  657. package/dist/routes/metrics.d.ts +0 -8
  658. package/dist/routes/metrics.js +0 -55
  659. package/dist/routes/mfa.d.ts +0 -5
  660. package/dist/routes/mfa.js +0 -628
  661. package/dist/routes/oauth.d.ts +0 -2
  662. package/dist/routes/oauth.js +0 -520
  663. package/dist/routes/oidc.d.ts +0 -2
  664. package/dist/routes/oidc.js +0 -29
  665. package/dist/routes/passkey.d.ts +0 -1
  666. package/dist/routes/passkey.js +0 -157
  667. package/dist/routes/saml.d.ts +0 -2
  668. package/dist/routes/saml.js +0 -86
  669. package/dist/routes/scim.d.ts +0 -2
  670. package/dist/routes/scim.js +0 -255
  671. package/dist/routes/uploads.js +0 -227
  672. package/dist/schemas/auth.js +0 -30
  673. package/dist/server.d.ts +0 -57
  674. package/dist/server.js +0 -112
  675. package/dist/services/auth.d.ts +0 -29
  676. package/dist/services/auth.js +0 -238
  677. package/dist/ws/index.d.ts +0 -10
  678. package/dist/ws/index.js +0 -39
  679. package/docs/sections/adding-middleware/full.md +0 -35
  680. package/docs/sections/adding-models/full.md +0 -125
  681. package/docs/sections/adding-models/overview.md +0 -13
  682. package/docs/sections/adding-routes/full.md +0 -182
  683. package/docs/sections/adding-routes/overview.md +0 -23
  684. package/docs/sections/auth-flow/full.md +0 -790
  685. package/docs/sections/auth-flow/overview.md +0 -10
  686. package/docs/sections/auth-security-examples/full.md +0 -388
  687. package/docs/sections/authentication/full.md +0 -130
  688. package/docs/sections/authentication/overview.md +0 -5
  689. package/docs/sections/cli/full.md +0 -42
  690. package/docs/sections/configuration/full.md +0 -172
  691. package/docs/sections/configuration/overview.md +0 -18
  692. package/docs/sections/configuration-example/full.md +0 -117
  693. package/docs/sections/configuration-example/overview.md +0 -30
  694. package/docs/sections/documentation/full.md +0 -171
  695. package/docs/sections/environment-variables/full.md +0 -55
  696. package/docs/sections/exports/full.md +0 -123
  697. package/docs/sections/extending-context/full.md +0 -59
  698. package/docs/sections/header.md +0 -3
  699. package/docs/sections/installation/full.md +0 -6
  700. package/docs/sections/jobs/full.md +0 -140
  701. package/docs/sections/jobs/overview.md +0 -15
  702. package/docs/sections/logging/full.md +0 -83
  703. package/docs/sections/metrics/full.md +0 -131
  704. package/docs/sections/mongodb-connections/full.md +0 -45
  705. package/docs/sections/mongodb-connections/overview.md +0 -7
  706. package/docs/sections/multi-tenancy/full.md +0 -66
  707. package/docs/sections/multi-tenancy/overview.md +0 -15
  708. package/docs/sections/oauth/full.md +0 -189
  709. package/docs/sections/oauth/overview.md +0 -16
  710. package/docs/sections/package-development/full.md +0 -7
  711. package/docs/sections/pagination/full.md +0 -93
  712. package/docs/sections/passkey-login/full.md +0 -90
  713. package/docs/sections/passkey-login/overview.md +0 -1
  714. package/docs/sections/peer-dependencies/full.md +0 -47
  715. package/docs/sections/quick-start/full.md +0 -43
  716. package/docs/sections/response-caching/full.md +0 -117
  717. package/docs/sections/response-caching/overview.md +0 -13
  718. package/docs/sections/roles/full.md +0 -225
  719. package/docs/sections/roles/overview.md +0 -14
  720. package/docs/sections/running-without-redis/full.md +0 -16
  721. package/docs/sections/running-without-redis-or-mongodb/full.md +0 -60
  722. package/docs/sections/signing/full.md +0 -203
  723. package/docs/sections/stack/full.md +0 -10
  724. package/docs/sections/uploads/full.md +0 -208
  725. package/docs/sections/versioning/full.md +0 -85
  726. package/docs/sections/webhook-auth/full.md +0 -100
  727. package/docs/sections/websocket/full.md +0 -196
  728. package/docs/sections/websocket/overview.md +0 -5
  729. package/docs/sections/websocket-rooms/full.md +0 -102
  730. package/docs/sections/websocket-rooms/overview.md +0 -5
  731. /package/dist/{lib/storageAdapter.js → packages/bunshot-admin/src/types/env.js} +0 -0
  732. /package/dist/{lib → packages/bunshot-auth/src/lib}/fingerprint.d.ts +0 -0
  733. /package/dist/{lib → packages/bunshot-auth/src/lib}/logger.d.ts +0 -0
  734. /package/dist/{lib → packages/bunshot-core/src}/constants.d.ts +0 -0
  735. /package/dist/{lib → packages/bunshot-core/src}/storageAdapter.d.ts +0 -0
  736. /package/dist/{lib → src/framework/lib}/createDtoMapper.d.ts +0 -0
  737. /package/dist/{lib → src/framework/lib}/stripUnreferencedSchemas.d.ts +0 -0
  738. /package/dist/{middleware → src/framework/middleware}/cors.d.ts +0 -0
  739. /package/dist/{middleware → src/framework/middleware}/cors.js +0 -0
  740. /package/dist/{middleware → src/framework/middleware}/index.d.ts +0 -0
  741. /package/dist/{middleware → src/framework/middleware}/logger.js +0 -0
  742. /package/dist/{lib → src/shared/lib}/constants.js +0 -0
@@ -0,0 +1,991 @@
1
+ import { getAuthCookieOptions } from '../lib/cookieOptions';
2
+ import { isProd } from '../lib/env';
3
+ import { consumeMfaChallenge, replaceMfaChallengeOtp } from '../lib/mfaChallenge';
4
+ import { refreshCsrfToken } from '../middleware/csrf';
5
+ import { userAuth } from '../middleware/userAuth';
6
+ import { ErrorResponse } from '../schemas/error';
7
+ import { SuccessResponse } from '../schemas/success';
8
+ import * as AuthService from '../services/auth';
9
+ import { emitLoginSuccess } from '../services/auth';
10
+ import * as MfaService from '../services/mfa';
11
+ import { setCookie } from 'hono/cookie';
12
+ import { z } from 'zod';
13
+ import { createRoute, withSecurity } from '../../../bunshot-core/src/index.js';
14
+ import { COOKIE_REFRESH_TOKEN, COOKIE_TOKEN, HttpError, createRouter, } from '../../../bunshot-core/src/index.js';
15
+ import { getClientIp } from '../../../bunshot-core/src/index.js';
16
+ const hookCtx = (c) => ({
17
+ ip: getClientIp(c) !== 'unknown' ? getClientIp(c) : undefined,
18
+ userAgent: c.req.header('user-agent') ?? undefined,
19
+ requestId: c.get('requestId'),
20
+ });
21
+ const tags = ['MFA'];
22
+ const RecoveryCodesSuccessResponse = SuccessResponse.extend({
23
+ recoveryCodes: z.array(z.string()).describe('One-time recovery codes. Store these securely.'),
24
+ });
25
+ const SetupTokenSuccessResponse = SuccessResponse.extend({
26
+ setupToken: z.string().describe('Setup challenge token for the follow-up verification request.'),
27
+ });
28
+ const WebAuthnRegistrationSuccessResponse = SuccessResponse.extend({
29
+ credentialId: z.string(),
30
+ recoveryCodes: z
31
+ .array(z.string())
32
+ .nullable()
33
+ .describe('Recovery codes returned when WebAuthn registration completes.'),
34
+ });
35
+ export const createMfaRouter = ({ rateLimit } = {}, runtime) => {
36
+ const { adapter, eventBus } = runtime;
37
+ const getConfig = () => runtime.config;
38
+ const cookieOptions = (maxAge) => getAuthCookieOptions(isProd(), runtime.config, maxAge);
39
+ const router = createRouter();
40
+ // Resolve MFA rate limits with defaults
41
+ const mfaVerifyOpts = {
42
+ windowMs: rateLimit?.mfaVerify?.windowMs ?? 15 * 60 * 1000,
43
+ max: rateLimit?.mfaVerify?.max ?? 10,
44
+ };
45
+ const mfaEmailOtpInitiateOpts = {
46
+ windowMs: rateLimit?.mfaEmailOtpInitiate?.windowMs ?? 15 * 60 * 1000,
47
+ max: rateLimit?.mfaEmailOtpInitiate?.max ?? 3,
48
+ };
49
+ const mfaResendOpts = {
50
+ windowMs: rateLimit?.mfaResend?.windowMs ?? 60 * 1000,
51
+ max: rateLimit?.mfaResend?.max ?? 5,
52
+ };
53
+ const mfaDisableOpts = {
54
+ windowMs: rateLimit?.mfaDisable?.windowMs ?? 15 * 60 * 1000,
55
+ max: rateLimit?.mfaDisable?.max ?? 5,
56
+ };
57
+ // All MFA setup/management routes require auth
58
+ router.use('/auth/mfa/setup', userAuth);
59
+ router.use('/auth/mfa/verify-setup', userAuth);
60
+ router.use('/auth/mfa', userAuth);
61
+ router.use('/auth/mfa/recovery-codes', userAuth);
62
+ router.use('/auth/mfa/email-otp/enable', userAuth);
63
+ router.use('/auth/mfa/email-otp/verify-setup', userAuth);
64
+ router.use('/auth/mfa/email-otp', userAuth);
65
+ router.use('/auth/mfa/methods', userAuth);
66
+ // ─── Setup ────────────────────────────────────────────────────────────────
67
+ router.openapi(withSecurity(createRoute({
68
+ method: 'post',
69
+ path: '/auth/mfa/setup',
70
+ summary: 'Initiate MFA setup',
71
+ description: 'Generates a TOTP secret and returns the otpauth URI for QR code scanning. The user must confirm setup by verifying a code via POST /auth/mfa/verify-setup.',
72
+ tags,
73
+ responses: {
74
+ 200: {
75
+ content: {
76
+ 'application/json': {
77
+ schema: z.object({
78
+ secret: z.string().describe('Base32-encoded TOTP secret.'),
79
+ uri: z.string().describe('otpauth:// URI for QR code generation.'),
80
+ }),
81
+ },
82
+ },
83
+ description: 'TOTP secret generated. Scan the QR code with an authenticator app.',
84
+ },
85
+ 401: {
86
+ content: { 'application/json': { schema: ErrorResponse } },
87
+ description: 'No valid session.',
88
+ },
89
+ 429: {
90
+ content: { 'application/json': { schema: ErrorResponse } },
91
+ description: 'Too many MFA setup attempts. Try again later.',
92
+ },
93
+ 501: {
94
+ content: { 'application/json': { schema: ErrorResponse } },
95
+ description: 'Auth adapter does not support MFA.',
96
+ },
97
+ },
98
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
99
+ const userId = c.get('authUserId');
100
+ if (await runtime.rateLimit.trackAttempt(`mfa-setup:${userId}`, {
101
+ windowMs: 15 * 60 * 1000,
102
+ max: 5,
103
+ })) {
104
+ return c.json({ error: 'Too many MFA setup attempts. Try again later.' }, 429);
105
+ }
106
+ const result = await MfaService.setupMfa(userId, runtime);
107
+ return c.json(result, 200);
108
+ });
109
+ // ─── Verify Setup ─────────────────────────────────────────────────────────
110
+ router.openapi(withSecurity(createRoute({
111
+ method: 'post',
112
+ path: '/auth/mfa/verify-setup',
113
+ summary: 'Confirm MFA setup',
114
+ description: 'Verifies a TOTP code from the authenticator app and enables MFA. Returns one-time recovery codes that should be stored securely. If email OTP was previously enabled, recovery codes are regenerated.',
115
+ tags,
116
+ request: {
117
+ body: {
118
+ content: {
119
+ 'application/json': {
120
+ schema: z.object({
121
+ code: z
122
+ .string()
123
+ .length(6)
124
+ .describe('6-digit TOTP code from the authenticator app.'),
125
+ }),
126
+ },
127
+ },
128
+ },
129
+ },
130
+ responses: {
131
+ 200: {
132
+ content: {
133
+ 'application/json': {
134
+ schema: RecoveryCodesSuccessResponse.extend({
135
+ recoveryCodes: z
136
+ .array(z.string())
137
+ .describe('One-time recovery codes. Store these securely — they cannot be shown again.'),
138
+ }),
139
+ },
140
+ },
141
+ description: 'MFA enabled successfully.',
142
+ },
143
+ 400: {
144
+ content: { 'application/json': { schema: ErrorResponse } },
145
+ description: 'MFA setup not initiated.',
146
+ },
147
+ 401: {
148
+ content: { 'application/json': { schema: ErrorResponse } },
149
+ description: 'Invalid TOTP code or no valid session.',
150
+ },
151
+ 501: {
152
+ content: { 'application/json': { schema: ErrorResponse } },
153
+ description: 'Auth adapter does not support MFA.',
154
+ },
155
+ },
156
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
157
+ const userId = c.get('authUserId');
158
+ const { code } = c.req.valid('json');
159
+ const recoveryCodes = await MfaService.verifySetup(userId, code, runtime);
160
+ eventBus.emit('security.auth.mfa.setup', { userId: c.get('authUserId') ?? undefined });
161
+ eventBus.emit('auth:mfa.enabled', { userId, method: 'totp' });
162
+ return c.json({ ok: true, recoveryCodes }, 200);
163
+ });
164
+ // ─── Verify (complete login after password) ───────────────────────────────
165
+ const MfaLoginResponse = z
166
+ .object({
167
+ token: z.string().describe('JWT session token.'),
168
+ userId: z.string().describe('Unique user ID.'),
169
+ refreshToken: z.string().optional().describe('Refresh token (when configured).'),
170
+ })
171
+ .openapi('MfaLoginResponse');
172
+ router.openapi(createRoute({
173
+ method: 'post',
174
+ path: '/auth/mfa/verify',
175
+ summary: 'Complete MFA login',
176
+ description: "Completes login by verifying a TOTP code, email OTP code, recovery code, or WebAuthn assertion after password authentication. Requires the mfaToken returned from the login endpoint. Optionally specify 'method' to target a specific verification method.",
177
+ tags,
178
+ request: {
179
+ body: {
180
+ content: {
181
+ 'application/json': {
182
+ schema: z.object({
183
+ mfaToken: z.string().describe('MFA challenge token from the login response.'),
184
+ code: z
185
+ .string()
186
+ .optional()
187
+ .describe('6-digit TOTP/email OTP code or 8-character recovery code. Required unless using WebAuthn.'),
188
+ method: z
189
+ .enum(['totp', 'emailOtp', 'webauthn'])
190
+ .optional()
191
+ .describe('Specify which MFA method to verify. If omitted, methods are tried automatically.'),
192
+ webauthnResponse: z
193
+ .record(z.string(), z.unknown())
194
+ .optional()
195
+ .describe('WebAuthn authentication response from navigator.credentials.get(). Pass the entire response object.'),
196
+ }),
197
+ },
198
+ },
199
+ },
200
+ },
201
+ responses: {
202
+ 200: {
203
+ content: { 'application/json': { schema: MfaLoginResponse } },
204
+ description: 'MFA verified. Session created.',
205
+ },
206
+ 401: {
207
+ content: { 'application/json': { schema: ErrorResponse } },
208
+ description: 'Invalid or expired MFA token, or invalid code.',
209
+ },
210
+ 429: {
211
+ content: { 'application/json': { schema: ErrorResponse } },
212
+ description: 'Too many MFA verification attempts. Try again later.',
213
+ },
214
+ },
215
+ }), async (c) => {
216
+ const ip = getClientIp(c);
217
+ if (await runtime.rateLimit.trackAttempt(`mfa-verify:${ip}`, mfaVerifyOpts)) {
218
+ return c.json({ error: 'Too many MFA verification attempts. Try again later.' }, 429);
219
+ }
220
+ const { mfaToken, code, method, webauthnResponse } = c.req.valid('json');
221
+ if (!code && !webauthnResponse) {
222
+ return c.json({ error: "Either 'code' or 'webauthnResponse' is required" }, 401);
223
+ }
224
+ const challenge = await consumeMfaChallenge(runtime.repos.mfaChallenge, mfaToken);
225
+ if (!challenge)
226
+ return c.json({ error: 'Invalid or expired MFA token' }, 401);
227
+ const { userId, emailOtpHash, webauthnChallenge } = challenge;
228
+ let valid = false;
229
+ if (method === 'webauthn' || (!method && webauthnResponse)) {
230
+ // WebAuthn verification
231
+ if (webauthnResponse && webauthnChallenge) {
232
+ valid = await MfaService.verifyWebAuthn(userId, webauthnResponse, webauthnChallenge, runtime);
233
+ }
234
+ }
235
+ else if (method === 'totp') {
236
+ // Only try TOTP
237
+ if (code)
238
+ valid = await MfaService.verifyTotp(userId, code, runtime);
239
+ }
240
+ else if (method === 'emailOtp') {
241
+ // Only try email OTP
242
+ if (code && emailOtpHash)
243
+ valid = MfaService.verifyEmailOtp(emailOtpHash, code);
244
+ }
245
+ else if (code) {
246
+ // Auto-detect: use emailOtpHash presence to pick order
247
+ if (emailOtpHash) {
248
+ // Email OTP first, then TOTP, then recovery
249
+ valid = MfaService.verifyEmailOtp(emailOtpHash, code);
250
+ if (!valid)
251
+ valid = await MfaService.verifyTotp(userId, code, runtime);
252
+ }
253
+ else {
254
+ // TOTP first
255
+ valid = await MfaService.verifyTotp(userId, code, runtime);
256
+ }
257
+ }
258
+ // Always try recovery code as fallback (code-based only)
259
+ if (!valid && code) {
260
+ valid = await MfaService.verifyRecoveryCode(userId, code, runtime);
261
+ }
262
+ if (!valid) {
263
+ eventBus.emit('security.auth.mfa.verify.failure', {});
264
+ return c.json({ error: 'Invalid MFA code' }, 401);
265
+ }
266
+ // Create session — reuse the service helper for refresh token support
267
+ const result = await AuthService.createSessionForUser(userId, runtime, {
268
+ ipAddress: getClientIp(c),
269
+ userAgent: c.req.header('user-agent') ?? undefined,
270
+ }, hookCtx(c));
271
+ // Mark MFA as verified on the new session so step-up is satisfied immediately.
272
+ // If this fails, clean up the orphaned session so the client can retry cleanly.
273
+ try {
274
+ await runtime.repos.session.setMfaVerifiedAt(result.sessionId);
275
+ }
276
+ catch (err) {
277
+ await runtime.repos.session.deleteSession(result.sessionId, runtime.config).catch(() => { }); // best-effort cleanup
278
+ throw err;
279
+ }
280
+ const rtConfig = getConfig().refreshToken;
281
+ setCookie(c, COOKIE_TOKEN, result.token, cookieOptions(rtConfig ? (rtConfig.accessTokenExpiry ?? 900) : undefined));
282
+ if (result.refreshToken) {
283
+ setCookie(c, COOKIE_REFRESH_TOKEN, result.refreshToken, cookieOptions(rtConfig?.refreshTokenExpiry ?? 2_592_000));
284
+ }
285
+ if (getConfig().csrfEnabled)
286
+ refreshCsrfToken(c);
287
+ eventBus.emit('security.auth.mfa.verify.success', {});
288
+ emitLoginSuccess(userId, result.sessionId, runtime);
289
+ return c.json({ token: result.token, userId, refreshToken: result.refreshToken }, 200);
290
+ });
291
+ // ─── Disable MFA ──────────────────────────────────────────────────────────
292
+ const disableMfaSchema = z.object({
293
+ method: z
294
+ .enum(['totp', 'emailOtp', 'webauthn', 'password', 'recovery'])
295
+ .optional()
296
+ .describe('Verification method. Inferred from provided credentials when omitted (code→totp, password→password).'),
297
+ code: z.string().optional().describe('TOTP code, email OTP code, or recovery code.'),
298
+ password: z.string().optional().describe("Account password (for method: 'password')."),
299
+ reauthToken: z
300
+ .string()
301
+ .optional()
302
+ .describe('Reauth challenge token (for emailOtp and webauthn methods).'),
303
+ webauthnResponse: z
304
+ .record(z.string(), z.unknown())
305
+ .optional()
306
+ .describe('WebAuthn authentication response.'),
307
+ });
308
+ router.openapi(withSecurity(createRoute({
309
+ method: 'delete',
310
+ path: '/auth/mfa',
311
+ summary: 'Disable MFA',
312
+ description: 'Disables MFA for the authenticated user. Requires identity verification via TOTP, email OTP, WebAuthn, password, or recovery code.',
313
+ tags,
314
+ request: {
315
+ body: {
316
+ content: {
317
+ 'application/json': {
318
+ schema: disableMfaSchema,
319
+ },
320
+ },
321
+ },
322
+ },
323
+ responses: {
324
+ 200: {
325
+ content: { 'application/json': { schema: SuccessResponse } },
326
+ description: 'MFA disabled.',
327
+ },
328
+ 400: {
329
+ content: { 'application/json': { schema: ErrorResponse } },
330
+ description: 'Missing required verification.',
331
+ },
332
+ 401: {
333
+ content: { 'application/json': { schema: ErrorResponse } },
334
+ description: 'Invalid verification or no valid session.',
335
+ },
336
+ 429: {
337
+ content: { 'application/json': { schema: ErrorResponse } },
338
+ description: 'Too many MFA disable attempts. Try again later.',
339
+ },
340
+ 501: {
341
+ content: { 'application/json': { schema: ErrorResponse } },
342
+ description: 'Auth adapter does not support MFA.',
343
+ },
344
+ },
345
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
346
+ const userId = c.get('authUserId');
347
+ const sessionId = c.get('sessionId');
348
+ const body = c.req.valid('json');
349
+ if (await runtime.rateLimit.trackAttempt(`mfa-disable:${userId}`, mfaDisableOpts)) {
350
+ eventBus.emit('security.rate_limit.exceeded', { meta: { path: c.req.path } });
351
+ return c.json({ error: 'Too many MFA disable attempts. Try again later.' }, 429);
352
+ }
353
+ // Infer method from provided credentials when not specified
354
+ const method = body.method ?? (body.password ? 'password' : body.code ? 'totp' : undefined);
355
+ if (!method) {
356
+ throw new HttpError(400, 'Verification is required to disable MFA. Provide method and credentials.');
357
+ }
358
+ const valid = await MfaService.verifyAnyFactor(userId, sessionId, runtime, {
359
+ method,
360
+ code: body.code,
361
+ password: body.password,
362
+ reauthToken: body.reauthToken,
363
+ webauthnResponse: body.webauthnResponse,
364
+ });
365
+ if (!valid) {
366
+ throw new HttpError(401, 'Invalid verification');
367
+ }
368
+ if (!adapter.setMfaEnabled || !adapter.setMfaSecret || !adapter.setRecoveryCodes) {
369
+ throw new HttpError(501, 'Auth adapter does not support MFA');
370
+ }
371
+ await adapter.setMfaEnabled(userId, false);
372
+ await adapter.setMfaSecret(userId, null);
373
+ await adapter.setRecoveryCodes(userId, []);
374
+ if (adapter.setMfaMethods) {
375
+ await adapter.setMfaMethods(userId, []);
376
+ }
377
+ eventBus.emit('auth:mfa.disabled', { userId });
378
+ return c.json({ ok: true }, 200);
379
+ });
380
+ // ─── Regenerate Recovery Codes ────────────────────────────────────────────
381
+ router.openapi(withSecurity(createRoute({
382
+ method: 'post',
383
+ path: '/auth/mfa/recovery-codes',
384
+ summary: 'Regenerate recovery codes',
385
+ description: 'Generates new recovery codes, invalidating all previous ones. Requires a valid TOTP code to confirm.',
386
+ tags,
387
+ request: {
388
+ body: {
389
+ content: {
390
+ 'application/json': {
391
+ schema: z.object({
392
+ code: z.string().length(6).describe('6-digit TOTP code to confirm regeneration.'),
393
+ }),
394
+ },
395
+ },
396
+ },
397
+ },
398
+ responses: {
399
+ 200: {
400
+ content: {
401
+ 'application/json': {
402
+ schema: z.object({
403
+ recoveryCodes: z.array(z.string()).describe('New one-time recovery codes.'),
404
+ }),
405
+ },
406
+ },
407
+ description: 'New recovery codes generated.',
408
+ },
409
+ 401: {
410
+ content: { 'application/json': { schema: ErrorResponse } },
411
+ description: 'Invalid TOTP code or no valid session.',
412
+ },
413
+ 501: {
414
+ content: { 'application/json': { schema: ErrorResponse } },
415
+ description: 'Auth adapter does not support MFA.',
416
+ },
417
+ },
418
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
419
+ const userId = c.get('authUserId');
420
+ const { code } = c.req.valid('json');
421
+ const recoveryCodes = await MfaService.regenerateRecoveryCodes(userId, code, runtime);
422
+ return c.json({ recoveryCodes }, 200);
423
+ });
424
+ // ─── Email OTP: Enable (initiate) ────────────────────────────────────────
425
+ router.openapi(withSecurity(createRoute({
426
+ method: 'post',
427
+ path: '/auth/mfa/email-otp/enable',
428
+ summary: 'Initiate email OTP setup',
429
+ description: "Sends a verification code to the user's email to confirm email OTP setup. Confirm via POST /auth/mfa/email-otp/verify-setup.",
430
+ tags,
431
+ responses: {
432
+ 200: {
433
+ content: {
434
+ 'application/json': {
435
+ schema: SetupTokenSuccessResponse,
436
+ },
437
+ },
438
+ description: 'Verification code sent to email.',
439
+ },
440
+ 400: {
441
+ content: { 'application/json': { schema: ErrorResponse } },
442
+ description: 'No email address on account.',
443
+ },
444
+ 401: {
445
+ content: { 'application/json': { schema: ErrorResponse } },
446
+ description: 'No valid session.',
447
+ },
448
+ 429: {
449
+ content: { 'application/json': { schema: ErrorResponse } },
450
+ description: 'Too many initiation attempts. Try again later.',
451
+ },
452
+ 501: {
453
+ content: { 'application/json': { schema: ErrorResponse } },
454
+ description: 'Email OTP is not configured.',
455
+ },
456
+ },
457
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
458
+ const userId = c.get('authUserId');
459
+ if (await runtime.rateLimit.trackAttempt(`mfa-email-otp-initiate:${userId}`, mfaEmailOtpInitiateOpts)) {
460
+ return c.json({ error: 'Too many initiation attempts. Try again later.' }, 429);
461
+ }
462
+ const setupToken = await MfaService.initiateEmailOtp(userId, runtime);
463
+ return c.json({ ok: true, setupToken }, 200);
464
+ });
465
+ // ─── Email OTP: Verify Setup ─────────────────────────────────────────────
466
+ router.openapi(withSecurity(createRoute({
467
+ method: 'post',
468
+ path: '/auth/mfa/email-otp/verify-setup',
469
+ summary: 'Confirm email OTP setup',
470
+ description: 'Verifies the code sent during email OTP initiation and enables email OTP as an MFA method. Returns recovery codes (new or regenerated if another MFA method was already active).',
471
+ tags,
472
+ request: {
473
+ body: {
474
+ content: {
475
+ 'application/json': {
476
+ schema: z.object({
477
+ setupToken: z
478
+ .string()
479
+ .describe('Setup challenge token from POST /auth/mfa/email-otp/enable.'),
480
+ code: z.string().describe('Verification code sent to email.'),
481
+ }),
482
+ },
483
+ },
484
+ },
485
+ },
486
+ responses: {
487
+ 200: {
488
+ content: {
489
+ 'application/json': {
490
+ schema: SuccessResponse.extend({
491
+ recoveryCodes: z
492
+ .array(z.string())
493
+ .optional()
494
+ .describe('Recovery codes (always returned when email OTP is enabled).'),
495
+ }),
496
+ },
497
+ },
498
+ description: 'Email OTP enabled.',
499
+ },
500
+ 401: {
501
+ content: { 'application/json': { schema: ErrorResponse } },
502
+ description: 'Invalid setup token or code.',
503
+ },
504
+ 501: {
505
+ content: { 'application/json': { schema: ErrorResponse } },
506
+ description: 'Auth adapter does not support MFA.',
507
+ },
508
+ },
509
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
510
+ const userId = c.get('authUserId');
511
+ const { setupToken, code } = c.req.valid('json');
512
+ const recoveryCodes = await MfaService.confirmEmailOtp(userId, setupToken, code, runtime);
513
+ eventBus.emit('security.auth.mfa.setup', { userId });
514
+ eventBus.emit('auth:mfa.enabled', { userId, method: 'email-otp' });
515
+ return c.json({ ok: true, recoveryCodes: recoveryCodes ?? undefined }, 200);
516
+ });
517
+ // ─── Email OTP: Disable ──────────────────────────────────────────────────
518
+ router.openapi(withSecurity(createRoute({
519
+ method: 'delete',
520
+ path: '/auth/mfa/email-otp',
521
+ summary: 'Disable email OTP',
522
+ description: 'Disables email OTP for the authenticated user. Requires identity verification via TOTP, email OTP, WebAuthn, password, or recovery code.',
523
+ tags,
524
+ request: {
525
+ body: {
526
+ content: {
527
+ 'application/json': {
528
+ schema: disableMfaSchema,
529
+ },
530
+ },
531
+ },
532
+ },
533
+ responses: {
534
+ 200: {
535
+ content: { 'application/json': { schema: SuccessResponse } },
536
+ description: 'Email OTP disabled.',
537
+ },
538
+ 400: {
539
+ content: { 'application/json': { schema: ErrorResponse } },
540
+ description: 'Missing required verification.',
541
+ },
542
+ 401: {
543
+ content: { 'application/json': { schema: ErrorResponse } },
544
+ description: 'Invalid credentials or no valid session.',
545
+ },
546
+ 501: {
547
+ content: { 'application/json': { schema: ErrorResponse } },
548
+ description: 'Auth adapter does not support MFA.',
549
+ },
550
+ },
551
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
552
+ const userId = c.get('authUserId');
553
+ const sessionId = c.get('sessionId');
554
+ const body = c.req.valid('json');
555
+ const method = body.method ?? (body.password ? 'password' : body.code ? 'totp' : undefined);
556
+ if (!method) {
557
+ throw new HttpError(400, 'Verification is required. Provide method and credentials.');
558
+ }
559
+ const valid = await MfaService.verifyAnyFactor(userId, sessionId, runtime, {
560
+ method,
561
+ code: body.code,
562
+ password: body.password,
563
+ reauthToken: body.reauthToken,
564
+ webauthnResponse: body.webauthnResponse,
565
+ });
566
+ if (!valid) {
567
+ throw new HttpError(401, 'Invalid verification');
568
+ }
569
+ // Remove "emailOtp" from methods
570
+ if (!adapter.setMfaEnabled)
571
+ return c.json({ error: 'Auth adapter does not support MFA' }, 501);
572
+ const methods = adapter.getMfaMethods ? await adapter.getMfaMethods(userId) : [];
573
+ if (adapter.setMfaMethods) {
574
+ const updated = methods.filter(m => m !== 'emailOtp');
575
+ await adapter.setMfaMethods(userId, updated);
576
+ if (updated.length === 0) {
577
+ await adapter.setMfaEnabled(userId, false);
578
+ if (adapter.setRecoveryCodes)
579
+ await adapter.setRecoveryCodes(userId, []);
580
+ }
581
+ }
582
+ eventBus.emit('auth:mfa.disabled', { userId, method: 'email-otp' });
583
+ return c.json({ ok: true }, 200);
584
+ });
585
+ // ─── Resend Email OTP ────────────────────────────────────────────────────
586
+ router.openapi(createRoute({
587
+ method: 'post',
588
+ path: '/auth/mfa/resend',
589
+ summary: 'Resend email OTP code',
590
+ description: 'Generates and sends a new email OTP code for the given MFA challenge. Rate-limited to 3 resends per challenge. Does not extend the challenge beyond 3x the original TTL.',
591
+ tags,
592
+ request: {
593
+ body: {
594
+ content: {
595
+ 'application/json': {
596
+ schema: z.object({
597
+ mfaToken: z.string().describe('MFA challenge token from the login response.'),
598
+ }),
599
+ },
600
+ },
601
+ },
602
+ },
603
+ responses: {
604
+ 200: {
605
+ content: { 'application/json': { schema: SuccessResponse } },
606
+ description: 'Code sent.',
607
+ },
608
+ 400: {
609
+ content: { 'application/json': { schema: ErrorResponse } },
610
+ description: 'Email OTP not configured.',
611
+ },
612
+ 401: {
613
+ content: { 'application/json': { schema: ErrorResponse } },
614
+ description: 'Invalid or expired MFA token.',
615
+ },
616
+ 429: {
617
+ content: { 'application/json': { schema: ErrorResponse } },
618
+ description: 'Maximum resends reached.',
619
+ },
620
+ },
621
+ }), async (c) => {
622
+ const ip = getClientIp(c);
623
+ if (await runtime.rateLimit.trackAttempt(`mfa-resend:${ip}`, mfaResendOpts)) {
624
+ return c.json({ error: 'Too many resend attempts. Try again later.' }, 429);
625
+ }
626
+ const { mfaToken } = c.req.valid('json');
627
+ const emailOtpConfig = getConfig().mfa?.emailOtp ?? null;
628
+ if (!emailOtpConfig)
629
+ return c.json({ error: 'Email OTP is not configured' }, 400);
630
+ const { code, hash } = MfaService.generateEmailOtpCode(runtime);
631
+ const result = await replaceMfaChallengeOtp(runtime.repos.mfaChallenge, mfaToken, hash, runtime.config);
632
+ if (!result)
633
+ return c.json({ error: 'Invalid/expired MFA token or maximum resends reached' }, 401);
634
+ // Get user email and send
635
+ const user = adapter.getUser ? await adapter.getUser(result.userId) : null;
636
+ if (user?.email) {
637
+ eventBus.emit('auth:delivery.email_otp', { email: user.email, code });
638
+ }
639
+ return c.json({ ok: true }, 200);
640
+ });
641
+ // ─── Get MFA Methods ────────────────────────────────────────────────────
642
+ router.openapi(withSecurity(createRoute({
643
+ method: 'get',
644
+ path: '/auth/mfa/methods',
645
+ summary: 'Get enabled MFA methods',
646
+ description: 'Returns the MFA methods currently enabled for the authenticated user.',
647
+ tags,
648
+ responses: {
649
+ 200: {
650
+ content: {
651
+ 'application/json': {
652
+ schema: z.object({
653
+ methods: z
654
+ .array(z.string())
655
+ .describe("Enabled MFA methods (e.g., 'totp', 'emailOtp')."),
656
+ }),
657
+ },
658
+ },
659
+ description: 'Enabled MFA methods.',
660
+ },
661
+ 401: {
662
+ content: { 'application/json': { schema: ErrorResponse } },
663
+ description: 'No valid session.',
664
+ },
665
+ },
666
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
667
+ const userId = c.get('authUserId');
668
+ const methods = await MfaService.getMfaMethods(userId, runtime);
669
+ return c.json({ methods }, 200);
670
+ });
671
+ // ─── WebAuthn / Security Keys ─────────────────────────────────────────────
672
+ if (getConfig().mfa?.webauthn) {
673
+ // Eager dependency check — fail fast at server start
674
+ MfaService.assertWebAuthnDependency().catch(err => {
675
+ throw err;
676
+ });
677
+ router.use('/auth/mfa/webauthn/*', userAuth);
678
+ // Register options
679
+ router.openapi(withSecurity(createRoute({
680
+ method: 'post',
681
+ path: '/auth/mfa/webauthn/register-options',
682
+ summary: 'Generate WebAuthn registration options',
683
+ description: 'Generates registration options for the client to pass to navigator.credentials.create(). Returns a registrationToken to confirm registration.',
684
+ tags,
685
+ responses: {
686
+ 200: {
687
+ content: {
688
+ 'application/json': {
689
+ schema: z.object({
690
+ options: z
691
+ .record(z.string(), z.unknown())
692
+ .describe('PublicKeyCredentialCreationOptions — pass directly to navigator.credentials.create().'),
693
+ registrationToken: z
694
+ .string()
695
+ .describe('Token to pass back when completing registration.'),
696
+ }),
697
+ },
698
+ },
699
+ description: 'Registration options generated.',
700
+ },
701
+ 401: {
702
+ content: { 'application/json': { schema: ErrorResponse } },
703
+ description: 'No valid session.',
704
+ },
705
+ 501: {
706
+ content: { 'application/json': { schema: ErrorResponse } },
707
+ description: 'WebAuthn not configured or adapter does not support it.',
708
+ },
709
+ },
710
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
711
+ const userId = c.get('authUserId');
712
+ const result = await MfaService.initiateWebAuthnRegistration(userId, runtime);
713
+ return c.json(result, 200);
714
+ });
715
+ // Complete registration
716
+ router.openapi(withSecurity(createRoute({
717
+ method: 'post',
718
+ path: '/auth/mfa/webauthn/register',
719
+ summary: 'Complete WebAuthn registration',
720
+ description: 'Verifies the attestation response from navigator.credentials.create() and stores the credential. Returns recovery codes.',
721
+ tags,
722
+ request: {
723
+ body: {
724
+ content: {
725
+ 'application/json': {
726
+ schema: z.object({
727
+ registrationToken: z
728
+ .string()
729
+ .describe('Token from POST /auth/mfa/webauthn/register-options.'),
730
+ attestationResponse: z
731
+ .record(z.string(), z.unknown())
732
+ .describe('Full response from navigator.credentials.create().'),
733
+ name: z
734
+ .string()
735
+ .optional()
736
+ .describe("User-friendly name for the key (e.g. 'YubiKey 5')."),
737
+ }),
738
+ },
739
+ },
740
+ },
741
+ },
742
+ responses: {
743
+ 200: {
744
+ content: {
745
+ 'application/json': {
746
+ schema: WebAuthnRegistrationSuccessResponse,
747
+ },
748
+ },
749
+ description: 'Security key registered.',
750
+ },
751
+ 401: {
752
+ content: { 'application/json': { schema: ErrorResponse } },
753
+ description: 'Invalid registration token or verification failed.',
754
+ },
755
+ 409: {
756
+ content: { 'application/json': { schema: ErrorResponse } },
757
+ description: 'Security key already registered to another account.',
758
+ },
759
+ 501: {
760
+ content: { 'application/json': { schema: ErrorResponse } },
761
+ description: 'WebAuthn not configured or adapter does not support it.',
762
+ },
763
+ },
764
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
765
+ const userId = c.get('authUserId');
766
+ const { registrationToken, attestationResponse, name } = c.req.valid('json');
767
+ const result = await MfaService.completeWebAuthnRegistration(userId, registrationToken, attestationResponse, runtime, name);
768
+ eventBus.emit('security.auth.mfa.setup', { userId });
769
+ eventBus.emit('auth:mfa.enabled', { userId, method: 'webauthn' });
770
+ return c.json({ ok: true, ...result }, 200);
771
+ });
772
+ // List credentials
773
+ router.openapi(withSecurity(createRoute({
774
+ method: 'get',
775
+ path: '/auth/mfa/webauthn/credentials',
776
+ summary: 'List WebAuthn credentials',
777
+ description: 'Returns the security keys registered for the authenticated user. Does not include private key data.',
778
+ tags,
779
+ responses: {
780
+ 200: {
781
+ content: {
782
+ 'application/json': {
783
+ schema: z.object({
784
+ credentials: z.array(z.object({
785
+ credentialId: z.string(),
786
+ name: z.string().optional(),
787
+ createdAt: z.number(),
788
+ transports: z.array(z.string()).optional(),
789
+ })),
790
+ }),
791
+ },
792
+ },
793
+ description: 'List of registered security keys.',
794
+ },
795
+ 401: {
796
+ content: { 'application/json': { schema: ErrorResponse } },
797
+ description: 'No valid session.',
798
+ },
799
+ },
800
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
801
+ const userId = c.get('authUserId');
802
+ const creds = adapter.getWebAuthnCredentials
803
+ ? await adapter.getWebAuthnCredentials(userId)
804
+ : [];
805
+ return c.json({
806
+ credentials: creds.map(cr => ({
807
+ credentialId: cr.credentialId,
808
+ name: cr.name,
809
+ createdAt: cr.createdAt,
810
+ transports: cr.transports,
811
+ })),
812
+ }, 200);
813
+ });
814
+ // Remove a single credential
815
+ router.openapi(withSecurity(createRoute({
816
+ method: 'delete',
817
+ path: '/auth/mfa/webauthn/credentials/{credentialId}',
818
+ summary: 'Remove a WebAuthn credential',
819
+ description: 'Removes a single security key. Identity verification is only required when removing the last MFA credential.',
820
+ tags,
821
+ request: {
822
+ params: z.object({ credentialId: z.string() }),
823
+ body: {
824
+ content: {
825
+ 'application/json': {
826
+ schema: z.object({
827
+ method: z
828
+ .enum(['totp', 'emailOtp', 'webauthn', 'password', 'recovery'])
829
+ .optional()
830
+ .describe('Verification method (required when removing the last MFA credential).'),
831
+ code: z
832
+ .string()
833
+ .optional()
834
+ .describe('TOTP code, email OTP code, or recovery code.'),
835
+ password: z
836
+ .string()
837
+ .optional()
838
+ .describe("Account password (for method: 'password')."),
839
+ reauthToken: z
840
+ .string()
841
+ .optional()
842
+ .describe('Reauth challenge token (for emailOtp and webauthn methods).'),
843
+ webauthnResponse: z
844
+ .record(z.string(), z.unknown())
845
+ .optional()
846
+ .describe('WebAuthn authentication response.'),
847
+ }),
848
+ },
849
+ },
850
+ },
851
+ },
852
+ responses: {
853
+ 200: {
854
+ content: { 'application/json': { schema: SuccessResponse } },
855
+ description: 'Credential removed.',
856
+ },
857
+ 400: {
858
+ content: { 'application/json': { schema: ErrorResponse } },
859
+ description: 'Missing required verification.',
860
+ },
861
+ 401: {
862
+ content: { 'application/json': { schema: ErrorResponse } },
863
+ description: 'Invalid credentials or no valid session.',
864
+ },
865
+ 404: {
866
+ content: { 'application/json': { schema: ErrorResponse } },
867
+ description: 'Credential not found.',
868
+ },
869
+ 501: {
870
+ content: { 'application/json': { schema: ErrorResponse } },
871
+ description: 'Adapter does not support WebAuthn.',
872
+ },
873
+ },
874
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
875
+ const userId = c.get('authUserId');
876
+ const sessionId = c.get('sessionId');
877
+ const { credentialId } = c.req.valid('param');
878
+ const { method, code, password, reauthToken, webauthnResponse } = c.req.valid('json');
879
+ // If method is provided, pre-verify before delegating
880
+ if (method) {
881
+ const valid = await MfaService.verifyAnyFactor(userId, sessionId, runtime, {
882
+ method,
883
+ code,
884
+ password,
885
+ reauthToken,
886
+ webauthnResponse: webauthnResponse,
887
+ });
888
+ if (!valid)
889
+ return c.json({ error: 'Invalid credentials' }, 401);
890
+ // Delegate without re-verifying (pass empty params to skip internal verifyIdentity)
891
+ if (!adapter.getWebAuthnCredentials || !adapter.removeWebAuthnCredential) {
892
+ return c.json({ error: 'Adapter does not support WebAuthn' }, 501);
893
+ }
894
+ const credentials = await adapter.getWebAuthnCredentials(userId);
895
+ if (!credentials.some(cr => cr.credentialId === credentialId)) {
896
+ return c.json({ error: 'Credential not found' }, 404);
897
+ }
898
+ await adapter.removeWebAuthnCredential(userId, credentialId);
899
+ const remaining = credentials.filter(cr => cr.credentialId !== credentialId);
900
+ if (remaining.length === 0 && adapter.setMfaMethods) {
901
+ const methods = adapter.getMfaMethods ? await adapter.getMfaMethods(userId) : [];
902
+ const updated = methods.filter(m => m !== 'webauthn');
903
+ await adapter.setMfaMethods(userId, updated);
904
+ if (updated.length === 0 && adapter.setMfaEnabled) {
905
+ await adapter.setMfaEnabled(userId, false);
906
+ if (adapter.setRecoveryCodes)
907
+ await adapter.setRecoveryCodes(userId, []);
908
+ }
909
+ }
910
+ }
911
+ else {
912
+ // No verification needed (not removing last credential)
913
+ await MfaService.removeWebAuthnCredential(userId, credentialId, { code, password }, runtime);
914
+ }
915
+ return c.json({ ok: true }, 200);
916
+ });
917
+ // Disable WebAuthn entirely
918
+ router.openapi(withSecurity(createRoute({
919
+ method: 'delete',
920
+ path: '/auth/mfa/webauthn',
921
+ summary: 'Disable WebAuthn MFA',
922
+ description: 'Removes all WebAuthn credentials and disables WebAuthn as an MFA method. Requires identity verification via TOTP, email OTP, WebAuthn, password, or recovery code.',
923
+ tags,
924
+ request: {
925
+ body: {
926
+ content: {
927
+ 'application/json': {
928
+ schema: disableMfaSchema,
929
+ },
930
+ },
931
+ },
932
+ },
933
+ responses: {
934
+ 200: {
935
+ content: { 'application/json': { schema: SuccessResponse } },
936
+ description: 'WebAuthn disabled.',
937
+ },
938
+ 400: {
939
+ content: { 'application/json': { schema: ErrorResponse } },
940
+ description: 'Missing required verification.',
941
+ },
942
+ 401: {
943
+ content: { 'application/json': { schema: ErrorResponse } },
944
+ description: 'Invalid credentials or no valid session.',
945
+ },
946
+ 501: {
947
+ content: { 'application/json': { schema: ErrorResponse } },
948
+ description: 'Adapter does not support WebAuthn.',
949
+ },
950
+ },
951
+ }), { cookieAuth: [] }, { userToken: [] }), async (c) => {
952
+ const userId = c.get('authUserId');
953
+ const sessionId = c.get('sessionId');
954
+ const body = c.req.valid('json');
955
+ const method = body.method ?? (body.password ? 'password' : body.code ? 'totp' : undefined);
956
+ if (!method) {
957
+ throw new HttpError(400, 'Verification is required. Provide method and credentials.');
958
+ }
959
+ const valid = await MfaService.verifyAnyFactor(userId, sessionId, runtime, {
960
+ method,
961
+ code: body.code,
962
+ password: body.password,
963
+ reauthToken: body.reauthToken,
964
+ webauthnResponse: body.webauthnResponse,
965
+ });
966
+ if (!valid) {
967
+ throw new HttpError(401, 'Invalid verification');
968
+ }
969
+ if (!adapter.getWebAuthnCredentials || !adapter.removeWebAuthnCredential) {
970
+ throw new HttpError(501, 'Auth adapter does not support WebAuthn');
971
+ }
972
+ const credentials = await adapter.getWebAuthnCredentials(userId);
973
+ for (const cred of credentials) {
974
+ await adapter.removeWebAuthnCredential(userId, cred.credentialId);
975
+ }
976
+ // Remove "webauthn" from methods
977
+ if (adapter.getMfaMethods && adapter.setMfaMethods) {
978
+ const methods = await adapter.getMfaMethods(userId);
979
+ const updated = methods.filter(m => m !== 'webauthn');
980
+ await adapter.setMfaMethods(userId, updated);
981
+ if (updated.length === 0 && adapter.setMfaEnabled) {
982
+ await adapter.setMfaEnabled(userId, false);
983
+ if (adapter.setRecoveryCodes)
984
+ await adapter.setRecoveryCodes(userId, []);
985
+ }
986
+ }
987
+ return c.json({ ok: true }, 200);
988
+ });
989
+ }
990
+ return router;
991
+ };