alepha 0.14.3 → 0.15.0

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 (317) hide show
  1. package/README.md +2 -5
  2. package/dist/api/audits/index.d.ts +620 -811
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/files/index.d.ts +185 -377
  5. package/dist/api/files/index.d.ts.map +1 -1
  6. package/dist/api/files/index.js +0 -1
  7. package/dist/api/files/index.js.map +1 -1
  8. package/dist/api/jobs/index.d.ts +245 -435
  9. package/dist/api/jobs/index.d.ts.map +1 -1
  10. package/dist/api/notifications/index.d.ts +238 -429
  11. package/dist/api/notifications/index.d.ts.map +1 -1
  12. package/dist/api/parameters/index.d.ts +236 -427
  13. package/dist/api/parameters/index.d.ts.map +1 -1
  14. package/dist/api/users/index.browser.js +1 -2
  15. package/dist/api/users/index.browser.js.map +1 -1
  16. package/dist/api/users/index.d.ts +1010 -1196
  17. package/dist/api/users/index.d.ts.map +1 -1
  18. package/dist/api/users/index.js +178 -151
  19. package/dist/api/users/index.js.map +1 -1
  20. package/dist/api/verifications/index.d.ts +17 -17
  21. package/dist/api/verifications/index.d.ts.map +1 -1
  22. package/dist/batch/index.d.ts +122 -122
  23. package/dist/batch/index.d.ts.map +1 -1
  24. package/dist/batch/index.js +1 -2
  25. package/dist/batch/index.js.map +1 -1
  26. package/dist/bucket/index.d.ts +163 -163
  27. package/dist/bucket/index.d.ts.map +1 -1
  28. package/dist/cache/core/index.d.ts +46 -46
  29. package/dist/cache/core/index.d.ts.map +1 -1
  30. package/dist/cache/redis/index.d.ts.map +1 -1
  31. package/dist/cli/index.d.ts +384 -285
  32. package/dist/cli/index.d.ts.map +1 -1
  33. package/dist/cli/index.js +1113 -623
  34. package/dist/cli/index.js.map +1 -1
  35. package/dist/command/index.d.ts +299 -300
  36. package/dist/command/index.d.ts.map +1 -1
  37. package/dist/command/index.js +13 -9
  38. package/dist/command/index.js.map +1 -1
  39. package/dist/core/index.browser.js +445 -103
  40. package/dist/core/index.browser.js.map +1 -1
  41. package/dist/core/index.d.ts +733 -625
  42. package/dist/core/index.d.ts.map +1 -1
  43. package/dist/core/index.js +446 -103
  44. package/dist/core/index.js.map +1 -1
  45. package/dist/core/index.native.js +445 -103
  46. package/dist/core/index.native.js.map +1 -1
  47. package/dist/datetime/index.d.ts +44 -44
  48. package/dist/datetime/index.d.ts.map +1 -1
  49. package/dist/datetime/index.js +4 -4
  50. package/dist/datetime/index.js.map +1 -1
  51. package/dist/email/index.d.ts +97 -50
  52. package/dist/email/index.d.ts.map +1 -1
  53. package/dist/email/index.js +129 -33
  54. package/dist/email/index.js.map +1 -1
  55. package/dist/fake/index.d.ts +7981 -14
  56. package/dist/fake/index.d.ts.map +1 -1
  57. package/dist/file/index.d.ts +523 -390
  58. package/dist/file/index.d.ts.map +1 -1
  59. package/dist/file/index.js +253 -1
  60. package/dist/file/index.js.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 +25 -26
  65. package/dist/logger/index.d.ts.map +1 -1
  66. package/dist/logger/index.js +12 -2
  67. package/dist/logger/index.js.map +1 -1
  68. package/dist/mcp/index.d.ts +197 -197
  69. package/dist/mcp/index.d.ts.map +1 -1
  70. package/dist/mcp/index.js +1 -1
  71. package/dist/mcp/index.js.map +1 -1
  72. package/dist/orm/chunk-DtkW-qnP.js +38 -0
  73. package/dist/orm/index.browser.js.map +1 -1
  74. package/dist/orm/index.bun.js +2814 -0
  75. package/dist/orm/index.bun.js.map +1 -0
  76. package/dist/orm/index.d.ts +1228 -1216
  77. package/dist/orm/index.d.ts.map +1 -1
  78. package/dist/orm/index.js +2041 -1967
  79. package/dist/orm/index.js.map +1 -1
  80. package/dist/queue/core/index.d.ts +248 -248
  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.bun.js +285 -0
  84. package/dist/redis/index.bun.js.map +1 -0
  85. package/dist/redis/index.d.ts +118 -136
  86. package/dist/redis/index.d.ts.map +1 -1
  87. package/dist/redis/index.js +18 -38
  88. package/dist/redis/index.js.map +1 -1
  89. package/dist/retry/index.d.ts +69 -69
  90. package/dist/retry/index.d.ts.map +1 -1
  91. package/dist/router/index.d.ts +6 -6
  92. package/dist/router/index.d.ts.map +1 -1
  93. package/dist/scheduler/index.d.ts +25 -25
  94. package/dist/scheduler/index.d.ts.map +1 -1
  95. package/dist/security/index.browser.js +5 -1
  96. package/dist/security/index.browser.js.map +1 -1
  97. package/dist/security/index.d.ts +417 -254
  98. package/dist/security/index.d.ts.map +1 -1
  99. package/dist/security/index.js +386 -86
  100. package/dist/security/index.js.map +1 -1
  101. package/dist/server/auth/index.d.ts +110 -110
  102. package/dist/server/auth/index.d.ts.map +1 -1
  103. package/dist/server/auth/index.js +20 -20
  104. package/dist/server/auth/index.js.map +1 -1
  105. package/dist/server/cache/index.d.ts +62 -47
  106. package/dist/server/cache/index.d.ts.map +1 -1
  107. package/dist/server/cache/index.js +56 -3
  108. package/dist/server/cache/index.js.map +1 -1
  109. package/dist/server/compress/index.d.ts +6 -0
  110. package/dist/server/compress/index.d.ts.map +1 -1
  111. package/dist/server/compress/index.js +36 -1
  112. package/dist/server/compress/index.js.map +1 -1
  113. package/dist/server/cookies/index.d.ts +6 -6
  114. package/dist/server/cookies/index.d.ts.map +1 -1
  115. package/dist/server/cookies/index.js +3 -3
  116. package/dist/server/cookies/index.js.map +1 -1
  117. package/dist/server/core/index.browser.js +2 -2
  118. package/dist/server/core/index.browser.js.map +1 -1
  119. package/dist/server/core/index.d.ts +242 -150
  120. package/dist/server/core/index.d.ts.map +1 -1
  121. package/dist/server/core/index.js +294 -125
  122. package/dist/server/core/index.js.map +1 -1
  123. package/dist/server/cors/index.d.ts +11 -12
  124. package/dist/server/cors/index.d.ts.map +1 -1
  125. package/dist/server/health/index.d.ts +0 -1
  126. package/dist/server/health/index.d.ts.map +1 -1
  127. package/dist/server/helmet/index.d.ts +2 -2
  128. package/dist/server/helmet/index.d.ts.map +1 -1
  129. package/dist/server/links/index.browser.js.map +1 -1
  130. package/dist/server/links/index.d.ts +123 -124
  131. package/dist/server/links/index.d.ts.map +1 -1
  132. package/dist/server/links/index.js +1 -2
  133. package/dist/server/links/index.js.map +1 -1
  134. package/dist/server/metrics/index.d.ts.map +1 -1
  135. package/dist/server/multipart/index.d.ts +6 -6
  136. package/dist/server/multipart/index.d.ts.map +1 -1
  137. package/dist/server/proxy/index.d.ts +102 -103
  138. package/dist/server/proxy/index.d.ts.map +1 -1
  139. package/dist/server/rate-limit/index.d.ts +16 -16
  140. package/dist/server/rate-limit/index.d.ts.map +1 -1
  141. package/dist/server/static/index.d.ts +44 -44
  142. package/dist/server/static/index.d.ts.map +1 -1
  143. package/dist/server/static/index.js +4 -0
  144. package/dist/server/static/index.js.map +1 -1
  145. package/dist/server/swagger/index.d.ts +48 -49
  146. package/dist/server/swagger/index.d.ts.map +1 -1
  147. package/dist/server/swagger/index.js +3 -5
  148. package/dist/server/swagger/index.js.map +1 -1
  149. package/dist/sms/index.d.ts +13 -11
  150. package/dist/sms/index.d.ts.map +1 -1
  151. package/dist/sms/index.js +7 -7
  152. package/dist/sms/index.js.map +1 -1
  153. package/dist/thread/index.d.ts +71 -72
  154. package/dist/thread/index.d.ts.map +1 -1
  155. package/dist/topic/core/index.d.ts +318 -318
  156. package/dist/topic/core/index.d.ts.map +1 -1
  157. package/dist/topic/redis/index.d.ts +6 -6
  158. package/dist/topic/redis/index.d.ts.map +1 -1
  159. package/dist/vite/index.d.ts +5805 -249
  160. package/dist/vite/index.d.ts.map +1 -1
  161. package/dist/vite/index.js +599 -513
  162. package/dist/vite/index.js.map +1 -1
  163. package/dist/websocket/index.browser.js +6 -6
  164. package/dist/websocket/index.browser.js.map +1 -1
  165. package/dist/websocket/index.d.ts +247 -247
  166. package/dist/websocket/index.d.ts.map +1 -1
  167. package/dist/websocket/index.js +6 -6
  168. package/dist/websocket/index.js.map +1 -1
  169. package/package.json +9 -14
  170. package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
  171. package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
  172. package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
  173. package/src/api/users/entities/users.ts +1 -1
  174. package/src/api/users/index.ts +8 -8
  175. package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
  176. package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
  177. package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
  178. package/src/api/users/services/CredentialService.ts +7 -7
  179. package/src/api/users/services/IdentityService.ts +4 -4
  180. package/src/api/users/services/RegistrationService.spec.ts +25 -27
  181. package/src/api/users/services/RegistrationService.ts +38 -27
  182. package/src/api/users/services/SessionCrudService.ts +3 -3
  183. package/src/api/users/services/SessionService.spec.ts +3 -3
  184. package/src/api/users/services/SessionService.ts +28 -9
  185. package/src/api/users/services/UserService.ts +7 -7
  186. package/src/batch/providers/BatchProvider.ts +1 -2
  187. package/src/cli/apps/AlephaCli.ts +0 -2
  188. package/src/cli/apps/AlephaPackageBuilderCli.ts +38 -19
  189. package/src/cli/assets/apiHelloControllerTs.ts +18 -0
  190. package/src/cli/assets/apiIndexTs.ts +16 -0
  191. package/src/cli/assets/claudeMd.ts +303 -0
  192. package/src/cli/assets/mainBrowserTs.ts +2 -2
  193. package/src/cli/assets/mainServerTs.ts +24 -0
  194. package/src/cli/assets/webAppRouterTs.ts +15 -0
  195. package/src/cli/assets/webHelloComponentTsx.ts +16 -0
  196. package/src/cli/assets/webIndexTs.ts +16 -0
  197. package/src/cli/atoms/buildOptions.ts +88 -0
  198. package/src/cli/commands/build.ts +70 -87
  199. package/src/cli/commands/db.ts +21 -22
  200. package/src/cli/commands/deploy.ts +17 -5
  201. package/src/cli/commands/dev.ts +22 -14
  202. package/src/cli/commands/format.ts +8 -2
  203. package/src/cli/commands/gen/env.ts +53 -0
  204. package/src/cli/commands/gen/openapi.ts +1 -1
  205. package/src/cli/commands/gen/resource.ts +15 -0
  206. package/src/cli/commands/gen.ts +7 -1
  207. package/src/cli/commands/init.ts +74 -30
  208. package/src/cli/commands/lint.ts +8 -2
  209. package/src/cli/commands/test.ts +8 -3
  210. package/src/cli/commands/typecheck.ts +5 -1
  211. package/src/cli/commands/verify.ts +5 -3
  212. package/src/cli/defineConfig.ts +49 -7
  213. package/src/cli/index.ts +0 -1
  214. package/src/cli/services/AlephaCliUtils.ts +39 -589
  215. package/src/cli/services/PackageManagerUtils.ts +301 -0
  216. package/src/cli/services/ProjectScaffolder.ts +306 -0
  217. package/src/command/helpers/Runner.spec.ts +2 -2
  218. package/src/command/helpers/Runner.ts +16 -4
  219. package/src/command/primitives/$command.ts +0 -6
  220. package/src/command/providers/CliProvider.ts +1 -3
  221. package/src/core/Alepha.ts +42 -0
  222. package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
  223. package/src/core/index.shared.ts +1 -0
  224. package/src/core/index.ts +2 -0
  225. package/src/core/primitives/$hook.ts +6 -2
  226. package/src/core/primitives/$module.spec.ts +4 -0
  227. package/src/core/providers/AlsProvider.ts +1 -1
  228. package/src/core/providers/CodecManager.spec.ts +12 -6
  229. package/src/core/providers/CodecManager.ts +26 -6
  230. package/src/core/providers/EventManager.ts +169 -13
  231. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +621 -0
  232. package/src/core/providers/KeylessJsonSchemaCodec.ts +407 -0
  233. package/src/core/providers/StateManager.spec.ts +27 -16
  234. package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
  235. package/src/email/providers/LocalEmailProvider.ts +52 -15
  236. package/src/email/providers/NodemailerEmailProvider.ts +167 -56
  237. package/src/file/errors/FileError.ts +7 -0
  238. package/src/file/index.ts +9 -1
  239. package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
  240. package/src/logger/index.ts +15 -3
  241. package/src/mcp/transports/StdioMcpTransport.ts +1 -1
  242. package/src/orm/index.browser.ts +1 -19
  243. package/src/orm/index.bun.ts +77 -0
  244. package/src/orm/index.shared-server.ts +22 -0
  245. package/src/orm/index.shared.ts +15 -0
  246. package/src/orm/index.ts +13 -39
  247. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
  248. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  249. package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
  250. package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
  251. package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
  252. package/src/orm/services/Repository.ts +8 -0
  253. package/src/queue/core/providers/WorkerProvider.spec.ts +48 -32
  254. package/src/redis/index.bun.ts +35 -0
  255. package/src/redis/providers/BunRedisProvider.ts +12 -43
  256. package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
  257. package/src/redis/providers/NodeRedisProvider.ts +16 -34
  258. package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
  259. package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
  260. package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
  261. package/src/security/index.browser.ts +5 -0
  262. package/src/security/index.ts +90 -7
  263. package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
  264. package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
  265. package/src/security/primitives/$role.ts +5 -5
  266. package/src/security/primitives/$serviceAccount.spec.ts +5 -5
  267. package/src/security/primitives/$serviceAccount.ts +3 -3
  268. package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
  269. package/src/server/auth/primitives/$auth.ts +10 -10
  270. package/src/server/auth/primitives/$authCredentials.ts +3 -3
  271. package/src/server/auth/primitives/$authGithub.ts +3 -3
  272. package/src/server/auth/primitives/$authGoogle.ts +3 -3
  273. package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
  274. package/src/server/cache/providers/ServerCacheProvider.spec.ts +183 -0
  275. package/src/server/cache/providers/ServerCacheProvider.ts +95 -10
  276. package/src/server/compress/providers/ServerCompressProvider.ts +61 -2
  277. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
  278. package/src/server/core/helpers/ServerReply.ts +2 -2
  279. package/src/server/core/providers/NodeHttpServerProvider.ts +25 -6
  280. package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
  281. package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
  282. package/src/server/core/providers/ServerProvider.ts +155 -22
  283. package/src/server/core/providers/ServerRouterProvider.ts +259 -115
  284. package/src/server/core/providers/ServerTimingProvider.ts +2 -2
  285. package/src/server/links/index.ts +1 -1
  286. package/src/server/links/providers/LinkProvider.ts +1 -1
  287. package/src/server/static/providers/ServerStaticProvider.ts +10 -0
  288. package/src/server/swagger/index.ts +1 -1
  289. package/src/server/swagger/providers/ServerSwaggerProvider.ts +5 -8
  290. package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
  291. package/src/sms/providers/LocalSmsProvider.ts +8 -7
  292. package/src/vite/helpers/boot.ts +28 -17
  293. package/src/vite/helpers/importViteReact.ts +13 -0
  294. package/src/vite/index.ts +1 -21
  295. package/src/vite/plugins/viteAlephaDev.ts +16 -1
  296. package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
  297. package/src/vite/tasks/buildClient.ts +11 -0
  298. package/src/vite/tasks/buildServer.ts +59 -4
  299. package/src/vite/tasks/devServer.ts +71 -0
  300. package/src/vite/tasks/generateCloudflare.ts +7 -0
  301. package/src/vite/tasks/index.ts +2 -1
  302. package/dist/server/security/index.browser.js +0 -13
  303. package/dist/server/security/index.browser.js.map +0 -1
  304. package/dist/server/security/index.d.ts +0 -173
  305. package/dist/server/security/index.d.ts.map +0 -1
  306. package/dist/server/security/index.js +0 -311
  307. package/dist/server/security/index.js.map +0 -1
  308. package/src/cli/assets/appRouterTs.ts +0 -9
  309. package/src/cli/assets/mainTs.ts +0 -13
  310. package/src/cli/assets/viteConfigTs.ts +0 -14
  311. package/src/cli/commands/run.ts +0 -24
  312. package/src/server/security/index.browser.ts +0 -10
  313. package/src/server/security/index.ts +0 -94
  314. package/src/vite/plugins/viteAlepha.ts +0 -37
  315. package/src/vite/plugins/viteAlephaBuild.ts +0 -281
  316. /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
  317. /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
@@ -1,12 +1,13 @@
1
1
  import m, { createRequire } from "node:module";
2
- import { access, cp, mkdir, readFile, stat, unlink, writeFile } from "node:fs/promises";
3
- import path, { basename, dirname, join, resolve } from "node:path";
4
- import { AlephaError, OPTIONS } from "alepha";
5
- import { analyzer } from "vite-bundle-analyzer";
6
- import { promises } from "node:fs";
2
+ import { access, cp, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
3
+ import path, { basename, dirname, join, relative, resolve } from "node:path";
4
+ import { AlephaError } from "alepha";
5
+ import { pathToFileURL } from "node:url";
6
+ import { createHash } from "node:crypto";
7
+ import { existsSync, mkdirSync, promises, writeFileSync } from "node:fs";
7
8
  import { promisify } from "node:util";
8
9
  import { brotliCompress, gzip } from "node:zlib";
9
- import { pathToFileURL } from "node:url";
10
+ import { analyzer } from "vite-bundle-analyzer";
10
11
 
11
12
  //#region ../../src/vite/helpers/boot.ts
12
13
  /**
@@ -15,6 +16,16 @@ import { pathToFileURL } from "node:url";
15
16
  * For avoiding cli -> vite, all code moved here.
16
17
  */
17
18
  /**
19
+ * Server entry files in priority order.
20
+ * main.server.ts is preferred over main.ts for consistency.
21
+ */
22
+ const SERVER_ENTRIES = [
23
+ "main.server.ts",
24
+ "main.server.tsx",
25
+ "main.ts",
26
+ "main.tsx"
27
+ ];
28
+ /**
18
29
  * Find browser/client entry file path.
19
30
  */
20
31
  const getClientEntry = async (root = process.cwd()) => {
@@ -27,6 +38,8 @@ const getClientEntry = async (root = process.cwd()) => {
27
38
  };
28
39
  /**
29
40
  * Find server entry file path.
41
+ *
42
+ * Optimized to use a single readdir() call instead of multiple access() calls.
30
43
  */
31
44
  const getServerEntry = async (root = process.cwd(), explicitEntry) => {
32
45
  if (explicitEntry) {
@@ -38,22 +51,14 @@ const getServerEntry = async (root = process.cwd(), explicitEntry) => {
38
51
  throw new AlephaError(`Explicit server entry file "${explicitEntry}" not found.`);
39
52
  }
40
53
  }
41
- const maybeEntry = [
42
- "src/main.server.ts",
43
- "src/server-entry.ts",
44
- "src/main.server.tsx",
45
- "src/server-entry.tsx",
46
- "src/main.ts",
47
- "src/main.tsx"
48
- ];
49
- for (const entry of maybeEntry) try {
50
- const path$1 = join(root, entry).replace(/\\/g, "/");
51
- await access(path$1);
52
- return path$1;
54
+ const srcDir = join(root, "src");
55
+ try {
56
+ const files = new Set(await readdir(srcDir));
57
+ for (const entry of SERVER_ENTRIES) if (files.has(entry)) return join(srcDir, entry).replace(/\\/g, "/");
53
58
  } catch {}
54
59
  const clientEntry = await getClientEntry(root);
55
60
  if (clientEntry) return clientEntry;
56
- throw new AlephaError(`Could not find a server entry file. List of supported entry file: ${maybeEntry.join(", ")}`);
61
+ throw new AlephaError(`Could not find a server entry file. Supported entries: ${SERVER_ENTRIES.map((e) => `src/${e}`).join(", ")}`);
57
62
  };
58
63
  /**
59
64
  * Extract first module script src from HTML.
@@ -159,12 +164,6 @@ function createBufferedLogger() {
159
164
  };
160
165
  }
161
166
 
162
- //#endregion
163
- //#region ../../src/vite/helpers/fileExists.ts
164
- const fileExists = async (path$1) => {
165
- return await access(join(process.cwd(), path$1)).then(() => true).catch(() => false);
166
- };
167
-
168
167
  //#endregion
169
168
  //#region ../../src/vite/helpers/importVite.ts
170
169
  const importVite = async () => {
@@ -180,88 +179,505 @@ const importVite = async () => {
180
179
  };
181
180
 
182
181
  //#endregion
183
- //#region ../../src/vite/plugins/viteCompress.ts
184
- const gzipCompress = promisify(gzip);
185
- const brotliCompress$1 = promisify(brotliCompress);
186
- function viteCompress(options = {}) {
187
- const { disabled = false, filter = /\.(js|mjs|cjs|css|wasm|svg)$/ } = options;
188
- return {
189
- name: "compress",
190
- apply: "build",
191
- async writeBundle(outputOptions, bundle) {
192
- if (disabled) return;
182
+ //#region ../../src/vite/tasks/runAlepha.ts
183
+ /**
184
+ * Create an Alepha runner for development.
185
+ *
186
+ * The runner manages the lifecycle of an Alepha application during
187
+ * Vite dev server operation, handling start/stop/restart and HMR.
188
+ */
189
+ function createAlephaRunner(opts) {
190
+ return new AlephaRunner({
191
+ root: process.cwd().replace(/\\/g, "/"),
192
+ started: false,
193
+ log: opts.debug ? (...msg) => console.log(...msg) : () => {},
194
+ entry: opts.entry,
195
+ onReload: () => {}
196
+ });
197
+ }
198
+ var AlephaRunner = class {
199
+ state;
200
+ constructor(state) {
201
+ this.state = state;
202
+ }
203
+ /**
204
+ * Set resolved Vite config.
205
+ */
206
+ setConfig(config) {
207
+ this.state.config = config;
208
+ }
209
+ /**
210
+ * Check if SSR is enabled for the running app.
211
+ */
212
+ isSsrEnabled() {
213
+ if (!this.state.app) return false;
214
+ return this.state.app.store.get("alepha.react.server.ssr") ?? false;
215
+ }
216
+ /**
217
+ * Check if app is started.
218
+ */
219
+ get isStarted() {
220
+ return this.state.started;
221
+ }
222
+ /**
223
+ * Get the running Alepha app instance.
224
+ */
225
+ get app() {
226
+ return this.state.app;
227
+ }
228
+ /**
229
+ * Start the Alepha application.
230
+ */
231
+ async start(server) {
232
+ const { loadEnv } = await importVite();
233
+ global.ssrFixStacktrace = (e) => {
234
+ server.ssrFixStacktrace(e);
235
+ let it = e;
236
+ do {
237
+ server.ssrFixStacktrace(it);
238
+ it = it.cause;
239
+ } while (it instanceof Error);
240
+ };
241
+ if (this.state.started) {
242
+ await this.restart(server, true);
243
+ return;
244
+ }
245
+ if (!this.state.config) {
246
+ this.state.log("[DEBUG] No config - skip starting");
247
+ return;
248
+ }
249
+ this.state.onReload?.();
250
+ this.state.log("[DEBUG] Starting Alepha app...");
251
+ this.state.started = false;
252
+ this.state.app = void 0;
253
+ const fileUrl = pathToFileURL(`${path.resolve(this.state.config.root, this.state.entry)}`).href;
254
+ const env = loadEnv("development", this.state.config.root, "");
255
+ const before = { ...process.env };
256
+ for (const key in env) process.env[key] = env[key];
257
+ let port = 5173;
258
+ const address = server.httpServer?.address();
259
+ if (typeof address === "object" && address?.port) port = address.port;
260
+ process.env.NODE_ENV ??= "development";
261
+ process.env.VITE_ALEPHA_DEV = "true";
262
+ process.env.SERVER_HOST ??= typeof server.config.server.host === "string" ? server.config.server.host : "localhost";
263
+ process.env.SERVER_PORT ??= String(port);
264
+ try {
193
265
  const now = Date.now();
194
- const outputDir = outputOptions.dir || resolve(process.cwd(), "dist");
195
- const files = Object.keys(bundle).filter((fileName) => {
196
- if (typeof filter === "function") return filter(fileName);
197
- return filter.test(fileName);
198
- }).map((fileName) => ({
199
- fileName,
200
- filePath: join(outputDir, fileName)
201
- }));
202
- const compressionTasks = [];
203
- for (const { filePath } of files) compressionTasks.push(compressFile(options, filePath));
204
- await Promise.all(compressionTasks);
205
- this.info(`Compressed ${files.length} file${files.length > 1 ? "s" : ""} in ${Date.now() - now}ms.`);
266
+ await server.ssrLoadModule(fileUrl, { fixStacktrace: true });
267
+ this.state.log(`[DEBUG] Alepha app loaded in ${Date.now() - now}ms`);
268
+ await new Promise((r) => setTimeout(r, 10));
269
+ this.state.app = globalThis.__alepha;
270
+ if (!this.state.app) {
271
+ this.state.log("[DEBUG] No app found - skip starting");
272
+ return;
273
+ }
274
+ this.state.app.store.set("alepha.node.server", server.httpServer);
275
+ console.log("");
276
+ await this.state.app.start();
277
+ this.state.started = true;
278
+ process.env = { ...before };
279
+ this.state.log("[DEBUG] Starting Done!");
280
+ } catch (e) {
281
+ if (e instanceof Error) {
282
+ let it = e;
283
+ do {
284
+ server.ssrFixStacktrace(it);
285
+ it = it.cause;
286
+ } while (it instanceof Error);
287
+ server.ssrFixStacktrace(e);
288
+ if (e.cause instanceof Error) server.ssrFixStacktrace(e.cause);
289
+ this.state.app?.log?.error("App failed to start:", e);
290
+ this.state.app?.log?.info("Waiting for changes to restart...");
291
+ }
292
+ this.state.log("[DEBUG] Alepha app start error");
293
+ this.state.started = false;
206
294
  }
207
- };
208
- }
209
- async function compressFile(options = {}, filePath) {
210
- const { brotli = true, gzip: gzip$1 = true } = options;
211
- const compressionTasks = [];
212
- const fileContentPromise = promises.readFile(filePath);
213
- if (gzip$1) {
214
- const gzipOptions = typeof gzip$1 === "object" ? gzip$1 : { level: 9 };
215
- compressionTasks.push(fileContentPromise.then(async (content) => {
216
- const compressed = await gzipCompress(content, gzipOptions);
217
- await promises.writeFile(`${filePath}.gz`, compressed);
218
- }));
219
295
  }
220
- if (brotli) {
221
- const brotliOptions = typeof brotli === "object" ? brotli : {};
222
- compressionTasks.push(fileContentPromise.then(async (content) => {
223
- const compressed = await brotliCompress$1(content, brotliOptions);
224
- await promises.writeFile(`${filePath}.br`, compressed);
225
- }));
296
+ /**
297
+ * Stop the Alepha application.
298
+ */
299
+ async stop() {
300
+ if (this.state.app?.stop && this.state.started) {
301
+ this.state.log("[DEBUG] Stopping Alepha app...");
302
+ await this.state.app.stop();
303
+ this.state.started = false;
304
+ this.state.log("[DEBUG] Stopping Done!");
305
+ } else this.state.log("[DEBUG] Alepha app not started - skip stop");
226
306
  }
227
- await Promise.all(compressionTasks);
307
+ /**
308
+ * Restart the Alepha application.
309
+ *
310
+ * @returns true if the restart was skipped due to locking
311
+ */
312
+ async restart(server, invalidate) {
313
+ if (this.state.lock) {
314
+ this.state.log("[DEBUG] STILL LOCKING");
315
+ return true;
316
+ }
317
+ this.state.log("[DEBUG] LOCK RESTART");
318
+ this.state.lock = Promise.withResolvers();
319
+ const now = Date.now();
320
+ this.state.log("[DEBUG] RESTART");
321
+ await this.stop();
322
+ this.state.log(`[DEBUG] RESTART (stop) in ${Date.now() - now}ms`);
323
+ if (invalidate) server.moduleGraph.invalidateAll();
324
+ await this.start(server);
325
+ this.state.log(`[DEBUG] RESTART OK in ${Date.now() - now}ms`);
326
+ setTimeout(() => {
327
+ this.state.log("[DEBUG] UNLOCK RESTART");
328
+ this.state.lock?.resolve();
329
+ this.state.lock = void 0;
330
+ }, 500);
331
+ return false;
332
+ }
333
+ /**
334
+ * Send reload event to client.
335
+ */
336
+ sendReload(server) {
337
+ server.ws.send({
338
+ type: "custom",
339
+ event: "alepha:reload",
340
+ data: {}
341
+ });
342
+ }
343
+ };
344
+ /**
345
+ * Check if a URL path is a Vite internal file.
346
+ */
347
+ function isViteInternalPath(pathname) {
348
+ const [path$1] = pathname.split("?");
349
+ if (path$1.startsWith("/@") || path$1.startsWith("/src") || path$1.includes("/node_modules/")) return true;
350
+ return false;
228
351
  }
229
352
 
230
353
  //#endregion
231
- //#region ../../src/vite/tasks/buildClient.ts
354
+ //#region ../../src/vite/plugins/viteAlephaDev.ts
232
355
  /**
233
- * Build client-side bundle with Vite.
356
+ * Plug Alepha into Vite development server.
234
357
  *
235
- * This task compiles the browser/client code for production,
236
- * including code splitting, minification, and optional compression.
358
+ * This plugin manages the Alepha application lifecycle during development,
359
+ * handling hot module replacement and request forwarding.
237
360
  */
238
- async function buildClient(opts) {
239
- const { build: viteBuild, mergeConfig } = await importVite();
240
- const plugins = [];
241
- const compress = opts.precompress ? typeof opts.precompress === "object" ? opts.precompress : {} : void 0;
242
- if (opts.stats) plugins.push(analyzer({ analyzerMode: "static" }));
243
- if (opts.precompress && compress) plugins.push(viteCompress(compress));
244
- const logger = opts.silent ? createBufferedLogger() : void 0;
245
- const viteBuildClientConfig = {
246
- mode: "production",
247
- logLevel: opts.silent ? "silent" : void 0,
248
- define: { "process.env.NODE_ENV": "\"production\"" },
249
- publicDir: "public",
250
- build: {
251
- chunkSizeWarningLimit: 1e3,
252
- outDir: opts.dist,
253
- rollupOptions: { output: {
254
- entryFileNames: "entry.[hash].js",
255
- chunkFileNames: "chunk.[hash].js",
256
- assetFileNames: "asset.[hash][extname]"
257
- } }
258
- },
259
- esbuild: { legalComments: "none" },
260
- customLogger: logger,
261
- plugins
262
- };
263
- try {
264
- await viteBuild(mergeConfig(viteBuildClientConfig, opts.config ?? {}));
361
+ async function viteAlephaDev(options = {}) {
362
+ let entry = options.serverEntry;
363
+ if (!entry) {
364
+ entry = await boot.getServerEntry();
365
+ if (!entry) return {
366
+ name: "alepha-dev",
367
+ apply: "serve",
368
+ config() {}
369
+ };
370
+ }
371
+ const runner = createAlephaRunner({
372
+ entry,
373
+ debug: options.debug
374
+ });
375
+ const { loadEnv } = await importVite();
376
+ const env = loadEnv("development", process.cwd(), "SERVER");
377
+ const config = {};
378
+ if (env.SERVER_PORT) config.server = { port: parseInt(env.SERVER_PORT, 10) };
379
+ return {
380
+ name: "alepha-dev",
381
+ apply: "serve",
382
+ config: () => config,
383
+ configResolved(resolvedConfig) {
384
+ runner.setConfig(resolvedConfig);
385
+ },
386
+ async handleHotUpdate(ctx) {
387
+ if (options.debug) console.log("[DEBUG] HMR", ctx.file);
388
+ if (ctx.file.includes("/.idea/")) return [];
389
+ const isServerOnly = !ctx.modules[0]?._clientModule;
390
+ const isBrowserOnly = !ctx.modules[0]?._ssrModule;
391
+ const isSsrEnabled = runner.isSsrEnabled();
392
+ if (isBrowserOnly) {
393
+ if (options.debug) console.log("[DEBUG] HMR - browser only - no reason to reload server");
394
+ return;
395
+ }
396
+ const root = process.cwd().replace(/\\/g, "/");
397
+ const invalidate = !ctx.file.startsWith(root);
398
+ if (invalidate && options.debug) console.log("[DEBUG] HMR - outside root - invalidate all");
399
+ if (!isSsrEnabled && isServerOnly) {
400
+ await runner.restart(ctx.server, invalidate);
401
+ return [];
402
+ }
403
+ if (isSsrEnabled && ctx.modules[0]) {
404
+ if (await runner.restart(ctx.server, invalidate)) return [];
405
+ if (!runner.isStarted) {
406
+ if (options.debug) console.log("[DEBUG] HMR - abort due to app not started");
407
+ return [];
408
+ }
409
+ if (isServerOnly && runner.isStarted) {
410
+ runner.sendReload(ctx.server);
411
+ return [];
412
+ }
413
+ }
414
+ },
415
+ async configureServer(server) {
416
+ if (env.SERVER_PORT) server.config.server.port = parseInt(env.SERVER_PORT, 10);
417
+ const middleware = (req, res, next) => {
418
+ if (runner.isStarted && runner.app && req.url && !isViteInternalPath(req.url)) {
419
+ let ended = false;
420
+ const writeHead = res.writeHead.bind(res);
421
+ res.writeHead = (...args) => {
422
+ ended = true;
423
+ return writeHead(args[0], args[1], args[2]);
424
+ };
425
+ return runner.app.events.emit("node:request", {
426
+ req,
427
+ res
428
+ }).then(() => {
429
+ if (!ended) next();
430
+ });
431
+ }
432
+ next();
433
+ };
434
+ server.middlewares.use((req, res, next) => {
435
+ middleware(req, res, next);
436
+ });
437
+ server.config.logger.info = (msg) => {
438
+ console.log(msg);
439
+ };
440
+ server.config.logger.clearScreen = () => {};
441
+ return () => {
442
+ server.httpServer?.once("listening", () => {
443
+ runner.start(server);
444
+ });
445
+ };
446
+ },
447
+ async closeBundle() {}
448
+ };
449
+ }
450
+
451
+ //#endregion
452
+ //#region ../../src/vite/plugins/viteAlephaSsrPreload.ts
453
+ /**
454
+ * Vite plugin that generates a preload manifest for SSR module preloading.
455
+ *
456
+ * Instead of injecting source paths directly into $page definitions (which would
457
+ * leak component paths in the browser bundle), this plugin:
458
+ *
459
+ * 1. Collects all lazy import paths from $page definitions during transform
460
+ * 2. Generates a manifest file mapping short keys to resolved source paths
461
+ * 3. Injects only the short key into $page definitions
462
+ *
463
+ * The manifest is written to `.vite/preload-manifest.json` alongside Vite's
464
+ * other manifests. The CLI build command moves all manifests to
465
+ * `dist/server/.ssr/` where SSRManifestProvider loads them at runtime.
466
+ *
467
+ * Before:
468
+ * ```typescript
469
+ * $page({
470
+ * path: '/users/:id',
471
+ * lazy: () => import('./UserDetail.tsx'),
472
+ * })
473
+ * ```
474
+ *
475
+ * After:
476
+ * ```typescript
477
+ * $page({
478
+ * path: '/users/:id',
479
+ * lazy: () => import('./UserDetail.tsx'),
480
+ * [Symbol.for("alepha.page.preload")]: "a1b2c3",
481
+ * })
482
+ * ```
483
+ *
484
+ * Manifest (.alepha/preload-manifest.json):
485
+ * ```json
486
+ * {
487
+ * "a1b2c3": "src/pages/UserDetail.tsx"
488
+ * }
489
+ * ```
490
+ */
491
+ function viteAlephaSsrPreload() {
492
+ let root = "";
493
+ const preloadMap = /* @__PURE__ */ new Map();
494
+ /**
495
+ * Generate a short hash key for a source path.
496
+ * Uses first 8 chars of MD5 hash for brevity while avoiding collisions.
497
+ */
498
+ function generateKey(sourcePath) {
499
+ return createHash("md5").update(sourcePath).digest("hex").slice(0, 8);
500
+ }
501
+ return {
502
+ name: "alepha-preload",
503
+ configResolved(config) {
504
+ root = config.root;
505
+ },
506
+ transform(code, id) {
507
+ if (!id.match(/\.[tj]sx?$/)) return null;
508
+ if (id.includes("node_modules")) return null;
509
+ if (!code.includes("$page") || !code.includes("lazy")) return null;
510
+ const insertions = [];
511
+ const pageStartRegex = /\$page\s*\(\s*\{/g;
512
+ let pageMatch = pageStartRegex.exec(code);
513
+ while (pageMatch !== null) {
514
+ const objectStartIndex = pageMatch.index + pageMatch[0].length - 1;
515
+ let braceCount = 1;
516
+ let i = objectStartIndex + 1;
517
+ while (i < code.length && braceCount > 0) {
518
+ if (code[i] === "{") braceCount++;
519
+ else if (code[i] === "}") braceCount--;
520
+ i++;
521
+ }
522
+ if (braceCount !== 0) {
523
+ pageMatch = pageStartRegex.exec(code);
524
+ continue;
525
+ }
526
+ const objectEndIndex = i - 1;
527
+ const pageContent = code.slice(objectStartIndex, objectEndIndex + 1);
528
+ if (pageContent.includes("alepha.page.preload")) {
529
+ pageMatch = pageStartRegex.exec(code);
530
+ continue;
531
+ }
532
+ const lazyMatch = /lazy\s*:\s*\(\s*\)\s*=>\s*import\s*\(\s*['"]([^'"]+)['"]\s*\)/.exec(pageContent);
533
+ if (!lazyMatch) {
534
+ pageMatch = pageStartRegex.exec(code);
535
+ continue;
536
+ }
537
+ const importPath = lazyMatch[1];
538
+ const currentDir = dirname(id);
539
+ let resolvedPath;
540
+ if (importPath.startsWith(".")) resolvedPath = resolve(currentDir, importPath);
541
+ else if (importPath.startsWith("/")) resolvedPath = resolve(root, importPath.slice(1));
542
+ else {
543
+ pageMatch = pageStartRegex.exec(code);
544
+ continue;
545
+ }
546
+ let relativePath = relative(root, resolvedPath);
547
+ relativePath = relativePath.replace(/\\/g, "/");
548
+ if (!relativePath.match(/\.[tj]sx?$/)) relativePath = `${relativePath}.tsx`;
549
+ else if (relativePath.endsWith(".jsx")) relativePath = relativePath.replace(/\.jsx$/, ".tsx");
550
+ else if (relativePath.endsWith(".js")) relativePath = relativePath.replace(/\.js$/, ".ts");
551
+ const key = generateKey(relativePath);
552
+ preloadMap.set(key, relativePath);
553
+ const preloadProperty = `${!code.slice(0, objectEndIndex).trimEnd().endsWith(",") ? "," : ""} [Symbol.for("alepha.page.preload")]: "${key}"`;
554
+ insertions.push({
555
+ position: objectEndIndex,
556
+ text: preloadProperty
557
+ });
558
+ pageMatch = pageStartRegex.exec(code);
559
+ }
560
+ if (insertions.length === 0) return null;
561
+ let result = code;
562
+ for (let j = insertions.length - 1; j >= 0; j--) {
563
+ const { position, text } = insertions[j];
564
+ result = result.slice(0, position) + text + result.slice(position);
565
+ }
566
+ return {
567
+ code: result,
568
+ map: null
569
+ };
570
+ },
571
+ writeBundle(options) {
572
+ const outDir = options.dir || "";
573
+ if (outDir.includes("server")) return;
574
+ if (preloadMap.size > 0) {
575
+ const viteDir = join(outDir, ".vite");
576
+ if (!existsSync(viteDir)) mkdirSync(viteDir, { recursive: true });
577
+ const manifest = Object.fromEntries(preloadMap);
578
+ writeFileSync(join(viteDir, "preload-manifest.json"), JSON.stringify(manifest, null, 2));
579
+ }
580
+ }
581
+ };
582
+ }
583
+
584
+ //#endregion
585
+ //#region ../../src/vite/plugins/viteCompress.ts
586
+ const gzipCompress = promisify(gzip);
587
+ const brotliCompress$1 = promisify(brotliCompress);
588
+ function viteCompress(options = {}) {
589
+ const { disabled = false, filter = /\.(js|mjs|cjs|css|wasm|svg)$/ } = options;
590
+ return {
591
+ name: "compress",
592
+ apply: "build",
593
+ async writeBundle(outputOptions, bundle) {
594
+ if (disabled) return;
595
+ const now = Date.now();
596
+ const outputDir = outputOptions.dir || resolve(process.cwd(), "dist");
597
+ const files = Object.keys(bundle).filter((fileName) => {
598
+ if (typeof filter === "function") return filter(fileName);
599
+ return filter.test(fileName);
600
+ }).map((fileName) => ({
601
+ fileName,
602
+ filePath: join(outputDir, fileName)
603
+ }));
604
+ const compressionTasks = [];
605
+ for (const { filePath } of files) compressionTasks.push(compressFile(options, filePath));
606
+ await Promise.all(compressionTasks);
607
+ this.info(`Compressed ${files.length} file${files.length > 1 ? "s" : ""} in ${Date.now() - now}ms.`);
608
+ }
609
+ };
610
+ }
611
+ async function compressFile(options = {}, filePath) {
612
+ const { brotli = true, gzip: gzip$1 = true } = options;
613
+ const compressionTasks = [];
614
+ const fileContentPromise = promises.readFile(filePath);
615
+ if (gzip$1) {
616
+ const gzipOptions = typeof gzip$1 === "object" ? gzip$1 : { level: 9 };
617
+ compressionTasks.push(fileContentPromise.then(async (content) => {
618
+ const compressed = await gzipCompress(content, gzipOptions);
619
+ await promises.writeFile(`${filePath}.gz`, compressed);
620
+ }));
621
+ }
622
+ if (brotli) {
623
+ const brotliOptions = typeof brotli === "object" ? brotli : {};
624
+ compressionTasks.push(fileContentPromise.then(async (content) => {
625
+ const compressed = await brotliCompress$1(content, brotliOptions);
626
+ await promises.writeFile(`${filePath}.br`, compressed);
627
+ }));
628
+ }
629
+ await Promise.all(compressionTasks);
630
+ }
631
+
632
+ //#endregion
633
+ //#region ../../src/vite/helpers/importViteReact.ts
634
+ const importViteReact = async () => {
635
+ try {
636
+ const { default: viteReact } = createRequire(import.meta.url)("@vitejs/plugin-react");
637
+ return viteReact;
638
+ } catch {}
639
+ };
640
+
641
+ //#endregion
642
+ //#region ../../src/vite/tasks/buildClient.ts
643
+ /**
644
+ * Build client-side bundle with Vite.
645
+ *
646
+ * This task compiles the browser/client code for production,
647
+ * including code splitting, minification, and optional compression.
648
+ */
649
+ async function buildClient(opts) {
650
+ const { build: viteBuild, mergeConfig } = await importVite();
651
+ const plugins = [];
652
+ const viteReact = await importViteReact();
653
+ if (viteReact) plugins.push(viteReact());
654
+ plugins.push(viteAlephaSsrPreload());
655
+ const compress = opts.precompress ? typeof opts.precompress === "object" ? opts.precompress : {} : void 0;
656
+ if (opts.stats) plugins.push(analyzer({ analyzerMode: "static" }));
657
+ if (opts.precompress && compress) plugins.push(viteCompress(compress));
658
+ const logger = opts.silent ? createBufferedLogger() : void 0;
659
+ const viteBuildClientConfig = {
660
+ mode: "production",
661
+ logLevel: opts.silent ? "silent" : void 0,
662
+ define: { "process.env.NODE_ENV": "\"production\"" },
663
+ publicDir: "public",
664
+ build: {
665
+ chunkSizeWarningLimit: 1e3,
666
+ outDir: opts.dist,
667
+ manifest: true,
668
+ ssrManifest: true,
669
+ rollupOptions: { output: {
670
+ entryFileNames: "entry.[hash].js",
671
+ chunkFileNames: "chunk.[hash].js",
672
+ assetFileNames: "asset.[hash][extname]"
673
+ } }
674
+ },
675
+ esbuild: { legalComments: "none" },
676
+ customLogger: logger,
677
+ plugins
678
+ };
679
+ try {
680
+ await viteBuild(mergeConfig(viteBuildClientConfig, opts.config ?? {}));
265
681
  } catch (error) {
266
682
  logger?.flush();
267
683
  throw error;
@@ -307,14 +723,27 @@ async function generateExternals(opts) {
307
723
  async function buildServer(opts) {
308
724
  const { build: viteBuild, mergeConfig } = await importVite();
309
725
  const plugins = [];
726
+ const viteReact = await importViteReact();
727
+ if (viteReact && opts.clientDir) plugins.push(viteReact());
728
+ plugins.push(viteAlephaSsrPreload());
310
729
  if (opts.stats) plugins.push(analyzer({ analyzerMode: "static" }));
311
730
  const logger = opts.silent ? createBufferedLogger() : void 0;
731
+ const conditions = [
732
+ "node",
733
+ "import",
734
+ "module",
735
+ "default"
736
+ ];
737
+ if (opts.conditions) conditions.unshift(...opts.conditions);
312
738
  const viteBuildServerConfig = {
313
739
  mode: "production",
314
740
  logLevel: opts.silent ? "silent" : void 0,
315
741
  define: { "process.env.NODE_ENV": "\"production\"" },
316
742
  publicDir: false,
317
- ssr: { noExternal: true },
743
+ ssr: {
744
+ noExternal: true,
745
+ resolve: { conditions }
746
+ },
318
747
  build: {
319
748
  sourcemap: true,
320
749
  ssr: opts.entry,
@@ -322,7 +751,7 @@ async function buildServer(opts) {
322
751
  minify: true,
323
752
  chunkSizeWarningLimit: 1e4,
324
753
  rollupOptions: {
325
- external: ["bun"],
754
+ external: [/^bun(:|$)/, /^cloudflare:/],
326
755
  output: {
327
756
  entryFileNames: "[hash].js",
328
757
  chunkFileNames: "[hash].js",
@@ -353,12 +782,37 @@ async function buildServer(opts) {
353
782
  const entryFile = extractEntryFromBundle(opts.entry, result);
354
783
  let template = "";
355
784
  if (opts.clientDir) template = `__alepha.set("alepha.react.server.template", \`${(await readFile(`${opts.distDir}/${opts.clientDir}/index.html`, "utf-8")).replace(/>\s*</g, "><").trim()}\`);\n`;
785
+ let manifest = "";
786
+ if (opts.clientDir) {
787
+ const viteDir = `${opts.distDir}/${opts.clientDir}/.vite`;
788
+ const combined = {
789
+ ssr: await loadJsonFile(`${viteDir}/ssr-manifest.json`),
790
+ client: await loadJsonFile(`${viteDir}/manifest.json`),
791
+ preload: await loadJsonFile(`${viteDir}/preload-manifest.json`)
792
+ };
793
+ manifest = `__alepha.set("alepha.react.ssr.manifest", ${JSON.stringify(combined)});\n`;
794
+ await rm(viteDir, {
795
+ recursive: true,
796
+ force: true
797
+ });
798
+ }
356
799
  await writeFile(`${opts.distDir}/index.js`, `// This file was automatically generated. DO NOT MODIFY.
357
800
  // Changes to this file will be lost when the code is regenerated.
358
- \nimport './server/${entryFile}';\n\n${template}`.trim());
801
+ \n${template}${manifest}import './server/${entryFile}';\n`.trim());
359
802
  return { entryFile };
360
803
  }
361
804
  /**
805
+ * Load a JSON file, returning undefined if it doesn't exist.
806
+ */
807
+ async function loadJsonFile(path$1) {
808
+ try {
809
+ const content = await readFile(path$1, "utf-8");
810
+ return JSON.parse(content);
811
+ } catch {
812
+ return;
813
+ }
814
+ }
815
+ /**
362
816
  * Extract entry filename from Vite build result.
363
817
  */
364
818
  function extractEntryFromBundle(entry, result) {
@@ -418,6 +872,39 @@ async function copyAssets(opts) {
418
872
  else await fn();
419
873
  }
420
874
 
875
+ //#endregion
876
+ //#region ../../src/vite/tasks/devServer.ts
877
+ /**
878
+ * Start Vite development server with Alepha plugins.
879
+ *
880
+ * This task starts the Vite dev server with all required plugins:
881
+ * - @vitejs/plugin-react (JSX/TSX compilation)
882
+ * - viteAlephaDev (Alepha server integration)
883
+ * - viteAlephaSsrPreload (SSR module preloading)
884
+ */
885
+ async function devServer(opts = {}) {
886
+ const { createServer, mergeConfig } = await importVite();
887
+ const plugins = [];
888
+ const viteReact = await importViteReact();
889
+ if (viteReact) plugins.push(viteReact());
890
+ plugins.push(viteAlephaSsrPreload());
891
+ plugins.push(await viteAlephaDev({
892
+ serverEntry: opts.entry,
893
+ debug: opts.debug
894
+ }));
895
+ const server = await createServer(mergeConfig({
896
+ plugins,
897
+ server: {
898
+ port: opts.port,
899
+ host: opts.host
900
+ }
901
+ }, {}));
902
+ await server.listen();
903
+ console.log("");
904
+ server.printUrls();
905
+ server.bindCLIShortcuts({ print: true });
906
+ }
907
+
421
908
  //#endregion
422
909
  //#region ../../src/vite/tasks/generateCloudflare.ts
423
910
  const WARNING_COMMENT$1 = "// This file was automatically generated. DO NOT MODIFY.\n// Changes to this file will be lost when the code is regenerated.\n";
@@ -438,6 +925,11 @@ async function generateCloudflare(opts = {}) {
438
925
  main: "./main.cloudflare.js",
439
926
  compatibility_flags: ["nodejs_compat"],
440
927
  compatibility_date: "2025-11-17",
928
+ no_bundle: true,
929
+ rules: [{
930
+ type: "ESModule",
931
+ globs: ["index.js", "server/*.js"]
932
+ }],
441
933
  ...opts.config
442
934
  };
443
935
  if (hasAssets) wrangler.assets ??= {
@@ -482,6 +974,12 @@ export default {
482
974
  await writeFile(join(root, distDir, "main.cloudflare.js"), `${WARNING_COMMENT$1}\n${workerCode}`.trim());
483
975
  }
484
976
 
977
+ //#endregion
978
+ //#region ../../src/vite/helpers/fileExists.ts
979
+ const fileExists = async (path$1) => {
980
+ return await access(join(process.cwd(), path$1)).then(() => true).catch(() => false);
981
+ };
982
+
485
983
  //#endregion
486
984
  //#region ../../src/vite/tasks/generateDocker.ts
487
985
  /**
@@ -704,417 +1202,5 @@ async function renderFile(page, options, dist, compress) {
704
1202
  }
705
1203
 
706
1204
  //#endregion
707
- //#region ../../src/vite/tasks/runAlepha.ts
708
- /**
709
- * Create an Alepha runner for development.
710
- *
711
- * The runner manages the lifecycle of an Alepha application during
712
- * Vite dev server operation, handling start/stop/restart and HMR.
713
- */
714
- function createAlephaRunner(opts) {
715
- return new AlephaRunner({
716
- root: process.cwd().replace(/\\/g, "/"),
717
- started: false,
718
- log: opts.debug ? (...msg) => console.log(...msg) : () => {},
719
- entry: opts.entry,
720
- onReload: () => {}
721
- });
722
- }
723
- var AlephaRunner = class {
724
- state;
725
- constructor(state) {
726
- this.state = state;
727
- }
728
- /**
729
- * Set resolved Vite config.
730
- */
731
- setConfig(config) {
732
- this.state.config = config;
733
- }
734
- /**
735
- * Check if SSR is enabled for the running app.
736
- */
737
- isSsrEnabled() {
738
- if (!this.state.app) return false;
739
- return this.state.app.store.get("alepha.react.server.ssr") ?? false;
740
- }
741
- /**
742
- * Check if app is started.
743
- */
744
- get isStarted() {
745
- return this.state.started;
746
- }
747
- /**
748
- * Get the running Alepha app instance.
749
- */
750
- get app() {
751
- return this.state.app;
752
- }
753
- /**
754
- * Start the Alepha application.
755
- */
756
- async start(server) {
757
- const { loadEnv } = await importVite();
758
- global.ssrFixStacktrace = (e) => {
759
- server.ssrFixStacktrace(e);
760
- let it = e;
761
- do {
762
- server.ssrFixStacktrace(it);
763
- it = it.cause;
764
- } while (it instanceof Error);
765
- };
766
- if (this.state.started) {
767
- await this.restart(server, true);
768
- return;
769
- }
770
- if (!this.state.config) {
771
- this.state.log("[DEBUG] No config - skip starting");
772
- return;
773
- }
774
- this.state.onReload?.();
775
- this.state.log("[DEBUG] Starting Alepha app...");
776
- this.state.started = false;
777
- this.state.app = void 0;
778
- const fileUrl = pathToFileURL(`${path.resolve(this.state.config.root, this.state.entry)}`).href;
779
- const env = loadEnv("development", this.state.config.root, "");
780
- const before = { ...process.env };
781
- for (const key in env) process.env[key] = env[key];
782
- let port = 5173;
783
- const address = server.httpServer?.address();
784
- if (typeof address === "object" && address?.port) port = address.port;
785
- process.env.NODE_ENV ??= "development";
786
- process.env.VITE_ALEPHA_DEV = "true";
787
- process.env.SERVER_HOST ??= typeof server.config.server.host === "string" ? server.config.server.host : "localhost";
788
- process.env.SERVER_PORT ??= String(port);
789
- try {
790
- const now = Date.now();
791
- await server.ssrLoadModule(fileUrl, { fixStacktrace: true });
792
- this.state.log(`[DEBUG] Alepha app loaded in ${Date.now() - now}ms`);
793
- await new Promise((r) => setTimeout(r, 10));
794
- this.state.app = globalThis.__alepha;
795
- if (!this.state.app) {
796
- this.state.log("[DEBUG] No app found - skip starting");
797
- return;
798
- }
799
- this.state.app.store.set("alepha.node.server", server.httpServer);
800
- console.log("");
801
- await this.state.app.start();
802
- this.state.started = true;
803
- process.env = { ...before };
804
- this.state.log("[DEBUG] Starting Done!");
805
- } catch (e) {
806
- if (e instanceof Error) {
807
- let it = e;
808
- do {
809
- server.ssrFixStacktrace(it);
810
- it = it.cause;
811
- } while (it instanceof Error);
812
- server.ssrFixStacktrace(e);
813
- if (e.cause instanceof Error) server.ssrFixStacktrace(e.cause);
814
- this.state.app?.log?.error("App failed to start:", e);
815
- this.state.app?.log?.info("Waiting for changes to restart...");
816
- }
817
- this.state.log("[DEBUG] Alepha app start error");
818
- this.state.started = false;
819
- }
820
- }
821
- /**
822
- * Stop the Alepha application.
823
- */
824
- async stop() {
825
- if (this.state.app?.stop && this.state.started) {
826
- this.state.log("[DEBUG] Stopping Alepha app...");
827
- await this.state.app.stop();
828
- this.state.started = false;
829
- this.state.log("[DEBUG] Stopping Done!");
830
- } else this.state.log("[DEBUG] Alepha app not started - skip stop");
831
- }
832
- /**
833
- * Restart the Alepha application.
834
- *
835
- * @returns true if the restart was skipped due to locking
836
- */
837
- async restart(server, invalidate) {
838
- if (this.state.lock) {
839
- this.state.log("[DEBUG] STILL LOCKING");
840
- return true;
841
- }
842
- this.state.log("[DEBUG] LOCK RESTART");
843
- this.state.lock = Promise.withResolvers();
844
- const now = Date.now();
845
- this.state.log("[DEBUG] RESTART");
846
- await this.stop();
847
- this.state.log(`[DEBUG] RESTART (stop) in ${Date.now() - now}ms`);
848
- if (invalidate) server.moduleGraph.invalidateAll();
849
- await this.start(server);
850
- this.state.log(`[DEBUG] RESTART OK in ${Date.now() - now}ms`);
851
- setTimeout(() => {
852
- this.state.log("[DEBUG] UNLOCK RESTART");
853
- this.state.lock?.resolve();
854
- this.state.lock = void 0;
855
- }, 500);
856
- return false;
857
- }
858
- /**
859
- * Send reload event to client.
860
- */
861
- sendReload(server) {
862
- server.ws.send({
863
- type: "custom",
864
- event: "alepha:reload",
865
- data: {}
866
- });
867
- }
868
- };
869
- /**
870
- * Check if a URL path is a Vite internal file.
871
- */
872
- function isViteInternalPath(pathname) {
873
- const [path$1] = pathname.split("?");
874
- if (path$1.startsWith("/@") || path$1.startsWith("/src") || path$1.includes("/node_modules/")) return true;
875
- return false;
876
- }
877
-
878
- //#endregion
879
- //#region ../../src/vite/plugins/viteAlephaBuild.ts
880
- /**
881
- * Alepha build plugin for Vite.
882
- *
883
- * This plugin orchestrates the complete build process:
884
- * 1. Build client (if index.html exists)
885
- * 2. Build server (SSR)
886
- * 3. Copy assets from packages
887
- * 4. Pre-render static pages (if enabled)
888
- * 5. Generate sitemap (if enabled)
889
- * 6. Generate deployment config (Vercel/Cloudflare/Docker)
890
- *
891
- * Build mode can be controlled via ALEPHA_BUILD_MODE env var for CLI integration.
892
- */
893
- async function viteAlephaBuild(options = {}) {
894
- const entry = options.serverEntry ?? await boot.getServerEntry();
895
- const distDir = "dist";
896
- const clientDir = "public";
897
- let rootConfig = {};
898
- return {
899
- name: "alepha:build",
900
- apply: "build",
901
- [OPTIONS]: options,
902
- config(config, ctx) {
903
- if (process.env.ALEPHA_BUILD_MODE === "cli") return;
904
- if (!process.env.VITE_DOUBLE_BUILD_DONE) rootConfig = config;
905
- if (ctx.isSsrBuild || !process.env.VITE_DOUBLE_BUILD_DONE) config.publicDir = false;
906
- else config.publicDir = "public";
907
- },
908
- async buildStart() {
909
- const buildMode = process.env.ALEPHA_BUILD_MODE;
910
- if (buildMode === "cli") return;
911
- if (process.env.VITE_DOUBLE_BUILD_DONE === "true") return;
912
- process.env.VITE_DOUBLE_BUILD_DONE = "true";
913
- const hasClient = options.client !== false && await fileExists("index.html");
914
- const buildClientOptions = typeof options.client === "object" ? options.client : {};
915
- const stats = options.stats ?? process.env.ALEPHA_BUILD_STATS === "true";
916
- if (buildMode === "client") {
917
- if (hasClient) await buildClient({
918
- ...buildClientOptions,
919
- config: rootConfig,
920
- dist: `${distDir}/${clientDir}`,
921
- stats
922
- });
923
- process.exit(0);
924
- }
925
- if (buildMode === "server") {
926
- if (entry) {
927
- let clientBuilt = false;
928
- try {
929
- await readFile(`${distDir}/${clientDir}/index.html`, "utf-8");
930
- clientBuilt = true;
931
- } catch {}
932
- await buildServer({
933
- config: { base: rootConfig.base || "" },
934
- entry,
935
- distDir,
936
- clientDir: clientBuilt ? clientDir : void 0,
937
- stats
938
- });
939
- }
940
- process.exit(0);
941
- }
942
- if (hasClient) await buildClient({
943
- ...buildClientOptions,
944
- config: rootConfig,
945
- dist: `${distDir}/${clientDir}`,
946
- stats
947
- });
948
- let template = "";
949
- if (hasClient) template = await readFile(`${distDir}/${clientDir}/index.html`, "utf-8");
950
- if (entry) {
951
- await buildServer({
952
- config: { base: rootConfig.base || "" },
953
- entry,
954
- distDir,
955
- clientDir: hasClient ? clientDir : void 0,
956
- stats
957
- });
958
- if (hasClient && options.serverEntry !== false) await unlink(`${distDir}/${clientDir}/index.html`);
959
- await copyAssets({
960
- entry: `${distDir}/index.js`,
961
- distDir
962
- });
963
- }
964
- if (buildClientOptions.sitemap && entry) await writeFile(`${distDir}/${clientDir}/sitemap.xml`, await generateSitemap({
965
- entry: `${distDir}/index.js`,
966
- baseUrl: buildClientOptions.sitemap.hostname
967
- }));
968
- if (buildClientOptions.prerender && template) await prerenderPages({
969
- dist: `${distDir}/${clientDir}`,
970
- entry: `${distDir}/index.js`,
971
- compress: buildClientOptions.precompress
972
- });
973
- if (options.vercel) await generateVercel({
974
- distDir,
975
- clientDir,
976
- config: typeof options.vercel === "boolean" ? {} : options.vercel
977
- });
978
- if (options.cloudflare) await generateCloudflare({
979
- distDir,
980
- config: typeof options.cloudflare === "boolean" ? {} : options.cloudflare
981
- });
982
- if (options.docker) await generateDocker({
983
- distDir,
984
- ...typeof options.docker === "boolean" ? {} : options.docker
985
- });
986
- process.exit(0);
987
- }
988
- };
989
- }
990
-
991
- //#endregion
992
- //#region ../../src/vite/plugins/viteAlephaDev.ts
993
- /**
994
- * Plug Alepha into Vite development server.
995
- *
996
- * This plugin manages the Alepha application lifecycle during development,
997
- * handling hot module replacement and request forwarding.
998
- */
999
- async function viteAlephaDev(options = {}) {
1000
- let entry = options.serverEntry;
1001
- if (!entry) {
1002
- entry = await boot.getServerEntry();
1003
- if (!entry) return {
1004
- name: "alepha-dev",
1005
- apply: "serve",
1006
- config() {}
1007
- };
1008
- }
1009
- const runner = createAlephaRunner({
1010
- entry,
1011
- debug: options.debug
1012
- });
1013
- return {
1014
- name: "alepha-dev",
1015
- apply: "serve",
1016
- configResolved(resolvedConfig) {
1017
- runner.setConfig(resolvedConfig);
1018
- },
1019
- async handleHotUpdate(ctx) {
1020
- if (options.debug) console.log("[DEBUG] HMR", ctx.file);
1021
- if (ctx.file.includes("/.idea/")) return [];
1022
- const isServerOnly = !ctx.modules[0]?._clientModule;
1023
- const isBrowserOnly = !ctx.modules[0]?._ssrModule;
1024
- const isSsrEnabled = runner.isSsrEnabled();
1025
- if (isBrowserOnly) {
1026
- if (options.debug) console.log("[DEBUG] HMR - browser only - no reason to reload server");
1027
- return;
1028
- }
1029
- const root = process.cwd().replace(/\\/g, "/");
1030
- const invalidate = !ctx.file.startsWith(root);
1031
- if (invalidate && options.debug) console.log("[DEBUG] HMR - outside root - invalidate all");
1032
- if (!isSsrEnabled && isServerOnly) {
1033
- await runner.restart(ctx.server, invalidate);
1034
- return [];
1035
- }
1036
- if (isSsrEnabled && ctx.modules[0]) {
1037
- if (await runner.restart(ctx.server, invalidate)) return [];
1038
- if (!runner.isStarted) {
1039
- if (options.debug) console.log("[DEBUG] HMR - abort due to app not started");
1040
- return [];
1041
- }
1042
- if (isServerOnly && runner.isStarted) {
1043
- runner.sendReload(ctx.server);
1044
- return [];
1045
- }
1046
- }
1047
- },
1048
- async configureServer(server) {
1049
- const middleware = (req, res, next) => {
1050
- if (runner.isStarted && runner.app && req.url && !isViteInternalPath(req.url)) {
1051
- let ended = false;
1052
- const writeHead = res.writeHead.bind(res);
1053
- res.writeHead = (...args) => {
1054
- ended = true;
1055
- return writeHead(args[0], args[1], args[2]);
1056
- };
1057
- return runner.app.events.emit("node:request", {
1058
- req,
1059
- res
1060
- }).then(() => {
1061
- if (!ended) next();
1062
- });
1063
- }
1064
- next();
1065
- };
1066
- server.middlewares.use((req, res, next) => {
1067
- middleware(req, res, next);
1068
- });
1069
- server.config.logger.info = (msg) => {
1070
- console.log(msg);
1071
- };
1072
- server.config.logger.clearScreen = () => {};
1073
- return () => {
1074
- server.httpServer?.once("listening", () => {
1075
- runner.start(server);
1076
- });
1077
- };
1078
- },
1079
- async closeBundle() {}
1080
- };
1081
- }
1082
-
1083
- //#endregion
1084
- //#region ../../src/vite/plugins/viteAlepha.ts
1085
- function viteAlepha(options = {}) {
1086
- if (process.env.NODE_ENV === "test") return [];
1087
- const plugins = [];
1088
- if (options.react !== false) try {
1089
- const { default: viteReact } = createRequire(import.meta.url)("@vitejs/plugin-react");
1090
- plugins.push(viteReact());
1091
- } catch (e) {}
1092
- plugins.push(viteAlephaDev(options), viteAlephaBuild(options));
1093
- plugins[OPTIONS] = options;
1094
- return plugins;
1095
- }
1096
-
1097
- //#endregion
1098
- //#region ../../src/vite/index.ts
1099
- /**
1100
- * Plugin vite for Alepha framework.
1101
- *
1102
- * This module provides Vite plugins and configurations to integrate Alepha applications with Vite's build and development processes.
1103
- *
1104
- * @example
1105
- * ```ts
1106
- * import { defineConfig } from "vite";
1107
- * import { viteAlepha } from "alepha/vite";
1108
- *
1109
- * export default defineConfig({
1110
- * plugins: [viteAlepha()],
1111
- * // other Vite configurations...
1112
- * });
1113
- * ```
1114
- *
1115
- * @module alepha.vite
1116
- */
1117
-
1118
- //#endregion
1119
- export { AlephaRunner, boot, buildClient, buildServer, compressFile, copyAssets, createAlephaRunner, createBufferedLogger, generateCloudflare, generateDocker, generateExternals, generateSitemap, generateVercel, isViteInternalPath, prerenderPages, viteAlepha, viteAlephaBuild, viteAlephaDev, viteCompress };
1205
+ export { AlephaRunner, boot, buildClient, buildServer, compressFile, copyAssets, createAlephaRunner, createBufferedLogger, devServer, generateCloudflare, generateDocker, generateExternals, generateSitemap, generateVercel, isViteInternalPath, prerenderPages, viteAlephaDev, viteAlephaSsrPreload, viteCompress };
1120
1206
  //# sourceMappingURL=index.js.map