alepha 0.15.4 → 0.15.5

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 (282) hide show
  1. package/README.md +26 -11
  2. package/dist/api/audits/index.d.ts +3 -3
  3. package/dist/api/audits/index.js +3 -3
  4. package/dist/api/audits/index.js.map +1 -1
  5. package/dist/api/files/index.d.ts +3 -3
  6. package/dist/api/files/index.js +3 -3
  7. package/dist/api/files/index.js.map +1 -1
  8. package/dist/api/jobs/index.d.ts +47 -4
  9. package/dist/api/jobs/index.d.ts.map +1 -1
  10. package/dist/api/jobs/index.js +100 -5
  11. package/dist/api/jobs/index.js.map +1 -1
  12. package/dist/api/keys/index.d.ts +3 -3
  13. package/dist/api/keys/index.js +3 -3
  14. package/dist/api/keys/index.js.map +1 -1
  15. package/dist/api/notifications/index.d.ts +3 -3
  16. package/dist/api/notifications/index.js +3 -3
  17. package/dist/api/notifications/index.js.map +1 -1
  18. package/dist/api/parameters/index.d.ts +263 -263
  19. package/dist/api/parameters/index.d.ts.map +1 -1
  20. package/dist/api/parameters/index.js +31 -30
  21. package/dist/api/parameters/index.js.map +1 -1
  22. package/dist/api/users/index.d.ts +373 -67
  23. package/dist/api/users/index.d.ts.map +1 -1
  24. package/dist/api/users/index.js +273 -72
  25. package/dist/api/users/index.js.map +1 -1
  26. package/dist/api/verifications/index.d.ts +3 -3
  27. package/dist/api/verifications/index.js +3 -3
  28. package/dist/api/verifications/index.js.map +1 -1
  29. package/dist/batch/index.d.ts +7 -7
  30. package/dist/batch/index.js +3 -3
  31. package/dist/batch/index.js.map +1 -1
  32. package/dist/bucket/index.d.ts +3 -3
  33. package/dist/bucket/index.js +6 -6
  34. package/dist/bucket/index.js.map +1 -1
  35. package/dist/cache/core/index.d.ts +3 -3
  36. package/dist/cache/core/index.js +3 -3
  37. package/dist/cache/core/index.js.map +1 -1
  38. package/dist/cli/index.d.ts +5607 -20
  39. package/dist/cli/index.d.ts.map +1 -1
  40. package/dist/cli/index.js +103 -89
  41. package/dist/cli/index.js.map +1 -1
  42. package/dist/command/index.d.ts +11 -4
  43. package/dist/command/index.d.ts.map +1 -1
  44. package/dist/command/index.js +8 -6
  45. package/dist/command/index.js.map +1 -1
  46. package/dist/core/index.browser.js.map +1 -1
  47. package/dist/core/index.d.ts +4 -8
  48. package/dist/core/index.d.ts.map +1 -1
  49. package/dist/core/index.js +3 -3
  50. package/dist/core/index.js.map +1 -1
  51. package/dist/core/index.native.js.map +1 -1
  52. package/dist/datetime/index.d.ts +3 -3
  53. package/dist/datetime/index.js +3 -3
  54. package/dist/datetime/index.js.map +1 -1
  55. package/dist/email/index.d.ts +3 -3
  56. package/dist/email/index.js +8 -8
  57. package/dist/email/index.js.map +1 -1
  58. package/dist/fake/index.d.ts +3 -3
  59. package/dist/fake/index.js +3 -3
  60. package/dist/fake/index.js.map +1 -1
  61. package/dist/lock/core/index.d.ts +3 -3
  62. package/dist/lock/core/index.js +3 -3
  63. package/dist/lock/core/index.js.map +1 -1
  64. package/dist/logger/index.d.ts +3 -3
  65. package/dist/logger/index.js +6 -3
  66. package/dist/logger/index.js.map +1 -1
  67. package/dist/mcp/index.d.ts +3 -3
  68. package/dist/mcp/index.js +3 -3
  69. package/dist/mcp/index.js.map +1 -1
  70. package/dist/orm/index.d.ts +12 -12
  71. package/dist/orm/index.js +4 -4
  72. package/dist/orm/index.js.map +1 -1
  73. package/dist/queue/core/index.d.ts +3 -3
  74. package/dist/queue/core/index.js +3 -3
  75. package/dist/queue/core/index.js.map +1 -1
  76. package/dist/react/auth/index.d.ts +3 -3
  77. package/dist/react/auth/index.js +3 -3
  78. package/dist/react/auth/index.js.map +1 -1
  79. package/dist/react/core/index.d.ts +3 -3
  80. package/dist/react/core/index.js +3 -3
  81. package/dist/react/core/index.js.map +1 -1
  82. package/dist/react/form/index.d.ts +3 -3
  83. package/dist/react/form/index.js +3 -3
  84. package/dist/react/form/index.js.map +1 -1
  85. package/dist/react/head/index.d.ts +3 -3
  86. package/dist/react/head/index.js +3 -3
  87. package/dist/react/head/index.js.map +1 -1
  88. package/dist/react/i18n/index.d.ts +3 -3
  89. package/dist/react/i18n/index.js +3 -3
  90. package/dist/react/i18n/index.js.map +1 -1
  91. package/dist/react/intro/index.css +337 -0
  92. package/dist/react/intro/index.css.map +1 -0
  93. package/dist/react/intro/index.d.ts +10 -0
  94. package/dist/react/intro/index.d.ts.map +1 -0
  95. package/dist/react/intro/index.js +222 -0
  96. package/dist/react/intro/index.js.map +1 -0
  97. package/dist/react/router/index.browser.js +2 -2
  98. package/dist/react/router/index.browser.js.map +1 -1
  99. package/dist/react/router/index.d.ts +1 -1
  100. package/dist/react/router/index.d.ts.map +1 -1
  101. package/dist/react/router/index.js +5 -5
  102. package/dist/react/router/index.js.map +1 -1
  103. package/dist/redis/index.d.ts +17 -17
  104. package/dist/redis/index.js +3 -3
  105. package/dist/redis/index.js.map +1 -1
  106. package/dist/retry/index.d.ts +3 -3
  107. package/dist/retry/index.js +3 -3
  108. package/dist/retry/index.js.map +1 -1
  109. package/dist/scheduler/index.d.ts +3 -3
  110. package/dist/scheduler/index.js +3 -3
  111. package/dist/scheduler/index.js.map +1 -1
  112. package/dist/security/index.d.ts +3 -3
  113. package/dist/security/index.js +5 -5
  114. package/dist/security/index.js.map +1 -1
  115. package/dist/server/auth/index.d.ts +3 -3
  116. package/dist/server/auth/index.js +3 -3
  117. package/dist/server/auth/index.js.map +1 -1
  118. package/dist/server/cache/index.d.ts +3 -3
  119. package/dist/server/cache/index.js +3 -3
  120. package/dist/server/cache/index.js.map +1 -1
  121. package/dist/server/compress/index.d.ts +3 -3
  122. package/dist/server/compress/index.js +3 -3
  123. package/dist/server/compress/index.js.map +1 -1
  124. package/dist/server/cookies/index.d.ts +3 -3
  125. package/dist/server/cookies/index.js +3 -3
  126. package/dist/server/cookies/index.js.map +1 -1
  127. package/dist/server/core/index.d.ts +5 -16
  128. package/dist/server/core/index.d.ts.map +1 -1
  129. package/dist/server/core/index.js +13 -29
  130. package/dist/server/core/index.js.map +1 -1
  131. package/dist/server/cors/index.d.ts +3 -3
  132. package/dist/server/cors/index.js +3 -3
  133. package/dist/server/cors/index.js.map +1 -1
  134. package/dist/server/health/index.d.ts +20 -20
  135. package/dist/server/health/index.js +3 -3
  136. package/dist/server/health/index.js.map +1 -1
  137. package/dist/server/helmet/index.d.ts +3 -3
  138. package/dist/server/helmet/index.js +3 -3
  139. package/dist/server/helmet/index.js.map +1 -1
  140. package/dist/server/links/index.d.ts +42 -42
  141. package/dist/server/links/index.d.ts.map +1 -1
  142. package/dist/server/links/index.js +3 -3
  143. package/dist/server/links/index.js.map +1 -1
  144. package/dist/server/metrics/index.d.ts +3 -3
  145. package/dist/server/metrics/index.js +3 -3
  146. package/dist/server/metrics/index.js.map +1 -1
  147. package/dist/server/multipart/index.d.ts +3 -3
  148. package/dist/server/multipart/index.js +3 -3
  149. package/dist/server/multipart/index.js.map +1 -1
  150. package/dist/server/proxy/index.d.ts +3 -3
  151. package/dist/server/proxy/index.js +3 -3
  152. package/dist/server/proxy/index.js.map +1 -1
  153. package/dist/server/rate-limit/index.d.ts +3 -3
  154. package/dist/server/rate-limit/index.js +3 -3
  155. package/dist/server/rate-limit/index.js.map +1 -1
  156. package/dist/server/static/index.d.ts +3 -3
  157. package/dist/server/static/index.js +6 -6
  158. package/dist/server/static/index.js.map +1 -1
  159. package/dist/server/swagger/index.d.ts +3 -3
  160. package/dist/server/swagger/index.js +6 -6
  161. package/dist/server/swagger/index.js.map +1 -1
  162. package/dist/sms/index.d.ts +3 -3
  163. package/dist/sms/index.js +6 -6
  164. package/dist/sms/index.js.map +1 -1
  165. package/dist/system/index.d.ts +3 -3
  166. package/dist/system/index.js +3 -3
  167. package/dist/system/index.js.map +1 -1
  168. package/dist/thread/index.d.ts +3 -3
  169. package/dist/thread/index.js +3 -3
  170. package/dist/thread/index.js.map +1 -1
  171. package/dist/topic/core/index.d.ts +3 -3
  172. package/dist/topic/core/index.js +3 -3
  173. package/dist/topic/core/index.js.map +1 -1
  174. package/dist/vite/index.d.ts +6284 -3
  175. package/dist/vite/index.d.ts.map +1 -1
  176. package/dist/websocket/index.d.ts +3 -3
  177. package/dist/websocket/index.js +3 -3
  178. package/dist/websocket/index.js.map +1 -1
  179. package/package.json +7 -2
  180. package/src/api/audits/index.ts +3 -3
  181. package/src/api/files/index.ts +3 -3
  182. package/src/api/jobs/controllers/AdminJobController.ts +15 -2
  183. package/src/api/jobs/index.ts +4 -3
  184. package/src/api/jobs/services/JobAudits.spec.ts +89 -0
  185. package/src/api/jobs/services/JobAudits.ts +101 -0
  186. package/src/api/keys/index.ts +3 -3
  187. package/src/api/notifications/index.ts +3 -3
  188. package/src/api/parameters/index.ts +5 -3
  189. package/src/api/users/__tests__/ApiKeys-integration.spec.ts +1 -1
  190. package/src/api/users/__tests__/ApiKeys.spec.ts +1 -1
  191. package/src/api/users/__tests__/EmailVerification.spec.ts +16 -1
  192. package/src/api/users/__tests__/PasswordReset.spec.ts +11 -0
  193. package/src/api/users/atoms/realmAuthSettingsAtom.ts +10 -0
  194. package/src/api/users/index.ts +8 -9
  195. package/src/api/users/primitives/$realm.ts +117 -19
  196. package/src/api/users/providers/RealmProvider.ts +15 -7
  197. package/src/api/users/services/CredentialService.spec.ts +11 -0
  198. package/src/api/users/services/CredentialService.ts +47 -24
  199. package/src/api/users/services/IdentityService.ts +12 -4
  200. package/src/api/users/services/RegistrationService.spec.ts +11 -0
  201. package/src/api/users/services/RegistrationService.ts +33 -12
  202. package/src/api/users/services/SessionService.ts +83 -12
  203. package/src/api/users/services/UserAudits.ts +47 -0
  204. package/src/api/users/services/UserFiles.ts +19 -0
  205. package/src/api/users/services/UserJobs.spec.ts +107 -0
  206. package/src/api/users/services/UserJobs.ts +62 -0
  207. package/src/api/users/services/UserParameters.ts +23 -0
  208. package/src/api/users/services/UserService.ts +34 -17
  209. package/src/api/verifications/index.ts +3 -3
  210. package/src/batch/index.ts +3 -3
  211. package/src/bucket/index.ts +3 -3
  212. package/src/cache/core/index.ts +3 -3
  213. package/src/cli/commands/db.ts +9 -0
  214. package/src/cli/commands/init.spec.ts +2 -17
  215. package/src/cli/commands/init.ts +37 -1
  216. package/src/cli/providers/ViteDevServerProvider.ts +5 -2
  217. package/src/cli/services/AlephaCliUtils.ts +17 -0
  218. package/src/cli/services/PackageManagerUtils.ts +15 -1
  219. package/src/cli/services/ProjectScaffolder.ts +8 -13
  220. package/src/cli/templates/agentMd.ts +2 -25
  221. package/src/cli/templates/apiAppSecurityTs.ts +37 -2
  222. package/src/cli/templates/mainCss.ts +2 -32
  223. package/src/cli/templates/webAppRouterTs.ts +5 -5
  224. package/src/cli/templates/webHomeComponentTsx.ts +10 -0
  225. package/src/command/helpers/Runner.ts +14 -1
  226. package/src/command/index.ts +3 -3
  227. package/src/core/helpers/primitive.ts +0 -5
  228. package/src/core/index.ts +3 -3
  229. package/src/datetime/index.ts +3 -3
  230. package/src/email/index.ts +3 -3
  231. package/src/email/providers/LocalEmailProvider.ts +2 -2
  232. package/src/fake/index.ts +3 -3
  233. package/src/lock/core/index.ts +3 -3
  234. package/src/logger/index.ts +3 -3
  235. package/src/logger/providers/PrettyFormatterProvider.ts +7 -0
  236. package/src/mcp/index.ts +3 -3
  237. package/src/orm/index.ts +3 -3
  238. package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
  239. package/src/queue/core/index.ts +3 -3
  240. package/src/react/auth/index.ts +3 -3
  241. package/src/react/core/index.ts +3 -3
  242. package/src/react/form/index.ts +3 -3
  243. package/src/react/head/index.ts +3 -3
  244. package/src/react/i18n/index.ts +3 -3
  245. package/src/react/intro/components/GettingStarted.css +334 -0
  246. package/src/react/intro/components/GettingStarted.tsx +276 -0
  247. package/src/react/intro/index.ts +1 -0
  248. package/src/react/router/index.browser.ts +2 -0
  249. package/src/react/router/index.ts +2 -0
  250. package/src/redis/index.ts +3 -3
  251. package/src/retry/index.ts +3 -3
  252. package/src/router/index.ts +3 -3
  253. package/src/scheduler/index.ts +3 -3
  254. package/src/security/index.ts +3 -3
  255. package/src/security/providers/JwtProvider.ts +2 -2
  256. package/src/server/auth/index.ts +3 -3
  257. package/src/server/cache/index.ts +3 -3
  258. package/src/server/compress/index.ts +3 -3
  259. package/src/server/cookies/index.ts +3 -3
  260. package/src/server/core/index.ts +3 -3
  261. package/src/server/core/primitives/$action.spec.ts +3 -2
  262. package/src/server/core/primitives/$action.ts +6 -2
  263. package/src/server/core/providers/NodeHttpServerProvider.ts +2 -15
  264. package/src/server/core/providers/ServerProvider.ts +4 -2
  265. package/src/server/core/providers/ServerRouterProvider.ts +5 -27
  266. package/src/server/cors/index.ts +3 -3
  267. package/src/server/health/index.ts +3 -3
  268. package/src/server/helmet/index.ts +3 -3
  269. package/src/server/links/index.ts +3 -3
  270. package/src/server/metrics/index.ts +3 -3
  271. package/src/server/multipart/index.ts +3 -3
  272. package/src/server/proxy/index.ts +3 -3
  273. package/src/server/rate-limit/index.ts +3 -3
  274. package/src/server/static/index.ts +3 -3
  275. package/src/server/swagger/index.ts +3 -3
  276. package/src/sms/index.ts +3 -3
  277. package/src/system/index.ts +3 -3
  278. package/src/thread/index.ts +3 -3
  279. package/src/topic/core/index.ts +3 -3
  280. package/src/websocket/index.ts +3 -3
  281. package/src/cli/templates/webHelloComponentTsx.ts +0 -30
  282. /package/src/api/users/{notifications → services}/UserNotifications.ts +0 -0
@@ -0,0 +1,101 @@
1
+ import { $audit, type AuditLogOptions } from "alepha/api/audits";
2
+
3
+ /**
4
+ * Job-specific audit service.
5
+ *
6
+ * Provides type-safe audit logging for job-related events.
7
+ * This service is lazy-loaded when the audits feature is enabled.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const jobAudits = alepha.inject(JobAudits);
12
+ * await jobAudits.logTrigger("my-job", { description: "Manually triggered" });
13
+ * ```
14
+ */
15
+ export class JobAudits {
16
+ protected readonly audit = $audit({
17
+ type: "job",
18
+ description: "Background job execution events",
19
+ actions: ["trigger", "pause", "resume", "cancel", "schedule_change"],
20
+ });
21
+
22
+ /**
23
+ * Log a manual job trigger event.
24
+ */
25
+ public async logTrigger(
26
+ jobName: string,
27
+ options: Omit<AuditLogOptions, "resourceType" | "resourceId"> = {},
28
+ ) {
29
+ await this.audit.log("trigger", {
30
+ ...options,
31
+ resourceType: "job",
32
+ resourceId: jobName,
33
+ description: options.description ?? `Manually triggered job: ${jobName}`,
34
+ });
35
+ }
36
+
37
+ /**
38
+ * Log a job pause event.
39
+ */
40
+ public async logPause(
41
+ jobName: string,
42
+ options: Omit<AuditLogOptions, "resourceType" | "resourceId"> = {},
43
+ ) {
44
+ await this.audit.log("pause", {
45
+ ...options,
46
+ resourceType: "job",
47
+ resourceId: jobName,
48
+ description: options.description ?? `Paused job: ${jobName}`,
49
+ });
50
+ }
51
+
52
+ /**
53
+ * Log a job resume event.
54
+ */
55
+ public async logResume(
56
+ jobName: string,
57
+ options: Omit<AuditLogOptions, "resourceType" | "resourceId"> = {},
58
+ ) {
59
+ await this.audit.log("resume", {
60
+ ...options,
61
+ resourceType: "job",
62
+ resourceId: jobName,
63
+ description: options.description ?? `Resumed job: ${jobName}`,
64
+ });
65
+ }
66
+
67
+ /**
68
+ * Log a job cancellation event.
69
+ */
70
+ public async logCancel(
71
+ jobName: string,
72
+ options: Omit<AuditLogOptions, "resourceType" | "resourceId"> = {},
73
+ ) {
74
+ await this.audit.log("cancel", {
75
+ ...options,
76
+ resourceType: "job",
77
+ resourceId: jobName,
78
+ description: options.description ?? `Cancelled job: ${jobName}`,
79
+ });
80
+ }
81
+
82
+ /**
83
+ * Log a job schedule change event.
84
+ */
85
+ public async logScheduleChange(
86
+ jobName: string,
87
+ options: Omit<AuditLogOptions, "resourceType" | "resourceId"> & {
88
+ oldCron?: string;
89
+ newCron?: string;
90
+ } = {},
91
+ ) {
92
+ const { oldCron, newCron, ...rest } = options;
93
+ await this.audit.log("schedule_change", {
94
+ ...rest,
95
+ resourceType: "job",
96
+ resourceId: jobName,
97
+ description: rest.description ?? `Changed schedule for job: ${jobName}`,
98
+ metadata: { oldCron, newCron, ...rest.metadata },
99
+ });
100
+ }
101
+ }
@@ -16,9 +16,9 @@ export * from "./schemas/revokeApiKeyResponseSchema.ts";
16
16
  export * from "./services/ApiKeyService.ts";
17
17
 
18
18
  /**
19
- * | type | quality | stability |
20
- * |------|---------|--------------|
21
- * | backend | good | experimental |
19
+ * | Stability | Since | Runtime |
20
+ * |-----------|-------|---------|
21
+ * | 3 - stable | 0.11.0 | node, bun, workerd|
22
22
  *
23
23
  * API key management module for programmatic access.
24
24
  *
@@ -25,9 +25,9 @@ export * from "./services/NotificationService.ts";
25
25
  // ---------------------------------------------------------------------------------------------------------------------
26
26
 
27
27
  /**
28
- * | type | quality | stability |
29
- * |------|---------|-----------|
30
- * | backend | standard | stable |
28
+ * | Stability | Since | Runtime |
29
+ * |-----------|-------|---------|
30
+ * | 3 - stable | 0.10.0 | node, bun, workerd|
31
31
  *
32
32
  * User notification management.
33
33
  *
@@ -1,5 +1,6 @@
1
1
  import { $module } from "alepha";
2
2
  import { AdminConfigController } from "./controllers/AdminConfigController.ts";
3
+ import { $config } from "./primitives/$config.ts";
3
4
  import { ConfigActivationScheduler } from "./schedulers/ConfigActivationScheduler.ts";
4
5
  import { ConfigStore } from "./services/ConfigStore.ts";
5
6
 
@@ -19,9 +20,9 @@ export * from "./services/ConfigStore.ts";
19
20
  // ---------------------------------------------------------------------------------------------------------------------
20
21
 
21
22
  /**
22
- * | type | quality | stability |
23
- * |------|---------|-----------|
24
- * | backend | standard | stable |
23
+ * | Stability | Since | Runtime |
24
+ * |-----------|-------|---------|
25
+ * | 3 - stable | 0.9.0 | node, bun, workerd|
25
26
  *
26
27
  * Application configuration management.
27
28
  *
@@ -35,5 +36,6 @@ export * from "./services/ConfigStore.ts";
35
36
  */
36
37
  export const AlephaApiParameters = $module({
37
38
  name: "alepha.api.parameters",
39
+ primitives: [$config],
38
40
  services: [ConfigStore, AdminConfigController, ConfigActivationScheduler],
39
41
  });
@@ -33,7 +33,7 @@ const setup = async () => {
33
33
  // Create a realm with API keys enabled
34
34
  class TestApp {
35
35
  realm = $realm({
36
- apiKeys: true,
36
+ features: { apiKeys: true },
37
37
  });
38
38
 
39
39
  // A protected action to test API key authentication (any authenticated user)
@@ -20,7 +20,7 @@ const setup = async () => {
20
20
  // Create a realm with API keys enabled
21
21
  class TestApp {
22
22
  realm = $realm({
23
- apiKeys: true,
23
+ features: { apiKeys: true },
24
24
  });
25
25
  }
26
26
 
@@ -5,7 +5,13 @@ import { AlephaEmail, MemoryEmailProvider } from "alepha/email";
5
5
  import { AlephaSecurity } from "alepha/security";
6
6
  import { BadRequestError } from "alepha/server";
7
7
  import { describe, it } from "vitest";
8
- import { AlephaApiUsers, UserController, UserService } from "../index.ts";
8
+ import {
9
+ AlephaApiUsers,
10
+ RealmProvider,
11
+ UserController,
12
+ UserNotifications,
13
+ UserService,
14
+ } from "../index.ts";
9
15
 
10
16
  const setup = async () => {
11
17
  const alepha = Alepha.create({
@@ -16,9 +22,18 @@ const setup = async () => {
16
22
  alepha.with(AlephaEmail);
17
23
  alepha.with(AlephaApiVerification);
18
24
  alepha.with(AlephaApiUsers);
25
+ alepha.with(UserNotifications);
19
26
 
20
27
  await alepha.start();
21
28
 
29
+ // Enable notifications for the default realm
30
+ const realmProvider = alepha.inject(RealmProvider);
31
+ realmProvider.register("default", {
32
+ features: {
33
+ notifications: true,
34
+ },
35
+ });
36
+
22
37
  const emailProvider = alepha.inject(MemoryEmailProvider);
23
38
  emailProvider.records = [];
24
39
 
@@ -8,8 +8,10 @@ import { describe, it } from "vitest";
8
8
  import {
9
9
  AlephaApiUsers,
10
10
  CredentialService,
11
+ RealmProvider,
11
12
  SessionService,
12
13
  UserController,
14
+ UserNotifications,
13
15
  } from "../index.ts";
14
16
 
15
17
  const setup = async () => {
@@ -21,9 +23,18 @@ const setup = async () => {
21
23
  alepha.with(AlephaEmail);
22
24
  alepha.with(AlephaApiVerification);
23
25
  alepha.with(AlephaApiUsers);
26
+ alepha.with(UserNotifications);
24
27
 
25
28
  await alepha.start();
26
29
 
30
+ // Enable notifications for the default realm
31
+ const realmProvider = alepha.inject(RealmProvider);
32
+ realmProvider.register("default", {
33
+ features: {
34
+ notifications: true,
35
+ },
36
+ });
37
+
27
38
  const emailProvider = alepha.inject(MemoryEmailProvider);
28
39
  emailProvider.records = [];
29
40
 
@@ -62,6 +62,14 @@ export const realmAuthSettingsAtom = $atom({
62
62
  resetPasswordAllowed: t.boolean({
63
63
  description: "Enable forgot password functionality",
64
64
  }),
65
+ adminEmails: t.array(t.email(), {
66
+ description:
67
+ "List of email addresses that are automatically promoted to admin role on login",
68
+ }),
69
+ adminUsernames: t.array(t.text(), {
70
+ description:
71
+ "List of usernames that are automatically promoted to admin role on login",
72
+ }),
65
73
  passwordPolicy: t.object({
66
74
  minLength: t.integer({
67
75
  description: "Minimum password length",
@@ -97,6 +105,8 @@ export const realmAuthSettingsAtom = $atom({
97
105
  resetPasswordAllowed: false,
98
106
  firstNameLastNameEnabled: false,
99
107
  firstNameLastNameRequired: false,
108
+ adminEmails: [],
109
+ adminUsernames: [],
100
110
  // TODO: not implemented yet
101
111
  passwordPolicy: {
102
112
  minLength: 8,
@@ -1,6 +1,4 @@
1
1
  import { $module } from "alepha";
2
- import { AlephaApiNotifications } from "alepha/api/notifications";
3
- import { AlephaApiVerification } from "alepha/api/verifications";
4
2
  import { AlephaEmail } from "alepha/email";
5
3
  import { AlephaServerCompress } from "alepha/server/compress";
6
4
  import { AlephaServerHelmet } from "alepha/server/helmet";
@@ -9,7 +7,6 @@ import { AdminSessionController } from "./controllers/AdminSessionController.ts"
9
7
  import { AdminUserController } from "./controllers/AdminUserController.ts";
10
8
  import { RealmController } from "./controllers/RealmController.ts";
11
9
  import { UserController } from "./controllers/UserController.ts";
12
- import { UserNotifications } from "./notifications/UserNotifications.ts";
13
10
  import { RealmProvider } from "./providers/RealmProvider.ts";
14
11
  import { CredentialService } from "./services/CredentialService.ts";
15
12
  import { IdentityService } from "./services/IdentityService.ts";
@@ -52,14 +49,19 @@ export * from "./services/IdentityService.ts";
52
49
  export * from "./services/RegistrationService.ts";
53
50
  export * from "./services/SessionCrudService.ts";
54
51
  export * from "./services/SessionService.ts";
52
+ export * from "./services/UserAudits.ts";
53
+ export * from "./services/UserFiles.ts";
54
+ export * from "./services/UserJobs.ts";
55
+ export * from "./services/UserNotifications.ts";
56
+ export * from "./services/UserParameters.ts";
55
57
  export * from "./services/UserService.ts";
56
58
 
57
59
  // ---------------------------------------------------------------------------------------------------------------------
58
60
 
59
61
  /**
60
- * | type | quality | stability |
61
- * |------|---------|-----------|
62
- * | backend | epic | stable |
62
+ * | Stability | Since | Runtime |
63
+ * |-----------|-------|---------|
64
+ * | 3 - stable | 0.5.0 | node, bun, workerd|
63
65
  *
64
66
  * Complete user management with multi-realm support for multi-tenant applications.
65
67
  *
@@ -78,8 +80,6 @@ export * from "./services/UserService.ts";
78
80
  export const AlephaApiUsers = $module({
79
81
  name: "alepha.api.users",
80
82
  services: [
81
- AlephaApiVerification,
82
- AlephaApiNotifications,
83
83
  AlephaServerHelmet,
84
84
  AlephaServerCompress,
85
85
  AlephaEmail,
@@ -95,6 +95,5 @@ export const AlephaApiUsers = $module({
95
95
  AdminSessionController,
96
96
  AdminIdentityController,
97
97
  RealmController,
98
- UserNotifications,
99
98
  ],
100
99
  });
@@ -1,8 +1,6 @@
1
1
  import { $context } from "alepha";
2
- import { AlephaApiAudits } from "alepha/api/audits";
3
- import { AlephaApiFiles } from "alepha/api/files";
4
- import { AlephaApiJobs } from "alepha/api/jobs";
5
2
  import { AlephaApiKeys, ApiKeyService } from "alepha/api/keys";
3
+ import { AlephaApiVerification } from "alepha/api/verifications";
6
4
  import type { Repository } from "alepha/orm";
7
5
  import {
8
6
  $issuer,
@@ -27,6 +25,11 @@ import type { sessions } from "../entities/sessions.ts";
27
25
  import { DEFAULT_USER_REALM_NAME, type users } from "../entities/users.ts";
28
26
  import { RealmProvider } from "../providers/RealmProvider.ts";
29
27
  import { SessionService } from "../services/SessionService.ts";
28
+ import { UserAudits } from "../services/UserAudits.ts";
29
+ import { UserFiles } from "../services/UserFiles.ts";
30
+ import { UserJobs } from "../services/UserJobs.ts";
31
+ import { UserNotifications } from "../services/UserNotifications.ts";
32
+ import { UserParameters } from "../services/UserParameters.ts";
30
33
 
31
34
  export type RealmPrimitive = IssuerPrimitive & WithLinkFn & WithLoginFn;
32
35
 
@@ -66,12 +69,50 @@ export const $realm = (options: RealmOptions = {}): RealmPrimitive => {
66
69
  options.settings.phoneEnabled = true;
67
70
  }
68
71
 
72
+ // Merge features with defaults
73
+ const features: RealmFeatures = {
74
+ jobs: false,
75
+ notifications: false,
76
+ apiKeys: false,
77
+ parameters: false,
78
+ files: false,
79
+ audits: false,
80
+ organizations: false,
81
+ ...options.features,
82
+ };
83
+
84
+ // When notifications are disabled, force verification-dependent settings to false
85
+ // These features require sending codes via email/SMS which won't work without notifications
86
+ if (!features.notifications) {
87
+ options.settings.verifyEmailRequired = false;
88
+ options.settings.verifyPhoneRequired = false;
89
+ options.settings.resetPasswordAllowed = false;
90
+ }
91
+
69
92
  const realmRegistration = realmProvider.register(name, options);
70
93
 
71
- // For now, all modules are enabled
72
- alepha.with(AlephaApiFiles);
73
- alepha.with(AlephaApiAudits);
74
- alepha.with(AlephaApiJobs);
94
+ // Enable features based on configuration
95
+ // Each feature registers its wrapper service which internally uses the module primitives
96
+ if (features.files) {
97
+ alepha.with(UserFiles);
98
+ }
99
+
100
+ if (features.audits) {
101
+ alepha.with(UserAudits);
102
+ }
103
+
104
+ if (features.jobs) {
105
+ alepha.with(UserJobs);
106
+ }
107
+
108
+ if (features.notifications) {
109
+ alepha.with(AlephaApiVerification);
110
+ alepha.with(UserNotifications);
111
+ }
112
+
113
+ if (features.parameters) {
114
+ alepha.with(UserParameters);
115
+ }
75
116
 
76
117
  // Collect custom resolvers that will be registered during $issuer.onInit()
77
118
  // This ensures they are registered AFTER the realm is created (not on the default test realm)
@@ -80,7 +121,7 @@ export const $realm = (options: RealmOptions = {}): RealmPrimitive => {
80
121
  ];
81
122
 
82
123
  // Enable API key authentication - must be added to customResolvers before $issuer() call
83
- if (options.apiKeys) {
124
+ if (features.apiKeys) {
84
125
  alepha.with(AlephaApiKeys);
85
126
  const apiKeyService = alepha.inject(ApiKeyService);
86
127
  customResolvers.push(apiKeyService.createResolver());
@@ -176,6 +217,71 @@ export const $realm = (options: RealmOptions = {}): RealmPrimitive => {
176
217
 
177
218
  // ---------------------------------------------------------------------------------------------------------------------
178
219
 
220
+ export interface RealmFeatures {
221
+ /**
222
+ * Enable job execution tracking and purge functionality.
223
+ *
224
+ * @default false
225
+ */
226
+ jobs?: boolean;
227
+
228
+ /**
229
+ * Enable notification system for password reset, verification emails, etc.
230
+ *
231
+ * @default false
232
+ */
233
+ notifications?: boolean;
234
+
235
+ /**
236
+ * Enable API key authentication for programmatic access.
237
+ *
238
+ * When enabled, users can create API keys to access protected endpoints
239
+ * without using JWT tokens. API keys are useful for:
240
+ * - Programmatic access (CLI tools, scripts)
241
+ * - Long-lived authentication tokens
242
+ * - Third-party integrations (MCP servers)
243
+ *
244
+ * API keys can be passed via:
245
+ * - Query parameter: `?api_key=ak_xxx`
246
+ * - Bearer header: `Authorization: Bearer ak_xxx`
247
+ *
248
+ * @default false
249
+ */
250
+ apiKeys?: boolean;
251
+
252
+ /**
253
+ * Enable runtime configuration management.
254
+ *
255
+ * Allows configuring realm settings at runtime with versioning and scheduled activation.
256
+ *
257
+ * @default false
258
+ */
259
+ parameters?: boolean;
260
+
261
+ /**
262
+ * Enable file management for avatar uploads and attachments.
263
+ *
264
+ * @default false
265
+ */
266
+ files?: boolean;
267
+
268
+ /**
269
+ * Enable audit trail for compliance and event logging.
270
+ *
271
+ * @default false
272
+ */
273
+ audits?: boolean;
274
+
275
+ /**
276
+ * Enable organization management to group users.
277
+ *
278
+ * @default false
279
+ */
280
+ organizations?: boolean;
281
+ }
282
+
283
+ // ---------------------------------------------------------------------------------------------------------------------
284
+
179
285
  export interface RealmOptions {
180
286
  /**
181
287
  * Secret key for signing tokens.
@@ -209,17 +315,9 @@ export interface RealmOptions {
209
315
  };
210
316
 
211
317
  /**
212
- * Enable API key authentication.
213
- *
214
- * When enabled, users can create API keys to access protected endpoints
215
- * without using JWT tokens. API keys are useful for:
216
- * - Programmatic access (CLI tools, scripts)
217
- * - Long-lived authentication tokens
218
- * - Third-party integrations
318
+ * Enable or disable realm features.
219
319
  *
220
- * API keys can be passed via:
221
- * - Query parameter: `?api_key=ak_xxx`
222
- * - Bearer header: `Authorization: Bearer ak_xxx`
320
+ * Features control which modules are loaded with the realm.
223
321
  */
224
- apiKeys?: boolean;
322
+ features?: Partial<RealmFeatures>;
225
323
  }
@@ -1,5 +1,4 @@
1
1
  import { $inject, Alepha, AlephaError } from "alepha";
2
- import { $bucket } from "alepha/bucket";
3
2
  import { $repository, type Repository } from "alepha/orm";
4
3
  import {
5
4
  type RealmAuthSettings,
@@ -8,7 +7,7 @@ import {
8
7
  import { identities } from "../entities/identities.ts";
9
8
  import { sessions } from "../entities/sessions.ts";
10
9
  import { DEFAULT_USER_REALM_NAME, users } from "../entities/users.ts";
11
- import type { RealmOptions } from "../primitives/$realm.ts";
10
+ import type { RealmFeatures, RealmOptions } from "../primitives/$realm.ts";
12
11
 
13
12
  export interface RealmRepositories {
14
13
  identities: Repository<typeof identities.schema>;
@@ -20,6 +19,7 @@ export interface Realm {
20
19
  name: string;
21
20
  repositories: RealmRepositories;
22
21
  settings: RealmAuthSettings;
22
+ features: RealmFeatures;
23
23
  }
24
24
 
25
25
  export class RealmProvider {
@@ -31,12 +31,19 @@ export class RealmProvider {
31
31
 
32
32
  protected realms = new Map<string, Realm>();
33
33
 
34
- public avatars = $bucket({
35
- maxSize: 5 * 1024 * 1024, // 5 MB
36
- mimeTypes: ["image/jpeg", "image/png", "image/gif", "image/webp"],
37
- });
38
-
39
34
  public register(realmName: string, realmOptions: RealmOptions = {}) {
35
+ // Merge features with defaults
36
+ const features: RealmFeatures = {
37
+ jobs: false,
38
+ notifications: false,
39
+ apiKeys: false,
40
+ parameters: false,
41
+ files: false,
42
+ audits: false,
43
+ organizations: false,
44
+ ...realmOptions.features,
45
+ };
46
+
40
47
  this.realms.set(realmName, {
41
48
  name: realmName,
42
49
  repositories: {
@@ -53,6 +60,7 @@ export class RealmProvider {
53
60
  ...realmOptions.settings?.passwordPolicy,
54
61
  },
55
62
  },
63
+ features,
56
64
  });
57
65
  return this.getRealm(realmName);
58
66
  }
@@ -8,7 +8,9 @@ import { describe, it } from "vitest";
8
8
  import {
9
9
  AlephaApiUsers,
10
10
  CredentialService,
11
+ RealmProvider,
11
12
  SessionService,
13
+ UserNotifications,
12
14
  UserService,
13
15
  } from "../index.ts";
14
16
 
@@ -21,9 +23,18 @@ const setup = async () => {
21
23
  alepha.with(AlephaEmail);
22
24
  alepha.with(AlephaApiVerification);
23
25
  alepha.with(AlephaApiUsers);
26
+ alepha.with(UserNotifications);
24
27
 
25
28
  await alepha.start();
26
29
 
30
+ // Enable notifications for the default realm
31
+ const realmProvider = alepha.inject(RealmProvider);
32
+ realmProvider.register("default", {
33
+ features: {
34
+ notifications: true,
35
+ },
36
+ });
37
+
27
38
  const emailProvider = alepha.inject(MemoryEmailProvider);
28
39
  emailProvider.records = [];
29
40