@avleon/core 0.0.27 → 0.0.29

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 (77) hide show
  1. package/README.md +601 -561
  2. package/dist/application.js +1 -1
  3. package/dist/cache.d.ts +1 -1
  4. package/dist/cache.js +2 -2
  5. package/dist/collection.d.ts +25 -32
  6. package/dist/collection.js +50 -6
  7. package/dist/collection.test.d.ts +1 -0
  8. package/dist/collection.test.js +59 -0
  9. package/dist/config.d.ts +2 -0
  10. package/dist/config.js +30 -5
  11. package/dist/config.test.d.ts +1 -0
  12. package/dist/config.test.js +40 -0
  13. package/dist/controller.js +2 -2
  14. package/dist/environment-variables.js +42 -5
  15. package/dist/event-dispatcher.d.ts +23 -0
  16. package/dist/event-dispatcher.js +102 -0
  17. package/dist/event-subscriber.d.ts +15 -0
  18. package/dist/event-subscriber.js +96 -0
  19. package/dist/exceptions/http-exceptions.js +1 -1
  20. package/dist/exceptions/index.d.ts +1 -1
  21. package/dist/exceptions/system-exception.js +3 -1
  22. package/dist/file-storage.js +1 -1
  23. package/dist/helpers.js +1 -1
  24. package/dist/icore.d.ts +5 -0
  25. package/dist/icore.js +53 -18
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.js +6 -1
  28. package/dist/utils/index.d.ts +2 -2
  29. package/dist/utils/optional-require.js +2 -2
  30. package/dist/validation.d.ts +1 -1
  31. package/dist/websocket.d.ts +7 -0
  32. package/dist/websocket.js +20 -0
  33. package/dist/websocket.test.d.ts +0 -0
  34. package/dist/websocket.test.js +1 -0
  35. package/package.json +37 -6
  36. package/src/application.ts +104 -125
  37. package/src/authentication.ts +16 -16
  38. package/src/cache.ts +91 -91
  39. package/src/collection.test.ts +71 -0
  40. package/src/collection.ts +344 -254
  41. package/src/config.test.ts +35 -0
  42. package/src/config.ts +85 -42
  43. package/src/constants.ts +1 -1
  44. package/src/container.ts +54 -54
  45. package/src/controller.ts +125 -127
  46. package/src/decorators.ts +27 -27
  47. package/src/environment-variables.ts +53 -46
  48. package/src/event-dispatcher.ts +100 -0
  49. package/src/event-subscriber.ts +79 -0
  50. package/src/exceptions/http-exceptions.ts +86 -86
  51. package/src/exceptions/index.ts +1 -1
  52. package/src/exceptions/system-exception.ts +35 -34
  53. package/src/file-storage.ts +206 -206
  54. package/src/helpers.ts +324 -328
  55. package/src/icore.ts +1106 -1084
  56. package/src/index.ts +32 -30
  57. package/src/interfaces/avleon-application.ts +32 -40
  58. package/src/logger.ts +72 -72
  59. package/src/map-types.ts +159 -159
  60. package/src/middleware.ts +121 -98
  61. package/src/multipart.ts +116 -116
  62. package/src/openapi.ts +372 -372
  63. package/src/params.ts +111 -111
  64. package/src/queue.ts +126 -126
  65. package/src/response.ts +74 -74
  66. package/src/results.ts +30 -30
  67. package/src/route-methods.ts +186 -186
  68. package/src/swagger-schema.ts +213 -213
  69. package/src/testing.ts +220 -220
  70. package/src/types/app-builder.interface.ts +18 -19
  71. package/src/types/application.interface.ts +7 -9
  72. package/src/utils/hash.ts +8 -5
  73. package/src/utils/index.ts +2 -2
  74. package/src/utils/optional-require.ts +50 -50
  75. package/src/validation.ts +160 -156
  76. package/src/validator-extend.ts +25 -25
  77. package/src/websocket.ts +47 -0
@@ -1,206 +1,206 @@
1
- import fs, { createReadStream, PathLike } from "fs";
2
- import path from "path";
3
- import { pipeline } from "stream/promises";
4
- import {
5
- BadRequestException,
6
- InternalErrorException,
7
- } from "./exceptions/http-exceptions";
8
- import { MultipartFile } from "./multipart";
9
- import { AppService } from "./decorators";
10
- import os from "os";
11
- import { SystemUseError } from "./exceptions/system-exception";
12
- import { SavedMultipartFile } from "@fastify/multipart";
13
-
14
- interface TransformOptions {
15
- resize?: { width: number; height: number };
16
- format?: "jpeg" | "png" | "webp" | "avif";
17
- quality?: number;
18
- // Add other sharp options as needed
19
- }
20
-
21
- /*
22
- //temp file
23
- files[0].type // "file"
24
- files[0].filepath
25
- files[0].fieldname
26
- files[0].filename
27
- files[0].encoding
28
- files[0].mimetype
29
- files[0].fields
30
-
31
- */
32
-
33
- /*
34
- // stream file
35
- data.file // stream
36
- data.fields // other parsed parts
37
- data.fieldname
38
- data.filename
39
- data.encoding
40
- data.mimetype
41
- */
42
-
43
- export interface FileStorageInterface {
44
- transform(options: TransformOptions): FileStorage;
45
- save(
46
- file: MultipartFile,
47
- options?: SaveOptionsSingle
48
- ): Promise<MultipartFile | undefined>;
49
- saveAll(
50
- files: MultipartFile[],
51
- options?: SaveOptions
52
- ): Promise<MultipartFile[] | undefined>;
53
-
54
- remove(filepath: PathLike): Promise<void>;
55
- }
56
-
57
- export interface SaveOptions {
58
- overwrite?: boolean;
59
- to?: string;
60
- }
61
-
62
- export interface SaveOptionsSingle extends SaveOptions {
63
- saveAs?: string;
64
- }
65
-
66
- @AppService
67
- export class FileStorage implements FileStorageInterface {
68
- private transformOptions: TransformOptions | null = null;
69
-
70
- transform(options: TransformOptions) {
71
- this.transformOptions = options;
72
- return this;
73
- }
74
-
75
- private isFileExists(fpath: PathLike) {
76
- return fs.existsSync(fpath);
77
- }
78
-
79
- async save(f: MultipartFile, options?: SaveOptionsSingle) {
80
- let foptions: SaveOptionsSingle = {
81
- overwrite: options && options.overwrite ? options.overwrite : true,
82
- };
83
- try {
84
- if (f.type == "file") {
85
- const fname = path.join(process.cwd(), `public/${f.filename}`);
86
-
87
- if (!foptions.overwrite && this.isFileExists(fname)) {
88
- throw new SystemUseError("File already exits.");
89
- }
90
-
91
- await pipeline(f.file, fs.createWriteStream(fname));
92
- return f;
93
- }
94
- } catch (err) {
95
- throw new SystemUseError("Can't upload file");
96
- }
97
- }
98
-
99
- async remove(filepath: PathLike) {
100
- if (!this.isFileExists(path.join(process.cwd(), "public/" + filepath))) {
101
- throw new SystemUseError("File doesn't exists.");
102
- }
103
- return fs.unlinkSync(path.join(process.cwd(), "public/" + filepath));
104
- }
105
-
106
- async saveAll(files: MultipartFile[], options?: SaveOptions) {
107
- try {
108
- let foptions: SaveOptions = {
109
- overwrite: options && options.overwrite ? options.overwrite : true,
110
- };
111
- for (let f of files) {
112
- let uploadPath = `public`;
113
- if (options?.to) {
114
- uploadPath = `public/${options.to}`;
115
- }
116
- const fname = path.join(process.cwd(), `${uploadPath}/${f.filename}`);
117
- await this.ensureDirectoryExists(fname);
118
- if (f.file) {
119
- await pipeline(f.file, fs.createWriteStream(fname));
120
- } else {
121
- const fp = f as SavedMultipartFile;
122
- await pipeline(
123
- fs.createReadStream(fp.filepath),
124
- fs.createWriteStream(fname)
125
- );
126
- fs.unlinkSync(fp.filepath);
127
- }
128
- }
129
- return files;
130
- } catch (error) {
131
- console.error(error);
132
- throw new SystemUseError("Can't upload file");
133
- }
134
- }
135
-
136
- private async processImage(
137
- fileStream: NodeJS.ReadableStream,
138
- outputPath: string
139
- ) {
140
- try {
141
- const sharp = await import("sharp"); // Lazy import sharp
142
-
143
- let sharpPipeline = sharp.default();
144
-
145
- if (this.transformOptions?.resize) {
146
- sharpPipeline = sharpPipeline.resize(
147
- this.transformOptions.resize.width,
148
- this.transformOptions.resize.height
149
- );
150
- }
151
-
152
- if (this.transformOptions?.format) {
153
- switch (this.transformOptions.format) {
154
- case "jpeg":
155
- sharpPipeline = sharpPipeline.jpeg({
156
- quality: this.transformOptions.quality || 80,
157
- });
158
- break;
159
- case "png":
160
- sharpPipeline = sharpPipeline.png({
161
- quality: this.transformOptions.quality || 80,
162
- });
163
- break;
164
- case "webp":
165
- sharpPipeline = sharpPipeline.webp({
166
- quality: this.transformOptions.quality || 80,
167
- });
168
- break;
169
- case "avif":
170
- sharpPipeline = sharpPipeline.avif({
171
- quality: this.transformOptions.quality || 80,
172
- });
173
- break;
174
- default:
175
- break;
176
- }
177
- }
178
-
179
- await pipeline(
180
- fileStream,
181
- sharpPipeline,
182
- fs.createWriteStream(outputPath)
183
- );
184
- } catch (error: any) {
185
- if (
186
- error.code === "MODULE_NOT_FOUND" &&
187
- error.message.includes("sharp")
188
- ) {
189
- throw new InternalErrorException(
190
- "sharp module not found. Please install sharp to use image transformations."
191
- );
192
- }
193
- console.error("Image processing failed:", error);
194
- throw new InternalErrorException("Image processing failed.");
195
- } finally {
196
- this.transformOptions = null; // Reset transform options after processing
197
- }
198
- }
199
-
200
- private async ensureDirectoryExists(filePath: string) {
201
- const dir = path.dirname(filePath);
202
- if (!fs.existsSync(dir)) {
203
- fs.mkdirSync(dir, { recursive: true });
204
- }
205
- }
206
- }
1
+ import fs, { createReadStream, PathLike } from "fs";
2
+ import path from "path";
3
+ import { pipeline } from "stream/promises";
4
+ import {
5
+ BadRequestException,
6
+ InternalErrorException,
7
+ } from "./exceptions/http-exceptions";
8
+ import { MultipartFile } from "./multipart";
9
+ import { AppService } from "./decorators";
10
+ import os from "os";
11
+ import { SystemUseError } from "./exceptions/system-exception";
12
+ import { SavedMultipartFile } from "@fastify/multipart";
13
+
14
+ interface TransformOptions {
15
+ resize?: { width: number; height: number };
16
+ format?: "jpeg" | "png" | "webp" | "avif";
17
+ quality?: number;
18
+ // Add other sharp options as needed
19
+ }
20
+
21
+ /*
22
+ //temp file
23
+ files[0].type // "file"
24
+ files[0].filepath
25
+ files[0].fieldname
26
+ files[0].filename
27
+ files[0].encoding
28
+ files[0].mimetype
29
+ files[0].fields
30
+
31
+ */
32
+
33
+ /*
34
+ // stream file
35
+ data.file // stream
36
+ data.fields // other parsed parts
37
+ data.fieldname
38
+ data.filename
39
+ data.encoding
40
+ data.mimetype
41
+ */
42
+
43
+ export interface FileStorageInterface {
44
+ transform(options: TransformOptions): FileStorage;
45
+ save(
46
+ file: MultipartFile,
47
+ options?: SaveOptionsSingle,
48
+ ): Promise<MultipartFile | undefined>;
49
+ saveAll(
50
+ files: MultipartFile[],
51
+ options?: SaveOptions,
52
+ ): Promise<MultipartFile[] | undefined>;
53
+
54
+ remove(filepath: PathLike): Promise<void>;
55
+ }
56
+
57
+ export interface SaveOptions {
58
+ overwrite?: boolean;
59
+ to?: string;
60
+ }
61
+
62
+ export interface SaveOptionsSingle extends SaveOptions {
63
+ saveAs?: string;
64
+ }
65
+
66
+ @AppService
67
+ export class FileStorage implements FileStorageInterface {
68
+ private transformOptions: TransformOptions | null = null;
69
+
70
+ transform(options: TransformOptions) {
71
+ this.transformOptions = options;
72
+ return this;
73
+ }
74
+
75
+ private isFileExists(fpath: PathLike) {
76
+ return fs.existsSync(fpath);
77
+ }
78
+
79
+ async save(f: MultipartFile, options?: SaveOptionsSingle) {
80
+ let foptions: SaveOptionsSingle = {
81
+ overwrite: options && options.overwrite ? options.overwrite : true,
82
+ };
83
+ try {
84
+ if (f.type == "file") {
85
+ const fname = path.join(process.cwd(), `public/${f.filename}`);
86
+
87
+ if (!foptions.overwrite && this.isFileExists(fname)) {
88
+ throw new SystemUseError("File already exits.");
89
+ }
90
+
91
+ await pipeline(f.file, fs.createWriteStream(fname));
92
+ return f;
93
+ }
94
+ } catch (err) {
95
+ throw new SystemUseError("Can't upload file");
96
+ }
97
+ }
98
+
99
+ async remove(filepath: PathLike) {
100
+ if (!this.isFileExists(path.join(process.cwd(), "public/" + filepath))) {
101
+ throw new SystemUseError("File doesn't exists.");
102
+ }
103
+ return fs.unlinkSync(path.join(process.cwd(), "public/" + filepath));
104
+ }
105
+
106
+ async saveAll(files: MultipartFile[], options?: SaveOptions) {
107
+ try {
108
+ let foptions: SaveOptions = {
109
+ overwrite: options && options.overwrite ? options.overwrite : true,
110
+ };
111
+ for (let f of files) {
112
+ let uploadPath = "public";
113
+ if (options?.to) {
114
+ uploadPath = `public/${options.to}`;
115
+ }
116
+ const fname = path.join(process.cwd(), `${uploadPath}/${f.filename}`);
117
+ await this.ensureDirectoryExists(fname);
118
+ if (f.file) {
119
+ await pipeline(f.file, fs.createWriteStream(fname));
120
+ } else {
121
+ const fp = f as SavedMultipartFile;
122
+ await pipeline(
123
+ fs.createReadStream(fp.filepath),
124
+ fs.createWriteStream(fname),
125
+ );
126
+ fs.unlinkSync(fp.filepath);
127
+ }
128
+ }
129
+ return files;
130
+ } catch (error) {
131
+ console.error(error);
132
+ throw new SystemUseError("Can't upload file");
133
+ }
134
+ }
135
+
136
+ private async processImage(
137
+ fileStream: NodeJS.ReadableStream,
138
+ outputPath: string,
139
+ ) {
140
+ try {
141
+ const sharp = await import("sharp"); // Lazy import sharp
142
+
143
+ let sharpPipeline = sharp.default();
144
+
145
+ if (this.transformOptions?.resize) {
146
+ sharpPipeline = sharpPipeline.resize(
147
+ this.transformOptions.resize.width,
148
+ this.transformOptions.resize.height,
149
+ );
150
+ }
151
+
152
+ if (this.transformOptions?.format) {
153
+ switch (this.transformOptions.format) {
154
+ case "jpeg":
155
+ sharpPipeline = sharpPipeline.jpeg({
156
+ quality: this.transformOptions.quality || 80,
157
+ });
158
+ break;
159
+ case "png":
160
+ sharpPipeline = sharpPipeline.png({
161
+ quality: this.transformOptions.quality || 80,
162
+ });
163
+ break;
164
+ case "webp":
165
+ sharpPipeline = sharpPipeline.webp({
166
+ quality: this.transformOptions.quality || 80,
167
+ });
168
+ break;
169
+ case "avif":
170
+ sharpPipeline = sharpPipeline.avif({
171
+ quality: this.transformOptions.quality || 80,
172
+ });
173
+ break;
174
+ default:
175
+ break;
176
+ }
177
+ }
178
+
179
+ await pipeline(
180
+ fileStream,
181
+ sharpPipeline,
182
+ fs.createWriteStream(outputPath),
183
+ );
184
+ } catch (error: any) {
185
+ if (
186
+ error.code === "MODULE_NOT_FOUND" &&
187
+ error.message.includes("sharp")
188
+ ) {
189
+ throw new InternalErrorException(
190
+ "sharp module not found. Please install sharp to use image transformations.",
191
+ );
192
+ }
193
+ console.error("Image processing failed:", error);
194
+ throw new InternalErrorException("Image processing failed.");
195
+ } finally {
196
+ this.transformOptions = null; // Reset transform options after processing
197
+ }
198
+ }
199
+
200
+ private async ensureDirectoryExists(filePath: string) {
201
+ const dir = path.dirname(filePath);
202
+ if (!fs.existsSync(dir)) {
203
+ fs.mkdirSync(dir, { recursive: true });
204
+ }
205
+ }
206
+ }