@asenajs/ergenecore 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +636 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/Ergenecore.d.ts +598 -0
- package/dist/lib/Ergenecore.js +1406 -0
- package/dist/lib/Ergenecore.js.map +1 -0
- package/dist/lib/ErgenecoreContextWrapper.d.ts +190 -0
- package/dist/lib/ErgenecoreContextWrapper.js +387 -0
- package/dist/lib/ErgenecoreContextWrapper.js.map +1 -0
- package/dist/lib/ErgenecoreWebsocketAdapter.d.ts +68 -0
- package/dist/lib/ErgenecoreWebsocketAdapter.js +233 -0
- package/dist/lib/ErgenecoreWebsocketAdapter.js.map +1 -0
- package/dist/lib/defaults/ConfigService.d.ts +39 -0
- package/dist/lib/defaults/ConfigService.js +30 -0
- package/dist/lib/defaults/ConfigService.js.map +1 -0
- package/dist/lib/defaults/MiddlewareService.d.ts +39 -0
- package/dist/lib/defaults/MiddlewareService.js +30 -0
- package/dist/lib/defaults/MiddlewareService.js.map +1 -0
- package/dist/lib/defaults/StaticServeService.d.ts +24 -0
- package/dist/lib/defaults/StaticServeService.js +23 -0
- package/dist/lib/defaults/StaticServeService.js.map +1 -0
- package/dist/lib/defaults/ValidationService.d.ts +35 -0
- package/dist/lib/defaults/ValidationService.js +34 -0
- package/dist/lib/defaults/ValidationService.js.map +1 -0
- package/dist/lib/defaults/index.d.ts +25 -0
- package/dist/lib/defaults/index.js +26 -0
- package/dist/lib/defaults/index.js.map +1 -0
- package/dist/lib/errors.d.ts +84 -0
- package/dist/lib/errors.js +108 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/index.d.ts +36 -0
- package/dist/lib/index.js +37 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/middlewares/CorsMiddleware.d.ts +147 -0
- package/dist/lib/middlewares/CorsMiddleware.js +163 -0
- package/dist/lib/middlewares/CorsMiddleware.js.map +1 -0
- package/dist/lib/middlewares/RateLimiterMiddleware.d.ts +330 -0
- package/dist/lib/middlewares/RateLimiterMiddleware.js +300 -0
- package/dist/lib/middlewares/RateLimiterMiddleware.js.map +1 -0
- package/dist/lib/types/Handler.d.ts +65 -0
- package/dist/lib/types/Handler.js +10 -0
- package/dist/lib/types/Handler.js.map +1 -0
- package/dist/lib/types/StaticServeExtras.d.ts +29 -0
- package/dist/lib/types/StaticServeExtras.js +2 -0
- package/dist/lib/types/StaticServeExtras.js.map +1 -0
- package/dist/lib/types/Validation.d.ts +7 -0
- package/dist/lib/types/Validation.js +2 -0
- package/dist/lib/types/Validation.js.map +1 -0
- package/dist/lib/types/index.d.ts +24 -0
- package/dist/lib/types/index.js +25 -0
- package/dist/lib/types/index.js.map +1 -0
- package/dist/lib/utils/factory.d.ts +121 -0
- package/dist/lib/utils/factory.js +144 -0
- package/dist/lib/utils/factory.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Exception for Ergenecore
|
|
3
|
+
*
|
|
4
|
+
* Public API for throwing HTTP errors in handlers and middlewares.
|
|
5
|
+
* Inspired by Hono's HTTPException pattern.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // In middleware
|
|
10
|
+
* if (!user) {
|
|
11
|
+
* throw new HttpException(401, 'Unauthorized', {
|
|
12
|
+
* headers: { 'WWW-Authenticate': 'Bearer' }
|
|
13
|
+
* });
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* // In handler
|
|
17
|
+
* if (!isValid) {
|
|
18
|
+
* throw new HttpException(400, { error: 'Invalid data' });
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare class HttpException extends Error {
|
|
23
|
+
/**
|
|
24
|
+
* HTTP status code
|
|
25
|
+
*/
|
|
26
|
+
readonly status: number;
|
|
27
|
+
/**
|
|
28
|
+
* Response body (can be string or object)
|
|
29
|
+
*/
|
|
30
|
+
readonly body: string | object;
|
|
31
|
+
/**
|
|
32
|
+
* Optional response init options (headers, statusText, etc.)
|
|
33
|
+
*/
|
|
34
|
+
readonly options?: ResponseInit;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new HttpException
|
|
37
|
+
*
|
|
38
|
+
* @param status - HTTP status code (e.g., 401, 403, 404)
|
|
39
|
+
* @param body - Response body (string or object to be JSON stringified)
|
|
40
|
+
* @param options - Optional ResponseInit options (headers, statusText, etc.)
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* // Simple message
|
|
45
|
+
* throw new HttpException(404, 'Not Found');
|
|
46
|
+
*
|
|
47
|
+
* // JSON object
|
|
48
|
+
* throw new HttpException(400, { error: 'Invalid input', field: 'email' });
|
|
49
|
+
*
|
|
50
|
+
* // With headers
|
|
51
|
+
* throw new HttpException(429, 'Too Many Requests', {
|
|
52
|
+
* headers: { 'Retry-After': '60' }
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
constructor(status: number, body?: string | object, options?: ResponseInit);
|
|
57
|
+
/**
|
|
58
|
+
* Converts the exception to a Response object
|
|
59
|
+
*
|
|
60
|
+
* @returns Bun Response object ready to be returned
|
|
61
|
+
*/
|
|
62
|
+
getResponse(): Response;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Internal error class for middleware response propagation
|
|
66
|
+
*
|
|
67
|
+
* This error is thrown internally when a middleware returns a Response object,
|
|
68
|
+
* allowing the response to be propagated through the middleware chain without
|
|
69
|
+
* being lost in the recursive next() pattern.
|
|
70
|
+
*
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
export declare class MiddlewareResponseError extends Error {
|
|
74
|
+
/**
|
|
75
|
+
* The Response object returned by the middleware
|
|
76
|
+
*/
|
|
77
|
+
readonly response: Response;
|
|
78
|
+
/**
|
|
79
|
+
* Creates a new MiddlewareResponseError
|
|
80
|
+
*
|
|
81
|
+
* @param response - Response object to propagate
|
|
82
|
+
*/
|
|
83
|
+
constructor(response: Response);
|
|
84
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Exception for Ergenecore
|
|
3
|
+
*
|
|
4
|
+
* Public API for throwing HTTP errors in handlers and middlewares.
|
|
5
|
+
* Inspired by Hono's HTTPException pattern.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // In middleware
|
|
10
|
+
* if (!user) {
|
|
11
|
+
* throw new HttpException(401, 'Unauthorized', {
|
|
12
|
+
* headers: { 'WWW-Authenticate': 'Bearer' }
|
|
13
|
+
* });
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* // In handler
|
|
17
|
+
* if (!isValid) {
|
|
18
|
+
* throw new HttpException(400, { error: 'Invalid data' });
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class HttpException extends Error {
|
|
23
|
+
/**
|
|
24
|
+
* HTTP status code
|
|
25
|
+
*/
|
|
26
|
+
status;
|
|
27
|
+
/**
|
|
28
|
+
* Response body (can be string or object)
|
|
29
|
+
*/
|
|
30
|
+
body;
|
|
31
|
+
/**
|
|
32
|
+
* Optional response init options (headers, statusText, etc.)
|
|
33
|
+
*/
|
|
34
|
+
options;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new HttpException
|
|
37
|
+
*
|
|
38
|
+
* @param status - HTTP status code (e.g., 401, 403, 404)
|
|
39
|
+
* @param body - Response body (string or object to be JSON stringified)
|
|
40
|
+
* @param options - Optional ResponseInit options (headers, statusText, etc.)
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* // Simple message
|
|
45
|
+
* throw new HttpException(404, 'Not Found');
|
|
46
|
+
*
|
|
47
|
+
* // JSON object
|
|
48
|
+
* throw new HttpException(400, { error: 'Invalid input', field: 'email' });
|
|
49
|
+
*
|
|
50
|
+
* // With headers
|
|
51
|
+
* throw new HttpException(429, 'Too Many Requests', {
|
|
52
|
+
* headers: { 'Retry-After': '60' }
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
constructor(status, body = '', options) {
|
|
57
|
+
const message = typeof body === 'string' ? body : JSON.stringify(body);
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = 'HttpException';
|
|
60
|
+
this.status = status;
|
|
61
|
+
this.body = body;
|
|
62
|
+
this.options = options;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Converts the exception to a Response object
|
|
66
|
+
*
|
|
67
|
+
* @returns Bun Response object ready to be returned
|
|
68
|
+
*/
|
|
69
|
+
getResponse() {
|
|
70
|
+
const body = typeof this.body === 'string' ? this.body : JSON.stringify(this.body);
|
|
71
|
+
const headers = new Headers(this.options?.headers);
|
|
72
|
+
// Set Content-Type to application/json if body is an object and not already set
|
|
73
|
+
if (typeof this.body === 'object' && !headers.has('Content-Type')) {
|
|
74
|
+
headers.set('Content-Type', 'application/json');
|
|
75
|
+
}
|
|
76
|
+
return new Response(body, {
|
|
77
|
+
status: this.status,
|
|
78
|
+
statusText: this.options?.statusText,
|
|
79
|
+
headers,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Internal error class for middleware response propagation
|
|
85
|
+
*
|
|
86
|
+
* This error is thrown internally when a middleware returns a Response object,
|
|
87
|
+
* allowing the response to be propagated through the middleware chain without
|
|
88
|
+
* being lost in the recursive next() pattern.
|
|
89
|
+
*
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
export class MiddlewareResponseError extends Error {
|
|
93
|
+
/**
|
|
94
|
+
* The Response object returned by the middleware
|
|
95
|
+
*/
|
|
96
|
+
response;
|
|
97
|
+
/**
|
|
98
|
+
* Creates a new MiddlewareResponseError
|
|
99
|
+
*
|
|
100
|
+
* @param response - Response object to propagate
|
|
101
|
+
*/
|
|
102
|
+
constructor(response) {
|
|
103
|
+
super('MIDDLEWARE_RETURNED_RESPONSE');
|
|
104
|
+
this.name = 'MiddlewareResponseError';
|
|
105
|
+
this.response = response;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../lib/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAEtC;;OAEG;IACa,MAAM,CAAS;IAE/B;;OAEG;IACa,IAAI,CAAkB;IAEtC;;OAEG;IACa,OAAO,CAAgB;IAEvC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,YAAmB,MAAc,EAAE,OAAwB,EAAE,EAAE,OAAsB;QACnF,MAAM,OAAO,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAEvE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACI,WAAW;QAChB,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEnF,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAEnD,gFAAgF;QAChF,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;YAClE,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAClD,CAAC;QAED,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;YACxB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU;YACpC,OAAO;SACR,CAAC,CAAC;IACL,CAAC;CAEF;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAEhD;;OAEG;IACa,QAAQ,CAAW;IAEnC;;;;OAIG;IACH,YAAmB,QAAkB;QACnC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CAEF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ergenecore - Blazing-fast native Bun adapter for Asena.js
|
|
3
|
+
*
|
|
4
|
+
* Main entry point for the Ergenecore adapter.
|
|
5
|
+
* Exports the core adapter, factory functions, types, and base classes.
|
|
6
|
+
*
|
|
7
|
+
* @module ergenecore
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { AsenaServerFactory } from '@asenajs/asena';
|
|
12
|
+
* import { createErgenecoreAdapter, type Context } from '@asenajs/ergenecore';
|
|
13
|
+
*
|
|
14
|
+
* const adapter = createErgenecoreAdapter();
|
|
15
|
+
* const server = await AsenaServerFactory.create({
|
|
16
|
+
* adapter,
|
|
17
|
+
* logger,
|
|
18
|
+
* port: 3000
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* await server.start();
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export { Ergenecore } from './Ergenecore';
|
|
25
|
+
export { ErgenecoreContextWrapper } from './ErgenecoreContextWrapper';
|
|
26
|
+
export { ErgenecoreWebsocketAdapter } from './ErgenecoreWebsocketAdapter';
|
|
27
|
+
export { HttpException } from './errors';
|
|
28
|
+
export { createErgenecoreAdapter, createProductionAdapter, createDevelopmentAdapter, type ErgenecoreOptions, } from './utils/factory';
|
|
29
|
+
export { ValidationService } from './defaults/ValidationService';
|
|
30
|
+
export { ConfigService } from './defaults/ConfigService';
|
|
31
|
+
export { MiddlewareService } from './defaults/MiddlewareService';
|
|
32
|
+
export { StaticServeService } from './defaults/StaticServeService';
|
|
33
|
+
export type { Context } from './ErgenecoreContextWrapper';
|
|
34
|
+
export type { ErgenecoreHandler, ErgenecoreNext } from './types/Handler';
|
|
35
|
+
export type { StaticServeExtras } from './types/StaticServeExtras';
|
|
36
|
+
export type { ValidationSchema, ValidationSchemaWithHook } from './types/Validation';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ergenecore - Blazing-fast native Bun adapter for Asena.js
|
|
3
|
+
*
|
|
4
|
+
* Main entry point for the Ergenecore adapter.
|
|
5
|
+
* Exports the core adapter, factory functions, types, and base classes.
|
|
6
|
+
*
|
|
7
|
+
* @module ergenecore
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { AsenaServerFactory } from '@asenajs/asena';
|
|
12
|
+
* import { createErgenecoreAdapter, type Context } from '@asenajs/ergenecore';
|
|
13
|
+
*
|
|
14
|
+
* const adapter = createErgenecoreAdapter();
|
|
15
|
+
* const server = await AsenaServerFactory.create({
|
|
16
|
+
* adapter,
|
|
17
|
+
* logger,
|
|
18
|
+
* port: 3000
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* await server.start();
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
// Core adapter
|
|
25
|
+
export { Ergenecore } from './Ergenecore';
|
|
26
|
+
export { ErgenecoreContextWrapper } from './ErgenecoreContextWrapper';
|
|
27
|
+
export { ErgenecoreWebsocketAdapter } from './ErgenecoreWebsocketAdapter';
|
|
28
|
+
// Error classes
|
|
29
|
+
export { HttpException } from './errors';
|
|
30
|
+
// Factory functions
|
|
31
|
+
export { createErgenecoreAdapter, createProductionAdapter, createDevelopmentAdapter, } from './utils/factory';
|
|
32
|
+
// Default base classes
|
|
33
|
+
export { ValidationService } from './defaults/ValidationService';
|
|
34
|
+
export { ConfigService } from './defaults/ConfigService';
|
|
35
|
+
export { MiddlewareService } from './defaults/MiddlewareService';
|
|
36
|
+
export { StaticServeService } from './defaults/StaticServeService';
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,eAAe;AACf,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE1E,gBAAgB;AAChB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,oBAAoB;AACpB,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,GAEzB,MAAM,iBAAiB,CAAC;AAEzB,uBAAuB;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS Middleware for Ergenecore
|
|
3
|
+
*
|
|
4
|
+
* Handles Cross-Origin Resource Sharing (CORS) by:
|
|
5
|
+
* - Setting appropriate CORS headers on responses
|
|
6
|
+
* - Handling preflight OPTIONS requests
|
|
7
|
+
* - Supporting origin validation
|
|
8
|
+
* - Zero external dependencies (uses Bun's native APIs)
|
|
9
|
+
*
|
|
10
|
+
* @module defaults/CorsMiddleware
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { Middleware } from '@asenajs/asena/server';
|
|
15
|
+
* import { CorsMiddleware } from '@asenajs/ergenecore';
|
|
16
|
+
*
|
|
17
|
+
* @Middleware()
|
|
18
|
+
* export class MyCorsMiddleware extends CorsMiddleware {
|
|
19
|
+
* constructor() {
|
|
20
|
+
* super({
|
|
21
|
+
* origin: '*', // or ['https://example.com']
|
|
22
|
+
* methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
23
|
+
* credentials: true
|
|
24
|
+
* });
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
import type { Context } from '../ErgenecoreContextWrapper';
|
|
30
|
+
import { MiddlewareService } from '../defaults/MiddlewareService';
|
|
31
|
+
/**
|
|
32
|
+
* CORS configuration options
|
|
33
|
+
*/
|
|
34
|
+
export interface CorsOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Allowed origins
|
|
37
|
+
* - Use '*' to allow all origins
|
|
38
|
+
* - Use string[] to allow specific origins
|
|
39
|
+
* - Use function for dynamic origin validation
|
|
40
|
+
*
|
|
41
|
+
* @default '*'
|
|
42
|
+
*/
|
|
43
|
+
origin?: '*' | string[] | ((origin: string) => boolean);
|
|
44
|
+
/**
|
|
45
|
+
* Allowed HTTP methods
|
|
46
|
+
*
|
|
47
|
+
* @default ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']
|
|
48
|
+
*/
|
|
49
|
+
methods?: string[];
|
|
50
|
+
/**
|
|
51
|
+
* Allowed headers
|
|
52
|
+
*
|
|
53
|
+
* @default ['Content-Type', 'Authorization']
|
|
54
|
+
*/
|
|
55
|
+
allowedHeaders?: string[];
|
|
56
|
+
/**
|
|
57
|
+
* Exposed headers (visible to client JavaScript)
|
|
58
|
+
*
|
|
59
|
+
* @default []
|
|
60
|
+
*/
|
|
61
|
+
exposedHeaders?: string[];
|
|
62
|
+
/**
|
|
63
|
+
* Allow credentials (cookies, authorization headers, TLS client certificates)
|
|
64
|
+
*
|
|
65
|
+
* @default false
|
|
66
|
+
*/
|
|
67
|
+
credentials?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Preflight cache duration in seconds
|
|
70
|
+
*
|
|
71
|
+
* @default 86400 (24 hours)
|
|
72
|
+
*/
|
|
73
|
+
maxAge?: number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* CORS Middleware
|
|
77
|
+
*
|
|
78
|
+
* Implements CORS (Cross-Origin Resource Sharing) for Ergenecore adapter.
|
|
79
|
+
* Extend this class and configure it via constructor to customize CORS behavior.
|
|
80
|
+
*
|
|
81
|
+
* **Performance Optimizations:**
|
|
82
|
+
* - Lazy header allocation (only when needed)
|
|
83
|
+
* - Pre-joined header strings for common cases
|
|
84
|
+
* - Fast origin validation
|
|
85
|
+
* - Minimal string allocations
|
|
86
|
+
*
|
|
87
|
+
* **CORS Flow:**
|
|
88
|
+
* 1. Check if request has Origin header (if not, skip CORS)
|
|
89
|
+
* 2. Validate origin against allowed origins
|
|
90
|
+
* 3. Handle preflight OPTIONS request → return 204 immediately
|
|
91
|
+
* 4. For other requests → set CORS headers and call next()
|
|
92
|
+
*/
|
|
93
|
+
export declare class CorsMiddleware extends MiddlewareService {
|
|
94
|
+
private readonly origin;
|
|
95
|
+
private readonly methods;
|
|
96
|
+
private readonly allowedHeaders;
|
|
97
|
+
private readonly exposedHeaders;
|
|
98
|
+
private readonly credentials;
|
|
99
|
+
private readonly maxAge;
|
|
100
|
+
/**
|
|
101
|
+
* Creates a new CORS middleware instance
|
|
102
|
+
*
|
|
103
|
+
* @param options - CORS configuration options
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* @Middleware()
|
|
108
|
+
* export class CustomCors extends CorsMiddleware {
|
|
109
|
+
* constructor() {
|
|
110
|
+
* super({
|
|
111
|
+
* origin: ['https://example.com', 'https://app.example.com'],
|
|
112
|
+
* methods: ['GET', 'POST'],
|
|
113
|
+
* credentials: true,
|
|
114
|
+
* maxAge: 3600
|
|
115
|
+
* });
|
|
116
|
+
* }
|
|
117
|
+
* }
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
constructor(options?: CorsOptions);
|
|
121
|
+
/**
|
|
122
|
+
* CORS middleware handler
|
|
123
|
+
*
|
|
124
|
+
* Execution flow:
|
|
125
|
+
* 1. Check if Origin header present (if not, skip CORS)
|
|
126
|
+
* 2. Validate origin
|
|
127
|
+
* 3. Handle preflight OPTIONS → return 204 No Content
|
|
128
|
+
* 4. Set CORS headers for actual request → call next()
|
|
129
|
+
*
|
|
130
|
+
* @param context - Ergenecore context wrapper
|
|
131
|
+
* @param next - Function to call next middleware or handler
|
|
132
|
+
* @returns Response for preflight, or result of next() for actual requests
|
|
133
|
+
*/
|
|
134
|
+
handle(context: Context, next: () => Promise<void>): Promise<any>;
|
|
135
|
+
/**
|
|
136
|
+
* Determines the allowed origin value for the response
|
|
137
|
+
*
|
|
138
|
+
* Performance:
|
|
139
|
+
* - Fast path for '*' (most common case)
|
|
140
|
+
* - Array.includes() for string array (O(n) but n is typically small)
|
|
141
|
+
* - Function call for dynamic validation
|
|
142
|
+
*
|
|
143
|
+
* @param requestOrigin - Origin from request header
|
|
144
|
+
* @returns Allowed origin string or null if not allowed
|
|
145
|
+
*/
|
|
146
|
+
private getAllowedOrigin;
|
|
147
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS Middleware for Ergenecore
|
|
3
|
+
*
|
|
4
|
+
* Handles Cross-Origin Resource Sharing (CORS) by:
|
|
5
|
+
* - Setting appropriate CORS headers on responses
|
|
6
|
+
* - Handling preflight OPTIONS requests
|
|
7
|
+
* - Supporting origin validation
|
|
8
|
+
* - Zero external dependencies (uses Bun's native APIs)
|
|
9
|
+
*
|
|
10
|
+
* @module defaults/CorsMiddleware
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { Middleware } from '@asenajs/asena/server';
|
|
15
|
+
* import { CorsMiddleware } from '@asenajs/ergenecore';
|
|
16
|
+
*
|
|
17
|
+
* @Middleware()
|
|
18
|
+
* export class MyCorsMiddleware extends CorsMiddleware {
|
|
19
|
+
* constructor() {
|
|
20
|
+
* super({
|
|
21
|
+
* origin: '*', // or ['https://example.com']
|
|
22
|
+
* methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
23
|
+
* credentials: true
|
|
24
|
+
* });
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
import { MiddlewareService } from '../defaults/MiddlewareService';
|
|
30
|
+
/**
|
|
31
|
+
* CORS Middleware
|
|
32
|
+
*
|
|
33
|
+
* Implements CORS (Cross-Origin Resource Sharing) for Ergenecore adapter.
|
|
34
|
+
* Extend this class and configure it via constructor to customize CORS behavior.
|
|
35
|
+
*
|
|
36
|
+
* **Performance Optimizations:**
|
|
37
|
+
* - Lazy header allocation (only when needed)
|
|
38
|
+
* - Pre-joined header strings for common cases
|
|
39
|
+
* - Fast origin validation
|
|
40
|
+
* - Minimal string allocations
|
|
41
|
+
*
|
|
42
|
+
* **CORS Flow:**
|
|
43
|
+
* 1. Check if request has Origin header (if not, skip CORS)
|
|
44
|
+
* 2. Validate origin against allowed origins
|
|
45
|
+
* 3. Handle preflight OPTIONS request → return 204 immediately
|
|
46
|
+
* 4. For other requests → set CORS headers and call next()
|
|
47
|
+
*/
|
|
48
|
+
export class CorsMiddleware extends MiddlewareService {
|
|
49
|
+
origin;
|
|
50
|
+
methods;
|
|
51
|
+
allowedHeaders;
|
|
52
|
+
exposedHeaders;
|
|
53
|
+
credentials;
|
|
54
|
+
maxAge;
|
|
55
|
+
/**
|
|
56
|
+
* Creates a new CORS middleware instance
|
|
57
|
+
*
|
|
58
|
+
* @param options - CORS configuration options
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* @Middleware()
|
|
63
|
+
* export class CustomCors extends CorsMiddleware {
|
|
64
|
+
* constructor() {
|
|
65
|
+
* super({
|
|
66
|
+
* origin: ['https://example.com', 'https://app.example.com'],
|
|
67
|
+
* methods: ['GET', 'POST'],
|
|
68
|
+
* credentials: true,
|
|
69
|
+
* maxAge: 3600
|
|
70
|
+
* });
|
|
71
|
+
* }
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
constructor(options = {}) {
|
|
76
|
+
super();
|
|
77
|
+
// Pre-process and store configuration (avoid runtime processing)
|
|
78
|
+
this.origin = options.origin ?? '*';
|
|
79
|
+
this.methods = (options.methods ?? ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']).join(', ');
|
|
80
|
+
this.allowedHeaders = (options.allowedHeaders ?? ['Content-Type', 'Authorization']).join(', ');
|
|
81
|
+
this.exposedHeaders = (options.exposedHeaders ?? []).join(', ');
|
|
82
|
+
this.credentials = options.credentials ?? false;
|
|
83
|
+
this.maxAge = String(options.maxAge ?? 86400); // 24 hours default
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* CORS middleware handler
|
|
87
|
+
*
|
|
88
|
+
* Execution flow:
|
|
89
|
+
* 1. Check if Origin header present (if not, skip CORS)
|
|
90
|
+
* 2. Validate origin
|
|
91
|
+
* 3. Handle preflight OPTIONS → return 204 No Content
|
|
92
|
+
* 4. Set CORS headers for actual request → call next()
|
|
93
|
+
*
|
|
94
|
+
* @param context - Ergenecore context wrapper
|
|
95
|
+
* @param next - Function to call next middleware or handler
|
|
96
|
+
* @returns Response for preflight, or result of next() for actual requests
|
|
97
|
+
*/
|
|
98
|
+
async handle(context, next) {
|
|
99
|
+
const origin = context.req.headers.get('Origin');
|
|
100
|
+
// If no Origin header, this is not a CORS request → skip
|
|
101
|
+
if (!origin) {
|
|
102
|
+
return await next();
|
|
103
|
+
}
|
|
104
|
+
// Validate origin
|
|
105
|
+
const allowedOrigin = this.getAllowedOrigin(origin);
|
|
106
|
+
if (!allowedOrigin) {
|
|
107
|
+
// Origin not allowed → block request
|
|
108
|
+
return new Response('CORS: Origin not allowed', { status: 403 });
|
|
109
|
+
}
|
|
110
|
+
// Set CORS headers using context.setResponseHeader (lazy initialization)
|
|
111
|
+
context.setResponseHeader('Access-Control-Allow-Origin', allowedOrigin);
|
|
112
|
+
if (this.credentials) {
|
|
113
|
+
context.setResponseHeader('Access-Control-Allow-Credentials', 'true');
|
|
114
|
+
}
|
|
115
|
+
if (this.exposedHeaders) {
|
|
116
|
+
context.setResponseHeader('Access-Control-Expose-Headers', this.exposedHeaders);
|
|
117
|
+
}
|
|
118
|
+
// Handle preflight OPTIONS request
|
|
119
|
+
if (context.req.method === 'OPTIONS') {
|
|
120
|
+
// Build headers object for preflight response
|
|
121
|
+
const headers = {
|
|
122
|
+
'Access-Control-Allow-Origin': allowedOrigin,
|
|
123
|
+
'Access-Control-Allow-Methods': this.methods,
|
|
124
|
+
'Access-Control-Allow-Headers': this.allowedHeaders,
|
|
125
|
+
'Access-Control-Max-Age': this.maxAge,
|
|
126
|
+
};
|
|
127
|
+
if (this.credentials) {
|
|
128
|
+
headers['Access-Control-Allow-Credentials'] = 'true';
|
|
129
|
+
}
|
|
130
|
+
// Return 204 No Content for preflight
|
|
131
|
+
return new Response(null, { status: 204, headers });
|
|
132
|
+
}
|
|
133
|
+
// For actual requests, continue to handler
|
|
134
|
+
return await next();
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Determines the allowed origin value for the response
|
|
138
|
+
*
|
|
139
|
+
* Performance:
|
|
140
|
+
* - Fast path for '*' (most common case)
|
|
141
|
+
* - Array.includes() for string array (O(n) but n is typically small)
|
|
142
|
+
* - Function call for dynamic validation
|
|
143
|
+
*
|
|
144
|
+
* @param requestOrigin - Origin from request header
|
|
145
|
+
* @returns Allowed origin string or null if not allowed
|
|
146
|
+
*/
|
|
147
|
+
getAllowedOrigin(requestOrigin) {
|
|
148
|
+
// Fast path: Allow all origins
|
|
149
|
+
if (this.origin === '*') {
|
|
150
|
+
return '*';
|
|
151
|
+
}
|
|
152
|
+
// Array of specific origins
|
|
153
|
+
if (Array.isArray(this.origin)) {
|
|
154
|
+
return this.origin.includes(requestOrigin) ? requestOrigin : null;
|
|
155
|
+
}
|
|
156
|
+
// Function-based validation
|
|
157
|
+
if (typeof this.origin === 'function') {
|
|
158
|
+
return this.origin(requestOrigin) ? requestOrigin : null;
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=CorsMiddleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CorsMiddleware.js","sourceRoot":"","sources":["../../../lib/middlewares/CorsMiddleware.ts"],"names":[],"mappings":"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"}
|