@noony-serverless/core 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/core/core.d.ts +16 -48
- package/build/core/core.js +2 -61
- package/build/core/handler.d.ts +37 -16
- package/build/core/handler.js +131 -42
- package/build/core/index.d.ts +0 -1
- package/build/core/index.js +0 -1
- package/build/middlewares/ConsolidatedValidationMiddleware.d.ts +126 -0
- package/build/middlewares/ConsolidatedValidationMiddleware.js +330 -0
- package/build/middlewares/ProcessingMiddleware.d.ts +138 -0
- package/build/middlewares/ProcessingMiddleware.js +425 -0
- package/build/middlewares/SecurityMiddleware.d.ts +157 -0
- package/build/middlewares/SecurityMiddleware.js +307 -0
- package/build/middlewares/authenticationMiddleware.d.ts +379 -0
- package/build/middlewares/authenticationMiddleware.js +216 -0
- package/build/middlewares/bodyParserMiddleware.d.ts +99 -0
- package/build/middlewares/bodyParserMiddleware.js +99 -0
- package/build/middlewares/bodyValidationMiddleware.d.ts +69 -3
- package/build/middlewares/bodyValidationMiddleware.js +68 -2
- package/build/middlewares/dependencyInjectionMiddleware.d.ts +238 -0
- package/build/middlewares/dependencyInjectionMiddleware.js +238 -0
- package/build/middlewares/errorHandlerMiddleware.d.ts +94 -0
- package/build/middlewares/errorHandlerMiddleware.js +105 -0
- package/build/middlewares/guards/RouteGuards.d.ts +476 -21
- package/build/middlewares/guards/RouteGuards.js +418 -21
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.d.ts +271 -0
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.js +301 -0
- package/build/middlewares/guards/cache/CacheAdapter.d.ts +369 -28
- package/build/middlewares/guards/cache/CacheAdapter.js +124 -5
- package/build/middlewares/guards/cache/MemoryCacheAdapter.d.ts +113 -4
- package/build/middlewares/guards/cache/MemoryCacheAdapter.js +113 -4
- package/build/middlewares/guards/config/GuardConfiguration.d.ts +568 -18
- package/build/middlewares/guards/config/GuardConfiguration.js +266 -10
- package/build/middlewares/guards/guards/FastAuthGuard.d.ts +5 -5
- package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +5 -13
- package/build/middlewares/guards/guards/PermissionGuardFactory.js +4 -4
- package/build/middlewares/guards/index.d.ts +43 -1
- package/build/middlewares/guards/index.js +46 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +1 -1
- package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/services/FastUserContextService.d.ts +20 -33
- package/build/middlewares/guards/services/FastUserContextService.js +19 -5
- package/build/middlewares/headerVariablesMiddleware.d.ts +118 -0
- package/build/middlewares/headerVariablesMiddleware.js +118 -0
- package/build/middlewares/httpAttributesMiddleware.d.ts +235 -0
- package/build/middlewares/httpAttributesMiddleware.js +236 -1
- package/build/middlewares/index.d.ts +3 -1
- package/build/middlewares/index.js +6 -1
- package/build/middlewares/queryParametersMiddleware.d.ts +105 -0
- package/build/middlewares/queryParametersMiddleware.js +105 -0
- package/build/middlewares/rateLimitingMiddleware.d.ts +601 -9
- package/build/middlewares/rateLimitingMiddleware.js +623 -11
- package/build/middlewares/responseWrapperMiddleware.d.ts +170 -1
- package/build/middlewares/responseWrapperMiddleware.js +170 -1
- package/build/middlewares/securityAuditMiddleware.js +5 -5
- package/package.json +11 -9
- package/build/core/containerPool.d.ts +0 -44
- package/build/core/containerPool.js +0 -103
- package/build/middlewares/validationMiddleware.d.ts +0 -9
- package/build/middlewares/validationMiddleware.js +0 -40
|
@@ -23,9 +23,13 @@
|
|
|
23
23
|
* @version 1.0.0
|
|
24
24
|
*/
|
|
25
25
|
import { CacheAdapter } from '../cache/CacheAdapter';
|
|
26
|
-
import { GuardConfiguration
|
|
26
|
+
import { GuardConfiguration } from '../config/GuardConfiguration';
|
|
27
27
|
import { PermissionRegistry } from '../registry/PermissionRegistry';
|
|
28
|
-
import { PermissionResolverType, PermissionCheckResult } from '../resolvers/PermissionResolver';
|
|
28
|
+
import { PermissionResolverType, PermissionCheckResult, PermissionExpression } from '../resolvers/PermissionResolver';
|
|
29
|
+
/**
|
|
30
|
+
* Type alias for permission requirements that can be strings, string arrays, or complex expressions
|
|
31
|
+
*/
|
|
32
|
+
type PermissionRequirement = string | string[] | PermissionExpression | Record<string, unknown>;
|
|
29
33
|
/**
|
|
30
34
|
* User context with cached permissions and metadata
|
|
31
35
|
*/
|
|
@@ -33,7 +37,7 @@ export interface UserContext {
|
|
|
33
37
|
userId: string;
|
|
34
38
|
permissions: Set<string>;
|
|
35
39
|
roles: string[];
|
|
36
|
-
metadata: Record<string,
|
|
40
|
+
metadata: Record<string, unknown>;
|
|
37
41
|
expandedPermissions?: Set<string>;
|
|
38
42
|
lastUpdated: string;
|
|
39
43
|
expiresAt?: string;
|
|
@@ -48,7 +52,7 @@ export interface UserPermissionSource {
|
|
|
48
52
|
getUserPermissions(userId: string): Promise<{
|
|
49
53
|
permissions: string[];
|
|
50
54
|
roles: string[];
|
|
51
|
-
metadata?: Record<string,
|
|
55
|
+
metadata?: Record<string, unknown>;
|
|
52
56
|
} | null>;
|
|
53
57
|
/**
|
|
54
58
|
* Get role-based permissions for expansion
|
|
@@ -85,6 +89,12 @@ export declare class FastUserContextService {
|
|
|
85
89
|
private permissionChecks;
|
|
86
90
|
private totalResolutionTimeUs;
|
|
87
91
|
constructor(cache: CacheAdapter, config: GuardConfiguration, permissionSource: UserPermissionSource, permissionRegistry: PermissionRegistry);
|
|
92
|
+
/**
|
|
93
|
+
* Check if caching is effectively disabled
|
|
94
|
+
*
|
|
95
|
+
* @returns true if caching is disabled (either by environment variable or NoopCacheAdapter)
|
|
96
|
+
*/
|
|
97
|
+
private isCachingDisabled;
|
|
88
98
|
/**
|
|
89
99
|
* Get or load user context with permissions
|
|
90
100
|
*
|
|
@@ -107,7 +117,7 @@ export declare class FastUserContextService {
|
|
|
107
117
|
* @param options - Check options
|
|
108
118
|
* @returns Detailed permission check result
|
|
109
119
|
*/
|
|
110
|
-
checkPermission(userId: string, requirement:
|
|
120
|
+
checkPermission(userId: string, requirement: PermissionRequirement, options?: PermissionCheckOptions): Promise<PermissionCheckResult>;
|
|
111
121
|
/**
|
|
112
122
|
* Batch check multiple permissions for a user
|
|
113
123
|
*
|
|
@@ -120,7 +130,7 @@ export declare class FastUserContextService {
|
|
|
120
130
|
* @returns Array of permission check results
|
|
121
131
|
*/
|
|
122
132
|
checkPermissions(userId: string, requirements: Array<{
|
|
123
|
-
requirement:
|
|
133
|
+
requirement: PermissionRequirement;
|
|
124
134
|
resolverType?: PermissionResolverType;
|
|
125
135
|
}>, options?: PermissionCheckOptions): Promise<PermissionCheckResult[]>;
|
|
126
136
|
/**
|
|
@@ -155,33 +165,9 @@ export declare class FastUserContextService {
|
|
|
155
165
|
averageResolutionTimeUs: number;
|
|
156
166
|
totalResolutionTimeUs: number;
|
|
157
167
|
resolverStats: {
|
|
158
|
-
plain:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
totalResolutionTimeUs: number;
|
|
162
|
-
};
|
|
163
|
-
wildcard: {
|
|
164
|
-
strategy: PermissionResolutionStrategy;
|
|
165
|
-
checkCount: number;
|
|
166
|
-
averageResolutionTimeUs: number;
|
|
167
|
-
totalResolutionTimeUs: number;
|
|
168
|
-
cacheHitRate: number;
|
|
169
|
-
cacheHits: number;
|
|
170
|
-
cacheMisses: number;
|
|
171
|
-
};
|
|
172
|
-
expression: {
|
|
173
|
-
checkCount: number;
|
|
174
|
-
averageResolutionTimeUs: number;
|
|
175
|
-
totalResolutionTimeUs: number;
|
|
176
|
-
cacheHitRate: number;
|
|
177
|
-
cacheHits: number;
|
|
178
|
-
cacheMisses: number;
|
|
179
|
-
complexityDistribution: {
|
|
180
|
-
simple: number;
|
|
181
|
-
moderate: number;
|
|
182
|
-
complex: number;
|
|
183
|
-
};
|
|
184
|
-
};
|
|
168
|
+
plain: Record<string, unknown>;
|
|
169
|
+
wildcard: Record<string, unknown>;
|
|
170
|
+
expression: Record<string, unknown>;
|
|
185
171
|
};
|
|
186
172
|
};
|
|
187
173
|
/**
|
|
@@ -213,4 +199,5 @@ export declare class FastUserContextService {
|
|
|
213
199
|
*/
|
|
214
200
|
private recordAuditTrail;
|
|
215
201
|
}
|
|
202
|
+
export {};
|
|
216
203
|
//# sourceMappingURL=FastUserContextService.d.ts.map
|
|
@@ -41,6 +41,7 @@ const PlainPermissionResolver_1 = require("../resolvers/PlainPermissionResolver"
|
|
|
41
41
|
const WildcardPermissionResolver_1 = require("../resolvers/WildcardPermissionResolver");
|
|
42
42
|
const ExpressionPermissionResolver_1 = require("../resolvers/ExpressionPermissionResolver");
|
|
43
43
|
const PermissionResolver_1 = require("../resolvers/PermissionResolver");
|
|
44
|
+
const NoopCacheAdapter_1 = require("../cache/NoopCacheAdapter");
|
|
44
45
|
/**
|
|
45
46
|
* Fast User Context Service Implementation
|
|
46
47
|
*/
|
|
@@ -66,9 +67,19 @@ let FastUserContextService = class FastUserContextService {
|
|
|
66
67
|
this._permissionRegistry = permissionRegistry;
|
|
67
68
|
// Initialize permission resolvers
|
|
68
69
|
this.plainResolver = new PlainPermissionResolver_1.PlainPermissionResolver();
|
|
69
|
-
this.wildcardResolver = new WildcardPermissionResolver_1.WildcardPermissionResolver(config.security.permissionResolutionStrategy
|
|
70
|
+
this.wildcardResolver = new WildcardPermissionResolver_1.WildcardPermissionResolver(config.security.permissionResolutionStrategy ??
|
|
71
|
+
GuardConfiguration_1.PermissionResolutionStrategy.PRE_EXPANSION, this._permissionRegistry, cache);
|
|
70
72
|
this.expressionResolver = new ExpressionPermissionResolver_1.ExpressionPermissionResolver(cache);
|
|
71
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if caching is effectively disabled
|
|
76
|
+
*
|
|
77
|
+
* @returns true if caching is disabled (either by environment variable or NoopCacheAdapter)
|
|
78
|
+
*/
|
|
79
|
+
isCachingDisabled() {
|
|
80
|
+
return (!GuardConfiguration_1.GuardConfiguration.isCachingEnabled() ||
|
|
81
|
+
this.cache instanceof NoopCacheAdapter_1.NoopCacheAdapter);
|
|
82
|
+
}
|
|
72
83
|
/**
|
|
73
84
|
* Get or load user context with permissions
|
|
74
85
|
*
|
|
@@ -83,8 +94,9 @@ let FastUserContextService = class FastUserContextService {
|
|
|
83
94
|
const startTime = process.hrtime.bigint();
|
|
84
95
|
this.contextLoads++;
|
|
85
96
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
97
|
+
const cachingDisabled = this.isCachingDisabled();
|
|
98
|
+
// Check cache first unless forced refresh or caching is disabled
|
|
99
|
+
if (!forceRefresh && !cachingDisabled) {
|
|
88
100
|
const cachedContext = await this.loadFromCache(userId);
|
|
89
101
|
if (cachedContext) {
|
|
90
102
|
this.cacheHits++;
|
|
@@ -99,8 +111,10 @@ let FastUserContextService = class FastUserContextService {
|
|
|
99
111
|
}
|
|
100
112
|
// Build user context
|
|
101
113
|
const context = await this.buildUserContext(userId, userData);
|
|
102
|
-
// Cache the context
|
|
103
|
-
|
|
114
|
+
// Cache the context only if caching is enabled
|
|
115
|
+
if (!cachingDisabled) {
|
|
116
|
+
await this.saveToCache(context);
|
|
117
|
+
}
|
|
104
118
|
return context;
|
|
105
119
|
}
|
|
106
120
|
finally {
|
|
@@ -1,8 +1,126 @@
|
|
|
1
1
|
import { BaseMiddleware, Context } from '../core';
|
|
2
|
+
/**
|
|
3
|
+
* Middleware class that validates the presence of required HTTP headers.
|
|
4
|
+
* Throws a ValidationError if any required header is missing or empty.
|
|
5
|
+
*
|
|
6
|
+
* @implements {BaseMiddleware}
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* API key authentication via headers:
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { Handler, HeaderVariablesMiddleware } from '@noony-serverless/core';
|
|
12
|
+
*
|
|
13
|
+
* const requiredHeaders = ['authorization', 'x-api-key', 'content-type'];
|
|
14
|
+
*
|
|
15
|
+
* const secureApiHandler = new Handler()
|
|
16
|
+
* .use(new HeaderVariablesMiddleware(requiredHeaders))
|
|
17
|
+
* .handle(async (context) => {
|
|
18
|
+
* const authHeader = context.req.headers.authorization;
|
|
19
|
+
* const apiKey = context.req.headers['x-api-key'];
|
|
20
|
+
*
|
|
21
|
+
* // Headers are guaranteed to exist after middleware validation
|
|
22
|
+
* console.log('Auth header:', authHeader);
|
|
23
|
+
* console.log('API key:', apiKey);
|
|
24
|
+
*
|
|
25
|
+
* return { success: true, authenticated: true };
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* Content negotiation requirements:
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const contentHeaders = ['accept', 'content-type', 'accept-language'];
|
|
33
|
+
*
|
|
34
|
+
* const internationalApiHandler = new Handler()
|
|
35
|
+
* .use(new HeaderVariablesMiddleware(contentHeaders))
|
|
36
|
+
* .handle(async (context) => {
|
|
37
|
+
* const acceptLang = context.req.headers['accept-language'];
|
|
38
|
+
* const contentType = context.req.headers['content-type'];
|
|
39
|
+
*
|
|
40
|
+
* const language = Array.isArray(acceptLang) ? acceptLang[0] : acceptLang;
|
|
41
|
+
* const responseData = getLocalizedContent(language);
|
|
42
|
+
*
|
|
43
|
+
* return { success: true, data: responseData, language };
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* Custom business headers validation:
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const businessHeaders = ['x-tenant-id', 'x-request-id', 'x-client-version'];
|
|
51
|
+
*
|
|
52
|
+
* const multiTenantHandler = new Handler()
|
|
53
|
+
* .use(new HeaderVariablesMiddleware(businessHeaders))
|
|
54
|
+
* .handle(async (context) => {
|
|
55
|
+
* const tenantId = context.req.headers['x-tenant-id'];
|
|
56
|
+
* const requestId = context.req.headers['x-request-id'];
|
|
57
|
+
* const clientVersion = context.req.headers['x-client-version'];
|
|
58
|
+
*
|
|
59
|
+
* console.log(`Processing request ${requestId} for tenant ${tenantId} with client ${clientVersion}`);
|
|
60
|
+
*
|
|
61
|
+
* const tenantData = await getTenantData(tenantId as string);
|
|
62
|
+
* return { success: true, tenant: tenantData };
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
2
66
|
export declare class HeaderVariablesMiddleware implements BaseMiddleware {
|
|
3
67
|
private requiredHeaders;
|
|
4
68
|
constructor(requiredHeaders: string[]);
|
|
5
69
|
before(context: Context): Promise<void>;
|
|
6
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Factory function that creates a header validation middleware.
|
|
73
|
+
* Validates that all required headers are present in the request.
|
|
74
|
+
*
|
|
75
|
+
* @param requiredHeaders - Array of header names that must be present
|
|
76
|
+
* @returns BaseMiddleware object with header validation logic
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* Simple header validation:
|
|
80
|
+
* ```typescript
|
|
81
|
+
* import { Handler, headerVariablesMiddleware } from '@noony-serverless/core';
|
|
82
|
+
*
|
|
83
|
+
* const authHandler = new Handler()
|
|
84
|
+
* .use(headerVariablesMiddleware(['authorization']))
|
|
85
|
+
* .handle(async (context) => {
|
|
86
|
+
* const token = context.req.headers.authorization;
|
|
87
|
+
* // Proceed with authentication logic
|
|
88
|
+
* return { success: true, message: 'Authenticated' };
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* Multiple required headers:
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const webhookHandler = new Handler()
|
|
96
|
+
* .use(headerVariablesMiddleware([
|
|
97
|
+
* 'x-webhook-signature',
|
|
98
|
+
* 'x-webhook-timestamp',
|
|
99
|
+
* 'content-type'
|
|
100
|
+
* ]))
|
|
101
|
+
* .handle(async (context) => {
|
|
102
|
+
* const signature = context.req.headers['x-webhook-signature'];
|
|
103
|
+
* const timestamp = context.req.headers['x-webhook-timestamp'];
|
|
104
|
+
*
|
|
105
|
+
* // Validate webhook authenticity
|
|
106
|
+
* const isValid = validateWebhookSignature(signature, timestamp, context.req.body);
|
|
107
|
+
* return { success: isValid };
|
|
108
|
+
* });
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* API versioning through headers:
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const versionedApiHandler = new Handler()
|
|
115
|
+
* .use(headerVariablesMiddleware(['x-api-version', 'accept']))
|
|
116
|
+
* .handle(async (context) => {
|
|
117
|
+
* const apiVersion = context.req.headers['x-api-version'];
|
|
118
|
+
* const accept = context.req.headers.accept;
|
|
119
|
+
*
|
|
120
|
+
* const handler = getHandlerForVersion(apiVersion as string);
|
|
121
|
+
* return handler.process(context.req.body);
|
|
122
|
+
* });
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
7
125
|
export declare const headerVariablesMiddleware: (requiredHeaders: string[]) => BaseMiddleware;
|
|
8
126
|
//# sourceMappingURL=headerVariablesMiddleware.d.ts.map
|
|
@@ -11,6 +11,70 @@ const validateHeaders = (requiredHeaders, headers) => {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Middleware class that validates the presence of required HTTP headers.
|
|
16
|
+
* Throws a ValidationError if any required header is missing or empty.
|
|
17
|
+
*
|
|
18
|
+
* @implements {BaseMiddleware}
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* API key authentication via headers:
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { Handler, HeaderVariablesMiddleware } from '@noony-serverless/core';
|
|
24
|
+
*
|
|
25
|
+
* const requiredHeaders = ['authorization', 'x-api-key', 'content-type'];
|
|
26
|
+
*
|
|
27
|
+
* const secureApiHandler = new Handler()
|
|
28
|
+
* .use(new HeaderVariablesMiddleware(requiredHeaders))
|
|
29
|
+
* .handle(async (context) => {
|
|
30
|
+
* const authHeader = context.req.headers.authorization;
|
|
31
|
+
* const apiKey = context.req.headers['x-api-key'];
|
|
32
|
+
*
|
|
33
|
+
* // Headers are guaranteed to exist after middleware validation
|
|
34
|
+
* console.log('Auth header:', authHeader);
|
|
35
|
+
* console.log('API key:', apiKey);
|
|
36
|
+
*
|
|
37
|
+
* return { success: true, authenticated: true };
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* Content negotiation requirements:
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const contentHeaders = ['accept', 'content-type', 'accept-language'];
|
|
45
|
+
*
|
|
46
|
+
* const internationalApiHandler = new Handler()
|
|
47
|
+
* .use(new HeaderVariablesMiddleware(contentHeaders))
|
|
48
|
+
* .handle(async (context) => {
|
|
49
|
+
* const acceptLang = context.req.headers['accept-language'];
|
|
50
|
+
* const contentType = context.req.headers['content-type'];
|
|
51
|
+
*
|
|
52
|
+
* const language = Array.isArray(acceptLang) ? acceptLang[0] : acceptLang;
|
|
53
|
+
* const responseData = getLocalizedContent(language);
|
|
54
|
+
*
|
|
55
|
+
* return { success: true, data: responseData, language };
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* Custom business headers validation:
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const businessHeaders = ['x-tenant-id', 'x-request-id', 'x-client-version'];
|
|
63
|
+
*
|
|
64
|
+
* const multiTenantHandler = new Handler()
|
|
65
|
+
* .use(new HeaderVariablesMiddleware(businessHeaders))
|
|
66
|
+
* .handle(async (context) => {
|
|
67
|
+
* const tenantId = context.req.headers['x-tenant-id'];
|
|
68
|
+
* const requestId = context.req.headers['x-request-id'];
|
|
69
|
+
* const clientVersion = context.req.headers['x-client-version'];
|
|
70
|
+
*
|
|
71
|
+
* console.log(`Processing request ${requestId} for tenant ${tenantId} with client ${clientVersion}`);
|
|
72
|
+
*
|
|
73
|
+
* const tenantData = await getTenantData(tenantId as string);
|
|
74
|
+
* return { success: true, tenant: tenantData };
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
14
78
|
class HeaderVariablesMiddleware {
|
|
15
79
|
requiredHeaders;
|
|
16
80
|
constructor(requiredHeaders) {
|
|
@@ -22,6 +86,60 @@ class HeaderVariablesMiddleware {
|
|
|
22
86
|
}
|
|
23
87
|
}
|
|
24
88
|
exports.HeaderVariablesMiddleware = HeaderVariablesMiddleware;
|
|
89
|
+
/**
|
|
90
|
+
* Factory function that creates a header validation middleware.
|
|
91
|
+
* Validates that all required headers are present in the request.
|
|
92
|
+
*
|
|
93
|
+
* @param requiredHeaders - Array of header names that must be present
|
|
94
|
+
* @returns BaseMiddleware object with header validation logic
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* Simple header validation:
|
|
98
|
+
* ```typescript
|
|
99
|
+
* import { Handler, headerVariablesMiddleware } from '@noony-serverless/core';
|
|
100
|
+
*
|
|
101
|
+
* const authHandler = new Handler()
|
|
102
|
+
* .use(headerVariablesMiddleware(['authorization']))
|
|
103
|
+
* .handle(async (context) => {
|
|
104
|
+
* const token = context.req.headers.authorization;
|
|
105
|
+
* // Proceed with authentication logic
|
|
106
|
+
* return { success: true, message: 'Authenticated' };
|
|
107
|
+
* });
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* Multiple required headers:
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const webhookHandler = new Handler()
|
|
114
|
+
* .use(headerVariablesMiddleware([
|
|
115
|
+
* 'x-webhook-signature',
|
|
116
|
+
* 'x-webhook-timestamp',
|
|
117
|
+
* 'content-type'
|
|
118
|
+
* ]))
|
|
119
|
+
* .handle(async (context) => {
|
|
120
|
+
* const signature = context.req.headers['x-webhook-signature'];
|
|
121
|
+
* const timestamp = context.req.headers['x-webhook-timestamp'];
|
|
122
|
+
*
|
|
123
|
+
* // Validate webhook authenticity
|
|
124
|
+
* const isValid = validateWebhookSignature(signature, timestamp, context.req.body);
|
|
125
|
+
* return { success: isValid };
|
|
126
|
+
* });
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* API versioning through headers:
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const versionedApiHandler = new Handler()
|
|
133
|
+
* .use(headerVariablesMiddleware(['x-api-version', 'accept']))
|
|
134
|
+
* .handle(async (context) => {
|
|
135
|
+
* const apiVersion = context.req.headers['x-api-version'];
|
|
136
|
+
* const accept = context.req.headers.accept;
|
|
137
|
+
*
|
|
138
|
+
* const handler = getHandlerForVersion(apiVersion as string);
|
|
139
|
+
* return handler.process(context.req.body);
|
|
140
|
+
* });
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
25
143
|
const headerVariablesMiddleware = (requiredHeaders) => ({
|
|
26
144
|
async before(context) {
|
|
27
145
|
context.req.headers = context.req.headers || {};
|
|
@@ -1,10 +1,245 @@
|
|
|
1
1
|
import { Context } from '../core/core';
|
|
2
2
|
import { BaseMiddleware } from '../core/handler';
|
|
3
3
|
import { ZodSchema } from 'zod';
|
|
4
|
+
/**
|
|
5
|
+
* Middleware class that extracts path parameters from the URL.
|
|
6
|
+
* Parses URL segments and extracts parameters based on colon-prefixed patterns.
|
|
7
|
+
*
|
|
8
|
+
* @implements {BaseMiddleware}
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* Basic path parameter extraction:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { Handler, PathParametersMiddleware } from '@noony-serverless/core';
|
|
14
|
+
*
|
|
15
|
+
* // For URL: /users/123/posts/456
|
|
16
|
+
* const userPostHandler = new Handler()
|
|
17
|
+
* .use(new PathParametersMiddleware())
|
|
18
|
+
* .handle(async (context) => {
|
|
19
|
+
* // Assuming your routing pattern is /users/:userId/posts/:postId
|
|
20
|
+
* const { userId, postId } = context.req.params || {};
|
|
21
|
+
*
|
|
22
|
+
* const user = await getUserById(userId);
|
|
23
|
+
* const post = await getPostById(postId);
|
|
24
|
+
*
|
|
25
|
+
* return { success: true, user, post };
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* RESTful API with multiple parameters:
|
|
31
|
+
* ```typescript
|
|
32
|
+
* // For URL: /api/v1/organizations/org-123/projects/proj-456/tasks/task-789
|
|
33
|
+
* const taskHandler = new Handler()
|
|
34
|
+
* .use(new PathParametersMiddleware())
|
|
35
|
+
* .handle(async (context) => {
|
|
36
|
+
* const { organizationId, projectId, taskId } = context.req.params || {};
|
|
37
|
+
*
|
|
38
|
+
* const task = await getTask(organizationId, projectId, taskId);
|
|
39
|
+
* return { success: true, task };
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* E-commerce product details:
|
|
45
|
+
* ```typescript
|
|
46
|
+
* // For URL: /categories/electronics/products/laptop-123
|
|
47
|
+
* const productHandler = new Handler()
|
|
48
|
+
* .use(new PathParametersMiddleware())
|
|
49
|
+
* .handle(async (context) => {
|
|
50
|
+
* const { category, productId } = context.req.params || {};
|
|
51
|
+
*
|
|
52
|
+
* const product = await getProductByCategory(category, productId);
|
|
53
|
+
* const recommendations = await getRecommendations(category, productId);
|
|
54
|
+
*
|
|
55
|
+
* return { success: true, product, recommendations };
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
4
59
|
export declare class PathParametersMiddleware implements BaseMiddleware {
|
|
5
60
|
before(context: Context): Promise<void>;
|
|
6
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Factory function that creates a path parameters extraction middleware.
|
|
64
|
+
* Extracts URL path segments and sets them in context.req.params.
|
|
65
|
+
*
|
|
66
|
+
* @returns BaseMiddleware object with path parameter extraction logic
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* Simple product API:
|
|
70
|
+
* ```typescript
|
|
71
|
+
* import { Handler, pathParameters } from '@noony-serverless/core';
|
|
72
|
+
*
|
|
73
|
+
* // For URL: /products/123
|
|
74
|
+
* const getProductHandler = new Handler()
|
|
75
|
+
* .use(pathParameters())
|
|
76
|
+
* .handle(async (context) => {
|
|
77
|
+
* const productId = context.req.params?.id;
|
|
78
|
+
* const product = await getProduct(productId);
|
|
79
|
+
* return { success: true, product };
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* Blog post with category:
|
|
85
|
+
* ```typescript
|
|
86
|
+
* // For URL: /blog/technology/post-123
|
|
87
|
+
* const blogPostHandler = new Handler()
|
|
88
|
+
* .use(pathParameters())
|
|
89
|
+
* .handle(async (context) => {
|
|
90
|
+
* const { category, postId } = context.req.params || {};
|
|
91
|
+
* const post = await getBlogPost(category, postId);
|
|
92
|
+
* const relatedPosts = await getRelatedPosts(category);
|
|
93
|
+
* return { success: true, post, relatedPosts };
|
|
94
|
+
* });
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* Nested resource API:
|
|
99
|
+
* ```typescript
|
|
100
|
+
* // For URL: /users/user-123/orders/order-456/items
|
|
101
|
+
* const orderItemsHandler = new Handler()
|
|
102
|
+
* .use(pathParameters())
|
|
103
|
+
* .handle(async (context) => {
|
|
104
|
+
* const { userId, orderId } = context.req.params || {};
|
|
105
|
+
* const orderItems = await getOrderItems(userId, orderId);
|
|
106
|
+
* return { success: true, items: orderItems };
|
|
107
|
+
* });
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
7
110
|
export declare const pathParameters: () => BaseMiddleware;
|
|
111
|
+
/**
|
|
112
|
+
* Factory function that creates a header validation middleware.
|
|
113
|
+
* Validates that all required headers are present in the request.
|
|
114
|
+
*
|
|
115
|
+
* @param requiredHeaders - Array of header names that must be present
|
|
116
|
+
* @returns BaseMiddleware object with header validation logic
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* API authentication headers:
|
|
120
|
+
* ```typescript
|
|
121
|
+
* import { Handler, headerVariablesValidator } from '@noony-serverless/core';
|
|
122
|
+
*
|
|
123
|
+
* const secureApiHandler = new Handler()
|
|
124
|
+
* .use(headerVariablesValidator(['authorization', 'x-api-key']))
|
|
125
|
+
* .handle(async (context) => {
|
|
126
|
+
* const authToken = context.req.headers.authorization;
|
|
127
|
+
* const apiKey = context.req.headers['x-api-key'];
|
|
128
|
+
*
|
|
129
|
+
* const isValid = await validateCredentials(authToken, apiKey);
|
|
130
|
+
* return { success: isValid, message: 'Access granted' };
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* Content type validation:
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const uploadHandler = new Handler()
|
|
138
|
+
* .use(headerVariablesValidator(['content-type', 'content-length']))
|
|
139
|
+
* .handle(async (context) => {
|
|
140
|
+
* const contentType = context.req.headers['content-type'];
|
|
141
|
+
* const contentLength = context.req.headers['content-length'];
|
|
142
|
+
*
|
|
143
|
+
* if (contentType !== 'application/json') {
|
|
144
|
+
* throw new Error('Only JSON content is accepted');
|
|
145
|
+
* }
|
|
146
|
+
*
|
|
147
|
+
* return { success: true, received: contentLength };
|
|
148
|
+
* });
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* Multi-tenant application:
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const tenantHandler = new Handler()
|
|
155
|
+
* .use(headerVariablesValidator(['x-tenant-id', 'x-client-version']))
|
|
156
|
+
* .handle(async (context) => {
|
|
157
|
+
* const tenantId = context.req.headers['x-tenant-id'];
|
|
158
|
+
* const clientVersion = context.req.headers['x-client-version'];
|
|
159
|
+
*
|
|
160
|
+
* const tenantConfig = await getTenantConfig(tenantId);
|
|
161
|
+
* return { success: true, config: tenantConfig, version: clientVersion };
|
|
162
|
+
* });
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
8
165
|
export declare const headerVariablesValidator: (requiredHeaders: string[]) => BaseMiddleware;
|
|
166
|
+
/**
|
|
167
|
+
* Factory function that creates a query parameter validation middleware using Zod schema.
|
|
168
|
+
* Validates query parameters against a provided schema and throws ValidationError if invalid.
|
|
169
|
+
*
|
|
170
|
+
* @param schema - Zod schema to validate query parameters against
|
|
171
|
+
* @returns BaseMiddleware object with query parameter validation logic
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* Pagination parameters validation:
|
|
175
|
+
* ```typescript
|
|
176
|
+
* import { z } from 'zod';
|
|
177
|
+
* import { Handler, validatedQueryParameters } from '@noony-serverless/core';
|
|
178
|
+
*
|
|
179
|
+
* const paginationSchema = z.object({
|
|
180
|
+
* page: z.string().regex(/^\d+$/).transform(Number).default('1'),
|
|
181
|
+
* limit: z.string().regex(/^\d+$/).transform(Number).default('10'),
|
|
182
|
+
* sort: z.enum(['asc', 'desc']).default('asc')
|
|
183
|
+
* });
|
|
184
|
+
*
|
|
185
|
+
* const listUsersHandler = new Handler()
|
|
186
|
+
* .use(validatedQueryParameters(paginationSchema))
|
|
187
|
+
* .handle(async (context) => {
|
|
188
|
+
* const { page, limit, sort } = context.req.query;
|
|
189
|
+
* const users = await getUsersPaginated(page, limit, sort);
|
|
190
|
+
* return { success: true, users, pagination: { page, limit, sort } };
|
|
191
|
+
* });
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* Search and filter parameters:
|
|
196
|
+
* ```typescript
|
|
197
|
+
* const searchSchema = z.object({
|
|
198
|
+
* q: z.string().min(1),
|
|
199
|
+
* category: z.string().optional(),
|
|
200
|
+
* price_min: z.string().regex(/^\d+(\.\d{2})?$/).optional(),
|
|
201
|
+
* price_max: z.string().regex(/^\d+(\.\d{2})?$/).optional(),
|
|
202
|
+
* in_stock: z.enum(['true', 'false']).optional()
|
|
203
|
+
* });
|
|
204
|
+
*
|
|
205
|
+
* const searchProductsHandler = new Handler()
|
|
206
|
+
* .use(validatedQueryParameters(searchSchema))
|
|
207
|
+
* .handle(async (context) => {
|
|
208
|
+
* const { q, category, price_min, price_max, in_stock } = context.req.query;
|
|
209
|
+
* const filters = {
|
|
210
|
+
* query: q,
|
|
211
|
+
* category,
|
|
212
|
+
* priceRange: { min: price_min, max: price_max },
|
|
213
|
+
* inStock: in_stock === 'true'
|
|
214
|
+
* };
|
|
215
|
+
* const products = await searchProducts(filters);
|
|
216
|
+
* return { success: true, products, filters };
|
|
217
|
+
* });
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* Date range and reporting parameters:
|
|
222
|
+
* ```typescript
|
|
223
|
+
* const reportSchema = z.object({
|
|
224
|
+
* start_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
225
|
+
* end_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
226
|
+
* granularity: z.enum(['day', 'week', 'month']).default('day'),
|
|
227
|
+
* metrics: z.string().transform(val => val.split(',')).optional()
|
|
228
|
+
* });
|
|
229
|
+
*
|
|
230
|
+
* const analyticsHandler = new Handler()
|
|
231
|
+
* .use(validatedQueryParameters(reportSchema))
|
|
232
|
+
* .handle(async (context) => {
|
|
233
|
+
* const { start_date, end_date, granularity, metrics } = context.req.query;
|
|
234
|
+
* const report = await generateReport({
|
|
235
|
+
* startDate: new Date(start_date),
|
|
236
|
+
* endDate: new Date(end_date),
|
|
237
|
+
* granularity,
|
|
238
|
+
* metrics
|
|
239
|
+
* });
|
|
240
|
+
* return { success: true, report };
|
|
241
|
+
* });
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
9
244
|
export declare const validatedQueryParameters: (schema: ZodSchema) => BaseMiddleware;
|
|
10
245
|
//# sourceMappingURL=httpAttributesMiddleware.d.ts.map
|