alepha 0.15.3 → 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 (318) hide show
  1. package/README.md +26 -11
  2. package/dist/api/audits/index.d.ts +335 -335
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js +11 -3
  5. package/dist/api/audits/index.js.map +1 -1
  6. package/dist/api/files/index.d.ts +3 -3
  7. package/dist/api/files/index.js +4 -3
  8. package/dist/api/files/index.js.map +1 -1
  9. package/dist/api/jobs/index.d.ts +198 -155
  10. package/dist/api/jobs/index.d.ts.map +1 -1
  11. package/dist/api/jobs/index.js +103 -5
  12. package/dist/api/jobs/index.js.map +1 -1
  13. package/dist/api/keys/index.d.ts +198 -198
  14. package/dist/api/keys/index.d.ts.map +1 -1
  15. package/dist/api/keys/index.js +3 -3
  16. package/dist/api/keys/index.js.map +1 -1
  17. package/dist/api/notifications/index.browser.js +1 -0
  18. package/dist/api/notifications/index.browser.js.map +1 -1
  19. package/dist/api/notifications/index.d.ts +3 -3
  20. package/dist/api/notifications/index.js +4 -3
  21. package/dist/api/notifications/index.js.map +1 -1
  22. package/dist/api/parameters/index.d.ts +263 -263
  23. package/dist/api/parameters/index.d.ts.map +1 -1
  24. package/dist/api/parameters/index.js +41 -30
  25. package/dist/api/parameters/index.js.map +1 -1
  26. package/dist/api/users/index.d.ts +383 -77
  27. package/dist/api/users/index.d.ts.map +1 -1
  28. package/dist/api/users/index.js +284 -72
  29. package/dist/api/users/index.js.map +1 -1
  30. package/dist/api/verifications/index.d.ts +131 -131
  31. package/dist/api/verifications/index.d.ts.map +1 -1
  32. package/dist/api/verifications/index.js +3 -3
  33. package/dist/api/verifications/index.js.map +1 -1
  34. package/dist/batch/index.d.ts +3 -3
  35. package/dist/batch/index.js +3 -3
  36. package/dist/batch/index.js.map +1 -1
  37. package/dist/bucket/index.d.ts +3 -3
  38. package/dist/bucket/index.js +6 -6
  39. package/dist/bucket/index.js.map +1 -1
  40. package/dist/cache/core/index.d.ts +3 -3
  41. package/dist/cache/core/index.js +3 -3
  42. package/dist/cache/core/index.js.map +1 -1
  43. package/dist/cli/index.d.ts +5612 -20
  44. package/dist/cli/index.d.ts.map +1 -1
  45. package/dist/cli/index.js +122 -91
  46. package/dist/cli/index.js.map +1 -1
  47. package/dist/command/index.d.ts +11 -4
  48. package/dist/command/index.d.ts.map +1 -1
  49. package/dist/command/index.js +8 -6
  50. package/dist/command/index.js.map +1 -1
  51. package/dist/core/index.browser.js.map +1 -1
  52. package/dist/core/index.d.ts +4 -8
  53. package/dist/core/index.d.ts.map +1 -1
  54. package/dist/core/index.js +3 -3
  55. package/dist/core/index.js.map +1 -1
  56. package/dist/core/index.native.js.map +1 -1
  57. package/dist/datetime/index.d.ts +3 -3
  58. package/dist/datetime/index.js +3 -3
  59. package/dist/datetime/index.js.map +1 -1
  60. package/dist/email/index.d.ts +16 -16
  61. package/dist/email/index.d.ts.map +1 -1
  62. package/dist/email/index.js +10562 -10
  63. package/dist/email/index.js.map +1 -1
  64. package/dist/fake/index.d.ts +3 -3
  65. package/dist/fake/index.js +3 -3
  66. package/dist/fake/index.js.map +1 -1
  67. package/dist/lock/core/index.d.ts +9 -4
  68. package/dist/lock/core/index.d.ts.map +1 -1
  69. package/dist/lock/core/index.js +12 -4
  70. package/dist/lock/core/index.js.map +1 -1
  71. package/dist/logger/index.d.ts +3 -3
  72. package/dist/logger/index.js +6 -3
  73. package/dist/logger/index.js.map +1 -1
  74. package/dist/mcp/index.d.ts +3 -3
  75. package/dist/mcp/index.js +3 -3
  76. package/dist/mcp/index.js.map +1 -1
  77. package/dist/orm/index.d.ts +12 -12
  78. package/dist/orm/index.js +4 -4
  79. package/dist/orm/index.js.map +1 -1
  80. package/dist/queue/core/index.d.ts +3 -3
  81. package/dist/queue/core/index.js +3 -3
  82. package/dist/queue/core/index.js.map +1 -1
  83. package/dist/react/auth/index.browser.js +2 -1
  84. package/dist/react/auth/index.browser.js.map +1 -1
  85. package/dist/react/auth/index.d.ts +3 -3
  86. package/dist/react/auth/index.js +5 -4
  87. package/dist/react/auth/index.js.map +1 -1
  88. package/dist/react/core/index.d.ts +6 -6
  89. package/dist/react/core/index.js +3 -3
  90. package/dist/react/core/index.js.map +1 -1
  91. package/dist/react/form/index.d.ts +3 -3
  92. package/dist/react/form/index.js +3 -3
  93. package/dist/react/form/index.js.map +1 -1
  94. package/dist/react/head/index.d.ts +3 -3
  95. package/dist/react/head/index.js +3 -3
  96. package/dist/react/head/index.js.map +1 -1
  97. package/dist/react/i18n/index.d.ts +3 -3
  98. package/dist/react/i18n/index.js +3 -3
  99. package/dist/react/i18n/index.js.map +1 -1
  100. package/dist/react/intro/index.css +337 -0
  101. package/dist/react/intro/index.css.map +1 -0
  102. package/dist/react/intro/index.d.ts +10 -0
  103. package/dist/react/intro/index.d.ts.map +1 -0
  104. package/dist/react/intro/index.js +222 -0
  105. package/dist/react/intro/index.js.map +1 -0
  106. package/dist/react/router/index.browser.js +2 -2
  107. package/dist/react/router/index.browser.js.map +1 -1
  108. package/dist/react/router/index.d.ts +11 -1
  109. package/dist/react/router/index.d.ts.map +1 -1
  110. package/dist/react/router/index.js +21 -11
  111. package/dist/react/router/index.js.map +1 -1
  112. package/dist/redis/index.d.ts +22 -22
  113. package/dist/redis/index.js +3 -3
  114. package/dist/redis/index.js.map +1 -1
  115. package/dist/retry/index.d.ts +3 -3
  116. package/dist/retry/index.js +3 -3
  117. package/dist/retry/index.js.map +1 -1
  118. package/dist/scheduler/index.d.ts +16 -4
  119. package/dist/scheduler/index.d.ts.map +1 -1
  120. package/dist/scheduler/index.js +45 -7
  121. package/dist/scheduler/index.js.map +1 -1
  122. package/dist/security/index.d.ts +3 -3
  123. package/dist/security/index.js +5 -5
  124. package/dist/security/index.js.map +1 -1
  125. package/dist/server/auth/index.d.ts +3 -3
  126. package/dist/server/auth/index.js +3 -3
  127. package/dist/server/auth/index.js.map +1 -1
  128. package/dist/server/cache/index.d.ts +3 -3
  129. package/dist/server/cache/index.js +3 -3
  130. package/dist/server/cache/index.js.map +1 -1
  131. package/dist/server/compress/index.d.ts +3 -3
  132. package/dist/server/compress/index.d.ts.map +1 -1
  133. package/dist/server/compress/index.js +4 -3
  134. package/dist/server/compress/index.js.map +1 -1
  135. package/dist/server/cookies/index.d.ts +3 -3
  136. package/dist/server/cookies/index.js +3 -3
  137. package/dist/server/cookies/index.js.map +1 -1
  138. package/dist/server/core/index.d.ts +14 -25
  139. package/dist/server/core/index.d.ts.map +1 -1
  140. package/dist/server/core/index.js +13 -29
  141. package/dist/server/core/index.js.map +1 -1
  142. package/dist/server/cors/index.d.ts +3 -3
  143. package/dist/server/cors/index.js +3 -3
  144. package/dist/server/cors/index.js.map +1 -1
  145. package/dist/server/health/index.d.ts +20 -20
  146. package/dist/server/health/index.js +3 -3
  147. package/dist/server/health/index.js.map +1 -1
  148. package/dist/server/helmet/index.d.ts +3 -3
  149. package/dist/server/helmet/index.js +3 -3
  150. package/dist/server/helmet/index.js.map +1 -1
  151. package/dist/server/links/index.d.ts +42 -42
  152. package/dist/server/links/index.d.ts.map +1 -1
  153. package/dist/server/links/index.js +4 -4
  154. package/dist/server/links/index.js.map +1 -1
  155. package/dist/server/metrics/index.d.ts +3 -3
  156. package/dist/server/metrics/index.js +3 -3
  157. package/dist/server/metrics/index.js.map +1 -1
  158. package/dist/server/multipart/index.d.ts +3 -3
  159. package/dist/server/multipart/index.js +3 -3
  160. package/dist/server/multipart/index.js.map +1 -1
  161. package/dist/server/proxy/index.d.ts +3 -3
  162. package/dist/server/proxy/index.js +3 -3
  163. package/dist/server/proxy/index.js.map +1 -1
  164. package/dist/server/rate-limit/index.d.ts +3 -3
  165. package/dist/server/rate-limit/index.js +3 -3
  166. package/dist/server/rate-limit/index.js.map +1 -1
  167. package/dist/server/static/index.d.ts +3 -3
  168. package/dist/server/static/index.js +6 -6
  169. package/dist/server/static/index.js.map +1 -1
  170. package/dist/server/swagger/index.d.ts +3 -3
  171. package/dist/server/swagger/index.js +6 -6
  172. package/dist/server/swagger/index.js.map +1 -1
  173. package/dist/sms/index.d.ts +3 -3
  174. package/dist/sms/index.js +6 -6
  175. package/dist/sms/index.js.map +1 -1
  176. package/dist/system/index.d.ts +3 -3
  177. package/dist/system/index.js +3 -3
  178. package/dist/system/index.js.map +1 -1
  179. package/dist/thread/index.d.ts +3 -3
  180. package/dist/thread/index.js +3 -3
  181. package/dist/thread/index.js.map +1 -1
  182. package/dist/topic/core/index.d.ts +3 -3
  183. package/dist/topic/core/index.js +3 -3
  184. package/dist/topic/core/index.js.map +1 -1
  185. package/dist/vite/index.d.ts +6286 -4
  186. package/dist/vite/index.d.ts.map +1 -1
  187. package/dist/vite/index.js +28 -2
  188. package/dist/vite/index.js.map +1 -1
  189. package/dist/websocket/index.d.ts +37 -37
  190. package/dist/websocket/index.d.ts.map +1 -1
  191. package/dist/websocket/index.js +3 -3
  192. package/dist/websocket/index.js.map +1 -1
  193. package/package.json +12 -4
  194. package/src/api/audits/controllers/AdminAuditController.ts +8 -0
  195. package/src/api/audits/index.ts +3 -3
  196. package/src/api/files/controllers/AdminFileStatsController.ts +1 -0
  197. package/src/api/files/index.ts +3 -3
  198. package/src/api/jobs/controllers/AdminJobController.ts +18 -2
  199. package/src/api/jobs/index.ts +4 -3
  200. package/src/api/jobs/services/JobAudits.spec.ts +89 -0
  201. package/src/api/jobs/services/JobAudits.ts +101 -0
  202. package/src/api/keys/index.ts +3 -3
  203. package/src/api/notifications/controllers/AdminNotificationController.ts +1 -0
  204. package/src/api/notifications/index.ts +3 -3
  205. package/src/api/parameters/controllers/AdminConfigController.ts +10 -0
  206. package/src/api/parameters/index.ts +5 -3
  207. package/src/api/users/__tests__/ApiKeys-integration.spec.ts +1 -1
  208. package/src/api/users/__tests__/ApiKeys.spec.ts +1 -1
  209. package/src/api/users/__tests__/EmailVerification.spec.ts +16 -1
  210. package/src/api/users/__tests__/PasswordReset.spec.ts +11 -0
  211. package/src/api/users/atoms/realmAuthSettingsAtom.ts +10 -0
  212. package/src/api/users/controllers/AdminIdentityController.ts +3 -0
  213. package/src/api/users/controllers/AdminSessionController.ts +3 -0
  214. package/src/api/users/controllers/AdminUserController.ts +5 -0
  215. package/src/api/users/index.ts +8 -9
  216. package/src/api/users/primitives/$realm.ts +117 -19
  217. package/src/api/users/providers/RealmProvider.ts +15 -7
  218. package/src/api/users/services/CredentialService.spec.ts +11 -0
  219. package/src/api/users/services/CredentialService.ts +47 -24
  220. package/src/api/users/services/IdentityService.ts +12 -4
  221. package/src/api/users/services/RegistrationService.spec.ts +11 -0
  222. package/src/api/users/services/RegistrationService.ts +33 -12
  223. package/src/api/users/services/SessionService.ts +83 -12
  224. package/src/api/users/services/UserAudits.ts +47 -0
  225. package/src/api/users/services/UserFiles.ts +19 -0
  226. package/src/api/users/services/UserJobs.spec.ts +107 -0
  227. package/src/api/users/services/UserJobs.ts +62 -0
  228. package/src/api/users/services/UserParameters.ts +23 -0
  229. package/src/api/users/services/UserService.ts +34 -17
  230. package/src/api/verifications/index.ts +3 -3
  231. package/src/batch/index.ts +3 -3
  232. package/src/bucket/index.ts +3 -3
  233. package/src/cache/core/index.ts +3 -3
  234. package/src/cli/commands/build.ts +1 -0
  235. package/src/cli/commands/db.ts +9 -0
  236. package/src/cli/commands/init.spec.ts +2 -17
  237. package/src/cli/commands/init.ts +37 -1
  238. package/src/cli/providers/ViteDevServerProvider.ts +36 -2
  239. package/src/cli/services/AlephaCliUtils.ts +17 -0
  240. package/src/cli/services/PackageManagerUtils.ts +15 -1
  241. package/src/cli/services/ProjectScaffolder.ts +8 -13
  242. package/src/cli/templates/agentMd.ts +2 -25
  243. package/src/cli/templates/apiAppSecurityTs.ts +37 -2
  244. package/src/cli/templates/mainCss.ts +2 -32
  245. package/src/cli/templates/webAppRouterTs.ts +5 -5
  246. package/src/cli/templates/webHomeComponentTsx.ts +10 -0
  247. package/src/command/helpers/Runner.ts +14 -1
  248. package/src/command/index.ts +3 -3
  249. package/src/core/helpers/primitive.ts +0 -5
  250. package/src/core/index.ts +3 -3
  251. package/src/datetime/index.ts +3 -3
  252. package/src/email/index.ts +3 -3
  253. package/src/email/index.workerd.ts +36 -0
  254. package/src/email/providers/LocalEmailProvider.ts +2 -2
  255. package/src/email/providers/WorkermailerEmailProvider.ts +221 -0
  256. package/src/fake/index.ts +3 -3
  257. package/src/lock/core/index.ts +3 -3
  258. package/src/lock/core/primitives/$lock.ts +13 -1
  259. package/src/logger/index.ts +3 -3
  260. package/src/logger/providers/PrettyFormatterProvider.ts +7 -0
  261. package/src/mcp/index.ts +3 -3
  262. package/src/orm/index.ts +3 -3
  263. package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
  264. package/src/queue/core/index.ts +3 -3
  265. package/src/react/auth/index.ts +3 -3
  266. package/src/react/auth/services/ReactAuth.ts +3 -1
  267. package/src/react/core/index.ts +3 -3
  268. package/src/react/form/index.ts +3 -3
  269. package/src/react/head/index.ts +3 -3
  270. package/src/react/i18n/index.ts +3 -3
  271. package/src/react/intro/components/GettingStarted.css +334 -0
  272. package/src/react/intro/components/GettingStarted.tsx +276 -0
  273. package/src/react/intro/index.ts +1 -0
  274. package/src/react/router/atoms/ssrManifestAtom.ts +7 -0
  275. package/src/react/router/index.browser.ts +2 -0
  276. package/src/react/router/index.ts +2 -0
  277. package/src/react/router/providers/ReactServerProvider.ts +14 -4
  278. package/src/react/router/providers/SSRManifestProvider.ts +7 -0
  279. package/src/redis/index.ts +3 -3
  280. package/src/retry/index.ts +3 -3
  281. package/src/router/index.ts +3 -3
  282. package/src/scheduler/index.ts +3 -3
  283. package/src/scheduler/index.workerd.ts +43 -0
  284. package/src/scheduler/providers/CronProvider.ts +53 -6
  285. package/src/scheduler/providers/WorkerdCronProvider.ts +102 -0
  286. package/src/security/index.ts +3 -3
  287. package/src/security/providers/JwtProvider.ts +2 -2
  288. package/src/server/auth/index.ts +3 -3
  289. package/src/server/cache/index.ts +3 -3
  290. package/src/server/compress/index.ts +3 -3
  291. package/src/server/compress/providers/ServerCompressProvider.ts +6 -0
  292. package/src/server/cookies/index.ts +3 -3
  293. package/src/server/core/index.ts +3 -3
  294. package/src/server/core/primitives/$action.spec.ts +3 -2
  295. package/src/server/core/primitives/$action.ts +6 -2
  296. package/src/server/core/providers/NodeHttpServerProvider.ts +2 -15
  297. package/src/server/core/providers/ServerProvider.ts +4 -2
  298. package/src/server/core/providers/ServerRouterProvider.ts +5 -27
  299. package/src/server/cors/index.ts +3 -3
  300. package/src/server/health/index.ts +3 -3
  301. package/src/server/helmet/index.ts +3 -3
  302. package/src/server/links/index.ts +3 -3
  303. package/src/server/links/providers/ServerLinksProvider.spec.ts +332 -0
  304. package/src/server/links/providers/ServerLinksProvider.ts +1 -1
  305. package/src/server/metrics/index.ts +3 -3
  306. package/src/server/multipart/index.ts +3 -3
  307. package/src/server/proxy/index.ts +3 -3
  308. package/src/server/rate-limit/index.ts +3 -3
  309. package/src/server/static/index.ts +3 -3
  310. package/src/server/swagger/index.ts +3 -3
  311. package/src/sms/index.ts +3 -3
  312. package/src/system/index.ts +3 -3
  313. package/src/thread/index.ts +3 -3
  314. package/src/topic/core/index.ts +3 -3
  315. package/src/vite/tasks/generateCloudflare.ts +38 -2
  316. package/src/websocket/index.ts +3 -3
  317. package/src/cli/templates/webHelloComponentTsx.ts +0 -30
  318. /package/src/api/users/{notifications → services}/UserNotifications.ts +0 -0
@@ -9,6 +9,7 @@ import type {
9
9
  import { FileSystemProvider } from "alepha/system";
10
10
  import { AppEntryProvider } from "../providers/AppEntryProvider.ts";
11
11
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
12
+ import { PackageManagerUtils } from "../services/PackageManagerUtils.ts";
12
13
 
13
14
  const drizzleCommandFlags = t.object({
14
15
  provider: t.optional(
@@ -29,6 +30,7 @@ export class DbCommand {
29
30
  protected readonly log = $logger();
30
31
  protected readonly fs = $inject(FileSystemProvider);
31
32
  protected readonly utils = $inject(AlephaCliUtils);
33
+ protected readonly pm = $inject(PackageManagerUtils);
32
34
  protected readonly entryProvider = $inject(AppEntryProvider);
33
35
 
34
36
  /**
@@ -316,6 +318,13 @@ export class DbCommand {
316
318
  this.log.info("");
317
319
  this.log.info(options.logMessage(providerName, dialect));
318
320
 
321
+ if (dialect === "sqlite") {
322
+ await this.pm.ensureDependency(options.root, "better-sqlite3", {
323
+ dev: true,
324
+ exec: (cmd, opts) => this.utils.exec(cmd, opts),
325
+ });
326
+ }
327
+
319
328
  const drizzleConfigJsPath = await this.prepareDrizzleConfig({
320
329
  kit: drizzleKitProvider,
321
330
  provider,
@@ -316,7 +316,7 @@ describe("alepha init", () => {
316
316
 
317
317
  expect(fs.wasWritten("/project/src/web/index.ts")).toBe(true);
318
318
  expect(fs.wasWritten("/project/src/web/AppRouter.ts")).toBe(true);
319
- expect(fs.wasWritten("/project/src/web/components/Hello.tsx")).toBe(true);
319
+ expect(fs.wasWritten("/project/src/web/components/Home.tsx")).toBe(true);
320
320
  });
321
321
 
322
322
  it("should create main.browser.ts for client-side entry", async () => {
@@ -331,28 +331,13 @@ describe("alepha init", () => {
331
331
  ).toBe(true);
332
332
  });
333
333
 
334
- it("should create main.css with base styles", async () => {
334
+ it("should create main.css", async () => {
335
335
  const { fs, cli, cmd, json } = createTestEnv();
336
336
  await setupProject(fs, json);
337
337
 
338
338
  await cli.run(cmd.init, { argv: "--react", root: "/project" });
339
339
 
340
340
  expect(fs.wasWritten("/project/src/main.css")).toBe(true);
341
- expect(fs.wasWrittenMatching("/project/src/main.css", /box-sizing/)).toBe(
342
- true,
343
- );
344
- });
345
-
346
- it("should create main.css with @alepha/ui import when --ui", async () => {
347
- const { fs, cli, cmd, json } = createTestEnv();
348
- await setupProject(fs, json);
349
-
350
- await cli.run(cmd.init, { argv: "--react --ui", root: "/project" });
351
-
352
- expect(fs.wasWritten("/project/src/main.css")).toBe(true);
353
- expect(
354
- fs.wasWrittenMatching("/project/src/main.css", /@alepha\/ui\/styles/),
355
- ).toBe(true);
356
341
  });
357
342
 
358
343
  it("should not create api structure without --api flag", async () => {
@@ -1,11 +1,14 @@
1
1
  import { $inject, t } from "alepha";
2
2
  import { $command } from "alepha/command";
3
+ import { $logger, ConsoleColorProvider } from "alepha/logger";
3
4
  import { FileSystemProvider } from "alepha/system";
4
5
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
5
6
  import { PackageManagerUtils } from "../services/PackageManagerUtils.ts";
6
7
  import { ProjectScaffolder } from "../services/ProjectScaffolder.ts";
7
8
 
8
9
  export class InitCommand {
10
+ protected readonly log = $logger();
11
+ protected readonly colors = $inject(ConsoleColorProvider);
9
12
  protected readonly utils = $inject(AlephaCliUtils);
10
13
  protected readonly pm = $inject(PackageManagerUtils);
11
14
  protected readonly scaffolder = $inject(ProjectScaffolder);
@@ -106,6 +109,11 @@ export class InitCommand {
106
109
 
107
110
  const isExpo = await this.pm.hasExpo(root);
108
111
 
112
+ // Get git email for admin auto-promotion (if auth enabled)
113
+ const adminEmail = flags.auth
114
+ ? await this.utils.getGitEmail()
115
+ : undefined;
116
+
109
117
  const force = !!flags.force;
110
118
 
111
119
  await run({
@@ -113,9 +121,9 @@ export class InitCommand {
113
121
  handler: async () => {
114
122
  await this.scaffolder.ensureConfig(root, {
115
123
  force,
116
- tsconfigJson: !workspace.config.tsconfigJson,
117
124
  packageJson: { ...flags, isPackage: workspace.isPackage },
118
125
  // Skip workspace-level configs if they exist at workspace root
126
+ tsconfigJson: !workspace.config.tsconfigJson,
119
127
  biomeJson: !workspace.config.biomeJson,
120
128
  editorconfig: !workspace.config.editorconfig,
121
129
  agentMd: agentType
@@ -132,6 +140,7 @@ export class InitCommand {
132
140
  if (flags.api) {
133
141
  await this.scaffolder.ensureApiProject(root, {
134
142
  auth: !!flags.auth,
143
+ adminEmail,
135
144
  force,
136
145
  });
137
146
  }
@@ -196,6 +205,33 @@ export class InitCommand {
196
205
  });
197
206
  }
198
207
  }
208
+
209
+ run.end();
210
+
211
+ // Success message
212
+ const projectName = args || ".";
213
+ const pmRun = pmName === "npm" ? "npm run" : pmName;
214
+ const c = this.colors;
215
+
216
+ this.log.info("");
217
+ this.log.info(` ${c.set("GREEN", "✓")} Project ready!`);
218
+ this.log.info("");
219
+ this.log.info(
220
+ ` ${c.set("GREY_DARK", "$")} cd ${c.set("CYAN", projectName)}`,
221
+ );
222
+ this.log.info(
223
+ ` ${c.set("GREY_DARK", "$")} ${c.set("CYAN", `${pmRun} dev`)}`,
224
+ );
225
+
226
+ if (adminEmail) {
227
+ this.log.info("");
228
+ this.log.info(` Admin email: ${c.set("GREEN", adminEmail)}`);
229
+ this.log.info(
230
+ ` ${c.set("GREY_DARK", "(from git config, change in src/api/AppSecurity.ts)")}`,
231
+ );
232
+ }
233
+
234
+ this.log.info("");
199
235
  },
200
236
  });
201
237
  }
@@ -219,6 +219,9 @@ export class ViteDevServerProvider {
219
219
  );
220
220
  }
221
221
 
222
+ // expose Vite server to Alepha for Logger SSR Fix stack traces
223
+ alepha.store.set("alepha.vite.server" as any, this.server);
224
+
222
225
  this.alepha = alepha;
223
226
  await this.setupAlepha();
224
227
 
@@ -245,6 +248,11 @@ export class ViteDevServerProvider {
245
248
  return;
246
249
  }
247
250
 
251
+ // Generate dev head content using Vite's transformIndexHtml
252
+ // This lets Vite and all plugins (React, etc.) inject their scripts
253
+ const devHead = await this.generateDevHead();
254
+ this.alepha.store.set("alepha.react.ssr.manifest" as any, { devHead });
255
+
248
256
  this.alepha.events.on("server:onRequest", {
249
257
  priority: "first",
250
258
  callback: async ({ request }) => {
@@ -264,6 +272,32 @@ export class ViteDevServerProvider {
264
272
  });
265
273
  }
266
274
 
275
+ /**
276
+ * Generate dev head content by transforming a minimal HTML through Vite.
277
+ * This lets Vite and all plugins inject their scripts (HMR client, React Fast Refresh, etc.).
278
+ */
279
+ protected async generateDevHead(): Promise<string> {
280
+ const { browser, style } = this.options.entry;
281
+
282
+ // Build minimal HTML with entry points
283
+ const scripts: string[] = [];
284
+ if (style) {
285
+ scripts.push(`<link rel="stylesheet" href="/${style}">`);
286
+ }
287
+ if (browser) {
288
+ scripts.push(`<script type="module" src="/${browser}"></script>`);
289
+ }
290
+
291
+ const minimalHtml = `<!DOCTYPE html><html><head>${scripts.join("\n")}</head><body></body></html>`;
292
+
293
+ // Transform through Vite to inject all plugin scripts
294
+ const transformed = await this.server.transformIndexHtml("/", minimalHtml);
295
+
296
+ // Extract head content
297
+ const headMatch = transformed.match(/<head>([\s\S]*?)<\/head>/i);
298
+ return headMatch?.[1]?.trim() ?? "";
299
+ }
300
+
267
301
  /**
268
302
  * Check if request is for an HTML page (not an asset).
269
303
  */
@@ -312,8 +346,8 @@ export class ViteDevServerProvider {
312
346
  const originalEnd = res.end.bind(res);
313
347
 
314
348
  const guardedCall = <T>(fn: (...args: any[]) => T, ...args: any[]): T => {
315
- if (resolved && !ctx.metadata.vite) {
316
- // Vite didn't handle this request, silently ignore late writes
349
+ if (resolved && ctx.metadata.vite) {
350
+ // Vite already handled this request, ignore late writes from framework
317
351
  return undefined as T;
318
352
  }
319
353
  return fn(...args);
@@ -161,4 +161,21 @@ ${models.map((it: string) => `export const ${it} = models["${it}"];`).join("\n")
161
161
  return "unknown";
162
162
  }
163
163
  }
164
+
165
+ /**
166
+ * Get the user's email from git config.
167
+ *
168
+ * @returns The git user email or undefined if not configured
169
+ */
170
+ public async getGitEmail(): Promise<string | undefined> {
171
+ try {
172
+ const result = await this.shell.run("git config user.email", {
173
+ capture: true,
174
+ });
175
+ const email = result.trim();
176
+ return email || undefined;
177
+ } catch {
178
+ return undefined;
179
+ }
180
+ }
164
181
  }
@@ -48,6 +48,7 @@ export class PackageManagerUtils {
48
48
 
49
49
  /**
50
50
  * Detect the package manager used in the project.
51
+ * Checks current directory first, then workspace root if in a monorepo.
51
52
  */
52
53
  public async getPackageManager(
53
54
  root: string,
@@ -55,10 +56,21 @@ export class PackageManagerUtils {
55
56
  ): Promise<"yarn" | "pnpm" | "npm" | "bun"> {
56
57
  if (pm) return pm;
57
58
  if (this.alepha.isBun()) return "bun";
59
+
60
+ // Check current directory first
58
61
  if (await this.fs.exists(this.fs.join(root, "bun.lock"))) return "bun";
59
62
  if (await this.fs.exists(this.fs.join(root, "yarn.lock"))) return "yarn";
60
63
  if (await this.fs.exists(this.fs.join(root, "pnpm-lock.yaml")))
61
64
  return "pnpm";
65
+ if (await this.fs.exists(this.fs.join(root, "package-lock.json")))
66
+ return "npm";
67
+
68
+ // Check workspace root (for monorepo packages like apps/blog)
69
+ const workspace = await this.getWorkspaceContext(root);
70
+ if (workspace.packageManager) {
71
+ return workspace.packageManager;
72
+ }
73
+
62
74
  return "npm";
63
75
  }
64
76
 
@@ -358,7 +370,9 @@ export class PackageManagerUtils {
358
370
  alepha: `^${version}`,
359
371
  };
360
372
 
361
- const devDependencies: Record<string, string> = {};
373
+ const devDependencies: Record<string, string> = {
374
+ vite: alephaDeps.vite,
375
+ };
362
376
 
363
377
  // Add biome/vitest only if not a workspace package (workspace root has them)
364
378
  if (!modes.isPackage) {
@@ -19,7 +19,7 @@ import { mainCss } from "../templates/mainCss.ts";
19
19
  import { mainServerTs } from "../templates/mainServerTs.ts";
20
20
  import { tsconfigJson } from "../templates/tsconfigJson.ts";
21
21
  import { webAppRouterTs } from "../templates/webAppRouterTs.ts";
22
- import { webHelloComponentTsx } from "../templates/webHelloComponentTsx.ts";
22
+ import { webHomeComponentTsx } from "../templates/webHomeComponentTsx.ts";
23
23
  import { webIndexTs } from "../templates/webIndexTs.ts";
24
24
  import { AlephaCliUtils } from "./AlephaCliUtils.ts";
25
25
  import {
@@ -34,7 +34,7 @@ import {
34
34
  * - Project structure (src/api, src/web)
35
35
  * - Configuration files (tsconfig, biome, editorconfig)
36
36
  * - Entry points (main.server.ts, main.browser.ts)
37
- * - Example code (HelloController, Hello component)
37
+ * - Example code (HelloController, Home component)
38
38
  */
39
39
  export class ProjectScaffolder {
40
40
  protected readonly log = $logger();
@@ -228,7 +228,7 @@ export class ProjectScaffolder {
228
228
  */
229
229
  public async ensureApiProject(
230
230
  root: string,
231
- opts: { auth?: boolean; force?: boolean } = {},
231
+ opts: { auth?: boolean; adminEmail?: string; force?: boolean } = {},
232
232
  ): Promise<void> {
233
233
  const appName = this.getAppName(root);
234
234
 
@@ -256,7 +256,7 @@ export class ProjectScaffolder {
256
256
  await this.ensureFile(
257
257
  root,
258
258
  "src/api/AppSecurity.ts",
259
- apiAppSecurityTs(),
259
+ apiAppSecurityTs({ adminEmail: opts.adminEmail }),
260
260
  opts.force,
261
261
  );
262
262
  }
@@ -272,7 +272,7 @@ export class ProjectScaffolder {
272
272
  * Creates:
273
273
  * - src/main.browser.ts
274
274
  * - src/main.css
275
- * - src/web/index.ts, src/web/AppRouter.ts, src/web/components/Hello.tsx
275
+ * - src/web/index.ts, src/web/AppRouter.ts, src/web/components/Home.tsx
276
276
  */
277
277
  public async ensureWebProject(
278
278
  root: string,
@@ -292,12 +292,7 @@ export class ProjectScaffolder {
292
292
  });
293
293
 
294
294
  // src/main.css
295
- await this.ensureFile(
296
- root,
297
- "src/main.css",
298
- mainCss({ ui: opts.ui }),
299
- opts.force,
300
- );
295
+ await this.ensureFile(root, "src/main.css", mainCss(), opts.force);
301
296
 
302
297
  // Web structure
303
298
  await this.ensureFile(
@@ -319,8 +314,8 @@ export class ProjectScaffolder {
319
314
  );
320
315
  await this.ensureFile(
321
316
  root,
322
- "src/web/components/Hello.tsx",
323
- webHelloComponentTsx({ auth: opts.auth }),
317
+ "src/web/components/Home.tsx",
318
+ webHomeComponentTsx(),
324
319
  opts.force,
325
320
  );
326
321
  await this.ensureFile(
@@ -27,6 +27,7 @@ This file provides guidance to AI coding assistants when working with this Aleph
27
27
 
28
28
  ### Pages with \`$page\`
29
29
  \`\`\`tsx
30
+ import { t } from "alepha";
30
31
  import { $page } from "alepha/react/router";
31
32
  import { $client } from "alepha/server/links";
32
33
  import type { UserController } from "./UserController.ts";
@@ -196,31 +197,6 @@ class AppRouter {
196
197
  }
197
198
  \`\`\`
198
199
 
199
- ### Modules with \`$module\`
200
- \`\`\`typescript
201
- // src/api/index.ts - Groups all API services
202
- import { $module } from "alepha";
203
-
204
- export const ApiModule = $module({
205
- name: "app.api",
206
- services: [
207
- UserController,
208
- OrderController,
209
- UserService,
210
- ],
211
- });
212
-
213
- // src/web/index.ts - Groups all web services (React only)
214
- export const WebModule = $module({
215
- name: "app.web",
216
- services: [AppRouter, Toaster],
217
- register(alepha) {
218
- // Optional: configure additional services
219
- alepha.with(SomeLibrary);
220
- },
221
- });
222
- \`\`\`
223
-
224
200
  ### Environment Variables
225
201
  \`\`\`typescript
226
202
  import { $env, t } from "alepha";
@@ -268,6 +244,7 @@ describe("UserService", () => {
268
244
  it("should create user", async () => {
269
245
  const alepha = Alepha.create().with(UserService);
270
246
  const service = alepha.inject(UserService);
247
+ await alepha.start();
271
248
 
272
249
  const user = await service.create({ email: "test@example.com" });
273
250
  expect(user.email).toBe("test@example.com");
@@ -1,10 +1,45 @@
1
- export const apiAppSecurityTs = () => {
1
+ export const apiAppSecurityTs = (opts: { adminEmail?: string } = {}) => {
2
+ const adminEmailsValue = opts.adminEmail ? `["${opts.adminEmail}"]` : "[]";
3
+
2
4
  return `
3
5
  import { $realm } from "alepha/api/users";
4
6
 
5
7
  export class AppSecurity {
6
8
  users = $realm({
7
- // configure your realm here
9
+ settings: {
10
+ // Auto-promote these users to admin on login
11
+ adminEmails: ${adminEmailsValue},
12
+ adminUsernames: [],
13
+
14
+ // Registration & login options
15
+ registrationAllowed: true,
16
+ emailEnabled: true,
17
+ emailRequired: true,
18
+ usernameEnabled: false,
19
+ usernameRequired: false,
20
+ phoneEnabled: false,
21
+ phoneRequired: false,
22
+
23
+ // Verification (requires notifications feature)
24
+ verifyEmailRequired: false,
25
+ verifyPhoneRequired: false,
26
+ resetPasswordAllowed: false,
27
+ },
28
+ features: {
29
+ // Enable additional features
30
+ notifications: false,
31
+ audits: false,
32
+ apiKeys: false,
33
+ jobs: false,
34
+ files: false,
35
+ parameters: false,
36
+ },
37
+ identities: {
38
+ // Enable authentication providers
39
+ credentials: true,
40
+ // google: true,
41
+ // github: true,
42
+ },
8
43
  });
9
44
  }
10
45
  `.trim();
@@ -1,33 +1,3 @@
1
- export interface MainCssOptions {
2
- ui?: boolean;
3
- }
4
-
5
- export const mainCss = (options: MainCssOptions = {}) => {
6
- if (options.ui) {
7
- return `@import "@alepha/ui/styles";`;
8
- }
9
-
10
- return `
11
- * {
12
- box-sizing: border-box;
13
- margin: 0;
14
- padding: 0;
15
- }
16
-
17
- html,
18
- body {
19
- height: 100%;
20
- }
21
-
22
- body {
23
- font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
24
- "Helvetica Neue", Arial, sans-serif;
25
- line-height: 1.5;
26
- -webkit-font-smoothing: antialiased;
27
- }
28
-
29
- #root {
30
- height: 100%;
31
- }
32
- `.trim();
1
+ export const mainCss = () => {
2
+ return `@import "@alepha/ui/styles";`;
33
3
  };
@@ -47,22 +47,22 @@ export const webAppRouterTs = (options: {
47
47
  }
48
48
 
49
49
  classMembers.push(` layout = $page({
50
- parent: this.ui.root,
51
- children: () => [this.home],
52
- });`);
50
+ parent: this.ui.root,
51
+ children: () => [this.home],
52
+ });`);
53
53
  }
54
54
 
55
55
  // Home page - with or without loader
56
56
  if (options.api) {
57
57
  classMembers.push(` home = $page({
58
58
  path: "/",
59
- lazy: () => import("./components/Hello.tsx"),
59
+ lazy: () => import("./components/Home.tsx"),
60
60
  loader: () => this.api.hello(),
61
61
  });`);
62
62
  } else {
63
63
  classMembers.push(` home = $page({
64
64
  path: "/",
65
- lazy: () => import("./components/Hello.tsx"),
65
+ lazy: () => import("./components/Home.tsx"),
66
66
  });`);
67
67
  }
68
68
 
@@ -0,0 +1,10 @@
1
+ export const webHomeComponentTsx = () => {
2
+ return `import { GettingStarted } from "alepha/react/intro";
3
+
4
+ const Home = () => {
5
+ return <GettingStarted />;
6
+ };
7
+
8
+ export default Home;
9
+ `;
10
+ };
@@ -34,11 +34,19 @@ export interface RunnerMethod {
34
34
  ): Promise<string>;
35
35
  rm: (glob: string | string[], options?: RunOptions) => Promise<string>;
36
36
  cp: (source: string, dest: string, options?: RunOptions) => Promise<string>;
37
+
38
+ /**
39
+ * Ends the runner and prints a summary of executed tasks.
40
+ *
41
+ * > This is automatically called at the end of command execution.
42
+ * > But can be called manually if needed to print more stuff before the command ends.
43
+ */
44
+ end: () => void;
37
45
  }
38
46
 
39
47
  export class Runner {
40
48
  protected readonly log = $logger();
41
- protected readonly timers: Timer[] = [];
49
+ protected timers: Timer[] = [];
42
50
  protected readonly startTime: number = Date.now();
43
51
  protected readonly prettyPrint = $inject(PrettyPrint);
44
52
  protected readonly alepha = $inject(Alepha);
@@ -149,6 +157,8 @@ export class Runner {
149
157
  );
150
158
  };
151
159
 
160
+ runFn.end = () => this.end();
161
+
152
162
  return runFn;
153
163
  }
154
164
 
@@ -189,6 +199,9 @@ export class Runner {
189
199
  const totalTime = ((Date.now() - this.startTime) / 1000).toFixed(1);
190
200
  this.log.info(`Total time: ${totalTime}s`);
191
201
  this.log.info(``);
202
+
203
+ // clear timers after rendering
204
+ this.timers = [];
192
205
  }
193
206
 
194
207
  protected async executeTask(task: Task): Promise<string> {
@@ -19,9 +19,9 @@ export * from "./providers/CliProvider.ts";
19
19
  // ---------------------------------------------------------------------------------------------------------------------
20
20
 
21
21
  /**
22
- * | type | quality | stability |
23
- * |------|---------|-----------|
24
- * | tooling | rare | stable |
22
+ * | Stability | Since | Runtime |
23
+ * |-----------|-------|---------|
24
+ * | 3 - stable | 0.6.0 | node, bun|
25
25
  *
26
26
  * Declarative CLI command framework.
27
27
  *
@@ -47,11 +47,6 @@ export abstract class Primitive<T extends object = {}> {
47
47
 
48
48
  // ---------------------------------------------------------------------------------------------------------------------
49
49
 
50
- export type PrimitiveFactory<TPrimitive extends Primitive = Primitive> = {
51
- (options: TPrimitive["options"]): TPrimitive;
52
- [KIND]: InstantiableClass<TPrimitive>;
53
- };
54
-
55
50
  export type PrimitiveFactoryLike<T extends object = any> = {
56
51
  (options: T): any;
57
52
  [KIND]: any;
package/src/core/index.ts CHANGED
@@ -23,9 +23,9 @@ export * from "./index.shared.ts";
23
23
  // ---------------------------------------------------------------------------------------------------------------------
24
24
 
25
25
  /**
26
- * | type | quality | stability |
27
- * |------|---------|-----------|
28
- * | tooling | epic | stable |
26
+ * | Stability | Since | Runtime |
27
+ * |-----------|-------|---------|
28
+ * | 3 - stable | 0.1.0 | node, bun, workerd, browser, expo|
29
29
  *
30
30
  * Foundation of the entire framework with dependency injection and lifecycle management.
31
31
  *
@@ -8,9 +8,9 @@ export * from "./providers/DateTimeProvider.ts";
8
8
  // ---------------------------------------------------------------------------------------------------------------------
9
9
 
10
10
  /**
11
- * | type | quality | stability |
12
- * |------|---------|-----------|
13
- * | tooling | standard | stable |
11
+ * | Stability | Since | Runtime |
12
+ * |-----------|-------|---------|
13
+ * | 3 - stable | 0.10.0 | node, bun, workerd, browser, expo|
14
14
  *
15
15
  * Date and time operations.
16
16
  *
@@ -36,9 +36,9 @@ declare module "alepha" {
36
36
  // ---------------------------------------------------------------------------------------------------------------------
37
37
 
38
38
  /**
39
- * | type | quality | stability |
40
- * |------|---------|-----------|
41
- * | backend | rare | stable |
39
+ * | Stability | Since | Runtime |
40
+ * |-----------|-------|---------|
41
+ * | 3 - stable | 0.4.0 | node, bun, workerd|
42
42
  *
43
43
  * Email delivery with template support.
44
44
  *
@@ -0,0 +1,36 @@
1
+ import { $module } from "alepha";
2
+ import { $email } from "./primitives/$email.ts";
3
+ import { EmailProvider } from "./providers/EmailProvider.ts";
4
+ import { MemoryEmailProvider } from "./providers/MemoryEmailProvider.ts";
5
+ import { WorkermailerEmailProvider } from "./providers/WorkermailerEmailProvider.ts";
6
+
7
+ // ---------------------------------------------------------------------------------------------------------------------
8
+
9
+ export * from "./errors/EmailError.ts";
10
+ export * from "./primitives/$email.ts";
11
+ export * from "./providers/EmailProvider.ts";
12
+ export * from "./providers/MemoryEmailProvider.ts";
13
+ export * from "./providers/WorkermailerEmailProvider.ts";
14
+
15
+ // ---------------------------------------------------------------------------------------------------------------------
16
+
17
+ export const AlephaEmail = $module({
18
+ name: "alepha.email",
19
+ primitives: [$email],
20
+ services: [EmailProvider, MemoryEmailProvider, WorkermailerEmailProvider],
21
+ register: (alepha) => {
22
+ if (alepha.env.EMAIL_HOST) {
23
+ alepha.with({
24
+ optional: true,
25
+ provide: EmailProvider,
26
+ use: WorkermailerEmailProvider,
27
+ });
28
+ } else {
29
+ alepha.with({
30
+ optional: true,
31
+ provide: EmailProvider,
32
+ use: MemoryEmailProvider,
33
+ });
34
+ }
35
+ },
36
+ });