@avleon/core 0.0.28 → 0.0.30

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 (73) hide show
  1. package/dist/application.js +1 -1
  2. package/dist/cache.d.ts +1 -1
  3. package/dist/cache.js +2 -2
  4. package/dist/collection.d.ts +25 -32
  5. package/dist/collection.js +50 -6
  6. package/dist/collection.test.d.ts +1 -0
  7. package/dist/collection.test.js +59 -0
  8. package/dist/config.d.ts +2 -0
  9. package/dist/config.js +30 -5
  10. package/dist/config.test.d.ts +1 -0
  11. package/dist/config.test.js +40 -0
  12. package/dist/controller.js +2 -2
  13. package/dist/environment-variables.js +42 -5
  14. package/dist/event-dispatcher.d.ts +23 -0
  15. package/dist/event-dispatcher.js +102 -0
  16. package/dist/event-subscriber.d.ts +15 -0
  17. package/dist/event-subscriber.js +96 -0
  18. package/dist/exceptions/http-exceptions.js +1 -1
  19. package/dist/exceptions/index.d.ts +1 -1
  20. package/dist/exceptions/system-exception.js +3 -1
  21. package/dist/file-storage.js +1 -1
  22. package/dist/helpers.js +1 -1
  23. package/dist/icore.d.ts +5 -0
  24. package/dist/icore.js +53 -18
  25. package/dist/index.d.ts +2 -0
  26. package/dist/index.js +6 -1
  27. package/dist/utils/index.d.ts +2 -2
  28. package/dist/utils/optional-require.js +2 -2
  29. package/dist/validation.d.ts +1 -1
  30. package/dist/websocket.d.ts +7 -0
  31. package/dist/websocket.js +20 -0
  32. package/dist/websocket.test.d.ts +0 -0
  33. package/dist/websocket.test.js +1 -0
  34. package/package.json +4 -3
  35. package/src/application.ts +0 -104
  36. package/src/authentication.ts +0 -16
  37. package/src/cache.ts +0 -91
  38. package/src/collection.test.ts +0 -71
  39. package/src/collection.ts +0 -344
  40. package/src/config.test.ts +0 -35
  41. package/src/config.ts +0 -85
  42. package/src/constants.ts +0 -1
  43. package/src/container.ts +0 -54
  44. package/src/controller.ts +0 -125
  45. package/src/decorators.ts +0 -27
  46. package/src/environment-variables.ts +0 -53
  47. package/src/exceptions/http-exceptions.ts +0 -86
  48. package/src/exceptions/index.ts +0 -1
  49. package/src/exceptions/system-exception.ts +0 -35
  50. package/src/file-storage.ts +0 -206
  51. package/src/helpers.ts +0 -324
  52. package/src/icore.ts +0 -1060
  53. package/src/index.ts +0 -30
  54. package/src/interfaces/avleon-application.ts +0 -32
  55. package/src/logger.ts +0 -72
  56. package/src/map-types.ts +0 -159
  57. package/src/middleware.ts +0 -119
  58. package/src/multipart.ts +0 -116
  59. package/src/openapi.ts +0 -372
  60. package/src/params.ts +0 -111
  61. package/src/queue.ts +0 -126
  62. package/src/response.ts +0 -74
  63. package/src/results.ts +0 -30
  64. package/src/route-methods.ts +0 -186
  65. package/src/swagger-schema.ts +0 -213
  66. package/src/testing.ts +0 -220
  67. package/src/types/app-builder.interface.ts +0 -18
  68. package/src/types/application.interface.ts +0 -7
  69. package/src/utils/hash.ts +0 -8
  70. package/src/utils/index.ts +0 -2
  71. package/src/utils/optional-require.ts +0 -50
  72. package/src/validation.ts +0 -160
  73. package/src/validator-extend.ts +0 -25
package/src/controller.ts DELETED
@@ -1,125 +0,0 @@
1
- /**
2
- * @copyright 2024
3
- * @author Tareq Hossain
4
- * @email xtrinsic96@gmail.com
5
- * @url https://github.com/xtareq
6
- */
7
-
8
- import Container, { Service } from "typedi";
9
- import container, {
10
- API_CONTROLLER_METADATA_KEY,
11
- CONTROLLER_META_KEY,
12
- registerController,
13
- } from "./container";
14
-
15
- /**
16
- * Options for configuring a controller.
17
- * @remarks
18
- * Controller default options
19
- * @type {Object} ControllerOptions
20
- * @property {string} [name] - The name of the controller.
21
- * @property {string} [path] - The base path for the controller's routes.
22
- * @property {string} [version] - The version of the controller. If not provided, it will default to the version from `package.json`.
23
- * @property {string} [since] - The date or version since the controller was introduced.
24
- * @property {any} [meta] - Additional metadata associated with the controller.
25
- */
26
- export type ControllerOptions = {
27
- /**
28
- *@property {string} name
29
- *@description Name of the controller. If specified it'll used as swagger tags
30
- *@default Contorller class name
31
- * */
32
- name?: string;
33
- path?: string;
34
- version?: string; // Will look at package.json if not set
35
- since?: string;
36
- meta?: any;
37
- };
38
-
39
- export function createControllerDecorator(
40
- type: "api" | "web" = "web",
41
- ): (
42
- pathOrOptions?: string | ControllerOptions,
43
- maybeOptions?: ControllerOptions,
44
- ) => ClassDecorator {
45
- return function (
46
- pathOrOptions?: string | ControllerOptions,
47
- maybeOptions?: ControllerOptions,
48
- ): ClassDecorator {
49
- return function (target: Function) {
50
- let path = "/";
51
- let options: ControllerOptions = {};
52
-
53
- if (typeof pathOrOptions === "string") {
54
- path = pathOrOptions;
55
- options = maybeOptions || {};
56
- } else if (typeof pathOrOptions === "object") {
57
- options = pathOrOptions;
58
- path = options.path || "/";
59
- }
60
- Reflect.defineMetadata(API_CONTROLLER_METADATA_KEY, true, target);
61
- // Ensure Service is applied as a ClassDecorator
62
- if (typeof Service === "function") {
63
- registerController(target); // Add to custom registry
64
- Service()(target); // Apply DI decorator
65
- Reflect.defineMetadata(
66
- CONTROLLER_META_KEY,
67
- { type, path, options },
68
- target,
69
- );
70
- } else {
71
- throw new Error("Service decorator is not a function");
72
- }
73
- };
74
- };
75
- }
76
-
77
- // Predefined Controller Decorators
78
- //export const Controller = createControllerDecorator("web");
79
- /**
80
- *@description Api controller's are used for rest . It will populate
81
- * json on return and all it http methods {get} {post} etc must return
82
- *Results.*
83
- * @param path {string} this will used as route prefix
84
- *
85
- **/
86
-
87
- export function ApiController(target: Function): void;
88
- export function ApiController(path: string): ClassDecorator;
89
- /**
90
- *@description Api controller's are used for rest . It will populate
91
- * json on return and all it http methods {get} {post} etc must return
92
- * Results.*
93
- * @param {ControllerOptions} options this will used as route prefix
94
- *
95
- **/
96
- export function ApiController(options: ControllerOptions): ClassDecorator;
97
- export function ApiController(
98
- path: string,
99
- options?: ControllerOptions,
100
- ): ClassDecorator;
101
- export function ApiController(
102
- pathOrOptions: Function | string | ControllerOptions = "/",
103
- mayBeOptions?: ControllerOptions,
104
- ): any {
105
- if (typeof pathOrOptions == "function") {
106
- Reflect.defineMetadata(API_CONTROLLER_METADATA_KEY, true, pathOrOptions);
107
- // Ensure Service is applied as a ClassDecorator
108
- if (typeof Service === "function") {
109
- registerController(pathOrOptions); // Add to custom registry
110
- Service()(pathOrOptions); // Apply DI decorator
111
- Reflect.defineMetadata(
112
- CONTROLLER_META_KEY,
113
- { type: "api", path: "/", options: {} },
114
- pathOrOptions,
115
- );
116
- } else {
117
- throw new Error("Service decorator is not a function");
118
- }
119
- } else {
120
- if (mayBeOptions) {
121
- return createControllerDecorator("api")(pathOrOptions, mayBeOptions);
122
- }
123
- return createControllerDecorator("api")(pathOrOptions);
124
- }
125
- }
package/src/decorators.ts DELETED
@@ -1,27 +0,0 @@
1
- /**
2
- * @copyright 2024
3
- * @author Tareq Hossain
4
- * @email xtrinsic96@gmail.com
5
- * @url https://github.com/xtareq
6
- */
7
-
8
- import { Service as _service } from "typedi";
9
- import container, { registerService } from "./container";
10
- export function AppService(target: any): void;
11
- export function AppService(): any;
12
- export function AppService(target?: any) {
13
- if (target) {
14
- _service()(target);
15
- } else {
16
- return function (tg: any) {
17
- _service()(tg);
18
- };
19
- }
20
- }
21
-
22
- export * from "./controller";
23
- export * from "./route-methods";
24
- export * from "./openapi";
25
- export const Utility = _service;
26
- export const Helper = _service;
27
- export * from "./params";
@@ -1,53 +0,0 @@
1
- /**
2
- * @copyright 2024
3
- * @author Tareq Hossain
4
- * @email xtrinsic96@gmail.com
5
- * @url https://github.com/xtareq
6
- */
7
-
8
- import dotenv from "dotenv";
9
- import path from "path";
10
- import fs, { existsSync } from "fs";
11
- import { Service } from "typedi";
12
- import {
13
- EnvironmentVariableNotFound,
14
- SystemUseError,
15
- } from "./exceptions/system-exception";
16
-
17
- dotenv.config({ path: path.join(process.cwd(), ".env") });
18
-
19
- @Service()
20
- export class Environment {
21
- private parseEnvFile(filePath: string): any {
22
- try {
23
- const isExis = existsSync(filePath);
24
- if (!isExis) {
25
- return { ...process.env };
26
- }
27
- const fileContent = fs.readFileSync(filePath, "utf8");
28
- const parsedEnv = dotenv.parse(fileContent);
29
- return { ...parsedEnv, ...process.env };
30
- } catch (error) {
31
- console.error(`Error parsing .env file: ${error}`);
32
- return {};
33
- }
34
- }
35
-
36
- get<T = any>(key: string): T {
37
- const parsedEnv = this.parseEnvFile(path.join(process.cwd(), ".env"));
38
- return parsedEnv[key] as T;
39
- }
40
-
41
- getOrThrow<T = any>(key: string): T {
42
- const parsedEnv = this.parseEnvFile(path.join(process.cwd(), ".env"));
43
- if (!Object(parsedEnv).hasOwnProperty(key)) {
44
- throw new EnvironmentVariableNotFound(key);
45
- }
46
- return parsedEnv[key] as T;
47
- }
48
-
49
- getAll<T = any>(): T {
50
- const parsedEnv = this.parseEnvFile(path.join(process.cwd(), ".env"));
51
- return parsedEnv as T;
52
- }
53
- }
@@ -1,86 +0,0 @@
1
- /**
2
- * @copyright 2024
3
- * @author Tareq Hossain
4
- * @email xtrinsic96@gmail.com
5
- * @url https://github.com/xtareq
6
- */
7
- export abstract class BaseHttpException extends Error {
8
- code: number = 500;
9
- name: string = "HttpException";
10
- constructor(message: any) {
11
- super(JSON.stringify(message));
12
- }
13
- isCustomException() {
14
- return true;
15
- }
16
- }
17
-
18
- export class BadRequestException extends BaseHttpException {
19
- name: string = "BadRequest";
20
- code: number = 400;
21
-
22
- constructor(message: any) {
23
- super(message);
24
- }
25
- }
26
-
27
- export class ValidationErrorException extends BadRequestException {
28
- name: string = "ValidationError";
29
- }
30
-
31
- export class InternalErrorException extends BaseHttpException {
32
- name: string = "InternalError";
33
- code: number = 500;
34
-
35
- constructor(message: any = "Something going wrong") {
36
- super(message);
37
- }
38
- }
39
-
40
- export class NotFoundException extends BaseHttpException {
41
- name: string = "NotFound";
42
- code: number = 404;
43
- constructor(message: any) {
44
- super(message);
45
- }
46
- }
47
-
48
- export class UnauthorizedException extends BaseHttpException {
49
- name: string = "Unauthorized";
50
- code: number = 401;
51
- constructor(message: any) {
52
- super(message);
53
- }
54
- }
55
-
56
- export class ForbiddenException extends BaseHttpException {
57
- name: string = "Forbidden";
58
- code: number = 403;
59
- constructor(message: any) {
60
- super(message);
61
- }
62
- }
63
-
64
- export type HttpExceptionTypes =
65
- | NotFoundException
66
- | BadRequestException
67
- | UnauthorizedException
68
- | InternalErrorException
69
- | ForbiddenException;
70
-
71
- // export type HttpExceptions = {
72
- // NotFound: (message: any) => NotFoundException,
73
- // ValidationError: (message: any) =>ValidationErrorException,
74
- // BadRequest: (message: any) => BadRequestException,
75
- // Unauthorized: (message: any) => UnauthorizedException,
76
- // Forbidden: (message: any) => ForbiddenException,
77
- // InternalError: (message: any) => InternalErrorException
78
- // }
79
- export const HttpExceptions = {
80
- notFound: (message: any = "") => new NotFoundException(message),
81
- validationError: (message: any = "") => new ValidationErrorException(message),
82
- badRequest: (message: any = "") => new BadRequestException(message),
83
- unauthorized: (message: any = "") => new UnauthorizedException(message),
84
- forbidden: (message: any = "") => new ForbiddenException(message),
85
- internalError: (message: any = "") => new InternalErrorException(message),
86
- };
@@ -1 +0,0 @@
1
- export * from "./http-exceptions";
@@ -1,35 +0,0 @@
1
- /**
2
- * @copyright 2024
3
- * @author Tareq Hossain
4
- * @email xtrinsic96@gmail.com
5
- * @url https://github.com/xtareq
6
- */
7
- export interface IRouteDuplicateErr {
8
- path: string;
9
- mpath: string;
10
- method: string;
11
- controller: string;
12
- inverseController?: string;
13
- }
14
-
15
- export class SystemUseError extends Error {
16
- constructor(message: string) {
17
- super(message);
18
- }
19
- }
20
- export class DuplicateRouteException extends Error {
21
- constructor(params: IRouteDuplicateErr) {
22
- let sameController = params.controller == params.inverseController;
23
- let message = `Duplicate route found for method ${params.method.toUpperCase()}:${params.path == "" ? "'/'" : params.path} `;
24
- message += sameController
25
- ? `in ${params.controller}`
26
- : `both in ${params.controller} and ${params.inverseController}`;
27
- super(message);
28
- }
29
- }
30
-
31
- export class EnvironmentVariableNotFound extends Error {
32
- constructor(key: string) {
33
- super(`${key} not found in environment variables.`);
34
- }
35
- }
@@ -1,206 +0,0 @@
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
- }