alepha 0.15.3 → 0.15.5

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 (318) hide show
  1. package/README.md +26 -11
  2. package/dist/api/audits/index.d.ts +335 -335
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js +11 -3
  5. package/dist/api/audits/index.js.map +1 -1
  6. package/dist/api/files/index.d.ts +3 -3
  7. package/dist/api/files/index.js +4 -3
  8. package/dist/api/files/index.js.map +1 -1
  9. package/dist/api/jobs/index.d.ts +198 -155
  10. package/dist/api/jobs/index.d.ts.map +1 -1
  11. package/dist/api/jobs/index.js +103 -5
  12. package/dist/api/jobs/index.js.map +1 -1
  13. package/dist/api/keys/index.d.ts +198 -198
  14. package/dist/api/keys/index.d.ts.map +1 -1
  15. package/dist/api/keys/index.js +3 -3
  16. package/dist/api/keys/index.js.map +1 -1
  17. package/dist/api/notifications/index.browser.js +1 -0
  18. package/dist/api/notifications/index.browser.js.map +1 -1
  19. package/dist/api/notifications/index.d.ts +3 -3
  20. package/dist/api/notifications/index.js +4 -3
  21. package/dist/api/notifications/index.js.map +1 -1
  22. package/dist/api/parameters/index.d.ts +263 -263
  23. package/dist/api/parameters/index.d.ts.map +1 -1
  24. package/dist/api/parameters/index.js +41 -30
  25. package/dist/api/parameters/index.js.map +1 -1
  26. package/dist/api/users/index.d.ts +383 -77
  27. package/dist/api/users/index.d.ts.map +1 -1
  28. package/dist/api/users/index.js +284 -72
  29. package/dist/api/users/index.js.map +1 -1
  30. package/dist/api/verifications/index.d.ts +131 -131
  31. package/dist/api/verifications/index.d.ts.map +1 -1
  32. package/dist/api/verifications/index.js +3 -3
  33. package/dist/api/verifications/index.js.map +1 -1
  34. package/dist/batch/index.d.ts +3 -3
  35. package/dist/batch/index.js +3 -3
  36. package/dist/batch/index.js.map +1 -1
  37. package/dist/bucket/index.d.ts +3 -3
  38. package/dist/bucket/index.js +6 -6
  39. package/dist/bucket/index.js.map +1 -1
  40. package/dist/cache/core/index.d.ts +3 -3
  41. package/dist/cache/core/index.js +3 -3
  42. package/dist/cache/core/index.js.map +1 -1
  43. package/dist/cli/index.d.ts +5612 -20
  44. package/dist/cli/index.d.ts.map +1 -1
  45. package/dist/cli/index.js +122 -91
  46. package/dist/cli/index.js.map +1 -1
  47. package/dist/command/index.d.ts +11 -4
  48. package/dist/command/index.d.ts.map +1 -1
  49. package/dist/command/index.js +8 -6
  50. package/dist/command/index.js.map +1 -1
  51. package/dist/core/index.browser.js.map +1 -1
  52. package/dist/core/index.d.ts +4 -8
  53. package/dist/core/index.d.ts.map +1 -1
  54. package/dist/core/index.js +3 -3
  55. package/dist/core/index.js.map +1 -1
  56. package/dist/core/index.native.js.map +1 -1
  57. package/dist/datetime/index.d.ts +3 -3
  58. package/dist/datetime/index.js +3 -3
  59. package/dist/datetime/index.js.map +1 -1
  60. package/dist/email/index.d.ts +16 -16
  61. package/dist/email/index.d.ts.map +1 -1
  62. package/dist/email/index.js +10562 -10
  63. package/dist/email/index.js.map +1 -1
  64. package/dist/fake/index.d.ts +3 -3
  65. package/dist/fake/index.js +3 -3
  66. package/dist/fake/index.js.map +1 -1
  67. package/dist/lock/core/index.d.ts +9 -4
  68. package/dist/lock/core/index.d.ts.map +1 -1
  69. package/dist/lock/core/index.js +12 -4
  70. package/dist/lock/core/index.js.map +1 -1
  71. package/dist/logger/index.d.ts +3 -3
  72. package/dist/logger/index.js +6 -3
  73. package/dist/logger/index.js.map +1 -1
  74. package/dist/mcp/index.d.ts +3 -3
  75. package/dist/mcp/index.js +3 -3
  76. package/dist/mcp/index.js.map +1 -1
  77. package/dist/orm/index.d.ts +12 -12
  78. package/dist/orm/index.js +4 -4
  79. package/dist/orm/index.js.map +1 -1
  80. package/dist/queue/core/index.d.ts +3 -3
  81. package/dist/queue/core/index.js +3 -3
  82. package/dist/queue/core/index.js.map +1 -1
  83. package/dist/react/auth/index.browser.js +2 -1
  84. package/dist/react/auth/index.browser.js.map +1 -1
  85. package/dist/react/auth/index.d.ts +3 -3
  86. package/dist/react/auth/index.js +5 -4
  87. package/dist/react/auth/index.js.map +1 -1
  88. package/dist/react/core/index.d.ts +6 -6
  89. package/dist/react/core/index.js +3 -3
  90. package/dist/react/core/index.js.map +1 -1
  91. package/dist/react/form/index.d.ts +3 -3
  92. package/dist/react/form/index.js +3 -3
  93. package/dist/react/form/index.js.map +1 -1
  94. package/dist/react/head/index.d.ts +3 -3
  95. package/dist/react/head/index.js +3 -3
  96. package/dist/react/head/index.js.map +1 -1
  97. package/dist/react/i18n/index.d.ts +3 -3
  98. package/dist/react/i18n/index.js +3 -3
  99. package/dist/react/i18n/index.js.map +1 -1
  100. package/dist/react/intro/index.css +337 -0
  101. package/dist/react/intro/index.css.map +1 -0
  102. package/dist/react/intro/index.d.ts +10 -0
  103. package/dist/react/intro/index.d.ts.map +1 -0
  104. package/dist/react/intro/index.js +222 -0
  105. package/dist/react/intro/index.js.map +1 -0
  106. package/dist/react/router/index.browser.js +2 -2
  107. package/dist/react/router/index.browser.js.map +1 -1
  108. package/dist/react/router/index.d.ts +11 -1
  109. package/dist/react/router/index.d.ts.map +1 -1
  110. package/dist/react/router/index.js +21 -11
  111. package/dist/react/router/index.js.map +1 -1
  112. package/dist/redis/index.d.ts +22 -22
  113. package/dist/redis/index.js +3 -3
  114. package/dist/redis/index.js.map +1 -1
  115. package/dist/retry/index.d.ts +3 -3
  116. package/dist/retry/index.js +3 -3
  117. package/dist/retry/index.js.map +1 -1
  118. package/dist/scheduler/index.d.ts +16 -4
  119. package/dist/scheduler/index.d.ts.map +1 -1
  120. package/dist/scheduler/index.js +45 -7
  121. package/dist/scheduler/index.js.map +1 -1
  122. package/dist/security/index.d.ts +3 -3
  123. package/dist/security/index.js +5 -5
  124. package/dist/security/index.js.map +1 -1
  125. package/dist/server/auth/index.d.ts +3 -3
  126. package/dist/server/auth/index.js +3 -3
  127. package/dist/server/auth/index.js.map +1 -1
  128. package/dist/server/cache/index.d.ts +3 -3
  129. package/dist/server/cache/index.js +3 -3
  130. package/dist/server/cache/index.js.map +1 -1
  131. package/dist/server/compress/index.d.ts +3 -3
  132. package/dist/server/compress/index.d.ts.map +1 -1
  133. package/dist/server/compress/index.js +4 -3
  134. package/dist/server/compress/index.js.map +1 -1
  135. package/dist/server/cookies/index.d.ts +3 -3
  136. package/dist/server/cookies/index.js +3 -3
  137. package/dist/server/cookies/index.js.map +1 -1
  138. package/dist/server/core/index.d.ts +14 -25
  139. package/dist/server/core/index.d.ts.map +1 -1
  140. package/dist/server/core/index.js +13 -29
  141. package/dist/server/core/index.js.map +1 -1
  142. package/dist/server/cors/index.d.ts +3 -3
  143. package/dist/server/cors/index.js +3 -3
  144. package/dist/server/cors/index.js.map +1 -1
  145. package/dist/server/health/index.d.ts +20 -20
  146. package/dist/server/health/index.js +3 -3
  147. package/dist/server/health/index.js.map +1 -1
  148. package/dist/server/helmet/index.d.ts +3 -3
  149. package/dist/server/helmet/index.js +3 -3
  150. package/dist/server/helmet/index.js.map +1 -1
  151. package/dist/server/links/index.d.ts +42 -42
  152. package/dist/server/links/index.d.ts.map +1 -1
  153. package/dist/server/links/index.js +4 -4
  154. package/dist/server/links/index.js.map +1 -1
  155. package/dist/server/metrics/index.d.ts +3 -3
  156. package/dist/server/metrics/index.js +3 -3
  157. package/dist/server/metrics/index.js.map +1 -1
  158. package/dist/server/multipart/index.d.ts +3 -3
  159. package/dist/server/multipart/index.js +3 -3
  160. package/dist/server/multipart/index.js.map +1 -1
  161. package/dist/server/proxy/index.d.ts +3 -3
  162. package/dist/server/proxy/index.js +3 -3
  163. package/dist/server/proxy/index.js.map +1 -1
  164. package/dist/server/rate-limit/index.d.ts +3 -3
  165. package/dist/server/rate-limit/index.js +3 -3
  166. package/dist/server/rate-limit/index.js.map +1 -1
  167. package/dist/server/static/index.d.ts +3 -3
  168. package/dist/server/static/index.js +6 -6
  169. package/dist/server/static/index.js.map +1 -1
  170. package/dist/server/swagger/index.d.ts +3 -3
  171. package/dist/server/swagger/index.js +6 -6
  172. package/dist/server/swagger/index.js.map +1 -1
  173. package/dist/sms/index.d.ts +3 -3
  174. package/dist/sms/index.js +6 -6
  175. package/dist/sms/index.js.map +1 -1
  176. package/dist/system/index.d.ts +3 -3
  177. package/dist/system/index.js +3 -3
  178. package/dist/system/index.js.map +1 -1
  179. package/dist/thread/index.d.ts +3 -3
  180. package/dist/thread/index.js +3 -3
  181. package/dist/thread/index.js.map +1 -1
  182. package/dist/topic/core/index.d.ts +3 -3
  183. package/dist/topic/core/index.js +3 -3
  184. package/dist/topic/core/index.js.map +1 -1
  185. package/dist/vite/index.d.ts +6286 -4
  186. package/dist/vite/index.d.ts.map +1 -1
  187. package/dist/vite/index.js +28 -2
  188. package/dist/vite/index.js.map +1 -1
  189. package/dist/websocket/index.d.ts +37 -37
  190. package/dist/websocket/index.d.ts.map +1 -1
  191. package/dist/websocket/index.js +3 -3
  192. package/dist/websocket/index.js.map +1 -1
  193. package/package.json +12 -4
  194. package/src/api/audits/controllers/AdminAuditController.ts +8 -0
  195. package/src/api/audits/index.ts +3 -3
  196. package/src/api/files/controllers/AdminFileStatsController.ts +1 -0
  197. package/src/api/files/index.ts +3 -3
  198. package/src/api/jobs/controllers/AdminJobController.ts +18 -2
  199. package/src/api/jobs/index.ts +4 -3
  200. package/src/api/jobs/services/JobAudits.spec.ts +89 -0
  201. package/src/api/jobs/services/JobAudits.ts +101 -0
  202. package/src/api/keys/index.ts +3 -3
  203. package/src/api/notifications/controllers/AdminNotificationController.ts +1 -0
  204. package/src/api/notifications/index.ts +3 -3
  205. package/src/api/parameters/controllers/AdminConfigController.ts +10 -0
  206. package/src/api/parameters/index.ts +5 -3
  207. package/src/api/users/__tests__/ApiKeys-integration.spec.ts +1 -1
  208. package/src/api/users/__tests__/ApiKeys.spec.ts +1 -1
  209. package/src/api/users/__tests__/EmailVerification.spec.ts +16 -1
  210. package/src/api/users/__tests__/PasswordReset.spec.ts +11 -0
  211. package/src/api/users/atoms/realmAuthSettingsAtom.ts +10 -0
  212. package/src/api/users/controllers/AdminIdentityController.ts +3 -0
  213. package/src/api/users/controllers/AdminSessionController.ts +3 -0
  214. package/src/api/users/controllers/AdminUserController.ts +5 -0
  215. package/src/api/users/index.ts +8 -9
  216. package/src/api/users/primitives/$realm.ts +117 -19
  217. package/src/api/users/providers/RealmProvider.ts +15 -7
  218. package/src/api/users/services/CredentialService.spec.ts +11 -0
  219. package/src/api/users/services/CredentialService.ts +47 -24
  220. package/src/api/users/services/IdentityService.ts +12 -4
  221. package/src/api/users/services/RegistrationService.spec.ts +11 -0
  222. package/src/api/users/services/RegistrationService.ts +33 -12
  223. package/src/api/users/services/SessionService.ts +83 -12
  224. package/src/api/users/services/UserAudits.ts +47 -0
  225. package/src/api/users/services/UserFiles.ts +19 -0
  226. package/src/api/users/services/UserJobs.spec.ts +107 -0
  227. package/src/api/users/services/UserJobs.ts +62 -0
  228. package/src/api/users/services/UserParameters.ts +23 -0
  229. package/src/api/users/services/UserService.ts +34 -17
  230. package/src/api/verifications/index.ts +3 -3
  231. package/src/batch/index.ts +3 -3
  232. package/src/bucket/index.ts +3 -3
  233. package/src/cache/core/index.ts +3 -3
  234. package/src/cli/commands/build.ts +1 -0
  235. package/src/cli/commands/db.ts +9 -0
  236. package/src/cli/commands/init.spec.ts +2 -17
  237. package/src/cli/commands/init.ts +37 -1
  238. package/src/cli/providers/ViteDevServerProvider.ts +36 -2
  239. package/src/cli/services/AlephaCliUtils.ts +17 -0
  240. package/src/cli/services/PackageManagerUtils.ts +15 -1
  241. package/src/cli/services/ProjectScaffolder.ts +8 -13
  242. package/src/cli/templates/agentMd.ts +2 -25
  243. package/src/cli/templates/apiAppSecurityTs.ts +37 -2
  244. package/src/cli/templates/mainCss.ts +2 -32
  245. package/src/cli/templates/webAppRouterTs.ts +5 -5
  246. package/src/cli/templates/webHomeComponentTsx.ts +10 -0
  247. package/src/command/helpers/Runner.ts +14 -1
  248. package/src/command/index.ts +3 -3
  249. package/src/core/helpers/primitive.ts +0 -5
  250. package/src/core/index.ts +3 -3
  251. package/src/datetime/index.ts +3 -3
  252. package/src/email/index.ts +3 -3
  253. package/src/email/index.workerd.ts +36 -0
  254. package/src/email/providers/LocalEmailProvider.ts +2 -2
  255. package/src/email/providers/WorkermailerEmailProvider.ts +221 -0
  256. package/src/fake/index.ts +3 -3
  257. package/src/lock/core/index.ts +3 -3
  258. package/src/lock/core/primitives/$lock.ts +13 -1
  259. package/src/logger/index.ts +3 -3
  260. package/src/logger/providers/PrettyFormatterProvider.ts +7 -0
  261. package/src/mcp/index.ts +3 -3
  262. package/src/orm/index.ts +3 -3
  263. package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
  264. package/src/queue/core/index.ts +3 -3
  265. package/src/react/auth/index.ts +3 -3
  266. package/src/react/auth/services/ReactAuth.ts +3 -1
  267. package/src/react/core/index.ts +3 -3
  268. package/src/react/form/index.ts +3 -3
  269. package/src/react/head/index.ts +3 -3
  270. package/src/react/i18n/index.ts +3 -3
  271. package/src/react/intro/components/GettingStarted.css +334 -0
  272. package/src/react/intro/components/GettingStarted.tsx +276 -0
  273. package/src/react/intro/index.ts +1 -0
  274. package/src/react/router/atoms/ssrManifestAtom.ts +7 -0
  275. package/src/react/router/index.browser.ts +2 -0
  276. package/src/react/router/index.ts +2 -0
  277. package/src/react/router/providers/ReactServerProvider.ts +14 -4
  278. package/src/react/router/providers/SSRManifestProvider.ts +7 -0
  279. package/src/redis/index.ts +3 -3
  280. package/src/retry/index.ts +3 -3
  281. package/src/router/index.ts +3 -3
  282. package/src/scheduler/index.ts +3 -3
  283. package/src/scheduler/index.workerd.ts +43 -0
  284. package/src/scheduler/providers/CronProvider.ts +53 -6
  285. package/src/scheduler/providers/WorkerdCronProvider.ts +102 -0
  286. package/src/security/index.ts +3 -3
  287. package/src/security/providers/JwtProvider.ts +2 -2
  288. package/src/server/auth/index.ts +3 -3
  289. package/src/server/cache/index.ts +3 -3
  290. package/src/server/compress/index.ts +3 -3
  291. package/src/server/compress/providers/ServerCompressProvider.ts +6 -0
  292. package/src/server/cookies/index.ts +3 -3
  293. package/src/server/core/index.ts +3 -3
  294. package/src/server/core/primitives/$action.spec.ts +3 -2
  295. package/src/server/core/primitives/$action.ts +6 -2
  296. package/src/server/core/providers/NodeHttpServerProvider.ts +2 -15
  297. package/src/server/core/providers/ServerProvider.ts +4 -2
  298. package/src/server/core/providers/ServerRouterProvider.ts +5 -27
  299. package/src/server/cors/index.ts +3 -3
  300. package/src/server/health/index.ts +3 -3
  301. package/src/server/helmet/index.ts +3 -3
  302. package/src/server/links/index.ts +3 -3
  303. package/src/server/links/providers/ServerLinksProvider.spec.ts +332 -0
  304. package/src/server/links/providers/ServerLinksProvider.ts +1 -1
  305. package/src/server/metrics/index.ts +3 -3
  306. package/src/server/multipart/index.ts +3 -3
  307. package/src/server/proxy/index.ts +3 -3
  308. package/src/server/rate-limit/index.ts +3 -3
  309. package/src/server/static/index.ts +3 -3
  310. package/src/server/swagger/index.ts +3 -3
  311. package/src/sms/index.ts +3 -3
  312. package/src/system/index.ts +3 -3
  313. package/src/thread/index.ts +3 -3
  314. package/src/topic/core/index.ts +3 -3
  315. package/src/vite/tasks/generateCloudflare.ts +38 -2
  316. package/src/websocket/index.ts +3 -3
  317. package/src/cli/templates/webHelloComponentTsx.ts +0 -30
  318. /package/src/api/users/{notifications → services}/UserNotifications.ts +0 -0
@@ -0,0 +1,332 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { Alepha, t } from "alepha";
3
+ import { $issuer, AlephaSecurity } from "alepha/security";
4
+ import { $action, ServerProvider } from "alepha/server";
5
+ import { describe, it } from "vitest";
6
+ import { LinkProvider, ServerLinksProvider } from "../index.ts";
7
+
8
+ describe("ServerLinksProvider", () => {
9
+ describe("secured field in links", () => {
10
+ it("should set secured=undefined for public actions (no secure option)", async ({
11
+ expect,
12
+ }) => {
13
+ class App {
14
+ publicAction = $action({
15
+ handler: () => "PUBLIC",
16
+ });
17
+ }
18
+
19
+ const alepha = Alepha.create().with(App).with(ServerLinksProvider);
20
+ await alepha.start();
21
+
22
+ const links = alepha.inject(LinkProvider).getServerLinks();
23
+ const link = links.find((l) => l.name === "publicAction");
24
+
25
+ expect(link).toBeDefined();
26
+ expect(link?.secured).toBeUndefined();
27
+ });
28
+
29
+ it("should set secured=false for explicitly public actions", async ({
30
+ expect,
31
+ }) => {
32
+ class App {
33
+ publicAction = $action({
34
+ secure: false,
35
+ handler: () => "PUBLIC",
36
+ });
37
+ }
38
+
39
+ const alepha = Alepha.create().with(App).with(ServerLinksProvider);
40
+ await alepha.start();
41
+
42
+ const links = alepha.inject(LinkProvider).getServerLinks();
43
+ const link = links.find((l) => l.name === "publicAction");
44
+
45
+ expect(link).toBeDefined();
46
+ expect(link?.secured).toBe(false);
47
+ });
48
+
49
+ it("should set secured=true for secured actions", async ({ expect }) => {
50
+ class App {
51
+ securedAction = $action({
52
+ secure: true,
53
+ handler: () => "SECURED",
54
+ });
55
+ }
56
+
57
+ const alepha = Alepha.create().with(App).with(ServerLinksProvider);
58
+ await alepha.start();
59
+
60
+ const links = alepha.inject(LinkProvider).getServerLinks();
61
+ const link = links.find((l) => l.name === "securedAction");
62
+
63
+ expect(link).toBeDefined();
64
+ expect(link?.secured).toBe(true);
65
+ });
66
+
67
+ it("should set secured to object for realm-secured actions", async ({
68
+ expect,
69
+ }) => {
70
+ class App {
71
+ realmAction = $action({
72
+ secure: { realm: "admin" },
73
+ handler: () => "REALM",
74
+ });
75
+ }
76
+
77
+ const alepha = Alepha.create().with(App).with(ServerLinksProvider);
78
+ await alepha.start();
79
+
80
+ const links = alepha.inject(LinkProvider).getServerLinks();
81
+ const link = links.find((l) => l.name === "realmAction");
82
+
83
+ expect(link).toBeDefined();
84
+ expect(link?.secured).toEqual({ realm: "admin" });
85
+ });
86
+ });
87
+
88
+ describe("/_links endpoint with security", () => {
89
+ it("should return public actions to unauthenticated users", async ({
90
+ expect,
91
+ }) => {
92
+ class App {
93
+ publicAction = $action({
94
+ schema: { response: t.text() },
95
+ handler: () => "PUBLIC",
96
+ });
97
+ issuer = $issuer({
98
+ secret: "test",
99
+ roles: [{ name: "user", permissions: [{ name: "*" }] }],
100
+ });
101
+ }
102
+
103
+ const alepha = Alepha.create()
104
+ .with(App)
105
+ .with(ServerLinksProvider)
106
+ .with(AlephaSecurity);
107
+ await alepha.start();
108
+
109
+ const res = await fetch(
110
+ `${alepha.inject(ServerProvider).hostname}/api/_links`,
111
+ );
112
+ const data = await res.json();
113
+
114
+ expect(data.links).toContainEqual(
115
+ expect.objectContaining({
116
+ name: "publicAction",
117
+ path: "/publicAction",
118
+ }),
119
+ );
120
+ });
121
+
122
+ it("should NOT return secured actions to unauthenticated users", async ({
123
+ expect,
124
+ }) => {
125
+ class App {
126
+ securedAction = $action({
127
+ secure: true,
128
+ schema: { response: t.text() },
129
+ handler: () => "SECURED",
130
+ });
131
+ issuer = $issuer({
132
+ secret: "test",
133
+ roles: [{ name: "user", permissions: [{ name: "*" }] }],
134
+ });
135
+ }
136
+
137
+ const alepha = Alepha.create()
138
+ .with(App)
139
+ .with(ServerLinksProvider)
140
+ .with(AlephaSecurity);
141
+ await alepha.start();
142
+
143
+ const res = await fetch(
144
+ `${alepha.inject(ServerProvider).hostname}/api/_links`,
145
+ );
146
+ const data = await res.json();
147
+
148
+ expect(data.links).not.toContainEqual(
149
+ expect.objectContaining({
150
+ name: "securedAction",
151
+ }),
152
+ );
153
+ });
154
+
155
+ it("should return secured actions to authenticated users with permissions", async ({
156
+ expect,
157
+ }) => {
158
+ class App {
159
+ securedAction = $action({
160
+ secure: true,
161
+ schema: { response: t.text() },
162
+ handler: () => "SECURED",
163
+ });
164
+ issuer = $issuer({
165
+ secret: "test",
166
+ roles: [{ name: "user", permissions: [{ name: "*" }] }],
167
+ });
168
+ }
169
+
170
+ const alepha = Alepha.create()
171
+ .with(App)
172
+ .with(ServerLinksProvider)
173
+ .with(AlephaSecurity);
174
+ await alepha.start();
175
+
176
+ // Use HttpClient to get a token automatically in test mode
177
+ const app = alepha.inject(App);
178
+ const { data } = await app.securedAction.fetch(
179
+ {},
180
+ {
181
+ user: { id: randomUUID(), roles: ["user"] },
182
+ },
183
+ );
184
+ expect(data).toBe("SECURED");
185
+ });
186
+
187
+ it("should return both public and secured actions when user is authenticated", async ({
188
+ expect,
189
+ }) => {
190
+ class App {
191
+ publicAction = $action({
192
+ schema: { response: t.text() },
193
+ handler: () => "PUBLIC",
194
+ });
195
+ securedAction = $action({
196
+ secure: true,
197
+ schema: { response: t.text() },
198
+ handler: () => "SECURED",
199
+ });
200
+ issuer = $issuer({
201
+ secret: "test",
202
+ roles: [{ name: "user", permissions: [{ name: "*" }] }],
203
+ });
204
+ }
205
+
206
+ const alepha = Alepha.create()
207
+ .with(App)
208
+ .with(ServerLinksProvider)
209
+ .with(AlephaSecurity);
210
+ await alepha.start();
211
+
212
+ const linksProvider = alepha.inject(ServerLinksProvider);
213
+ const user = { id: randomUUID(), roles: ["user"] };
214
+
215
+ const { links } = await linksProvider.getUserApiLinks({ user });
216
+
217
+ expect(links).toContainEqual(
218
+ expect.objectContaining({ name: "publicAction" }),
219
+ );
220
+ expect(links).toContainEqual(
221
+ expect.objectContaining({ name: "securedAction" }),
222
+ );
223
+ });
224
+
225
+ it("should filter secured actions based on user permissions", async ({
226
+ expect,
227
+ }) => {
228
+ class App {
229
+ adminOnly = $action({
230
+ secure: true,
231
+ group: "admin",
232
+ schema: { response: t.text() },
233
+ handler: () => "ADMIN",
234
+ });
235
+ userAction = $action({
236
+ secure: true,
237
+ group: "user",
238
+ schema: { response: t.text() },
239
+ handler: () => "USER",
240
+ });
241
+ issuer = $issuer({
242
+ secret: "test",
243
+ roles: [
244
+ { name: "admin", permissions: [{ name: "*" }] },
245
+ { name: "user", permissions: [{ name: "user:*" }] },
246
+ ],
247
+ });
248
+ }
249
+
250
+ const alepha = Alepha.create()
251
+ .with(App)
252
+ .with(ServerLinksProvider)
253
+ .with(AlephaSecurity);
254
+ await alepha.start();
255
+
256
+ const linksProvider = alepha.inject(ServerLinksProvider);
257
+
258
+ // User with "user" role should only see userAction
259
+ const userLinks = await linksProvider.getUserApiLinks({
260
+ user: { id: randomUUID(), roles: ["user"] },
261
+ });
262
+
263
+ expect(userLinks.links).toContainEqual(
264
+ expect.objectContaining({ name: "userAction" }),
265
+ );
266
+ expect(userLinks.links).not.toContainEqual(
267
+ expect.objectContaining({ name: "adminOnly" }),
268
+ );
269
+
270
+ // User with "admin" role should see both
271
+ const adminLinks = await linksProvider.getUserApiLinks({
272
+ user: { id: randomUUID(), roles: ["admin"] },
273
+ });
274
+
275
+ expect(adminLinks.links).toContainEqual(
276
+ expect.objectContaining({ name: "userAction" }),
277
+ );
278
+ expect(adminLinks.links).toContainEqual(
279
+ expect.objectContaining({ name: "adminOnly" }),
280
+ );
281
+ });
282
+ });
283
+
284
+ describe("mixed public and secured actions", () => {
285
+ it("should correctly differentiate public from secured in server links", async ({
286
+ expect,
287
+ }) => {
288
+ class App {
289
+ getUsers = $action({
290
+ path: "/users",
291
+ schema: { response: t.array(t.text()) },
292
+ handler: () => ["user1", "user2"],
293
+ });
294
+ createUser = $action({
295
+ path: "/users",
296
+ secure: true,
297
+ schema: {
298
+ body: t.object({ name: t.text() }),
299
+ response: t.text(),
300
+ },
301
+ handler: ({ body }) => body.name,
302
+ });
303
+ deleteUser = $action({
304
+ method: "DELETE",
305
+ path: "/users/:id",
306
+ secure: true,
307
+ schema: {
308
+ params: t.object({ id: t.text() }),
309
+ response: t.void(),
310
+ },
311
+ handler: () => {},
312
+ });
313
+ }
314
+
315
+ const alepha = Alepha.create().with(App).with(ServerLinksProvider);
316
+ await alepha.start();
317
+
318
+ const links = alepha.inject(LinkProvider).getServerLinks();
319
+
320
+ const getUsers = links.find((l) => l.name === "getUsers");
321
+ const createUser = links.find((l) => l.name === "createUser");
322
+ const deleteUser = links.find((l) => l.name === "deleteUser");
323
+
324
+ // getUsers is public (no secure option)
325
+ expect(getUsers?.secured).toBeUndefined();
326
+
327
+ // createUser and deleteUser are secured
328
+ expect(createUser?.secured).toBe(true);
329
+ expect(deleteUser?.secured).toBe(true);
330
+ });
331
+ });
332
+ });
@@ -48,7 +48,7 @@ export class ServerLinksProvider {
48
48
  group: action.group,
49
49
  schema: action.options.schema,
50
50
  requestBodyType: action.getBodyContentType(),
51
- secured: action.options.secure ?? true,
51
+ secured: action.options.secure,
52
52
  method: action.method === "GET" ? undefined : action.method,
53
53
  prefix: action.prefix,
54
54
  path: action.path,
@@ -9,9 +9,9 @@ export * from "./providers/ServerMetricsProvider.ts";
9
9
  // ---------------------------------------------------------------------------------------------------------------------
10
10
 
11
11
  /**
12
- * | type | quality | stability |
13
- * |------|---------|-----------|
14
- * | devops | standard | stable |
12
+ * | Stability | Since | Runtime |
13
+ * |-----------|-------|---------|
14
+ * | 2 - beta | 0.14.0 | node, bun|
15
15
  *
16
16
  * Prometheus-style metrics collection.
17
17
  *
@@ -9,9 +9,9 @@ export * from "./providers/ServerMultipartProvider.ts";
9
9
  // ---------------------------------------------------------------------------------------------------------------------
10
10
 
11
11
  /**
12
- * | type | quality | stability |
13
- * |------|---------|-----------|
14
- * | backend | standard | stable |
12
+ * | Stability | Since | Runtime |
13
+ * |-----------|-------|---------|
14
+ * | 3 - stable | 0.5.0 | node, bun|
15
15
  *
16
16
  * Multipart form data handling for file uploads.
17
17
  *
@@ -11,9 +11,9 @@ export * from "./providers/ServerProxyProvider.ts";
11
11
  // ---------------------------------------------------------------------------------------------------------------------
12
12
 
13
13
  /**
14
- * | type | quality | stability |
15
- * |------|---------|-----------|
16
- * | backend | standard | stable |
14
+ * | Stability | Since | Runtime |
15
+ * |-----------|-------|---------|
16
+ * | 2 - beta | 0.12.0 | node, bun|
17
17
  *
18
18
  * Reverse proxy routing.
19
19
  *
@@ -54,9 +54,9 @@ export interface RateLimitOptions {
54
54
  }
55
55
 
56
56
  /**
57
- * | type | quality | stability |
58
- * |------|---------|-----------|
59
- * | backend | standard | stable |
57
+ * | Stability | Since | Runtime |
58
+ * |-----------|-------|---------|
59
+ * | 3 - stable | 0.16.0 | node, bun, workerd|
60
60
  *
61
61
  * Request rate limiting on actions.
62
62
  *
@@ -11,9 +11,9 @@ export * from "./providers/ServerStaticProvider.ts";
11
11
  // ---------------------------------------------------------------------------------------------------------------------
12
12
 
13
13
  /**
14
- * | type | quality | stability |
15
- * |------|---------|-----------|
16
- * | backend | standard | stable |
14
+ * | Stability | Since | Runtime |
15
+ * |-----------|-------|---------|
16
+ * | 3 - stable | 0.3.0 | node, bun|
17
17
  *
18
18
  * Static file serving.
19
19
  *
@@ -30,9 +30,9 @@ declare module "alepha/server" {
30
30
  // ---------------------------------------------------------------------------------------------------------------------
31
31
 
32
32
  /**
33
- * | type | quality | stability |
34
- * |------|---------|-----------|
35
- * | backend | standard | stable |
33
+ * | Stability | Since | Runtime |
34
+ * |-----------|-------|---------|
35
+ * | 3 - stable | 0.9.0 | node, bun|
36
36
  *
37
37
  * Automatic API documentation generation.
38
38
  *
package/src/sms/index.ts CHANGED
@@ -34,9 +34,9 @@ declare module "alepha" {
34
34
  // ---------------------------------------------------------------------------------------------------------------------
35
35
 
36
36
  /**
37
- * | type | quality | stability |
38
- * |------|---------|-----------|
39
- * | backend | rare | stable |
37
+ * | Stability | Since | Runtime |
38
+ * |-----------|-------|---------|
39
+ * | 3 - stable | 0.15.0 | node, bun|
40
40
  *
41
41
  * SMS delivery with multiple provider support.
42
42
  *
@@ -21,9 +21,9 @@ export * from "./services/FileDetector.ts";
21
21
  // ---------------------------------------------------------------------------------------------------------------------
22
22
 
23
23
  /**
24
- * | type | quality | stability |
25
- * |------|---------|-----------|
26
- * | tooling | standard | stable |
24
+ * | Stability | Since | Runtime |
25
+ * |-----------|-------|---------|
26
+ * | 3 - stable | 0.14.0 | node, bun, browser|
27
27
  *
28
28
  * System-level abstractions for portable code across runtimes.
29
29
  *
@@ -22,9 +22,9 @@ Alepha.prototype.isWorkerThread = function (this: Alepha): boolean {
22
22
  // ---------------------------------------------------------------------------------------------------------------------
23
23
 
24
24
  /**
25
- * | type | quality | stability |
26
- * |------|---------|-----------|
27
- * | backend | standard | experimental |
25
+ * | Stability | Since | Runtime |
26
+ * |-----------|-------|---------|
27
+ * | 1 - experimental | 0.16.0 | node|
28
28
  *
29
29
  * Multi-threading support.
30
30
  *
@@ -15,9 +15,9 @@ export * from "./providers/TopicProvider.ts";
15
15
  // ---------------------------------------------------------------------------------------------------------------------
16
16
 
17
17
  /**
18
- * | type | quality | stability |
19
- * |------|---------|-----------|
20
- * | backend | rare | stable |
18
+ * | Stability | Since | Runtime |
19
+ * |-----------|-------|---------|
20
+ * | 3 - stable | 0.7.0 | node, bun|
21
21
  *
22
22
  * Publish/subscribe messaging for event-driven architectures.
23
23
  *
@@ -1,5 +1,8 @@
1
1
  import { access, writeFile } from "node:fs/promises";
2
2
  import { basename, join } from "node:path";
3
+ import type { Alepha } from "alepha";
4
+ import type { CronProvider } from "alepha/scheduler";
5
+ import type { WorkerdCronProvider } from "../../scheduler/providers/WorkerdCronProvider.ts";
3
6
 
4
7
  export interface GenerateCloudflareOptions {
5
8
  /**
@@ -13,6 +16,8 @@ export interface GenerateCloudflareOptions {
13
16
  * Additional Wrangler configuration options to merge into wrangler.jsonc.
14
17
  */
15
18
  config?: WranglerConfig;
19
+
20
+ alepha: Alepha;
16
21
  }
17
22
 
18
23
  export interface WranglerConfig {
@@ -31,7 +36,7 @@ const WARNING_COMMENT =
31
36
  * - worker.js entry point for Cloudflare Workers
32
37
  */
33
38
  export async function generateCloudflare(
34
- opts: GenerateCloudflareOptions = {},
39
+ opts: GenerateCloudflareOptions,
35
40
  ): Promise<void> {
36
41
  const distDir = opts.distDir ?? "dist";
37
42
  const root = process.cwd();
@@ -40,6 +45,15 @@ export async function generateCloudflare(
40
45
  .then(() => true)
41
46
  .catch(() => false);
42
47
 
48
+ let workerdCronProvider: CronProvider | undefined;
49
+ try {
50
+ workerdCronProvider = opts.alepha.inject(
51
+ "CronProvider",
52
+ ) as WorkerdCronProvider;
53
+ } catch {}
54
+
55
+ const crons = workerdCronProvider?.getCronJobs();
56
+
43
57
  const wrangler: WranglerConfig = {
44
58
  name,
45
59
  main: "./main.cloudflare.js",
@@ -62,6 +76,12 @@ export async function generateCloudflare(
62
76
  };
63
77
  }
64
78
 
79
+ if (crons && crons.length > 0) {
80
+ const cronExpressions = [...new Set(crons.map((c) => c.expression))];
81
+ wrangler.triggers ??= {};
82
+ wrangler.triggers.crons = cronExpressions;
83
+ }
84
+
65
85
  const url = process.env.DATABASE_URL;
66
86
  if (url?.startsWith("d1:")) {
67
87
  const [name, id] = url.replace("d1://", "").replace("d1:", "").split(":");
@@ -102,7 +122,7 @@ export default {
102
122
  try {
103
123
  await __alepha.start();
104
124
  } catch (err) {
105
- console.error(err);
125
+ console.error("Failed to start Alepha for fetch event", err);
106
126
  return new Response("Internal Server Error", { status: 500 });
107
127
  }
108
128
 
@@ -110,6 +130,22 @@ export default {
110
130
 
111
131
  return ctx.res;
112
132
  },
133
+
134
+ scheduled: async (event, env, ctx) => {
135
+ __alepha.set("cloudflare.env", env);
136
+
137
+ try {
138
+ await __alepha.start();
139
+ } catch (err) {
140
+ console.error("Failed to start Alepha for scheduled event", err);
141
+ throw err;
142
+ }
143
+
144
+ await __alepha.events.emit("cloudflare:scheduled", {
145
+ cron: event.cron,
146
+ scheduledTime: event.scheduledTime,
147
+ });
148
+ },
113
149
  };
114
150
  `.trim();
115
151
 
@@ -58,9 +58,9 @@ export * from "./providers/NodeWebSocketServerProvider.ts";
58
58
  // ---------------------------------------------------------------------------------------------------------------------
59
59
 
60
60
  /**
61
- * | type | quality | stability |
62
- * |------|---------|-----------|
63
- * | backend | rare | experimental |
61
+ * | Stability | Since | Runtime |
62
+ * |-----------|-------|---------|
63
+ * | 1 - experimental | 0.19.0 | node, browser|
64
64
  *
65
65
  * Real-time bidirectional communication.
66
66
  *
@@ -1,30 +0,0 @@
1
- export const webHelloComponentTsx = (options: { auth?: boolean } = {}) => {
2
- const imports: string[] = [];
3
-
4
- if (options.auth) {
5
- imports.push('import { UserButton } from "@alepha/ui/auth";');
6
- }
7
- imports.push('import { useState } from "react";');
8
-
9
- const userButton = options.auth ? "\n <UserButton />" : "";
10
-
11
- return `${imports.join("\n")}
12
-
13
- interface Props {
14
- message?: string;
15
- }
16
-
17
- const Hello = (props: Props) => {
18
- const [message, setMessage] = useState(props.message ?? "");
19
- return (
20
- <div>
21
- <h1>{message}</h1>
22
- <input value={message} onChange={(e) => setMessage(e.target.value)} />
23
- <p>Edit this component in src/web/components/Hello.tsx</p>${userButton}
24
- </div>
25
- );
26
- };
27
-
28
- export default Hello;
29
- `;
30
- };