@avleon/core 0.0.40 → 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.
- package/README.md +37 -5
- package/dist/cache.test.d.ts +1 -0
- package/dist/cache.test.js +36 -0
- package/dist/controller.d.ts +2 -0
- package/dist/controller.js +13 -0
- package/dist/controller.test.d.ts +1 -0
- package/dist/controller.test.js +111 -0
- package/dist/environment-variables.test.d.ts +1 -0
- package/dist/environment-variables.test.js +70 -0
- package/dist/exceptions/http-exceptions.d.ts +1 -0
- package/dist/exceptions/http-exceptions.js +3 -1
- package/dist/file-storage.d.ts +44 -9
- package/dist/file-storage.js +209 -59
- package/dist/file-storage.test.d.ts +1 -0
- package/dist/file-storage.test.js +104 -0
- package/dist/helpers.test.d.ts +1 -0
- package/dist/helpers.test.js +95 -0
- package/dist/icore.d.ts +7 -5
- package/dist/icore.js +191 -69
- package/dist/icore.test.d.ts +1 -0
- package/dist/icore.test.js +14 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +8 -1
- package/dist/kenx-provider.test.d.ts +1 -0
- package/dist/kenx-provider.test.js +36 -0
- package/dist/logger.test.d.ts +1 -0
- package/dist/logger.test.js +42 -0
- package/dist/middleware.test.d.ts +1 -0
- package/dist/middleware.test.js +121 -0
- package/dist/multipart.test.d.ts +1 -0
- package/dist/multipart.test.js +87 -0
- package/dist/openapi.test.d.ts +1 -0
- package/dist/openapi.test.js +111 -0
- package/dist/params.test.d.ts +1 -0
- package/dist/params.test.js +83 -0
- package/dist/queue.test.d.ts +1 -0
- package/dist/queue.test.js +79 -0
- package/dist/route-methods.test.d.ts +1 -0
- package/dist/route-methods.test.js +129 -0
- package/dist/swagger-schema.d.ts +42 -0
- package/dist/swagger-schema.js +331 -58
- package/dist/swagger-schema.test.d.ts +1 -0
- package/dist/swagger-schema.test.js +105 -0
- package/dist/validation.d.ts +7 -0
- package/dist/validation.js +2 -0
- package/dist/validation.test.d.ts +1 -0
- package/dist/validation.test.js +61 -0
- package/dist/websocket.test.d.ts +1 -0
- package/dist/websocket.test.js +27 -0
- package/package.json +11 -9
package/README.md
CHANGED
|
@@ -504,24 +504,53 @@ export class UserService {
|
|
|
504
504
|
}
|
|
505
505
|
```
|
|
506
506
|
|
|
507
|
-
### File Uploads
|
|
507
|
+
### File Uploads & File Storage
|
|
508
508
|
|
|
509
509
|
Handle file uploads with multipart support:
|
|
510
510
|
|
|
511
511
|
```typescript
|
|
512
512
|
// Configure multipart file uploads
|
|
513
513
|
app.useMultipart({
|
|
514
|
-
destination: path.join(process.cwd(), 'uploads'),
|
|
514
|
+
destination: path.join(process.cwd(), 'public/uploads'),
|
|
515
515
|
limits: {
|
|
516
516
|
fileSize: 5 * 1024 * 1024 // 5MB
|
|
517
517
|
}
|
|
518
518
|
});
|
|
519
|
-
|
|
519
|
+
```
|
|
520
|
+
```typescript
|
|
520
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
|
+
})
|
|
521
542
|
@Post('/upload')
|
|
522
|
-
async
|
|
543
|
+
async uploadSingleFile(@UploadFile('file') file: MultipartFile) {
|
|
523
544
|
// Process uploaded file
|
|
524
|
-
|
|
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;
|
|
525
554
|
}
|
|
526
555
|
```
|
|
527
556
|
|
|
@@ -530,6 +559,9 @@ async uploadFile(@MultipartFile() file: any) {
|
|
|
530
559
|
Serve static files:
|
|
531
560
|
|
|
532
561
|
```typescript
|
|
562
|
+
import path from 'path';
|
|
563
|
+
|
|
564
|
+
|
|
533
565
|
app.useStaticFiles({
|
|
534
566
|
path: path.join(process.cwd(), "public"),
|
|
535
567
|
prefix: "/static/",
|
|
@@ -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
|
+
});
|
package/dist/controller.d.ts
CHANGED
package/dist/controller.js
CHANGED
|
@@ -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
|
+
});
|
|
@@ -9,9 +9,11 @@ exports.HttpExceptions = exports.ForbiddenException = exports.UnauthorizedExcept
|
|
|
9
9
|
*/
|
|
10
10
|
class BaseHttpException extends Error {
|
|
11
11
|
constructor(message) {
|
|
12
|
-
|
|
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;
|
package/dist/file-storage.d.ts
CHANGED
|
@@ -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
|
|
14
|
-
saveAll(files: MultipartFile[], options?: SaveOptions): Promise<MultipartFile[]
|
|
15
|
-
remove(filepath:
|
|
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
|
-
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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 {};
|