From 9048b39e76db54e78cb7c1e4a12bd9fc14efbb8a Mon Sep 17 00:00:00 2001 From: anjula-sack Date: Sat, 5 Aug 2023 17:13:01 +0530 Subject: [PATCH 01/10] Refactor the code --- .eslintrc.json | 23 + .github/workflows/CI.yml | 32 + .prettierrc | 4 +- dist/jest.config.js | 6 + dist/src/app.js | 50 + dist/src/configs/dbConfig.js | 17 + dist/src/configs/envConfig.js | 16 + dist/src/configs/passport.js | 41 + dist/src/controllers/auth.controller.js | 107 + dist/src/controllers/profile.controller.js | 22 + dist/src/entities/profile.entity.js | 119 + dist/src/enums/profileType.enum.js | 8 + dist/src/routes/auth.route.js | 11 + dist/src/routes/profile/profile.route.js | 11 + dist/src/routes/profile/profile.route.test.js | 58 + dist/src/server.js | 9 + dist/test/integration/db.test.js | 30 + eslint.ts | 9 - jest.config.ts | 4 +- package-lock.json | 2106 +++++++++++++++-- package.json | 18 +- src/app.ts | 52 +- src/configs/dbConfig.ts | 25 +- src/configs/envConfig.ts | 6 +- src/configs/passport.ts | 32 +- src/controllers/auth.controller.ts | 110 + .../profile.controller.ts} | 41 +- src/entities/profile.entity.ts | 88 + src/entity/profile.entity.ts | 82 - src/enums/profileType.enum.ts | 4 +- src/routes/auth.route.ts | 12 +- src/routes/profile.route.test.ts | 28 +- src/routes/profile.route.ts | 10 +- src/services/auth.service.ts | 110 - test/integration/db.test.ts | 20 +- tsconfig.json | 5 +- 36 files changed, 2839 insertions(+), 487 deletions(-) create mode 100644 .eslintrc.json create mode 100644 .github/workflows/CI.yml create mode 100644 dist/jest.config.js create mode 100644 dist/src/app.js create mode 100644 dist/src/configs/dbConfig.js create mode 100644 dist/src/configs/envConfig.js create mode 100644 dist/src/configs/passport.js create mode 100644 dist/src/controllers/auth.controller.js create mode 100644 dist/src/controllers/profile.controller.js create mode 100644 dist/src/entities/profile.entity.js create mode 100644 dist/src/enums/profileType.enum.js create mode 100644 dist/src/routes/auth.route.js create mode 100644 dist/src/routes/profile/profile.route.js create mode 100644 dist/src/routes/profile/profile.route.test.js create mode 100644 dist/src/server.js create mode 100644 dist/test/integration/db.test.js delete mode 100644 eslint.ts create mode 100644 src/controllers/auth.controller.ts rename src/{services/profile.service.ts => controllers/profile.controller.ts} (56%) create mode 100644 src/entities/profile.entity.ts delete mode 100644 src/entity/profile.entity.ts delete mode 100644 src/services/auth.service.ts diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..4e9243a8 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "standard-with-typescript", + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "prettier" + ], + "plugins": ["@typescript-eslint", "prettier"], + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module", + "project": "./tsconfig.json" + }, + "rules": { + "@typescript-eslint/naming-convention": 0, + "@typescript-eslint/no-misused-promises": 0, + "@typescript-eslint/strict-boolean-expressions": 0 + } +} diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 00000000..7b0a9dde --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,32 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install dependencies + run: npm install + + - name: ESLint check + run: npm run lint + + - name: Build + run: npm run build diff --git a/.prettierrc b/.prettierrc index 0a725205..c50384fb 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,6 @@ { - "trailingComma": "es5", + "trailingComma": "none", "tabWidth": 2, - "semi": true, + "semi": false, "singleQuote": true } diff --git a/dist/jest.config.js b/dist/jest.config.js new file mode 100644 index 00000000..b1f8f1e5 --- /dev/null +++ b/dist/jest.config.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = { + preset: 'ts-jest', + testEnvironment: 'node' +}; diff --git a/dist/src/app.js b/dist/src/app.js new file mode 100644 index 00000000..235dfd8a --- /dev/null +++ b/dist/src/app.js @@ -0,0 +1,50 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.startServer = void 0; +const express_1 = __importDefault(require("express")); +const body_parser_1 = __importDefault(require("body-parser")); +const cors_1 = __importDefault(require("cors")); +const dbConfig_1 = require("./configs/dbConfig"); +const auth_route_1 = __importDefault(require("./routes/auth.route")); +const profile_route_1 = __importDefault(require("./routes/profile/profile.route")); +const passport_1 = __importDefault(require("passport")); +require("./configs/passport"); +const envConfig_1 = require("./configs/envConfig"); +const port = envConfig_1.SERVER_PORT; +const app = (0, express_1.default)(); +app.use(body_parser_1.default.json()); +app.use((0, cors_1.default)()); +app.use(passport_1.default.initialize()); +app.get('/', (req, res) => { + res.send('ScholarX Backend'); +}); +app.use('/api/auth', auth_route_1.default); +app.use('/api/me', profile_route_1.default); +const startServer = () => __awaiter(void 0, void 0, void 0, function* () { + try { + yield dbConfig_1.dataSource.initialize(); + console.log('DB connection is successful'); + app.listen(port, () => { + console.log(`Server is running on http://localhost:${port}`); + }); + return app; + } + catch (err) { + console.log('DB connection was not successful', err); + throw err; + } +}); +exports.startServer = startServer; +exports.default = exports.startServer; diff --git a/dist/src/configs/dbConfig.js b/dist/src/configs/dbConfig.js new file mode 100644 index 00000000..2977ba24 --- /dev/null +++ b/dist/src/configs/dbConfig.js @@ -0,0 +1,17 @@ +"use strict"; +var _a; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.dataSource = void 0; +const typeorm_1 = require("typeorm"); +const envConfig_1 = require("./envConfig"); +exports.dataSource = new typeorm_1.DataSource({ + type: 'postgres', + host: envConfig_1.DB_HOST, + port: (_a = Number(envConfig_1.DB_PORT)) !== null && _a !== void 0 ? _a : 5432, + username: envConfig_1.DB_USER, + password: envConfig_1.DB_PASSWORD, + database: envConfig_1.DB_NAME, + entities: ['src/entities/*.ts'], + logging: false, + synchronize: true +}); diff --git a/dist/src/configs/envConfig.js b/dist/src/configs/envConfig.js new file mode 100644 index 00000000..044e56ef --- /dev/null +++ b/dist/src/configs/envConfig.js @@ -0,0 +1,16 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _a; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.JWT_SECRET = exports.SERVER_PORT = exports.DB_PORT = exports.DB_PASSWORD = exports.DB_NAME = exports.DB_HOST = exports.DB_USER = void 0; +const dotenv_1 = __importDefault(require("dotenv")); +dotenv_1.default.config(); +exports.DB_USER = process.env.DB_USER; +exports.DB_HOST = process.env.DB_HOST; +exports.DB_NAME = process.env.DB_NAME; +exports.DB_PASSWORD = process.env.DB_PASSWORD; +exports.DB_PORT = process.env.DB_PORT; +exports.SERVER_PORT = (_a = process.env.SERVER_PORT) !== null && _a !== void 0 ? _a : 3000; +exports.JWT_SECRET = process.env.JWT_SECRET; diff --git a/dist/src/configs/passport.js b/dist/src/configs/passport.js new file mode 100644 index 00000000..b4627dfb --- /dev/null +++ b/dist/src/configs/passport.js @@ -0,0 +1,41 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const passport_1 = __importDefault(require("passport")); +const passport_jwt_1 = require("passport-jwt"); +const dbConfig_1 = require("./dbConfig"); +const profile_entity_1 = __importDefault(require("../entities/profile.entity")); +const envConfig_1 = require("./envConfig"); +const options = { + jwtFromRequest: passport_jwt_1.ExtractJwt.fromAuthHeaderAsBearerToken(), + secretOrKey: envConfig_1.JWT_SECRET +}; +passport_1.default.use(new passport_jwt_1.Strategy(options, (jwtPayload, done) => __awaiter(void 0, void 0, void 0, function* () { + try { + const profileRepository = dbConfig_1.dataSource.getRepository(profile_entity_1.default); + const profile = yield profileRepository.findOne({ + where: { uuid: jwtPayload.userId } + }); + if (!profile) { + done(null, false); + } + else { + done(null, profile); + } + } + catch (error) { + done(error, false); + } +}))); +exports.default = passport_1.default; diff --git a/dist/src/controllers/auth.controller.js b/dist/src/controllers/auth.controller.js new file mode 100644 index 00000000..789fc51a --- /dev/null +++ b/dist/src/controllers/auth.controller.js @@ -0,0 +1,107 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.requireAuth = exports.login = exports.register = void 0; +const dbConfig_1 = require("../configs/dbConfig"); +const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); +const bcrypt_1 = __importDefault(require("bcrypt")); +const passport_1 = __importDefault(require("passport")); +const profile_entity_1 = __importDefault(require("../entities/profile.entity")); +const envConfig_1 = require("../configs/envConfig"); +const register = (req, res) => __awaiter(void 0, void 0, void 0, function* () { + try { + const { email, password } = req.body; + if (!email || !password) { + res.status(400).json({ error: 'Email and password are required fields' }); + } + const profileRepository = dbConfig_1.dataSource.getRepository(profile_entity_1.default); + const existingProfile = yield profileRepository.findOne({ + where: { primary_email: email } + }); + if (existingProfile != null) { + res.status(409).json({ error: 'Email already exists' }); + } + const hashedPassword = yield bcrypt_1.default.hash(password, 10); + const newProfile = profileRepository.create({ + primary_email: email, + password: hashedPassword, + contact_email: '', + first_name: '', + last_name: '', + image_url: '', + linkedin_url: '' + }); + yield profileRepository.save(newProfile); + res.status(201).json({ + uuid: newProfile.uuid, + primary_email: newProfile.primary_email, + contact_email: newProfile.contact_email, + first_name: newProfile.first_name, + last_name: newProfile.last_name, + image_url: newProfile.image_url, + linkedin_url: newProfile.linkedin_url + }); + } + catch (err) { + console.error('Error executing query', err); + res.status(500).json({ error: 'Internal server error' }); + } +}); +exports.register = register; +const login = (req, res) => __awaiter(void 0, void 0, void 0, function* () { + try { + const { email, password } = req.body; + if (!email || !password) { + res.status(400).json({ error: 'Email and password are required fields' }); + } + const profileRepository = dbConfig_1.dataSource.getRepository(profile_entity_1.default); + const profile = yield profileRepository + .createQueryBuilder('profile') + .addSelect('profile.password') + .where({ primary_email: email }) + .getOne(); + if (profile == null) { + res.status(401).json({ error: 'Invalid email or password' }); + } + const passwordMatch = yield (profile === null || profile === void 0 ? void 0 : profile.comparePassword(password)); + if (!passwordMatch) { + res.status(401).json({ error: 'Invalid email or password' }); + } + const token = jsonwebtoken_1.default.sign({ userId: profile === null || profile === void 0 ? void 0 : profile.uuid }, envConfig_1.JWT_SECRET !== null && envConfig_1.JWT_SECRET !== void 0 ? envConfig_1.JWT_SECRET : '', { + expiresIn: '10h' // To-Do: Change value in production + }); + res.json({ token }); + } + catch (err) { + console.error('Error executing query', err); + res.status(500).json({ error: 'Internal server error' }); + } +}); +exports.login = login; +const requireAuth = (req, res, next) => { + passport_1.default.authenticate('jwt', { session: false }, (err, user) => { + if (err) { + next(err); + return; + } + if (!user) { + return res.status(401).json({ message: 'Unauthorised' }); + } + else { + req.user = user; + next(); + } + })(req, res, next); +}; +exports.requireAuth = requireAuth; diff --git a/dist/src/controllers/profile.controller.js b/dist/src/controllers/profile.controller.js new file mode 100644 index 00000000..61c59960 --- /dev/null +++ b/dist/src/controllers/profile.controller.js @@ -0,0 +1,22 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getProfile = void 0; +const getProfile = (req, res) => __awaiter(void 0, void 0, void 0, function* () { + try { + res.status(200).json(req.user); + } + catch (err) { + console.error('Error executing query', err); + res.status(500).json({ error: err }); + } +}); +exports.getProfile = getProfile; diff --git a/dist/src/entities/profile.entity.js b/dist/src/entities/profile.entity.js new file mode 100644 index 00000000..21624de4 --- /dev/null +++ b/dist/src/entities/profile.entity.js @@ -0,0 +1,119 @@ +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + 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; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const bcrypt_1 = __importDefault(require("bcrypt")); +const typeorm_1 = require("typeorm"); +const uuid_1 = require("uuid"); +const profileType_enum_1 = require("../enums/profileType.enum"); +let Profile = class Profile { + constructor(primary_email, contact_email, first_name, last_name, image_uri, linkedin_uri, type, password) { + this.primary_email = primary_email; + this.contact_email = contact_email; + this.first_name = first_name; + this.last_name = last_name; + this.image_url = image_uri; + this.linkedin_url = linkedin_uri; + this.type = type !== null && type !== void 0 ? type : profileType_enum_1.ProfileTypes.DEFAULT; + this.password = password; + } + comparePassword(candidatePassword) { + return __awaiter(this, void 0, void 0, function* () { + return yield bcrypt_1.default.compare(candidatePassword, this.password); + }); + } + updateTimestamps() { + this.updated_at = new Date(); + if (!this.uuid) { + this.created_at = new Date(); + } + } + generateUuid() { + return __awaiter(this, void 0, void 0, function* () { + if (!this.uuid) { + this.uuid = (0, uuid_1.v4)(); + } + }); + } +}; +__decorate([ + (0, typeorm_1.PrimaryGeneratedColumn)('uuid'), + __metadata("design:type", String) +], Profile.prototype, "uuid", void 0); +__decorate([ + (0, typeorm_1.Column)({ type: 'varchar', length: 255, unique: true }), + __metadata("design:type", String) +], Profile.prototype, "primary_email", void 0); +__decorate([ + (0, typeorm_1.Column)({ type: 'varchar', length: 255 }), + __metadata("design:type", String) +], Profile.prototype, "contact_email", void 0); +__decorate([ + (0, typeorm_1.Column)({ type: 'varchar', length: 255 }), + __metadata("design:type", String) +], Profile.prototype, "first_name", void 0); +__decorate([ + (0, typeorm_1.Column)({ type: 'varchar', length: 255 }), + __metadata("design:type", String) +], Profile.prototype, "last_name", void 0); +__decorate([ + (0, typeorm_1.Column)({ type: 'varchar', length: 255 }), + __metadata("design:type", String) +], Profile.prototype, "image_url", void 0); +__decorate([ + (0, typeorm_1.Column)({ type: 'varchar', length: 255 }), + __metadata("design:type", String) +], Profile.prototype, "linkedin_url", void 0); +__decorate([ + (0, typeorm_1.Column)({ type: 'enum', enum: profileType_enum_1.ProfileTypes, default: profileType_enum_1.ProfileTypes.DEFAULT }), + __metadata("design:type", String) +], Profile.prototype, "type", void 0); +__decorate([ + (0, typeorm_1.Column)({ type: 'varchar', length: 255, select: false }), + __metadata("design:type", String) +], Profile.prototype, "password", void 0); +__decorate([ + (0, typeorm_1.Column)({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }), + __metadata("design:type", Object) +], Profile.prototype, "created_at", void 0); +__decorate([ + (0, typeorm_1.Column)({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }), + __metadata("design:type", Object) +], Profile.prototype, "updated_at", void 0); +__decorate([ + (0, typeorm_1.BeforeInsert)(), + (0, typeorm_1.BeforeUpdate)(), + __metadata("design:type", Function), + __metadata("design:paramtypes", []), + __metadata("design:returntype", void 0) +], Profile.prototype, "updateTimestamps", null); +__decorate([ + (0, typeorm_1.BeforeInsert)(), + __metadata("design:type", Function), + __metadata("design:paramtypes", []), + __metadata("design:returntype", Promise) +], Profile.prototype, "generateUuid", null); +Profile = __decorate([ + (0, typeorm_1.Entity)({ name: 'profile' }), + __metadata("design:paramtypes", [String, String, String, String, String, String, String, String]) +], Profile); +exports.default = Profile; diff --git a/dist/src/enums/profileType.enum.js b/dist/src/enums/profileType.enum.js new file mode 100644 index 00000000..54646686 --- /dev/null +++ b/dist/src/enums/profileType.enum.js @@ -0,0 +1,8 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ProfileTypes = void 0; +var ProfileTypes; +(function (ProfileTypes) { + ProfileTypes["DEFAULT"] = "default"; + ProfileTypes["ADMIN"] = "admin"; +})(ProfileTypes || (exports.ProfileTypes = ProfileTypes = {})); diff --git a/dist/src/routes/auth.route.js b/dist/src/routes/auth.route.js new file mode 100644 index 00000000..45c58aba --- /dev/null +++ b/dist/src/routes/auth.route.js @@ -0,0 +1,11 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const auth_controller_1 = require("../controllers/auth.controller"); +const authRouter = express_1.default.Router(); +authRouter.post('/register', auth_controller_1.register); +authRouter.post('/login', auth_controller_1.login); +exports.default = authRouter; diff --git a/dist/src/routes/profile/profile.route.js b/dist/src/routes/profile/profile.route.js new file mode 100644 index 00000000..e12d2129 --- /dev/null +++ b/dist/src/routes/profile/profile.route.js @@ -0,0 +1,11 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const profile_controller_1 = require("../../controllers/profile.controller"); +const auth_controller_1 = require("../../controllers/auth.controller"); +const profileRouter = express_1.default.Router(); +profileRouter.get('/profile', auth_controller_1.requireAuth, profile_controller_1.getProfile); +exports.default = profileRouter; diff --git a/dist/src/routes/profile/profile.route.test.js b/dist/src/routes/profile/profile.route.test.js new file mode 100644 index 00000000..f60729a6 --- /dev/null +++ b/dist/src/routes/profile/profile.route.test.js @@ -0,0 +1,58 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const app_1 = require("../../app"); +const supertest_1 = __importDefault(require("supertest")); +describe('profile', () => { + let server; + describe('Get profile route', () => { + let accessToken; + const randomString = Math.random().toString(36).substr(2, 5); + beforeAll(() => __awaiter(void 0, void 0, void 0, function* () { + server = yield (0, app_1.startServer)(); + const testUser = { + email: `test${randomString}@gmail.com`, + password: '123' + }; + yield (0, supertest_1.default)(server) + .post('/api/auth/register') + .send(testUser) + .expect(201); + const response = yield (0, supertest_1.default)(server) + .post('/api/auth/login') + .send(testUser) + .expect(200); + accessToken = response.body.token; + }), 5000); + it('should return a 401 without a valid access token', () => __awaiter(void 0, void 0, void 0, function* () { + yield (0, supertest_1.default)(server).get('/api/me/profile').expect(401); + })); + it('should return a 200 with a user profile object', () => __awaiter(void 0, void 0, void 0, function* () { + const response = yield (0, supertest_1.default)(server) + .get('/api/me/profile') + .set('Authorization', `Bearer ${accessToken}`) + .expect(200); + expect(response.body).toHaveProperty('created_at'); + expect(response.body).toHaveProperty('updated_at'); + expect(response.body).toHaveProperty('primary_email'); + expect(response.body).toHaveProperty('contact_email'); + expect(response.body).toHaveProperty('first_name'); + expect(response.body).toHaveProperty('last_name'); + expect(response.body).toHaveProperty('image_url'); + expect(response.body).toHaveProperty('linkedin_url'); + expect(response.body).toHaveProperty('type'); + expect(response.body).toHaveProperty('uuid'); + })); + }); +}); diff --git a/dist/src/server.js b/dist/src/server.js new file mode 100644 index 00000000..14c5a8a2 --- /dev/null +++ b/dist/src/server.js @@ -0,0 +1,9 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const app_1 = __importDefault(require("./app")); +(0, app_1.default)().then(() => { + console.log("Server started!"); +}).catch((err) => { console.log("Something went wrong!", err); }); diff --git a/dist/test/integration/db.test.js b/dist/test/integration/db.test.js new file mode 100644 index 00000000..db34ac09 --- /dev/null +++ b/dist/test/integration/db.test.js @@ -0,0 +1,30 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.initConnection = void 0; +const dbConfig_1 = require("../../src/configs/dbConfig"); +const initConnection = () => __awaiter(void 0, void 0, void 0, function* () { + yield dbConfig_1.dataSource + .initialize() + .then(() => { + console.log('Data Source has been initialized!'); + }) + .catch((err) => { + console.error('Error during Data Source initialization:', err); + throw new Error('Data Source initialization failed'); + }); +}); +exports.initConnection = initConnection; +describe('typeorm connection', () => { + it('should test typeorm connection', () => __awaiter(void 0, void 0, void 0, function* () { + yield expect((0, exports.initConnection)()).resolves.not.toThrow(); + })); +}); diff --git a/eslint.ts b/eslint.ts deleted file mode 100644 index c1620180..00000000 --- a/eslint.ts +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], - env: { - node: true, - }, -}; diff --git a/jest.config.ts b/jest.config.ts index 809175f6..045354ba 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,4 +1,4 @@ export default { preset: 'ts-jest', - testEnvironment: 'node', -}; + testEnvironment: 'node' +} diff --git a/package-lock.json b/package-lock.json index dc8f6b11..d5c06a83 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,15 +36,30 @@ "@types/prettier": "^2.7.2", "@types/supertest": "^2.0.12", "@types/uuid": "^9.0.2", - "@typescript-eslint/eslint-plugin": "^5.59.5", + "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.59.5", - "eslint": "^8.40.0", + "eslint": "^8.46.0", + "eslint-config-prettier": "^8.10.0", + "eslint-config-standard-with-typescript": "^37.0.0", + "eslint-plugin-import": "^2.28.0", + "eslint-plugin-n": "^16.0.1", + "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-promise": "^6.1.1", "jest": "^29.6.1", - "prettier": "^2.8.8", + "prettier": "^3.0.0", "supertest": "^6.3.3", "ts-jest": "^29.1.0", "ts-node-dev": "^2.0.0", - "typescript": "^5.0.4" + "typescript": "^5.1.6" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/@ampproject/remapping": { @@ -728,23 +743,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -840,18 +855,18 @@ } }, "node_modules/@eslint/js": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", - "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", + "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -1425,6 +1440,26 @@ "node": ">= 8" } }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -1626,9 +1661,15 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "node_modules/@types/jsonwebtoken": { @@ -1852,17 +1893,17 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz", - "integrity": "sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.5", - "@typescript-eslint/type-utils": "5.59.5", - "@typescript-eslint/utils": "5.59.5", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", "semver": "^7.3.7", @@ -1885,6 +1926,53 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2009,13 +2097,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz", - "integrity": "sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.5", - "@typescript-eslint/utils": "5.59.5", + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -2035,6 +2123,63 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/type-utils/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2052,12 +2197,45 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/type-utils/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@typescript-eslint/type-utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@typescript-eslint/types": { "version": "5.59.5", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.5.tgz", @@ -2155,17 +2333,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.5.tgz", - "integrity": "sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.5", - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/typescript-estree": "5.59.5", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, @@ -2180,6 +2358,97 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2192,10 +2461,16 @@ "node": ">=10" } }, + "node_modules/@typescript-eslint/utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2248,9 +2523,9 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "bin": { "acorn": "bin/acorn" }, @@ -2417,11 +2692,43 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -2431,31 +2738,118 @@ "node": ">=8" } }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/babel-jest": { - "version": "29.6.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.1.tgz", - "integrity": "sha512-qu+3bdPEQC6KZSPz+4Fyjbga5OODNcp49j6GKzG1EKbkfyJBxEYGVUmVGpwCSeGouG52R4EgYMLb6p9YeEEQ4A==", + "node_modules/array.prototype.findlastindex": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz", + "integrity": "sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==", "dev": true, "dependencies": { - "@jest/transform": "^29.6.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-jest": { + "version": "29.6.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.1.tgz", + "integrity": "sha512-qu+3bdPEQC6KZSPz+4Fyjbga5OODNcp49j6GKzG1EKbkfyJBxEYGVUmVGpwCSeGouG52R4EgYMLb6p9YeEEQ4A==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.6.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.5.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -2571,6 +2965,15 @@ "node": ">= 10.0.0" } }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2603,6 +3006,18 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2715,6 +3130,63 @@ "node": ">=4" } }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/builtins/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/builtins/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/builtins/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -3108,6 +3580,178 @@ "node": ">=0.10.0" } }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-browser/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/default-browser/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3280,13 +3924,106 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + }, "engines": { - "node": ">=6" - } + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } }, "node_modules/escape-html": { "version": "1.0.3", @@ -3303,27 +4040,27 @@ } }, "node_modules/eslint": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz", + "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.40.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.1", + "@eslint/js": "^8.46.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.2", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -3331,22 +4068,19 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -3359,6 +4093,309 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-config-standard": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0" + } + }, + "node_modules/eslint-config-standard-with-typescript": { + "version": "37.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-37.0.0.tgz", + "integrity": "sha512-V8I/Q1eFf9tiOuFHkbksUdWO3p1crFmewecfBtRxXdnvb71BCJx+1xAknlIRZMwZioMX3/bPtMVCZsf1+AjjOw==", + "dev": true, + "dependencies": { + "@typescript-eslint/parser": "^5.52.0", + "eslint-config-standard": "17.1.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.52.0", + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0", + "typescript": "*" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.8.tgz", + "integrity": "sha512-tEe+Pok22qIGaK3KoMP+N96GVDS66B/zreoVVmiavLvRUEmGRtvb4B8wO9jwnb8d2lvHtrkhZ7UD73dWBVnf/Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-es-x": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.2.0.tgz", + "integrity": "sha512-9dvv5CcvNjSJPqnS5uZkqb3xmbeqRLnvXKK7iI5+oK/yTusyc46zbBZKENGsOfojm/mKfszyZb+wNqNPAPeGXA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.6.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz", + "integrity": "sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", + "has": "^1.0.3", + "is-core-module": "^2.12.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "resolve": "^1.22.3", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-n": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.0.1.tgz", + "integrity": "sha512-CDmHegJN0OF3L5cz5tATH84RPQm9kG+Yx39wIqIwPR2C0uhBGMWfbbOtetR83PQjjidA5aXMu+LEFw1jaSwvTA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "builtins": "^5.0.1", + "eslint-plugin-es-x": "^7.1.0", + "ignore": "^5.2.4", + "is-core-module": "^2.12.1", + "minimatch": "^3.1.2", + "resolve": "^1.22.2", + "semver": "^7.5.3" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-n/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-n/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-n/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", + "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -3373,9 +4410,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", + "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3420,9 +4457,9 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -3535,18 +4572,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -3560,12 +4585,12 @@ } }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" }, @@ -3790,10 +4815,16 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -3930,6 +4961,15 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -4026,6 +5066,33 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -4097,6 +5164,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -4137,6 +5220,21 @@ "node": ">=4" } }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -4157,16 +5255,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "node_modules/has": { @@ -4180,6 +5290,15 @@ "node": ">= 0.4.0" } }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4188,6 +5307,18 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", @@ -4210,6 +5341,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -4401,6 +5547,20 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -4409,12 +5569,38 @@ "node": ">= 0.10" } }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -4427,10 +5613,38 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -4439,6 +5653,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4477,6 +5721,36 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4486,6 +5760,21 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -4495,11 +5784,123 @@ "node": ">=8" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, + "bin": { + "is-docker": "cli.js" + }, "engines": { "node": ">=8" }, @@ -4507,6 +5908,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5222,16 +6629,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5753,6 +7150,79 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.0.tgz", + "integrity": "sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -5793,18 +7263,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -6180,20 +7668,32 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.1.tgz", + "integrity": "sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-format": { "version": "29.6.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.1.tgz", @@ -6367,6 +7867,23 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6376,12 +7893,12 @@ } }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", "dev": true, "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -6444,6 +7961,21 @@ "rimraf": "bin.js" } }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6467,6 +7999,24 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -6486,6 +8036,20 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -6704,6 +8268,51 @@ "node": ">=8" } }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6867,6 +8476,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/tar": { "version": "6.1.15", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", @@ -6927,6 +8552,18 @@ "node": ">=0.8" } }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -7140,10 +8777,34 @@ "strip-json-comments": "^2.0.0" } }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -7211,6 +8872,71 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typeorm": { "version": "0.3.16", "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.16.tgz", @@ -7389,15 +9115,30 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/unpipe": { @@ -7408,6 +9149,15 @@ "node": ">= 0.8" } }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", @@ -7564,6 +9314,41 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -7572,15 +9357,6 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index a68706fe..3e6151cc 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "scripts": { "start": "nodemon --watch 'src/**/*.ts' --exec ts-node-dev --respawn src/app.ts", "test": "jest", - "lint": "eslint .", - "lint:fix": "eslint . --fix", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", "format": "prettier --write \"src/**/*.ts\"" }, "author": "", @@ -40,14 +40,20 @@ "@types/prettier": "^2.7.2", "@types/supertest": "^2.0.12", "@types/uuid": "^9.0.2", - "@typescript-eslint/eslint-plugin": "^5.59.5", + "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.59.5", - "eslint": "^8.40.0", + "eslint": "^8.46.0", + "eslint-config-prettier": "^8.10.0", + "eslint-config-standard-with-typescript": "^37.0.0", + "eslint-plugin-import": "^2.28.0", + "eslint-plugin-n": "^16.0.1", + "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-promise": "^6.1.1", "jest": "^29.6.1", - "prettier": "^2.8.8", + "prettier": "^3.0.0", "supertest": "^6.3.3", "ts-jest": "^29.1.0", "ts-node-dev": "^2.0.0", - "typescript": "^5.0.4" + "typescript": "^5.1.6" } } diff --git a/src/app.ts b/src/app.ts index 97602247..a2709001 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,30 +1,38 @@ -import express from 'express'; -import bodyParser from 'body-parser'; -import cors from 'cors'; -import { initConnection } from './configs/dbConfig'; -import authRouter from './routes/auth.route'; -import profileRouter from './routes/profile.route'; -import passport from 'passport'; -import './configs/passport'; -import { SERVER_PORT } from './configs/envConfig'; +import express from 'express' +import bodyParser from 'body-parser' +import cors from 'cors' +import { dataSource } from './configs/dbConfig' +import authRouter from './routes/auth.route' +import profileRouter from './routes/profile.route' +import passport from 'passport' +import './configs/passport' +import { SERVER_PORT } from './configs/envConfig' -const port = SERVER_PORT; -initConnection(); +const port = SERVER_PORT -const app = express(); -app.use(bodyParser.json()); -app.use(cors()); -app.use(passport.initialize()); +dataSource + .initialize() + .then(() => { + console.log('d') + }) + .catch(() => { + console.log('d') + }) + +const app = express() +app.use(bodyParser.json()) +app.use(cors()) +app.use(passport.initialize()) app.get('/', (req, res) => { - res.send('ScholarX Backend'); -}); + res.send('ScholarX Backend') +}) -app.use('/api/auth', authRouter); -app.use('/api/me', profileRouter); +app.use('/api/auth', authRouter) +app.use('/api/me', profileRouter) const server = app.listen(port, () => { - console.log(`Server is running on http://localhost:${port}`); -}); + console.log(`Server is running on http://localhost:${port}`) +}) -export default server; +export default server diff --git a/src/configs/dbConfig.ts b/src/configs/dbConfig.ts index 77285cb2..7186e955 100644 --- a/src/configs/dbConfig.ts +++ b/src/configs/dbConfig.ts @@ -1,25 +1,14 @@ -import { DataSource } from 'typeorm'; -import { DB_PASSWORD, DB_HOST, DB_PORT, DB_USER, DB_NAME } from './envConfig'; +import { DataSource } from 'typeorm' +import { DB_PASSWORD, DB_HOST, DB_PORT, DB_USER, DB_NAME } from './envConfig' + export const dataSource = new DataSource({ type: 'postgres', host: DB_HOST, - port: Number(DB_PORT) || 5432, + port: Number(DB_PORT) ?? 5432, username: DB_USER, password: DB_PASSWORD, database: DB_NAME, - entities: ['src/entity/*.ts'], + entities: ['src/entities/*.ts'], logging: true, - synchronize: false, -}); - -export async function initConnection() { - await dataSource - .initialize() - .then(() => { - console.log('Data Source has been initialized!'); - }) - .catch((err) => { - console.error('Error during Data Source initialization:', err); - throw new Error('Data Source initialization failed'); - }); -} + synchronize: true +}) diff --git a/src/configs/envConfig.ts b/src/configs/envConfig.ts index 27893465..bff54e95 100644 --- a/src/configs/envConfig.ts +++ b/src/configs/envConfig.ts @@ -1,11 +1,11 @@ -import dotenv from 'dotenv'; +import dotenv from 'dotenv' -dotenv.config(); +dotenv.config() export const DB_USER = process.env.DB_USER export const DB_HOST = process.env.DB_HOST export const DB_NAME = process.env.DB_NAME export const DB_PASSWORD = process.env.DB_PASSWORD export const DB_PORT = process.env.DB_PORT -export const SERVER_PORT = process.env.SERVER_PORT || 3000; +export const SERVER_PORT = process.env.SERVER_PORT ?? 3000 export const JWT_SECRET = process.env.JWT_SECRET diff --git a/src/configs/passport.ts b/src/configs/passport.ts index 5aea7916..5b16dafc 100644 --- a/src/configs/passport.ts +++ b/src/configs/passport.ts @@ -1,31 +1,31 @@ -import passport from 'passport'; -import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt'; -import { dataSource } from './dbConfig'; -import Profile from '../entity/profile.entity'; // Import the Profile entity -import { JWT_SECRET } from './envConfig'; +import passport from 'passport' +import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt' +import { dataSource } from './dbConfig' +import Profile from '../entities/profile.entity' +import { JWT_SECRET } from './envConfig' const options = { jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - secretOrKey: JWT_SECRET, -}; + secretOrKey: JWT_SECRET +} passport.use( new JwtStrategy(options, async (jwtPayload, done) => { try { - const profileRepository = dataSource.getRepository(Profile); + const profileRepository = dataSource.getRepository(Profile) const profile = await profileRepository.findOne({ - where: { uuid: jwtPayload.userId }, - }); + where: { uuid: jwtPayload.userId } + }) if (!profile) { - return done(null, false); + done(null, false) + } else { + done(null, profile) } - - return done(null, profile); } catch (error) { - return done(error, false); + done(error, false) } }) -); +) -export default passport; +export default passport diff --git a/src/controllers/auth.controller.ts b/src/controllers/auth.controller.ts new file mode 100644 index 00000000..94027f84 --- /dev/null +++ b/src/controllers/auth.controller.ts @@ -0,0 +1,110 @@ +import { dataSource } from '../configs/dbConfig' +import { type Request, type Response, type NextFunction } from 'express' +import jwt from 'jsonwebtoken' +import bcrypt from 'bcrypt' +import passport from 'passport' +import Profile from '../entities/profile.entity' +import { JWT_SECRET } from '../configs/envConfig' + +export const register = async (req: Request, res: Response): Promise => { + try { + const { email, password } = req.body + + if (!email || !password) { + res.status(400).json({ error: 'Email and password are required fields' }) + } + + const profileRepository = dataSource.getRepository(Profile) + + const existingProfile = await profileRepository.findOne({ + where: { primary_email: email } + }) + if (existingProfile != null) { + res.status(409).json({ error: 'Email already exists' }) + } + + const hashedPassword = await bcrypt.hash(password, 10) + const newProfile = profileRepository.create({ + primary_email: email, + password: hashedPassword, + contact_email: '', + first_name: '', + last_name: '', + image_url: '', + linkedin_url: '' + }) + await profileRepository.save(newProfile) + + res.status(201).json({ + uuid: newProfile.uuid, + primary_email: newProfile.primary_email, + contact_email: newProfile.contact_email, + first_name: newProfile.first_name, + last_name: newProfile.last_name, + image_url: newProfile.image_url, + linkedin_url: newProfile.linkedin_url + }) + } catch (err) { + console.error('Error executing query', err) + res.status(500).json({ error: 'Internal server error' }) + } +} + +export const login = async (req: Request, res: Response): Promise => { + try { + const { email, password }: { email: string; password: string } = req.body + + if (!email || !password) { + res.status(400).json({ error: 'Email and password are required fields' }) + } + + const profileRepository = dataSource.getRepository(Profile) + const profile = await profileRepository + .createQueryBuilder('profile') + .addSelect('profile.password') + .where({ primary_email: email }) + .getOne() + + if (profile == null) { + res.status(401).json({ error: 'Invalid email or password' }) + } + + const passwordMatch = await profile?.comparePassword(password) + + if (!passwordMatch) { + res.status(401).json({ error: 'Invalid email or password' }) + } + + const token = jwt.sign({ userId: profile?.uuid }, JWT_SECRET ?? '', { + expiresIn: '10h' // To-Do: Change value in production + }) + res.json({ token }) + } catch (err) { + console.error('Error executing query', err) + res.status(500).json({ error: 'Internal server error' }) + } +} + +export const requireAuth = ( + req: Request, + res: Response, + next: NextFunction +): void => { + passport.authenticate( + 'jwt', + { session: false }, + (err: Error, user: Profile) => { + if (err) { + next(err) + return + } + + if (!user) { + return res.status(401).json({ message: 'Unauthorised' }) + } else { + req.user = user + next() + } + } + )(req, res, next) +} diff --git a/src/services/profile.service.ts b/src/controllers/profile.controller.ts similarity index 56% rename from src/services/profile.service.ts rename to src/controllers/profile.controller.ts index db7a054d..d103df16 100644 --- a/src/services/profile.service.ts +++ b/src/controllers/profile.controller.ts @@ -1,28 +1,29 @@ -import { Request, Response } from 'express'; -import { dataSource } from '../configs/dbConfig'; -import Profile from '../entity/profile.entity'; +import { type Request, type Response } from 'express' -export const getProfile = async (req: Request, res: Response) => { +export const getProfile = async ( + req: Request, + res: Response +): Promise => { try { - res.status(200).json(req.user); + res.status(200).json(req.user) } catch (err) { - console.error('Error executing query', err); - res.status(500).json({ error: err }); + console.error('Error executing query', err) + res.status(500).json({ error: err }) } -}; +} export const updateProfile = async (req: Request, res: Response) => { try { - const user: any = req.user; + const user: any = req.user const { primary_email, contact_email, first_name, last_name, image_url, - linkedin_url, - }: Profile = req.body; - const profileRepository = dataSource.getRepository(Profile); + linkedin_url + }: Profile = req.body + const profileRepository = dataSource.getRepository(Profile) const updatedProfile = await profileRepository .createQueryBuilder() @@ -34,7 +35,7 @@ export const updateProfile = async (req: Request, res: Response) => { last_name: last_name, image_url: image_url, linkedin_url: linkedin_url, - updated_at: new Date().toISOString(), + updated_at: new Date().toISOString() }) .where('uuid = :uuid', { uuid: user.uuid }) .returning([ @@ -47,17 +48,17 @@ export const updateProfile = async (req: Request, res: Response) => { 'linkedin_url', 'type', 'created_at', - 'updated_at', + 'updated_at' ]) - .execute(); + .execute() if (updatedProfile.raw.length === 0) { - return res.status(404).json({ message: 'Profile not found' }); + return res.status(404).json({ message: 'Profile not found' }) } - return res.status(200).json(updatedProfile.raw[0]); + return res.status(200).json(updatedProfile.raw[0]) } catch (err) { - console.error('Error executing query', err); - return res.status(500).json({ error: err }); + console.error('Error executing query', err) + return res.status(500).json({ error: err }) } -}; +} diff --git a/src/entities/profile.entity.ts b/src/entities/profile.entity.ts new file mode 100644 index 00000000..8b09ee72 --- /dev/null +++ b/src/entities/profile.entity.ts @@ -0,0 +1,88 @@ +import bcrypt from 'bcrypt' +import { + Entity, + PrimaryGeneratedColumn, + Column, + BeforeInsert, + BeforeUpdate +} from 'typeorm' +import { v4 as uuidv4 } from 'uuid' +import { ProfileTypes } from '../enums/profileType.enum' + +@Entity({ name: 'profile' }) +class Profile { + @PrimaryGeneratedColumn('uuid') + uuid!: string + + @Column({ type: 'varchar', length: 255, unique: true }) + primary_email: string + + @Column({ type: 'varchar', length: 255 }) + contact_email: string + + @Column({ type: 'varchar', length: 255 }) + first_name: string + + @Column({ type: 'varchar', length: 255 }) + last_name: string + + @Column({ type: 'varchar', length: 255 }) + image_url: string + + @Column({ type: 'varchar', length: 255 }) + linkedin_url: string + + @Column({ type: 'enum', enum: ProfileTypes, default: ProfileTypes.DEFAULT }) + type: ProfileTypes + + @Column({ type: 'varchar', length: 255, select: false }) + password: string + + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + created_at: Date | undefined + + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + updated_at: Date | undefined + + constructor( + primary_email: string, + contact_email: string, + first_name: string, + last_name: string, + image_uri: string, + linkedin_uri: string, + type: ProfileTypes, + password: string + ) { + this.primary_email = primary_email + this.contact_email = contact_email + this.first_name = first_name + this.last_name = last_name + this.image_url = image_uri + this.linkedin_url = linkedin_uri + this.type = type ?? ProfileTypes.DEFAULT + this.password = password + } + + async comparePassword(candidatePassword: string): Promise { + return await bcrypt.compare(candidatePassword, this.password) + } + + @BeforeInsert() + @BeforeUpdate() + updateTimestamps(): void { + this.updated_at = new Date() + if (!this.uuid) { + this.created_at = new Date() + } + } + + @BeforeInsert() + async generateUuid(): Promise { + if (!this.uuid) { + this.uuid = uuidv4() + } + } +} + +export default Profile diff --git a/src/entity/profile.entity.ts b/src/entity/profile.entity.ts deleted file mode 100644 index 54909789..00000000 --- a/src/entity/profile.entity.ts +++ /dev/null @@ -1,82 +0,0 @@ -import bcrypt from 'bcrypt'; -import { Entity, PrimaryGeneratedColumn, Column, BeforeInsert, BeforeUpdate } from 'typeorm'; -import {v4 as uuidv4} from 'uuid'; -import { ProfileTypes } from '../enums/profileType.enum'; - -@Entity({ name: 'profile' }) -class Profile { - @PrimaryGeneratedColumn('uuid') - uuid!: string; - - @Column({type: 'varchar', length: 255, unique: true }) - primary_email: string; - - @Column({ type: 'varchar', length: 255 }) - contact_email: string; - - @Column({ type: 'varchar', length: 255 }) - first_name: string; - - @Column({ type: 'varchar', length: 255 }) - last_name: string; - - @Column({ type: 'varchar', length: 255 }) - image_url: string; - - @Column({ type: 'varchar', length: 255 }) - linkedin_url: string; - - @Column({ type: 'enum',enum: ProfileTypes, default:ProfileTypes.DEFAULT}) - type: ProfileTypes; - - @Column({ type: 'varchar', length: 255, select: false }) - password: string; - - @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) - created_at: Date | undefined; - - @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) - updated_at: Date | undefined; - - constructor( - primary_email: string, - contact_email: string, - first_name: string, - last_name: string, - image_uri: string, - linkedin_uri: string, - type: ProfileTypes, - password: string - ) { - this.primary_email = primary_email; - this.contact_email = contact_email; - this.first_name = first_name; - this.last_name = last_name; - this.image_url = image_uri; - this.linkedin_url = linkedin_uri; - this.type = type || ProfileTypes.DEFAULT; - this.password = password; - } - - async comparePassword(candidatePassword: string): Promise { - return bcrypt.compare(candidatePassword, this.password); - } - - @BeforeInsert() - @BeforeUpdate() - updateTimestamps() { - this.updated_at = new Date(); - if (!this.uuid) { - this.created_at = new Date(); - } - } - - @BeforeInsert() - async generateUuid() { - if (!this.uuid) { - this.uuid = uuidv4(); - } - } -} - -export default Profile; diff --git a/src/enums/profileType.enum.ts b/src/enums/profileType.enum.ts index 6e2ac646..3ef4c314 100644 --- a/src/enums/profileType.enum.ts +++ b/src/enums/profileType.enum.ts @@ -1,4 +1,4 @@ export enum ProfileTypes { - DEFAULT = "default", - ADMIN = "admin" + DEFAULT = 'default', + ADMIN = 'admin' } diff --git a/src/routes/auth.route.ts b/src/routes/auth.route.ts index 1db2d98f..179bc10a 100644 --- a/src/routes/auth.route.ts +++ b/src/routes/auth.route.ts @@ -1,9 +1,9 @@ -import express from 'express'; -import { register, login } from '../services/auth.service'; +import express from 'express' +import { register, login } from '../controllers/auth.controller' -const authRouter = express.Router(); +const authRouter = express.Router() -authRouter.post('/register', register); -authRouter.post('/login', login); +authRouter.post('/register', register) +authRouter.post('/login', login) -export default authRouter; +export default authRouter diff --git a/src/routes/profile.route.test.ts b/src/routes/profile.route.test.ts index f218c525..d52cbf33 100644 --- a/src/routes/profile.route.test.ts +++ b/src/routes/profile.route.test.ts @@ -1,33 +1,33 @@ -import server from '../app'; -import supertest from 'supertest'; +import server from '../app' +import supertest from 'supertest' describe('profile', () => { describe('Get profile route', () => { - let accessToken: string; + let accessToken: string beforeAll(async () => { const testUser = { email: 'test@gmail.com', - password: '123', - }; + password: '123' + } const response = await supertest(server) .post('/api/auth/login') .send(testUser) - .expect(200); + .expect(200) - accessToken = response.body.token; - }); + accessToken = response.body.token + }) it('should return a 401 without a valid access token', async () => { - await supertest(server).get('/api/me/profile').expect(401); - }); + await supertest(server).get('/api/me/profile').expect(401) + }) it('should return a 200 with a user profile object', async () => { const response = await supertest(server) .get('/api/me/profile') .set('Authorization', `Bearer ${accessToken}`) - .expect(200); + .expect(200) expect(response.body).toHaveProperty('created_at'); expect(response.body).toHaveProperty('updated_at'); @@ -51,6 +51,11 @@ describe('profile', () => { password: '123', }; + await supertest(server) + .post('/api/auth/login') + .send(testUser) + .expect(200) + const response = await supertest(server) .post('/api/auth/login') .send(testUser) @@ -81,3 +86,4 @@ describe('profile', () => { }); }); }); + diff --git a/src/routes/profile.route.ts b/src/routes/profile.route.ts index c120bd1f..3c5d1fed 100644 --- a/src/routes/profile.route.ts +++ b/src/routes/profile.route.ts @@ -1,10 +1,10 @@ -import express from 'express'; -import { getProfile, updateProfile } from '../services/profile.service'; -import { requireAuth } from '../services/auth.service'; +import express from 'express' +import { getProfile, updateProfile } from '../controllers/profile.controller' +import { requireAuth } from '../controllers/auth.controller' -const profileRouter = express.Router(); +const profileRouter = express.Router() profileRouter.get('/profile', requireAuth, getProfile); profileRouter.put('/profile', requireAuth, updateProfile); -export default profileRouter; +export default profileRouter diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts deleted file mode 100644 index 2c34e0f0..00000000 --- a/src/services/auth.service.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { dataSource } from '../configs/dbConfig'; -import { Request, Response, NextFunction } from 'express'; -import jwt from 'jsonwebtoken'; -import bcrypt from 'bcrypt'; -import passport from 'passport'; -import Profile from '../entity/profile.entity'; -import { FindOneOptions } from 'typeorm'; -import { JWT_SECRET } from '../configs/envConfig'; - -export const register = async (req: Request, res: Response) => { - try { - const { email, password } = req.body; - - if (!email || !password) { - return res - .status(400) - .json({ error: 'Email and password are required fields' }); - } - - const profileRepository = dataSource.getRepository(Profile); - - const existingProfile = await profileRepository.findOne({ - where: { primary_email: email }, - } as FindOneOptions); - if (existingProfile) { - return res.status(409).json({ error: 'Email already exists' }); - } - - const hashedPassword = await bcrypt.hash(password, 10); - const newProfile = profileRepository.create({ - primary_email: email, - password: hashedPassword, - contact_email: '', - first_name: '', - last_name: '', - image_url: '', - linkedin_url: '', - }); - await profileRepository.save(newProfile); - - res.status(201).json({ - uuid: newProfile.uuid, - primary_email: newProfile.primary_email, - contact_email: newProfile.contact_email, - first_name: newProfile.first_name, - last_name: newProfile.last_name, - image_url: newProfile.image_url, - linkedin_url: newProfile.linkedin_url, - }); - } catch (err) { - console.error('Error executing query', err); - res.status(500).json({ error: 'Internal server error' }); - } -}; - -export const login = async (req: Request, res: Response) => { - try { - const { email, password } = req.body; - - if (!email || !password) { - return res - .status(400) - .json({ error: 'Email and password are required fields' }); - } - - const profileRepository = dataSource.getRepository(Profile); - const profile = await profileRepository - .createQueryBuilder('profile') - .addSelect('profile.password') - .where({ primary_email: email }) - .getOne(); - - if (!profile) { - return res.status(401).json({ error: 'Invalid email or password' }); - } - - const passwordMatch = await profile.comparePassword(password); - - if (!passwordMatch) { - return res.status(401).json({ error: 'Invalid email or password' }); - } - - const token = jwt.sign({ userId: profile.uuid }, JWT_SECRET || '', { - expiresIn: '10h', // To-Do: Change value in production - }); - res.json({ token }); - } catch (err) { - console.error('Error executing query', err); - res.status(500).json({ error: 'Internal server error' }); - } -}; - -export const requireAuth = ( - req: Request, - res: Response, - next: NextFunction -) => { - passport.authenticate('jwt', { session: false }, (err: Error, user: any) => { - if (err) { - return next(err); - } - - if (!user) { - return res.status(401).json({ message: 'Unauthorised' }); - } else { - req.user = user; - next(); - } - })(req, res, next); -}; diff --git a/test/integration/db.test.ts b/test/integration/db.test.ts index d6918333..b758071d 100644 --- a/test/integration/db.test.ts +++ b/test/integration/db.test.ts @@ -1,7 +1,19 @@ -import { initConnection } from '../../src/configs/dbConfig'; +import { dataSource } from "../../src/configs/dbConfig" + +export const initConnection = async (): Promise => { + await dataSource + .initialize() + .then(() => { + console.log('Data Source has been initialized!') + }) + .catch((err) => { + console.error('Error during Data Source initialization:', err) + throw new Error('Data Source initialization failed') + }) +} describe('typeorm connection', () => { it('should test typeorm connection', async () => { - await expect(initConnection()).resolves.not.toThrow(); - }); -}); + await expect(initConnection()).resolves.not.toThrow() + }) +}) diff --git a/tsconfig.json b/tsconfig.json index f90cbef2..0f2fb33d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,9 +7,6 @@ "esModuleInterop": true, "experimentalDecorators": true, "emitDecoratorMetadata": true - }, - "include": [ - "src/index.ts" ,"src/**/*.ts" - ] + "include": ["src/**/*.ts", "test/", "jest.config.ts"] } From e18efb00b706cefd920a85af276b8c09bbe65317 Mon Sep 17 00:00:00 2001 From: anjula-sack Date: Sat, 5 Aug 2023 17:55:52 +0530 Subject: [PATCH 02/10] Fix test failures --- src/app.ts | 30 ++++++++++++++----- src/configs/dbConfig.ts | 2 +- .../{ => profile}/profile.route.test.ts | 15 ++++++++-- src/routes/{ => profile}/profile.route.ts | 0 4 files changed, 36 insertions(+), 11 deletions(-) rename src/routes/{ => profile}/profile.route.test.ts (88%) rename src/routes/{ => profile}/profile.route.ts (100%) diff --git a/src/app.ts b/src/app.ts index a2709001..c1fabd38 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,9 +1,11 @@ import express from 'express' +import type { Express } from 'express' +import type { Server } from 'http' import bodyParser from 'body-parser' import cors from 'cors' import { dataSource } from './configs/dbConfig' import authRouter from './routes/auth.route' -import profileRouter from './routes/profile.route' +import profileRouter from './routes/profile/profile.route' import passport from 'passport' import './configs/passport' import { SERVER_PORT } from './configs/envConfig' @@ -13,10 +15,10 @@ const port = SERVER_PORT dataSource .initialize() .then(() => { - console.log('d') + console.log('DB connection is successful') }) - .catch(() => { - console.log('d') + .catch((err) => { + console.log('DB connection was not successful', err) }) const app = express() @@ -31,8 +33,20 @@ app.get('/', (req, res) => { app.use('/api/auth', authRouter) app.use('/api/me', profileRouter) -const server = app.listen(port, () => { - console.log(`Server is running on http://localhost:${port}`) -}) +export const startServer = async (): Promise => { + try { + await dataSource.initialize() + console.log('DB connection is successful') + + app.listen(port, () => { + console.log(`Server is running on http://localhost:${port}`) + }) + + return app + } catch (err) { + console.log('DB connection was not successful', err) + throw err + } +} -export default server +export default startServer diff --git a/src/configs/dbConfig.ts b/src/configs/dbConfig.ts index 7186e955..7ae54204 100644 --- a/src/configs/dbConfig.ts +++ b/src/configs/dbConfig.ts @@ -9,6 +9,6 @@ export const dataSource = new DataSource({ password: DB_PASSWORD, database: DB_NAME, entities: ['src/entities/*.ts'], - logging: true, + logging: false, synchronize: true }) diff --git a/src/routes/profile.route.test.ts b/src/routes/profile/profile.route.test.ts similarity index 88% rename from src/routes/profile.route.test.ts rename to src/routes/profile/profile.route.test.ts index d52cbf33..ac21d1e0 100644 --- a/src/routes/profile.route.test.ts +++ b/src/routes/profile/profile.route.test.ts @@ -1,16 +1,26 @@ -import server from '../app' +import { startServer } from '../../app' +import type { Express } from "express" import supertest from 'supertest' +import { dataSource } from '../../configs/dbConfig' describe('profile', () => { + let server: Express; describe('Get profile route', () => { let accessToken: string beforeAll(async () => { + server = await startServer(); + const testUser = { - email: 'test@gmail.com', + email: 'test@gmail.comae', password: '123' } + await supertest(server) + .post('/api/auth/register') + .send(testUser) + .expect(201) + const response = await supertest(server) .post('/api/auth/login') .send(testUser) @@ -20,6 +30,7 @@ describe('profile', () => { }) it('should return a 401 without a valid access token', async () => { + await supertest(server).get('/api/me/profile').expect(401) }) diff --git a/src/routes/profile.route.ts b/src/routes/profile/profile.route.ts similarity index 100% rename from src/routes/profile.route.ts rename to src/routes/profile/profile.route.ts From 230cf3b1aa868f5b1efe6e4ccd118945b6d99b6a Mon Sep 17 00:00:00 2001 From: anjula-sack Date: Sat, 5 Aug 2023 20:19:45 +0530 Subject: [PATCH 03/10] Fix the eslint issues --- .eslintrc.json | 5 +- package-lock.json | 966 ++++++++++++++++++++++- package.json | 4 +- src/app.ts | 10 - src/routes/profile/profile.route.test.ts | 6 +- src/server.ts | 4 + 6 files changed, 977 insertions(+), 18 deletions(-) create mode 100644 src/server.ts diff --git a/.eslintrc.json b/.eslintrc.json index 4e9243a8..0e234ea9 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,7 +9,7 @@ "plugin:@typescript-eslint/recommended", "prettier" ], - "plugins": ["@typescript-eslint", "prettier"], + "plugins": ["@typescript-eslint", "prettier", "unused-imports"], "parserOptions": { "ecmaVersion": "latest", "sourceType": "module", @@ -18,6 +18,7 @@ "rules": { "@typescript-eslint/naming-convention": 0, "@typescript-eslint/no-misused-promises": 0, - "@typescript-eslint/strict-boolean-expressions": 0 + "@typescript-eslint/strict-boolean-expressions": 0, + "unused-imports/no-unused-imports": "error" } } diff --git a/package-lock.json b/package-lock.json index d5c06a83..1745cf5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "typeorm": "^0.3.16" }, "devDependencies": { + "@testcontainers/postgresql": "^10.0.2", "@types/bcrypt": "^5.0.0", "@types/body-parser": "^1.19.2", "@types/cors": "^2.8.13", @@ -45,7 +46,9 @@ "eslint-plugin-n": "^16.0.1", "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-unused-imports": "^2.0.0", "jest": "^29.6.1", + "nodemon": "^3.0.1", "prettier": "^3.0.0", "supertest": "^6.3.3", "ts-jest": "^29.1.0", @@ -710,6 +713,12 @@ "node": ">=6.9.0" } }, + "node_modules/@balena/dockerignore": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz", + "integrity": "sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==", + "dev": true + }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -1489,6 +1498,15 @@ "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" }, + "node_modules/@testcontainers/postgresql": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@testcontainers/postgresql/-/postgresql-10.0.2.tgz", + "integrity": "sha512-bubJ2bRC8yqJgi6NR8wpMUOhQu43hi4E3eIEypQC/vi6Fv8N9ido4BEshlTFKqvoYw28d75O9mAJwCWjFZkSBg==", + "dev": true, + "dependencies": { + "testcontainers": "^10.0.2" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -1834,6 +1852,25 @@ "@types/node": "*" } }, + "node_modules/@types/ssh2": { + "version": "0.5.52", + "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-0.5.52.tgz", + "integrity": "sha512-lbLLlXxdCZOSJMCInKH2+9V/77ET2J6NPQHpFI0kda61Dd1KglJs+fPQBchizmzYSOJBgdTajhPqBO1xxLywvg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/ssh2-streams": "*" + } + }, + "node_modules/@types/ssh2-streams": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@types/ssh2-streams/-/ssh2-streams-0.1.9.tgz", + "integrity": "sha512-I2J9jKqfmvXLR5GomDiCoHrEJ58hAOmFrekfFqmCFd+A6gaEStvWnPykoWUwld1PNg4G5ag1LwdA+Lz1doRJqg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -2666,6 +2703,81 @@ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, + "node_modules/archiver": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", + "dev": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.3", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/are-we-there-yet": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", @@ -2819,6 +2931,27 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "node_modules/async-lock": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.0.tgz", + "integrity": "sha512-coglx5yIWuetakm3/1dsX9hxCNox22h7+V80RQOu2XUUMidtArxKoZoOtHUPuR84SycKTXzgGzAUR5hJxujyJQ==", + "dev": true + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2837,6 +2970,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", + "dev": true + }, "node_modules/babel-jest": { "version": "29.6.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.1.tgz", @@ -2965,6 +3104,15 @@ "node": ">= 10.0.0" } }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, "node_modules/big-integer": { "version": "1.6.51", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", @@ -2983,6 +3131,41 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/body-parser": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", @@ -3111,6 +3294,15 @@ "ieee754": "^1.2.1" } }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -3130,6 +3322,16 @@ "node": ">=4" } }, + "node_modules/buildcheck": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz", + "integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -3187,6 +3389,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/byline": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", + "integrity": "sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -3451,6 +3662,21 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, + "node_modules/compress-commons": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "dev": true, + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3505,6 +3731,12 @@ "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", "dev": true }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -3517,6 +3749,46 @@ "node": ">= 0.10" } }, + "node_modules/cpu-features": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.8.tgz", + "integrity": "sha512-BbHBvtYhUhksqTjr6bhNOjGgMnhwhGTQmOoZGD+K7BCaQDCuZl/Ve1ZxUSMRwVC4D/rkCPQ2MAIeYzrWyK7eEg==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "buildcheck": "~0.0.6", + "nan": "^2.17.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", + "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -3839,6 +4111,88 @@ "node": ">=8" } }, + "node_modules/docker-compose": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.24.2.tgz", + "integrity": "sha512-2/WLvA7UZ6A2LDLQrYW0idKipmNBWhtfvrn2yzjC5PnHDzuFVj1zAZN6MJxVMKP0zZH8uzAK6OwVZYHGuyCmTw==", + "dev": true, + "dependencies": { + "yaml": "^2.2.2" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/docker-modem": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-3.0.8.tgz", + "integrity": "sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "readable-stream": "^3.5.0", + "split-ca": "^1.0.1", + "ssh2": "^1.11.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/docker-modem/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/docker-modem/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/dockerode": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.3.5.tgz", + "integrity": "sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA==", + "dev": true, + "dependencies": { + "@balena/dockerignore": "^1.0.2", + "docker-modem": "^3.0.0", + "tar-fs": "~2.0.1" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/dockerode/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/dockerode/node_modules/tar-fs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz", + "integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -3915,6 +4269,15 @@ "node": ">= 0.8" } }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -4396,6 +4759,36 @@ "eslint": "^7.0.0 || ^8.0.0" } }, + "node_modules/eslint-plugin-unused-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz", + "integrity": "sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A==", + "dev": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0", + "eslint": "^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -4821,6 +5214,12 @@ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "dev": true }, + "node_modules/fast-fifo": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.0.tgz", + "integrity": "sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", @@ -5015,6 +5414,12 @@ "node": ">= 0.6" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -5152,6 +5557,18 @@ "node": ">=8.0.0" } }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -5480,6 +5897,12 @@ "node": ">= 4" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -6768,6 +7191,54 @@ "node": ">=6" } }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -6813,8 +7284,32 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.memoize": { - "version": "4.1.2", + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "dev": true @@ -6825,6 +7320,12 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -7017,6 +7518,12 @@ "node": ">=10" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -7032,6 +7539,13 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "dev": true, + "optional": true + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7088,6 +7602,103 @@ "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", "dev": true }, + "node_modules/nodemon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nodemon/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -7720,6 +8331,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -7733,6 +8350,29 @@ "node": ">= 6" } }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/properties-reader": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/properties-reader/-/properties-reader-2.2.0.tgz", + "integrity": "sha512-CgVcr8MwGoBKK24r9TwHfZkLLaNFHQ6y4wgT9w/XzdpacOOi5ciH4hcuLechSDAwXsfrGQtI2JTutY2djOx2Ow==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -7745,6 +8385,22 @@ "node": ">= 0.10" } }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -7804,6 +8460,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -7845,6 +8507,36 @@ "node": ">= 6" } }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -7939,6 +8631,15 @@ "node": ">=10" } }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -8166,6 +8867,51 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -8200,6 +8946,12 @@ "source-map": "^0.6.0" } }, + "node_modules/split-ca": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz", + "integrity": "sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==", + "dev": true + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -8214,6 +8966,34 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "node_modules/ssh-remote-port-forward": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/ssh-remote-port-forward/-/ssh-remote-port-forward-1.0.4.tgz", + "integrity": "sha512-x0LV1eVDwjf1gmG7TTnfqIzf+3VPRz7vrNIjX6oYLbeCrf/PeVY6hkT68Mg+q02qXxQhrLjB0jfgvhevoCRmLQ==", + "dev": true, + "dependencies": { + "@types/ssh2": "^0.5.48", + "ssh2": "^1.4.0" + } + }, + "node_modules/ssh2": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.14.0.tgz", + "integrity": "sha512-AqzD1UCqit8tbOKoj6ztDDi1ffJZ2rV2SwlgrVVrHPkV5vWqGJOVp5pmtj18PunkPJAuKQsnInyKV+/Nb2bUnA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "asn1": "^0.2.6", + "bcrypt-pbkdf": "^1.0.2" + }, + "engines": { + "node": ">=10.16.0" + }, + "optionalDependencies": { + "cpu-features": "~0.0.8", + "nan": "^2.17.0" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -8234,6 +9014,16 @@ "node": ">= 0.8" } }, + "node_modules/streamx": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.0.tgz", + "integrity": "sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -8508,6 +9298,44 @@ "node": ">=10" } }, + "node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/tar-fs/node_modules/tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tar/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -8527,6 +9355,51 @@ "node": ">=8" } }, + "node_modules/testcontainers": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-10.0.2.tgz", + "integrity": "sha512-+NaLTsjy4scWjLCeLeUS8nKcMgQDBse/UDJwRd5U23n14mAWFxU7hBItS6s9bzw0Iv253eDQ2pSEQJO0pbknpw==", + "dev": true, + "dependencies": { + "@balena/dockerignore": "^1.0.2", + "archiver": "^5.3.1", + "async-lock": "^1.4.0", + "byline": "^5.0.0", + "debug": "^4.3.4", + "docker-compose": "^0.24.2", + "dockerode": "^3.3.5", + "get-port": "^5.1.1", + "node-fetch": "^2.6.12", + "proper-lockfile": "^4.1.2", + "properties-reader": "^2.2.0", + "ssh-remote-port-forward": "^1.0.4", + "tar-fs": "^3.0.4", + "tmp": "^0.2.1" + } + }, + "node_modules/testcontainers/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/testcontainers/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -8564,6 +9437,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/tmp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -8599,6 +9499,33 @@ "node": ">=0.6" } }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -8827,6 +9754,12 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9141,6 +10074,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -9413,6 +10352,15 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -9457,6 +10405,20 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zip-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", + "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", + "dev": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "compress-commons": "^4.1.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } } } } diff --git a/package.json b/package.json index 3e6151cc..41e1ff8f 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "start": "nodemon --watch 'src/**/*.ts' --exec ts-node-dev --respawn src/app.ts", + "start": "nodemon --watch 'src/**/*.ts' --exec ts-node-dev --respawn src/server.ts", "test": "jest", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", @@ -49,7 +49,9 @@ "eslint-plugin-n": "^16.0.1", "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-unused-imports": "^2.0.0", "jest": "^29.6.1", + "nodemon": "^3.0.1", "prettier": "^3.0.0", "supertest": "^6.3.3", "ts-jest": "^29.1.0", diff --git a/src/app.ts b/src/app.ts index c1fabd38..7d2d1138 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,5 @@ import express from 'express' import type { Express } from 'express' -import type { Server } from 'http' import bodyParser from 'body-parser' import cors from 'cors' import { dataSource } from './configs/dbConfig' @@ -12,15 +11,6 @@ import { SERVER_PORT } from './configs/envConfig' const port = SERVER_PORT -dataSource - .initialize() - .then(() => { - console.log('DB connection is successful') - }) - .catch((err) => { - console.log('DB connection was not successful', err) - }) - const app = express() app.use(bodyParser.json()) app.use(cors()) diff --git a/src/routes/profile/profile.route.test.ts b/src/routes/profile/profile.route.test.ts index ac21d1e0..40fec88b 100644 --- a/src/routes/profile/profile.route.test.ts +++ b/src/routes/profile/profile.route.test.ts @@ -1,18 +1,18 @@ import { startServer } from '../../app' import type { Express } from "express" import supertest from 'supertest' -import { dataSource } from '../../configs/dbConfig' describe('profile', () => { let server: Express; describe('Get profile route', () => { let accessToken: string + const randomString = Math.random().toString(36).substr(2, 5); beforeAll(async () => { server = await startServer(); const testUser = { - email: 'test@gmail.comae', + email: `test${randomString}@gmail.com`, password: '123' } @@ -27,7 +27,7 @@ describe('profile', () => { .expect(200) accessToken = response.body.token - }) + }, 5000) it('should return a 401 without a valid access token', async () => { diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 00000000..7aedb55a --- /dev/null +++ b/src/server.ts @@ -0,0 +1,4 @@ +import startServer from "./app"; + +startServer().then(()=> {console.log() +}).catch(()=>{console.log()}) \ No newline at end of file From 6325bb1caf0785766b14cdcfa331fc11991e1a00 Mon Sep 17 00:00:00 2001 From: anjula-sack Date: Sat, 5 Aug 2023 20:31:15 +0530 Subject: [PATCH 04/10] Add build script --- .gitignore | 1 + .prettierrc | 3 ++- package.json | 1 + src/server.ts | 4 ++-- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 713d5006..a884d38f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ .env +dist/ diff --git a/.prettierrc b/.prettierrc index c50384fb..5b429c37 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,5 +2,6 @@ "trailingComma": "none", "tabWidth": 2, "semi": false, - "singleQuote": true + "singleQuote": true, + "endOfLine": "auto" } diff --git a/package.json b/package.json index 41e1ff8f..d4238963 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "index.js", "scripts": { "start": "nodemon --watch 'src/**/*.ts' --exec ts-node-dev --respawn src/server.ts", + "build": "tsc", "test": "jest", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", diff --git a/src/server.ts b/src/server.ts index 7aedb55a..cbfa8287 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,4 +1,4 @@ import startServer from "./app"; -startServer().then(()=> {console.log() -}).catch(()=>{console.log()}) \ No newline at end of file +startServer().then(()=> {console.log("Server started!") +}).catch((err) => { console.log("Something went wrong!", err) }) From 2101d6b9c30f4a5384b403e9b2bf098d5973eb50 Mon Sep 17 00:00:00 2001 From: anjula-sack Date: Sat, 5 Aug 2023 20:32:36 +0530 Subject: [PATCH 05/10] Update the CI workflow --- .github/workflows/CI.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 7b0a9dde..1151c744 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -28,5 +28,8 @@ jobs: - name: ESLint check run: npm run lint + - name: Run tests + run: npm run test + - name: Build run: npm run build From 80375d39cba9863ccd904ade2bc91c2892e19b9d Mon Sep 17 00:00:00 2001 From: anjula-sack Date: Sat, 5 Aug 2023 20:53:19 +0530 Subject: [PATCH 06/10] Update the CI workflow --- .github/workflows/CI.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 1151c744..1000f551 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -13,6 +13,17 @@ jobs: runs-on: ubuntu-latest + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: password + POSTGRES_DB: mydatabase + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: - name: Checkout code uses: actions/checkout@v3 @@ -28,6 +39,16 @@ jobs: - name: ESLint check run: npm run lint + - name: Set up environment variables + run: | + echo "DB_USER=postgres" >> .env + echo "DB_HOST=localhost" >> .env + echo "DB_NAME=mydatabase" >> .env + echo "DB_PASSWORD=password" >> .env + echo "DB_PORT=5432" >> .env + echo "SERVER_PORT=4000" >> .env + echo "JWT_SECRET=your_jwt_secret_key" >> .env + - name: Run tests run: npm run test From b1199a9a29097781f5901e5630a01baaa4ca62f3 Mon Sep 17 00:00:00 2001 From: anjula-sack Date: Sat, 5 Aug 2023 22:34:16 +0530 Subject: [PATCH 07/10] Fix the jest exit issue --- jest.config.ts | 3 ++- package.json | 2 +- src/app.ts | 1 - src/routes/profile/profile.route.test.ts | 6 +++--- src/server.ts | 12 ++++++++++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/jest.config.ts b/jest.config.ts index 045354ba..5cfed72c 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,4 +1,5 @@ export default { preset: 'ts-jest', - testEnvironment: 'node' + testEnvironment: 'node', + modulePathIgnorePatterns: ['/dist/'] } diff --git a/package.json b/package.json index d4238963..23b0bd69 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "start": "nodemon --watch 'src/**/*.ts' --exec ts-node-dev --respawn src/server.ts", "build": "tsc", - "test": "jest", + "test": "jest --forceExit", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", "format": "prettier --write \"src/**/*.ts\"" diff --git a/src/app.ts b/src/app.ts index 7d2d1138..5cc30de9 100644 --- a/src/app.ts +++ b/src/app.ts @@ -27,7 +27,6 @@ export const startServer = async (): Promise => { try { await dataSource.initialize() console.log('DB connection is successful') - app.listen(port, () => { console.log(`Server is running on http://localhost:${port}`) }) diff --git a/src/routes/profile/profile.route.test.ts b/src/routes/profile/profile.route.test.ts index 40fec88b..5eb05e7a 100644 --- a/src/routes/profile/profile.route.test.ts +++ b/src/routes/profile/profile.route.test.ts @@ -1,12 +1,13 @@ -import { startServer } from '../../app' +import { startServer } from '../../app' import type { Express } from "express" import supertest from 'supertest' +import { dataSource } from '../../configs/dbConfig'; describe('profile', () => { let server: Express; describe('Get profile route', () => { let accessToken: string - const randomString = Math.random().toString(36).substr(2, 5); + const randomString = Math.random().toString(36); beforeAll(async () => { server = await startServer(); @@ -30,7 +31,6 @@ describe('profile', () => { }, 5000) it('should return a 401 without a valid access token', async () => { - await supertest(server).get('/api/me/profile').expect(401) }) diff --git a/src/server.ts b/src/server.ts index cbfa8287..6b7d5526 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,4 +1,12 @@ import startServer from "./app"; -startServer().then(()=> {console.log("Server started!") -}).catch((err) => { console.log("Something went wrong!", err) }) +async function start() : Promise{ + try { + await startServer(); + console.log("Server started!"); + } catch (err) { + console.error("Something went wrong!", err); + } +} + +start().catch((err) => {console.error(err)}); From e2200177315fa574e1b63e57822518b9cb176a71 Mon Sep 17 00:00:00 2001 From: anjula-sack Date: Sat, 5 Aug 2023 23:59:47 +0530 Subject: [PATCH 08/10] Fix the conflicts --- src/controllers/profile.controller.ts | 33 ++++--- src/routes/profile/profile.route.test.ts | 115 ++++++++++------------- src/routes/profile/profile.route.ts | 4 +- 3 files changed, 70 insertions(+), 82 deletions(-) diff --git a/src/controllers/profile.controller.ts b/src/controllers/profile.controller.ts index d103df16..8d95bd42 100644 --- a/src/controllers/profile.controller.ts +++ b/src/controllers/profile.controller.ts @@ -1,4 +1,6 @@ import { type Request, type Response } from 'express' +import { dataSource } from '../configs/dbConfig' +import Profile from '../entities/profile.entity' export const getProfile = async ( req: Request, @@ -12,9 +14,13 @@ export const getProfile = async ( } } -export const updateProfile = async (req: Request, res: Response) => { +export const updateProfile = async ( + req: Request, + res: Response +): Promise => { try { - const user: any = req.user + const user: Profile | undefined = req.user as Profile + const { primary_email, contact_email, @@ -22,22 +28,23 @@ export const updateProfile = async (req: Request, res: Response) => { last_name, image_url, linkedin_url - }: Profile = req.body + } = req.body + const profileRepository = dataSource.getRepository(Profile) const updatedProfile = await profileRepository .createQueryBuilder() .update(Profile) .set({ - primary_email: primary_email, - contact_email: contact_email, - first_name: first_name, - last_name: last_name, - image_url: image_url, - linkedin_url: linkedin_url, + primary_email, + contact_email, + first_name, + last_name, + image_url, + linkedin_url, updated_at: new Date().toISOString() }) - .where('uuid = :uuid', { uuid: user.uuid }) + .where('uuid = :uuid', { uuid: user?.uuid }) .returning([ 'uuid', 'primary_email', @@ -53,12 +60,12 @@ export const updateProfile = async (req: Request, res: Response) => { .execute() if (updatedProfile.raw.length === 0) { - return res.status(404).json({ message: 'Profile not found' }) + res.status(404).json({ message: 'Profile not found' }) } - return res.status(200).json(updatedProfile.raw[0]) + res.status(200).json(updatedProfile.raw[0]) } catch (err) { console.error('Error executing query', err) - return res.status(500).json({ error: err }) + res.status(500).json({ error: err }) } } diff --git a/src/routes/profile/profile.route.test.ts b/src/routes/profile/profile.route.test.ts index 5eb05e7a..6845ba7e 100644 --- a/src/routes/profile/profile.route.test.ts +++ b/src/routes/profile/profile.route.test.ts @@ -1,35 +1,35 @@ -import { startServer } from '../../app' -import type { Express } from "express" +import { startServer } from '../../app' +import type { Express } from 'express' import supertest from 'supertest' -import { dataSource } from '../../configs/dbConfig'; +import { dataSource } from '../../configs/dbConfig' + +const randomString = Math.random().toString(36) +let server: Express +let accessToken: string describe('profile', () => { - let server: Express; - describe('Get profile route', () => { - let accessToken: string - const randomString = Math.random().toString(36); + beforeAll(async () => { + server = await startServer() - beforeAll(async () => { - server = await startServer(); + const testUser = { + email: `test${randomString}@gmail.com`, + password: '123' + } - const testUser = { - email: `test${randomString}@gmail.com`, - password: '123' - } + await supertest(server) + .post('/api/auth/register') + .send(testUser) + .expect(201) - await supertest(server) - .post('/api/auth/register') - .send(testUser) - .expect(201) - - const response = await supertest(server) - .post('/api/auth/login') - .send(testUser) - .expect(200) + const response = await supertest(server) + .post('/api/auth/login') + .send(testUser) + .expect(200) - accessToken = response.body.token - }, 5000) + accessToken = response.body.token + }, 5000) + describe('Get profile route', () => { it('should return a 401 without a valid access token', async () => { await supertest(server).get('/api/me/profile').expect(401) }) @@ -40,61 +40,42 @@ describe('profile', () => { .set('Authorization', `Bearer ${accessToken}`) .expect(200) - expect(response.body).toHaveProperty('created_at'); - expect(response.body).toHaveProperty('updated_at'); - expect(response.body).toHaveProperty('primary_email'); - expect(response.body).toHaveProperty('contact_email'); - expect(response.body).toHaveProperty('first_name'); - expect(response.body).toHaveProperty('last_name'); - expect(response.body).toHaveProperty('image_url'); - expect(response.body).toHaveProperty('linkedin_url'); - expect(response.body).toHaveProperty('type'); - expect(response.body).toHaveProperty('uuid'); - }); - }); + expect(response.body).toHaveProperty('created_at') + expect(response.body).toHaveProperty('updated_at') + expect(response.body).toHaveProperty('primary_email') + expect(response.body).toHaveProperty('contact_email') + expect(response.body).toHaveProperty('first_name') + expect(response.body).toHaveProperty('last_name') + expect(response.body).toHaveProperty('image_url') + expect(response.body).toHaveProperty('linkedin_url') + expect(response.body).toHaveProperty('type') + expect(response.body).toHaveProperty('uuid') + }) + }) describe('Update profile route', () => { - let accessToken: string; - - beforeAll(async () => { - const testUser = { - email: 'test@gmail.com', - password: '123', - }; - - await supertest(server) - .post('/api/auth/login') - .send(testUser) - .expect(200) - - const response = await supertest(server) - .post('/api/auth/login') - .send(testUser) - .expect(200); - - accessToken = response.body.token; - }); - it('should update the user profile and return a 200', async () => { const updatedProfile = { - primary_email: 'test@gmail.com', contact_email: 'test_contact@example.com', first_name: 'John', last_name: 'Doe', image_url: 'https://example.com/test_profile_image.jpg', - linkedin_url: 'https://www.linkedin.com/in/johndoe', - }; + linkedin_url: 'https://www.linkedin.com/in/johndoe' + } await supertest(server) .put('/api/me/profile') .set('Authorization', `Bearer ${accessToken}`) .send(updatedProfile) - .expect(200); - }); + .expect(200) + }) it('should return a 401 without a valid access token', async () => { - await supertest(server).put('/api/me/profile').send({}).expect(401); - }); - }); -}); - + await supertest(server).put('/api/me/profile').send({}).expect(401) + }) + + afterAll(async () => { + await dataSource.destroy() + }) + }) +}) diff --git a/src/routes/profile/profile.route.ts b/src/routes/profile/profile.route.ts index 3c5d1fed..c2500673 100644 --- a/src/routes/profile/profile.route.ts +++ b/src/routes/profile/profile.route.ts @@ -1,6 +1,6 @@ import express from 'express' -import { getProfile, updateProfile } from '../controllers/profile.controller' -import { requireAuth } from '../controllers/auth.controller' +import { getProfile, updateProfile } from '../../controllers/profile.controller' +import { requireAuth } from '../../controllers/auth.controller' const profileRouter = express.Router() From 51e415c4d91996cd2552760f83555b5cd563b4fc Mon Sep 17 00:00:00 2001 From: anjula-sack Date: Sun, 6 Aug 2023 00:02:46 +0530 Subject: [PATCH 09/10] Remove build files --- dist/jest.config.js | 6 - dist/src/app.js | 50 -------- dist/src/configs/dbConfig.js | 17 --- dist/src/configs/envConfig.js | 16 --- dist/src/configs/passport.js | 41 ------ dist/src/controllers/auth.controller.js | 107 ---------------- dist/src/controllers/profile.controller.js | 22 ---- dist/src/entities/profile.entity.js | 119 ------------------ dist/src/enums/profileType.enum.js | 8 -- dist/src/routes/auth.route.js | 11 -- dist/src/routes/profile/profile.route.js | 11 -- dist/src/routes/profile/profile.route.test.js | 58 --------- dist/src/server.js | 9 -- dist/test/integration/db.test.js | 30 ----- 14 files changed, 505 deletions(-) delete mode 100644 dist/jest.config.js delete mode 100644 dist/src/app.js delete mode 100644 dist/src/configs/dbConfig.js delete mode 100644 dist/src/configs/envConfig.js delete mode 100644 dist/src/configs/passport.js delete mode 100644 dist/src/controllers/auth.controller.js delete mode 100644 dist/src/controllers/profile.controller.js delete mode 100644 dist/src/entities/profile.entity.js delete mode 100644 dist/src/enums/profileType.enum.js delete mode 100644 dist/src/routes/auth.route.js delete mode 100644 dist/src/routes/profile/profile.route.js delete mode 100644 dist/src/routes/profile/profile.route.test.js delete mode 100644 dist/src/server.js delete mode 100644 dist/test/integration/db.test.js diff --git a/dist/jest.config.js b/dist/jest.config.js deleted file mode 100644 index b1f8f1e5..00000000 --- a/dist/jest.config.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = { - preset: 'ts-jest', - testEnvironment: 'node' -}; diff --git a/dist/src/app.js b/dist/src/app.js deleted file mode 100644 index 235dfd8a..00000000 --- a/dist/src/app.js +++ /dev/null @@ -1,50 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.startServer = void 0; -const express_1 = __importDefault(require("express")); -const body_parser_1 = __importDefault(require("body-parser")); -const cors_1 = __importDefault(require("cors")); -const dbConfig_1 = require("./configs/dbConfig"); -const auth_route_1 = __importDefault(require("./routes/auth.route")); -const profile_route_1 = __importDefault(require("./routes/profile/profile.route")); -const passport_1 = __importDefault(require("passport")); -require("./configs/passport"); -const envConfig_1 = require("./configs/envConfig"); -const port = envConfig_1.SERVER_PORT; -const app = (0, express_1.default)(); -app.use(body_parser_1.default.json()); -app.use((0, cors_1.default)()); -app.use(passport_1.default.initialize()); -app.get('/', (req, res) => { - res.send('ScholarX Backend'); -}); -app.use('/api/auth', auth_route_1.default); -app.use('/api/me', profile_route_1.default); -const startServer = () => __awaiter(void 0, void 0, void 0, function* () { - try { - yield dbConfig_1.dataSource.initialize(); - console.log('DB connection is successful'); - app.listen(port, () => { - console.log(`Server is running on http://localhost:${port}`); - }); - return app; - } - catch (err) { - console.log('DB connection was not successful', err); - throw err; - } -}); -exports.startServer = startServer; -exports.default = exports.startServer; diff --git a/dist/src/configs/dbConfig.js b/dist/src/configs/dbConfig.js deleted file mode 100644 index 2977ba24..00000000 --- a/dist/src/configs/dbConfig.js +++ /dev/null @@ -1,17 +0,0 @@ -"use strict"; -var _a; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.dataSource = void 0; -const typeorm_1 = require("typeorm"); -const envConfig_1 = require("./envConfig"); -exports.dataSource = new typeorm_1.DataSource({ - type: 'postgres', - host: envConfig_1.DB_HOST, - port: (_a = Number(envConfig_1.DB_PORT)) !== null && _a !== void 0 ? _a : 5432, - username: envConfig_1.DB_USER, - password: envConfig_1.DB_PASSWORD, - database: envConfig_1.DB_NAME, - entities: ['src/entities/*.ts'], - logging: false, - synchronize: true -}); diff --git a/dist/src/configs/envConfig.js b/dist/src/configs/envConfig.js deleted file mode 100644 index 044e56ef..00000000 --- a/dist/src/configs/envConfig.js +++ /dev/null @@ -1,16 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -var _a; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.JWT_SECRET = exports.SERVER_PORT = exports.DB_PORT = exports.DB_PASSWORD = exports.DB_NAME = exports.DB_HOST = exports.DB_USER = void 0; -const dotenv_1 = __importDefault(require("dotenv")); -dotenv_1.default.config(); -exports.DB_USER = process.env.DB_USER; -exports.DB_HOST = process.env.DB_HOST; -exports.DB_NAME = process.env.DB_NAME; -exports.DB_PASSWORD = process.env.DB_PASSWORD; -exports.DB_PORT = process.env.DB_PORT; -exports.SERVER_PORT = (_a = process.env.SERVER_PORT) !== null && _a !== void 0 ? _a : 3000; -exports.JWT_SECRET = process.env.JWT_SECRET; diff --git a/dist/src/configs/passport.js b/dist/src/configs/passport.js deleted file mode 100644 index b4627dfb..00000000 --- a/dist/src/configs/passport.js +++ /dev/null @@ -1,41 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const passport_1 = __importDefault(require("passport")); -const passport_jwt_1 = require("passport-jwt"); -const dbConfig_1 = require("./dbConfig"); -const profile_entity_1 = __importDefault(require("../entities/profile.entity")); -const envConfig_1 = require("./envConfig"); -const options = { - jwtFromRequest: passport_jwt_1.ExtractJwt.fromAuthHeaderAsBearerToken(), - secretOrKey: envConfig_1.JWT_SECRET -}; -passport_1.default.use(new passport_jwt_1.Strategy(options, (jwtPayload, done) => __awaiter(void 0, void 0, void 0, function* () { - try { - const profileRepository = dbConfig_1.dataSource.getRepository(profile_entity_1.default); - const profile = yield profileRepository.findOne({ - where: { uuid: jwtPayload.userId } - }); - if (!profile) { - done(null, false); - } - else { - done(null, profile); - } - } - catch (error) { - done(error, false); - } -}))); -exports.default = passport_1.default; diff --git a/dist/src/controllers/auth.controller.js b/dist/src/controllers/auth.controller.js deleted file mode 100644 index 789fc51a..00000000 --- a/dist/src/controllers/auth.controller.js +++ /dev/null @@ -1,107 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.requireAuth = exports.login = exports.register = void 0; -const dbConfig_1 = require("../configs/dbConfig"); -const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); -const bcrypt_1 = __importDefault(require("bcrypt")); -const passport_1 = __importDefault(require("passport")); -const profile_entity_1 = __importDefault(require("../entities/profile.entity")); -const envConfig_1 = require("../configs/envConfig"); -const register = (req, res) => __awaiter(void 0, void 0, void 0, function* () { - try { - const { email, password } = req.body; - if (!email || !password) { - res.status(400).json({ error: 'Email and password are required fields' }); - } - const profileRepository = dbConfig_1.dataSource.getRepository(profile_entity_1.default); - const existingProfile = yield profileRepository.findOne({ - where: { primary_email: email } - }); - if (existingProfile != null) { - res.status(409).json({ error: 'Email already exists' }); - } - const hashedPassword = yield bcrypt_1.default.hash(password, 10); - const newProfile = profileRepository.create({ - primary_email: email, - password: hashedPassword, - contact_email: '', - first_name: '', - last_name: '', - image_url: '', - linkedin_url: '' - }); - yield profileRepository.save(newProfile); - res.status(201).json({ - uuid: newProfile.uuid, - primary_email: newProfile.primary_email, - contact_email: newProfile.contact_email, - first_name: newProfile.first_name, - last_name: newProfile.last_name, - image_url: newProfile.image_url, - linkedin_url: newProfile.linkedin_url - }); - } - catch (err) { - console.error('Error executing query', err); - res.status(500).json({ error: 'Internal server error' }); - } -}); -exports.register = register; -const login = (req, res) => __awaiter(void 0, void 0, void 0, function* () { - try { - const { email, password } = req.body; - if (!email || !password) { - res.status(400).json({ error: 'Email and password are required fields' }); - } - const profileRepository = dbConfig_1.dataSource.getRepository(profile_entity_1.default); - const profile = yield profileRepository - .createQueryBuilder('profile') - .addSelect('profile.password') - .where({ primary_email: email }) - .getOne(); - if (profile == null) { - res.status(401).json({ error: 'Invalid email or password' }); - } - const passwordMatch = yield (profile === null || profile === void 0 ? void 0 : profile.comparePassword(password)); - if (!passwordMatch) { - res.status(401).json({ error: 'Invalid email or password' }); - } - const token = jsonwebtoken_1.default.sign({ userId: profile === null || profile === void 0 ? void 0 : profile.uuid }, envConfig_1.JWT_SECRET !== null && envConfig_1.JWT_SECRET !== void 0 ? envConfig_1.JWT_SECRET : '', { - expiresIn: '10h' // To-Do: Change value in production - }); - res.json({ token }); - } - catch (err) { - console.error('Error executing query', err); - res.status(500).json({ error: 'Internal server error' }); - } -}); -exports.login = login; -const requireAuth = (req, res, next) => { - passport_1.default.authenticate('jwt', { session: false }, (err, user) => { - if (err) { - next(err); - return; - } - if (!user) { - return res.status(401).json({ message: 'Unauthorised' }); - } - else { - req.user = user; - next(); - } - })(req, res, next); -}; -exports.requireAuth = requireAuth; diff --git a/dist/src/controllers/profile.controller.js b/dist/src/controllers/profile.controller.js deleted file mode 100644 index 61c59960..00000000 --- a/dist/src/controllers/profile.controller.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getProfile = void 0; -const getProfile = (req, res) => __awaiter(void 0, void 0, void 0, function* () { - try { - res.status(200).json(req.user); - } - catch (err) { - console.error('Error executing query', err); - res.status(500).json({ error: err }); - } -}); -exports.getProfile = getProfile; diff --git a/dist/src/entities/profile.entity.js b/dist/src/entities/profile.entity.js deleted file mode 100644 index 21624de4..00000000 --- a/dist/src/entities/profile.entity.js +++ /dev/null @@ -1,119 +0,0 @@ -"use strict"; -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - 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; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -var __metadata = (this && this.__metadata) || function (k, v) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const bcrypt_1 = __importDefault(require("bcrypt")); -const typeorm_1 = require("typeorm"); -const uuid_1 = require("uuid"); -const profileType_enum_1 = require("../enums/profileType.enum"); -let Profile = class Profile { - constructor(primary_email, contact_email, first_name, last_name, image_uri, linkedin_uri, type, password) { - this.primary_email = primary_email; - this.contact_email = contact_email; - this.first_name = first_name; - this.last_name = last_name; - this.image_url = image_uri; - this.linkedin_url = linkedin_uri; - this.type = type !== null && type !== void 0 ? type : profileType_enum_1.ProfileTypes.DEFAULT; - this.password = password; - } - comparePassword(candidatePassword) { - return __awaiter(this, void 0, void 0, function* () { - return yield bcrypt_1.default.compare(candidatePassword, this.password); - }); - } - updateTimestamps() { - this.updated_at = new Date(); - if (!this.uuid) { - this.created_at = new Date(); - } - } - generateUuid() { - return __awaiter(this, void 0, void 0, function* () { - if (!this.uuid) { - this.uuid = (0, uuid_1.v4)(); - } - }); - } -}; -__decorate([ - (0, typeorm_1.PrimaryGeneratedColumn)('uuid'), - __metadata("design:type", String) -], Profile.prototype, "uuid", void 0); -__decorate([ - (0, typeorm_1.Column)({ type: 'varchar', length: 255, unique: true }), - __metadata("design:type", String) -], Profile.prototype, "primary_email", void 0); -__decorate([ - (0, typeorm_1.Column)({ type: 'varchar', length: 255 }), - __metadata("design:type", String) -], Profile.prototype, "contact_email", void 0); -__decorate([ - (0, typeorm_1.Column)({ type: 'varchar', length: 255 }), - __metadata("design:type", String) -], Profile.prototype, "first_name", void 0); -__decorate([ - (0, typeorm_1.Column)({ type: 'varchar', length: 255 }), - __metadata("design:type", String) -], Profile.prototype, "last_name", void 0); -__decorate([ - (0, typeorm_1.Column)({ type: 'varchar', length: 255 }), - __metadata("design:type", String) -], Profile.prototype, "image_url", void 0); -__decorate([ - (0, typeorm_1.Column)({ type: 'varchar', length: 255 }), - __metadata("design:type", String) -], Profile.prototype, "linkedin_url", void 0); -__decorate([ - (0, typeorm_1.Column)({ type: 'enum', enum: profileType_enum_1.ProfileTypes, default: profileType_enum_1.ProfileTypes.DEFAULT }), - __metadata("design:type", String) -], Profile.prototype, "type", void 0); -__decorate([ - (0, typeorm_1.Column)({ type: 'varchar', length: 255, select: false }), - __metadata("design:type", String) -], Profile.prototype, "password", void 0); -__decorate([ - (0, typeorm_1.Column)({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }), - __metadata("design:type", Object) -], Profile.prototype, "created_at", void 0); -__decorate([ - (0, typeorm_1.Column)({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }), - __metadata("design:type", Object) -], Profile.prototype, "updated_at", void 0); -__decorate([ - (0, typeorm_1.BeforeInsert)(), - (0, typeorm_1.BeforeUpdate)(), - __metadata("design:type", Function), - __metadata("design:paramtypes", []), - __metadata("design:returntype", void 0) -], Profile.prototype, "updateTimestamps", null); -__decorate([ - (0, typeorm_1.BeforeInsert)(), - __metadata("design:type", Function), - __metadata("design:paramtypes", []), - __metadata("design:returntype", Promise) -], Profile.prototype, "generateUuid", null); -Profile = __decorate([ - (0, typeorm_1.Entity)({ name: 'profile' }), - __metadata("design:paramtypes", [String, String, String, String, String, String, String, String]) -], Profile); -exports.default = Profile; diff --git a/dist/src/enums/profileType.enum.js b/dist/src/enums/profileType.enum.js deleted file mode 100644 index 54646686..00000000 --- a/dist/src/enums/profileType.enum.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ProfileTypes = void 0; -var ProfileTypes; -(function (ProfileTypes) { - ProfileTypes["DEFAULT"] = "default"; - ProfileTypes["ADMIN"] = "admin"; -})(ProfileTypes || (exports.ProfileTypes = ProfileTypes = {})); diff --git a/dist/src/routes/auth.route.js b/dist/src/routes/auth.route.js deleted file mode 100644 index 45c58aba..00000000 --- a/dist/src/routes/auth.route.js +++ /dev/null @@ -1,11 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const express_1 = __importDefault(require("express")); -const auth_controller_1 = require("../controllers/auth.controller"); -const authRouter = express_1.default.Router(); -authRouter.post('/register', auth_controller_1.register); -authRouter.post('/login', auth_controller_1.login); -exports.default = authRouter; diff --git a/dist/src/routes/profile/profile.route.js b/dist/src/routes/profile/profile.route.js deleted file mode 100644 index e12d2129..00000000 --- a/dist/src/routes/profile/profile.route.js +++ /dev/null @@ -1,11 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const express_1 = __importDefault(require("express")); -const profile_controller_1 = require("../../controllers/profile.controller"); -const auth_controller_1 = require("../../controllers/auth.controller"); -const profileRouter = express_1.default.Router(); -profileRouter.get('/profile', auth_controller_1.requireAuth, profile_controller_1.getProfile); -exports.default = profileRouter; diff --git a/dist/src/routes/profile/profile.route.test.js b/dist/src/routes/profile/profile.route.test.js deleted file mode 100644 index f60729a6..00000000 --- a/dist/src/routes/profile/profile.route.test.js +++ /dev/null @@ -1,58 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const app_1 = require("../../app"); -const supertest_1 = __importDefault(require("supertest")); -describe('profile', () => { - let server; - describe('Get profile route', () => { - let accessToken; - const randomString = Math.random().toString(36).substr(2, 5); - beforeAll(() => __awaiter(void 0, void 0, void 0, function* () { - server = yield (0, app_1.startServer)(); - const testUser = { - email: `test${randomString}@gmail.com`, - password: '123' - }; - yield (0, supertest_1.default)(server) - .post('/api/auth/register') - .send(testUser) - .expect(201); - const response = yield (0, supertest_1.default)(server) - .post('/api/auth/login') - .send(testUser) - .expect(200); - accessToken = response.body.token; - }), 5000); - it('should return a 401 without a valid access token', () => __awaiter(void 0, void 0, void 0, function* () { - yield (0, supertest_1.default)(server).get('/api/me/profile').expect(401); - })); - it('should return a 200 with a user profile object', () => __awaiter(void 0, void 0, void 0, function* () { - const response = yield (0, supertest_1.default)(server) - .get('/api/me/profile') - .set('Authorization', `Bearer ${accessToken}`) - .expect(200); - expect(response.body).toHaveProperty('created_at'); - expect(response.body).toHaveProperty('updated_at'); - expect(response.body).toHaveProperty('primary_email'); - expect(response.body).toHaveProperty('contact_email'); - expect(response.body).toHaveProperty('first_name'); - expect(response.body).toHaveProperty('last_name'); - expect(response.body).toHaveProperty('image_url'); - expect(response.body).toHaveProperty('linkedin_url'); - expect(response.body).toHaveProperty('type'); - expect(response.body).toHaveProperty('uuid'); - })); - }); -}); diff --git a/dist/src/server.js b/dist/src/server.js deleted file mode 100644 index 14c5a8a2..00000000 --- a/dist/src/server.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const app_1 = __importDefault(require("./app")); -(0, app_1.default)().then(() => { - console.log("Server started!"); -}).catch((err) => { console.log("Something went wrong!", err); }); diff --git a/dist/test/integration/db.test.js b/dist/test/integration/db.test.js deleted file mode 100644 index db34ac09..00000000 --- a/dist/test/integration/db.test.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.initConnection = void 0; -const dbConfig_1 = require("../../src/configs/dbConfig"); -const initConnection = () => __awaiter(void 0, void 0, void 0, function* () { - yield dbConfig_1.dataSource - .initialize() - .then(() => { - console.log('Data Source has been initialized!'); - }) - .catch((err) => { - console.error('Error during Data Source initialization:', err); - throw new Error('Data Source initialization failed'); - }); -}); -exports.initConnection = initConnection; -describe('typeorm connection', () => { - it('should test typeorm connection', () => __awaiter(void 0, void 0, void 0, function* () { - yield expect((0, exports.initConnection)()).resolves.not.toThrow(); - })); -}); From 464aefe1f54a53fa06375cc8a22862077c3979dc Mon Sep 17 00:00:00 2001 From: anjula-sack Date: Sun, 6 Aug 2023 18:26:59 +0530 Subject: [PATCH 10/10] Add the service layer --- src/controllers/auth.controller.ts | 66 +++--------------------- src/controllers/profile.controller.ts | 63 ++++++---------------- src/routes/profile/profile.route.test.ts | 5 +- src/routes/profile/profile.route.ts | 9 ++-- src/services/auth.service.ts | 61 ++++++++++++++++++++++ src/services/profile.service.ts | 52 +++++++++++++++++++ 6 files changed, 147 insertions(+), 109 deletions(-) create mode 100644 src/services/auth.service.ts create mode 100644 src/services/profile.service.ts diff --git a/src/controllers/auth.controller.ts b/src/controllers/auth.controller.ts index 94027f84..c1256467 100644 --- a/src/controllers/auth.controller.ts +++ b/src/controllers/auth.controller.ts @@ -1,10 +1,7 @@ -import { dataSource } from '../configs/dbConfig' -import { type Request, type Response, type NextFunction } from 'express' -import jwt from 'jsonwebtoken' -import bcrypt from 'bcrypt' +import type { Request, Response, NextFunction } from 'express' +import { registerUser, loginUser } from '../services/auth.service' import passport from 'passport' -import Profile from '../entities/profile.entity' -import { JWT_SECRET } from '../configs/envConfig' +import type Profile from '../entities/profile.entity' export const register = async (req: Request, res: Response): Promise => { try { @@ -14,36 +11,8 @@ export const register = async (req: Request, res: Response): Promise => { res.status(400).json({ error: 'Email and password are required fields' }) } - const profileRepository = dataSource.getRepository(Profile) - - const existingProfile = await profileRepository.findOne({ - where: { primary_email: email } - }) - if (existingProfile != null) { - res.status(409).json({ error: 'Email already exists' }) - } - - const hashedPassword = await bcrypt.hash(password, 10) - const newProfile = profileRepository.create({ - primary_email: email, - password: hashedPassword, - contact_email: '', - first_name: '', - last_name: '', - image_url: '', - linkedin_url: '' - }) - await profileRepository.save(newProfile) - - res.status(201).json({ - uuid: newProfile.uuid, - primary_email: newProfile.primary_email, - contact_email: newProfile.contact_email, - first_name: newProfile.first_name, - last_name: newProfile.last_name, - image_url: newProfile.image_url, - linkedin_url: newProfile.linkedin_url - }) + const newUser = await registerUser(email, password) + res.status(201).json(newUser) } catch (err) { console.error('Error executing query', err) res.status(500).json({ error: 'Internal server error' }) @@ -52,33 +21,14 @@ export const register = async (req: Request, res: Response): Promise => { export const login = async (req: Request, res: Response): Promise => { try { - const { email, password }: { email: string; password: string } = req.body + const { email, password } = req.body if (!email || !password) { res.status(400).json({ error: 'Email and password are required fields' }) } - const profileRepository = dataSource.getRepository(Profile) - const profile = await profileRepository - .createQueryBuilder('profile') - .addSelect('profile.password') - .where({ primary_email: email }) - .getOne() - - if (profile == null) { - res.status(401).json({ error: 'Invalid email or password' }) - } - - const passwordMatch = await profile?.comparePassword(password) - - if (!passwordMatch) { - res.status(401).json({ error: 'Invalid email or password' }) - } - - const token = jwt.sign({ userId: profile?.uuid }, JWT_SECRET ?? '', { - expiresIn: '10h' // To-Do: Change value in production - }) - res.json({ token }) + const tokenData = await loginUser(email, password) + res.json(tokenData) } catch (err) { console.error('Error executing query', err) res.status(500).json({ error: 'Internal server error' }) diff --git a/src/controllers/profile.controller.ts b/src/controllers/profile.controller.ts index 8d95bd42..c77b69d6 100644 --- a/src/controllers/profile.controller.ts +++ b/src/controllers/profile.controller.ts @@ -1,69 +1,40 @@ -import { type Request, type Response } from 'express' -import { dataSource } from '../configs/dbConfig' -import Profile from '../entities/profile.entity' +import type { Request, Response } from 'express' +import { getProfile, updateProfile } from '../services/profile.service' -export const getProfile = async ( +export const getProfileHandler = async ( req: Request, res: Response ): Promise => { try { - res.status(200).json(req.user) + const user = await getProfile(req) + if (!user) { + res.status(404).json({ message: 'Profile not found' }) + } + + res.status(200).json(user) } catch (err) { console.error('Error executing query', err) res.status(500).json({ error: err }) } } -export const updateProfile = async ( +export const updateProfileHandler = async ( req: Request, res: Response ): Promise => { try { - const user: Profile | undefined = req.user as Profile - - const { - primary_email, - contact_email, - first_name, - last_name, - image_url, - linkedin_url - } = req.body - - const profileRepository = dataSource.getRepository(Profile) + const user = await getProfile(req) + if (!user) { + res.status(404).json({ message: 'Profile not found' }) + } - const updatedProfile = await profileRepository - .createQueryBuilder() - .update(Profile) - .set({ - primary_email, - contact_email, - first_name, - last_name, - image_url, - linkedin_url, - updated_at: new Date().toISOString() - }) - .where('uuid = :uuid', { uuid: user?.uuid }) - .returning([ - 'uuid', - 'primary_email', - 'contact_email', - 'first_name', - 'last_name', - 'image_url', - 'linkedin_url', - 'type', - 'created_at', - 'updated_at' - ]) - .execute() + const updatedProfile = user && (await updateProfile(user, req.body)) - if (updatedProfile.raw.length === 0) { + if (!updatedProfile) { res.status(404).json({ message: 'Profile not found' }) } - res.status(200).json(updatedProfile.raw[0]) + res.status(200).json(updatedProfile) } catch (err) { console.error('Error executing query', err) res.status(500).json({ error: err }) diff --git a/src/routes/profile/profile.route.test.ts b/src/routes/profile/profile.route.test.ts index 6845ba7e..12da6fa1 100644 --- a/src/routes/profile/profile.route.test.ts +++ b/src/routes/profile/profile.route.test.ts @@ -30,7 +30,7 @@ describe('profile', () => { }, 5000) describe('Get profile route', () => { - it('should return a 401 without a valid access token', async () => { + it('should return a 401 when a valid access token is not provided', async () => { await supertest(server).get('/api/me/profile').expect(401) }) @@ -50,6 +50,7 @@ describe('profile', () => { expect(response.body).toHaveProperty('linkedin_url') expect(response.body).toHaveProperty('type') expect(response.body).toHaveProperty('uuid') + expect(response.body).not.toHaveProperty('password') }) }) @@ -70,7 +71,7 @@ describe('profile', () => { .expect(200) }) - it('should return a 401 without a valid access token', async () => { + it('should return a 401 when a valid access token is not provided', async () => { await supertest(server).put('/api/me/profile').send({}).expect(401) }) diff --git a/src/routes/profile/profile.route.ts b/src/routes/profile/profile.route.ts index c2500673..f2742802 100644 --- a/src/routes/profile/profile.route.ts +++ b/src/routes/profile/profile.route.ts @@ -1,10 +1,13 @@ import express from 'express' -import { getProfile, updateProfile } from '../../controllers/profile.controller' +import { + getProfileHandler, + updateProfileHandler +} from '../../controllers/profile.controller' import { requireAuth } from '../../controllers/auth.controller' const profileRouter = express.Router() -profileRouter.get('/profile', requireAuth, getProfile); -profileRouter.put('/profile', requireAuth, updateProfile); +profileRouter.get('/profile', requireAuth, getProfileHandler) +profileRouter.put('/profile', requireAuth, updateProfileHandler) export default profileRouter diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts new file mode 100644 index 00000000..800be25a --- /dev/null +++ b/src/services/auth.service.ts @@ -0,0 +1,61 @@ +import { dataSource } from '../configs/dbConfig' +import bcrypt from 'bcrypt' +import jwt from 'jsonwebtoken' +import Profile from '../entities/profile.entity' +import { JWT_SECRET } from '../configs/envConfig' + +export const registerUser = async ( + email: string, + password: string +): Promise => { + const profileRepository = dataSource.getRepository(Profile) + + const existingProfile = await profileRepository.findOne({ + where: { primary_email: email } + }) + if (existingProfile != null) { + throw new Error('Email already exists') + } + + const hashedPassword = await bcrypt.hash(password, 10) + const newProfile = profileRepository.create({ + primary_email: email, + password: hashedPassword, + contact_email: '', + first_name: '', + last_name: '', + image_url: '', + linkedin_url: '' + }) + await profileRepository.save(newProfile) + + return newProfile +} + +export const loginUser = async ( + email: string, + password: string +): Promise<{ token: string }> => { + const profileRepository = dataSource.getRepository(Profile) + const profile = await profileRepository + .createQueryBuilder('profile') + .addSelect('profile.password') + .where({ primary_email: email }) + .getOne() + + if (!profile) { + throw new Error('Invalid email or password') + } + + const passwordMatch = await bcrypt.compare(password, profile.password) + + if (!passwordMatch) { + throw new Error('Invalid email or password') + } + + const token = jwt.sign({ userId: profile.uuid }, JWT_SECRET ?? '', { + expiresIn: '10h' // To-Do: Change value in production + }) + + return { token } +} diff --git a/src/services/profile.service.ts b/src/services/profile.service.ts new file mode 100644 index 00000000..aa442df6 --- /dev/null +++ b/src/services/profile.service.ts @@ -0,0 +1,52 @@ +import type { Request } from 'express' +import { dataSource } from '../configs/dbConfig' +import Profile from '../entities/profile.entity' + +export const getProfile = async ( + req: Request +): Promise => { + return req.user as Profile +} + +export const updateProfile = async ( + user: Profile, + { + primary_email, + contact_email, + first_name, + last_name, + image_url, + linkedin_url + }: Partial +): Promise => { + const profileRepository = dataSource.getRepository(Profile) + + const updatedProfile = await profileRepository + .createQueryBuilder() + .update(Profile) + .set({ + primary_email, + contact_email, + first_name, + last_name, + image_url, + linkedin_url, + updated_at: new Date().toISOString() + }) + .where('uuid = :uuid', { uuid: user?.uuid }) + .returning([ + 'uuid', + 'primary_email', + 'contact_email', + 'first_name', + 'last_name', + 'image_url', + 'linkedin_url', + 'type', + 'created_at', + 'updated_at' + ]) + .execute() + + return updatedProfile.raw.length === 0 ? undefined : updatedProfile.raw[0] +}