@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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +636 -0
  3. package/dist/index.d.ts +24 -0
  4. package/dist/index.js +25 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/Ergenecore.d.ts +598 -0
  7. package/dist/lib/Ergenecore.js +1406 -0
  8. package/dist/lib/Ergenecore.js.map +1 -0
  9. package/dist/lib/ErgenecoreContextWrapper.d.ts +190 -0
  10. package/dist/lib/ErgenecoreContextWrapper.js +387 -0
  11. package/dist/lib/ErgenecoreContextWrapper.js.map +1 -0
  12. package/dist/lib/ErgenecoreWebsocketAdapter.d.ts +68 -0
  13. package/dist/lib/ErgenecoreWebsocketAdapter.js +233 -0
  14. package/dist/lib/ErgenecoreWebsocketAdapter.js.map +1 -0
  15. package/dist/lib/defaults/ConfigService.d.ts +39 -0
  16. package/dist/lib/defaults/ConfigService.js +30 -0
  17. package/dist/lib/defaults/ConfigService.js.map +1 -0
  18. package/dist/lib/defaults/MiddlewareService.d.ts +39 -0
  19. package/dist/lib/defaults/MiddlewareService.js +30 -0
  20. package/dist/lib/defaults/MiddlewareService.js.map +1 -0
  21. package/dist/lib/defaults/StaticServeService.d.ts +24 -0
  22. package/dist/lib/defaults/StaticServeService.js +23 -0
  23. package/dist/lib/defaults/StaticServeService.js.map +1 -0
  24. package/dist/lib/defaults/ValidationService.d.ts +35 -0
  25. package/dist/lib/defaults/ValidationService.js +34 -0
  26. package/dist/lib/defaults/ValidationService.js.map +1 -0
  27. package/dist/lib/defaults/index.d.ts +25 -0
  28. package/dist/lib/defaults/index.js +26 -0
  29. package/dist/lib/defaults/index.js.map +1 -0
  30. package/dist/lib/errors.d.ts +84 -0
  31. package/dist/lib/errors.js +108 -0
  32. package/dist/lib/errors.js.map +1 -0
  33. package/dist/lib/index.d.ts +36 -0
  34. package/dist/lib/index.js +37 -0
  35. package/dist/lib/index.js.map +1 -0
  36. package/dist/lib/middlewares/CorsMiddleware.d.ts +147 -0
  37. package/dist/lib/middlewares/CorsMiddleware.js +163 -0
  38. package/dist/lib/middlewares/CorsMiddleware.js.map +1 -0
  39. package/dist/lib/middlewares/RateLimiterMiddleware.d.ts +330 -0
  40. package/dist/lib/middlewares/RateLimiterMiddleware.js +300 -0
  41. package/dist/lib/middlewares/RateLimiterMiddleware.js.map +1 -0
  42. package/dist/lib/types/Handler.d.ts +65 -0
  43. package/dist/lib/types/Handler.js +10 -0
  44. package/dist/lib/types/Handler.js.map +1 -0
  45. package/dist/lib/types/StaticServeExtras.d.ts +29 -0
  46. package/dist/lib/types/StaticServeExtras.js +2 -0
  47. package/dist/lib/types/StaticServeExtras.js.map +1 -0
  48. package/dist/lib/types/Validation.d.ts +7 -0
  49. package/dist/lib/types/Validation.js +2 -0
  50. package/dist/lib/types/Validation.js.map +1 -0
  51. package/dist/lib/types/index.d.ts +24 -0
  52. package/dist/lib/types/index.js +25 -0
  53. package/dist/lib/types/index.js.map +1 -0
  54. package/dist/lib/utils/factory.d.ts +121 -0
  55. package/dist/lib/utils/factory.js +144 -0
  56. package/dist/lib/utils/factory.js.map +1 -0
  57. 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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"}