serverless-event-orchestrator 1.0.1
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/LICENSE +21 -0
- package/README.md +377 -0
- package/dist/dispatcher.d.ts +18 -0
- package/dist/dispatcher.d.ts.map +1 -0
- package/dist/dispatcher.js +345 -0
- package/dist/dispatcher.js.map +1 -0
- package/dist/http/body-parser.d.ts +27 -0
- package/dist/http/body-parser.d.ts.map +1 -0
- package/dist/http/body-parser.js +56 -0
- package/dist/http/body-parser.js.map +1 -0
- package/dist/http/cors.d.ts +32 -0
- package/dist/http/cors.d.ts.map +1 -0
- package/dist/http/cors.js +69 -0
- package/dist/http/cors.js.map +1 -0
- package/dist/http/index.d.ts +4 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +20 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/response.d.ts +104 -0
- package/dist/http/response.d.ts.map +1 -0
- package/dist/http/response.js +164 -0
- package/dist/http/response.js.map +1 -0
- package/dist/identity/extractor.d.ts +39 -0
- package/dist/identity/extractor.d.ts.map +1 -0
- package/dist/identity/extractor.js +88 -0
- package/dist/identity/extractor.js.map +1 -0
- package/dist/identity/index.d.ts +2 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +18 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/types/event-type.enum.d.ts +20 -0
- package/dist/types/event-type.enum.d.ts.map +1 -0
- package/dist/types/event-type.enum.js +25 -0
- package/dist/types/event-type.enum.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +19 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/routes.d.ts +163 -0
- package/dist/types/routes.d.ts.map +1 -0
- package/dist/types/routes.js +3 -0
- package/dist/types/routes.js.map +1 -0
- package/dist/utils/headers.d.ts +28 -0
- package/dist/utils/headers.d.ts.map +1 -0
- package/dist/utils/headers.js +61 -0
- package/dist/utils/headers.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +19 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/path-matcher.d.ts +33 -0
- package/dist/utils/path-matcher.d.ts.map +1 -0
- package/dist/utils/path-matcher.js +74 -0
- package/dist/utils/path-matcher.js.map +1 -0
- package/jest.config.js +32 -0
- package/package.json +68 -0
- package/src/dispatcher.ts +415 -0
- package/src/http/body-parser.ts +60 -0
- package/src/http/cors.ts +76 -0
- package/src/http/index.ts +3 -0
- package/src/http/response.ts +194 -0
- package/src/identity/extractor.ts +89 -0
- package/src/identity/index.ts +1 -0
- package/src/index.ts +92 -0
- package/src/types/event-type.enum.ts +20 -0
- package/src/types/index.ts +2 -0
- package/src/types/routes.ts +182 -0
- package/src/utils/headers.ts +72 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/path-matcher.ts +79 -0
- package/tests/cors.test.ts +133 -0
- package/tests/dispatcher.test.ts +425 -0
- package/tests/headers.test.ts +99 -0
- package/tests/identity.test.ts +171 -0
- package/tests/path-matcher.test.ts +102 -0
- package/tests/response.test.ts +155 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { RouteSegment } from './event-type.enum.js';
|
|
2
|
+
/**
|
|
3
|
+
* HTTP methods supported by the router
|
|
4
|
+
*/
|
|
5
|
+
export type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options';
|
|
6
|
+
/**
|
|
7
|
+
* Middleware function signature
|
|
8
|
+
* Returns the modified event or throws an error to halt execution
|
|
9
|
+
*/
|
|
10
|
+
export type MiddlewareFn = (event: NormalizedEvent) => Promise<NormalizedEvent | void>;
|
|
11
|
+
/**
|
|
12
|
+
* Route configuration for a single endpoint
|
|
13
|
+
*/
|
|
14
|
+
export interface RouteConfig {
|
|
15
|
+
handler: (event: NormalizedEvent) => Promise<any>;
|
|
16
|
+
middleware?: MiddlewareFn[];
|
|
17
|
+
cors?: boolean | CorsConfig;
|
|
18
|
+
rateLimit?: RateLimitConfig;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* CORS configuration options
|
|
22
|
+
*/
|
|
23
|
+
export interface CorsConfig {
|
|
24
|
+
origins: string[] | '*';
|
|
25
|
+
methods?: string[];
|
|
26
|
+
headers?: string[];
|
|
27
|
+
credentials?: boolean;
|
|
28
|
+
maxAge?: number;
|
|
29
|
+
exposedHeaders?: string[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Rate limit configuration
|
|
33
|
+
*/
|
|
34
|
+
export interface RateLimitConfig {
|
|
35
|
+
burstLimit: number;
|
|
36
|
+
rateLimit: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Standard HTTP router structure
|
|
40
|
+
* Maps HTTP methods to path-handler pairs
|
|
41
|
+
*/
|
|
42
|
+
export type HttpRouter = {
|
|
43
|
+
[K in HttpMethod]?: {
|
|
44
|
+
[path: string]: RouteConfig;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Segmented HTTP router for access control categorization
|
|
49
|
+
* Allows organizing routes by security context
|
|
50
|
+
*/
|
|
51
|
+
export interface SegmentedHttpRouter {
|
|
52
|
+
public?: HttpRouter;
|
|
53
|
+
private?: HttpRouter;
|
|
54
|
+
backoffice?: HttpRouter;
|
|
55
|
+
internal?: HttpRouter;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Segment configuration with optional middleware
|
|
59
|
+
*/
|
|
60
|
+
export interface SegmentConfig {
|
|
61
|
+
routes: HttpRouter;
|
|
62
|
+
middleware?: MiddlewareFn[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Advanced segmented router with per-segment middleware
|
|
66
|
+
*/
|
|
67
|
+
export interface AdvancedSegmentedRouter {
|
|
68
|
+
public?: SegmentConfig | HttpRouter;
|
|
69
|
+
private?: SegmentConfig | HttpRouter;
|
|
70
|
+
backoffice?: SegmentConfig | HttpRouter;
|
|
71
|
+
internal?: SegmentConfig | HttpRouter;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* EventBridge routes configuration
|
|
75
|
+
* Maps operation names to handlers
|
|
76
|
+
*/
|
|
77
|
+
export type EventBridgeRoutes = Record<string, (event: NormalizedEvent) => Promise<any>>;
|
|
78
|
+
/**
|
|
79
|
+
* Lambda invocation routes
|
|
80
|
+
*/
|
|
81
|
+
export type LambdaRoutes = Record<string, (event: NormalizedEvent) => Promise<any>>;
|
|
82
|
+
/**
|
|
83
|
+
* SQS queue routes
|
|
84
|
+
* Maps queue names to handlers
|
|
85
|
+
*/
|
|
86
|
+
export type SqsRoutes = Record<string, (event: NormalizedEvent) => Promise<any>>;
|
|
87
|
+
/**
|
|
88
|
+
* Complete dispatch routes configuration
|
|
89
|
+
*/
|
|
90
|
+
export interface DispatchRoutes {
|
|
91
|
+
apigateway?: HttpRouter | SegmentedHttpRouter | AdvancedSegmentedRouter;
|
|
92
|
+
eventbridge?: EventBridgeRoutes;
|
|
93
|
+
lambda?: LambdaRoutes;
|
|
94
|
+
sqs?: SqsRoutes;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Identity context extracted from the event
|
|
98
|
+
*/
|
|
99
|
+
export interface IdentityContext {
|
|
100
|
+
userId?: string;
|
|
101
|
+
email?: string;
|
|
102
|
+
groups?: string[];
|
|
103
|
+
issuer?: string;
|
|
104
|
+
claims?: Record<string, any>;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Route match result with extracted parameters
|
|
108
|
+
*/
|
|
109
|
+
export interface RouteMatch {
|
|
110
|
+
handler: (event: NormalizedEvent) => Promise<any>;
|
|
111
|
+
params: Record<string, string>;
|
|
112
|
+
segment: RouteSegment;
|
|
113
|
+
middleware?: MiddlewareFn[];
|
|
114
|
+
config: RouteConfig;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Normalized event structure passed to handlers
|
|
118
|
+
*/
|
|
119
|
+
export interface NormalizedEvent {
|
|
120
|
+
eventRaw: any;
|
|
121
|
+
eventType: string;
|
|
122
|
+
payload: {
|
|
123
|
+
body?: Record<string, any>;
|
|
124
|
+
pathParameters?: Record<string, string>;
|
|
125
|
+
queryStringParameters?: Record<string, string>;
|
|
126
|
+
headers?: Record<string, string>;
|
|
127
|
+
};
|
|
128
|
+
params: Record<string, string>;
|
|
129
|
+
context: {
|
|
130
|
+
segment: RouteSegment;
|
|
131
|
+
identity?: IdentityContext;
|
|
132
|
+
requestId?: string;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Orchestrator configuration options
|
|
137
|
+
*/
|
|
138
|
+
export interface OrchestratorConfig {
|
|
139
|
+
/**
|
|
140
|
+
* Enable verbose logging for debugging
|
|
141
|
+
*/
|
|
142
|
+
debug?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* User Pool ID mappings for segment-based validation
|
|
145
|
+
*/
|
|
146
|
+
userPools?: {
|
|
147
|
+
[K in RouteSegment]?: string;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Global middleware applied to all routes
|
|
151
|
+
*/
|
|
152
|
+
globalMiddleware?: MiddlewareFn[];
|
|
153
|
+
/**
|
|
154
|
+
* Custom response handlers
|
|
155
|
+
*/
|
|
156
|
+
responses?: {
|
|
157
|
+
notFound?: () => any;
|
|
158
|
+
forbidden?: () => any;
|
|
159
|
+
badRequest?: (message?: string) => any;
|
|
160
|
+
internalError?: (message?: string) => any;
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/types/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/types/routes.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header normalization utilities
|
|
3
|
+
* HTTP headers are case-insensitive, this ensures consistent access
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Normalizes headers to lowercase keys for consistent access
|
|
7
|
+
* @param headers - Original headers object
|
|
8
|
+
* @returns Headers with lowercase keys
|
|
9
|
+
*/
|
|
10
|
+
export declare function normalizeHeaders(headers: Record<string, string> | undefined): Record<string, string>;
|
|
11
|
+
/**
|
|
12
|
+
* Gets a header value case-insensitively
|
|
13
|
+
* @param headers - Headers object
|
|
14
|
+
* @param name - Header name to find
|
|
15
|
+
* @returns Header value or undefined
|
|
16
|
+
*/
|
|
17
|
+
export declare function getHeader(headers: Record<string, string> | undefined, name: string): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Standard CORS headers for preflight responses
|
|
20
|
+
*/
|
|
21
|
+
export declare function getCorsHeaders(config?: {
|
|
22
|
+
origins?: string[] | '*';
|
|
23
|
+
methods?: string[];
|
|
24
|
+
headers?: string[];
|
|
25
|
+
credentials?: boolean;
|
|
26
|
+
maxAge?: number;
|
|
27
|
+
}): Record<string, string>;
|
|
28
|
+
//# sourceMappingURL=headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/utils/headers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUpG;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYvG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE;IACtC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoBzB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Header normalization utilities
|
|
4
|
+
* HTTP headers are case-insensitive, this ensures consistent access
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.normalizeHeaders = normalizeHeaders;
|
|
8
|
+
exports.getHeader = getHeader;
|
|
9
|
+
exports.getCorsHeaders = getCorsHeaders;
|
|
10
|
+
/**
|
|
11
|
+
* Normalizes headers to lowercase keys for consistent access
|
|
12
|
+
* @param headers - Original headers object
|
|
13
|
+
* @returns Headers with lowercase keys
|
|
14
|
+
*/
|
|
15
|
+
function normalizeHeaders(headers) {
|
|
16
|
+
if (!headers)
|
|
17
|
+
return {};
|
|
18
|
+
const normalized = {};
|
|
19
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
20
|
+
normalized[key.toLowerCase()] = value;
|
|
21
|
+
}
|
|
22
|
+
return normalized;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Gets a header value case-insensitively
|
|
26
|
+
* @param headers - Headers object
|
|
27
|
+
* @param name - Header name to find
|
|
28
|
+
* @returns Header value or undefined
|
|
29
|
+
*/
|
|
30
|
+
function getHeader(headers, name) {
|
|
31
|
+
if (!headers)
|
|
32
|
+
return undefined;
|
|
33
|
+
const normalizedName = name.toLowerCase();
|
|
34
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
35
|
+
if (key.toLowerCase() === normalizedName) {
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Standard CORS headers for preflight responses
|
|
43
|
+
*/
|
|
44
|
+
function getCorsHeaders(config) {
|
|
45
|
+
const origin = config?.origins === '*' ? '*' : (config?.origins?.join(', ') || '*');
|
|
46
|
+
const methods = config?.methods?.join(', ') || 'GET,POST,PUT,DELETE,PATCH,OPTIONS';
|
|
47
|
+
const headers = config?.headers?.join(', ') || 'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token';
|
|
48
|
+
const corsHeaders = {
|
|
49
|
+
'Access-Control-Allow-Origin': origin,
|
|
50
|
+
'Access-Control-Allow-Methods': methods,
|
|
51
|
+
'Access-Control-Allow-Headers': headers,
|
|
52
|
+
};
|
|
53
|
+
if (config?.credentials) {
|
|
54
|
+
corsHeaders['Access-Control-Allow-Credentials'] = 'true';
|
|
55
|
+
}
|
|
56
|
+
if (config?.maxAge) {
|
|
57
|
+
corsHeaders['Access-Control-Max-Age'] = String(config.maxAge);
|
|
58
|
+
}
|
|
59
|
+
return corsHeaders;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headers.js","sourceRoot":"","sources":["../../src/utils/headers.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAOH,4CAUC;AAQD,8BAYC;AAKD,wCA0BC;AAlED;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,OAA2C;IAC1E,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAExB,MAAM,UAAU,GAA2B,EAAE,CAAC;IAE9C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC;IACxC,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,SAAS,CAAC,OAA2C,EAAE,IAAY;IACjF,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAE/B,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAE1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,cAAc,EAAE,CAAC;YACzC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,MAM9B;IACC,MAAM,MAAM,GAAG,MAAM,EAAE,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;IACpF,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,mCAAmC,CAAC;IACnF,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,sEAAsE,CAAC;IAEtH,MAAM,WAAW,GAA2B;QAC1C,6BAA6B,EAAE,MAAM;QACrC,8BAA8B,EAAE,OAAO;QACvC,8BAA8B,EAAE,OAAO;KACxC,CAAC;IAEF,IAAI,MAAM,EAAE,WAAW,EAAE,CAAC;QACxB,WAAW,CAAC,kCAAkC,CAAC,GAAG,MAAM,CAAC;IAC3D,CAAC;IAED,IAAI,MAAM,EAAE,MAAM,EAAE,CAAC;QACnB,WAAW,CAAC,wBAAwB,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./path-matcher.js"), exports);
|
|
18
|
+
__exportStar(require("./headers.js"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,+CAA6B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path matching utilities for extracting path parameters
|
|
3
|
+
* Supports patterns like /users/{id} and /users/{userId}/posts/{postId}
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Converts a route pattern to a regex and extracts parameter names
|
|
7
|
+
* @param pattern - Route pattern like /users/{id}
|
|
8
|
+
* @returns Object with regex and parameter names
|
|
9
|
+
*/
|
|
10
|
+
export declare function patternToRegex(pattern: string): {
|
|
11
|
+
regex: RegExp;
|
|
12
|
+
paramNames: string[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Matches a path against a pattern and extracts parameters
|
|
16
|
+
* @param pattern - Route pattern like /users/{id}
|
|
17
|
+
* @param path - Actual path like /users/123
|
|
18
|
+
* @returns Extracted parameters or null if no match
|
|
19
|
+
*/
|
|
20
|
+
export declare function matchPath(pattern: string, path: string): Record<string, string> | null;
|
|
21
|
+
/**
|
|
22
|
+
* Checks if a pattern contains path parameters
|
|
23
|
+
* @param pattern - Route pattern to check
|
|
24
|
+
* @returns True if pattern has parameters
|
|
25
|
+
*/
|
|
26
|
+
export declare function hasPathParameters(pattern: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Normalizes a path by removing trailing slashes and ensuring leading slash
|
|
29
|
+
* @param path - Path to normalize
|
|
30
|
+
* @returns Normalized path
|
|
31
|
+
*/
|
|
32
|
+
export declare function normalizePath(path: string): string;
|
|
33
|
+
//# sourceMappingURL=path-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-matcher.d.ts","sourceRoot":"","sources":["../../src/utils/path-matcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAkBvF;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CActF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYlD"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Path matching utilities for extracting path parameters
|
|
4
|
+
* Supports patterns like /users/{id} and /users/{userId}/posts/{postId}
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.patternToRegex = patternToRegex;
|
|
8
|
+
exports.matchPath = matchPath;
|
|
9
|
+
exports.hasPathParameters = hasPathParameters;
|
|
10
|
+
exports.normalizePath = normalizePath;
|
|
11
|
+
/**
|
|
12
|
+
* Converts a route pattern to a regex and extracts parameter names
|
|
13
|
+
* @param pattern - Route pattern like /users/{id}
|
|
14
|
+
* @returns Object with regex and parameter names
|
|
15
|
+
*/
|
|
16
|
+
function patternToRegex(pattern) {
|
|
17
|
+
const paramNames = [];
|
|
18
|
+
// Escape special regex characters except for our parameter syntax
|
|
19
|
+
let regexPattern = pattern
|
|
20
|
+
.replace(/[.+?^${}()|[\]\\]/g, '\\$&')
|
|
21
|
+
.replace(/\\\{(\w+)\\\}/g, (_, paramName) => {
|
|
22
|
+
paramNames.push(paramName);
|
|
23
|
+
return '([^/]+)';
|
|
24
|
+
});
|
|
25
|
+
// Ensure exact match
|
|
26
|
+
regexPattern = `^${regexPattern}$`;
|
|
27
|
+
return {
|
|
28
|
+
regex: new RegExp(regexPattern),
|
|
29
|
+
paramNames,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Matches a path against a pattern and extracts parameters
|
|
34
|
+
* @param pattern - Route pattern like /users/{id}
|
|
35
|
+
* @param path - Actual path like /users/123
|
|
36
|
+
* @returns Extracted parameters or null if no match
|
|
37
|
+
*/
|
|
38
|
+
function matchPath(pattern, path) {
|
|
39
|
+
const { regex, paramNames } = patternToRegex(pattern);
|
|
40
|
+
const match = path.match(regex);
|
|
41
|
+
if (!match) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const params = {};
|
|
45
|
+
paramNames.forEach((name, index) => {
|
|
46
|
+
params[name] = match[index + 1];
|
|
47
|
+
});
|
|
48
|
+
return params;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Checks if a pattern contains path parameters
|
|
52
|
+
* @param pattern - Route pattern to check
|
|
53
|
+
* @returns True if pattern has parameters
|
|
54
|
+
*/
|
|
55
|
+
function hasPathParameters(pattern) {
|
|
56
|
+
return /\{[\w]+\}/.test(pattern);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Normalizes a path by removing trailing slashes and ensuring leading slash
|
|
60
|
+
* @param path - Path to normalize
|
|
61
|
+
* @returns Normalized path
|
|
62
|
+
*/
|
|
63
|
+
function normalizePath(path) {
|
|
64
|
+
if (!path)
|
|
65
|
+
return '/';
|
|
66
|
+
// Ensure leading slash
|
|
67
|
+
let normalized = path.startsWith('/') ? path : `/${path}`;
|
|
68
|
+
// Remove trailing slash (except for root)
|
|
69
|
+
if (normalized.length > 1 && normalized.endsWith('/')) {
|
|
70
|
+
normalized = normalized.slice(0, -1);
|
|
71
|
+
}
|
|
72
|
+
return normalized;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=path-matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-matcher.js","sourceRoot":"","sources":["../../src/utils/path-matcher.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAOH,wCAkBC;AAQD,8BAcC;AAOD,8CAEC;AAOD,sCAYC;AAzED;;;;GAIG;AACH,SAAgB,cAAc,CAAC,OAAe;IAC5C,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,kEAAkE;IAClE,IAAI,YAAY,GAAG,OAAO;SACvB,OAAO,CAAC,oBAAoB,EAAE,MAAM,CAAC;SACrC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE;QAC1C,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3B,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;IAEL,qBAAqB;IACrB,YAAY,GAAG,IAAI,YAAY,GAAG,CAAC;IAEnC,OAAO;QACL,KAAK,EAAE,IAAI,MAAM,CAAC,YAAY,CAAC;QAC/B,UAAU;KACX,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,SAAS,CAAC,OAAe,EAAE,IAAY;IACrD,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAEhC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACjC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,SAAgB,iBAAiB,CAAC,OAAe;IAC/C,OAAO,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED;;;;GAIG;AACH,SAAgB,aAAa,CAAC,IAAY;IACxC,IAAI,CAAC,IAAI;QAAE,OAAO,GAAG,CAAC;IAEtB,uBAAuB;IACvB,IAAI,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAE1D,0CAA0C;IAC1C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtD,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
preset: 'ts-jest',
|
|
4
|
+
testEnvironment: 'node',
|
|
5
|
+
roots: ['<rootDir>/src', '<rootDir>/tests'],
|
|
6
|
+
testMatch: ['**/*.test.ts'],
|
|
7
|
+
moduleNameMapper: {
|
|
8
|
+
'^(\\.{1,2}/.*)\\.js$': '$1'
|
|
9
|
+
},
|
|
10
|
+
transform: {
|
|
11
|
+
'^.+\\.tsx?$': ['ts-jest', {
|
|
12
|
+
useESM: false,
|
|
13
|
+
tsconfig: {
|
|
14
|
+
module: 'commonjs',
|
|
15
|
+
moduleResolution: 'node'
|
|
16
|
+
}
|
|
17
|
+
}]
|
|
18
|
+
},
|
|
19
|
+
collectCoverageFrom: [
|
|
20
|
+
'src/**/*.ts',
|
|
21
|
+
'!src/**/*.d.ts',
|
|
22
|
+
'!src/**/index.ts'
|
|
23
|
+
],
|
|
24
|
+
coverageThreshold: {
|
|
25
|
+
global: {
|
|
26
|
+
branches: 70,
|
|
27
|
+
functions: 90,
|
|
28
|
+
lines: 80,
|
|
29
|
+
statements: 80
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "serverless-event-orchestrator",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "A lightweight, type-safe event dispatcher and middleware orchestrator for AWS Lambda. Designed for hexagonal architectures with support for segmented routing (public, private, backoffice), Cognito User Pool validation, and built-in infrastructure middlewares.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./http": {
|
|
14
|
+
"import": "./dist/http/index.js",
|
|
15
|
+
"require": "./dist/http/index.js",
|
|
16
|
+
"types": "./dist/http/index.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./identity": {
|
|
19
|
+
"import": "./dist/identity/index.js",
|
|
20
|
+
"require": "./dist/identity/index.js",
|
|
21
|
+
"types": "./dist/identity/index.d.ts"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"test": "jest --passWithNoTests",
|
|
27
|
+
"test:watch": "jest --watchAll",
|
|
28
|
+
"test:coverage": "jest --coverage",
|
|
29
|
+
"clean": "rm -rf dist",
|
|
30
|
+
"prepublishOnly": "npm run clean && npm run build && npm test"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/carlosmora01/serverless-event-orchestrator.git"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"aws",
|
|
38
|
+
"lambda",
|
|
39
|
+
"serverless",
|
|
40
|
+
"eventbridge",
|
|
41
|
+
"apigateway",
|
|
42
|
+
"sqs",
|
|
43
|
+
"router",
|
|
44
|
+
"dispatcher",
|
|
45
|
+
"cognito",
|
|
46
|
+
"middleware",
|
|
47
|
+
"hexagonal-architecture"
|
|
48
|
+
],
|
|
49
|
+
"author": "Carlos Mora",
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/carlosmora01/serverless-event-orchestrator/issues"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/carlosmora01/serverless-event-orchestrator#readme",
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/jest": "^29.5.0",
|
|
57
|
+
"@types/node": "^20.0.0",
|
|
58
|
+
"jest": "^29.7.0",
|
|
59
|
+
"ts-jest": "^29.1.0",
|
|
60
|
+
"typescript": "^5.3.0"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"@types/aws-lambda": "^8.10.0"
|
|
64
|
+
},
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=18.0.0"
|
|
67
|
+
}
|
|
68
|
+
}
|