@avleon/core 0.0.32 → 0.0.37

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/License ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Tareq Hossain
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -48,6 +48,7 @@ Avleon is a powerful, TypeScript-based web framework built on top of Fastify, de
48
48
  - [mapPost](#mappost)
49
49
  - [mapPut](#mapput)
50
50
  - [mapDelete](#mapdelete)
51
+ - [Testing](#testing)
51
52
 
52
53
  ## Features
53
54
 
@@ -77,7 +78,7 @@ pnpm add @avleon/core
77
78
 
78
79
  ## Quick Start
79
80
 
80
- ### Route Based
81
+ ### Minimal
81
82
 
82
83
  ```typescript
83
84
  import { Avleon, ApiController, Get, Results } from "@avleon/core";
@@ -349,10 +350,9 @@ class UserDto {
349
350
 
350
351
  Generate API documentation automatically:
351
352
 
352
- ```typescript
353
- const app = new Avleon({
354
- controllers: [UserController],
355
- openapi: {
353
+ ```typescript
354
+
355
+ app.useOpenApi({
356
356
  info: {
357
357
  title: "User API",
358
358
  version: "1.0.0",
@@ -364,9 +364,9 @@ const app = new Avleon({
364
364
  description: "Development server",
365
365
  },
366
366
  ],
367
- },
368
- });
369
- ```
367
+ });
368
+
369
+ ```
370
370
 
371
371
  You can also customize the OpenAPI UI:
372
372
 
@@ -430,6 +430,27 @@ app.useDataSource(DataSourceConfig);
430
430
  // ... other impments
431
431
  ```
432
432
 
433
+ Now in your Controller or Injected service use can use like this
434
+
435
+ ```typescript
436
+ import { AppService, InjectRepository } from "@avleon/core";
437
+ import { Repository } from "typeorm";
438
+ import { User } from "model_path";
439
+
440
+ @AppService
441
+ export class UserService {
442
+ constructor(
443
+ @InjectRepository(User)
444
+ private readonly _userRepository: Repository<User>,
445
+ ) {}
446
+
447
+ async findAll() {
448
+ const users = await this._userRepository.find();
449
+ return users;
450
+ }
451
+ }
452
+ ```
453
+
433
454
  ### File Uploads
434
455
 
435
456
  Handle file uploads with multipart support:
@@ -445,7 +466,7 @@ app.useMultipart({
445
466
 
446
467
  // In your controller
447
468
  @Post('/upload')
448
- async uploadFile(@File() file: any) {
469
+ async uploadFile(@MultipartFile() file: any) {
449
470
  // Process uploaded file
450
471
  return HttpResponse.Ok({ filename: file.filename });
451
472
  }
@@ -462,46 +483,9 @@ app.useStaticFiles({
462
483
  });
463
484
  ```
464
485
 
465
- ### Testing
466
-
467
- Test your API endpoints with the built-in testing utilities:
468
-
469
- ```typescript
470
- import { TestBuilder } from "@avleon/core";
471
-
472
- const testBuilder = TestBuilder.createBuilder();
473
- const app = testBuilder.getTestApplication({
474
- controllers: [UserController],
475
- });
476
-
477
- // Test your API endpoints
478
- const response = await app.get("/users");
479
- expect(response.statusCode).toBe(200);
480
- ```
481
-
482
486
  ## Configuration
483
487
 
484
- Configure your application with environment variables:
485
-
486
- ```typescript
487
- // .env
488
- PORT=3000
489
- DATABASE_URL=postgres://user:password@localhost:5432/db
490
-
491
- // app.ts
492
- import { Environment } from '@avleon/core';
493
-
494
- const env = new Environment();
495
- env.load();
496
-
497
- const app = new Avleon({
498
- controllers: [UserController],
499
- env: {
500
- port: 'PORT',
501
- databaseUrl: 'DATABASE_URL',
502
- },
503
- });
504
- ```
488
+ Coming soon...
505
489
 
506
490
  ## Route Mapping
507
491
 
@@ -558,6 +542,8 @@ app.mapDelete("/users/:id", async (req, res) => {
558
542
  });
559
543
  ```
560
544
 
545
+ ### Add openapi and middleware support for inline route
546
+
561
547
  Each of these methods returns a route object that can be used to add middleware or Swagger documentation to the route.
562
548
 
563
549
  ```typescript
@@ -592,6 +578,12 @@ app
592
578
  });
593
579
  ```
594
580
 
581
+ ### Testing
582
+
583
+ Test your API endpoints with the built-in testing utilities:
584
+
585
+ Coming soon...
586
+
595
587
  ## License
596
588
 
597
589
  ISC
@@ -223,7 +223,6 @@ function InjectRepository(model) {
223
223
  });
224
224
  }
225
225
  catch (error) {
226
- console.log(error);
227
226
  if (error.name && error.name == "ServiceNotFoundError") {
228
227
  console.log("Database didn't initialized.");
229
228
  }
@@ -4,6 +4,7 @@
4
4
  * @email xtrinsic96@gmail.com
5
5
  * @url https://github.com/xtareq
6
6
  */
7
+ import { Knex } from "knex";
7
8
  import TypediContainer from "typedi";
8
9
  export declare const FEATURE_KEY: unique symbol;
9
10
  export declare const ROUTE_META_KEY: unique symbol;
@@ -25,4 +26,5 @@ export declare function getRegisteredControllers(): Function[];
25
26
  export declare const API_CONTROLLER_METADATA_KEY: unique symbol;
26
27
  export declare function isApiController(target: Function): boolean;
27
28
  export declare function registerDataSource(dataSource: any): void;
29
+ export declare function registerKnex(dataSource: Knex.Config): void;
28
30
  export default Container;
package/dist/container.js CHANGED
@@ -10,12 +10,7 @@ exports.getRegisteredServices = getRegisteredServices;
10
10
  exports.getRegisteredControllers = getRegisteredControllers;
11
11
  exports.isApiController = isApiController;
12
12
  exports.registerDataSource = registerDataSource;
13
- /**
14
- * @copyright 2024
15
- * @author Tareq Hossain
16
- * @email xtrinsic96@gmail.com
17
- * @url https://github.com/xtareq
18
- */
13
+ exports.registerKnex = registerKnex;
19
14
  const typedi_1 = __importDefault(require("typedi"));
20
15
  exports.FEATURE_KEY = Symbol.for("features");
21
16
  exports.ROUTE_META_KEY = Symbol("iroute:options");
@@ -54,4 +49,7 @@ Container.set("appName", "Iqra");
54
49
  function registerDataSource(dataSource) {
55
50
  Container.set("idatasource", dataSource);
56
51
  }
52
+ function registerKnex(dataSource) {
53
+ Container.set("KnexConnection", dataSource);
54
+ }
57
55
  exports.default = Container;
@@ -4,9 +4,46 @@
4
4
  * @email xtrinsic96@gmail.com
5
5
  * @url https://github.com/xtareq
6
6
  */
7
+ /**
8
+ * @class Environment
9
+ * @description A service class to manage access to environment variables.
10
+ * It loads variables from `.env` file and merges them with `process.env`,
11
+ * giving precedence to `process.env` values.
12
+ */
7
13
  export declare class Environment {
14
+ /**
15
+ * Parses the given `.env` file and merges it with `process.env`.
16
+ * Values from `process.env` take precedence.
17
+ *
18
+ * @private
19
+ * @param filePath - Absolute path to the `.env` file.
20
+ * @returns A dictionary of merged environment variables.
21
+ */
8
22
  private parseEnvFile;
23
+ /**
24
+ * Retrieves the value of the specified environment variable.
25
+ *
26
+ * @template T
27
+ * @param key - The name of the environment variable.
28
+ * @returns The value of the variable, or `undefined` if not found.
29
+ */
9
30
  get<T = any>(key: string): T;
31
+ /**
32
+ * Retrieves the value of the specified environment variable.
33
+ * Throws an error if the variable is not found.
34
+ *
35
+ * @template T
36
+ * @param key - The name of the environment variable.
37
+ * @throws {EnvironmentVariableNotFound} If the variable does not exist.
38
+ * @returns The value of the variable.
39
+ */
10
40
  getOrThrow<T = any>(key: string): T;
41
+ /**
42
+ * Retrieves all available environment variables,
43
+ * with `process.env` values taking precedence over `.env` values.
44
+ *
45
+ * @template T
46
+ * @returns An object containing all environment variables.
47
+ */
11
48
  getAll<T = any>(): T;
12
49
  }
@@ -55,7 +55,21 @@ const fs_1 = __importStar(require("fs"));
55
55
  const typedi_1 = require("typedi");
56
56
  const system_exception_1 = require("./exceptions/system-exception");
57
57
  dotenv_1.default.config({ path: path_1.default.join(process.cwd(), ".env") });
58
+ /**
59
+ * @class Environment
60
+ * @description A service class to manage access to environment variables.
61
+ * It loads variables from `.env` file and merges them with `process.env`,
62
+ * giving precedence to `process.env` values.
63
+ */
58
64
  let Environment = class Environment {
65
+ /**
66
+ * Parses the given `.env` file and merges it with `process.env`.
67
+ * Values from `process.env` take precedence.
68
+ *
69
+ * @private
70
+ * @param filePath - Absolute path to the `.env` file.
71
+ * @returns A dictionary of merged environment variables.
72
+ */
59
73
  parseEnvFile(filePath) {
60
74
  try {
61
75
  const isExis = (0, fs_1.existsSync)(filePath);
@@ -71,10 +85,26 @@ let Environment = class Environment {
71
85
  return {};
72
86
  }
73
87
  }
88
+ /**
89
+ * Retrieves the value of the specified environment variable.
90
+ *
91
+ * @template T
92
+ * @param key - The name of the environment variable.
93
+ * @returns The value of the variable, or `undefined` if not found.
94
+ */
74
95
  get(key) {
75
96
  const parsedEnv = this.parseEnvFile(path_1.default.join(process.cwd(), ".env"));
76
97
  return parsedEnv[key];
77
98
  }
99
+ /**
100
+ * Retrieves the value of the specified environment variable.
101
+ * Throws an error if the variable is not found.
102
+ *
103
+ * @template T
104
+ * @param key - The name of the environment variable.
105
+ * @throws {EnvironmentVariableNotFound} If the variable does not exist.
106
+ * @returns The value of the variable.
107
+ */
78
108
  getOrThrow(key) {
79
109
  const parsedEnv = this.parseEnvFile(path_1.default.join(process.cwd(), ".env"));
80
110
  if (!Object(parsedEnv).hasOwnProperty(key)) {
@@ -82,6 +112,13 @@ let Environment = class Environment {
82
112
  }
83
113
  return parsedEnv[key];
84
114
  }
115
+ /**
116
+ * Retrieves all available environment variables,
117
+ * with `process.env` values taking precedence over `.env` values.
118
+ *
119
+ * @template T
120
+ * @returns An object containing all environment variables.
121
+ */
85
122
  getAll() {
86
123
  const parsedEnv = this.parseEnvFile(path_1.default.join(process.cwd(), ".env"));
87
124
  return parsedEnv;
package/dist/icore.d.ts CHANGED
@@ -16,6 +16,7 @@ import { FastifyCorsOptions } from "@fastify/cors";
16
16
  import { FastifyMultipartOptions } from "@fastify/multipart";
17
17
  import { MultipartFile } from "./multipart";
18
18
  import { ServerOptions } from "socket.io";
19
+ import { Knex } from "knex";
19
20
  export type FuncRoute = {
20
21
  handler: any;
21
22
  middlewares?: any[];
@@ -149,6 +150,7 @@ export declare class AvleonApplication {
149
150
  useOpenApi<T = OpenApiUiOptions>(configOrClass: OpenApiConfigInput<T>): void;
150
151
  useMultipart<T extends MultipartOptions>(options: ConfigInput<T>): void;
151
152
  useDataSource<T extends DataSourceOptions>(options: ConfigInput<T>): void;
153
+ useKnex<T extends Knex.Config>(options: ConfigInput<T>): void;
152
154
  private _useCache;
153
155
  useMiddlewares<T extends AvleonMiddleware>(mclasses: Constructor<T>[]): void;
154
156
  useAuthoriztion<T extends any>(middleware: Constructor<T>): void;
@@ -218,12 +220,13 @@ export interface IAppBuilder {
218
220
  export declare class AvleonTest {
219
221
  private constructor();
220
222
  static getController<T>(controller: Constructor<T>, deps?: any[]): T;
221
- private getService;
223
+ static getProvider<T>(service: Constructor<T>, deps?: any[]): T;
222
224
  static createTestApplication(options: TestAppOptions): TestApplication;
223
225
  static from(app: AvleonApplication): TestApplication;
224
226
  static clean(): void;
225
227
  }
226
228
  export declare class Avleon {
227
229
  static createApplication(): AvleonApplication;
230
+ static createTestApplication(options: TestAppOptions): TestApplication;
228
231
  }
229
232
  export {};
package/dist/icore.js CHANGED
@@ -229,6 +229,18 @@ class AvleonApplication {
229
229
  this.dataSource = datasource;
230
230
  typedi_1.default.set("idatasource", datasource);
231
231
  }
232
+ useKnex(options) {
233
+ let dataSourceOptions;
234
+ if (this._isConfigClass(options)) {
235
+ dataSourceOptions = this.appConfig.get(options);
236
+ }
237
+ else {
238
+ dataSourceOptions = options;
239
+ }
240
+ if (!dataSourceOptions)
241
+ throw new system_exception_1.SystemUseError("Invlaid datasource options.");
242
+ (0, container_1.registerKnex)(dataSourceOptions);
243
+ }
232
244
  _useCache(options) { }
233
245
  useMiddlewares(mclasses) {
234
246
  for (const mclass of mclasses) {
@@ -308,7 +320,6 @@ class AvleonApplication {
308
320
  method: methodmetaOptions.method.toUpperCase(),
309
321
  schema: { ...schema },
310
322
  handler: async (req, res) => {
311
- var _a;
312
323
  let reqClone = req;
313
324
  // class level authrization
314
325
  if (authClsMeata.authorize && this.authorizeMiddleware) {
@@ -368,18 +379,44 @@ class AvleonApplication {
368
379
  }
369
380
  }
370
381
  const result = await prototype[method].apply(ctrl, args);
371
- if (result instanceof stream_1.default || (result === null || result === void 0 ? void 0 : result.pipe)) {
372
- if (!res.sent && ((_a = result.options) === null || _a === void 0 ? void 0 : _a.downloadName)) {
373
- res.header('Content-Type', 'application/octet-stream');
374
- res.header('Content-Disposition', `attachment; filename="${result.options.downloadName}"`);
382
+ // Custom wrapped file download
383
+ if (result === null || result === void 0 ? void 0 : result.__isFileDownload) {
384
+ const { stream, filename, contentType = "application/octet-stream", } = result;
385
+ if (!stream || typeof stream.pipe !== "function") {
386
+ return res.code(500).send({
387
+ code: 500,
388
+ error: "INTERNAL_ERROR",
389
+ message: "Invalid stream object",
390
+ });
375
391
  }
376
- return result.pipe(res.raw);
392
+ res.header("Content-Type", contentType);
393
+ res.header("Content-Disposition", `attachment; filename="${filename}"`);
394
+ stream.on("error", (err) => {
395
+ console.error("Stream error:", err);
396
+ if (!res.sent) {
397
+ res.code(500).send({
398
+ code: 500,
399
+ error: "StreamError",
400
+ message: "Error while streaming file.",
401
+ });
402
+ }
403
+ });
404
+ return res.send(stream);
377
405
  }
378
- if (result && result.__isFileDownload) {
379
- const { stream, filename, contentType = 'application/octet-stream' } = result;
380
- res.header('Content-Type', contentType);
381
- res.header('Content-Disposition', `attachment; filename="${filename}"`);
382
- return stream.pipe(res.raw);
406
+ // Native stream (not wrapped)
407
+ if (result instanceof stream_1.default || typeof (result === null || result === void 0 ? void 0 : result.pipe) === "function") {
408
+ result.on("error", (err) => {
409
+ console.error("Stream error:", err);
410
+ if (!res.sent) {
411
+ res.code(500).send({
412
+ code: 500,
413
+ error: "StreamError",
414
+ message: "Error while streaming file.",
415
+ });
416
+ }
417
+ });
418
+ res.header("Content-Type", "application/octet-stream");
419
+ return res.send(result);
383
420
  }
384
421
  return res.send(result);
385
422
  },
@@ -514,14 +551,6 @@ class AvleonApplication {
514
551
  }
515
552
  }
516
553
  }
517
- // addFeature(feature:{controllers:Function[]}){
518
- // feature.controllers.forEach(c=> this.controllers.push(c))
519
- // }
520
- // mapFeature(){
521
- // if(!this.isMapFeatures){
522
- // this.isMapFeatures = true;
523
- // }
524
- // }
525
554
  async _mapControllers() {
526
555
  if (this.controllers.length > 0) {
527
556
  for (let controller of this.controllers) {
@@ -534,10 +563,6 @@ class AvleonApplication {
534
563
  }
535
564
  }
536
565
  }
537
- // useControllersAuto(controllerPath?:string) {
538
- // this.registerControllerAuto = true;
539
- // //this.autoControllers();
540
- // }
541
566
  async mapFn(fn) {
542
567
  const original = fn;
543
568
  fn = function () { };
@@ -694,8 +719,6 @@ class AvleonApplication {
694
719
  }
695
720
  getTestApp(buildOptions) {
696
721
  try {
697
- // }
698
- // this.initializeDatabase();
699
722
  this._mapControllers();
700
723
  this.rMap.forEach((value, key) => {
701
724
  const [m, r] = key.split(":");
@@ -758,7 +781,11 @@ class AvleonTest {
758
781
  });
759
782
  return typedi_1.default.get(controller);
760
783
  }
761
- getService(service) {
784
+ static getProvider(service, deps = []) {
785
+ const paramTypes = Reflect.getMetadata("design:paramtypes", service) || [];
786
+ deps.forEach((dep, i) => {
787
+ typedi_1.default.set(paramTypes[i], dep);
788
+ });
762
789
  return typedi_1.default.get(service);
763
790
  }
764
791
  static createTestApplication(options) {
@@ -781,5 +808,9 @@ class Avleon {
781
808
  const app = AvleonApplication.getApp();
782
809
  return app;
783
810
  }
811
+ static createTestApplication(options) {
812
+ const app = AvleonTest.createTestApplication(options);
813
+ return app;
814
+ }
784
815
  }
785
816
  exports.Avleon = Avleon;
package/dist/index.d.ts CHANGED
@@ -25,6 +25,7 @@ export * from "./multipart";
25
25
  export * from "./file-storage";
26
26
  export * from "./logger";
27
27
  export * from "./event-dispatcher";
28
+ export * from "./kenx-provider";
28
29
  export { Subscribe, Private } from "./event-subscriber";
29
30
  export declare const GetSchema: typeof sw.generateSwaggerSchema;
30
31
  export { default as AvleonContainer } from "./container";
package/dist/index.js CHANGED
@@ -71,6 +71,7 @@ __exportStar(require("./multipart"), exports);
71
71
  __exportStar(require("./file-storage"), exports);
72
72
  __exportStar(require("./logger"), exports);
73
73
  __exportStar(require("./event-dispatcher"), exports);
74
+ __exportStar(require("./kenx-provider"), exports);
74
75
  var event_subscriber_1 = require("./event-subscriber");
75
76
  Object.defineProperty(exports, "Subscribe", { enumerable: true, get: function () { return event_subscriber_1.Subscribe; } });
76
77
  Object.defineProperty(exports, "Private", { enumerable: true, get: function () { return event_subscriber_1.Private; } });
@@ -0,0 +1,7 @@
1
+ import type { Knex } from "knex";
2
+ export declare class DB {
3
+ private connection;
4
+ constructor();
5
+ init(config: Knex.Config): Knex<any, any[]>;
6
+ get client(): Knex;
7
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DB = void 0;
13
+ const typedi_1 = require("typedi");
14
+ const typedi_2 = require("typedi");
15
+ let DB = class DB {
16
+ constructor() {
17
+ const existing = typedi_2.Container.has("KnexConnection")
18
+ ? typedi_2.Container.get("KnexConnection")
19
+ : null;
20
+ if (existing) {
21
+ this.connection = existing;
22
+ }
23
+ }
24
+ // Initialize manually (call this in main if you want)
25
+ init(config) {
26
+ if (!this.connection) {
27
+ const knex = require("knex");
28
+ this.connection = knex(config);
29
+ typedi_2.Container.set("KnexConnection", this.connection);
30
+ }
31
+ return this.connection;
32
+ }
33
+ get client() {
34
+ if (!this.connection) {
35
+ throw new Error("Knex is not initialized. Call DB.init(config) first.");
36
+ }
37
+ return this.connection;
38
+ }
39
+ };
40
+ exports.DB = DB;
41
+ exports.DB = DB = __decorate([
42
+ (0, typedi_1.Service)(),
43
+ __metadata("design:paramtypes", [])
44
+ ], DB);
package/package.json CHANGED
@@ -1,19 +1,8 @@
1
1
  {
2
2
  "name": "@avleon/core",
3
- "version": "0.0.32",
3
+ "version": "0.0.37",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
- "scripts": {
7
- "build": "npm run clean && tsc",
8
- "clean": "rimraf dist",
9
- "watch": "tsc-watch",
10
- "lint": "eslint .",
11
- "lint:fix": "eslint . --fix",
12
- "format": "prettier --write .",
13
- "test": "jest",
14
- "test:watch": "jest --watch",
15
- "prepare": "husky install"
16
- },
17
6
  "keywords": [
18
7
  "restapi",
19
8
  "avleon",
@@ -35,6 +24,7 @@
35
24
  "husky": "^8.0.0",
36
25
  "ioredis": "^5.6.1",
37
26
  "jest": "^29.7.0",
27
+ "knex": "^3.1.0",
38
28
  "lint-staged": "^16.0.0",
39
29
  "mssql": "^11.0.1",
40
30
  "mysql2": "^3.14.1",
@@ -75,7 +65,8 @@
75
65
  "@scalar/fastify-api-reference": "*",
76
66
  "ioredis": "*",
77
67
  "sharp": "*",
78
- "typeorm": "*"
68
+ "typeorm": "*",
69
+ "knex": "*"
79
70
  },
80
71
  "peerDependenciesMeta": {
81
72
  "@scalar/fastify-api-reference": {
@@ -89,6 +80,9 @@
89
80
  },
90
81
  "typeorm": {
91
82
  "optional": true
83
+ },
84
+ "knex": {
85
+ "optional": true
92
86
  }
93
87
  },
94
88
  "lint-staged": {
@@ -111,5 +105,16 @@
111
105
  },
112
106
  "files": [
113
107
  "dist"
114
- ]
115
- }
108
+ ],
109
+ "scripts": {
110
+ "build": "npm run clean && tsc",
111
+ "clean": "rimraf dist",
112
+ "watch": "tsc-watch",
113
+ "lint": "eslint .",
114
+ "lint:fix": "eslint . --fix",
115
+ "format": "prettier --write .",
116
+ "test": "jest",
117
+ "test:watch": "jest --watch",
118
+ "husky:init": "husky install"
119
+ }
120
+ }