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
@@ -0,0 +1,630 @@
1
+ import { Alepha } from "alepha";
2
+ import { AlephaApiVerification } from "alepha/api/verifications";
3
+ import { DateTimeProvider } from "alepha/datetime";
4
+ import { AlephaEmail, MemoryEmailProvider } from "alepha/email";
5
+ import { AlephaSecurity, CryptoProvider } from "alepha/security";
6
+ import { BadRequestError, ConflictError, HttpError } from "alepha/server";
7
+ import { describe, it } from "vitest";
8
+ import {
9
+ AlephaApiUsers,
10
+ RegistrationService,
11
+ SessionService,
12
+ UserRealmProvider,
13
+ UserService,
14
+ } from "../index.ts";
15
+
16
+ const setup = async (realmSettings?: Record<string, unknown>) => {
17
+ const alepha = Alepha.create();
18
+
19
+ alepha.with(AlephaSecurity);
20
+ alepha.with(AlephaEmail);
21
+ alepha.with(AlephaApiVerification);
22
+ alepha.with(AlephaApiUsers);
23
+
24
+ await alepha.start();
25
+
26
+ const emailProvider = alepha.inject(MemoryEmailProvider);
27
+ emailProvider.records = [];
28
+
29
+ const userRealmProvider = alepha.inject(UserRealmProvider);
30
+
31
+ // Configure realm settings if provided (applies to default realm)
32
+ if (realmSettings) {
33
+ userRealmProvider.register("default", {
34
+ settings: realmSettings as never,
35
+ });
36
+ }
37
+
38
+ return {
39
+ alepha,
40
+ registrationService: alepha.inject(RegistrationService),
41
+ userService: alepha.inject(UserService),
42
+ sessionService: alepha.inject(SessionService),
43
+ cryptoProvider: alepha.inject(CryptoProvider),
44
+ dateTimeProvider: alepha.inject(DateTimeProvider),
45
+ emailProvider,
46
+ userRealmProvider,
47
+ };
48
+ };
49
+
50
+ // Helper to extract code from email
51
+ const extractCode = (emailBody: string): string => {
52
+ const match = emailBody.match(/(\d{6})/);
53
+ if (!match) throw new Error("Code not found in email");
54
+ return match[1];
55
+ };
56
+
57
+ describe("alepha/api/users - RegistrationService", () => {
58
+ describe("Phase 1: createRegistrationIntent", () => {
59
+ it("should create a registration intent with valid data", async ({
60
+ expect,
61
+ }) => {
62
+ const { registrationService } = await setup();
63
+
64
+ const result = await registrationService.createRegistrationIntent({
65
+ email: "newuser@example.com",
66
+ password: "SecurePassword123!",
67
+ username: "newuser",
68
+ firstName: "New",
69
+ lastName: "User",
70
+ });
71
+
72
+ expect(result.intentId).toBeDefined();
73
+ expect(result.expiresAt).toBeDefined();
74
+ expect(result.expectCaptcha).toBe(false);
75
+ expect(result.expectEmailVerification).toBe(false);
76
+ expect(result.expectPhoneVerification).toBe(false);
77
+ });
78
+
79
+ it("should create intent with email verification required when configured", async ({
80
+ expect,
81
+ }) => {
82
+ const { registrationService, emailProvider, userRealmProvider } =
83
+ await setup();
84
+
85
+ // Register realm with email verification required
86
+ userRealmProvider.register("verify-email-realm", {
87
+ settings: {
88
+ verifyEmailRequired: true,
89
+ } as never,
90
+ });
91
+
92
+ const result = await registrationService.createRegistrationIntent(
93
+ {
94
+ email: "verify@example.com",
95
+ password: "SecurePassword123!",
96
+ },
97
+ "verify-email-realm",
98
+ );
99
+
100
+ expect(result.intentId).toBeDefined();
101
+ expect(result.expectEmailVerification).toBe(true);
102
+ expect(result.expectPhoneVerification).toBe(false);
103
+ expect(result.expectCaptcha).toBe(false);
104
+
105
+ // Verify email was sent
106
+ await expect.poll(() => emailProvider.records.length).toBe(1);
107
+ expect(emailProvider.records[0].to).toBe("verify@example.com");
108
+ expect(emailProvider.records[0].subject).toBe(
109
+ "Verify your email address",
110
+ );
111
+ });
112
+
113
+ it("should reject registration when disabled in realm settings", async ({
114
+ expect,
115
+ }) => {
116
+ const { registrationService, userRealmProvider } = await setup();
117
+
118
+ userRealmProvider.register("no-registration-realm", {
119
+ settings: {
120
+ registrationAllowed: false,
121
+ } as never,
122
+ });
123
+
124
+ await expect(
125
+ registrationService.createRegistrationIntent(
126
+ {
127
+ email: "test@example.com",
128
+ password: "SecurePassword123!",
129
+ },
130
+ "no-registration-realm",
131
+ ),
132
+ ).rejects.toThrowError(BadRequestError);
133
+ });
134
+
135
+ it("should reject when required username is missing", async ({
136
+ expect,
137
+ }) => {
138
+ const { registrationService, userRealmProvider } = await setup();
139
+
140
+ userRealmProvider.register("username-required-realm", {
141
+ settings: {
142
+ usernameRequired: true,
143
+ } as never,
144
+ });
145
+
146
+ await expect(
147
+ registrationService.createRegistrationIntent(
148
+ {
149
+ email: "test@example.com",
150
+ password: "SecurePassword123!",
151
+ // username is missing
152
+ },
153
+ "username-required-realm",
154
+ ),
155
+ ).rejects.toThrowError(BadRequestError);
156
+ });
157
+
158
+ it("should reject when required email is missing", async ({ expect }) => {
159
+ const { registrationService } = await setup();
160
+
161
+ // Default realm requires email
162
+ await expect(
163
+ registrationService.createRegistrationIntent({
164
+ username: "testuser",
165
+ password: "SecurePassword123!",
166
+ // email is missing
167
+ }),
168
+ ).rejects.toThrowError(BadRequestError);
169
+ });
170
+
171
+ it("should reject when required phone is missing", async ({ expect }) => {
172
+ const { registrationService, userRealmProvider } = await setup();
173
+
174
+ userRealmProvider.register("phone-required-realm", {
175
+ settings: {
176
+ phoneRequired: true,
177
+ emailRequired: false,
178
+ } as never,
179
+ });
180
+
181
+ await expect(
182
+ registrationService.createRegistrationIntent(
183
+ {
184
+ email: "test@example.com",
185
+ password: "SecurePassword123!",
186
+ // phoneNumber is missing
187
+ },
188
+ "phone-required-realm",
189
+ ),
190
+ ).rejects.toThrowError(BadRequestError);
191
+ });
192
+
193
+ it("should reject duplicate username", async ({ expect }) => {
194
+ const { registrationService, userService } = await setup();
195
+
196
+ // Create existing user
197
+ await userService.users().create({
198
+ username: "existinguser",
199
+ email: "existing@example.com",
200
+ roles: ["user"],
201
+ });
202
+
203
+ await expect(
204
+ registrationService.createRegistrationIntent({
205
+ username: "existinguser",
206
+ email: "new@example.com",
207
+ password: "SecurePassword123!",
208
+ }),
209
+ ).rejects.toThrowError(ConflictError);
210
+ });
211
+
212
+ it("should reject duplicate email", async ({ expect }) => {
213
+ const { registrationService, userService } = await setup();
214
+
215
+ // Create existing user
216
+ await userService.users().create({
217
+ username: "existinguser",
218
+ email: "existing@example.com",
219
+ roles: ["user"],
220
+ });
221
+
222
+ await expect(
223
+ registrationService.createRegistrationIntent({
224
+ username: "newuser",
225
+ email: "existing@example.com",
226
+ password: "SecurePassword123!",
227
+ }),
228
+ ).rejects.toThrowError(ConflictError);
229
+ });
230
+
231
+ it("should reject duplicate phone number", async ({ expect }) => {
232
+ const { registrationService, userService, userRealmProvider } =
233
+ await setup();
234
+
235
+ userRealmProvider.register("phone-realm", {
236
+ settings: {
237
+ phoneEnabled: true,
238
+ emailRequired: false,
239
+ } as never,
240
+ });
241
+
242
+ // Create existing user with phone
243
+ await userService.users("phone-realm").create({
244
+ username: "existinguser",
245
+ email: "existing@example.com",
246
+ phoneNumber: "+1234567890",
247
+ roles: ["user"],
248
+ });
249
+
250
+ await expect(
251
+ registrationService.createRegistrationIntent(
252
+ {
253
+ username: "newuser",
254
+ email: "new@example.com",
255
+ phoneNumber: "+1234567890",
256
+ password: "SecurePassword123!",
257
+ },
258
+ "phone-realm",
259
+ ),
260
+ ).rejects.toThrowError(ConflictError);
261
+ });
262
+
263
+ it("should set correct expiration time (10 minutes)", async ({
264
+ expect,
265
+ }) => {
266
+ const { registrationService, dateTimeProvider } = await setup();
267
+
268
+ const before = dateTimeProvider.now();
269
+
270
+ const result = await registrationService.createRegistrationIntent({
271
+ email: "expiry@example.com",
272
+ password: "SecurePassword123!",
273
+ });
274
+
275
+ const expiresAt = dateTimeProvider.of(result.expiresAt);
276
+ const expectedExpiry = before.add(10, "minutes");
277
+
278
+ // Should expire approximately 10 minutes from now
279
+ expect(expiresAt.diff(expectedExpiry, "seconds")).toBeLessThan(5);
280
+ });
281
+ });
282
+
283
+ describe("Phase 2: completeRegistration", () => {
284
+ it("should complete registration without verification requirements", async ({
285
+ expect,
286
+ }) => {
287
+ const { registrationService, userService } = await setup();
288
+
289
+ // Create intent
290
+ const intent = await registrationService.createRegistrationIntent({
291
+ email: "complete@example.com",
292
+ password: "SecurePassword123!",
293
+ username: "completeuser",
294
+ firstName: "Complete",
295
+ lastName: "User",
296
+ });
297
+
298
+ // Complete registration
299
+ const user = await registrationService.completeRegistration({
300
+ intentId: intent.intentId,
301
+ });
302
+
303
+ expect(user.id).toBeDefined();
304
+ expect(user.email).toBe("complete@example.com");
305
+ expect(user.username).toBe("completeuser");
306
+ expect(user.firstName).toBe("Complete");
307
+ expect(user.lastName).toBe("User");
308
+ expect(user.roles).toContain("user");
309
+ expect(user.enabled).toBe(true);
310
+ });
311
+
312
+ it("should complete registration with valid email verification code", async ({
313
+ expect,
314
+ }) => {
315
+ const { registrationService, emailProvider, userRealmProvider } =
316
+ await setup();
317
+
318
+ userRealmProvider.register("email-verify-realm", {
319
+ settings: {
320
+ verifyEmailRequired: true,
321
+ } as never,
322
+ });
323
+
324
+ // Create intent (sends verification email)
325
+ const intent = await registrationService.createRegistrationIntent(
326
+ {
327
+ email: "emailverify@example.com",
328
+ password: "SecurePassword123!",
329
+ },
330
+ "email-verify-realm",
331
+ );
332
+
333
+ expect(intent.expectEmailVerification).toBe(true);
334
+
335
+ // Extract code from email
336
+ await expect.poll(() => emailProvider.records.length).toBe(1);
337
+ const emailCode = extractCode(emailProvider.records[0].body);
338
+
339
+ // Complete registration with code
340
+ const user = await registrationService.completeRegistration({
341
+ intentId: intent.intentId,
342
+ emailCode,
343
+ });
344
+
345
+ expect(user.email).toBe("emailverify@example.com");
346
+ expect(user.emailVerified).toBe(true);
347
+ });
348
+
349
+ it("should reject expired intent (410 Gone)", async ({ expect }) => {
350
+ const { registrationService, dateTimeProvider } = await setup();
351
+
352
+ // Create intent
353
+ const intent = await registrationService.createRegistrationIntent({
354
+ email: "expired@example.com",
355
+ password: "SecurePassword123!",
356
+ });
357
+
358
+ // Travel forward 11 minutes (intent expires at 10)
359
+ dateTimeProvider.travel(11, "minutes");
360
+
361
+ // Attempt to complete
362
+ await expect(
363
+ registrationService.completeRegistration({
364
+ intentId: intent.intentId,
365
+ }),
366
+ ).rejects.toThrow(HttpError);
367
+ });
368
+
369
+ it("should reject invalid intent ID", async ({ expect }) => {
370
+ const { registrationService } = await setup();
371
+
372
+ await expect(
373
+ registrationService.completeRegistration({
374
+ intentId: "550e8400-e29b-41d4-a716-446655440000",
375
+ }),
376
+ ).rejects.toThrow(HttpError);
377
+ });
378
+
379
+ it("should reject when email code is required but not provided", async ({
380
+ expect,
381
+ }) => {
382
+ const { registrationService, userRealmProvider } = await setup();
383
+
384
+ userRealmProvider.register("email-required-realm", {
385
+ settings: {
386
+ verifyEmailRequired: true,
387
+ } as never,
388
+ });
389
+
390
+ const intent = await registrationService.createRegistrationIntent(
391
+ {
392
+ email: "needscode@example.com",
393
+ password: "SecurePassword123!",
394
+ },
395
+ "email-required-realm",
396
+ );
397
+
398
+ await expect(
399
+ registrationService.completeRegistration({
400
+ intentId: intent.intentId,
401
+ // emailCode not provided
402
+ }),
403
+ ).rejects.toThrowError(BadRequestError);
404
+ });
405
+
406
+ it("should reject invalid email verification code", async ({ expect }) => {
407
+ const { registrationService, userRealmProvider } = await setup();
408
+
409
+ userRealmProvider.register("email-verify-realm", {
410
+ settings: {
411
+ verifyEmailRequired: true,
412
+ } as never,
413
+ });
414
+
415
+ const intent = await registrationService.createRegistrationIntent(
416
+ {
417
+ email: "wrongcode@example.com",
418
+ password: "SecurePassword123!",
419
+ },
420
+ "email-verify-realm",
421
+ );
422
+
423
+ await expect(
424
+ registrationService.completeRegistration({
425
+ intentId: intent.intentId,
426
+ emailCode: "000000", // Wrong code
427
+ }),
428
+ ).rejects.toThrowError(BadRequestError);
429
+ });
430
+
431
+ it("should not allow intent reuse after successful registration", async ({
432
+ expect,
433
+ }) => {
434
+ const { registrationService } = await setup();
435
+
436
+ const intent = await registrationService.createRegistrationIntent({
437
+ email: "onetime@example.com",
438
+ password: "SecurePassword123!",
439
+ });
440
+
441
+ // First completion should succeed
442
+ await registrationService.completeRegistration({
443
+ intentId: intent.intentId,
444
+ });
445
+
446
+ // Second attempt should fail (intent deleted)
447
+ await expect(
448
+ registrationService.completeRegistration({
449
+ intentId: intent.intentId,
450
+ }),
451
+ ).rejects.toThrow(HttpError);
452
+ });
453
+
454
+ it("should detect race condition when email is taken during verification", async ({
455
+ expect,
456
+ }) => {
457
+ const { registrationService, userService, userRealmProvider } =
458
+ await setup();
459
+
460
+ userRealmProvider.register("race-realm", {
461
+ settings: {
462
+ verifyEmailRequired: false,
463
+ } as never,
464
+ });
465
+
466
+ // Create intent
467
+ const intent = await registrationService.createRegistrationIntent(
468
+ {
469
+ email: "race@example.com",
470
+ password: "SecurePassword123!",
471
+ },
472
+ "race-realm",
473
+ );
474
+
475
+ // Simulate another user registering with same email while verification pending
476
+ await userService.users("race-realm").create({
477
+ email: "race@example.com",
478
+ username: "racewinner",
479
+ roles: ["user"],
480
+ });
481
+
482
+ // Attempt to complete should fail
483
+ await expect(
484
+ registrationService.completeRegistration({
485
+ intentId: intent.intentId,
486
+ }),
487
+ ).rejects.toThrowError(ConflictError);
488
+ });
489
+
490
+ it("should create credentials identity with hashed password", async ({
491
+ expect,
492
+ }) => {
493
+ const { registrationService, sessionService, userRealmProvider } =
494
+ await setup();
495
+
496
+ const intent = await registrationService.createRegistrationIntent({
497
+ email: "withpassword@example.com",
498
+ password: "SecurePassword123!",
499
+ });
500
+
501
+ const user = await registrationService.completeRegistration({
502
+ intentId: intent.intentId,
503
+ });
504
+
505
+ // Verify login works with the password
506
+ const loggedInUser = await sessionService.login(
507
+ "credentials",
508
+ "withpassword@example.com",
509
+ "SecurePassword123!",
510
+ );
511
+
512
+ expect(loggedInUser?.id).toBe(user.id);
513
+ });
514
+
515
+ it("should allow login with username after registration", async ({
516
+ expect,
517
+ }) => {
518
+ const { registrationService, sessionService } = await setup({
519
+ usernameEnabled: true,
520
+ });
521
+
522
+ const intent = await registrationService.createRegistrationIntent({
523
+ email: "logintest@example.com",
524
+ username: "loginuser",
525
+ password: "SecurePassword123!",
526
+ });
527
+
528
+ const user = await registrationService.completeRegistration({
529
+ intentId: intent.intentId,
530
+ });
531
+
532
+ // Verify login works with username
533
+ const loggedInUser = await sessionService.login(
534
+ "credentials",
535
+ "loginuser",
536
+ "SecurePassword123!",
537
+ );
538
+
539
+ expect(loggedInUser?.id).toBe(user.id);
540
+ });
541
+ });
542
+
543
+ describe("Full registration flow integration", () => {
544
+ it("should complete full registration flow without verification", async ({
545
+ expect,
546
+ }) => {
547
+ const { registrationService, sessionService } = await setup({
548
+ usernameEnabled: true,
549
+ });
550
+
551
+ // Phase 1: Create intent
552
+ const intent = await registrationService.createRegistrationIntent({
553
+ email: "fullflow@example.com",
554
+ username: "fullflowuser",
555
+ password: "SecurePassword123!",
556
+ firstName: "Full",
557
+ lastName: "Flow",
558
+ });
559
+
560
+ expect(intent.expectEmailVerification).toBe(false);
561
+ expect(intent.expectPhoneVerification).toBe(false);
562
+
563
+ // Phase 2: Complete registration
564
+ const user = await registrationService.completeRegistration({
565
+ intentId: intent.intentId,
566
+ });
567
+
568
+ expect(user.email).toBe("fullflow@example.com");
569
+ expect(user.username).toBe("fullflowuser");
570
+
571
+ // Verify user can login
572
+ const session = await sessionService.login(
573
+ "credentials",
574
+ "fullflowuser",
575
+ "SecurePassword123!",
576
+ );
577
+ expect(session?.id).toBe(user.id);
578
+ });
579
+
580
+ it("should complete full registration flow with email verification", async ({
581
+ expect,
582
+ }) => {
583
+ const {
584
+ registrationService,
585
+ sessionService,
586
+ emailProvider,
587
+ userRealmProvider,
588
+ } = await setup();
589
+
590
+ userRealmProvider.register("full-verify-realm", {
591
+ settings: {
592
+ verifyEmailRequired: true,
593
+ } as never,
594
+ });
595
+
596
+ // Phase 1: Create intent
597
+ const intent = await registrationService.createRegistrationIntent(
598
+ {
599
+ email: "fullverify@example.com",
600
+ password: "SecurePassword123!",
601
+ },
602
+ "full-verify-realm",
603
+ );
604
+
605
+ expect(intent.expectEmailVerification).toBe(true);
606
+
607
+ // Extract verification code
608
+ await expect.poll(() => emailProvider.records.length).toBe(1);
609
+ const emailCode = extractCode(emailProvider.records[0].body);
610
+
611
+ // Phase 2: Complete registration with code
612
+ const user = await registrationService.completeRegistration({
613
+ intentId: intent.intentId,
614
+ emailCode,
615
+ });
616
+
617
+ expect(user.email).toBe("fullverify@example.com");
618
+ expect(user.emailVerified).toBe(true);
619
+
620
+ // Verify user can login
621
+ const session = await sessionService.login(
622
+ "credentials",
623
+ "fullverify@example.com",
624
+ "SecurePassword123!",
625
+ "full-verify-realm",
626
+ );
627
+ expect(session?.id).toBe(user.id);
628
+ });
629
+ });
630
+ });
@@ -1,5 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { $inject } from "alepha";
3
+ import { AuditService } from "alepha/api/audits";
3
4
  import type { VerificationController } from "alepha/api/verifications";
4
5
  import { $cache } from "alepha/cache";
5
6
  import { DateTimeProvider } from "alepha/datetime";
@@ -45,6 +46,7 @@ export class RegistrationService {
45
46
  protected readonly verificationController = $client<VerificationController>();
46
47
  protected readonly userNotifications = $inject(UserNotifications);
47
48
  protected readonly userRealmProvider = $inject(UserRealmProvider);
49
+ protected readonly auditService = $inject(AuditService);
48
50
 
49
51
  protected readonly intentCache = $cache<RegistrationIntent>({
50
52
  name: "registration-intents",
@@ -273,6 +275,22 @@ export class RegistrationService {
273
275
  username: user.username,
274
276
  });
275
277
 
278
+ const realm = this.userRealmProvider.getRealm(userRealmName);
279
+
280
+ await this.auditService.recordUser("create", {
281
+ userId: user.id,
282
+ userEmail: user.email ?? undefined,
283
+ userRealm: realm.name,
284
+ resourceId: user.id,
285
+ description: "User registered",
286
+ metadata: {
287
+ username: user.username,
288
+ email: user.email,
289
+ emailVerified: user.emailVerified,
290
+ registrationMethod: "credentials",
291
+ },
292
+ });
293
+
276
294
  return user;
277
295
  }
278
296