alepha 0.14.4 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/README.md +44 -102
  2. package/dist/api/audits/index.d.ts +331 -443
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js +2 -2
  5. package/dist/api/audits/index.js.map +1 -1
  6. package/dist/api/files/index.d.ts +0 -113
  7. package/dist/api/files/index.d.ts.map +1 -1
  8. package/dist/api/files/index.js +2 -3
  9. package/dist/api/files/index.js.map +1 -1
  10. package/dist/api/jobs/index.d.ts +151 -262
  11. package/dist/api/jobs/index.d.ts.map +1 -1
  12. package/dist/api/notifications/index.browser.js +4 -4
  13. package/dist/api/notifications/index.browser.js.map +1 -1
  14. package/dist/api/notifications/index.d.ts +164 -276
  15. package/dist/api/notifications/index.d.ts.map +1 -1
  16. package/dist/api/notifications/index.js +4 -4
  17. package/dist/api/notifications/index.js.map +1 -1
  18. package/dist/api/parameters/index.d.ts +265 -377
  19. package/dist/api/parameters/index.d.ts.map +1 -1
  20. package/dist/api/users/index.browser.js +1 -2
  21. package/dist/api/users/index.browser.js.map +1 -1
  22. package/dist/api/users/index.d.ts +195 -301
  23. package/dist/api/users/index.d.ts.map +1 -1
  24. package/dist/api/users/index.js +203 -184
  25. package/dist/api/users/index.js.map +1 -1
  26. package/dist/api/verifications/index.d.ts.map +1 -1
  27. package/dist/batch/index.d.ts.map +1 -1
  28. package/dist/batch/index.js +1 -2
  29. package/dist/batch/index.js.map +1 -1
  30. package/dist/bucket/index.d.ts.map +1 -1
  31. package/dist/cache/core/index.d.ts.map +1 -1
  32. package/dist/cache/redis/index.d.ts.map +1 -1
  33. package/dist/cache/redis/index.js +2 -2
  34. package/dist/cache/redis/index.js.map +1 -1
  35. package/dist/cli/index.d.ts +5900 -165
  36. package/dist/cli/index.d.ts.map +1 -1
  37. package/dist/cli/index.js +1481 -639
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/command/index.d.ts +8 -4
  40. package/dist/command/index.d.ts.map +1 -1
  41. package/dist/command/index.js +29 -25
  42. package/dist/command/index.js.map +1 -1
  43. package/dist/core/index.browser.js +563 -54
  44. package/dist/core/index.browser.js.map +1 -1
  45. package/dist/core/index.d.ts +175 -8
  46. package/dist/core/index.d.ts.map +1 -1
  47. package/dist/core/index.js +564 -54
  48. package/dist/core/index.js.map +1 -1
  49. package/dist/core/index.native.js +563 -54
  50. package/dist/core/index.native.js.map +1 -1
  51. package/dist/datetime/index.d.ts.map +1 -1
  52. package/dist/datetime/index.js +4 -4
  53. package/dist/datetime/index.js.map +1 -1
  54. package/dist/email/index.d.ts +89 -42
  55. package/dist/email/index.d.ts.map +1 -1
  56. package/dist/email/index.js +129 -33
  57. package/dist/email/index.js.map +1 -1
  58. package/dist/fake/index.d.ts +7969 -2
  59. package/dist/fake/index.d.ts.map +1 -1
  60. package/dist/fake/index.js +22 -22
  61. package/dist/fake/index.js.map +1 -1
  62. package/dist/file/index.d.ts +134 -1
  63. package/dist/file/index.d.ts.map +1 -1
  64. package/dist/file/index.js +253 -1
  65. package/dist/file/index.js.map +1 -1
  66. package/dist/lock/core/index.d.ts.map +1 -1
  67. package/dist/lock/redis/index.d.ts.map +1 -1
  68. package/dist/logger/index.d.ts +1 -2
  69. package/dist/logger/index.d.ts.map +1 -1
  70. package/dist/logger/index.js +1 -5
  71. package/dist/logger/index.js.map +1 -1
  72. package/dist/mcp/index.d.ts +19 -1
  73. package/dist/mcp/index.d.ts.map +1 -1
  74. package/dist/mcp/index.js +28 -4
  75. package/dist/mcp/index.js.map +1 -1
  76. package/dist/orm/chunk-DH6iiROE.js +38 -0
  77. package/dist/orm/index.browser.js +9 -9
  78. package/dist/orm/index.browser.js.map +1 -1
  79. package/dist/orm/index.bun.js +2821 -0
  80. package/dist/orm/index.bun.js.map +1 -0
  81. package/dist/orm/index.d.ts +318 -169
  82. package/dist/orm/index.d.ts.map +1 -1
  83. package/dist/orm/index.js +2086 -1776
  84. package/dist/orm/index.js.map +1 -1
  85. package/dist/queue/core/index.d.ts +4 -4
  86. package/dist/queue/core/index.d.ts.map +1 -1
  87. package/dist/queue/redis/index.d.ts.map +1 -1
  88. package/dist/redis/index.bun.js +285 -0
  89. package/dist/redis/index.bun.js.map +1 -0
  90. package/dist/redis/index.d.ts +13 -31
  91. package/dist/redis/index.d.ts.map +1 -1
  92. package/dist/redis/index.js +18 -38
  93. package/dist/redis/index.js.map +1 -1
  94. package/dist/retry/index.d.ts.map +1 -1
  95. package/dist/router/index.d.ts.map +1 -1
  96. package/dist/scheduler/index.d.ts +83 -1
  97. package/dist/scheduler/index.d.ts.map +1 -1
  98. package/dist/scheduler/index.js +393 -1
  99. package/dist/scheduler/index.js.map +1 -1
  100. package/dist/security/index.browser.js +5 -1
  101. package/dist/security/index.browser.js.map +1 -1
  102. package/dist/security/index.d.ts +598 -112
  103. package/dist/security/index.d.ts.map +1 -1
  104. package/dist/security/index.js +1808 -97
  105. package/dist/security/index.js.map +1 -1
  106. package/dist/server/auth/index.d.ts +1200 -175
  107. package/dist/server/auth/index.d.ts.map +1 -1
  108. package/dist/server/auth/index.js +1268 -37
  109. package/dist/server/auth/index.js.map +1 -1
  110. package/dist/server/cache/index.d.ts +6 -3
  111. package/dist/server/cache/index.d.ts.map +1 -1
  112. package/dist/server/cache/index.js +1 -1
  113. package/dist/server/cache/index.js.map +1 -1
  114. package/dist/server/compress/index.d.ts.map +1 -1
  115. package/dist/server/cookies/index.d.ts.map +1 -1
  116. package/dist/server/cookies/index.js +3 -3
  117. package/dist/server/cookies/index.js.map +1 -1
  118. package/dist/server/core/index.d.ts +115 -13
  119. package/dist/server/core/index.d.ts.map +1 -1
  120. package/dist/server/core/index.js +321 -139
  121. package/dist/server/core/index.js.map +1 -1
  122. package/dist/server/cors/index.d.ts +0 -1
  123. package/dist/server/cors/index.d.ts.map +1 -1
  124. package/dist/server/health/index.d.ts +0 -1
  125. package/dist/server/health/index.d.ts.map +1 -1
  126. package/dist/server/helmet/index.d.ts.map +1 -1
  127. package/dist/server/links/index.browser.js +9 -1
  128. package/dist/server/links/index.browser.js.map +1 -1
  129. package/dist/server/links/index.d.ts +1 -2
  130. package/dist/server/links/index.d.ts.map +1 -1
  131. package/dist/server/links/index.js +14 -7
  132. package/dist/server/links/index.js.map +1 -1
  133. package/dist/server/metrics/index.d.ts +514 -1
  134. package/dist/server/metrics/index.d.ts.map +1 -1
  135. package/dist/server/metrics/index.js +4462 -4
  136. package/dist/server/metrics/index.js.map +1 -1
  137. package/dist/server/multipart/index.d.ts.map +1 -1
  138. package/dist/server/proxy/index.d.ts +0 -1
  139. package/dist/server/proxy/index.d.ts.map +1 -1
  140. package/dist/server/rate-limit/index.d.ts.map +1 -1
  141. package/dist/server/static/index.d.ts.map +1 -1
  142. package/dist/server/swagger/index.d.ts +1 -2
  143. package/dist/server/swagger/index.d.ts.map +1 -1
  144. package/dist/server/swagger/index.js +1 -2
  145. package/dist/server/swagger/index.js.map +1 -1
  146. package/dist/sms/index.d.ts +3 -1
  147. package/dist/sms/index.d.ts.map +1 -1
  148. package/dist/sms/index.js +10 -10
  149. package/dist/sms/index.js.map +1 -1
  150. package/dist/thread/index.d.ts +0 -1
  151. package/dist/thread/index.d.ts.map +1 -1
  152. package/dist/thread/index.js +2 -2
  153. package/dist/thread/index.js.map +1 -1
  154. package/dist/topic/core/index.d.ts.map +1 -1
  155. package/dist/topic/redis/index.d.ts.map +1 -1
  156. package/dist/vite/index.d.ts +6315 -149
  157. package/dist/vite/index.d.ts.map +1 -1
  158. package/dist/vite/index.js +140 -469
  159. package/dist/vite/index.js.map +1 -1
  160. package/dist/websocket/index.browser.js +9 -9
  161. package/dist/websocket/index.browser.js.map +1 -1
  162. package/dist/websocket/index.d.ts +28 -28
  163. package/dist/websocket/index.d.ts.map +1 -1
  164. package/dist/websocket/index.js +9 -9
  165. package/dist/websocket/index.js.map +1 -1
  166. package/package.json +13 -18
  167. package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
  168. package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
  169. package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
  170. package/src/api/users/entities/users.ts +1 -1
  171. package/src/api/users/index.ts +8 -8
  172. package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
  173. package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
  174. package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
  175. package/src/api/users/services/CredentialService.ts +7 -7
  176. package/src/api/users/services/IdentityService.ts +4 -4
  177. package/src/api/users/services/RegistrationService.spec.ts +25 -27
  178. package/src/api/users/services/RegistrationService.ts +38 -27
  179. package/src/api/users/services/SessionCrudService.ts +3 -3
  180. package/src/api/users/services/SessionService.spec.ts +3 -3
  181. package/src/api/users/services/SessionService.ts +27 -18
  182. package/src/api/users/services/UserService.ts +7 -7
  183. package/src/batch/providers/BatchProvider.ts +1 -2
  184. package/src/cli/apps/AlephaCli.ts +2 -2
  185. package/src/cli/apps/AlephaPackageBuilderCli.ts +47 -20
  186. package/src/cli/assets/apiHelloControllerTs.ts +19 -0
  187. package/src/cli/assets/apiIndexTs.ts +16 -0
  188. package/src/cli/assets/biomeJson.ts +2 -1
  189. package/src/cli/assets/claudeMd.ts +308 -0
  190. package/src/cli/assets/dummySpecTs.ts +2 -1
  191. package/src/cli/assets/editorconfig.ts +2 -1
  192. package/src/cli/assets/mainBrowserTs.ts +4 -3
  193. package/src/cli/assets/mainCss.ts +24 -0
  194. package/src/cli/assets/mainServerTs.ts +24 -0
  195. package/src/cli/assets/tsconfigJson.ts +2 -1
  196. package/src/cli/assets/webAppRouterTs.ts +16 -0
  197. package/src/cli/assets/webHelloComponentTsx.ts +20 -0
  198. package/src/cli/assets/webIndexTs.ts +16 -0
  199. package/src/cli/atoms/appEntryOptions.ts +13 -0
  200. package/src/cli/atoms/buildOptions.ts +1 -1
  201. package/src/cli/atoms/changelogOptions.ts +1 -1
  202. package/src/cli/commands/build.ts +97 -61
  203. package/src/cli/commands/db.ts +21 -18
  204. package/src/cli/commands/deploy.ts +17 -5
  205. package/src/cli/commands/dev.ts +26 -47
  206. package/src/cli/commands/gen/env.ts +1 -1
  207. package/src/cli/commands/init.ts +79 -25
  208. package/src/cli/commands/lint.ts +9 -3
  209. package/src/cli/commands/test.ts +8 -2
  210. package/src/cli/commands/typecheck.ts +5 -1
  211. package/src/cli/commands/verify.ts +4 -2
  212. package/src/cli/defineConfig.ts +9 -0
  213. package/src/cli/index.ts +2 -1
  214. package/src/cli/providers/AppEntryProvider.ts +131 -0
  215. package/src/cli/providers/ViteBuildProvider.ts +82 -0
  216. package/src/cli/providers/ViteDevServerProvider.ts +350 -0
  217. package/src/cli/providers/ViteTemplateProvider.ts +27 -0
  218. package/src/cli/services/AlephaCliUtils.ts +72 -602
  219. package/src/cli/services/PackageManagerUtils.ts +308 -0
  220. package/src/cli/services/ProjectScaffolder.ts +329 -0
  221. package/src/command/helpers/Runner.ts +15 -3
  222. package/src/core/Alepha.ts +2 -8
  223. package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
  224. package/src/core/index.shared.ts +1 -0
  225. package/src/core/index.ts +2 -0
  226. package/src/core/primitives/$hook.ts +6 -2
  227. package/src/core/primitives/$module.spec.ts +4 -0
  228. package/src/core/primitives/$module.ts +12 -0
  229. package/src/core/providers/AlsProvider.ts +1 -1
  230. package/src/core/providers/CodecManager.spec.ts +12 -6
  231. package/src/core/providers/CodecManager.ts +26 -6
  232. package/src/core/providers/EventManager.ts +169 -13
  233. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +878 -0
  234. package/src/core/providers/KeylessJsonSchemaCodec.ts +789 -0
  235. package/src/core/providers/SchemaValidator.spec.ts +236 -0
  236. package/src/core/providers/StateManager.spec.ts +27 -16
  237. package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
  238. package/src/email/providers/LocalEmailProvider.ts +52 -15
  239. package/src/email/providers/NodemailerEmailProvider.ts +167 -56
  240. package/src/file/errors/FileError.ts +7 -0
  241. package/src/file/index.ts +9 -1
  242. package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
  243. package/src/logger/providers/PrettyFormatterProvider.ts +0 -9
  244. package/src/mcp/errors/McpError.ts +30 -0
  245. package/src/mcp/index.ts +3 -0
  246. package/src/mcp/transports/SseMcpTransport.ts +16 -6
  247. package/src/orm/index.browser.ts +1 -19
  248. package/src/orm/index.bun.ts +77 -0
  249. package/src/orm/index.shared-server.ts +22 -0
  250. package/src/orm/index.shared.ts +15 -0
  251. package/src/orm/index.ts +19 -39
  252. package/src/orm/providers/DrizzleKitProvider.ts +3 -5
  253. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
  254. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  255. package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
  256. package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
  257. package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
  258. package/src/orm/services/Repository.ts +19 -0
  259. package/src/redis/index.bun.ts +35 -0
  260. package/src/redis/providers/BunRedisProvider.ts +12 -43
  261. package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
  262. package/src/redis/providers/NodeRedisProvider.ts +16 -34
  263. package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
  264. package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
  265. package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
  266. package/src/security/index.browser.ts +5 -0
  267. package/src/security/index.ts +90 -7
  268. package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
  269. package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
  270. package/src/security/primitives/$role.ts +5 -5
  271. package/src/security/primitives/$serviceAccount.spec.ts +5 -5
  272. package/src/security/primitives/$serviceAccount.ts +3 -3
  273. package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
  274. package/src/server/auth/primitives/$auth.ts +10 -10
  275. package/src/server/auth/primitives/$authCredentials.ts +3 -3
  276. package/src/server/auth/primitives/$authGithub.ts +3 -3
  277. package/src/server/auth/primitives/$authGoogle.ts +3 -3
  278. package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
  279. package/src/server/cache/providers/ServerCacheProvider.ts +1 -1
  280. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
  281. package/src/server/core/index.ts +1 -1
  282. package/src/server/core/providers/BunHttpServerProvider.ts +1 -1
  283. package/src/server/core/providers/NodeHttpServerProvider.spec.ts +125 -0
  284. package/src/server/core/providers/NodeHttpServerProvider.ts +92 -24
  285. package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
  286. package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
  287. package/src/server/core/providers/ServerProvider.ts +144 -24
  288. package/src/server/core/providers/ServerRouterProvider.ts +259 -115
  289. package/src/server/core/providers/ServerTimingProvider.ts +2 -2
  290. package/src/server/links/atoms/apiLinksAtom.ts +7 -0
  291. package/src/server/links/index.browser.ts +2 -0
  292. package/src/server/links/index.ts +3 -1
  293. package/src/server/links/providers/LinkProvider.ts +1 -1
  294. package/src/server/swagger/index.ts +1 -1
  295. package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
  296. package/src/sms/providers/LocalSmsProvider.ts +8 -7
  297. package/src/vite/index.ts +3 -2
  298. package/src/vite/tasks/buildClient.ts +0 -1
  299. package/src/vite/tasks/buildServer.ts +80 -22
  300. package/src/vite/tasks/copyAssets.ts +5 -4
  301. package/src/vite/tasks/generateCloudflare.ts +7 -0
  302. package/src/vite/tasks/generateSitemap.ts +64 -23
  303. package/src/vite/tasks/index.ts +0 -2
  304. package/src/vite/tasks/prerenderPages.ts +49 -24
  305. package/dist/server/security/index.browser.js +0 -13
  306. package/dist/server/security/index.browser.js.map +0 -1
  307. package/dist/server/security/index.d.ts +0 -173
  308. package/dist/server/security/index.d.ts.map +0 -1
  309. package/dist/server/security/index.js +0 -311
  310. package/dist/server/security/index.js.map +0 -1
  311. package/src/cli/assets/appRouterTs.ts +0 -9
  312. package/src/cli/assets/indexHtml.ts +0 -15
  313. package/src/cli/assets/mainTs.ts +0 -13
  314. package/src/cli/commands/format.ts +0 -17
  315. package/src/server/security/index.browser.ts +0 -10
  316. package/src/server/security/index.ts +0 -94
  317. package/src/vite/helpers/boot.ts +0 -106
  318. package/src/vite/plugins/viteAlephaDev.ts +0 -177
  319. package/src/vite/tasks/devServer.ts +0 -69
  320. package/src/vite/tasks/runAlepha.ts +0 -270
  321. /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
  322. /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
@@ -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
  }
package/src/vite/index.ts CHANGED
@@ -1,15 +1,16 @@
1
1
  import type { Alepha } from "alepha";
2
2
 
3
3
  // Helpers (for advanced use)
4
- export * from "./helpers/boot.ts";
5
4
  export * from "./helpers/createBufferedLogger.ts";
5
+ export * from "./helpers/importVite.ts";
6
+ export * from "./helpers/importViteReact.ts";
6
7
  // Plugins (public API)
7
- export * from "./plugins/viteAlephaDev.ts";
8
8
  export * from "./plugins/viteAlephaSsrPreload.ts";
9
9
  export * from "./plugins/viteCompress.ts";
10
10
  // Tasks (for CLI integration)
11
11
  export * from "./tasks/index.ts";
12
12
 
13
13
  declare global {
14
+ var __alepha: Alepha;
14
15
  var __cli_alepha: Alepha;
15
16
  }
@@ -103,7 +103,6 @@ export async function buildClient(opts: BuildClientOptions): Promise<void> {
103
103
  outDir: opts.dist,
104
104
  // Generate manifest for SSR module preloading
105
105
  manifest: true,
106
- ssrManifest: true,
107
106
  rollupOptions: {
108
107
  output: {
109
108
  entryFileNames: "entry.[hash].js",
@@ -1,6 +1,6 @@
1
1
  import { readFile, rm, writeFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { AlephaError } from "alepha";
3
+ import { type Alepha, AlephaError } from "alepha";
4
4
  import type * as vite from "vite";
5
5
  import type { UserConfig } from "vite";
6
6
  import { analyzer as viteAnalyzer } from "vite-bundle-analyzer";
@@ -27,11 +27,6 @@ export interface BuildServerOptions {
27
27
  */
28
28
  clientDir?: string;
29
29
 
30
- /**
31
- * Override Vite config options.
32
- */
33
- config?: UserConfig;
34
-
35
30
  /**
36
31
  * If true, generate build stats report.
37
32
  */
@@ -43,6 +38,16 @@ export interface BuildServerOptions {
43
38
  * @default false
44
39
  */
45
40
  silent?: boolean;
41
+
42
+ /**
43
+ * Add more entry point conditions for SSR module resolution (e.g., "bun").
44
+ */
45
+ conditions?: string[];
46
+
47
+ /**
48
+ * Alepha instance to set SSR manifest for pre-rendering.
49
+ */
50
+ alepha: Alepha;
46
51
  }
47
52
 
48
53
  export interface BuildServerResult {
@@ -50,6 +55,15 @@ export interface BuildServerResult {
50
55
  * The filename of the built server entry (e.g., "abc123.js").
51
56
  */
52
57
  entryFile: string;
58
+
59
+ /**
60
+ * SSR manifest data for module preloading.
61
+ * Can be used to set in alepha store for pre-rendering.
62
+ */
63
+ manifest?: {
64
+ client?: Record<string, any>;
65
+ preload?: Record<string, string>;
66
+ };
53
67
  }
54
68
 
55
69
  /**
@@ -62,7 +76,7 @@ export interface BuildServerResult {
62
76
  export async function buildServer(
63
77
  opts: BuildServerOptions,
64
78
  ): Promise<BuildServerResult> {
65
- const { build: viteBuild, mergeConfig } = await importVite();
79
+ const { build: viteBuild, resolveConfig } = await importVite();
66
80
  const plugins: any[] = [];
67
81
 
68
82
  const viteReact = await importViteReact();
@@ -83,6 +97,12 @@ export async function buildServer(
83
97
  // Create buffered logger for silent mode
84
98
  const logger = opts.silent ? createBufferedLogger() : undefined;
85
99
 
100
+ const conditions = ["node", "import", "module", "default"];
101
+ if (opts.conditions) {
102
+ conditions.unshift(...opts.conditions);
103
+ }
104
+
105
+ // note: we still can override this config via config file (vite.config.ts)
86
106
  const viteBuildServerConfig: UserConfig = {
87
107
  mode: "production",
88
108
  logLevel: opts.silent ? "silent" : undefined,
@@ -92,6 +112,7 @@ export async function buildServer(
92
112
  publicDir: false,
93
113
  ssr: {
94
114
  noExternal: true,
115
+ resolve: { conditions },
95
116
  },
96
117
  build: {
97
118
  sourcemap: true,
@@ -100,7 +121,7 @@ export async function buildServer(
100
121
  minify: true,
101
122
  chunkSizeWarningLimit: 10000,
102
123
  rollupOptions: {
103
- external: ["bun"],
124
+ external: [/^bun(:|$)/, /^cloudflare:/],
104
125
  output: {
105
126
  entryFileNames: "[hash].js",
106
127
  chunkFileNames: "[hash].js",
@@ -110,24 +131,32 @@ export async function buildServer(
110
131
  },
111
132
  },
112
133
  esbuild: { legalComments: "none", keepNames: true },
113
- customLogger: logger,
134
+ customLogger: logger, // mock logger to avoid noisy output
114
135
  plugins,
115
136
  };
116
137
 
138
+ // create inline config by merging alepha built-in + extended config
139
+
117
140
  let result: vite.Rollup.RollupOutput | vite.Rollup.RollupOutput[];
118
141
  try {
119
- result = (await viteBuild(
120
- mergeConfig(viteBuildServerConfig, opts.config || {}),
121
- )) as vite.Rollup.RollupOutput | vite.Rollup.RollupOutput[];
142
+ result = (await viteBuild(viteBuildServerConfig)) as
143
+ | vite.Rollup.RollupOutput
144
+ | vite.Rollup.RollupOutput[];
122
145
  } catch (error) {
123
- // Flush buffered logs on failure so user can see what happened
146
+ // flush buffered logs on failure so user can see what happened
124
147
  logger?.flush();
125
148
  throw error;
126
149
  }
127
150
 
128
- // Extract resolved config to get externals
129
- const resolvedConfig = (result as any).resolvedConfig;
130
- const externals: string[] = resolvedConfig?.ssr?.external ?? [];
151
+ // resolve final config to read externals
152
+ const resolvedConfig = await resolveConfig(viteBuildServerConfig, "build");
153
+
154
+ // extract resolved config to get externals
155
+ const externals: string[] = [];
156
+
157
+ if (Array.isArray(resolvedConfig?.ssr?.external)) {
158
+ externals.push(...resolvedConfig.ssr.external);
159
+ }
131
160
 
132
161
  // Generate package.json with externals
133
162
  await generateExternals({
@@ -150,21 +179,29 @@ export async function buildServer(
150
179
  // Embed SSR manifests if client was built
151
180
  // This bundles all manifest data into index.js for serverless deployments
152
181
  let manifest = "";
182
+ let manifestData:
183
+ | { client?: Record<string, any>; preload?: Record<string, string> }
184
+ | undefined;
185
+
153
186
  if (opts.clientDir) {
154
187
  const viteDir = `${opts.distDir}/${opts.clientDir}/.vite`;
155
- const ssrManifest = await loadJsonFile(`${viteDir}/ssr-manifest.json`);
156
188
  const clientManifest = await loadJsonFile(`${viteDir}/manifest.json`);
157
189
  const preloadManifest = await loadJsonFile(
158
190
  `${viteDir}/preload-manifest.json`,
159
191
  );
160
192
 
161
- const combined = {
162
- ssr: ssrManifest,
163
- client: clientManifest,
193
+ // Strip unused fields from client manifest to reduce bundle size
194
+ const strippedClientManifest = stripClientManifest(clientManifest);
195
+
196
+ manifestData = {
197
+ client: strippedClientManifest,
164
198
  preload: preloadManifest,
165
199
  };
166
200
 
167
- manifest = `__alepha.set("alepha.react.ssr.manifest", ${JSON.stringify(combined)});\n`;
201
+ manifest = `__alepha.set("alepha.react.ssr.manifest", ${JSON.stringify(manifestData)});\n`;
202
+
203
+ // Set manifest in alepha store for pre-rendering
204
+ opts.alepha.store.set("alepha.react.ssr.manifest" as any, manifestData);
168
205
 
169
206
  // Remove .vite directory - no longer needed at runtime
170
207
  await rm(viteDir, { recursive: true, force: true });
@@ -180,7 +217,7 @@ export async function buildServer(
180
217
  `${warning}\n${template}${manifest}import './server/${entryFile}';\n`.trim(),
181
218
  );
182
219
 
183
- return { entryFile };
220
+ return { entryFile, manifest: manifestData };
184
221
  }
185
222
 
186
223
  /**
@@ -195,6 +232,27 @@ async function loadJsonFile(path: string): Promise<any> {
195
232
  }
196
233
  }
197
234
 
235
+ /**
236
+ * Strip unused fields from client manifest to reduce bundle size.
237
+ * Only keeps: file, isEntry, imports, css
238
+ */
239
+ function stripClientManifest(
240
+ manifest: Record<string, any> | undefined,
241
+ ): Record<string, any> | undefined {
242
+ if (!manifest) return undefined;
243
+
244
+ const stripped: Record<string, any> = {};
245
+ for (const [key, entry] of Object.entries(manifest)) {
246
+ stripped[key] = {
247
+ file: entry.file,
248
+ ...(entry.isEntry && { isEntry: entry.isEntry }),
249
+ ...(entry.imports?.length && { imports: entry.imports }),
250
+ ...(entry.css?.length && { css: entry.css }),
251
+ };
252
+ }
253
+ return stripped;
254
+ }
255
+
198
256
  /**
199
257
  * Extract entry filename from Vite build result.
200
258
  */
@@ -1,9 +1,10 @@
1
1
  import { cp, mkdir } from "node:fs/promises";
2
2
  import { createRequire } from "node:module";
3
3
  import { dirname, join, resolve } from "node:path";
4
- import { importAlepha } from "../helpers/importAlepha.ts";
4
+ import type { Alepha } from "alepha";
5
5
 
6
6
  export interface CopyAssetsOptions {
7
+ alepha: Alepha;
7
8
  /**
8
9
  * Entry point for the built Alepha application.
9
10
  */
@@ -17,7 +18,7 @@ export interface CopyAssetsOptions {
17
18
  /**
18
19
  * @default process.cwd()
19
20
  */
20
- root?: string;
21
+ root: string;
21
22
 
22
23
  /**
23
24
  * Add Runner for logging (@see Alepha CLI)
@@ -38,8 +39,8 @@ export interface CopyAssetsOptions {
38
39
  * Used by modules like AlephaServerSwagger to distribute UI files.
39
40
  */
40
41
  export async function copyAssets(opts: CopyAssetsOptions): Promise<void> {
41
- const root = opts.root ?? process.cwd();
42
- const alepha = await importAlepha(opts.entry);
42
+ const root = opts.root;
43
+ const alepha = opts.alepha;
43
44
  const assets = alepha.store.get("alepha.build.assets");
44
45
 
45
46
  if (!assets || assets.length === 0) {