@avleon/core 0.0.20 → 0.0.25

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 (75) hide show
  1. package/README.md +559 -2
  2. package/dist/application.d.ts +47 -0
  3. package/dist/application.js +50 -0
  4. package/dist/cache.d.ts +12 -0
  5. package/dist/cache.js +78 -0
  6. package/dist/collection.js +3 -2
  7. package/dist/container.d.ts +1 -0
  8. package/dist/container.js +2 -1
  9. package/dist/environment-variables.js +1 -1
  10. package/dist/file-storage.js +0 -128
  11. package/dist/helpers.d.ts +2 -0
  12. package/dist/helpers.js +41 -4
  13. package/dist/icore.d.ts +93 -42
  14. package/dist/icore.js +319 -251
  15. package/dist/index.d.ts +2 -2
  16. package/dist/index.js +4 -2
  17. package/dist/middleware.js +0 -8
  18. package/dist/multipart.js +4 -1
  19. package/dist/openapi.d.ts +37 -37
  20. package/dist/params.js +2 -2
  21. package/dist/response.js +6 -2
  22. package/dist/route-methods.js +1 -1
  23. package/dist/swagger-schema.js +4 -1
  24. package/dist/testing.js +6 -3
  25. package/dist/utils/index.d.ts +2 -0
  26. package/dist/utils/index.js +18 -0
  27. package/dist/utils/optional-require.d.ts +8 -0
  28. package/dist/utils/optional-require.js +70 -0
  29. package/dist/validation.d.ts +4 -1
  30. package/dist/validation.js +10 -5
  31. package/package.json +26 -9
  32. package/src/application.ts +125 -0
  33. package/src/authentication.ts +16 -0
  34. package/src/cache.ts +91 -0
  35. package/src/collection.ts +254 -0
  36. package/src/config.ts +42 -0
  37. package/src/constants.ts +1 -0
  38. package/src/container.ts +54 -0
  39. package/src/controller.ts +127 -0
  40. package/src/decorators.ts +27 -0
  41. package/src/environment-variables.ts +46 -0
  42. package/src/exceptions/http-exceptions.ts +86 -0
  43. package/src/exceptions/index.ts +1 -0
  44. package/src/exceptions/system-exception.ts +34 -0
  45. package/src/file-storage.ts +206 -0
  46. package/src/helpers.ts +328 -0
  47. package/src/icore.ts +1140 -0
  48. package/src/index.ts +30 -0
  49. package/src/logger.ts +72 -0
  50. package/src/map-types.ts +159 -0
  51. package/src/middleware.ts +98 -0
  52. package/src/multipart.ts +116 -0
  53. package/src/openapi.ts +372 -0
  54. package/src/params.ts +111 -0
  55. package/src/queue.ts +126 -0
  56. package/src/response.ts +117 -0
  57. package/src/results.ts +30 -0
  58. package/src/route-methods.ts +186 -0
  59. package/src/swagger-schema.ts +213 -0
  60. package/src/testing.ts +220 -0
  61. package/src/types/app-builder.interface.ts +19 -0
  62. package/src/types/application.interface.ts +9 -0
  63. package/src/utils/hash.ts +5 -0
  64. package/src/utils/index.ts +2 -0
  65. package/src/utils/optional-require.ts +50 -0
  66. package/src/validation.ts +156 -0
  67. package/src/validator-extend.ts +25 -0
  68. package/dist/classToOpenapi.d.ts +0 -0
  69. package/dist/classToOpenapi.js +0 -1
  70. package/dist/render.d.ts +0 -1
  71. package/dist/render.js +0 -8
  72. package/jest.config.ts +0 -9
  73. package/tsconfig.json +0 -25
  74. /package/dist/{security.d.ts → utils/hash.d.ts} +0 -0
  75. /package/dist/{security.js → utils/hash.js} +0 -0
package/README.md CHANGED
@@ -1,4 +1,561 @@
1
- # avleon-core
1
+ # Avleon Core Framework
2
2
 
3
+ ## Overview
3
4
 
4
- # Api (V0.0.1)
5
+ Avleon is a powerful, TypeScript-based web framework built on top of Fastify, designed to simplify API development with a focus on decorators, dependency injection, and OpenAPI documentation. It provides a robust set of tools for building scalable, maintainable web applications with minimal boilerplate code.
6
+
7
+ ## Table of Contents
8
+
9
+ - [Features](#features)
10
+ - [Installation](#installation)
11
+ - [Quick Start](#quick-start)
12
+ - [Core Concepts](#core-concepts)
13
+ - [Application Creation](#application-creation)
14
+ - [Controllers](#controllers)
15
+ - [Route Methods](#route-methods)
16
+ - [Parameter Decorators](#parameter-decorators)
17
+ - [Response Handling](#response-handling)
18
+ - [Middleware](#middleware)
19
+ - [Authentication & Authorization](#authentication--authorization)
20
+ - [Validation](#validation)
21
+ - [OpenAPI Documentation](#openapi-documentation)
22
+ - [Advanced Features](#advanced-features)
23
+ - [Database Integration](#database-integration)
24
+ - [File Uploads](#file-uploads)
25
+ - [Static Files](#static-files)
26
+ - [Testing](#testing)
27
+ - [Configuration](#configuration)
28
+ - [Route Mapping](#route-mapping)
29
+ - [mapGet](#mapget)
30
+ - [mapPost](#mappost)
31
+ - [mapPut](#mapput)
32
+ - [mapDelete](#mapdelete)
33
+
34
+ ## Features
35
+
36
+ - **Decorator-based API Development**: Define controllers, routes, and middleware using TypeScript decorators
37
+ - **Dependency Injection**: Built-in DI system using TypeDI for service management
38
+ - **OpenAPI/Swagger Integration**: Automatic API documentation generation with support for both Swagger UI and Scalar
39
+ - **Validation**: Request validation with support for class-validator and custom validation rules
40
+ - **Middleware System**: Flexible middleware architecture for request processing
41
+ - **Response Handling**: Standardized response formats with HTTP status codes
42
+ - **File Upload**: Built-in support for multipart file uploads with file validation
43
+ - **Authentication & Authorization**: Middleware for securing your API endpoints
44
+ - **Database Integration**: Support for TypeORM for database operations
45
+ - **Queue System**: Background job processing capabilities
46
+ - **Environment Configuration**: Environment variable management
47
+ - **Logging**: Integrated logging with Pino
48
+ - **Testing**: Built-in testing utilities for API endpoints
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ npm install @avleon/core
54
+ # or
55
+ yarn add @avleon/core
56
+ # or
57
+ pnpm add @avleon/core
58
+ ```
59
+
60
+ ## Quick Start
61
+
62
+ ```typescript
63
+ import { Avleon, ApiController, Get, Results } from '@avleon/core';
64
+
65
+ // Define a controller
66
+ @ApiController('/hello')
67
+ class HelloController {
68
+ @Get('/')
69
+ async sayHello() {
70
+ return Results.Ok({ message: 'Hello, Avleon!' });
71
+ }
72
+ }
73
+
74
+ // Create and start the application
75
+ const app = new Avleon({
76
+ controllers: [HelloController],
77
+ openapi: {
78
+ info: {
79
+ title: 'My Avleon API',
80
+ version: '1.0.0',
81
+ },
82
+ },
83
+ });
84
+
85
+ app.start();
86
+ ```
87
+
88
+ ## Core Concepts
89
+
90
+ ### Application Creation
91
+
92
+ Avleon provides a builder pattern for creating applications:
93
+
94
+ ```typescript
95
+ import { Builder } from '@avleon/core';
96
+
97
+ // Create an application using the builder
98
+ const builder = Builder.createAppBuilder();
99
+ const app = builder.build();
100
+
101
+ // Configure and start the application
102
+ app.useCors();
103
+ app.mapControllers([UserController]);
104
+ app.start(3000);
105
+ ```
106
+
107
+ ### Controllers
108
+
109
+ Controllers are the entry points for your API requests. They are defined using the `@ApiController` decorator:
110
+
111
+ ```typescript
112
+ @ApiController('/users')
113
+ class UserController {
114
+ // Route handlers go here
115
+ }
116
+ ```
117
+
118
+ You can also specify controller options:
119
+
120
+ ```typescript
121
+ @ApiController({
122
+ path: '/users',
123
+ name: 'User Management',
124
+ version: '1.0.0',
125
+ since: '2024-01-01'
126
+ })
127
+ class UserController {
128
+ // Route handlers go here
129
+ }
130
+ ```
131
+
132
+ ### Route Methods
133
+
134
+ Define HTTP methods using decorators:
135
+
136
+ ```typescript
137
+ @Get('/')
138
+ async getUsers() {
139
+ // Handle GET request
140
+ }
141
+
142
+ @Post('/')
143
+ async createUser(@Body() user: UserDto) {
144
+ // Handle POST request
145
+ }
146
+
147
+ @Put('/:id')
148
+ async updateUser(@Param('id') id: string, @Body() user: UserDto) {
149
+ // Handle PUT request
150
+ }
151
+
152
+ @Delete('/:id')
153
+ async deleteUser(@Param('id') id: string) {
154
+ // Handle DELETE request
155
+ }
156
+ ```
157
+
158
+ ### Parameter Decorators
159
+
160
+ Extract data from requests using parameter decorators:
161
+
162
+ ```typescript
163
+ @Get('/:id')
164
+ async getUser(
165
+ @Param('id') id: string,
166
+ @Query('include') include: string,
167
+ @Header('authorization') token: string,
168
+ @Body() data: UserDto
169
+ ) {
170
+ // Access route parameters, query strings, headers, and request body
171
+ }
172
+ ```
173
+
174
+ You can also access the current user and files:
175
+
176
+ ```typescript
177
+ @Post('/upload')
178
+ async uploadFile(
179
+ @User() currentUser: any,
180
+ @File() file: any
181
+ ) {
182
+ // Access the current user and uploaded file
183
+ }
184
+
185
+ @Post('/upload-multiple')
186
+ async uploadFiles(
187
+ @Files() files: any[]
188
+ ) {
189
+ // Access multiple uploaded files
190
+ }
191
+ ```
192
+
193
+ ### Response Handling
194
+
195
+ Return standardized responses using the `Results` class:
196
+
197
+ ```typescript
198
+ @Get('/:id')
199
+ async getUser(@Param('id') id: string) {
200
+ const user = await this.userService.findById(id);
201
+
202
+ if (!user) {
203
+ return Results.NotFound('User not found');
204
+ }
205
+
206
+ return Results.Ok(user);
207
+ }
208
+ ```
209
+
210
+ ### Middleware
211
+
212
+ Create and apply middleware for cross-cutting concerns:
213
+
214
+ ```typescript
215
+ @Middleware
216
+ class LoggingMiddleware extends AppMiddleware {
217
+ async invoke(req: IRequest) {
218
+ console.log(`Request: ${req.method} ${req.url}`);
219
+ return req;
220
+ }
221
+ }
222
+
223
+ @UseMiddleware(LoggingMiddleware)
224
+ @ApiController('/users')
225
+ class UserController {
226
+ // Controller methods
227
+ }
228
+ ```
229
+
230
+ You can also apply middleware to specific routes:
231
+
232
+ ```typescript
233
+ @ApiController('/users')
234
+ class UserController {
235
+ @UseMiddleware(LoggingMiddleware)
236
+ @Get('/')
237
+ async getUsers() {
238
+ // Only this route will use the LoggingMiddleware
239
+ }
240
+ }
241
+ ```
242
+
243
+ ### Authentication & Authorization
244
+
245
+ Secure your API with authentication and authorization:
246
+
247
+ ```typescript
248
+ @Authorize
249
+ class JwtAuthMiddleware extends AuthorizeMiddleware {
250
+ authorize(roles: string[]) {
251
+ return async (req: IRequest) => {
252
+ // Implement JWT authentication logic
253
+ return req;
254
+ };
255
+ }
256
+ }
257
+
258
+ @Authorized()
259
+ @ApiController('/admin')
260
+ class AdminController {
261
+ // Protected controller methods
262
+ }
263
+
264
+ // Or protect specific routes with roles
265
+ @ApiController('/admin')
266
+ class AdminController {
267
+ @Authorized(['admin'])
268
+ @Get('/')
269
+ async adminDashboard() {
270
+ // Only users with 'admin' role can access this
271
+ }
272
+ }
273
+ ```
274
+
275
+ ### Validation
276
+
277
+ Validate request data using class-validator:
278
+
279
+ ```typescript
280
+ class UserDto {
281
+ @IsString()
282
+ @IsNotEmpty()
283
+ name: string;
284
+
285
+ @IsEmail()
286
+ email: string;
287
+
288
+ @IsNumber()
289
+ @Min(0)
290
+ @Max(120)
291
+ age: number;
292
+ }
293
+
294
+ @Post('/')
295
+ async createUser(@Body() user: UserDto) {
296
+ // User data is automatically validated
297
+ return Results.Created(user);
298
+ }
299
+ ```
300
+
301
+ You can also use custom validation rules:
302
+
303
+ ```typescript
304
+ class UserDto {
305
+ @Validate({
306
+ type: 'string',
307
+ required: true,
308
+ message: 'Name is required'
309
+ })
310
+ name: string;
311
+
312
+ @Validate({
313
+ type: 'number',
314
+ min: 0,
315
+ max: 120,
316
+ message: 'Age must be between 0 and 120'
317
+ })
318
+ age: number;
319
+ }
320
+ ```
321
+
322
+ ### OpenAPI Documentation
323
+
324
+ Generate API documentation automatically:
325
+
326
+ ```typescript
327
+ const app = new Avleon({
328
+ controllers: [UserController],
329
+ openapi: {
330
+ info: {
331
+ title: 'User API',
332
+ version: '1.0.0',
333
+ description: 'API for managing users',
334
+ },
335
+ servers: [
336
+ {
337
+ url: 'http://localhost:3000',
338
+ description: 'Development server',
339
+ },
340
+ ],
341
+ },
342
+ });
343
+ ```
344
+
345
+ You can also customize the OpenAPI UI:
346
+
347
+ ```typescript
348
+ app.useOpenApi(OpenApiConfig, (config) => {
349
+ // Modify the OpenAPI configuration
350
+ config.info.title = 'Custom API Title';
351
+ return config;
352
+ });
353
+
354
+ // Or use Swagger UI with custom options
355
+ app.useSwagger({
356
+ routePrefix: '/api-docs',
357
+ ui: 'default', // or 'scalar' for Scalar UI
358
+ theme: {
359
+ // Custom theme options
360
+ }
361
+ });
362
+ ```
363
+
364
+ ## Advanced Features
365
+
366
+ ### Database Integration
367
+
368
+ Connect to databases using TypeORM:
369
+
370
+ ```typescript
371
+ const app = new Avleon({
372
+ controllers: [UserController],
373
+ database: {
374
+ type: 'postgres',
375
+ host: 'localhost',
376
+ port: 5432,
377
+ username: 'postgres',
378
+ password: 'password',
379
+ database: 'avleon',
380
+ entities: [User],
381
+ synchronize: true,
382
+ },
383
+ });
384
+ ```
385
+
386
+ Or use the builder pattern:
387
+
388
+ ```typescript
389
+ const builder = Builder.createAppBuilder();
390
+ builder.addDataSource(DatabaseConfig);
391
+ const app = builder.build();
392
+ ```
393
+
394
+ ### File Uploads
395
+
396
+ Handle file uploads with multipart support:
397
+
398
+ ```typescript
399
+ // Configure multipart file uploads
400
+ app.useMultipart({
401
+ destination: path.join(process.cwd(), 'uploads'),
402
+ limits: {
403
+ fileSize: 5 * 1024 * 1024 // 5MB
404
+ }
405
+ });
406
+
407
+ // In your controller
408
+ @Post('/upload')
409
+ async uploadFile(@File() file: any) {
410
+ // Process uploaded file
411
+ return Results.Ok({ filename: file.filename });
412
+ }
413
+ ```
414
+
415
+ ### Static Files
416
+
417
+ Serve static files:
418
+
419
+ ```typescript
420
+ app.useStaticFiles({
421
+ path: path.join(process.cwd(), 'public'),
422
+ prefix: '/static/'
423
+ });
424
+ ```
425
+
426
+ ### Testing
427
+
428
+ Test your API endpoints with the built-in testing utilities:
429
+
430
+ ```typescript
431
+ import { TestBuilder } from '@avleon/core';
432
+
433
+ const testBuilder = TestBuilder.createBuilder();
434
+ const app = testBuilder.getTestApplication({
435
+ controllers: [UserController]
436
+ });
437
+
438
+ // Test your API endpoints
439
+ const response = await app.get('/users');
440
+ expect(response.statusCode).toBe(200);
441
+ ```
442
+
443
+ ## Configuration
444
+
445
+ Configure your application with environment variables:
446
+
447
+ ```typescript
448
+ // .env
449
+ PORT=3000
450
+ DATABASE_URL=postgres://user:password@localhost:5432/db
451
+
452
+ // app.ts
453
+ import { Environment } from '@avleon/core';
454
+
455
+ const env = new Environment();
456
+ env.load();
457
+
458
+ const app = new Avleon({
459
+ controllers: [UserController],
460
+ env: {
461
+ port: 'PORT',
462
+ databaseUrl: 'DATABASE_URL',
463
+ },
464
+ });
465
+ ```
466
+
467
+ ## Route Mapping
468
+
469
+ Avleon provides several methods for mapping routes in your application:
470
+
471
+ ### mapGet
472
+
473
+ The `mapGet` method is used to define GET routes in your application. It takes a path string and a handler function as parameters.
474
+
475
+ ```typescript
476
+ app.mapGet("/users", async (req, res) => {
477
+ // Handle GET request to /users
478
+ return { users: [] };
479
+ });
480
+ ```
481
+
482
+ ### mapPost
483
+
484
+ The `mapPost` method is used to define POST routes in your application. It takes a path string and a handler function as parameters.
485
+
486
+ ```typescript
487
+ app.mapPost("/users", async (req, res) => {
488
+ // Handle POST request to /users
489
+ const userData = req.body;
490
+ // Process user data
491
+ return { success: true };
492
+ });
493
+ ```
494
+
495
+ ### mapPut
496
+
497
+ The `mapPut` method is used to define PUT routes in your application. It takes a path string and a handler function as parameters.
498
+
499
+ ```typescript
500
+ app.mapPut("/users/:id", async (req, res) => {
501
+ // Handle PUT request to /users/:id
502
+ const userId = req.params.id;
503
+ const userData = req.body;
504
+ // Update user data
505
+ return { success: true };
506
+ });
507
+ ```
508
+
509
+ ### mapDelete
510
+
511
+ The `mapDelete` method is used to define DELETE routes in your application. It takes a path string and a handler function as parameters.
512
+
513
+ ```typescript
514
+ app.mapDelete("/users/:id", async (req, res) => {
515
+ // Handle DELETE request to /users/:id
516
+ const userId = req.params.id;
517
+ // Delete user
518
+ return { success: true };
519
+ });
520
+ ```
521
+
522
+ Each of these methods returns a route object that can be used to add middleware or Swagger documentation to the route.
523
+
524
+ ```typescript
525
+ app.mapGet("/users", async (req, res) => {
526
+ // Handler function
527
+ })
528
+ .useMiddleware([AuthMiddleware])
529
+ .useSwagger({
530
+ summary: "Get all users",
531
+ description: "Retrieves a list of all users",
532
+ tags: ["users"],
533
+ response: {
534
+ 200: {
535
+ description: "Successful response",
536
+ content: {
537
+ "application/json": {
538
+ schema: {
539
+ type: "array",
540
+ items: {
541
+ type: "object",
542
+ properties: {
543
+ id: { type: "string" },
544
+ name: { type: "string" }
545
+ }
546
+ }
547
+ }
548
+ }
549
+ }
550
+ }
551
+ }
552
+ });
553
+ ```
554
+
555
+ ## License
556
+
557
+ ISC
558
+
559
+ ## Author
560
+
561
+ Tareq Hossain - [GitHub](https://github.com/xtareq)
@@ -0,0 +1,47 @@
1
+ import { Constructor } from "./helpers";
2
+ import { RouteShorthandMethod } from "fastify";
3
+ export interface AvleonApplication {
4
+ useCors: () => void;
5
+ useOpenApi: () => void;
6
+ useView: () => void;
7
+ useAuth: () => void;
8
+ useMultipart: () => void;
9
+ useDataSource: () => void;
10
+ useMiddlewares: () => void;
11
+ useControllers: () => void;
12
+ useAutoControllers: () => void;
13
+ useStaticFiles: () => void;
14
+ useCustomErrorHandler: () => void;
15
+ mapGroup: () => any;
16
+ mapGet: () => any;
17
+ mapPost: () => any;
18
+ mapPut: () => any;
19
+ mapPatch: () => any;
20
+ mapDelete: () => any;
21
+ mapView: () => any;
22
+ run: (port: number) => void;
23
+ }
24
+ export interface InlineRoutes {
25
+ get: RouteShorthandMethod;
26
+ post: RouteShorthandMethod;
27
+ put: RouteShorthandMethod;
28
+ patch: RouteShorthandMethod;
29
+ delete: RouteShorthandMethod;
30
+ }
31
+ export interface Application {
32
+ inlineRoutes: () => InlineRoutes;
33
+ mapGroup: (path?: string | RegExp) => InlineRoutes;
34
+ /**
35
+ * Start the application
36
+ * @param port
37
+ * @returns void
38
+ */
39
+ start: (port?: number) => void;
40
+ }
41
+ export interface TestApplication {
42
+ getController: <T>(controller: Constructor<T>) => T;
43
+ }
44
+ export declare class Builder {
45
+ static createApplication(): Application;
46
+ static createTestApplication(app?: Application): TestApplication;
47
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Builder = void 0;
7
+ const typedi_1 = __importDefault(require("typedi"));
8
+ const fastify_1 = __importDefault(require("fastify"));
9
+ class IqraTestApplication {
10
+ getController(controller) {
11
+ const con = typedi_1.default.get(controller);
12
+ return con;
13
+ }
14
+ }
15
+ class IqraApplication {
16
+ constructor() {
17
+ if (!this.app) {
18
+ this.app = fastify_1.default.prototype;
19
+ }
20
+ }
21
+ inlineRoutes() {
22
+ return {
23
+ get: this.app.get,
24
+ post: this.app.post,
25
+ put: this.app.put,
26
+ patch: this.app.patch,
27
+ delete: this.app.delete
28
+ };
29
+ }
30
+ mapGroup(path) {
31
+ return this.inlineRoutes();
32
+ }
33
+ start(port) {
34
+ const p = port ? port : 4000;
35
+ this.app.listen({ port: p });
36
+ }
37
+ }
38
+ class Builder {
39
+ static createApplication() {
40
+ const app = new IqraApplication();
41
+ return app;
42
+ }
43
+ static createTestApplication(app) {
44
+ const testApp = new IqraTestApplication();
45
+ return testApp;
46
+ }
47
+ }
48
+ exports.Builder = Builder;
49
+ const app = Builder.createApplication();
50
+ const route = app.inlineRoutes();
@@ -0,0 +1,12 @@
1
+ import type { Redis } from 'ioredis';
2
+ export declare class CacheManager {
3
+ private store;
4
+ private tagsMap;
5
+ private redis;
6
+ constructor(redisInstance?: Redis);
7
+ private redisTagKey;
8
+ get<T>(key: string): Promise<T | null>;
9
+ set<T>(key: string, value: T, tags?: string[], ttl?: number): Promise<void>;
10
+ delete(key: string): Promise<void>;
11
+ invalidateTag(tag: string): Promise<void>;
12
+ }