wynkjs 1.0.7 → 1.0.8

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 CHANGED
@@ -573,6 +573,82 @@ export function myPlugin(options = {}) {
573
573
  app.use(myPlugin({ option: "value" }));
574
574
  ```
575
575
 
576
+ #### Swagger / OpenAPI Documentation
577
+
578
+ **✨ New Feature**: WynkJS can use Elysia's Swagger plugin for automatic API documentation!
579
+
580
+ Since WynkJS is built on top of Elysia, you can use the official `@elysiajs/swagger` plugin to generate interactive API documentation from your WynkJS decorators.
581
+
582
+ ```bash
583
+ bun add @elysiajs/swagger
584
+ ```
585
+
586
+ ```typescript
587
+ import { WynkFactory } from "wynkjs";
588
+ import { swagger } from "@elysiajs/swagger";
589
+
590
+ const app = WynkFactory.create({
591
+ controllers: [UserController, ProductController],
592
+ });
593
+
594
+ const server = await app.build();
595
+
596
+ // Add Swagger documentation
597
+ server.use(
598
+ swagger({
599
+ documentation: {
600
+ info: {
601
+ title: "My API Documentation",
602
+ version: "1.0.0",
603
+ description: "Auto-generated from WynkJS decorators",
604
+ },
605
+ tags: [
606
+ { name: "users", description: "User management" },
607
+ { name: "products", description: "Product catalog" },
608
+ ],
609
+ },
610
+ path: "/docs",
611
+ })
612
+ );
613
+
614
+ server.listen(3000);
615
+ // 📚 Visit: http://localhost:3000/docs
616
+ ```
617
+
618
+ **What gets auto-documented:**
619
+
620
+ ✅ All HTTP routes (@Get, @Post, etc.)
621
+ ✅ Query parameters (from DTOs)
622
+ ✅ Request body schemas (from DTOs)
623
+ ✅ Path parameters (from DTOs)
624
+ ✅ Validation rules (min, max, format)
625
+ ✅ JWT Authentication support
626
+
627
+ **With JWT Authentication:**
628
+
629
+ ```typescript
630
+ server.use(
631
+ swagger({
632
+ documentation: {
633
+ info: { title: "Secure API", version: "1.0.0" },
634
+ components: {
635
+ securitySchemes: {
636
+ bearerAuth: {
637
+ type: "http",
638
+ scheme: "bearer",
639
+ bearerFormat: "JWT",
640
+ },
641
+ },
642
+ },
643
+ security: [{ bearerAuth: [] }],
644
+ },
645
+ path: "/docs",
646
+ })
647
+ );
648
+ ```
649
+
650
+ 📚 See [Swagger Integration Guide](./docs/SWAGGER_INTEGRATION.md) for complete examples and best practices.
651
+
576
652
  ### �🔒 Authentication with Guards
577
653
 
578
654
  ```typescript
package/dist/index.d.ts CHANGED
@@ -21,6 +21,13 @@ export * from "./decorators/formatter.decorators";
21
21
  export * from "./filters/exception.filters";
22
22
  export * from "./decorators/database.decorators";
23
23
  export * from "./dto";
24
+ export { Request } from "./request";
25
+ export { Response } from "./response";
26
+ export type { WynkRequest } from "./request";
27
+ export type { WynkResponse } from "./response";
28
+ export type { CookieOptions } from "./response";
29
+ export type { Request as RequestType } from "./request";
30
+ export type { Response as ResponseType } from "./response";
24
31
  export { schemaRegistry } from "./schema-registry";
25
32
  export * from "./factory";
26
33
  export type { CorsOptions } from "./cors";
@@ -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,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"}
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,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,YAAY,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACxD,YAAY,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,YAAY,CAAC;AAG3D,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
@@ -40,6 +40,9 @@ export * from "./decorators/database.decorators";
40
40
  // See: plugins/drizzle and plugins/mongoose
41
41
  // DTO Utilities
42
42
  export * from "./dto";
43
+ // Request and Response wrappers
44
+ export { Request } from "./request";
45
+ export { Response } from "./response";
43
46
  // Schema Registry for custom error messages
44
47
  export { schemaRegistry } from "./schema-registry";
45
48
  // Application Factory
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Request Wrapper for WynkJS Framework
3
+ * Provides a clean API for accessing request data and adding custom properties
4
+ */
5
+ export interface CookieOptions {
6
+ domain?: string;
7
+ expires?: Date;
8
+ httpOnly?: boolean;
9
+ maxAge?: number;
10
+ path?: string;
11
+ sameSite?: boolean | "lax" | "strict" | "none";
12
+ secure?: boolean;
13
+ priority?: "low" | "medium" | "high";
14
+ partitioned?: boolean;
15
+ }
16
+ /**
17
+ * Request class - wraps Elysia context for request operations
18
+ * Allows middleware to add custom properties that persist through the request lifecycle
19
+ */
20
+ export declare class Request {
21
+ private ctx;
22
+ private customData;
23
+ private originalRequest;
24
+ constructor(ctx: any);
25
+ /**
26
+ * Get request body
27
+ */
28
+ get body(): any;
29
+ /**
30
+ * Get route parameters
31
+ */
32
+ get params(): any;
33
+ /**
34
+ * Get query parameters
35
+ */
36
+ get query(): any;
37
+ /**
38
+ * Get request headers
39
+ */
40
+ get headers(): any;
41
+ /**
42
+ * Get request method (GET, POST, etc.)
43
+ */
44
+ get method(): string;
45
+ /**
46
+ * Get request URL
47
+ */
48
+ get url(): string;
49
+ /**
50
+ * Get request path
51
+ */
52
+ get path(): string;
53
+ /**
54
+ * Get client IP address
55
+ */
56
+ get ip(): string | undefined;
57
+ /**
58
+ * Get cookies from request
59
+ */
60
+ get cookies(): Record<string, string>;
61
+ /**
62
+ * Get a specific cookie value
63
+ */
64
+ getCookie(name: string): string | undefined;
65
+ /**
66
+ * Get user object (set by authentication middleware)
67
+ */
68
+ get user(): any;
69
+ /**
70
+ * Set user object (typically used by authentication middleware)
71
+ */
72
+ set user(value: any);
73
+ /**
74
+ * Get the raw Elysia context
75
+ */
76
+ get raw(): any;
77
+ /**
78
+ * Get the Response wrapper instance
79
+ */
80
+ getResponse(): any;
81
+ /**
82
+ * Set custom data that persists through request lifecycle
83
+ * Useful for middleware to pass data to handlers
84
+ *
85
+ * @example
86
+ * // In middleware
87
+ * request.set('startTime', Date.now());
88
+ *
89
+ * // In handler
90
+ * const startTime = request.get('startTime');
91
+ */
92
+ set(key: string, value: any): this;
93
+ /**
94
+ * Get custom data set by middleware
95
+ */
96
+ get(key: string): any;
97
+ /**
98
+ * Check if custom data exists
99
+ */
100
+ has(key: string): boolean;
101
+ /**
102
+ * Delete custom data
103
+ */
104
+ delete(key: string): boolean;
105
+ /**
106
+ * Get all custom data
107
+ */
108
+ getAllCustomData(): Record<string, any>;
109
+ /**
110
+ * Check if request accepts a certain content type
111
+ */
112
+ accepts(type: string): boolean;
113
+ /**
114
+ * Check if request is JSON
115
+ */
116
+ isJson(): boolean;
117
+ /**
118
+ * Check if request is form data
119
+ */
120
+ isFormData(): boolean;
121
+ /**
122
+ * Get bearer token from Authorization header
123
+ */
124
+ getBearerToken(): string | undefined;
125
+ }
126
+ export type WynkRequest = Request;
127
+ //# sourceMappingURL=request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../core/request.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,eAAe,CAAM;gBAEjB,GAAG,EAAE,GAAG;IAMpB;;OAEG;IACH,IAAI,IAAI,IAAI,GAAG,CAEd;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,GAAG,CAEhB;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,GAAG,CAEf;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,GAAG,CAoBjB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;OAEG;IACH,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,IAAI,EAAE,IAAI,MAAM,GAAG,SAAS,CAM3B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAapC;IAED;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3C;;OAEG;IACH,IAAI,IAAI,IAAI,GAAG,CAEd;IAED;;OAEG;IACH,IAAI,IAAI,CAAC,KAAK,EAAE,GAAG,EAElB;IAED;;OAEG;IACH,IAAI,GAAG,IAAI,GAAG,CAEb;IAED;;OAEG;IACH,WAAW,IAAI,GAAG;IAIlB;;;;;;;;;;OAUG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAUlC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG;IAIrB;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAQ5B;;OAEG;IACH,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAQvC;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAK9B;;OAEG;IACH,MAAM,IAAI,OAAO;IAKjB;;OAEG;IACH,UAAU,IAAI,OAAO;IAKrB;;OAEG;IACH,cAAc,IAAI,MAAM,GAAG,SAAS;CAOrC;AAGD,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC"}
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Request Wrapper for WynkJS Framework
3
+ * Provides a clean API for accessing request data and adding custom properties
4
+ */
5
+ /**
6
+ * Request class - wraps Elysia context for request operations
7
+ * Allows middleware to add custom properties that persist through the request lifecycle
8
+ */
9
+ export class Request {
10
+ ctx;
11
+ customData = new Map();
12
+ originalRequest;
13
+ constructor(ctx) {
14
+ this.ctx = ctx;
15
+ // Store reference to original request object before it gets overwritten
16
+ this.originalRequest = ctx.request;
17
+ }
18
+ /**
19
+ * Get request body
20
+ */
21
+ get body() {
22
+ return this.ctx.body;
23
+ }
24
+ /**
25
+ * Get route parameters
26
+ */
27
+ get params() {
28
+ return this.ctx.params;
29
+ }
30
+ /**
31
+ * Get query parameters
32
+ */
33
+ get query() {
34
+ return this.ctx.query;
35
+ }
36
+ /**
37
+ * Get request headers
38
+ */
39
+ get headers() {
40
+ // Get headers from ctx or from the original Elysia request object
41
+ const headers = this.ctx.headers || this.originalRequest?.headers;
42
+ if (!headers)
43
+ return {};
44
+ // If headers is a plain object, wrap it to provide get() method
45
+ if (typeof headers === 'object' && !headers.get) {
46
+ return {
47
+ ...headers,
48
+ get(name) {
49
+ return headers[name] || headers[name.toLowerCase()];
50
+ },
51
+ has(name) {
52
+ return name in headers || name.toLowerCase() in headers;
53
+ }
54
+ };
55
+ }
56
+ return headers;
57
+ }
58
+ /**
59
+ * Get request method (GET, POST, etc.)
60
+ */
61
+ get method() {
62
+ return this.originalRequest?.method || this.ctx.method || "GET";
63
+ }
64
+ /**
65
+ * Get request URL
66
+ */
67
+ get url() {
68
+ return this.originalRequest?.url || this.ctx.url || "";
69
+ }
70
+ /**
71
+ * Get request path
72
+ */
73
+ get path() {
74
+ return this.ctx.path || new URL(this.url).pathname;
75
+ }
76
+ /**
77
+ * Get client IP address
78
+ */
79
+ get ip() {
80
+ return (this.headers.get?.("x-forwarded-for") ||
81
+ this.headers.get?.("x-real-ip") ||
82
+ this.originalRequest?.ip);
83
+ }
84
+ /**
85
+ * Get cookies from request
86
+ */
87
+ get cookies() {
88
+ const cookieHeader = this.headers.get?.("cookie");
89
+ if (!cookieHeader)
90
+ return {};
91
+ const cookies = {};
92
+ cookieHeader.split(";").forEach((cookie) => {
93
+ const [name, ...rest] = cookie.split("=");
94
+ if (name && rest.length > 0) {
95
+ cookies[name.trim()] = rest.join("=").trim();
96
+ }
97
+ });
98
+ return cookies;
99
+ }
100
+ /**
101
+ * Get a specific cookie value
102
+ */
103
+ getCookie(name) {
104
+ return this.cookies[name];
105
+ }
106
+ /**
107
+ * Get user object (set by authentication middleware)
108
+ */
109
+ get user() {
110
+ return this.ctx.user;
111
+ }
112
+ /**
113
+ * Set user object (typically used by authentication middleware)
114
+ */
115
+ set user(value) {
116
+ this.ctx.user = value;
117
+ }
118
+ /**
119
+ * Get the raw Elysia context
120
+ */
121
+ get raw() {
122
+ return this.ctx;
123
+ }
124
+ /**
125
+ * Get the Response wrapper instance
126
+ */
127
+ getResponse() {
128
+ return this.ctx.response;
129
+ }
130
+ /**
131
+ * Set custom data that persists through request lifecycle
132
+ * Useful for middleware to pass data to handlers
133
+ *
134
+ * @example
135
+ * // In middleware
136
+ * request.set('startTime', Date.now());
137
+ *
138
+ * // In handler
139
+ * const startTime = request.get('startTime');
140
+ */
141
+ set(key, value) {
142
+ this.customData.set(key, value);
143
+ // Also set on ctx for backward compatibility
144
+ if (!this.ctx.customData) {
145
+ this.ctx.customData = {};
146
+ }
147
+ this.ctx.customData[key] = value;
148
+ return this;
149
+ }
150
+ /**
151
+ * Get custom data set by middleware
152
+ */
153
+ get(key) {
154
+ return this.customData.get(key) || this.ctx.customData?.[key];
155
+ }
156
+ /**
157
+ * Check if custom data exists
158
+ */
159
+ has(key) {
160
+ return this.customData.has(key) || (this.ctx.customData && key in this.ctx.customData);
161
+ }
162
+ /**
163
+ * Delete custom data
164
+ */
165
+ delete(key) {
166
+ const deleted = this.customData.delete(key);
167
+ if (this.ctx.customData && key in this.ctx.customData) {
168
+ delete this.ctx.customData[key];
169
+ }
170
+ return deleted;
171
+ }
172
+ /**
173
+ * Get all custom data
174
+ */
175
+ getAllCustomData() {
176
+ const data = {};
177
+ this.customData.forEach((value, key) => {
178
+ data[key] = value;
179
+ });
180
+ return { ...data, ...this.ctx.customData };
181
+ }
182
+ /**
183
+ * Check if request accepts a certain content type
184
+ */
185
+ accepts(type) {
186
+ const acceptHeader = this.headers.get?.("accept") || "";
187
+ return acceptHeader.includes(type);
188
+ }
189
+ /**
190
+ * Check if request is JSON
191
+ */
192
+ isJson() {
193
+ const contentType = this.headers.get?.("content-type") || "";
194
+ return contentType.includes("application/json");
195
+ }
196
+ /**
197
+ * Check if request is form data
198
+ */
199
+ isFormData() {
200
+ const contentType = this.headers.get?.("content-type") || "";
201
+ return contentType.includes("multipart/form-data") || contentType.includes("application/x-www-form-urlencoded");
202
+ }
203
+ /**
204
+ * Get bearer token from Authorization header
205
+ */
206
+ getBearerToken() {
207
+ const authHeader = this.headers.get?.("authorization");
208
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
209
+ return undefined;
210
+ }
211
+ return authHeader.substring(7);
212
+ }
213
+ }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Response Wrapper for WynkJS Framework
3
+ * Provides a clean API for setting cookies, headers, status codes, and sending responses
4
+ */
5
+ export interface CookieOptions {
6
+ domain?: string;
7
+ expires?: Date;
8
+ httpOnly?: boolean;
9
+ maxAge?: number;
10
+ path?: string;
11
+ sameSite?: boolean | "lax" | "strict" | "none";
12
+ secure?: boolean;
13
+ priority?: "low" | "medium" | "high";
14
+ partitioned?: boolean;
15
+ }
16
+ /**
17
+ * Response class - wraps Elysia context for response operations
18
+ * Provides methods to set cookies, headers, status codes, and control response behavior
19
+ */
20
+ export declare class Response {
21
+ private ctx;
22
+ private _headers;
23
+ private _cookies;
24
+ private _status?;
25
+ constructor(ctx: any);
26
+ /**
27
+ * Set HTTP status code
28
+ */
29
+ status(code: number): this;
30
+ /**
31
+ * Get current status code
32
+ */
33
+ getStatus(): number;
34
+ /**
35
+ * Set a response header
36
+ */
37
+ header(name: string, value: string): this;
38
+ /**
39
+ * Set multiple headers at once
40
+ */
41
+ headers(headers: Record<string, string>): this;
42
+ /**
43
+ * Get a response header
44
+ */
45
+ getHeader(name: string): string | undefined;
46
+ /**
47
+ * Remove a response header
48
+ */
49
+ removeHeader(name: string): this;
50
+ /**
51
+ * Set a cookie
52
+ *
53
+ * @example
54
+ * response.cookie('sessionId', '12345', {
55
+ * httpOnly: true,
56
+ * secure: true,
57
+ * maxAge: 3600,
58
+ * sameSite: 'strict'
59
+ * });
60
+ */
61
+ cookie(name: string, value: string, options?: CookieOptions): this;
62
+ /**
63
+ * Clear a cookie by setting it to expire immediately
64
+ */
65
+ clearCookie(name: string, options?: Pick<CookieOptions, "domain" | "path">): this;
66
+ /**
67
+ * Get all cookies that have been set
68
+ */
69
+ getCookies(): Map<string, {
70
+ value: string;
71
+ options?: CookieOptions;
72
+ }>;
73
+ /**
74
+ * Send JSON response
75
+ */
76
+ json(data: any): any;
77
+ /**
78
+ * Send HTML response
79
+ */
80
+ html(content: string): string;
81
+ /**
82
+ * Send plain text response
83
+ */
84
+ text(content: string): string;
85
+ /**
86
+ * Redirect to a different URL
87
+ */
88
+ redirect(url: string, statusCode?: number): void;
89
+ /**
90
+ * Set content type
91
+ */
92
+ type(contentType: string): this;
93
+ /**
94
+ * Set cache control
95
+ */
96
+ cache(maxAge: number, options?: {
97
+ private?: boolean;
98
+ noCache?: boolean;
99
+ noStore?: boolean;
100
+ }): this;
101
+ /**
102
+ * Disable caching
103
+ */
104
+ noCache(): this;
105
+ /**
106
+ * Set CORS headers
107
+ */
108
+ cors(options?: {
109
+ origin?: string;
110
+ methods?: string[];
111
+ headers?: string[];
112
+ credentials?: boolean;
113
+ maxAge?: number;
114
+ }): this;
115
+ /**
116
+ * Get the raw Elysia set object
117
+ */
118
+ get raw(): any;
119
+ /**
120
+ * Send a file download
121
+ */
122
+ download(filename: string): this;
123
+ /**
124
+ * Send response with custom status code
125
+ */
126
+ send(data: any, statusCode?: number): any;
127
+ }
128
+ export type WynkResponse = Response;
129
+ //# sourceMappingURL=response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../core/response.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Response Wrapper for WynkJS Framework
3
+ * Provides a clean API for setting cookies, headers, status codes, and sending responses
4
+ */
5
+ /**
6
+ * Response class - wraps Elysia context for response operations
7
+ * Provides methods to set cookies, headers, status codes, and control response behavior
8
+ */
9
+ export class Response {
10
+ ctx;
11
+ _headers = new Map();
12
+ _cookies = new Map();
13
+ _status;
14
+ constructor(ctx) {
15
+ this.ctx = ctx;
16
+ // Initialize Elysia's set object if it doesn't exist
17
+ if (!this.ctx.set) {
18
+ this.ctx.set = {
19
+ headers: {},
20
+ status: 200,
21
+ };
22
+ }
23
+ if (!this.ctx.set.headers) {
24
+ this.ctx.set.headers = {};
25
+ }
26
+ }
27
+ /**
28
+ * Set HTTP status code
29
+ */
30
+ status(code) {
31
+ this._status = code;
32
+ this.ctx.set.status = code;
33
+ return this;
34
+ }
35
+ /**
36
+ * Get current status code
37
+ */
38
+ getStatus() {
39
+ return this._status || this.ctx.set.status || 200;
40
+ }
41
+ /**
42
+ * Set a response header
43
+ */
44
+ header(name, value) {
45
+ this._headers.set(name, value);
46
+ this.ctx.set.headers[name] = value;
47
+ return this;
48
+ }
49
+ /**
50
+ * Set multiple headers at once
51
+ */
52
+ headers(headers) {
53
+ Object.entries(headers).forEach(([name, value]) => {
54
+ this.header(name, value);
55
+ });
56
+ return this;
57
+ }
58
+ /**
59
+ * Get a response header
60
+ */
61
+ getHeader(name) {
62
+ return this._headers.get(name) || this.ctx.set.headers[name];
63
+ }
64
+ /**
65
+ * Remove a response header
66
+ */
67
+ removeHeader(name) {
68
+ this._headers.delete(name);
69
+ delete this.ctx.set.headers[name];
70
+ return this;
71
+ }
72
+ /**
73
+ * Set a cookie
74
+ *
75
+ * @example
76
+ * response.cookie('sessionId', '12345', {
77
+ * httpOnly: true,
78
+ * secure: true,
79
+ * maxAge: 3600,
80
+ * sameSite: 'strict'
81
+ * });
82
+ */
83
+ cookie(name, value, options) {
84
+ this._cookies.set(name, { value, options });
85
+ // Build cookie string
86
+ let cookieString = `${name}=${value}`;
87
+ if (options) {
88
+ if (options.domain) {
89
+ cookieString += `; Domain=${options.domain}`;
90
+ }
91
+ if (options.expires) {
92
+ cookieString += `; Expires=${options.expires.toUTCString()}`;
93
+ }
94
+ if (options.httpOnly) {
95
+ cookieString += "; HttpOnly";
96
+ }
97
+ if (options.maxAge !== undefined) {
98
+ cookieString += `; Max-Age=${options.maxAge}`;
99
+ }
100
+ if (options.path) {
101
+ cookieString += `; Path=${options.path}`;
102
+ }
103
+ else {
104
+ cookieString += "; Path=/"; // Default path
105
+ }
106
+ if (options.sameSite) {
107
+ const sameSiteValue = typeof options.sameSite === "boolean"
108
+ ? "Strict"
109
+ : options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1);
110
+ cookieString += `; SameSite=${sameSiteValue}`;
111
+ }
112
+ if (options.secure) {
113
+ cookieString += "; Secure";
114
+ }
115
+ if (options.priority) {
116
+ cookieString += `; Priority=${options.priority.charAt(0).toUpperCase() + options.priority.slice(1)}`;
117
+ }
118
+ if (options.partitioned) {
119
+ cookieString += "; Partitioned";
120
+ }
121
+ }
122
+ else {
123
+ cookieString += "; Path=/"; // Default path if no options
124
+ }
125
+ // Append to Set-Cookie header (can have multiple)
126
+ const existingSetCookie = this.ctx.set.headers["Set-Cookie"];
127
+ if (existingSetCookie) {
128
+ if (Array.isArray(existingSetCookie)) {
129
+ this.ctx.set.headers["Set-Cookie"] = [...existingSetCookie, cookieString];
130
+ }
131
+ else {
132
+ this.ctx.set.headers["Set-Cookie"] = [existingSetCookie, cookieString];
133
+ }
134
+ }
135
+ else {
136
+ this.ctx.set.headers["Set-Cookie"] = cookieString;
137
+ }
138
+ return this;
139
+ }
140
+ /**
141
+ * Clear a cookie by setting it to expire immediately
142
+ */
143
+ clearCookie(name, options) {
144
+ return this.cookie(name, "", {
145
+ ...options,
146
+ expires: new Date(0),
147
+ maxAge: 0,
148
+ });
149
+ }
150
+ /**
151
+ * Get all cookies that have been set
152
+ */
153
+ getCookies() {
154
+ return this._cookies;
155
+ }
156
+ /**
157
+ * Send JSON response
158
+ */
159
+ json(data) {
160
+ this.header("Content-Type", "application/json");
161
+ return data;
162
+ }
163
+ /**
164
+ * Send HTML response
165
+ */
166
+ html(content) {
167
+ this.header("Content-Type", "text/html");
168
+ return content;
169
+ }
170
+ /**
171
+ * Send plain text response
172
+ */
173
+ text(content) {
174
+ this.header("Content-Type", "text/plain");
175
+ return content;
176
+ }
177
+ /**
178
+ * Redirect to a different URL
179
+ */
180
+ redirect(url, statusCode = 302) {
181
+ this.ctx.set.redirect = url;
182
+ this.ctx.set.status = statusCode;
183
+ }
184
+ /**
185
+ * Set content type
186
+ */
187
+ type(contentType) {
188
+ return this.header("Content-Type", contentType);
189
+ }
190
+ /**
191
+ * Set cache control
192
+ */
193
+ cache(maxAge, options) {
194
+ let cacheControl = "";
195
+ if (options?.private) {
196
+ cacheControl = "private";
197
+ }
198
+ else {
199
+ cacheControl = "public";
200
+ }
201
+ if (options?.noCache) {
202
+ cacheControl += ", no-cache";
203
+ }
204
+ if (options?.noStore) {
205
+ cacheControl += ", no-store";
206
+ }
207
+ if (maxAge > 0) {
208
+ cacheControl += `, max-age=${maxAge}`;
209
+ }
210
+ return this.header("Cache-Control", cacheControl);
211
+ }
212
+ /**
213
+ * Disable caching
214
+ */
215
+ noCache() {
216
+ return this.header("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate")
217
+ .header("Pragma", "no-cache")
218
+ .header("Expires", "0");
219
+ }
220
+ /**
221
+ * Set CORS headers
222
+ */
223
+ cors(options) {
224
+ this.header("Access-Control-Allow-Origin", options?.origin || "*");
225
+ if (options?.methods) {
226
+ this.header("Access-Control-Allow-Methods", options.methods.join(", "));
227
+ }
228
+ if (options?.headers) {
229
+ this.header("Access-Control-Allow-Headers", options.headers.join(", "));
230
+ }
231
+ if (options?.credentials) {
232
+ this.header("Access-Control-Allow-Credentials", "true");
233
+ }
234
+ if (options?.maxAge !== undefined) {
235
+ this.header("Access-Control-Max-Age", options.maxAge.toString());
236
+ }
237
+ return this;
238
+ }
239
+ /**
240
+ * Get the raw Elysia set object
241
+ */
242
+ get raw() {
243
+ return this.ctx.set;
244
+ }
245
+ /**
246
+ * Send a file download
247
+ */
248
+ download(filename) {
249
+ return this.header("Content-Disposition", `attachment; filename="${filename}"`);
250
+ }
251
+ /**
252
+ * Send response with custom status code
253
+ */
254
+ send(data, statusCode) {
255
+ if (statusCode) {
256
+ this.status(statusCode);
257
+ }
258
+ return data;
259
+ }
260
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"ultra-optimized-handler.d.ts","sourceRoot":"","sources":["../core/ultra-optimized-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;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;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,mBAAmB,GAC3B,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAiU5B;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,CAU5B"}
1
+ {"version":3,"file":"ultra-optimized-handler.d.ts","sourceRoot":"","sources":["../core/ultra-optimized-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAcH,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;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,mBAAmB,GAC3B,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAgV5B;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,CAqB5B"}
@@ -23,6 +23,8 @@
23
23
  import { createExecutionContext, executeGuards, } from "./decorators/guard.decorators";
24
24
  import { executeInterceptors } from "./decorators/interceptor.decorators";
25
25
  import { executePipes } from "./decorators/pipe.decorators";
26
+ import { Request } from "./request";
27
+ import { Response } from "./response";
26
28
  import { executeExceptionFilters, HttpException, } from "./decorators/exception.decorators";
27
29
  /**
28
30
  * Ultra-optimized handler builder
@@ -52,6 +54,11 @@ export function buildUltraOptimizedHandler(options) {
52
54
  !hasResponseModifiers) {
53
55
  // Direct call - zero overhead!
54
56
  return async (ctx) => {
57
+ if (!ctx.__wynk_wrapped__) {
58
+ ctx.request = new Request(ctx);
59
+ ctx.response = new Response(ctx);
60
+ ctx.__wynk_wrapped__ = true;
61
+ }
55
62
  return await instance[methodName](ctx);
56
63
  };
57
64
  }
@@ -62,6 +69,11 @@ export function buildUltraOptimizedHandler(options) {
62
69
  !hasResponseModifiers &&
63
70
  hasParams) {
64
71
  return async (ctx) => {
72
+ if (!ctx.__wynk_wrapped__) {
73
+ ctx.request = new Request(ctx);
74
+ ctx.response = new Response(ctx);
75
+ ctx.__wynk_wrapped__ = true;
76
+ }
65
77
  const args = new Array(params.length);
66
78
  for (const param of params) {
67
79
  let value;
@@ -129,6 +141,11 @@ export function buildUltraOptimizedHandler(options) {
129
141
  // CASE 3: Full-featured handler (has guards/interceptors/filters)
130
142
  // This is where we MUST use try-catch, but still avoid nested async
131
143
  return async (ctx) => {
144
+ if (!ctx.__wynk_wrapped__) {
145
+ ctx.request = new Request(ctx);
146
+ ctx.response = new Response(ctx);
147
+ ctx.__wynk_wrapped__ = true;
148
+ }
132
149
  try {
133
150
  // Guards
134
151
  if (hasGuards) {
@@ -294,9 +311,19 @@ export function buildMiddlewareChain(handler, middlewares) {
294
311
  if (middlewares.length === 0) {
295
312
  return handler;
296
313
  }
297
- return middlewares.reduceRight((next, middleware) => {
314
+ // Build chain without wrapping in each layer
315
+ const chain = middlewares.reduceRight((next, middleware) => {
298
316
  return async (ctx) => {
299
317
  return await middleware(ctx, () => next(ctx));
300
318
  };
301
319
  }, handler);
320
+ // Wrap ONCE at the top level
321
+ return async (ctx) => {
322
+ if (!ctx.__wynk_wrapped__) {
323
+ ctx.request = new Request(ctx);
324
+ ctx.response = new Response(ctx);
325
+ ctx.__wynk_wrapped__ = true;
326
+ }
327
+ return await chain(ctx);
328
+ };
302
329
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wynkjs",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "A high-performance TypeScript framework built on Elysia for Bun with elegant decorator-based architecture, built-in compression, and plugin system - 10x faster than Express/NestJS",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -51,7 +51,9 @@
51
51
  "test:all": "bun test tests/",
52
52
  "test:core": "bash tests/test-core.sh",
53
53
  "test:watch": "bun test tests/ --watch",
54
- "test:coverage": "bun test tests/ --coverage"
54
+ "test:coverage": "bun test tests/ --coverage",
55
+ "test:ci": "bun test tests/ --coverage",
56
+ "ci": "bun test tests/ --coverage"
55
57
  },
56
58
  "peerDependencies": {},
57
59
  "devDependencies": {
@@ -73,9 +75,10 @@
73
75
  "LICENSE"
74
76
  ],
75
77
  "dependencies": {
78
+ "@elysiajs/cors": "^1.4.0",
79
+ "@elysiajs/swagger": "^1.3.1",
76
80
  "elysia": "^1.0.0",
77
81
  "reflect-metadata": "^0.2.2",
78
- "@elysiajs/cors": "^1.4.0",
79
82
  "tsyringe": "^4.10.0"
80
83
  }
81
84
  }