alepha 0.14.4 → 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 (277) hide show
  1. package/README.md +1 -4
  2. package/dist/api/audits/index.d.ts +619 -731
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/files/index.d.ts +185 -298
  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 -356
  9. package/dist/api/jobs/index.d.ts.map +1 -1
  10. package/dist/api/notifications/index.d.ts +238 -350
  11. package/dist/api/notifications/index.d.ts.map +1 -1
  12. package/dist/api/parameters/index.d.ts +499 -611
  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 +1697 -1804
  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 +132 -132
  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 +302 -299
  32. package/dist/cli/index.d.ts.map +1 -1
  33. package/dist/cli/index.js +966 -564
  34. package/dist/cli/index.js.map +1 -1
  35. package/dist/command/index.d.ts +303 -299
  36. package/dist/command/index.d.ts.map +1 -1
  37. package/dist/command/index.js +11 -7
  38. package/dist/command/index.js.map +1 -1
  39. package/dist/core/index.browser.js +419 -99
  40. package/dist/core/index.browser.js.map +1 -1
  41. package/dist/core/index.d.ts +718 -625
  42. package/dist/core/index.d.ts.map +1 -1
  43. package/dist/core/index.js +420 -99
  44. package/dist/core/index.js.map +1 -1
  45. package/dist/core/index.native.js +419 -99
  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/mcp/index.d.ts +197 -197
  67. package/dist/mcp/index.d.ts.map +1 -1
  68. package/dist/orm/chunk-DtkW-qnP.js +38 -0
  69. package/dist/orm/index.browser.js.map +1 -1
  70. package/dist/orm/index.bun.js +2814 -0
  71. package/dist/orm/index.bun.js.map +1 -0
  72. package/dist/orm/index.d.ts +1205 -1057
  73. package/dist/orm/index.d.ts.map +1 -1
  74. package/dist/orm/index.js +2056 -1753
  75. package/dist/orm/index.js.map +1 -1
  76. package/dist/queue/core/index.d.ts +248 -248
  77. package/dist/queue/core/index.d.ts.map +1 -1
  78. package/dist/queue/redis/index.d.ts.map +1 -1
  79. package/dist/redis/index.bun.js +285 -0
  80. package/dist/redis/index.bun.js.map +1 -0
  81. package/dist/redis/index.d.ts +118 -136
  82. package/dist/redis/index.d.ts.map +1 -1
  83. package/dist/redis/index.js +18 -38
  84. package/dist/redis/index.js.map +1 -1
  85. package/dist/retry/index.d.ts +69 -69
  86. package/dist/retry/index.d.ts.map +1 -1
  87. package/dist/router/index.d.ts +6 -6
  88. package/dist/router/index.d.ts.map +1 -1
  89. package/dist/scheduler/index.d.ts +25 -25
  90. package/dist/scheduler/index.d.ts.map +1 -1
  91. package/dist/security/index.browser.js +5 -1
  92. package/dist/security/index.browser.js.map +1 -1
  93. package/dist/security/index.d.ts +417 -254
  94. package/dist/security/index.d.ts.map +1 -1
  95. package/dist/security/index.js +386 -86
  96. package/dist/security/index.js.map +1 -1
  97. package/dist/server/auth/index.d.ts +277 -277
  98. package/dist/server/auth/index.d.ts.map +1 -1
  99. package/dist/server/auth/index.js +20 -20
  100. package/dist/server/auth/index.js.map +1 -1
  101. package/dist/server/cache/index.d.ts +60 -57
  102. package/dist/server/cache/index.d.ts.map +1 -1
  103. package/dist/server/cache/index.js +1 -1
  104. package/dist/server/cache/index.js.map +1 -1
  105. package/dist/server/compress/index.d.ts +3 -3
  106. package/dist/server/compress/index.d.ts.map +1 -1
  107. package/dist/server/cookies/index.d.ts +6 -6
  108. package/dist/server/cookies/index.d.ts.map +1 -1
  109. package/dist/server/cookies/index.js +3 -3
  110. package/dist/server/cookies/index.js.map +1 -1
  111. package/dist/server/core/index.d.ts +242 -150
  112. package/dist/server/core/index.d.ts.map +1 -1
  113. package/dist/server/core/index.js +288 -122
  114. package/dist/server/core/index.js.map +1 -1
  115. package/dist/server/cors/index.d.ts +11 -12
  116. package/dist/server/cors/index.d.ts.map +1 -1
  117. package/dist/server/health/index.d.ts +0 -1
  118. package/dist/server/health/index.d.ts.map +1 -1
  119. package/dist/server/helmet/index.d.ts +2 -2
  120. package/dist/server/helmet/index.d.ts.map +1 -1
  121. package/dist/server/links/index.browser.js.map +1 -1
  122. package/dist/server/links/index.d.ts +84 -85
  123. package/dist/server/links/index.d.ts.map +1 -1
  124. package/dist/server/links/index.js +1 -2
  125. package/dist/server/links/index.js.map +1 -1
  126. package/dist/server/metrics/index.d.ts.map +1 -1
  127. package/dist/server/multipart/index.d.ts +6 -6
  128. package/dist/server/multipart/index.d.ts.map +1 -1
  129. package/dist/server/proxy/index.d.ts +102 -103
  130. package/dist/server/proxy/index.d.ts.map +1 -1
  131. package/dist/server/rate-limit/index.d.ts +16 -16
  132. package/dist/server/rate-limit/index.d.ts.map +1 -1
  133. package/dist/server/static/index.d.ts +44 -44
  134. package/dist/server/static/index.d.ts.map +1 -1
  135. package/dist/server/swagger/index.d.ts +48 -49
  136. package/dist/server/swagger/index.d.ts.map +1 -1
  137. package/dist/server/swagger/index.js +1 -2
  138. package/dist/server/swagger/index.js.map +1 -1
  139. package/dist/sms/index.d.ts +13 -11
  140. package/dist/sms/index.d.ts.map +1 -1
  141. package/dist/sms/index.js +7 -7
  142. package/dist/sms/index.js.map +1 -1
  143. package/dist/thread/index.d.ts +71 -72
  144. package/dist/thread/index.d.ts.map +1 -1
  145. package/dist/topic/core/index.d.ts +318 -318
  146. package/dist/topic/core/index.d.ts.map +1 -1
  147. package/dist/topic/redis/index.d.ts +6 -6
  148. package/dist/topic/redis/index.d.ts.map +1 -1
  149. package/dist/vite/index.d.ts +5720 -159
  150. package/dist/vite/index.d.ts.map +1 -1
  151. package/dist/vite/index.js +41 -18
  152. package/dist/vite/index.js.map +1 -1
  153. package/dist/websocket/index.browser.js +6 -6
  154. package/dist/websocket/index.browser.js.map +1 -1
  155. package/dist/websocket/index.d.ts +247 -247
  156. package/dist/websocket/index.d.ts.map +1 -1
  157. package/dist/websocket/index.js +6 -6
  158. package/dist/websocket/index.js.map +1 -1
  159. package/package.json +9 -14
  160. package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
  161. package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
  162. package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
  163. package/src/api/users/entities/users.ts +1 -1
  164. package/src/api/users/index.ts +8 -8
  165. package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
  166. package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
  167. package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
  168. package/src/api/users/services/CredentialService.ts +7 -7
  169. package/src/api/users/services/IdentityService.ts +4 -4
  170. package/src/api/users/services/RegistrationService.spec.ts +25 -27
  171. package/src/api/users/services/RegistrationService.ts +38 -27
  172. package/src/api/users/services/SessionCrudService.ts +3 -3
  173. package/src/api/users/services/SessionService.spec.ts +3 -3
  174. package/src/api/users/services/SessionService.ts +28 -9
  175. package/src/api/users/services/UserService.ts +7 -7
  176. package/src/batch/providers/BatchProvider.ts +1 -2
  177. package/src/cli/apps/AlephaPackageBuilderCli.ts +38 -19
  178. package/src/cli/assets/apiHelloControllerTs.ts +18 -0
  179. package/src/cli/assets/apiIndexTs.ts +16 -0
  180. package/src/cli/assets/claudeMd.ts +303 -0
  181. package/src/cli/assets/mainBrowserTs.ts +2 -2
  182. package/src/cli/assets/mainServerTs.ts +24 -0
  183. package/src/cli/assets/webAppRouterTs.ts +15 -0
  184. package/src/cli/assets/webHelloComponentTsx.ts +16 -0
  185. package/src/cli/assets/webIndexTs.ts +16 -0
  186. package/src/cli/commands/build.ts +41 -21
  187. package/src/cli/commands/db.ts +21 -18
  188. package/src/cli/commands/deploy.ts +17 -5
  189. package/src/cli/commands/dev.ts +13 -17
  190. package/src/cli/commands/format.ts +8 -2
  191. package/src/cli/commands/init.ts +74 -29
  192. package/src/cli/commands/lint.ts +8 -2
  193. package/src/cli/commands/test.ts +8 -2
  194. package/src/cli/commands/typecheck.ts +5 -1
  195. package/src/cli/commands/verify.ts +4 -2
  196. package/src/cli/services/AlephaCliUtils.ts +39 -600
  197. package/src/cli/services/PackageManagerUtils.ts +301 -0
  198. package/src/cli/services/ProjectScaffolder.ts +306 -0
  199. package/src/command/helpers/Runner.ts +15 -3
  200. package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
  201. package/src/core/index.shared.ts +1 -0
  202. package/src/core/index.ts +2 -0
  203. package/src/core/primitives/$hook.ts +6 -2
  204. package/src/core/primitives/$module.spec.ts +4 -0
  205. package/src/core/providers/AlsProvider.ts +1 -1
  206. package/src/core/providers/CodecManager.spec.ts +12 -6
  207. package/src/core/providers/CodecManager.ts +26 -6
  208. package/src/core/providers/EventManager.ts +169 -13
  209. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +621 -0
  210. package/src/core/providers/KeylessJsonSchemaCodec.ts +407 -0
  211. package/src/core/providers/StateManager.spec.ts +27 -16
  212. package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
  213. package/src/email/providers/LocalEmailProvider.ts +52 -15
  214. package/src/email/providers/NodemailerEmailProvider.ts +167 -56
  215. package/src/file/errors/FileError.ts +7 -0
  216. package/src/file/index.ts +9 -1
  217. package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
  218. package/src/orm/index.browser.ts +1 -19
  219. package/src/orm/index.bun.ts +77 -0
  220. package/src/orm/index.shared-server.ts +22 -0
  221. package/src/orm/index.shared.ts +15 -0
  222. package/src/orm/index.ts +19 -39
  223. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
  224. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  225. package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
  226. package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
  227. package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
  228. package/src/orm/services/Repository.ts +8 -0
  229. package/src/redis/index.bun.ts +35 -0
  230. package/src/redis/providers/BunRedisProvider.ts +12 -43
  231. package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
  232. package/src/redis/providers/NodeRedisProvider.ts +16 -34
  233. package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
  234. package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
  235. package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
  236. package/src/security/index.browser.ts +5 -0
  237. package/src/security/index.ts +90 -7
  238. package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
  239. package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
  240. package/src/security/primitives/$role.ts +5 -5
  241. package/src/security/primitives/$serviceAccount.spec.ts +5 -5
  242. package/src/security/primitives/$serviceAccount.ts +3 -3
  243. package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
  244. package/src/server/auth/primitives/$auth.ts +10 -10
  245. package/src/server/auth/primitives/$authCredentials.ts +3 -3
  246. package/src/server/auth/primitives/$authGithub.ts +3 -3
  247. package/src/server/auth/primitives/$authGoogle.ts +3 -3
  248. package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
  249. package/src/server/cache/providers/ServerCacheProvider.ts +1 -1
  250. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
  251. package/src/server/core/providers/NodeHttpServerProvider.ts +25 -6
  252. package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
  253. package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
  254. package/src/server/core/providers/ServerProvider.ts +144 -21
  255. package/src/server/core/providers/ServerRouterProvider.ts +259 -115
  256. package/src/server/core/providers/ServerTimingProvider.ts +2 -2
  257. package/src/server/links/index.ts +1 -1
  258. package/src/server/links/providers/LinkProvider.ts +1 -1
  259. package/src/server/swagger/index.ts +1 -1
  260. package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
  261. package/src/sms/providers/LocalSmsProvider.ts +8 -7
  262. package/src/vite/helpers/boot.ts +28 -17
  263. package/src/vite/tasks/buildServer.ts +12 -1
  264. package/src/vite/tasks/devServer.ts +3 -1
  265. package/src/vite/tasks/generateCloudflare.ts +7 -0
  266. package/dist/server/security/index.browser.js +0 -13
  267. package/dist/server/security/index.browser.js.map +0 -1
  268. package/dist/server/security/index.d.ts +0 -173
  269. package/dist/server/security/index.d.ts.map +0 -1
  270. package/dist/server/security/index.js +0 -311
  271. package/dist/server/security/index.js.map +0 -1
  272. package/src/cli/assets/appRouterTs.ts +0 -9
  273. package/src/cli/assets/mainTs.ts +0 -13
  274. package/src/server/security/index.browser.ts +0 -10
  275. package/src/server/security/index.ts +0 -94
  276. /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
  277. /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
  }
@@ -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
 
@@ -43,6 +43,11 @@ export interface BuildServerOptions {
43
43
  * @default false
44
44
  */
45
45
  silent?: boolean;
46
+
47
+ /**
48
+ * Add more entry point conditions for SSR module resolution (e.g., "bun").
49
+ */
50
+ conditions?: string[];
46
51
  }
47
52
 
48
53
  export interface BuildServerResult {
@@ -83,6 +88,11 @@ export async function buildServer(
83
88
  // Create buffered logger for silent mode
84
89
  const logger = opts.silent ? createBufferedLogger() : undefined;
85
90
 
91
+ const conditions = ["node", "import", "module", "default"];
92
+ if (opts.conditions) {
93
+ conditions.unshift(...opts.conditions);
94
+ }
95
+
86
96
  const viteBuildServerConfig: UserConfig = {
87
97
  mode: "production",
88
98
  logLevel: opts.silent ? "silent" : undefined,
@@ -92,6 +102,7 @@ export async function buildServer(
92
102
  publicDir: false,
93
103
  ssr: {
94
104
  noExternal: true,
105
+ resolve: { conditions },
95
106
  },
96
107
  build: {
97
108
  sourcemap: true,
@@ -100,7 +111,7 @@ export async function buildServer(
100
111
  minify: true,
101
112
  chunkSizeWarningLimit: 10000,
102
113
  rollupOptions: {
103
- external: ["bun"],
114
+ external: [/^bun(:|$)/, /^cloudflare:/],
104
115
  output: {
105
116
  entryFileNames: "[hash].js",
106
117
  chunkFileNames: "[hash].js",
@@ -65,5 +65,7 @@ export async function devServer(opts: DevServerOptions = {}): Promise<void> {
65
65
  const server = await createServer(mergeConfig(config, {}));
66
66
  await server.listen();
67
67
 
68
- // server.printUrls();
68
+ console.log(""); // blank line
69
+ server.printUrls();
70
+ server.bindCLIShortcuts({ print: true });
69
71
  }
@@ -45,6 +45,13 @@ export async function generateCloudflare(
45
45
  main: "./main.cloudflare.js",
46
46
  compatibility_flags: ["nodejs_compat"],
47
47
  compatibility_date: "2025-11-17",
48
+ no_bundle: true,
49
+ rules: [
50
+ {
51
+ type: "ESModule",
52
+ globs: ["index.js", "server/*.js"],
53
+ },
54
+ ],
48
55
  ...opts.config,
49
56
  };
50
57
 
@@ -1,13 +0,0 @@
1
- import { $module } from "alepha";
2
- import { AlephaSecurity } from "alepha/security";
3
- import { AlephaServer } from "alepha/server";
4
-
5
- //#region ../../src/server/security/index.browser.ts
6
- const AlephaServerSecurity = $module({
7
- name: "alepha.server.security",
8
- services: [AlephaServer, AlephaSecurity]
9
- });
10
-
11
- //#endregion
12
- export { AlephaServerSecurity };
13
- //# sourceMappingURL=index.browser.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.browser.js","names":[],"sources":["../../../src/server/security/index.browser.ts"],"sourcesContent":["import { $module } from \"alepha\";\nimport { AlephaSecurity } from \"alepha/security\";\nimport { AlephaServer } from \"alepha/server\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const AlephaServerSecurity = $module({\n name: \"alepha.server.security\",\n services: [AlephaServer, AlephaSecurity],\n});\n"],"mappings":";;;;;AAMA,MAAa,uBAAuB,QAAQ;CAC1C,MAAM;CACN,UAAU,CAAC,cAAc,eAAe;CACzC,CAAC"}