alepha 0.14.2 → 0.14.4

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 (405) hide show
  1. package/README.md +1 -1
  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 +706 -785
  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 +58 -137
  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 +29 -108
  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 +504 -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 +277 -351
  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 +787 -852
  35. package/dist/api/users/index.d.ts.map +1 -1
  36. package/dist/api/users/index.js +827 -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 +128 -128
  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/bin/index.d.ts +1 -2
  45. package/dist/bin/index.js +0 -1
  46. package/dist/bin/index.js.map +1 -1
  47. package/dist/cli/index.d.ts +252 -131
  48. package/dist/cli/index.d.ts.map +1 -1
  49. package/dist/cli/index.js +595 -395
  50. package/dist/cli/index.js.map +1 -1
  51. package/dist/command/index.d.ts +46 -11
  52. package/dist/command/index.d.ts.map +1 -1
  53. package/dist/command/index.js +99 -19
  54. package/dist/command/index.js.map +1 -1
  55. package/dist/core/index.browser.js +40 -22
  56. package/dist/core/index.browser.js.map +1 -1
  57. package/dist/core/index.d.ts +45 -1
  58. package/dist/core/index.d.ts.map +1 -1
  59. package/dist/core/index.js +40 -22
  60. package/dist/core/index.js.map +1 -1
  61. package/dist/core/index.native.js +40 -22
  62. package/dist/core/index.native.js.map +1 -1
  63. package/dist/fake/index.js +195 -168
  64. package/dist/fake/index.js.map +1 -1
  65. package/dist/file/index.d.ts +8 -0
  66. package/dist/file/index.d.ts.map +1 -1
  67. package/dist/file/index.js +3 -0
  68. package/dist/file/index.js.map +1 -1
  69. package/dist/logger/index.d.ts +1 -1
  70. package/dist/logger/index.d.ts.map +1 -1
  71. package/dist/logger/index.js +12 -2
  72. package/dist/logger/index.js.map +1 -1
  73. package/dist/mcp/index.js +1 -1
  74. package/dist/mcp/index.js.map +1 -1
  75. package/dist/orm/index.d.ts +59 -195
  76. package/dist/orm/index.d.ts.map +1 -1
  77. package/dist/orm/index.js +201 -430
  78. package/dist/orm/index.js.map +1 -1
  79. package/dist/security/index.d.ts +1 -1
  80. package/dist/security/index.d.ts.map +1 -1
  81. package/dist/security/index.js +1 -1
  82. package/dist/security/index.js.map +1 -1
  83. package/dist/server/auth/index.d.ts +171 -155
  84. package/dist/server/auth/index.d.ts.map +1 -1
  85. package/dist/server/auth/index.js +0 -1
  86. package/dist/server/auth/index.js.map +1 -1
  87. package/dist/server/cache/index.d.ts +12 -0
  88. package/dist/server/cache/index.d.ts.map +1 -1
  89. package/dist/server/cache/index.js +55 -2
  90. package/dist/server/cache/index.js.map +1 -1
  91. package/dist/server/compress/index.d.ts +6 -0
  92. package/dist/server/compress/index.d.ts.map +1 -1
  93. package/dist/server/compress/index.js +38 -1
  94. package/dist/server/compress/index.js.map +1 -1
  95. package/dist/server/core/index.browser.js +2 -2
  96. package/dist/server/core/index.browser.js.map +1 -1
  97. package/dist/server/core/index.d.ts +10 -10
  98. package/dist/server/core/index.d.ts.map +1 -1
  99. package/dist/server/core/index.js +7 -4
  100. package/dist/server/core/index.js.map +1 -1
  101. package/dist/server/links/index.browser.js +22 -6
  102. package/dist/server/links/index.browser.js.map +1 -1
  103. package/dist/server/links/index.d.ts +46 -44
  104. package/dist/server/links/index.d.ts.map +1 -1
  105. package/dist/server/links/index.js +24 -41
  106. package/dist/server/links/index.js.map +1 -1
  107. package/dist/server/static/index.d.ts.map +1 -1
  108. package/dist/server/static/index.js +4 -0
  109. package/dist/server/static/index.js.map +1 -1
  110. package/dist/server/swagger/index.d.ts +2 -1
  111. package/dist/server/swagger/index.d.ts.map +1 -1
  112. package/dist/server/swagger/index.js +9 -5
  113. package/dist/server/swagger/index.js.map +1 -1
  114. package/dist/vite/index.d.ts +101 -106
  115. package/dist/vite/index.d.ts.map +1 -1
  116. package/dist/vite/index.js +574 -503
  117. package/dist/vite/index.js.map +1 -1
  118. package/dist/websocket/index.d.ts +7 -7
  119. package/package.json +7 -7
  120. package/src/api/audits/controllers/{AuditController.ts → AdminAuditController.ts} +5 -6
  121. package/src/api/audits/entities/audits.ts +5 -5
  122. package/src/api/audits/index.browser.ts +1 -1
  123. package/src/api/audits/index.ts +3 -3
  124. package/src/api/audits/primitives/$audit.spec.ts +276 -0
  125. package/src/api/audits/services/AuditService.spec.ts +495 -0
  126. package/src/api/files/__tests__/$bucket.spec.ts +91 -0
  127. package/src/api/files/controllers/AdminFileStatsController.spec.ts +166 -0
  128. package/src/api/files/controllers/{StorageStatsController.ts → AdminFileStatsController.ts} +2 -2
  129. package/src/api/files/controllers/FileController.spec.ts +558 -0
  130. package/src/api/files/controllers/FileController.ts +4 -5
  131. package/src/api/files/entities/files.ts +5 -5
  132. package/src/api/files/index.browser.ts +1 -1
  133. package/src/api/files/index.ts +4 -4
  134. package/src/api/files/jobs/FileJobs.spec.ts +52 -0
  135. package/src/api/files/services/FileService.spec.ts +109 -0
  136. package/src/api/jobs/__tests__/JobController.spec.ts +343 -0
  137. package/src/api/jobs/controllers/{JobController.ts → AdminJobController.ts} +2 -2
  138. package/src/api/jobs/entities/jobExecutions.ts +5 -5
  139. package/src/api/jobs/index.ts +3 -3
  140. package/src/api/jobs/primitives/$job.spec.ts +476 -0
  141. package/src/api/notifications/controllers/{NotificationController.ts → AdminNotificationController.ts} +4 -5
  142. package/src/api/notifications/entities/notifications.ts +5 -5
  143. package/src/api/notifications/index.browser.ts +1 -1
  144. package/src/api/notifications/index.ts +4 -4
  145. package/src/api/parameters/controllers/{ConfigController.ts → AdminConfigController.ts} +46 -107
  146. package/src/api/parameters/entities/parameters.ts +7 -17
  147. package/src/api/parameters/index.ts +3 -3
  148. package/src/api/parameters/primitives/$config.spec.ts +356 -0
  149. package/src/api/parameters/schemas/activateConfigBodySchema.ts +12 -0
  150. package/src/api/parameters/schemas/checkScheduledResponseSchema.ts +8 -0
  151. package/src/api/parameters/schemas/configCurrentResponseSchema.ts +13 -0
  152. package/src/api/parameters/schemas/configHistoryResponseSchema.ts +9 -0
  153. package/src/api/parameters/schemas/configNameParamSchema.ts +10 -0
  154. package/src/api/parameters/schemas/configNamesResponseSchema.ts +8 -0
  155. package/src/api/parameters/schemas/configTreeNodeSchema.ts +13 -0
  156. package/src/api/parameters/schemas/configVersionParamSchema.ts +9 -0
  157. package/src/api/parameters/schemas/configVersionResponseSchema.ts +9 -0
  158. package/src/api/parameters/schemas/configsByStatusResponseSchema.ts +9 -0
  159. package/src/api/parameters/schemas/createConfigVersionBodySchema.ts +24 -0
  160. package/src/api/parameters/schemas/index.ts +15 -0
  161. package/src/api/parameters/schemas/parameterResponseSchema.ts +26 -0
  162. package/src/api/parameters/schemas/parameterStatusSchema.ts +13 -0
  163. package/src/api/parameters/schemas/rollbackConfigBodySchema.ts +15 -0
  164. package/src/api/parameters/schemas/statusParamSchema.ts +9 -0
  165. package/src/api/users/__tests__/EmailVerification.spec.ts +369 -0
  166. package/src/api/users/__tests__/PasswordReset.spec.ts +550 -0
  167. package/src/api/users/controllers/AdminIdentityController.spec.ts +365 -0
  168. package/src/api/users/controllers/{IdentityController.ts → AdminIdentityController.ts} +3 -4
  169. package/src/api/users/controllers/AdminSessionController.spec.ts +274 -0
  170. package/src/api/users/controllers/{SessionController.ts → AdminSessionController.ts} +3 -4
  171. package/src/api/users/controllers/AdminUserController.spec.ts +372 -0
  172. package/src/api/users/controllers/AdminUserController.ts +116 -0
  173. package/src/api/users/controllers/UserController.ts +4 -107
  174. package/src/api/users/controllers/UserRealmController.ts +3 -0
  175. package/src/api/users/entities/identities.ts +6 -6
  176. package/src/api/users/entities/sessions.ts +6 -6
  177. package/src/api/users/entities/users.ts +9 -9
  178. package/src/api/users/index.ts +9 -6
  179. package/src/api/users/primitives/$userRealm.ts +13 -8
  180. package/src/api/users/services/CredentialService.spec.ts +509 -0
  181. package/src/api/users/services/CredentialService.ts +46 -0
  182. package/src/api/users/services/IdentityService.ts +15 -0
  183. package/src/api/users/services/RegistrationService.spec.ts +630 -0
  184. package/src/api/users/services/RegistrationService.ts +18 -0
  185. package/src/api/users/services/SessionService.spec.ts +301 -0
  186. package/src/api/users/services/SessionService.ts +110 -1
  187. package/src/api/users/services/UserService.ts +67 -2
  188. package/src/api/verifications/__tests__/CodeVerification.spec.ts +318 -0
  189. package/src/api/verifications/__tests__/LinkVerification.spec.ts +279 -0
  190. package/src/api/verifications/entities/verifications.ts +6 -6
  191. package/src/api/verifications/jobs/VerificationJobs.spec.ts +50 -0
  192. package/src/batch/__tests__/startup-buffering.spec.ts +458 -0
  193. package/src/batch/primitives/$batch.spec.ts +766 -0
  194. package/src/batch/providers/BatchProvider.spec.ts +786 -0
  195. package/src/bin/index.ts +0 -1
  196. package/src/bucket/__tests__/shared.ts +194 -0
  197. package/src/bucket/primitives/$bucket.spec.ts +104 -0
  198. package/src/bucket/providers/FileStorageProvider.spec.ts +13 -0
  199. package/src/bucket/providers/LocalFileStorageProvider.spec.ts +77 -0
  200. package/src/bucket/providers/MemoryFileStorageProvider.spec.ts +82 -0
  201. package/src/cache/core/__tests__/shared.ts +377 -0
  202. package/src/cache/core/primitives/$cache.spec.ts +111 -0
  203. package/src/cache/redis/__tests__/cache-redis.spec.ts +70 -0
  204. package/src/cli/apps/AlephaCli.ts +25 -6
  205. package/src/cli/atoms/buildOptions.ts +88 -0
  206. package/src/cli/commands/build.ts +32 -69
  207. package/src/cli/commands/db.ts +0 -4
  208. package/src/cli/commands/dev.ts +34 -10
  209. package/src/cli/commands/gen/changelog.spec.ts +315 -0
  210. package/src/cli/commands/{changelog.ts → gen/changelog.ts} +9 -9
  211. package/src/cli/commands/gen/env.ts +53 -0
  212. package/src/cli/commands/gen/openapi.ts +71 -0
  213. package/src/cli/commands/gen/resource.ts +15 -0
  214. package/src/cli/commands/gen.ts +24 -0
  215. package/src/cli/commands/init.ts +2 -1
  216. package/src/cli/commands/root.ts +12 -3
  217. package/src/cli/commands/test.ts +0 -1
  218. package/src/cli/commands/typecheck.ts +5 -0
  219. package/src/cli/commands/verify.ts +1 -1
  220. package/src/cli/defineConfig.ts +49 -7
  221. package/src/cli/index.ts +2 -2
  222. package/src/cli/services/AlephaCliUtils.ts +105 -55
  223. package/src/cli/services/GitMessageParser.ts +1 -1
  224. package/src/command/helpers/Asker.spec.ts +127 -0
  225. package/src/command/helpers/Runner.spec.ts +126 -0
  226. package/src/command/helpers/Runner.ts +1 -1
  227. package/src/command/primitives/$command.spec.ts +1588 -0
  228. package/src/command/primitives/$command.ts +0 -6
  229. package/src/command/providers/CliProvider.ts +75 -27
  230. package/src/core/Alepha.ts +87 -0
  231. package/src/core/__tests__/Alepha-emit.spec.ts +22 -0
  232. package/src/core/__tests__/Alepha-graph.spec.ts +93 -0
  233. package/src/core/__tests__/Alepha-has.spec.ts +41 -0
  234. package/src/core/__tests__/Alepha-inject.spec.ts +93 -0
  235. package/src/core/__tests__/Alepha-register.spec.ts +81 -0
  236. package/src/core/__tests__/Alepha-start.spec.ts +176 -0
  237. package/src/core/__tests__/Alepha-with.spec.ts +14 -0
  238. package/src/core/__tests__/TypeBox-usecases.spec.ts +35 -0
  239. package/src/core/__tests__/TypeBoxLocale.spec.ts +15 -0
  240. package/src/core/__tests__/descriptor.spec.ts +34 -0
  241. package/src/core/__tests__/fixtures/A.ts +5 -0
  242. package/src/core/__tests__/pagination.spec.ts +77 -0
  243. package/src/core/helpers/jsonSchemaToTypeBox.ts +2 -2
  244. package/src/core/primitives/$atom.spec.ts +43 -0
  245. package/src/core/primitives/$hook.spec.ts +130 -0
  246. package/src/core/primitives/$inject.spec.ts +175 -0
  247. package/src/core/primitives/$module.spec.ts +115 -0
  248. package/src/core/providers/CodecManager.spec.ts +740 -0
  249. package/src/core/providers/EventManager.spec.ts +762 -0
  250. package/src/core/providers/EventManager.ts +4 -0
  251. package/src/core/providers/StateManager.spec.ts +365 -0
  252. package/src/core/providers/TypeProvider.spec.ts +1607 -0
  253. package/src/core/providers/TypeProvider.ts +20 -26
  254. package/src/datetime/primitives/$interval.spec.ts +103 -0
  255. package/src/datetime/providers/DateTimeProvider.spec.ts +86 -0
  256. package/src/email/primitives/$email.spec.ts +175 -0
  257. package/src/email/providers/LocalEmailProvider.spec.ts +341 -0
  258. package/src/fake/__tests__/keyName.example.ts +40 -0
  259. package/src/fake/__tests__/keyName.spec.ts +152 -0
  260. package/src/fake/__tests__/module.example.ts +32 -0
  261. package/src/fake/providers/FakeProvider.spec.ts +438 -0
  262. package/src/file/providers/FileSystemProvider.ts +8 -0
  263. package/src/file/providers/NodeFileSystemProvider.spec.ts +418 -0
  264. package/src/file/providers/NodeFileSystemProvider.ts +5 -0
  265. package/src/file/services/FileDetector.spec.ts +591 -0
  266. package/src/lock/core/__tests__/shared.ts +190 -0
  267. package/src/lock/core/providers/MemoryLockProvider.spec.ts +25 -0
  268. package/src/lock/redis/providers/RedisLockProvider.spec.ts +25 -0
  269. package/src/logger/__tests__/SimpleFormatterProvider.spec.ts +109 -0
  270. package/src/logger/index.ts +15 -3
  271. package/src/logger/primitives/$logger.spec.ts +108 -0
  272. package/src/logger/services/Logger.spec.ts +295 -0
  273. package/src/mcp/__tests__/errors.spec.ts +175 -0
  274. package/src/mcp/__tests__/integration.spec.ts +450 -0
  275. package/src/mcp/helpers/jsonrpc.spec.ts +380 -0
  276. package/src/mcp/primitives/$prompt.spec.ts +468 -0
  277. package/src/mcp/primitives/$resource.spec.ts +390 -0
  278. package/src/mcp/primitives/$tool.spec.ts +406 -0
  279. package/src/mcp/providers/McpServerProvider.spec.ts +797 -0
  280. package/src/mcp/transports/StdioMcpTransport.ts +1 -1
  281. package/src/orm/__tests__/$repository-crud.spec.ts +276 -0
  282. package/src/orm/__tests__/$repository-hooks.spec.ts +325 -0
  283. package/src/orm/__tests__/$repository-orderBy.spec.ts +128 -0
  284. package/src/orm/__tests__/$repository-pagination-sort.spec.ts +149 -0
  285. package/src/orm/__tests__/$repository-save.spec.ts +37 -0
  286. package/src/orm/__tests__/ModelBuilder-integration.spec.ts +490 -0
  287. package/src/orm/__tests__/ModelBuilder-types.spec.ts +186 -0
  288. package/src/orm/__tests__/PostgresProvider.spec.ts +46 -0
  289. package/src/orm/__tests__/delete-returning.spec.ts +256 -0
  290. package/src/orm/__tests__/deletedAt.spec.ts +80 -0
  291. package/src/orm/__tests__/enums.spec.ts +315 -0
  292. package/src/orm/__tests__/execute.spec.ts +72 -0
  293. package/src/orm/__tests__/fixtures/bigEntitySchema.ts +65 -0
  294. package/src/orm/__tests__/fixtures/userEntitySchema.ts +27 -0
  295. package/src/orm/__tests__/joins.spec.ts +1114 -0
  296. package/src/orm/__tests__/page.spec.ts +287 -0
  297. package/src/orm/__tests__/primaryKey.spec.ts +87 -0
  298. package/src/orm/__tests__/query-date-encoding.spec.ts +402 -0
  299. package/src/orm/__tests__/ref-auto-onDelete.spec.ts +156 -0
  300. package/src/orm/__tests__/references.spec.ts +102 -0
  301. package/src/orm/__tests__/security.spec.ts +710 -0
  302. package/src/orm/__tests__/sqlite.spec.ts +111 -0
  303. package/src/orm/__tests__/string-operators.spec.ts +429 -0
  304. package/src/orm/__tests__/timestamps.spec.ts +388 -0
  305. package/src/orm/__tests__/validation.spec.ts +183 -0
  306. package/src/orm/__tests__/version.spec.ts +64 -0
  307. package/src/orm/helpers/parseQueryString.spec.ts +196 -0
  308. package/src/orm/index.ts +2 -8
  309. package/src/orm/primitives/$repository.spec.ts +137 -0
  310. package/src/orm/primitives/$sequence.spec.ts +29 -0
  311. package/src/orm/primitives/$transaction.spec.ts +82 -0
  312. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -3
  313. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  314. package/src/orm/providers/drivers/CloudflareD1Provider.ts +1 -1
  315. package/src/orm/providers/drivers/DatabaseProvider.ts +1 -1
  316. package/src/orm/providers/drivers/NodePostgresProvider.ts +3 -3
  317. package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
  318. package/src/orm/providers/drivers/PglitePostgresProvider.ts +2 -2
  319. package/src/orm/services/ModelBuilder.spec.ts +575 -0
  320. package/src/orm/services/Repository.spec.ts +137 -0
  321. package/src/queue/core/__tests__/shared.ts +143 -0
  322. package/src/queue/core/providers/MemoryQueueProvider.spec.ts +23 -0
  323. package/src/queue/core/providers/WorkerProvider.spec.ts +394 -0
  324. package/src/queue/redis/providers/RedisQueueProvider.spec.ts +23 -0
  325. package/src/redis/__tests__/redis.spec.ts +58 -0
  326. package/src/retry/primitives/$retry.spec.ts +234 -0
  327. package/src/retry/providers/RetryProvider.spec.ts +438 -0
  328. package/src/router/__tests__/match.spec.ts +252 -0
  329. package/src/router/providers/RouterProvider.spec.ts +197 -0
  330. package/src/scheduler/__tests__/$scheduler-cron.spec.ts +25 -0
  331. package/src/scheduler/__tests__/$scheduler-interval.spec.ts +25 -0
  332. package/src/scheduler/__tests__/shared.ts +77 -0
  333. package/src/security/__tests__/bug-1-wildcard-after-start.spec.ts +229 -0
  334. package/src/security/__tests__/bug-2-password-validation.spec.ts +245 -0
  335. package/src/security/__tests__/bug-3-regex-vulnerability.spec.ts +407 -0
  336. package/src/security/__tests__/bug-4-oauth2-validation.spec.ts +439 -0
  337. package/src/security/__tests__/multi-layer-permissions.spec.ts +522 -0
  338. package/src/security/primitives/$permission.spec.ts +30 -0
  339. package/src/security/primitives/$permission.ts +2 -2
  340. package/src/security/primitives/$realm.spec.ts +101 -0
  341. package/src/security/primitives/$role.spec.ts +52 -0
  342. package/src/security/primitives/$serviceAccount.spec.ts +61 -0
  343. package/src/security/providers/SecurityProvider.spec.ts +350 -0
  344. package/src/server/auth/providers/ServerAuthProvider.ts +0 -2
  345. package/src/server/cache/providers/ServerCacheProvider.spec.ts +1125 -0
  346. package/src/server/cache/providers/ServerCacheProvider.ts +94 -9
  347. package/src/server/compress/providers/ServerCompressProvider.spec.ts +31 -0
  348. package/src/server/compress/providers/ServerCompressProvider.ts +63 -2
  349. package/src/server/cookies/providers/ServerCookiesProvider.spec.ts +253 -0
  350. package/src/server/core/__tests__/ServerRouterProvider-getRoutes.spec.ts +334 -0
  351. package/src/server/core/__tests__/ServerRouterProvider-requestId.spec.ts +129 -0
  352. package/src/server/core/helpers/ServerReply.ts +2 -2
  353. package/src/server/core/primitives/$action.spec.ts +191 -0
  354. package/src/server/core/primitives/$route.spec.ts +65 -0
  355. package/src/server/core/providers/ServerBodyParserProvider.spec.ts +93 -0
  356. package/src/server/core/providers/ServerLoggerProvider.spec.ts +100 -0
  357. package/src/server/core/providers/ServerProvider.ts +14 -2
  358. package/src/server/core/services/HttpClient.spec.ts +123 -0
  359. package/src/server/core/services/UserAgentParser.spec.ts +111 -0
  360. package/src/server/cors/providers/ServerCorsProvider.spec.ts +481 -0
  361. package/src/server/health/providers/ServerHealthProvider.spec.ts +22 -0
  362. package/src/server/helmet/providers/ServerHelmetProvider.spec.ts +105 -0
  363. package/src/server/links/__tests__/$action.spec.ts +238 -0
  364. package/src/server/links/__tests__/fixtures/CrudApp.ts +122 -0
  365. package/src/server/links/__tests__/requestId.spec.ts +120 -0
  366. package/src/server/links/primitives/$remote.spec.ts +228 -0
  367. package/src/server/links/providers/LinkProvider.spec.ts +54 -0
  368. package/src/server/links/providers/LinkProvider.ts +49 -3
  369. package/src/server/links/providers/ServerLinksProvider.ts +1 -53
  370. package/src/server/links/schemas/apiLinksResponseSchema.ts +7 -0
  371. package/src/server/metrics/providers/ServerMetricsProvider.spec.ts +25 -0
  372. package/src/server/multipart/providers/ServerMultipartProvider.spec.ts +528 -0
  373. package/src/server/proxy/primitives/$proxy.spec.ts +87 -0
  374. package/src/server/rate-limit/__tests__/ActionRateLimit.spec.ts +211 -0
  375. package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +344 -0
  376. package/src/server/security/__tests__/BasicAuth.spec.ts +684 -0
  377. package/src/server/security/__tests__/ServerSecurityProvider-realm.spec.ts +388 -0
  378. package/src/server/security/providers/ServerSecurityProvider.spec.ts +123 -0
  379. package/src/server/static/primitives/$serve.spec.ts +193 -0
  380. package/src/server/static/providers/ServerStaticProvider.ts +10 -0
  381. package/src/server/swagger/__tests__/ui.spec.ts +52 -0
  382. package/src/server/swagger/primitives/$swagger.spec.ts +193 -0
  383. package/src/server/swagger/providers/ServerSwaggerProvider.ts +19 -12
  384. package/src/sms/primitives/$sms.spec.ts +165 -0
  385. package/src/sms/providers/LocalSmsProvider.spec.ts +224 -0
  386. package/src/sms/providers/MemorySmsProvider.spec.ts +193 -0
  387. package/src/thread/primitives/$thread.spec.ts +186 -0
  388. package/src/topic/core/__tests__/shared.ts +144 -0
  389. package/src/topic/core/providers/MemoryTopicProvider.spec.ts +23 -0
  390. package/src/topic/redis/providers/RedisTopicProvider.spec.ts +23 -0
  391. package/src/vite/helpers/importViteReact.ts +13 -0
  392. package/src/vite/index.ts +1 -21
  393. package/src/vite/plugins/viteAlephaDev.ts +32 -5
  394. package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
  395. package/src/vite/tasks/buildClient.ts +11 -0
  396. package/src/vite/tasks/buildServer.ts +47 -3
  397. package/src/vite/tasks/devServer.ts +69 -0
  398. package/src/vite/tasks/index.ts +2 -1
  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/assets/viteConfigTs.ts +0 -14
  403. package/src/cli/commands/run.ts +0 -24
  404. package/src/vite/plugins/viteAlepha.ts +0 -37
  405. package/src/vite/plugins/viteAlephaBuild.ts +0 -281
@@ -4,20 +4,19 @@ import { AlephaApiVerification } from "alepha/api/verifications";
4
4
  import { AlephaEmail } from "alepha/email";
5
5
  import { AlephaServerCompress } from "alepha/server/compress";
6
6
  import { AlephaServerHelmet } from "alepha/server/helmet";
7
- import { $entity, $repository, pageQuerySchema, parseQueryString, pg } from "alepha/orm";
8
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";
9
10
  import { $logger } from "alepha/logger";
10
11
  import { $bucket } from "alepha/bucket";
12
+ import { $client } from "alepha/server/links";
11
13
  import { randomInt, randomUUID } from "node:crypto";
12
14
  import { $cache } from "alepha/cache";
13
15
  import { DateTimeProvider } from "alepha/datetime";
14
16
  import { $realm, CryptoProvider, InvalidCredentialsError, SecurityProvider } from "alepha/security";
15
- import { $client } from "alepha/server/links";
16
17
  import { $authCredentials, $authGithub, $authGoogle, ServerAuthProvider, authenticationProviderSchema } from "alepha/server/auth";
17
18
  import { FileSystemProvider } from "alepha/file";
18
- import { AlephaApiAudits } from "alepha/api/audits";
19
19
  import { AlephaApiFiles } from "alepha/api/files";
20
- import { AlephaApiJobs } from "alepha/api/jobs";
21
20
 
22
21
  //#region ../../src/api/users/schemas/identityQuerySchema.ts
23
22
  const identityQuerySchema = t.extend(pageQuerySchema, {
@@ -31,11 +30,11 @@ const DEFAULT_USER_REALM_NAME = "default";
31
30
  const users = $entity({
32
31
  name: "users",
33
32
  schema: t.object({
34
- id: pg.primaryKey(t.uuid()),
35
- version: pg.version(),
36
- createdAt: pg.createdAt(),
37
- updatedAt: pg.updatedAt(),
38
- 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),
39
38
  username: t.optional(t.shortText({
40
39
  minLength: 3,
41
40
  maxLength: 50,
@@ -43,12 +42,12 @@ const users = $entity({
43
42
  })),
44
43
  email: t.optional(t.string({ format: "email" })),
45
44
  phoneNumber: t.optional(t.e164()),
46
- roles: pg.default(t.array(t.string()), []),
45
+ roles: db.default(t.array(t.string()), []),
47
46
  firstName: t.optional(t.string()),
48
47
  lastName: t.optional(t.string()),
49
48
  picture: t.optional(t.string()),
50
- enabled: pg.default(t.boolean(), true),
51
- emailVerified: pg.default(t.boolean(), false)
49
+ enabled: db.default(t.boolean(), true),
50
+ emailVerified: db.default(t.boolean(), false)
52
51
  }),
53
52
  indexes: [
54
53
  {
@@ -71,11 +70,11 @@ const users = $entity({
71
70
  const identities = $entity({
72
71
  name: "identities",
73
72
  schema: t.object({
74
- id: pg.primaryKey(t.uuid()),
75
- version: pg.version(),
76
- createdAt: pg.createdAt(),
77
- updatedAt: pg.updatedAt(),
78
- 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),
79
78
  password: t.optional(t.text()),
80
79
  provider: t.text(),
81
80
  providerUserId: t.optional(t.text()),
@@ -147,12 +146,12 @@ const realmAuthSettingsAtom = $atom({
147
146
  const sessions = $entity({
148
147
  name: "sessions",
149
148
  schema: t.object({
150
- id: pg.primaryKey(t.uuid()),
151
- version: pg.version(),
152
- createdAt: pg.createdAt(),
153
- updatedAt: pg.updatedAt(),
149
+ id: db.primaryKey(t.uuid()),
150
+ version: db.version(),
151
+ createdAt: db.createdAt(),
152
+ updatedAt: db.updatedAt(),
154
153
  refreshToken: t.uuid(),
155
- userId: pg.ref(t.uuid(), () => users.cols.id),
154
+ userId: db.ref(t.uuid(), () => users.cols.id),
156
155
  expiresAt: t.datetime(),
157
156
  ip: t.optional(t.text()),
158
157
  userAgent: t.optional(t.object({
@@ -242,6 +241,7 @@ var UserRealmProvider = class {
242
241
  var IdentityService = class {
243
242
  log = $logger();
244
243
  userRealmProvider = $inject(UserRealmProvider);
244
+ auditService = $inject(AuditService);
245
245
  identities(userRealmName) {
246
246
  return this.userRealmProvider.identityRepository(userRealmName);
247
247
  }
@@ -295,14 +295,25 @@ var IdentityService = class {
295
295
  provider: identity.provider,
296
296
  userId: identity.userId
297
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
+ });
298
309
  }
299
310
  };
300
311
 
301
312
  //#endregion
302
- //#region ../../src/api/users/controllers/IdentityController.ts
303
- var IdentityController = class {
313
+ //#region ../../src/api/users/controllers/AdminIdentityController.ts
314
+ var AdminIdentityController = class {
304
315
  url = "/identities";
305
- group = "identities";
316
+ group = "admin:identities";
306
317
  identityService = $inject(IdentityService);
307
318
  /**
308
319
  * Find identities with pagination and filtering.
@@ -313,7 +324,7 @@ var IdentityController = class {
313
324
  description: "Find identities with pagination and filtering",
314
325
  schema: {
315
326
  query: t.extend(identityQuerySchema, { userRealmName: t.optional(t.string()) }),
316
- response: pg.page(identityResourceSchema)
327
+ response: t.page(identityResourceSchema)
317
328
  },
318
329
  handler: ({ query }) => {
319
330
  const { userRealmName, ...q } = query;
@@ -439,10 +450,10 @@ var SessionCrudService = class {
439
450
  };
440
451
 
441
452
  //#endregion
442
- //#region ../../src/api/users/controllers/SessionController.ts
443
- var SessionController = class {
453
+ //#region ../../src/api/users/controllers/AdminSessionController.ts
454
+ var AdminSessionController = class {
444
455
  url = "/sessions";
445
- group = "sessions";
456
+ group = "admin:sessions";
446
457
  sessionService = $inject(SessionCrudService);
447
458
  /**
448
459
  * Find sessions with pagination and filtering.
@@ -453,7 +464,7 @@ var SessionController = class {
453
464
  description: "Find sessions with pagination and filtering",
454
465
  schema: {
455
466
  query: t.extend(sessionQuerySchema, { userRealmName: t.optional(t.string()) }),
456
- response: pg.page(sessionResourceSchema)
467
+ response: t.page(sessionResourceSchema)
457
468
  },
458
469
  handler: ({ query }) => {
459
470
  const { userRealmName, ...q } = query;
@@ -497,92 +508,10 @@ var SessionController = class {
497
508
  });
498
509
  };
499
510
 
500
- //#endregion
501
- //#region ../../src/api/users/schemas/completePasswordResetRequestSchema.ts
502
- /**
503
- * Request schema for completing a password reset.
504
- *
505
- * Requires the intent ID from Phase 1, the verification code,
506
- * and the new password.
507
- */
508
- const completePasswordResetRequestSchema = t.object({
509
- intentId: t.uuid({ description: "The intent ID from createPasswordResetIntent" }),
510
- code: t.string({ description: "6-digit verification code sent via email" }),
511
- newPassword: t.string({
512
- minLength: 8,
513
- description: "New password (minimum 8 characters)"
514
- })
515
- });
516
-
517
- //#endregion
518
- //#region ../../src/api/users/schemas/completeRegistrationRequestSchema.ts
519
- const completeRegistrationRequestSchema = t.object({
520
- intentId: t.uuid({ description: "The registration intent ID from the first phase" }),
521
- emailCode: t.optional(t.string({ description: "Email verification code (if email verification required)" })),
522
- phoneCode: t.optional(t.string({ description: "Phone verification code (if phone verification required)" })),
523
- captchaToken: t.optional(t.string({ description: "Captcha token (if captcha required)" }))
524
- });
525
-
526
511
  //#endregion
527
512
  //#region ../../src/api/users/schemas/createUserSchema.ts
528
513
  const createUserSchema = t.omit(users.insertSchema, ["realm"]);
529
514
 
530
- //#endregion
531
- //#region ../../src/api/users/schemas/passwordResetIntentResponseSchema.ts
532
- /**
533
- * Response schema for password reset intent creation.
534
- *
535
- * Contains the intent ID needed for Phase 2 completion,
536
- * along with expiration time.
537
- */
538
- const passwordResetIntentResponseSchema = t.object({
539
- intentId: t.uuid({ description: "Unique identifier for this password reset intent" }),
540
- expiresAt: t.datetime({ description: "ISO timestamp when this intent expires" })
541
- });
542
-
543
- //#endregion
544
- //#region ../../src/api/users/schemas/registerQuerySchema.ts
545
- /**
546
- * Schema for user registration query parameters.
547
- * Allows specifying a custom user realm.
548
- */
549
- const registerQuerySchema = t.object({ userRealmName: t.optional(t.text({ description: "The user realm to register the user in (defaults to 'default')" })) });
550
-
551
- //#endregion
552
- //#region ../../src/api/users/schemas/registerRequestSchema.ts
553
- /**
554
- * Schema for user registration request body.
555
- * Password is always required, other fields depend on realm settings.
556
- */
557
- const registerRequestSchema = t.object({
558
- password: t.string({
559
- minLength: 8,
560
- description: "Password for the account"
561
- }),
562
- username: t.optional(t.string({
563
- minLength: 3,
564
- description: "Unique username for the account"
565
- })),
566
- email: t.optional(t.string({
567
- format: "email",
568
- description: "User's email address"
569
- })),
570
- phoneNumber: t.optional(t.string({ description: "User's phone number" })),
571
- firstName: t.optional(t.string({ description: "User's first name" })),
572
- lastName: t.optional(t.string({ description: "User's last name" })),
573
- picture: t.optional(t.string({ description: "User's profile picture URL" }))
574
- });
575
-
576
- //#endregion
577
- //#region ../../src/api/users/schemas/registrationIntentResponseSchema.ts
578
- const registrationIntentResponseSchema = t.object({
579
- intentId: t.uuid({ description: "Unique identifier for the registration intent" }),
580
- expectCaptcha: t.boolean({ description: "Whether captcha verification is required" }),
581
- expectEmailVerification: t.boolean({ description: "Whether email verification is required" }),
582
- expectPhoneVerification: t.boolean({ description: "Whether phone verification is required" }),
583
- expiresAt: t.datetime({ description: "When the registration intent expires" })
584
- });
585
-
586
515
  //#endregion
587
516
  //#region ../../src/api/users/schemas/updateUserSchema.ts
588
517
  const updateUserSchema = t.partial(t.omit(users.insertSchema, [
@@ -738,136 +667,578 @@ var UserNotifications = class {
738
667
  };
739
668
 
740
669
  //#endregion
741
- //#region ../../src/api/users/services/CredentialService.ts
742
- const INTENT_TTL_MINUTES$1 = 10;
743
- var CredentialService = class {
670
+ //#region ../../src/api/users/services/UserService.ts
671
+ var UserService = class {
744
672
  log = $logger();
745
- cryptoProvider = $inject(CryptoProvider);
746
- dateTimeProvider = $inject(DateTimeProvider);
747
673
  verificationController = $client();
748
674
  userNotifications = $inject(UserNotifications);
749
675
  userRealmProvider = $inject(UserRealmProvider);
750
- intentCache = $cache({
751
- name: "password-reset-intents",
752
- ttl: [INTENT_TTL_MINUTES$1, "minutes"]
753
- });
676
+ auditService = $inject(AuditService);
754
677
  users(userRealmName) {
755
678
  return this.userRealmProvider.userRepository(userRealmName);
756
679
  }
757
- sessions(userRealmName) {
758
- return this.userRealmProvider.sessionRepository(userRealmName);
759
- }
760
- identities(userRealmName) {
761
- return this.userRealmProvider.identityRepository(userRealmName);
762
- }
763
680
  /**
764
- * Phase 1: Create a password reset intent.
765
- *
766
- * Validates the email, checks for existing user with credentials,
767
- * sends verification code, and stores the intent in cache.
768
- *
769
- * @param email - User's email address
770
- * @param userRealmName - Optional realm name
771
- * @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").
772
686
  */
773
- async createPasswordResetIntent(email, userRealmName) {
774
- this.log.trace("Creating password reset intent", {
687
+ async requestEmailVerification(email, userRealmName, method = "code", verifyUrl) {
688
+ this.log.trace("Requesting email verification", {
775
689
  email,
776
- userRealmName
690
+ userRealmName,
691
+ method
777
692
  });
778
- const intentId = randomUUID();
779
- const expiresAt = this.dateTimeProvider.now().add(INTENT_TTL_MINUTES$1, "minutes").toISOString();
780
693
  const user = await this.users(userRealmName).findOne({ where: { email: { eq: email } } }).catch(() => void 0);
781
694
  if (!user) {
782
- this.log.debug("Password reset requested for non-existent email", { email });
783
- return {
784
- intentId,
785
- expiresAt
786
- };
695
+ this.log.debug("Email verification requested for non-existent user", { email });
696
+ return true;
787
697
  }
788
- const identity = await this.identities(userRealmName).findOne({ where: {
789
- userId: { eq: user.id },
790
- provider: { eq: "credentials" }
791
- } }).catch(() => void 0);
792
- if (!identity) {
793
- this.log.debug("Password reset requested for user without credentials", { userId: user.id });
794
- return {
795
- intentId,
796
- expiresAt
797
- };
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;
798
704
  }
799
705
  try {
800
706
  const verification = await this.verificationController.requestVerificationCode({
801
- params: { type: "code" },
707
+ params: { type: method },
802
708
  body: { target: email }
803
709
  });
804
- await this.userNotifications.passwordReset.push({
805
- contact: email,
806
- 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", {
807
724
  email,
808
- code: verification.token,
809
- expiresInMinutes: Math.floor(verification.codeExpiration / 60)
810
- }
811
- });
812
- 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", {
813
743
  email,
814
- userId: user.id,
815
- identityId: identity.id,
816
- realmName: userRealmName,
817
- expiresAt
818
- };
819
- await this.intentCache.set(intentId, intent);
820
- this.log.info("Password reset intent created", {
821
- intentId,
822
- userId: user.id,
823
- email
744
+ error
824
745
  });
825
- } catch (error) {
826
- this.log.warn("Failed to create password reset verification", error);
827
746
  }
828
- return {
829
- intentId,
830
- expiresAt
831
- };
747
+ return true;
832
748
  }
833
749
  /**
834
- * Phase 2: Complete password reset using an intent.
835
- *
836
- * Validates the verification code, updates the password,
837
- * and invalidates all existing sessions.
838
- *
839
- * @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.
840
752
  */
841
- async completePasswordReset(body) {
842
- this.log.trace("Completing password reset", { intentId: body.intentId });
843
- const intent = await this.intentCache.get(body.intentId);
844
- if (!intent) {
845
- this.log.warn("Invalid or expired password reset intent", { intentId: body.intentId });
846
- throw new HttpError({
847
- status: 410,
848
- message: "Invalid or expired password reset intent"
849
- });
850
- }
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";
851
759
  if ((await this.verificationController.validateVerificationCode({
852
- params: { type: "code" },
760
+ params: { type },
853
761
  body: {
854
- target: intent.email,
855
- token: body.code
762
+ target: email,
763
+ token
856
764
  }
857
765
  }).catch(() => {
858
- this.log.warn("Invalid verification code for password reset", {
859
- intentId: body.intentId,
860
- email: intent.email
766
+ this.log.warn("Invalid email verification token", {
767
+ email,
768
+ type
861
769
  });
862
- throw new BadRequestError("Invalid or expired verification code");
770
+ throw new BadRequestError("Invalid or expired verification token");
863
771
  })).alreadyVerified) {
864
- this.log.warn("Verification code reuse attempt", {
865
- intentId: body.intentId,
866
- email: intent.email
867
- });
868
- 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");
869
774
  }
870
- 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);
871
1242
  const hashedPassword = await this.cryptoProvider.hashPassword(body.newPassword);
872
1243
  await this.identities(intent.realmName).updateById(intent.identityId, { password: hashedPassword });
873
1244
  await this.sessions(intent.realmName).deleteMany({ userId: { eq: intent.userId } });
@@ -875,6 +1246,23 @@ var CredentialService = class {
875
1246
  userId: intent.userId,
876
1247
  email: intent.email
877
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
+ });
878
1266
  }
879
1267
  /**
880
1268
  * @deprecated Use createPasswordResetIntent instead
@@ -917,6 +1305,23 @@ var CredentialService = class {
917
1305
  const hashedPassword = await this.cryptoProvider.hashPassword(newPassword);
918
1306
  await this.identities(userRealmName).updateById(identity.id, { password: hashedPassword });
919
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
+ });
920
1325
  }
921
1326
  };
922
1327
 
@@ -930,6 +1335,7 @@ var RegistrationService = class {
930
1335
  verificationController = $client();
931
1336
  userNotifications = $inject(UserNotifications);
932
1337
  userRealmProvider = $inject(UserRealmProvider);
1338
+ auditService = $inject(AuditService);
933
1339
  intentCache = $cache({
934
1340
  name: "registration-intents",
935
1341
  ttl: [INTENT_TTL_MINUTES, "minutes"]
@@ -1071,6 +1477,20 @@ var RegistrationService = class {
1071
1477
  email: user.email,
1072
1478
  username: user.username
1073
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
+ });
1074
1494
  return user;
1075
1495
  }
1076
1496
  /**
@@ -1092,317 +1512,95 @@ var RegistrationService = class {
1092
1512
  }
1093
1513
  if (body.phoneNumber) {
1094
1514
  if (await userRepository.findOne({ where: { phoneNumber: { eq: body.phoneNumber } } }).catch(() => void 0)) {
1095
- this.log.debug("Phone number already taken", { phoneNumber: body.phoneNumber });
1096
- throw new ConflictError("User with this phone number already exists");
1097
- }
1098
- }
1099
- }
1100
- /**
1101
- * Send email verification code.
1102
- */
1103
- async sendEmailVerification(email) {
1104
- this.log.debug("Sending email verification code", { email });
1105
- try {
1106
- const verification = await this.verificationController.requestVerificationCode({
1107
- params: { type: "code" },
1108
- body: { target: email }
1109
- });
1110
- await this.userNotifications.emailVerification.push({
1111
- contact: email,
1112
- variables: {
1113
- email,
1114
- code: verification.token,
1115
- expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1116
- }
1117
- });
1118
- this.log.debug("Email verification code sent", { email });
1119
- } catch (error) {
1120
- this.log.warn("Failed to send email verification code", error);
1121
- }
1122
- }
1123
- /**
1124
- * Send phone verification code.
1125
- */
1126
- async sendPhoneVerification(phoneNumber) {
1127
- this.log.debug("Sending phone verification code", { phoneNumber });
1128
- try {
1129
- const verification = await this.verificationController.requestVerificationCode({
1130
- params: { type: "code" },
1131
- body: { target: phoneNumber }
1132
- });
1133
- await this.userNotifications.phoneVerification.push({
1134
- contact: phoneNumber,
1135
- variables: {
1136
- phoneNumber,
1137
- code: verification.token,
1138
- expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1139
- }
1140
- });
1141
- this.log.debug("Phone verification code sent", { phoneNumber });
1142
- } catch (error) {
1143
- this.log.warn("Failed to send phone verification code", {
1144
- phoneNumber,
1145
- error
1146
- });
1147
- }
1148
- }
1149
- /**
1150
- * Verify email code using verification service.
1151
- */
1152
- async verifyEmailCode(email, code) {
1153
- if ((await this.verificationController.validateVerificationCode({
1154
- params: { type: "code" },
1155
- body: {
1156
- target: email,
1157
- token: code
1158
- }
1159
- }).catch(() => {
1160
- this.log.warn("Invalid email verification code", { email });
1161
- throw new BadRequestError("Invalid or expired email verification code");
1162
- })).alreadyVerified) {
1163
- this.log.warn("Email verification code already used", { email });
1164
- throw new BadRequestError("Email verification code has already been used");
1165
- }
1166
- }
1167
- /**
1168
- * Verify phone code using verification service.
1169
- */
1170
- async verifyPhoneCode(phoneNumber, code) {
1171
- if ((await this.verificationController.validateVerificationCode({
1172
- params: { type: "code" },
1173
- body: {
1174
- target: phoneNumber,
1175
- token: code
1176
- }
1177
- }).catch(() => {
1178
- this.log.warn("Invalid phone verification code", { phoneNumber });
1179
- throw new BadRequestError("Invalid or expired phone verification code");
1180
- })).alreadyVerified) {
1181
- this.log.warn("Phone verification code already used", { phoneNumber });
1182
- throw new BadRequestError("Phone verification code has already been used");
1183
- }
1184
- }
1185
- };
1186
-
1187
- //#endregion
1188
- //#region ../../src/api/users/services/UserService.ts
1189
- var UserService = class {
1190
- log = $logger();
1191
- verificationController = $client();
1192
- userNotifications = $inject(UserNotifications);
1193
- userRealmProvider = $inject(UserRealmProvider);
1194
- users(userRealmName) {
1195
- return this.userRealmProvider.userRepository(userRealmName);
1196
- }
1197
- /**
1198
- * Request email verification for a user.
1199
- * @param email - The email address to verify.
1200
- * @param userRealmName - Optional realm name.
1201
- * @param method - The verification method: "code" (default) or "link".
1202
- * @param verifyUrl - Base URL for verification link (required when method is "link").
1203
- */
1204
- async requestEmailVerification(email, userRealmName, method = "code", verifyUrl) {
1205
- this.log.trace("Requesting email verification", {
1206
- email,
1207
- userRealmName,
1208
- method
1209
- });
1210
- const user = await this.users(userRealmName).findOne({ where: { email: { eq: email } } }).catch(() => void 0);
1211
- if (!user) {
1212
- this.log.debug("Email verification requested for non-existent user", { email });
1213
- return true;
1214
- }
1215
- if (user.emailVerified) {
1216
- this.log.debug("Email verification requested for already verified user", {
1217
- email,
1218
- userId: user.id
1219
- });
1220
- return true;
1221
- }
1222
- try {
1223
- const verification = await this.verificationController.requestVerificationCode({
1224
- params: { type: method },
1225
- body: { target: email }
1226
- });
1227
- if (method === "link") {
1228
- const url = new URL(verifyUrl || "/verify-email", "http://localhost");
1229
- url.searchParams.set("email", email);
1230
- url.searchParams.set("token", verification.token);
1231
- const fullVerifyUrl = verifyUrl ? `${verifyUrl}${url.search}` : url.pathname + url.search;
1232
- await this.userNotifications.emailVerificationLink.push({
1233
- contact: email,
1234
- variables: {
1235
- email,
1236
- verifyUrl: fullVerifyUrl,
1237
- expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1238
- }
1239
- });
1240
- this.log.debug("Email verification link sent", {
1241
- email,
1242
- userId: user.id
1243
- });
1244
- } else {
1245
- await this.userNotifications.emailVerification.push({
1246
- contact: email,
1247
- variables: {
1248
- email,
1249
- code: verification.token,
1250
- expiresInMinutes: Math.floor(verification.codeExpiration / 60)
1251
- }
1252
- });
1253
- this.log.debug("Email verification code sent", {
1254
- email,
1255
- userId: user.id
1256
- });
1257
- }
1258
- } catch (error) {
1259
- this.log.warn("Failed to send email verification", {
1260
- email,
1261
- error
1262
- });
1263
- }
1264
- return true;
1265
- }
1266
- /**
1267
- * Verify a user's email using a valid verification token.
1268
- * Supports both code (6-digit) and link (UUID) verification tokens.
1269
- */
1270
- async verifyEmail(email, token, userRealmName) {
1271
- this.log.trace("Verifying email", {
1272
- email,
1273
- userRealmName
1274
- });
1275
- const type = /^\d{6}$/.test(token) ? "code" : "link";
1276
- if ((await this.verificationController.validateVerificationCode({
1277
- params: { type },
1278
- body: {
1279
- target: email,
1280
- token
1281
- }
1282
- }).catch(() => {
1283
- this.log.warn("Invalid email verification token", {
1284
- email,
1285
- type
1286
- });
1287
- throw new BadRequestError("Invalid or expired verification token");
1288
- })).alreadyVerified) {
1289
- this.log.warn("Email verification token already used", { email });
1290
- throw new BadRequestError("Invalid or expired verification token");
1291
- }
1292
- const user = await this.users(userRealmName).findOne({ where: { email: { eq: email } } });
1293
- await this.users(userRealmName).updateById(user.id, { emailVerified: true });
1294
- this.log.info("Email verified", {
1295
- email,
1296
- userId: user.id,
1297
- type
1298
- });
1299
- }
1300
- /**
1301
- * Check if an email is verified.
1302
- */
1303
- async isEmailVerified(email, userRealmName) {
1304
- this.log.trace("Checking if email is verified", {
1305
- email,
1306
- userRealmName
1307
- });
1308
- return (await this.users(userRealmName).findOne({ where: { email: { eq: email } } }).catch(() => void 0))?.emailVerified ?? false;
1309
- }
1310
- /**
1311
- * Find users with pagination and filtering.
1312
- */
1313
- async findUsers(q = {}, userRealmName) {
1314
- this.log.trace("Finding users", {
1315
- query: q,
1316
- userRealmName
1317
- });
1318
- q.sort ??= "-createdAt";
1319
- const where = this.users(userRealmName).createQueryWhere();
1320
- if (q.email) where.email = { like: q.email };
1321
- if (q.enabled !== void 0) where.enabled = { eq: q.enabled };
1322
- if (q.emailVerified !== void 0) where.emailVerified = { eq: q.emailVerified };
1323
- if (q.roles) where.roles = { arrayContains: q.roles };
1324
- if (q.query) Object.assign(where, parseQueryString(q.query));
1325
- const result = await this.users(userRealmName).paginate(q, { where }, { count: true });
1326
- this.log.debug("Users found", {
1327
- count: result.content.length,
1328
- total: result.page.totalElements
1329
- });
1330
- 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
+ }
1331
1519
  }
1332
1520
  /**
1333
- * Get a user by ID.
1521
+ * Send email verification code.
1334
1522
  */
1335
- async getUserById(id, userRealmName) {
1336
- this.log.trace("Getting user by ID", {
1337
- id,
1338
- userRealmName
1339
- });
1340
- 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
+ }
1341
1542
  }
1342
1543
  /**
1343
- * Create a new user.
1544
+ * Send phone verification code.
1344
1545
  */
1345
- async createUser(data, userRealmName) {
1346
- this.log.trace("Creating user", {
1347
- username: data.username,
1348
- email: data.email,
1349
- userRealmName
1350
- });
1351
- const realm = this.userRealmProvider.getRealm(userRealmName);
1352
- if (data.username) {
1353
- if (await this.users(userRealmName).findOne({ where: { username: { eq: data.username } } }).catch(() => void 0)) {
1354
- this.log.debug("Username already taken", { username: data.username });
1355
- throw new BadRequestError("User with this username already exists");
1356
- }
1357
- }
1358
- if (data.email) {
1359
- if (await this.users(userRealmName).findOne({ where: { email: { eq: data.email } } }).catch(() => void 0)) {
1360
- this.log.debug("Email already taken", { email: data.email });
1361
- throw new BadRequestError("User with this email already exists");
1362
- }
1363
- }
1364
- if (data.phoneNumber) {
1365
- if (await this.users(userRealmName).findOne({ where: { phoneNumber: { eq: data.phoneNumber } } }).catch(() => void 0)) {
1366
- this.log.debug("Phone number already taken", { phoneNumber: data.phoneNumber });
1367
- throw new BadRequestError("User with this phone number already exists");
1368
- }
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
+ });
1369
1567
  }
1370
- const user = await this.users(userRealmName).create({
1371
- ...data,
1372
- roles: data.roles ?? ["user"],
1373
- realm: realm.name
1374
- });
1375
- this.log.info("User created", {
1376
- userId: user.id,
1377
- username: user.username,
1378
- email: user.email
1379
- });
1380
- return user;
1381
1568
  }
1382
1569
  /**
1383
- * Update an existing user.
1570
+ * Verify email code using verification service.
1384
1571
  */
1385
- async updateUser(id, data, userRealmName) {
1386
- this.log.trace("Updating user", {
1387
- id,
1388
- userRealmName
1389
- });
1390
- await this.getUserById(id, userRealmName);
1391
- const user = await this.users(userRealmName).updateById(id, data);
1392
- this.log.debug("User updated", { userId: id });
1393
- 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
+ }
1394
1586
  }
1395
1587
  /**
1396
- * Delete a user by ID.
1588
+ * Verify phone code using verification service.
1397
1589
  */
1398
- async deleteUser(id, userRealmName) {
1399
- this.log.trace("Deleting user", {
1400
- id,
1401
- userRealmName
1402
- });
1403
- await this.getUserById(id, userRealmName);
1404
- await this.users(userRealmName).deleteById(id);
1405
- 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
+ }
1406
1604
  }
1407
1605
  };
1408
1606
 
@@ -1419,6 +1617,7 @@ var UserController = class {
1419
1617
  * Validates data, creates verification sessions, and stores intent in cache.
1420
1618
  */
1421
1619
  createRegistrationIntent = $action({
1620
+ group: this.group,
1422
1621
  method: "POST",
1423
1622
  path: `${this.url}/register`,
1424
1623
  secure: false,
@@ -1430,55 +1629,11 @@ var UserController = class {
1430
1629
  handler: ({ body, query }) => this.registrationService.createRegistrationIntent(body, query.userRealmName)
1431
1630
  });
1432
1631
  /**
1433
- * Find users with pagination and filtering.
1434
- */
1435
- findUsers = $action({
1436
- path: this.url,
1437
- group: this.group,
1438
- description: "Find users with pagination and filtering",
1439
- schema: {
1440
- query: t.extend(userQuerySchema, { userRealmName: t.optional(t.string()) }),
1441
- response: pg.page(userResourceSchema)
1442
- },
1443
- handler: ({ query }) => {
1444
- const { userRealmName, ...q } = query;
1445
- return this.userService.findUsers(q, userRealmName);
1446
- }
1447
- });
1448
- /**
1449
- * Get a user by ID.
1450
- */
1451
- getUser = $action({
1452
- path: `${this.url}/:id`,
1453
- group: this.group,
1454
- description: "Get a user by ID",
1455
- schema: {
1456
- params: t.object({ id: t.uuid() }),
1457
- query: t.object({ userRealmName: t.optional(t.string()) }),
1458
- response: userResourceSchema
1459
- },
1460
- handler: ({ params, query }) => this.userService.getUserById(params.id, query.userRealmName)
1461
- });
1462
- /**
1463
- * Create a new user.
1464
- */
1465
- createUser = $action({
1466
- method: "POST",
1467
- path: this.url,
1468
- group: this.group,
1469
- description: "Create a new user",
1470
- schema: {
1471
- query: t.object({ userRealmName: t.optional(t.string()) }),
1472
- body: createUserSchema,
1473
- response: userResourceSchema
1474
- },
1475
- handler: ({ body, query }) => this.userService.createUser(body, query.userRealmName)
1476
- });
1477
- /**
1478
1632
  * Phase 2: Complete registration using an intent.
1479
1633
  * Validates verification codes and creates the user.
1480
1634
  */
1481
1635
  createUserFromIntent = $action({
1636
+ group: this.group,
1482
1637
  method: "POST",
1483
1638
  path: `${this.url}/register/complete`,
1484
1639
  secure: false,
@@ -1489,47 +1644,11 @@ var UserController = class {
1489
1644
  handler: ({ body }) => this.registrationService.completeRegistration(body)
1490
1645
  });
1491
1646
  /**
1492
- * Update a user.
1493
- */
1494
- updateUser = $action({
1495
- method: "PATCH",
1496
- path: `${this.url}/:id`,
1497
- group: this.group,
1498
- description: "Update a user",
1499
- schema: {
1500
- params: t.object({ id: t.uuid() }),
1501
- query: t.object({ userRealmName: t.optional(t.string()) }),
1502
- body: updateUserSchema,
1503
- response: userResourceSchema
1504
- },
1505
- handler: ({ params, body, query }) => this.userService.updateUser(params.id, body, query.userRealmName)
1506
- });
1507
- /**
1508
- * Delete a user.
1509
- */
1510
- deleteUser = $action({
1511
- method: "DELETE",
1512
- path: `${this.url}/:id`,
1513
- group: this.group,
1514
- description: "Delete a user",
1515
- schema: {
1516
- params: t.object({ id: t.uuid() }),
1517
- query: t.object({ userRealmName: t.optional(t.string()) }),
1518
- response: okSchema
1519
- },
1520
- handler: async ({ params, query }) => {
1521
- await this.userService.deleteUser(params.id, query.userRealmName);
1522
- return {
1523
- ok: true,
1524
- id: params.id
1525
- };
1526
- }
1527
- });
1528
- /**
1529
1647
  * Phase 1: Create a password reset intent.
1530
1648
  * Validates email, sends verification code, and stores intent in cache.
1531
1649
  */
1532
1650
  createPasswordResetIntent = $action({
1651
+ group: this.group,
1533
1652
  method: "POST",
1534
1653
  path: `${this.url}/password-reset`,
1535
1654
  secure: false,
@@ -1545,6 +1664,7 @@ var UserController = class {
1545
1664
  * Validates verification code, updates password, and invalidates sessions.
1546
1665
  */
1547
1666
  completePasswordReset = $action({
1667
+ group: this.group,
1548
1668
  method: "POST",
1549
1669
  path: `${this.url}/password-reset/complete`,
1550
1670
  secure: false,
@@ -1727,6 +1847,7 @@ const userRealmConfigSchema = t.object({
1727
1847
  */
1728
1848
  var UserRealmController = class {
1729
1849
  url = "/realms";
1850
+ group = "realms";
1730
1851
  userRealmProvider = $inject(UserRealmProvider);
1731
1852
  serverAuthProvider = $inject(ServerAuthProvider);
1732
1853
  /**
@@ -1734,6 +1855,7 @@ var UserRealmController = class {
1734
1855
  * This endpoint is not exposed in the API documentation.
1735
1856
  */
1736
1857
  getRealmConfig = $action({
1858
+ group: this.group,
1737
1859
  method: "GET",
1738
1860
  path: `${this.url}/config`,
1739
1861
  secure: false,
@@ -1755,6 +1877,7 @@ var UserRealmController = class {
1755
1877
  }
1756
1878
  });
1757
1879
  checkUsernameAvailability = $action({
1880
+ group: this.group,
1758
1881
  path: `${this.url}/check-username`,
1759
1882
  secure: false,
1760
1883
  schema: {
@@ -1779,6 +1902,7 @@ var SessionService = class {
1779
1902
  log = $logger();
1780
1903
  userRealmProvider = $inject(UserRealmProvider);
1781
1904
  fileController = $client();
1905
+ auditService = $inject(AuditService);
1782
1906
  users(userRealmName) {
1783
1907
  return this.userRealmProvider.userRepository(userRealmName);
1784
1908
  }
@@ -1818,6 +1942,14 @@ var SessionService = class {
1818
1942
  username,
1819
1943
  realm: name
1820
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
+ });
1821
1953
  throw new InvalidCredentialsError();
1822
1954
  }
1823
1955
  const user = await users$1.findOne({ where }).catch(() => void 0);
@@ -1827,6 +1959,14 @@ var SessionService = class {
1827
1959
  username,
1828
1960
  realm: name
1829
1961
  });
1962
+ await this.auditService.recordAuth("login_failed", {
1963
+ userRealm: name,
1964
+ description: "User not found",
1965
+ metadata: {
1966
+ provider,
1967
+ username
1968
+ }
1969
+ });
1830
1970
  throw new InvalidCredentialsError();
1831
1971
  }
1832
1972
  const identity = await identities$1.findOne({ where: {
@@ -1849,8 +1989,28 @@ var SessionService = class {
1849
1989
  username,
1850
1990
  realm: name
1851
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
+ });
1852
2001
  throw new InvalidCredentialsError();
1853
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
+ });
1854
2014
  return user;
1855
2015
  } catch (error) {
1856
2016
  if (error instanceof InvalidCredentialsError) throw error;
@@ -1901,6 +2061,14 @@ var SessionService = class {
1901
2061
  sessionId: session.id,
1902
2062
  userId: session.userId
1903
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
+ });
1904
2072
  return {
1905
2073
  user,
1906
2074
  expiresIn: expiresAt.unix() - now.unix(),
@@ -1909,8 +2077,18 @@ var SessionService = class {
1909
2077
  }
1910
2078
  async deleteSession(refreshToken, userRealmName) {
1911
2079
  this.log.trace("Deleting session");
2080
+ const session = await this.sessions(userRealmName).findOne({ where: { refreshToken: { eq: refreshToken } } }).catch(() => void 0);
1912
2081
  await this.sessions(userRealmName).deleteOne({ refreshToken });
1913
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
+ }
1914
2092
  }
1915
2093
  async link(provider, profile, userRealmName) {
1916
2094
  this.log.trace("Linking OAuth2 profile", {
@@ -1931,7 +2109,19 @@ var SessionService = class {
1931
2109
  identityId: identity.id,
1932
2110
  userId: identity.userId
1933
2111
  });
1934
- 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;
1935
2125
  }
1936
2126
  if (!profile.email) {
1937
2127
  this.log.debug("OAuth2 profile has no email, returning profile as-is", {
@@ -1956,6 +2146,18 @@ var SessionService = class {
1956
2146
  providerUserId: profile.sub,
1957
2147
  userId: existing.id
1958
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
+ });
1959
2161
  return existing;
1960
2162
  }
1961
2163
  const user = await users$1.create({
@@ -1992,6 +2194,31 @@ var SessionService = class {
1992
2194
  email: user.email,
1993
2195
  username: user.username
1994
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
+ });
1995
2222
  return user;
1996
2223
  }
1997
2224
  };
@@ -2017,10 +2244,13 @@ const $userRealm = (options = {}) => {
2017
2244
  const securityProvider = alepha.inject(SecurityProvider);
2018
2245
  const userRealmProvider = alepha.inject(UserRealmProvider);
2019
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;
2020
2251
  const userRealm = userRealmProvider.register(name, options);
2021
- if (options.modules?.audits) alepha.with(AlephaApiAudits);
2022
- if (options.modules?.files) alepha.with(AlephaApiFiles);
2023
- if (options.modules?.jobs) alepha.with(AlephaApiJobs);
2252
+ alepha.with(AlephaApiFiles);
2253
+ alepha.with(AlephaApiAudits);
2024
2254
  const realm = $realm({
2025
2255
  ...options.realm,
2026
2256
  name,
@@ -2154,13 +2384,14 @@ const AlephaApiUsers = $module({
2154
2384
  UserService,
2155
2385
  IdentityService,
2156
2386
  UserController,
2157
- SessionController,
2158
- IdentityController,
2387
+ AdminUserController,
2388
+ AdminSessionController,
2389
+ AdminIdentityController,
2159
2390
  UserRealmController,
2160
2391
  UserNotifications
2161
2392
  ]
2162
2393
  });
2163
2394
 
2164
2395
  //#endregion
2165
- 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 };
2166
2397
  //# sourceMappingURL=index.js.map