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 +76 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/request.d.ts +127 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +213 -0
- package/dist/response.d.ts +129 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +260 -0
- package/dist/ultra-optimized-handler.d.ts.map +1 -1
- package/dist/ultra-optimized-handler.js +28 -1
- package/package.json +6 -3
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";
|
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,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"}
|
package/dist/request.js
ADDED
|
@@ -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":"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,QAAQ;IACnB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,QAAQ,CAAsE;IACtF,OAAO,CAAC,OAAO,CAAC,CAAS;gBAEb,GAAG,EAAE,GAAG;IAcpB;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAM1B;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAMzC;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAO9C;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3C;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMhC;;;;;;;;;;OAUG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI;IA0DlE;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,MAAM,CAAC,GAAG,IAAI;IAQjF;;OAEG;IACH,UAAU,IAAI,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,aAAa,CAAA;KAAE,CAAC;IAIrE;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG;IAKpB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAK7B;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAK7B;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,GAAE,MAAY,GAAG,IAAI;IAKrD;;OAEG;IACH,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAwBlG;;OAEG;IACH,OAAO,IAAI,IAAI;IAMf;;OAEG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI;IAsBR;;OAEG;IACH,IAAI,GAAG,IAAI,GAAG,CAEb;IAED;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,GAAG;CAM1C;AAGD,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC"}
|
package/dist/response.js
ADDED
|
@@ -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;
|
|
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
|
-
|
|
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.
|
|
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
|
}
|