alepha 0.14.4 → 0.15.1

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 (322) hide show
  1. package/README.md +44 -102
  2. package/dist/api/audits/index.d.ts +331 -443
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js +2 -2
  5. package/dist/api/audits/index.js.map +1 -1
  6. package/dist/api/files/index.d.ts +0 -113
  7. package/dist/api/files/index.d.ts.map +1 -1
  8. package/dist/api/files/index.js +2 -3
  9. package/dist/api/files/index.js.map +1 -1
  10. package/dist/api/jobs/index.d.ts +151 -262
  11. package/dist/api/jobs/index.d.ts.map +1 -1
  12. package/dist/api/notifications/index.browser.js +4 -4
  13. package/dist/api/notifications/index.browser.js.map +1 -1
  14. package/dist/api/notifications/index.d.ts +164 -276
  15. package/dist/api/notifications/index.d.ts.map +1 -1
  16. package/dist/api/notifications/index.js +4 -4
  17. package/dist/api/notifications/index.js.map +1 -1
  18. package/dist/api/parameters/index.d.ts +265 -377
  19. package/dist/api/parameters/index.d.ts.map +1 -1
  20. package/dist/api/users/index.browser.js +1 -2
  21. package/dist/api/users/index.browser.js.map +1 -1
  22. package/dist/api/users/index.d.ts +195 -301
  23. package/dist/api/users/index.d.ts.map +1 -1
  24. package/dist/api/users/index.js +203 -184
  25. package/dist/api/users/index.js.map +1 -1
  26. package/dist/api/verifications/index.d.ts.map +1 -1
  27. package/dist/batch/index.d.ts.map +1 -1
  28. package/dist/batch/index.js +1 -2
  29. package/dist/batch/index.js.map +1 -1
  30. package/dist/bucket/index.d.ts.map +1 -1
  31. package/dist/cache/core/index.d.ts.map +1 -1
  32. package/dist/cache/redis/index.d.ts.map +1 -1
  33. package/dist/cache/redis/index.js +2 -2
  34. package/dist/cache/redis/index.js.map +1 -1
  35. package/dist/cli/index.d.ts +5900 -165
  36. package/dist/cli/index.d.ts.map +1 -1
  37. package/dist/cli/index.js +1481 -639
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/command/index.d.ts +8 -4
  40. package/dist/command/index.d.ts.map +1 -1
  41. package/dist/command/index.js +29 -25
  42. package/dist/command/index.js.map +1 -1
  43. package/dist/core/index.browser.js +563 -54
  44. package/dist/core/index.browser.js.map +1 -1
  45. package/dist/core/index.d.ts +175 -8
  46. package/dist/core/index.d.ts.map +1 -1
  47. package/dist/core/index.js +564 -54
  48. package/dist/core/index.js.map +1 -1
  49. package/dist/core/index.native.js +563 -54
  50. package/dist/core/index.native.js.map +1 -1
  51. package/dist/datetime/index.d.ts.map +1 -1
  52. package/dist/datetime/index.js +4 -4
  53. package/dist/datetime/index.js.map +1 -1
  54. package/dist/email/index.d.ts +89 -42
  55. package/dist/email/index.d.ts.map +1 -1
  56. package/dist/email/index.js +129 -33
  57. package/dist/email/index.js.map +1 -1
  58. package/dist/fake/index.d.ts +7969 -2
  59. package/dist/fake/index.d.ts.map +1 -1
  60. package/dist/fake/index.js +22 -22
  61. package/dist/fake/index.js.map +1 -1
  62. package/dist/file/index.d.ts +134 -1
  63. package/dist/file/index.d.ts.map +1 -1
  64. package/dist/file/index.js +253 -1
  65. package/dist/file/index.js.map +1 -1
  66. package/dist/lock/core/index.d.ts.map +1 -1
  67. package/dist/lock/redis/index.d.ts.map +1 -1
  68. package/dist/logger/index.d.ts +1 -2
  69. package/dist/logger/index.d.ts.map +1 -1
  70. package/dist/logger/index.js +1 -5
  71. package/dist/logger/index.js.map +1 -1
  72. package/dist/mcp/index.d.ts +19 -1
  73. package/dist/mcp/index.d.ts.map +1 -1
  74. package/dist/mcp/index.js +28 -4
  75. package/dist/mcp/index.js.map +1 -1
  76. package/dist/orm/chunk-DH6iiROE.js +38 -0
  77. package/dist/orm/index.browser.js +9 -9
  78. package/dist/orm/index.browser.js.map +1 -1
  79. package/dist/orm/index.bun.js +2821 -0
  80. package/dist/orm/index.bun.js.map +1 -0
  81. package/dist/orm/index.d.ts +318 -169
  82. package/dist/orm/index.d.ts.map +1 -1
  83. package/dist/orm/index.js +2086 -1776
  84. package/dist/orm/index.js.map +1 -1
  85. package/dist/queue/core/index.d.ts +4 -4
  86. package/dist/queue/core/index.d.ts.map +1 -1
  87. package/dist/queue/redis/index.d.ts.map +1 -1
  88. package/dist/redis/index.bun.js +285 -0
  89. package/dist/redis/index.bun.js.map +1 -0
  90. package/dist/redis/index.d.ts +13 -31
  91. package/dist/redis/index.d.ts.map +1 -1
  92. package/dist/redis/index.js +18 -38
  93. package/dist/redis/index.js.map +1 -1
  94. package/dist/retry/index.d.ts.map +1 -1
  95. package/dist/router/index.d.ts.map +1 -1
  96. package/dist/scheduler/index.d.ts +83 -1
  97. package/dist/scheduler/index.d.ts.map +1 -1
  98. package/dist/scheduler/index.js +393 -1
  99. package/dist/scheduler/index.js.map +1 -1
  100. package/dist/security/index.browser.js +5 -1
  101. package/dist/security/index.browser.js.map +1 -1
  102. package/dist/security/index.d.ts +598 -112
  103. package/dist/security/index.d.ts.map +1 -1
  104. package/dist/security/index.js +1808 -97
  105. package/dist/security/index.js.map +1 -1
  106. package/dist/server/auth/index.d.ts +1200 -175
  107. package/dist/server/auth/index.d.ts.map +1 -1
  108. package/dist/server/auth/index.js +1268 -37
  109. package/dist/server/auth/index.js.map +1 -1
  110. package/dist/server/cache/index.d.ts +6 -3
  111. package/dist/server/cache/index.d.ts.map +1 -1
  112. package/dist/server/cache/index.js +1 -1
  113. package/dist/server/cache/index.js.map +1 -1
  114. package/dist/server/compress/index.d.ts.map +1 -1
  115. package/dist/server/cookies/index.d.ts.map +1 -1
  116. package/dist/server/cookies/index.js +3 -3
  117. package/dist/server/cookies/index.js.map +1 -1
  118. package/dist/server/core/index.d.ts +115 -13
  119. package/dist/server/core/index.d.ts.map +1 -1
  120. package/dist/server/core/index.js +321 -139
  121. package/dist/server/core/index.js.map +1 -1
  122. package/dist/server/cors/index.d.ts +0 -1
  123. package/dist/server/cors/index.d.ts.map +1 -1
  124. package/dist/server/health/index.d.ts +0 -1
  125. package/dist/server/health/index.d.ts.map +1 -1
  126. package/dist/server/helmet/index.d.ts.map +1 -1
  127. package/dist/server/links/index.browser.js +9 -1
  128. package/dist/server/links/index.browser.js.map +1 -1
  129. package/dist/server/links/index.d.ts +1 -2
  130. package/dist/server/links/index.d.ts.map +1 -1
  131. package/dist/server/links/index.js +14 -7
  132. package/dist/server/links/index.js.map +1 -1
  133. package/dist/server/metrics/index.d.ts +514 -1
  134. package/dist/server/metrics/index.d.ts.map +1 -1
  135. package/dist/server/metrics/index.js +4462 -4
  136. package/dist/server/metrics/index.js.map +1 -1
  137. package/dist/server/multipart/index.d.ts.map +1 -1
  138. package/dist/server/proxy/index.d.ts +0 -1
  139. package/dist/server/proxy/index.d.ts.map +1 -1
  140. package/dist/server/rate-limit/index.d.ts.map +1 -1
  141. package/dist/server/static/index.d.ts.map +1 -1
  142. package/dist/server/swagger/index.d.ts +1 -2
  143. package/dist/server/swagger/index.d.ts.map +1 -1
  144. package/dist/server/swagger/index.js +1 -2
  145. package/dist/server/swagger/index.js.map +1 -1
  146. package/dist/sms/index.d.ts +3 -1
  147. package/dist/sms/index.d.ts.map +1 -1
  148. package/dist/sms/index.js +10 -10
  149. package/dist/sms/index.js.map +1 -1
  150. package/dist/thread/index.d.ts +0 -1
  151. package/dist/thread/index.d.ts.map +1 -1
  152. package/dist/thread/index.js +2 -2
  153. package/dist/thread/index.js.map +1 -1
  154. package/dist/topic/core/index.d.ts.map +1 -1
  155. package/dist/topic/redis/index.d.ts.map +1 -1
  156. package/dist/vite/index.d.ts +6315 -149
  157. package/dist/vite/index.d.ts.map +1 -1
  158. package/dist/vite/index.js +140 -469
  159. package/dist/vite/index.js.map +1 -1
  160. package/dist/websocket/index.browser.js +9 -9
  161. package/dist/websocket/index.browser.js.map +1 -1
  162. package/dist/websocket/index.d.ts +28 -28
  163. package/dist/websocket/index.d.ts.map +1 -1
  164. package/dist/websocket/index.js +9 -9
  165. package/dist/websocket/index.js.map +1 -1
  166. package/package.json +13 -18
  167. package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
  168. package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
  169. package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
  170. package/src/api/users/entities/users.ts +1 -1
  171. package/src/api/users/index.ts +8 -8
  172. package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
  173. package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
  174. package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
  175. package/src/api/users/services/CredentialService.ts +7 -7
  176. package/src/api/users/services/IdentityService.ts +4 -4
  177. package/src/api/users/services/RegistrationService.spec.ts +25 -27
  178. package/src/api/users/services/RegistrationService.ts +38 -27
  179. package/src/api/users/services/SessionCrudService.ts +3 -3
  180. package/src/api/users/services/SessionService.spec.ts +3 -3
  181. package/src/api/users/services/SessionService.ts +27 -18
  182. package/src/api/users/services/UserService.ts +7 -7
  183. package/src/batch/providers/BatchProvider.ts +1 -2
  184. package/src/cli/apps/AlephaCli.ts +2 -2
  185. package/src/cli/apps/AlephaPackageBuilderCli.ts +47 -20
  186. package/src/cli/assets/apiHelloControllerTs.ts +19 -0
  187. package/src/cli/assets/apiIndexTs.ts +16 -0
  188. package/src/cli/assets/biomeJson.ts +2 -1
  189. package/src/cli/assets/claudeMd.ts +308 -0
  190. package/src/cli/assets/dummySpecTs.ts +2 -1
  191. package/src/cli/assets/editorconfig.ts +2 -1
  192. package/src/cli/assets/mainBrowserTs.ts +4 -3
  193. package/src/cli/assets/mainCss.ts +24 -0
  194. package/src/cli/assets/mainServerTs.ts +24 -0
  195. package/src/cli/assets/tsconfigJson.ts +2 -1
  196. package/src/cli/assets/webAppRouterTs.ts +16 -0
  197. package/src/cli/assets/webHelloComponentTsx.ts +20 -0
  198. package/src/cli/assets/webIndexTs.ts +16 -0
  199. package/src/cli/atoms/appEntryOptions.ts +13 -0
  200. package/src/cli/atoms/buildOptions.ts +1 -1
  201. package/src/cli/atoms/changelogOptions.ts +1 -1
  202. package/src/cli/commands/build.ts +97 -61
  203. package/src/cli/commands/db.ts +21 -18
  204. package/src/cli/commands/deploy.ts +17 -5
  205. package/src/cli/commands/dev.ts +26 -47
  206. package/src/cli/commands/gen/env.ts +1 -1
  207. package/src/cli/commands/init.ts +79 -25
  208. package/src/cli/commands/lint.ts +9 -3
  209. package/src/cli/commands/test.ts +8 -2
  210. package/src/cli/commands/typecheck.ts +5 -1
  211. package/src/cli/commands/verify.ts +4 -2
  212. package/src/cli/defineConfig.ts +9 -0
  213. package/src/cli/index.ts +2 -1
  214. package/src/cli/providers/AppEntryProvider.ts +131 -0
  215. package/src/cli/providers/ViteBuildProvider.ts +82 -0
  216. package/src/cli/providers/ViteDevServerProvider.ts +350 -0
  217. package/src/cli/providers/ViteTemplateProvider.ts +27 -0
  218. package/src/cli/services/AlephaCliUtils.ts +72 -602
  219. package/src/cli/services/PackageManagerUtils.ts +308 -0
  220. package/src/cli/services/ProjectScaffolder.ts +329 -0
  221. package/src/command/helpers/Runner.ts +15 -3
  222. package/src/core/Alepha.ts +2 -8
  223. package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
  224. package/src/core/index.shared.ts +1 -0
  225. package/src/core/index.ts +2 -0
  226. package/src/core/primitives/$hook.ts +6 -2
  227. package/src/core/primitives/$module.spec.ts +4 -0
  228. package/src/core/primitives/$module.ts +12 -0
  229. package/src/core/providers/AlsProvider.ts +1 -1
  230. package/src/core/providers/CodecManager.spec.ts +12 -6
  231. package/src/core/providers/CodecManager.ts +26 -6
  232. package/src/core/providers/EventManager.ts +169 -13
  233. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +878 -0
  234. package/src/core/providers/KeylessJsonSchemaCodec.ts +789 -0
  235. package/src/core/providers/SchemaValidator.spec.ts +236 -0
  236. package/src/core/providers/StateManager.spec.ts +27 -16
  237. package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
  238. package/src/email/providers/LocalEmailProvider.ts +52 -15
  239. package/src/email/providers/NodemailerEmailProvider.ts +167 -56
  240. package/src/file/errors/FileError.ts +7 -0
  241. package/src/file/index.ts +9 -1
  242. package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
  243. package/src/logger/providers/PrettyFormatterProvider.ts +0 -9
  244. package/src/mcp/errors/McpError.ts +30 -0
  245. package/src/mcp/index.ts +3 -0
  246. package/src/mcp/transports/SseMcpTransport.ts +16 -6
  247. package/src/orm/index.browser.ts +1 -19
  248. package/src/orm/index.bun.ts +77 -0
  249. package/src/orm/index.shared-server.ts +22 -0
  250. package/src/orm/index.shared.ts +15 -0
  251. package/src/orm/index.ts +19 -39
  252. package/src/orm/providers/DrizzleKitProvider.ts +3 -5
  253. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
  254. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  255. package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
  256. package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
  257. package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
  258. package/src/orm/services/Repository.ts +19 -0
  259. package/src/redis/index.bun.ts +35 -0
  260. package/src/redis/providers/BunRedisProvider.ts +12 -43
  261. package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
  262. package/src/redis/providers/NodeRedisProvider.ts +16 -34
  263. package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
  264. package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
  265. package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
  266. package/src/security/index.browser.ts +5 -0
  267. package/src/security/index.ts +90 -7
  268. package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
  269. package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
  270. package/src/security/primitives/$role.ts +5 -5
  271. package/src/security/primitives/$serviceAccount.spec.ts +5 -5
  272. package/src/security/primitives/$serviceAccount.ts +3 -3
  273. package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
  274. package/src/server/auth/primitives/$auth.ts +10 -10
  275. package/src/server/auth/primitives/$authCredentials.ts +3 -3
  276. package/src/server/auth/primitives/$authGithub.ts +3 -3
  277. package/src/server/auth/primitives/$authGoogle.ts +3 -3
  278. package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
  279. package/src/server/cache/providers/ServerCacheProvider.ts +1 -1
  280. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
  281. package/src/server/core/index.ts +1 -1
  282. package/src/server/core/providers/BunHttpServerProvider.ts +1 -1
  283. package/src/server/core/providers/NodeHttpServerProvider.spec.ts +125 -0
  284. package/src/server/core/providers/NodeHttpServerProvider.ts +92 -24
  285. package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
  286. package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
  287. package/src/server/core/providers/ServerProvider.ts +144 -24
  288. package/src/server/core/providers/ServerRouterProvider.ts +259 -115
  289. package/src/server/core/providers/ServerTimingProvider.ts +2 -2
  290. package/src/server/links/atoms/apiLinksAtom.ts +7 -0
  291. package/src/server/links/index.browser.ts +2 -0
  292. package/src/server/links/index.ts +3 -1
  293. package/src/server/links/providers/LinkProvider.ts +1 -1
  294. package/src/server/swagger/index.ts +1 -1
  295. package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
  296. package/src/sms/providers/LocalSmsProvider.ts +8 -7
  297. package/src/vite/index.ts +3 -2
  298. package/src/vite/tasks/buildClient.ts +0 -1
  299. package/src/vite/tasks/buildServer.ts +80 -22
  300. package/src/vite/tasks/copyAssets.ts +5 -4
  301. package/src/vite/tasks/generateCloudflare.ts +7 -0
  302. package/src/vite/tasks/generateSitemap.ts +64 -23
  303. package/src/vite/tasks/index.ts +0 -2
  304. package/src/vite/tasks/prerenderPages.ts +49 -24
  305. package/dist/server/security/index.browser.js +0 -13
  306. package/dist/server/security/index.browser.js.map +0 -1
  307. package/dist/server/security/index.d.ts +0 -173
  308. package/dist/server/security/index.d.ts.map +0 -1
  309. package/dist/server/security/index.js +0 -311
  310. package/dist/server/security/index.js.map +0 -1
  311. package/src/cli/assets/appRouterTs.ts +0 -9
  312. package/src/cli/assets/indexHtml.ts +0 -15
  313. package/src/cli/assets/mainTs.ts +0 -13
  314. package/src/cli/commands/format.ts +0 -17
  315. package/src/server/security/index.browser.ts +0 -10
  316. package/src/server/security/index.ts +0 -94
  317. package/src/vite/helpers/boot.ts +0 -106
  318. package/src/vite/plugins/viteAlephaDev.ts +0 -177
  319. package/src/vite/tasks/devServer.ts +0 -69
  320. package/src/vite/tasks/runAlepha.ts +0 -270
  321. /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
  322. /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
@@ -14,7 +14,7 @@ import { type ServerRequest, UnauthorizedError } from "alepha/server";
14
14
  import type { OAuth2Profile } from "alepha/server/auth";
15
15
  import { $client } from "alepha/server/links";
16
16
  import type { UserEntity } from "../entities/users.ts";
17
- import { UserRealmProvider } from "../providers/UserRealmProvider.ts";
17
+ import { RealmProvider } from "../providers/RealmProvider.ts";
18
18
 
19
19
  export class SessionService {
20
20
  protected readonly alepha = $inject(Alepha);
@@ -22,20 +22,20 @@ export class SessionService {
22
22
  protected readonly dateTimeProvider = $inject(DateTimeProvider);
23
23
  protected readonly cryptoProvider = $inject(CryptoProvider);
24
24
  protected readonly log = $logger();
25
- protected readonly userRealmProvider = $inject(UserRealmProvider);
25
+ protected readonly realmProvider = $inject(RealmProvider);
26
26
  protected readonly fileController = $client<FileController>();
27
27
  protected readonly auditService = $inject(AuditService);
28
28
 
29
29
  public users(userRealmName?: string) {
30
- return this.userRealmProvider.userRepository(userRealmName);
30
+ return this.realmProvider.userRepository(userRealmName);
31
31
  }
32
32
 
33
33
  public sessions(userRealmName?: string) {
34
- return this.userRealmProvider.sessionRepository(userRealmName);
34
+ return this.realmProvider.sessionRepository(userRealmName);
35
35
  }
36
36
 
37
37
  public identities(userRealmName?: string) {
38
- return this.userRealmProvider.identityRepository(userRealmName);
38
+ return this.realmProvider.identityRepository(userRealmName);
39
39
  }
40
40
 
41
41
  /**
@@ -55,7 +55,7 @@ export class SessionService {
55
55
  password: string,
56
56
  userRealmName?: string,
57
57
  ): Promise<UserEntity> {
58
- const { settings, name } = this.userRealmProvider.getRealm(userRealmName);
58
+ const { settings, name } = this.realmProvider.getRealm(userRealmName);
59
59
  const isEmail = username.includes("@");
60
60
  const isPhone = /^[+\d][\d\s()-]+$/.test(username);
61
61
  const isUsername = !isEmail && !isPhone;
@@ -70,6 +70,25 @@ export class SessionService {
70
70
  where.realm = name;
71
71
 
72
72
  if (settings.usernameEnabled !== false && isUsername) {
73
+ // validate username format if regex is provided
74
+ if (settings.usernameRegExp) {
75
+ const regex = new RegExp(settings.usernameRegExp);
76
+ if (!regex.test(username)) {
77
+ this.log.warn("Username does not match required format", {
78
+ provider,
79
+ username,
80
+ realm: name,
81
+ });
82
+
83
+ await this.auditService.recordAuth("login_failed", {
84
+ userRealm: name,
85
+ description: "Username does not match required format",
86
+ metadata: { provider, username },
87
+ });
88
+
89
+ throw new InvalidCredentialsError();
90
+ }
91
+ }
73
92
  where.username = username;
74
93
  } else if (settings.emailEnabled !== false && isEmail) {
75
94
  where.email = username;
@@ -237,16 +256,6 @@ export class SessionService {
237
256
  userId: session.userId,
238
257
  });
239
258
 
240
- const { name } = this.userRealmProvider.getRealm(userRealmName);
241
-
242
- await this.auditService.recordAuth("token_refresh", {
243
- userId: user.id,
244
- userEmail: user.email ?? undefined,
245
- userRealm: name,
246
- sessionId: session.id,
247
- description: "Session token refreshed",
248
- });
249
-
250
259
  return {
251
260
  user,
252
261
  expiresIn: expiresAt.unix() - now.unix(),
@@ -270,7 +279,7 @@ export class SessionService {
270
279
  this.log.debug("Session deleted");
271
280
 
272
281
  if (session) {
273
- const { name } = this.userRealmProvider.getRealm(userRealmName);
282
+ const { name } = this.realmProvider.getRealm(userRealmName);
274
283
 
275
284
  await this.auditService.recordAuth("logout", {
276
285
  userId: session.userId,
@@ -292,7 +301,7 @@ export class SessionService {
292
301
  email: profile.email,
293
302
  });
294
303
 
295
- const realm = this.userRealmProvider.getRealm(userRealmName);
304
+ const realm = this.realmProvider.getRealm(userRealmName);
296
305
  const identities = this.identities(userRealmName);
297
306
  const users = this.users(userRealmName);
298
307
 
@@ -7,7 +7,7 @@ import { BadRequestError } from "alepha/server";
7
7
  import { $client } from "alepha/server/links";
8
8
  import type { UserEntity } from "../entities/users.ts";
9
9
  import { UserNotifications } from "../notifications/UserNotifications.ts";
10
- import { UserRealmProvider } from "../providers/UserRealmProvider.ts";
10
+ import { RealmProvider } from "../providers/RealmProvider.ts";
11
11
  import type { CreateUser } from "../schemas/createUserSchema.ts";
12
12
  import type { UpdateUser } from "../schemas/updateUserSchema.ts";
13
13
  import type { UserQuery } from "../schemas/userQuerySchema.ts";
@@ -16,11 +16,11 @@ export class UserService {
16
16
  protected readonly log = $logger();
17
17
  protected readonly verificationController = $client<VerificationController>();
18
18
  protected readonly userNotifications = $inject(UserNotifications);
19
- protected readonly userRealmProvider = $inject(UserRealmProvider);
19
+ protected readonly realmProvider = $inject(RealmProvider);
20
20
  protected readonly auditService = $inject(AuditService);
21
21
 
22
22
  public users(userRealmName?: string) {
23
- return this.userRealmProvider.userRepository(userRealmName);
23
+ return this.realmProvider.userRepository(userRealmName);
24
24
  }
25
25
 
26
26
  /**
@@ -156,7 +156,7 @@ export class UserService {
156
156
 
157
157
  this.log.info("Email verified", { email, userId: user.id, type });
158
158
 
159
- const realm = this.userRealmProvider.getRealm(userRealmName);
159
+ const realm = this.realmProvider.getRealm(userRealmName);
160
160
 
161
161
  await this.auditService.recordUser("update", {
162
162
  userId: user.id,
@@ -256,7 +256,7 @@ export class UserService {
256
256
  userRealmName,
257
257
  });
258
258
 
259
- const realm = this.userRealmProvider.getRealm(userRealmName);
259
+ const realm = this.realmProvider.getRealm(userRealmName);
260
260
 
261
261
  // TODO: one query instead of 3
262
262
 
@@ -342,7 +342,7 @@ export class UserService {
342
342
  const user = await this.users(userRealmName).updateById(id, data);
343
343
  this.log.debug("User updated", { userId: id });
344
344
 
345
- const realm = this.userRealmProvider.getRealm(userRealmName);
345
+ const realm = this.realmProvider.getRealm(userRealmName);
346
346
 
347
347
  // Build changes object showing what was updated
348
348
  const changes: Record<string, { from: unknown; to: unknown }> = {};
@@ -382,7 +382,7 @@ export class UserService {
382
382
  await this.users(userRealmName).deleteById(id);
383
383
  this.log.info("User deleted", { userId: id });
384
384
 
385
- const realm = this.userRealmProvider.getRealm(userRealmName);
385
+ const realm = this.realmProvider.getRealm(userRealmName);
386
386
 
387
387
  await this.auditService.recordUser("delete", {
388
388
  userRealm: realm.name,
@@ -1,4 +1,3 @@
1
- import { randomUUID } from "node:crypto";
2
1
  import { $inject, type Alepha } from "alepha";
3
2
  import { DateTimeProvider, type DurationLike } from "alepha/datetime";
4
3
  import { $logger } from "alepha/logger";
@@ -188,7 +187,7 @@ export class BatchProvider {
188
187
  item: TItem,
189
188
  ): string {
190
189
  // 1. Generate unique ID
191
- const id = randomUUID();
190
+ const id = crypto.randomUUID();
192
191
 
193
192
  // 2. Determine the partition key (with error handling)
194
193
  let partitionKey: string;
@@ -5,7 +5,6 @@ import { CleanCommand } from "../commands/clean.ts";
5
5
  import { DbCommand } from "../commands/db.ts";
6
6
  import { DeployCommand } from "../commands/deploy.ts";
7
7
  import { DevCommand } from "../commands/dev.ts";
8
- import { FormatCommand } from "../commands/format.ts";
9
8
  import { GitProvider } from "../commands/gen/changelog.ts";
10
9
  import { GenCommand } from "../commands/gen.ts";
11
10
  import { InitCommand } from "../commands/init.ts";
@@ -14,6 +13,7 @@ import { RootCommand } from "../commands/root.ts";
14
13
  import { TestCommand } from "../commands/test.ts";
15
14
  import { TypecheckCommand } from "../commands/typecheck.ts";
16
15
  import { VerifyCommand } from "../commands/verify.ts";
16
+ import { AppEntryProvider } from "../providers/AppEntryProvider.ts";
17
17
 
18
18
  // ---------------------------------------------------------------------------------------------------------------------
19
19
 
@@ -73,7 +73,6 @@ export const AlephaCli = $module({
73
73
  DbCommand,
74
74
  DeployCommand,
75
75
  DevCommand,
76
- FormatCommand,
77
76
  InitCommand,
78
77
  LintCommand,
79
78
  RootCommand,
@@ -82,6 +81,7 @@ export const AlephaCli = $module({
82
81
  VerifyCommand,
83
82
  GenCommand,
84
83
  // Support services
84
+ AppEntryProvider,
85
85
  GitProvider,
86
86
  ],
87
87
  });
@@ -1,7 +1,7 @@
1
1
  import { access, readdir, readFile } from "node:fs/promises";
2
2
  import * as os from "node:os";
3
3
  import { join } from "node:path";
4
- import { $inject } from "alepha";
4
+ import { $inject, AlephaError } from "alepha";
5
5
  import { $command } from "alepha/command";
6
6
  import { FileSystemProvider } from "alepha/file";
7
7
  import type { InlineConfig } from "tsdown";
@@ -11,6 +11,7 @@ interface Module {
11
11
  dependencies: string[];
12
12
  native?: boolean;
13
13
  browser?: boolean;
14
+ bun?: boolean;
14
15
  node?: boolean;
15
16
  }
16
17
 
@@ -24,13 +25,13 @@ export class AlephaPackageBuilderCli {
24
25
  handler: async ({ run, root }) => {
25
26
  const modules: Array<Module> = [];
26
27
 
27
- const pkg = await readFile("package.json", "utf-8");
28
- const pkgData = JSON.parse(pkg);
28
+ const pkgBuffer = await this.fs.readFile("package.json");
29
+ const pkgData = JSON.parse(pkgBuffer.toString("utf-8"));
29
30
  const packageName = pkgData.name as string;
30
31
 
31
32
  await run("analyze modules", async () => {
32
33
  modules.push(
33
- ...(await analyzeModules(join(root, this.src), packageName)),
34
+ ...(await analyzeModules(this.fs.join(root, this.src), packageName)),
34
35
  );
35
36
  });
36
37
 
@@ -56,6 +57,10 @@ export class AlephaPackageBuilderCli {
56
57
  pkgData.exports[path].browser = `./src/${item.name}/index.browser.ts`;
57
58
  }
58
59
 
60
+ if (item.bun) {
61
+ pkgData.exports[path].bun = `./src/${item.name}/index.bun.ts`;
62
+ }
63
+
59
64
  pkgData.exports[path].import = `./src/${item.name}/index.ts`;
60
65
  pkgData.exports[path].default = `./src/${item.name}/index.ts`;
61
66
  }
@@ -72,21 +77,20 @@ export class AlephaPackageBuilderCli {
72
77
 
73
78
  await this.fs.writeFile("package.json", JSON.stringify(pkgData, null, 2));
74
79
 
75
- const tmpDir = join(root, "node_modules/.alepha");
80
+ const tmpDir = this.fs.join(root, "node_modules/.alepha");
76
81
  await this.fs.mkdir(tmpDir, { recursive: true }).catch(() => {});
77
82
 
78
83
  await this.fs.writeFile(
79
- join(tmpDir, "module-dependencies.json"),
84
+ this.fs.join(tmpDir, "module-dependencies.json"),
80
85
  JSON.stringify(modules, null, 2),
81
86
  );
82
87
 
83
- const tsconfig = await readFile(
84
- join(root, "../../tsconfig.json"),
85
- "utf-8",
88
+ const tsconfigBuffer = await this.fs.readFile(
89
+ this.fs.join(root, "../../tsconfig.json"),
86
90
  );
87
91
 
88
92
  const external: string[] = Object.keys(
89
- JSON.parse(tsconfig).compilerOptions.paths,
93
+ JSON.parse(tsconfigBuffer.toString("utf-8")).compilerOptions.paths,
90
94
  );
91
95
 
92
96
  external.push("bun");
@@ -96,46 +100,61 @@ export class AlephaPackageBuilderCli {
96
100
 
97
101
  const build = async (item: Module) => {
98
102
  const entries: InlineConfig[] = [];
99
- const src = join(root, this.src, item.name);
100
- const dest = join(root, this.dist, item.name);
103
+ const src = this.fs.join(root, this.src, item.name);
104
+ const dest = this.fs.join(root, this.dist, item.name);
101
105
 
102
106
  entries.push({
103
- entry: join(src, "index.ts"),
107
+ entry: this.fs.join(src, "index.ts"),
104
108
  outDir: dest,
105
109
  format: ["esm"],
106
110
  sourcemap: true,
107
111
  fixedExtension: false,
108
112
  platform: "node", // TODO: node must be enabled only if index.node.ts exists
113
+ inlineOnly: false,
109
114
  external,
110
115
  dts: {
111
116
  sourcemap: true,
112
- resolve: false,
113
117
  },
114
118
  });
115
119
 
116
120
  if (item.native) {
117
121
  entries.push({
118
- entry: join(src, "index.native.ts"),
122
+ entry: this.fs.join(src, "index.native.ts"),
119
123
  outDir: dest,
120
124
  platform: "neutral",
121
125
  sourcemap: true,
122
126
  dts: false,
127
+ inlineOnly: false,
123
128
  external,
124
129
  });
125
130
  }
126
131
 
127
132
  if (item.browser) {
128
133
  entries.push({
129
- entry: join(src, "index.browser.ts"),
134
+ entry: this.fs.join(src, "index.browser.ts"),
130
135
  outDir: dest,
131
136
  platform: "browser",
132
137
  sourcemap: true,
133
138
  dts: false,
139
+ inlineOnly: false,
134
140
  external,
135
141
  });
136
142
  }
137
143
 
138
- const config = join(
144
+ if (item.bun) {
145
+ entries.push({
146
+ entry: this.fs.join(src, "index.bun.ts"),
147
+ outDir: dest,
148
+ platform: "node",
149
+ sourcemap: true,
150
+ fixedExtension: false,
151
+ dts: false,
152
+ inlineOnly: false,
153
+ external,
154
+ });
155
+ }
156
+
157
+ const config = this.fs.join(
139
158
  tmpDir,
140
159
  `tsdown-${item.name.replace("/", "-")}.config.js`,
141
160
  );
@@ -143,8 +162,10 @@ export class AlephaPackageBuilderCli {
143
162
  config,
144
163
  `export default ${JSON.stringify(entries, null, 2)};`,
145
164
  );
165
+
166
+ // /!\ Warning /!\
167
+ // avoid to call tsdown programmatically, when we spawn 8 processes at once it 'JavaScript heap out of memory' :---)
146
168
  await run(`npx tsdown -c=${config}`);
147
- //await this.fs.rm(config);
148
169
  };
149
170
 
150
171
  const concurrency = Math.ceil(os.cpus().length / 2);
@@ -168,6 +189,8 @@ export class AlephaPackageBuilderCli {
168
189
  });
169
190
  }
170
191
 
192
+ export default AlephaPackageBuilderCli;
193
+
171
194
  async function getAllFiles(dir: string): Promise<string[]> {
172
195
  const files: string[] = [];
173
196
 
@@ -261,7 +284,9 @@ function detectCircularDependencies(modules: Module[]): void {
261
284
  for (const module of modules) {
262
285
  const cycle = hasCycle(module.name);
263
286
  if (cycle) {
264
- throw new Error(`Circular dependency detected: ${cycle.join(" -> ")}`);
287
+ throw new AlephaError(
288
+ `Circular dependency detected: ${cycle.join(" -> ")}`,
289
+ );
265
290
  }
266
291
  }
267
292
  }
@@ -287,13 +312,14 @@ export async function analyzeModules(
287
312
  // This is a module
288
313
  const dependencies = new Set<string>();
289
314
 
290
- // Check for browser/node entry points
315
+ // Check for browser/node/bun entry points
291
316
  const hasBrowser = await fileExists(
292
317
  join(modulePath, "index.browser.ts"),
293
318
  );
294
319
  const hasNative = await fileExists(
295
320
  join(modulePath, "index.native.ts"),
296
321
  );
322
+ const hasBun = await fileExists(join(modulePath, "index.bun.ts"));
297
323
  const hasNode = await fileExists(join(modulePath, "index.node.ts"));
298
324
 
299
325
  // Get all .ts/.tsx files in this module
@@ -328,6 +354,7 @@ export async function analyzeModules(
328
354
 
329
355
  if (hasNative) module.native = true;
330
356
  if (hasBrowser) module.browser = true;
357
+ if (hasBun) module.bun = true;
331
358
  if (hasNode) module.node = true;
332
359
 
333
360
  modules.push(module);
@@ -0,0 +1,19 @@
1
+ export const apiHelloControllerTs = () =>
2
+ `
3
+ import { t } from "alepha";
4
+ import { $action } from "alepha/server";
5
+
6
+ export class HelloController {
7
+ hello = $action({
8
+ path: "/hello",
9
+ schema: {
10
+ response: t.object({
11
+ message: t.string(),
12
+ }),
13
+ },
14
+ handler: () => ({
15
+ message: "Hello, Alepha!",
16
+ }),
17
+ });
18
+ }
19
+ `.trim();
@@ -0,0 +1,16 @@
1
+ export interface ApiIndexTsOptions {
2
+ appName?: string;
3
+ }
4
+
5
+ export const apiIndexTs = (options: ApiIndexTsOptions = {}) => {
6
+ const { appName = "app" } = options;
7
+ return `
8
+ import { $module } from "alepha";
9
+ import { HelloController } from "./controllers/HelloController.ts";
10
+
11
+ export const ApiModule = $module({
12
+ name: "${appName}.api",
13
+ services: [HelloController],
14
+ });
15
+ `.trim();
16
+ };
@@ -1,4 +1,5 @@
1
- export const biomeJson = `
1
+ export const biomeJson = () =>
2
+ `
2
3
  {
3
4
  "$schema": "https://biomejs.dev/schemas/latest/schema.json",
4
5
  "vcs": {