├── .eslintignore ├── mysql ├── sqls │ └── 01_create_database.sql └── conf │ └── my.conf ├── src ├── firebase │ ├── index.ts │ ├── initilize.ts │ └── middleware.ts ├── user │ ├── dto │ │ ├── index.ts │ │ └── create-user.ts │ ├── user.interface.ts │ ├── user.entity.ts │ ├── user.module.ts │ ├── user.service.spec.ts │ ├── user.controller.spec.ts │ ├── user.controller.ts │ └── user.service.ts ├── app.service.ts ├── main.ts ├── app.controller.ts ├── db │ └── migrations │ │ ├── 1560835282975-add_avatar_url.ts │ │ └── 1560832504985-Initialize.ts ├── app.controller.spec.ts ├── app.module.ts └── config │ └── TypeOrmNamingStrategy.js ├── .vscode └── settings.json ├── nest-cli.json ├── .prettierrc ├── tsconfig.build.json ├── nodemon.json ├── nodemon-debug.json ├── test ├── jest-e2e.json └── app.e2e-spec.ts ├── Dockerfile ├── tsconfig.json ├── .gitignore ├── ormconfig.js ├── docker-compose.sample.yml ├── .eslintrc.js ├── README.md └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/src/**/*.d.ts -------------------------------------------------------------------------------- /mysql/sqls/01_create_database.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE users; -------------------------------------------------------------------------------- /src/firebase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './middleware' 2 | -------------------------------------------------------------------------------- /src/user/dto/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-user' 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } 4 | -------------------------------------------------------------------------------- /nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "ts", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src" 5 | } 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "semi": false, 5 | "printWidth": 120 6 | } 7 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /src/user/user.interface.ts: -------------------------------------------------------------------------------- 1 | export interface User { 2 | id: string 3 | username: string 4 | age: number 5 | avatarUrl: string 6 | } 7 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src"], 3 | "ext": "ts", 4 | "ignore": ["src/**/*.spec.ts"], 5 | "exec": "ts-node -r tsconfig-paths/register src/main.ts" 6 | } 7 | -------------------------------------------------------------------------------- /src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common' 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!' 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /nodemon-debug.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src"], 3 | "ext": "ts", 4 | "ignore": ["src/**/*.spec.ts"], 5 | "exec": "node --inspect-brk -r ts-node/register -r tsconfig-paths/register src/main.ts" 6 | } 7 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core' 2 | import { AppModule } from './app.module' 3 | 4 | async function bootstrap() { 5 | const app = await NestFactory.create(AppModule) 6 | await app.listen(3000) 7 | } 8 | bootstrap() 9 | -------------------------------------------------------------------------------- /test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/user/dto/create-user.ts: -------------------------------------------------------------------------------- 1 | import { IsNotEmpty } from 'class-validator' 2 | 3 | export class CreateUserDto { 4 | @IsNotEmpty() 5 | readonly username: string 6 | @IsNotEmpty() 7 | readonly age: number 8 | @IsNotEmpty() 9 | readonly avatarUrl: string 10 | } 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG NODE_VERSION=12 2 | 3 | FROM node:${NODE_VERSION}-alpine AS builder 4 | 5 | RUN mkdir -p /api 6 | WORKDIR /api 7 | 8 | COPY package.json . 9 | RUN npm install 10 | 11 | COPY . . 12 | 13 | EXPOSE 3000 14 | 15 | # ENTRYPOINT [ "npm" ] 16 | CMD ["npm", "run", "start:dev"] -------------------------------------------------------------------------------- /mysql/conf/my.conf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | skip-character-set-client-handshake 3 | default-time-zone='+9:00' 4 | character-set-server = utf8mb4 5 | collation-server = utf8mb4_general_ci 6 | slow_query_log = 1 7 | slow_query_log_file = /var/log/slow_query.log 8 | long_query_time = 1 9 | [client] 10 | default-character-set = utf8mb4 11 | -------------------------------------------------------------------------------- /src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common' 2 | import { AppService } from './app.service' 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/user/user.entity.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column, PrimaryColumn } from 'typeorm' 2 | 3 | @Entity('user') 4 | export class UserEntity { 5 | @PrimaryColumn() 6 | id: string 7 | 8 | @Column('varchar') 9 | username: string 10 | 11 | @Column('int') 12 | age: number 13 | 14 | @Column('varchar') 15 | avatarUrl: string 16 | } 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "target": "es6", 9 | "sourceMap": true, 10 | "outDir": "./dist", 11 | "baseUrl": "./", 12 | "incremental": true 13 | }, 14 | "exclude": ["node_modules", "dist"] 15 | } 16 | -------------------------------------------------------------------------------- /src/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { UserController } from './user.controller' 3 | import { TypeOrmModule } from '@nestjs/typeorm' 4 | import { UserEntity } from './user.entity' 5 | import { UserService } from './user.service' 6 | 7 | @Module({ 8 | imports: [TypeOrmModule.forFeature([UserEntity])], 9 | providers: [UserService], 10 | controllers: [UserController], 11 | exports: [UserService], 12 | }) 13 | export class UserModule {} 14 | -------------------------------------------------------------------------------- /src/firebase/initilize.ts: -------------------------------------------------------------------------------- 1 | import * as admin from 'firebase-admin' 2 | 3 | export default admin.initializeApp({ 4 | credential: admin.credential.cert({ 5 | projectId: process.env.PROJECT_ID, 6 | privateKey: process.env.PRIVATE_KEY.replace(/\\n/g, '\n'), 7 | clientEmail: process.env.CLIENT_EMAIL, 8 | }), 9 | }) 10 | 11 | declare global { 12 | namespace Express { 13 | interface Request { 14 | firebaseUser: admin.auth.DecodedIdToken 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/db/migrations/1560835282975-add_avatar_url.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm' 2 | 3 | export class addAvatarUrl1560835282975 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.query('ALTER TABLE `user` ADD `avatar_url` varchar(255) NOT NULL') 6 | } 7 | 8 | public async down(queryRunner: QueryRunner): Promise { 9 | await queryRunner.query('ALTER TABLE `user` DROP COLUMN `avatar_url`') 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/user/user.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing' 2 | import { UserService } from './user.service' 3 | 4 | describe('UserService', () => { 5 | let service: UserService 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [UserService], 10 | }).compile() 11 | 12 | service = module.get(UserService) 13 | }) 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined() 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /src/user/user.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing' 2 | import { UserController } from './user.controller' 3 | 4 | describe('User Controller', () => { 5 | let controller: UserController 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | controllers: [UserController], 10 | }).compile() 11 | 12 | controller = module.get(UserController) 13 | }) 14 | 15 | it('should be defined', () => { 16 | expect(controller).toBeDefined() 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /src/db/migrations/1560832504985-Initialize.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm' 2 | 3 | export class Initialize1560832504985 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.query( 6 | 'CREATE TABLE `user` (`id` varchar(255) NOT NULL, `username` varchar(255) NOT NULL, `age` int NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB', 7 | ) 8 | } 9 | 10 | public async down(queryRunner: QueryRunner): Promise { 11 | await queryRunner.query('DROP TABLE `user`') 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | 36 | #mysql 37 | data 38 | 39 | ## secret 40 | serviceAccountKey.json 41 | docker-compose.yml -------------------------------------------------------------------------------- /ormconfig.js: -------------------------------------------------------------------------------- 1 | const TypeOrmNamingStrategy = require('./src/config/TypeOrmNamingStrategy.js') // これ! 2 | 3 | module.exports = { 4 | type: 'mysql', 5 | host: 'db', 6 | port: 3306, 7 | username: 'root', 8 | password: 'root', 9 | database: 'users', 10 | charset: 'utf8mb4', 11 | entities: ['src/**/*.entity{.ts,.js}'], 12 | synchronize: false, 13 | migrations: ['src/db/migrations/**/*.ts'], 14 | subscribers: ['src/db/subscribers/**/*.ts'], 15 | cli: { 16 | entitiesDir: ['src/**/'], 17 | migrationsDir: 'src/db/migrations', 18 | subscribersDir: 'src/db/subscribers', 19 | }, 20 | namingStrategy: new TypeOrmNamingStrategy(), 21 | } 22 | -------------------------------------------------------------------------------- /test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import * as request from 'supertest'; 3 | import { AppModule } from './../src/app.module'; 4 | 5 | describe('AppController (e2e)', () => { 6 | let app; 7 | 8 | beforeEach(async () => { 9 | const moduleFixture: TestingModule = await Test.createTestingModule({ 10 | imports: [AppModule], 11 | }).compile(); 12 | 13 | app = moduleFixture.createNestApplication(); 14 | await app.init(); 15 | }); 16 | 17 | it('/ (GET)', () => { 18 | return request(app.getHttpServer()) 19 | .get('/') 20 | .expect(200) 21 | .expect('Hello World!'); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/user/user.controller.ts: -------------------------------------------------------------------------------- 1 | import { Get, Post, Body, Controller, Req } from '@nestjs/common' 2 | import { UserService } from './user.service' 3 | import { CreateUserDto } from './dto' 4 | import { Request } from 'express' 5 | 6 | @Controller() 7 | export class UserController { 8 | constructor(private readonly userService: UserService) {} 9 | 10 | @Get('users') 11 | findAll() { 12 | return this.userService.findAll() 13 | } 14 | 15 | @Post('users') 16 | // eslint-disable-next-line nestjs/use-validation-pipe 17 | create(@Req() request: Request, @Body('user') userDto: CreateUserDto) { 18 | return this.userService.create(request.firebaseUser.uid, userDto) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docker-compose.sample.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | api: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | ports: 9 | - '3000:3000' 10 | volumes: 11 | - .:/api 12 | - /api/node_modules 13 | environment: 14 | PROJECT_ID: 15 | PRIVATE_KEY: 16 | CLIENT_EMAIL: 17 | 18 | depends_on: 19 | - db 20 | 21 | db: 22 | image: mysql:5.7.19 23 | container_name: nestAPI-mysql 24 | ports: 25 | - '3306:3306' 26 | volumes: 27 | - ./mysql/sqls:/docker-entrypoint-initdb.d 28 | - ./mysql/data:/var/lib/mysql 29 | - ./mysql/conf:/etc/mysql/conf.d 30 | environment: 31 | - MYSQL_ROOT_PASSWORD=root 32 | -------------------------------------------------------------------------------- /src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing' 2 | import { AppController } from './app.controller' 3 | import { AppService } from './app.service' 4 | 5 | describe('AppController', () => { 6 | let appController: AppController 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile() 13 | 14 | appController = app.get(AppController) 15 | }) 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.getHello()).toBe('Hello World!') 20 | }) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '@nestjs/common' 2 | import { AppController } from './app.controller' 3 | import { AppService } from './app.service' 4 | import { TypeOrmModule } from '@nestjs/typeorm' 5 | import { Connection } from 'typeorm' 6 | import { UserModule } from './user/user.module' 7 | import { FirebaseAuthMiddleware } from './firebase' 8 | 9 | @Module({ 10 | imports: [TypeOrmModule.forRoot(), UserModule], 11 | controllers: [AppController], 12 | providers: [AppService], 13 | }) 14 | export class AppModule implements NestModule { 15 | configure(consumer: MiddlewareConsumer) { 16 | consumer.apply(FirebaseAuthMiddleware).forRoutes({ path: '*', method: RequestMethod.ALL }) 17 | } 18 | constructor(private readonly connection: Connection) {} 19 | } 20 | -------------------------------------------------------------------------------- /src/firebase/middleware.ts: -------------------------------------------------------------------------------- 1 | import firebase from './initilize' 2 | import { Injectable, NestMiddleware, HttpStatus } from '@nestjs/common' 3 | import { HttpException } from '@nestjs/common/exceptions/http.exception' 4 | import { Request, Response } from 'express' 5 | 6 | @Injectable() 7 | export class FirebaseAuthMiddleware implements NestMiddleware { 8 | async use(req: Request, _: Response, next: Function) { 9 | const { authorization } = req.headers 10 | // Bearer ezawagawg..... 11 | const token = authorization.slice(7) 12 | 13 | const user = await firebase 14 | .auth() 15 | .verifyIdToken(token) 16 | .catch(err => { 17 | throw new HttpException({ message: 'Input data validation failed', err }, HttpStatus.UNAUTHORIZED) 18 | }) 19 | 20 | req.firebaseUser = user 21 | next() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | es6: true, 4 | node: true, 5 | jest: true, 6 | }, 7 | extends: ['eslint:recommended', 'plugin:prettier/recommended', 'plugin:nestjs/recommended'], 8 | globals: { 9 | Atomics: 'readonly', 10 | SharedArrayBuffer: 'readonly', 11 | }, 12 | parser: '@typescript-eslint/parser', 13 | parserOptions: { 14 | sourceType: 'module', 15 | project: './tsconfig.json', 16 | tsconfigRootDir: __dirname, 17 | ecmaFeatures: { 18 | tsx: true, 19 | }, 20 | }, 21 | plugins: ['@typescript-eslint', 'nestjs'], 22 | rules: { 23 | 'no-unused-vars': 'off', 24 | '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], 25 | 'no-console': ['error', { allow: ['info', 'error'] }], 26 | }, 27 | settings: { 28 | react: { 29 | version: 'detect', 30 | }, 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | _nestjs-with-firebase_ is backend API server built in nestjs and firebase authentication 4 | 5 | ## Installation 6 | 7 | ```bash 8 | $ npm install 9 | ``` 10 | 11 | ## Running the app in container 12 | 13 | ```bash 14 | #build 15 | $ docker-compose build 16 | 17 | # up with hot reload 18 | $ docker-compose up -d 19 | ``` 20 | 21 | ## Migration 22 | 23 | ```bash 24 | # generate migration 25 | $ docker-compose run --rm api sh -c 'npm run migrate:generate' 26 | 27 | # run migrate 28 | $ docker-compose run --rm api sh -c 'npm run migrate:run' 29 | ``` 30 | 31 | ## Running the app in local 32 | 33 | ```bash 34 | # development 35 | $ npm run start 36 | 37 | # watch mode 38 | $ npm run start:dev 39 | 40 | # production mode 41 | $ npm run start:prod 42 | ``` 43 | 44 | ## Test 45 | 46 | ```bash 47 | # unit tests 48 | $ npm run test 49 | 50 | # e2e tests 51 | $ npm run test:e2e 52 | 53 | # test coverage 54 | $ npm run test:cov 55 | ``` 56 | -------------------------------------------------------------------------------- /src/config/TypeOrmNamingStrategy.js: -------------------------------------------------------------------------------- 1 | var DefaultNamingStrategy = require('typeorm').DefaultNamingStrategy 2 | var snakeCase = require('typeorm/util/StringUtils').snakeCase 3 | var pluralize = require('pluralize') 4 | 5 | module.exports = class TypeOrmNamingStrategy extends DefaultNamingStrategy { 6 | tableName(className, customName) { 7 | return customName || pluralize(snakeCase(className)) 8 | } 9 | 10 | columnName(propertyName, customName, embeddedPrefixes) { 11 | return snakeCase(embeddedPrefixes.join('_')) + (customName || snakeCase(propertyName)) 12 | } 13 | 14 | relationName(propertyName) { 15 | return snakeCase(propertyName) 16 | } 17 | 18 | joinColumnName(relationName, referencedColumnName) { 19 | return snakeCase(pluralize.singular(relationName) + '_' + referencedColumnName) 20 | } 21 | 22 | joinTableName(firstTableName, secondTableName) { 23 | return snakeCase(firstTableName + '_' + secondTableName) 24 | } 25 | 26 | joinTableColumnName(tableName, propertyName, columnName) { 27 | return snakeCase(pluralize.singular(tableName) + '_' + (columnName || propertyName)) 28 | } 29 | 30 | classTableInheritanceParentColumnName(parentTableName, parentTableIdPropertyName) { 31 | return snakeCase(pluralize.singular(parentTableName) + '_' + parentTableIdPropertyName) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/user/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common' 2 | import { InjectRepository } from '@nestjs/typeorm' 3 | import { Repository, getRepository } from 'typeorm' 4 | import { validate } from 'class-validator' 5 | import { HttpException } from '@nestjs/common/exceptions/http.exception' 6 | import { HttpStatus } from '@nestjs/common' 7 | import { UserEntity } from './user.entity' 8 | import { CreateUserDto } from './dto' 9 | 10 | @Injectable() 11 | export class UserService { 12 | constructor( 13 | @InjectRepository(UserEntity) 14 | private readonly userRepository: Repository, 15 | ) {} 16 | 17 | findAll(): Promise { 18 | return this.userRepository.find() 19 | } 20 | 21 | async create(uid: string, dto: CreateUserDto): Promise { 22 | const { username, age, avatarUrl } = dto 23 | 24 | const qb = await getRepository(UserEntity) 25 | .createQueryBuilder('user') 26 | .where('user.id = :id', { id: uid }) 27 | .limit(1) 28 | 29 | const user = await qb.getOne() 30 | 31 | if (user) { 32 | const errorBody = { id: `user has already exist UserID ${uid}` } 33 | throw new HttpException({ message: 'Input data validation failed', errorBody }, HttpStatus.CONFLICT) 34 | } 35 | 36 | const newUser = new UserEntity() 37 | 38 | newUser.id = uid 39 | newUser.username = username 40 | newUser.age = age 41 | newUser.avatarUrl = avatarUrl 42 | 43 | const errors = await validate(newUser) 44 | if (errors.length > 0) { 45 | const errorBody = { username: 'Userinput is not valid.' } 46 | throw new HttpException({ message: 'Input data validation failed', errorBody }, HttpStatus.BAD_REQUEST) 47 | } else { 48 | await this.userRepository.save(newUser) 49 | return 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nest-api", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "", 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "tsc -p tsconfig.build.json", 9 | "format": "prettier --write \"src/**/*.ts\"", 10 | "start": "ts-node -r tsconfig-paths/register src/main.ts", 11 | "start:dev": "concurrently --handle-input \"wait-on dist/main.js && nodemon\" \"tsc -w -p tsconfig.build.json\" ", 12 | "start:debug": "nodemon --config nodemon-debug.json", 13 | "prestart:prod": "rimraf dist && npm run build", 14 | "start:prod": "node dist/main.js", 15 | "test": "jest", 16 | "test:watch": "jest --watch", 17 | "test:cov": "jest --coverage", 18 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 19 | "test:e2e": "jest --config ./test/jest-e2e.json", 20 | "lint": "eslint --fix -c ./.eslintrc.js 'src/**/*.ts'", 21 | "migrate:generate": "ts-node $(npm bin)/typeorm migration:generate -n", 22 | "migrate:run": "ts-node $(npm bin)/typeorm migration:run" 23 | }, 24 | "dependencies": { 25 | "@nestjs/common": "^6.0.0", 26 | "@nestjs/core": "^6.0.0", 27 | "@nestjs/platform-express": "^6.0.0", 28 | "@nestjs/typeorm": "^6.1.2", 29 | "class-validator": "^0.9.1", 30 | "firebase-admin": "^8.1.0", 31 | "mysql": "^2.17.1", 32 | "pluralize": "^8.0.0", 33 | "reflect-metadata": "^0.1.12", 34 | "rimraf": "^2.6.2", 35 | "rxjs": "^6.3.3", 36 | "typeorm": "^0.2.18" 37 | }, 38 | "devDependencies": { 39 | "@nestjs/testing": "^6.0.0", 40 | "@types/express": "^4.16.0", 41 | "@types/jest": "^23.3.13", 42 | "@types/node": "^10.12.18", 43 | "@types/supertest": "^2.0.7", 44 | "@typescript-eslint/eslint-plugin": "^1.10.2", 45 | "@typescript-eslint/parser": "^1.10.2", 46 | "concurrently": "^4.1.0", 47 | "eslint": "^5.16.0", 48 | "eslint-config-prettier": "^5.0.0", 49 | "eslint-plugin-nestjs": "^1.2.3", 50 | "eslint-plugin-prettier": "^3.1.0", 51 | "husky": "^2.4.1", 52 | "jest": "^23.6.0", 53 | "lint-staged": "^8.2.1", 54 | "nodemon": "^1.18.9", 55 | "pre-commit": "^1.2.2", 56 | "prettier": "^1.18.2", 57 | "supertest": "^3.4.1", 58 | "ts-jest": "24.0.2", 59 | "ts-node": "8.1.0", 60 | "tsconfig-paths": "3.8.0", 61 | "typescript": "3.4.3", 62 | "wait-on": "^3.2.0" 63 | }, 64 | "husky": { 65 | "hooks": { 66 | "pre-commit": "lint-staged" 67 | } 68 | }, 69 | "lint-staged": { 70 | "*.ts": [ 71 | "eslint --fix -c ./.eslintrc.js 'src/**/*.ts'", 72 | "git add" 73 | ] 74 | }, 75 | "jest": { 76 | "moduleFileExtensions": [ 77 | "js", 78 | "json", 79 | "ts" 80 | ], 81 | "rootDir": "src", 82 | "testRegex": ".spec.ts$", 83 | "transform": { 84 | "^.+\\.(t|j)s$": "ts-jest" 85 | }, 86 | "coverageDirectory": "../coverage", 87 | "testEnvironment": "node" 88 | } 89 | } 90 | --------------------------------------------------------------------------------