@avleon/core 0.0.32 → 0.0.36
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/README.md +33 -40
- package/dist/collection.js +0 -1
- package/dist/icore.js +36 -11
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -48,6 +48,7 @@ Avleon is a powerful, TypeScript-based web framework built on top of Fastify, de
|
|
|
48
48
|
- [mapPost](#mappost)
|
|
49
49
|
- [mapPut](#mapput)
|
|
50
50
|
- [mapDelete](#mapdelete)
|
|
51
|
+
- [Testing](#testing)
|
|
51
52
|
|
|
52
53
|
## Features
|
|
53
54
|
|
|
@@ -77,7 +78,7 @@ pnpm add @avleon/core
|
|
|
77
78
|
|
|
78
79
|
## Quick Start
|
|
79
80
|
|
|
80
|
-
###
|
|
81
|
+
### Minimal
|
|
81
82
|
|
|
82
83
|
```typescript
|
|
83
84
|
import { Avleon, ApiController, Get, Results } from "@avleon/core";
|
|
@@ -430,6 +431,27 @@ app.useDataSource(DataSourceConfig);
|
|
|
430
431
|
// ... other impments
|
|
431
432
|
```
|
|
432
433
|
|
|
434
|
+
Now in your Controller or Injected service use can use like this
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
import { AppService, InjectRepository } from "@avleon/core";
|
|
438
|
+
import { Repository } from "typeorm";
|
|
439
|
+
import { User } from "model_path";
|
|
440
|
+
|
|
441
|
+
@AppService
|
|
442
|
+
export class UserService {
|
|
443
|
+
constructor(
|
|
444
|
+
@InjectRepository(User)
|
|
445
|
+
private readonly _userRepository: Repository<User>,
|
|
446
|
+
) {}
|
|
447
|
+
|
|
448
|
+
async findAll() {
|
|
449
|
+
const users = await this._userRepository.find();
|
|
450
|
+
return users;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
433
455
|
### File Uploads
|
|
434
456
|
|
|
435
457
|
Handle file uploads with multipart support:
|
|
@@ -445,7 +467,7 @@ app.useMultipart({
|
|
|
445
467
|
|
|
446
468
|
// In your controller
|
|
447
469
|
@Post('/upload')
|
|
448
|
-
async uploadFile(@
|
|
470
|
+
async uploadFile(@MultipartFile() file: any) {
|
|
449
471
|
// Process uploaded file
|
|
450
472
|
return HttpResponse.Ok({ filename: file.filename });
|
|
451
473
|
}
|
|
@@ -462,46 +484,9 @@ app.useStaticFiles({
|
|
|
462
484
|
});
|
|
463
485
|
```
|
|
464
486
|
|
|
465
|
-
### Testing
|
|
466
|
-
|
|
467
|
-
Test your API endpoints with the built-in testing utilities:
|
|
468
|
-
|
|
469
|
-
```typescript
|
|
470
|
-
import { TestBuilder } from "@avleon/core";
|
|
471
|
-
|
|
472
|
-
const testBuilder = TestBuilder.createBuilder();
|
|
473
|
-
const app = testBuilder.getTestApplication({
|
|
474
|
-
controllers: [UserController],
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
// Test your API endpoints
|
|
478
|
-
const response = await app.get("/users");
|
|
479
|
-
expect(response.statusCode).toBe(200);
|
|
480
|
-
```
|
|
481
|
-
|
|
482
487
|
## Configuration
|
|
483
488
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
```typescript
|
|
487
|
-
// .env
|
|
488
|
-
PORT=3000
|
|
489
|
-
DATABASE_URL=postgres://user:password@localhost:5432/db
|
|
490
|
-
|
|
491
|
-
// app.ts
|
|
492
|
-
import { Environment } from '@avleon/core';
|
|
493
|
-
|
|
494
|
-
const env = new Environment();
|
|
495
|
-
env.load();
|
|
496
|
-
|
|
497
|
-
const app = new Avleon({
|
|
498
|
-
controllers: [UserController],
|
|
499
|
-
env: {
|
|
500
|
-
port: 'PORT',
|
|
501
|
-
databaseUrl: 'DATABASE_URL',
|
|
502
|
-
},
|
|
503
|
-
});
|
|
504
|
-
```
|
|
489
|
+
Coming soon...
|
|
505
490
|
|
|
506
491
|
## Route Mapping
|
|
507
492
|
|
|
@@ -558,6 +543,8 @@ app.mapDelete("/users/:id", async (req, res) => {
|
|
|
558
543
|
});
|
|
559
544
|
```
|
|
560
545
|
|
|
546
|
+
### Add openapi and middleware support for inline route
|
|
547
|
+
|
|
561
548
|
Each of these methods returns a route object that can be used to add middleware or Swagger documentation to the route.
|
|
562
549
|
|
|
563
550
|
```typescript
|
|
@@ -592,6 +579,12 @@ app
|
|
|
592
579
|
});
|
|
593
580
|
```
|
|
594
581
|
|
|
582
|
+
### Testing
|
|
583
|
+
|
|
584
|
+
Test your API endpoints with the built-in testing utilities:
|
|
585
|
+
|
|
586
|
+
Coming soon...
|
|
587
|
+
|
|
595
588
|
## License
|
|
596
589
|
|
|
597
590
|
ISC
|
package/dist/collection.js
CHANGED
package/dist/icore.js
CHANGED
|
@@ -308,7 +308,6 @@ class AvleonApplication {
|
|
|
308
308
|
method: methodmetaOptions.method.toUpperCase(),
|
|
309
309
|
schema: { ...schema },
|
|
310
310
|
handler: async (req, res) => {
|
|
311
|
-
var _a;
|
|
312
311
|
let reqClone = req;
|
|
313
312
|
// class level authrization
|
|
314
313
|
if (authClsMeata.authorize && this.authorizeMiddleware) {
|
|
@@ -368,18 +367,44 @@ class AvleonApplication {
|
|
|
368
367
|
}
|
|
369
368
|
}
|
|
370
369
|
const result = await prototype[method].apply(ctrl, args);
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
370
|
+
// Custom wrapped file download
|
|
371
|
+
if (result === null || result === void 0 ? void 0 : result.__isFileDownload) {
|
|
372
|
+
const { stream, filename, contentType = "application/octet-stream", } = result;
|
|
373
|
+
if (!stream || typeof stream.pipe !== "function") {
|
|
374
|
+
return res.code(500).send({
|
|
375
|
+
code: 500,
|
|
376
|
+
error: "INTERNAL_ERROR",
|
|
377
|
+
message: "Invalid stream object",
|
|
378
|
+
});
|
|
375
379
|
}
|
|
376
|
-
|
|
380
|
+
res.header("Content-Type", contentType);
|
|
381
|
+
res.header("Content-Disposition", `attachment; filename="${filename}"`);
|
|
382
|
+
stream.on("error", (err) => {
|
|
383
|
+
console.error("Stream error:", err);
|
|
384
|
+
if (!res.sent) {
|
|
385
|
+
res.code(500).send({
|
|
386
|
+
code: 500,
|
|
387
|
+
error: "StreamError",
|
|
388
|
+
message: "Error while streaming file.",
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
return res.send(stream);
|
|
377
393
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
394
|
+
// Native stream (not wrapped)
|
|
395
|
+
if (result instanceof stream_1.default || typeof (result === null || result === void 0 ? void 0 : result.pipe) === "function") {
|
|
396
|
+
result.on("error", (err) => {
|
|
397
|
+
console.error("Stream error:", err);
|
|
398
|
+
if (!res.sent) {
|
|
399
|
+
res.code(500).send({
|
|
400
|
+
code: 500,
|
|
401
|
+
error: "StreamError",
|
|
402
|
+
message: "Error while streaming file.",
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
res.header("Content-Type", "application/octet-stream");
|
|
407
|
+
return res.send(result);
|
|
383
408
|
}
|
|
384
409
|
return res.send(result);
|
|
385
410
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@avleon/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.36",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"format": "prettier --write .",
|
|
13
13
|
"test": "jest",
|
|
14
14
|
"test:watch": "jest --watch",
|
|
15
|
-
"
|
|
15
|
+
"husky:init": "husky install"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"restapi",
|