@venizia/ignis-docs 0.0.1-7 → 0.0.1-9
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/package.json +12 -12
- package/wiki/changelogs/2025-12-17-refactor.md +22 -0
- package/wiki/changelogs/2025-12-18-performance-optimizations.md +192 -0
- package/wiki/changelogs/2025-12-18-repository-validation-security.md +445 -0
- package/wiki/changelogs/index.md +22 -0
- package/wiki/changelogs/v0.0.1-7-initial-architecture.md +137 -0
- package/wiki/changelogs/v0.0.1-8-model-repo-datasource-refactor.md +278 -0
- package/wiki/get-started/5-minute-quickstart.md +1 -1
- package/wiki/get-started/best-practices/api-usage-examples.md +12 -8
- package/wiki/get-started/best-practices/common-pitfalls.md +2 -2
- package/wiki/get-started/best-practices/data-modeling.md +14 -20
- package/wiki/get-started/building-a-crud-api.md +60 -75
- package/wiki/get-started/core-concepts/controllers.md +14 -14
- package/wiki/get-started/core-concepts/persistent.md +110 -130
- package/wiki/get-started/quickstart.md +1 -1
- package/wiki/references/base/controllers.md +40 -16
- package/wiki/references/base/datasources.md +195 -33
- package/wiki/references/base/dependency-injection.md +5 -5
- package/wiki/references/base/models.md +398 -28
- package/wiki/references/base/repositories.md +475 -22
- package/wiki/references/components/authentication.md +224 -7
- package/wiki/references/components/health-check.md +1 -1
- package/wiki/references/components/swagger.md +1 -1
- package/wiki/references/helpers/inversion.md +8 -3
- package/wiki/references/src-details/core.md +6 -5
- package/wiki/references/src-details/inversion.md +4 -4
- package/wiki/references/utilities/request.md +16 -7
|
@@ -9,8 +9,9 @@ JWT-based authentication and authorization system for Ignis applications.
|
|
|
9
9
|
| **AuthenticateComponent** | Main component registering auth services and controllers |
|
|
10
10
|
| **AuthenticationStrategyRegistry** | Singleton managing available auth strategies |
|
|
11
11
|
| **JWTAuthenticationStrategy** | JWT verification using `JWTTokenService` |
|
|
12
|
-
| **JWTTokenService** | Generate, verify, encrypt/decrypt JWT tokens |
|
|
12
|
+
| **JWTTokenService** | Generate, verify, encrypt/decrypt JWT tokens (safely handles undefined/null) |
|
|
13
13
|
| **IAuthService** | Interface for custom auth implementation (sign-in, sign-up) |
|
|
14
|
+
| **defineAuthController** | Factory function for creating custom auth controllers |
|
|
14
15
|
|
|
15
16
|
### Key Environment Variables
|
|
16
17
|
|
|
@@ -20,12 +21,26 @@ JWT-based authentication and authorization system for Ignis applications.
|
|
|
20
21
|
| `APP_ENV_JWT_SECRET` | Sign and verify JWT signature | ✅ Yes |
|
|
21
22
|
| `APP_ENV_JWT_EXPIRES_IN` | Token expiration (seconds) | Optional |
|
|
22
23
|
|
|
24
|
+
### Authentication Options Configuration
|
|
25
|
+
|
|
26
|
+
| Option | Type | Description |
|
|
27
|
+
|--------|------|-------------|
|
|
28
|
+
| `restOptions.useAuthController` | `boolean` | Enable/disable built-in auth controller (default: `false`) |
|
|
29
|
+
| `restOptions.controllerOpts` | `TDefineAuthControllerOpts` | Configuration for built-in auth controller (required if `useAuthController` is `true`) |
|
|
30
|
+
| `restOptions.controllerOpts.restPath` | `string` | Base path for auth endpoints (default: `/auth`) |
|
|
31
|
+
| `restOptions.controllerOpts.serviceKey` | `string` | Dependency injection key for auth service (default: `services.AuthenticationService`) |
|
|
32
|
+
| `restOptions.controllerOpts.requireAuthenticatedSignUp` | `boolean` | Whether sign-up requires authentication (default: `false`) |
|
|
33
|
+
| `restOptions.controllerOpts.payload` | `object` | Custom Zod schemas for request/response payloads |
|
|
34
|
+
| `alwaysAllowPaths` | `string[]` | Array of paths that bypass authentication |
|
|
35
|
+
| `tokenOptions` | `IJWTTokenServiceOptions` | JWT token configuration |
|
|
36
|
+
|
|
23
37
|
## Architecture Components
|
|
24
38
|
|
|
25
|
-
- **`AuthenticateComponent`**: Registers all necessary services and
|
|
39
|
+
- **`AuthenticateComponent`**: Registers all necessary services and optionally the authentication controller
|
|
26
40
|
- **`AuthenticationStrategyRegistry`**: Singleton managing authentication strategies
|
|
27
41
|
- **`JWTAuthenticationStrategy`**: JWT strategy implementation using `JWTTokenService`
|
|
28
|
-
- **`JWTTokenService`**: Generates, verifies, encrypts/decrypts JWT payloads
|
|
42
|
+
- **`JWTTokenService`**: Generates, verifies, encrypts/decrypts JWT payloads (handles undefined/null values safely)
|
|
43
|
+
- **`defineAuthController`**: Factory function to create customizable authentication controller
|
|
29
44
|
- **Protected Routes**: Use `authStrategies` in route configs to secure endpoints
|
|
30
45
|
|
|
31
46
|
## Implementation Details
|
|
@@ -62,6 +77,8 @@ APP_ENV_JWT_EXPIRES_IN=86400
|
|
|
62
77
|
|
|
63
78
|
In `src/application.ts`, register the `AuthenticateComponent` and the `JWTAuthenticationStrategy`. You also need to provide an `AuthenticationService`.
|
|
64
79
|
|
|
80
|
+
**Basic Setup (without built-in auth controller):**
|
|
81
|
+
|
|
65
82
|
```typescript
|
|
66
83
|
// src/application.ts
|
|
67
84
|
import {
|
|
@@ -79,7 +96,116 @@ export class Application extends BaseApplication {
|
|
|
79
96
|
|
|
80
97
|
registerAuth() {
|
|
81
98
|
this.service(AuthenticationService);
|
|
82
|
-
this.component(AuthenticateComponent
|
|
99
|
+
this.component(AuthenticateComponent, {
|
|
100
|
+
restOptions: {
|
|
101
|
+
useAuthController: false, // Default: controller not registered
|
|
102
|
+
},
|
|
103
|
+
alwaysAllowPaths: [],
|
|
104
|
+
tokenOptions: {
|
|
105
|
+
applicationSecret: process.env.APP_ENV_APPLICATION_SECRET,
|
|
106
|
+
jwtSecret: process.env.APP_ENV_JWT_SECRET,
|
|
107
|
+
getTokenExpiresFn: () => Number(process.env.APP_ENV_JWT_EXPIRES_IN || 86400),
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
AuthenticationStrategyRegistry.getInstance().register({
|
|
111
|
+
container: this,
|
|
112
|
+
name: Authentication.STRATEGY_JWT,
|
|
113
|
+
strategy: JWTAuthenticationStrategy,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
preConfigure(): ValueOrPromise<void> {
|
|
118
|
+
// ...
|
|
119
|
+
this.registerAuth();
|
|
120
|
+
// ...
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Advanced Setup (with built-in auth controller):**
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import {
|
|
129
|
+
AuthenticateComponent,
|
|
130
|
+
Authentication,
|
|
131
|
+
AuthenticationStrategyRegistry,
|
|
132
|
+
JWTAuthenticationStrategy,
|
|
133
|
+
BaseApplication,
|
|
134
|
+
ValueOrPromise,
|
|
135
|
+
} from '@venizia/ignis';
|
|
136
|
+
import { z } from '@hono/zod-openapi';
|
|
137
|
+
import { AuthenticationService } from './services';
|
|
138
|
+
|
|
139
|
+
export class Application extends BaseApplication {
|
|
140
|
+
// ...
|
|
141
|
+
|
|
142
|
+
registerAuth() {
|
|
143
|
+
this.service(AuthenticationService);
|
|
144
|
+
this.component(AuthenticateComponent, {
|
|
145
|
+
restOptions: {
|
|
146
|
+
useAuthController: true, // Enable built-in auth controller
|
|
147
|
+
controllerOpts: {
|
|
148
|
+
restPath: '/auth', // Base path for auth endpoints
|
|
149
|
+
serviceKey: 'services.AuthenticationService', // Default service key
|
|
150
|
+
requireAuthenticatedSignUp: false, // Whether sign-up requires authentication
|
|
151
|
+
payload: {
|
|
152
|
+
signIn: {
|
|
153
|
+
request: {
|
|
154
|
+
schema: z.object({
|
|
155
|
+
identifier: z.object({
|
|
156
|
+
type: z.string(),
|
|
157
|
+
value: z.string(),
|
|
158
|
+
}),
|
|
159
|
+
credential: z.object({
|
|
160
|
+
type: z.string(),
|
|
161
|
+
value: z.string(),
|
|
162
|
+
}),
|
|
163
|
+
})
|
|
164
|
+
},
|
|
165
|
+
response: {
|
|
166
|
+
schema: z.object({
|
|
167
|
+
token: z.string(),
|
|
168
|
+
})
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
signUp: {
|
|
172
|
+
request: {
|
|
173
|
+
schema: z.object({
|
|
174
|
+
username: z.string(),
|
|
175
|
+
email: z.string().email(),
|
|
176
|
+
password: z.string().min(8),
|
|
177
|
+
})
|
|
178
|
+
},
|
|
179
|
+
response: {
|
|
180
|
+
schema: z.object({
|
|
181
|
+
token: z.string(),
|
|
182
|
+
userId: z.string(),
|
|
183
|
+
})
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
changePassword: {
|
|
187
|
+
request: {
|
|
188
|
+
schema: z.object({
|
|
189
|
+
oldPassword: z.string(),
|
|
190
|
+
newPassword: z.string().min(8),
|
|
191
|
+
})
|
|
192
|
+
},
|
|
193
|
+
response: {
|
|
194
|
+
schema: z.object({
|
|
195
|
+
success: z.boolean(),
|
|
196
|
+
})
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
alwaysAllowPaths: [],
|
|
203
|
+
tokenOptions: {
|
|
204
|
+
applicationSecret: process.env.APP_ENV_APPLICATION_SECRET,
|
|
205
|
+
jwtSecret: process.env.APP_ENV_JWT_SECRET,
|
|
206
|
+
getTokenExpiresFn: () => Number(process.env.APP_ENV_JWT_EXPIRES_IN || 86400),
|
|
207
|
+
},
|
|
208
|
+
});
|
|
83
209
|
AuthenticationStrategyRegistry.getInstance().register({
|
|
84
210
|
container: this,
|
|
85
211
|
name: Authentication.STRATEGY_JWT,
|
|
@@ -158,7 +284,95 @@ export class AuthenticationService extends BaseService implements IAuthService {
|
|
|
158
284
|
|
|
159
285
|
This service is then registered in `application.ts` as shown in the previous step. It injects the `JWTTokenService` (provided by the `AuthenticateComponent`) to generate a token upon successful sign-in.
|
|
160
286
|
|
|
161
|
-
#### 3.
|
|
287
|
+
#### 3. Custom Authentication Controller (Optional)
|
|
288
|
+
|
|
289
|
+
If you need more control over the authentication endpoints, you can create a custom controller using the `defineAuthController` factory function.
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// src/controllers/custom-auth.controller.ts
|
|
293
|
+
import { defineAuthController } from '@venizia/ignis';
|
|
294
|
+
import { z } from '@hono/zod-openapi';
|
|
295
|
+
|
|
296
|
+
export const CustomAuthController = defineAuthController({
|
|
297
|
+
restPath: '/api/auth',
|
|
298
|
+
serviceKey: 'services.AuthenticationService',
|
|
299
|
+
requireAuthenticatedSignUp: true, // Require authentication for sign-up
|
|
300
|
+
payload: {
|
|
301
|
+
signIn: {
|
|
302
|
+
request: {
|
|
303
|
+
schema: z.object({
|
|
304
|
+
email: z.string().email(),
|
|
305
|
+
password: z.string(),
|
|
306
|
+
}),
|
|
307
|
+
},
|
|
308
|
+
response: {
|
|
309
|
+
schema: z.object({
|
|
310
|
+
token: z.string(),
|
|
311
|
+
expiresIn: z.number(),
|
|
312
|
+
}),
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
signUp: {
|
|
316
|
+
request: {
|
|
317
|
+
schema: z.object({
|
|
318
|
+
email: z.string().email(),
|
|
319
|
+
password: z.string().min(8),
|
|
320
|
+
firstName: z.string(),
|
|
321
|
+
lastName: z.string(),
|
|
322
|
+
}),
|
|
323
|
+
},
|
|
324
|
+
response: {
|
|
325
|
+
schema: z.object({
|
|
326
|
+
token: z.string(),
|
|
327
|
+
userId: z.string(),
|
|
328
|
+
}),
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
changePassword: {
|
|
332
|
+
request: {
|
|
333
|
+
schema: z.object({
|
|
334
|
+
currentPassword: z.string(),
|
|
335
|
+
newPassword: z.string().min(8),
|
|
336
|
+
}),
|
|
337
|
+
},
|
|
338
|
+
response: {
|
|
339
|
+
schema: z.object({
|
|
340
|
+
success: z.boolean(),
|
|
341
|
+
message: z.string().optional(),
|
|
342
|
+
}),
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Then register it in your application:
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
// src/application.ts
|
|
353
|
+
import { CustomAuthController } from './controllers/custom-auth.controller';
|
|
354
|
+
|
|
355
|
+
export class Application extends BaseApplication {
|
|
356
|
+
registerAuth() {
|
|
357
|
+
this.service(AuthenticationService);
|
|
358
|
+
this.component(AuthenticateComponent, {
|
|
359
|
+
restOptions: { useAuthController: false }, // Disable built-in controller
|
|
360
|
+
// ... other options
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Register your custom controller
|
|
364
|
+
this.controller(CustomAuthController);
|
|
365
|
+
|
|
366
|
+
AuthenticationStrategyRegistry.getInstance().register({
|
|
367
|
+
container: this,
|
|
368
|
+
name: Authentication.STRATEGY_JWT,
|
|
369
|
+
strategy: JWTAuthenticationStrategy,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
#### 4. Securing Routes
|
|
162
376
|
|
|
163
377
|
In your controllers, use decorator-based routing (`@get`, `@post`, etc.) with the `authStrategies` property in the `configs` object to protect endpoints. This will automatically run the necessary authentication middlewares and attach the authenticated user to the Hono `Context`, which can then be accessed type-safely using `TRouteContext`.
|
|
164
378
|
|
|
@@ -199,12 +413,15 @@ export class TestController extends BaseController {
|
|
|
199
413
|
secureData(c: TRouteContext<typeof SECURE_ROUTE_CONFIG>) {
|
|
200
414
|
// 'c' is fully typed here, including c.get and c.json return type
|
|
201
415
|
const user = c.get(Authentication.CURRENT_USER) as IJWTTokenPayload | undefined;
|
|
202
|
-
return c.json(
|
|
416
|
+
return c.json(
|
|
417
|
+
{ message: `Hello, ${user?.userId || 'guest'} from protected data` },
|
|
418
|
+
HTTP.ResultCodes.RS_2.Ok,
|
|
419
|
+
);
|
|
203
420
|
}
|
|
204
421
|
}
|
|
205
422
|
```
|
|
206
423
|
|
|
207
|
-
####
|
|
424
|
+
#### 5. Accessing the Current User in Context
|
|
208
425
|
|
|
209
426
|
After a route has been processed, the authenticated user's payload is available directly on the Hono `Context` object, using the `Authentication.CURRENT_USER` key.
|
|
210
427
|
|
|
@@ -127,7 +127,7 @@ export class HealthCheckController extends BaseController {
|
|
|
127
127
|
|
|
128
128
|
@api({ configs: ROUTE_CONFIGS['/'] })
|
|
129
129
|
checkHealth(c: TRouteContext<typeof ROUTE_CONFIGS['/']>) {
|
|
130
|
-
return c.json({ status: 'ok' });
|
|
130
|
+
return c.json({ status: 'ok' }, HTTP.ResultCodes.RS_2.Ok);
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
@api({ configs: ROUTE_CONFIGS['/ping'] })
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Core DI system enabling loosely coupled, testable, and extensible code.
|
|
4
4
|
|
|
5
|
-
> **
|
|
5
|
+
> **Architecture Update:** The core DI container functionality has been extracted to a standalone package `@venizia/ignis-inversion`.
|
|
6
|
+
>
|
|
7
|
+
> * **Standalone Container:** `@venizia/ignis-inversion` (Generic DI)
|
|
8
|
+
> * **Framework Integration:** `@venizia/ignis` (extends Core DI with Framework Metadata)
|
|
9
|
+
>
|
|
10
|
+
> Previously, this module resided in `@venizia/ignis-helpers`. It has now been moved to **Core** (`@venizia/ignis`) to better align with the framework architecture.
|
|
6
11
|
|
|
7
12
|
## Quick Reference
|
|
8
13
|
|
|
@@ -141,11 +146,11 @@ export class UserController extends BaseController {
|
|
|
141
146
|
The `MetadataRegistry` is a crucial part of the DI and routing systems. It's a singleton class responsible for storing and retrieving all the metadata attached by decorators like `@inject`, `@controller`, `@get`, etc.
|
|
142
147
|
|
|
143
148
|
- **Base File:** `packages/inversion/src/registry.ts` (core MetadataRegistry)
|
|
144
|
-
- **Extended File:** `packages/
|
|
149
|
+
- **Extended File:** `packages/core/src/helpers/inversion/registry.ts` (with framework metadata)
|
|
145
150
|
|
|
146
151
|
### Role in DI
|
|
147
152
|
|
|
148
153
|
- When you use a decorator (e.g., `@inject`), it calls a method on the `MetadataRegistry.getInstance()` to store information about the injection (like the binding key and target property/parameter).
|
|
149
154
|
- When the `Container` instantiates a class, it queries the `MetadataRegistry` to find out which dependencies need to be injected and where.
|
|
150
155
|
|
|
151
|
-
You typically won't interact with the `MetadataRegistry` directly, but it's the underlying mechanism that makes the decorator-based DI and routing systems work seamlessly.
|
|
156
|
+
You typically won't interact with the `MetadataRegistry` directly, but it's the underlying mechanism that makes the decorator-based DI and routing systems work seamlessly.
|
|
@@ -12,7 +12,7 @@ Detailed breakdown of the core framework directory structure.
|
|
|
12
12
|
|-----------|---------------|----------------|
|
|
13
13
|
| **`base`** | Core architecture | Applications, Controllers, Repositories, Services, Models |
|
|
14
14
|
| **`components`** | Pluggable features | Auth, Swagger, HealthCheck, SocketIO |
|
|
15
|
-
| **`helpers`** | Utilities | Re-exports from `@venizia/ignis-helpers` |
|
|
15
|
+
| **`helpers`** | Utilities | DI (extended), Re-exports from `@venizia/ignis-helpers` |
|
|
16
16
|
| **`common`** | Shared code | Constants, bindings, types, environments |
|
|
17
17
|
| **`utilities`** | Pure functions | Crypto, date, parse, performance, schema |
|
|
18
18
|
| **`__tests__`** | Tests | Integration and E2E tests |
|
|
@@ -27,7 +27,7 @@ Top-level breakdown of the `src` directory:
|
|
|
27
27
|
| **`base`** | The core building blocks and abstract classes of the framework. This is where the fundamental architecture is defined. |
|
|
28
28
|
| **`common`** | A directory for code that is shared and used across the entire framework. |
|
|
29
29
|
| **`components`** | A collection of ready-to-use, high-level components that can be plugged into an Ignis application. |
|
|
30
|
-
| **`helpers`** |
|
|
30
|
+
| **`helpers`** | Contains core extensions (like Inversion) and re-exports from `@venizia/ignis-helpers`. |
|
|
31
31
|
| **`utilities`** | A collection of pure, standalone utility functions. |
|
|
32
32
|
|
|
33
33
|
---
|
|
@@ -237,11 +237,12 @@ Generates interactive OpenAPI documentation.
|
|
|
237
237
|
|
|
238
238
|
### `helpers`
|
|
239
239
|
|
|
240
|
-
|
|
240
|
+
Contains framework extensions and utilities.
|
|
241
241
|
|
|
242
242
|
| File/Folder | Purpose/Key Details |
|
|
243
243
|
| :---------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
244
|
-
| `
|
|
244
|
+
| `inversion/`| **Framework DI Extension**: Extends `@venizia/ignis-inversion` to provide application-aware dependency injection with logging and enhanced metadata support. |
|
|
245
|
+
| `index.ts` | Re-exports extensions and utilities from `@venizia/ignis-helpers`. |
|
|
245
246
|
|
|
246
247
|
### `utilities`
|
|
247
248
|
|
|
@@ -260,4 +261,4 @@ This directory contains pure, standalone utility functions that perform common,
|
|
|
260
261
|
|
|
261
262
|
---
|
|
262
263
|
|
|
263
|
-
This detailed breakdown illustrates the modular and layered design of the Ignis framework, emphasizing its extensibility and adherence to robust architectural patterns.
|
|
264
|
+
This detailed breakdown illustrates the modular and layered design of the Ignis framework, emphasizing its extensibility and adherence to robust architectural patterns.
|
|
@@ -309,22 +309,22 @@ if (cache) {
|
|
|
309
309
|
|
|
310
310
|
---
|
|
311
311
|
|
|
312
|
-
##
|
|
312
|
+
## Integration with Framework
|
|
313
313
|
|
|
314
|
-
The `@venizia/ignis
|
|
314
|
+
The core `@venizia/ignis` package extends this base inversion package with:
|
|
315
315
|
|
|
316
316
|
- **ApplicationLogger integration**: Container with structured logging
|
|
317
317
|
- **Framework-specific metadata**: Controllers, models, repositories, data sources
|
|
318
318
|
- **Decorator implementations**: `@inject`, `@controller`, `@service`, etc.
|
|
319
319
|
|
|
320
|
-
For framework usage, import from `@venizia/ignis
|
|
320
|
+
For framework usage, import from `@venizia/ignis`. For standalone DI container usage, import directly from `@venizia/ignis-inversion`.
|
|
321
321
|
|
|
322
322
|
```typescript
|
|
323
323
|
// Standalone usage
|
|
324
324
|
import { Container, Binding } from '@venizia/ignis-inversion';
|
|
325
325
|
|
|
326
326
|
// Framework usage (includes logging and framework metadata)
|
|
327
|
-
import { Container, inject, service } from '@venizia/ignis
|
|
327
|
+
import { Container, inject, service } from '@venizia/ignis';
|
|
328
328
|
```
|
|
329
329
|
|
|
330
330
|
---
|
|
@@ -31,7 +31,7 @@ The function returns a `Promise` that resolves to an array of `IParsedFile` obje
|
|
|
31
31
|
Here is an example of how to use `parseMultipartBody` in a controller to handle a file upload.
|
|
32
32
|
|
|
33
33
|
```typescript
|
|
34
|
-
import { BaseController, controller,
|
|
34
|
+
import { BaseController, controller, HTTP } from '@venizia/ignis';
|
|
35
35
|
import { parseMultipartBody } from '@venizia/ignis';
|
|
36
36
|
|
|
37
37
|
@controller({ path: '/files' })
|
|
@@ -55,9 +55,15 @@ export class FileController extends BaseController {
|
|
|
55
55
|
|
|
56
56
|
console.log('Uploaded files:', files);
|
|
57
57
|
|
|
58
|
-
return c.json(
|
|
58
|
+
return c.json(
|
|
59
|
+
{ message: `${files.length} file(s) uploaded successfully.` },
|
|
60
|
+
HTTP.ResultCodes.RS_2.Ok,
|
|
61
|
+
);
|
|
59
62
|
} catch (error) {
|
|
60
|
-
return c.json(
|
|
63
|
+
return c.json(
|
|
64
|
+
{ message: 'Failed to upload files', error: error.message },
|
|
65
|
+
HTTP.ResultCodes.RS_5.InternalServerError,
|
|
66
|
+
);
|
|
61
67
|
}
|
|
62
68
|
},
|
|
63
69
|
});
|
|
@@ -180,10 +186,13 @@ export class FileController extends BaseController {
|
|
|
180
186
|
uploadDir: './uploads',
|
|
181
187
|
});
|
|
182
188
|
|
|
183
|
-
return ctx.json(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
189
|
+
return ctx.json(
|
|
190
|
+
{
|
|
191
|
+
message: 'Files uploaded successfully',
|
|
192
|
+
files: files.map(f => ({ name: f.originalname, size: f.size })),
|
|
193
|
+
},
|
|
194
|
+
HTTP.ResultCodes.RS_2.Ok,
|
|
195
|
+
);
|
|
187
196
|
},
|
|
188
197
|
});
|
|
189
198
|
|