From 08b52667b7f90bd15c6e48aaa7f0ebaec60d45a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Luiz=20Gon=C3=A7alves?= Date: Thu, 13 Jan 2022 15:17:46 -0300 Subject: [PATCH 1/2] iniciando projeto --- .gitignore | 4 ++++ package.json | 28 ++++++++++++++++++++++++ src/index.ts | 0 src/services/hashGenerator.ts | 18 ++++++++++++++++ src/services/idGenerator.ts | 5 +++++ src/services/tokenGenerator.ts | 39 ++++++++++++++++++++++++++++++++++ tsconfig.json | 14 ++++++++++++ 7 files changed, 108 insertions(+) create mode 100644 .gitignore create mode 100644 package.json create mode 100644 src/index.ts create mode 100644 src/services/hashGenerator.ts create mode 100644 src/services/idGenerator.ts create mode 100644 src/services/tokenGenerator.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d37d33f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.env +build +package-lock.json +node_modules \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..4c93d43 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "template-lama", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "bcryptjs": "^2.4.3", + "dotenv": "^11.0.0", + "express": "^4.17.2", + "jsonwebtoken": "^8.5.1", + "knex": "^0.95.15", + "mysql": "^2.18.1", + "uuid": "^8.3.2" + }, + "devDependencies": { + "@types/bcryptjs": "^2.4.2", + "@types/express": "^4.17.13", + "@types/jsonwebtoken": "^8.5.7", + "@types/knex": "^0.16.1", + "@types/uuid": "^8.3.4", + "typescript": "^4.5.4" + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/services/hashGenerator.ts b/src/services/hashGenerator.ts new file mode 100644 index 0000000..721ed90 --- /dev/null +++ b/src/services/hashGenerator.ts @@ -0,0 +1,18 @@ +import { compareSync, genSaltSync, hashSync } from "bcryptjs" + +export class HashManager { + createHash = (plainText: string) => { + const salt = genSaltSync(12) + + const cypherText = hashSync(plainText, salt) + + return cypherText + } + + compareHash = ( + plainText: string, + cypherText: string + ) => { + return compareSync(plainText, cypherText) + } +} \ No newline at end of file diff --git a/src/services/idGenerator.ts b/src/services/idGenerator.ts new file mode 100644 index 0000000..cc4303a --- /dev/null +++ b/src/services/idGenerator.ts @@ -0,0 +1,5 @@ +import { v4 } from "uuid"; + +export class IdGenerator { + generate = () => v4() +} \ No newline at end of file diff --git a/src/services/tokenGenerator.ts b/src/services/tokenGenerator.ts new file mode 100644 index 0000000..c4dc721 --- /dev/null +++ b/src/services/tokenGenerator.ts @@ -0,0 +1,39 @@ +import { config } from "dotenv"; +import { JwtPayload, sign, verify } from "jsonwebtoken"; + +config() + +export interface authenticationData { + id: string + role: string +} + +export class Authenticator { + generateToken = ( + payload: authenticationData + ) => { + return sign( + payload, + process.env.JWT_KEY as string, + { + expiresIn: "12" + } + ) + } + + getTokenData = (token: string): authenticationData | null => { + try { + const tokenData = verify( + token, + process.env.JWT_KEY! + ) as JwtPayload + + return { + id: tokenData.id, + role: tokenData.role + } + } catch (error) { + return null + } + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..91a231a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "sourceMap": true, + "outDir": "./build", + "rootDir": "./", + "removeComments": true, + "strict": true, + "noImplicitAny": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true + } +} \ No newline at end of file From 4f37f4bfeabf22f7a5098d90e1b1de755b4cf878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Luiz=20Gon=C3=A7alves?= Date: Mon, 17 Jan 2022 08:07:57 -0300 Subject: [PATCH 2/2] =?UTF-8?q?endpoints=20de=20usu=C3=A1rios=20e=20bandas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 --- package.json | 3 ++ src/buisiness/bandBuisiness.ts | 41 ++++++++++++++++++++++ src/buisiness/showBuisiness.ts | 41 ++++++++++++++++++++++ src/buisiness/userBuisiness.ts | 46 +++++++++++++++++++++++++ src/controller/app.ts | 13 +++++++ src/controller/bandController.ts | 40 ++++++++++++++++++++++ src/controller/showController.ts | 25 ++++++++++++++ src/controller/userController.ts | 37 ++++++++++++++++++++ src/data/bandDatabase.ts | 42 +++++++++++++++++++++++ src/data/baseDatabase.ts | 17 ++++++++++ src/data/showDatabase.ts | 35 +++++++++++++++++++ src/data/userDatabase.ts | 27 +++++++++++++++ src/index.ts | 11 ++++++ src/model/band.ts | 36 ++++++++++++++++++++ src/model/show.ts | 58 ++++++++++++++++++++++++++++++++ src/model/user.ts | 25 ++++++++++++++ src/routes/bandRoutes.ts | 2 ++ src/services/hashGenerator.ts | 6 ++-- src/services/tokenGenerator.ts | 14 ++++---- tsconfig.json | 2 +- 21 files changed, 510 insertions(+), 15 deletions(-) delete mode 100644 README.md create mode 100644 src/buisiness/bandBuisiness.ts create mode 100644 src/buisiness/showBuisiness.ts create mode 100644 src/buisiness/userBuisiness.ts create mode 100644 src/controller/app.ts create mode 100644 src/controller/bandController.ts create mode 100644 src/controller/showController.ts create mode 100644 src/controller/userController.ts create mode 100644 src/data/bandDatabase.ts create mode 100644 src/data/baseDatabase.ts create mode 100644 src/data/showDatabase.ts create mode 100644 src/data/userDatabase.ts create mode 100644 src/model/band.ts create mode 100644 src/model/show.ts create mode 100644 src/model/user.ts create mode 100644 src/routes/bandRoutes.ts diff --git a/README.md b/README.md deleted file mode 100644 index 6a2f62f..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Labenu Music Awards -Como você deve saber muito bem, o nosso querido chefinho Astrodev é uma pessoa com Networking incrível e ele conhece vários artistas estrelados. Além disso, ele também é um grande ~~megalomaníaco~~ visionário e está planejando fazer um grande evento: o **LAMA**, *Labenu Musical Awards*, um festival com várias bandas famosas para a formatura da sua turma e, no final, vocês podem eleger a banda que mais gostaram! Entretanto, na opinião dele, vocês só serão merecedores se entregarem um sistema impecável que permita o gerenciamento completo desses shows. - -Para isso já deixamos algumas tabelas prontas para vocês não precisarem se preocupar com a modelagem do banco. Deixamos também um template do projeto já com a estrutura da parte de usuários. Vocês podem usá-las a vontade, mas, se quiser fazer do zero sem esse auxílio, também pode. diff --git a/package.json b/package.json index 4c93d43..c4280de 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,14 @@ "description": "", "main": "index.js", "scripts": { + "start": "tsc && node ./build/index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "bcryptjs": "^2.4.3", + "cors": "^2.8.5", "dotenv": "^11.0.0", "express": "^4.17.2", "jsonwebtoken": "^8.5.1", @@ -19,6 +21,7 @@ }, "devDependencies": { "@types/bcryptjs": "^2.4.2", + "@types/cors": "^2.8.12", "@types/express": "^4.17.13", "@types/jsonwebtoken": "^8.5.7", "@types/knex": "^0.16.1", diff --git a/src/buisiness/bandBuisiness.ts b/src/buisiness/bandBuisiness.ts new file mode 100644 index 0000000..bac1be4 --- /dev/null +++ b/src/buisiness/bandBuisiness.ts @@ -0,0 +1,41 @@ +import { BandDatabase } from "../data/bandDatabase" +import { Authenticator } from "../services/tokenGenerator" +import { Band } from "../model/band"; +import { IdGenerator } from "../services/idGenerator"; +import { authenticationData } from "../services/tokenGenerator"; + +export class BandBuisiness { + + createBand = async ( + name: string, + mainGenre: string, + responsible: string, + token: string + ) => { + + const tokenData = new Authenticator().getTokenData(token) + + if (tokenData?.role !== "ADMIN") { + throw new Error("Funçao disponível apenas para administradores") + } + + if (!name || !mainGenre || !responsible) { + throw new Error("Preencha todos os campos de registro") + } + + const id = new IdGenerator().generate() + const band = new Band(id, name, mainGenre, responsible) + await new BandDatabase().createBand(band) + } + + getBandDetail = async (idOrName: string): Promise => { + + if(!idOrName) { + throw new Error("Preencha o campo de pesquisa") + } + + const band = await new BandDatabase().getBandDetail(idOrName) + + return band + } +} \ No newline at end of file diff --git a/src/buisiness/showBuisiness.ts b/src/buisiness/showBuisiness.ts new file mode 100644 index 0000000..4c0a6dc --- /dev/null +++ b/src/buisiness/showBuisiness.ts @@ -0,0 +1,41 @@ +import { BandDatabase } from "../data/bandDatabase" +import { ShowDatabase } from "../data/showDatabase" +import { Show } from "../model/show" +import { IdGenerator } from "../services/idGenerator" +import { Authenticator } from "../services/tokenGenerator" + +export class ShowBuisiness { + + createShow = async (weekDay: string, startTime: number, endTime: number, bandId: string, token: string) => { + + const tokenData = new Authenticator().getTokenData(token) + + if (tokenData.role !== "ADMIN") { + throw new Error("Função disponível apenas para administradores") + } + + if (!weekDay || !startTime || !endTime || !bandId) { + throw new Error("Preencha todos os campos") + } + + if (startTime < 8 || endTime > 23 || startTime >= endTime) { + throw new Error("Confira os horários") + } + + if (!Number.isInteger(startTime) || !Number.isInteger(endTime)) { + throw new Error("Shows apenas em horas inteiras") + } + + const bandFromDB = await new BandDatabase().getBandDetail(bandId) + + if (!bandFromDB) { + throw new Error("Banda não encontrada") + } + + const id = new IdGenerator().generate() + + const show = new Show(id, weekDay, bandId, startTime, endTime) + + await new ShowDatabase().createShow(show) + } +} \ No newline at end of file diff --git a/src/buisiness/userBuisiness.ts b/src/buisiness/userBuisiness.ts new file mode 100644 index 0000000..c7728b4 --- /dev/null +++ b/src/buisiness/userBuisiness.ts @@ -0,0 +1,46 @@ +import { UserDatabase } from "../data/userDatabase" +import { User } from "../model/user" +import { HashManager } from "../services/hashGenerator" +import { IdGenerator } from "../services/idGenerator" +import { Authenticator } from "../services/tokenGenerator" + +export class UserBuisiness { + + signup = async ( + name: string, + email: string, + password: string, + role: string + ): Promise => { + + const id = new IdGenerator().generate() + + const hashPassword = await new HashManager().createHash(password) + + const newUser = new User(id, name, email, hashPassword, role) + + await new UserDatabase().signup(newUser) + + const token = new Authenticator().generateToken({ id, role }) + + return token + } + + login = async ( + email: string, + password: string + ): Promise => { + + const checkedUserEmail = await new UserDatabase().login(email) + + const checkedPassword = await new HashManager().compareHash(password, checkedUserEmail.getPassword()) + + if (!checkedPassword) { + throw new Error("Senha incorreta") + } + + const token = new Authenticator().generateToken({ id: checkedUserEmail.getId(), role: checkedUserEmail.getRole() }) + + return token + } +} \ No newline at end of file diff --git a/src/controller/app.ts b/src/controller/app.ts new file mode 100644 index 0000000..9578313 --- /dev/null +++ b/src/controller/app.ts @@ -0,0 +1,13 @@ +import express, { Express } from "express" +import cors from "cors" + +const app: Express = express() + +app.use(express.json()) +app.use(cors()) + +app.listen(3003, () => { + console.log("Ready!") +}) + +export default app \ No newline at end of file diff --git a/src/controller/bandController.ts b/src/controller/bandController.ts new file mode 100644 index 0000000..d38b35b --- /dev/null +++ b/src/controller/bandController.ts @@ -0,0 +1,40 @@ +import { Response, Request } from "express"; +import { BandBuisiness } from "../buisiness/bandBuisiness"; + +export class BandController { + + createBand = async ( + req: Request, + res: Response + ) => { + try { + + const { name, mainGenre, responsible } = req.body + + const token = req.headers.authorization as string + + await new BandBuisiness().createBand(name, mainGenre, responsible, token) + + res.status(200).send("Banda registrada") + } catch (error: any) { + res.status(500) + .send({ error: error.message }) + } + } + + getBandDetail = async ( + req: Request, + res: Response + ) => { + try { + const input = (req.query.id ?? req.query.name) as string + + const band = await new BandBuisiness().getBandDetail(input) + + res.status(200).send(band) + } catch (error: any) { + res.status(error.customErrorCode || 400) + .send({ message: error.message }) + } + } +} \ No newline at end of file diff --git a/src/controller/showController.ts b/src/controller/showController.ts new file mode 100644 index 0000000..ac64a87 --- /dev/null +++ b/src/controller/showController.ts @@ -0,0 +1,25 @@ +import { Response, Request } from "express"; +import { ShowBuisiness } from "../buisiness/showBuisiness"; +import { Show } from "../model/show"; + +export class ShowController { + + createShow = async ( + req: Request, + res: Response + ) => { + + try { + + const { weekDay, bandId, startTime, endTime } = req.body + + const token = req.headers.authorization as string + + await new ShowBuisiness().createShow(weekDay, startTime, endTime, bandId, token) + + res.status(200).send("Show agendado") + } catch (error: any) { + res.status(error.customErrorCode || 400).send({ message: error.message }) + } + } +} \ No newline at end of file diff --git a/src/controller/userController.ts b/src/controller/userController.ts new file mode 100644 index 0000000..46c3ced --- /dev/null +++ b/src/controller/userController.ts @@ -0,0 +1,37 @@ +import { Request, Response } from "express"; +import { UserBuisiness } from "../buisiness/userBuisiness"; + +export class UserController { + + signup = async ( + req: Request, + res: Response + ) => { + try { + + const { name, email, password, role } = req.body + + const result = await new UserBuisiness().signup(name, email, password, role) + + res.status(200).send(result) + } catch (error: any) { + res.status(500).send("Falha interna") + } + } + + login = async ( + req: Request, + res: Response + ) => { + try { + + const { email, password } = req.body + + const result = await new UserBuisiness().login(email, password) + + res.status(200).send({ result }) + } catch (error: any) { + res.status(500).send({error: error.message}) + } + } +} \ No newline at end of file diff --git a/src/data/bandDatabase.ts b/src/data/bandDatabase.ts new file mode 100644 index 0000000..4f7b301 --- /dev/null +++ b/src/data/bandDatabase.ts @@ -0,0 +1,42 @@ +import { response } from "express"; +import { Band } from "../model/band"; +import { BaseDatabase } from "./baseDatabase"; + +export class BandDatabase extends BaseDatabase { + + createBand = async (band: Band): Promise => { + try { + + await this.connection("bands") + .insert({ + id: band.getId(), + name: band.getName(), + music_genre: band.getMainGenre(), + responsible: band.getResponsible() + }) + + } catch (error: any) { + throw new Error(error.sqlMessage || error.message) + } + } + + getBandDetail = async (idOrName: string) => { + try { + + const result = await this.connection("bands") + .select("*") + .where({ id: idOrName }) + .orWhere({ name: idOrName }) + + if (!result[0]) { + throw new Error("Não encontramos esta banda nos registros") + } + + const band = new Band(result[0].id, result[0].name, result[0].music_genre, result[0].responsible) + + return band + } catch (error: any) { + throw new Error(error.sqlMessage || error.message) + } + } +} \ No newline at end of file diff --git a/src/data/baseDatabase.ts b/src/data/baseDatabase.ts new file mode 100644 index 0000000..1427142 --- /dev/null +++ b/src/data/baseDatabase.ts @@ -0,0 +1,17 @@ +import knex from "knex"; +import dotenv from "dotenv"; + +dotenv.config() + +export class BaseDatabase { + protected connection = knex({ + client: "mysql", + connection: { + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_SCHEMA, + port: 3306 + } + }) +} \ No newline at end of file diff --git a/src/data/showDatabase.ts b/src/data/showDatabase.ts new file mode 100644 index 0000000..8e92f87 --- /dev/null +++ b/src/data/showDatabase.ts @@ -0,0 +1,35 @@ +import { ShowBuisiness } from "../buisiness/showBuisiness"; +import { Show } from "../model/show"; +import { BaseDatabase } from "./baseDatabase"; + +export class ShowDatabase extends BaseDatabase { + + createShow = async (show: Show): Promise => { + + try { + await this.connection("shows") + .insert({ + id: show.getId(), + band_id: show.getBandId(), + start_time: show.getStartTime(), + end_time: show.getEndTime(), + week_day: show.getWeekDay() + }) + } catch (error: any) { + throw new Error(error.sqlMessage || error.message) + } + } + + getShowByTime = async (weekDay: string, startTime: number, endTime: number) => { + + const result = await this.connection.raw( + ` + SELECT * FROM shows + WHERE week_day = "${weekDay} + AND WHERE start_time <= "${endTime} + AND WHERE end_time >= "${startTime}` + ) + } +} + +// WHERE Country='Mexico' \ No newline at end of file diff --git a/src/data/userDatabase.ts b/src/data/userDatabase.ts new file mode 100644 index 0000000..2000a29 --- /dev/null +++ b/src/data/userDatabase.ts @@ -0,0 +1,27 @@ +import { User } from "../model/user"; +import { BaseDatabase } from "./baseDatabase"; + +export class UserDatabase extends BaseDatabase { + + signup = async (user: User): Promise => { + try { + await this.connection("users").insert({ + id: user.getId(), + name: user.getName(), + email: user.getEmail(), + password: user.getPassword(), + role: user.getRole() + }) + } catch (error: any) { + throw new Error(error.sqlMessage || error.message) + } + } + + login = async (email: string) => { + + const result = await this.connection("users") + .select("*").where({ email }) + + return new User(result[0].id, result[0].name, result[0].email, result[0].password, result[0].role) + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index e69de29..f33683c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -0,0 +1,11 @@ +import app from "./controller/app"; +import { BandController } from "./controller/bandController"; +import { UserController } from "./controller/userController"; + +const userController = new UserController() +const bandController = new BandController() +app.post("/signup", userController.signup) +app.post("/login", userController.login) +// SENHAS: teste +app.put("/bandRegister", bandController.createBand) +app.get("/detail", bandController.getBandDetail) \ No newline at end of file diff --git a/src/model/band.ts b/src/model/band.ts new file mode 100644 index 0000000..dd0c449 --- /dev/null +++ b/src/model/band.ts @@ -0,0 +1,36 @@ +export class Band { + constructor( + private id: string, + private name: string, + private mainGenre: string, + private responsible: string + ) { } + + getId(): string { + return this.id + } + getName(): string { + return this.name + } + getMainGenre(): string { + return this.mainGenre + } + getResponsible(): string { + return this.responsible + } + setMainGenre(mainGenre: string) { + this.mainGenre = mainGenre + } + setResponsible(responsible: string) { + this.responsible = responsible + } + + public static toBand(data?: any): Band | undefined { + return (data && new Band( + data.id, + data.name, + data.mainGenre, + data.responsible + )) + } +} \ No newline at end of file diff --git a/src/model/show.ts b/src/model/show.ts new file mode 100644 index 0000000..29937d2 --- /dev/null +++ b/src/model/show.ts @@ -0,0 +1,58 @@ +// export enum WEEKDAY { +// FRIDAY = "FRIDAY", +// SATURDAY = "SATURDAY", +// SUNDAY = "SUNDAY" +// } + +export class Show { + constructor( + private id: string, + private weekDay: string, + private bandId: string, + private startTime: number, + private endTime: number, + ) { } + + getId(): string { + return this.id + } + getWeekDay(): string { + return this.weekDay + } + getBandId(): string { + return this.bandId + } + getStartTime(): number { + return this.startTime + } + getEndTime(): number { + return this.endTime + } + setId(id: string) { + this.id = id + } + setWeekDay(weekDay: string) { + this.weekDay = weekDay + } + setStartTime(startTime: number) { + this.startTime = startTime + } + setEndTime(endTime: number) { + this.endTime = endTime + } + setBandId(bandId: string) { + this.bandId = bandId + } + // public static toWeekDay(data?: any): WEEKDAY { + // switch (data) { + // case "FRIDAY": + // return WEEKDAY.FRIDAY + // case "SATURDAY": + // return WEEKDAY.SATURDAY + // case "SUNDAY": + // return WEEKDAY.SUNDAY + // default: + // throw new Error("Dia inválido") + // } + // } +} \ No newline at end of file diff --git a/src/model/user.ts b/src/model/user.ts new file mode 100644 index 0000000..372fa47 --- /dev/null +++ b/src/model/user.ts @@ -0,0 +1,25 @@ +export class User { + constructor( + private id: string, + private name: string, + private email: string, + private password: string, + private role: string + ) { } + + public getId() { + return this.id + } + public getName() { + return this.name + } + public getEmail() { + return this.email + } + public getPassword() { + return this.password + } + public getRole() { + return this.role + } +} \ No newline at end of file diff --git a/src/routes/bandRoutes.ts b/src/routes/bandRoutes.ts new file mode 100644 index 0000000..e9f7f5b --- /dev/null +++ b/src/routes/bandRoutes.ts @@ -0,0 +1,2 @@ +import { Express } from "express"; + diff --git a/src/services/hashGenerator.ts b/src/services/hashGenerator.ts index 721ed90..917e33a 100644 --- a/src/services/hashGenerator.ts +++ b/src/services/hashGenerator.ts @@ -1,7 +1,7 @@ import { compareSync, genSaltSync, hashSync } from "bcryptjs" export class HashManager { - createHash = (plainText: string) => { + createHash = async (plainText: string): Promise => { const salt = genSaltSync(12) const cypherText = hashSync(plainText, salt) @@ -9,10 +9,10 @@ export class HashManager { return cypherText } - compareHash = ( + compareHash = async ( plainText: string, cypherText: string - ) => { + ): Promise => { return compareSync(plainText, cypherText) } } \ No newline at end of file diff --git a/src/services/tokenGenerator.ts b/src/services/tokenGenerator.ts index c4dc721..e341f97 100644 --- a/src/services/tokenGenerator.ts +++ b/src/services/tokenGenerator.ts @@ -15,25 +15,25 @@ export class Authenticator { return sign( payload, process.env.JWT_KEY as string, - { - expiresIn: "12" - } + // { + // expiresIn: "12" + // } ) } - getTokenData = (token: string): authenticationData | null => { + getTokenData = (token: string): authenticationData => { try { const tokenData = verify( token, process.env.JWT_KEY! ) as JwtPayload - + return { id: tokenData.id, role: tokenData.role } - } catch (error) { - return null + } finally { + } } } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 91a231a..0d1b36d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "module": "commonjs", "sourceMap": true, "outDir": "./build", - "rootDir": "./", + "rootDir": "./src", "removeComments": true, "strict": true, "noImplicitAny": true,