@carno.js/core 1.1.1 → 1.1.2

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 (119) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +188 -188
  3. package/dist/Carno.js +46 -26
  4. package/dist/Carno.mjs +46 -26
  5. package/dist/bun/index.js +4 -4
  6. package/dist/bun/index.js.map +29 -29
  7. package/package.json +2 -2
  8. package/src/Carno.ts +718 -673
  9. package/src/DefaultRoutes.ts +34 -34
  10. package/src/cache/CacheDriver.ts +50 -50
  11. package/src/cache/CacheService.ts +139 -139
  12. package/src/cache/MemoryDriver.ts +104 -104
  13. package/src/cache/RedisDriver.ts +116 -116
  14. package/src/compiler/JITCompiler.ts +167 -167
  15. package/src/container/Container.ts +168 -168
  16. package/src/context/Context.ts +130 -130
  17. package/src/cors/CorsHandler.ts +145 -145
  18. package/src/decorators/Controller.ts +63 -63
  19. package/src/decorators/Inject.ts +16 -16
  20. package/src/decorators/Middleware.ts +22 -22
  21. package/src/decorators/Service.ts +18 -18
  22. package/src/decorators/methods.ts +58 -58
  23. package/src/decorators/params.ts +47 -47
  24. package/src/events/Lifecycle.ts +97 -97
  25. package/src/exceptions/HttpException.ts +99 -99
  26. package/src/index.ts +95 -95
  27. package/src/metadata.ts +46 -46
  28. package/src/middleware/CarnoMiddleware.ts +14 -14
  29. package/src/router/RadixRouter.ts +225 -225
  30. package/src/testing/TestHarness.ts +185 -185
  31. package/src/utils/Metadata.ts +43 -43
  32. package/src/utils/parseQuery.ts +161 -161
  33. package/src/validation/ValibotAdapter.ts +95 -95
  34. package/src/validation/ValidatorAdapter.ts +69 -69
  35. package/src/validation/ZodAdapter.ts +102 -102
  36. package/dist/Carno.d.js +0 -14
  37. package/dist/Carno.d.mjs +0 -1
  38. package/dist/DefaultRoutes.d.js +0 -13
  39. package/dist/DefaultRoutes.d.mjs +0 -0
  40. package/dist/cache/CacheDriver.d.js +0 -13
  41. package/dist/cache/CacheDriver.d.mjs +0 -0
  42. package/dist/cache/CacheService.d.js +0 -13
  43. package/dist/cache/CacheService.d.mjs +0 -0
  44. package/dist/cache/MemoryDriver.d.js +0 -13
  45. package/dist/cache/MemoryDriver.d.mjs +0 -0
  46. package/dist/cache/RedisDriver.d.js +0 -13
  47. package/dist/cache/RedisDriver.d.mjs +0 -0
  48. package/dist/compiler/JITCompiler.d.js +0 -13
  49. package/dist/compiler/JITCompiler.d.mjs +0 -0
  50. package/dist/container/Container.d.js +0 -13
  51. package/dist/container/Container.d.mjs +0 -0
  52. package/dist/context/Context.d.js +0 -13
  53. package/dist/context/Context.d.mjs +0 -0
  54. package/dist/cors/CorsHandler.d.js +0 -13
  55. package/dist/cors/CorsHandler.d.mjs +0 -0
  56. package/dist/decorators/Controller.d.js +0 -13
  57. package/dist/decorators/Controller.d.mjs +0 -0
  58. package/dist/decorators/Inject.d.js +0 -13
  59. package/dist/decorators/Inject.d.mjs +0 -0
  60. package/dist/decorators/Middleware.d.js +0 -13
  61. package/dist/decorators/Middleware.d.mjs +0 -0
  62. package/dist/decorators/Service.d.js +0 -13
  63. package/dist/decorators/Service.d.mjs +0 -0
  64. package/dist/decorators/methods.d.js +0 -13
  65. package/dist/decorators/methods.d.mjs +0 -0
  66. package/dist/decorators/params.d.js +0 -13
  67. package/dist/decorators/params.d.mjs +0 -0
  68. package/dist/events/Lifecycle.d.js +0 -13
  69. package/dist/events/Lifecycle.d.mjs +0 -0
  70. package/dist/exceptions/HttpException.d.js +0 -13
  71. package/dist/exceptions/HttpException.d.mjs +0 -0
  72. package/dist/index.d.js +0 -130
  73. package/dist/index.d.mjs +0 -78
  74. package/dist/metadata.d.js +0 -13
  75. package/dist/metadata.d.mjs +0 -0
  76. package/dist/middleware/CarnoMiddleware.d.js +0 -13
  77. package/dist/middleware/CarnoMiddleware.d.mjs +0 -0
  78. package/dist/router/RadixRouter.d.js +0 -13
  79. package/dist/router/RadixRouter.d.mjs +0 -0
  80. package/dist/testing/TestHarness.d.js +0 -13
  81. package/dist/testing/TestHarness.d.mjs +0 -0
  82. package/dist/utils/Metadata.d.js +0 -13
  83. package/dist/utils/Metadata.d.mjs +0 -0
  84. package/dist/utils/parseQuery.d.js +0 -13
  85. package/dist/utils/parseQuery.d.mjs +0 -0
  86. package/dist/validation/ValibotAdapter.d.js +0 -13
  87. package/dist/validation/ValibotAdapter.d.mjs +0 -0
  88. package/dist/validation/ValidatorAdapter.d.js +0 -13
  89. package/dist/validation/ValidatorAdapter.d.mjs +0 -0
  90. package/dist/validation/ZodAdapter.d.js +0 -13
  91. package/dist/validation/ZodAdapter.d.mjs +0 -0
  92. package/src/Carno.d.ts +0 -135
  93. package/src/DefaultRoutes.d.ts +0 -19
  94. package/src/cache/CacheDriver.d.ts +0 -43
  95. package/src/cache/CacheService.d.ts +0 -89
  96. package/src/cache/MemoryDriver.d.ts +0 -32
  97. package/src/cache/RedisDriver.d.ts +0 -34
  98. package/src/compiler/JITCompiler.d.ts +0 -36
  99. package/src/container/Container.d.ts +0 -38
  100. package/src/context/Context.d.ts +0 -36
  101. package/src/cors/CorsHandler.d.ts +0 -47
  102. package/src/decorators/Controller.d.ts +0 -13
  103. package/src/decorators/Inject.d.ts +0 -6
  104. package/src/decorators/Middleware.d.ts +0 -5
  105. package/src/decorators/Service.d.ts +0 -9
  106. package/src/decorators/methods.d.ts +0 -7
  107. package/src/decorators/params.d.ts +0 -13
  108. package/src/events/Lifecycle.d.ts +0 -54
  109. package/src/exceptions/HttpException.d.ts +0 -43
  110. package/src/index.d.ts +0 -42
  111. package/src/metadata.d.ts +0 -41
  112. package/src/middleware/CarnoMiddleware.d.ts +0 -12
  113. package/src/router/RadixRouter.d.ts +0 -19
  114. package/src/testing/TestHarness.d.ts +0 -71
  115. package/src/utils/Metadata.d.ts +0 -20
  116. package/src/utils/parseQuery.d.ts +0 -23
  117. package/src/validation/ValibotAdapter.d.ts +0 -30
  118. package/src/validation/ValidatorAdapter.d.ts +0 -54
  119. package/src/validation/ZodAdapter.d.ts +0 -35
@@ -1,145 +1,145 @@
1
- /**
2
- * CORS Configuration types.
3
- */
4
- export type CorsOrigin =
5
- | string
6
- | string[]
7
- | RegExp
8
- | ((origin: string) => boolean);
9
-
10
- export interface CorsConfig {
11
- origins: CorsOrigin;
12
- methods?: string[];
13
- allowedHeaders?: string[];
14
- exposedHeaders?: string[];
15
- credentials?: boolean;
16
- maxAge?: number;
17
- }
18
-
19
- export const DEFAULT_CORS_METHODS = ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'];
20
- export const DEFAULT_CORS_HEADERS = ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept', 'Origin'];
21
-
22
- type OriginMatcher = (origin: string) => boolean;
23
-
24
- /**
25
- * CORS Handler - Pre-computes headers at startup for maximum performance.
26
- */
27
- export class CorsHandler {
28
- private readonly cache = new Map<string, Record<string, string>>();
29
- private readonly methodsStr: string;
30
- private readonly headersStr: string;
31
- private readonly exposedStr: string | null;
32
- private readonly maxAgeStr: string | null;
33
- private readonly hasCredentials: boolean;
34
- private readonly isWildcard: boolean;
35
- private readonly matcher: OriginMatcher;
36
-
37
- // Pre-created preflight response for wildcard CORS
38
- private readonly preflightResponse: Response | null = null;
39
-
40
- constructor(config: CorsConfig) {
41
- this.methodsStr = (config.methods || DEFAULT_CORS_METHODS).join(', ');
42
- this.headersStr = (config.allowedHeaders || DEFAULT_CORS_HEADERS).join(', ');
43
- this.exposedStr = config.exposedHeaders?.join(', ') || null;
44
- this.maxAgeStr = config.maxAge?.toString() || null;
45
- this.hasCredentials = !!config.credentials;
46
- this.isWildcard = config.origins === '*';
47
- this.matcher = this.buildMatcher(config.origins);
48
-
49
- // Pre-create preflight response for wildcard
50
- if (this.isWildcard) {
51
- this.preflightResponse = new Response(null, {
52
- status: 204,
53
- headers: this.buildHeaders('*')
54
- });
55
- }
56
- }
57
-
58
- /**
59
- * Handle preflight (OPTIONS) request.
60
- */
61
- preflight(origin: string): Response {
62
- if (this.isWildcard && this.preflightResponse) {
63
- return this.preflightResponse.clone();
64
- }
65
-
66
- if (!this.isAllowed(origin)) {
67
- return new Response(null, { status: 403 });
68
- }
69
-
70
- return new Response(null, {
71
- status: 204,
72
- headers: this.getHeaders(origin)
73
- });
74
- }
75
-
76
- /**
77
- * Apply CORS headers to a response.
78
- */
79
- apply(response: Response, origin: string): Response {
80
- if (!this.isAllowed(origin)) {
81
- return response;
82
- }
83
-
84
- const headers = this.getHeaders(origin);
85
- for (const [key, value] of Object.entries(headers)) {
86
- response.headers.set(key, value);
87
- }
88
-
89
- return response;
90
- }
91
-
92
- /**
93
- * Check if origin is allowed.
94
- */
95
- isAllowed(origin: string): boolean {
96
- return this.matcher(origin);
97
- }
98
-
99
- /**
100
- * Get cached CORS headers for origin.
101
- */
102
- private getHeaders(origin: string): Record<string, string> {
103
- const key = this.isWildcard ? '*' : origin;
104
- let headers = this.cache.get(key);
105
-
106
- if (!headers) {
107
- headers = this.buildHeaders(origin);
108
- this.cache.set(key, headers);
109
- }
110
-
111
- return headers;
112
- }
113
-
114
- private buildHeaders(origin: string): Record<string, string> {
115
- const headers: Record<string, string> = {
116
- 'Access-Control-Allow-Origin': this.isWildcard ? '*' : origin,
117
- 'Access-Control-Allow-Methods': this.methodsStr,
118
- 'Access-Control-Allow-Headers': this.headersStr
119
- };
120
-
121
- if (this.hasCredentials) {
122
- headers['Access-Control-Allow-Credentials'] = 'true';
123
- }
124
- if (this.exposedStr) {
125
- headers['Access-Control-Expose-Headers'] = this.exposedStr;
126
- }
127
- if (this.maxAgeStr) {
128
- headers['Access-Control-Max-Age'] = this.maxAgeStr;
129
- }
130
-
131
- return headers;
132
- }
133
-
134
- private buildMatcher(origins: CorsOrigin): OriginMatcher {
135
- if (origins === '*') return () => true;
136
- if (typeof origins === 'string') return (o) => o === origins;
137
- if (Array.isArray(origins)) {
138
- const set = new Set(origins);
139
- return (o) => set.has(o);
140
- }
141
- if (origins instanceof RegExp) return (o) => origins.test(o);
142
- if (typeof origins === 'function') return origins;
143
- return () => false;
144
- }
145
- }
1
+ /**
2
+ * CORS Configuration types.
3
+ */
4
+ export type CorsOrigin =
5
+ | string
6
+ | string[]
7
+ | RegExp
8
+ | ((origin: string) => boolean);
9
+
10
+ export interface CorsConfig {
11
+ origins: CorsOrigin;
12
+ methods?: string[];
13
+ allowedHeaders?: string[];
14
+ exposedHeaders?: string[];
15
+ credentials?: boolean;
16
+ maxAge?: number;
17
+ }
18
+
19
+ export const DEFAULT_CORS_METHODS = ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'];
20
+ export const DEFAULT_CORS_HEADERS = ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept', 'Origin'];
21
+
22
+ type OriginMatcher = (origin: string) => boolean;
23
+
24
+ /**
25
+ * CORS Handler - Pre-computes headers at startup for maximum performance.
26
+ */
27
+ export class CorsHandler {
28
+ private readonly cache = new Map<string, Record<string, string>>();
29
+ private readonly methodsStr: string;
30
+ private readonly headersStr: string;
31
+ private readonly exposedStr: string | null;
32
+ private readonly maxAgeStr: string | null;
33
+ private readonly hasCredentials: boolean;
34
+ private readonly isWildcard: boolean;
35
+ private readonly matcher: OriginMatcher;
36
+
37
+ // Pre-created preflight response for wildcard CORS
38
+ private readonly preflightResponse: Response | null = null;
39
+
40
+ constructor(config: CorsConfig) {
41
+ this.methodsStr = (config.methods || DEFAULT_CORS_METHODS).join(', ');
42
+ this.headersStr = (config.allowedHeaders || DEFAULT_CORS_HEADERS).join(', ');
43
+ this.exposedStr = config.exposedHeaders?.join(', ') || null;
44
+ this.maxAgeStr = config.maxAge?.toString() || null;
45
+ this.hasCredentials = !!config.credentials;
46
+ this.isWildcard = config.origins === '*';
47
+ this.matcher = this.buildMatcher(config.origins);
48
+
49
+ // Pre-create preflight response for wildcard
50
+ if (this.isWildcard) {
51
+ this.preflightResponse = new Response(null, {
52
+ status: 204,
53
+ headers: this.buildHeaders('*')
54
+ });
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Handle preflight (OPTIONS) request.
60
+ */
61
+ preflight(origin: string): Response {
62
+ if (this.isWildcard && this.preflightResponse) {
63
+ return this.preflightResponse.clone();
64
+ }
65
+
66
+ if (!this.isAllowed(origin)) {
67
+ return new Response(null, { status: 403 });
68
+ }
69
+
70
+ return new Response(null, {
71
+ status: 204,
72
+ headers: this.getHeaders(origin)
73
+ });
74
+ }
75
+
76
+ /**
77
+ * Apply CORS headers to a response.
78
+ */
79
+ apply(response: Response, origin: string): Response {
80
+ if (!this.isAllowed(origin)) {
81
+ return response;
82
+ }
83
+
84
+ const headers = this.getHeaders(origin);
85
+ for (const [key, value] of Object.entries(headers)) {
86
+ response.headers.set(key, value);
87
+ }
88
+
89
+ return response;
90
+ }
91
+
92
+ /**
93
+ * Check if origin is allowed.
94
+ */
95
+ isAllowed(origin: string): boolean {
96
+ return this.matcher(origin);
97
+ }
98
+
99
+ /**
100
+ * Get cached CORS headers for origin.
101
+ */
102
+ private getHeaders(origin: string): Record<string, string> {
103
+ const key = this.isWildcard ? '*' : origin;
104
+ let headers = this.cache.get(key);
105
+
106
+ if (!headers) {
107
+ headers = this.buildHeaders(origin);
108
+ this.cache.set(key, headers);
109
+ }
110
+
111
+ return headers;
112
+ }
113
+
114
+ private buildHeaders(origin: string): Record<string, string> {
115
+ const headers: Record<string, string> = {
116
+ 'Access-Control-Allow-Origin': this.isWildcard ? '*' : origin,
117
+ 'Access-Control-Allow-Methods': this.methodsStr,
118
+ 'Access-Control-Allow-Headers': this.headersStr
119
+ };
120
+
121
+ if (this.hasCredentials) {
122
+ headers['Access-Control-Allow-Credentials'] = 'true';
123
+ }
124
+ if (this.exposedStr) {
125
+ headers['Access-Control-Expose-Headers'] = this.exposedStr;
126
+ }
127
+ if (this.maxAgeStr) {
128
+ headers['Access-Control-Max-Age'] = this.maxAgeStr;
129
+ }
130
+
131
+ return headers;
132
+ }
133
+
134
+ private buildMatcher(origins: CorsOrigin): OriginMatcher {
135
+ if (origins === '*') return () => true;
136
+ if (typeof origins === 'string') return (o) => o === origins;
137
+ if (Array.isArray(origins)) {
138
+ const set = new Set(origins);
139
+ return (o) => set.has(o);
140
+ }
141
+ if (origins instanceof RegExp) return (o) => origins.test(o);
142
+ if (typeof origins === 'function') return origins;
143
+ return () => false;
144
+ }
145
+ }
@@ -1,63 +1,63 @@
1
- import { CONTROLLER_META, ROUTES_META } from '../metadata';
2
- import type { ControllerOptions, ControllerMeta } from '../metadata';
3
-
4
- /**
5
- * Normalizes path or options to ControllerOptions.
6
- */
7
- function normalizeOptions(pathOrOptions?: string | ControllerOptions): ControllerOptions {
8
- if (!pathOrOptions) {
9
- return {};
10
- }
11
-
12
- if (typeof pathOrOptions === 'string') {
13
- return { path: pathOrOptions };
14
- }
15
-
16
- return pathOrOptions;
17
- }
18
-
19
- /**
20
- * Normalizes a path to start with / and not end with /.
21
- */
22
- function normalizePath(path: string): string {
23
- if (!path) return '';
24
-
25
- let normalized = path.startsWith('/') ? path : '/' + path;
26
-
27
- if (normalized !== '/' && normalized.endsWith('/')) {
28
- normalized = normalized.slice(0, -1);
29
- }
30
-
31
- return normalized;
32
- }
33
-
34
- /**
35
- * Marks a class as a controller with a base path.
36
- *
37
- * @example
38
- * // Simple path
39
- * @Controller('/users')
40
- *
41
- * @example
42
- * // With options
43
- * @Controller({ path: '/users', children: [ProfileController] })
44
- */
45
- export function Controller(pathOrOptions?: string | ControllerOptions): ClassDecorator {
46
- return (target) => {
47
- const options = normalizeOptions(pathOrOptions);
48
- const path = normalizePath(options.path || '');
49
-
50
- const meta: ControllerMeta = {
51
- path,
52
- scope: options.scope,
53
- children: options.children
54
- };
55
-
56
- Reflect.defineMetadata(CONTROLLER_META, meta, target);
57
-
58
- // Ensure routes array exists
59
- if (!Reflect.hasMetadata(ROUTES_META, target)) {
60
- Reflect.defineMetadata(ROUTES_META, [], target);
61
- }
62
- };
63
- }
1
+ import { CONTROLLER_META, ROUTES_META } from '../metadata';
2
+ import type { ControllerOptions, ControllerMeta } from '../metadata';
3
+
4
+ /**
5
+ * Normalizes path or options to ControllerOptions.
6
+ */
7
+ function normalizeOptions(pathOrOptions?: string | ControllerOptions): ControllerOptions {
8
+ if (!pathOrOptions) {
9
+ return {};
10
+ }
11
+
12
+ if (typeof pathOrOptions === 'string') {
13
+ return { path: pathOrOptions };
14
+ }
15
+
16
+ return pathOrOptions;
17
+ }
18
+
19
+ /**
20
+ * Normalizes a path to start with / and not end with /.
21
+ */
22
+ function normalizePath(path: string): string {
23
+ if (!path) return '';
24
+
25
+ let normalized = path.startsWith('/') ? path : '/' + path;
26
+
27
+ if (normalized !== '/' && normalized.endsWith('/')) {
28
+ normalized = normalized.slice(0, -1);
29
+ }
30
+
31
+ return normalized;
32
+ }
33
+
34
+ /**
35
+ * Marks a class as a controller with a base path.
36
+ *
37
+ * @example
38
+ * // Simple path
39
+ * @Controller('/users')
40
+ *
41
+ * @example
42
+ * // With options
43
+ * @Controller({ path: '/users', children: [ProfileController] })
44
+ */
45
+ export function Controller(pathOrOptions?: string | ControllerOptions): ClassDecorator {
46
+ return (target) => {
47
+ const options = normalizeOptions(pathOrOptions);
48
+ const path = normalizePath(options.path || '');
49
+
50
+ const meta: ControllerMeta = {
51
+ path,
52
+ scope: options.scope,
53
+ children: options.children
54
+ };
55
+
56
+ Reflect.defineMetadata(CONTROLLER_META, meta, target);
57
+
58
+ // Ensure routes array exists
59
+ if (!Reflect.hasMetadata(ROUTES_META, target)) {
60
+ Reflect.defineMetadata(ROUTES_META, [], target);
61
+ }
62
+ };
63
+ }
@@ -1,16 +1,16 @@
1
- import { INJECT_META } from '../metadata';
2
- import type { Token } from '../container/Container';
3
-
4
- /**
5
- * Explicitly specifies which token to inject.
6
- * Useful for interfaces or when automatic detection fails.
7
- */
8
- export function Inject(token: Token): ParameterDecorator {
9
- return (target, propertyKey, parameterIndex) => {
10
- const existing: Map<number, Token> = Reflect.getMetadata(INJECT_META, target) || new Map();
11
-
12
- existing.set(parameterIndex, token);
13
-
14
- Reflect.defineMetadata(INJECT_META, existing, target);
15
- };
16
- }
1
+ import { INJECT_META } from '../metadata';
2
+ import type { Token } from '../container/Container';
3
+
4
+ /**
5
+ * Explicitly specifies which token to inject.
6
+ * Useful for interfaces or when automatic detection fails.
7
+ */
8
+ export function Inject(token: Token): ParameterDecorator {
9
+ return (target, propertyKey, parameterIndex) => {
10
+ const existing: Map<number, Token> = Reflect.getMetadata(INJECT_META, target) || new Map();
11
+
12
+ existing.set(parameterIndex, token);
13
+
14
+ Reflect.defineMetadata(INJECT_META, existing, target);
15
+ };
16
+ }
@@ -1,22 +1,22 @@
1
- import { MIDDLEWARE_META, type MiddlewareInfo } from '../metadata';
2
-
3
- /**
4
- * Middleware decorator.
5
- * Can be applied to controllers or individual methods.
6
- */
7
- export function Use(...middlewares: Function[]): ClassDecorator & MethodDecorator {
8
- return function (target: any, propertyKey?: string) {
9
- const isMethod = propertyKey !== undefined;
10
- const metaTarget = isMethod ? target.constructor : target;
11
- const existing: MiddlewareInfo[] = Reflect.getMetadata(MIDDLEWARE_META, metaTarget) || [];
12
-
13
- for (const handler of middlewares) {
14
- existing.push({
15
- handler,
16
- target: isMethod ? propertyKey : undefined
17
- });
18
- }
19
-
20
- Reflect.defineMetadata(MIDDLEWARE_META, existing, metaTarget);
21
- } as ClassDecorator & MethodDecorator;
22
- }
1
+ import { MIDDLEWARE_META, type MiddlewareInfo } from '../metadata';
2
+
3
+ /**
4
+ * Middleware decorator.
5
+ * Can be applied to controllers or individual methods.
6
+ */
7
+ export function Use(...middlewares: Function[]): ClassDecorator & MethodDecorator {
8
+ return function (target: any, propertyKey?: string) {
9
+ const isMethod = propertyKey !== undefined;
10
+ const metaTarget = isMethod ? target.constructor : target;
11
+ const existing: MiddlewareInfo[] = Reflect.getMetadata(MIDDLEWARE_META, metaTarget) || [];
12
+
13
+ for (const handler of middlewares) {
14
+ existing.push({
15
+ handler,
16
+ target: isMethod ? propertyKey : undefined
17
+ });
18
+ }
19
+
20
+ Reflect.defineMetadata(MIDDLEWARE_META, existing, metaTarget);
21
+ } as ClassDecorator & MethodDecorator;
22
+ }
@@ -1,18 +1,18 @@
1
- import { SERVICE_META } from '../metadata';
2
- import { Scope } from '../container/Container';
3
-
4
- export interface ServiceOptions {
5
- scope?: Scope;
6
- }
7
-
8
- /**
9
- * Marks a class as an injectable service.
10
- * Services are singleton by default.
11
- */
12
- export function Service(options: ServiceOptions = {}): ClassDecorator {
13
- return (target) => {
14
- Reflect.defineMetadata(SERVICE_META, {
15
- scope: options.scope ?? Scope.SINGLETON
16
- }, target);
17
- };
18
- }
1
+ import { SERVICE_META } from '../metadata';
2
+ import { Scope } from '../container/Container';
3
+
4
+ export interface ServiceOptions {
5
+ scope?: Scope;
6
+ }
7
+
8
+ /**
9
+ * Marks a class as an injectable service.
10
+ * Services are singleton by default.
11
+ */
12
+ export function Service(options: ServiceOptions = {}): ClassDecorator {
13
+ return (target) => {
14
+ Reflect.defineMetadata(SERVICE_META, {
15
+ scope: options.scope ?? Scope.SINGLETON
16
+ }, target);
17
+ };
18
+ }
@@ -1,58 +1,58 @@
1
- import { ROUTES_META, type RouteInfo } from '../metadata';
2
-
3
- type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options';
4
-
5
- /**
6
- * Creates a method decorator for HTTP methods.
7
- * Supports both legacy decorators (experimentalDecorators) and TS5 stage 3 decorators.
8
- */
9
- function createMethodDecorator(method: HttpMethod) {
10
- return function (path: string = ''): any {
11
- return function (
12
- targetOrMethod: any,
13
- contextOrPropertyKey?: string | symbol | ClassMethodDecoratorContext,
14
- descriptor?: PropertyDescriptor
15
- ): any {
16
- // TS5 Stage 3 decorators: context is ClassMethodDecoratorContext
17
- if (contextOrPropertyKey && typeof contextOrPropertyKey === 'object' && 'kind' in contextOrPropertyKey) {
18
- const context = contextOrPropertyKey as ClassMethodDecoratorContext;
19
-
20
- context.addInitializer(function (this: any) {
21
- const constructor = this.constructor;
22
- const routes: RouteInfo[] = Reflect.getMetadata(ROUTES_META, constructor) || [];
23
-
24
- routes.push({
25
- method,
26
- path: path.startsWith('/') ? path : '/' + path,
27
- handlerName: String(context.name)
28
- });
29
-
30
- Reflect.defineMetadata(ROUTES_META, routes, constructor);
31
- });
32
-
33
- return targetOrMethod;
34
- }
35
-
36
- // Legacy decorators (experimentalDecorators: true)
37
- const constructor = targetOrMethod.constructor;
38
- const propertyKey = contextOrPropertyKey as string | symbol;
39
- const routes: RouteInfo[] = Reflect.getMetadata(ROUTES_META, constructor) || [];
40
-
41
- routes.push({
42
- method,
43
- path: path.startsWith('/') ? path : '/' + path,
44
- handlerName: String(propertyKey)
45
- });
46
-
47
- Reflect.defineMetadata(ROUTES_META, routes, constructor);
48
- };
49
- };
50
- }
51
-
52
- export const Get = createMethodDecorator('get');
53
- export const Post = createMethodDecorator('post');
54
- export const Put = createMethodDecorator('put');
55
- export const Delete = createMethodDecorator('delete');
56
- export const Patch = createMethodDecorator('patch');
57
- export const Head = createMethodDecorator('head');
58
- export const Options = createMethodDecorator('options');
1
+ import { ROUTES_META, type RouteInfo } from '../metadata';
2
+
3
+ type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options';
4
+
5
+ /**
6
+ * Creates a method decorator for HTTP methods.
7
+ * Supports both legacy decorators (experimentalDecorators) and TS5 stage 3 decorators.
8
+ */
9
+ function createMethodDecorator(method: HttpMethod) {
10
+ return function (path: string = ''): any {
11
+ return function (
12
+ targetOrMethod: any,
13
+ contextOrPropertyKey?: string | symbol | ClassMethodDecoratorContext,
14
+ descriptor?: PropertyDescriptor
15
+ ): any {
16
+ // TS5 Stage 3 decorators: context is ClassMethodDecoratorContext
17
+ if (contextOrPropertyKey && typeof contextOrPropertyKey === 'object' && 'kind' in contextOrPropertyKey) {
18
+ const context = contextOrPropertyKey as ClassMethodDecoratorContext;
19
+
20
+ context.addInitializer(function (this: any) {
21
+ const constructor = this.constructor;
22
+ const routes: RouteInfo[] = Reflect.getMetadata(ROUTES_META, constructor) || [];
23
+
24
+ routes.push({
25
+ method,
26
+ path: path.startsWith('/') ? path : '/' + path,
27
+ handlerName: String(context.name)
28
+ });
29
+
30
+ Reflect.defineMetadata(ROUTES_META, routes, constructor);
31
+ });
32
+
33
+ return targetOrMethod;
34
+ }
35
+
36
+ // Legacy decorators (experimentalDecorators: true)
37
+ const constructor = targetOrMethod.constructor;
38
+ const propertyKey = contextOrPropertyKey as string | symbol;
39
+ const routes: RouteInfo[] = Reflect.getMetadata(ROUTES_META, constructor) || [];
40
+
41
+ routes.push({
42
+ method,
43
+ path: path.startsWith('/') ? path : '/' + path,
44
+ handlerName: String(propertyKey)
45
+ });
46
+
47
+ Reflect.defineMetadata(ROUTES_META, routes, constructor);
48
+ };
49
+ };
50
+ }
51
+
52
+ export const Get = createMethodDecorator('get');
53
+ export const Post = createMethodDecorator('post');
54
+ export const Put = createMethodDecorator('put');
55
+ export const Delete = createMethodDecorator('delete');
56
+ export const Patch = createMethodDecorator('patch');
57
+ export const Head = createMethodDecorator('head');
58
+ export const Options = createMethodDecorator('options');