alepha 0.15.0 → 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 (222) hide show
  1. package/README.md +43 -98
  2. package/dist/api/audits/index.d.ts +240 -240
  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 +185 -185
  7. package/dist/api/files/index.d.ts.map +1 -1
  8. package/dist/api/files/index.js +2 -2
  9. package/dist/api/files/index.js.map +1 -1
  10. package/dist/api/jobs/index.d.ts +245 -245
  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 +74 -74
  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 +221 -221
  19. package/dist/api/parameters/index.d.ts.map +1 -1
  20. package/dist/api/users/index.d.ts +1632 -1631
  21. package/dist/api/users/index.d.ts.map +1 -1
  22. package/dist/api/users/index.js +26 -34
  23. package/dist/api/users/index.js.map +1 -1
  24. package/dist/api/verifications/index.d.ts +132 -132
  25. package/dist/api/verifications/index.d.ts.map +1 -1
  26. package/dist/batch/index.d.ts +122 -122
  27. package/dist/batch/index.d.ts.map +1 -1
  28. package/dist/bucket/index.d.ts +163 -163
  29. package/dist/bucket/index.d.ts.map +1 -1
  30. package/dist/cache/core/index.d.ts +46 -46
  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 +5933 -201
  36. package/dist/cli/index.d.ts.map +1 -1
  37. package/dist/cli/index.js +609 -169
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/command/index.d.ts +296 -296
  40. package/dist/command/index.d.ts.map +1 -1
  41. package/dist/command/index.js +19 -19
  42. package/dist/command/index.js.map +1 -1
  43. package/dist/core/index.browser.js +268 -79
  44. package/dist/core/index.browser.js.map +1 -1
  45. package/dist/core/index.d.ts +768 -694
  46. package/dist/core/index.d.ts.map +1 -1
  47. package/dist/core/index.js +268 -79
  48. package/dist/core/index.js.map +1 -1
  49. package/dist/core/index.native.js +268 -79
  50. package/dist/core/index.native.js.map +1 -1
  51. package/dist/datetime/index.d.ts +44 -44
  52. package/dist/datetime/index.d.ts.map +1 -1
  53. package/dist/email/index.d.ts +25 -25
  54. package/dist/email/index.d.ts.map +1 -1
  55. package/dist/fake/index.d.ts +5409 -5409
  56. package/dist/fake/index.d.ts.map +1 -1
  57. package/dist/fake/index.js +22 -22
  58. package/dist/fake/index.js.map +1 -1
  59. package/dist/file/index.d.ts +435 -435
  60. package/dist/file/index.d.ts.map +1 -1
  61. package/dist/lock/core/index.d.ts +208 -208
  62. package/dist/lock/core/index.d.ts.map +1 -1
  63. package/dist/lock/redis/index.d.ts.map +1 -1
  64. package/dist/logger/index.d.ts +24 -24
  65. package/dist/logger/index.d.ts.map +1 -1
  66. package/dist/logger/index.js +1 -5
  67. package/dist/logger/index.js.map +1 -1
  68. package/dist/mcp/index.d.ts +216 -198
  69. package/dist/mcp/index.d.ts.map +1 -1
  70. package/dist/mcp/index.js +28 -4
  71. package/dist/mcp/index.js.map +1 -1
  72. package/dist/orm/index.browser.js +9 -9
  73. package/dist/orm/index.browser.js.map +1 -1
  74. package/dist/orm/index.bun.js +83 -76
  75. package/dist/orm/index.bun.js.map +1 -1
  76. package/dist/orm/index.d.ts +961 -960
  77. package/dist/orm/index.d.ts.map +1 -1
  78. package/dist/orm/index.js +88 -81
  79. package/dist/orm/index.js.map +1 -1
  80. package/dist/queue/core/index.d.ts +244 -244
  81. package/dist/queue/core/index.d.ts.map +1 -1
  82. package/dist/queue/redis/index.d.ts.map +1 -1
  83. package/dist/redis/index.d.ts +105 -105
  84. package/dist/redis/index.d.ts.map +1 -1
  85. package/dist/retry/index.d.ts +69 -69
  86. package/dist/retry/index.d.ts.map +1 -1
  87. package/dist/router/index.d.ts +6 -6
  88. package/dist/router/index.d.ts.map +1 -1
  89. package/dist/scheduler/index.d.ts +108 -26
  90. package/dist/scheduler/index.d.ts.map +1 -1
  91. package/dist/scheduler/index.js +393 -1
  92. package/dist/scheduler/index.js.map +1 -1
  93. package/dist/security/index.d.ts +532 -209
  94. package/dist/security/index.d.ts.map +1 -1
  95. package/dist/security/index.js +1422 -11
  96. package/dist/security/index.js.map +1 -1
  97. package/dist/server/auth/index.d.ts +1296 -271
  98. package/dist/server/auth/index.d.ts.map +1 -1
  99. package/dist/server/auth/index.js +1249 -18
  100. package/dist/server/auth/index.js.map +1 -1
  101. package/dist/server/cache/index.d.ts +56 -56
  102. package/dist/server/cache/index.d.ts.map +1 -1
  103. package/dist/server/compress/index.d.ts +3 -3
  104. package/dist/server/compress/index.d.ts.map +1 -1
  105. package/dist/server/cookies/index.d.ts +6 -6
  106. package/dist/server/cookies/index.d.ts.map +1 -1
  107. package/dist/server/core/index.d.ts +196 -186
  108. package/dist/server/core/index.d.ts.map +1 -1
  109. package/dist/server/core/index.js +43 -27
  110. package/dist/server/core/index.js.map +1 -1
  111. package/dist/server/cors/index.d.ts +11 -11
  112. package/dist/server/cors/index.d.ts.map +1 -1
  113. package/dist/server/health/index.d.ts.map +1 -1
  114. package/dist/server/helmet/index.d.ts +2 -2
  115. package/dist/server/helmet/index.d.ts.map +1 -1
  116. package/dist/server/links/index.browser.js +9 -1
  117. package/dist/server/links/index.browser.js.map +1 -1
  118. package/dist/server/links/index.d.ts +83 -83
  119. package/dist/server/links/index.d.ts.map +1 -1
  120. package/dist/server/links/index.js +13 -5
  121. package/dist/server/links/index.js.map +1 -1
  122. package/dist/server/metrics/index.d.ts +514 -1
  123. package/dist/server/metrics/index.d.ts.map +1 -1
  124. package/dist/server/metrics/index.js +4462 -4
  125. package/dist/server/metrics/index.js.map +1 -1
  126. package/dist/server/multipart/index.d.ts +6 -6
  127. package/dist/server/multipart/index.d.ts.map +1 -1
  128. package/dist/server/proxy/index.d.ts +102 -102
  129. package/dist/server/proxy/index.d.ts.map +1 -1
  130. package/dist/server/rate-limit/index.d.ts +16 -16
  131. package/dist/server/rate-limit/index.d.ts.map +1 -1
  132. package/dist/server/static/index.d.ts +44 -44
  133. package/dist/server/static/index.d.ts.map +1 -1
  134. package/dist/server/swagger/index.d.ts +47 -47
  135. package/dist/server/swagger/index.d.ts.map +1 -1
  136. package/dist/sms/index.d.ts +11 -11
  137. package/dist/sms/index.d.ts.map +1 -1
  138. package/dist/sms/index.js +3 -3
  139. package/dist/sms/index.js.map +1 -1
  140. package/dist/thread/index.d.ts +71 -71
  141. package/dist/thread/index.d.ts.map +1 -1
  142. package/dist/thread/index.js +2 -2
  143. package/dist/thread/index.js.map +1 -1
  144. package/dist/topic/core/index.d.ts +318 -318
  145. package/dist/topic/core/index.d.ts.map +1 -1
  146. package/dist/topic/redis/index.d.ts +6 -6
  147. package/dist/topic/redis/index.d.ts.map +1 -1
  148. package/dist/vite/index.d.ts +2324 -1719
  149. package/dist/vite/index.d.ts.map +1 -1
  150. package/dist/vite/index.js +123 -475
  151. package/dist/vite/index.js.map +1 -1
  152. package/dist/websocket/index.browser.js +3 -3
  153. package/dist/websocket/index.browser.js.map +1 -1
  154. package/dist/websocket/index.d.ts +275 -275
  155. package/dist/websocket/index.d.ts.map +1 -1
  156. package/dist/websocket/index.js +3 -3
  157. package/dist/websocket/index.js.map +1 -1
  158. package/package.json +9 -9
  159. package/src/api/users/services/SessionService.ts +0 -10
  160. package/src/cli/apps/AlephaCli.ts +2 -2
  161. package/src/cli/apps/AlephaPackageBuilderCli.ts +9 -1
  162. package/src/cli/assets/apiHelloControllerTs.ts +2 -1
  163. package/src/cli/assets/biomeJson.ts +2 -1
  164. package/src/cli/assets/claudeMd.ts +9 -4
  165. package/src/cli/assets/dummySpecTs.ts +2 -1
  166. package/src/cli/assets/editorconfig.ts +2 -1
  167. package/src/cli/assets/mainBrowserTs.ts +2 -1
  168. package/src/cli/assets/mainCss.ts +24 -0
  169. package/src/cli/assets/tsconfigJson.ts +2 -1
  170. package/src/cli/assets/webAppRouterTs.ts +2 -1
  171. package/src/cli/assets/webHelloComponentTsx.ts +6 -2
  172. package/src/cli/atoms/appEntryOptions.ts +13 -0
  173. package/src/cli/atoms/buildOptions.ts +1 -1
  174. package/src/cli/atoms/changelogOptions.ts +1 -1
  175. package/src/cli/commands/build.ts +63 -47
  176. package/src/cli/commands/dev.ts +16 -33
  177. package/src/cli/commands/gen/env.ts +1 -1
  178. package/src/cli/commands/init.ts +17 -8
  179. package/src/cli/commands/lint.ts +1 -1
  180. package/src/cli/defineConfig.ts +9 -0
  181. package/src/cli/index.ts +2 -1
  182. package/src/cli/providers/AppEntryProvider.ts +131 -0
  183. package/src/cli/providers/ViteBuildProvider.ts +82 -0
  184. package/src/cli/providers/ViteDevServerProvider.ts +350 -0
  185. package/src/cli/providers/ViteTemplateProvider.ts +27 -0
  186. package/src/cli/services/AlephaCliUtils.ts +33 -2
  187. package/src/cli/services/PackageManagerUtils.ts +13 -6
  188. package/src/cli/services/ProjectScaffolder.ts +72 -49
  189. package/src/core/Alepha.ts +2 -8
  190. package/src/core/primitives/$module.ts +12 -0
  191. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +257 -0
  192. package/src/core/providers/KeylessJsonSchemaCodec.ts +396 -14
  193. package/src/core/providers/SchemaValidator.spec.ts +236 -0
  194. package/src/logger/providers/PrettyFormatterProvider.ts +0 -9
  195. package/src/mcp/errors/McpError.ts +30 -0
  196. package/src/mcp/index.ts +3 -0
  197. package/src/mcp/transports/SseMcpTransport.ts +16 -6
  198. package/src/orm/providers/DrizzleKitProvider.ts +3 -5
  199. package/src/orm/services/Repository.ts +11 -0
  200. package/src/server/core/index.ts +1 -1
  201. package/src/server/core/providers/BunHttpServerProvider.ts +1 -1
  202. package/src/server/core/providers/NodeHttpServerProvider.spec.ts +125 -0
  203. package/src/server/core/providers/NodeHttpServerProvider.ts +71 -22
  204. package/src/server/core/providers/ServerLoggerProvider.ts +2 -2
  205. package/src/server/core/providers/ServerProvider.ts +9 -12
  206. package/src/server/links/atoms/apiLinksAtom.ts +7 -0
  207. package/src/server/links/index.browser.ts +2 -0
  208. package/src/server/links/index.ts +2 -0
  209. package/src/vite/index.ts +3 -2
  210. package/src/vite/tasks/buildClient.ts +0 -1
  211. package/src/vite/tasks/buildServer.ts +68 -21
  212. package/src/vite/tasks/copyAssets.ts +5 -4
  213. package/src/vite/tasks/generateSitemap.ts +64 -23
  214. package/src/vite/tasks/index.ts +0 -2
  215. package/src/vite/tasks/prerenderPages.ts +49 -24
  216. package/src/cli/assets/indexHtml.ts +0 -15
  217. package/src/cli/commands/format.ts +0 -23
  218. package/src/vite/helpers/boot.ts +0 -117
  219. package/src/vite/plugins/viteAlephaDev.ts +0 -177
  220. package/src/vite/tasks/devServer.ts +0 -71
  221. package/src/vite/tasks/runAlepha.ts +0 -270
  222. /package/dist/orm/{chunk-DtkW-qnP.js → chunk-DH6iiROE.js} +0 -0
@@ -1,4 +1,5 @@
1
- export const apiHelloControllerTs = () => `
1
+ export const apiHelloControllerTs = () =>
2
+ `
2
3
  import { t } from "alepha";
3
4
  import { $action } from "alepha/server";
4
5
 
@@ -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": {
@@ -69,8 +69,8 @@ ${projectName}/
69
69
  │ │ ├── AppRouter.ts # Routes with $page
70
70
  │ │ └── index.ts # Web module definition with $module
71
71
  │ ├── main.server.ts # Server entry
72
- └── main.browser.ts # Browser entry (React only)
73
- ├── index.html # (React only)
72
+ ├── main.browser.ts # Browser entry (React only)
73
+ │ └── main.css # CSS entry (React only)
74
74
  ├── package.json
75
75
  └── tsconfig.json
76
76
  \`\`\`
@@ -117,6 +117,7 @@ This is an **Alepha** project - a convention-driven TypeScript framework for typ
117
117
  - Use \`protected\` instead of \`private\` for class members
118
118
  - Import with file extensions: \`import { User } from "./User.ts"\`
119
119
  - Use \`t\` from Alepha for schemas (not Zod)
120
+ - Prefer \`t.text()\` over \`t.string()\` for user input (has default max length, auto-trim, supports lowercase option)
120
121
 
121
122
  ## Project Structure
122
123
  ${projectStructure}
@@ -246,9 +247,13 @@ ${reactSection}
246
247
  | \`$cache\` | \`alepha/cache\` | Cached computations |
247
248
  | \`$bucket\` | \`alepha/bucket\` | File storage |
248
249
  | \`$issuer\` | \`alepha/security\` | JWT tokens |
249
- | \`$command\` | \`alepha/command\` | CLI commands |${react ? `
250
+ | \`$command\` | \`alepha/command\` | CLI commands |${
251
+ react
252
+ ? `
250
253
  | \`$page\` | \`@alepha/react/router\` | React pages with SSR |
251
- | \`$atom\` | \`alepha\` | Global state |` : ""}
254
+ | \`$atom\` | \`alepha\` | Global state |`
255
+ : ""
256
+ }
252
257
 
253
258
  ## Testing
254
259
 
@@ -1,4 +1,5 @@
1
- export const dummySpecTs = () => `
1
+ export const dummySpecTs = () =>
2
+ `
2
3
  import { test, expect } from "vitest";
3
4
 
4
5
  test("dummy test", () => {
@@ -1,4 +1,5 @@
1
- export const editorconfig = `
1
+ export const editorconfig = () =>
2
+ `
2
3
  # https://editorconfig.org
3
4
 
4
5
  root = true
@@ -1,4 +1,5 @@
1
- export const mainBrowserTs = () => `
1
+ export const mainBrowserTs = () =>
2
+ `
2
3
  import { Alepha, run } from "alepha";
3
4
  import { WebModule } from "./web/index.ts";
4
5
 
@@ -0,0 +1,24 @@
1
+ export const mainCss = () =>
2
+ `
3
+ * {
4
+ box-sizing: border-box;
5
+ margin: 0;
6
+ padding: 0;
7
+ }
8
+
9
+ html,
10
+ body {
11
+ height: 100%;
12
+ }
13
+
14
+ body {
15
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
16
+ "Helvetica Neue", Arial, sans-serif;
17
+ line-height: 1.5;
18
+ -webkit-font-smoothing: antialiased;
19
+ }
20
+
21
+ #root {
22
+ height: 100%;
23
+ }
24
+ `.trim();
@@ -1,4 +1,5 @@
1
- export const tsconfigJson = `
1
+ export const tsconfigJson = () =>
2
+ `
2
3
  {
3
4
  "extends": "alepha/tsconfig.base"
4
5
  }
@@ -1,4 +1,5 @@
1
- export const webAppRouterTs = () => `
1
+ export const webAppRouterTs = () =>
2
+ `
2
3
  import { $page } from "@alepha/react/router";
3
4
  import { $client } from "alepha/server/links";
4
5
  import type { HelloController } from "../api/controllers/HelloController.ts";
@@ -1,12 +1,16 @@
1
- export const webHelloComponentTsx = () => `
1
+ export const webHelloComponentTsx = () =>
2
+ `import { useState } from "react";
3
+
2
4
  interface Props {
3
5
  message: string;
4
6
  }
5
7
 
6
8
  const Hello = (props: Props) => {
9
+ const [message, setMessage] = useState(props.message);
7
10
  return (
8
11
  <div>
9
- <h1>{props.message}</h1>
12
+ <h1>{message}</h1>
13
+ <input value={message} onChange={e => setMessage(e.target.value)} />
10
14
  <p>Edit this component in src/web/components/Hello.tsx</p>
11
15
  </div>
12
16
  );
@@ -0,0 +1,13 @@
1
+ import { $atom, type Static, t } from "alepha";
2
+
3
+ export const appEntryOptions = $atom({
4
+ name: "alepha.cli.appEntry.options",
5
+ schema: t.object({
6
+ server: t.optional(t.text()),
7
+ browser: t.optional(t.text()),
8
+ style: t.optional(t.text()),
9
+ }),
10
+ default: {},
11
+ });
12
+
13
+ export type AppEntryOptions = Static<typeof appEntryOptions.schema>;
@@ -8,7 +8,7 @@ import { $atom } from "../../core/primitives/$atom.ts";
8
8
  * Options can be overridden via vite.config.ts or CLI flags.
9
9
  */
10
10
  export const buildOptions = $atom({
11
- name: "alepha.build.options",
11
+ name: "alepha.cli.build.options",
12
12
  description: "Build configuration options",
13
13
  schema: t.object({
14
14
  /**
@@ -29,7 +29,7 @@ export const DEFAULT_IGNORE = [
29
29
  * ```
30
30
  */
31
31
  export const changelogOptions = $atom({
32
- name: "alepha.changelog",
32
+ name: "alepha.cli.changelog.options",
33
33
  schema: t.object({
34
34
  /**
35
35
  * Scopes to ignore (e.g., "project", "release", "chore").
@@ -1,9 +1,8 @@
1
- import { $inject, $use, t } from "alepha";
1
+ import { $inject, $use, type Alepha, AlephaError, t } from "alepha";
2
2
  import { $command } from "alepha/command";
3
3
  import { FileSystemProvider } from "alepha/file";
4
4
  import { $logger } from "alepha/logger";
5
5
  import {
6
- boot,
7
6
  buildClient,
8
7
  buildServer,
9
8
  copyAssets,
@@ -14,6 +13,8 @@ import {
14
13
  prerenderPages,
15
14
  } from "alepha/vite";
16
15
  import { buildOptions } from "../atoms/buildOptions.ts";
16
+ import { AppEntryProvider } from "../providers/AppEntryProvider.ts";
17
+ import { ViteBuildProvider } from "../providers/ViteBuildProvider.ts";
17
18
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
18
19
  import { PackageManagerUtils } from "../services/PackageManagerUtils.ts";
19
20
  import { ProjectScaffolder } from "../services/ProjectScaffolder.ts";
@@ -24,15 +25,14 @@ export class BuildCommand {
24
25
  protected readonly utils = $inject(AlephaCliUtils);
25
26
  protected readonly pm = $inject(PackageManagerUtils);
26
27
  protected readonly scaffolder = $inject(ProjectScaffolder);
28
+ protected readonly boot = $inject(AppEntryProvider);
29
+ protected readonly viteBuildProvider = $inject(ViteBuildProvider);
27
30
  protected readonly options = $use(buildOptions);
28
31
 
29
32
  public readonly build = $command({
30
33
  name: "build",
31
34
  mode: "production",
32
35
  description: "Build the project for production",
33
- args: t.optional(
34
- t.text({ title: "path", description: "Filepath to build" }),
35
- ),
36
36
  flags: t.object({
37
37
  stats: t.optional(
38
38
  t.boolean({
@@ -65,9 +65,7 @@ export class BuildCommand {
65
65
  }),
66
66
  ),
67
67
  }),
68
- handler: async ({ flags, args, run, root }) => {
69
- // Tell viteAlephaBuild plugin to skip - CLI handles all tasks
70
- process.env.ALEPHA_BUILD_MODE = "cli";
68
+ handler: async ({ flags, run, root }) => {
71
69
  process.env.NODE_ENV = "production";
72
70
 
73
71
  if (await this.pm.hasExpo(root)) {
@@ -79,11 +77,11 @@ export class BuildCommand {
79
77
  tsconfigJson: true,
80
78
  });
81
79
 
82
- const entry = await boot.getServerEntry(root, args);
80
+ const entry = await this.boot.getAppEntry(root);
83
81
  this.log.trace("Entry file found", { entry });
84
82
 
85
83
  const distDir = "dist";
86
- const clientDir = "public";
84
+ const publicDir = "public";
87
85
 
88
86
  await this.pm.ensureDependency(root, "vite", {
89
87
  run,
@@ -95,27 +93,55 @@ export class BuildCommand {
95
93
  await this.utils.loadEnv(root, [".env", ".env.production"]);
96
94
 
97
95
  const stats = flags.stats ?? options.stats ?? false;
98
- const hasClient = await this.fs.exists(this.fs.join(root, "index.html"));
96
+ let template = "";
97
+ let hasClient = false;
98
+ let alepha: Alepha | undefined;
99
+
100
+ await run({
101
+ name: "analyze app",
102
+ handler: async () => {
103
+ alepha = await this.viteBuildProvider.init({ entry });
104
+ hasClient = this.viteBuildProvider.hasClient();
105
+ if (hasClient) {
106
+ template = this.viteBuildProvider.generateIndexHtml();
107
+ }
108
+ },
109
+ });
110
+
111
+ if (!alepha) {
112
+ throw new AlephaError("Alepha instance not found");
113
+ }
99
114
 
100
115
  // Build client (precompress always enabled)
101
116
  if (hasClient) {
102
- await run({
103
- name: "vite build client",
104
- handler: () =>
105
- buildClient({
106
- silent: true,
107
- dist: `${distDir}/${clientDir}`,
108
- stats,
109
- precompress: true,
110
- }),
111
- });
117
+ // TODO: find a way to avoid writing index.html to disk
118
+ const indexHtmlPath = this.fs.join(root, "index.html");
119
+ await this.fs.writeFile(indexHtmlPath, template);
120
+ try {
121
+ await run({
122
+ name: "vite build client",
123
+ handler: () =>
124
+ buildClient({
125
+ silent: true,
126
+ dist: `${distDir}/${publicDir}`,
127
+ stats,
128
+ precompress: true,
129
+ }),
130
+ });
131
+ } finally {
132
+ await this.fs.rm(indexHtmlPath);
133
+ }
112
134
  }
113
135
 
114
136
  // Build server
115
137
  await run({
116
138
  name: "vite build server",
117
139
  handler: async () => {
118
- const clientIndexPath = `${distDir}/${clientDir}/index.html`;
140
+ if (!alepha) {
141
+ throw new AlephaError("Alepha instance not found");
142
+ }
143
+
144
+ const clientIndexPath = `${distDir}/${publicDir}/index.html`;
119
145
  const clientBuilt = await this.fs.exists(clientIndexPath);
120
146
 
121
147
  const conditions: string[] = [];
@@ -131,19 +157,18 @@ export class BuildCommand {
131
157
  // workerd:
132
158
  // - react-dom
133
159
  // - postgres
134
-
135
- // TODO: investigate if we have more conditions like 'edge' to add here
136
160
  if (options.cloudflare) {
137
161
  conditions.push("workerd");
138
162
  }
139
163
 
140
164
  await buildServer({
141
165
  silent: true,
142
- entry,
166
+ entry: entry.server,
143
167
  distDir,
144
- clientDir: clientBuilt ? clientDir : undefined,
168
+ clientDir: clientBuilt ? publicDir : undefined,
145
169
  stats,
146
170
  conditions,
171
+ alepha,
147
172
  });
148
173
 
149
174
  // Server will handle index.html if both client & server are built
@@ -155,6 +180,7 @@ export class BuildCommand {
155
180
 
156
181
  // Copy assets
157
182
  await copyAssets({
183
+ alepha,
158
184
  root,
159
185
  entry: `${distDir}/index.js`,
160
186
  distDir,
@@ -165,30 +191,20 @@ export class BuildCommand {
165
191
  // Generate sitemap
166
192
  const sitemapHostname = flags.sitemap ?? options.sitemap?.hostname;
167
193
  if (sitemapHostname) {
168
- await run({
169
- name: "add sitemap",
170
- handler: async () => {
171
- await this.fs.writeFile(
172
- `${distDir}/${clientDir}/sitemap.xml`,
173
- await generateSitemap({
174
- entry: `${distDir}/index.js`,
175
- baseUrl: sitemapHostname,
176
- }),
177
- );
178
- },
194
+ await generateSitemap({
195
+ alepha,
196
+ baseUrl: sitemapHostname,
197
+ output: `${distDir}/${publicDir}/sitemap.xml`,
198
+ run,
179
199
  });
180
200
  }
181
201
 
182
202
  // Pre-render static pages (always enabled)
183
- await run({
184
- name: "pre-render pages",
185
- handler: async () => {
186
- await prerenderPages({
187
- dist: `${distDir}/${clientDir}`,
188
- entry: `${distDir}/index.js`,
189
- compress: true,
190
- });
191
- },
203
+ await prerenderPages({
204
+ alepha,
205
+ dist: `${distDir}/${publicDir}`,
206
+ compress: true,
207
+ run,
192
208
  });
193
209
  }
194
210
 
@@ -199,7 +215,7 @@ export class BuildCommand {
199
215
  handler: () =>
200
216
  generateVercel({
201
217
  distDir,
202
- clientDir,
218
+ clientDir: publicDir,
203
219
  config: options.vercel,
204
220
  }),
205
221
  });
@@ -1,8 +1,9 @@
1
- import { $inject, Alepha, t } from "alepha";
1
+ import { $inject, Alepha } from "alepha";
2
2
  import { $command } from "alepha/command";
3
3
  import { FileSystemProvider } from "alepha/file";
4
4
  import { $logger } from "alepha/logger";
5
- import { boot, devServer } from "alepha/vite";
5
+ import { AppEntryProvider } from "../providers/AppEntryProvider.ts";
6
+ import { ViteDevServerProvider } from "../providers/ViteDevServerProvider.ts";
6
7
  import { AlephaCliUtils } from "../services/AlephaCliUtils.ts";
7
8
  import { PackageManagerUtils } from "../services/PackageManagerUtils.ts";
8
9
  import { ProjectScaffolder } from "../services/ProjectScaffolder.ts";
@@ -14,6 +15,8 @@ export class DevCommand {
14
15
  protected readonly pm = $inject(PackageManagerUtils);
15
16
  protected readonly scaffolder = $inject(ProjectScaffolder);
16
17
  protected readonly alepha = $inject(Alepha);
18
+ protected readonly viteDevServer = $inject(ViteDevServerProvider);
19
+ protected readonly boot = $inject(AppEntryProvider);
17
20
 
18
21
  /**
19
22
  * Will run the project in watch mode.
@@ -24,9 +27,11 @@ export class DevCommand {
24
27
  public readonly dev = $command({
25
28
  name: "dev",
26
29
  description: "Run the project in development mode",
27
- args: t.optional(t.text({ title: "path", description: "Filepath to run" })),
28
- handler: async ({ args, root }) => {
29
- const expo = await this.pm.hasExpo(root);
30
+ handler: async ({ root }) => {
31
+ const [expo, react] = await Promise.all([
32
+ this.pm.hasExpo(root),
33
+ this.pm.hasReact(root),
34
+ ]);
30
35
 
31
36
  await this.scaffolder.ensureConfig(root, {
32
37
  tsconfigJson: true,
@@ -37,41 +42,19 @@ export class DevCommand {
37
42
  return;
38
43
  }
39
44
 
40
- const entry = await boot.getServerEntry(root, args);
41
- this.log.trace("Entry file found", { entry });
45
+ const entry = await this.boot.getAppEntry(root);
46
+ this.log.debug("Entry file found", { entry });
42
47
 
43
- const isFullstack = await this.isFullstackProject(root);
44
-
45
- if (!isFullstack) {
46
- const exe = (await this.isBunProject(root)) ? "bun" : "tsx";
47
- let cmd = `${exe} --watch`;
48
- if (await this.utils.exists(root, ".env")) {
49
- cmd += " --env-file=./.env";
50
- }
51
- cmd += ` ${entry}`;
52
- await this.utils.exec(cmd, {
53
- global: exe === "bun",
54
- });
55
- return;
56
- }
48
+ // -> here, we assume we use Vite as runner (api or fullstack)
49
+ // but it's planned to support Bun runner in the future as well
57
50
 
58
51
  // Ensure vite is installed before running
59
52
  await this.pm.ensureDependency(root, "vite", {
60
53
  exec: (cmd, opts) => this.utils.exec(cmd, opts),
61
54
  });
62
55
 
63
- await devServer();
56
+ await this.viteDevServer.init({ root, entry });
57
+ await this.viteDevServer.start();
64
58
  },
65
59
  });
66
-
67
- protected async isBunProject(root: string): Promise<boolean> {
68
- if (this.alepha.isBun()) {
69
- return true;
70
- }
71
- return this.fs.exists(this.fs.join(root, "bun.lock"));
72
- }
73
-
74
- protected async isFullstackProject(root: string): Promise<boolean> {
75
- return this.fs.exists(this.fs.join(root, "index.html"));
76
- }
77
60
  }
@@ -37,7 +37,7 @@ export class GenEnvCommand {
37
37
  if (value.enum) {
38
38
  dotEnvFile += `# Possible values: ${value.enum.join(", ")}\n`;
39
39
  }
40
- dotEnvFile += `${key}=${value.default || ""}\n\n`;
40
+ dotEnvFile += `#${key}=${value.default || ""}\n\n`;
41
41
  }
42
42
 
43
43
  if (flags.out) {
@@ -38,22 +38,28 @@ export class InitCommand {
38
38
  npm: t.optional(t.boolean({ description: "Use npm package manager" })),
39
39
  bun: t.optional(t.boolean({ description: "Use Bun package manager" })),
40
40
  // choose which dependencies to add
41
- web: t.optional(
41
+ react: t.optional(
42
42
  t.boolean({
43
43
  aliases: ["r"],
44
44
  description: "Include Alepha React dependencies",
45
45
  }),
46
46
  ),
47
- admin: t.optional(
47
+ ui: t.optional(
48
48
  t.boolean({ description: "Include Alepha UI dependencies" }),
49
49
  ),
50
50
  test: t.optional(
51
51
  t.boolean({ description: "Include Vitest and create test directory" }),
52
52
  ),
53
+ force: t.optional(
54
+ t.boolean({
55
+ aliases: ["f"],
56
+ description: "Override existing files",
57
+ }),
58
+ ),
53
59
  }),
54
60
  handler: async ({ run, flags, root, args }) => {
55
- if (flags.admin) {
56
- flags.web = true;
61
+ if (flags.react) {
62
+ flags.ui = true;
57
63
  }
58
64
 
59
65
  if (args) {
@@ -63,23 +69,26 @@ export class InitCommand {
63
69
 
64
70
  const isExpo = await this.pm.hasExpo(root);
65
71
 
72
+ const force = !!flags.force;
73
+
66
74
  await run({
67
75
  name: "ensuring configuration files",
68
76
  handler: async () => {
69
77
  await this.scaffolder.ensureConfig(root, {
78
+ force,
70
79
  tsconfigJson: true,
71
80
  packageJson: flags,
72
81
  biomeJson: true,
73
82
  editorconfig: true,
74
- indexHtml: !!flags.web && !isExpo,
83
+ indexHtml: !!flags.react && !isExpo,
75
84
  claudeMd: flags.agent
76
- ? { react: !!flags.web, ui: !!flags.admin }
85
+ ? { react: !!flags.react, ui: !!flags.ui }
77
86
  : false,
78
87
  });
79
88
 
80
89
  // Create API project structure if not React
81
- if (!flags.web) {
82
- await this.scaffolder.ensureApiProject(root);
90
+ if (!flags.react) {
91
+ await this.scaffolder.ensureApiProject(root, { force });
83
92
  }
84
93
  },
85
94
  });
@@ -17,7 +17,7 @@ export class LintCommand {
17
17
  await this.pm.ensureDependency(root, "@biomejs/biome", {
18
18
  exec: (cmd, opts) => this.utils.exec(cmd, opts),
19
19
  });
20
- await this.utils.exec("biome check --formatter-enabled=false --fix");
20
+ await this.utils.exec("biome check --fix");
21
21
  },
22
22
  });
23
23
  }
@@ -1,8 +1,13 @@
1
1
  import type { Alepha } from "alepha";
2
2
  import type { CommandPrimitive } from "alepha/command";
3
+ import {
4
+ type AppEntryOptions,
5
+ appEntryOptions,
6
+ } from "./atoms/appEntryOptions.ts";
3
7
  import { type BuildOptions, buildOptions } from "./atoms/buildOptions.ts";
4
8
 
5
9
  export interface AlephaCliConfig {
10
+ entry?: AppEntryOptions;
6
11
  /**
7
12
  * Add custom commands to the Alepha CLI.
8
13
  *
@@ -54,6 +59,10 @@ export const defineConfig = (
54
59
  alepha.set(buildOptions, config.build);
55
60
  }
56
61
 
62
+ if (config.entry) {
63
+ alepha.set(appEntryOptions, config.entry);
64
+ }
65
+
57
66
  return {
58
67
  ...config.commands,
59
68
  };
package/src/cli/index.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  export * from "./apps/AlephaCli.ts";
2
2
  export * from "./apps/AlephaPackageBuilderCli.ts";
3
+ export { default as AlephaPackageBuilderCli } from "./apps/AlephaPackageBuilderCli.ts";
3
4
  export * from "./atoms/changelogOptions.ts";
4
5
  export * from "./commands/build.ts";
5
6
  export * from "./commands/clean.ts";
6
7
  export * from "./commands/db.ts";
7
8
  export * from "./commands/deploy.ts";
8
9
  export * from "./commands/dev.ts";
9
- export * from "./commands/format.ts";
10
10
  export * from "./commands/gen/changelog.ts";
11
11
  export * from "./commands/gen/openapi.ts";
12
12
  export * from "./commands/init.ts";
@@ -16,6 +16,7 @@ export * from "./commands/test.ts";
16
16
  export * from "./commands/typecheck.ts";
17
17
  export * from "./commands/verify.ts";
18
18
  export * from "./defineConfig.ts";
19
+ export * from "./providers/AppEntryProvider.ts";
19
20
  export * from "./services/AlephaCliUtils.ts";
20
21
  export * from "./services/GitMessageParser.ts";
21
22
  export * from "./version.ts";