@avleon/core 0.0.39 → 0.0.42-rc0.1

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 (52) hide show
  1. package/README.md +113 -28
  2. package/dist/cache.test.d.ts +1 -0
  3. package/dist/cache.test.js +36 -0
  4. package/dist/controller.d.ts +2 -0
  5. package/dist/controller.js +13 -0
  6. package/dist/controller.test.d.ts +1 -0
  7. package/dist/controller.test.js +111 -0
  8. package/dist/environment-variables.test.d.ts +1 -0
  9. package/dist/environment-variables.test.js +70 -0
  10. package/dist/exceptions/http-exceptions.d.ts +1 -0
  11. package/dist/exceptions/http-exceptions.js +3 -1
  12. package/dist/file-storage.d.ts +44 -9
  13. package/dist/file-storage.js +209 -59
  14. package/dist/file-storage.test.d.ts +1 -0
  15. package/dist/file-storage.test.js +104 -0
  16. package/dist/helpers.test.d.ts +1 -0
  17. package/dist/helpers.test.js +95 -0
  18. package/dist/icore.d.ts +7 -5
  19. package/dist/icore.js +191 -69
  20. package/dist/icore.test.d.ts +1 -0
  21. package/dist/icore.test.js +14 -0
  22. package/dist/index.d.ts +24 -0
  23. package/dist/index.js +8 -1
  24. package/dist/kenx-provider.test.d.ts +1 -0
  25. package/dist/kenx-provider.test.js +36 -0
  26. package/dist/logger.test.d.ts +1 -0
  27. package/dist/logger.test.js +42 -0
  28. package/dist/middleware.d.ts +3 -0
  29. package/dist/middleware.js +7 -0
  30. package/dist/middleware.test.d.ts +1 -0
  31. package/dist/middleware.test.js +121 -0
  32. package/dist/multipart.test.d.ts +1 -0
  33. package/dist/multipart.test.js +87 -0
  34. package/dist/openapi.test.d.ts +1 -0
  35. package/dist/openapi.test.js +111 -0
  36. package/dist/params.test.d.ts +1 -0
  37. package/dist/params.test.js +83 -0
  38. package/dist/queue.test.d.ts +1 -0
  39. package/dist/queue.test.js +79 -0
  40. package/dist/route-methods.test.d.ts +1 -0
  41. package/dist/route-methods.test.js +129 -0
  42. package/dist/swagger-schema.d.ts +42 -0
  43. package/dist/swagger-schema.js +331 -58
  44. package/dist/swagger-schema.test.d.ts +1 -0
  45. package/dist/swagger-schema.test.js +105 -0
  46. package/dist/validation.d.ts +7 -0
  47. package/dist/validation.js +2 -0
  48. package/dist/validation.test.d.ts +1 -0
  49. package/dist/validation.test.js +61 -0
  50. package/dist/websocket.test.d.ts +1 -0
  51. package/dist/websocket.test.js +27 -0
  52. package/package.json +11 -9
package/README.md CHANGED
@@ -1,20 +1,9 @@
1
- # AvleonJs
1
+ # Avleon
2
2
 
3
- ## ⚠️ WARNING: NOT FOR PRODUCTION USE
3
+ ![npm version](https://img.shields.io/npm/v/@avleon/core.svg) ![Build](https://github.com/avleonjs/avleon-core/actions/workflows/release.yml/badge.svg)
4
+ ## ⚠️ WARNING
4
5
 
5
6
  > **🚧 This project is in active development.**
6
- >
7
- > It is **not stable** and **not ready** for live environments.
8
- > Use **only for testing, experimentation, or internal evaluation**.
9
- >
10
- > ####❗ Risks of using this in production:
11
- >
12
- > - 🔄 Breaking changes may be introduced at any time
13
- > - 🧪 Features are experimental and may be unstable
14
- > - 🔐 Security has not been audited
15
- > - 💥 Potential for data loss or critical errors
16
- >
17
- > **Please do not deploy this in production environments.**
18
7
 
19
8
  ## Overview
20
9
 
@@ -69,11 +58,11 @@ Avleon is a powerful, TypeScript-based web framework built on top of Fastify, de
69
58
  ## Installation
70
59
 
71
60
  ```bash
72
- npm install @avleon/core
61
+ npx @avleon/cli new myapp
73
62
  # or
74
- yarn add @avleon/core
63
+ yarn dlx @avleon/cli new myapp
75
64
  # or
76
- pnpm add @avleon/core
65
+ pnpm dlx @avleon/cli new myapp
77
66
  ```
78
67
 
79
68
  ## Quick Start
@@ -81,7 +70,7 @@ pnpm add @avleon/core
81
70
  ### Minimal
82
71
 
83
72
  ```typescript
84
- import { Avleon, ApiController, Get, Results } from "@avleon/core";
73
+ import { Avleon } from "@avleon/core";
85
74
 
86
75
  const app = Avleon.createApplication();
87
76
  app.mapGet("/", () => "Hello, Avleon");
@@ -123,7 +112,9 @@ const app = Avleon.createApplication();
123
112
  // Configure and run the application
124
113
  app.useCors();
125
114
  app.useControllers([UserController]);
126
- app.run(3000);
115
+ // For auto register controller `app.useControllers({auto:true});`
116
+
117
+ app.run(); // or app.run(port)
127
118
  ```
128
119
 
129
120
  ### Controllers
@@ -253,7 +244,9 @@ class UserController {
253
244
  Secure your API with authentication and authorization:
254
245
 
255
246
  ```typescript
256
- @Authorize
247
+ import { CanAuthorize } from "@avleon/core";
248
+
249
+ @CanAuthorize
257
250
  class JwtAuthorization extends AuthorizeMiddleware {
258
251
  authorize(roles: string[]) {
259
252
  return async (req: IRequest) => {
@@ -382,6 +375,66 @@ app.useOpenApi(OpenApiConfig, (config) => {
382
375
 
383
376
  ### Database Integration
384
377
 
378
+ ## 1. Knex
379
+
380
+ ```typescript
381
+ const app = Avleon.createApplication();
382
+ app.useKnex({
383
+ client: 'mysql',
384
+ connection: {
385
+ host: '127.0.0.1',
386
+ port: 3306,
387
+ user: 'your_database_user',
388
+ password: 'your_database_password',
389
+ database: 'myapp_test',
390
+ },
391
+ })
392
+ ```
393
+ or using config class
394
+
395
+ ```typescript
396
+ @AppConfig
397
+ export class KnexConfig implements IConfig {
398
+ // config method is mendatory
399
+ // config method has access to environment variables by default
400
+ config(env: Environment) {
401
+ return {
402
+ client: 'mysql',
403
+ connection: {
404
+ host: env.get("DB_HOST") || '127.0.0.1',
405
+ port: env.get("DB_PORT") || 3306,
406
+ user: env.get("DB_USER")|| 'your_database_user',
407
+ password: env.get("DB_PASS") || 'your_database_password',
408
+ database: env.get("DB_NAME") || 'myapp_test',
409
+ },
410
+ };
411
+ }
412
+ }
413
+
414
+ // now we can register it with our app
415
+
416
+ app.useKenx(KnexConfig)
417
+ ```
418
+
419
+ ### Exmaple uses
420
+
421
+ ```typescript
422
+ import { DB, AppService } from "@avleon/core";
423
+
424
+ @AppService
425
+ export class UsersService{
426
+ constructor(
427
+ private readonly db: DB
428
+ ){}
429
+
430
+ async findAll(){
431
+ const result = await this.db.client.select("*").from("users");
432
+ return result;
433
+ }
434
+ }
435
+ ```
436
+
437
+ ## 2. Typeorm
385
438
  Connect to databases using TypeORM:
386
439
 
387
440
  ```typescript
@@ -402,9 +455,9 @@ Or use the config class:
402
455
 
403
456
  ```typescript
404
457
  // datasource.config.ts
405
- import { Config, IConfig } from "@avleon/core";
458
+ import { AppConfig, IConfig } from "@avleon/core";
406
459
 
407
- @Config
460
+ @AppConfig
408
461
  export class DataSourceConfig implements IConfig {
409
462
  // config method is mendatory
410
463
  // config method has access to environment variables by default
@@ -451,24 +504,53 @@ export class UserService {
451
504
  }
452
505
  ```
453
506
 
454
- ### File Uploads
507
+ ### File Uploads & File Storage
455
508
 
456
509
  Handle file uploads with multipart support:
457
510
 
458
511
  ```typescript
459
512
  // Configure multipart file uploads
460
513
  app.useMultipart({
461
- destination: path.join(process.cwd(), 'uploads'),
514
+ destination: path.join(process.cwd(), 'public/uploads'),
462
515
  limits: {
463
516
  fileSize: 5 * 1024 * 1024 // 5MB
464
517
  }
465
518
  });
466
-
519
+ ```
520
+ ```typescript
467
521
  // In your controller
522
+ import {FileStorage} from '@avleon/core';
523
+
524
+ //inject FileStorage into constructor
525
+ constructor(
526
+ private readonly fileStorage: FileStorage
527
+ ){}
528
+
529
+ @OpenApi({
530
+ description: "Uploading single file"
531
+ body:{
532
+ type:"object",
533
+ properties:{
534
+ file:{
535
+ type:"string",
536
+ format:"binary"
537
+ }
538
+ },
539
+ required:["file"]
540
+ }
541
+ })
468
542
  @Post('/upload')
469
- async uploadFile(@MultipartFile() file: any) {
543
+ async uploadSingleFile(@UploadFile('file') file: MultipartFile) {
470
544
  // Process uploaded file
471
- return HttpResponse.Ok({ filename: file.filename });
545
+ const result = await this.fileStorage.save(file);
546
+ // or with new name
547
+ // const result = await this.fileStorage.save(file, {as:newname.ext});
548
+ // result
549
+ // {
550
+ // uploadPath:"/uplaod",
551
+ // staticPath: "/static/"
552
+ //}
553
+ return result;
472
554
  }
473
555
  ```
474
556
 
@@ -477,6 +559,9 @@ async uploadFile(@MultipartFile() file: any) {
477
559
  Serve static files:
478
560
 
479
561
  ```typescript
562
+ import path from 'path';
563
+
564
+
480
565
  app.useStaticFiles({
481
566
  path: path.join(process.cwd(), "public"),
482
567
  prefix: "/static/",
@@ -552,7 +637,7 @@ app
552
637
  // Handler function
553
638
  })
554
639
  .useMiddleware([AuthMiddleware])
555
- .useSwagger({
640
+ .useOpenApi({
556
641
  summary: "Get all users",
557
642
  description: "Retrieves a list of all users",
558
643
  tags: ["users"],
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const cache_1 = require("./cache");
4
+ describe("CacheManager (in-memory)", () => {
5
+ let cache;
6
+ beforeEach(() => {
7
+ cache = new cache_1.CacheManager();
8
+ });
9
+ it("should set and get a value", async () => {
10
+ await cache.set("foo", "bar");
11
+ const result = await cache.get("foo");
12
+ expect(result).toBe("bar");
13
+ });
14
+ it("should return null for missing key", async () => {
15
+ const result = await cache.get("missing");
16
+ expect(result).toBeNull();
17
+ });
18
+ it("should delete a key", async () => {
19
+ await cache.set("foo", "bar");
20
+ await cache.delete("foo");
21
+ const result = await cache.get("foo");
22
+ expect(result).toBeNull();
23
+ });
24
+ it("should associate keys with tags and invalidate by tag", async () => {
25
+ await cache.set("a", 1, ["tag1"]);
26
+ await cache.set("b", 2, ["tag1", "tag2"]);
27
+ await cache.set("c", 3, ["tag2"]);
28
+ await cache.invalidateTag("tag1");
29
+ expect(await cache.get("a")).toBeNull();
30
+ expect(await cache.get("b")).toBeNull();
31
+ expect(await cache.get("c")).toBe(3);
32
+ });
33
+ it("should not fail when invalidating a non-existent tag", async () => {
34
+ await expect(cache.invalidateTag("nope")).resolves.not.toThrow();
35
+ });
36
+ });
@@ -4,6 +4,8 @@
4
4
  * @email xtrinsic96@gmail.com
5
5
  * @url https://github.com/xtareq
6
6
  */
7
+ export declare const REQUEST_METADATA_KEY: unique symbol;
8
+ export declare function AvleonRequest(): ParameterDecorator;
7
9
  /**
8
10
  * Options for configuring a controller.
9
11
  * @remarks
@@ -6,10 +6,23 @@
6
6
  * @url https://github.com/xtareq
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.REQUEST_METADATA_KEY = void 0;
10
+ exports.AvleonRequest = AvleonRequest;
9
11
  exports.createControllerDecorator = createControllerDecorator;
10
12
  exports.ApiController = ApiController;
11
13
  const typedi_1 = require("typedi");
12
14
  const container_1 = require("./container");
15
+ exports.REQUEST_METADATA_KEY = Symbol('avleon:request');
16
+ function AvleonRequest() {
17
+ return (target, propertyKey, parameterIndex) => {
18
+ const existingParams = Reflect.getMetadata(exports.REQUEST_METADATA_KEY, target, propertyKey) || [];
19
+ existingParams.push({
20
+ index: parameterIndex,
21
+ type: 'request',
22
+ });
23
+ Reflect.defineMetadata(exports.REQUEST_METADATA_KEY, existingParams, target, propertyKey);
24
+ };
25
+ }
13
26
  function createControllerDecorator(type = "web") {
14
27
  return function (pathOrOptions, maybeOptions) {
15
28
  return function (target) {
@@ -0,0 +1 @@
1
+ import "reflect-metadata";
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ require("reflect-metadata");
43
+ const controller_1 = require("./controller");
44
+ const containerModule = __importStar(require("./container"));
45
+ const typedi_1 = require("typedi");
46
+ describe("Controller Decorators", () => {
47
+ beforeEach(() => {
48
+ jest.clearAllMocks();
49
+ });
50
+ describe("ApiController", () => {
51
+ it("should apply metadata and Service decorator when used as a class decorator", () => {
52
+ const registerControllerSpy = jest.spyOn(containerModule, "registerController");
53
+ let TestController = class TestController {
54
+ };
55
+ TestController = __decorate([
56
+ controller_1.ApiController
57
+ ], TestController);
58
+ expect(Reflect.getMetadata(containerModule.API_CONTROLLER_METADATA_KEY, TestController)).toBe(true);
59
+ expect(registerControllerSpy).toHaveBeenCalledWith(TestController);
60
+ expect(Reflect.getMetadata(containerModule.CONTROLLER_META_KEY, TestController)).toEqual({
61
+ type: "api",
62
+ path: "/",
63
+ options: {},
64
+ });
65
+ });
66
+ it("should apply metadata and Service decorator when used with a path", () => {
67
+ const registerControllerSpy = jest.spyOn(containerModule, "registerController");
68
+ let TestController = class TestController {
69
+ };
70
+ TestController = __decorate([
71
+ (0, controller_1.ApiController)("/test")
72
+ ], TestController);
73
+ expect(Reflect.getMetadata(containerModule.API_CONTROLLER_METADATA_KEY, TestController)).toBe(true);
74
+ expect(registerControllerSpy).toHaveBeenCalledWith(TestController);
75
+ expect(Reflect.getMetadata(containerModule.CONTROLLER_META_KEY, TestController)).toEqual({
76
+ type: "api",
77
+ path: "/test",
78
+ options: {},
79
+ });
80
+ });
81
+ it("should apply metadata and Service decorator when used with options", () => {
82
+ const registerControllerSpy = jest.spyOn(containerModule, "registerController");
83
+ const options = { name: "Custom", path: "/custom", version: "1.0.0" };
84
+ let TestController = class TestController {
85
+ };
86
+ TestController = __decorate([
87
+ (0, controller_1.ApiController)(options)
88
+ ], TestController);
89
+ expect(Reflect.getMetadata(containerModule.API_CONTROLLER_METADATA_KEY, TestController)).toBe(true);
90
+ expect(registerControllerSpy).toHaveBeenCalledWith(TestController);
91
+ expect(Reflect.getMetadata(containerModule.CONTROLLER_META_KEY, TestController)).toEqual({
92
+ type: "api",
93
+ path: "/custom",
94
+ options,
95
+ });
96
+ });
97
+ const originalService = typedi_1.Service;
98
+ // @ts-ignore
99
+ containerModule.Service = undefined;
100
+ expect(() => {
101
+ let TestController = class TestController {
102
+ };
103
+ TestController = __decorate([
104
+ controller_1.ApiController
105
+ ], TestController);
106
+ }).toThrow("Service decorator is not a function");
107
+ // Restore
108
+ // @ts-ignore
109
+ containerModule.Service = originalService;
110
+ });
111
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,70 @@
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
+ const environment_variables_1 = require("./environment-variables");
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ jest.mock("fs");
10
+ const mockedFs = fs_1.default;
11
+ describe("Environment", () => {
12
+ const envFilePath = path_1.default.join(process.cwd(), ".env");
13
+ const envContent = "TEST_KEY=123\nANOTHER_KEY=abc";
14
+ const parsedEnv = { TEST_KEY: "123", ANOTHER_KEY: "abc" };
15
+ beforeEach(() => {
16
+ jest.resetModules();
17
+ mockedFs.existsSync.mockClear();
18
+ mockedFs.readFileSync.mockClear();
19
+ process.env.TEST_KEY = "override";
20
+ process.env.ONLY_PROCESS = "proc";
21
+ });
22
+ afterEach(() => {
23
+ delete process.env.TEST_KEY;
24
+ delete process.env.ONLY_PROCESS;
25
+ });
26
+ it("should get value from process.env if present", () => {
27
+ mockedFs.existsSync.mockReturnValue(true);
28
+ mockedFs.readFileSync.mockReturnValue(envContent);
29
+ const env = new environment_variables_1.Environment();
30
+ expect(env.get("TEST_KEY")).toBe("override");
31
+ });
32
+ it("should get value from .env file if not in process.env", () => {
33
+ mockedFs.existsSync.mockReturnValue(true);
34
+ mockedFs.readFileSync.mockReturnValue(envContent);
35
+ const env = new environment_variables_1.Environment();
36
+ expect(env.get("ANOTHER_KEY")).toBe("abc");
37
+ });
38
+ it("should return undefined for missing key", () => {
39
+ mockedFs.existsSync.mockReturnValue(true);
40
+ mockedFs.readFileSync.mockReturnValue(envContent);
41
+ const env = new environment_variables_1.Environment();
42
+ expect(env.get("MISSING_KEY")).toBeUndefined();
43
+ });
44
+ it("should throw EnvironmentVariableNotFound for getOrThrow if missing", () => {
45
+ mockedFs.existsSync.mockReturnValue(true);
46
+ mockedFs.readFileSync.mockReturnValue(envContent);
47
+ const env = new environment_variables_1.Environment();
48
+ expect(() => env.getOrThrow("MISSING_KEY")).toThrow();
49
+ });
50
+ it("should get all variables with process.env taking precedence", () => {
51
+ mockedFs.existsSync.mockReturnValue(true);
52
+ mockedFs.readFileSync.mockReturnValue(envContent);
53
+ const env = new environment_variables_1.Environment();
54
+ const all = env.getAll();
55
+ expect(all.TEST_KEY).toBe("override");
56
+ expect(all.ANOTHER_KEY).toBe("abc");
57
+ expect(all.ONLY_PROCESS).toBe("proc");
58
+ });
59
+ it("should handle missing .env file gracefully", () => {
60
+ mockedFs.existsSync.mockReturnValue(false);
61
+ const env = new environment_variables_1.Environment();
62
+ expect(env.get("ONLY_PROCESS")).toBe("proc");
63
+ expect(env.get("TEST_KEY")).toBe("override");
64
+ });
65
+ it("should return empty object if error occurs during parsing", () => {
66
+ mockedFs.existsSync.mockImplementation(() => { throw new Error("fs error"); });
67
+ const env = new environment_variables_1.Environment();
68
+ expect(env.getAll()).toEqual({});
69
+ });
70
+ });
@@ -7,6 +7,7 @@
7
7
  export declare abstract class BaseHttpException extends Error {
8
8
  code: number;
9
9
  name: string;
10
+ payload: any;
10
11
  constructor(message: any);
11
12
  isCustomException(): boolean;
12
13
  }
@@ -9,9 +9,11 @@ exports.HttpExceptions = exports.ForbiddenException = exports.UnauthorizedExcept
9
9
  */
10
10
  class BaseHttpException extends Error {
11
11
  constructor(message) {
12
- super(JSON.stringify(message));
12
+ const stringMessage = typeof message === "string" ? message : JSON.stringify(message);
13
+ super(stringMessage);
13
14
  this.code = 500;
14
15
  this.name = "HttpException";
16
+ this.payload = typeof message === "string" ? { message } : message;
15
17
  }
16
18
  isCustomException() {
17
19
  return true;
@@ -1,4 +1,4 @@
1
- import { PathLike } from "fs";
1
+ import fs, { PathLike } from "fs";
2
2
  import { MultipartFile } from "./multipart";
3
3
  interface TransformOptions {
4
4
  resize?: {
@@ -10,9 +10,9 @@ interface TransformOptions {
10
10
  }
11
11
  export interface FileStorageInterface {
12
12
  transform(options: TransformOptions): FileStorage;
13
- save(file: MultipartFile, options?: SaveOptionsSingle): Promise<MultipartFile | undefined>;
14
- saveAll(files: MultipartFile[], options?: SaveOptions): Promise<MultipartFile[] | undefined>;
15
- remove(filepath: PathLike): Promise<void>;
13
+ save(file: MultipartFile, options?: SaveOptionsSingle): Promise<MultipartFile>;
14
+ saveAll(files: MultipartFile[], options?: SaveOptions): Promise<MultipartFile[]>;
15
+ remove(filepath: string): Promise<void>;
16
16
  }
17
17
  export interface SaveOptions {
18
18
  overwrite?: boolean;
@@ -23,12 +23,47 @@ export interface SaveOptionsSingle extends SaveOptions {
23
23
  }
24
24
  export declare class FileStorage implements FileStorageInterface {
25
25
  private transformOptions;
26
- transform(options: TransformOptions): this;
27
- private isFileExists;
28
- save(f: MultipartFile, options?: SaveOptionsSingle): Promise<import("@fastify/multipart").MultipartFile | undefined>;
29
- remove(filepath: PathLike): Promise<void>;
30
- saveAll(files: MultipartFile[], options?: SaveOptions): Promise<MultipartFile[]>;
26
+ private readonly baseDir;
27
+ private readonly maxFileSize;
28
+ constructor();
29
+ /**
30
+ * Set transformation options for the next save operation
31
+ */
32
+ transform(options: TransformOptions): FileStorage;
33
+ getUploadFile(fliePath: string): Promise<Buffer<ArrayBufferLike>>;
34
+ download(filepath: PathLike): Promise<{
35
+ download: boolean;
36
+ stream: fs.ReadStream;
37
+ filename: string;
38
+ }>;
39
+ downloadAs(filepath: PathLike, filename: string): Promise<{
40
+ download: boolean;
41
+ stream: fs.ReadStream;
42
+ filename: string;
43
+ }>;
44
+ /**
45
+ * Save a single file with optional transformations
46
+ */
47
+ save(f: MultipartFile, options?: SaveOptionsSingle): Promise<any>;
48
+ /**
49
+ * Save multiple files
50
+ */
51
+ saveAll(files: MultipartFile[], options?: SaveOptions): Promise<any[]>;
52
+ /**
53
+ * Remove a file from storage
54
+ */
55
+ remove(filepath: string): Promise<void>;
56
+ /**
57
+ * Process image with transformations using sharp
58
+ */
31
59
  private processImage;
60
+ /**
61
+ * Helper methods
62
+ */
63
+ private isFileExists;
32
64
  private ensureDirectoryExists;
65
+ private removeFileSync;
66
+ private isImageFile;
67
+ private validateFilename;
33
68
  }
34
69
  export {};