@portaidentity/server 1.7.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/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +33 -0
  4. package/dist/applications/cache.d.ts +64 -0
  5. package/dist/applications/cache.d.ts.map +1 -0
  6. package/dist/applications/cache.js +161 -0
  7. package/dist/applications/cache.js.map +1 -0
  8. package/dist/applications/errors.d.ts +25 -0
  9. package/dist/applications/errors.d.ts.map +1 -0
  10. package/dist/applications/errors.js +31 -0
  11. package/dist/applications/errors.js.map +1 -0
  12. package/dist/applications/index.d.ts +17 -0
  13. package/dist/applications/index.d.ts.map +1 -0
  14. package/dist/applications/index.js +19 -0
  15. package/dist/applications/index.js.map +1 -0
  16. package/dist/applications/repository.d.ts +184 -0
  17. package/dist/applications/repository.d.ts.map +1 -0
  18. package/dist/applications/repository.js +367 -0
  19. package/dist/applications/repository.js.map +1 -0
  20. package/dist/applications/service.d.ts +160 -0
  21. package/dist/applications/service.d.ts.map +1 -0
  22. package/dist/applications/service.js +388 -0
  23. package/dist/applications/service.js.map +1 -0
  24. package/dist/applications/slugs.d.ts +61 -0
  25. package/dist/applications/slugs.d.ts.map +1 -0
  26. package/dist/applications/slugs.js +115 -0
  27. package/dist/applications/slugs.js.map +1 -0
  28. package/dist/applications/types.d.ts +129 -0
  29. package/dist/applications/types.d.ts.map +1 -0
  30. package/dist/applications/types.js +62 -0
  31. package/dist/applications/types.js.map +1 -0
  32. package/dist/auth/csrf.d.ts +71 -0
  33. package/dist/auth/csrf.d.ts.map +1 -0
  34. package/dist/auth/csrf.js +112 -0
  35. package/dist/auth/csrf.js.map +1 -0
  36. package/dist/auth/email-renderer.d.ts +37 -0
  37. package/dist/auth/email-renderer.d.ts.map +1 -0
  38. package/dist/auth/email-renderer.js +116 -0
  39. package/dist/auth/email-renderer.js.map +1 -0
  40. package/dist/auth/email-service.d.ts +154 -0
  41. package/dist/auth/email-service.d.ts.map +1 -0
  42. package/dist/auth/email-service.js +415 -0
  43. package/dist/auth/email-service.js.map +1 -0
  44. package/dist/auth/email-transport.d.ts +65 -0
  45. package/dist/auth/email-transport.d.ts.map +1 -0
  46. package/dist/auth/email-transport.js +82 -0
  47. package/dist/auth/email-transport.js.map +1 -0
  48. package/dist/auth/i18n.d.ts +81 -0
  49. package/dist/auth/i18n.d.ts.map +1 -0
  50. package/dist/auth/i18n.js +395 -0
  51. package/dist/auth/i18n.js.map +1 -0
  52. package/dist/auth/index.d.ts +28 -0
  53. package/dist/auth/index.d.ts.map +1 -0
  54. package/dist/auth/index.js +31 -0
  55. package/dist/auth/index.js.map +1 -0
  56. package/dist/auth/interaction-authority.d.ts +39 -0
  57. package/dist/auth/interaction-authority.d.ts.map +1 -0
  58. package/dist/auth/interaction-authority.js +30 -0
  59. package/dist/auth/interaction-authority.js.map +1 -0
  60. package/dist/auth/magic-link-session.d.ts +81 -0
  61. package/dist/auth/magic-link-session.d.ts.map +1 -0
  62. package/dist/auth/magic-link-session.js +183 -0
  63. package/dist/auth/magic-link-session.js.map +1 -0
  64. package/dist/auth/rate-limiter.d.ts +143 -0
  65. package/dist/auth/rate-limiter.d.ts.map +1 -0
  66. package/dist/auth/rate-limiter.js +220 -0
  67. package/dist/auth/rate-limiter.js.map +1 -0
  68. package/dist/auth/recovery-crypto.d.ts +34 -0
  69. package/dist/auth/recovery-crypto.d.ts.map +1 -0
  70. package/dist/auth/recovery-crypto.js +103 -0
  71. package/dist/auth/recovery-crypto.js.map +1 -0
  72. package/dist/auth/recovery-job-processor.d.ts +24 -0
  73. package/dist/auth/recovery-job-processor.d.ts.map +1 -0
  74. package/dist/auth/recovery-job-processor.js +123 -0
  75. package/dist/auth/recovery-job-processor.js.map +1 -0
  76. package/dist/auth/recovery-job-repository.d.ts +219 -0
  77. package/dist/auth/recovery-job-repository.d.ts.map +1 -0
  78. package/dist/auth/recovery-job-repository.js +340 -0
  79. package/dist/auth/recovery-job-repository.js.map +1 -0
  80. package/dist/auth/recovery-service.d.ts +27 -0
  81. package/dist/auth/recovery-service.d.ts.map +1 -0
  82. package/dist/auth/recovery-service.js +53 -0
  83. package/dist/auth/recovery-service.js.map +1 -0
  84. package/dist/auth/recovery-worker.d.ts +158 -0
  85. package/dist/auth/recovery-worker.d.ts.map +1 -0
  86. package/dist/auth/recovery-worker.js +306 -0
  87. package/dist/auth/recovery-worker.js.map +1 -0
  88. package/dist/auth/template-engine.d.ts +134 -0
  89. package/dist/auth/template-engine.d.ts.map +1 -0
  90. package/dist/auth/template-engine.js +225 -0
  91. package/dist/auth/template-engine.js.map +1 -0
  92. package/dist/auth/token-repository.d.ts +238 -0
  93. package/dist/auth/token-repository.d.ts.map +1 -0
  94. package/dist/auth/token-repository.js +475 -0
  95. package/dist/auth/token-repository.js.map +1 -0
  96. package/dist/auth/tokens.d.ts +45 -0
  97. package/dist/auth/tokens.d.ts.map +1 -0
  98. package/dist/auth/tokens.js +51 -0
  99. package/dist/auth/tokens.js.map +1 -0
  100. package/dist/cli/bootstrap.d.ts +55 -0
  101. package/dist/cli/bootstrap.d.ts.map +1 -0
  102. package/dist/cli/bootstrap.js +90 -0
  103. package/dist/cli/bootstrap.js.map +1 -0
  104. package/dist/cli/commands/health.d.ts +20 -0
  105. package/dist/cli/commands/health.d.ts.map +1 -0
  106. package/dist/cli/commands/health.js +80 -0
  107. package/dist/cli/commands/health.js.map +1 -0
  108. package/dist/cli/commands/init.d.ts +48 -0
  109. package/dist/cli/commands/init.d.ts.map +1 -0
  110. package/dist/cli/commands/init.js +349 -0
  111. package/dist/cli/commands/init.js.map +1 -0
  112. package/dist/cli/commands/migrate.d.ts +19 -0
  113. package/dist/cli/commands/migrate.d.ts.map +1 -0
  114. package/dist/cli/commands/migrate.js +88 -0
  115. package/dist/cli/commands/migrate.js.map +1 -0
  116. package/dist/cli/commands/seed.d.ts +19 -0
  117. package/dist/cli/commands/seed.d.ts.map +1 -0
  118. package/dist/cli/commands/seed.js +71 -0
  119. package/dist/cli/commands/seed.js.map +1 -0
  120. package/dist/cli/commands/user-2fa.d.ts +29 -0
  121. package/dist/cli/commands/user-2fa.d.ts.map +1 -0
  122. package/dist/cli/commands/user-2fa.js +113 -0
  123. package/dist/cli/commands/user-2fa.js.map +1 -0
  124. package/dist/cli/error-handler.d.ts +31 -0
  125. package/dist/cli/error-handler.d.ts.map +1 -0
  126. package/dist/cli/error-handler.js +65 -0
  127. package/dist/cli/error-handler.js.map +1 -0
  128. package/dist/cli/index.d.ts +48 -0
  129. package/dist/cli/index.d.ts.map +1 -0
  130. package/dist/cli/index.js +99 -0
  131. package/dist/cli/index.js.map +1 -0
  132. package/dist/cli/output.d.ts +94 -0
  133. package/dist/cli/output.d.ts.map +1 -0
  134. package/dist/cli/output.js +124 -0
  135. package/dist/cli/output.js.map +1 -0
  136. package/dist/cli/prompt.d.ts +48 -0
  137. package/dist/cli/prompt.d.ts.map +1 -0
  138. package/dist/cli/prompt.js +96 -0
  139. package/dist/cli/prompt.js.map +1 -0
  140. package/dist/clients/cache.d.ts +63 -0
  141. package/dist/clients/cache.d.ts.map +1 -0
  142. package/dist/clients/cache.js +160 -0
  143. package/dist/clients/cache.js.map +1 -0
  144. package/dist/clients/crypto.d.ts +69 -0
  145. package/dist/clients/crypto.d.ts.map +1 -0
  146. package/dist/clients/crypto.js +83 -0
  147. package/dist/clients/crypto.js.map +1 -0
  148. package/dist/clients/errors.d.ts +27 -0
  149. package/dist/clients/errors.d.ts.map +1 -0
  150. package/dist/clients/errors.js +33 -0
  151. package/dist/clients/errors.js.map +1 -0
  152. package/dist/clients/index.d.ts +19 -0
  153. package/dist/clients/index.d.ts.map +1 -0
  154. package/dist/clients/index.js +23 -0
  155. package/dist/clients/index.js.map +1 -0
  156. package/dist/clients/repository.d.ts +161 -0
  157. package/dist/clients/repository.d.ts.map +1 -0
  158. package/dist/clients/repository.js +318 -0
  159. package/dist/clients/repository.js.map +1 -0
  160. package/dist/clients/resolve-login-methods.d.ts +74 -0
  161. package/dist/clients/resolve-login-methods.d.ts.map +1 -0
  162. package/dist/clients/resolve-login-methods.js +68 -0
  163. package/dist/clients/resolve-login-methods.js.map +1 -0
  164. package/dist/clients/secret-repository.d.ts +109 -0
  165. package/dist/clients/secret-repository.d.ts.map +1 -0
  166. package/dist/clients/secret-repository.js +166 -0
  167. package/dist/clients/secret-repository.js.map +1 -0
  168. package/dist/clients/secret-service.d.ts +87 -0
  169. package/dist/clients/secret-service.d.ts.map +1 -0
  170. package/dist/clients/secret-service.js +204 -0
  171. package/dist/clients/secret-service.js.map +1 -0
  172. package/dist/clients/service.d.ts +158 -0
  173. package/dist/clients/service.d.ts.map +1 -0
  174. package/dist/clients/service.js +523 -0
  175. package/dist/clients/service.js.map +1 -0
  176. package/dist/clients/types.d.ts +214 -0
  177. package/dist/clients/types.d.ts.map +1 -0
  178. package/dist/clients/types.js +77 -0
  179. package/dist/clients/types.js.map +1 -0
  180. package/dist/clients/validators.d.ts +87 -0
  181. package/dist/clients/validators.d.ts.map +1 -0
  182. package/dist/clients/validators.js +164 -0
  183. package/dist/clients/validators.js.map +1 -0
  184. package/dist/config/index.d.ts +23 -0
  185. package/dist/config/index.d.ts.map +1 -0
  186. package/dist/config/index.js +52 -0
  187. package/dist/config/index.js.map +1 -0
  188. package/dist/config/schema.d.ts +35 -0
  189. package/dist/config/schema.d.ts.map +1 -0
  190. package/dist/config/schema.js +167 -0
  191. package/dist/config/schema.js.map +1 -0
  192. package/dist/custom-claims/cache.d.ts +48 -0
  193. package/dist/custom-claims/cache.d.ts.map +1 -0
  194. package/dist/custom-claims/cache.js +122 -0
  195. package/dist/custom-claims/cache.js.map +1 -0
  196. package/dist/custom-claims/errors.d.ts +25 -0
  197. package/dist/custom-claims/errors.d.ts.map +1 -0
  198. package/dist/custom-claims/errors.js +31 -0
  199. package/dist/custom-claims/errors.js.map +1 -0
  200. package/dist/custom-claims/index.d.ts +14 -0
  201. package/dist/custom-claims/index.d.ts.map +1 -0
  202. package/dist/custom-claims/index.js +17 -0
  203. package/dist/custom-claims/index.js.map +1 -0
  204. package/dist/custom-claims/repository.d.ts +147 -0
  205. package/dist/custom-claims/repository.d.ts.map +1 -0
  206. package/dist/custom-claims/repository.js +338 -0
  207. package/dist/custom-claims/repository.js.map +1 -0
  208. package/dist/custom-claims/service.d.ts +129 -0
  209. package/dist/custom-claims/service.d.ts.map +1 -0
  210. package/dist/custom-claims/service.js +296 -0
  211. package/dist/custom-claims/service.js.map +1 -0
  212. package/dist/custom-claims/types.d.ts +132 -0
  213. package/dist/custom-claims/types.d.ts.map +1 -0
  214. package/dist/custom-claims/types.js +61 -0
  215. package/dist/custom-claims/types.js.map +1 -0
  216. package/dist/custom-claims/validators.d.ts +61 -0
  217. package/dist/custom-claims/validators.d.ts.map +1 -0
  218. package/dist/custom-claims/validators.js +136 -0
  219. package/dist/custom-claims/validators.js.map +1 -0
  220. package/dist/index.d.ts +14 -0
  221. package/dist/index.d.ts.map +1 -0
  222. package/dist/index.js +91 -0
  223. package/dist/index.js.map +1 -0
  224. package/dist/lib/admin-permissions.d.ts +147 -0
  225. package/dist/lib/admin-permissions.d.ts.map +1 -0
  226. package/dist/lib/admin-permissions.js +261 -0
  227. package/dist/lib/admin-permissions.js.map +1 -0
  228. package/dist/lib/audit-log.d.ts +45 -0
  229. package/dist/lib/audit-log.d.ts.map +1 -0
  230. package/dist/lib/audit-log.js +79 -0
  231. package/dist/lib/audit-log.js.map +1 -0
  232. package/dist/lib/branding-assets.d.ts +47 -0
  233. package/dist/lib/branding-assets.d.ts.map +1 -0
  234. package/dist/lib/branding-assets.js +93 -0
  235. package/dist/lib/branding-assets.js.map +1 -0
  236. package/dist/lib/bulk-operations.d.ts +54 -0
  237. package/dist/lib/bulk-operations.d.ts.map +1 -0
  238. package/dist/lib/bulk-operations.js +201 -0
  239. package/dist/lib/bulk-operations.js.map +1 -0
  240. package/dist/lib/cursor.d.ts +110 -0
  241. package/dist/lib/cursor.d.ts.map +1 -0
  242. package/dist/lib/cursor.js +115 -0
  243. package/dist/lib/cursor.js.map +1 -0
  244. package/dist/lib/data-export.d.ts +67 -0
  245. package/dist/lib/data-export.d.ts.map +1 -0
  246. package/dist/lib/data-export.js +272 -0
  247. package/dist/lib/data-export.js.map +1 -0
  248. package/dist/lib/data-import-plan.d.ts +50 -0
  249. package/dist/lib/data-import-plan.d.ts.map +1 -0
  250. package/dist/lib/data-import-plan.js +235 -0
  251. package/dist/lib/data-import-plan.js.map +1 -0
  252. package/dist/lib/data-import.d.ts +276 -0
  253. package/dist/lib/data-import.d.ts.map +1 -0
  254. package/dist/lib/data-import.js +1694 -0
  255. package/dist/lib/data-import.js.map +1 -0
  256. package/dist/lib/database.d.ts +22 -0
  257. package/dist/lib/database.d.ts.map +1 -0
  258. package/dist/lib/database.js +103 -0
  259. package/dist/lib/database.js.map +1 -0
  260. package/dist/lib/entity-history.d.ts +52 -0
  261. package/dist/lib/entity-history.d.ts.map +1 -0
  262. package/dist/lib/entity-history.js +121 -0
  263. package/dist/lib/entity-history.js.map +1 -0
  264. package/dist/lib/etag.d.ts +92 -0
  265. package/dist/lib/etag.d.ts.map +1 -0
  266. package/dist/lib/etag.js +155 -0
  267. package/dist/lib/etag.js.map +1 -0
  268. package/dist/lib/image-validator.d.ts +44 -0
  269. package/dist/lib/image-validator.d.ts.map +1 -0
  270. package/dist/lib/image-validator.js +204 -0
  271. package/dist/lib/image-validator.js.map +1 -0
  272. package/dist/lib/logger.d.ts +15 -0
  273. package/dist/lib/logger.d.ts.map +1 -0
  274. package/dist/lib/logger.js +84 -0
  275. package/dist/lib/logger.js.map +1 -0
  276. package/dist/lib/migrator.d.ts +14 -0
  277. package/dist/lib/migrator.d.ts.map +1 -0
  278. package/dist/lib/migrator.js +34 -0
  279. package/dist/lib/migrator.js.map +1 -0
  280. package/dist/lib/redis.d.ts +5 -0
  281. package/dist/lib/redis.d.ts.map +1 -0
  282. package/dist/lib/redis.js +29 -0
  283. package/dist/lib/redis.js.map +1 -0
  284. package/dist/lib/runtime-paths.d.ts +38 -0
  285. package/dist/lib/runtime-paths.d.ts.map +1 -0
  286. package/dist/lib/runtime-paths.js +50 -0
  287. package/dist/lib/runtime-paths.js.map +1 -0
  288. package/dist/lib/session-tracking.d.ts +81 -0
  289. package/dist/lib/session-tracking.d.ts.map +1 -0
  290. package/dist/lib/session-tracking.js +145 -0
  291. package/dist/lib/session-tracking.js.map +1 -0
  292. package/dist/lib/signing-key-crypto.d.ts +53 -0
  293. package/dist/lib/signing-key-crypto.d.ts.map +1 -0
  294. package/dist/lib/signing-key-crypto.js +108 -0
  295. package/dist/lib/signing-key-crypto.js.map +1 -0
  296. package/dist/lib/signing-keys.d.ts +141 -0
  297. package/dist/lib/signing-keys.d.ts.map +1 -0
  298. package/dist/lib/signing-keys.js +206 -0
  299. package/dist/lib/signing-keys.js.map +1 -0
  300. package/dist/lib/stats.d.ts +83 -0
  301. package/dist/lib/stats.d.ts.map +1 -0
  302. package/dist/lib/stats.js +187 -0
  303. package/dist/lib/stats.js.map +1 -0
  304. package/dist/lib/super-admin-protection.d.ts +69 -0
  305. package/dist/lib/super-admin-protection.d.ts.map +1 -0
  306. package/dist/lib/super-admin-protection.js +102 -0
  307. package/dist/lib/super-admin-protection.js.map +1 -0
  308. package/dist/lib/system-config.d.ts +79 -0
  309. package/dist/lib/system-config.d.ts.map +1 -0
  310. package/dist/lib/system-config.js +159 -0
  311. package/dist/lib/system-config.js.map +1 -0
  312. package/dist/middleware/admin-auth.d.ts +100 -0
  313. package/dist/middleware/admin-auth.d.ts.map +1 -0
  314. package/dist/middleware/admin-auth.js +241 -0
  315. package/dist/middleware/admin-auth.js.map +1 -0
  316. package/dist/middleware/admin-cors.d.ts +41 -0
  317. package/dist/middleware/admin-cors.d.ts.map +1 -0
  318. package/dist/middleware/admin-cors.js +83 -0
  319. package/dist/middleware/admin-cors.js.map +1 -0
  320. package/dist/middleware/admin-mutation-audit.d.ts +9 -0
  321. package/dist/middleware/admin-mutation-audit.d.ts.map +1 -0
  322. package/dist/middleware/admin-mutation-audit.js +76 -0
  323. package/dist/middleware/admin-mutation-audit.js.map +1 -0
  324. package/dist/middleware/admin-rate-limiter.d.ts +56 -0
  325. package/dist/middleware/admin-rate-limiter.d.ts.map +1 -0
  326. package/dist/middleware/admin-rate-limiter.js +97 -0
  327. package/dist/middleware/admin-rate-limiter.js.map +1 -0
  328. package/dist/middleware/client-secret-hash.d.ts +34 -0
  329. package/dist/middleware/client-secret-hash.d.ts.map +1 -0
  330. package/dist/middleware/client-secret-hash.js +74 -0
  331. package/dist/middleware/client-secret-hash.js.map +1 -0
  332. package/dist/middleware/error-handler.d.ts +3 -0
  333. package/dist/middleware/error-handler.d.ts.map +1 -0
  334. package/dist/middleware/error-handler.js +93 -0
  335. package/dist/middleware/error-handler.js.map +1 -0
  336. package/dist/middleware/health.d.ts +3 -0
  337. package/dist/middleware/health.d.ts.map +1 -0
  338. package/dist/middleware/health.js +35 -0
  339. package/dist/middleware/health.js.map +1 -0
  340. package/dist/middleware/metrics.d.ts +40 -0
  341. package/dist/middleware/metrics.d.ts.map +1 -0
  342. package/dist/middleware/metrics.js +75 -0
  343. package/dist/middleware/metrics.js.map +1 -0
  344. package/dist/middleware/oidc-client-tenant.d.ts +37 -0
  345. package/dist/middleware/oidc-client-tenant.d.ts.map +1 -0
  346. package/dist/middleware/oidc-client-tenant.js +156 -0
  347. package/dist/middleware/oidc-client-tenant.js.map +1 -0
  348. package/dist/middleware/oidc-cors.d.ts +33 -0
  349. package/dist/middleware/oidc-cors.d.ts.map +1 -0
  350. package/dist/middleware/oidc-cors.js +68 -0
  351. package/dist/middleware/oidc-cors.js.map +1 -0
  352. package/dist/middleware/oidc-preflight-cors.d.ts +54 -0
  353. package/dist/middleware/oidc-preflight-cors.d.ts.map +1 -0
  354. package/dist/middleware/oidc-preflight-cors.js +267 -0
  355. package/dist/middleware/oidc-preflight-cors.js.map +1 -0
  356. package/dist/middleware/prompt-login-reset.d.ts +103 -0
  357. package/dist/middleware/prompt-login-reset.d.ts.map +1 -0
  358. package/dist/middleware/prompt-login-reset.js +204 -0
  359. package/dist/middleware/prompt-login-reset.js.map +1 -0
  360. package/dist/middleware/ready.d.ts +23 -0
  361. package/dist/middleware/ready.d.ts.map +1 -0
  362. package/dist/middleware/ready.js +60 -0
  363. package/dist/middleware/ready.js.map +1 -0
  364. package/dist/middleware/request-logger.d.ts +27 -0
  365. package/dist/middleware/request-logger.d.ts.map +1 -0
  366. package/dist/middleware/request-logger.js +46 -0
  367. package/dist/middleware/request-logger.js.map +1 -0
  368. package/dist/middleware/require-permission.d.ts +28 -0
  369. package/dist/middleware/require-permission.d.ts.map +1 -0
  370. package/dist/middleware/require-permission.js +63 -0
  371. package/dist/middleware/require-permission.js.map +1 -0
  372. package/dist/middleware/require-user-organization.d.ts +18 -0
  373. package/dist/middleware/require-user-organization.d.ts.map +1 -0
  374. package/dist/middleware/require-user-organization.js +53 -0
  375. package/dist/middleware/require-user-organization.js.map +1 -0
  376. package/dist/middleware/root-page.d.ts +62 -0
  377. package/dist/middleware/root-page.d.ts.map +1 -0
  378. package/dist/middleware/root-page.js +134 -0
  379. package/dist/middleware/root-page.js.map +1 -0
  380. package/dist/middleware/security-headers.d.ts +98 -0
  381. package/dist/middleware/security-headers.d.ts.map +1 -0
  382. package/dist/middleware/security-headers.js +159 -0
  383. package/dist/middleware/security-headers.js.map +1 -0
  384. package/dist/middleware/tenant-resolver.d.ts +37 -0
  385. package/dist/middleware/tenant-resolver.d.ts.map +1 -0
  386. package/dist/middleware/tenant-resolver.js +71 -0
  387. package/dist/middleware/tenant-resolver.js.map +1 -0
  388. package/dist/middleware/token-rate-limiter.d.ts +89 -0
  389. package/dist/middleware/token-rate-limiter.d.ts.map +1 -0
  390. package/dist/middleware/token-rate-limiter.js +189 -0
  391. package/dist/middleware/token-rate-limiter.js.map +1 -0
  392. package/dist/oidc/account-finder.d.ts +52 -0
  393. package/dist/oidc/account-finder.d.ts.map +1 -0
  394. package/dist/oidc/account-finder.js +134 -0
  395. package/dist/oidc/account-finder.js.map +1 -0
  396. package/dist/oidc/adapter-factory.d.ts +90 -0
  397. package/dist/oidc/adapter-factory.d.ts.map +1 -0
  398. package/dist/oidc/adapter-factory.js +165 -0
  399. package/dist/oidc/adapter-factory.js.map +1 -0
  400. package/dist/oidc/configuration.d.ts +155 -0
  401. package/dist/oidc/configuration.d.ts.map +1 -0
  402. package/dist/oidc/configuration.js +531 -0
  403. package/dist/oidc/configuration.js.map +1 -0
  404. package/dist/oidc/postgres-adapter.d.ts +159 -0
  405. package/dist/oidc/postgres-adapter.d.ts.map +1 -0
  406. package/dist/oidc/postgres-adapter.js +222 -0
  407. package/dist/oidc/postgres-adapter.js.map +1 -0
  408. package/dist/oidc/protocol-security-observer.d.ts +38 -0
  409. package/dist/oidc/protocol-security-observer.d.ts.map +1 -0
  410. package/dist/oidc/protocol-security-observer.js +93 -0
  411. package/dist/oidc/protocol-security-observer.js.map +1 -0
  412. package/dist/oidc/provider.d.ts +37 -0
  413. package/dist/oidc/provider.d.ts.map +1 -0
  414. package/dist/oidc/provider.js +71 -0
  415. package/dist/oidc/provider.js.map +1 -0
  416. package/dist/oidc/redis-adapter.d.ts +140 -0
  417. package/dist/oidc/redis-adapter.d.ts.map +1 -0
  418. package/dist/oidc/redis-adapter.js +344 -0
  419. package/dist/oidc/redis-adapter.js.map +1 -0
  420. package/dist/organizations/cache.d.ts +60 -0
  421. package/dist/organizations/cache.d.ts.map +1 -0
  422. package/dist/organizations/cache.js +157 -0
  423. package/dist/organizations/cache.js.map +1 -0
  424. package/dist/organizations/errors.d.ts +25 -0
  425. package/dist/organizations/errors.d.ts.map +1 -0
  426. package/dist/organizations/errors.js +31 -0
  427. package/dist/organizations/errors.js.map +1 -0
  428. package/dist/organizations/index.d.ts +15 -0
  429. package/dist/organizations/index.d.ts.map +1 -0
  430. package/dist/organizations/index.js +15 -0
  431. package/dist/organizations/index.js.map +1 -0
  432. package/dist/organizations/repository.d.ts +183 -0
  433. package/dist/organizations/repository.d.ts.map +1 -0
  434. package/dist/organizations/repository.js +354 -0
  435. package/dist/organizations/repository.js.map +1 -0
  436. package/dist/organizations/service.d.ts +168 -0
  437. package/dist/organizations/service.d.ts.map +1 -0
  438. package/dist/organizations/service.js +511 -0
  439. package/dist/organizations/service.js.map +1 -0
  440. package/dist/organizations/slugs.d.ts +57 -0
  441. package/dist/organizations/slugs.d.ts.map +1 -0
  442. package/dist/organizations/slugs.js +130 -0
  443. package/dist/organizations/slugs.js.map +1 -0
  444. package/dist/organizations/types.d.ts +146 -0
  445. package/dist/organizations/types.d.ts.map +1 -0
  446. package/dist/organizations/types.js +49 -0
  447. package/dist/organizations/types.js.map +1 -0
  448. package/dist/rbac/cache.d.ts +110 -0
  449. package/dist/rbac/cache.d.ts.map +1 -0
  450. package/dist/rbac/cache.js +271 -0
  451. package/dist/rbac/cache.js.map +1 -0
  452. package/dist/rbac/errors.d.ts +34 -0
  453. package/dist/rbac/errors.d.ts.map +1 -0
  454. package/dist/rbac/errors.js +43 -0
  455. package/dist/rbac/errors.js.map +1 -0
  456. package/dist/rbac/index.d.ts +17 -0
  457. package/dist/rbac/index.d.ts.map +1 -0
  458. package/dist/rbac/index.js +21 -0
  459. package/dist/rbac/index.js.map +1 -0
  460. package/dist/rbac/mapping-repository.d.ts +121 -0
  461. package/dist/rbac/mapping-repository.d.ts.map +1 -0
  462. package/dist/rbac/mapping-repository.js +224 -0
  463. package/dist/rbac/mapping-repository.js.map +1 -0
  464. package/dist/rbac/permission-repository.d.ts +100 -0
  465. package/dist/rbac/permission-repository.d.ts.map +1 -0
  466. package/dist/rbac/permission-repository.js +190 -0
  467. package/dist/rbac/permission-repository.js.map +1 -0
  468. package/dist/rbac/permission-service.d.ts +85 -0
  469. package/dist/rbac/permission-service.d.ts.map +1 -0
  470. package/dist/rbac/permission-service.js +179 -0
  471. package/dist/rbac/permission-service.js.map +1 -0
  472. package/dist/rbac/role-repository.d.ts +104 -0
  473. package/dist/rbac/role-repository.d.ts.map +1 -0
  474. package/dist/rbac/role-repository.js +202 -0
  475. package/dist/rbac/role-repository.js.map +1 -0
  476. package/dist/rbac/role-service.d.ts +111 -0
  477. package/dist/rbac/role-service.d.ts.map +1 -0
  478. package/dist/rbac/role-service.js +256 -0
  479. package/dist/rbac/role-service.js.map +1 -0
  480. package/dist/rbac/slugs.d.ts +116 -0
  481. package/dist/rbac/slugs.d.ts.map +1 -0
  482. package/dist/rbac/slugs.js +178 -0
  483. package/dist/rbac/slugs.js.map +1 -0
  484. package/dist/rbac/types.d.ts +187 -0
  485. package/dist/rbac/types.d.ts.map +1 -0
  486. package/dist/rbac/types.js +75 -0
  487. package/dist/rbac/types.js.map +1 -0
  488. package/dist/rbac/user-role-service.d.ts +101 -0
  489. package/dist/rbac/user-role-service.d.ts.map +1 -0
  490. package/dist/rbac/user-role-service.js +166 -0
  491. package/dist/rbac/user-role-service.js.map +1 -0
  492. package/dist/routes/applications.d.ts +40 -0
  493. package/dist/routes/applications.d.ts.map +1 -0
  494. package/dist/routes/applications.js +284 -0
  495. package/dist/routes/applications.js.map +1 -0
  496. package/dist/routes/audit.d.ts +31 -0
  497. package/dist/routes/audit.d.ts.map +1 -0
  498. package/dist/routes/audit.js +140 -0
  499. package/dist/routes/audit.js.map +1 -0
  500. package/dist/routes/branding.d.ts +17 -0
  501. package/dist/routes/branding.d.ts.map +1 -0
  502. package/dist/routes/branding.js +104 -0
  503. package/dist/routes/branding.js.map +1 -0
  504. package/dist/routes/bulk.d.ts +37 -0
  505. package/dist/routes/bulk.d.ts.map +1 -0
  506. package/dist/routes/bulk.js +94 -0
  507. package/dist/routes/bulk.js.map +1 -0
  508. package/dist/routes/clients.d.ts +44 -0
  509. package/dist/routes/clients.d.ts.map +1 -0
  510. package/dist/routes/clients.js +353 -0
  511. package/dist/routes/clients.js.map +1 -0
  512. package/dist/routes/config.d.ts +35 -0
  513. package/dist/routes/config.d.ts.map +1 -0
  514. package/dist/routes/config.js +115 -0
  515. package/dist/routes/config.js.map +1 -0
  516. package/dist/routes/custom-claims.d.ts +38 -0
  517. package/dist/routes/custom-claims.d.ts.map +1 -0
  518. package/dist/routes/custom-claims.js +208 -0
  519. package/dist/routes/custom-claims.js.map +1 -0
  520. package/dist/routes/exports.d.ts +21 -0
  521. package/dist/routes/exports.d.ts.map +1 -0
  522. package/dist/routes/exports.js +98 -0
  523. package/dist/routes/exports.js.map +1 -0
  524. package/dist/routes/imports.d.ts +18 -0
  525. package/dist/routes/imports.d.ts.map +1 -0
  526. package/dist/routes/imports.js +72 -0
  527. package/dist/routes/imports.js.map +1 -0
  528. package/dist/routes/interactions.d.ts +111 -0
  529. package/dist/routes/interactions.d.ts.map +1 -0
  530. package/dist/routes/interactions.js +1074 -0
  531. package/dist/routes/interactions.js.map +1 -0
  532. package/dist/routes/invitation.d.ts +31 -0
  533. package/dist/routes/invitation.d.ts.map +1 -0
  534. package/dist/routes/invitation.js +342 -0
  535. package/dist/routes/invitation.js.map +1 -0
  536. package/dist/routes/keys.d.ts +28 -0
  537. package/dist/routes/keys.d.ts.map +1 -0
  538. package/dist/routes/keys.js +91 -0
  539. package/dist/routes/keys.js.map +1 -0
  540. package/dist/routes/magic-link.d.ts +43 -0
  541. package/dist/routes/magic-link.d.ts.map +1 -0
  542. package/dist/routes/magic-link.js +264 -0
  543. package/dist/routes/magic-link.js.map +1 -0
  544. package/dist/routes/organizations.d.ts +38 -0
  545. package/dist/routes/organizations.d.ts.map +1 -0
  546. package/dist/routes/organizations.js +347 -0
  547. package/dist/routes/organizations.js.map +1 -0
  548. package/dist/routes/password-reset.d.ts +65 -0
  549. package/dist/routes/password-reset.d.ts.map +1 -0
  550. package/dist/routes/password-reset.js +493 -0
  551. package/dist/routes/password-reset.js.map +1 -0
  552. package/dist/routes/permissions.d.ts +33 -0
  553. package/dist/routes/permissions.d.ts.map +1 -0
  554. package/dist/routes/permissions.js +166 -0
  555. package/dist/routes/permissions.js.map +1 -0
  556. package/dist/routes/roles.d.ts +37 -0
  557. package/dist/routes/roles.d.ts.map +1 -0
  558. package/dist/routes/roles.js +222 -0
  559. package/dist/routes/roles.js.map +1 -0
  560. package/dist/routes/sessions.d.ts +37 -0
  561. package/dist/routes/sessions.d.ts.map +1 -0
  562. package/dist/routes/sessions.js +121 -0
  563. package/dist/routes/sessions.js.map +1 -0
  564. package/dist/routes/stats.d.ts +28 -0
  565. package/dist/routes/stats.d.ts.map +1 -0
  566. package/dist/routes/stats.js +65 -0
  567. package/dist/routes/stats.js.map +1 -0
  568. package/dist/routes/two-factor-admin.d.ts +54 -0
  569. package/dist/routes/two-factor-admin.d.ts.map +1 -0
  570. package/dist/routes/two-factor-admin.js +344 -0
  571. package/dist/routes/two-factor-admin.js.map +1 -0
  572. package/dist/routes/two-factor.d.ts +31 -0
  573. package/dist/routes/two-factor.d.ts.map +1 -0
  574. package/dist/routes/two-factor.js +595 -0
  575. package/dist/routes/two-factor.js.map +1 -0
  576. package/dist/routes/user-roles.d.ts +33 -0
  577. package/dist/routes/user-roles.d.ts.map +1 -0
  578. package/dist/routes/user-roles.js +129 -0
  579. package/dist/routes/user-roles.js.map +1 -0
  580. package/dist/routes/users.d.ts +61 -0
  581. package/dist/routes/users.d.ts.map +1 -0
  582. package/dist/routes/users.js +868 -0
  583. package/dist/routes/users.js.map +1 -0
  584. package/dist/security/decision-context.d.ts +52 -0
  585. package/dist/security/decision-context.d.ts.map +1 -0
  586. package/dist/security/decision-context.js +150 -0
  587. package/dist/security/decision-context.js.map +1 -0
  588. package/dist/security/decision-event.d.ts +128 -0
  589. package/dist/security/decision-event.d.ts.map +1 -0
  590. package/dist/security/decision-event.js +225 -0
  591. package/dist/security/decision-event.js.map +1 -0
  592. package/dist/security/transport-decision.d.ts +6 -0
  593. package/dist/security/transport-decision.d.ts.map +1 -0
  594. package/dist/security/transport-decision.js +37 -0
  595. package/dist/security/transport-decision.js.map +1 -0
  596. package/dist/server.d.ts +50 -0
  597. package/dist/server.d.ts.map +1 -0
  598. package/dist/server.js +491 -0
  599. package/dist/server.js.map +1 -0
  600. package/dist/two-factor/cache.d.ts +47 -0
  601. package/dist/two-factor/cache.d.ts.map +1 -0
  602. package/dist/two-factor/cache.js +122 -0
  603. package/dist/two-factor/cache.js.map +1 -0
  604. package/dist/two-factor/crypto.d.ts +41 -0
  605. package/dist/two-factor/crypto.d.ts.map +1 -0
  606. package/dist/two-factor/crypto.js +94 -0
  607. package/dist/two-factor/crypto.js.map +1 -0
  608. package/dist/two-factor/errors.d.ts +82 -0
  609. package/dist/two-factor/errors.d.ts.map +1 -0
  610. package/dist/two-factor/errors.js +112 -0
  611. package/dist/two-factor/errors.js.map +1 -0
  612. package/dist/two-factor/index.d.ts +18 -0
  613. package/dist/two-factor/index.d.ts.map +1 -0
  614. package/dist/two-factor/index.js +25 -0
  615. package/dist/two-factor/index.js.map +1 -0
  616. package/dist/two-factor/otp.d.ts +43 -0
  617. package/dist/two-factor/otp.d.ts.map +1 -0
  618. package/dist/two-factor/otp.js +57 -0
  619. package/dist/two-factor/otp.js.map +1 -0
  620. package/dist/two-factor/recovery.d.ts +45 -0
  621. package/dist/two-factor/recovery.d.ts.map +1 -0
  622. package/dist/two-factor/recovery.js +104 -0
  623. package/dist/two-factor/recovery.js.map +1 -0
  624. package/dist/two-factor/repository.d.ts +156 -0
  625. package/dist/two-factor/repository.d.ts.map +1 -0
  626. package/dist/two-factor/repository.js +251 -0
  627. package/dist/two-factor/repository.js.map +1 -0
  628. package/dist/two-factor/service.d.ts +232 -0
  629. package/dist/two-factor/service.d.ts.map +1 -0
  630. package/dist/two-factor/service.js +599 -0
  631. package/dist/two-factor/service.js.map +1 -0
  632. package/dist/two-factor/totp.d.ts +57 -0
  633. package/dist/two-factor/totp.d.ts.map +1 -0
  634. package/dist/two-factor/totp.js +96 -0
  635. package/dist/two-factor/totp.js.map +1 -0
  636. package/dist/two-factor/types.d.ts +152 -0
  637. package/dist/two-factor/types.d.ts.map +1 -0
  638. package/dist/two-factor/types.js +64 -0
  639. package/dist/two-factor/types.js.map +1 -0
  640. package/dist/users/cache.d.ts +49 -0
  641. package/dist/users/cache.d.ts.map +1 -0
  642. package/dist/users/cache.js +140 -0
  643. package/dist/users/cache.js.map +1 -0
  644. package/dist/users/claims.d.ts +67 -0
  645. package/dist/users/claims.d.ts.map +1 -0
  646. package/dist/users/claims.js +104 -0
  647. package/dist/users/claims.js.map +1 -0
  648. package/dist/users/errors.d.ts +25 -0
  649. package/dist/users/errors.d.ts.map +1 -0
  650. package/dist/users/errors.js +31 -0
  651. package/dist/users/errors.js.map +1 -0
  652. package/dist/users/gdpr.d.ts +110 -0
  653. package/dist/users/gdpr.d.ts.map +1 -0
  654. package/dist/users/gdpr.js +211 -0
  655. package/dist/users/gdpr.js.map +1 -0
  656. package/dist/users/index.d.ts +20 -0
  657. package/dist/users/index.d.ts.map +1 -0
  658. package/dist/users/index.js +19 -0
  659. package/dist/users/index.js.map +1 -0
  660. package/dist/users/password.d.ts +85 -0
  661. package/dist/users/password.d.ts.map +1 -0
  662. package/dist/users/password.js +138 -0
  663. package/dist/users/password.js.map +1 -0
  664. package/dist/users/repository.d.ts +263 -0
  665. package/dist/users/repository.d.ts.map +1 -0
  666. package/dist/users/repository.js +499 -0
  667. package/dist/users/repository.js.map +1 -0
  668. package/dist/users/service.d.ts +299 -0
  669. package/dist/users/service.d.ts.map +1 -0
  670. package/dist/users/service.js +698 -0
  671. package/dist/users/service.js.map +1 -0
  672. package/dist/users/types.d.ts +220 -0
  673. package/dist/users/types.d.ts.map +1 -0
  674. package/dist/users/types.js +77 -0
  675. package/dist/users/types.js.map +1 -0
  676. package/locales/default/en/common.json +10 -0
  677. package/locales/default/en/consent.json +13 -0
  678. package/locales/default/en/emails.json +17 -0
  679. package/locales/default/en/errors.json +21 -0
  680. package/locales/default/en/forgot-password.json +11 -0
  681. package/locales/default/en/invitation.json +18 -0
  682. package/locales/default/en/login.json +17 -0
  683. package/locales/default/en/logout.json +9 -0
  684. package/locales/default/en/magic-link.json +12 -0
  685. package/locales/default/en/reset-password.json +16 -0
  686. package/locales/default/en/two-factor.json +29 -0
  687. package/migrations/.gitkeep +0 -0
  688. package/migrations/001_extensions.sql +22 -0
  689. package/migrations/002_organizations.sql +43 -0
  690. package/migrations/003_applications.sql +50 -0
  691. package/migrations/004_clients.sql +74 -0
  692. package/migrations/005_users.sql +119 -0
  693. package/migrations/006_roles_permissions.sql +80 -0
  694. package/migrations/007_custom_claims.sql +55 -0
  695. package/migrations/008_config.sql +51 -0
  696. package/migrations/009_audit_log.sql +31 -0
  697. package/migrations/010_oidc_adapter.sql +34 -0
  698. package/migrations/011_seed.sql +53 -0
  699. package/migrations/012_two_factor.sql +88 -0
  700. package/migrations/013_client_secret_sha256.sql +22 -0
  701. package/migrations/014_login_methods.sql +34 -0
  702. package/migrations/015_signing_key_encryption.sql +20 -0
  703. package/migrations/016_failed_login_count.sql +27 -0
  704. package/migrations/017_audit_retention.sql +11 -0
  705. package/migrations/018_admin_api_enhancements.sql +78 -0
  706. package/migrations/019_invitation_details.sql +27 -0
  707. package/migrations/020_two_factor_admin_permission.sql +108 -0
  708. package/migrations/021_auth_recovery_jobs.sql +74 -0
  709. package/migrations/022_recovery_artifact_ownership.sql +25 -0
  710. package/migrations/023_magic_link_authority.sql +39 -0
  711. package/package.json +106 -0
  712. package/templates/default/emails/invitation.hbs +39 -0
  713. package/templates/default/emails/invitation.txt.hbs +18 -0
  714. package/templates/default/emails/magic-link.hbs +30 -0
  715. package/templates/default/emails/magic-link.txt.hbs +11 -0
  716. package/templates/default/emails/otp-code.hbs +31 -0
  717. package/templates/default/emails/otp-code.txt.hbs +15 -0
  718. package/templates/default/emails/password-changed.hbs +24 -0
  719. package/templates/default/emails/password-changed.txt.hbs +7 -0
  720. package/templates/default/emails/password-reset.hbs +30 -0
  721. package/templates/default/emails/password-reset.txt.hbs +11 -0
  722. package/templates/default/emails/welcome.hbs +25 -0
  723. package/templates/default/emails/welcome.txt.hbs +9 -0
  724. package/templates/default/layouts/main.hbs +49 -0
  725. package/templates/default/pages/accept-invite.hbs +25 -0
  726. package/templates/default/pages/consent.hbs +27 -0
  727. package/templates/default/pages/error.hbs +15 -0
  728. package/templates/default/pages/forgot-password.hbs +21 -0
  729. package/templates/default/pages/invite-expired.hbs +6 -0
  730. package/templates/default/pages/invite-success.hbs +9 -0
  731. package/templates/default/pages/login.hbs +108 -0
  732. package/templates/default/pages/logout-success.hbs +5 -0
  733. package/templates/default/pages/logout.hbs +24 -0
  734. package/templates/default/pages/magic-link-sent.hbs +10 -0
  735. package/templates/default/pages/magic-link-success.hbs +17 -0
  736. package/templates/default/pages/reset-password.hbs +20 -0
  737. package/templates/default/pages/reset-success.hbs +9 -0
  738. package/templates/default/pages/two-factor-setup.hbs +65 -0
  739. package/templates/default/pages/two-factor-verify.hbs +77 -0
  740. package/templates/default/partials/flash-messages.hbs +10 -0
  741. package/templates/default/partials/footer.hbs +4 -0
  742. package/templates/default/partials/header.hbs +8 -0
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Redis-based sliding window rate limiter.
3
+ *
4
+ * Uses INCR + EXPIRE for atomic counter management. Each action type
5
+ * (login, magic link, password reset) has its own key format and
6
+ * configurable limits loaded from system_config with sensible defaults.
7
+ *
8
+ * Graceful degradation: if Redis is unavailable, requests are ALLOWED
9
+ * with a warning log — we never block legitimate users due to Redis failure.
10
+ *
11
+ * Key format: ratelimit:{action}:{org_id}:{identifier_hash}
12
+ *
13
+ * @example
14
+ * const key = buildLoginRateLimitKey(orgId, ip, email);
15
+ * const config = await loadLoginRateLimitConfig();
16
+ * const result = await checkRateLimit(key, config);
17
+ * if (!result.allowed) {
18
+ * ctx.status = 429;
19
+ * ctx.set('Retry-After', String(result.retryAfter));
20
+ * }
21
+ */
22
+ import crypto from 'node:crypto';
23
+ import { getRedis } from '../lib/redis.js';
24
+ import { getSystemConfigNumber } from '../lib/system-config.js';
25
+ import { logger } from '../lib/logger.js';
26
+ // ---------------------------------------------------------------------------
27
+ // Rate limit check
28
+ // ---------------------------------------------------------------------------
29
+ /**
30
+ * Check if a request is within the rate limit for the given key.
31
+ *
32
+ * Uses Redis INCR + conditional EXPIRE for atomic counter management:
33
+ * 1. INCR the key (creates it at 1 if new)
34
+ * 2. If TTL is -1 (no expiry), set EXPIRE to windowSeconds
35
+ * 3. Compare count against max — reject if exceeded
36
+ *
37
+ * On Redis failure, returns allowed: true with a warning log.
38
+ *
39
+ * @param key - Rate limit key (use a build*Key function to construct)
40
+ * @param config - Rate limit configuration (max requests + window)
41
+ * @returns Rate limit result with allowed status and metadata
42
+ */
43
+ export async function checkRateLimit(key, config) {
44
+ try {
45
+ return await executeRateLimit(key, config);
46
+ }
47
+ catch (error) {
48
+ // Graceful degradation: allow request on Redis failure
49
+ logger.warn({ error, key }, 'Rate limiter Redis error — allowing request');
50
+ return {
51
+ allowed: true,
52
+ remaining: config.max,
53
+ resetAt: new Date(Date.now() + config.windowSeconds * 1000),
54
+ retryAfter: 0,
55
+ };
56
+ }
57
+ }
58
+ /**
59
+ * Check a security-critical limit without allowing Redis failure to bypass the boundary.
60
+ *
61
+ * @param key - Privacy-safe, domain-separated Redis key.
62
+ * @param config - Maximum attempts and fixed window.
63
+ * @returns Current limit decision.
64
+ * @throws When Redis cannot durably increment and expire the attempt counter.
65
+ */
66
+ export async function checkRateLimitStrict(key, config) {
67
+ return executeRateLimit(key, config);
68
+ }
69
+ /** Execute the shared Redis counter algorithm without selecting a failure policy. */
70
+ async function executeRateLimit(key, config) {
71
+ const redis = getRedis();
72
+ const count = await redis.incr(key);
73
+ if (count === 1)
74
+ await redis.expire(key, config.windowSeconds);
75
+ const ttl = await redis.ttl(key);
76
+ if (ttl === -1)
77
+ await redis.expire(key, config.windowSeconds);
78
+ const effectiveTtl = ttl > 0 ? ttl : config.windowSeconds;
79
+ const resetAt = new Date(Date.now() + effectiveTtl * 1_000);
80
+ return count > config.max
81
+ ? { allowed: false, remaining: 0, resetAt, retryAfter: effectiveTtl }
82
+ : { allowed: true, remaining: config.max - count, resetAt, retryAfter: 0 };
83
+ }
84
+ // ---------------------------------------------------------------------------
85
+ // Rate limit reset
86
+ // ---------------------------------------------------------------------------
87
+ /**
88
+ * Reset the rate limit counter for a key.
89
+ *
90
+ * Called after successful authentication to clear the counter,
91
+ * allowing the user to make fresh attempts if they log out and back in.
92
+ *
93
+ * @param key - Rate limit key to reset
94
+ */
95
+ export async function resetRateLimit(key) {
96
+ try {
97
+ const redis = getRedis();
98
+ await redis.del(key);
99
+ }
100
+ catch (error) {
101
+ // Non-critical — log and continue
102
+ logger.warn({ error, key }, 'Failed to reset rate limit counter');
103
+ }
104
+ }
105
+ // ---------------------------------------------------------------------------
106
+ // Key builders
107
+ // ---------------------------------------------------------------------------
108
+ /**
109
+ * Hash an identifier for use in rate limit keys.
110
+ * Uses SHA-256 to normalize variable-length inputs into fixed-length keys
111
+ * and prevent PII from appearing in Redis key names.
112
+ *
113
+ * @param value - The raw identifier to hash
114
+ * @returns First 16 hex chars of SHA-256 (64-bit — enough for key uniqueness)
115
+ */
116
+ function hashIdentifier(value) {
117
+ return crypto.createHash('sha256').update(value).digest('hex').slice(0, 16);
118
+ }
119
+ /**
120
+ * Build a rate limit key for login attempts.
121
+ * Combines IP + email to rate-limit per user per source IP.
122
+ *
123
+ * Format: ratelimit:login:{org_id}:{sha256(ip + email)[:16]}
124
+ *
125
+ * @param orgId - Organization UUID
126
+ * @param ip - Client IP address
127
+ * @param email - Email address being attempted
128
+ * @returns Rate limit key string
129
+ */
130
+ export function buildLoginRateLimitKey(orgId, ip, email) {
131
+ return `ratelimit:login:${orgId}:${hashIdentifier(ip + email)}`;
132
+ }
133
+ /**
134
+ * Build a rate limit key for magic link requests.
135
+ * Rate-limits per email to prevent spam.
136
+ *
137
+ * Format: ratelimit:magic:{org_id}:{sha256(email)[:16]}
138
+ *
139
+ * @param orgId - Organization UUID
140
+ * @param email - Email address requesting magic link
141
+ * @returns Rate limit key string
142
+ */
143
+ export function buildMagicLinkRateLimitKey(orgId, email) {
144
+ return `ratelimit:magic:${orgId}:${hashIdentifier(email)}`;
145
+ }
146
+ /**
147
+ * Build the callback-attempt key from tenant, direct socket peer, and protected artifact digest.
148
+ *
149
+ * @param orgId - Route organization UUID.
150
+ * @param socketPeer - Direct TCP peer rather than a caller-controlled forwarding header.
151
+ * @param artifactDigest - Domain-separated keyed digest of the presented artifact.
152
+ * @returns Privacy-safe Redis key with isolated tenant, peer, and artifact budgets.
153
+ */
154
+ export function buildMagicLinkCallbackRateLimitKey(orgId, socketPeer, artifactDigest) {
155
+ return `ratelimit:magic-callback:${orgId}:${hashIdentifier(socketPeer)}:${artifactDigest}`;
156
+ }
157
+ /**
158
+ * Build a rate limit key for password reset requests.
159
+ * Rate-limits per email to prevent abuse.
160
+ *
161
+ * Format: ratelimit:reset:{org_id}:{sha256(email)[:16]}
162
+ *
163
+ * @param orgId - Organization UUID
164
+ * @param email - Email address requesting password reset
165
+ * @returns Rate limit key string
166
+ */
167
+ /**
168
+ * Build a generic rate limit key for custom actions (e.g., 2FA verification, OTP resend).
169
+ *
170
+ * @param action - Action identifier (e.g., '2fa_verify', '2fa_resend')
171
+ * @param orgId - Organization UUID
172
+ * @param identifier - User-specific identifier (e.g., userId)
173
+ * @returns Redis key string
174
+ */
175
+ export function buildRateLimitKey(action, orgId, identifier) {
176
+ return `ratelimit:${action}:${orgId}:${hashIdentifier(identifier)}`;
177
+ }
178
+ export function buildPasswordResetRateLimitKey(orgId, email) {
179
+ return `ratelimit:reset:${orgId}:${hashIdentifier(email)}`;
180
+ }
181
+ // ---------------------------------------------------------------------------
182
+ // Config loaders
183
+ // ---------------------------------------------------------------------------
184
+ /**
185
+ * Load login rate limit configuration from system_config.
186
+ *
187
+ * @returns Rate limit config with max attempts and window duration
188
+ */
189
+ export async function loadLoginRateLimitConfig() {
190
+ const [max, windowSeconds] = await Promise.all([
191
+ getSystemConfigNumber('rate_limit_login_max', 10),
192
+ getSystemConfigNumber('rate_limit_login_window', 900),
193
+ ]);
194
+ return { max, windowSeconds };
195
+ }
196
+ /**
197
+ * Load magic link rate limit configuration from system_config.
198
+ *
199
+ * @returns Rate limit config with max requests and window duration
200
+ */
201
+ export async function loadMagicLinkRateLimitConfig() {
202
+ const [max, windowSeconds] = await Promise.all([
203
+ getSystemConfigNumber('rate_limit_magic_link_max', 5),
204
+ getSystemConfigNumber('rate_limit_magic_link_window', 900),
205
+ ]);
206
+ return { max, windowSeconds };
207
+ }
208
+ /**
209
+ * Load password reset rate limit configuration from system_config.
210
+ *
211
+ * @returns Rate limit config with max requests and window duration
212
+ */
213
+ export async function loadPasswordResetRateLimitConfig() {
214
+ const [max, windowSeconds] = await Promise.all([
215
+ getSystemConfigNumber('rate_limit_password_reset_max', 5),
216
+ getSystemConfigNumber('rate_limit_password_reset_window', 900),
217
+ ]);
218
+ return { max, windowSeconds };
219
+ }
220
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/auth/rate-limiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /** Cryptographic protection for durable account-recovery work. */
2
+ import type { ProtectedRecoveryAddress, RecoveryJobType } from './recovery-job-repository.js';
3
+ /** Public authority fields used to identify one recovery operation. */
4
+ export interface RecoveryRequestAuthority {
5
+ /** Resolved tenant UUID. */
6
+ readonly organizationId: string;
7
+ /** Closed recovery operation. */
8
+ readonly jobType: RecoveryJobType;
9
+ /** OIDC interaction binding for magic links. */
10
+ readonly interactionUid: string | null;
11
+ }
12
+ /** Durable authority fields authenticated with every protected address. */
13
+ export interface RecoveryAddressAuthority extends RecoveryRequestAuthority {
14
+ /** Keyed request identity persisted beside the encrypted address. */
15
+ readonly idempotencyDigest: string;
16
+ }
17
+ /** Normalize and validate a public recovery email address. */
18
+ export declare function normalizeRecoveryAddress(address: string): string;
19
+ /** Encrypt a normalized recovery address with the active rotating cookie key. */
20
+ export declare function protectRecoveryAddress(address: string, authority: RecoveryAddressAuthority): ProtectedRecoveryAddress;
21
+ /** Decrypt and authenticate a protected recovery address using the retained key ring. */
22
+ export declare function revealRecoveryAddress(protectedAddress: ProtectedRecoveryAddress, authority: RecoveryAddressAuthority): string;
23
+ /** Derive a non-reversible idempotency digest for one admitted public action. */
24
+ export declare function recoveryIdempotencyDigest(authority: RecoveryRequestAuthority, actionNonce: string): string;
25
+ /** Derive the stable unpredictable plaintext token owned by one durable job. */
26
+ export declare function recoveryArtifactToken(jobId: string, jobType: RecoveryJobType, addressKeyId: string): string;
27
+ /**
28
+ * Derive a non-reversible callback identity without retaining the presented bearer artifact.
29
+ *
30
+ * @param artifact - Plaintext callback artifact held only for the current request.
31
+ * @returns A short keyed digest safe for an ephemeral rate-limit key.
32
+ */
33
+ export declare function magicLinkCallbackArtifactDigest(artifact: string): string;
34
+ //# sourceMappingURL=recovery-crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-crypto.d.ts","sourceRoot":"","sources":["../../src/auth/recovery-crypto.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAYlE,OAAO,KAAK,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAS9F,uEAAuE;AACvE,MAAM,WAAW,wBAAwB;IACvC,4BAA4B;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,iCAAiC;IACjC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,gDAAgD;IAChD,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED,2EAA2E;AAC3E,MAAM,WAAW,wBAAyB,SAAQ,wBAAwB;IACxE,qEAAqE;IACrE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC;AAED,8DAA8D;AAC9D,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhE;AAsBD,iFAAiF;AACjF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,wBAAwB,GAClC,wBAAwB,CAkB1B;AAED,yFAAyF;AACzF,wBAAgB,qBAAqB,CACnC,gBAAgB,EAAE,wBAAwB,EAC1C,SAAS,EAAE,wBAAwB,GAClC,MAAM,CAqBR;AAED,iFAAiF;AACjF,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,wBAAwB,EACnC,WAAW,EAAE,MAAM,GAClB,MAAM,CAOR;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,MAAM,GACnB,MAAM,CAQR;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxE"}
@@ -0,0 +1,103 @@
1
+ /** Cryptographic protection for durable account-recovery work. */
2
+ import { createCipheriv, createDecipheriv, createHash, createHmac, hkdfSync, randomBytes, } from 'node:crypto';
3
+ import { z } from 'zod';
4
+ import { config } from '../config/index.js';
5
+ const ADDRESS_CONTEXT = 'porta/recovery-address/v1';
6
+ const IDEMPOTENCY_CONTEXT = 'porta/recovery-idempotency/v1';
7
+ const TOKEN_CONTEXT = 'porta/recovery-token/v1';
8
+ const CALLBACK_CONTEXT = 'porta/magic-link-callback/v1';
9
+ const ALGORITHM = 'aes-256-gcm';
10
+ const addressSchema = z.string().trim().toLowerCase().email().max(255);
11
+ /** Normalize and validate a public recovery email address. */
12
+ export function normalizeRecoveryAddress(address) {
13
+ return addressSchema.parse(address);
14
+ }
15
+ function deriveKey(secret, context) {
16
+ return Buffer.from(hkdfSync('sha256', Buffer.from(secret), Buffer.alloc(0), context, 32));
17
+ }
18
+ function keyId(key) {
19
+ return createHash('sha256').update(key).digest('base64url').slice(0, 22);
20
+ }
21
+ function aad(authority) {
22
+ return Buffer.from(JSON.stringify([
23
+ ADDRESS_CONTEXT,
24
+ authority.organizationId,
25
+ authority.jobType,
26
+ authority.interactionUid,
27
+ authority.idempotencyDigest,
28
+ ]));
29
+ }
30
+ /** Encrypt a normalized recovery address with the active rotating cookie key. */
31
+ export function protectRecoveryAddress(address, authority) {
32
+ const normalized = normalizeRecoveryAddress(address);
33
+ const key = deriveKey(config.cookieKeys[0], ADDRESS_CONTEXT);
34
+ const iv = randomBytes(12);
35
+ const cipher = createCipheriv(ALGORITHM, key, iv);
36
+ cipher.setAAD(aad(authority));
37
+ const encoded = Buffer.from(normalized, 'utf8');
38
+ if (encoded.length > 510)
39
+ throw new Error('Normalized recovery address is too large');
40
+ const padded = randomBytes(512);
41
+ padded.writeUInt16BE(encoded.length, 0);
42
+ encoded.copy(padded, 2);
43
+ const ciphertext = Buffer.concat([cipher.update(padded), cipher.final()]);
44
+ return {
45
+ ciphertext: ciphertext.toString('base64url'),
46
+ iv: iv.toString('base64url'),
47
+ tag: cipher.getAuthTag().toString('base64url'),
48
+ keyId: keyId(key),
49
+ };
50
+ }
51
+ /** Decrypt and authenticate a protected recovery address using the retained key ring. */
52
+ export function revealRecoveryAddress(protectedAddress, authority) {
53
+ for (const secret of config.cookieKeys) {
54
+ const key = deriveKey(secret, ADDRESS_CONTEXT);
55
+ if (keyId(key) !== protectedAddress.keyId)
56
+ continue;
57
+ const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(protectedAddress.iv, 'base64url'));
58
+ decipher.setAAD(aad(authority));
59
+ decipher.setAuthTag(Buffer.from(protectedAddress.tag, 'base64url'));
60
+ const padded = Buffer.concat([
61
+ decipher.update(Buffer.from(protectedAddress.ciphertext, 'base64url')),
62
+ decipher.final(),
63
+ ]);
64
+ if (padded.length !== 512)
65
+ throw new Error('Protected recovery address has invalid length');
66
+ const length = padded.readUInt16BE(0);
67
+ if (length > 510)
68
+ throw new Error('Protected recovery address has invalid content');
69
+ return normalizeRecoveryAddress(padded.subarray(2, 2 + length).toString('utf8'));
70
+ }
71
+ throw new Error('Protected recovery address key is unavailable');
72
+ }
73
+ /** Derive a non-reversible idempotency digest for one admitted public action. */
74
+ export function recoveryIdempotencyDigest(authority, actionNonce) {
75
+ const key = deriveKey(config.cookieKeys[0], IDEMPOTENCY_CONTEXT);
76
+ return createHmac('sha256', key)
77
+ .update(JSON.stringify([authority.organizationId, authority.jobType, authority.interactionUid]))
78
+ .update('\0')
79
+ .update(actionNonce)
80
+ .digest('hex');
81
+ }
82
+ /** Derive the stable unpredictable plaintext token owned by one durable job. */
83
+ export function recoveryArtifactToken(jobId, jobType, addressKeyId) {
84
+ const secret = config.cookieKeys.find((candidate) => {
85
+ const addressKey = deriveKey(candidate, ADDRESS_CONTEXT);
86
+ return keyId(addressKey) === addressKeyId;
87
+ });
88
+ if (!secret)
89
+ throw new Error('Recovery artifact key is unavailable');
90
+ const key = deriveKey(secret, TOKEN_CONTEXT);
91
+ return createHmac('sha256', key).update(jobType).update('\0').update(jobId).digest('base64url');
92
+ }
93
+ /**
94
+ * Derive a non-reversible callback identity without retaining the presented bearer artifact.
95
+ *
96
+ * @param artifact - Plaintext callback artifact held only for the current request.
97
+ * @returns A short keyed digest safe for an ephemeral rate-limit key.
98
+ */
99
+ export function magicLinkCallbackArtifactDigest(artifact) {
100
+ const key = deriveKey(config.cookieKeys[0], CALLBACK_CONTEXT);
101
+ return createHmac('sha256', key).update(artifact).digest('base64url').slice(0, 22);
102
+ }
103
+ //# sourceMappingURL=recovery-crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-crypto.js","sourceRoot":"","sources":["../../src/auth/recovery-crypto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /** Account-specific processing for durable recovery jobs. */
2
+ import type { ClaimedRecoveryJob } from './recovery-job-repository.js';
3
+ import { type RecoveryJobProcessingResult, type RecoveryJobProcessor } from './recovery-worker.js';
4
+ import type { InteractionAuthorityResolver } from './interaction-authority.js';
5
+ /** Concrete tenant-scoped processor for magic-link and password-reset work. */
6
+ export declare class AccountRecoveryJobProcessor implements RecoveryJobProcessor {
7
+ protected readonly interactionAuthority?: InteractionAuthorityResolver | undefined;
8
+ /**
9
+ * Create a processor with the provider-owned interaction boundary used by magic-link work.
10
+ *
11
+ * @param interactionAuthority - Live interaction resolver. Password-reset jobs do not use it.
12
+ */
13
+ constructor(interactionAuthority?: InteractionAuthorityResolver | undefined);
14
+ /** Resolve eligibility, create one artifact, and deliver its stable link. */
15
+ process(job: ClaimedRecoveryJob): Promise<RecoveryJobProcessingResult>;
16
+ }
17
+ /**
18
+ * Create the production account-recovery processor.
19
+ *
20
+ * @param interactionAuthority - Live provider authority for interaction-bound magic links.
21
+ * @returns The account-independent processor used by the durable worker.
22
+ */
23
+ export declare function createAccountRecoveryJobProcessor(interactionAuthority?: InteractionAuthorityResolver): RecoveryJobProcessor;
24
+ //# sourceMappingURL=recovery-job-processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-job-processor.d.ts","sourceRoot":"","sources":["../../src/auth/recovery-job-processor.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAW7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAE/E,+EAA+E;AAC/E,qBAAa,2BAA4B,YAAW,oBAAoB;IAMnD,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,4BAA4B;IALzF;;;;OAIG;IACH,YAAsC,oBAAoB,CAAC,EAAE,4BAA4B,YAAA,EAAI;IAE7F,6EAA6E;IAChE,OAAO,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,2BAA2B,CAAC,CA4FlF;CACF;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,oBAAoB,CAAC,EAAE,4BAA4B,GAClD,oBAAoB,CAEtB"}
@@ -0,0 +1,123 @@
1
+ /** Account-specific processing for durable recovery jobs. */
2
+ import { config } from '../config/index.js';
3
+ import { writeAuditLog } from '../lib/audit-log.js';
4
+ import { getSystemConfigNumber } from '../lib/system-config.js';
5
+ import { getOrganizationById } from '../organizations/service.js';
6
+ import { getUserByEmail } from '../users/service.js';
7
+ import { sendRecoveryEmailStrict } from './email-service.js';
8
+ import { recoveryArtifactToken, revealRecoveryAddress } from './recovery-crypto.js';
9
+ import { ensureRecoveryJobToken } from './token-repository.js';
10
+ import { hashToken } from './tokens.js';
11
+ import { RecoveryJobProcessingError, } from './recovery-worker.js';
12
+ /** Concrete tenant-scoped processor for magic-link and password-reset work. */
13
+ export class AccountRecoveryJobProcessor {
14
+ interactionAuthority;
15
+ /**
16
+ * Create a processor with the provider-owned interaction boundary used by magic-link work.
17
+ *
18
+ * @param interactionAuthority - Live interaction resolver. Password-reset jobs do not use it.
19
+ */
20
+ constructor(interactionAuthority) {
21
+ this.interactionAuthority = interactionAuthority;
22
+ }
23
+ /** Resolve eligibility, create one artifact, and deliver its stable link. */
24
+ async process(job) {
25
+ let address;
26
+ try {
27
+ address = revealRecoveryAddress(job.protectedAddress, {
28
+ organizationId: job.organizationId,
29
+ jobType: job.jobType,
30
+ interactionUid: job.interactionUid,
31
+ idempotencyDigest: job.idempotencyDigest,
32
+ });
33
+ }
34
+ catch {
35
+ throw new RecoveryJobProcessingError('invalid_protected_input', false);
36
+ }
37
+ let organization;
38
+ let user;
39
+ try {
40
+ organization = await getOrganizationById(job.organizationId);
41
+ user = await getUserByEmail(job.organizationId, address);
42
+ }
43
+ catch {
44
+ throw new RecoveryJobProcessingError('database_unavailable', true);
45
+ }
46
+ if (!organization || organization.status !== 'active' || !user || user.status !== 'active') {
47
+ return 'no_op';
48
+ }
49
+ let plaintext;
50
+ try {
51
+ plaintext = recoveryArtifactToken(job.id, job.jobType, job.protectedAddress.keyId);
52
+ const ttlSeconds = await getSystemConfigNumber(job.jobType === 'magic_link' ? 'magic_link_ttl' : 'password_reset_ttl', job.jobType === 'magic_link' ? 900 : 3_600);
53
+ const artifactInput = {
54
+ recoveryJobId: job.id,
55
+ userId: user.id,
56
+ tokenHash: hashToken(plaintext),
57
+ expiresAt: new Date(Date.now() + ttlSeconds * 1_000),
58
+ };
59
+ let artifact;
60
+ if (job.jobType === 'magic_link') {
61
+ const liveAuthority = job.interactionUid
62
+ ? await this.interactionAuthority?.resolve(job.interactionUid)
63
+ : null;
64
+ if (job.interactionUid && !liveAuthority)
65
+ return 'no_op';
66
+ artifact = await ensureRecoveryJobToken({
67
+ ...artifactInput,
68
+ table: 'magic_link_tokens',
69
+ organizationId: job.organizationId,
70
+ interactionUid: job.interactionUid,
71
+ clientId: liveAuthority?.clientId ?? null,
72
+ });
73
+ }
74
+ else {
75
+ artifact = await ensureRecoveryJobToken({
76
+ ...artifactInput,
77
+ table: 'password_reset_tokens',
78
+ });
79
+ }
80
+ if (artifact === 'superseded')
81
+ return 'no_op';
82
+ }
83
+ catch {
84
+ throw new RecoveryJobProcessingError('database_unavailable', true);
85
+ }
86
+ const base = `${config.issuerBaseUrl}/${organization.slug}/auth`;
87
+ const recoveryUrl = job.jobType === 'magic_link'
88
+ ? `${base}/magic-link/${plaintext}${job.interactionUid ? `?interaction=${encodeURIComponent(job.interactionUid)}` : ''}`
89
+ : `${base}/reset-password/${plaintext}`;
90
+ try {
91
+ await sendRecoveryEmailStrict({
92
+ type: job.jobType,
93
+ user,
94
+ organization,
95
+ recoveryUrl,
96
+ locale: user.locale ?? organization.defaultLocale,
97
+ messageId: `<recovery-${job.id}@porta.invalid>`,
98
+ });
99
+ }
100
+ catch {
101
+ throw new RecoveryJobProcessingError('smtp_outcome_unknown', true);
102
+ }
103
+ void writeAuditLog({
104
+ organizationId: organization.id,
105
+ userId: user.id,
106
+ eventType: job.jobType === 'magic_link' ? 'user.magic_link.sent' : 'user.password_reset.requested',
107
+ eventCategory: 'authentication',
108
+ description: 'Recovery message accepted for delivery',
109
+ metadata: { recoveryType: job.jobType },
110
+ });
111
+ return 'completed';
112
+ }
113
+ }
114
+ /**
115
+ * Create the production account-recovery processor.
116
+ *
117
+ * @param interactionAuthority - Live provider authority for interaction-bound magic links.
118
+ * @returns The account-independent processor used by the durable worker.
119
+ */
120
+ export function createAccountRecoveryJobProcessor(interactionAuthority) {
121
+ return new AccountRecoveryJobProcessor(interactionAuthority);
122
+ }
123
+ //# sourceMappingURL=recovery-job-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-job-processor.js","sourceRoot":"","sources":["../../src/auth/recovery-job-processor.ts"],"names":[],"mappings":"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"}