@carno.js/core 1.1.0 → 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.
- package/LICENSE +21 -21
- package/README.md +188 -188
- package/dist/Carno.js +46 -26
- package/dist/Carno.mjs +46 -26
- package/dist/bun/index.js +4 -4
- package/dist/bun/index.js.map +29 -29
- package/package.json +2 -2
- package/src/Carno.ts +718 -673
- package/src/DefaultRoutes.ts +34 -34
- package/src/cache/CacheDriver.ts +50 -50
- package/src/cache/CacheService.ts +139 -139
- package/src/cache/MemoryDriver.ts +104 -104
- package/src/cache/RedisDriver.ts +116 -116
- package/src/compiler/JITCompiler.ts +167 -167
- package/src/container/Container.ts +168 -168
- package/src/context/Context.ts +130 -130
- package/src/cors/CorsHandler.ts +145 -145
- package/src/decorators/Controller.ts +63 -63
- package/src/decorators/Inject.ts +16 -16
- package/src/decorators/Middleware.ts +22 -22
- package/src/decorators/Service.ts +18 -18
- package/src/decorators/methods.ts +58 -58
- package/src/decorators/params.ts +47 -47
- package/src/events/Lifecycle.ts +97 -97
- package/src/exceptions/HttpException.ts +99 -99
- package/src/index.ts +95 -95
- package/src/metadata.ts +46 -46
- package/src/middleware/CarnoMiddleware.ts +14 -14
- package/src/router/RadixRouter.ts +225 -225
- package/src/testing/TestHarness.ts +185 -185
- package/src/utils/Metadata.ts +43 -43
- package/src/utils/parseQuery.ts +161 -161
- package/src/validation/ValibotAdapter.ts +95 -95
- package/src/validation/ValidatorAdapter.ts +69 -69
- package/src/validation/ZodAdapter.ts +102 -102
- package/dist/Carno.d.js +0 -14
- package/dist/Carno.d.mjs +0 -1
- package/dist/DefaultRoutes.d.js +0 -13
- package/dist/DefaultRoutes.d.mjs +0 -0
- package/dist/cache/CacheDriver.d.js +0 -13
- package/dist/cache/CacheDriver.d.mjs +0 -0
- package/dist/cache/CacheService.d.js +0 -13
- package/dist/cache/CacheService.d.mjs +0 -0
- package/dist/cache/MemoryDriver.d.js +0 -13
- package/dist/cache/MemoryDriver.d.mjs +0 -0
- package/dist/cache/RedisDriver.d.js +0 -13
- package/dist/cache/RedisDriver.d.mjs +0 -0
- package/dist/compiler/JITCompiler.d.js +0 -13
- package/dist/compiler/JITCompiler.d.mjs +0 -0
- package/dist/container/Container.d.js +0 -13
- package/dist/container/Container.d.mjs +0 -0
- package/dist/context/Context.d.js +0 -13
- package/dist/context/Context.d.mjs +0 -0
- package/dist/cors/CorsHandler.d.js +0 -13
- package/dist/cors/CorsHandler.d.mjs +0 -0
- package/dist/decorators/Controller.d.js +0 -13
- package/dist/decorators/Controller.d.mjs +0 -0
- package/dist/decorators/Inject.d.js +0 -13
- package/dist/decorators/Inject.d.mjs +0 -0
- package/dist/decorators/Middleware.d.js +0 -13
- package/dist/decorators/Middleware.d.mjs +0 -0
- package/dist/decorators/Service.d.js +0 -13
- package/dist/decorators/Service.d.mjs +0 -0
- package/dist/decorators/methods.d.js +0 -13
- package/dist/decorators/methods.d.mjs +0 -0
- package/dist/decorators/params.d.js +0 -13
- package/dist/decorators/params.d.mjs +0 -0
- package/dist/events/Lifecycle.d.js +0 -13
- package/dist/events/Lifecycle.d.mjs +0 -0
- package/dist/exceptions/HttpException.d.js +0 -13
- package/dist/exceptions/HttpException.d.mjs +0 -0
- package/dist/index.d.js +0 -130
- package/dist/index.d.mjs +0 -78
- package/dist/metadata.d.js +0 -13
- package/dist/metadata.d.mjs +0 -0
- package/dist/middleware/CarnoMiddleware.d.js +0 -13
- package/dist/middleware/CarnoMiddleware.d.mjs +0 -0
- package/dist/router/RadixRouter.d.js +0 -13
- package/dist/router/RadixRouter.d.mjs +0 -0
- package/dist/testing/TestHarness.d.js +0 -13
- package/dist/testing/TestHarness.d.mjs +0 -0
- package/dist/utils/Metadata.d.js +0 -13
- package/dist/utils/Metadata.d.mjs +0 -0
- package/dist/utils/parseQuery.d.js +0 -13
- package/dist/utils/parseQuery.d.mjs +0 -0
- package/dist/validation/ValibotAdapter.d.js +0 -13
- package/dist/validation/ValibotAdapter.d.mjs +0 -0
- package/dist/validation/ValidatorAdapter.d.js +0 -13
- package/dist/validation/ValidatorAdapter.d.mjs +0 -0
- package/dist/validation/ZodAdapter.d.js +0 -13
- package/dist/validation/ZodAdapter.d.mjs +0 -0
- package/src/Carno.d.ts +0 -135
- package/src/DefaultRoutes.d.ts +0 -19
- package/src/cache/CacheDriver.d.ts +0 -43
- package/src/cache/CacheService.d.ts +0 -89
- package/src/cache/MemoryDriver.d.ts +0 -32
- package/src/cache/RedisDriver.d.ts +0 -34
- package/src/compiler/JITCompiler.d.ts +0 -36
- package/src/container/Container.d.ts +0 -38
- package/src/context/Context.d.ts +0 -36
- package/src/cors/CorsHandler.d.ts +0 -47
- package/src/decorators/Controller.d.ts +0 -13
- package/src/decorators/Inject.d.ts +0 -6
- package/src/decorators/Middleware.d.ts +0 -5
- package/src/decorators/Service.d.ts +0 -9
- package/src/decorators/methods.d.ts +0 -7
- package/src/decorators/params.d.ts +0 -13
- package/src/events/Lifecycle.d.ts +0 -54
- package/src/exceptions/HttpException.d.ts +0 -43
- package/src/index.d.ts +0 -42
- package/src/metadata.d.ts +0 -41
- package/src/middleware/CarnoMiddleware.d.ts +0 -12
- package/src/router/RadixRouter.d.ts +0 -19
- package/src/testing/TestHarness.d.ts +0 -71
- package/src/utils/Metadata.d.ts +0 -20
- package/src/utils/parseQuery.d.ts +0 -23
- package/src/validation/ValibotAdapter.d.ts +0 -30
- package/src/validation/ValidatorAdapter.d.ts +0 -54
- package/src/validation/ZodAdapter.d.ts +0 -35
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 carno.js
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 carno.js
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,188 +1,188 @@
|
|
|
1
|
-
# @carno.js/core
|
|
2
|
-
|
|
3
|
-
Ultra-fast, performance-first HTTP framework for Bun.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
bun add @carno.js/core
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Prerequisites
|
|
12
|
-
|
|
13
|
-
Enable decorators in your `tsconfig.json`:
|
|
14
|
-
|
|
15
|
-
```json
|
|
16
|
-
{
|
|
17
|
-
"compilerOptions": {
|
|
18
|
-
"experimentalDecorators": true,
|
|
19
|
-
"emitDecoratorMetadata": true
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Quick Start
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
import { Carno, Controller, Get, Service, Param } from '@carno.js/core';
|
|
28
|
-
|
|
29
|
-
@Service()
|
|
30
|
-
class GreetService {
|
|
31
|
-
greet(name: string) {
|
|
32
|
-
return `Hello, ${name}!`;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@Controller('/greet')
|
|
37
|
-
class GreetController {
|
|
38
|
-
constructor(private greetService: GreetService) {}
|
|
39
|
-
|
|
40
|
-
@Get('/:name')
|
|
41
|
-
greet(@Param('name') name: string) {
|
|
42
|
-
return { message: this.greetService.greet(name) };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const app = new Carno();
|
|
47
|
-
app.services([GreetService]);
|
|
48
|
-
app.controllers([GreetController]);
|
|
49
|
-
app.listen(3000);
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## API Overview
|
|
53
|
-
|
|
54
|
-
### Application
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
const app = new Carno(config?: CarnoConfig);
|
|
58
|
-
|
|
59
|
-
app.controllers([...]); // Register controllers
|
|
60
|
-
app.services([...]); // Register services
|
|
61
|
-
app.middlewares([...]); // Register global middlewares
|
|
62
|
-
app.use(plugin); // Use a plugin/module
|
|
63
|
-
await app.listen(3000); // Start server
|
|
64
|
-
await app.stop(); // Stop server
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Decorators
|
|
68
|
-
|
|
69
|
-
#### Controllers & Routes
|
|
70
|
-
|
|
71
|
-
| Decorator | Description |
|
|
72
|
-
| :--- | :--- |
|
|
73
|
-
| `@Controller(path?)` | Define a controller with optional base path |
|
|
74
|
-
| `@Get(path?)` | Handle GET requests |
|
|
75
|
-
| `@Post(path?)` | Handle POST requests |
|
|
76
|
-
| `@Put(path?)` | Handle PUT requests |
|
|
77
|
-
| `@Delete(path?)` | Handle DELETE requests |
|
|
78
|
-
| `@Patch(path?)` | Handle PATCH requests |
|
|
79
|
-
|
|
80
|
-
#### Parameters
|
|
81
|
-
|
|
82
|
-
| Decorator | Description |
|
|
83
|
-
| :--- | :--- |
|
|
84
|
-
| `@Param(key?)` | Route parameters |
|
|
85
|
-
| `@Query(key?)` | Query string parameters |
|
|
86
|
-
| `@Body(key?)` | Request body |
|
|
87
|
-
| `@Header(key?)` | Request headers |
|
|
88
|
-
| `@Req()` | Raw Request object |
|
|
89
|
-
| `@Ctx()` | Full Context object |
|
|
90
|
-
|
|
91
|
-
#### Dependency Injection
|
|
92
|
-
|
|
93
|
-
| Decorator | Description |
|
|
94
|
-
| :--- | :--- |
|
|
95
|
-
| `@Service(options?)` | Mark class as injectable service |
|
|
96
|
-
| `@Inject(token)` | Inject by token (for interfaces) |
|
|
97
|
-
|
|
98
|
-
#### Middleware
|
|
99
|
-
|
|
100
|
-
| Decorator | Description |
|
|
101
|
-
| :--- | :--- |
|
|
102
|
-
| `@Middleware(middleware)` | Apply middleware to controller/route |
|
|
103
|
-
|
|
104
|
-
#### Lifecycle
|
|
105
|
-
|
|
106
|
-
| Decorator | Description |
|
|
107
|
-
| :--- | :--- |
|
|
108
|
-
| `@OnApplicationInit()` | Called after DI container is ready |
|
|
109
|
-
| `@OnApplicationBoot()` | Called when server starts listening |
|
|
110
|
-
| `@OnApplicationShutdown()` | Called when server is stopping |
|
|
111
|
-
|
|
112
|
-
### Validation
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
import { z } from 'zod';
|
|
116
|
-
import { Schema, ZodAdapter } from '@carno.js/core';
|
|
117
|
-
|
|
118
|
-
@Schema(z.object({
|
|
119
|
-
name: z.string().min(2),
|
|
120
|
-
email: z.string().email(),
|
|
121
|
-
}))
|
|
122
|
-
class CreateUserDto {
|
|
123
|
-
name!: string;
|
|
124
|
-
email!: string;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const app = new Carno({ validation: new ZodAdapter() });
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### CORS
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
const app = new Carno({
|
|
134
|
-
cors: {
|
|
135
|
-
origins: '*', // or specific origin(s)
|
|
136
|
-
methods: ['GET', 'POST'],
|
|
137
|
-
headers: ['Content-Type'],
|
|
138
|
-
credentials: true,
|
|
139
|
-
maxAge: 86400,
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Exceptions
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
import {
|
|
148
|
-
BadRequestException,
|
|
149
|
-
UnauthorizedException,
|
|
150
|
-
ForbiddenException,
|
|
151
|
-
NotFoundException,
|
|
152
|
-
ConflictException,
|
|
153
|
-
InternalServerErrorException,
|
|
154
|
-
} from '@carno.js/core';
|
|
155
|
-
|
|
156
|
-
throw new NotFoundException('User not found');
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Testing
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
import { withTestApp } from '@carno.js/core';
|
|
163
|
-
|
|
164
|
-
await withTestApp(
|
|
165
|
-
async (harness) => {
|
|
166
|
-
const res = await harness.get('/users');
|
|
167
|
-
expect(res.status).toBe(200);
|
|
168
|
-
},
|
|
169
|
-
{ controllers: [UserController], listen: true }
|
|
170
|
-
);
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
## Configuration
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
interface CarnoConfig {
|
|
177
|
-
exports?: (Token | ProviderConfig)[];
|
|
178
|
-
globalMiddlewares?: MiddlewareHandler[];
|
|
179
|
-
disableStartupLog?: boolean;
|
|
180
|
-
cors?: CorsConfig;
|
|
181
|
-
validation?: ValidatorAdapter | boolean;
|
|
182
|
-
cache?: CacheConfig | boolean;
|
|
183
|
-
}
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
## License
|
|
187
|
-
|
|
188
|
-
MIT
|
|
1
|
+
# @carno.js/core
|
|
2
|
+
|
|
3
|
+
Ultra-fast, performance-first HTTP framework for Bun.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @carno.js/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
Enable decorators in your `tsconfig.json`:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"compilerOptions": {
|
|
18
|
+
"experimentalDecorators": true,
|
|
19
|
+
"emitDecoratorMetadata": true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { Carno, Controller, Get, Service, Param } from '@carno.js/core';
|
|
28
|
+
|
|
29
|
+
@Service()
|
|
30
|
+
class GreetService {
|
|
31
|
+
greet(name: string) {
|
|
32
|
+
return `Hello, ${name}!`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Controller('/greet')
|
|
37
|
+
class GreetController {
|
|
38
|
+
constructor(private greetService: GreetService) {}
|
|
39
|
+
|
|
40
|
+
@Get('/:name')
|
|
41
|
+
greet(@Param('name') name: string) {
|
|
42
|
+
return { message: this.greetService.greet(name) };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const app = new Carno();
|
|
47
|
+
app.services([GreetService]);
|
|
48
|
+
app.controllers([GreetController]);
|
|
49
|
+
app.listen(3000);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## API Overview
|
|
53
|
+
|
|
54
|
+
### Application
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const app = new Carno(config?: CarnoConfig);
|
|
58
|
+
|
|
59
|
+
app.controllers([...]); // Register controllers
|
|
60
|
+
app.services([...]); // Register services
|
|
61
|
+
app.middlewares([...]); // Register global middlewares
|
|
62
|
+
app.use(plugin); // Use a plugin/module
|
|
63
|
+
await app.listen(3000); // Start server
|
|
64
|
+
await app.stop(); // Stop server
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Decorators
|
|
68
|
+
|
|
69
|
+
#### Controllers & Routes
|
|
70
|
+
|
|
71
|
+
| Decorator | Description |
|
|
72
|
+
| :--- | :--- |
|
|
73
|
+
| `@Controller(path?)` | Define a controller with optional base path |
|
|
74
|
+
| `@Get(path?)` | Handle GET requests |
|
|
75
|
+
| `@Post(path?)` | Handle POST requests |
|
|
76
|
+
| `@Put(path?)` | Handle PUT requests |
|
|
77
|
+
| `@Delete(path?)` | Handle DELETE requests |
|
|
78
|
+
| `@Patch(path?)` | Handle PATCH requests |
|
|
79
|
+
|
|
80
|
+
#### Parameters
|
|
81
|
+
|
|
82
|
+
| Decorator | Description |
|
|
83
|
+
| :--- | :--- |
|
|
84
|
+
| `@Param(key?)` | Route parameters |
|
|
85
|
+
| `@Query(key?)` | Query string parameters |
|
|
86
|
+
| `@Body(key?)` | Request body |
|
|
87
|
+
| `@Header(key?)` | Request headers |
|
|
88
|
+
| `@Req()` | Raw Request object |
|
|
89
|
+
| `@Ctx()` | Full Context object |
|
|
90
|
+
|
|
91
|
+
#### Dependency Injection
|
|
92
|
+
|
|
93
|
+
| Decorator | Description |
|
|
94
|
+
| :--- | :--- |
|
|
95
|
+
| `@Service(options?)` | Mark class as injectable service |
|
|
96
|
+
| `@Inject(token)` | Inject by token (for interfaces) |
|
|
97
|
+
|
|
98
|
+
#### Middleware
|
|
99
|
+
|
|
100
|
+
| Decorator | Description |
|
|
101
|
+
| :--- | :--- |
|
|
102
|
+
| `@Middleware(middleware)` | Apply middleware to controller/route |
|
|
103
|
+
|
|
104
|
+
#### Lifecycle
|
|
105
|
+
|
|
106
|
+
| Decorator | Description |
|
|
107
|
+
| :--- | :--- |
|
|
108
|
+
| `@OnApplicationInit()` | Called after DI container is ready |
|
|
109
|
+
| `@OnApplicationBoot()` | Called when server starts listening |
|
|
110
|
+
| `@OnApplicationShutdown()` | Called when server is stopping |
|
|
111
|
+
|
|
112
|
+
### Validation
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { z } from 'zod';
|
|
116
|
+
import { Schema, ZodAdapter } from '@carno.js/core';
|
|
117
|
+
|
|
118
|
+
@Schema(z.object({
|
|
119
|
+
name: z.string().min(2),
|
|
120
|
+
email: z.string().email(),
|
|
121
|
+
}))
|
|
122
|
+
class CreateUserDto {
|
|
123
|
+
name!: string;
|
|
124
|
+
email!: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const app = new Carno({ validation: new ZodAdapter() });
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### CORS
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const app = new Carno({
|
|
134
|
+
cors: {
|
|
135
|
+
origins: '*', // or specific origin(s)
|
|
136
|
+
methods: ['GET', 'POST'],
|
|
137
|
+
headers: ['Content-Type'],
|
|
138
|
+
credentials: true,
|
|
139
|
+
maxAge: 86400,
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Exceptions
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import {
|
|
148
|
+
BadRequestException,
|
|
149
|
+
UnauthorizedException,
|
|
150
|
+
ForbiddenException,
|
|
151
|
+
NotFoundException,
|
|
152
|
+
ConflictException,
|
|
153
|
+
InternalServerErrorException,
|
|
154
|
+
} from '@carno.js/core';
|
|
155
|
+
|
|
156
|
+
throw new NotFoundException('User not found');
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Testing
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { withTestApp } from '@carno.js/core';
|
|
163
|
+
|
|
164
|
+
await withTestApp(
|
|
165
|
+
async (harness) => {
|
|
166
|
+
const res = await harness.get('/users');
|
|
167
|
+
expect(res.status).toBe(200);
|
|
168
|
+
},
|
|
169
|
+
{ controllers: [UserController], listen: true }
|
|
170
|
+
);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Configuration
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
interface CarnoConfig {
|
|
177
|
+
exports?: (Token | ProviderConfig)[];
|
|
178
|
+
globalMiddlewares?: MiddlewareHandler[];
|
|
179
|
+
disableStartupLog?: boolean;
|
|
180
|
+
cors?: CorsConfig;
|
|
181
|
+
validation?: ValidatorAdapter | boolean;
|
|
182
|
+
cache?: CacheConfig | boolean;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
MIT
|
package/dist/Carno.js
CHANGED
|
@@ -216,37 +216,57 @@ class Carno {
|
|
|
216
216
|
}
|
|
217
217
|
createHandler(compiled, params, middlewares, bodyDtoType) {
|
|
218
218
|
const handler = compiled.fn, hasMiddlewares = middlewares.length > 0, hasParams = params.length > 0, applyCors = this.hasCors ? this.applyCors.bind(this) : null, validator = bodyDtoType ? this.validator : null, hasMiddlewaresOrValidation = hasMiddlewares || !!validator;
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
219
|
+
if (!hasMiddlewaresOrValidation && !hasParams)
|
|
220
|
+
return compiled.isAsync ? async (req) => {
|
|
221
|
+
const ctx = new import_Context.Context(req), result = await handler(ctx), response = this.buildResponse(result);
|
|
222
|
+
return applyCors ? applyCors(response, req) : response;
|
|
223
|
+
} : (req) => {
|
|
224
|
+
const ctx = new import_Context.Context(req), result = handler(ctx), response = this.buildResponse(result);
|
|
225
|
+
return applyCors ? applyCors(response, req) : response;
|
|
226
|
+
};
|
|
227
|
+
if (!hasMiddlewaresOrValidation && hasParams)
|
|
228
|
+
return compiled.isAsync ? async (req) => {
|
|
229
|
+
const ctx = new import_Context.Context(req, req.params), result = await handler(ctx), response = this.buildResponse(result);
|
|
230
|
+
return applyCors ? applyCors(response, req) : response;
|
|
231
|
+
} : (req) => {
|
|
232
|
+
const ctx = new import_Context.Context(req, req.params), result = handler(ctx), response = this.buildResponse(result);
|
|
233
|
+
return applyCors ? applyCors(response, req) : response;
|
|
234
|
+
};
|
|
235
|
+
const coreHandler = async (ctx) => (validator && bodyDtoType && (await ctx.parseBody(), validator.validateOrThrow(bodyDtoType, ctx.body)), compiled.isAsync ? await handler(ctx) : handler(ctx)), chain = this.buildMiddlewareChain(
|
|
236
|
+
middlewares,
|
|
237
|
+
coreHandler,
|
|
238
|
+
this.buildResponse.bind(this)
|
|
239
|
+
);
|
|
240
|
+
return async (req) => {
|
|
241
|
+
const ctx = new import_Context.Context(req, req.params || {}), response = await chain(ctx);
|
|
240
242
|
return applyCors ? applyCors(response, req) : response;
|
|
241
243
|
};
|
|
242
244
|
}
|
|
243
245
|
resolveMiddleware(middleware) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
246
|
+
return typeof middleware == "function" && middleware.prototype?.handle ? { kind: "class", instance: this.container.get(middleware) } : { kind: "function", handler: middleware };
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Build an onion-style middleware chain.
|
|
250
|
+
* Wraps from inside-out so each middleware can run code before and after next().
|
|
251
|
+
*/
|
|
252
|
+
buildMiddlewareChain(middlewares, coreHandler, buildResponseFn) {
|
|
253
|
+
let chain = async (ctx) => {
|
|
254
|
+
const result = await coreHandler(ctx);
|
|
255
|
+
return buildResponseFn(result);
|
|
256
|
+
};
|
|
257
|
+
for (let i = middlewares.length - 1; i >= 0; i--) {
|
|
258
|
+
const mw = middlewares[i], nextLayer = chain;
|
|
259
|
+
mw.kind === "function" ? chain = async (ctx) => {
|
|
260
|
+
const result = await mw.handler(ctx);
|
|
261
|
+
return result instanceof Response ? result : nextLayer(ctx);
|
|
262
|
+
} : chain = async (ctx) => {
|
|
263
|
+
let response;
|
|
264
|
+
return await mw.instance.handle(ctx, async () => {
|
|
265
|
+
response = await nextLayer(ctx);
|
|
266
|
+
}), response ?? new Response(null, { status: 200 });
|
|
267
|
+
};
|
|
248
268
|
}
|
|
249
|
-
return
|
|
269
|
+
return chain;
|
|
250
270
|
}
|
|
251
271
|
/**
|
|
252
272
|
* Apply CORS headers to a response.
|
package/dist/Carno.mjs
CHANGED
|
@@ -208,37 +208,57 @@ class Carno {
|
|
|
208
208
|
}
|
|
209
209
|
createHandler(compiled, params, middlewares, bodyDtoType) {
|
|
210
210
|
const handler = compiled.fn, hasMiddlewares = middlewares.length > 0, hasParams = params.length > 0, applyCors = this.hasCors ? this.applyCors.bind(this) : null, validator = bodyDtoType ? this.validator : null, hasMiddlewaresOrValidation = hasMiddlewares || !!validator;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
211
|
+
if (!hasMiddlewaresOrValidation && !hasParams)
|
|
212
|
+
return compiled.isAsync ? async (req) => {
|
|
213
|
+
const ctx = new Context(req), result = await handler(ctx), response = this.buildResponse(result);
|
|
214
|
+
return applyCors ? applyCors(response, req) : response;
|
|
215
|
+
} : (req) => {
|
|
216
|
+
const ctx = new Context(req), result = handler(ctx), response = this.buildResponse(result);
|
|
217
|
+
return applyCors ? applyCors(response, req) : response;
|
|
218
|
+
};
|
|
219
|
+
if (!hasMiddlewaresOrValidation && hasParams)
|
|
220
|
+
return compiled.isAsync ? async (req) => {
|
|
221
|
+
const ctx = new Context(req, req.params), result = await handler(ctx), response = this.buildResponse(result);
|
|
222
|
+
return applyCors ? applyCors(response, req) : response;
|
|
223
|
+
} : (req) => {
|
|
224
|
+
const ctx = new Context(req, req.params), result = handler(ctx), response = this.buildResponse(result);
|
|
225
|
+
return applyCors ? applyCors(response, req) : response;
|
|
226
|
+
};
|
|
227
|
+
const coreHandler = async (ctx) => (validator && bodyDtoType && (await ctx.parseBody(), validator.validateOrThrow(bodyDtoType, ctx.body)), compiled.isAsync ? await handler(ctx) : handler(ctx)), chain = this.buildMiddlewareChain(
|
|
228
|
+
middlewares,
|
|
229
|
+
coreHandler,
|
|
230
|
+
this.buildResponse.bind(this)
|
|
231
|
+
);
|
|
232
|
+
return async (req) => {
|
|
233
|
+
const ctx = new Context(req, req.params || {}), response = await chain(ctx);
|
|
232
234
|
return applyCors ? applyCors(response, req) : response;
|
|
233
235
|
};
|
|
234
236
|
}
|
|
235
237
|
resolveMiddleware(middleware) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
238
|
+
return typeof middleware == "function" && middleware.prototype?.handle ? { kind: "class", instance: this.container.get(middleware) } : { kind: "function", handler: middleware };
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Build an onion-style middleware chain.
|
|
242
|
+
* Wraps from inside-out so each middleware can run code before and after next().
|
|
243
|
+
*/
|
|
244
|
+
buildMiddlewareChain(middlewares, coreHandler, buildResponseFn) {
|
|
245
|
+
let chain = async (ctx) => {
|
|
246
|
+
const result = await coreHandler(ctx);
|
|
247
|
+
return buildResponseFn(result);
|
|
248
|
+
};
|
|
249
|
+
for (let i = middlewares.length - 1; i >= 0; i--) {
|
|
250
|
+
const mw = middlewares[i], nextLayer = chain;
|
|
251
|
+
mw.kind === "function" ? chain = async (ctx) => {
|
|
252
|
+
const result = await mw.handler(ctx);
|
|
253
|
+
return result instanceof Response ? result : nextLayer(ctx);
|
|
254
|
+
} : chain = async (ctx) => {
|
|
255
|
+
let response;
|
|
256
|
+
return await mw.instance.handle(ctx, async () => {
|
|
257
|
+
response = await nextLayer(ctx);
|
|
258
|
+
}), response ?? new Response(null, { status: 200 });
|
|
259
|
+
};
|
|
240
260
|
}
|
|
241
|
-
return
|
|
261
|
+
return chain;
|
|
242
262
|
}
|
|
243
263
|
/**
|
|
244
264
|
* Apply CORS headers to a response.
|