@avleon/core 0.0.5 → 0.0.7

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 CHANGED
@@ -1,4 +1,4 @@
1
1
  # avleon-core
2
2
 
3
3
 
4
- # Api (V0.0.)
4
+ # Api (V0.0.1)
@@ -1,9 +1,7 @@
1
1
  export type CurrentUser = {};
2
- export declare abstract class Authetication {
3
- abstract login(): void;
4
- abstract register(): void;
5
- abstract verifyToken(): boolean;
6
- abstract currentUser(): CurrentUser;
2
+ export declare abstract class BaseAuthetication {
3
+ abstract authenticate(): Promise<Boolean>;
4
+ abstract authorize(): Promise<Boolean>;
7
5
  }
8
6
  export declare function Authorized(): void;
9
7
  export declare function CurrentUser(): void;
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Authetication = void 0;
3
+ exports.BaseAuthetication = void 0;
4
4
  exports.Authorized = Authorized;
5
5
  exports.CurrentUser = CurrentUser;
6
- class Authetication {
6
+ class BaseAuthetication {
7
7
  }
8
- exports.Authetication = Authetication;
8
+ exports.BaseAuthetication = BaseAuthetication;
9
9
  function Authorized() {
10
10
  }
11
11
  function CurrentUser() { }
package/dist/config.d.ts CHANGED
@@ -18,13 +18,12 @@ export interface IAppConfig {
18
18
  apiKey: string;
19
19
  timezone: string;
20
20
  }
21
- interface ConfigClass {
22
- invoke(env: Environment): object;
21
+ export interface IConfig {
22
+ config(env: Environment): object;
23
23
  }
24
- export declare function Config(target: {
25
- new (...args: any[]): ConfigClass;
24
+ export declare function Config<T extends IConfig>(target: {
25
+ new (): T;
26
26
  }): void;
27
- export declare function GetConfig<T extends ConfigClass>(ConfigClass: {
28
- new (...args: any[]): T;
29
- }): ReturnType<T["invoke"]>;
30
- export {};
27
+ export declare function GetConfig<T extends IConfig>(ConfigClass: {
28
+ new (): T;
29
+ }): ReturnType<T["config"]>;
package/dist/config.js CHANGED
@@ -3,17 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Config = Config;
4
4
  exports.GetConfig = GetConfig;
5
5
  const CONFIG_METADATA_KEY = Symbol("config");
6
+ const configInstances = new Map();
6
7
  function Config(target) {
7
- if (typeof target.prototype.invoke !== "function") {
8
- throw new Error(`Class "${target.name}" must implement an "invoke" method.`);
8
+ if (typeof target.prototype.config !== "function") {
9
+ throw new Error(`Class "${target.name}" must implement a "config" method.`);
9
10
  }
10
11
  Reflect.defineMetadata(CONFIG_METADATA_KEY, target, target);
12
+ // Auto-instantiate and store the config instance
13
+ configInstances.set(target.name, new target());
11
14
  }
12
15
  function GetConfig(ConfigClass) {
13
- const ConfigCtor = Reflect.getMetadata(CONFIG_METADATA_KEY, ConfigClass);
14
- if (!ConfigCtor) {
15
- throw new Error(`Class "${ConfigClass.name}" is not decorated with @Config.`);
16
+ const instance = configInstances.get(ConfigClass.name);
17
+ if (!instance) {
18
+ throw new Error(`Class "${ConfigClass.name}" is not registered as a config.`);
16
19
  }
17
- const instance = new ConfigCtor();
18
- return instance.invoke(process.env);
20
+ return instance.config(process.env);
19
21
  }
@@ -7,6 +7,7 @@ export declare const REQUEST_BODY_META_KEY: unique symbol;
7
7
  export declare const REQUEST_USER_META_KEY: unique symbol;
8
8
  export declare const REQUEST_HEADER_META_KEY: unique symbol;
9
9
  export declare const DATASOURCE_META_KEY: unique symbol;
10
+ export declare const AUTHORIZATION_META_KEY: unique symbol;
10
11
  declare const Container: typeof TypediContainer;
11
12
  export declare function registerController(controller: Function): void;
12
13
  export declare function registerService(service: Function): void;
package/dist/container.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.API_CONTROLLER_METADATA_KEY = exports.DATASOURCE_META_KEY = exports.REQUEST_HEADER_META_KEY = exports.REQUEST_USER_META_KEY = exports.REQUEST_BODY_META_KEY = exports.QUERY_META_KEY = exports.PARAM_META_KEY = exports.CONTROLLER_META_KEY = exports.ROUTE_META_KEY = void 0;
6
+ exports.API_CONTROLLER_METADATA_KEY = exports.AUTHORIZATION_META_KEY = exports.DATASOURCE_META_KEY = exports.REQUEST_HEADER_META_KEY = exports.REQUEST_USER_META_KEY = exports.REQUEST_BODY_META_KEY = exports.QUERY_META_KEY = exports.PARAM_META_KEY = exports.CONTROLLER_META_KEY = exports.ROUTE_META_KEY = void 0;
7
7
  exports.registerController = registerController;
8
8
  exports.registerService = registerService;
9
9
  exports.getRegisteredServices = getRegisteredServices;
@@ -19,6 +19,7 @@ exports.REQUEST_BODY_META_KEY = Symbol("iparam:options");
19
19
  exports.REQUEST_USER_META_KEY = Symbol("iparam:options");
20
20
  exports.REQUEST_HEADER_META_KEY = Symbol("iheader:options");
21
21
  exports.DATASOURCE_META_KEY = Symbol("idatasource:options");
22
+ exports.AUTHORIZATION_META_KEY = Symbol("idatasource:authorization");
22
23
  const controllerRegistry = new Set();
23
24
  const serviceRegistry = new Set();
24
25
  const optionsRegistry = new Map();
@@ -35,7 +35,8 @@ export declare function createControllerDecorator(type?: "api" | "web"): (pathOr
35
35
  * @param path {string} this will used as route prefix
36
36
  *
37
37
  **/
38
- export declare function ApiController(path?: string): ClassDecorator;
38
+ export declare function ApiController(target: Function): void;
39
+ export declare function ApiController(path: string): ClassDecorator;
39
40
  /**
40
41
  *@description Api controller's are used for rest . It will populate
41
42
  * json on return and all it http methods {get} {post} etc must return
@@ -31,8 +31,22 @@ function createControllerDecorator(type = "web") {
31
31
  };
32
32
  }
33
33
  function ApiController(pathOrOptions = "/", mayBeOptions) {
34
- if (mayBeOptions) {
35
- return createControllerDecorator("api")(pathOrOptions, mayBeOptions);
34
+ if (typeof pathOrOptions == 'function') {
35
+ Reflect.defineMetadata(container_1.API_CONTROLLER_METADATA_KEY, true, pathOrOptions);
36
+ // Ensure Service is applied as a ClassDecorator
37
+ if (typeof typedi_1.Service === "function") {
38
+ (0, container_1.registerController)(pathOrOptions); // Add to custom registry
39
+ (0, typedi_1.Service)()(pathOrOptions); // Apply DI decorator
40
+ Reflect.defineMetadata(container_1.CONTROLLER_META_KEY, { type: 'api', path: "/", options: {} }, pathOrOptions);
41
+ }
42
+ else {
43
+ throw new Error("Service decorator is not a function");
44
+ }
45
+ }
46
+ else {
47
+ if (mayBeOptions) {
48
+ return createControllerDecorator("api")(pathOrOptions, mayBeOptions);
49
+ }
50
+ return createControllerDecorator("api")(pathOrOptions);
36
51
  }
37
- return createControllerDecorator("api")(pathOrOptions);
38
52
  }
package/dist/helpers.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export declare const uuid: `${string}-${string}-${string}-${string}-${string}`;
2
2
  export declare function inject<T>(cls: new (...args: any[]) => T): T;
3
3
  export type Constructor<T = any> = new (...args: any[]) => T;
4
+ export declare function isConstructor(func: any): boolean;
4
5
  export declare function formatUrl(path: string): string;
5
6
  export declare function parsedPath(ipath: string): string;
6
7
  export declare const isClassValidator: (target: Constructor) => boolean;
package/dist/helpers.js CHANGED
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.isClassValidatorClass = exports.getLineNumber = exports.isClassValidator = exports.uuid = void 0;
7
7
  exports.inject = inject;
8
+ exports.isConstructor = isConstructor;
8
9
  exports.formatUrl = formatUrl;
9
10
  exports.parsedPath = parsedPath;
10
11
  exports.normalizePath = normalizePath;
@@ -34,6 +35,28 @@ function inject(cls) {
34
35
  throw new system_exception_1.SystemUseError(`Not a project class. Maybe you wanna register it first.`);
35
36
  }
36
37
  }
38
+ function isConstructor(func) {
39
+ // Check if the func is a function
40
+ if (typeof func !== 'function') {
41
+ return false;
42
+ }
43
+ // Check if it's an arrow function or a built-in JavaScript function
44
+ if (func === Function.prototype.bind || func instanceof RegExp) {
45
+ return false;
46
+ }
47
+ // Check if it has a `prototype` property
48
+ if (func.prototype && typeof func.prototype === 'object') {
49
+ return true;
50
+ }
51
+ // If it's not a constructor, check if it can be called with the new keyword
52
+ try {
53
+ const instance = new func();
54
+ return typeof instance === 'object';
55
+ }
56
+ catch (e) {
57
+ return false;
58
+ }
59
+ }
37
60
  function formatUrl(path) {
38
61
  if (typeof path !== "string") {
39
62
  throw new Error("The path must be a string");
package/dist/icore.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from "fastify";
1
+ import { FastifyInstance, FastifyReply, FastifyRequest, HookHandlerDoneFunction } from "fastify";
2
2
  import { Constructor } from "./helpers";
3
+ import { PathLike } from "fs";
3
4
  import { DataSourceOptions } from "typeorm";
4
5
  import { AppMiddleware } from "./middleware";
5
6
  import { OpenApiOptions, OpenApiUiOptions } from "./openapi";
@@ -37,6 +38,10 @@ export interface MethodParamMeta {
37
38
  currentUser: ParamMetaOptions[];
38
39
  swagger?: OpenApiUiOptions;
39
40
  }
41
+ type StaticFileOptions = {
42
+ path?: PathLike;
43
+ prefix?: string;
44
+ };
40
45
  declare class AvleonApplication {
41
46
  private static instance;
42
47
  private static buildOptions;
@@ -49,6 +54,7 @@ declare class AvleonApplication {
49
54
  private hasSwagger;
50
55
  private globalSwaggerOptions;
51
56
  private controllers;
57
+ private authorizeMiddleware?;
52
58
  private constructor();
53
59
  static getInternalApp(buildOptions: any): AvleonApplication;
54
60
  isDevelopment(): boolean;
@@ -67,6 +73,7 @@ declare class AvleonApplication {
67
73
  handleRoute(args: any): Promise<void>;
68
74
  private mapFn;
69
75
  useMiddlewares<T extends AppMiddleware>(mclasses: Constructor<T>[]): void;
76
+ useAuthoriztion<T extends any>(middleware: Constructor<T>): void;
70
77
  private _handleError;
71
78
  mapRoute<T extends (...args: any[]) => any>(method: "get" | "post" | "put" | "delete", path: string | undefined, fn: T): Promise<void>;
72
79
  private _routeHandler;
@@ -86,7 +93,9 @@ declare class AvleonApplication {
86
93
  useMiddleware: <M extends AppMiddleware>(middlewares: Constructor<AppMiddleware>[]) => /*elided*/ any;
87
94
  useSwagger: (options: OpenApiOptions) => /*elided*/ any;
88
95
  };
96
+ useStaticFiles(options?: StaticFileOptions): void;
89
97
  run(port?: number): Promise<void>;
98
+ getTestApp(app: AvleonApplication): FastifyInstance<import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
90
99
  }
91
100
  export declare class Builder {
92
101
  private static instance;
@@ -95,6 +104,7 @@ export declare class Builder {
95
104
  private dataSource?;
96
105
  private constructor();
97
106
  static createAppBuilder(): Builder;
107
+ static creatTestAppBilder(): Builder;
98
108
  registerPlugin<T extends Function, S extends {}>(plugin: T, options: S): Promise<void>;
99
109
  addDataSource(config: DataSourceOptions): Promise<void>;
100
110
  build(): AvleonApplication;
package/dist/icore.js CHANGED
@@ -57,7 +57,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
57
57
  exports.Builder = void 0;
58
58
  const fastify_1 = __importDefault(require("fastify"));
59
59
  const typedi_1 = __importDefault(require("typedi"));
60
- const promises_1 = __importDefault(require("fs/promises")); // Use promises for asynchronous file operations
60
+ const promises_1 = __importDefault(require("fs/promises"));
61
61
  const path_1 = __importDefault(require("path"));
62
62
  const container_1 = __importStar(require("./container"));
63
63
  const helpers_1 = require("./helpers");
@@ -65,7 +65,6 @@ const system_exception_1 = require("./exceptions/system-exception");
65
65
  const fs_1 = require("fs");
66
66
  const exceptions_1 = require("./exceptions");
67
67
  const swagger_1 = __importDefault(require("@fastify/swagger"));
68
- const fastify_api_reference_1 = __importDefault(require("@scalar/fastify-api-reference"));
69
68
  const environment_variables_1 = require("./environment-variables");
70
69
  const isTsNode = process.env.TS_NODE_DEV ||
71
70
  process.env.TS_NODE_PROJECT ||
@@ -82,6 +81,7 @@ class AvleonApplication {
82
81
  this.hasSwagger = false;
83
82
  this.globalSwaggerOptions = {};
84
83
  this.controllers = [];
84
+ this.authorizeMiddleware = undefined;
85
85
  this.metaCache = new Map();
86
86
  this.app = (0, fastify_1.default)();
87
87
  // this.app.setValidatorCompiler(() => () => true);
@@ -96,25 +96,28 @@ class AvleonApplication {
96
96
  return AvleonApplication.instance;
97
97
  }
98
98
  isDevelopment() {
99
- return environment_variables_1.env['NODE_ENV'] == "development";
99
+ return environment_variables_1.env["NODE_ENV"] == "development";
100
100
  }
101
101
  async initSwagger(options) {
102
- const { routePrefix } = options, restOptions = __rest(options, ["routePrefix"]);
102
+ const { routePrefix, logo, theme } = options, restOptions = __rest(options, ["routePrefix", "logo", "theme"]);
103
103
  this.app.register(swagger_1.default, {
104
- openapi: Object.assign({ openapi: '3.0.0' }, restOptions)
104
+ openapi: Object.assign({ openapi: "3.0.0" }, restOptions),
105
105
  });
106
106
  const rPrefix = routePrefix ? routePrefix : "/docs";
107
107
  //import fastifyApiReference from "@scalar/fastify-api-reference";
108
- await this.app.register(fastify_api_reference_1.default, {
108
+ //const fastifyApiReference = await require("@scalar/fastify-api-reference");
109
+ await this.app.register(require("@fastify/swagger-ui"), {
110
+ logo: logo ? logo : null,
111
+ theme: theme ? theme : {},
109
112
  routePrefix: rPrefix,
110
113
  configuration: {
111
114
  metaData: {
112
- title: 'Avleon Api',
113
- ogTitle: 'Avleon'
115
+ title: "Avleon Api",
116
+ ogTitle: "Avleon",
114
117
  },
115
- theme: 'kepler',
116
- favicon: '/static/favicon.png'
117
- }
118
+ theme: "kepler",
119
+ favicon: "/static/favicon.png",
120
+ },
118
121
  });
119
122
  }
120
123
  async useSwagger(options) {
@@ -146,6 +149,13 @@ class AvleonApplication {
146
149
  let classMiddlewares = [];
147
150
  const tag = ctrl.constructor.name.replace("Controller", "");
148
151
  const swaggerControllerMeta = Reflect.getMetadata("controller:openapi", ctrl.constructor) || {};
152
+ const authClsMeata = Reflect.getMetadata(container_1.AUTHORIZATION_META_KEY, ctrl.constructor) || { authorize: false, options: undefined };
153
+ if (authClsMeata.authorize && this.authorizeMiddleware) {
154
+ this.app.addHook("preHandler", (req, res) => {
155
+ return this.authorizeMiddleware.authorize(req);
156
+ });
157
+ }
158
+ console.log("ClassMiddlware:", tag + ":", authClsMeata);
149
159
  try {
150
160
  for (var _d = true, methods_1 = __asyncValues(methods), methods_1_1; methods_1_1 = await methods_1.next(), _a = methods_1_1.done, !_a; _d = true) {
151
161
  _c = methods_1_1.value;
@@ -165,6 +175,7 @@ class AvleonApplication {
165
175
  const classMiddlewares = this.executeMiddlewares(ctrl, method);
166
176
  // handle openapi data
167
177
  const swaggerMeta = Reflect.getMetadata("route:openapi", prototype, method) || {};
178
+ const authClsMethodMeata = Reflect.getMetadata(container_1.AUTHORIZATION_META_KEY, ctrl.constructor, method) || { authorize: false, options: undefined };
168
179
  const allMeta = this._processMeta(prototype, method);
169
180
  const routePath = methodmetaOptions.path == "" ? "/" : methodmetaOptions.path;
170
181
  this.app.route({
@@ -173,10 +184,16 @@ class AvleonApplication {
173
184
  schema: Object.assign(Object.assign(Object.assign({}, swaggerControllerMeta), swaggerMeta), { tags: [tag] }),
174
185
  handler: async (req, res) => {
175
186
  let reqClone = req;
187
+ if (authClsMethodMeata.authorize && this.authorizeMiddleware) {
188
+ const cls = container_1.default.get(this.authorizeMiddleware);
189
+ await cls.authorize(reqClone, authClsMethodMeata.options);
190
+ if (res.sent)
191
+ return;
192
+ }
176
193
  if (classMiddlewares.length > 0) {
177
194
  for (let m of classMiddlewares) {
178
195
  const cls = typedi_1.default.get(m.constructor);
179
- reqClone = await cls.invoke(reqClone, res);
196
+ reqClone = (await cls.invoke(reqClone, res));
180
197
  if (res.sent)
181
198
  return;
182
199
  }
@@ -297,11 +314,24 @@ class AvleonApplication {
297
314
  this.app.addHook("preHandler", cls.invoke);
298
315
  }
299
316
  }
317
+ useAuthoriztion(middleware) {
318
+ this.authorizeMiddleware = middleware;
319
+ }
300
320
  _handleError(error) {
301
321
  if (error instanceof exceptions_1.BaseHttpException) {
302
- return { code: error.code, error: error.name, message: (0, helpers_1.isValidJsonString)(error.message) ? JSON.parse(error.message) : error.message };
322
+ return {
323
+ code: error.code,
324
+ error: error.name,
325
+ message: (0, helpers_1.isValidJsonString)(error.message)
326
+ ? JSON.parse(error.message)
327
+ : error.message,
328
+ };
303
329
  }
304
- return { code: 500, error: 'INTERNALERROR', message: error.message ? error.message : "Something going wrong." };
330
+ return {
331
+ code: 500,
332
+ error: "INTERNALERROR",
333
+ message: error.message ? error.message : "Something going wrong.",
334
+ };
305
335
  }
306
336
  async mapRoute(method, path = "", fn) {
307
337
  await this.mapFn(fn); // Assuming mapFn is needed for all methods
@@ -328,7 +358,7 @@ class AvleonApplication {
328
358
  this.rMap.set(routeKey, {
329
359
  handler: fn,
330
360
  middlewares: [],
331
- schema: {}
361
+ schema: {},
332
362
  });
333
363
  this.mapFn(fn);
334
364
  const route = {
@@ -367,16 +397,18 @@ class AvleonApplication {
367
397
  mapDelete(path = "", fn) {
368
398
  return this._routeHandler(path, "DELETE", fn);
369
399
  }
400
+ useStaticFiles(options = { path: undefined, prefix: undefined }) {
401
+ this.app.register(require("@fastify/static"), {
402
+ root: options.path ? options.path : path_1.default.join(process.cwd(), "public"),
403
+ prefix: options.prefix ? options.prefix : "/static/",
404
+ });
405
+ }
370
406
  async run(port = 4000) {
371
407
  if (this.alreadyRun)
372
408
  throw new system_exception_1.SystemUseError("App already running");
373
409
  this.alreadyRun = true;
374
410
  if (AvleonApplication.buildOptions.database) {
375
411
  }
376
- this.app.register(require('@fastify/static'), {
377
- root: path_1.default.join(process.cwd(), 'public'),
378
- prefix: '/static/'
379
- });
380
412
  //this.app.swagger();
381
413
  if (this.hasSwagger) {
382
414
  await this.initSwagger(this.globalSwaggerOptions);
@@ -401,7 +433,11 @@ class AvleonApplication {
401
433
  this.app.setErrorHandler(async (error, req, res) => {
402
434
  const handledErr = this._handleError(error);
403
435
  if (error instanceof exceptions_1.ValidationErrorException) {
404
- return res.status(handledErr.code).send({ code: handledErr.code, error: handledErr.error, errors: handledErr.message });
436
+ return res.status(handledErr.code).send({
437
+ code: handledErr.code,
438
+ error: handledErr.error,
439
+ errors: handledErr.message,
440
+ });
405
441
  }
406
442
  return res.status(handledErr.code).send(handledErr);
407
443
  });
@@ -409,6 +445,9 @@ class AvleonApplication {
409
445
  await this.app.listen({ port });
410
446
  console.log(`Application running on port: 0.0.0.0:${port}`);
411
447
  }
448
+ getTestApp(app) {
449
+ return this.app;
450
+ }
412
451
  }
413
452
  AvleonApplication.buildOptions = {};
414
453
  // Applciation Builder
@@ -423,6 +462,12 @@ class Builder {
423
462
  }
424
463
  return Builder.instance;
425
464
  }
465
+ static creatTestAppBilder() {
466
+ if (!Builder.instance) {
467
+ Builder.instance = new Builder();
468
+ }
469
+ return Builder.instance;
470
+ }
426
471
  async registerPlugin(plugin, options) {
427
472
  container_1.default.set(plugin, plugin.prototype);
428
473
  }
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export * from "./map-types";
8
8
  export * from "./response";
9
9
  export * from "./exceptions";
10
10
  export * from "./validator-extend";
11
+ export * from "./validation";
11
12
  export * from "./environment-variables";
12
13
  export * from "./collection";
13
14
  export * from "./queue";
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ __exportStar(require("./map-types"), exports);
31
31
  __exportStar(require("./response"), exports);
32
32
  __exportStar(require("./exceptions"), exports);
33
33
  __exportStar(require("./validator-extend"), exports);
34
+ __exportStar(require("./validation"), exports);
34
35
  __exportStar(require("./environment-variables"), exports);
35
36
  __exportStar(require("./collection"), exports);
36
37
  __exportStar(require("./queue"), exports);
@@ -3,8 +3,22 @@ import { HttpException } from "./exceptions";
3
3
  export declare abstract class AppMiddleware {
4
4
  abstract invoke(req: IRequest, res?: IResponse): Promise<IRequest | HttpException>;
5
5
  }
6
+ export type AuthHandler = (req: IRequest, roles?: string[]) => Promise<IRequest | HttpException>;
6
7
  export type Constructor<T> = {
7
8
  new (...args: any[]): T;
8
9
  };
10
+ export declare abstract class AuthorizeMiddleware {
11
+ abstract authorize(roles: string[]): (req: IRequest, res?: IResponse) => IRequest | Promise<IRequest>;
12
+ }
13
+ export type AuthReturnTypes = IRequest | Promise<IRequest>;
14
+ interface AuthorizeClass {
15
+ authorize(req: IRequest, options?: any): AuthReturnTypes;
16
+ }
17
+ export declare function Authorize(target: {
18
+ new (...args: any[]): AuthorizeClass;
19
+ }): void;
20
+ export declare function Authorized(): ClassDecorator & MethodDecorator;
21
+ export declare function Authorized(options?: any): ClassDecorator & MethodDecorator;
9
22
  export declare function Middleware(target: Constructor<AppMiddleware>): void;
10
23
  export declare function UseMiddleware<T extends AppMiddleware | (new (...args: any[]) => AppMiddleware)>(options: T | T[]): MethodDecorator & ClassDecorator;
24
+ export {};
@@ -1,12 +1,40 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AppMiddleware = void 0;
3
+ exports.AuthorizeMiddleware = exports.AppMiddleware = void 0;
4
+ exports.Authorize = Authorize;
5
+ exports.Authorized = Authorized;
4
6
  exports.Middleware = Middleware;
5
7
  exports.UseMiddleware = UseMiddleware;
6
8
  const typedi_1 = require("typedi");
9
+ const container_1 = require("./container");
7
10
  class AppMiddleware {
8
11
  }
9
12
  exports.AppMiddleware = AppMiddleware;
13
+ class AuthorizeMiddleware {
14
+ }
15
+ exports.AuthorizeMiddleware = AuthorizeMiddleware;
16
+ function Authorize(target) {
17
+ if (typeof target.prototype.authorize !== "function") {
18
+ throw new Error(`Class "${target.name}" must implement an "authorize" method.`);
19
+ }
20
+ (0, typedi_1.Service)()(target);
21
+ }
22
+ function Authorized(options = {}) {
23
+ return function (target, propertyKey, descriptor) {
24
+ if (propertyKey && descriptor) {
25
+ Reflect.defineMetadata(container_1.AUTHORIZATION_META_KEY, { authorize: true, options }, target.constructor, propertyKey);
26
+ }
27
+ else {
28
+ Reflect.defineMetadata(container_1.AUTHORIZATION_META_KEY, { authorize: true, options }, target);
29
+ }
30
+ };
31
+ }
32
+ function Middleware(target) {
33
+ if (typeof target.prototype.invoke !== "function") {
34
+ throw new Error(`Class "${target.name}" must implement an "invoke" method.`);
35
+ }
36
+ (0, typedi_1.Service)()(target);
37
+ }
10
38
  // export function CurrentUser(): ParameterDecorator {
11
39
  // return (target, propertyKey, parameterIndex) => {
12
40
  // const existingMetadata =
@@ -15,12 +43,6 @@ exports.AppMiddleware = AppMiddleware;
15
43
  // Reflect.defineMetadata("currentUser:params", existingMetadata, target, propertyKey!);
16
44
  // };
17
45
  // }
18
- function Middleware(target) {
19
- if (typeof target.prototype.invoke !== "function") {
20
- throw new Error(`Class "${target.name}" must implement an "invoke" method.`);
21
- }
22
- (0, typedi_1.Service)()(target);
23
- }
24
46
  function UseMiddleware(options) {
25
47
  return function (target, propertyKey, descriptor) {
26
48
  const normalizeMiddleware = (middleware) => typeof middleware === "function" ? new middleware() : middleware;
package/dist/openapi.d.ts CHANGED
@@ -28,6 +28,8 @@ interface ServerVariableObject {
28
28
  description?: string;
29
29
  }
30
30
  export type OpenApiUiOptions = {
31
+ logo?: any;
32
+ theme?: any;
31
33
  openapi?: string;
32
34
  routePrefix?: string;
33
35
  info?: InfoObject;
@@ -4,6 +4,7 @@ exports.generateSwaggerSchema = generateSwaggerSchema;
4
4
  function generateSwaggerSchema(classType) {
5
5
  const { getMetadataStorage } = require("class-validator");
6
6
  const { plainToInstance } = require("class-transformer");
7
+ //const { isArray } = require("lodash"); // Add lodash for array check
7
8
  const metadataStorage = getMetadataStorage();
8
9
  const validationMetadata = metadataStorage.getTargetValidationMetadatas(classType, "", true);
9
10
  const schema = {
@@ -12,18 +13,136 @@ function generateSwaggerSchema(classType) {
12
13
  required: [],
13
14
  };
14
15
  validationMetadata.forEach((meta) => {
16
+ var _a, _b;
15
17
  const propertyName = meta.propertyName;
16
18
  // Infer the type dynamically using Reflect metadata
17
19
  const propertyType = Reflect.getMetadata("design:type", classType.prototype, propertyName);
18
- schema.properties[propertyName] = {
19
- type: (propertyType === null || propertyType === void 0 ? void 0 : propertyType.name.toLowerCase()) || "string", // Default to string if type cannot be inferred
20
- };
21
- if (meta.name === "isNotEmpty") {
22
- schema.required.push(propertyName);
23
- }
24
- if (meta.name === "minLength") {
25
- schema.properties[propertyName].minLength = meta.constraints[0];
20
+ let swaggerProperty = {};
21
+ switch (propertyType) {
22
+ case String:
23
+ swaggerProperty.type = "string";
24
+ break;
25
+ case Number:
26
+ swaggerProperty.type = "number";
27
+ break;
28
+ case Boolean:
29
+ swaggerProperty.type = "boolean";
30
+ break;
31
+ case Date:
32
+ swaggerProperty.type = "string";
33
+ swaggerProperty.format = "date-time";
34
+ break;
35
+ case Array:
36
+ // Attempt to infer array item type
37
+ const arrayItemType = Reflect.getMetadata("design:type", classType.prototype, propertyName + "[0]" // Attempt to get array item type. Very fragile.
38
+ );
39
+ if (arrayItemType) {
40
+ swaggerProperty.type = "array";
41
+ swaggerProperty.items = {
42
+ type: arrayItemType.name.toLowerCase(), // basic type inference
43
+ };
44
+ if (arrayItemType === Object) {
45
+ //try to infer the Object type within array
46
+ const nestedSchema = generateSwaggerSchema(Reflect.getMetadata("design:type", classType.prototype, propertyName + "[0]"));
47
+ swaggerProperty.items = nestedSchema;
48
+ }
49
+ }
50
+ else {
51
+ swaggerProperty.type = "array";
52
+ swaggerProperty.items = {}; // Array of unknown type
53
+ }
54
+ break;
55
+ case Object:
56
+ //Nested object
57
+ const nestedSchema = generateSwaggerSchema(Reflect.getMetadata("design:type", classType.prototype, propertyName));
58
+ swaggerProperty = nestedSchema;
59
+ break;
60
+ default:
61
+ swaggerProperty.type = ((_a = propertyType === null || propertyType === void 0 ? void 0 : propertyType.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || "string"; // Default to string if type cannot be inferred
26
62
  }
63
+ schema.properties[propertyName] = swaggerProperty;
64
+ (_b = meta.constraints) === null || _b === void 0 ? void 0 : _b.forEach((constraint) => {
65
+ switch (constraint.name) {
66
+ case "isNotEmpty":
67
+ if (!schema.required.includes(propertyName)) {
68
+ schema.required.push(propertyName);
69
+ }
70
+ break;
71
+ case "minLength":
72
+ schema.properties[propertyName].minLength = constraint.constraints[0];
73
+ break;
74
+ case "maxLength":
75
+ schema.properties[propertyName].maxLength = constraint.constraints[0];
76
+ break;
77
+ case "min":
78
+ schema.properties[propertyName].minimum = constraint.constraints[0];
79
+ break;
80
+ case "max":
81
+ schema.properties[propertyName].maximum = constraint.constraints[0];
82
+ break;
83
+ case "isEmail":
84
+ schema.properties[propertyName].format = "email";
85
+ break;
86
+ case "isDate":
87
+ schema.properties[propertyName].format = "date-time";
88
+ break;
89
+ case "isIn":
90
+ schema.properties[propertyName].enum = constraint.constraints[0];
91
+ break;
92
+ case "isNumber":
93
+ schema.properties[propertyName].type = "number";
94
+ break;
95
+ case "isInt":
96
+ schema.properties[propertyName].type = "integer";
97
+ break;
98
+ case "isBoolean":
99
+ schema.properties[propertyName].type = "boolean";
100
+ break;
101
+ case "isString":
102
+ schema.properties[propertyName].type = "string";
103
+ break;
104
+ case "isOptional":
105
+ if (schema.required.includes(propertyName)) {
106
+ schema.required = schema.required.filter((item) => item !== propertyName);
107
+ }
108
+ break;
109
+ // Add more cases for other validators as needed
110
+ }
111
+ });
27
112
  });
28
113
  return schema;
29
114
  }
115
+ // export function generateSwaggerSchema(classType: any) {
116
+ // const { getMetadataStorage } = require("class-validator");
117
+ // const { plainToInstance } = require("class-transformer");
118
+ // const metadataStorage = getMetadataStorage();
119
+ // const validationMetadata = metadataStorage.getTargetValidationMetadatas(
120
+ // classType,
121
+ // "",
122
+ // true,
123
+ // );
124
+ // const schema: any = {
125
+ // type: "object",
126
+ // properties: {},
127
+ // required: [],
128
+ // };
129
+ // validationMetadata.forEach((meta: any) => {
130
+ // const propertyName = meta.propertyName;
131
+ // // Infer the type dynamically using Reflect metadata
132
+ // const propertyType = Reflect.getMetadata(
133
+ // "design:type",
134
+ // classType.prototype,
135
+ // propertyName,
136
+ // );
137
+ // schema.properties[propertyName] = {
138
+ // type: propertyType?.name.toLowerCase() || "string", // Default to string if type cannot be inferred
139
+ // };
140
+ // if (meta.name === "isNotEmpty") {
141
+ // schema.required.push(propertyName);
142
+ // }
143
+ // if (meta.name === "minLength") {
144
+ // schema.properties[propertyName].minLength = meta.constraints[0];
145
+ // }
146
+ // });
147
+ // return schema;
148
+ // }
@@ -0,0 +1,23 @@
1
+ type BaseRule = {
2
+ required?: boolean;
3
+ optional?: boolean;
4
+ message?: string;
5
+ };
6
+ type StringRule = BaseRule & {
7
+ type: "string";
8
+ };
9
+ type NumberRule = BaseRule & {
10
+ type: "number";
11
+ min?: number;
12
+ max?: number;
13
+ exact?: number;
14
+ };
15
+ type BooleanRule = BaseRule & {
16
+ type: "boolean";
17
+ };
18
+ export type ValidationRule = StringRule | NumberRule | BooleanRule;
19
+ export type ValidationProps = {
20
+ [key: string]: ValidationRule;
21
+ };
22
+ export declare function validateOrThrow<T extends {}>(obj: T, rules: ValidationProps): any;
23
+ export {};
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateOrThrow = validateOrThrow;
4
+ const exceptions_1 = require("./exceptions");
5
+ class PValidationRule {
6
+ constructor(name, type, message) {
7
+ this.name = name;
8
+ this.type = type;
9
+ this.message = message;
10
+ }
11
+ }
12
+ class Validator {
13
+ constructor(obj) {
14
+ this.rules = [];
15
+ this.init(obj);
16
+ }
17
+ init(obj) {
18
+ Object.keys(obj).forEach((key) => {
19
+ const rule = obj[key];
20
+ this.rules.push(new PValidationRule(key, rule.type, rule.message));
21
+ });
22
+ }
23
+ validate(obj) {
24
+ const erors = [];
25
+ this.rules.forEach((k) => {
26
+ const r = Object.keys(obj).find((key) => key == k.name);
27
+ let messages = [];
28
+ if (!r || obj[r] == undefined || obj[r] == "") {
29
+ messages.push({
30
+ constraint: "required",
31
+ message: k.name + " is required",
32
+ });
33
+ }
34
+ if (k.type == "string" && typeof obj[k.name] != "string") {
35
+ messages.push({
36
+ constraint: "type",
37
+ message: `${k.name} must be type ${k.type}`,
38
+ });
39
+ }
40
+ if (k.type == "number" && !parseInt(obj[k.name])) {
41
+ messages.push({
42
+ constraint: "type",
43
+ message: `${k.name} must be type ${k.type}`,
44
+ });
45
+ }
46
+ if (k.type == "number") {
47
+ obj[k.name] = parseInt(obj[k.name]);
48
+ }
49
+ if (k.type == "boolean" && !isBool(obj[k.name])) {
50
+ messages.push({
51
+ constraint: "type",
52
+ message: `${k.name} must be type ${k.type}`,
53
+ });
54
+ }
55
+ if (k.type == "boolean") {
56
+ obj[k.name] = parseBoolean(obj[k.name]);
57
+ }
58
+ if (messages.length > 0) {
59
+ erors.push({
60
+ path: k.name,
61
+ messages: messages,
62
+ });
63
+ }
64
+ });
65
+ return [erors, obj];
66
+ }
67
+ }
68
+ const isBool = (val) => {
69
+ if (typeof val == "boolean")
70
+ return true;
71
+ if (parseInt(val) == 0 || parseInt(val) == 1)
72
+ return true;
73
+ if (val == "true" || val == "false")
74
+ return true;
75
+ return false;
76
+ };
77
+ const parseBoolean = (val) => {
78
+ if (typeof val === "boolean")
79
+ return val;
80
+ // if (typeof val === "number") {
81
+ // return val !== 0; // Common convention: 0 → false, any other number → true
82
+ // }
83
+ if (parseInt(val) == 1)
84
+ return true;
85
+ if (typeof val === "string") {
86
+ const normalized = val.trim().toLowerCase();
87
+ return normalized === "true";
88
+ }
89
+ return false; // Default for unsupported types (null, undefined, objects, etc.)
90
+ };
91
+ function validateOrThrow(obj, rules) {
92
+ const valid = new Validator(rules);
93
+ const errors = valid.validate(obj);
94
+ if (errors[0].length > 0) {
95
+ throw new exceptions_1.BadRequestException(errors[0]);
96
+ }
97
+ return errors[1];
98
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avleon/core",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "scripts": {
@@ -25,7 +25,6 @@
25
25
  "@fastify/static": "^8.1.1",
26
26
  "@fastify/swagger": "^9.4.0",
27
27
  "@fastify/swagger-ui": "^5.1.0",
28
- "@scalar/fastify-api-reference": "^1.25.122",
29
28
  "class-transformer": "^0.5.1",
30
29
  "class-validator": "^0.14.1",
31
30
  "dotenv": "^16.4.7",
@@ -34,12 +33,15 @@
34
33
  "typedi": "^0.10.0",
35
34
  "typeorm": "^0.3.20"
36
35
  },
36
+ "peerDependencies": {
37
+ "@scalar/fastify-api-reference":"^1.25.130"
38
+ },
37
39
  "directories": {
38
40
  "test": "tests"
39
41
  },
40
42
  "description": "avleon core",
41
43
  "repository": {
42
44
  "type": "git",
43
- "url": "git+https://github.com/xtareq/avleon-core"
45
+ "url": "git+https://github.com/avleonjs/avleon-core"
44
46
  }
45
47
  }