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.
- package/README.md +1 -1
- package/dist/api-files/index.d.ts +28 -91
- package/dist/api-files/index.js +10 -755
- package/dist/api-files/index.js.map +1 -1
- package/dist/api-jobs/index.d.ts +46 -46
- package/dist/api-jobs/index.js +13 -13
- package/dist/api-jobs/index.js.map +1 -1
- package/dist/api-notifications/index.d.ts +129 -146
- package/dist/api-notifications/index.js +17 -39
- package/dist/api-notifications/index.js.map +1 -1
- package/dist/api-parameters/index.d.ts +21 -22
- package/dist/api-parameters/index.js +22 -22
- package/dist/api-parameters/index.js.map +1 -1
- package/dist/api-users/index.d.ts +223 -2000
- package/dist/api-users/index.js +914 -4787
- package/dist/api-users/index.js.map +1 -1
- package/dist/api-verifications/index.d.ts +96 -96
- package/dist/batch/index.d.ts +13 -13
- package/dist/batch/index.js +8 -8
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.d.ts +14 -14
- package/dist/bucket/index.js +12 -12
- package/dist/bucket/index.js.map +1 -1
- package/dist/cache/index.d.ts +11 -11
- package/dist/cache/index.js +9 -9
- package/dist/cache/index.js.map +1 -1
- package/dist/cli/index.d.ts +28 -26
- package/dist/cli/index.js +50 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +19 -19
- package/dist/command/index.js +25 -25
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +218 -218
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +232 -232
- package/dist/core/index.js +218 -218
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +2113 -0
- package/dist/core/index.native.js.map +1 -0
- package/dist/datetime/index.d.ts +9 -9
- package/dist/datetime/index.js +7 -7
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +16 -16
- package/dist/email/index.js +9 -9
- package/dist/email/index.js.map +1 -1
- package/dist/file/index.js +1 -1
- package/dist/file/index.js.map +1 -1
- package/dist/lock/index.d.ts +9 -9
- package/dist/lock/index.js +8 -8
- package/dist/lock/index.js.map +1 -1
- package/dist/lock-redis/index.js +3 -66
- package/dist/lock-redis/index.js.map +1 -1
- package/dist/logger/index.d.ts +5 -5
- package/dist/logger/index.js +8 -8
- package/dist/logger/index.js.map +1 -1
- package/dist/orm/index.browser.js +114 -114
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.d.ts +218 -218
- package/dist/orm/index.js +46 -46
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/index.d.ts +29 -29
- package/dist/queue/index.js +20 -20
- package/dist/queue/index.js.map +1 -1
- package/dist/queue-redis/index.d.ts +2 -2
- package/dist/redis/index.d.ts +10 -10
- package/dist/retry/index.d.ts +19 -19
- package/dist/retry/index.js +7 -7
- package/dist/retry/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +16 -16
- package/dist/scheduler/index.js +9 -9
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +80 -80
- package/dist/security/index.js +32 -32
- package/dist/security/index.js.map +1 -1
- package/dist/server/index.browser.js +1 -1
- package/dist/server/index.browser.js.map +1 -1
- package/dist/server/index.d.ts +101 -101
- package/dist/server/index.js +16 -16
- package/dist/server/index.js.map +1 -1
- package/dist/server-auth/index.browser.js +4 -982
- package/dist/server-auth/index.browser.js.map +1 -1
- package/dist/server-auth/index.d.ts +204 -785
- package/dist/server-auth/index.js +47 -1239
- package/dist/server-auth/index.js.map +1 -1
- package/dist/server-cache/index.d.ts +10 -10
- package/dist/server-cache/index.js +2 -2
- package/dist/server-cache/index.js.map +1 -1
- package/dist/server-compress/index.d.ts +4 -4
- package/dist/server-compress/index.js +1 -1
- package/dist/server-compress/index.js.map +1 -1
- package/dist/server-cookies/index.browser.js +8 -8
- package/dist/server-cookies/index.browser.js.map +1 -1
- package/dist/server-cookies/index.d.ts +17 -17
- package/dist/server-cookies/index.js +10 -10
- package/dist/server-cookies/index.js.map +1 -1
- package/dist/server-cors/index.d.ts +17 -17
- package/dist/server-cors/index.js +9 -9
- package/dist/server-cors/index.js.map +1 -1
- package/dist/server-health/index.d.ts +19 -19
- package/dist/server-helmet/index.d.ts +1 -1
- package/dist/server-links/index.browser.js +12 -12
- package/dist/server-links/index.browser.js.map +1 -1
- package/dist/server-links/index.d.ts +59 -251
- package/dist/server-links/index.js +23 -502
- package/dist/server-links/index.js.map +1 -1
- package/dist/server-metrics/index.d.ts +4 -4
- package/dist/server-multipart/index.d.ts +2 -2
- package/dist/server-proxy/index.d.ts +12 -12
- package/dist/server-proxy/index.js +10 -10
- package/dist/server-proxy/index.js.map +1 -1
- package/dist/server-rate-limit/index.d.ts +22 -22
- package/dist/server-rate-limit/index.js +12 -12
- package/dist/server-rate-limit/index.js.map +1 -1
- package/dist/server-security/index.d.ts +22 -22
- package/dist/server-security/index.js +15 -15
- package/dist/server-security/index.js.map +1 -1
- package/dist/server-static/index.d.ts +14 -14
- package/dist/server-static/index.js +8 -8
- package/dist/server-static/index.js.map +1 -1
- package/dist/server-swagger/index.d.ts +25 -184
- package/dist/server-swagger/index.js +21 -724
- package/dist/server-swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +14 -14
- package/dist/sms/index.js +9 -9
- package/dist/sms/index.js.map +1 -1
- package/dist/thread/index.d.ts +11 -11
- package/dist/thread/index.js +17 -17
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/index.d.ts +26 -26
- package/dist/topic/index.js +16 -16
- package/dist/topic/index.js.map +1 -1
- package/dist/topic-redis/index.d.ts +1 -1
- package/dist/vite/index.d.ts +3 -3
- package/dist/vite/index.js +8 -8
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +11 -11
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +58 -58
- package/dist/websocket/index.js +13 -13
- package/dist/websocket/index.js.map +1 -1
- package/package.json +113 -52
- package/src/api-files/services/FileService.ts +5 -7
- package/src/api-jobs/index.ts +1 -1
- package/src/api-jobs/{descriptors → primitives}/$job.ts +8 -8
- package/src/api-jobs/providers/JobProvider.ts +9 -9
- package/src/api-jobs/services/JobService.ts +5 -5
- package/src/api-notifications/index.ts +5 -15
- package/src/api-notifications/{descriptors → primitives}/$notification.ts +10 -10
- package/src/api-notifications/services/NotificationSenderService.ts +3 -3
- package/src/api-parameters/index.ts +1 -1
- package/src/api-parameters/{descriptors → primitives}/$config.ts +7 -12
- package/src/api-users/index.ts +1 -1
- package/src/api-users/{descriptors → primitives}/$userRealm.ts +8 -8
- package/src/api-users/providers/UserRealmProvider.ts +1 -1
- package/src/batch/index.ts +3 -3
- package/src/batch/{descriptors → primitives}/$batch.ts +13 -16
- package/src/bucket/index.ts +8 -8
- package/src/bucket/{descriptors → primitives}/$bucket.ts +8 -8
- package/src/bucket/providers/LocalFileStorageProvider.ts +3 -3
- package/src/cache/index.ts +4 -4
- package/src/cache/{descriptors → primitives}/$cache.ts +15 -15
- package/src/cli/apps/AlephaPackageBuilderCli.ts +24 -2
- package/src/cli/commands/DrizzleCommands.ts +6 -6
- package/src/cli/commands/VerifyCommands.ts +1 -1
- package/src/cli/commands/ViteCommands.ts +6 -1
- package/src/cli/services/ProjectUtils.ts +34 -3
- package/src/command/index.ts +5 -5
- package/src/command/{descriptors → primitives}/$command.ts +9 -12
- package/src/command/providers/CliProvider.ts +10 -10
- package/src/core/Alepha.ts +30 -33
- package/src/core/constants/KIND.ts +1 -1
- package/src/core/constants/OPTIONS.ts +1 -1
- package/src/core/helpers/{descriptor.ts → primitive.ts} +18 -18
- package/src/core/helpers/ref.ts +1 -1
- package/src/core/index.shared.ts +8 -8
- package/src/core/{descriptors → primitives}/$context.ts +5 -5
- package/src/core/{descriptors → primitives}/$hook.ts +4 -4
- package/src/core/{descriptors → primitives}/$inject.ts +2 -2
- package/src/core/{descriptors → primitives}/$module.ts +9 -9
- package/src/core/{descriptors → primitives}/$use.ts +2 -2
- package/src/core/providers/CodecManager.ts +1 -1
- package/src/core/providers/JsonSchemaCodec.ts +1 -1
- package/src/core/providers/StateManager.ts +2 -2
- package/src/datetime/index.ts +3 -3
- package/src/datetime/{descriptors → primitives}/$interval.ts +6 -6
- package/src/email/index.ts +4 -4
- package/src/email/{descriptors → primitives}/$email.ts +8 -8
- package/src/file/index.ts +1 -1
- package/src/lock/index.ts +3 -3
- package/src/lock/{descriptors → primitives}/$lock.ts +10 -10
- package/src/logger/index.ts +8 -8
- package/src/logger/{descriptors → primitives}/$logger.ts +2 -2
- package/src/logger/services/Logger.ts +1 -1
- package/src/orm/constants/PG_SYMBOLS.ts +2 -2
- package/src/orm/index.browser.ts +2 -2
- package/src/orm/index.ts +8 -8
- package/src/orm/{descriptors → primitives}/$entity.ts +11 -11
- package/src/orm/{descriptors → primitives}/$repository.ts +2 -2
- package/src/orm/{descriptors → primitives}/$sequence.ts +8 -8
- package/src/orm/{descriptors → primitives}/$transaction.ts +4 -4
- package/src/orm/providers/PostgresTypeProvider.ts +3 -3
- package/src/orm/providers/RepositoryProvider.ts +4 -4
- package/src/orm/providers/drivers/DatabaseProvider.ts +7 -7
- package/src/orm/services/ModelBuilder.ts +9 -9
- package/src/orm/services/PgRelationManager.ts +2 -2
- package/src/orm/services/PostgresModelBuilder.ts +5 -5
- package/src/orm/services/Repository.ts +7 -7
- package/src/orm/services/SqliteModelBuilder.ts +5 -5
- package/src/queue/index.ts +7 -7
- package/src/queue/{descriptors → primitives}/$consumer.ts +15 -15
- package/src/queue/{descriptors → primitives}/$queue.ts +12 -12
- package/src/queue/providers/WorkerProvider.ts +7 -7
- package/src/retry/index.ts +3 -3
- package/src/retry/{descriptors → primitives}/$retry.ts +14 -14
- package/src/scheduler/index.ts +3 -3
- package/src/scheduler/{descriptors → primitives}/$scheduler.ts +9 -9
- package/src/scheduler/providers/CronProvider.ts +1 -1
- package/src/security/index.ts +9 -9
- package/src/security/{descriptors → primitives}/$permission.ts +7 -7
- package/src/security/{descriptors → primitives}/$realm.ts +6 -12
- package/src/security/{descriptors → primitives}/$role.ts +12 -12
- package/src/security/{descriptors → primitives}/$serviceAccount.ts +8 -8
- package/src/server/index.browser.ts +1 -1
- package/src/server/index.ts +14 -14
- package/src/server/{descriptors → primitives}/$action.ts +13 -13
- package/src/server/{descriptors → primitives}/$route.ts +9 -9
- package/src/server/providers/NodeHttpServerProvider.ts +1 -1
- package/src/server/services/HttpClient.ts +1 -1
- package/src/server-auth/index.browser.ts +1 -1
- package/src/server-auth/index.ts +6 -6
- package/src/server-auth/{descriptors → primitives}/$auth.ts +10 -10
- package/src/server-auth/{descriptors → primitives}/$authCredentials.ts +4 -4
- package/src/server-auth/{descriptors → primitives}/$authGithub.ts +4 -4
- package/src/server-auth/{descriptors → primitives}/$authGoogle.ts +4 -4
- package/src/server-auth/providers/ServerAuthProvider.ts +4 -4
- package/src/server-cache/providers/ServerCacheProvider.ts +7 -7
- package/src/server-compress/providers/ServerCompressProvider.ts +3 -3
- package/src/server-cookies/index.browser.ts +2 -2
- package/src/server-cookies/index.ts +5 -5
- package/src/server-cookies/{descriptors → primitives}/$cookie.browser.ts +12 -12
- package/src/server-cookies/{descriptors → primitives}/$cookie.ts +13 -13
- package/src/server-cookies/providers/ServerCookiesProvider.ts +4 -4
- package/src/server-cookies/services/CookieParser.ts +1 -1
- package/src/server-cors/index.ts +3 -3
- package/src/server-cors/{descriptors → primitives}/$cors.ts +11 -13
- package/src/server-cors/providers/ServerCorsProvider.ts +5 -5
- package/src/server-links/index.browser.ts +5 -5
- package/src/server-links/index.ts +9 -9
- package/src/server-links/{descriptors → primitives}/$remote.ts +11 -11
- package/src/server-links/providers/LinkProvider.ts +7 -7
- package/src/server-links/providers/{RemoteDescriptorProvider.ts → RemotePrimitiveProvider.ts} +6 -6
- package/src/server-links/providers/ServerLinksProvider.ts +3 -3
- package/src/server-proxy/index.ts +3 -3
- package/src/server-proxy/{descriptors → primitives}/$proxy.ts +8 -8
- package/src/server-proxy/providers/ServerProxyProvider.ts +4 -4
- package/src/server-rate-limit/index.ts +6 -6
- package/src/server-rate-limit/{descriptors → primitives}/$rateLimit.ts +13 -13
- package/src/server-rate-limit/providers/ServerRateLimitProvider.ts +5 -5
- package/src/server-security/index.ts +3 -3
- package/src/server-security/{descriptors → primitives}/$basicAuth.ts +13 -13
- package/src/server-security/providers/ServerBasicAuthProvider.ts +5 -5
- package/src/server-security/providers/ServerSecurityProvider.ts +4 -4
- package/src/server-static/index.ts +3 -3
- package/src/server-static/{descriptors → primitives}/$serve.ts +8 -10
- package/src/server-static/providers/ServerStaticProvider.ts +6 -6
- package/src/server-swagger/index.ts +5 -5
- package/src/server-swagger/{descriptors → primitives}/$swagger.ts +9 -9
- package/src/server-swagger/providers/ServerSwaggerProvider.ts +11 -10
- package/src/sms/index.ts +4 -4
- package/src/sms/{descriptors → primitives}/$sms.ts +8 -8
- package/src/thread/index.ts +3 -3
- package/src/thread/{descriptors → primitives}/$thread.ts +13 -13
- package/src/thread/providers/ThreadProvider.ts +7 -9
- package/src/topic/index.ts +5 -5
- package/src/topic/{descriptors → primitives}/$subscriber.ts +14 -14
- package/src/topic/{descriptors → primitives}/$topic.ts +10 -10
- package/src/topic/providers/TopicProvider.ts +4 -4
- package/src/vite/tasks/copyAssets.ts +1 -1
- package/src/vite/tasks/generateSitemap.ts +3 -3
- package/src/vite/tasks/prerenderPages.ts +2 -2
- package/src/vite/tasks/runAlepha.ts +2 -2
- package/src/websocket/index.browser.ts +3 -3
- package/src/websocket/index.shared.ts +2 -2
- package/src/websocket/index.ts +4 -4
- package/src/websocket/interfaces/WebSocketInterfaces.ts +3 -3
- package/src/websocket/{descriptors → primitives}/$channel.ts +10 -10
- package/src/websocket/{descriptors → primitives}/$websocket.ts +8 -8
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +7 -7
- package/src/websocket/providers/WebSocketServerProvider.ts +3 -3
- package/src/websocket/services/WebSocketClient.ts +5 -5
- package/src/api-notifications/providers/MemorySmsProvider.ts +0 -20
- package/src/api-notifications/providers/SmsProvider.ts +0 -8
- /package/src/core/{descriptors → primitives}/$atom.ts +0 -0
- /package/src/core/{descriptors → primitives}/$env.ts +0 -0
- /package/src/server-auth/{descriptors → primitives}/$authApple.ts +0 -0
- /package/src/server-links/{descriptors → primitives}/$client.ts +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as alepha1 from "alepha";
|
|
2
|
-
import {
|
|
2
|
+
import { KIND, Primitive, Static } from "alepha";
|
|
3
3
|
import { ServerRequest, ServerRouterProvider } from "alepha/server";
|
|
4
4
|
import * as alepha_cache0 from "alepha/cache";
|
|
5
5
|
import * as alepha_logger0 from "alepha/logger";
|
|
@@ -34,7 +34,7 @@ declare class ServerRateLimitProvider {
|
|
|
34
34
|
RATE_LIMIT_WINDOW_MS: number;
|
|
35
35
|
RATE_LIMIT_MAX_REQUESTS: number;
|
|
36
36
|
};
|
|
37
|
-
protected readonly cache: alepha_cache0.
|
|
37
|
+
protected readonly cache: alepha_cache0.CachePrimitiveFn<RateLimitData, any[]>;
|
|
38
38
|
protected readonly globalOptions: Readonly<{
|
|
39
39
|
windowMs?: number | undefined;
|
|
40
40
|
max?: number | undefined;
|
|
@@ -44,18 +44,18 @@ declare class ServerRateLimitProvider {
|
|
|
44
44
|
/**
|
|
45
45
|
* Registered rate limit configurations with their path patterns
|
|
46
46
|
*/
|
|
47
|
-
readonly registeredConfigs:
|
|
47
|
+
readonly registeredConfigs: RateLimitPrimitiveOptions[];
|
|
48
48
|
/**
|
|
49
|
-
* Register a rate limit configuration (called by
|
|
49
|
+
* Register a rate limit configuration (called by primitives)
|
|
50
50
|
*/
|
|
51
|
-
registerRateLimit(config:
|
|
52
|
-
protected readonly onStart: alepha1.
|
|
53
|
-
readonly onRequest: alepha1.
|
|
54
|
-
readonly onActionRequest: alepha1.
|
|
51
|
+
registerRateLimit(config: RateLimitPrimitiveOptions): void;
|
|
52
|
+
protected readonly onStart: alepha1.HookPrimitive<"start">;
|
|
53
|
+
readonly onRequest: alepha1.HookPrimitive<"server:onRequest">;
|
|
54
|
+
readonly onActionRequest: alepha1.HookPrimitive<"action:onRequest">;
|
|
55
55
|
/**
|
|
56
56
|
* Build complete rate limit options by merging with global defaults
|
|
57
57
|
*/
|
|
58
|
-
protected buildRateLimitOptions(config:
|
|
58
|
+
protected buildRateLimitOptions(config: RateLimitPrimitiveOptions): RateLimitOptions;
|
|
59
59
|
/**
|
|
60
60
|
* Set rate limit headers on the response
|
|
61
61
|
*/
|
|
@@ -70,10 +70,10 @@ interface RateLimitData {
|
|
|
70
70
|
hits: number[];
|
|
71
71
|
}
|
|
72
72
|
//#endregion
|
|
73
|
-
//#region src/server-rate-limit/
|
|
73
|
+
//#region src/server-rate-limit/primitives/$rateLimit.d.ts
|
|
74
74
|
/**
|
|
75
75
|
* Declares rate limiting for server routes or custom usage.
|
|
76
|
-
* This
|
|
76
|
+
* This primitive provides methods to check rate limits and configure behavior
|
|
77
77
|
* within the server request/response cycle.
|
|
78
78
|
*
|
|
79
79
|
* @example
|
|
@@ -98,33 +98,33 @@ interface RateLimitData {
|
|
|
98
98
|
* ```
|
|
99
99
|
*/
|
|
100
100
|
declare const $rateLimit: {
|
|
101
|
-
(options?:
|
|
102
|
-
[KIND]: typeof
|
|
101
|
+
(options?: RateLimitPrimitiveOptions): AbstractRateLimitPrimitive;
|
|
102
|
+
[KIND]: typeof RateLimitPrimitive;
|
|
103
103
|
};
|
|
104
|
-
interface
|
|
104
|
+
interface RateLimitPrimitiveOptions extends RateLimitOptions {
|
|
105
105
|
/** Name identifier for this rate limit (default: property key) */
|
|
106
106
|
name?: string;
|
|
107
107
|
/** Path patterns to match (supports wildcards like /api/*) */
|
|
108
108
|
paths?: string[];
|
|
109
109
|
}
|
|
110
|
-
interface
|
|
110
|
+
interface AbstractRateLimitPrimitive {
|
|
111
111
|
readonly name: string;
|
|
112
|
-
readonly options:
|
|
112
|
+
readonly options: RateLimitPrimitiveOptions;
|
|
113
113
|
check(request: ServerRequest, options?: RateLimitOptions): Promise<RateLimitResult>;
|
|
114
114
|
}
|
|
115
|
-
declare class
|
|
115
|
+
declare class RateLimitPrimitive extends Primitive<RateLimitPrimitiveOptions> implements AbstractRateLimitPrimitive {
|
|
116
116
|
protected readonly serverRateLimitProvider: ServerRateLimitProvider;
|
|
117
117
|
get name(): string;
|
|
118
118
|
protected onInit(): void;
|
|
119
119
|
/**
|
|
120
|
-
* Checks rate limit for the given request using this
|
|
120
|
+
* Checks rate limit for the given request using this primitive's configuration.
|
|
121
121
|
*/
|
|
122
122
|
check(request: ServerRequest, options?: RateLimitOptions): Promise<RateLimitResult>;
|
|
123
123
|
}
|
|
124
124
|
//#endregion
|
|
125
125
|
//#region src/server-rate-limit/index.d.ts
|
|
126
126
|
declare module "alepha/server" {
|
|
127
|
-
interface
|
|
127
|
+
interface ActionPrimitiveOptions<TConfig> {
|
|
128
128
|
/**
|
|
129
129
|
* Rate limiting configuration for this action.
|
|
130
130
|
* When specified, the action will be rate limited according to these settings.
|
|
@@ -155,8 +155,8 @@ interface RateLimitOptions {
|
|
|
155
155
|
* Provides rate limiting capabilities for server routes and actions with configurable limits and windows.
|
|
156
156
|
*
|
|
157
157
|
* The server-rate-limit module enables per-route and per-action rate limiting using either:
|
|
158
|
-
* - The `$rateLimit`
|
|
159
|
-
* - The `rateLimit` option in action
|
|
158
|
+
* - The `$rateLimit` primitive with `paths` option for path-based rate limiting
|
|
159
|
+
* - The `rateLimit` option in action primitives for action-specific limiting
|
|
160
160
|
*
|
|
161
161
|
* It offers sliding window rate limiting, custom key generation, and seamless integration with server routes.
|
|
162
162
|
*
|
|
@@ -179,5 +179,5 @@ interface RateLimitOptions {
|
|
|
179
179
|
*/
|
|
180
180
|
declare const AlephaServerRateLimit: alepha1.Service<alepha1.Module>;
|
|
181
181
|
//#endregion
|
|
182
|
-
export { $rateLimit,
|
|
182
|
+
export { $rateLimit, AbstractRateLimitPrimitive, AlephaServerRateLimit, RateLimitAtomOptions, RateLimitOptions, RateLimitPrimitive, RateLimitPrimitiveOptions, RateLimitResult, ServerRateLimitProvider, rateLimitOptions };
|
|
183
183
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $atom, $env, $hook, $inject, $module, $use,
|
|
1
|
+
import { $atom, $env, $hook, $inject, $module, $use, KIND, Primitive, createPrimitive, t } from "alepha";
|
|
2
2
|
import { AlephaServer, HttpError, ServerRouterProvider } from "alepha/server";
|
|
3
3
|
import { $cache } from "alepha/cache";
|
|
4
4
|
import { $logger } from "alepha/logger";
|
|
@@ -41,7 +41,7 @@ var ServerRateLimitProvider = class {
|
|
|
41
41
|
*/
|
|
42
42
|
registeredConfigs = [];
|
|
43
43
|
/**
|
|
44
|
-
* Register a rate limit configuration (called by
|
|
44
|
+
* Register a rate limit configuration (called by primitives)
|
|
45
45
|
*/
|
|
46
46
|
registerRateLimit(config) {
|
|
47
47
|
this.registeredConfigs.push(config);
|
|
@@ -147,10 +147,10 @@ var ServerRateLimitProvider = class {
|
|
|
147
147
|
};
|
|
148
148
|
|
|
149
149
|
//#endregion
|
|
150
|
-
//#region src/server-rate-limit/
|
|
150
|
+
//#region src/server-rate-limit/primitives/$rateLimit.ts
|
|
151
151
|
/**
|
|
152
152
|
* Declares rate limiting for server routes or custom usage.
|
|
153
|
-
* This
|
|
153
|
+
* This primitive provides methods to check rate limits and configure behavior
|
|
154
154
|
* within the server request/response cycle.
|
|
155
155
|
*
|
|
156
156
|
* @example
|
|
@@ -175,9 +175,9 @@ var ServerRateLimitProvider = class {
|
|
|
175
175
|
* ```
|
|
176
176
|
*/
|
|
177
177
|
const $rateLimit = (options = {}) => {
|
|
178
|
-
return
|
|
178
|
+
return createPrimitive(RateLimitPrimitive, options);
|
|
179
179
|
};
|
|
180
|
-
var
|
|
180
|
+
var RateLimitPrimitive = class extends Primitive {
|
|
181
181
|
serverRateLimitProvider = $inject(ServerRateLimitProvider);
|
|
182
182
|
get name() {
|
|
183
183
|
return this.options.name ?? `${this.config.propertyKey}`;
|
|
@@ -186,7 +186,7 @@ var RateLimitDescriptor = class extends Descriptor {
|
|
|
186
186
|
this.serverRateLimitProvider.registerRateLimit(this.options);
|
|
187
187
|
}
|
|
188
188
|
/**
|
|
189
|
-
* Checks rate limit for the given request using this
|
|
189
|
+
* Checks rate limit for the given request using this primitive's configuration.
|
|
190
190
|
*/
|
|
191
191
|
async check(request, options) {
|
|
192
192
|
const mergedOptions = {
|
|
@@ -196,7 +196,7 @@ var RateLimitDescriptor = class extends Descriptor {
|
|
|
196
196
|
return this.serverRateLimitProvider.checkLimit(request, mergedOptions);
|
|
197
197
|
}
|
|
198
198
|
};
|
|
199
|
-
$rateLimit[KIND] =
|
|
199
|
+
$rateLimit[KIND] = RateLimitPrimitive;
|
|
200
200
|
|
|
201
201
|
//#endregion
|
|
202
202
|
//#region src/server-rate-limit/index.ts
|
|
@@ -204,8 +204,8 @@ $rateLimit[KIND] = RateLimitDescriptor;
|
|
|
204
204
|
* Provides rate limiting capabilities for server routes and actions with configurable limits and windows.
|
|
205
205
|
*
|
|
206
206
|
* The server-rate-limit module enables per-route and per-action rate limiting using either:
|
|
207
|
-
* - The `$rateLimit`
|
|
208
|
-
* - The `rateLimit` option in action
|
|
207
|
+
* - The `$rateLimit` primitive with `paths` option for path-based rate limiting
|
|
208
|
+
* - The `rateLimit` option in action primitives for action-specific limiting
|
|
209
209
|
*
|
|
210
210
|
* It offers sliding window rate limiting, custom key generation, and seamless integration with server routes.
|
|
211
211
|
*
|
|
@@ -228,10 +228,10 @@ $rateLimit[KIND] = RateLimitDescriptor;
|
|
|
228
228
|
*/
|
|
229
229
|
const AlephaServerRateLimit = $module({
|
|
230
230
|
name: "alepha.server.rate-limit",
|
|
231
|
-
|
|
231
|
+
primitives: [$rateLimit],
|
|
232
232
|
services: [AlephaServer, ServerRateLimitProvider]
|
|
233
233
|
});
|
|
234
234
|
|
|
235
235
|
//#endregion
|
|
236
|
-
export { $rateLimit, AlephaServerRateLimit,
|
|
236
|
+
export { $rateLimit, AlephaServerRateLimit, RateLimitPrimitive, ServerRateLimitProvider, rateLimitOptions };
|
|
237
237
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["result: RateLimitResult"],"sources":["../../src/server-rate-limit/providers/ServerRateLimitProvider.ts","../../src/server-rate-limit/descriptors/$rateLimit.ts","../../src/server-rate-limit/index.ts"],"sourcesContent":["import { $atom, $env, $hook, $inject, $use, type Static, t } from \"alepha\";\nimport { $cache } from \"alepha/cache\";\nimport { $logger } from \"alepha/logger\";\nimport {\n HttpError,\n type ServerRequest,\n ServerRouterProvider,\n} from \"alepha/server\";\nimport type { RateLimitDescriptorOptions } from \"../descriptors/$rateLimit.ts\";\nimport type { RateLimitOptions } from \"../index.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface RateLimitResult {\n allowed: boolean;\n limit: number;\n remaining: number;\n resetTime: number;\n retryAfter?: number;\n}\n\n/**\n * Rate limit configuration atom (global defaults)\n */\nexport const rateLimitOptions = $atom({\n name: \"alepha.server.rate-limit.options\",\n schema: t.object({\n windowMs: t.optional(\n t.number({\n description: \"Window duration in milliseconds\",\n }),\n ),\n max: t.optional(\n t.number({\n description: \"Maximum number of requests per window\",\n }),\n ),\n skipFailedRequests: t.optional(\n t.boolean({\n description: \"Skip rate limiting for failed requests\",\n }),\n ),\n skipSuccessfulRequests: t.optional(\n t.boolean({\n description: \"Skip rate limiting for successful requests\",\n }),\n ),\n }),\n default: {},\n});\n\nexport type RateLimitAtomOptions = Static<typeof rateLimitOptions.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [rateLimitOptions.key]: RateLimitAtomOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nconst envSchema = t.object({\n RATE_LIMIT_WINDOW_MS: t.number({\n default: 15 * 60 * 1000, // 15 minutes\n description: \"Rate limit window in milliseconds\",\n }),\n RATE_LIMIT_MAX_REQUESTS: t.number({\n default: 100,\n description: \"Maximum requests per window\",\n }),\n});\n\nexport class ServerRateLimitProvider {\n protected readonly log = $logger();\n protected readonly serverRouterProvider = $inject(ServerRouterProvider);\n protected readonly env = $env(envSchema);\n\n protected readonly cache = $cache<RateLimitData>({\n name: \"server-rate-limit\",\n ttl: [this.env.RATE_LIMIT_WINDOW_MS, \"milliseconds\"],\n });\n\n protected readonly globalOptions = $use(rateLimitOptions);\n\n /**\n * Registered rate limit configurations with their path patterns\n */\n public readonly registeredConfigs: RateLimitDescriptorOptions[] = [];\n\n /**\n * Register a rate limit configuration (called by descriptors)\n */\n public registerRateLimit(config: RateLimitDescriptorOptions): void {\n this.registeredConfigs.push(config);\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n // Apply path-specific rate limit configs to routes\n for (const config of this.registeredConfigs) {\n if (config.paths) {\n for (const pattern of config.paths) {\n const matchedRoutes = this.serverRouterProvider.getRoutes(pattern);\n for (const route of matchedRoutes) {\n route.rateLimit = this.buildRateLimitOptions(config);\n }\n }\n }\n }\n\n if (this.registeredConfigs.length > 0) {\n this.log.info(\n `Initialized with ${this.registeredConfigs.length} registered rate-limit configurations.`,\n );\n }\n },\n });\n\n public readonly onRequest = $hook({\n on: \"server:onRequest\",\n handler: async ({ route, request }) => {\n // Use route-specific rate limit if defined, otherwise use global options\n const rateLimitConfig = route.rateLimit ?? this.globalOptions;\n\n // Skip if no rate limiting configured\n if (!rateLimitConfig.max && !rateLimitConfig.windowMs) {\n return;\n }\n\n const result = await this.checkLimit(request, rateLimitConfig);\n this.setRateLimitHeaders(request, result);\n\n if (!result.allowed) {\n throw new HttpError({\n status: 429,\n message: \"Too Many Requests\",\n });\n }\n },\n });\n\n public readonly onActionRequest = $hook({\n on: \"action:onRequest\",\n handler: async ({ action, request }) => {\n // Check if this action has rate limiting enabled\n const rateLimit = action.options?.rateLimit;\n if (!rateLimit) {\n return; // No rate limiting for this action\n }\n\n const result = await this.checkLimit(request, rateLimit);\n\n if (!result.allowed) {\n // Actions are internal - don't set HTTP headers\n // Only throw error to prevent action execution\n throw new HttpError({\n status: 429,\n message: \"Too Many Requests\",\n });\n }\n\n // Action allowed - no headers to set since actions are internal\n },\n });\n\n /**\n * Build complete rate limit options by merging with global defaults\n */\n protected buildRateLimitOptions(\n config: RateLimitDescriptorOptions,\n ): RateLimitOptions {\n return {\n max: config.max ?? this.globalOptions.max,\n windowMs: config.windowMs ?? this.globalOptions.windowMs,\n keyGenerator: config.keyGenerator,\n skipFailedRequests:\n config.skipFailedRequests ?? this.globalOptions.skipFailedRequests,\n skipSuccessfulRequests:\n config.skipSuccessfulRequests ??\n this.globalOptions.skipSuccessfulRequests,\n };\n }\n\n /**\n * Set rate limit headers on the response\n */\n protected setRateLimitHeaders(\n request: ServerRequest,\n result: RateLimitResult,\n ): void {\n request.reply.setHeader(\"X-RateLimit-Limit\", result.limit.toString());\n request.reply.setHeader(\n \"X-RateLimit-Remaining\",\n result.remaining.toString(),\n );\n request.reply.setHeader(\n \"X-RateLimit-Reset\",\n Math.ceil(result.resetTime / 1000).toString(),\n );\n\n if (!result.allowed && result.retryAfter) {\n request.reply.setHeader(\"Retry-After\", result.retryAfter.toString());\n }\n }\n\n public async checkLimit(\n req: ServerRequest,\n options: RateLimitOptions = {},\n ): Promise<RateLimitResult> {\n const windowMs = options.windowMs ?? this.env.RATE_LIMIT_WINDOW_MS;\n const max = options.max ?? this.env.RATE_LIMIT_MAX_REQUESTS;\n const key = this.generateKey(req);\n\n const now = Date.now();\n const windowStart = now - windowMs;\n\n // Get current rate limit data\n const currentData = (await this.cache.get(key)) || {\n count: 0,\n windowStart: now,\n hits: [],\n };\n\n // Clean old hits outside the current window\n const validHits = currentData.hits.filter(\n (hit: number) => hit >= windowStart,\n );\n\n // Check if limit exceeded\n const allowed = validHits.length < max;\n const remaining = Math.max(0, max - validHits.length);\n const resetTime = Math.max(...validHits, windowStart) + windowMs;\n\n // If allowed, record this request\n if (allowed) {\n validHits.push(now);\n await this.cache.set(key, {\n count: validHits.length,\n windowStart: Math.min(currentData.windowStart, windowStart),\n hits: validHits,\n });\n }\n\n const result: RateLimitResult = {\n allowed,\n limit: max,\n remaining: allowed ? remaining - 1 : remaining,\n resetTime,\n };\n\n if (!allowed) {\n result.retryAfter = Math.ceil((resetTime - now) / 1000);\n }\n\n return result;\n }\n\n protected generateKey(req: ServerRequest): string {\n // Default to IP-based rate limiting\n const ip = this.getClientIP(req);\n return `ip:${ip}`;\n }\n\n protected getClientIP(req: ServerRequest): string {\n // Check x-forwarded-for header first (for proxies/load balancers)\n const forwarded = req.headers?.[\"x-forwarded-for\"];\n if (forwarded) {\n // x-forwarded-for can contain multiple IPs, get the first one (original client)\n const firstIp = forwarded.split(\",\")[0].trim();\n if (firstIp) return firstIp;\n }\n\n return req.ip || \"unknown\";\n }\n}\n\ninterface RateLimitData {\n count: number;\n windowStart: number;\n hits: number[];\n}\n","import { $inject, createDescriptor, Descriptor, KIND } from \"alepha\";\nimport type { ServerRequest } from \"alepha/server\";\nimport type { RateLimitOptions } from \"../index.ts\";\nimport {\n type RateLimitResult,\n ServerRateLimitProvider,\n} from \"../providers/ServerRateLimitProvider.ts\";\n\n/**\n * Declares rate limiting for server routes or custom usage.\n * This descriptor provides methods to check rate limits and configure behavior\n * within the server request/response cycle.\n *\n * @example\n * ```ts\n * class ApiService {\n * // Apply rate limiting to specific paths\n * apiRateLimit = $rateLimit({\n * paths: [\"/api/*\"],\n * max: 100,\n * windowMs: 15 * 60 * 1000, // 15 minutes\n * });\n *\n * // Or use check() method for manual rate limiting\n * customAction = $action({\n * handler: async (req) => {\n * const result = await this.apiRateLimit.check(req);\n * if (!result.allowed) throw new Error(\"Rate limited\");\n * return \"ok\";\n * },\n * });\n * }\n * ```\n */\nexport const $rateLimit = (\n options: RateLimitDescriptorOptions = {},\n): AbstractRateLimitDescriptor => {\n return createDescriptor(RateLimitDescriptor, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface RateLimitDescriptorOptions extends RateLimitOptions {\n /** Name identifier for this rate limit (default: property key) */\n name?: string;\n /** Path patterns to match (supports wildcards like /api/*) */\n paths?: string[];\n}\n\nexport interface AbstractRateLimitDescriptor {\n readonly name: string;\n readonly options: RateLimitDescriptorOptions;\n check(\n request: ServerRequest,\n options?: RateLimitOptions,\n ): Promise<RateLimitResult>;\n}\n\nexport class RateLimitDescriptor\n extends Descriptor<RateLimitDescriptorOptions>\n implements AbstractRateLimitDescriptor\n{\n protected readonly serverRateLimitProvider = $inject(ServerRateLimitProvider);\n\n public get name(): string {\n return this.options.name ?? `${this.config.propertyKey}`;\n }\n\n protected onInit() {\n // Register this rate limit configuration with the provider\n this.serverRateLimitProvider.registerRateLimit(this.options);\n }\n\n /**\n * Checks rate limit for the given request using this descriptor's configuration.\n */\n public async check(\n request: ServerRequest,\n options?: RateLimitOptions,\n ): Promise<RateLimitResult> {\n const mergedOptions = { ...this.options, ...options };\n return this.serverRateLimitProvider.checkLimit(request, mergedOptions);\n }\n}\n\n$rateLimit[KIND] = RateLimitDescriptor;\n","import { $module } from \"alepha\";\nimport { AlephaServer } from \"alepha/server\";\nimport { $rateLimit } from \"./descriptors/$rateLimit.ts\";\nimport { ServerRateLimitProvider } from \"./providers/ServerRateLimitProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./descriptors/$rateLimit.ts\";\nexport * from \"./providers/ServerRateLimitProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha/server\" {\n interface ActionDescriptorOptions<TConfig> {\n /**\n * Rate limiting configuration for this action.\n * When specified, the action will be rate limited according to these settings.\n */\n rateLimit?: RateLimitOptions;\n }\n\n interface ServerRoute {\n /**\n * Route-specific rate limit configuration.\n * If set, overrides the global rate limit options for this route.\n */\n rateLimit?: RateLimitOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface RateLimitOptions {\n /** Maximum number of requests per window (default: 100) */\n max?: number;\n /** Window duration in milliseconds (default: 15 minutes) */\n windowMs?: number;\n /** Custom key generator function */\n keyGenerator?: (req: any) => string;\n /** Skip rate limiting for failed requests */\n skipFailedRequests?: boolean;\n /** Skip rate limiting for successful requests */\n skipSuccessfulRequests?: boolean;\n}\n\n/**\n * Provides rate limiting capabilities for server routes and actions with configurable limits and windows.\n *\n * The server-rate-limit module enables per-route and per-action rate limiting using either:\n * - The `$rateLimit` descriptor with `paths` option for path-based rate limiting\n * - The `rateLimit` option in action descriptors for action-specific limiting\n *\n * It offers sliding window rate limiting, custom key generation, and seamless integration with server routes.\n *\n * @example\n * ```ts\n * import { $rateLimit, AlephaServerRateLimit } from \"alepha/server-rate-limit\";\n *\n * class ApiService {\n * // Path-specific rate limiting\n * apiRateLimit = $rateLimit({\n * paths: [\"/api/*\"],\n * max: 100,\n * windowMs: 15 * 60 * 1000, // 15 minutes\n * });\n * }\n * ```\n *\n * @see {@link $rateLimit}\n * @module alepha.server.rate-limit\n */\nexport const AlephaServerRateLimit = $module({\n name: \"alepha.server.rate-limit\",\n descriptors: [$rateLimit],\n services: [AlephaServer, ServerRateLimitProvider],\n});\n"],"mappings":";;;;;;;;;AAwBA,MAAa,mBAAmB,MAAM;CACpC,MAAM;CACN,QAAQ,EAAE,OAAO;EACf,UAAU,EAAE,SACV,EAAE,OAAO,EACP,aAAa,mCACd,CAAC,CACH;EACD,KAAK,EAAE,SACL,EAAE,OAAO,EACP,aAAa,yCACd,CAAC,CACH;EACD,oBAAoB,EAAE,SACpB,EAAE,QAAQ,EACR,aAAa,0CACd,CAAC,CACH;EACD,wBAAwB,EAAE,SACxB,EAAE,QAAQ,EACR,aAAa,8CACd,CAAC,CACH;EACF,CAAC;CACF,SAAS,EAAE;CACZ,CAAC;AAYF,MAAM,YAAY,EAAE,OAAO;CACzB,sBAAsB,EAAE,OAAO;EAC7B,SAAS,MAAU;EACnB,aAAa;EACd,CAAC;CACF,yBAAyB,EAAE,OAAO;EAChC,SAAS;EACT,aAAa;EACd,CAAC;CACH,CAAC;AAEF,IAAa,0BAAb,MAAqC;CACnC,AAAmB,MAAM,SAAS;CAClC,AAAmB,uBAAuB,QAAQ,qBAAqB;CACvE,AAAmB,MAAM,KAAK,UAAU;CAExC,AAAmB,QAAQ,OAAsB;EAC/C,MAAM;EACN,KAAK,CAAC,KAAK,IAAI,sBAAsB,eAAe;EACrD,CAAC;CAEF,AAAmB,gBAAgB,KAAK,iBAAiB;;;;CAKzD,AAAgB,oBAAkD,EAAE;;;;CAKpE,AAAO,kBAAkB,QAA0C;AACjE,OAAK,kBAAkB,KAAK,OAAO;;CAGrC,AAAmB,UAAU,MAAM;EACjC,IAAI;EACJ,SAAS,YAAY;AAEnB,QAAK,MAAM,UAAU,KAAK,kBACxB,KAAI,OAAO,MACT,MAAK,MAAM,WAAW,OAAO,OAAO;IAClC,MAAM,gBAAgB,KAAK,qBAAqB,UAAU,QAAQ;AAClE,SAAK,MAAM,SAAS,cAClB,OAAM,YAAY,KAAK,sBAAsB,OAAO;;AAM5D,OAAI,KAAK,kBAAkB,SAAS,EAClC,MAAK,IAAI,KACP,oBAAoB,KAAK,kBAAkB,OAAO,wCACnD;;EAGN,CAAC;CAEF,AAAgB,YAAY,MAAM;EAChC,IAAI;EACJ,SAAS,OAAO,EAAE,OAAO,cAAc;GAErC,MAAM,kBAAkB,MAAM,aAAa,KAAK;AAGhD,OAAI,CAAC,gBAAgB,OAAO,CAAC,gBAAgB,SAC3C;GAGF,MAAM,SAAS,MAAM,KAAK,WAAW,SAAS,gBAAgB;AAC9D,QAAK,oBAAoB,SAAS,OAAO;AAEzC,OAAI,CAAC,OAAO,QACV,OAAM,IAAI,UAAU;IAClB,QAAQ;IACR,SAAS;IACV,CAAC;;EAGP,CAAC;CAEF,AAAgB,kBAAkB,MAAM;EACtC,IAAI;EACJ,SAAS,OAAO,EAAE,QAAQ,cAAc;GAEtC,MAAM,YAAY,OAAO,SAAS;AAClC,OAAI,CAAC,UACH;AAKF,OAAI,EAFW,MAAM,KAAK,WAAW,SAAS,UAAU,EAE5C,QAGV,OAAM,IAAI,UAAU;IAClB,QAAQ;IACR,SAAS;IACV,CAAC;;EAKP,CAAC;;;;CAKF,AAAU,sBACR,QACkB;AAClB,SAAO;GACL,KAAK,OAAO,OAAO,KAAK,cAAc;GACtC,UAAU,OAAO,YAAY,KAAK,cAAc;GAChD,cAAc,OAAO;GACrB,oBACE,OAAO,sBAAsB,KAAK,cAAc;GAClD,wBACE,OAAO,0BACP,KAAK,cAAc;GACtB;;;;;CAMH,AAAU,oBACR,SACA,QACM;AACN,UAAQ,MAAM,UAAU,qBAAqB,OAAO,MAAM,UAAU,CAAC;AACrE,UAAQ,MAAM,UACZ,yBACA,OAAO,UAAU,UAAU,CAC5B;AACD,UAAQ,MAAM,UACZ,qBACA,KAAK,KAAK,OAAO,YAAY,IAAK,CAAC,UAAU,CAC9C;AAED,MAAI,CAAC,OAAO,WAAW,OAAO,WAC5B,SAAQ,MAAM,UAAU,eAAe,OAAO,WAAW,UAAU,CAAC;;CAIxE,MAAa,WACX,KACA,UAA4B,EAAE,EACJ;EAC1B,MAAM,WAAW,QAAQ,YAAY,KAAK,IAAI;EAC9C,MAAM,MAAM,QAAQ,OAAO,KAAK,IAAI;EACpC,MAAM,MAAM,KAAK,YAAY,IAAI;EAEjC,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,cAAc,MAAM;EAG1B,MAAM,cAAe,MAAM,KAAK,MAAM,IAAI,IAAI,IAAK;GACjD,OAAO;GACP,aAAa;GACb,MAAM,EAAE;GACT;EAGD,MAAM,YAAY,YAAY,KAAK,QAChC,QAAgB,OAAO,YACzB;EAGD,MAAM,UAAU,UAAU,SAAS;EACnC,MAAM,YAAY,KAAK,IAAI,GAAG,MAAM,UAAU,OAAO;EACrD,MAAM,YAAY,KAAK,IAAI,GAAG,WAAW,YAAY,GAAG;AAGxD,MAAI,SAAS;AACX,aAAU,KAAK,IAAI;AACnB,SAAM,KAAK,MAAM,IAAI,KAAK;IACxB,OAAO,UAAU;IACjB,aAAa,KAAK,IAAI,YAAY,aAAa,YAAY;IAC3D,MAAM;IACP,CAAC;;EAGJ,MAAMA,SAA0B;GAC9B;GACA,OAAO;GACP,WAAW,UAAU,YAAY,IAAI;GACrC;GACD;AAED,MAAI,CAAC,QACH,QAAO,aAAa,KAAK,MAAM,YAAY,OAAO,IAAK;AAGzD,SAAO;;CAGT,AAAU,YAAY,KAA4B;AAGhD,SAAO,MADI,KAAK,YAAY,IAAI;;CAIlC,AAAU,YAAY,KAA4B;EAEhD,MAAM,YAAY,IAAI,UAAU;AAChC,MAAI,WAAW;GAEb,MAAM,UAAU,UAAU,MAAM,IAAI,CAAC,GAAG,MAAM;AAC9C,OAAI,QAAS,QAAO;;AAGtB,SAAO,IAAI,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/OrB,MAAa,cACX,UAAsC,EAAE,KACR;AAChC,QAAO,iBAAiB,qBAAqB,QAAQ;;AAqBvD,IAAa,sBAAb,cACU,WAEV;CACE,AAAmB,0BAA0B,QAAQ,wBAAwB;CAE7E,IAAW,OAAe;AACxB,SAAO,KAAK,QAAQ,QAAQ,GAAG,KAAK,OAAO;;CAG7C,AAAU,SAAS;AAEjB,OAAK,wBAAwB,kBAAkB,KAAK,QAAQ;;;;;CAM9D,MAAa,MACX,SACA,SAC0B;EAC1B,MAAM,gBAAgB;GAAE,GAAG,KAAK;GAAS,GAAG;GAAS;AACrD,SAAO,KAAK,wBAAwB,WAAW,SAAS,cAAc;;;AAI1E,WAAW,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdnB,MAAa,wBAAwB,QAAQ;CAC3C,MAAM;CACN,aAAa,CAAC,WAAW;CACzB,UAAU,CAAC,cAAc,wBAAwB;CAClD,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["result: RateLimitResult"],"sources":["../../src/server-rate-limit/providers/ServerRateLimitProvider.ts","../../src/server-rate-limit/primitives/$rateLimit.ts","../../src/server-rate-limit/index.ts"],"sourcesContent":["import { $atom, $env, $hook, $inject, $use, type Static, t } from \"alepha\";\nimport { $cache } from \"alepha/cache\";\nimport { $logger } from \"alepha/logger\";\nimport {\n HttpError,\n type ServerRequest,\n ServerRouterProvider,\n} from \"alepha/server\";\nimport type { RateLimitOptions } from \"../index.ts\";\nimport type { RateLimitPrimitiveOptions } from \"../primitives/$rateLimit.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface RateLimitResult {\n allowed: boolean;\n limit: number;\n remaining: number;\n resetTime: number;\n retryAfter?: number;\n}\n\n/**\n * Rate limit configuration atom (global defaults)\n */\nexport const rateLimitOptions = $atom({\n name: \"alepha.server.rate-limit.options\",\n schema: t.object({\n windowMs: t.optional(\n t.number({\n description: \"Window duration in milliseconds\",\n }),\n ),\n max: t.optional(\n t.number({\n description: \"Maximum number of requests per window\",\n }),\n ),\n skipFailedRequests: t.optional(\n t.boolean({\n description: \"Skip rate limiting for failed requests\",\n }),\n ),\n skipSuccessfulRequests: t.optional(\n t.boolean({\n description: \"Skip rate limiting for successful requests\",\n }),\n ),\n }),\n default: {},\n});\n\nexport type RateLimitAtomOptions = Static<typeof rateLimitOptions.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [rateLimitOptions.key]: RateLimitAtomOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nconst envSchema = t.object({\n RATE_LIMIT_WINDOW_MS: t.number({\n default: 15 * 60 * 1000, // 15 minutes\n description: \"Rate limit window in milliseconds\",\n }),\n RATE_LIMIT_MAX_REQUESTS: t.number({\n default: 100,\n description: \"Maximum requests per window\",\n }),\n});\n\nexport class ServerRateLimitProvider {\n protected readonly log = $logger();\n protected readonly serverRouterProvider = $inject(ServerRouterProvider);\n protected readonly env = $env(envSchema);\n\n protected readonly cache = $cache<RateLimitData>({\n name: \"server-rate-limit\",\n ttl: [this.env.RATE_LIMIT_WINDOW_MS, \"milliseconds\"],\n });\n\n protected readonly globalOptions = $use(rateLimitOptions);\n\n /**\n * Registered rate limit configurations with their path patterns\n */\n public readonly registeredConfigs: RateLimitPrimitiveOptions[] = [];\n\n /**\n * Register a rate limit configuration (called by primitives)\n */\n public registerRateLimit(config: RateLimitPrimitiveOptions): void {\n this.registeredConfigs.push(config);\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n // Apply path-specific rate limit configs to routes\n for (const config of this.registeredConfigs) {\n if (config.paths) {\n for (const pattern of config.paths) {\n const matchedRoutes = this.serverRouterProvider.getRoutes(pattern);\n for (const route of matchedRoutes) {\n route.rateLimit = this.buildRateLimitOptions(config);\n }\n }\n }\n }\n\n if (this.registeredConfigs.length > 0) {\n this.log.info(\n `Initialized with ${this.registeredConfigs.length} registered rate-limit configurations.`,\n );\n }\n },\n });\n\n public readonly onRequest = $hook({\n on: \"server:onRequest\",\n handler: async ({ route, request }) => {\n // Use route-specific rate limit if defined, otherwise use global options\n const rateLimitConfig = route.rateLimit ?? this.globalOptions;\n\n // Skip if no rate limiting configured\n if (!rateLimitConfig.max && !rateLimitConfig.windowMs) {\n return;\n }\n\n const result = await this.checkLimit(request, rateLimitConfig);\n this.setRateLimitHeaders(request, result);\n\n if (!result.allowed) {\n throw new HttpError({\n status: 429,\n message: \"Too Many Requests\",\n });\n }\n },\n });\n\n public readonly onActionRequest = $hook({\n on: \"action:onRequest\",\n handler: async ({ action, request }) => {\n // Check if this action has rate limiting enabled\n const rateLimit = action.options?.rateLimit;\n if (!rateLimit) {\n return; // No rate limiting for this action\n }\n\n const result = await this.checkLimit(request, rateLimit);\n\n if (!result.allowed) {\n // Actions are internal - don't set HTTP headers\n // Only throw error to prevent action execution\n throw new HttpError({\n status: 429,\n message: \"Too Many Requests\",\n });\n }\n\n // Action allowed - no headers to set since actions are internal\n },\n });\n\n /**\n * Build complete rate limit options by merging with global defaults\n */\n protected buildRateLimitOptions(\n config: RateLimitPrimitiveOptions,\n ): RateLimitOptions {\n return {\n max: config.max ?? this.globalOptions.max,\n windowMs: config.windowMs ?? this.globalOptions.windowMs,\n keyGenerator: config.keyGenerator,\n skipFailedRequests:\n config.skipFailedRequests ?? this.globalOptions.skipFailedRequests,\n skipSuccessfulRequests:\n config.skipSuccessfulRequests ??\n this.globalOptions.skipSuccessfulRequests,\n };\n }\n\n /**\n * Set rate limit headers on the response\n */\n protected setRateLimitHeaders(\n request: ServerRequest,\n result: RateLimitResult,\n ): void {\n request.reply.setHeader(\"X-RateLimit-Limit\", result.limit.toString());\n request.reply.setHeader(\n \"X-RateLimit-Remaining\",\n result.remaining.toString(),\n );\n request.reply.setHeader(\n \"X-RateLimit-Reset\",\n Math.ceil(result.resetTime / 1000).toString(),\n );\n\n if (!result.allowed && result.retryAfter) {\n request.reply.setHeader(\"Retry-After\", result.retryAfter.toString());\n }\n }\n\n public async checkLimit(\n req: ServerRequest,\n options: RateLimitOptions = {},\n ): Promise<RateLimitResult> {\n const windowMs = options.windowMs ?? this.env.RATE_LIMIT_WINDOW_MS;\n const max = options.max ?? this.env.RATE_LIMIT_MAX_REQUESTS;\n const key = this.generateKey(req);\n\n const now = Date.now();\n const windowStart = now - windowMs;\n\n // Get current rate limit data\n const currentData = (await this.cache.get(key)) || {\n count: 0,\n windowStart: now,\n hits: [],\n };\n\n // Clean old hits outside the current window\n const validHits = currentData.hits.filter(\n (hit: number) => hit >= windowStart,\n );\n\n // Check if limit exceeded\n const allowed = validHits.length < max;\n const remaining = Math.max(0, max - validHits.length);\n const resetTime = Math.max(...validHits, windowStart) + windowMs;\n\n // If allowed, record this request\n if (allowed) {\n validHits.push(now);\n await this.cache.set(key, {\n count: validHits.length,\n windowStart: Math.min(currentData.windowStart, windowStart),\n hits: validHits,\n });\n }\n\n const result: RateLimitResult = {\n allowed,\n limit: max,\n remaining: allowed ? remaining - 1 : remaining,\n resetTime,\n };\n\n if (!allowed) {\n result.retryAfter = Math.ceil((resetTime - now) / 1000);\n }\n\n return result;\n }\n\n protected generateKey(req: ServerRequest): string {\n // Default to IP-based rate limiting\n const ip = this.getClientIP(req);\n return `ip:${ip}`;\n }\n\n protected getClientIP(req: ServerRequest): string {\n // Check x-forwarded-for header first (for proxies/load balancers)\n const forwarded = req.headers?.[\"x-forwarded-for\"];\n if (forwarded) {\n // x-forwarded-for can contain multiple IPs, get the first one (original client)\n const firstIp = forwarded.split(\",\")[0].trim();\n if (firstIp) return firstIp;\n }\n\n return req.ip || \"unknown\";\n }\n}\n\ninterface RateLimitData {\n count: number;\n windowStart: number;\n hits: number[];\n}\n","import { $inject, createPrimitive, KIND, Primitive } from \"alepha\";\nimport type { ServerRequest } from \"alepha/server\";\nimport type { RateLimitOptions } from \"../index.ts\";\nimport {\n type RateLimitResult,\n ServerRateLimitProvider,\n} from \"../providers/ServerRateLimitProvider.ts\";\n\n/**\n * Declares rate limiting for server routes or custom usage.\n * This primitive provides methods to check rate limits and configure behavior\n * within the server request/response cycle.\n *\n * @example\n * ```ts\n * class ApiService {\n * // Apply rate limiting to specific paths\n * apiRateLimit = $rateLimit({\n * paths: [\"/api/*\"],\n * max: 100,\n * windowMs: 15 * 60 * 1000, // 15 minutes\n * });\n *\n * // Or use check() method for manual rate limiting\n * customAction = $action({\n * handler: async (req) => {\n * const result = await this.apiRateLimit.check(req);\n * if (!result.allowed) throw new Error(\"Rate limited\");\n * return \"ok\";\n * },\n * });\n * }\n * ```\n */\nexport const $rateLimit = (\n options: RateLimitPrimitiveOptions = {},\n): AbstractRateLimitPrimitive => {\n return createPrimitive(RateLimitPrimitive, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface RateLimitPrimitiveOptions extends RateLimitOptions {\n /** Name identifier for this rate limit (default: property key) */\n name?: string;\n /** Path patterns to match (supports wildcards like /api/*) */\n paths?: string[];\n}\n\nexport interface AbstractRateLimitPrimitive {\n readonly name: string;\n readonly options: RateLimitPrimitiveOptions;\n check(\n request: ServerRequest,\n options?: RateLimitOptions,\n ): Promise<RateLimitResult>;\n}\n\nexport class RateLimitPrimitive\n extends Primitive<RateLimitPrimitiveOptions>\n implements AbstractRateLimitPrimitive\n{\n protected readonly serverRateLimitProvider = $inject(ServerRateLimitProvider);\n\n public get name(): string {\n return this.options.name ?? `${this.config.propertyKey}`;\n }\n\n protected onInit() {\n // Register this rate limit configuration with the provider\n this.serverRateLimitProvider.registerRateLimit(this.options);\n }\n\n /**\n * Checks rate limit for the given request using this primitive's configuration.\n */\n public async check(\n request: ServerRequest,\n options?: RateLimitOptions,\n ): Promise<RateLimitResult> {\n const mergedOptions = { ...this.options, ...options };\n return this.serverRateLimitProvider.checkLimit(request, mergedOptions);\n }\n}\n\n$rateLimit[KIND] = RateLimitPrimitive;\n","import { $module } from \"alepha\";\nimport { AlephaServer } from \"alepha/server\";\nimport { $rateLimit } from \"./primitives/$rateLimit.ts\";\nimport { ServerRateLimitProvider } from \"./providers/ServerRateLimitProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./primitives/$rateLimit.ts\";\nexport * from \"./providers/ServerRateLimitProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha/server\" {\n interface ActionPrimitiveOptions<TConfig> {\n /**\n * Rate limiting configuration for this action.\n * When specified, the action will be rate limited according to these settings.\n */\n rateLimit?: RateLimitOptions;\n }\n\n interface ServerRoute {\n /**\n * Route-specific rate limit configuration.\n * If set, overrides the global rate limit options for this route.\n */\n rateLimit?: RateLimitOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface RateLimitOptions {\n /** Maximum number of requests per window (default: 100) */\n max?: number;\n /** Window duration in milliseconds (default: 15 minutes) */\n windowMs?: number;\n /** Custom key generator function */\n keyGenerator?: (req: any) => string;\n /** Skip rate limiting for failed requests */\n skipFailedRequests?: boolean;\n /** Skip rate limiting for successful requests */\n skipSuccessfulRequests?: boolean;\n}\n\n/**\n * Provides rate limiting capabilities for server routes and actions with configurable limits and windows.\n *\n * The server-rate-limit module enables per-route and per-action rate limiting using either:\n * - The `$rateLimit` primitive with `paths` option for path-based rate limiting\n * - The `rateLimit` option in action primitives for action-specific limiting\n *\n * It offers sliding window rate limiting, custom key generation, and seamless integration with server routes.\n *\n * @example\n * ```ts\n * import { $rateLimit, AlephaServerRateLimit } from \"alepha/server-rate-limit\";\n *\n * class ApiService {\n * // Path-specific rate limiting\n * apiRateLimit = $rateLimit({\n * paths: [\"/api/*\"],\n * max: 100,\n * windowMs: 15 * 60 * 1000, // 15 minutes\n * });\n * }\n * ```\n *\n * @see {@link $rateLimit}\n * @module alepha.server.rate-limit\n */\nexport const AlephaServerRateLimit = $module({\n name: \"alepha.server.rate-limit\",\n primitives: [$rateLimit],\n services: [AlephaServer, ServerRateLimitProvider],\n});\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as alepha5 from "alepha";
|
|
2
|
-
import { Alepha,
|
|
2
|
+
import { Alepha, KIND, Primitive } from "alepha";
|
|
3
3
|
import { JwtProvider, Permission, SecurityProvider, UserAccount, UserAccountToken } from "alepha/security";
|
|
4
4
|
import { FetchOptions, ServerRequest, ServerRouterProvider } from "alepha/server";
|
|
5
5
|
import * as alepha_logger0 from "alepha/logger";
|
|
@@ -9,7 +9,7 @@ interface BasicAuthOptions {
|
|
|
9
9
|
username: string;
|
|
10
10
|
password: string;
|
|
11
11
|
}
|
|
12
|
-
interface
|
|
12
|
+
interface BasicAuthPrimitiveConfig extends BasicAuthOptions {
|
|
13
13
|
/** Name identifier for this basic auth (default: property key) */
|
|
14
14
|
name?: string;
|
|
15
15
|
/** Path patterns to match (supports wildcards like /devtools/*) */
|
|
@@ -21,22 +21,22 @@ declare class ServerBasicAuthProvider {
|
|
|
21
21
|
protected readonly routerProvider: ServerRouterProvider;
|
|
22
22
|
protected readonly realm = "Secure Area";
|
|
23
23
|
/**
|
|
24
|
-
* Registered basic auth
|
|
24
|
+
* Registered basic auth primitives with their configurations
|
|
25
25
|
*/
|
|
26
|
-
readonly registeredAuths:
|
|
26
|
+
readonly registeredAuths: BasicAuthPrimitiveConfig[];
|
|
27
27
|
/**
|
|
28
|
-
* Register a basic auth configuration (called by
|
|
28
|
+
* Register a basic auth configuration (called by primitives)
|
|
29
29
|
*/
|
|
30
|
-
registerAuth(config:
|
|
31
|
-
readonly onStart: alepha5.
|
|
30
|
+
registerAuth(config: BasicAuthPrimitiveConfig): void;
|
|
31
|
+
readonly onStart: alepha5.HookPrimitive<"start">;
|
|
32
32
|
/**
|
|
33
33
|
* Hook into server:onRequest to check basic auth
|
|
34
34
|
*/
|
|
35
|
-
readonly onRequest: alepha5.
|
|
35
|
+
readonly onRequest: alepha5.HookPrimitive<"server:onRequest">;
|
|
36
36
|
/**
|
|
37
37
|
* Hook into action:onRequest to check basic auth for actions
|
|
38
38
|
*/
|
|
39
|
-
readonly onActionRequest: alepha5.
|
|
39
|
+
readonly onActionRequest: alepha5.HookPrimitive<"action:onRequest">;
|
|
40
40
|
/**
|
|
41
41
|
* Check basic authentication
|
|
42
42
|
*/
|
|
@@ -66,9 +66,9 @@ declare class ServerSecurityProvider {
|
|
|
66
66
|
protected readonly securityProvider: SecurityProvider;
|
|
67
67
|
protected readonly jwtProvider: JwtProvider;
|
|
68
68
|
protected readonly alepha: Alepha;
|
|
69
|
-
protected readonly onConfigure: alepha5.
|
|
70
|
-
protected readonly onActionRequest: alepha5.
|
|
71
|
-
protected readonly onRequest: alepha5.
|
|
69
|
+
protected readonly onConfigure: alepha5.HookPrimitive<"configure">;
|
|
70
|
+
protected readonly onActionRequest: alepha5.HookPrimitive<"action:onRequest">;
|
|
71
|
+
protected readonly onRequest: alepha5.HookPrimitive<"server:onRequest">;
|
|
72
72
|
protected check(user: UserAccountToken, secure: ServerRouteSecure): void;
|
|
73
73
|
/**
|
|
74
74
|
* Get the user account token for a local action call.
|
|
@@ -85,33 +85,33 @@ declare class ServerSecurityProvider {
|
|
|
85
85
|
user?: UserAccountToken | "system" | "context";
|
|
86
86
|
}, permission?: Permission): UserAccountToken;
|
|
87
87
|
protected createTestUser(): UserAccountToken;
|
|
88
|
-
protected readonly onClientRequest: alepha5.
|
|
88
|
+
protected readonly onClientRequest: alepha5.HookPrimitive<"client:onRequest">;
|
|
89
89
|
}
|
|
90
90
|
type ServerRouteSecure = {
|
|
91
91
|
realm?: string;
|
|
92
92
|
basic?: BasicAuthOptions;
|
|
93
93
|
};
|
|
94
94
|
//#endregion
|
|
95
|
-
//#region src/server-security/
|
|
95
|
+
//#region src/server-security/primitives/$basicAuth.d.ts
|
|
96
96
|
/**
|
|
97
97
|
* Declares HTTP Basic Authentication for server routes.
|
|
98
|
-
* This
|
|
98
|
+
* This primitive provides methods to protect routes with username/password authentication.
|
|
99
99
|
*/
|
|
100
100
|
declare const $basicAuth: {
|
|
101
|
-
(options:
|
|
102
|
-
[KIND]: typeof
|
|
101
|
+
(options: BasicAuthPrimitiveConfig): AbstractBasicAuthPrimitive;
|
|
102
|
+
[KIND]: typeof BasicAuthPrimitive;
|
|
103
103
|
};
|
|
104
|
-
interface
|
|
104
|
+
interface AbstractBasicAuthPrimitive {
|
|
105
105
|
readonly name: string;
|
|
106
|
-
readonly options:
|
|
106
|
+
readonly options: BasicAuthPrimitiveConfig;
|
|
107
107
|
check(request: ServerRequest, options?: BasicAuthOptions): void;
|
|
108
108
|
}
|
|
109
|
-
declare class
|
|
109
|
+
declare class BasicAuthPrimitive extends Primitive<BasicAuthPrimitiveConfig> implements AbstractBasicAuthPrimitive {
|
|
110
110
|
protected readonly serverBasicAuthProvider: ServerBasicAuthProvider;
|
|
111
111
|
get name(): string;
|
|
112
112
|
protected onInit(): void;
|
|
113
113
|
/**
|
|
114
|
-
* Checks basic auth for the given request using this
|
|
114
|
+
* Checks basic auth for the given request using this primitive's configuration.
|
|
115
115
|
*/
|
|
116
116
|
check(request: ServerRequest, options?: BasicAuthOptions): void;
|
|
117
117
|
}
|
|
@@ -169,5 +169,5 @@ declare module "alepha/server" {
|
|
|
169
169
|
*/
|
|
170
170
|
declare const AlephaServerSecurity: alepha5.Service<alepha5.Module>;
|
|
171
171
|
//#endregion
|
|
172
|
-
export { $basicAuth,
|
|
172
|
+
export { $basicAuth, AbstractBasicAuthPrimitive, AlephaServerSecurity, BasicAuthOptions, BasicAuthPrimitive, BasicAuthPrimitiveConfig, ServerBasicAuthProvider, ServerRouteSecure, ServerSecurityProvider, isBasicAuth };
|
|
173
173
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $hook, $inject, $module, Alepha,
|
|
1
|
+
import { $hook, $inject, $module, Alepha, KIND, Primitive, createPrimitive } from "alepha";
|
|
2
2
|
import { $permission, $realm, $role, AlephaSecurity, JwtProvider, SecurityProvider, userAccountInfoSchema } from "alepha/security";
|
|
3
3
|
import { $action, AlephaServer, ForbiddenError, HttpError, ServerRouterProvider, UnauthorizedError } from "alepha/server";
|
|
4
4
|
import { randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -11,11 +11,11 @@ var ServerBasicAuthProvider = class {
|
|
|
11
11
|
routerProvider = $inject(ServerRouterProvider);
|
|
12
12
|
realm = "Secure Area";
|
|
13
13
|
/**
|
|
14
|
-
* Registered basic auth
|
|
14
|
+
* Registered basic auth primitives with their configurations
|
|
15
15
|
*/
|
|
16
16
|
registeredAuths = [];
|
|
17
17
|
/**
|
|
18
|
-
* Register a basic auth configuration (called by
|
|
18
|
+
* Register a basic auth configuration (called by primitives)
|
|
19
19
|
*/
|
|
20
20
|
registerAuth(config) {
|
|
21
21
|
this.registeredAuths.push(config);
|
|
@@ -113,15 +113,15 @@ const isBasicAuth = (value) => {
|
|
|
113
113
|
};
|
|
114
114
|
|
|
115
115
|
//#endregion
|
|
116
|
-
//#region src/server-security/
|
|
116
|
+
//#region src/server-security/primitives/$basicAuth.ts
|
|
117
117
|
/**
|
|
118
118
|
* Declares HTTP Basic Authentication for server routes.
|
|
119
|
-
* This
|
|
119
|
+
* This primitive provides methods to protect routes with username/password authentication.
|
|
120
120
|
*/
|
|
121
121
|
const $basicAuth = (options) => {
|
|
122
|
-
return
|
|
122
|
+
return createPrimitive(BasicAuthPrimitive, options);
|
|
123
123
|
};
|
|
124
|
-
var
|
|
124
|
+
var BasicAuthPrimitive = class extends Primitive {
|
|
125
125
|
serverBasicAuthProvider = $inject(ServerBasicAuthProvider);
|
|
126
126
|
get name() {
|
|
127
127
|
return this.options.name ?? `${this.config.propertyKey}`;
|
|
@@ -130,7 +130,7 @@ var BasicAuthDescriptor = class extends Descriptor {
|
|
|
130
130
|
this.serverBasicAuthProvider.registerAuth(this.options);
|
|
131
131
|
}
|
|
132
132
|
/**
|
|
133
|
-
* Checks basic auth for the given request using this
|
|
133
|
+
* Checks basic auth for the given request using this primitive's configuration.
|
|
134
134
|
*/
|
|
135
135
|
check(request, options) {
|
|
136
136
|
const mergedOptions = {
|
|
@@ -140,7 +140,7 @@ var BasicAuthDescriptor = class extends Descriptor {
|
|
|
140
140
|
this.serverBasicAuthProvider.checkAuth(request, mergedOptions);
|
|
141
141
|
}
|
|
142
142
|
};
|
|
143
|
-
$basicAuth[KIND] =
|
|
143
|
+
$basicAuth[KIND] = BasicAuthPrimitive;
|
|
144
144
|
|
|
145
145
|
//#endregion
|
|
146
146
|
//#region src/server-security/providers/ServerSecurityProvider.ts
|
|
@@ -152,7 +152,7 @@ var ServerSecurityProvider = class {
|
|
|
152
152
|
onConfigure = $hook({
|
|
153
153
|
on: "configure",
|
|
154
154
|
handler: async () => {
|
|
155
|
-
for (const action of this.alepha.
|
|
155
|
+
for (const action of this.alepha.primitives($action)) {
|
|
156
156
|
if (action.options.disabled || action.options.secure === false || this.securityProvider.getRealms().length === 0) continue;
|
|
157
157
|
if (typeof action.options.secure !== "object") this.securityProvider.createPermission({
|
|
158
158
|
name: action.name,
|
|
@@ -176,7 +176,7 @@ var ServerSecurityProvider = class {
|
|
|
176
176
|
request.user = this.createUserFromLocalFunctionContext(options, permission);
|
|
177
177
|
const route = action.route;
|
|
178
178
|
if (typeof route.secure === "object") this.check(request.user, route.secure);
|
|
179
|
-
this.alepha.
|
|
179
|
+
this.alepha.store.set("alepha.server.request.user", this.alepha.codec.decode(userAccountInfoSchema, request.user));
|
|
180
180
|
} catch (error) {
|
|
181
181
|
if (action.options.secure || permission) throw error;
|
|
182
182
|
this.log.trace("Skipping security check for action");
|
|
@@ -200,7 +200,7 @@ var ServerSecurityProvider = class {
|
|
|
200
200
|
try {
|
|
201
201
|
request.user = await this.securityProvider.createUserFromToken(request.headers.authorization, { permission });
|
|
202
202
|
if (typeof route.secure === "object") this.check(request.user, route.secure);
|
|
203
|
-
this.alepha.
|
|
203
|
+
this.alepha.store.set("alepha.server.request.user", this.alepha.codec.decode(userAccountInfoSchema, request.user));
|
|
204
204
|
this.log.trace("User set from request token", {
|
|
205
205
|
user: request.user,
|
|
206
206
|
permission
|
|
@@ -232,7 +232,7 @@ var ServerSecurityProvider = class {
|
|
|
232
232
|
const type = typeof options.user === "string" ? options.user : void 0;
|
|
233
233
|
let user;
|
|
234
234
|
const fromContext = this.alepha.context.get("request")?.user;
|
|
235
|
-
const fromSystem = this.alepha.
|
|
235
|
+
const fromSystem = this.alepha.store.get("alepha.server.security.system.user");
|
|
236
236
|
if (type === "system") user = fromSystem;
|
|
237
237
|
else if (type === "context") user = fromContext;
|
|
238
238
|
else user = fromOptions ?? fromContext ?? fromSystem;
|
|
@@ -292,7 +292,7 @@ var ServerSecurityProvider = class {
|
|
|
292
292
|
*/
|
|
293
293
|
const AlephaServerSecurity = $module({
|
|
294
294
|
name: "alepha.server.security",
|
|
295
|
-
|
|
295
|
+
primitives: [
|
|
296
296
|
$realm,
|
|
297
297
|
$role,
|
|
298
298
|
$permission,
|
|
@@ -307,5 +307,5 @@ const AlephaServerSecurity = $module({
|
|
|
307
307
|
});
|
|
308
308
|
|
|
309
309
|
//#endregion
|
|
310
|
-
export { $basicAuth, AlephaServerSecurity,
|
|
310
|
+
export { $basicAuth, AlephaServerSecurity, BasicAuthPrimitive, ServerBasicAuthProvider, ServerSecurityProvider, isBasicAuth };
|
|
311
311
|
//# sourceMappingURL=index.js.map
|