wynkjs 1.0.3 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +528 -348
  2. package/dist/cors.d.ts +28 -0
  3. package/dist/cors.d.ts.map +1 -0
  4. package/dist/cors.js +121 -0
  5. package/dist/database.d.ts +1 -1
  6. package/dist/database.js +1 -1
  7. package/dist/decorators/exception.advanced.d.ts +286 -18
  8. package/dist/decorators/exception.advanced.d.ts.map +1 -1
  9. package/dist/decorators/exception.advanced.js +410 -17
  10. package/dist/decorators/exception.decorators.d.ts +93 -2
  11. package/dist/decorators/exception.decorators.d.ts.map +1 -1
  12. package/dist/decorators/exception.decorators.js +140 -8
  13. package/dist/decorators/formatter.decorators.d.ts +93 -0
  14. package/dist/decorators/formatter.decorators.d.ts.map +1 -0
  15. package/dist/decorators/formatter.decorators.js +131 -0
  16. package/dist/decorators/guard.decorators.d.ts +2 -2
  17. package/dist/decorators/guard.decorators.d.ts.map +1 -1
  18. package/dist/decorators/guard.decorators.js +11 -5
  19. package/dist/decorators/http.decorators.d.ts +10 -4
  20. package/dist/decorators/http.decorators.d.ts.map +1 -1
  21. package/dist/decorators/http.decorators.js +9 -2
  22. package/dist/decorators/interceptor.advanced.d.ts +9 -9
  23. package/dist/decorators/interceptor.advanced.d.ts.map +1 -1
  24. package/dist/decorators/interceptor.advanced.js +7 -7
  25. package/dist/decorators/interceptor.decorators.d.ts +9 -7
  26. package/dist/decorators/interceptor.decorators.d.ts.map +1 -1
  27. package/dist/decorators/interceptor.decorators.js +29 -18
  28. package/dist/decorators/param.decorators.d.ts +2 -2
  29. package/dist/decorators/param.decorators.js +1 -1
  30. package/dist/decorators/pipe.decorators.d.ts +4 -4
  31. package/dist/decorators/pipe.decorators.d.ts.map +1 -1
  32. package/dist/decorators/pipe.decorators.js +4 -4
  33. package/dist/dto.js +1 -1
  34. package/dist/factory.d.ts +30 -2
  35. package/dist/factory.d.ts.map +1 -1
  36. package/dist/factory.js +210 -186
  37. package/dist/filters/exception.filters.d.ts +124 -0
  38. package/dist/filters/exception.filters.d.ts.map +1 -0
  39. package/dist/filters/exception.filters.js +208 -0
  40. package/dist/global-prefix.d.ts +49 -0
  41. package/dist/global-prefix.d.ts.map +1 -0
  42. package/dist/global-prefix.js +155 -0
  43. package/dist/index.d.ts +7 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +6 -1
  46. package/dist/interfaces/interceptor.interface.d.ts +15 -0
  47. package/dist/interfaces/interceptor.interface.d.ts.map +1 -0
  48. package/dist/interfaces/interceptor.interface.js +1 -0
  49. package/dist/optimized-handler.d.ts +31 -0
  50. package/dist/optimized-handler.d.ts.map +1 -0
  51. package/dist/optimized-handler.js +180 -0
  52. package/dist/pipes/validation.pipe.d.ts +12 -12
  53. package/dist/pipes/validation.pipe.d.ts.map +1 -1
  54. package/dist/pipes/validation.pipe.js +43 -15
  55. package/dist/schema-registry.d.ts +51 -0
  56. package/dist/schema-registry.d.ts.map +1 -0
  57. package/dist/schema-registry.js +134 -0
  58. package/dist/testing/index.d.ts +2 -2
  59. package/dist/testing/index.js +2 -2
  60. package/dist/ultra-optimized-handler.d.ts +51 -0
  61. package/dist/ultra-optimized-handler.d.ts.map +1 -0
  62. package/dist/ultra-optimized-handler.js +302 -0
  63. package/package.json +17 -10
@@ -0,0 +1,302 @@
1
+ /**
2
+ * ULTRA-OPTIMIZED Handler Builder for WynkJS
3
+ *
4
+ * KEY OPTIMIZATION: Eliminate nested async/await and IIFEs
5
+ *
6
+ * Performance findings:
7
+ * - Direct sync: 32ms per 1M calls
8
+ * - Single async: 42ms per 1M calls
9
+ * - Nested async + IIFE: 232ms per 1M calls (5.7x SLOWER!)
10
+ *
11
+ * Root cause: The current pattern creates an IIFE for every request:
12
+ * return (async () => { try { ... } catch { ... } })();
13
+ *
14
+ * This creates massive overhead because:
15
+ * 1. Creates a new Promise on EVERY request
16
+ * 2. Wraps it in a try-catch block
17
+ * 3. Immediately invokes it (IIFE pattern)
18
+ * 4. Then awaits the result
19
+ *
20
+ * Solution: Build a SINGLE async function at registration time,
21
+ * not nested functions that get called on every request.
22
+ */
23
+ import { createExecutionContext, executeGuards, } from "./decorators/guard.decorators";
24
+ import { executeInterceptors } from "./decorators/interceptor.decorators";
25
+ import { executePipes } from "./decorators/pipe.decorators";
26
+ import { executeExceptionFilters, HttpException, } from "./decorators/exception.decorators";
27
+ /**
28
+ * Ultra-optimized handler builder
29
+ * Builds a SINGLE async function, not nested closures
30
+ */
31
+ export function buildUltraOptimizedHandler(options) {
32
+ const { instance, methodName, ControllerClass, params, allGuards, allInterceptors, allPipes, allFilters, httpCode, headers, redirect, routePath, routeMethod, } = options;
33
+ // Pre-sort params once during registration
34
+ if (params.length > 0) {
35
+ params.sort((a, b) => a.index - b.index);
36
+ }
37
+ // Determine which features are actually used
38
+ const hasGuards = allGuards.length > 0;
39
+ const hasInterceptors = allInterceptors.length > 0;
40
+ const hasPipes = allPipes.length > 0;
41
+ const hasFilters = allFilters.length > 0;
42
+ const hasParams = params.length > 0;
43
+ const hasResponseModifiers = !!(httpCode || headers || redirect);
44
+ // Build specialized handler based on what's actually needed
45
+ // This eliminates ALL conditional checks at runtime
46
+ // CASE 1: Absolute minimal - no features at all (like /health endpoint)
47
+ if (!hasGuards &&
48
+ !hasInterceptors &&
49
+ !hasPipes &&
50
+ !hasFilters &&
51
+ !hasParams &&
52
+ !hasResponseModifiers) {
53
+ // Direct call - zero overhead!
54
+ return async (ctx) => {
55
+ return await instance[methodName](ctx);
56
+ };
57
+ }
58
+ // CASE 2: Has params but no other features
59
+ if (!hasGuards &&
60
+ !hasInterceptors &&
61
+ !hasFilters &&
62
+ !hasResponseModifiers &&
63
+ hasParams) {
64
+ return async (ctx) => {
65
+ const args = new Array(params.length);
66
+ for (const param of params) {
67
+ let value;
68
+ switch (param.type) {
69
+ case "body":
70
+ value = param.data ? ctx.body?.[param.data] : ctx.body;
71
+ break;
72
+ case "param":
73
+ value = param.data ? ctx.params?.[param.data] : ctx.params;
74
+ break;
75
+ case "query":
76
+ value = param.data ? ctx.query?.[param.data] : ctx.query;
77
+ break;
78
+ case "headers":
79
+ value = param.data
80
+ ? ctx.headers?.get?.(param.data) ||
81
+ ctx.request?.headers?.get?.(param.data)
82
+ : ctx.headers || ctx.request?.headers;
83
+ break;
84
+ case "request":
85
+ value = ctx.request || ctx;
86
+ break;
87
+ case "response":
88
+ value = ctx.set || ctx.response;
89
+ break;
90
+ case "context":
91
+ if (param.data) {
92
+ const keys = param.data.split(".");
93
+ value = keys.reduce((obj, key) => obj?.[key], ctx);
94
+ }
95
+ else {
96
+ value = ctx;
97
+ }
98
+ break;
99
+ case "user":
100
+ value = param.data ? ctx.user?.[param.data] : ctx.user;
101
+ break;
102
+ case "file":
103
+ value = ctx.body?.file || ctx.file;
104
+ break;
105
+ case "files":
106
+ value = ctx.body?.files || ctx.files;
107
+ break;
108
+ }
109
+ // Apply pipes if any
110
+ if (hasPipes) {
111
+ const metadata = {
112
+ type: param.type,
113
+ data: param.data,
114
+ };
115
+ value = await executePipes(allPipes, value, metadata);
116
+ }
117
+ if (param.pipes && param.pipes.length > 0) {
118
+ const metadata = {
119
+ type: param.type,
120
+ data: param.data,
121
+ };
122
+ value = await executePipes(param.pipes, value, metadata);
123
+ }
124
+ args[param.index] = value;
125
+ }
126
+ return await instance[methodName].apply(instance, args);
127
+ };
128
+ }
129
+ // CASE 3: Full-featured handler (has guards/interceptors/filters)
130
+ // This is where we MUST use try-catch, but still avoid nested async
131
+ return async (ctx) => {
132
+ try {
133
+ // Guards
134
+ if (hasGuards) {
135
+ const executionContext = createExecutionContext(ctx, instance[methodName], ControllerClass);
136
+ // Add route metadata
137
+ executionContext.path = routePath;
138
+ executionContext.method = routeMethod;
139
+ executionContext.request = ctx.request || ctx;
140
+ executionContext.body = ctx.body;
141
+ executionContext.params = ctx.params;
142
+ executionContext.query = ctx.query;
143
+ executionContext.headers = ctx.headers || ctx.request?.headers;
144
+ const canActivate = await executeGuards(allGuards, executionContext);
145
+ if (!canActivate) {
146
+ throw new HttpException("Forbidden", 403, "Access denied");
147
+ }
148
+ }
149
+ // Prepare the actual handler execution
150
+ const executeMethod = async () => {
151
+ if (!hasParams) {
152
+ return await instance[methodName](ctx);
153
+ }
154
+ const args = new Array(params.length);
155
+ for (const param of params) {
156
+ let value;
157
+ switch (param.type) {
158
+ case "body":
159
+ value = param.data ? ctx.body?.[param.data] : ctx.body;
160
+ break;
161
+ case "param":
162
+ value = param.data ? ctx.params?.[param.data] : ctx.params;
163
+ break;
164
+ case "query":
165
+ value = param.data ? ctx.query?.[param.data] : ctx.query;
166
+ break;
167
+ case "headers":
168
+ value = param.data
169
+ ? ctx.headers?.get?.(param.data) ||
170
+ ctx.request?.headers?.get?.(param.data)
171
+ : ctx.headers || ctx.request?.headers;
172
+ break;
173
+ case "request":
174
+ value = ctx.request || ctx;
175
+ break;
176
+ case "response":
177
+ value = ctx.set || ctx.response;
178
+ break;
179
+ case "context":
180
+ if (param.data) {
181
+ const keys = param.data.split(".");
182
+ value = keys.reduce((obj, key) => obj?.[key], ctx);
183
+ }
184
+ else {
185
+ value = ctx;
186
+ }
187
+ break;
188
+ case "user":
189
+ value = param.data ? ctx.user?.[param.data] : ctx.user;
190
+ break;
191
+ case "file":
192
+ value = ctx.body?.file || ctx.file;
193
+ break;
194
+ case "files":
195
+ value = ctx.body?.files || ctx.files;
196
+ break;
197
+ }
198
+ if (hasPipes) {
199
+ const metadata = {
200
+ type: param.type,
201
+ data: param.data,
202
+ };
203
+ value = await executePipes(allPipes, value, metadata);
204
+ }
205
+ if (param.pipes && param.pipes.length > 0) {
206
+ const metadata = {
207
+ type: param.type,
208
+ data: param.data,
209
+ };
210
+ value = await executePipes(param.pipes, value, metadata);
211
+ }
212
+ args[param.index] = value;
213
+ }
214
+ return await instance[methodName].apply(instance, args);
215
+ };
216
+ // Interceptors
217
+ let result;
218
+ if (hasInterceptors) {
219
+ const executionContext = createExecutionContext(ctx, instance[methodName], ControllerClass);
220
+ // Add route metadata
221
+ executionContext.path = routePath;
222
+ executionContext.method = routeMethod;
223
+ executionContext.request = ctx.request || ctx;
224
+ executionContext.body = ctx.body;
225
+ executionContext.params = ctx.params;
226
+ executionContext.query = ctx.query;
227
+ executionContext.headers = ctx.headers || ctx.request?.headers;
228
+ result = await executeInterceptors(allInterceptors, executionContext, executeMethod);
229
+ }
230
+ else {
231
+ result = await executeMethod();
232
+ }
233
+ // Response modifiers
234
+ if (hasResponseModifiers) {
235
+ if (redirect) {
236
+ ctx.set.redirect = redirect.url;
237
+ ctx.set.status = redirect.statusCode;
238
+ return;
239
+ }
240
+ if (httpCode) {
241
+ ctx.set.status = httpCode;
242
+ }
243
+ if (headers) {
244
+ Object.entries(headers).forEach(([key, value]) => {
245
+ ctx.set.headers[key] = value;
246
+ });
247
+ }
248
+ }
249
+ return result;
250
+ }
251
+ catch (error) {
252
+ // Exception filters (only if configured)
253
+ if (hasFilters) {
254
+ const executionContext = createExecutionContext(ctx, instance[methodName], ControllerClass);
255
+ // Add route metadata
256
+ executionContext.path = routePath;
257
+ executionContext.method = routeMethod;
258
+ executionContext.request = ctx.request || ctx;
259
+ executionContext.body = ctx.body;
260
+ executionContext.params = ctx.params;
261
+ executionContext.query = ctx.query;
262
+ executionContext.headers = ctx.headers || ctx.request?.headers;
263
+ try {
264
+ const result = await executeExceptionFilters(allFilters, error, executionContext);
265
+ if (result) {
266
+ if (result.statusCode) {
267
+ ctx.set.status = result.statusCode;
268
+ }
269
+ return result;
270
+ }
271
+ }
272
+ catch (filterError) {
273
+ error = filterError;
274
+ }
275
+ }
276
+ // Default error handling
277
+ if (error instanceof HttpException) {
278
+ ctx.set.status = error.getStatus();
279
+ return error.getResponse();
280
+ }
281
+ ctx.set.status = 500;
282
+ return {
283
+ statusCode: 500,
284
+ message: error.message || "Internal server error",
285
+ error: "Internal Server Error",
286
+ };
287
+ }
288
+ };
289
+ }
290
+ /**
291
+ * Build middleware chain - same as before
292
+ */
293
+ export function buildMiddlewareChain(handler, middlewares) {
294
+ if (middlewares.length === 0) {
295
+ return handler;
296
+ }
297
+ return middlewares.reduceRight((next, middleware) => {
298
+ return async (ctx) => {
299
+ return await middleware(ctx, () => next(ctx));
300
+ };
301
+ }, handler);
302
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "wynkjs",
3
- "version": "1.0.3",
4
- "description": "A high-performance TypeScript framework built on Elysia for Bun with NestJS-style decorators - 20x faster than Express",
3
+ "version": "1.0.6",
4
+ "description": "A high-performance TypeScript framework built on Elysia for Bun with elegant decorator-based architecture - 10x faster than Express/NestJS",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -10,6 +10,10 @@
10
10
  "wynk",
11
11
  "wynkjs",
12
12
  "elysia",
13
+ "nestjs",
14
+ "nestjs alternative",
15
+ "express",
16
+ "expressjs alternative",
13
17
  "bun",
14
18
  "framework",
15
19
  "typescript",
@@ -18,7 +22,8 @@
18
22
  "web-framework",
19
23
  "http",
20
24
  "api",
21
- "nestjs-alternative",
25
+ "bun-framework",
26
+ "typescript-decorators",
22
27
  "dependency-injection",
23
28
  "rest-api",
24
29
  "backend",
@@ -37,15 +42,14 @@
37
42
  "scripts": {
38
43
  "build": "tsc",
39
44
  "prepublishOnly": "npm run build",
40
- "test": "bun test"
41
- },
42
- "peerDependencies": {
43
- "elysia": "^1.0.0",
44
- "reflect-metadata": "^0.2.2"
45
+ "test": "bun test",
46
+ "test:all": "bun test tests/",
47
+ "test:core": "bash tests/test-core.sh",
48
+ "test:watch": "bun test tests/ --watch",
49
+ "test:coverage": "bun test tests/ --coverage"
45
50
  },
51
+ "peerDependencies": {},
46
52
  "devDependencies": {
47
- "elysia": "^1.0.0",
48
- "reflect-metadata": "^0.2.2",
49
53
  "@types/bun": "latest",
50
54
  "typescript": "^5.0.0"
51
55
  },
@@ -64,6 +68,9 @@
64
68
  "LICENSE"
65
69
  ],
66
70
  "dependencies": {
71
+ "elysia": "^1.0.0",
72
+ "reflect-metadata": "^0.2.2",
73
+ "@elysiajs/cors": "^1.4.0",
67
74
  "tsyringe": "^4.10.0"
68
75
  }
69
76
  }