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
@@ -80,10 +80,6 @@ export class ServerSwaggerProvider {
80
80
  }
81
81
 
82
82
  this.json = await this.setupSwaggerPlugin(options);
83
-
84
- if (this.json) {
85
- this.log.info("Swagger documentation generated successfully.");
86
- }
87
83
  },
88
84
  });
89
85
 
@@ -115,6 +111,8 @@ export class ServerSwaggerProvider {
115
111
 
116
112
  if (options.ui !== false) {
117
113
  await this.configureSwaggerUi(prefix, options);
114
+ } else {
115
+ this.log.info(`Swagger API available at ${prefix}/json`);
118
116
  }
119
117
 
120
118
  return json;
@@ -362,7 +360,6 @@ export class ServerSwaggerProvider {
362
360
  },
363
361
  handler: () => json,
364
362
  });
365
- this.log.info(`Swagger API available at ${prefix}/json`);
366
363
  }
367
364
 
368
365
  protected async configureSwaggerUi(
@@ -428,9 +425,9 @@ window.onload = function() {
428
425
  },
429
426
  });
430
427
 
431
- this.log.info(
432
- `Swagger UI available at ${this.serverProvider.hostname}${prefix}/`,
433
- );
428
+ this.log.info("SwaggerUI OK", {
429
+ url: `${this.serverProvider.hostname}${prefix}`,
430
+ });
434
431
  }
435
432
 
436
433
  protected async getAssetPath(
@@ -1,117 +1,102 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
1
+ import { Alepha } from "alepha";
2
+ import { FileSystemProvider, MemoryFileSystemProvider } from "alepha/file";
3
3
  import { beforeEach, describe, expect, test, vi } from "vitest";
4
4
  import { SmsError } from "../errors/SmsError.ts";
5
- import { LocalSmsProvider } from "../providers/LocalSmsProvider.ts";
5
+ import { LocalSmsProvider } from "./LocalSmsProvider.ts";
6
6
 
7
- // Mock fs and path modules
8
- vi.mock("node:fs/promises");
9
- vi.mock("node:path");
10
-
11
- // Mock logger
12
- vi.mock("alepha/logger", () => ({
13
- $logger: () => ({
14
- debug: vi.fn(),
15
- info: vi.fn(),
16
- error: vi.fn(),
17
- }),
18
- }));
19
-
20
- const mockedFs = vi.mocked(fs);
21
- const mockedPath = vi.mocked(path);
7
+ // ---------------------------------------------------------------------------------------------------------------------
22
8
 
23
9
  describe("LocalSmsProvider", () => {
24
- let provider: LocalSmsProvider;
25
-
26
- beforeEach(() => {
27
- vi.clearAllMocks();
28
- // Setup default path.join mock
29
- mockedPath.join.mockImplementation((...args) => args.join("/"));
30
- });
31
-
32
10
  describe("send", () => {
33
- beforeEach(() => {
34
- provider = new LocalSmsProvider({ directory: "test-sms" });
35
- });
36
-
37
11
  test("should successfully send SMS to local file", async () => {
38
- mockedFs.mkdir.mockResolvedValue(undefined);
39
- mockedFs.writeFile.mockResolvedValue();
12
+ const alepha = Alepha.create().with({
13
+ provide: FileSystemProvider,
14
+ use: MemoryFileSystemProvider,
15
+ });
40
16
 
41
- const to = "+1234567890";
42
- const message = "Test message";
17
+ const provider = alepha.inject(LocalSmsProvider);
18
+ const memoryFs = alepha.inject(MemoryFileSystemProvider);
19
+ await alepha.start();
43
20
 
44
21
  await provider.send({
45
- to,
46
- message,
22
+ to: "+1234567890",
23
+ message: "Test message",
47
24
  });
48
25
 
49
- expect(mockedFs.mkdir).toHaveBeenCalledWith("test-sms", {
50
- recursive: true,
51
- });
52
- expect(mockedFs.writeFile).toHaveBeenCalledWith(
53
- expect.stringContaining("+1234567890"),
54
- expect.stringContaining(message),
55
- "utf8",
56
- );
26
+ expect(memoryFs.mkdirCalls).toHaveLength(1);
27
+ expect(memoryFs.mkdirCalls[0].path).toBe("node_modules/.alepha/sms");
28
+ expect(memoryFs.mkdirCalls[0].options).toEqual({ recursive: true });
29
+
30
+ expect(memoryFs.writeFileCalls).toHaveLength(1);
31
+ expect(memoryFs.writeFileCalls[0].path).toContain("+1234567890");
32
+ expect(memoryFs.writeFileCalls[0].data).toContain("Test message");
57
33
  });
58
34
 
59
35
  test("should create proper filename with sanitized phone and timestamp", async () => {
60
- mockedFs.mkdir.mockResolvedValue(undefined);
61
- mockedFs.writeFile.mockResolvedValue();
36
+ const alepha = Alepha.create().with({
37
+ provide: FileSystemProvider,
38
+ use: MemoryFileSystemProvider,
39
+ });
62
40
 
63
- const to = "+1 (234) 567-8900";
64
- const message = "Test message";
41
+ const provider = alepha.inject(LocalSmsProvider);
42
+ const memoryFs = alepha.inject(MemoryFileSystemProvider);
43
+ await alepha.start();
65
44
 
66
45
  // Mock Date to have predictable timestamp
67
46
  const mockDate = new Date("2023-01-01T12:00:00.000Z");
68
47
  vi.setSystemTime(mockDate);
69
48
 
70
49
  await provider.send({
71
- to,
72
- message,
50
+ to: "+1 (234) 567-8900",
51
+ message: "Test message",
73
52
  });
74
53
 
75
- expect(mockedPath.join).toHaveBeenCalledWith(
76
- "test-sms",
54
+ expect(memoryFs.joinCalls).toHaveLength(1);
55
+ expect(memoryFs.joinCalls[0]).toEqual([
56
+ "node_modules/.alepha/sms",
77
57
  "+1__234__567_8900+2023-01-01T12-00-00-000Z.txt",
78
- );
58
+ ]);
79
59
 
80
60
  vi.useRealTimers();
81
61
  });
82
62
 
83
63
  test("should sanitize special characters in phone number", async () => {
84
- mockedFs.mkdir.mockResolvedValue(undefined);
85
- mockedFs.writeFile.mockResolvedValue();
64
+ const alepha = Alepha.create().with({
65
+ provide: FileSystemProvider,
66
+ use: MemoryFileSystemProvider,
67
+ });
86
68
 
87
- const to = "+1-234-567-8900 ext. 123";
88
- const message = "Test message";
69
+ const provider = alepha.inject(LocalSmsProvider);
70
+ const memoryFs = alepha.inject(MemoryFileSystemProvider);
71
+ await alepha.start();
89
72
 
90
73
  await provider.send({
91
- to,
92
- message,
74
+ to: "+1-234-567-8900 ext. 123",
75
+ message: "Test message",
93
76
  });
94
77
 
95
- expect(mockedPath.join).toHaveBeenCalledWith(
96
- "test-sms",
97
- expect.stringMatching(/\+1_234_567_8900______123\+.+\.txt/),
78
+ expect(memoryFs.joinCalls).toHaveLength(1);
79
+ expect(memoryFs.joinCalls[0][1]).toMatch(
80
+ /\+1_234_567_8900______123\+.+\.txt/,
98
81
  );
99
82
  });
100
83
 
101
84
  test("should create proper text content", async () => {
102
- mockedFs.mkdir.mockResolvedValue(undefined);
103
- mockedFs.writeFile.mockResolvedValue();
85
+ const alepha = Alepha.create().with({
86
+ provide: FileSystemProvider,
87
+ use: MemoryFileSystemProvider,
88
+ });
104
89
 
105
- const to = "+1234567890";
106
- const message = "Test message with content";
90
+ const provider = alepha.inject(LocalSmsProvider);
91
+ const memoryFs = alepha.inject(MemoryFileSystemProvider);
92
+ await alepha.start();
107
93
 
108
94
  await provider.send({
109
- to,
110
- message,
95
+ to: "+1234567890",
96
+ message: "Test message with content",
111
97
  });
112
98
 
113
- const writeCall = mockedFs.writeFile.mock.calls[0];
114
- const textContent = writeCall[1] as string;
99
+ const textContent = memoryFs.writeFileCalls[0].data;
115
100
 
116
101
  expect(textContent).toContain("SMS Message");
117
102
  expect(textContent).toContain("+1234567890");
@@ -120,85 +105,145 @@ describe("LocalSmsProvider", () => {
120
105
  });
121
106
 
122
107
  test("should throw SmsError when mkdir fails", async () => {
123
- const mkdirError = new Error("Permission denied");
124
- mockedFs.mkdir.mockRejectedValue(mkdirError);
108
+ const alepha = Alepha.create().with({
109
+ provide: FileSystemProvider,
110
+ use: MemoryFileSystemProvider,
111
+ });
112
+
113
+ const provider = alepha.inject(LocalSmsProvider);
114
+ const memoryFs = alepha.inject(MemoryFileSystemProvider);
115
+ await alepha.start();
125
116
 
126
- const to = "+1234567890";
127
- const message = "Test message";
117
+ memoryFs.mkdirError = new Error("Permission denied");
128
118
 
129
119
  await expect(
130
120
  provider.send({
131
- to,
132
- message,
121
+ to: "+1234567890",
122
+ message: "Test message",
133
123
  }),
134
124
  ).rejects.toThrow(SmsError);
125
+
135
126
  await expect(
136
127
  provider.send({
137
- to,
138
- message,
128
+ to: "+1234567890",
129
+ message: "Test message",
139
130
  }),
140
131
  ).rejects.toThrow("Failed to save SMS to local file: Permission denied");
141
132
  });
142
133
 
143
134
  test("should throw SmsError when writeFile fails", async () => {
144
- mockedFs.mkdir.mockResolvedValue(undefined);
145
- const writeError = new Error("Disk full");
146
- mockedFs.writeFile.mockRejectedValue(writeError);
135
+ const alepha = Alepha.create().with({
136
+ provide: FileSystemProvider,
137
+ use: MemoryFileSystemProvider,
138
+ });
139
+
140
+ const provider = alepha.inject(LocalSmsProvider);
141
+ const memoryFs = alepha.inject(MemoryFileSystemProvider);
142
+ await alepha.start();
147
143
 
148
- const to = "+1234567890";
149
- const message = "Test message";
144
+ memoryFs.writeFileError = new Error("Disk full");
150
145
 
151
146
  await expect(
152
147
  provider.send({
153
- to,
154
- message,
148
+ to: "+1234567890",
149
+ message: "Test message",
155
150
  }),
156
151
  ).rejects.toThrow(SmsError);
152
+
157
153
  await expect(
158
154
  provider.send({
159
- to,
160
- message,
155
+ to: "+1234567890",
156
+ message: "Test message",
161
157
  }),
162
158
  ).rejects.toThrow("Failed to save SMS to local file: Disk full");
163
159
  });
164
160
 
165
161
  test("should handle non-Error exceptions", async () => {
166
- mockedFs.mkdir.mockResolvedValue(undefined);
167
- mockedFs.writeFile.mockRejectedValue("String error");
162
+ const alepha = Alepha.create().with({
163
+ provide: FileSystemProvider,
164
+ use: MemoryFileSystemProvider,
165
+ });
166
+
167
+ const provider = alepha.inject(LocalSmsProvider);
168
+ const memoryFs = alepha.inject(MemoryFileSystemProvider);
169
+ await alepha.start();
168
170
 
169
- const to = "+1234567890";
170
- const message = "Test message";
171
+ // Simulate non-Error throw
172
+ memoryFs.writeFileError = "String error" as unknown as Error;
171
173
 
172
174
  await expect(
173
175
  provider.send({
174
- to,
175
- message,
176
+ to: "+1234567890",
177
+ message: "Test message",
176
178
  }),
177
179
  ).rejects.toThrow(SmsError);
178
- await expect(
179
- provider.send({
180
- to,
181
- message,
182
- }),
183
- ).rejects.toThrow("Failed to save SMS to local file: String error");
180
+ });
181
+
182
+ test("should handle multiple recipients", async () => {
183
+ const alepha = Alepha.create().with({
184
+ provide: FileSystemProvider,
185
+ use: MemoryFileSystemProvider,
186
+ });
187
+
188
+ const provider = alepha.inject(LocalSmsProvider);
189
+ const memoryFs = alepha.inject(MemoryFileSystemProvider);
190
+ await alepha.start();
191
+
192
+ await provider.send({
193
+ to: ["+1111111111", "+2222222222"],
194
+ message: "Broadcast message",
195
+ });
196
+
197
+ expect(memoryFs.writeFileCalls).toHaveLength(2);
198
+ expect(memoryFs.writeFileCalls[0].path).toContain("+1111111111");
199
+ expect(memoryFs.writeFileCalls[1].path).toContain("+2222222222");
200
+ });
201
+
202
+ test("should use custom directory when provided", async () => {
203
+ const alepha = Alepha.create().with({
204
+ provide: FileSystemProvider,
205
+ use: MemoryFileSystemProvider,
206
+ });
207
+
208
+ class CustomLocalSmsProvider extends LocalSmsProvider {
209
+ constructor() {
210
+ super({ directory: "custom-sms-dir" });
211
+ }
212
+ }
213
+
214
+ const provider = alepha.inject(CustomLocalSmsProvider);
215
+ const memoryFs = alepha.inject(MemoryFileSystemProvider);
216
+ await alepha.start();
217
+
218
+ await provider.send({
219
+ to: "+1234567890",
220
+ message: "Test",
221
+ });
222
+
223
+ expect(memoryFs.mkdirCalls[0].path).toBe("custom-sms-dir");
224
+ expect(memoryFs.joinCalls[0][0]).toBe("custom-sms-dir");
184
225
  });
185
226
  });
186
227
 
187
228
  describe("createSmsText", () => {
188
- beforeEach(() => {
189
- provider = new LocalSmsProvider();
229
+ let provider: LocalSmsProvider;
230
+
231
+ beforeEach(async () => {
232
+ const alepha = Alepha.create().with({
233
+ provide: FileSystemProvider,
234
+ use: MemoryFileSystemProvider,
235
+ });
236
+ provider = alepha.inject(LocalSmsProvider);
237
+ await alepha.start();
190
238
  });
191
239
 
192
240
  test("should create proper text structure", () => {
193
241
  const mockDate = new Date("2023-01-01T12:00:00.000Z");
194
242
  vi.setSystemTime(mockDate);
195
243
 
196
- const to = "+1234567890";
197
- const message = "Test message";
198
-
199
244
  const text = provider.createSmsText({
200
- to,
201
- message,
245
+ to: "+1234567890",
246
+ message: "Test message",
202
247
  });
203
248
 
204
249
  expect(text).toContain("SMS Message");
@@ -210,12 +255,9 @@ describe("LocalSmsProvider", () => {
210
255
  });
211
256
 
212
257
  test("should handle multiline messages", () => {
213
- const to = "+1234567890";
214
- const message = "Line 1\nLine 2\nLine 3";
215
-
216
258
  const text = provider.createSmsText({
217
- to,
218
- message,
259
+ to: "+1234567890",
260
+ message: "Line 1\nLine 2\nLine 3",
219
261
  });
220
262
 
221
263
  expect(text).toContain("Line 1\nLine 2\nLine 3");
@@ -1,5 +1,5 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
1
+ import { $inject } from "alepha";
2
+ import { FileSystemProvider } from "alepha/file";
3
3
  import { $logger } from "alepha/logger";
4
4
  import { SmsError } from "../errors/SmsError.ts";
5
5
  import type { SmsProvider, SmsSendOptions } from "./SmsProvider.ts";
@@ -7,17 +7,18 @@ import type { SmsProvider, SmsSendOptions } from "./SmsProvider.ts";
7
7
  export interface LocalSmsProviderOptions {
8
8
  /**
9
9
  * Directory to save SMS files.
10
- * @default "node_modules/.sms" (relative to project root)
10
+ * @default "node_modules/.alepha/sms" (relative to project root)
11
11
  */
12
12
  directory?: string;
13
13
  }
14
14
 
15
15
  export class LocalSmsProvider implements SmsProvider {
16
16
  protected readonly log = $logger();
17
+ protected readonly fs = $inject(FileSystemProvider);
17
18
  protected readonly directory: string;
18
19
 
19
20
  constructor(options: LocalSmsProviderOptions = {}) {
20
- this.directory = options.directory ?? "node_modules/.sms";
21
+ this.directory = options.directory ?? "node_modules/.alepha/sms";
21
22
  }
22
23
 
23
24
  public async send(options: SmsSendOptions): Promise<void> {
@@ -31,14 +32,14 @@ export class LocalSmsProvider implements SmsProvider {
31
32
 
32
33
  try {
33
34
  // Ensure directory exists
34
- await fs.mkdir(this.directory, { recursive: true });
35
+ await this.fs.mkdir(this.directory, { recursive: true });
35
36
 
36
37
  // Create filename: phone+date
37
38
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
38
39
  for (const recipient of Array.isArray(to) ? to : [to]) {
39
40
  const sanitizedPhone = recipient.replace(/[^0-9+]/g, "_");
40
41
  const filename = `${sanitizedPhone}+${timestamp}.txt`;
41
- const filepath = path.join(this.directory, filename);
42
+ const filepath = this.fs.join(this.directory, filename);
42
43
 
43
44
  // Create text content
44
45
  const textContent = this.createSmsText({
@@ -47,7 +48,7 @@ export class LocalSmsProvider implements SmsProvider {
47
48
  });
48
49
 
49
50
  // Write to file
50
- await fs.writeFile(filepath, textContent, "utf8");
51
+ await this.fs.writeFile(filepath, textContent);
51
52
 
52
53
  this.log.info("SMS saved to local file", { filepath, to });
53
54
  }
@@ -1,4 +1,4 @@
1
- import { access, readFile } from "node:fs/promises";
1
+ import { access, readdir, readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { AlephaError } from "alepha";
4
4
 
@@ -8,6 +8,17 @@ import { AlephaError } from "alepha";
8
8
  * For avoiding cli -> vite, all code moved here.
9
9
  */
10
10
 
11
+ /**
12
+ * Server entry files in priority order.
13
+ * main.server.ts is preferred over main.ts for consistency.
14
+ */
15
+ const SERVER_ENTRIES = [
16
+ "main.server.ts",
17
+ "main.server.tsx",
18
+ "main.ts",
19
+ "main.tsx",
20
+ ] as const;
21
+
11
22
  /**
12
23
  * Find browser/client entry file path.
13
24
  */
@@ -25,6 +36,8 @@ const getClientEntry = async (
25
36
 
26
37
  /**
27
38
  * Find server entry file path.
39
+ *
40
+ * Optimized to use a single readdir() call instead of multiple access() calls.
28
41
  */
29
42
  const getServerEntry = async (
30
43
  root = process.cwd(),
@@ -42,32 +55,30 @@ const getServerEntry = async (
42
55
  }
43
56
  }
44
57
 
45
- const maybeEntry = [
46
- "src/main.server.ts",
47
- "src/server-entry.ts",
48
- "src/main.server.tsx",
49
- "src/server-entry.tsx",
50
- "src/main.ts",
51
- "src/main.tsx",
52
- ];
58
+ // Single IO: read src/ directory listing
59
+ const srcDir = join(root, "src");
60
+ try {
61
+ const files = new Set(await readdir(srcDir));
53
62
 
54
- for (const entry of maybeEntry) {
55
- try {
56
- const path = join(root, entry).replace(/\\/g, "/");
57
- await access(path);
58
- return path;
59
- } catch {
60
- // continue to next entry
63
+ // Find first matching entry in priority order
64
+ for (const entry of SERVER_ENTRIES) {
65
+ if (files.has(entry)) {
66
+ return join(srcDir, entry).replace(/\\/g, "/");
67
+ }
61
68
  }
69
+ } catch {
70
+ // src/ directory doesn't exist, fall through to client entry
62
71
  }
63
72
 
73
+ // Fallback: try client entry from index.html
64
74
  const clientEntry = await getClientEntry(root);
65
75
  if (clientEntry) {
66
76
  return clientEntry;
67
77
  }
68
78
 
79
+ const fullPaths = SERVER_ENTRIES.map((e) => `src/${e}`);
69
80
  throw new AlephaError(
70
- `Could not find a server entry file. List of supported entry file: ${maybeEntry.join(", ")}`,
81
+ `Could not find a server entry file. Supported entries: ${fullPaths.join(", ")}`,
71
82
  );
72
83
  };
73
84
 
@@ -0,0 +1,13 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ export const importViteReact = async (): Promise<any> => {
4
+ // Add React plugin for JSX/TSX compilation
5
+ try {
6
+ const { default: viteReact } = createRequire(import.meta.url)(
7
+ "@vitejs/plugin-react",
8
+ );
9
+ return viteReact;
10
+ } catch {
11
+ // @vitejs/plugin-react not installed, skip
12
+ }
13
+ };
package/src/vite/index.ts CHANGED
@@ -4,9 +4,8 @@ import type { Alepha } from "alepha";
4
4
  export * from "./helpers/boot.ts";
5
5
  export * from "./helpers/createBufferedLogger.ts";
6
6
  // Plugins (public API)
7
- export * from "./plugins/viteAlepha.ts";
8
- export * from "./plugins/viteAlephaBuild.ts";
9
7
  export * from "./plugins/viteAlephaDev.ts";
8
+ export * from "./plugins/viteAlephaSsrPreload.ts";
10
9
  export * from "./plugins/viteCompress.ts";
11
10
  // Tasks (for CLI integration)
12
11
  export * from "./tasks/index.ts";
@@ -14,22 +13,3 @@ export * from "./tasks/index.ts";
14
13
  declare global {
15
14
  var __cli_alepha: Alepha;
16
15
  }
17
-
18
- /**
19
- * Plugin vite for Alepha framework.
20
- *
21
- * This module provides Vite plugins and configurations to integrate Alepha applications with Vite's build and development processes.
22
- *
23
- * @example
24
- * ```ts
25
- * import { defineConfig } from "vite";
26
- * import { viteAlepha } from "alepha/vite";
27
- *
28
- * export default defineConfig({
29
- * plugins: [viteAlepha()],
30
- * // other Vite configurations...
31
- * });
32
- * ```
33
- *
34
- * @module alepha.vite
35
- */
@@ -1,6 +1,7 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
- import type { Plugin, ResolvedConfig } from "vite";
2
+ import type { Plugin, ResolvedConfig, UserConfig } from "vite";
3
3
  import { boot } from "../helpers/boot.ts";
4
+ import { importVite } from "../helpers/importVite.ts";
4
5
  import { createAlephaRunner, isViteInternalPath } from "../tasks/runAlepha.ts";
5
6
 
6
7
  export interface ViteAlephaDevOptions {
@@ -44,9 +45,20 @@ export async function viteAlephaDev(
44
45
  debug: options.debug,
45
46
  });
46
47
 
48
+ const { loadEnv } = await importVite();
49
+ const env = loadEnv("development", process.cwd(), "SERVER");
50
+
51
+ const config: UserConfig = {};
52
+ if (env.SERVER_PORT) {
53
+ config.server = {
54
+ port: parseInt(env.SERVER_PORT, 10),
55
+ };
56
+ }
57
+
47
58
  return {
48
59
  name: "alepha-dev",
49
60
  apply: "serve",
61
+ config: () => config,
50
62
  configResolved(resolvedConfig: ResolvedConfig) {
51
63
  runner.setConfig(resolvedConfig);
52
64
  },
@@ -103,6 +115,9 @@ export async function viteAlephaDev(
103
115
  }
104
116
  },
105
117
  async configureServer(server) {
118
+ if (env.SERVER_PORT) {
119
+ server.config.server.port = parseInt(env.SERVER_PORT, 10);
120
+ }
106
121
  const middleware = (
107
122
  req: IncomingMessage,
108
123
  res: ServerResponse,