alepha 0.14.1 → 0.14.3

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 (402) hide show
  1. package/README.md +3 -3
  2. package/dist/api/audits/index.browser.js +5 -5
  3. package/dist/api/audits/index.browser.js.map +1 -1
  4. package/dist/api/audits/index.d.ts +784 -784
  5. package/dist/api/audits/index.d.ts.map +1 -1
  6. package/dist/api/audits/index.js +13 -13
  7. package/dist/api/audits/index.js.map +1 -1
  8. package/dist/api/files/index.browser.js +5 -5
  9. package/dist/api/files/index.browser.js.map +1 -1
  10. package/dist/api/files/index.d.ts +57 -57
  11. package/dist/api/files/index.d.ts.map +1 -1
  12. package/dist/api/files/index.js +71 -71
  13. package/dist/api/files/index.js.map +1 -1
  14. package/dist/api/jobs/index.browser.js +5 -5
  15. package/dist/api/jobs/index.browser.js.map +1 -1
  16. package/dist/api/jobs/index.d.ts +165 -165
  17. package/dist/api/jobs/index.d.ts.map +1 -1
  18. package/dist/api/jobs/index.js +10 -10
  19. package/dist/api/jobs/index.js.map +1 -1
  20. package/dist/api/notifications/index.browser.js +10 -10
  21. package/dist/api/notifications/index.browser.js.map +1 -1
  22. package/dist/api/notifications/index.d.ts +583 -171
  23. package/dist/api/notifications/index.d.ts.map +1 -1
  24. package/dist/api/notifications/index.js +12 -12
  25. package/dist/api/notifications/index.js.map +1 -1
  26. package/dist/api/parameters/index.browser.js +163 -10
  27. package/dist/api/parameters/index.browser.js.map +1 -1
  28. package/dist/api/parameters/index.d.ts +281 -276
  29. package/dist/api/parameters/index.d.ts.map +1 -1
  30. package/dist/api/parameters/index.js +196 -91
  31. package/dist/api/parameters/index.js.map +1 -1
  32. package/dist/api/users/index.browser.js +19 -19
  33. package/dist/api/users/index.browser.js.map +1 -1
  34. package/dist/api/users/index.d.ts +778 -764
  35. package/dist/api/users/index.d.ts.map +1 -1
  36. package/dist/api/users/index.js +831 -596
  37. package/dist/api/users/index.js.map +1 -1
  38. package/dist/api/verifications/index.browser.js +6 -6
  39. package/dist/api/verifications/index.browser.js.map +1 -1
  40. package/dist/api/verifications/index.d.ts +125 -125
  41. package/dist/api/verifications/index.d.ts.map +1 -1
  42. package/dist/api/verifications/index.js +6 -6
  43. package/dist/api/verifications/index.js.map +1 -1
  44. package/dist/batch/index.js.map +1 -1
  45. package/dist/bin/index.d.ts +1 -2
  46. package/dist/bin/index.js +0 -1
  47. package/dist/bin/index.js.map +1 -1
  48. package/dist/cache/core/index.js.map +1 -1
  49. package/dist/cli/index.d.ts +249 -218
  50. package/dist/cli/index.d.ts.map +1 -1
  51. package/dist/cli/index.js +951 -821
  52. package/dist/cli/index.js.map +1 -1
  53. package/dist/command/index.d.ts +40 -0
  54. package/dist/command/index.d.ts.map +1 -1
  55. package/dist/command/index.js +97 -17
  56. package/dist/command/index.js.map +1 -1
  57. package/dist/core/index.browser.js +14 -18
  58. package/dist/core/index.browser.js.map +1 -1
  59. package/dist/core/index.d.ts +29 -0
  60. package/dist/core/index.d.ts.map +1 -1
  61. package/dist/core/index.js +21 -24
  62. package/dist/core/index.js.map +1 -1
  63. package/dist/core/index.native.js +21 -24
  64. package/dist/core/index.native.js.map +1 -1
  65. package/dist/datetime/index.js.map +1 -1
  66. package/dist/fake/index.js +195 -168
  67. package/dist/fake/index.js.map +1 -1
  68. package/dist/file/index.d.ts +8 -0
  69. package/dist/file/index.d.ts.map +1 -1
  70. package/dist/file/index.js +3 -0
  71. package/dist/file/index.js.map +1 -1
  72. package/dist/lock/redis/index.js.map +1 -1
  73. package/dist/logger/index.js.map +1 -1
  74. package/dist/mcp/index.d.ts.map +1 -1
  75. package/dist/mcp/index.js.map +1 -1
  76. package/dist/orm/index.browser.js +26 -5
  77. package/dist/orm/index.browser.js.map +1 -1
  78. package/dist/orm/index.d.ts +146 -121
  79. package/dist/orm/index.d.ts.map +1 -1
  80. package/dist/orm/index.js +49 -24
  81. package/dist/orm/index.js.map +1 -1
  82. package/dist/redis/index.js.map +1 -1
  83. package/dist/retry/index.js.map +1 -1
  84. package/dist/router/index.js.map +1 -1
  85. package/dist/scheduler/index.d.ts +6 -6
  86. package/dist/scheduler/index.js.map +1 -1
  87. package/dist/security/index.d.ts +29 -29
  88. package/dist/security/index.d.ts.map +1 -1
  89. package/dist/security/index.js +1 -1
  90. package/dist/security/index.js.map +1 -1
  91. package/dist/server/auth/index.d.ts +171 -155
  92. package/dist/server/auth/index.d.ts.map +1 -1
  93. package/dist/server/auth/index.js +0 -1
  94. package/dist/server/auth/index.js.map +1 -1
  95. package/dist/server/cache/index.js.map +1 -1
  96. package/dist/server/compress/index.d.ts.map +1 -1
  97. package/dist/server/compress/index.js +2 -0
  98. package/dist/server/compress/index.js.map +1 -1
  99. package/dist/server/cookies/index.browser.js.map +1 -1
  100. package/dist/server/cookies/index.js.map +1 -1
  101. package/dist/server/core/index.browser.js.map +1 -1
  102. package/dist/server/core/index.d.ts.map +1 -1
  103. package/dist/server/core/index.js +1 -1
  104. package/dist/server/core/index.js.map +1 -1
  105. package/dist/server/health/index.d.ts +17 -17
  106. package/dist/server/helmet/index.js.map +1 -1
  107. package/dist/server/links/index.browser.js +22 -6
  108. package/dist/server/links/index.browser.js.map +1 -1
  109. package/dist/server/links/index.d.ts +46 -44
  110. package/dist/server/links/index.d.ts.map +1 -1
  111. package/dist/server/links/index.js +24 -41
  112. package/dist/server/links/index.js.map +1 -1
  113. package/dist/server/multipart/index.js.map +1 -1
  114. package/dist/server/rate-limit/index.js.map +1 -1
  115. package/dist/server/security/index.js.map +1 -1
  116. package/dist/server/swagger/index.d.ts +2 -1
  117. package/dist/server/swagger/index.d.ts.map +1 -1
  118. package/dist/server/swagger/index.js +8 -3
  119. package/dist/server/swagger/index.js.map +1 -1
  120. package/dist/thread/index.js.map +1 -1
  121. package/dist/topic/core/index.js.map +1 -1
  122. package/dist/vite/index.d.ts.map +1 -1
  123. package/dist/vite/index.js +12 -4
  124. package/dist/vite/index.js.map +1 -1
  125. package/dist/websocket/index.browser.js.map +1 -1
  126. package/dist/websocket/index.js.map +1 -1
  127. package/package.json +7 -7
  128. package/src/api/audits/controllers/{AuditController.ts → AdminAuditController.ts} +5 -6
  129. package/src/api/audits/entities/audits.ts +5 -5
  130. package/src/api/audits/index.browser.ts +1 -1
  131. package/src/api/audits/index.ts +3 -3
  132. package/src/api/audits/primitives/$audit.spec.ts +276 -0
  133. package/src/api/audits/services/AuditService.spec.ts +495 -0
  134. package/src/api/files/__tests__/$bucket.spec.ts +91 -0
  135. package/src/api/files/controllers/AdminFileStatsController.spec.ts +166 -0
  136. package/src/api/files/controllers/{StorageStatsController.ts → AdminFileStatsController.ts} +2 -2
  137. package/src/api/files/controllers/FileController.spec.ts +558 -0
  138. package/src/api/files/controllers/FileController.ts +4 -5
  139. package/src/api/files/entities/files.ts +5 -5
  140. package/src/api/files/index.browser.ts +1 -1
  141. package/src/api/files/index.ts +4 -4
  142. package/src/api/files/jobs/FileJobs.spec.ts +52 -0
  143. package/src/api/files/services/FileService.spec.ts +109 -0
  144. package/src/api/jobs/__tests__/JobController.spec.ts +343 -0
  145. package/src/api/jobs/controllers/{JobController.ts → AdminJobController.ts} +2 -2
  146. package/src/api/jobs/entities/jobExecutions.ts +5 -5
  147. package/src/api/jobs/index.ts +3 -3
  148. package/src/api/jobs/primitives/$job.spec.ts +476 -0
  149. package/src/api/notifications/controllers/{NotificationController.ts → AdminNotificationController.ts} +4 -5
  150. package/src/api/notifications/entities/notifications.ts +5 -5
  151. package/src/api/notifications/index.browser.ts +1 -1
  152. package/src/api/notifications/index.ts +4 -4
  153. package/src/api/parameters/controllers/{ConfigController.ts → AdminConfigController.ts} +46 -107
  154. package/src/api/parameters/entities/parameters.ts +7 -17
  155. package/src/api/parameters/index.ts +3 -3
  156. package/src/api/parameters/primitives/$config.spec.ts +356 -0
  157. package/src/api/parameters/schemas/activateConfigBodySchema.ts +12 -0
  158. package/src/api/parameters/schemas/checkScheduledResponseSchema.ts +8 -0
  159. package/src/api/parameters/schemas/configCurrentResponseSchema.ts +13 -0
  160. package/src/api/parameters/schemas/configHistoryResponseSchema.ts +9 -0
  161. package/src/api/parameters/schemas/configNameParamSchema.ts +10 -0
  162. package/src/api/parameters/schemas/configNamesResponseSchema.ts +8 -0
  163. package/src/api/parameters/schemas/configTreeNodeSchema.ts +13 -0
  164. package/src/api/parameters/schemas/configVersionParamSchema.ts +9 -0
  165. package/src/api/parameters/schemas/configVersionResponseSchema.ts +9 -0
  166. package/src/api/parameters/schemas/configsByStatusResponseSchema.ts +9 -0
  167. package/src/api/parameters/schemas/createConfigVersionBodySchema.ts +24 -0
  168. package/src/api/parameters/schemas/index.ts +15 -0
  169. package/src/api/parameters/schemas/parameterResponseSchema.ts +26 -0
  170. package/src/api/parameters/schemas/parameterStatusSchema.ts +13 -0
  171. package/src/api/parameters/schemas/rollbackConfigBodySchema.ts +15 -0
  172. package/src/api/parameters/schemas/statusParamSchema.ts +9 -0
  173. package/src/api/users/__tests__/EmailVerification.spec.ts +369 -0
  174. package/src/api/users/__tests__/PasswordReset.spec.ts +550 -0
  175. package/src/api/users/controllers/AdminIdentityController.spec.ts +365 -0
  176. package/src/api/users/controllers/{IdentityController.ts → AdminIdentityController.ts} +3 -4
  177. package/src/api/users/controllers/AdminSessionController.spec.ts +274 -0
  178. package/src/api/users/controllers/{SessionController.ts → AdminSessionController.ts} +3 -4
  179. package/src/api/users/controllers/AdminUserController.spec.ts +372 -0
  180. package/src/api/users/controllers/AdminUserController.ts +116 -0
  181. package/src/api/users/controllers/UserController.ts +4 -107
  182. package/src/api/users/controllers/UserRealmController.ts +3 -0
  183. package/src/api/users/entities/identities.ts +6 -6
  184. package/src/api/users/entities/sessions.ts +6 -6
  185. package/src/api/users/entities/users.ts +9 -9
  186. package/src/api/users/index.ts +13 -6
  187. package/src/api/users/primitives/$userRealm.ts +13 -8
  188. package/src/api/users/services/CredentialService.spec.ts +509 -0
  189. package/src/api/users/services/CredentialService.ts +46 -0
  190. package/src/api/users/services/IdentityService.ts +15 -0
  191. package/src/api/users/services/RegistrationService.spec.ts +630 -0
  192. package/src/api/users/services/RegistrationService.ts +18 -0
  193. package/src/api/users/services/SessionService.spec.ts +301 -0
  194. package/src/api/users/services/SessionService.ts +110 -1
  195. package/src/api/users/services/UserService.ts +67 -2
  196. package/src/api/verifications/__tests__/CodeVerification.spec.ts +318 -0
  197. package/src/api/verifications/__tests__/LinkVerification.spec.ts +279 -0
  198. package/src/api/verifications/entities/verifications.ts +6 -6
  199. package/src/api/verifications/jobs/VerificationJobs.spec.ts +50 -0
  200. package/src/batch/__tests__/startup-buffering.spec.ts +458 -0
  201. package/src/batch/primitives/$batch.spec.ts +766 -0
  202. package/src/batch/providers/BatchProvider.spec.ts +786 -0
  203. package/src/bin/index.ts +0 -1
  204. package/src/bucket/__tests__/shared.ts +194 -0
  205. package/src/bucket/primitives/$bucket.spec.ts +104 -0
  206. package/src/bucket/providers/FileStorageProvider.spec.ts +13 -0
  207. package/src/bucket/providers/LocalFileStorageProvider.spec.ts +77 -0
  208. package/src/bucket/providers/MemoryFileStorageProvider.spec.ts +82 -0
  209. package/src/cache/core/__tests__/shared.ts +377 -0
  210. package/src/cache/core/primitives/$cache.spec.ts +111 -0
  211. package/src/cache/redis/__tests__/cache-redis.spec.ts +70 -0
  212. package/src/cli/apps/AlephaCli.ts +54 -16
  213. package/src/cli/apps/AlephaPackageBuilderCli.ts +2 -1
  214. package/src/cli/assets/appRouterTs.ts +1 -1
  215. package/src/cli/commands/{ViteCommands.ts → build.ts} +2 -105
  216. package/src/cli/commands/clean.ts +14 -0
  217. package/src/cli/commands/{DrizzleCommands.ts → db.ts} +10 -117
  218. package/src/cli/commands/{DeployCommands.ts → deploy.ts} +1 -1
  219. package/src/cli/commands/dev.ts +69 -0
  220. package/src/cli/commands/format.ts +17 -0
  221. package/src/cli/commands/gen/changelog.spec.ts +315 -0
  222. package/src/cli/commands/{ChangelogCommands.ts → gen/changelog.ts} +16 -31
  223. package/src/cli/commands/gen/openapi.ts +71 -0
  224. package/src/cli/commands/gen.ts +18 -0
  225. package/src/cli/commands/{CoreCommands.ts → init.ts} +4 -40
  226. package/src/cli/commands/lint.ts +17 -0
  227. package/src/cli/commands/root.ts +41 -0
  228. package/src/cli/commands/run.ts +24 -0
  229. package/src/cli/commands/test.ts +42 -0
  230. package/src/cli/commands/typecheck.ts +24 -0
  231. package/src/cli/commands/{VerifyCommands.ts → verify.ts} +1 -13
  232. package/src/cli/defineConfig.ts +10 -1
  233. package/src/cli/index.ts +17 -7
  234. package/src/cli/services/AlephaCliUtils.ts +71 -32
  235. package/src/cli/services/GitMessageParser.ts +1 -1
  236. package/src/command/helpers/Asker.spec.ts +127 -0
  237. package/src/command/helpers/Runner.spec.ts +126 -0
  238. package/src/command/primitives/$command.spec.ts +1588 -0
  239. package/src/command/providers/CliProvider.ts +74 -24
  240. package/src/core/Alepha.ts +52 -4
  241. package/src/core/__tests__/Alepha-emit.spec.ts +22 -0
  242. package/src/core/__tests__/Alepha-graph.spec.ts +93 -0
  243. package/src/core/__tests__/Alepha-has.spec.ts +41 -0
  244. package/src/core/__tests__/Alepha-inject.spec.ts +93 -0
  245. package/src/core/__tests__/Alepha-register.spec.ts +81 -0
  246. package/src/core/__tests__/Alepha-start.spec.ts +176 -0
  247. package/src/core/__tests__/Alepha-with.spec.ts +14 -0
  248. package/src/core/__tests__/TypeBox-usecases.spec.ts +35 -0
  249. package/src/core/__tests__/TypeBoxLocale.spec.ts +15 -0
  250. package/src/core/__tests__/descriptor.spec.ts +34 -0
  251. package/src/core/__tests__/fixtures/A.ts +5 -0
  252. package/src/core/__tests__/pagination.spec.ts +77 -0
  253. package/src/core/helpers/jsonSchemaToTypeBox.ts +2 -2
  254. package/src/core/primitives/$atom.spec.ts +43 -0
  255. package/src/core/primitives/$hook.spec.ts +130 -0
  256. package/src/core/primitives/$inject.spec.ts +175 -0
  257. package/src/core/primitives/$module.spec.ts +115 -0
  258. package/src/core/providers/CodecManager.spec.ts +740 -0
  259. package/src/core/providers/EventManager.spec.ts +762 -0
  260. package/src/core/providers/EventManager.ts +4 -0
  261. package/src/core/providers/StateManager.spec.ts +365 -0
  262. package/src/core/providers/TypeProvider.spec.ts +1607 -0
  263. package/src/core/providers/TypeProvider.ts +20 -26
  264. package/src/datetime/primitives/$interval.spec.ts +103 -0
  265. package/src/datetime/providers/DateTimeProvider.spec.ts +86 -0
  266. package/src/email/primitives/$email.spec.ts +175 -0
  267. package/src/email/providers/LocalEmailProvider.spec.ts +341 -0
  268. package/src/fake/__tests__/keyName.example.ts +40 -0
  269. package/src/fake/__tests__/keyName.spec.ts +152 -0
  270. package/src/fake/__tests__/module.example.ts +32 -0
  271. package/src/fake/providers/FakeProvider.spec.ts +438 -0
  272. package/src/file/providers/FileSystemProvider.ts +8 -0
  273. package/src/file/providers/NodeFileSystemProvider.spec.ts +418 -0
  274. package/src/file/providers/NodeFileSystemProvider.ts +5 -0
  275. package/src/file/services/FileDetector.spec.ts +591 -0
  276. package/src/lock/core/__tests__/shared.ts +190 -0
  277. package/src/lock/core/providers/MemoryLockProvider.spec.ts +25 -0
  278. package/src/lock/redis/providers/RedisLockProvider.spec.ts +25 -0
  279. package/src/logger/__tests__/SimpleFormatterProvider.spec.ts +109 -0
  280. package/src/logger/primitives/$logger.spec.ts +108 -0
  281. package/src/logger/services/Logger.spec.ts +295 -0
  282. package/src/mcp/__tests__/errors.spec.ts +175 -0
  283. package/src/mcp/__tests__/integration.spec.ts +450 -0
  284. package/src/mcp/helpers/jsonrpc.spec.ts +380 -0
  285. package/src/mcp/primitives/$prompt.spec.ts +468 -0
  286. package/src/mcp/primitives/$resource.spec.ts +390 -0
  287. package/src/mcp/primitives/$tool.spec.ts +406 -0
  288. package/src/mcp/providers/McpServerProvider.spec.ts +797 -0
  289. package/src/orm/__tests__/$repository-crud.spec.ts +276 -0
  290. package/src/orm/__tests__/$repository-hooks.spec.ts +325 -0
  291. package/src/orm/__tests__/$repository-orderBy.spec.ts +128 -0
  292. package/src/orm/__tests__/$repository-pagination-sort.spec.ts +149 -0
  293. package/src/orm/__tests__/$repository-save.spec.ts +37 -0
  294. package/src/orm/__tests__/ModelBuilder-integration.spec.ts +490 -0
  295. package/src/orm/__tests__/ModelBuilder-types.spec.ts +186 -0
  296. package/src/orm/__tests__/PostgresProvider.spec.ts +46 -0
  297. package/src/orm/__tests__/delete-returning.spec.ts +256 -0
  298. package/src/orm/__tests__/deletedAt.spec.ts +80 -0
  299. package/src/orm/__tests__/enums.spec.ts +315 -0
  300. package/src/orm/__tests__/execute.spec.ts +72 -0
  301. package/src/orm/__tests__/fixtures/bigEntitySchema.ts +65 -0
  302. package/src/orm/__tests__/fixtures/userEntitySchema.ts +27 -0
  303. package/src/orm/__tests__/joins.spec.ts +1114 -0
  304. package/src/orm/__tests__/page.spec.ts +287 -0
  305. package/src/orm/__tests__/primaryKey.spec.ts +87 -0
  306. package/src/orm/__tests__/query-date-encoding.spec.ts +402 -0
  307. package/src/orm/__tests__/ref-auto-onDelete.spec.ts +156 -0
  308. package/src/orm/__tests__/references.spec.ts +102 -0
  309. package/src/orm/__tests__/security.spec.ts +710 -0
  310. package/src/orm/__tests__/sqlite.spec.ts +111 -0
  311. package/src/orm/__tests__/string-operators.spec.ts +429 -0
  312. package/src/orm/__tests__/timestamps.spec.ts +388 -0
  313. package/src/orm/__tests__/validation.spec.ts +183 -0
  314. package/src/orm/__tests__/version.spec.ts +64 -0
  315. package/src/orm/helpers/parseQueryString.spec.ts +196 -0
  316. package/src/orm/index.browser.ts +1 -1
  317. package/src/orm/index.ts +10 -6
  318. package/src/orm/primitives/$repository.spec.ts +137 -0
  319. package/src/orm/primitives/$sequence.spec.ts +29 -0
  320. package/src/orm/primitives/$transaction.spec.ts +82 -0
  321. package/src/orm/providers/{PostgresTypeProvider.ts → DatabaseTypeProvider.ts} +25 -3
  322. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -3
  323. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  324. package/src/orm/providers/drivers/CloudflareD1Provider.ts +1 -1
  325. package/src/orm/providers/drivers/DatabaseProvider.ts +1 -1
  326. package/src/orm/providers/drivers/NodePostgresProvider.ts +3 -3
  327. package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
  328. package/src/orm/providers/drivers/PglitePostgresProvider.ts +2 -2
  329. package/src/orm/services/ModelBuilder.spec.ts +575 -0
  330. package/src/orm/services/Repository.spec.ts +137 -0
  331. package/src/queue/core/__tests__/shared.ts +143 -0
  332. package/src/queue/core/providers/MemoryQueueProvider.spec.ts +23 -0
  333. package/src/queue/core/providers/WorkerProvider.spec.ts +378 -0
  334. package/src/queue/redis/providers/RedisQueueProvider.spec.ts +23 -0
  335. package/src/redis/__tests__/redis.spec.ts +58 -0
  336. package/src/retry/primitives/$retry.spec.ts +234 -0
  337. package/src/retry/providers/RetryProvider.spec.ts +438 -0
  338. package/src/router/__tests__/match.spec.ts +252 -0
  339. package/src/router/providers/RouterProvider.spec.ts +197 -0
  340. package/src/scheduler/__tests__/$scheduler-cron.spec.ts +25 -0
  341. package/src/scheduler/__tests__/$scheduler-interval.spec.ts +25 -0
  342. package/src/scheduler/__tests__/shared.ts +77 -0
  343. package/src/security/__tests__/bug-1-wildcard-after-start.spec.ts +229 -0
  344. package/src/security/__tests__/bug-2-password-validation.spec.ts +245 -0
  345. package/src/security/__tests__/bug-3-regex-vulnerability.spec.ts +407 -0
  346. package/src/security/__tests__/bug-4-oauth2-validation.spec.ts +439 -0
  347. package/src/security/__tests__/multi-layer-permissions.spec.ts +522 -0
  348. package/src/security/primitives/$permission.spec.ts +30 -0
  349. package/src/security/primitives/$permission.ts +2 -2
  350. package/src/security/primitives/$realm.spec.ts +101 -0
  351. package/src/security/primitives/$role.spec.ts +52 -0
  352. package/src/security/primitives/$serviceAccount.spec.ts +61 -0
  353. package/src/security/providers/SecurityProvider.spec.ts +350 -0
  354. package/src/server/auth/providers/ServerAuthProvider.ts +0 -2
  355. package/src/server/cache/providers/ServerCacheProvider.spec.ts +942 -0
  356. package/src/server/compress/providers/ServerCompressProvider.spec.ts +31 -0
  357. package/src/server/compress/providers/ServerCompressProvider.ts +2 -0
  358. package/src/server/cookies/providers/ServerCookiesProvider.spec.ts +253 -0
  359. package/src/server/core/__tests__/ServerRouterProvider-getRoutes.spec.ts +334 -0
  360. package/src/server/core/__tests__/ServerRouterProvider-requestId.spec.ts +129 -0
  361. package/src/server/core/primitives/$action.spec.ts +191 -0
  362. package/src/server/core/primitives/$route.spec.ts +65 -0
  363. package/src/server/core/providers/ServerBodyParserProvider.spec.ts +93 -0
  364. package/src/server/core/providers/ServerLoggerProvider.spec.ts +100 -0
  365. package/src/server/core/providers/ServerProvider.ts +3 -1
  366. package/src/server/core/services/HttpClient.spec.ts +123 -0
  367. package/src/server/core/services/UserAgentParser.spec.ts +111 -0
  368. package/src/server/cors/providers/ServerCorsProvider.spec.ts +481 -0
  369. package/src/server/health/providers/ServerHealthProvider.spec.ts +22 -0
  370. package/src/server/helmet/providers/ServerHelmetProvider.spec.ts +105 -0
  371. package/src/server/links/__tests__/$action.spec.ts +238 -0
  372. package/src/server/links/__tests__/fixtures/CrudApp.ts +122 -0
  373. package/src/server/links/__tests__/requestId.spec.ts +120 -0
  374. package/src/server/links/primitives/$remote.spec.ts +228 -0
  375. package/src/server/links/providers/LinkProvider.spec.ts +54 -0
  376. package/src/server/links/providers/LinkProvider.ts +49 -3
  377. package/src/server/links/providers/ServerLinksProvider.ts +1 -53
  378. package/src/server/links/schemas/apiLinksResponseSchema.ts +7 -0
  379. package/src/server/metrics/providers/ServerMetricsProvider.spec.ts +25 -0
  380. package/src/server/multipart/providers/ServerMultipartProvider.spec.ts +528 -0
  381. package/src/server/proxy/primitives/$proxy.spec.ts +87 -0
  382. package/src/server/rate-limit/__tests__/ActionRateLimit.spec.ts +211 -0
  383. package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +344 -0
  384. package/src/server/security/__tests__/BasicAuth.spec.ts +684 -0
  385. package/src/server/security/__tests__/ServerSecurityProvider-realm.spec.ts +388 -0
  386. package/src/server/security/providers/ServerSecurityProvider.spec.ts +123 -0
  387. package/src/server/static/primitives/$serve.spec.ts +193 -0
  388. package/src/server/swagger/__tests__/ui.spec.ts +52 -0
  389. package/src/server/swagger/primitives/$swagger.spec.ts +193 -0
  390. package/src/server/swagger/providers/ServerSwaggerProvider.ts +18 -8
  391. package/src/sms/primitives/$sms.spec.ts +165 -0
  392. package/src/sms/providers/LocalSmsProvider.spec.ts +224 -0
  393. package/src/sms/providers/MemorySmsProvider.spec.ts +193 -0
  394. package/src/thread/primitives/$thread.spec.ts +186 -0
  395. package/src/topic/core/__tests__/shared.ts +144 -0
  396. package/src/topic/core/providers/MemoryTopicProvider.spec.ts +23 -0
  397. package/src/topic/redis/providers/RedisTopicProvider.spec.ts +23 -0
  398. package/src/vite/plugins/viteAlephaDev.ts +16 -4
  399. package/src/vite/tasks/runAlepha.ts +7 -1
  400. package/src/websocket/__tests__/$websocket-new.spec.ts +195 -0
  401. package/src/websocket/primitives/$channel.spec.ts +30 -0
  402. package/src/cli/commands/BiomeCommands.ts +0 -29
@@ -2,20 +2,21 @@ import { $atom, $context, $hook, $inject, $module, Alepha, AlephaError, t } from
2
2
  import { $notification, AlephaApiNotifications } from "alepha/api/notifications";
3
3
  import { AlephaApiVerification } from "alepha/api/verifications";
4
4
  import { AlephaEmail } from "alepha/email";
5
- import { $entity, $repository, pageQuerySchema, parseQueryString, pg } from "alepha/orm";
5
+ import { AlephaServerCompress } from "alepha/server/compress";
6
+ import { AlephaServerHelmet } from "alepha/server/helmet";
6
7
  import { $action, BadRequestError, ConflictError, HttpError, UnauthorizedError, okSchema } from "alepha/server";
8
+ import { $entity, $repository, db, pageQuerySchema, parseQueryString } from "alepha/orm";
9
+ import { AlephaApiAudits, AuditService } from "alepha/api/audits";
7
10
  import { $logger } from "alepha/logger";
8
11
  import { $bucket } from "alepha/bucket";
12
+ import { $client } from "alepha/server/links";
9
13
  import { randomInt, randomUUID } from "node:crypto";
10
14
  import { $cache } from "alepha/cache";
11
15
  import { DateTimeProvider } from "alepha/datetime";
12
16
  import { $realm, CryptoProvider, InvalidCredentialsError, SecurityProvider } from "alepha/security";
13
- import { $client } from "alepha/server/links";
14
17
  import { $authCredentials, $authGithub, $authGoogle, ServerAuthProvider, authenticationProviderSchema } from "alepha/server/auth";
15
18
  import { FileSystemProvider } from "alepha/file";
16
- import { AlephaApiAudits } from "alepha/api/audits";
17
19
  import { AlephaApiFiles } from "alepha/api/files";
18
- import { AlephaApiJobs } from "alepha/api/jobs";
19
20
 
20
21
  //#region ../../src/api/users/schemas/identityQuerySchema.ts
21
22
  const identityQuerySchema = t.extend(pageQuerySchema, {
@@ -29,11 +30,11 @@ const DEFAULT_USER_REALM_NAME = "default";
29
30
  const users = $entity({
30
31
  name: "users",
31
32
  schema: t.object({
32
- id: pg.primaryKey(t.uuid()),
33
- version: pg.version(),
34
- createdAt: pg.createdAt(),
35
- updatedAt: pg.updatedAt(),
36
- realm: pg.default(t.text(), DEFAULT_USER_REALM_NAME),
33
+ id: db.primaryKey(t.uuid()),
34
+ version: db.version(),
35
+ createdAt: db.createdAt(),
36
+ updatedAt: db.updatedAt(),
37
+ realm: db.default(t.text(), DEFAULT_USER_REALM_NAME),
37
38
  username: t.optional(t.shortText({
38
39
  minLength: 3,
39
40
  maxLength: 50,
@@ -41,12 +42,12 @@ const users = $entity({
41
42
  })),
42
43
  email: t.optional(t.string({ format: "email" })),
43
44
  phoneNumber: t.optional(t.e164()),
44
- roles: pg.default(t.array(t.string()), []),
45
+ roles: db.default(t.array(t.string()), []),
45
46
  firstName: t.optional(t.string()),
46
47
  lastName: t.optional(t.string()),
47
48
  picture: t.optional(t.string()),
48
- enabled: pg.default(t.boolean(), true),
49
- emailVerified: pg.default(t.boolean(), false)
49
+ enabled: db.default(t.boolean(), true),
50
+ emailVerified: db.default(t.boolean(), false)
50
51
  }),
51
52
  indexes: [
52
53
  {
@@ -69,11 +70,11 @@ const users = $entity({
69
70
  const identities = $entity({
70
71
  name: "identities",
71
72
  schema: t.object({
72
- id: pg.primaryKey(t.uuid()),
73
- version: pg.version(),
74
- createdAt: pg.createdAt(),
75
- updatedAt: pg.updatedAt(),
76
- userId: pg.ref(t.uuid(), () => users.cols.id),
73
+ id: db.primaryKey(t.uuid()),
74
+ version: db.version(),
75
+ createdAt: db.createdAt(),
76
+ updatedAt: db.updatedAt(),
77
+ userId: db.ref(t.uuid(), () => users.cols.id),
77
78
  password: t.optional(t.text()),
78
79
  provider: t.text(),
79
80
  providerUserId: t.optional(t.text()),
@@ -145,12 +146,12 @@ const realmAuthSettingsAtom = $atom({
145
146
  const sessions = $entity({
146
147
  name: "sessions",
147
148
  schema: t.object({
148
- id: pg.primaryKey(t.uuid()),
149
- version: pg.version(),
150
- createdAt: pg.createdAt(),
151
- updatedAt: pg.updatedAt(),
149
+ id: db.primaryKey(t.uuid()),
150
+ version: db.version(),
151
+ createdAt: db.createdAt(),
152
+ updatedAt: db.updatedAt(),
152
153
  refreshToken: t.uuid(),
153
- userId: pg.ref(t.uuid(), () => users.cols.id),
154
+ userId: db.ref(t.uuid(), () => users.cols.id),
154
155
  expiresAt: t.datetime(),
155
156
  ip: t.optional(t.text()),
156
157
  userAgent: t.optional(t.object({
@@ -240,6 +241,7 @@ var UserRealmProvider = class {
240
241
  var IdentityService = class {
241
242
  log = $logger();
242
243
  userRealmProvider = $inject(UserRealmProvider);
244
+ auditService = $inject(AuditService);
243
245
  identities(userRealmName) {
244
246
  return this.userRealmProvider.identityRepository(userRealmName);
245
247
  }
@@ -293,14 +295,25 @@ var IdentityService = class {
293
295
  provider: identity.provider,
294
296
  userId: identity.userId
295
297
  });
298
+ const realm = this.userRealmProvider.getRealm(userRealmName);
299
+ await this.auditService.recordUser("update", {
300
+ userRealm: realm.name,
301
+ resourceId: identity.userId,
302
+ description: `Identity provider disconnected: ${identity.provider}`,
303
+ metadata: {
304
+ identityId: id,
305
+ provider: identity.provider,
306
+ userId: identity.userId
307
+ }
308
+ });
296
309
  }
297
310
  };
298
311
 
299
312
  //#endregion
300
- //#region ../../src/api/users/controllers/IdentityController.ts
301
- var IdentityController = class {
313
+ //#region ../../src/api/users/controllers/AdminIdentityController.ts
314
+ var AdminIdentityController = class {
302
315
  url = "/identities";
303
- group = "identities";
316
+ group = "admin:identities";
304
317
  identityService = $inject(IdentityService);
305
318
  /**
306
319
  * Find identities with pagination and filtering.
@@ -311,7 +324,7 @@ var IdentityController = class {
311
324
  description: "Find identities with pagination and filtering",
312
325
  schema: {
313
326
  query: t.extend(identityQuerySchema, { userRealmName: t.optional(t.string()) }),
314
- response: pg.page(identityResourceSchema)
327
+ response: t.page(identityResourceSchema)
315
328
  },
316
329
  handler: ({ query }) => {
317
330
  const { userRealmName, ...q } = query;
@@ -437,10 +450,10 @@ var SessionCrudService = class {
437
450
  };
438
451
 
439
452
  //#endregion
440
- //#region ../../src/api/users/controllers/SessionController.ts
441
- var SessionController = class {
453
+ //#region ../../src/api/users/controllers/AdminSessionController.ts
454
+ var AdminSessionController = class {
442
455
  url = "/sessions";
443
- group = "sessions";
456
+ group = "admin:sessions";
444
457
  sessionService = $inject(SessionCrudService);
445
458
  /**
446
459
  * Find sessions with pagination and filtering.
@@ -451,7 +464,7 @@ var SessionController = class {
451
464
  description: "Find sessions with pagination and filtering",
452
465
  schema: {
453
466
  query: t.extend(sessionQuerySchema, { userRealmName: t.optional(t.string()) }),
454
- response: pg.page(sessionResourceSchema)
467
+ response: t.page(sessionResourceSchema)
455
468
  },
456
469
  handler: ({ query }) => {
457
470
  const { userRealmName, ...q } = query;
@@ -495,92 +508,10 @@ var SessionController = class {
495
508
  });
496
509
  };
497
510
 
498
- //#endregion
499
- //#region ../../src/api/users/schemas/completePasswordResetRequestSchema.ts
500
- /**
501
- * Request schema for completing a password reset.
502
- *
503
- * Requires the intent ID from Phase 1, the verification code,
504
- * and the new password.
505
- */
506
- const completePasswordResetRequestSchema = t.object({
507
- intentId: t.uuid({ description: "The intent ID from createPasswordResetIntent" }),
508
- code: t.string({ description: "6-digit verification code sent via email" }),
509
- newPassword: t.string({
510
- minLength: 8,
511
- description: "New password (minimum 8 characters)"
512
- })
513
- });
514
-
515
- //#endregion
516
- //#region ../../src/api/users/schemas/completeRegistrationRequestSchema.ts
517
- const completeRegistrationRequestSchema = t.object({
518
- intentId: t.uuid({ description: "The registration intent ID from the first phase" }),
519
- emailCode: t.optional(t.string({ description: "Email verification code (if email verification required)" })),
520
- phoneCode: t.optional(t.string({ description: "Phone verification code (if phone verification required)" })),
521
- captchaToken: t.optional(t.string({ description: "Captcha token (if captcha required)" }))
522
- });
523
-
524
511
  //#endregion
525
512
  //#region ../../src/api/users/schemas/createUserSchema.ts
526
513
  const createUserSchema = t.omit(users.insertSchema, ["realm"]);
527
514
 
528
- //#endregion
529
- //#region ../../src/api/users/schemas/passwordResetIntentResponseSchema.ts
530
- /**
531
- * Response schema for password reset intent creation.
532
- *
533
- * Contains the intent ID needed for Phase 2 completion,
534
- * along with expiration time.
535
- */
536
- const passwordResetIntentResponseSchema = t.object({
537
- intentId: t.uuid({ description: "Unique identifier for this password reset intent" }),
538
- expiresAt: t.datetime({ description: "ISO timestamp when this intent expires" })
539
- });
540
-
541
- //#endregion
542
- //#region ../../src/api/users/schemas/registerQuerySchema.ts
543
- /**
544
- * Schema for user registration query parameters.
545
- * Allows specifying a custom user realm.
546
- */
547
- const registerQuerySchema = t.object({ userRealmName: t.optional(t.text({ description: "The user realm to register the user in (defaults to 'default')" })) });
548
-
549
- //#endregion
550
- //#region ../../src/api/users/schemas/registerRequestSchema.ts
551
- /**
552
- * Schema for user registration request body.
553
- * Password is always required, other fields depend on realm settings.
554
- */
555
- const registerRequestSchema = t.object({
556
- password: t.string({
557
- minLength: 8,
558
- description: "Password for the account"
559
- }),
560
- username: t.optional(t.string({
561
- minLength: 3,
562
- description: "Unique username for the account"
563
- })),
564
- email: t.optional(t.string({
565
- format: "email",
566
- description: "User's email address"
567
- })),
568
- phoneNumber: t.optional(t.string({ description: "User's phone number" })),
569
- firstName: t.optional(t.string({ description: "User's first name" })),
570
- lastName: t.optional(t.string({ description: "User's last name" })),
571
- picture: t.optional(t.string({ description: "User's profile picture URL" }))
572
- });
573
-
574
- //#endregion
575
- //#region ../../src/api/users/schemas/registrationIntentResponseSchema.ts
576
- const registrationIntentResponseSchema = t.object({
577
- intentId: t.uuid({ description: "Unique identifier for the registration intent" }),
578
- expectCaptcha: t.boolean({ description: "Whether captcha verification is required" }),
579
- expectEmailVerification: t.boolean({ description: "Whether email verification is required" }),
580
- expectPhoneVerification: t.boolean({ description: "Whether phone verification is required" }),
581
- expiresAt: t.datetime({ description: "When the registration intent expires" })
582
- });
583
-
584
515
  //#endregion
585
516
  //#region ../../src/api/users/schemas/updateUserSchema.ts
586
517
  const updateUserSchema = t.partial(t.omit(users.insertSchema, [
@@ -736,136 +667,578 @@ var UserNotifications = class {
736
667
  };
737
668
 
738
669
  //#endregion
739
- //#region ../../src/api/users/services/CredentialService.ts
740
- const INTENT_TTL_MINUTES$1 = 10;
741
- var CredentialService = class {
670
+ //#region ../../src/api/users/services/UserService.ts
671
+ var UserService = class {
742
672
  log = $logger();
743
- cryptoProvider = $inject(CryptoProvider);
744
- dateTimeProvider = $inject(DateTimeProvider);
745
673
  verificationController = $client();
746
674
  userNotifications = $inject(UserNotifications);
747
675
  userRealmProvider = $inject(UserRealmProvider);
748
- intentCache = $cache({
749
- name: "password-reset-intents",
750
- ttl: [INTENT_TTL_MINUTES$1, "minutes"]
751
- });
676
+ auditService = $inject(AuditService);
752
677
  users(userRealmName) {
753
678
  return this.userRealmProvider.userRepository(userRealmName);
754
679
  }
755
- sessions(userRealmName) {
756
- return this.userRealmProvider.sessionRepository(userRealmName);
757
- }
758
- identities(userRealmName) {
759
- return this.userRealmProvider.identityRepository(userRealmName);
760
- }
761
680
  /**
762
- * Phase 1: Create a password reset intent.
763
- *
764
- * Validates the email, checks for existing user with credentials,
765
- * sends verification code, and stores the intent in cache.
766
- *
767
- * @param email - User's email address
768
- * @param userRealmName - Optional realm name
769
- * @returns Intent response with intentId and expiration (always returns for security)
681
+ * Request email verification for a user.
682
+ * @param email - The email address to verify.
683
+ * @param userRealmName - Optional realm name.
684
+ * @param method - The verification method: "code" (default) or "link".
685
+ * @param verifyUrl - Base URL for verification link (required when method is "link").
770
686
  */
771
- async createPasswordResetIntent(email, userRealmName) {
772
- this.log.trace("Creating password reset intent", {
687
+ async requestEmailVerification(email, userRealmName, method = "code", verifyUrl) {
688
+ this.log.trace("Requesting email verification", {
773
689
  email,
774
- userRealmName
690
+ userRealmName,
691
+ method
775
692
  });
776
- const intentId = randomUUID();
777
- const expiresAt = this.dateTimeProvider.now().add(INTENT_TTL_MINUTES$1, "minutes").toISOString();
778
693
  const user = await this.users(userRealmName).findOne({ where: { email: { eq: email } } }).catch(() => void 0);
779
694
  if (!user) {
780
- this.log.debug("Password reset requested for non-existent email", { email });
781
- return {
782
- intentId,
783
- expiresAt
784
- };
695
+ this.log.debug("Email verification requested for non-existent user", { email });
696
+ return true;
785
697
  }
786
- const identity = await this.identities(userRealmName).findOne({ where: {
787
- userId: { eq: user.id },
788
- provider: { eq: "credentials" }
789
- } }).catch(() => void 0);
790
- if (!identity) {
791
- this.log.debug("Password reset requested for user without credentials", { userId: user.id });
792
- return {
793
- intentId,
794
- expiresAt
795
- };
698
+ if (user.emailVerified) {
699
+ this.log.debug("Email verification requested for already verified user", {
700
+ email,
701
+ userId: user.id
702
+ });
703
+ return true;
796
704
  }
797
705
  try {
798
706
  const verification = await this.verificationController.requestVerificationCode({
799
- params: { type: "code" },
707
+ params: { type: method },
800
708
  body: { target: email }
801
709
  });
802
- await this.userNotifications.passwordReset.push({
803
- contact: email,
804
- variables: {
710
+ if (method === "link") {
711
+ const url = new URL(verifyUrl || "/verify-email", "http://localhost");
712
+ url.searchParams.set("email", email);
713
+ url.searchParams.set("token", verification.token);
714
+ const fullVerifyUrl = verifyUrl ? `${verifyUrl}${url.search}` : url.pathname + url.search;
715
+ await this.userNotifications.emailVerificationLink.push({
716
+ contact: email,
717
+ variables: {
718
+ email,
719
+ verifyUrl: fullVerifyUrl,
720
+ expiresInMinutes: Math.floor(verification.codeExpiration / 60)
721
+ }
722
+ });
723
+ this.log.debug("Email verification link sent", {
805
724
  email,
806
- code: verification.token,
807
- expiresInMinutes: Math.floor(verification.codeExpiration / 60)
808
- }
809
- });
810
- const intent = {
725
+ userId: user.id
726
+ });
727
+ } else {
728
+ await this.userNotifications.emailVerification.push({
729
+ contact: email,
730
+ variables: {
731
+ email,
732
+ code: verification.token,
733
+ expiresInMinutes: Math.floor(verification.codeExpiration / 60)
734
+ }
735
+ });
736
+ this.log.debug("Email verification code sent", {
737
+ email,
738
+ userId: user.id
739
+ });
740
+ }
741
+ } catch (error) {
742
+ this.log.warn("Failed to send email verification", {
811
743
  email,
812
- userId: user.id,
813
- identityId: identity.id,
814
- realmName: userRealmName,
815
- expiresAt
816
- };
817
- await this.intentCache.set(intentId, intent);
818
- this.log.info("Password reset intent created", {
819
- intentId,
820
- userId: user.id,
821
- email
744
+ error
822
745
  });
823
- } catch (error) {
824
- this.log.warn("Failed to create password reset verification", error);
825
746
  }
826
- return {
827
- intentId,
828
- expiresAt
829
- };
747
+ return true;
830
748
  }
831
749
  /**
832
- * Phase 2: Complete password reset using an intent.
833
- *
834
- * Validates the verification code, updates the password,
835
- * and invalidates all existing sessions.
836
- *
837
- * @param body - Request body with intentId, code, and newPassword
750
+ * Verify a user's email using a valid verification token.
751
+ * Supports both code (6-digit) and link (UUID) verification tokens.
838
752
  */
839
- async completePasswordReset(body) {
840
- this.log.trace("Completing password reset", { intentId: body.intentId });
841
- const intent = await this.intentCache.get(body.intentId);
842
- if (!intent) {
843
- this.log.warn("Invalid or expired password reset intent", { intentId: body.intentId });
844
- throw new HttpError({
845
- status: 410,
846
- message: "Invalid or expired password reset intent"
847
- });
848
- }
753
+ async verifyEmail(email, token, userRealmName) {
754
+ this.log.trace("Verifying email", {
755
+ email,
756
+ userRealmName
757
+ });
758
+ const type = /^\d{6}$/.test(token) ? "code" : "link";
849
759
  if ((await this.verificationController.validateVerificationCode({
850
- params: { type: "code" },
760
+ params: { type },
851
761
  body: {
852
- target: intent.email,
853
- token: body.code
762
+ target: email,
763
+ token
854
764
  }
855
765
  }).catch(() => {
856
- this.log.warn("Invalid verification code for password reset", {
857
- intentId: body.intentId,
858
- email: intent.email
766
+ this.log.warn("Invalid email verification token", {
767
+ email,
768
+ type
859
769
  });
860
- throw new BadRequestError("Invalid or expired verification code");
770
+ throw new BadRequestError("Invalid or expired verification token");
861
771
  })).alreadyVerified) {
862
- this.log.warn("Verification code reuse attempt", {
863
- intentId: body.intentId,
864
- email: intent.email
865
- });
866
- throw new BadRequestError("Verification code has already been used");
772
+ this.log.warn("Email verification token already used", { email });
773
+ throw new BadRequestError("Invalid or expired verification token");
867
774
  }
868
- await this.intentCache.invalidate(body.intentId);
775
+ const user = await this.users(userRealmName).findOne({ where: { email: { eq: email } } });
776
+ await this.users(userRealmName).updateById(user.id, { emailVerified: true });
777
+ this.log.info("Email verified", {
778
+ email,
779
+ userId: user.id,
780
+ type
781
+ });
782
+ const realm = this.userRealmProvider.getRealm(userRealmName);
783
+ await this.auditService.recordUser("update", {
784
+ userId: user.id,
785
+ userEmail: email,
786
+ userRealm: realm.name,
787
+ resourceId: user.id,
788
+ description: "Email verified",
789
+ metadata: {
790
+ email,
791
+ verificationType: type
792
+ }
793
+ });
794
+ }
795
+ /**
796
+ * Check if an email is verified.
797
+ */
798
+ async isEmailVerified(email, userRealmName) {
799
+ this.log.trace("Checking if email is verified", {
800
+ email,
801
+ userRealmName
802
+ });
803
+ return (await this.users(userRealmName).findOne({ where: { email: { eq: email } } }).catch(() => void 0))?.emailVerified ?? false;
804
+ }
805
+ /**
806
+ * Find users with pagination and filtering.
807
+ */
808
+ async findUsers(q = {}, userRealmName) {
809
+ this.log.trace("Finding users", {
810
+ query: q,
811
+ userRealmName
812
+ });
813
+ q.sort ??= "-createdAt";
814
+ const where = this.users(userRealmName).createQueryWhere();
815
+ if (q.email) where.email = { like: q.email };
816
+ if (q.enabled !== void 0) where.enabled = { eq: q.enabled };
817
+ if (q.emailVerified !== void 0) where.emailVerified = { eq: q.emailVerified };
818
+ if (q.roles) where.roles = { arrayContains: q.roles };
819
+ if (q.query) Object.assign(where, parseQueryString(q.query));
820
+ const result = await this.users(userRealmName).paginate(q, { where }, { count: true });
821
+ this.log.debug("Users found", {
822
+ count: result.content.length,
823
+ total: result.page.totalElements
824
+ });
825
+ return result;
826
+ }
827
+ /**
828
+ * Get a user by ID.
829
+ */
830
+ async getUserById(id, userRealmName) {
831
+ this.log.trace("Getting user by ID", {
832
+ id,
833
+ userRealmName
834
+ });
835
+ return await this.users(userRealmName).findById(id);
836
+ }
837
+ /**
838
+ * Create a new user.
839
+ */
840
+ async createUser(data, userRealmName) {
841
+ this.log.trace("Creating user", {
842
+ username: data.username,
843
+ email: data.email,
844
+ userRealmName
845
+ });
846
+ const realm = this.userRealmProvider.getRealm(userRealmName);
847
+ if (data.username) {
848
+ if (await this.users(userRealmName).findOne({ where: { username: { eq: data.username } } }).catch(() => void 0)) {
849
+ this.log.debug("Username already taken", { username: data.username });
850
+ throw new BadRequestError("User with this username already exists");
851
+ }
852
+ }
853
+ if (data.email) {
854
+ if (await this.users(userRealmName).findOne({ where: { email: { eq: data.email } } }).catch(() => void 0)) {
855
+ this.log.debug("Email already taken", { email: data.email });
856
+ throw new BadRequestError("User with this email already exists");
857
+ }
858
+ }
859
+ if (data.phoneNumber) {
860
+ if (await this.users(userRealmName).findOne({ where: { phoneNumber: { eq: data.phoneNumber } } }).catch(() => void 0)) {
861
+ this.log.debug("Phone number already taken", { phoneNumber: data.phoneNumber });
862
+ throw new BadRequestError("User with this phone number already exists");
863
+ }
864
+ }
865
+ const user = await this.users(userRealmName).create({
866
+ ...data,
867
+ roles: data.roles ?? ["user"],
868
+ realm: realm.name
869
+ });
870
+ this.log.info("User created", {
871
+ userId: user.id,
872
+ username: user.username,
873
+ email: user.email
874
+ });
875
+ await this.auditService.recordUser("create", {
876
+ userRealm: realm.name,
877
+ resourceId: user.id,
878
+ description: "User created",
879
+ metadata: {
880
+ username: user.username,
881
+ email: user.email,
882
+ roles: user.roles
883
+ }
884
+ });
885
+ return user;
886
+ }
887
+ /**
888
+ * Update an existing user.
889
+ */
890
+ async updateUser(id, data, userRealmName) {
891
+ this.log.trace("Updating user", {
892
+ id,
893
+ userRealmName
894
+ });
895
+ const before = await this.getUserById(id, userRealmName);
896
+ const user = await this.users(userRealmName).updateById(id, data);
897
+ this.log.debug("User updated", { userId: id });
898
+ const realm = this.userRealmProvider.getRealm(userRealmName);
899
+ const changes = {};
900
+ for (const key of Object.keys(data)) if (data[key] !== void 0 && before[key] !== data[key]) changes[key] = {
901
+ from: before[key],
902
+ to: data[key]
903
+ };
904
+ const isRoleChange = data.roles !== void 0 && JSON.stringify(before.roles) !== JSON.stringify(data.roles);
905
+ await this.auditService.recordUser(isRoleChange ? "role_change" : "update", {
906
+ userRealm: realm.name,
907
+ resourceId: user.id,
908
+ description: isRoleChange ? "User roles changed" : `User updated: ${Object.keys(changes).join(", ")}`,
909
+ metadata: { changes }
910
+ });
911
+ return user;
912
+ }
913
+ /**
914
+ * Delete a user by ID.
915
+ */
916
+ async deleteUser(id, userRealmName) {
917
+ this.log.trace("Deleting user", {
918
+ id,
919
+ userRealmName
920
+ });
921
+ const user = await this.getUserById(id, userRealmName);
922
+ await this.users(userRealmName).deleteById(id);
923
+ this.log.info("User deleted", { userId: id });
924
+ const realm = this.userRealmProvider.getRealm(userRealmName);
925
+ await this.auditService.recordUser("delete", {
926
+ userRealm: realm.name,
927
+ resourceId: id,
928
+ severity: "warning",
929
+ description: "User deleted",
930
+ metadata: {
931
+ username: user.username,
932
+ email: user.email
933
+ }
934
+ });
935
+ }
936
+ };
937
+
938
+ //#endregion
939
+ //#region ../../src/api/users/controllers/AdminUserController.ts
940
+ var AdminUserController = class {
941
+ url = "/users";
942
+ group = "admin:users";
943
+ userService = $inject(UserService);
944
+ /**
945
+ * Find users with pagination and filtering.
946
+ */
947
+ findUsers = $action({
948
+ path: this.url,
949
+ group: this.group,
950
+ description: "Find users with pagination and filtering",
951
+ schema: {
952
+ query: t.extend(userQuerySchema, { userRealmName: t.optional(t.string()) }),
953
+ response: t.page(userResourceSchema)
954
+ },
955
+ handler: ({ query }) => {
956
+ const { userRealmName, ...q } = query;
957
+ return this.userService.findUsers(q, userRealmName);
958
+ }
959
+ });
960
+ /**
961
+ * Get a user by ID.
962
+ */
963
+ getUser = $action({
964
+ path: `${this.url}/:id`,
965
+ group: this.group,
966
+ description: "Get a user by ID",
967
+ schema: {
968
+ params: t.object({ id: t.uuid() }),
969
+ query: t.object({ userRealmName: t.optional(t.string()) }),
970
+ response: userResourceSchema
971
+ },
972
+ handler: ({ params, query }) => this.userService.getUserById(params.id, query.userRealmName)
973
+ });
974
+ /**
975
+ * Create a new user.
976
+ */
977
+ createUser = $action({
978
+ method: "POST",
979
+ path: this.url,
980
+ group: this.group,
981
+ description: "Create a new user",
982
+ schema: {
983
+ query: t.object({ userRealmName: t.optional(t.string()) }),
984
+ body: createUserSchema,
985
+ response: userResourceSchema
986
+ },
987
+ handler: ({ body, query }) => this.userService.createUser(body, query.userRealmName)
988
+ });
989
+ /**
990
+ * Update a user.
991
+ */
992
+ updateUser = $action({
993
+ method: "PATCH",
994
+ path: `${this.url}/:id`,
995
+ group: this.group,
996
+ description: "Update a user",
997
+ schema: {
998
+ params: t.object({ id: t.uuid() }),
999
+ query: t.object({ userRealmName: t.optional(t.string()) }),
1000
+ body: updateUserSchema,
1001
+ response: userResourceSchema
1002
+ },
1003
+ handler: ({ params, body, query }) => this.userService.updateUser(params.id, body, query.userRealmName)
1004
+ });
1005
+ /**
1006
+ * Delete a user.
1007
+ */
1008
+ deleteUser = $action({
1009
+ method: "DELETE",
1010
+ path: `${this.url}/:id`,
1011
+ group: this.group,
1012
+ description: "Delete a user",
1013
+ schema: {
1014
+ params: t.object({ id: t.uuid() }),
1015
+ query: t.object({ userRealmName: t.optional(t.string()) }),
1016
+ response: okSchema
1017
+ },
1018
+ handler: async ({ params, query }) => {
1019
+ await this.userService.deleteUser(params.id, query.userRealmName);
1020
+ return {
1021
+ ok: true,
1022
+ id: params.id
1023
+ };
1024
+ }
1025
+ });
1026
+ };
1027
+
1028
+ //#endregion
1029
+ //#region ../../src/api/users/schemas/completePasswordResetRequestSchema.ts
1030
+ /**
1031
+ * Request schema for completing a password reset.
1032
+ *
1033
+ * Requires the intent ID from Phase 1, the verification code,
1034
+ * and the new password.
1035
+ */
1036
+ const completePasswordResetRequestSchema = t.object({
1037
+ intentId: t.uuid({ description: "The intent ID from createPasswordResetIntent" }),
1038
+ code: t.string({ description: "6-digit verification code sent via email" }),
1039
+ newPassword: t.string({
1040
+ minLength: 8,
1041
+ description: "New password (minimum 8 characters)"
1042
+ })
1043
+ });
1044
+
1045
+ //#endregion
1046
+ //#region ../../src/api/users/schemas/completeRegistrationRequestSchema.ts
1047
+ const completeRegistrationRequestSchema = t.object({
1048
+ intentId: t.uuid({ description: "The registration intent ID from the first phase" }),
1049
+ emailCode: t.optional(t.string({ description: "Email verification code (if email verification required)" })),
1050
+ phoneCode: t.optional(t.string({ description: "Phone verification code (if phone verification required)" })),
1051
+ captchaToken: t.optional(t.string({ description: "Captcha token (if captcha required)" }))
1052
+ });
1053
+
1054
+ //#endregion
1055
+ //#region ../../src/api/users/schemas/passwordResetIntentResponseSchema.ts
1056
+ /**
1057
+ * Response schema for password reset intent creation.
1058
+ *
1059
+ * Contains the intent ID needed for Phase 2 completion,
1060
+ * along with expiration time.
1061
+ */
1062
+ const passwordResetIntentResponseSchema = t.object({
1063
+ intentId: t.uuid({ description: "Unique identifier for this password reset intent" }),
1064
+ expiresAt: t.datetime({ description: "ISO timestamp when this intent expires" })
1065
+ });
1066
+
1067
+ //#endregion
1068
+ //#region ../../src/api/users/schemas/registerQuerySchema.ts
1069
+ /**
1070
+ * Schema for user registration query parameters.
1071
+ * Allows specifying a custom user realm.
1072
+ */
1073
+ const registerQuerySchema = t.object({ userRealmName: t.optional(t.text({ description: "The user realm to register the user in (defaults to 'default')" })) });
1074
+
1075
+ //#endregion
1076
+ //#region ../../src/api/users/schemas/registerRequestSchema.ts
1077
+ /**
1078
+ * Schema for user registration request body.
1079
+ * Password is always required, other fields depend on realm settings.
1080
+ */
1081
+ const registerRequestSchema = t.object({
1082
+ password: t.string({
1083
+ minLength: 8,
1084
+ description: "Password for the account"
1085
+ }),
1086
+ username: t.optional(t.string({
1087
+ minLength: 3,
1088
+ description: "Unique username for the account"
1089
+ })),
1090
+ email: t.optional(t.string({
1091
+ format: "email",
1092
+ description: "User's email address"
1093
+ })),
1094
+ phoneNumber: t.optional(t.string({ description: "User's phone number" })),
1095
+ firstName: t.optional(t.string({ description: "User's first name" })),
1096
+ lastName: t.optional(t.string({ description: "User's last name" })),
1097
+ picture: t.optional(t.string({ description: "User's profile picture URL" }))
1098
+ });
1099
+
1100
+ //#endregion
1101
+ //#region ../../src/api/users/schemas/registrationIntentResponseSchema.ts
1102
+ const registrationIntentResponseSchema = t.object({
1103
+ intentId: t.uuid({ description: "Unique identifier for the registration intent" }),
1104
+ expectCaptcha: t.boolean({ description: "Whether captcha verification is required" }),
1105
+ expectEmailVerification: t.boolean({ description: "Whether email verification is required" }),
1106
+ expectPhoneVerification: t.boolean({ description: "Whether phone verification is required" }),
1107
+ expiresAt: t.datetime({ description: "When the registration intent expires" })
1108
+ });
1109
+
1110
+ //#endregion
1111
+ //#region ../../src/api/users/services/CredentialService.ts
1112
+ const INTENT_TTL_MINUTES$1 = 10;
1113
+ var CredentialService = class {
1114
+ log = $logger();
1115
+ cryptoProvider = $inject(CryptoProvider);
1116
+ dateTimeProvider = $inject(DateTimeProvider);
1117
+ verificationController = $client();
1118
+ userNotifications = $inject(UserNotifications);
1119
+ userRealmProvider = $inject(UserRealmProvider);
1120
+ auditService = $inject(AuditService);
1121
+ intentCache = $cache({
1122
+ name: "password-reset-intents",
1123
+ ttl: [INTENT_TTL_MINUTES$1, "minutes"]
1124
+ });
1125
+ users(userRealmName) {
1126
+ return this.userRealmProvider.userRepository(userRealmName);
1127
+ }
1128
+ sessions(userRealmName) {
1129
+ return this.userRealmProvider.sessionRepository(userRealmName);
1130
+ }
1131
+ identities(userRealmName) {
1132
+ return this.userRealmProvider.identityRepository(userRealmName);
1133
+ }
1134
+ /**
1135
+ * Phase 1: Create a password reset intent.
1136
+ *
1137
+ * Validates the email, checks for existing user with credentials,
1138
+ * sends verification code, and stores the intent in cache.
1139
+ *
1140
+ * @param email - User's email address
1141
+ * @param userRealmName - Optional realm name
1142
+ * @returns Intent response with intentId and expiration (always returns for security)
1143
+ */
1144
+ async createPasswordResetIntent(email, userRealmName) {
1145
+ this.log.trace("Creating password reset intent", {
1146
+ email,
1147
+ userRealmName
1148
+ });
1149
+ const intentId = randomUUID();
1150
+ const expiresAt = this.dateTimeProvider.now().add(INTENT_TTL_MINUTES$1, "minutes").toISOString();
1151
+ const user = await this.users(userRealmName).findOne({ where: { email: { eq: email } } }).catch(() => void 0);
1152
+ if (!user) {
1153
+ this.log.debug("Password reset requested for non-existent email", { email });
1154
+ return {
1155
+ intentId,
1156
+ expiresAt
1157
+ };
1158
+ }
1159
+ const identity = await this.identities(userRealmName).findOne({ where: {
1160
+ userId: { eq: user.id },
1161
+ provider: { eq: "credentials" }
1162
+ } }).catch(() => void 0);
1163
+ if (!identity) {
1164
+ this.log.debug("Password reset requested for user without credentials", { userId: user.id });
1165
+ return {
1166
+ intentId,
1167
+ expiresAt
1168
+ };
1169
+ }
1170
+ try {
1171
+ const verification = await this.verificationController.requestVerificationCode({
1172
+ params: { type: "code" },
1173
+ body: { target: email }
1174
+ });
1175
+ await this.userNotifications.passwordReset.push({
1176
+ contact: email,
1177
+ variables: {
1178
+ email,
1179
+ code: verification.token,
1180
+ expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1181
+ }
1182
+ });
1183
+ const intent = {
1184
+ email,
1185
+ userId: user.id,
1186
+ identityId: identity.id,
1187
+ realmName: userRealmName,
1188
+ expiresAt
1189
+ };
1190
+ await this.intentCache.set(intentId, intent);
1191
+ this.log.info("Password reset intent created", {
1192
+ intentId,
1193
+ userId: user.id,
1194
+ email
1195
+ });
1196
+ } catch (error) {
1197
+ this.log.warn("Failed to create password reset verification", error);
1198
+ }
1199
+ return {
1200
+ intentId,
1201
+ expiresAt
1202
+ };
1203
+ }
1204
+ /**
1205
+ * Phase 2: Complete password reset using an intent.
1206
+ *
1207
+ * Validates the verification code, updates the password,
1208
+ * and invalidates all existing sessions.
1209
+ *
1210
+ * @param body - Request body with intentId, code, and newPassword
1211
+ */
1212
+ async completePasswordReset(body) {
1213
+ this.log.trace("Completing password reset", { intentId: body.intentId });
1214
+ const intent = await this.intentCache.get(body.intentId);
1215
+ if (!intent) {
1216
+ this.log.warn("Invalid or expired password reset intent", { intentId: body.intentId });
1217
+ throw new HttpError({
1218
+ status: 410,
1219
+ message: "Invalid or expired password reset intent"
1220
+ });
1221
+ }
1222
+ if ((await this.verificationController.validateVerificationCode({
1223
+ params: { type: "code" },
1224
+ body: {
1225
+ target: intent.email,
1226
+ token: body.code
1227
+ }
1228
+ }).catch(() => {
1229
+ this.log.warn("Invalid verification code for password reset", {
1230
+ intentId: body.intentId,
1231
+ email: intent.email
1232
+ });
1233
+ throw new BadRequestError("Invalid or expired verification code");
1234
+ })).alreadyVerified) {
1235
+ this.log.warn("Verification code reuse attempt", {
1236
+ intentId: body.intentId,
1237
+ email: intent.email
1238
+ });
1239
+ throw new BadRequestError("Verification code has already been used");
1240
+ }
1241
+ await this.intentCache.invalidate(body.intentId);
869
1242
  const hashedPassword = await this.cryptoProvider.hashPassword(body.newPassword);
870
1243
  await this.identities(intent.realmName).updateById(intent.identityId, { password: hashedPassword });
871
1244
  await this.sessions(intent.realmName).deleteMany({ userId: { eq: intent.userId } });
@@ -873,6 +1246,23 @@ var CredentialService = class {
873
1246
  userId: intent.userId,
874
1247
  email: intent.email
875
1248
  });
1249
+ const realm = this.userRealmProvider.getRealm(intent.realmName);
1250
+ await this.auditService.recordUser("update", {
1251
+ userId: intent.userId,
1252
+ userEmail: intent.email,
1253
+ userRealm: realm.name,
1254
+ resourceId: intent.userId,
1255
+ description: "Password reset completed",
1256
+ metadata: { email: intent.email }
1257
+ });
1258
+ await this.auditService.record("security", "sessions_invalidated", {
1259
+ userId: intent.userId,
1260
+ userEmail: intent.email,
1261
+ userRealm: realm.name,
1262
+ resourceId: intent.userId,
1263
+ severity: "warning",
1264
+ description: "All sessions invalidated after password reset"
1265
+ });
876
1266
  }
877
1267
  /**
878
1268
  * @deprecated Use createPasswordResetIntent instead
@@ -915,6 +1305,23 @@ var CredentialService = class {
915
1305
  const hashedPassword = await this.cryptoProvider.hashPassword(newPassword);
916
1306
  await this.identities(userRealmName).updateById(identity.id, { password: hashedPassword });
917
1307
  await this.sessions(userRealmName).deleteMany({ userId: { eq: user.id } });
1308
+ const realm = this.userRealmProvider.getRealm(userRealmName);
1309
+ await this.auditService.recordUser("update", {
1310
+ userId: user.id,
1311
+ userEmail: email,
1312
+ userRealm: realm.name,
1313
+ resourceId: user.id,
1314
+ description: "Password reset completed (legacy)",
1315
+ metadata: { email }
1316
+ });
1317
+ await this.auditService.record("security", "sessions_invalidated", {
1318
+ userId: user.id,
1319
+ userEmail: email,
1320
+ userRealm: realm.name,
1321
+ resourceId: user.id,
1322
+ severity: "warning",
1323
+ description: "All sessions invalidated after password reset"
1324
+ });
918
1325
  }
919
1326
  };
920
1327
 
@@ -928,6 +1335,7 @@ var RegistrationService = class {
928
1335
  verificationController = $client();
929
1336
  userNotifications = $inject(UserNotifications);
930
1337
  userRealmProvider = $inject(UserRealmProvider);
1338
+ auditService = $inject(AuditService);
931
1339
  intentCache = $cache({
932
1340
  name: "registration-intents",
933
1341
  ttl: [INTENT_TTL_MINUTES, "minutes"]
@@ -1069,6 +1477,20 @@ var RegistrationService = class {
1069
1477
  email: user.email,
1070
1478
  username: user.username
1071
1479
  });
1480
+ const realm = this.userRealmProvider.getRealm(userRealmName);
1481
+ await this.auditService.recordUser("create", {
1482
+ userId: user.id,
1483
+ userEmail: user.email ?? void 0,
1484
+ userRealm: realm.name,
1485
+ resourceId: user.id,
1486
+ description: "User registered",
1487
+ metadata: {
1488
+ username: user.username,
1489
+ email: user.email,
1490
+ emailVerified: user.emailVerified,
1491
+ registrationMethod: "credentials"
1492
+ }
1493
+ });
1072
1494
  return user;
1073
1495
  }
1074
1496
  /**
@@ -1090,317 +1512,95 @@ var RegistrationService = class {
1090
1512
  }
1091
1513
  if (body.phoneNumber) {
1092
1514
  if (await userRepository.findOne({ where: { phoneNumber: { eq: body.phoneNumber } } }).catch(() => void 0)) {
1093
- this.log.debug("Phone number already taken", { phoneNumber: body.phoneNumber });
1094
- throw new ConflictError("User with this phone number already exists");
1095
- }
1096
- }
1097
- }
1098
- /**
1099
- * Send email verification code.
1100
- */
1101
- async sendEmailVerification(email) {
1102
- this.log.debug("Sending email verification code", { email });
1103
- try {
1104
- const verification = await this.verificationController.requestVerificationCode({
1105
- params: { type: "code" },
1106
- body: { target: email }
1107
- });
1108
- await this.userNotifications.emailVerification.push({
1109
- contact: email,
1110
- variables: {
1111
- email,
1112
- code: verification.token,
1113
- expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1114
- }
1115
- });
1116
- this.log.debug("Email verification code sent", { email });
1117
- } catch (error) {
1118
- this.log.warn("Failed to send email verification code", error);
1119
- }
1120
- }
1121
- /**
1122
- * Send phone verification code.
1123
- */
1124
- async sendPhoneVerification(phoneNumber) {
1125
- this.log.debug("Sending phone verification code", { phoneNumber });
1126
- try {
1127
- const verification = await this.verificationController.requestVerificationCode({
1128
- params: { type: "code" },
1129
- body: { target: phoneNumber }
1130
- });
1131
- await this.userNotifications.phoneVerification.push({
1132
- contact: phoneNumber,
1133
- variables: {
1134
- phoneNumber,
1135
- code: verification.token,
1136
- expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1137
- }
1138
- });
1139
- this.log.debug("Phone verification code sent", { phoneNumber });
1140
- } catch (error) {
1141
- this.log.warn("Failed to send phone verification code", {
1142
- phoneNumber,
1143
- error
1144
- });
1145
- }
1146
- }
1147
- /**
1148
- * Verify email code using verification service.
1149
- */
1150
- async verifyEmailCode(email, code) {
1151
- if ((await this.verificationController.validateVerificationCode({
1152
- params: { type: "code" },
1153
- body: {
1154
- target: email,
1155
- token: code
1156
- }
1157
- }).catch(() => {
1158
- this.log.warn("Invalid email verification code", { email });
1159
- throw new BadRequestError("Invalid or expired email verification code");
1160
- })).alreadyVerified) {
1161
- this.log.warn("Email verification code already used", { email });
1162
- throw new BadRequestError("Email verification code has already been used");
1163
- }
1164
- }
1165
- /**
1166
- * Verify phone code using verification service.
1167
- */
1168
- async verifyPhoneCode(phoneNumber, code) {
1169
- if ((await this.verificationController.validateVerificationCode({
1170
- params: { type: "code" },
1171
- body: {
1172
- target: phoneNumber,
1173
- token: code
1174
- }
1175
- }).catch(() => {
1176
- this.log.warn("Invalid phone verification code", { phoneNumber });
1177
- throw new BadRequestError("Invalid or expired phone verification code");
1178
- })).alreadyVerified) {
1179
- this.log.warn("Phone verification code already used", { phoneNumber });
1180
- throw new BadRequestError("Phone verification code has already been used");
1181
- }
1182
- }
1183
- };
1184
-
1185
- //#endregion
1186
- //#region ../../src/api/users/services/UserService.ts
1187
- var UserService = class {
1188
- log = $logger();
1189
- verificationController = $client();
1190
- userNotifications = $inject(UserNotifications);
1191
- userRealmProvider = $inject(UserRealmProvider);
1192
- users(userRealmName) {
1193
- return this.userRealmProvider.userRepository(userRealmName);
1194
- }
1195
- /**
1196
- * Request email verification for a user.
1197
- * @param email - The email address to verify.
1198
- * @param userRealmName - Optional realm name.
1199
- * @param method - The verification method: "code" (default) or "link".
1200
- * @param verifyUrl - Base URL for verification link (required when method is "link").
1201
- */
1202
- async requestEmailVerification(email, userRealmName, method = "code", verifyUrl) {
1203
- this.log.trace("Requesting email verification", {
1204
- email,
1205
- userRealmName,
1206
- method
1207
- });
1208
- const user = await this.users(userRealmName).findOne({ where: { email: { eq: email } } }).catch(() => void 0);
1209
- if (!user) {
1210
- this.log.debug("Email verification requested for non-existent user", { email });
1211
- return true;
1212
- }
1213
- if (user.emailVerified) {
1214
- this.log.debug("Email verification requested for already verified user", {
1215
- email,
1216
- userId: user.id
1217
- });
1218
- return true;
1219
- }
1220
- try {
1221
- const verification = await this.verificationController.requestVerificationCode({
1222
- params: { type: method },
1223
- body: { target: email }
1224
- });
1225
- if (method === "link") {
1226
- const url = new URL(verifyUrl || "/verify-email", "http://localhost");
1227
- url.searchParams.set("email", email);
1228
- url.searchParams.set("token", verification.token);
1229
- const fullVerifyUrl = verifyUrl ? `${verifyUrl}${url.search}` : url.pathname + url.search;
1230
- await this.userNotifications.emailVerificationLink.push({
1231
- contact: email,
1232
- variables: {
1233
- email,
1234
- verifyUrl: fullVerifyUrl,
1235
- expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1236
- }
1237
- });
1238
- this.log.debug("Email verification link sent", {
1239
- email,
1240
- userId: user.id
1241
- });
1242
- } else {
1243
- await this.userNotifications.emailVerification.push({
1244
- contact: email,
1245
- variables: {
1246
- email,
1247
- code: verification.token,
1248
- expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1249
- }
1250
- });
1251
- this.log.debug("Email verification code sent", {
1252
- email,
1253
- userId: user.id
1254
- });
1255
- }
1256
- } catch (error) {
1257
- this.log.warn("Failed to send email verification", {
1258
- email,
1259
- error
1260
- });
1261
- }
1262
- return true;
1263
- }
1264
- /**
1265
- * Verify a user's email using a valid verification token.
1266
- * Supports both code (6-digit) and link (UUID) verification tokens.
1267
- */
1268
- async verifyEmail(email, token, userRealmName) {
1269
- this.log.trace("Verifying email", {
1270
- email,
1271
- userRealmName
1272
- });
1273
- const type = /^\d{6}$/.test(token) ? "code" : "link";
1274
- if ((await this.verificationController.validateVerificationCode({
1275
- params: { type },
1276
- body: {
1277
- target: email,
1278
- token
1279
- }
1280
- }).catch(() => {
1281
- this.log.warn("Invalid email verification token", {
1282
- email,
1283
- type
1284
- });
1285
- throw new BadRequestError("Invalid or expired verification token");
1286
- })).alreadyVerified) {
1287
- this.log.warn("Email verification token already used", { email });
1288
- throw new BadRequestError("Invalid or expired verification token");
1289
- }
1290
- const user = await this.users(userRealmName).findOne({ where: { email: { eq: email } } });
1291
- await this.users(userRealmName).updateById(user.id, { emailVerified: true });
1292
- this.log.info("Email verified", {
1293
- email,
1294
- userId: user.id,
1295
- type
1296
- });
1297
- }
1298
- /**
1299
- * Check if an email is verified.
1300
- */
1301
- async isEmailVerified(email, userRealmName) {
1302
- this.log.trace("Checking if email is verified", {
1303
- email,
1304
- userRealmName
1305
- });
1306
- return (await this.users(userRealmName).findOne({ where: { email: { eq: email } } }).catch(() => void 0))?.emailVerified ?? false;
1307
- }
1308
- /**
1309
- * Find users with pagination and filtering.
1310
- */
1311
- async findUsers(q = {}, userRealmName) {
1312
- this.log.trace("Finding users", {
1313
- query: q,
1314
- userRealmName
1315
- });
1316
- q.sort ??= "-createdAt";
1317
- const where = this.users(userRealmName).createQueryWhere();
1318
- if (q.email) where.email = { like: q.email };
1319
- if (q.enabled !== void 0) where.enabled = { eq: q.enabled };
1320
- if (q.emailVerified !== void 0) where.emailVerified = { eq: q.emailVerified };
1321
- if (q.roles) where.roles = { arrayContains: q.roles };
1322
- if (q.query) Object.assign(where, parseQueryString(q.query));
1323
- const result = await this.users(userRealmName).paginate(q, { where }, { count: true });
1324
- this.log.debug("Users found", {
1325
- count: result.content.length,
1326
- total: result.page.totalElements
1327
- });
1328
- return result;
1515
+ this.log.debug("Phone number already taken", { phoneNumber: body.phoneNumber });
1516
+ throw new ConflictError("User with this phone number already exists");
1517
+ }
1518
+ }
1329
1519
  }
1330
1520
  /**
1331
- * Get a user by ID.
1521
+ * Send email verification code.
1332
1522
  */
1333
- async getUserById(id, userRealmName) {
1334
- this.log.trace("Getting user by ID", {
1335
- id,
1336
- userRealmName
1337
- });
1338
- return await this.users(userRealmName).findById(id);
1523
+ async sendEmailVerification(email) {
1524
+ this.log.debug("Sending email verification code", { email });
1525
+ try {
1526
+ const verification = await this.verificationController.requestVerificationCode({
1527
+ params: { type: "code" },
1528
+ body: { target: email }
1529
+ });
1530
+ await this.userNotifications.emailVerification.push({
1531
+ contact: email,
1532
+ variables: {
1533
+ email,
1534
+ code: verification.token,
1535
+ expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1536
+ }
1537
+ });
1538
+ this.log.debug("Email verification code sent", { email });
1539
+ } catch (error) {
1540
+ this.log.warn("Failed to send email verification code", error);
1541
+ }
1339
1542
  }
1340
1543
  /**
1341
- * Create a new user.
1544
+ * Send phone verification code.
1342
1545
  */
1343
- async createUser(data, userRealmName) {
1344
- this.log.trace("Creating user", {
1345
- username: data.username,
1346
- email: data.email,
1347
- userRealmName
1348
- });
1349
- const realm = this.userRealmProvider.getRealm(userRealmName);
1350
- if (data.username) {
1351
- if (await this.users(userRealmName).findOne({ where: { username: { eq: data.username } } }).catch(() => void 0)) {
1352
- this.log.debug("Username already taken", { username: data.username });
1353
- throw new BadRequestError("User with this username already exists");
1354
- }
1355
- }
1356
- if (data.email) {
1357
- if (await this.users(userRealmName).findOne({ where: { email: { eq: data.email } } }).catch(() => void 0)) {
1358
- this.log.debug("Email already taken", { email: data.email });
1359
- throw new BadRequestError("User with this email already exists");
1360
- }
1361
- }
1362
- if (data.phoneNumber) {
1363
- if (await this.users(userRealmName).findOne({ where: { phoneNumber: { eq: data.phoneNumber } } }).catch(() => void 0)) {
1364
- this.log.debug("Phone number already taken", { phoneNumber: data.phoneNumber });
1365
- throw new BadRequestError("User with this phone number already exists");
1366
- }
1546
+ async sendPhoneVerification(phoneNumber) {
1547
+ this.log.debug("Sending phone verification code", { phoneNumber });
1548
+ try {
1549
+ const verification = await this.verificationController.requestVerificationCode({
1550
+ params: { type: "code" },
1551
+ body: { target: phoneNumber }
1552
+ });
1553
+ await this.userNotifications.phoneVerification.push({
1554
+ contact: phoneNumber,
1555
+ variables: {
1556
+ phoneNumber,
1557
+ code: verification.token,
1558
+ expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1559
+ }
1560
+ });
1561
+ this.log.debug("Phone verification code sent", { phoneNumber });
1562
+ } catch (error) {
1563
+ this.log.warn("Failed to send phone verification code", {
1564
+ phoneNumber,
1565
+ error
1566
+ });
1367
1567
  }
1368
- const user = await this.users(userRealmName).create({
1369
- ...data,
1370
- roles: data.roles ?? ["user"],
1371
- realm: realm.name
1372
- });
1373
- this.log.info("User created", {
1374
- userId: user.id,
1375
- username: user.username,
1376
- email: user.email
1377
- });
1378
- return user;
1379
1568
  }
1380
1569
  /**
1381
- * Update an existing user.
1570
+ * Verify email code using verification service.
1382
1571
  */
1383
- async updateUser(id, data, userRealmName) {
1384
- this.log.trace("Updating user", {
1385
- id,
1386
- userRealmName
1387
- });
1388
- await this.getUserById(id, userRealmName);
1389
- const user = await this.users(userRealmName).updateById(id, data);
1390
- this.log.debug("User updated", { userId: id });
1391
- return user;
1572
+ async verifyEmailCode(email, code) {
1573
+ if ((await this.verificationController.validateVerificationCode({
1574
+ params: { type: "code" },
1575
+ body: {
1576
+ target: email,
1577
+ token: code
1578
+ }
1579
+ }).catch(() => {
1580
+ this.log.warn("Invalid email verification code", { email });
1581
+ throw new BadRequestError("Invalid or expired email verification code");
1582
+ })).alreadyVerified) {
1583
+ this.log.warn("Email verification code already used", { email });
1584
+ throw new BadRequestError("Email verification code has already been used");
1585
+ }
1392
1586
  }
1393
1587
  /**
1394
- * Delete a user by ID.
1588
+ * Verify phone code using verification service.
1395
1589
  */
1396
- async deleteUser(id, userRealmName) {
1397
- this.log.trace("Deleting user", {
1398
- id,
1399
- userRealmName
1400
- });
1401
- await this.getUserById(id, userRealmName);
1402
- await this.users(userRealmName).deleteById(id);
1403
- this.log.info("User deleted", { userId: id });
1590
+ async verifyPhoneCode(phoneNumber, code) {
1591
+ if ((await this.verificationController.validateVerificationCode({
1592
+ params: { type: "code" },
1593
+ body: {
1594
+ target: phoneNumber,
1595
+ token: code
1596
+ }
1597
+ }).catch(() => {
1598
+ this.log.warn("Invalid phone verification code", { phoneNumber });
1599
+ throw new BadRequestError("Invalid or expired phone verification code");
1600
+ })).alreadyVerified) {
1601
+ this.log.warn("Phone verification code already used", { phoneNumber });
1602
+ throw new BadRequestError("Phone verification code has already been used");
1603
+ }
1404
1604
  }
1405
1605
  };
1406
1606
 
@@ -1417,6 +1617,7 @@ var UserController = class {
1417
1617
  * Validates data, creates verification sessions, and stores intent in cache.
1418
1618
  */
1419
1619
  createRegistrationIntent = $action({
1620
+ group: this.group,
1420
1621
  method: "POST",
1421
1622
  path: `${this.url}/register`,
1422
1623
  secure: false,
@@ -1428,55 +1629,11 @@ var UserController = class {
1428
1629
  handler: ({ body, query }) => this.registrationService.createRegistrationIntent(body, query.userRealmName)
1429
1630
  });
1430
1631
  /**
1431
- * Find users with pagination and filtering.
1432
- */
1433
- findUsers = $action({
1434
- path: this.url,
1435
- group: this.group,
1436
- description: "Find users with pagination and filtering",
1437
- schema: {
1438
- query: t.extend(userQuerySchema, { userRealmName: t.optional(t.string()) }),
1439
- response: pg.page(userResourceSchema)
1440
- },
1441
- handler: ({ query }) => {
1442
- const { userRealmName, ...q } = query;
1443
- return this.userService.findUsers(q, userRealmName);
1444
- }
1445
- });
1446
- /**
1447
- * Get a user by ID.
1448
- */
1449
- getUser = $action({
1450
- path: `${this.url}/:id`,
1451
- group: this.group,
1452
- description: "Get a user by ID",
1453
- schema: {
1454
- params: t.object({ id: t.uuid() }),
1455
- query: t.object({ userRealmName: t.optional(t.string()) }),
1456
- response: userResourceSchema
1457
- },
1458
- handler: ({ params, query }) => this.userService.getUserById(params.id, query.userRealmName)
1459
- });
1460
- /**
1461
- * Create a new user.
1462
- */
1463
- createUser = $action({
1464
- method: "POST",
1465
- path: this.url,
1466
- group: this.group,
1467
- description: "Create a new user",
1468
- schema: {
1469
- query: t.object({ userRealmName: t.optional(t.string()) }),
1470
- body: createUserSchema,
1471
- response: userResourceSchema
1472
- },
1473
- handler: ({ body, query }) => this.userService.createUser(body, query.userRealmName)
1474
- });
1475
- /**
1476
1632
  * Phase 2: Complete registration using an intent.
1477
1633
  * Validates verification codes and creates the user.
1478
1634
  */
1479
1635
  createUserFromIntent = $action({
1636
+ group: this.group,
1480
1637
  method: "POST",
1481
1638
  path: `${this.url}/register/complete`,
1482
1639
  secure: false,
@@ -1487,47 +1644,11 @@ var UserController = class {
1487
1644
  handler: ({ body }) => this.registrationService.completeRegistration(body)
1488
1645
  });
1489
1646
  /**
1490
- * Update a user.
1491
- */
1492
- updateUser = $action({
1493
- method: "PATCH",
1494
- path: `${this.url}/:id`,
1495
- group: this.group,
1496
- description: "Update a user",
1497
- schema: {
1498
- params: t.object({ id: t.uuid() }),
1499
- query: t.object({ userRealmName: t.optional(t.string()) }),
1500
- body: updateUserSchema,
1501
- response: userResourceSchema
1502
- },
1503
- handler: ({ params, body, query }) => this.userService.updateUser(params.id, body, query.userRealmName)
1504
- });
1505
- /**
1506
- * Delete a user.
1507
- */
1508
- deleteUser = $action({
1509
- method: "DELETE",
1510
- path: `${this.url}/:id`,
1511
- group: this.group,
1512
- description: "Delete a user",
1513
- schema: {
1514
- params: t.object({ id: t.uuid() }),
1515
- query: t.object({ userRealmName: t.optional(t.string()) }),
1516
- response: okSchema
1517
- },
1518
- handler: async ({ params, query }) => {
1519
- await this.userService.deleteUser(params.id, query.userRealmName);
1520
- return {
1521
- ok: true,
1522
- id: params.id
1523
- };
1524
- }
1525
- });
1526
- /**
1527
1647
  * Phase 1: Create a password reset intent.
1528
1648
  * Validates email, sends verification code, and stores intent in cache.
1529
1649
  */
1530
1650
  createPasswordResetIntent = $action({
1651
+ group: this.group,
1531
1652
  method: "POST",
1532
1653
  path: `${this.url}/password-reset`,
1533
1654
  secure: false,
@@ -1543,6 +1664,7 @@ var UserController = class {
1543
1664
  * Validates verification code, updates password, and invalidates sessions.
1544
1665
  */
1545
1666
  completePasswordReset = $action({
1667
+ group: this.group,
1546
1668
  method: "POST",
1547
1669
  path: `${this.url}/password-reset/complete`,
1548
1670
  secure: false,
@@ -1725,6 +1847,7 @@ const userRealmConfigSchema = t.object({
1725
1847
  */
1726
1848
  var UserRealmController = class {
1727
1849
  url = "/realms";
1850
+ group = "realms";
1728
1851
  userRealmProvider = $inject(UserRealmProvider);
1729
1852
  serverAuthProvider = $inject(ServerAuthProvider);
1730
1853
  /**
@@ -1732,6 +1855,7 @@ var UserRealmController = class {
1732
1855
  * This endpoint is not exposed in the API documentation.
1733
1856
  */
1734
1857
  getRealmConfig = $action({
1858
+ group: this.group,
1735
1859
  method: "GET",
1736
1860
  path: `${this.url}/config`,
1737
1861
  secure: false,
@@ -1753,6 +1877,7 @@ var UserRealmController = class {
1753
1877
  }
1754
1878
  });
1755
1879
  checkUsernameAvailability = $action({
1880
+ group: this.group,
1756
1881
  path: `${this.url}/check-username`,
1757
1882
  secure: false,
1758
1883
  schema: {
@@ -1777,6 +1902,7 @@ var SessionService = class {
1777
1902
  log = $logger();
1778
1903
  userRealmProvider = $inject(UserRealmProvider);
1779
1904
  fileController = $client();
1905
+ auditService = $inject(AuditService);
1780
1906
  users(userRealmName) {
1781
1907
  return this.userRealmProvider.userRepository(userRealmName);
1782
1908
  }
@@ -1816,6 +1942,14 @@ var SessionService = class {
1816
1942
  username,
1817
1943
  realm: name
1818
1944
  });
1945
+ await this.auditService.recordAuth("login_failed", {
1946
+ userRealm: name,
1947
+ description: "Invalid login identifier format",
1948
+ metadata: {
1949
+ provider,
1950
+ username
1951
+ }
1952
+ });
1819
1953
  throw new InvalidCredentialsError();
1820
1954
  }
1821
1955
  const user = await users$1.findOne({ where }).catch(() => void 0);
@@ -1825,6 +1959,14 @@ var SessionService = class {
1825
1959
  username,
1826
1960
  realm: name
1827
1961
  });
1962
+ await this.auditService.recordAuth("login_failed", {
1963
+ userRealm: name,
1964
+ description: "User not found",
1965
+ metadata: {
1966
+ provider,
1967
+ username
1968
+ }
1969
+ });
1828
1970
  throw new InvalidCredentialsError();
1829
1971
  }
1830
1972
  const identity = await identities$1.findOne({ where: {
@@ -1847,8 +1989,28 @@ var SessionService = class {
1847
1989
  username,
1848
1990
  realm: name
1849
1991
  });
1992
+ await this.auditService.recordAuth("login_failed", {
1993
+ userRealm: name,
1994
+ resourceId: user.id,
1995
+ description: "Invalid password",
1996
+ metadata: {
1997
+ provider,
1998
+ username
1999
+ }
2000
+ });
1850
2001
  throw new InvalidCredentialsError();
1851
2002
  }
2003
+ await this.auditService.recordAuth("login", {
2004
+ userId: user.id,
2005
+ userEmail: user.email ?? void 0,
2006
+ userRealm: name,
2007
+ resourceId: user.id,
2008
+ description: `User logged in via ${provider}`,
2009
+ metadata: {
2010
+ provider,
2011
+ username
2012
+ }
2013
+ });
1852
2014
  return user;
1853
2015
  } catch (error) {
1854
2016
  if (error instanceof InvalidCredentialsError) throw error;
@@ -1899,6 +2061,14 @@ var SessionService = class {
1899
2061
  sessionId: session.id,
1900
2062
  userId: session.userId
1901
2063
  });
2064
+ const { name } = this.userRealmProvider.getRealm(userRealmName);
2065
+ await this.auditService.recordAuth("token_refresh", {
2066
+ userId: user.id,
2067
+ userEmail: user.email ?? void 0,
2068
+ userRealm: name,
2069
+ sessionId: session.id,
2070
+ description: "Session token refreshed"
2071
+ });
1902
2072
  return {
1903
2073
  user,
1904
2074
  expiresIn: expiresAt.unix() - now.unix(),
@@ -1907,8 +2077,18 @@ var SessionService = class {
1907
2077
  }
1908
2078
  async deleteSession(refreshToken, userRealmName) {
1909
2079
  this.log.trace("Deleting session");
2080
+ const session = await this.sessions(userRealmName).findOne({ where: { refreshToken: { eq: refreshToken } } }).catch(() => void 0);
1910
2081
  await this.sessions(userRealmName).deleteOne({ refreshToken });
1911
2082
  this.log.debug("Session deleted");
2083
+ if (session) {
2084
+ const { name } = this.userRealmProvider.getRealm(userRealmName);
2085
+ await this.auditService.recordAuth("logout", {
2086
+ userId: session.userId,
2087
+ userRealm: name,
2088
+ sessionId: session.id,
2089
+ description: "User logged out"
2090
+ });
2091
+ }
1912
2092
  }
1913
2093
  async link(provider, profile, userRealmName) {
1914
2094
  this.log.trace("Linking OAuth2 profile", {
@@ -1929,7 +2109,19 @@ var SessionService = class {
1929
2109
  identityId: identity.id,
1930
2110
  userId: identity.userId
1931
2111
  });
1932
- return users$1.findById(identity.userId);
2112
+ const user$1 = await users$1.findById(identity.userId);
2113
+ await this.auditService.recordAuth("login", {
2114
+ userId: user$1.id,
2115
+ userEmail: user$1.email ?? void 0,
2116
+ userRealm: realm.name,
2117
+ resourceId: user$1.id,
2118
+ description: `User logged in via OAuth2 (${provider})`,
2119
+ metadata: {
2120
+ provider,
2121
+ providerUserId: profile.sub
2122
+ }
2123
+ });
2124
+ return user$1;
1933
2125
  }
1934
2126
  if (!profile.email) {
1935
2127
  this.log.debug("OAuth2 profile has no email, returning profile as-is", {
@@ -1954,6 +2146,18 @@ var SessionService = class {
1954
2146
  providerUserId: profile.sub,
1955
2147
  userId: existing.id
1956
2148
  });
2149
+ await this.auditService.recordAuth("login", {
2150
+ userId: existing.id,
2151
+ userEmail: existing.email ?? void 0,
2152
+ userRealm: realm.name,
2153
+ resourceId: existing.id,
2154
+ description: `OAuth2 identity linked to existing user (${provider})`,
2155
+ metadata: {
2156
+ provider,
2157
+ providerUserId: profile.sub,
2158
+ linked: true
2159
+ }
2160
+ });
1957
2161
  return existing;
1958
2162
  }
1959
2163
  const user = await users$1.create({
@@ -1990,6 +2194,31 @@ var SessionService = class {
1990
2194
  email: user.email,
1991
2195
  username: user.username
1992
2196
  });
2197
+ await this.auditService.recordUser("create", {
2198
+ userId: user.id,
2199
+ userEmail: user.email ?? void 0,
2200
+ userRealm: realm.name,
2201
+ resourceId: user.id,
2202
+ description: `User created via OAuth2 (${provider})`,
2203
+ metadata: {
2204
+ provider,
2205
+ providerUserId: profile.sub,
2206
+ username: user.username,
2207
+ email: user.email
2208
+ }
2209
+ });
2210
+ await this.auditService.recordAuth("login", {
2211
+ userId: user.id,
2212
+ userEmail: user.email ?? void 0,
2213
+ userRealm: realm.name,
2214
+ resourceId: user.id,
2215
+ description: `First login via OAuth2 (${provider})`,
2216
+ metadata: {
2217
+ provider,
2218
+ providerUserId: profile.sub,
2219
+ firstLogin: true
2220
+ }
2221
+ });
1993
2222
  return user;
1994
2223
  }
1995
2224
  };
@@ -2015,10 +2244,13 @@ const $userRealm = (options = {}) => {
2015
2244
  const securityProvider = alepha.inject(SecurityProvider);
2016
2245
  const userRealmProvider = alepha.inject(UserRealmProvider);
2017
2246
  const name = options.realm?.name ?? DEFAULT_USER_REALM_NAME;
2247
+ options.settings ??= {};
2248
+ if (options.settings.emailRequired) options.settings.emailEnabled = true;
2249
+ if (options.settings.usernameRequired) options.settings.usernameEnabled = true;
2250
+ if (options.settings.phoneRequired) options.settings.phoneEnabled = true;
2018
2251
  const userRealm = userRealmProvider.register(name, options);
2019
- if (options.modules?.audits) alepha.with(AlephaApiAudits);
2020
- if (options.modules?.files) alepha.with(AlephaApiFiles);
2021
- if (options.modules?.jobs) alepha.with(AlephaApiJobs);
2252
+ alepha.with(AlephaApiFiles);
2253
+ alepha.with(AlephaApiAudits);
2022
2254
  const realm = $realm({
2023
2255
  ...options.realm,
2024
2256
  name,
@@ -2141,6 +2373,8 @@ const AlephaApiUsers = $module({
2141
2373
  services: [
2142
2374
  AlephaApiVerification,
2143
2375
  AlephaApiNotifications,
2376
+ AlephaServerHelmet,
2377
+ AlephaServerCompress,
2144
2378
  AlephaEmail,
2145
2379
  UserRealmProvider,
2146
2380
  SessionService,
@@ -2150,13 +2384,14 @@ const AlephaApiUsers = $module({
2150
2384
  UserService,
2151
2385
  IdentityService,
2152
2386
  UserController,
2153
- SessionController,
2154
- IdentityController,
2387
+ AdminUserController,
2388
+ AdminSessionController,
2389
+ AdminIdentityController,
2155
2390
  UserRealmController,
2156
2391
  UserNotifications
2157
2392
  ]
2158
2393
  });
2159
2394
 
2160
2395
  //#endregion
2161
- export { $userRealm, AlephaApiUsers, CredentialService, DEFAULT_USER_REALM_NAME, IdentityController, IdentityService, RegistrationService, SessionController, SessionCrudService, SessionService, UserController, UserRealmController, UserRealmProvider, UserService, completePasswordResetRequestSchema, completeRegistrationRequestSchema, createUserSchema, identities, identityQuerySchema, identityResourceSchema, loginSchema, passwordResetIntentResponseSchema, realmAuthSettingsAtom, registerSchema, registrationIntentResponseSchema, resetPasswordRequestSchema, resetPasswordSchema, sessionQuerySchema, sessionResourceSchema, sessions, updateUserSchema, userQuerySchema, userRealmConfigSchema, userResourceSchema, users };
2396
+ export { $userRealm, AdminIdentityController, AdminSessionController, AdminUserController, AlephaApiUsers, CredentialService, DEFAULT_USER_REALM_NAME, IdentityService, RegistrationService, SessionCrudService, SessionService, UserController, UserRealmController, UserRealmProvider, UserService, completePasswordResetRequestSchema, completeRegistrationRequestSchema, createUserSchema, identities, identityQuerySchema, identityResourceSchema, loginSchema, passwordResetIntentResponseSchema, realmAuthSettingsAtom, registerSchema, registrationIntentResponseSchema, resetPasswordRequestSchema, resetPasswordSchema, sessionQuerySchema, sessionResourceSchema, sessions, updateUserSchema, userQuerySchema, userRealmConfigSchema, userResourceSchema, users };
2162
2397
  //# sourceMappingURL=index.js.map