alepha 0.13.1 → 0.13.2

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 (296) hide show
  1. package/README.md +1 -1
  2. package/dist/api-files/index.d.ts +28 -91
  3. package/dist/api-files/index.js +10 -755
  4. package/dist/api-files/index.js.map +1 -1
  5. package/dist/api-jobs/index.d.ts +46 -46
  6. package/dist/api-jobs/index.js +13 -13
  7. package/dist/api-jobs/index.js.map +1 -1
  8. package/dist/api-notifications/index.d.ts +129 -146
  9. package/dist/api-notifications/index.js +17 -39
  10. package/dist/api-notifications/index.js.map +1 -1
  11. package/dist/api-parameters/index.d.ts +21 -22
  12. package/dist/api-parameters/index.js +22 -22
  13. package/dist/api-parameters/index.js.map +1 -1
  14. package/dist/api-users/index.d.ts +223 -2000
  15. package/dist/api-users/index.js +914 -4787
  16. package/dist/api-users/index.js.map +1 -1
  17. package/dist/api-verifications/index.d.ts +96 -96
  18. package/dist/batch/index.d.ts +13 -13
  19. package/dist/batch/index.js +8 -8
  20. package/dist/batch/index.js.map +1 -1
  21. package/dist/bucket/index.d.ts +14 -14
  22. package/dist/bucket/index.js +12 -12
  23. package/dist/bucket/index.js.map +1 -1
  24. package/dist/cache/index.d.ts +11 -11
  25. package/dist/cache/index.js +9 -9
  26. package/dist/cache/index.js.map +1 -1
  27. package/dist/cli/index.d.ts +28 -26
  28. package/dist/cli/index.js +50 -13
  29. package/dist/cli/index.js.map +1 -1
  30. package/dist/command/index.d.ts +19 -19
  31. package/dist/command/index.js +25 -25
  32. package/dist/command/index.js.map +1 -1
  33. package/dist/core/index.browser.js +218 -218
  34. package/dist/core/index.browser.js.map +1 -1
  35. package/dist/core/index.d.ts +232 -232
  36. package/dist/core/index.js +218 -218
  37. package/dist/core/index.js.map +1 -1
  38. package/dist/core/index.native.js +2113 -0
  39. package/dist/core/index.native.js.map +1 -0
  40. package/dist/datetime/index.d.ts +9 -9
  41. package/dist/datetime/index.js +7 -7
  42. package/dist/datetime/index.js.map +1 -1
  43. package/dist/email/index.d.ts +16 -16
  44. package/dist/email/index.js +9 -9
  45. package/dist/email/index.js.map +1 -1
  46. package/dist/file/index.js +1 -1
  47. package/dist/file/index.js.map +1 -1
  48. package/dist/lock/index.d.ts +9 -9
  49. package/dist/lock/index.js +8 -8
  50. package/dist/lock/index.js.map +1 -1
  51. package/dist/lock-redis/index.js +3 -66
  52. package/dist/lock-redis/index.js.map +1 -1
  53. package/dist/logger/index.d.ts +5 -5
  54. package/dist/logger/index.js +8 -8
  55. package/dist/logger/index.js.map +1 -1
  56. package/dist/orm/index.browser.js +114 -114
  57. package/dist/orm/index.browser.js.map +1 -1
  58. package/dist/orm/index.d.ts +218 -218
  59. package/dist/orm/index.js +46 -46
  60. package/dist/orm/index.js.map +1 -1
  61. package/dist/queue/index.d.ts +29 -29
  62. package/dist/queue/index.js +20 -20
  63. package/dist/queue/index.js.map +1 -1
  64. package/dist/queue-redis/index.d.ts +2 -2
  65. package/dist/redis/index.d.ts +10 -10
  66. package/dist/retry/index.d.ts +19 -19
  67. package/dist/retry/index.js +7 -7
  68. package/dist/retry/index.js.map +1 -1
  69. package/dist/scheduler/index.d.ts +16 -16
  70. package/dist/scheduler/index.js +9 -9
  71. package/dist/scheduler/index.js.map +1 -1
  72. package/dist/security/index.d.ts +80 -80
  73. package/dist/security/index.js +32 -32
  74. package/dist/security/index.js.map +1 -1
  75. package/dist/server/index.browser.js +1 -1
  76. package/dist/server/index.browser.js.map +1 -1
  77. package/dist/server/index.d.ts +101 -101
  78. package/dist/server/index.js +16 -16
  79. package/dist/server/index.js.map +1 -1
  80. package/dist/server-auth/index.browser.js +4 -982
  81. package/dist/server-auth/index.browser.js.map +1 -1
  82. package/dist/server-auth/index.d.ts +204 -785
  83. package/dist/server-auth/index.js +47 -1239
  84. package/dist/server-auth/index.js.map +1 -1
  85. package/dist/server-cache/index.d.ts +10 -10
  86. package/dist/server-cache/index.js +2 -2
  87. package/dist/server-cache/index.js.map +1 -1
  88. package/dist/server-compress/index.d.ts +4 -4
  89. package/dist/server-compress/index.js +1 -1
  90. package/dist/server-compress/index.js.map +1 -1
  91. package/dist/server-cookies/index.browser.js +8 -8
  92. package/dist/server-cookies/index.browser.js.map +1 -1
  93. package/dist/server-cookies/index.d.ts +17 -17
  94. package/dist/server-cookies/index.js +10 -10
  95. package/dist/server-cookies/index.js.map +1 -1
  96. package/dist/server-cors/index.d.ts +17 -17
  97. package/dist/server-cors/index.js +9 -9
  98. package/dist/server-cors/index.js.map +1 -1
  99. package/dist/server-health/index.d.ts +19 -19
  100. package/dist/server-helmet/index.d.ts +1 -1
  101. package/dist/server-links/index.browser.js +12 -12
  102. package/dist/server-links/index.browser.js.map +1 -1
  103. package/dist/server-links/index.d.ts +59 -251
  104. package/dist/server-links/index.js +23 -502
  105. package/dist/server-links/index.js.map +1 -1
  106. package/dist/server-metrics/index.d.ts +4 -4
  107. package/dist/server-multipart/index.d.ts +2 -2
  108. package/dist/server-proxy/index.d.ts +12 -12
  109. package/dist/server-proxy/index.js +10 -10
  110. package/dist/server-proxy/index.js.map +1 -1
  111. package/dist/server-rate-limit/index.d.ts +22 -22
  112. package/dist/server-rate-limit/index.js +12 -12
  113. package/dist/server-rate-limit/index.js.map +1 -1
  114. package/dist/server-security/index.d.ts +22 -22
  115. package/dist/server-security/index.js +15 -15
  116. package/dist/server-security/index.js.map +1 -1
  117. package/dist/server-static/index.d.ts +14 -14
  118. package/dist/server-static/index.js +8 -8
  119. package/dist/server-static/index.js.map +1 -1
  120. package/dist/server-swagger/index.d.ts +25 -184
  121. package/dist/server-swagger/index.js +21 -724
  122. package/dist/server-swagger/index.js.map +1 -1
  123. package/dist/sms/index.d.ts +14 -14
  124. package/dist/sms/index.js +9 -9
  125. package/dist/sms/index.js.map +1 -1
  126. package/dist/thread/index.d.ts +11 -11
  127. package/dist/thread/index.js +17 -17
  128. package/dist/thread/index.js.map +1 -1
  129. package/dist/topic/index.d.ts +26 -26
  130. package/dist/topic/index.js +16 -16
  131. package/dist/topic/index.js.map +1 -1
  132. package/dist/topic-redis/index.d.ts +1 -1
  133. package/dist/vite/index.d.ts +3 -3
  134. package/dist/vite/index.js +8 -8
  135. package/dist/vite/index.js.map +1 -1
  136. package/dist/websocket/index.browser.js +11 -11
  137. package/dist/websocket/index.browser.js.map +1 -1
  138. package/dist/websocket/index.d.ts +58 -58
  139. package/dist/websocket/index.js +13 -13
  140. package/dist/websocket/index.js.map +1 -1
  141. package/package.json +113 -52
  142. package/src/api-files/services/FileService.ts +5 -7
  143. package/src/api-jobs/index.ts +1 -1
  144. package/src/api-jobs/{descriptors → primitives}/$job.ts +8 -8
  145. package/src/api-jobs/providers/JobProvider.ts +9 -9
  146. package/src/api-jobs/services/JobService.ts +5 -5
  147. package/src/api-notifications/index.ts +5 -15
  148. package/src/api-notifications/{descriptors → primitives}/$notification.ts +10 -10
  149. package/src/api-notifications/services/NotificationSenderService.ts +3 -3
  150. package/src/api-parameters/index.ts +1 -1
  151. package/src/api-parameters/{descriptors → primitives}/$config.ts +7 -12
  152. package/src/api-users/index.ts +1 -1
  153. package/src/api-users/{descriptors → primitives}/$userRealm.ts +8 -8
  154. package/src/api-users/providers/UserRealmProvider.ts +1 -1
  155. package/src/batch/index.ts +3 -3
  156. package/src/batch/{descriptors → primitives}/$batch.ts +13 -16
  157. package/src/bucket/index.ts +8 -8
  158. package/src/bucket/{descriptors → primitives}/$bucket.ts +8 -8
  159. package/src/bucket/providers/LocalFileStorageProvider.ts +3 -3
  160. package/src/cache/index.ts +4 -4
  161. package/src/cache/{descriptors → primitives}/$cache.ts +15 -15
  162. package/src/cli/apps/AlephaPackageBuilderCli.ts +24 -2
  163. package/src/cli/commands/DrizzleCommands.ts +6 -6
  164. package/src/cli/commands/VerifyCommands.ts +1 -1
  165. package/src/cli/commands/ViteCommands.ts +6 -1
  166. package/src/cli/services/ProjectUtils.ts +34 -3
  167. package/src/command/index.ts +5 -5
  168. package/src/command/{descriptors → primitives}/$command.ts +9 -12
  169. package/src/command/providers/CliProvider.ts +10 -10
  170. package/src/core/Alepha.ts +30 -33
  171. package/src/core/constants/KIND.ts +1 -1
  172. package/src/core/constants/OPTIONS.ts +1 -1
  173. package/src/core/helpers/{descriptor.ts → primitive.ts} +18 -18
  174. package/src/core/helpers/ref.ts +1 -1
  175. package/src/core/index.shared.ts +8 -8
  176. package/src/core/{descriptors → primitives}/$context.ts +5 -5
  177. package/src/core/{descriptors → primitives}/$hook.ts +4 -4
  178. package/src/core/{descriptors → primitives}/$inject.ts +2 -2
  179. package/src/core/{descriptors → primitives}/$module.ts +9 -9
  180. package/src/core/{descriptors → primitives}/$use.ts +2 -2
  181. package/src/core/providers/CodecManager.ts +1 -1
  182. package/src/core/providers/JsonSchemaCodec.ts +1 -1
  183. package/src/core/providers/StateManager.ts +2 -2
  184. package/src/datetime/index.ts +3 -3
  185. package/src/datetime/{descriptors → primitives}/$interval.ts +6 -6
  186. package/src/email/index.ts +4 -4
  187. package/src/email/{descriptors → primitives}/$email.ts +8 -8
  188. package/src/file/index.ts +1 -1
  189. package/src/lock/index.ts +3 -3
  190. package/src/lock/{descriptors → primitives}/$lock.ts +10 -10
  191. package/src/logger/index.ts +8 -8
  192. package/src/logger/{descriptors → primitives}/$logger.ts +2 -2
  193. package/src/logger/services/Logger.ts +1 -1
  194. package/src/orm/constants/PG_SYMBOLS.ts +2 -2
  195. package/src/orm/index.browser.ts +2 -2
  196. package/src/orm/index.ts +8 -8
  197. package/src/orm/{descriptors → primitives}/$entity.ts +11 -11
  198. package/src/orm/{descriptors → primitives}/$repository.ts +2 -2
  199. package/src/orm/{descriptors → primitives}/$sequence.ts +8 -8
  200. package/src/orm/{descriptors → primitives}/$transaction.ts +4 -4
  201. package/src/orm/providers/PostgresTypeProvider.ts +3 -3
  202. package/src/orm/providers/RepositoryProvider.ts +4 -4
  203. package/src/orm/providers/drivers/DatabaseProvider.ts +7 -7
  204. package/src/orm/services/ModelBuilder.ts +9 -9
  205. package/src/orm/services/PgRelationManager.ts +2 -2
  206. package/src/orm/services/PostgresModelBuilder.ts +5 -5
  207. package/src/orm/services/Repository.ts +7 -7
  208. package/src/orm/services/SqliteModelBuilder.ts +5 -5
  209. package/src/queue/index.ts +7 -7
  210. package/src/queue/{descriptors → primitives}/$consumer.ts +15 -15
  211. package/src/queue/{descriptors → primitives}/$queue.ts +12 -12
  212. package/src/queue/providers/WorkerProvider.ts +7 -7
  213. package/src/retry/index.ts +3 -3
  214. package/src/retry/{descriptors → primitives}/$retry.ts +14 -14
  215. package/src/scheduler/index.ts +3 -3
  216. package/src/scheduler/{descriptors → primitives}/$scheduler.ts +9 -9
  217. package/src/scheduler/providers/CronProvider.ts +1 -1
  218. package/src/security/index.ts +9 -9
  219. package/src/security/{descriptors → primitives}/$permission.ts +7 -7
  220. package/src/security/{descriptors → primitives}/$realm.ts +6 -12
  221. package/src/security/{descriptors → primitives}/$role.ts +12 -12
  222. package/src/security/{descriptors → primitives}/$serviceAccount.ts +8 -8
  223. package/src/server/index.browser.ts +1 -1
  224. package/src/server/index.ts +14 -14
  225. package/src/server/{descriptors → primitives}/$action.ts +13 -13
  226. package/src/server/{descriptors → primitives}/$route.ts +9 -9
  227. package/src/server/providers/NodeHttpServerProvider.ts +1 -1
  228. package/src/server/services/HttpClient.ts +1 -1
  229. package/src/server-auth/index.browser.ts +1 -1
  230. package/src/server-auth/index.ts +6 -6
  231. package/src/server-auth/{descriptors → primitives}/$auth.ts +10 -10
  232. package/src/server-auth/{descriptors → primitives}/$authCredentials.ts +4 -4
  233. package/src/server-auth/{descriptors → primitives}/$authGithub.ts +4 -4
  234. package/src/server-auth/{descriptors → primitives}/$authGoogle.ts +4 -4
  235. package/src/server-auth/providers/ServerAuthProvider.ts +4 -4
  236. package/src/server-cache/providers/ServerCacheProvider.ts +7 -7
  237. package/src/server-compress/providers/ServerCompressProvider.ts +3 -3
  238. package/src/server-cookies/index.browser.ts +2 -2
  239. package/src/server-cookies/index.ts +5 -5
  240. package/src/server-cookies/{descriptors → primitives}/$cookie.browser.ts +12 -12
  241. package/src/server-cookies/{descriptors → primitives}/$cookie.ts +13 -13
  242. package/src/server-cookies/providers/ServerCookiesProvider.ts +4 -4
  243. package/src/server-cookies/services/CookieParser.ts +1 -1
  244. package/src/server-cors/index.ts +3 -3
  245. package/src/server-cors/{descriptors → primitives}/$cors.ts +11 -13
  246. package/src/server-cors/providers/ServerCorsProvider.ts +5 -5
  247. package/src/server-links/index.browser.ts +5 -5
  248. package/src/server-links/index.ts +9 -9
  249. package/src/server-links/{descriptors → primitives}/$remote.ts +11 -11
  250. package/src/server-links/providers/LinkProvider.ts +7 -7
  251. package/src/server-links/providers/{RemoteDescriptorProvider.ts → RemotePrimitiveProvider.ts} +6 -6
  252. package/src/server-links/providers/ServerLinksProvider.ts +3 -3
  253. package/src/server-proxy/index.ts +3 -3
  254. package/src/server-proxy/{descriptors → primitives}/$proxy.ts +8 -8
  255. package/src/server-proxy/providers/ServerProxyProvider.ts +4 -4
  256. package/src/server-rate-limit/index.ts +6 -6
  257. package/src/server-rate-limit/{descriptors → primitives}/$rateLimit.ts +13 -13
  258. package/src/server-rate-limit/providers/ServerRateLimitProvider.ts +5 -5
  259. package/src/server-security/index.ts +3 -3
  260. package/src/server-security/{descriptors → primitives}/$basicAuth.ts +13 -13
  261. package/src/server-security/providers/ServerBasicAuthProvider.ts +5 -5
  262. package/src/server-security/providers/ServerSecurityProvider.ts +4 -4
  263. package/src/server-static/index.ts +3 -3
  264. package/src/server-static/{descriptors → primitives}/$serve.ts +8 -10
  265. package/src/server-static/providers/ServerStaticProvider.ts +6 -6
  266. package/src/server-swagger/index.ts +5 -5
  267. package/src/server-swagger/{descriptors → primitives}/$swagger.ts +9 -9
  268. package/src/server-swagger/providers/ServerSwaggerProvider.ts +11 -10
  269. package/src/sms/index.ts +4 -4
  270. package/src/sms/{descriptors → primitives}/$sms.ts +8 -8
  271. package/src/thread/index.ts +3 -3
  272. package/src/thread/{descriptors → primitives}/$thread.ts +13 -13
  273. package/src/thread/providers/ThreadProvider.ts +7 -9
  274. package/src/topic/index.ts +5 -5
  275. package/src/topic/{descriptors → primitives}/$subscriber.ts +14 -14
  276. package/src/topic/{descriptors → primitives}/$topic.ts +10 -10
  277. package/src/topic/providers/TopicProvider.ts +4 -4
  278. package/src/vite/tasks/copyAssets.ts +1 -1
  279. package/src/vite/tasks/generateSitemap.ts +3 -3
  280. package/src/vite/tasks/prerenderPages.ts +2 -2
  281. package/src/vite/tasks/runAlepha.ts +2 -2
  282. package/src/websocket/index.browser.ts +3 -3
  283. package/src/websocket/index.shared.ts +2 -2
  284. package/src/websocket/index.ts +4 -4
  285. package/src/websocket/interfaces/WebSocketInterfaces.ts +3 -3
  286. package/src/websocket/{descriptors → primitives}/$channel.ts +10 -10
  287. package/src/websocket/{descriptors → primitives}/$websocket.ts +8 -8
  288. package/src/websocket/providers/NodeWebSocketServerProvider.ts +7 -7
  289. package/src/websocket/providers/WebSocketServerProvider.ts +3 -3
  290. package/src/websocket/services/WebSocketClient.ts +5 -5
  291. package/src/api-notifications/providers/MemorySmsProvider.ts +0 -20
  292. package/src/api-notifications/providers/SmsProvider.ts +0 -8
  293. /package/src/core/{descriptors → primitives}/$atom.ts +0 -0
  294. /package/src/core/{descriptors → primitives}/$env.ts +0 -0
  295. /package/src/server-auth/{descriptors → primitives}/$authApple.ts +0 -0
  296. /package/src/server-links/{descriptors → primitives}/$client.ts +0 -0
@@ -1,457 +1,15 @@
1
- import { $env, $hook, $inject, $module, Alepha, Descriptor, KIND, createDescriptor, isTypeFile, t } from "alepha";
1
+ import { $hook, $inject, $module, Alepha, t } from "alepha";
2
2
  import { $bucket, AlephaBucket, FileNotFoundError } from "alepha/bucket";
3
- import { $cache, AlephaCache } from "alepha/cache";
4
- import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
3
+ import { AlephaServerCache } from "alepha/server/cache";
4
+ import { AlephaServerMultipart } from "alepha/server/multipart";
5
+ import { $entity, $repository, pageQuerySchema, pg } from "alepha/orm";
6
+ import { $action, NotFoundError, okSchema } from "alepha/server";
7
+ import { createHash } from "node:crypto";
5
8
  import { DateTimeProvider } from "alepha/datetime";
6
9
  import { $logger } from "alepha/logger";
7
- import { $action, ActionDescriptor, AlephaServer, ForbiddenError, HttpError, NotFoundError, ServerRouterProvider, UnauthorizedError, isMultipart, okSchema } from "alepha/server";
8
- import { createReadStream } from "node:fs";
9
- import { readFile, unlink, writeFile } from "node:fs/promises";
10
- import * as os from "node:os";
11
- import { ReadableStream } from "node:stream/web";
12
- import { $entity, $repository, pageQuerySchema, pg } from "alepha/orm";
13
- import { $permission, $realm, $role, AlephaSecurity, JwtProvider, SecurityProvider, userAccountInfoSchema } from "alepha/security";
10
+ import "alepha/server/security";
14
11
  import { $scheduler } from "alepha/scheduler";
15
12
 
16
- //#region src/server-cache/providers/ServerCacheProvider.ts
17
- ActionDescriptor.prototype.invalidate = async function() {
18
- await this.alepha.inject(ServerCacheProvider).invalidate(this.route);
19
- };
20
- var ServerCacheProvider = class {
21
- log = $logger();
22
- alepha = $inject(Alepha);
23
- time = $inject(DateTimeProvider);
24
- cache = $cache({ provider: "memory" });
25
- generateETag(content) {
26
- return `"${createHash("md5").update(content).digest("hex")}"`;
27
- }
28
- async invalidate(route) {
29
- if (!route.cache) return;
30
- await this.cache.invalidate(this.createCacheKey(route));
31
- }
32
- onActionRequest = $hook({
33
- on: "action:onRequest",
34
- handler: async ({ action, request }) => {
35
- const cache = action.route.cache;
36
- if (this.shouldStore(cache)) {
37
- const key = this.createCacheKey(action.route, request);
38
- const cached = await this.cache.get(key);
39
- if (cached) {
40
- const body = cached.contentType === "application/json" ? JSON.parse(cached.body) : cached.body;
41
- this.log.trace("Cache hit for action", {
42
- key,
43
- action: action.name
44
- });
45
- request.reply.body = body;
46
- } else this.log.trace("Cache miss for action", {
47
- key,
48
- action: action.name
49
- });
50
- }
51
- }
52
- });
53
- onActionResponse = $hook({
54
- on: "action:onResponse",
55
- handler: async ({ action, request, response }) => {
56
- const cache = action.route.cache;
57
- if (!this.shouldStore(cache) || !response) return;
58
- if (request.reply.status && request.reply.status >= 400) return;
59
- const contentType = typeof response === "string" ? "text/plain" : "application/json";
60
- const body = contentType === "text/plain" ? response : JSON.stringify(response);
61
- const generatedEtag = this.generateETag(body);
62
- const lastModified = this.time.toISOString();
63
- const key = this.createCacheKey(action.route, request);
64
- this.log.trace("Storing response", {
65
- key,
66
- action: action.name
67
- });
68
- await this.cache.set(key, {
69
- body,
70
- lastModified,
71
- contentType,
72
- hash: generatedEtag
73
- });
74
- const cacheControl = this.buildCacheControlHeader(cache);
75
- if (cacheControl) request.reply.setHeader("cache-control", cacheControl);
76
- }
77
- });
78
- onRequest = $hook({
79
- on: "server:onRequest",
80
- handler: async ({ route, request }) => {
81
- const cache = route.cache;
82
- const shouldStore = this.shouldStore(cache);
83
- const shouldUseEtag = this.shouldUseEtag(cache);
84
- if (!shouldStore && !shouldUseEtag) return;
85
- const key = this.createCacheKey(route, request);
86
- const cached = await this.cache.get(key);
87
- if (cached) {
88
- if (request.headers["if-none-match"] === cached.hash || request.headers["if-modified-since"] === cached.lastModified) {
89
- request.reply.status = 304;
90
- request.reply.setHeader("etag", cached.hash);
91
- request.reply.setHeader("last-modified", cached.lastModified);
92
- this.log.trace("ETag match, returning 304", {
93
- route: route.path,
94
- etag: cached.hash
95
- });
96
- return;
97
- }
98
- if (shouldStore) {
99
- this.log.trace("Cache hit for route", {
100
- key,
101
- route: route.path
102
- });
103
- request.reply.body = cached.body;
104
- request.reply.status = cached.status ?? 200;
105
- if (cached.contentType) request.reply.setHeader("Content-Type", cached.contentType);
106
- request.reply.setHeader("etag", cached.hash);
107
- request.reply.setHeader("last-modified", cached.lastModified);
108
- }
109
- } else if (shouldStore) this.log.trace("Cache miss for route", {
110
- key,
111
- route: route.path
112
- });
113
- }
114
- });
115
- onSend = $hook({
116
- on: "server:onSend",
117
- handler: async ({ route, request }) => {
118
- const cache = route.cache;
119
- const shouldStore = this.shouldStore(cache);
120
- const shouldUseEtag = this.shouldUseEtag(cache);
121
- if (request.reply.headers.etag) return;
122
- if (!shouldStore && shouldUseEtag && request.reply.body != null && (typeof request.reply.body === "string" || Buffer.isBuffer(request.reply.body))) {
123
- const generatedEtag = this.generateETag(request.reply.body);
124
- if (request.headers["if-none-match"] === generatedEtag) {
125
- request.reply.status = 304;
126
- request.reply.body = void 0;
127
- request.reply.setHeader("etag", generatedEtag);
128
- this.log.trace("ETag match on send, returning 304", {
129
- route: route.path,
130
- etag: generatedEtag
131
- });
132
- return;
133
- }
134
- }
135
- }
136
- });
137
- onResponse = $hook({
138
- on: "server:onResponse",
139
- priority: "first",
140
- handler: async ({ route, request, response }) => {
141
- const cache = route.cache;
142
- const cacheControl = this.buildCacheControlHeader(cache);
143
- if (cacheControl) response.headers["cache-control"] = cacheControl;
144
- const shouldStore = this.shouldStore(cache);
145
- const shouldUseEtag = this.shouldUseEtag(cache);
146
- if (!shouldStore && !shouldUseEtag) return;
147
- if (typeof response.body !== "string") return;
148
- if (response.status && response.status >= 400) return;
149
- const key = this.createCacheKey(route, request);
150
- const generatedEtag = this.generateETag(response.body);
151
- const lastModified = this.time.toISOString();
152
- response.headers ??= {};
153
- if (shouldStore) {
154
- this.log.trace("Storing response", {
155
- key,
156
- route: route.path,
157
- cache: !!cache,
158
- etag: shouldUseEtag
159
- });
160
- await this.cache.set(key, {
161
- body: response.body,
162
- status: response.status,
163
- contentType: response.headers?.["content-type"],
164
- lastModified,
165
- hash: generatedEtag
166
- });
167
- }
168
- if (shouldUseEtag) {
169
- response.headers.etag = generatedEtag;
170
- response.headers["last-modified"] = lastModified;
171
- }
172
- }
173
- });
174
- buildCacheControlHeader(cache) {
175
- if (!cache) return;
176
- if (cache === true || typeof cache === "string" || typeof cache === "number") return;
177
- const control = cache.control;
178
- if (!control) return;
179
- if (typeof control === "string") return control;
180
- if (control === true) return "public, max-age=300";
181
- const directives = [];
182
- if (control.public) directives.push("public");
183
- if (control.private) directives.push("private");
184
- if (control.noCache) directives.push("no-cache");
185
- if (control.noStore) directives.push("no-store");
186
- if (control.maxAge !== void 0) {
187
- const maxAgeSeconds = this.durationToSeconds(control.maxAge);
188
- directives.push(`max-age=${maxAgeSeconds}`);
189
- }
190
- if (control.sMaxAge !== void 0) {
191
- const sMaxAgeSeconds = this.durationToSeconds(control.sMaxAge);
192
- directives.push(`s-maxage=${sMaxAgeSeconds}`);
193
- }
194
- if (control.mustRevalidate) directives.push("must-revalidate");
195
- if (control.proxyRevalidate) directives.push("proxy-revalidate");
196
- if (control.immutable) directives.push("immutable");
197
- return directives.length > 0 ? directives.join(", ") : void 0;
198
- }
199
- durationToSeconds(duration) {
200
- if (typeof duration === "number") return duration;
201
- return this.time.duration(duration).asSeconds();
202
- }
203
- shouldStore(cache) {
204
- if (!cache) return false;
205
- if (cache === true) return true;
206
- if (typeof cache === "object" && cache.store) return true;
207
- return false;
208
- }
209
- shouldUseEtag(cache) {
210
- if (cache === true) return true;
211
- if (typeof cache === "object" && cache.etag) return true;
212
- return false;
213
- }
214
- createCacheKey(route, config) {
215
- const params = [];
216
- for (const [key, value] of Object.entries(config?.params ?? {})) params.push(`${key}=${value}`);
217
- for (const [key, value] of Object.entries(config?.query ?? {})) params.push(`${key}=${value}`);
218
- return `${route.method}:${route.path.replaceAll(":", "")}:${params.join(",").replaceAll(":", "")}`;
219
- }
220
- };
221
-
222
- //#endregion
223
- //#region src/server-cache/index.ts
224
- /**
225
- * Plugin for Alepha Server that provides server-side caching capabilities.
226
- * It uses the Alepha Cache module to cache responses from server actions ($action).
227
- * It also provides a ETag-based cache invalidation mechanism.
228
- *
229
- * @example
230
- * ```ts
231
- * import { Alepha } from "alepha";
232
- * import { $action } from "alepha/server";
233
- * import { AlephaServerCache } from "alepha/server/cache";
234
- *
235
- * class ApiServer {
236
- * hello = $action({
237
- * cache: true,
238
- * handler: () => "Hello, World!",
239
- * });
240
- * }
241
- *
242
- * const alepha = Alepha.create()
243
- * .with(AlephaServerCache)
244
- * .with(ApiServer);
245
- *
246
- * run(alepha);
247
- * ```
248
- *
249
- * @see {@link ServerCacheProvider}
250
- * @module alepha.server.cache
251
- */
252
- const AlephaServerCache = $module({
253
- name: "alepha.server.cache",
254
- services: [AlephaCache, ServerCacheProvider]
255
- });
256
-
257
- //#endregion
258
- //#region src/server-multipart/providers/ServerMultipartProvider.ts
259
- const envSchema = t.object({
260
- SERVER_MULTIPART_LIMIT: t.integer({
261
- default: 1e7,
262
- min: 0,
263
- description: "Maximum total size of multipart request body in bytes."
264
- }),
265
- SERVER_MULTIPART_FILE_LIMIT: t.integer({
266
- default: 5e6,
267
- min: 0,
268
- description: "Maximum size of a single file in bytes."
269
- }),
270
- SERVER_MULTIPART_FILE_COUNT: t.integer({
271
- default: 10,
272
- min: 1,
273
- description: "Maximum number of files allowed in a single request."
274
- })
275
- });
276
- var ServerMultipartProvider = class {
277
- alepha = $inject(Alepha);
278
- env = $env(envSchema);
279
- log = $logger();
280
- onRequest = $hook({
281
- on: "server:onRequest",
282
- handler: async ({ route, request }) => {
283
- if (request.body) return;
284
- if (!route.schema?.body) return;
285
- let webRequest;
286
- if (request.raw.web?.req) webRequest = request.raw.web.req;
287
- else if (request.raw.node?.req) webRequest = new Request(request.url, {
288
- method: request.method,
289
- headers: request.headers,
290
- body: ReadableStream.from(request.raw.node.req),
291
- duplex: "half"
292
- });
293
- if (!webRequest) return;
294
- const contentType = request.headers["content-type"];
295
- const contentLength = request.headers["content-length"];
296
- if (contentLength) {
297
- const size = Number.parseInt(contentLength, 10);
298
- if (!Number.isNaN(size) && size > this.env.SERVER_MULTIPART_LIMIT) {
299
- this.log.error(`Multipart request size limit exceeded: ${size} > ${this.env.SERVER_MULTIPART_LIMIT}`);
300
- throw new HttpError({
301
- status: 413,
302
- message: `Request body size limit exceeded. Maximum allowed: ${this.env.SERVER_MULTIPART_LIMIT} bytes`
303
- });
304
- }
305
- }
306
- if (!contentType?.startsWith("multipart/form-data")) {
307
- if (!isMultipart(route)) return;
308
- throw new HttpError({
309
- status: 415,
310
- message: `Invalid content-type: ${contentType} - only "multipart/form-data" is accepted`
311
- });
312
- }
313
- const { body, cleanup } = await this.handleMultipartBodyFromWeb(route, webRequest);
314
- request.body = body;
315
- request.metadata.multipart = { cleanup };
316
- }
317
- });
318
- onResponse = $hook({
319
- on: "server:onResponse",
320
- handler: async ({ request }) => {
321
- const cleanup = request.metadata.multipart?.cleanup;
322
- if (typeof cleanup === "function") await cleanup();
323
- }
324
- });
325
- async handleMultipartBodyFromWeb(route, request) {
326
- let formData;
327
- try {
328
- formData = await request.formData();
329
- } catch (error) {
330
- throw new HttpError({
331
- status: 400,
332
- message: "Malformed multipart/form-data"
333
- }, error);
334
- }
335
- const body = {};
336
- const tempFiles = [];
337
- const cleanupOnError = async () => {
338
- for (const file of tempFiles) try {
339
- await file.cleanup();
340
- } catch {}
341
- };
342
- try {
343
- let fileCount = 0;
344
- let totalSize = 0;
345
- if (route.schema?.body && t.schema.isObject(route.schema.body)) {
346
- for (const [key, value] of Object.entries(route.schema.body.properties)) if (t.schema.isSchema(value)) if (isTypeFile(value)) {
347
- const file = formData.get(key);
348
- if (file && typeof file === "object" && "arrayBuffer" in file) {
349
- const blob = file;
350
- fileCount++;
351
- if (fileCount > this.env.SERVER_MULTIPART_FILE_COUNT) {
352
- this.log.error(`Too many files in multipart request: ${fileCount} > ${this.env.SERVER_MULTIPART_FILE_COUNT}`);
353
- throw new HttpError({
354
- status: 413,
355
- message: `Too many files. Maximum allowed: ${this.env.SERVER_MULTIPART_FILE_COUNT}`
356
- });
357
- }
358
- if (blob.size > this.env.SERVER_MULTIPART_FILE_LIMIT) {
359
- this.log.error(`File "${key}" exceeds size limit: ${blob.size} > ${this.env.SERVER_MULTIPART_FILE_LIMIT}`);
360
- throw new HttpError({
361
- status: 413,
362
- message: `File "${key}" exceeds size limit. Maximum allowed: ${this.env.SERVER_MULTIPART_FILE_LIMIT} bytes`
363
- });
364
- }
365
- totalSize += blob.size;
366
- if (totalSize > this.env.SERVER_MULTIPART_LIMIT) {
367
- this.log.error(`Total multipart size exceeds limit: ${totalSize} > ${this.env.SERVER_MULTIPART_LIMIT}`);
368
- throw new HttpError({
369
- status: 413,
370
- message: `Total request size exceeds limit. Maximum allowed: ${this.env.SERVER_MULTIPART_LIMIT} bytes`
371
- });
372
- }
373
- const hybridFile = await this.createHybridFile(blob, key);
374
- body[key] = hybridFile;
375
- tempFiles.push(hybridFile);
376
- }
377
- } else {
378
- const fieldValue = formData.get(key);
379
- if (fieldValue !== null) {
380
- const stringValue = typeof fieldValue === "string" ? fieldValue : "";
381
- body[key] = this.alepha.codec.decode(value, stringValue);
382
- }
383
- }
384
- }
385
- return {
386
- body,
387
- cleanup: async () => {
388
- for (const file of tempFiles) await file.cleanup();
389
- }
390
- };
391
- } catch (error) {
392
- await cleanupOnError();
393
- throw error;
394
- }
395
- }
396
- /**
397
- * This is a legacy code, previously we used "busboy" to parse multipart in Node.js environment.
398
- * Now we rely on Web Request's formData() method, which is supported in modern Node.js versions.
399
- * However, we still need to create temporary files for uploaded files to provide a consistent File-like interface.
400
- *
401
- * TODO: In future, we might want to refactor this to avoid using temporary files if not necessary?
402
- */
403
- async createHybridFile(file, fieldName) {
404
- const tmpPath = `${os.tmpdir()}/${randomUUID()}`;
405
- const arrayBuffer = await file.arrayBuffer();
406
- await writeFile(tmpPath, Buffer.from(arrayBuffer));
407
- const fileName = file.name || `${fieldName}_${Date.now()}`;
408
- return {
409
- _state: {
410
- cleanup: false,
411
- size: file.size,
412
- tmpPath
413
- },
414
- name: fileName,
415
- type: file.type || "application/octet-stream",
416
- lastModified: file.lastModified || Date.now(),
417
- filepath: tmpPath,
418
- get size() {
419
- return this._state.size;
420
- },
421
- stream() {
422
- return createReadStream(tmpPath);
423
- },
424
- async arrayBuffer() {
425
- const content = await readFile(tmpPath);
426
- return content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength);
427
- },
428
- text: async () => {
429
- return await readFile(tmpPath, "utf-8");
430
- },
431
- async cleanup() {
432
- if (this._state.cleanup) return;
433
- await unlink(tmpPath);
434
- this._state.cleanup = true;
435
- }
436
- };
437
- }
438
- };
439
-
440
- //#endregion
441
- //#region src/server-multipart/index.ts
442
- /**
443
- * This module provides support for handling multipart/form-data requests.
444
- * It allows to parse body data containing t.file().
445
- *
446
- * @see {@link ServerMultipartProvider}
447
- * @module alepha.server.multipart
448
- */
449
- const AlephaServerMultipart = $module({
450
- name: "alepha.server.multipart",
451
- services: [AlephaServer, ServerMultipartProvider]
452
- });
453
-
454
- //#endregion
455
13
  //#region src/api-files/schemas/fileQuerySchema.ts
456
14
  const fileQuerySchema = t.extend(pageQuerySchema, {
457
15
  bucket: t.optional(t.string()),
@@ -550,14 +108,14 @@ var FileService = class {
550
108
  return hash.digest("hex");
551
109
  }
552
110
  /**
553
- * Gets a bucket descriptor by name.
111
+ * Gets a bucket primitive by name.
554
112
  *
555
113
  * @param bucketName - The name of the bucket to retrieve (defaults to "default")
556
- * @returns The bucket descriptor
114
+ * @returns The bucket primitive
557
115
  * @throws {NotFoundError} If the bucket is not found
558
116
  */
559
117
  bucket(bucketName = this.defaultBucket.name) {
560
- const bucket = this.alepha.descriptors($bucket).find((it) => it.name === bucketName);
118
+ const bucket = this.alepha.primitives($bucket).find((it) => it.name === bucketName);
561
119
  if (!bucket) throw new NotFoundError(`Bucket '${bucketName}' not found.`);
562
120
  return bucket;
563
121
  }
@@ -871,309 +429,6 @@ var FileController = class {
871
429
  });
872
430
  };
873
431
 
874
- //#endregion
875
- //#region src/server-security/providers/ServerBasicAuthProvider.ts
876
- var ServerBasicAuthProvider = class {
877
- alepha = $inject(Alepha);
878
- log = $logger();
879
- routerProvider = $inject(ServerRouterProvider);
880
- realm = "Secure Area";
881
- /**
882
- * Registered basic auth descriptors with their configurations
883
- */
884
- registeredAuths = [];
885
- /**
886
- * Register a basic auth configuration (called by descriptors)
887
- */
888
- registerAuth(config) {
889
- this.registeredAuths.push(config);
890
- }
891
- onStart = $hook({
892
- on: "start",
893
- handler: async () => {
894
- for (const auth of this.registeredAuths) if (auth.paths) for (const pattern of auth.paths) {
895
- const matchedRoutes = this.routerProvider.getRoutes(pattern);
896
- for (const route of matchedRoutes) route.secure = { basic: {
897
- username: auth.username,
898
- password: auth.password
899
- } };
900
- }
901
- if (this.registeredAuths.length > 0) this.log.info(`Initialized with ${this.registeredAuths.length} registered basic-auth configurations.`);
902
- }
903
- });
904
- /**
905
- * Hook into server:onRequest to check basic auth
906
- */
907
- onRequest = $hook({
908
- on: "server:onRequest",
909
- handler: async ({ route, request }) => {
910
- const routeAuth = route.secure;
911
- if (typeof routeAuth === "object" && "basic" in routeAuth && routeAuth.basic) this.checkAuth(request, routeAuth.basic);
912
- }
913
- });
914
- /**
915
- * Hook into action:onRequest to check basic auth for actions
916
- */
917
- onActionRequest = $hook({
918
- on: "action:onRequest",
919
- handler: async ({ action, request }) => {
920
- const routeAuth = action.route.secure;
921
- if (isBasicAuth(routeAuth)) this.checkAuth(request, routeAuth.basic);
922
- }
923
- });
924
- /**
925
- * Check basic authentication
926
- */
927
- checkAuth(request, options) {
928
- const authHeader = request.headers?.authorization;
929
- if (!authHeader || !authHeader.startsWith("Basic ")) {
930
- this.sendAuthRequired(request);
931
- throw new HttpError({
932
- status: 401,
933
- message: "Authentication required"
934
- });
935
- }
936
- const base64Credentials = authHeader.slice(6);
937
- const credentials = Buffer.from(base64Credentials, "base64").toString("utf-8");
938
- const colonIndex = credentials.indexOf(":");
939
- const username = colonIndex !== -1 ? credentials.slice(0, colonIndex) : credentials;
940
- const password = colonIndex !== -1 ? credentials.slice(colonIndex + 1) : "";
941
- if (!this.timingSafeCredentialCheck(username, password, options.username, options.password)) {
942
- this.sendAuthRequired(request);
943
- this.log.warn(`Failed basic auth attempt for user`, { username });
944
- throw new HttpError({
945
- status: 401,
946
- message: "Invalid credentials"
947
- });
948
- }
949
- }
950
- /**
951
- * Performs a timing-safe comparison of credentials to prevent timing attacks.
952
- * Always compares both username and password to avoid leaking which one is wrong.
953
- */
954
- timingSafeCredentialCheck(inputUsername, inputPassword, expectedUsername, expectedPassword) {
955
- const inputUserBuf = Buffer.from(inputUsername, "utf-8");
956
- const expectedUserBuf = Buffer.from(expectedUsername, "utf-8");
957
- const inputPassBuf = Buffer.from(inputPassword, "utf-8");
958
- const expectedPassBuf = Buffer.from(expectedPassword, "utf-8");
959
- return (this.safeCompare(inputUserBuf, expectedUserBuf) & this.safeCompare(inputPassBuf, expectedPassBuf)) === 1;
960
- }
961
- /**
962
- * Compares two buffers in constant time, handling different lengths safely.
963
- * Returns 1 if equal, 0 if not equal.
964
- */
965
- safeCompare(input, expected) {
966
- if (input.length !== expected.length) {
967
- timingSafeEqual(input, input);
968
- return 0;
969
- }
970
- return timingSafeEqual(input, expected) ? 1 : 0;
971
- }
972
- /**
973
- * Send WWW-Authenticate header
974
- */
975
- sendAuthRequired(request) {
976
- request.reply.setHeader("WWW-Authenticate", `Basic realm="${this.realm}"`);
977
- }
978
- };
979
- const isBasicAuth = (value) => {
980
- return typeof value === "object" && !!value && "basic" in value && !!value.basic;
981
- };
982
-
983
- //#endregion
984
- //#region src/server-security/descriptors/$basicAuth.ts
985
- /**
986
- * Declares HTTP Basic Authentication for server routes.
987
- * This descriptor provides methods to protect routes with username/password authentication.
988
- */
989
- const $basicAuth = (options) => {
990
- return createDescriptor(BasicAuthDescriptor, options);
991
- };
992
- var BasicAuthDescriptor = class extends Descriptor {
993
- serverBasicAuthProvider = $inject(ServerBasicAuthProvider);
994
- get name() {
995
- return this.options.name ?? `${this.config.propertyKey}`;
996
- }
997
- onInit() {
998
- this.serverBasicAuthProvider.registerAuth(this.options);
999
- }
1000
- /**
1001
- * Checks basic auth for the given request using this descriptor's configuration.
1002
- */
1003
- check(request, options) {
1004
- const mergedOptions = {
1005
- ...this.options,
1006
- ...options
1007
- };
1008
- this.serverBasicAuthProvider.checkAuth(request, mergedOptions);
1009
- }
1010
- };
1011
- $basicAuth[KIND] = BasicAuthDescriptor;
1012
-
1013
- //#endregion
1014
- //#region src/server-security/providers/ServerSecurityProvider.ts
1015
- var ServerSecurityProvider = class {
1016
- log = $logger();
1017
- securityProvider = $inject(SecurityProvider);
1018
- jwtProvider = $inject(JwtProvider);
1019
- alepha = $inject(Alepha);
1020
- onConfigure = $hook({
1021
- on: "configure",
1022
- handler: async () => {
1023
- for (const action of this.alepha.descriptors($action)) {
1024
- if (action.options.disabled || action.options.secure === false || this.securityProvider.getRealms().length === 0) continue;
1025
- if (typeof action.options.secure !== "object") this.securityProvider.createPermission({
1026
- name: action.name,
1027
- group: action.group,
1028
- method: action.route.method,
1029
- path: action.route.path
1030
- });
1031
- }
1032
- }
1033
- });
1034
- onActionRequest = $hook({
1035
- on: "action:onRequest",
1036
- handler: async ({ action, request, options }) => {
1037
- if (action.options.secure === false && !options.user) {
1038
- this.log.trace("Skipping security check for route");
1039
- return;
1040
- }
1041
- if (isBasicAuth(action.route.secure)) return;
1042
- const permission = this.securityProvider.getPermissions().find((it) => it.path === action.route.path && it.method === action.route.method);
1043
- try {
1044
- request.user = this.createUserFromLocalFunctionContext(options, permission);
1045
- const route = action.route;
1046
- if (typeof route.secure === "object") this.check(request.user, route.secure);
1047
- this.alepha.state.set("alepha.server.request.user", this.alepha.codec.decode(userAccountInfoSchema, request.user));
1048
- } catch (error) {
1049
- if (action.options.secure || permission) throw error;
1050
- this.log.trace("Skipping security check for action");
1051
- }
1052
- }
1053
- });
1054
- onRequest = $hook({
1055
- on: "server:onRequest",
1056
- priority: "last",
1057
- handler: async ({ request, route }) => {
1058
- if (route.secure === false) {
1059
- this.log.trace("Skipping security check for route - explicitly disabled");
1060
- return;
1061
- }
1062
- if (isBasicAuth(route.secure)) return;
1063
- const permission = this.securityProvider.getPermissions().find((it) => it.path === route.path && it.method === route.method);
1064
- if (!request.headers.authorization && !route.secure && !permission) {
1065
- this.log.trace("Skipping security check for route - no authorization header and not secure");
1066
- return;
1067
- }
1068
- try {
1069
- request.user = await this.securityProvider.createUserFromToken(request.headers.authorization, { permission });
1070
- if (typeof route.secure === "object") this.check(request.user, route.secure);
1071
- this.alepha.state.set("alepha.server.request.user", this.alepha.codec.decode(userAccountInfoSchema, request.user));
1072
- this.log.trace("User set from request token", {
1073
- user: request.user,
1074
- permission
1075
- });
1076
- } catch (error) {
1077
- if (route.secure || permission) throw error;
1078
- this.log.trace("Skipping security check for route - error occurred", error);
1079
- }
1080
- }
1081
- });
1082
- check(user, secure) {
1083
- if (secure.realm) {
1084
- if (user.realm !== secure.realm) throw new ForbiddenError(`User must belong to realm '${secure.realm}' to access this route`);
1085
- }
1086
- }
1087
- /**
1088
- * Get the user account token for a local action call.
1089
- * There are three possible sources for the user:
1090
- * - `options.user`: the user passed in the options
1091
- * - `"system"`: the system user from the state (you MUST set state `server.security.system.user`)
1092
- * - `"context"`: the user from the request context (you MUST be in an HTTP request context)
1093
- *
1094
- * Priority order: `options.user` > `"system"` > `"context"`.
1095
- *
1096
- * In testing environment, if no user is provided, a test user is created based on the SecurityProvider's roles.
1097
- */
1098
- createUserFromLocalFunctionContext(options, permission) {
1099
- const fromOptions = typeof options.user === "object" ? options.user : void 0;
1100
- const type = typeof options.user === "string" ? options.user : void 0;
1101
- let user;
1102
- const fromContext = this.alepha.context.get("request")?.user;
1103
- const fromSystem = this.alepha.state.get("alepha.server.security.system.user");
1104
- if (type === "system") user = fromSystem;
1105
- else if (type === "context") user = fromContext;
1106
- else user = fromOptions ?? fromContext ?? fromSystem;
1107
- if (!user) {
1108
- if (this.alepha.isTest() && !("user" in options)) return this.createTestUser();
1109
- throw new UnauthorizedError("User is required for calling this action");
1110
- }
1111
- const roles = user.roles ?? (this.alepha.isTest() ? this.securityProvider.getRoles().map((role) => role.name) : []);
1112
- let ownership;
1113
- if (permission) {
1114
- const result = this.securityProvider.checkPermission(permission, ...roles);
1115
- if (!result.isAuthorized) throw new ForbiddenError(`Permission '${this.securityProvider.permissionToString(permission)}' is required for this route`);
1116
- ownership = result.ownership;
1117
- }
1118
- return {
1119
- ...user,
1120
- ownership
1121
- };
1122
- }
1123
- createTestUser() {
1124
- return {
1125
- id: randomUUID(),
1126
- name: "Test",
1127
- roles: this.securityProvider.getRoles().map((role) => role.name)
1128
- };
1129
- }
1130
- onClientRequest = $hook({
1131
- on: "client:onRequest",
1132
- handler: async ({ request, options }) => {
1133
- if (!this.alepha.isTest()) return;
1134
- if ("user" in options && options.user === void 0) return;
1135
- request.headers = new Headers(request.headers);
1136
- if (!request.headers.has("authorization")) {
1137
- const test = this.createTestUser();
1138
- const user = typeof options?.user === "object" ? options.user : void 0;
1139
- const sub = user?.id ?? test.id;
1140
- const roles = user?.roles ?? test.roles;
1141
- const token = await this.jwtProvider.create({
1142
- sub,
1143
- roles
1144
- }, user?.realm ?? this.securityProvider.getRealms()[0]?.name);
1145
- request.headers.set("authorization", `Bearer ${token}`);
1146
- }
1147
- }
1148
- });
1149
- };
1150
-
1151
- //#endregion
1152
- //#region src/server-security/index.ts
1153
- /**
1154
- * Plugin for Alepha Server that provides security features. Based on the Alepha Security module.
1155
- *
1156
- * By default, all $action will be guarded by a permission check.
1157
- *
1158
- * @see {@link ServerSecurityProvider}
1159
- * @module alepha.server.security
1160
- */
1161
- const AlephaServerSecurity = $module({
1162
- name: "alepha.server.security",
1163
- descriptors: [
1164
- $realm,
1165
- $role,
1166
- $permission,
1167
- $basicAuth
1168
- ],
1169
- services: [
1170
- AlephaServer,
1171
- AlephaSecurity,
1172
- ServerSecurityProvider,
1173
- ServerBasicAuthProvider
1174
- ]
1175
- });
1176
-
1177
432
  //#endregion
1178
433
  //#region src/api-files/schemas/storageStatsSchema.ts
1179
434
  const bucketStatsSchema = t.object({