@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.
Files changed (50) hide show
  1. package/README.md +37 -5
  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.test.d.ts +1 -0
  29. package/dist/middleware.test.js +121 -0
  30. package/dist/multipart.test.d.ts +1 -0
  31. package/dist/multipart.test.js +87 -0
  32. package/dist/openapi.test.d.ts +1 -0
  33. package/dist/openapi.test.js +111 -0
  34. package/dist/params.test.d.ts +1 -0
  35. package/dist/params.test.js +83 -0
  36. package/dist/queue.test.d.ts +1 -0
  37. package/dist/queue.test.js +79 -0
  38. package/dist/route-methods.test.d.ts +1 -0
  39. package/dist/route-methods.test.js +129 -0
  40. package/dist/swagger-schema.d.ts +42 -0
  41. package/dist/swagger-schema.js +331 -58
  42. package/dist/swagger-schema.test.d.ts +1 -0
  43. package/dist/swagger-schema.test.js +105 -0
  44. package/dist/validation.d.ts +7 -0
  45. package/dist/validation.js +2 -0
  46. package/dist/validation.test.d.ts +1 -0
  47. package/dist/validation.test.js +61 -0
  48. package/dist/websocket.test.d.ts +1 -0
  49. package/dist/websocket.test.js +27 -0
  50. package/package.json +11 -9
@@ -38,111 +38,226 @@ var __importStar = (this && this.__importStar) || (function () {
38
38
  return result;
39
39
  };
40
40
  })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
41
44
  var __importDefault = (this && this.__importDefault) || function (mod) {
42
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
43
46
  };
44
47
  Object.defineProperty(exports, "__esModule", { value: true });
45
48
  exports.FileStorage = void 0;
46
- const fs_1 = __importDefault(require("fs"));
49
+ const fs_1 = __importStar(require("fs"));
47
50
  const path_1 = __importDefault(require("path"));
48
51
  const promises_1 = require("stream/promises");
49
- const http_exceptions_1 = require("./exceptions/http-exceptions");
50
52
  const decorators_1 = require("./decorators");
51
53
  const system_exception_1 = require("./exceptions/system-exception");
54
+ const http_exceptions_1 = require("./exceptions/http-exceptions");
52
55
  let FileStorage = class FileStorage {
53
56
  constructor() {
54
57
  this.transformOptions = null;
58
+ this.maxFileSize = 50 * 1024 * 1024; // 50MB default
59
+ this.baseDir = path_1.default.join(process.cwd(), "public");
60
+ this.ensureDirectoryExists(this.baseDir);
55
61
  }
62
+ /**
63
+ * Set transformation options for the next save operation
64
+ */
56
65
  transform(options) {
57
66
  this.transformOptions = options;
58
67
  return this;
59
68
  }
60
- isFileExists(fpath) {
61
- return fs_1.default.existsSync(fpath);
69
+ async getUploadFile(fliePath) {
70
+ const f = await fs_1.default.promises.readFile(path_1.default.join(this.baseDir, fliePath));
71
+ return f;
72
+ }
73
+ async download(filepath) {
74
+ const filename = filepath
75
+ .toString()
76
+ .split(/[\/\\]/)
77
+ .pop() || "file";
78
+ const s = (0, fs_1.createReadStream)(filepath);
79
+ return {
80
+ download: true,
81
+ stream: s,
82
+ filename,
83
+ };
62
84
  }
85
+ async downloadAs(filepath, filename) {
86
+ const s = (0, fs_1.createReadStream)(filepath);
87
+ return {
88
+ download: true,
89
+ stream: s,
90
+ filename,
91
+ };
92
+ }
93
+ /**
94
+ * Save a single file with optional transformations
95
+ */
63
96
  async save(f, options) {
64
- let foptions = {
65
- overwrite: options && options.overwrite ? options.overwrite : true,
97
+ var _a;
98
+ const opts = {
99
+ overwrite: (_a = options === null || options === void 0 ? void 0 : options.overwrite) !== null && _a !== void 0 ? _a : true,
100
+ to: options === null || options === void 0 ? void 0 : options.to,
101
+ saveAs: options === null || options === void 0 ? void 0 : options.saveAs,
66
102
  };
103
+ if (f.type !== "file") {
104
+ throw new system_exception_1.SystemUseError("Invalid file type");
105
+ }
67
106
  try {
68
- if (f.type == "file") {
69
- const fname = path_1.default.join(process.cwd(), `public/${f.filename}`);
70
- if (!foptions.overwrite && this.isFileExists(fname)) {
71
- throw new system_exception_1.SystemUseError("File already exits.");
72
- }
73
- await (0, promises_1.pipeline)(f.file, fs_1.default.createWriteStream(fname));
74
- return f;
107
+ const filename = opts.saveAs || f.filename;
108
+ this.validateFilename(filename);
109
+ const uploadDir = opts.to
110
+ ? path_1.default.join(this.baseDir, opts.to)
111
+ : this.baseDir;
112
+ const fullPath = path_1.default.join(uploadDir, filename);
113
+ if (!fullPath.startsWith(this.baseDir)) {
114
+ throw new system_exception_1.SystemUseError("Invalid file path");
115
+ }
116
+ // Check if file exists
117
+ if (!opts.overwrite && this.isFileExists(fullPath)) {
118
+ throw new system_exception_1.SystemUseError("File already exists");
119
+ }
120
+ await this.ensureDirectoryExists(uploadDir);
121
+ let sourceStream;
122
+ const savedFile = f;
123
+ if (savedFile.filepath && !f.file) {
124
+ sourceStream = fs_1.default.createReadStream(savedFile.filepath);
75
125
  }
126
+ else if (f.file) {
127
+ sourceStream = f.file;
128
+ }
129
+ else {
130
+ throw new system_exception_1.SystemUseError("No file stream or filepath available");
131
+ }
132
+ if (this.transformOptions && this.isImageFile(filename)) {
133
+ await this.processImage(sourceStream, fullPath);
134
+ }
135
+ else {
136
+ await (0, promises_1.pipeline)(sourceStream, fs_1.default.createWriteStream(fullPath));
137
+ }
138
+ if (savedFile.filepath && fs_1.default.existsSync(savedFile.filepath)) {
139
+ this.removeFileSync(savedFile.filepath);
140
+ }
141
+ if (opts.saveAs) {
142
+ f.filename = opts.saveAs;
143
+ }
144
+ return {
145
+ uploadPath: (options === null || options === void 0 ? void 0 : options.to) ? '/uploads/' + options.to + "/" + f.filename : '/uploads/' + f.filename,
146
+ staticPath: (options === null || options === void 0 ? void 0 : options.to) ? '/static/' + options.to + "/" + f.filename : '/static/' + f.filename
147
+ };
76
148
  }
77
149
  catch (err) {
78
- throw new system_exception_1.SystemUseError("Can't upload file");
79
- }
80
- }
81
- async remove(filepath) {
82
- if (!this.isFileExists(path_1.default.join(process.cwd(), "public/" + filepath))) {
83
- throw new system_exception_1.SystemUseError("File doesn't exists.");
150
+ if (err instanceof system_exception_1.SystemUseError ||
151
+ err instanceof http_exceptions_1.InternalErrorException) {
152
+ throw err;
153
+ }
154
+ console.error("File save error:", err);
155
+ throw new system_exception_1.SystemUseError("Failed to upload file");
84
156
  }
85
- return fs_1.default.unlinkSync(path_1.default.join(process.cwd(), "public/" + filepath));
86
157
  }
158
+ /**
159
+ * Save multiple files
160
+ */
87
161
  async saveAll(files, options) {
88
- try {
89
- let foptions = {
90
- overwrite: options && options.overwrite ? options.overwrite : true,
91
- };
92
- for (let f of files) {
93
- let uploadPath = "public";
94
- if (options === null || options === void 0 ? void 0 : options.to) {
95
- uploadPath = `public/${options.to}`;
162
+ var _a;
163
+ if (!files || files.length === 0) {
164
+ return [];
165
+ }
166
+ const opts = {
167
+ overwrite: (_a = options === null || options === void 0 ? void 0 : options.overwrite) !== null && _a !== void 0 ? _a : true,
168
+ to: options === null || options === void 0 ? void 0 : options.to,
169
+ };
170
+ const uploadDir = opts.to ? path_1.default.join(this.baseDir, opts.to) : this.baseDir;
171
+ await this.ensureDirectoryExists(uploadDir);
172
+ const results = [];
173
+ for (const f of files) {
174
+ try {
175
+ this.validateFilename(f.filename);
176
+ const fullPath = path_1.default.join(uploadDir, f.filename);
177
+ if (!fullPath.startsWith(this.baseDir)) {
178
+ throw new system_exception_1.SystemUseError(`Invalid file path for ${f.filename}`);
179
+ }
180
+ if (!opts.overwrite && this.isFileExists(fullPath)) {
181
+ throw new system_exception_1.SystemUseError(`File ${f.filename} already exists`);
96
182
  }
97
- const fname = path_1.default.join(process.cwd(), `${uploadPath}/${f.filename}`);
98
- await this.ensureDirectoryExists(fname);
99
183
  if (f.file) {
100
- await (0, promises_1.pipeline)(f.file, fs_1.default.createWriteStream(fname));
184
+ if (this.transformOptions && this.isImageFile(f.filename)) {
185
+ await this.processImage(f.file, fullPath);
186
+ }
187
+ else {
188
+ await (0, promises_1.pipeline)(f.file, fs_1.default.createWriteStream(fullPath));
189
+ }
101
190
  }
102
191
  else {
103
192
  const fp = f;
104
- await (0, promises_1.pipeline)(fs_1.default.createReadStream(fp.filepath), fs_1.default.createWriteStream(fname));
105
- fs_1.default.unlinkSync(fp.filepath);
193
+ if (!fp.filepath) {
194
+ throw new system_exception_1.SystemUseError(`No filepath for ${f.filename}`);
195
+ }
196
+ if (this.transformOptions && this.isImageFile(f.filename)) {
197
+ await this.processImage(fs_1.default.createReadStream(fp.filepath), fullPath);
198
+ }
199
+ else {
200
+ await (0, promises_1.pipeline)(fs_1.default.createReadStream(fp.filepath), fs_1.default.createWriteStream(fullPath));
201
+ }
202
+ this.removeFileSync(fp.filepath);
106
203
  }
204
+ results.push({
205
+ uploadPath: (options === null || options === void 0 ? void 0 : options.to) ? '/uploads/' + options.to + "/" + f.filename : '/uploads/' + f.filename,
206
+ staticPath: (options === null || options === void 0 ? void 0 : options.to) ? '/static/' + options.to + "/" + f.filename : '/static/' + f.filename
207
+ });
208
+ }
209
+ catch (error) {
210
+ console.error(`Failed to save file ${f.filename}:`, error);
211
+ throw new system_exception_1.SystemUseError(`Failed to upload file ${f.filename}`);
107
212
  }
108
- return files;
213
+ }
214
+ return results;
215
+ }
216
+ /**
217
+ * Remove a file from storage
218
+ */
219
+ async remove(filepath) {
220
+ const fullPath = path_1.default.join(this.baseDir, filepath);
221
+ // Security check
222
+ if (!fullPath.startsWith(this.baseDir)) {
223
+ throw new system_exception_1.SystemUseError("Invalid file path");
224
+ }
225
+ if (!this.isFileExists(fullPath)) {
226
+ throw new system_exception_1.SystemUseError("File doesn't exist");
227
+ }
228
+ try {
229
+ fs_1.default.unlinkSync(fullPath);
109
230
  }
110
231
  catch (error) {
111
- console.error(error);
112
- throw new system_exception_1.SystemUseError("Can't upload file");
232
+ console.error("File removal error:", error);
233
+ throw new system_exception_1.SystemUseError("Failed to remove file");
113
234
  }
114
235
  }
236
+ /**
237
+ * Process image with transformations using sharp
238
+ */
115
239
  async processImage(fileStream, outputPath) {
116
240
  var _a, _b;
117
241
  try {
118
- const sharp = await Promise.resolve().then(() => __importStar(require("sharp"))); // Lazy import sharp
242
+ const sharp = await Promise.resolve().then(() => __importStar(require("sharp")));
119
243
  let sharpPipeline = sharp.default();
120
244
  if ((_a = this.transformOptions) === null || _a === void 0 ? void 0 : _a.resize) {
121
- sharpPipeline = sharpPipeline.resize(this.transformOptions.resize.width, this.transformOptions.resize.height);
245
+ sharpPipeline = sharpPipeline.resize(this.transformOptions.resize.width, this.transformOptions.resize.height, { fit: "inside", withoutEnlargement: true });
122
246
  }
123
247
  if ((_b = this.transformOptions) === null || _b === void 0 ? void 0 : _b.format) {
248
+ const quality = this.transformOptions.quality || 80;
124
249
  switch (this.transformOptions.format) {
125
250
  case "jpeg":
126
- sharpPipeline = sharpPipeline.jpeg({
127
- quality: this.transformOptions.quality || 80,
128
- });
251
+ sharpPipeline = sharpPipeline.jpeg({ quality });
129
252
  break;
130
253
  case "png":
131
- sharpPipeline = sharpPipeline.png({
132
- quality: this.transformOptions.quality || 80,
133
- });
254
+ sharpPipeline = sharpPipeline.png({ quality });
134
255
  break;
135
256
  case "webp":
136
- sharpPipeline = sharpPipeline.webp({
137
- quality: this.transformOptions.quality || 80,
138
- });
257
+ sharpPipeline = sharpPipeline.webp({ quality });
139
258
  break;
140
259
  case "avif":
141
- sharpPipeline = sharpPipeline.avif({
142
- quality: this.transformOptions.quality || 80,
143
- });
144
- break;
145
- default:
260
+ sharpPipeline = sharpPipeline.avif({ quality });
146
261
  break;
147
262
  }
148
263
  }
@@ -154,20 +269,55 @@ let FileStorage = class FileStorage {
154
269
  throw new http_exceptions_1.InternalErrorException("sharp module not found. Please install sharp to use image transformations.");
155
270
  }
156
271
  console.error("Image processing failed:", error);
157
- throw new http_exceptions_1.InternalErrorException("Image processing failed.");
272
+ throw new http_exceptions_1.InternalErrorException("Image processing failed");
158
273
  }
159
274
  finally {
160
- this.transformOptions = null; // Reset transform options after processing
275
+ this.transformOptions = null;
161
276
  }
162
277
  }
163
- async ensureDirectoryExists(filePath) {
164
- const dir = path_1.default.dirname(filePath);
165
- if (!fs_1.default.existsSync(dir)) {
166
- fs_1.default.mkdirSync(dir, { recursive: true });
278
+ /**
279
+ * Helper methods
280
+ */
281
+ isFileExists(fpath) {
282
+ return fs_1.default.existsSync(fpath);
283
+ }
284
+ async ensureDirectoryExists(dirPath) {
285
+ if (!fs_1.default.existsSync(dirPath)) {
286
+ fs_1.default.mkdirSync(dirPath, { recursive: true });
287
+ }
288
+ }
289
+ removeFileSync(filepath) {
290
+ try {
291
+ if (fs_1.default.existsSync(filepath)) {
292
+ fs_1.default.unlinkSync(filepath);
293
+ }
294
+ }
295
+ catch (error) {
296
+ console.error("Failed to remove temp file:", error);
297
+ }
298
+ }
299
+ isImageFile(filename) {
300
+ const ext = path_1.default.extname(filename).toLowerCase();
301
+ return [".jpg", ".jpeg", ".png", ".webp", ".avif", ".gif", ".bmp"].includes(ext);
302
+ }
303
+ validateFilename(filename) {
304
+ if (!filename || filename.trim() === "") {
305
+ throw new system_exception_1.SystemUseError("Invalid filename");
306
+ }
307
+ // Check for path traversal attempts
308
+ if (filename.includes("..") ||
309
+ filename.includes("/") ||
310
+ filename.includes("\\")) {
311
+ throw new system_exception_1.SystemUseError("Invalid filename: path traversal detected");
312
+ }
313
+ // Check for null bytes
314
+ if (filename.includes("\0")) {
315
+ throw new system_exception_1.SystemUseError("Invalid filename: null byte detected");
167
316
  }
168
317
  }
169
318
  };
170
319
  exports.FileStorage = FileStorage;
171
320
  exports.FileStorage = FileStorage = __decorate([
172
- decorators_1.AppService
321
+ decorators_1.AppService,
322
+ __metadata("design:paramtypes", [])
173
323
  ], FileStorage);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,104 @@
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 fs_1 = __importDefault(require("fs"));
7
+ const stream_1 = require("stream");
8
+ const file_storage_1 = require("./file-storage");
9
+ const system_exception_1 = require("./exceptions/system-exception");
10
+ const promises_1 = require("stream/promises");
11
+ jest.mock("fs");
12
+ jest.mock("stream/promises", () => ({
13
+ pipeline: jest.fn((...args) => Promise.resolve()),
14
+ }));
15
+ const mockFs = fs_1.default;
16
+ describe("FileStorage", () => {
17
+ let fileStorage;
18
+ const testFile = {
19
+ type: "file",
20
+ filename: "test.txt",
21
+ file: new stream_1.Readable({ read() { } }),
22
+ };
23
+ beforeEach(() => {
24
+ jest.clearAllMocks();
25
+ fileStorage = new file_storage_1.FileStorage();
26
+ mockFs.existsSync.mockReturnValue(false);
27
+ mockFs.createWriteStream.mockReturnValue({});
28
+ mockFs.createReadStream.mockReturnValue({});
29
+ mockFs.unlinkSync.mockImplementation(() => { });
30
+ mockFs.mkdirSync.mockImplementation(() => undefined);
31
+ });
32
+ describe("save", () => {
33
+ it("should save a file successfully", async () => {
34
+ await expect(fileStorage.save(testFile)).resolves.toEqual(testFile);
35
+ });
36
+ it("should throw SystemUseError if file exists and overwrite is false", async () => {
37
+ mockFs.existsSync.mockReturnValue(true);
38
+ await expect(fileStorage.save(testFile, { overwrite: false })).rejects.toThrow(system_exception_1.SystemUseError);
39
+ });
40
+ it("should throw SystemUseError on pipeline error", async () => {
41
+ promises_1.pipeline.mockImplementationOnce(() => {
42
+ throw new Error("Pipeline failed");
43
+ });
44
+ await expect(fileStorage.save(testFile)).rejects.toThrow(system_exception_1.SystemUseError);
45
+ });
46
+ });
47
+ describe("remove", () => {
48
+ it("should remove a file successfully", async () => {
49
+ mockFs.existsSync.mockReturnValue(true);
50
+ await expect(fileStorage.remove("test.txt")).resolves.toBeUndefined();
51
+ expect(mockFs.unlinkSync).toHaveBeenCalled();
52
+ });
53
+ it("should throw SystemUseError if file does not exist", async () => {
54
+ mockFs.existsSync.mockReturnValue(false);
55
+ await expect(fileStorage.remove("test.txt")).rejects.toThrow(system_exception_1.SystemUseError);
56
+ });
57
+ });
58
+ describe("saveAll", () => {
59
+ it("should save multiple files successfully", async () => {
60
+ const files = [
61
+ { ...testFile, filename: "a.txt" },
62
+ { ...testFile, filename: "b.txt" },
63
+ ];
64
+ await expect(fileStorage.saveAll(files)).resolves.toEqual(files);
65
+ });
66
+ it("should throw SystemUseError on error", async () => {
67
+ promises_1.pipeline.mockImplementationOnce(() => {
68
+ throw new Error("Pipeline failed");
69
+ });
70
+ await expect(fileStorage.saveAll([testFile])).rejects.toThrow(system_exception_1.SystemUseError);
71
+ });
72
+ });
73
+ describe("transform", () => {
74
+ it("should set transform options and return itself", () => {
75
+ const options = { resize: { width: 100, height: 100 }, format: "jpeg" };
76
+ const result = fileStorage.transform(options);
77
+ expect(result).toBe(fileStorage);
78
+ // @ts-ignore
79
+ expect(fileStorage.transformOptions).toEqual(options);
80
+ });
81
+ });
82
+ // describe("processImage", () => {
83
+ // it("should throw InternalErrorException if sharp is not installed", async () => {
84
+ // jest.resetModules();
85
+ // const fileStorage = new (require("./file-storage").FileStorage)();
86
+ // fileStorage.transform({ format: "jpeg" });
87
+ // await expect(
88
+ // fileStorage["processImage"](new Readable({ read() {} }), "output.jpg"),
89
+ // ).rejects.toThrow(InternalErrorException);
90
+ // });
91
+ // });
92
+ describe("ensureDirectoryExists", () => {
93
+ it("should create directory if not exists", async () => {
94
+ mockFs.existsSync.mockReturnValue(false);
95
+ await fileStorage["ensureDirectoryExists"]("public/test.txt");
96
+ expect(mockFs.mkdirSync).toHaveBeenCalled();
97
+ });
98
+ it("should not create directory if exists", async () => {
99
+ mockFs.existsSync.mockReturnValue(true);
100
+ await fileStorage["ensureDirectoryExists"]("public/test.txt");
101
+ expect(mockFs.mkdirSync).not.toHaveBeenCalled();
102
+ });
103
+ });
104
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const helpers_1 = require("./helpers");
4
+ describe("helpers.ts", () => {
5
+ describe("formatUrl", () => {
6
+ it("should format URLs correctly", () => {
7
+ expect((0, helpers_1.formatUrl)("test")).toBe("/test");
8
+ expect((0, helpers_1.formatUrl)("/test")).toBe("/test");
9
+ expect((0, helpers_1.formatUrl)("///test//")).toBe("/test");
10
+ expect(() => (0, helpers_1.formatUrl)(123)).toThrow();
11
+ });
12
+ });
13
+ describe("parsedPath", () => {
14
+ it("should ensure path starts with /", () => {
15
+ expect((0, helpers_1.parsedPath)("abc")).toBe("/abc");
16
+ expect((0, helpers_1.parsedPath)("/abc")).toBe("/abc");
17
+ });
18
+ });
19
+ describe("findDuplicates", () => {
20
+ it("should find duplicates in array", () => {
21
+ expect((0, helpers_1.findDuplicates)(["a", "b", "a", "c", "b"])).toEqual(["a", "b"]);
22
+ expect((0, helpers_1.findDuplicates)(["a", "b", "c"])).toEqual([]);
23
+ });
24
+ });
25
+ describe("getDataType", () => {
26
+ it("should return correct data type", () => {
27
+ expect((0, helpers_1.getDataType)(String)).toBe("string");
28
+ expect((0, helpers_1.getDataType)(Number)).toBe("number");
29
+ expect((0, helpers_1.getDataType)(Boolean)).toBe("boolean");
30
+ expect((0, helpers_1.getDataType)(Object)).toBe("object");
31
+ expect((0, helpers_1.getDataType)(Array)).toBe(Array);
32
+ });
33
+ });
34
+ describe("isValidType", () => {
35
+ it("should validate types correctly", () => {
36
+ expect((0, helpers_1.isValidType)("abc", String)).toBe(true);
37
+ expect((0, helpers_1.isValidType)(123, Number)).toBe(true);
38
+ expect((0, helpers_1.isValidType)(true, Boolean)).toBe(true);
39
+ expect((0, helpers_1.isValidType)({}, Object)).toBe(true);
40
+ expect((0, helpers_1.isValidType)(undefined, String)).toBe(true);
41
+ expect((0, helpers_1.isValidType)(null, Number)).toBe(true);
42
+ expect((0, helpers_1.isValidType)("123", Number)).toBe(true);
43
+ expect((0, helpers_1.isValidType)("abc", Number)).toBe(false);
44
+ });
45
+ });
46
+ describe("isValidJsonString", () => {
47
+ it("should validate JSON strings", () => {
48
+ expect((0, helpers_1.isValidJsonString)('{"a":1}')).toEqual({ a: 1 });
49
+ expect((0, helpers_1.isValidJsonString)("not json")).toBe(false);
50
+ });
51
+ });
52
+ describe("jsonToJs", () => {
53
+ it("should parse JSON to JS object", () => {
54
+ expect((0, helpers_1.jsonToJs)('{"a":1}')).toEqual({ a: 1 });
55
+ expect((0, helpers_1.jsonToJs)("bad json")).toBe(false);
56
+ });
57
+ });
58
+ // describe("normalizePath", () => {
59
+ // it("should normalize paths", () => {
60
+ // expect(normalizePath("api", "v1")).toBe("/api/v1");
61
+ // expect(normalizePath("/", "/")).toBe("/");
62
+ // expect(normalizePath("api/", "/v1/")).toBe("/api/v1");
63
+ // });
64
+ // });
65
+ describe("extrctParamFromUrl", () => {
66
+ it("should extract params from URL", () => {
67
+ expect((0, helpers_1.extrctParamFromUrl)("/user/:id/:name")).toEqual([
68
+ { key: "id", required: true },
69
+ { key: "name", required: true },
70
+ ]);
71
+ expect((0, helpers_1.extrctParamFromUrl)("/user/?:id")).toEqual([
72
+ { key: "id", required: false },
73
+ ]);
74
+ });
75
+ });
76
+ describe("pick", () => {
77
+ it("should pick properties from object", () => {
78
+ const obj = { a: 1, b: { c: 2, d: 3 }, e: 4 };
79
+ expect((0, helpers_1.pick)(obj, ["a"])).toEqual({ a: 1 });
80
+ expect((0, helpers_1.pick)(obj, ["b.c"])).toEqual({ b: { c: 2 } });
81
+ expect((0, helpers_1.pick)(obj, ["b.d", "e"])).toEqual({ b: { d: 3 }, e: 4 });
82
+ });
83
+ });
84
+ describe("exclude", () => {
85
+ it("should exclude properties from object", () => {
86
+ const obj = { a: 1, b: { c: 2, d: 3 }, e: 4 };
87
+ expect((0, helpers_1.exclude)(obj, ["a"])).toEqual({ b: { c: 2, d: 3 }, e: 4 });
88
+ expect((0, helpers_1.exclude)(obj, ["b.c"])).toEqual({ a: 1, b: { d: 3 }, e: 4 });
89
+ expect((0, helpers_1.exclude)([obj, obj], ["e"])).toEqual([
90
+ { a: 1, b: { c: 2, d: 3 } },
91
+ { a: 1, b: { c: 2, d: 3 } },
92
+ ]);
93
+ });
94
+ });
95
+ });
package/dist/icore.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * @email xtrinsic96@gmail.com
5
5
  * @url https://github.com/xtareq
6
6
  */
7
- import { FastifyReply, FastifyRequest, HookHandlerDoneFunction, InjectOptions, LightMyRequestResponse } from "fastify";
7
+ import { FastifyReply, FastifyRequest, HookHandlerDoneFunction, InjectOptions, LightMyRequestResponse, FastifyLoggerOptions } from "fastify";
8
8
  import { Constructable } from "typedi";
9
9
  import { Constructor } from "./helpers";
10
10
  import { PathLike } from "fs";
@@ -62,6 +62,7 @@ export interface ParamMetaFilesOptions {
62
62
  fieldName: string;
63
63
  }
64
64
  export interface MethodParamMeta {
65
+ request: any[];
65
66
  params: ParamMetaOptions[];
66
67
  query: ParamMetaOptions[];
67
68
  body: ParamMetaOptions[];
@@ -141,6 +142,7 @@ export declare class AvleonApplication {
141
142
  private constructor();
142
143
  static getApp(): AvleonApplication;
143
144
  static getInternalApp(buildOptions: any): AvleonApplication;
145
+ useLogger<T = FastifyLoggerOptions>(corsOptions?: ConfigInput<T>): void;
144
146
  isDevelopment(): boolean;
145
147
  private initSwagger;
146
148
  private _isConfigClass;
@@ -164,10 +166,10 @@ export declare class AvleonApplication {
164
166
  */
165
167
  private buildController;
166
168
  /**
167
- * map all request parameters
168
- * @param req
169
- * @param meta
170
- * @returns
169
+ * Maps request data to controller method arguments based on decorators
170
+ * @param req - The incoming request object
171
+ * @param meta - Metadata about method parameters
172
+ * @returns Array of arguments to pass to the controller method
171
173
  */
172
174
  private _mapArgs;
173
175
  /**