alepha 0.14.3 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/README.md +2 -5
  2. package/dist/api/audits/index.d.ts +620 -811
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/files/index.d.ts +185 -377
  5. package/dist/api/files/index.d.ts.map +1 -1
  6. package/dist/api/files/index.js +0 -1
  7. package/dist/api/files/index.js.map +1 -1
  8. package/dist/api/jobs/index.d.ts +245 -435
  9. package/dist/api/jobs/index.d.ts.map +1 -1
  10. package/dist/api/notifications/index.d.ts +238 -429
  11. package/dist/api/notifications/index.d.ts.map +1 -1
  12. package/dist/api/parameters/index.d.ts +236 -427
  13. package/dist/api/parameters/index.d.ts.map +1 -1
  14. package/dist/api/users/index.browser.js +1 -2
  15. package/dist/api/users/index.browser.js.map +1 -1
  16. package/dist/api/users/index.d.ts +1010 -1196
  17. package/dist/api/users/index.d.ts.map +1 -1
  18. package/dist/api/users/index.js +178 -151
  19. package/dist/api/users/index.js.map +1 -1
  20. package/dist/api/verifications/index.d.ts +17 -17
  21. package/dist/api/verifications/index.d.ts.map +1 -1
  22. package/dist/batch/index.d.ts +122 -122
  23. package/dist/batch/index.d.ts.map +1 -1
  24. package/dist/batch/index.js +1 -2
  25. package/dist/batch/index.js.map +1 -1
  26. package/dist/bucket/index.d.ts +163 -163
  27. package/dist/bucket/index.d.ts.map +1 -1
  28. package/dist/cache/core/index.d.ts +46 -46
  29. package/dist/cache/core/index.d.ts.map +1 -1
  30. package/dist/cache/redis/index.d.ts.map +1 -1
  31. package/dist/cli/index.d.ts +384 -285
  32. package/dist/cli/index.d.ts.map +1 -1
  33. package/dist/cli/index.js +1113 -623
  34. package/dist/cli/index.js.map +1 -1
  35. package/dist/command/index.d.ts +299 -300
  36. package/dist/command/index.d.ts.map +1 -1
  37. package/dist/command/index.js +13 -9
  38. package/dist/command/index.js.map +1 -1
  39. package/dist/core/index.browser.js +445 -103
  40. package/dist/core/index.browser.js.map +1 -1
  41. package/dist/core/index.d.ts +733 -625
  42. package/dist/core/index.d.ts.map +1 -1
  43. package/dist/core/index.js +446 -103
  44. package/dist/core/index.js.map +1 -1
  45. package/dist/core/index.native.js +445 -103
  46. package/dist/core/index.native.js.map +1 -1
  47. package/dist/datetime/index.d.ts +44 -44
  48. package/dist/datetime/index.d.ts.map +1 -1
  49. package/dist/datetime/index.js +4 -4
  50. package/dist/datetime/index.js.map +1 -1
  51. package/dist/email/index.d.ts +97 -50
  52. package/dist/email/index.d.ts.map +1 -1
  53. package/dist/email/index.js +129 -33
  54. package/dist/email/index.js.map +1 -1
  55. package/dist/fake/index.d.ts +7981 -14
  56. package/dist/fake/index.d.ts.map +1 -1
  57. package/dist/file/index.d.ts +523 -390
  58. package/dist/file/index.d.ts.map +1 -1
  59. package/dist/file/index.js +253 -1
  60. package/dist/file/index.js.map +1 -1
  61. package/dist/lock/core/index.d.ts +208 -208
  62. package/dist/lock/core/index.d.ts.map +1 -1
  63. package/dist/lock/redis/index.d.ts.map +1 -1
  64. package/dist/logger/index.d.ts +25 -26
  65. package/dist/logger/index.d.ts.map +1 -1
  66. package/dist/logger/index.js +12 -2
  67. package/dist/logger/index.js.map +1 -1
  68. package/dist/mcp/index.d.ts +197 -197
  69. package/dist/mcp/index.d.ts.map +1 -1
  70. package/dist/mcp/index.js +1 -1
  71. package/dist/mcp/index.js.map +1 -1
  72. package/dist/orm/chunk-DtkW-qnP.js +38 -0
  73. package/dist/orm/index.browser.js.map +1 -1
  74. package/dist/orm/index.bun.js +2814 -0
  75. package/dist/orm/index.bun.js.map +1 -0
  76. package/dist/orm/index.d.ts +1228 -1216
  77. package/dist/orm/index.d.ts.map +1 -1
  78. package/dist/orm/index.js +2041 -1967
  79. package/dist/orm/index.js.map +1 -1
  80. package/dist/queue/core/index.d.ts +248 -248
  81. package/dist/queue/core/index.d.ts.map +1 -1
  82. package/dist/queue/redis/index.d.ts.map +1 -1
  83. package/dist/redis/index.bun.js +285 -0
  84. package/dist/redis/index.bun.js.map +1 -0
  85. package/dist/redis/index.d.ts +118 -136
  86. package/dist/redis/index.d.ts.map +1 -1
  87. package/dist/redis/index.js +18 -38
  88. package/dist/redis/index.js.map +1 -1
  89. package/dist/retry/index.d.ts +69 -69
  90. package/dist/retry/index.d.ts.map +1 -1
  91. package/dist/router/index.d.ts +6 -6
  92. package/dist/router/index.d.ts.map +1 -1
  93. package/dist/scheduler/index.d.ts +25 -25
  94. package/dist/scheduler/index.d.ts.map +1 -1
  95. package/dist/security/index.browser.js +5 -1
  96. package/dist/security/index.browser.js.map +1 -1
  97. package/dist/security/index.d.ts +417 -254
  98. package/dist/security/index.d.ts.map +1 -1
  99. package/dist/security/index.js +386 -86
  100. package/dist/security/index.js.map +1 -1
  101. package/dist/server/auth/index.d.ts +110 -110
  102. package/dist/server/auth/index.d.ts.map +1 -1
  103. package/dist/server/auth/index.js +20 -20
  104. package/dist/server/auth/index.js.map +1 -1
  105. package/dist/server/cache/index.d.ts +62 -47
  106. package/dist/server/cache/index.d.ts.map +1 -1
  107. package/dist/server/cache/index.js +56 -3
  108. package/dist/server/cache/index.js.map +1 -1
  109. package/dist/server/compress/index.d.ts +6 -0
  110. package/dist/server/compress/index.d.ts.map +1 -1
  111. package/dist/server/compress/index.js +36 -1
  112. package/dist/server/compress/index.js.map +1 -1
  113. package/dist/server/cookies/index.d.ts +6 -6
  114. package/dist/server/cookies/index.d.ts.map +1 -1
  115. package/dist/server/cookies/index.js +3 -3
  116. package/dist/server/cookies/index.js.map +1 -1
  117. package/dist/server/core/index.browser.js +2 -2
  118. package/dist/server/core/index.browser.js.map +1 -1
  119. package/dist/server/core/index.d.ts +242 -150
  120. package/dist/server/core/index.d.ts.map +1 -1
  121. package/dist/server/core/index.js +294 -125
  122. package/dist/server/core/index.js.map +1 -1
  123. package/dist/server/cors/index.d.ts +11 -12
  124. package/dist/server/cors/index.d.ts.map +1 -1
  125. package/dist/server/health/index.d.ts +0 -1
  126. package/dist/server/health/index.d.ts.map +1 -1
  127. package/dist/server/helmet/index.d.ts +2 -2
  128. package/dist/server/helmet/index.d.ts.map +1 -1
  129. package/dist/server/links/index.browser.js.map +1 -1
  130. package/dist/server/links/index.d.ts +123 -124
  131. package/dist/server/links/index.d.ts.map +1 -1
  132. package/dist/server/links/index.js +1 -2
  133. package/dist/server/links/index.js.map +1 -1
  134. package/dist/server/metrics/index.d.ts.map +1 -1
  135. package/dist/server/multipart/index.d.ts +6 -6
  136. package/dist/server/multipart/index.d.ts.map +1 -1
  137. package/dist/server/proxy/index.d.ts +102 -103
  138. package/dist/server/proxy/index.d.ts.map +1 -1
  139. package/dist/server/rate-limit/index.d.ts +16 -16
  140. package/dist/server/rate-limit/index.d.ts.map +1 -1
  141. package/dist/server/static/index.d.ts +44 -44
  142. package/dist/server/static/index.d.ts.map +1 -1
  143. package/dist/server/static/index.js +4 -0
  144. package/dist/server/static/index.js.map +1 -1
  145. package/dist/server/swagger/index.d.ts +48 -49
  146. package/dist/server/swagger/index.d.ts.map +1 -1
  147. package/dist/server/swagger/index.js +3 -5
  148. package/dist/server/swagger/index.js.map +1 -1
  149. package/dist/sms/index.d.ts +13 -11
  150. package/dist/sms/index.d.ts.map +1 -1
  151. package/dist/sms/index.js +7 -7
  152. package/dist/sms/index.js.map +1 -1
  153. package/dist/thread/index.d.ts +71 -72
  154. package/dist/thread/index.d.ts.map +1 -1
  155. package/dist/topic/core/index.d.ts +318 -318
  156. package/dist/topic/core/index.d.ts.map +1 -1
  157. package/dist/topic/redis/index.d.ts +6 -6
  158. package/dist/topic/redis/index.d.ts.map +1 -1
  159. package/dist/vite/index.d.ts +5805 -249
  160. package/dist/vite/index.d.ts.map +1 -1
  161. package/dist/vite/index.js +599 -513
  162. package/dist/vite/index.js.map +1 -1
  163. package/dist/websocket/index.browser.js +6 -6
  164. package/dist/websocket/index.browser.js.map +1 -1
  165. package/dist/websocket/index.d.ts +247 -247
  166. package/dist/websocket/index.d.ts.map +1 -1
  167. package/dist/websocket/index.js +6 -6
  168. package/dist/websocket/index.js.map +1 -1
  169. package/package.json +9 -14
  170. package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
  171. package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
  172. package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
  173. package/src/api/users/entities/users.ts +1 -1
  174. package/src/api/users/index.ts +8 -8
  175. package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
  176. package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
  177. package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
  178. package/src/api/users/services/CredentialService.ts +7 -7
  179. package/src/api/users/services/IdentityService.ts +4 -4
  180. package/src/api/users/services/RegistrationService.spec.ts +25 -27
  181. package/src/api/users/services/RegistrationService.ts +38 -27
  182. package/src/api/users/services/SessionCrudService.ts +3 -3
  183. package/src/api/users/services/SessionService.spec.ts +3 -3
  184. package/src/api/users/services/SessionService.ts +28 -9
  185. package/src/api/users/services/UserService.ts +7 -7
  186. package/src/batch/providers/BatchProvider.ts +1 -2
  187. package/src/cli/apps/AlephaCli.ts +0 -2
  188. package/src/cli/apps/AlephaPackageBuilderCli.ts +38 -19
  189. package/src/cli/assets/apiHelloControllerTs.ts +18 -0
  190. package/src/cli/assets/apiIndexTs.ts +16 -0
  191. package/src/cli/assets/claudeMd.ts +303 -0
  192. package/src/cli/assets/mainBrowserTs.ts +2 -2
  193. package/src/cli/assets/mainServerTs.ts +24 -0
  194. package/src/cli/assets/webAppRouterTs.ts +15 -0
  195. package/src/cli/assets/webHelloComponentTsx.ts +16 -0
  196. package/src/cli/assets/webIndexTs.ts +16 -0
  197. package/src/cli/atoms/buildOptions.ts +88 -0
  198. package/src/cli/commands/build.ts +70 -87
  199. package/src/cli/commands/db.ts +21 -22
  200. package/src/cli/commands/deploy.ts +17 -5
  201. package/src/cli/commands/dev.ts +22 -14
  202. package/src/cli/commands/format.ts +8 -2
  203. package/src/cli/commands/gen/env.ts +53 -0
  204. package/src/cli/commands/gen/openapi.ts +1 -1
  205. package/src/cli/commands/gen/resource.ts +15 -0
  206. package/src/cli/commands/gen.ts +7 -1
  207. package/src/cli/commands/init.ts +74 -30
  208. package/src/cli/commands/lint.ts +8 -2
  209. package/src/cli/commands/test.ts +8 -3
  210. package/src/cli/commands/typecheck.ts +5 -1
  211. package/src/cli/commands/verify.ts +5 -3
  212. package/src/cli/defineConfig.ts +49 -7
  213. package/src/cli/index.ts +0 -1
  214. package/src/cli/services/AlephaCliUtils.ts +39 -589
  215. package/src/cli/services/PackageManagerUtils.ts +301 -0
  216. package/src/cli/services/ProjectScaffolder.ts +306 -0
  217. package/src/command/helpers/Runner.spec.ts +2 -2
  218. package/src/command/helpers/Runner.ts +16 -4
  219. package/src/command/primitives/$command.ts +0 -6
  220. package/src/command/providers/CliProvider.ts +1 -3
  221. package/src/core/Alepha.ts +42 -0
  222. package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
  223. package/src/core/index.shared.ts +1 -0
  224. package/src/core/index.ts +2 -0
  225. package/src/core/primitives/$hook.ts +6 -2
  226. package/src/core/primitives/$module.spec.ts +4 -0
  227. package/src/core/providers/AlsProvider.ts +1 -1
  228. package/src/core/providers/CodecManager.spec.ts +12 -6
  229. package/src/core/providers/CodecManager.ts +26 -6
  230. package/src/core/providers/EventManager.ts +169 -13
  231. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +621 -0
  232. package/src/core/providers/KeylessJsonSchemaCodec.ts +407 -0
  233. package/src/core/providers/StateManager.spec.ts +27 -16
  234. package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
  235. package/src/email/providers/LocalEmailProvider.ts +52 -15
  236. package/src/email/providers/NodemailerEmailProvider.ts +167 -56
  237. package/src/file/errors/FileError.ts +7 -0
  238. package/src/file/index.ts +9 -1
  239. package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
  240. package/src/logger/index.ts +15 -3
  241. package/src/mcp/transports/StdioMcpTransport.ts +1 -1
  242. package/src/orm/index.browser.ts +1 -19
  243. package/src/orm/index.bun.ts +77 -0
  244. package/src/orm/index.shared-server.ts +22 -0
  245. package/src/orm/index.shared.ts +15 -0
  246. package/src/orm/index.ts +13 -39
  247. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
  248. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  249. package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
  250. package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
  251. package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
  252. package/src/orm/services/Repository.ts +8 -0
  253. package/src/queue/core/providers/WorkerProvider.spec.ts +48 -32
  254. package/src/redis/index.bun.ts +35 -0
  255. package/src/redis/providers/BunRedisProvider.ts +12 -43
  256. package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
  257. package/src/redis/providers/NodeRedisProvider.ts +16 -34
  258. package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
  259. package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
  260. package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
  261. package/src/security/index.browser.ts +5 -0
  262. package/src/security/index.ts +90 -7
  263. package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
  264. package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
  265. package/src/security/primitives/$role.ts +5 -5
  266. package/src/security/primitives/$serviceAccount.spec.ts +5 -5
  267. package/src/security/primitives/$serviceAccount.ts +3 -3
  268. package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
  269. package/src/server/auth/primitives/$auth.ts +10 -10
  270. package/src/server/auth/primitives/$authCredentials.ts +3 -3
  271. package/src/server/auth/primitives/$authGithub.ts +3 -3
  272. package/src/server/auth/primitives/$authGoogle.ts +3 -3
  273. package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
  274. package/src/server/cache/providers/ServerCacheProvider.spec.ts +183 -0
  275. package/src/server/cache/providers/ServerCacheProvider.ts +95 -10
  276. package/src/server/compress/providers/ServerCompressProvider.ts +61 -2
  277. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
  278. package/src/server/core/helpers/ServerReply.ts +2 -2
  279. package/src/server/core/providers/NodeHttpServerProvider.ts +25 -6
  280. package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
  281. package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
  282. package/src/server/core/providers/ServerProvider.ts +155 -22
  283. package/src/server/core/providers/ServerRouterProvider.ts +259 -115
  284. package/src/server/core/providers/ServerTimingProvider.ts +2 -2
  285. package/src/server/links/index.ts +1 -1
  286. package/src/server/links/providers/LinkProvider.ts +1 -1
  287. package/src/server/static/providers/ServerStaticProvider.ts +10 -0
  288. package/src/server/swagger/index.ts +1 -1
  289. package/src/server/swagger/providers/ServerSwaggerProvider.ts +5 -8
  290. package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
  291. package/src/sms/providers/LocalSmsProvider.ts +8 -7
  292. package/src/vite/helpers/boot.ts +28 -17
  293. package/src/vite/helpers/importViteReact.ts +13 -0
  294. package/src/vite/index.ts +1 -21
  295. package/src/vite/plugins/viteAlephaDev.ts +16 -1
  296. package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
  297. package/src/vite/tasks/buildClient.ts +11 -0
  298. package/src/vite/tasks/buildServer.ts +59 -4
  299. package/src/vite/tasks/devServer.ts +71 -0
  300. package/src/vite/tasks/generateCloudflare.ts +7 -0
  301. package/src/vite/tasks/index.ts +2 -1
  302. package/dist/server/security/index.browser.js +0 -13
  303. package/dist/server/security/index.browser.js.map +0 -1
  304. package/dist/server/security/index.d.ts +0 -173
  305. package/dist/server/security/index.d.ts.map +0 -1
  306. package/dist/server/security/index.js +0 -311
  307. package/dist/server/security/index.js.map +0 -1
  308. package/src/cli/assets/appRouterTs.ts +0 -9
  309. package/src/cli/assets/mainTs.ts +0 -13
  310. package/src/cli/assets/viteConfigTs.ts +0 -14
  311. package/src/cli/commands/run.ts +0 -24
  312. package/src/server/security/index.browser.ts +0 -10
  313. package/src/server/security/index.ts +0 -94
  314. package/src/vite/plugins/viteAlepha.ts +0 -37
  315. package/src/vite/plugins/viteAlephaBuild.ts +0 -281
  316. /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
  317. /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
@@ -4,19 +4,23 @@ import {
4
4
  type RedisClientType,
5
5
  type SetOptions,
6
6
  } from "@redis/client";
7
- import { $env, $hook, $inject, Alepha, type Static, t } from "alepha";
7
+ import {
8
+ $env,
9
+ $hook,
10
+ $inject,
11
+ Alepha,
12
+ AlephaError,
13
+ type Static,
14
+ t,
15
+ } from "alepha";
8
16
  import { $logger } from "alepha/logger";
9
17
  import { RedisProvider, type RedisSetOptions } from "./RedisProvider.ts";
10
18
 
11
19
  const envSchema = t.object({
12
- REDIS_URL: t.optional(t.text()),
13
- REDIS_PORT: t.integer({
14
- default: "6379",
15
- }),
16
- REDIS_HOST: t.text({
17
- default: "localhost",
20
+ REDIS_URL: t.text({
21
+ default: "redis://localhost:6379",
22
+ description: "Redis connection URL",
18
23
  }),
19
- REDIS_PASSWORD: t.optional(t.text()),
20
24
  });
21
25
 
22
26
  declare module "alepha" {
@@ -39,10 +43,8 @@ export type NodeRedisClientOptions = Parameters<typeof createClient>[0];
39
43
  *
40
44
  * @example
41
45
  * ```ts
42
- * // Set REDIS_URL environment variable
43
- * // REDIS_URL=redis://localhost:6379
44
- *
45
- * // Or configure via REDIS_HOST, REDIS_PORT, REDIS_PASSWORD
46
+ * // Set REDIS_URL environment variable (default: redis://localhost:6379)
47
+ * // REDIS_URL=redis://:password@myredis.example.com:6379
46
48
  *
47
49
  * // Or configure programmatically
48
50
  * alepha.with({
@@ -59,7 +61,7 @@ export class NodeRedisProvider extends RedisProvider {
59
61
 
60
62
  public get publisher(): NodeRedisClient {
61
63
  if (!this.client.isReady) {
62
- throw new Error("Redis client is not ready");
64
+ throw new AlephaError("Redis client is not ready");
63
65
  }
64
66
 
65
67
  return this.client;
@@ -235,27 +237,7 @@ export class NodeRedisProvider extends RedisProvider {
235
237
  * Get the Redis connection URL.
236
238
  */
237
239
  protected getUrl(): string {
238
- // Prefer REDIS_URL if set
239
- if (this.env.REDIS_URL) {
240
- return this.env.REDIS_URL;
241
- }
242
-
243
- // Build URL from components
244
- const url = new URL("redis://127.0.0.1:6379");
245
-
246
- if (this.env.REDIS_PASSWORD) {
247
- url.password = this.env.REDIS_PASSWORD;
248
- }
249
-
250
- if (this.env.REDIS_HOST) {
251
- url.hostname = this.env.REDIS_HOST;
252
- }
253
-
254
- if (this.env.REDIS_PORT) {
255
- url.port = String(this.env.REDIS_PORT);
256
- }
257
-
258
- return url.toString();
240
+ return this.env.REDIS_URL;
259
241
  }
260
242
 
261
243
  /**
@@ -3,7 +3,7 @@ import { $action, AlephaServer } from "alepha/server";
3
3
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
4
4
  import {
5
5
  $basicAuth,
6
- AlephaServerSecurity,
6
+ AlephaSecurity,
7
7
  ServerBasicAuthProvider,
8
8
  } from "../index.ts";
9
9
 
@@ -58,7 +58,7 @@ describe("Basic Authentication", () => {
58
58
  beforeEach(async () => {
59
59
  alepha = Alepha.create()
60
60
  .with(AlephaServer)
61
- .with(AlephaServerSecurity)
61
+ .with(AlephaSecurity)
62
62
  .with(TestApp);
63
63
 
64
64
  await alepha.start();
@@ -269,7 +269,7 @@ describe("Basic Authentication", () => {
269
269
 
270
270
  const edgeAlepha = Alepha.create()
271
271
  .with(AlephaServer)
272
- .with(AlephaServerSecurity)
272
+ .with(AlephaSecurity)
273
273
  .with(EdgeCaseApp);
274
274
 
275
275
  await edgeAlepha.start();
@@ -301,7 +301,7 @@ describe("Basic Authentication", () => {
301
301
 
302
302
  const emptyAlepha = Alepha.create()
303
303
  .with(AlephaServer)
304
- .with(AlephaServerSecurity)
304
+ .with(AlephaSecurity)
305
305
  .with(EmptyPasswordApp);
306
306
 
307
307
  await emptyAlepha.start();
@@ -333,7 +333,7 @@ describe("Basic Authentication", () => {
333
333
 
334
334
  const specialAlepha = Alepha.create()
335
335
  .with(AlephaServer)
336
- .with(AlephaServerSecurity)
336
+ .with(AlephaSecurity)
337
337
  .with(SpecialCharsApp);
338
338
 
339
339
  await specialAlepha.start();
@@ -365,7 +365,7 @@ describe("Basic Authentication", () => {
365
365
 
366
366
  const unicodeAlepha = Alepha.create()
367
367
  .with(AlephaServer)
368
- .with(AlephaServerSecurity)
368
+ .with(AlephaSecurity)
369
369
  .with(UnicodeApp);
370
370
 
371
371
  await unicodeAlepha.start();
@@ -397,7 +397,7 @@ describe("Basic Authentication", () => {
397
397
 
398
398
  const unicodeAlepha = Alepha.create()
399
399
  .with(AlephaServer)
400
- .with(AlephaServerSecurity)
400
+ .with(AlephaSecurity)
401
401
  .with(UnicodeApp);
402
402
 
403
403
  await unicodeAlepha.start();
@@ -434,7 +434,7 @@ describe("Basic Authentication", () => {
434
434
 
435
435
  const longAlepha = Alepha.create()
436
436
  .with(AlephaServer)
437
- .with(AlephaServerSecurity)
437
+ .with(AlephaSecurity)
438
438
  .with(LongCredsApp);
439
439
 
440
440
  await longAlepha.start();
@@ -466,7 +466,7 @@ describe("Basic Authentication", () => {
466
466
 
467
467
  const emptyUserAlepha = Alepha.create()
468
468
  .with(AlephaServer)
469
- .with(AlephaServerSecurity)
469
+ .with(AlephaSecurity)
470
470
  .with(EmptyUsernameApp);
471
471
 
472
472
  await emptyUserAlepha.start();
@@ -549,7 +549,7 @@ describe("Basic Authentication", () => {
549
549
 
550
550
  const wsAlepha = Alepha.create()
551
551
  .with(AlephaServer)
552
- .with(AlephaServerSecurity)
552
+ .with(AlephaSecurity)
553
553
  .with(WhitespaceApp);
554
554
 
555
555
  await wsAlepha.start();
@@ -582,7 +582,7 @@ describe("Basic Authentication", () => {
582
582
 
583
583
  const wsAlepha = Alepha.create()
584
584
  .with(AlephaServer)
585
- .with(AlephaServerSecurity)
585
+ .with(AlephaSecurity)
586
586
  .with(WhitespaceApp);
587
587
 
588
588
  await wsAlepha.start();
@@ -1,14 +1,19 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { Alepha } from "alepha";
3
- import { $realm } from "alepha/security";
4
- import { $action, $route, ForbiddenError, ServerProvider } from "alepha/server";
3
+ import {
4
+ $action,
5
+ $route,
6
+ AlephaServer,
7
+ ForbiddenError,
8
+ ServerProvider,
9
+ } from "alepha/server";
5
10
  import { describe, expect, it } from "vitest";
6
- import { AlephaServerSecurity } from "../index.ts";
11
+ import { $issuer, AlephaSecurity } from "../index.ts";
7
12
 
8
13
  describe("ServerSecurityProvider - Realm Protection", () => {
9
14
  it("should allow access when user belongs to the required realm", async () => {
10
15
  class TestApp {
11
- realmA = $realm({
16
+ realmA = $issuer({
12
17
  secret: "test-realm-a",
13
18
  roles: [
14
19
  {
@@ -18,7 +23,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
18
23
  ],
19
24
  });
20
25
 
21
- realmB = $realm({
26
+ realmB = $issuer({
22
27
  secret: "test-realm-b",
23
28
  roles: [
24
29
  {
@@ -43,7 +48,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
43
48
  });
44
49
  }
45
50
 
46
- const alepha = Alepha.create().with(AlephaServerSecurity);
51
+ const alepha = Alepha.create().with(AlephaServer).with(AlephaSecurity);
47
52
  const app = alepha.inject(TestApp);
48
53
  await alepha.start();
49
54
 
@@ -85,7 +90,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
85
90
 
86
91
  it("should deny access when user does not belong to the required realm", async () => {
87
92
  class TestApp {
88
- realmA = $realm({
93
+ realmA = $issuer({
89
94
  secret: "test-realm-a",
90
95
  roles: [
91
96
  {
@@ -95,7 +100,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
95
100
  ],
96
101
  });
97
102
 
98
- realmB = $realm({
103
+ realmB = $issuer({
99
104
  secret: "test-realm-b",
100
105
  roles: [
101
106
  {
@@ -120,7 +125,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
120
125
  });
121
126
  }
122
127
 
123
- const alepha = Alepha.create().with(AlephaServerSecurity);
128
+ const alepha = Alepha.create().with(AlephaServer).with(AlephaSecurity);
124
129
  const app = alepha.inject(TestApp);
125
130
  await alepha.start();
126
131
 
@@ -172,7 +177,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
172
177
 
173
178
  it("should work with actions when user has no realm attribute", async () => {
174
179
  class TestApp {
175
- realmA = $realm({
180
+ realmA = $issuer({
176
181
  secret: "test-realm-a",
177
182
  roles: [
178
183
  {
@@ -188,7 +193,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
188
193
  });
189
194
  }
190
195
 
191
- const alepha = Alepha.create().with(AlephaServerSecurity);
196
+ const alepha = Alepha.create().with(AlephaServer).with(AlephaSecurity);
192
197
  const app = alepha.inject(TestApp);
193
198
  await alepha.start();
194
199
 
@@ -215,7 +220,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
215
220
 
216
221
  it("should combine realm and permission checks", async () => {
217
222
  class TestApp {
218
- realmA = $realm({
223
+ realmA = $issuer({
219
224
  secret: "test-realm-a",
220
225
  roles: [
221
226
  {
@@ -229,7 +234,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
229
234
  ],
230
235
  });
231
236
 
232
- realmB = $realm({
237
+ realmB = $issuer({
233
238
  secret: "test-realm-b",
234
239
  });
235
240
 
@@ -248,7 +253,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
248
253
  });
249
254
  }
250
255
 
251
- const alepha = Alepha.create().with(AlephaServerSecurity);
256
+ const alepha = Alepha.create().with(AlephaServer).with(AlephaSecurity);
252
257
  const app = alepha.inject(TestApp);
253
258
  await alepha.start();
254
259
 
@@ -336,7 +341,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
336
341
 
337
342
  it("should work with fetch requests when realm is valid", async () => {
338
343
  class TestApp {
339
- realmA = $realm({
344
+ realmA = $issuer({
340
345
  secret: "test-realm-a",
341
346
  roles: [
342
347
  {
@@ -352,7 +357,7 @@ describe("ServerSecurityProvider - Realm Protection", () => {
352
357
  });
353
358
  }
354
359
 
355
- const alepha = Alepha.create().with(AlephaServerSecurity);
360
+ const alepha = Alepha.create().with(AlephaServer).with(AlephaSecurity);
356
361
  const app = alepha.inject(TestApp);
357
362
  await alepha.start();
358
363
 
@@ -1,15 +1,15 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { Alepha } from "alepha";
3
- import { $realm } from "alepha/security";
4
3
  import {
5
4
  $action,
5
+ AlephaServer,
6
6
  ForbiddenError,
7
7
  HttpError,
8
8
  ServerProvider,
9
9
  UnauthorizedError,
10
10
  } from "alepha/server";
11
11
  import { describe, expect, it } from "vitest";
12
- import { AlephaServerSecurity } from "../index.ts";
12
+ import { $issuer, AlephaSecurity } from "../index.ts";
13
13
 
14
14
  describe("ServerSecurityProvider", () => {
15
15
  it("should protect action from unauthorized users", async () => {
@@ -19,7 +19,7 @@ describe("ServerSecurityProvider", () => {
19
19
  });
20
20
  }
21
21
 
22
- const alepha = Alepha.create().with(AlephaServerSecurity);
22
+ const alepha = Alepha.create().with(AlephaServer).with(AlephaSecurity);
23
23
  const app = alepha.inject(TestApp);
24
24
  await alepha.start();
25
25
 
@@ -62,7 +62,7 @@ describe("ServerSecurityProvider", () => {
62
62
  group: "read",
63
63
  handler: () => "USER",
64
64
  });
65
- realm = $realm({
65
+ issuer = $issuer({
66
66
  secret: "test",
67
67
  roles: [
68
68
  {
@@ -77,7 +77,7 @@ describe("ServerSecurityProvider", () => {
77
77
  });
78
78
  }
79
79
 
80
- const alepha = Alepha.create().with(AlephaServerSecurity);
80
+ const alepha = Alepha.create().with(AlephaServer).with(AlephaSecurity);
81
81
  const app = alepha.inject(TestApp);
82
82
  await alepha.start();
83
83
 
@@ -11,3 +11,8 @@ export * from "./schemas/userAccountInfoSchema.ts";
11
11
  export const AlephaSecurity = $module({
12
12
  name: "alepha.security",
13
13
  });
14
+
15
+ /**
16
+ * @deprecated Use `AlephaSecurity` instead. Server security providers are automatically registered when `AlephaServer` is available.
17
+ */
18
+ export const AlephaServerSecurity = AlephaSecurity;
@@ -1,27 +1,37 @@
1
- import { $module } from "alepha";
1
+ import { $module, type Alepha } from "alepha";
2
+ import { AlephaServer, type FetchOptions } from "alepha/server";
3
+ import type { UserAccountToken } from "./interfaces/UserAccountToken.ts";
4
+ import { $basicAuth } from "./primitives/$basicAuth.ts";
5
+ import { $issuer } from "./primitives/$issuer.ts";
2
6
  import { $permission } from "./primitives/$permission.ts";
3
- import { $realm } from "./primitives/$realm.ts";
4
7
  import { $role } from "./primitives/$role.ts";
5
8
  import { CryptoProvider } from "./providers/CryptoProvider.ts";
6
9
  import { JwtProvider } from "./providers/JwtProvider.ts";
7
10
  import { SecurityProvider } from "./providers/SecurityProvider.ts";
11
+ import { ServerBasicAuthProvider } from "./providers/ServerBasicAuthProvider.ts";
12
+ import { ServerSecurityProvider } from "./providers/ServerSecurityProvider.ts";
8
13
  import type { UserAccount } from "./schemas/userAccountInfoSchema.ts";
9
14
 
10
15
  export * from "./errors/InvalidCredentialsError.ts";
11
16
  export * from "./errors/InvalidPermissionError.ts";
12
17
  export * from "./errors/SecurityError.ts";
13
18
  export * from "./interfaces/UserAccountToken.ts";
19
+ export * from "./primitives/$basicAuth.ts";
20
+ export * from "./primitives/$issuer.ts";
14
21
  export * from "./primitives/$permission.ts";
15
- export * from "./primitives/$realm.ts";
16
22
  export * from "./primitives/$role.ts";
17
23
  export * from "./primitives/$serviceAccount.ts";
18
24
  export * from "./providers/CryptoProvider.ts";
19
25
  export * from "./providers/JwtProvider.ts";
20
26
  export * from "./providers/SecurityProvider.ts";
27
+ export * from "./providers/ServerBasicAuthProvider.ts";
28
+ export * from "./providers/ServerSecurityProvider.ts";
21
29
  export * from "./schemas/permissionSchema.ts";
22
30
  export * from "./schemas/roleSchema.ts";
23
31
  export * from "./schemas/userAccountInfoSchema.ts";
24
32
 
33
+ import type { ServerRouteSecure } from "./providers/ServerSecurityProvider.ts";
34
+
25
35
  declare module "alepha" {
26
36
  interface Hooks {
27
37
  "security:user:created": {
@@ -29,22 +39,95 @@ declare module "alepha" {
29
39
  user: UserAccount;
30
40
  };
31
41
  }
42
+
43
+ interface State {
44
+ /**
45
+ * Real (or fake) user account, used for internal actions.
46
+ *
47
+ * If you define this, you assume that all actions are executed by this user by default.
48
+ * > To force a different user, you need to pass it explicitly in the options.
49
+ */
50
+ "alepha.server.security.system.user"?: UserAccountToken;
51
+
52
+ /**
53
+ * The authenticated user account attached to the server request state.
54
+ *
55
+ * @internal
56
+ */
57
+ "alepha.server.request.user"?: UserAccount;
58
+ }
59
+ }
60
+
61
+ declare module "alepha/server" {
62
+ interface ServerRequest<TConfig> {
63
+ user?: UserAccountToken; // for all routes, user is maybe present
64
+ }
65
+
66
+ interface ServerActionRequest<TConfig> {
67
+ user: UserAccountToken; // for actions, user is always present
68
+ }
69
+
70
+ interface ServerRoute {
71
+ /**
72
+ * If true, the route will be protected by the security provider.
73
+ * All actions are secure by default, but you can disable it for specific actions.
74
+ */
75
+ secure?: boolean | ServerRouteSecure;
76
+ }
77
+
78
+ interface ClientRequestOptions extends FetchOptions {
79
+ /**
80
+ * Forward user from the previous request.
81
+ * If "system", use system user. @see {ServerSecurityProvider.localSystemUser}
82
+ * If "context", use the user from the current context (e.g. request).
83
+ *
84
+ * @default "system" if provided, else "context" if available.
85
+ */
86
+ user?: UserAccountToken | "system" | "context";
87
+ }
32
88
  }
33
89
 
34
90
  /**
35
91
  * Provides comprehensive authentication and authorization capabilities with JWT tokens, role-based access control, and user management.
36
92
  *
37
- * The security module enables building secure applications using primitives like `$realm`, `$role`, and `$permission`
93
+ * The security module enables building secure applications using primitives like `$issuer`, `$role`, and `$permission`
38
94
  * on class properties. It offers JWT-based authentication, fine-grained permissions, service accounts, and seamless
39
95
  * integration with various authentication providers and user management systems.
40
96
  *
41
- * @see {@link $realm}
97
+ * When used with `AlephaServer`, this module automatically registers `ServerSecurityProvider` and `ServerBasicAuthProvider`
98
+ * to protect HTTP routes and actions with JWT and Basic Auth.
99
+ *
100
+ * @see {@link $issuer}
42
101
  * @see {@link $role}
43
102
  * @see {@link $permission}
103
+ * @see {@link $basicAuth}
44
104
  * @module alepha.security
45
105
  */
46
106
  export const AlephaSecurity = $module({
47
107
  name: "alepha.security",
48
- primitives: [$realm, $role, $permission],
49
- services: [SecurityProvider, JwtProvider, CryptoProvider],
108
+ primitives: [$issuer, $role, $permission, $basicAuth],
109
+ services: [
110
+ SecurityProvider,
111
+ JwtProvider,
112
+ CryptoProvider,
113
+ ServerSecurityProvider,
114
+ ServerBasicAuthProvider,
115
+ ],
116
+ register: (alepha: Alepha) => {
117
+ // Always register core security providers
118
+ alepha.with(SecurityProvider);
119
+ alepha.with(JwtProvider);
120
+ alepha.with(CryptoProvider);
121
+
122
+ // Register server security providers only if AlephaServer is available
123
+ if (alepha.has(AlephaServer)) {
124
+ alepha.with(ServerSecurityProvider);
125
+ alepha.with(ServerBasicAuthProvider);
126
+ }
127
+ },
50
128
  });
129
+
130
+ /**
131
+ * @deprecated Use `AlephaSecurity` instead. Server security providers are automatically registered when `AlephaServer` is available.
132
+ */
133
+ export const AlephaServerSecurity = AlephaSecurity;
@@ -2,9 +2,9 @@ import { randomUUID } from "node:crypto";
2
2
  import { Alepha } from "alepha";
3
3
  import { DateTimeProvider } from "alepha/datetime";
4
4
  import { describe, test } from "vitest";
5
- import { $realm } from "../index.ts";
5
+ import { $issuer } from "../index.ts";
6
6
 
7
- describe("$realm", () => {
7
+ describe("$issuer", () => {
8
8
  const roles = [
9
9
  {
10
10
  name: "admin",
@@ -18,7 +18,7 @@ describe("$realm", () => {
18
18
 
19
19
  test("should create token (access & refresh)", async ({ expect }) => {
20
20
  class App {
21
- realm = $realm({
21
+ issuer = $issuer({
22
22
  secret: "test",
23
23
  roles,
24
24
  });
@@ -37,15 +37,15 @@ describe("$realm", () => {
37
37
 
38
38
  const now = dt.pause();
39
39
 
40
- const token = await app.realm.createToken(user);
40
+ const token = await app.issuer.createToken(user);
41
41
 
42
42
  expect(token).toEqual({
43
43
  access_token: expect.any(String),
44
- expires_in: app.realm.accessTokenExpiration.asSeconds(),
44
+ expires_in: app.issuer.accessTokenExpiration.asSeconds(),
45
45
  refresh_token: expect.any(String),
46
46
  token_type: "Bearer",
47
47
  issued_at: now.unix(),
48
- refresh_token_expires_in: app.realm.refreshTokenExpiration.asSeconds(),
48
+ refresh_token_expires_in: app.issuer.refreshTokenExpiration.asSeconds(),
49
49
  });
50
50
 
51
51
  expect(
@@ -54,9 +54,9 @@ describe("$realm", () => {
54
54
  ),
55
55
  ).toEqual({
56
56
  sub: user.id,
57
- aud: app.realm.name,
57
+ aud: app.issuer.name,
58
58
  iat: now.unix(),
59
- exp: now.unix() + app.realm.accessTokenExpiration.asSeconds(),
59
+ exp: now.unix() + app.issuer.accessTokenExpiration.asSeconds(),
60
60
  name: user.name,
61
61
  roles: ["admin", "user"],
62
62
  sid: expect.any(String),
@@ -71,9 +71,9 @@ describe("$realm", () => {
71
71
  ),
72
72
  ).toEqual({
73
73
  sub: user.id,
74
- aud: app.realm.name,
74
+ aud: app.issuer.name,
75
75
  iat: now.unix(),
76
- exp: now.unix() + app.realm.refreshTokenExpiration.asSeconds(),
76
+ exp: now.unix() + app.issuer.refreshTokenExpiration.asSeconds(),
77
77
  });
78
78
 
79
79
  expect(
@@ -88,7 +88,7 @@ describe("$realm", () => {
88
88
  typ: "refresh",
89
89
  });
90
90
 
91
- const newToken = await app.realm.createToken(user, token);
91
+ const newToken = await app.issuer.createToken(user, token);
92
92
  expect(newToken).toEqual({
93
93
  access_token: expect.any(String),
94
94
  issued_at: now.unix(),
@@ -13,43 +13,46 @@ import type { Role } from "../schemas/roleSchema.ts";
13
13
  import type { UserAccount } from "../schemas/userAccountInfoSchema.ts";
14
14
 
15
15
  /**
16
- * Create a new realm.
16
+ * Create a new issuer.
17
+ *
18
+ * An issuer is responsible for creating and verifying JWT tokens.
19
+ * It can be internal (with a secret) or external (with a JWKS).
17
20
  */
18
- export const $realm = (options: RealmPrimitiveOptions): RealmPrimitive => {
19
- return createPrimitive(RealmPrimitive, options);
21
+ export const $issuer = (options: IssuerPrimitiveOptions): IssuerPrimitive => {
22
+ return createPrimitive(IssuerPrimitive, options);
20
23
  };
21
24
 
22
25
  // ---------------------------------------------------------------------------------------------------------------------
23
26
 
24
- export type RealmPrimitiveOptions = {
27
+ export type IssuerPrimitiveOptions = {
25
28
  /**
26
- * Define the realm name.
29
+ * Define the issuer name.
27
30
  * If not provided, it will use the property key.
28
31
  */
29
32
  name?: string;
30
33
 
31
34
  /**
32
- * Short description about the realm.
35
+ * Short description about the issuer.
33
36
  */
34
37
  description?: string;
35
38
 
36
39
  /**
37
- * All roles available in the realm. Role is a string (role name) or a Role object (embedded role).
40
+ * All roles available in the issuer. Role is a string (role name) or a Role object (embedded role).
38
41
  */
39
42
  roles?: Array<string | Role>;
40
43
 
41
44
  /**
42
- * Realm settings.
45
+ * Issuer settings.
43
46
  */
44
- settings?: RealmSettings;
47
+ settings?: IssuerSettings;
45
48
 
46
49
  /**
47
50
  * Parse the JWT payload to create a user account info.
48
51
  */
49
52
  profile?: (jwtPayload: Record<string, any>) => UserAccount;
50
- } & (RealmInternal | RealmExternal);
53
+ } & (IssuerInternal | IssuerExternal);
51
54
 
52
- export interface RealmSettings {
55
+ export interface IssuerSettings {
53
56
  accessToken?: {
54
57
  /**
55
58
  * Lifetime of the access token.
@@ -87,14 +90,14 @@ export interface RealmSettings {
87
90
  onDeleteSession?: (refreshToken: string) => Promise<void>;
88
91
  }
89
92
 
90
- export type RealmInternal = {
93
+ export type IssuerInternal = {
91
94
  /**
92
95
  * Internal secret to sign JWT tokens and verify them.
93
96
  */
94
97
  secret: string;
95
98
  };
96
99
 
97
- export interface RealmExternal {
100
+ export interface IssuerExternal {
98
101
  /**
99
102
  * URL to the JWKS (JSON Web Key Set) to verify JWT tokens from external providers.
100
103
  */
@@ -103,7 +106,7 @@ export interface RealmExternal {
103
106
 
104
107
  // ---------------------------------------------------------------------------------------------------------------------
105
108
 
106
- export class RealmPrimitive extends Primitive<RealmPrimitiveOptions> {
109
+ export class IssuerPrimitive extends Primitive<IssuerPrimitiveOptions> {
107
110
  protected readonly securityProvider = $inject(SecurityProvider);
108
111
  protected readonly dateTimeProvider = $inject(DateTimeProvider);
109
112
  protected readonly jwt = $inject(JwtProvider);
@@ -148,14 +151,14 @@ export class RealmPrimitive extends Primitive<RealmPrimitiveOptions> {
148
151
  }
149
152
 
150
153
  /**
151
- * Get all roles in the realm.
154
+ * Get all roles in the issuer.
152
155
  */
153
156
  public getRoles(): Role[] {
154
157
  return this.securityProvider.getRoles(this.name);
155
158
  }
156
159
 
157
160
  /**
158
- * Set all roles in the realm.
161
+ * Set all roles in the issuer.
159
162
  */
160
163
  public async setRoles(roles: Role[]): Promise<void> {
161
164
  await this.securityProvider.updateRealm(this.name, roles);
@@ -336,7 +339,7 @@ export class RealmPrimitive extends Primitive<RealmPrimitiveOptions> {
336
339
  }
337
340
  }
338
341
 
339
- $realm[KIND] = RealmPrimitive;
342
+ $issuer[KIND] = IssuerPrimitive;
340
343
 
341
344
  // ---------------------------------------------------------------------------------------------------------------------
342
345