wynkjs 1.0.4 → 1.0.7
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 +361 -315
- package/dist/cors.d.ts +28 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +121 -0
- package/dist/decorators/exception.decorators.d.ts +1 -0
- package/dist/decorators/exception.decorators.d.ts.map +1 -1
- package/dist/decorators/exception.decorators.js +20 -3
- package/dist/decorators/guard.decorators.d.ts.map +1 -1
- package/dist/decorators/guard.decorators.js +11 -5
- package/dist/decorators/http.decorators.d.ts +8 -3
- package/dist/decorators/http.decorators.d.ts.map +1 -1
- package/dist/decorators/http.decorators.js +9 -2
- package/dist/decorators/interceptor.advanced.d.ts +9 -9
- package/dist/decorators/interceptor.advanced.d.ts.map +1 -1
- package/dist/decorators/interceptor.advanced.js +7 -7
- package/dist/decorators/interceptor.decorators.d.ts +9 -7
- package/dist/decorators/interceptor.decorators.d.ts.map +1 -1
- package/dist/decorators/interceptor.decorators.js +29 -18
- package/dist/decorators/param.decorators.d.ts +2 -2
- package/dist/decorators/param.decorators.js +1 -1
- package/dist/decorators/pipe.decorators.d.ts +2 -2
- package/dist/decorators/pipe.decorators.js +2 -2
- package/dist/factory.d.ts +62 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +191 -180
- package/dist/global-prefix.d.ts +49 -0
- package/dist/global-prefix.d.ts.map +1 -0
- package/dist/global-prefix.js +155 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/interfaces/interceptor.interface.d.ts +15 -0
- package/dist/interfaces/interceptor.interface.d.ts.map +1 -0
- package/dist/interfaces/interceptor.interface.js +1 -0
- package/dist/optimized-handler.d.ts +31 -0
- package/dist/optimized-handler.d.ts.map +1 -0
- package/dist/optimized-handler.js +180 -0
- package/dist/pipes/validation.pipe.d.ts +10 -10
- package/dist/pipes/validation.pipe.js +4 -4
- package/dist/plugins/compression.d.ts +75 -0
- package/dist/plugins/compression.d.ts.map +1 -0
- package/dist/plugins/compression.js +125 -0
- package/dist/ultra-optimized-handler.d.ts +51 -0
- package/dist/ultra-optimized-handler.d.ts.map +1 -0
- package/dist/ultra-optimized-handler.js +302 -0
- package/package.json +17 -10
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Elysia } from "elysia";
|
|
2
|
+
/**
|
|
3
|
+
* Global Prefix Module for WynkJS Framework
|
|
4
|
+
* Adds a prefix to all routes in the application
|
|
5
|
+
* Separated from factory.ts for better maintainability
|
|
6
|
+
*/
|
|
7
|
+
export interface GlobalPrefixOptions {
|
|
8
|
+
prefix: string;
|
|
9
|
+
exclude?: string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Apply global prefix to all routes
|
|
13
|
+
* @param app - Elysia instance
|
|
14
|
+
* @param prefix - Prefix string (e.g., '/api', '/v1')
|
|
15
|
+
* @param options - Additional options like route exclusions
|
|
16
|
+
* @returns Modified Elysia instance
|
|
17
|
+
*/
|
|
18
|
+
export declare function applyGlobalPrefix(app: Elysia, prefix: string | GlobalPrefixOptions): any;
|
|
19
|
+
/**
|
|
20
|
+
* Normalize prefix path
|
|
21
|
+
* - Ensures it starts with /
|
|
22
|
+
* - Removes trailing /
|
|
23
|
+
* - Validates format
|
|
24
|
+
* @param prefix - Raw prefix string
|
|
25
|
+
* @returns Normalized prefix
|
|
26
|
+
*/
|
|
27
|
+
export declare function normalizePrefixPath(prefix: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Check if a route should be excluded from global prefix
|
|
30
|
+
* @param path - Route path
|
|
31
|
+
* @param excludedRoutes - List of routes to exclude
|
|
32
|
+
* @returns true if route should be excluded
|
|
33
|
+
*/
|
|
34
|
+
export declare function isRouteExcluded(path: string, excludedRoutes: string[]): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Apply global prefix to an existing Elysia app by wrapping it
|
|
37
|
+
* This is useful when you want to add prefix to already configured app
|
|
38
|
+
* @param app - Existing Elysia instance
|
|
39
|
+
* @param prefix - Prefix to apply
|
|
40
|
+
* @returns New Elysia instance with prefix
|
|
41
|
+
*/
|
|
42
|
+
export declare function wrapWithPrefix(app: Elysia, prefix: string | GlobalPrefixOptions): any;
|
|
43
|
+
/**
|
|
44
|
+
* Validate global prefix configuration
|
|
45
|
+
* @param prefix - Prefix configuration
|
|
46
|
+
* @returns true if valid, throws error if invalid
|
|
47
|
+
*/
|
|
48
|
+
export declare function validateGlobalPrefix(prefix: string | GlobalPrefixOptions): boolean;
|
|
49
|
+
//# sourceMappingURL=global-prefix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-prefix.d.ts","sourceRoot":"","sources":["../core/global-prefix.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;;GAIG;AAEH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GAAG,mBAAmB,GACnC,GAAG,CAkCL;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA0B1D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAuBT;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GAAG,mBAAmB,GACnC,GAAG,CA0BL;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,GAAG,mBAAmB,GACnC,OAAO,CA2CT"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Elysia } from "elysia";
|
|
2
|
+
/**
|
|
3
|
+
* Apply global prefix to all routes
|
|
4
|
+
* @param app - Elysia instance
|
|
5
|
+
* @param prefix - Prefix string (e.g., '/api', '/v1')
|
|
6
|
+
* @param options - Additional options like route exclusions
|
|
7
|
+
* @returns Modified Elysia instance
|
|
8
|
+
*/
|
|
9
|
+
export function applyGlobalPrefix(app, prefix) {
|
|
10
|
+
// Normalize prefix
|
|
11
|
+
let prefixStr;
|
|
12
|
+
let excludedRoutes = [];
|
|
13
|
+
if (typeof prefix === "string") {
|
|
14
|
+
prefixStr = prefix;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
prefixStr = prefix.prefix;
|
|
18
|
+
excludedRoutes = prefix.exclude || [];
|
|
19
|
+
}
|
|
20
|
+
// Validate and normalize prefix
|
|
21
|
+
prefixStr = normalizePrefixPath(prefixStr);
|
|
22
|
+
if (!prefixStr) {
|
|
23
|
+
console.warn("⚠️ Global prefix is empty after normalization. Skipping prefix setup.");
|
|
24
|
+
return app;
|
|
25
|
+
}
|
|
26
|
+
// Create a new Elysia instance with the prefix
|
|
27
|
+
const prefixedApp = new Elysia({ prefix: prefixStr });
|
|
28
|
+
// Note: Elysia's prefix option automatically applies to all routes
|
|
29
|
+
// registered on this instance. We'll return the prefixed instance.
|
|
30
|
+
console.log(`✅ Global prefix applied: ${prefixStr}`);
|
|
31
|
+
if (excludedRoutes.length > 0) {
|
|
32
|
+
console.log(` Excluded routes: ${excludedRoutes.join(", ")}`);
|
|
33
|
+
}
|
|
34
|
+
return prefixedApp;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Normalize prefix path
|
|
38
|
+
* - Ensures it starts with /
|
|
39
|
+
* - Removes trailing /
|
|
40
|
+
* - Validates format
|
|
41
|
+
* @param prefix - Raw prefix string
|
|
42
|
+
* @returns Normalized prefix
|
|
43
|
+
*/
|
|
44
|
+
export function normalizePrefixPath(prefix) {
|
|
45
|
+
if (!prefix) {
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
let normalized = prefix.trim();
|
|
49
|
+
// Ensure starts with /
|
|
50
|
+
if (!normalized.startsWith("/")) {
|
|
51
|
+
normalized = "/" + normalized;
|
|
52
|
+
}
|
|
53
|
+
// Remove trailing /
|
|
54
|
+
if (normalized.endsWith("/") && normalized.length > 1) {
|
|
55
|
+
normalized = normalized.slice(0, -1);
|
|
56
|
+
}
|
|
57
|
+
// Validate format (no spaces, no special chars except /, -, _)
|
|
58
|
+
const validPattern = /^\/[\w\-\/]*$/;
|
|
59
|
+
if (!validPattern.test(normalized)) {
|
|
60
|
+
throw new Error(`Invalid global prefix format: "${prefix}". Only alphanumeric, hyphens, underscores, and forward slashes are allowed.`);
|
|
61
|
+
}
|
|
62
|
+
return normalized;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if a route should be excluded from global prefix
|
|
66
|
+
* @param path - Route path
|
|
67
|
+
* @param excludedRoutes - List of routes to exclude
|
|
68
|
+
* @returns true if route should be excluded
|
|
69
|
+
*/
|
|
70
|
+
export function isRouteExcluded(path, excludedRoutes) {
|
|
71
|
+
if (!excludedRoutes || excludedRoutes.length === 0) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
// Normalize the path
|
|
75
|
+
const normalizedPath = path.startsWith("/") ? path : "/" + path;
|
|
76
|
+
// Check for exact match or wildcard match
|
|
77
|
+
return excludedRoutes.some((excluded) => {
|
|
78
|
+
// Exact match
|
|
79
|
+
if (excluded === normalizedPath) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
// Wildcard match (e.g., '/health/*')
|
|
83
|
+
if (excluded.endsWith("/*")) {
|
|
84
|
+
const base = excluded.slice(0, -2);
|
|
85
|
+
return normalizedPath.startsWith(base);
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Apply global prefix to an existing Elysia app by wrapping it
|
|
92
|
+
* This is useful when you want to add prefix to already configured app
|
|
93
|
+
* @param app - Existing Elysia instance
|
|
94
|
+
* @param prefix - Prefix to apply
|
|
95
|
+
* @returns New Elysia instance with prefix
|
|
96
|
+
*/
|
|
97
|
+
export function wrapWithPrefix(app, prefix) {
|
|
98
|
+
let prefixStr;
|
|
99
|
+
let excludedRoutes = [];
|
|
100
|
+
if (typeof prefix === "string") {
|
|
101
|
+
prefixStr = prefix;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
prefixStr = prefix.prefix;
|
|
105
|
+
excludedRoutes = prefix.exclude || [];
|
|
106
|
+
}
|
|
107
|
+
prefixStr = normalizePrefixPath(prefixStr);
|
|
108
|
+
// Create wrapper app with prefix
|
|
109
|
+
const wrapper = new Elysia();
|
|
110
|
+
// Mount the original app under the prefix
|
|
111
|
+
wrapper.use(new Elysia({
|
|
112
|
+
prefix: prefixStr,
|
|
113
|
+
}).use(app));
|
|
114
|
+
console.log(`✅ Wrapped existing app with prefix: ${prefixStr}`);
|
|
115
|
+
return wrapper;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Validate global prefix configuration
|
|
119
|
+
* @param prefix - Prefix configuration
|
|
120
|
+
* @returns true if valid, throws error if invalid
|
|
121
|
+
*/
|
|
122
|
+
export function validateGlobalPrefix(prefix) {
|
|
123
|
+
if (typeof prefix === "string") {
|
|
124
|
+
// Validate string prefix
|
|
125
|
+
if (prefix.length === 0) {
|
|
126
|
+
throw new Error("Global prefix cannot be an empty string");
|
|
127
|
+
}
|
|
128
|
+
normalizePrefixPath(prefix); // This will throw if invalid
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
if (typeof prefix === "object" && prefix !== null) {
|
|
132
|
+
// Validate object prefix
|
|
133
|
+
if (!prefix.prefix) {
|
|
134
|
+
throw new Error("GlobalPrefixOptions must have a 'prefix' property");
|
|
135
|
+
}
|
|
136
|
+
if (typeof prefix.prefix !== "string") {
|
|
137
|
+
throw new Error("Global prefix must be a string");
|
|
138
|
+
}
|
|
139
|
+
normalizePrefixPath(prefix.prefix); // This will throw if invalid
|
|
140
|
+
// Validate exclude array
|
|
141
|
+
if (prefix.exclude !== undefined) {
|
|
142
|
+
if (!Array.isArray(prefix.exclude)) {
|
|
143
|
+
throw new Error("GlobalPrefixOptions.exclude must be an array");
|
|
144
|
+
}
|
|
145
|
+
// Validate each excluded route
|
|
146
|
+
prefix.exclude.forEach((route) => {
|
|
147
|
+
if (typeof route !== "string") {
|
|
148
|
+
throw new Error("All routes in GlobalPrefixOptions.exclude must be strings");
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
throw new Error("Global prefix must be string or GlobalPrefixOptions object");
|
|
155
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,12 @@ export * from "./decorators/database.decorators";
|
|
|
23
23
|
export * from "./dto";
|
|
24
24
|
export { schemaRegistry } from "./schema-registry";
|
|
25
25
|
export * from "./factory";
|
|
26
|
+
export type { CorsOptions } from "./cors";
|
|
27
|
+
export { setupCors, validateCorsOptions } from "./cors";
|
|
28
|
+
export type { GlobalPrefixOptions } from "./global-prefix";
|
|
29
|
+
export { applyGlobalPrefix, normalizePrefixPath, validateGlobalPrefix, wrapWithPrefix, } from "./global-prefix";
|
|
30
|
+
export { compression } from "./plugins/compression";
|
|
31
|
+
export type { CompressionOptions } from "./plugins/compression";
|
|
26
32
|
export * from "./testing";
|
|
27
33
|
/**
|
|
28
34
|
* Framework version
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../core/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,kBAAkB,CAAC;AAI1B,OAAO,EACL,UAAU,EACV,MAAM,EACN,SAAS,EACT,cAAc,EACd,QAAQ,EACR,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAGpD,OAAO,EACL,UAAU,IAAI,UAAU,EACxB,MAAM,IAAI,MAAM,EAChB,SAAS,IAAI,SAAS,EACtB,cAAc,IAAI,cAAc,EAChC,QAAQ,IAAI,QAAQ,EACpB,SAAS,IAAI,SAAS,GACvB,MAAM,UAAU,CAAC;AAGlB,cAAc,8BAA8B,CAAC;AAG7C,cAAc,+BAA+B,CAAC;AAG9C,cAAc,+BAA+B,CAAC;AAG9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC;AAGlD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAI3C,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAI5C,cAAc,kCAAkC,CAAC;AASjD,cAAc,OAAO,CAAC;AAGtB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGnD,cAAc,WAAW,CAAC;AAG1B,cAAc,WAAW,CAAC;AAE1B;;GAEG;AACH,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B;;GAEG;AACH,eAAO,MAAM,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../core/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,kBAAkB,CAAC;AAI1B,OAAO,EACL,UAAU,EACV,MAAM,EACN,SAAS,EACT,cAAc,EACd,QAAQ,EACR,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAGpD,OAAO,EACL,UAAU,IAAI,UAAU,EACxB,MAAM,IAAI,MAAM,EAChB,SAAS,IAAI,SAAS,EACtB,cAAc,IAAI,cAAc,EAChC,QAAQ,IAAI,QAAQ,EACpB,SAAS,IAAI,SAAS,GACvB,MAAM,UAAU,CAAC;AAGlB,cAAc,8BAA8B,CAAC;AAG7C,cAAc,+BAA+B,CAAC;AAG9C,cAAc,+BAA+B,CAAC;AAG9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC;AAGlD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAI3C,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAI5C,cAAc,kCAAkC,CAAC;AASjD,cAAc,OAAO,CAAC;AAGtB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGnD,cAAc,WAAW,CAAC;AAG1B,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAGxD,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,GACf,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAGhE,cAAc,WAAW,CAAC;AAE1B;;GAEG;AACH,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B;;GAEG;AACH,eAAO,MAAM,cAAc,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,10 @@ export * from "./dto";
|
|
|
44
44
|
export { schemaRegistry } from "./schema-registry";
|
|
45
45
|
// Application Factory
|
|
46
46
|
export * from "./factory";
|
|
47
|
+
export { setupCors, validateCorsOptions } from "./cors";
|
|
48
|
+
export { applyGlobalPrefix, normalizePrefixPath, validateGlobalPrefix, wrapWithPrefix, } from "./global-prefix";
|
|
49
|
+
// Plugins
|
|
50
|
+
export { compression } from "./plugins/compression";
|
|
47
51
|
// Testing Module
|
|
48
52
|
export * from "./testing";
|
|
49
53
|
/**
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface InterceptorContext {
|
|
2
|
+
getRequest<T = any>(): T;
|
|
3
|
+
getResponse<T = any>(): T;
|
|
4
|
+
getContext<T = any>(): T;
|
|
5
|
+
getHandler(): Function;
|
|
6
|
+
getClass(): any;
|
|
7
|
+
request?: any;
|
|
8
|
+
body?: any;
|
|
9
|
+
params?: any;
|
|
10
|
+
query?: any;
|
|
11
|
+
headers?: any;
|
|
12
|
+
path?: string;
|
|
13
|
+
method?: string;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=interceptor.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptor.interface.d.ts","sourceRoot":"","sources":["../../core/interfaces/interceptor.interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;IACzB,WAAW,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;IAC1B,UAAU,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;IACzB,UAAU,IAAI,QAAQ,CAAC;IACvB,QAAQ,IAAI,GAAG,CAAC;IAEhB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,OAAO,CAAC,EAAE,GAAG,CAAC;IAEd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optimized Handler Builder for WynkJS
|
|
3
|
+
* Builds route handlers conditionally - only adds overhead when features are actually used
|
|
4
|
+
*/
|
|
5
|
+
import { ParamMetadata } from "./decorators/param.decorators";
|
|
6
|
+
export interface HandlerBuildOptions {
|
|
7
|
+
instance: any;
|
|
8
|
+
methodName: string;
|
|
9
|
+
ControllerClass: any;
|
|
10
|
+
params: ParamMetadata[];
|
|
11
|
+
allGuards: any[];
|
|
12
|
+
allInterceptors: any[];
|
|
13
|
+
allPipes: any[];
|
|
14
|
+
allFilters: any[];
|
|
15
|
+
httpCode?: number;
|
|
16
|
+
headers?: Record<string, string>;
|
|
17
|
+
redirect?: {
|
|
18
|
+
url: string;
|
|
19
|
+
statusCode: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build optimized handler - only include overhead when features are used
|
|
24
|
+
* This eliminates conditional checks on every request for unused features
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildOptimizedHandler(options: HandlerBuildOptions): (ctx: any) => Promise<any>;
|
|
27
|
+
/**
|
|
28
|
+
* Build middleware chain - only if middleware exists
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildMiddlewareChain(handler: (ctx: any) => Promise<any>, middlewares: any[]): (ctx: any) => Promise<any>;
|
|
31
|
+
//# sourceMappingURL=optimized-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimized-handler.d.ts","sourceRoot":"","sources":["../core/optimized-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,GAAG,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,GAAG,CAAC;IACrB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,SAAS,EAAE,GAAG,EAAE,CAAC;IACjB,eAAe,EAAE,GAAG,EAAE,CAAC;IACvB,QAAQ,EAAE,GAAG,EAAE,CAAC;IAChB,UAAU,EAAE,GAAG,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,mBAAmB,GAC3B,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAyM5B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,EACnC,WAAW,EAAE,GAAG,EAAE,GACjB,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAW5B"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optimized Handler Builder for WynkJS
|
|
3
|
+
* Builds route handlers conditionally - only adds overhead when features are actually used
|
|
4
|
+
*/
|
|
5
|
+
import { createExecutionContext, executeGuards, } from "./decorators/guard.decorators";
|
|
6
|
+
import { executeInterceptors } from "./decorators/interceptor.decorators";
|
|
7
|
+
import { executePipes } from "./decorators/pipe.decorators";
|
|
8
|
+
import { executeExceptionFilters, HttpException, } from "./decorators/exception.decorators";
|
|
9
|
+
/**
|
|
10
|
+
* Build optimized handler - only include overhead when features are used
|
|
11
|
+
* This eliminates conditional checks on every request for unused features
|
|
12
|
+
*/
|
|
13
|
+
export function buildOptimizedHandler(options) {
|
|
14
|
+
const { instance, methodName, ControllerClass, params, allGuards, allInterceptors, allPipes, allFilters, httpCode, headers, redirect, } = options;
|
|
15
|
+
// Pre-sort params once during registration (not on every request)
|
|
16
|
+
if (params.length > 0) {
|
|
17
|
+
params.sort((a, b) => a.index - b.index);
|
|
18
|
+
}
|
|
19
|
+
// Base parameter extractor and method executor
|
|
20
|
+
const extractParamsAndExecute = async (ctx) => {
|
|
21
|
+
if (params.length === 0) {
|
|
22
|
+
// No parameter decorators - pass full context
|
|
23
|
+
return await instance[methodName](ctx);
|
|
24
|
+
}
|
|
25
|
+
// Build arguments array
|
|
26
|
+
const args = new Array(params.length);
|
|
27
|
+
for (const param of params) {
|
|
28
|
+
let value;
|
|
29
|
+
// Extract value based on type (optimized switch)
|
|
30
|
+
switch (param.type) {
|
|
31
|
+
case "body":
|
|
32
|
+
value = param.data ? ctx.body?.[param.data] : ctx.body;
|
|
33
|
+
break;
|
|
34
|
+
case "param":
|
|
35
|
+
value = param.data ? ctx.params?.[param.data] : ctx.params;
|
|
36
|
+
break;
|
|
37
|
+
case "query":
|
|
38
|
+
value = param.data ? ctx.query?.[param.data] : ctx.query;
|
|
39
|
+
break;
|
|
40
|
+
case "headers":
|
|
41
|
+
value = param.data
|
|
42
|
+
? ctx.headers?.get?.(param.data) ||
|
|
43
|
+
ctx.request?.headers?.get?.(param.data)
|
|
44
|
+
: ctx.headers || ctx.request?.headers;
|
|
45
|
+
break;
|
|
46
|
+
case "request":
|
|
47
|
+
value = ctx.request || ctx;
|
|
48
|
+
break;
|
|
49
|
+
case "response":
|
|
50
|
+
value = ctx.set || ctx.response;
|
|
51
|
+
break;
|
|
52
|
+
case "context":
|
|
53
|
+
if (param.data) {
|
|
54
|
+
const keys = param.data.split(".");
|
|
55
|
+
value = keys.reduce((obj, key) => obj?.[key], ctx);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
value = ctx;
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case "user":
|
|
62
|
+
value = param.data ? ctx.user?.[param.data] : ctx.user;
|
|
63
|
+
break;
|
|
64
|
+
case "file":
|
|
65
|
+
value = ctx.body?.file || ctx.file;
|
|
66
|
+
break;
|
|
67
|
+
case "files":
|
|
68
|
+
value = ctx.body?.files || ctx.files;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
// Apply parameter-specific pipes
|
|
72
|
+
if (param.pipes && param.pipes.length > 0) {
|
|
73
|
+
const metadata = {
|
|
74
|
+
type: param.type,
|
|
75
|
+
data: param.data,
|
|
76
|
+
};
|
|
77
|
+
value = await executePipes(param.pipes, value, metadata);
|
|
78
|
+
}
|
|
79
|
+
// Apply global/controller/method pipes
|
|
80
|
+
if (allPipes.length > 0) {
|
|
81
|
+
const metadata = {
|
|
82
|
+
type: param.type,
|
|
83
|
+
data: param.data,
|
|
84
|
+
};
|
|
85
|
+
value = await executePipes(allPipes, value, metadata);
|
|
86
|
+
}
|
|
87
|
+
args[param.index] = value;
|
|
88
|
+
}
|
|
89
|
+
return await instance[methodName].apply(instance, args);
|
|
90
|
+
};
|
|
91
|
+
// Build handler layers conditionally
|
|
92
|
+
let handler = extractParamsAndExecute;
|
|
93
|
+
// Wrap with interceptors (only if they exist)
|
|
94
|
+
if (allInterceptors.length > 0) {
|
|
95
|
+
const prevHandler = handler;
|
|
96
|
+
handler = async (ctx) => {
|
|
97
|
+
const executionContext = createExecutionContext(ctx, instance[methodName], ControllerClass);
|
|
98
|
+
return await executeInterceptors(allInterceptors, executionContext, () => prevHandler(ctx));
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
// Wrap with guards (only if they exist)
|
|
102
|
+
if (allGuards.length > 0) {
|
|
103
|
+
const prevHandler = handler;
|
|
104
|
+
handler = async (ctx) => {
|
|
105
|
+
const executionContext = createExecutionContext(ctx, instance[methodName], ControllerClass);
|
|
106
|
+
const canActivate = await executeGuards(allGuards, executionContext);
|
|
107
|
+
if (!canActivate) {
|
|
108
|
+
throw new HttpException("Forbidden", 403, "Access denied");
|
|
109
|
+
}
|
|
110
|
+
return await prevHandler(ctx);
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// Final handler with response modifications
|
|
114
|
+
const finalHandler = async (ctx) => {
|
|
115
|
+
try {
|
|
116
|
+
const result = await handler(ctx);
|
|
117
|
+
// Handle redirect (if configured)
|
|
118
|
+
if (redirect) {
|
|
119
|
+
ctx.set.redirect = redirect.url;
|
|
120
|
+
ctx.set.status = redirect.statusCode;
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// Set custom HTTP code (if configured)
|
|
124
|
+
if (httpCode) {
|
|
125
|
+
ctx.set.status = httpCode;
|
|
126
|
+
}
|
|
127
|
+
// Set custom headers (if configured)
|
|
128
|
+
if (headers) {
|
|
129
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
130
|
+
ctx.set.headers[key] = value;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
// Execute exception filters (only if they exist)
|
|
137
|
+
if (allFilters.length > 0) {
|
|
138
|
+
const executionContext = createExecutionContext(ctx, instance[methodName], ControllerClass);
|
|
139
|
+
try {
|
|
140
|
+
const result = await executeExceptionFilters(allFilters, error, executionContext);
|
|
141
|
+
if (result) {
|
|
142
|
+
if (result.statusCode) {
|
|
143
|
+
ctx.set.status = result.statusCode;
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (filterError) {
|
|
149
|
+
error = filterError;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Default error handling
|
|
153
|
+
if (error instanceof HttpException) {
|
|
154
|
+
ctx.set.status = error.getStatus();
|
|
155
|
+
return error.getResponse();
|
|
156
|
+
}
|
|
157
|
+
ctx.set.status = 500;
|
|
158
|
+
return {
|
|
159
|
+
statusCode: 500,
|
|
160
|
+
message: error.message || "Internal server error",
|
|
161
|
+
error: "Internal Server Error",
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
return finalHandler;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Build middleware chain - only if middleware exists
|
|
169
|
+
*/
|
|
170
|
+
export function buildMiddlewareChain(handler, middlewares) {
|
|
171
|
+
if (middlewares.length === 0) {
|
|
172
|
+
return handler;
|
|
173
|
+
}
|
|
174
|
+
// Build middleware chain (removed console.log for performance)
|
|
175
|
+
return middlewares.reduceRight((next, middleware) => {
|
|
176
|
+
return async (ctx) => {
|
|
177
|
+
return await middleware(ctx, () => next(ctx));
|
|
178
|
+
};
|
|
179
|
+
}, handler);
|
|
180
|
+
}
|
|
@@ -15,9 +15,9 @@ export interface ArgumentMetadata {
|
|
|
15
15
|
data?: string;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
* Validation Error structure (
|
|
18
|
+
* Validation Error structure (WynkJS format)
|
|
19
19
|
*/
|
|
20
|
-
export interface
|
|
20
|
+
export interface WynkJSValidationError {
|
|
21
21
|
type: "validation";
|
|
22
22
|
on: "body" | "params" | "query" | "headers";
|
|
23
23
|
property: string;
|
|
@@ -36,36 +36,36 @@ export interface ElysiaValidationError {
|
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
38
|
* Base Validation Pipe
|
|
39
|
-
* Handles
|
|
39
|
+
* Handles WynkJS validation errors and formats them
|
|
40
40
|
*/
|
|
41
41
|
export declare class ValidationPipe implements ValidationPipeTransform {
|
|
42
42
|
protected options: {
|
|
43
|
-
exceptionFactory?: (errors:
|
|
43
|
+
exceptionFactory?: (errors: WynkJSValidationError) => any;
|
|
44
44
|
transform?: boolean;
|
|
45
45
|
whitelist?: boolean;
|
|
46
46
|
};
|
|
47
47
|
constructor(options?: {
|
|
48
|
-
exceptionFactory?: (errors:
|
|
48
|
+
exceptionFactory?: (errors: WynkJSValidationError) => any;
|
|
49
49
|
transform?: boolean;
|
|
50
50
|
whitelist?: boolean;
|
|
51
51
|
});
|
|
52
52
|
/**
|
|
53
|
-
* Transform method (not used for
|
|
53
|
+
* Transform method (not used for WynkJS validation, but required by interface)
|
|
54
54
|
*/
|
|
55
55
|
transform(value: any, metadata: ArgumentMetadata): any;
|
|
56
56
|
/**
|
|
57
|
-
* Format
|
|
57
|
+
* Format WynkJS validation error
|
|
58
58
|
* This is called by the exception filter
|
|
59
59
|
*/
|
|
60
60
|
formatError(exception: any): any;
|
|
61
61
|
/**
|
|
62
|
-
* Parse
|
|
62
|
+
* Parse WynkJS validation error from exception
|
|
63
63
|
*/
|
|
64
|
-
protected parseValidationError(exception: any):
|
|
64
|
+
protected parseValidationError(exception: any): WynkJSValidationError;
|
|
65
65
|
/**
|
|
66
66
|
* Default error formatting with custom errorMessage support
|
|
67
67
|
*/
|
|
68
|
-
protected defaultFormatError(error:
|
|
68
|
+
protected defaultFormatError(error: WynkJSValidationError, schemaKey?: string): any;
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
71
|
* Custom Format Error Pipe
|
|
@@ -2,7 +2,7 @@ import "reflect-metadata";
|
|
|
2
2
|
import { schemaRegistry } from "../schema-registry";
|
|
3
3
|
/**
|
|
4
4
|
* Base Validation Pipe
|
|
5
|
-
* Handles
|
|
5
|
+
* Handles WynkJS validation errors and formats them
|
|
6
6
|
*/
|
|
7
7
|
export class ValidationPipe {
|
|
8
8
|
options;
|
|
@@ -10,13 +10,13 @@ export class ValidationPipe {
|
|
|
10
10
|
this.options = options || {};
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Transform method (not used for
|
|
13
|
+
* Transform method (not used for WynkJS validation, but required by interface)
|
|
14
14
|
*/
|
|
15
15
|
transform(value, metadata) {
|
|
16
16
|
return value;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* Format
|
|
19
|
+
* Format WynkJS validation error
|
|
20
20
|
* This is called by the exception filter
|
|
21
21
|
*/
|
|
22
22
|
formatError(exception) {
|
|
@@ -30,7 +30,7 @@ export class ValidationPipe {
|
|
|
30
30
|
return this.defaultFormatError(validationError);
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
* Parse
|
|
33
|
+
* Parse WynkJS validation error from exception
|
|
34
34
|
*/
|
|
35
35
|
parseValidationError(exception) {
|
|
36
36
|
let validationData;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compression Plugin Options
|
|
3
|
+
*/
|
|
4
|
+
export interface CompressionOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Minimum byte size for compression
|
|
7
|
+
* @default 1024
|
|
8
|
+
*/
|
|
9
|
+
threshold?: number;
|
|
10
|
+
/**
|
|
11
|
+
* Preferred encoding order (first match will be used)
|
|
12
|
+
* @default ["br", "gzip", "deflate"]
|
|
13
|
+
*/
|
|
14
|
+
encodings?: ("br" | "gzip" | "deflate")[];
|
|
15
|
+
/**
|
|
16
|
+
* Brotli compression options
|
|
17
|
+
*/
|
|
18
|
+
brotliOptions?: {
|
|
19
|
+
params?: Record<number, number>;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Zlib (gzip/deflate) compression options
|
|
23
|
+
*/
|
|
24
|
+
zlibOptions?: {
|
|
25
|
+
level?: number;
|
|
26
|
+
memLevel?: number;
|
|
27
|
+
strategy?: number;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compression Plugin for WynkJS
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import { WynkFactory } from "wynkjs";
|
|
36
|
+
* import { compression } from "wynkjs/plugins/compression";
|
|
37
|
+
*
|
|
38
|
+
* const app = WynkFactory.create({
|
|
39
|
+
* controllers: [UserController],
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* // Add compression middleware
|
|
43
|
+
* app.use(compression({
|
|
44
|
+
* threshold: 1024,
|
|
45
|
+
* encodings: ["br", "gzip", "deflate"]
|
|
46
|
+
* }));
|
|
47
|
+
*
|
|
48
|
+
* await app.listen(3000);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* Compression Plugin for WynkJS
|
|
53
|
+
*
|
|
54
|
+
* Simple compression middleware using Elysia's onAfterHandle hook
|
|
55
|
+
* Supports Brotli, Gzip, and Deflate compression
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* import { WynkFactory, compression } from "wynkjs";
|
|
60
|
+
*
|
|
61
|
+
* const app = WynkFactory.create({
|
|
62
|
+
* controllers: [UserController],
|
|
63
|
+
* });
|
|
64
|
+
*
|
|
65
|
+
* // Add compression middleware
|
|
66
|
+
* app.use(compression({
|
|
67
|
+
* threshold: 1024,
|
|
68
|
+
* encodings: ["gzip", "br"]
|
|
69
|
+
* }));
|
|
70
|
+
*
|
|
71
|
+
* await app.listen(3000);
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function compression(options?: CompressionOptions): (app: any) => any;
|
|
75
|
+
//# sourceMappingURL=compression.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compression.d.ts","sourceRoot":"","sources":["../../core/plugins/compression.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;IAE1C;;OAEG;IACH,aAAa,CAAC,EAAE;QACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACjC,CAAC;IAEF;;OAEG;IACH,WAAW,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CACzB,OAAO,GAAE,kBAAuB,GAC/B,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,CA4FnB"}
|