init push

main
Josh 2 years ago
parent b555d4e4c9
commit 791a14e482

@ -0,0 +1,24 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};

109
.gitignore vendored

@ -0,0 +1,109 @@
# ---> Node
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test

@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "all"
}

@ -0,0 +1 @@
web: npm run start

@ -1,2 +1 @@
# scb-rtgs-api # appliq-ms-organization

@ -0,0 +1,19 @@
server:
port: 3100
db:
type: 'postgres'
port: '5434'
sid: 'appliq-dummy'
jwt:
expiresIn: 3600
otp:
expiresIn: 5
crypto:
accessToken: 'accessToken@#123'
refreshToken: 'refreshToken@#123'
commonKey: 'APPLIQ'

@ -0,0 +1,9 @@
db:
host: '161.97.157.52'
username: 'postgres'
password: 'inv123'
sid: 'appliq-dummy'
synchronize: false
jwt:
secret: 'topSecret51'

@ -0,0 +1,12 @@
[
{
"VAN": "KGZASCB",
"tag": "scb-dev",
"host": "111.92.84.50",
"username": "corepacs",
"password": "corepacs",
"sid": "pacs",
"port":1521,
"bankName":"KANGAZHA_SCB"
}
]

@ -0,0 +1,4 @@
{
"collection": "@nestjs/schematics",
"sourceRoot": "src"
}

23599
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,83 @@
{
"name": "appliq-community-api",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.543.0",
"@aws-sdk/credential-providers": "^3.540.0",
"@nestjs/axios": "^3.0.0",
"@nestjs/common": "^9.4.3",
"@nestjs/config": "^3.2.2",
"@nestjs/core": "^9.4.3",
"@nestjs/jwt": "^10.0.3",
"@nestjs/passport": "^9.0.3",
"@nestjs/platform-express": "^9.4.3",
"@nestjs/typeorm": "^9.0.1",
"@types/passport-jwt": "^3.0.8",
"config": "^3.3.9",
"npm": "^9.8.1",
"oracledb": "^5.1.0",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0",
"typeorm": "^0.3.16"
},
"devDependencies": {
"@nestjs/cli": "^9.5.0",
"@nestjs/schematics": "^9.2.0",
"@nestjs/testing": "^9.4.3",
"@types/crypto-js": "^4.1.1",
"@types/express": "^4.17.13",
"@types/jest": "28.1.8",
"@types/node": "^16.0.0",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "28.1.3",
"prettier": "^2.3.2",
"source-map-support": "^0.5.20",
"supertest": "^6.1.3",
"ts-jest": "28.0.8",
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"tsconfig-paths": "4.1.0",
"typescript": "^4.7.4"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}

@ -0,0 +1,21 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './auth/auth.module';
import { DataSource } from 'typeorm';
import { RtgsModule } from './tables/rtgs/rtgs.module';
import getTypeOrmConfig from './config/typeorm.config';
@Module({
imports: [
// TypeOrmModule.forRootAsync({
// useFactory: async () => await getTypeOrmConfig(),
// }),
AuthModule,
RtgsModule,
],
controllers: [],
providers: [],
})
export class AppModule {
constructor() {}
}

@ -0,0 +1,10 @@
import { Controller, Get, UseGuards } from "@nestjs/common";
import { GetUser } from "./dto/get-user.decorator";
import { PcduserDto } from "./dto/pcd-user.dto";
import { AuthGuard } from "@nestjs/passport";
import { AuthService } from "./auth.service";
@Controller('auth')
export class AuthController {
}

@ -0,0 +1,18 @@
import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import * as config from 'config';
import { PassportModule } from '@nestjs/passport';
const jwtConfig = config.get('jwt');
@Module({
imports: [],
controllers: [AuthController],
providers: [
AuthService
],
exports: [],
})
export class AuthModule { }

@ -0,0 +1,4 @@
export class AuthService {
constructor() { }
}

@ -0,0 +1,15 @@
export class AuthCreadentialsDto {
username: string;
password: string;
module?: string;
custId: string;
email: string;
secuLevel: any;
}

@ -0,0 +1,10 @@
import { createParamDecorator, ExecutionContext } from "@nestjs/common";
export const GetUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);

@ -0,0 +1,25 @@
export class PcduserDto {
userId?: string;
pass?: string | null;
salt?: string | null;
secuLevel: string | null;
email: string;
refreshtoken?: string;
region: number;
image: string;
firstName: string;
lastName: string;
uuid: string;
}

@ -0,0 +1,19 @@
export class TokenDto {
userId : string
firstName? : string
lastName? : string
accessToken: string;
refreshToken: string;
emailId: string;
module: string;
changePassword?:string
secuLevel?:string
}

@ -0,0 +1,23 @@
import * as config1 from 'config'
import { DataSourceOptions } from "typeorm";
let dbConfig = config1.get('db');
async function getTypeOrmConfig(): Promise<DataSourceOptions> {
let typeormModule ={
type: dbConfig.type,
host: dbConfig.host,
port: dbConfig.port,
username: dbConfig.username,
password: dbConfig.password,
database: dbConfig.sid,
entities: [__dirname + '/../**/*.entity.{js,ts}'],
synchronize: false,
logging: false
}
return typeormModule
}
export default getTypeOrmConfig;

@ -0,0 +1,17 @@
export class rtgsDto {
clientCode: string
VAN: string
vCode: string
bankUTR: string
modeofTXN: string
amount: number
corpTXNID: string
corptxnStatus: string
statusCode: string
statusMessage: string
remitterName: string
remitterAccountnumber: string
remitterIFSC: string
date: Date
sendertoReceiverInformation: string
}

@ -0,0 +1,63 @@
import { Body, DefaultValuePipe, Delete, Get, Logger, Param, ParseIntPipe, Post, Put, Query, UsePipes, ValidationPipe } from "@nestjs/common";
import { GetUser } from "src/auth/dto/get-user.decorator";
import { PcduserDto } from "src/auth/dto/pcd-user.dto";
import { FindManyOptions } from "typeorm";
import { PcdFormGridService } from "./pcd-form-grid.service";
import { AuthGuard } from "@nestjs/passport";
import { AuthModule } from "src/auth/auth.module";
export class PcdFormGridController<T>{
private logger = new Logger('PcdFormGridController'); // for logging
constructor(
private service: PcdFormGridService<T>
) {
}
@Get()
async findAll(
@Query() filter: FindManyOptions,
@GetUser() user: PcduserDto
): Promise<any[]> {
return await this.service.findAll(filter, user);
}
@Get('/:id')
async getOne(
@Query() filterDto: FindManyOptions,
@Param('id') id: string,
@GetUser() user: PcduserDto,
): Promise<any> {
return await this.service.findOne(filterDto, id, user);
}
@UsePipes(ValidationPipe)
@Post()
async createOne(
@Body() body: T,
@GetUser() user: PcduserDto
): Promise<any> {
return await this.service.createOne(body, user);
}
@Put('/:id')
async updateOne(
@Body(ValidationPipe) body: any,
@Param('id') id: number,
@GetUser() user: PcduserDto
) {
return await this.service.updateOne(body, id, user);
}
@Delete('/:id')
async deleteOne(
@Query() filter: FindManyOptions,
@Param('id') id: string,
@GetUser() user: PcduserDto,
): Promise<any> {
return await this.service.deleteOne(filter, id, user);
}
}

@ -0,0 +1,285 @@
import { BadRequestException, ConflictException, HttpException, InternalServerErrorException, NotAcceptableException } from '@nestjs/common';
import { PcduserDto } from 'src/auth/dto/pcd-user.dto';
import { FindManyOptions, Not, Repository } from 'typeorm';
import { PcdFormGridInterface } from '../interface/pcd-form-grid.interface';
import * as config from 'config'
import { log } from 'console';
const dbConfig = config.get('db');
export class PcdFormGridService<T> implements PcdFormGridInterface {
MAIN_KEY: string = 'id';
CUSTID: string = '';
MANDATORY_FEILDS: string[] = [];
DUPLICATE_CHK: string[] = [];
FK_FEILDS: { column: string, relation: Repository<any> }[] = [];
ROW_COUNT: string = '';
constructor(
private repo: Repository<any>
) { }
async preFindAll(filter: FindManyOptions, user: PcduserDto): Promise<boolean> {
return true;
}
async findAll(filter: FindManyOptions, user: PcduserDto): Promise<any[]> {
if (!filter.where) filter.where = {};
if (!await this.preFindAll(filter, user))
throw new BadRequestException(`Unepected Error Occured in findAll`);
// console.log("====1==== filter===", filter);
const result = await this.repo.find(filter);
// console.log("====2==== result===", result);
return await this.postFindAll(filter, user, result);
}
async postFindAll(filter: FindManyOptions, user: PcduserDto, result: T[]): Promise<T[]> {
return result;
}
async preFindOne(filter: FindManyOptions, id: string | number, user: PcduserDto): Promise<boolean> {
return true;
}
async findOne(filter: FindManyOptions, id: string | number, user: PcduserDto): Promise<any> {
if (!filter.where) filter.where = {};
filter.where[this.MAIN_KEY] = id;
if (!await this.preFindOne(filter, id, user))
throw new BadRequestException(`Unepected Error Occured in findAll`);
const result = await this.repo.findOne(filter);
return await this.postFindOne(filter, id, user, result);
}
async postFindOne(filter: FindManyOptions, id: string | number, user: PcduserDto, result: T): Promise<T> {
return result;
}
async preCreateOne(body: T, user: PcduserDto): Promise<boolean> {
return true;
}
async createOne(body: any, user: PcduserDto): Promise<any> {
for (let colMan of this.MANDATORY_FEILDS) {
if (!body[colMan] || body[colMan].toString().trim() == "") {
throw new BadRequestException(`${colMan} field Cannot be Blank`);
}
}
console.log("==this.DUPLICATE_CHK===", this.DUPLICATE_CHK);
for (let dupCol of this.DUPLICATE_CHK) {
const dupfilter = { where: {} };
// if (!dupCol.isSl || (user.coCodeD.secondryLangauge && user.coCodeD.multiLanguageYn == 'Y' && dupCol.isSl)) {
// if (dupCol && isArray(dupCol) && dupCol.column.length > 0) {
// dupCol.forEach(element => {
// console.log("===element====", element);
dupfilter.where[dupCol] = body[dupCol];
// })
// }
// else
// dupfilter.where[dupCol.column] = body[dupCol.column];
// }
// else
// continue;
console.log("===dupRec filter====", dupfilter);
let dupRec = await this.repo.findOne(dupfilter);
if (dupRec)
throw new BadRequestException(`Duplication not allowed for ${dupCol}`);
}
console.log("==user.userId==", user);
if (user ) {
body["createdBy"] = user.userId;
body["modifiedBy"] = user.userId;
// body[this.CUSTID] = user.custId;
}
if (!await this.preCreateOne(body, user))
throw new BadRequestException(`Unexpected Error Occured in create`);
for (let eagerCol of await this.getEagerColumns()) {
delete body[eagerCol];
}
try {
await this.repo.save(body);
const filter: FindManyOptions = await this.getFilterWithPrimaryKey(body);
const result = await this.findOne(filter, body[this.MAIN_KEY], user);
return await this.postCreateOne(body, user, result);
} catch (err) {
console.log("==err==", err);
throw new InternalServerErrorException(err);
}
}
async postCreateOne(body: T, user: PcduserDto, result: T): Promise<T> {
return result;
}
async preUpdateOne(body: T, id: string | number, user: PcduserDto): Promise<boolean> {
return true;
}
async updateOne(body: any, id: string | number, user: PcduserDto): Promise<any> {
console.log("====user====", user);
console.log(id);
console.log(body);
for (let colMan of this.MANDATORY_FEILDS) {
if (!body[colMan] || body[colMan].toString().trim() == "") {
throw new BadRequestException(`${colMan} field Cannot be Blank`);
}
}
for (let dupCol of this.DUPLICATE_CHK) {
const dupfilter = { where: {} };
dupfilter.where[this.MAIN_KEY] = Not(body[this.MAIN_KEY]);
// if (!dupCol.isSl || (user.coCodeD.secondryLangauge && user.coCodeD.multiLanguageYn == 'Y' && dupCol.isSl)) {
// if (dupCol.column && isArray(dupCol.column) && dupCol.column.length > 0) {
// dupCol.column.forEach(element => {
// dupfilter.where[element] = body[element];
// })
// }
// else
dupfilter.where[dupCol] = body[dupCol];
// }
// else
// continue;
let dupRec = await this.repo.findOne(dupfilter);
if (dupRec)
throw new BadRequestException(`Duplication not allowed for ${dupCol}`);
}
const filter: FindManyOptions = await this.getFilterWithPrimaryKey(body);
const updateRow = await this.getOne(filter, body[this.MAIN_KEY], user);
console.log("====updateRow====", updateRow);
for (let eagerCol of await this.getEagerColumns()) {
delete body[eagerCol];
}
// updateRow["coCode"] = user.coCode;
const COLUMNS = await this.getAllColumns();
const PRIMARY_KEYS = await this.getPrimaryKeys();
COLUMNS.forEach((row) => {
if (!PRIMARY_KEYS.includes(row))
updateRow[row] = body[row];
});
console.log("====update row 1 ====", updateRow);
await this.repo.save(updateRow);
// const filter: FindManyOptions = await this.getFilterWithPrimaryKey(body);
const result = await this.findOne(filter, body[this.MAIN_KEY], user);
return await this.postUpdateOne(body, id, user, result);
}
async postUpdateOne(body: T, id: string | number, user: PcduserDto, result: T): Promise<T> {
return result;
}
async preDeleteOne(filter: FindManyOptions, id: string | number, user: PcduserDto): Promise<boolean> {
for (let fkRel of this.FK_FEILDS) {
const fkFilter = { where: {} };
fkFilter.where[fkRel.column] = id;
const result = await fkRel.relation.findOne(fkFilter);
if (result)
throw new ConflictException(`Can't delete Record. Detail Records Exists.`);
}
return true;
}
async deleteOne(filter: FindManyOptions, id: string | number, user: PcduserDto): Promise<any> {
if (!filter.where) filter.where = {};
filter.where[this.MAIN_KEY] = id;
// if (this.CUSTID)
// filter.where[this.CUSTID] = user.custId;
if (!await this.preDeleteOne(filter, id, user))
throw new BadRequestException(`Unexpected Error Occured in delete`);
const delFilter = await this.getDeleteFilter(filter);
if (!delFilter[this.MAIN_KEY])
throw new NotAcceptableException(`Please select a data to delete`);
try {
const result = await this.repo.delete(delFilter);
return await this.postDeleteOne(filter, id, user, result);
} catch (err) {
if (err.status) throw new HttpException(err.message, err.status);
throw new InternalServerErrorException(`${err.message}`);
}
}
async postDeleteOne(filter: FindManyOptions, id: string | number, user: PcduserDto, result: any): Promise<any> {
return result;
}
async getDeleteFilter(whereFilter: FindManyOptions): Promise<any> {
const filter: FindManyOptions = {};
const PRIMARY_KEYS = await this.getPrimaryKeys();
await PRIMARY_KEYS.forEach((column) => {
filter[column] = whereFilter.where[column];
});
return filter;
}
async getOne(filter: FindManyOptions, id: string | number, user: PcduserDto): Promise<any> {
if (!filter.where) filter.where = {};
// if (this.CUSTID)
// filter.where[this.CUSTID] = user.custId;
filter.where[this.MAIN_KEY] = id;
const result = await this.repo.findOne(filter);
return result;
}
async getAllColumns(): Promise<string[]> {
const COLUMNS: string[] = [];
for (let columnProperty in this.repo.metadata.propertiesMap) {
COLUMNS.push(this.repo.metadata.propertiesMap[columnProperty]);
}
// in the below method it will not take the forignKey columns Like modelD etc..
// await this.repo.metadata.columns.forEach((row) => {
// COLUMNS.push(row.propertyName);
// });
return COLUMNS;
}
async getPrimaryKeys(): Promise<string[]> {
const PRIMARY_KEYS: string[] = [];
await this.repo.metadata.primaryColumns.forEach((row) => {
PRIMARY_KEYS.push(row.propertyName);
});
return PRIMARY_KEYS;
}
async getFilterWithPrimaryKey(body: T): Promise<FindManyOptions> {
const filter: FindManyOptions = { where: {} };
const PRIMARY_KEYS = await this.getPrimaryKeys();
await PRIMARY_KEYS.forEach((column) => {
filter.where[column] = body[column];
});
return filter;
}
async getEagerColumns(): Promise<string[]> {
/*
For getting Eager true columns having Many to One relations.
We need to remove the eager columns before insertions or updations or it will not allow to save data (But save message will show, but data not updated)
*/
const COLUMNS: string[] = [];
for (let columnProperty of this.repo.metadata.eagerRelations) {
COLUMNS.push(columnProperty.propertyName);
}
return COLUMNS;
}
}

@ -0,0 +1,42 @@
import { Logger, Get, Query, Delete, Post, Body, Param, UseGuards } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
import { AuthModule } from "src/auth/auth.module";
import { FindManyOptions } from "typeorm";
import { PcdTransactionService } from "./pcd-transaction.service";
import { GetUser } from "src/auth/dto/get-user.decorator";
import { PcduserDto } from "src/auth/dto/pcd-user.dto";
export class PcdTransactionController<T> {
private logger = new Logger('PcdTransactionController'); // for logging
constructor(
private service: PcdTransactionService<T>
) { }
@Get()
async findList(@Query() filter: FindManyOptions,
@GetUser() user: PcduserDto
): Promise<T[]> {
return await this.service.findList(filter, user);
}
@Get('/:id')
async findOne(@Query() filter: FindManyOptions, @Param('id') id: string,): Promise<T> {
return await this.service.findOne(filter, id);
}
@UseGuards(AuthGuard())
@Post()
async createOne(@Body() body: T,
@GetUser() user: PcduserDto): Promise<T> {
return await this.service.createOne(body, user);
}
@UseGuards(AuthGuard())
@Delete('/:id')
async delete(@Query() filter: FindManyOptions, @Param('id') id: string, @GetUser() user: PcduserDto): Promise<any> {
return await this.service.deleteOne(filter, id, user);
}
}

@ -0,0 +1,357 @@
import { PcdtTransactionInterface } from "../interface/pcd-transaction.interface";
import { FindManyOptions, Repository, QueryRunner, DataSource } from "typeorm";
import { BadRequestException, NotAcceptableException, InternalServerErrorException, MethodNotAllowedException, HttpException, Inject } from "@nestjs/common";
import { TransactionDetailDto } from "src/framework/custom/transaction-detail.dto";
import { PcduserDto } from "src/auth/dto/pcd-user.dto";
//import { TENANT_CONNECTION } from "src/tenant/tenant.module";
// import { IintDto } from "../../dto/iint.dto";
// import { IintvrnoDto } from "../../dto/iintvrno.dto";
// import { IintService } from "../../tables/iint/iint.service";
export class PcdTransactionService<T> implements PcdtTransactionInterface {
MAIN_KEY: string = "id";
TXN_TYPE: string = "";
DETAIL_DATA_FORMAT: TransactionDetailDto[] = [];
constructor(
private connection: DataSource,
private repo: Repository<any>
) { }
async preFindList(filter: FindManyOptions, user: PcduserDto): Promise<boolean> {
return true
}
async findList(filter: FindManyOptions, user: PcduserDto): Promise<T[]> {
if (!filter.where) filter.where = {};
if (this.TXN_TYPE) filter.where[this.DETAIL_DATA_FORMAT[0].transactionTypeColumnName] = this.TXN_TYPE;
// if (!filter.where[this.DETAIL_DATA_FORMAT[0].transactionTypeColumnName])
// return;
if (!await this.preFindList(filter, user))
throw new BadRequestException(`Unexpected Error Occured in findList`);
console.log(filter , this.TXN_TYPE);
let result: T[] = await this.repo.find(filter);
return await this.postFindList(filter, result);
}
async postFindList(filter: FindManyOptions, result: T[]): Promise<T[]> {
return result;
}
async preFindOne(filter: FindManyOptions,): Promise<boolean> {
return true
}
async findOne(filter: FindManyOptions, id: string | number,): Promise<T> {
if (!filter.where) filter.where = {};
if (this.TXN_TYPE) filter.where[this.DETAIL_DATA_FORMAT[0].transactionTypeColumnName] = this.TXN_TYPE;
let orgFilter = Object.create(filter);
filter.where[this.MAIN_KEY] = id;
if (!await this.preFindOne(filter))
throw new BadRequestException(`Unepected Error Occured in findOne`);
//branch right check();
let result: T = await this.repo.findOne(filter);
if (!result)
return result;
result = await this.getDetailData(result, orgFilter, this.DETAIL_DATA_FORMAT);
return await this.postFindOne(filter, result);
}
async postFindOne(filter: FindManyOptions, result: T): Promise<T> {
return result;
}
async preDeleteOne(filter: FindManyOptions, id: string | number,user): Promise<boolean> {
return true;
}
async deleteOne(filter: any, id: string | number,user): Promise<any> {
if (!filter || !filter.where) filter.where = {};
if (this.TXN_TYPE) filter.where[this.DETAIL_DATA_FORMAT[0].transactionTypeColumnName] = this.TXN_TYPE;
filter.where[this.MAIN_KEY] = id;
const delFilter = await this.getDeleteFilter(filter);
if (!delFilter[this.MAIN_KEY])
throw new NotAcceptableException(`Please select a record`);
if (!await this.preDeleteOne(filter, id,user))
throw new BadRequestException(`Unepected Error Occured in deleteOne`);
const queryRunner = this.connection.createQueryRunner();
await queryRunner.connect();
try {
await queryRunner.startTransaction();
await this.deleteDetailDataTabels(id, this.DETAIL_DATA_FORMAT, queryRunner);
const result = await queryRunner.manager.delete(this.repo.metadata.name, id);
await queryRunner.commitTransaction();
return await this.postDeleteOne(filter, result);
} catch (err) {
if (queryRunner.isTransactionActive)
await queryRunner.rollbackTransaction();
throw new InternalServerErrorException(`${err.message}`);
} finally {
await queryRunner.release();
}
// const result = await this.repo.delete(delFilter);
}
async postDeleteOne(filter: FindManyOptions, result: any): Promise<any> {
return result;
}
async preCreateOne(user,body: T,): Promise<boolean> {
return true;
}
async beforeCreateOne(body: T, queryRunner: QueryRunner): Promise<boolean> {
return true;
}
async createOne(body: T, user: PcduserDto): Promise<T> {
//console.log('--- incoming = ', body);
if (this.TXN_TYPE) body[this.DETAIL_DATA_FORMAT[0].transactionTypeColumnName] = this.TXN_TYPE;
if (!await this.preCreateOne(user,body))
throw new BadRequestException(`Unexpected Error Occured in CreateOne`);
for (let eagerCol of await this.getEagerColumns()) {
delete body[eagerCol];
}
const queryRunner = this.connection.createQueryRunner();
await queryRunner.connect();
try {
await queryRunner.startTransaction();
if (this.TXN_TYPE) body[this.DETAIL_DATA_FORMAT[0].transactionTypeColumnName] = this.TXN_TYPE;
// await this.checkAndSetVrNo(body, user, queryRunner);
// for deleting deleted details from the angular
for (let row of this.DETAIL_DATA_FORMAT) {
body[row.detailName] = await this.deleteDetailData(body[row.detailName], row, queryRunner);
}
body["createdBy"] = 'SYSTEM';
body["modifiedBy"] = 'SYSTEM';
if (!await this.beforeCreateOne(body, queryRunner))
throw new BadRequestException(`Unepected Error Occured in CreateOne`);
const data = await queryRunner.manager.save(this.repo.metadata.name, body);
await this.insertDetailData(body, this.DETAIL_DATA_FORMAT, queryRunner, data);
await this.afterCreateOne(body);
await queryRunner.commitTransaction();
const filter: FindManyOptions = await this.getFilterWithPrimaryKey(body);
const result = await this.findOne(filter, data[this.MAIN_KEY]);
return await this.postCreateOne(user , body, result);
} catch (err) {
// since we have errors lets rollback changes we made
console.log('--- err --', err);
console.log('QueryFailedError', err.QueryFailedError);
console.log('*******err name*****', err.name);
console.log('-- message------', err.message);
console.log('-- code------', err.code);
console.log('--- err.status --', err.status);
console.log("===is active===", queryRunner.isTransactionActive);
if (queryRunner.isTransactionActive)
await queryRunner.rollbackTransaction();
console.log("heree===afterrollback");
if (err.status && err.status == '401') throw new MethodNotAllowedException(`${err.message.message}`);
if (!(err.name == "QueryFailedError")) if (queryRunner.isTransactionActive) await queryRunner.rollbackTransaction();
//console.log("====after rollback====");
if (err.name == "QueryFailedError") {
if (err.precedingErrors && err.precedingErrors.length > 0 && err.precedingErrors[0].originalError)
throw new BadRequestException(`${err.precedingErrors[0].originalError}`);
if (err.originalError)
throw new BadRequestException(`${err.originalError}`);
}
if (err.status && err.status == 500) throw new HttpException(err.message.error, err.message.statusCode);
if (err.status) throw new HttpException(err.message, err.status);
throw new InternalServerErrorException(`${err.message}`);
}
finally {
console.log('--- finally --- ');
await queryRunner.release();
}
}
async afterCreateOne(body: T): Promise<void> {
}
async postCreateOne(user , body: T, result: T): Promise<T> {
return result;
}
async insertDetailData(body: T, detailData: TransactionDetailDto[], queryRunner: QueryRunner, insertedData: T): Promise<void> {
for (let row of detailData) {
await this.insertDetailData2ndLevel(body[row.detailName], row, queryRunner, insertedData, insertedData);
}
}
async deleteDetailDataTabels(id: string | number, detailDataFormat: TransactionDetailDto[], queryRunner: QueryRunner): Promise<any> {
for (let row of detailDataFormat) {
await this.deleteDetailTableData(id, row, queryRunner);
}
}
async deleteDetailTableData(id: string | number, detailData: TransactionDetailDto, queryRunner: QueryRunner): Promise<any> {
if (detailData.childDetail && detailData.childDetail.length > 0) {
for (let child of detailData.childDetail) {
await this.deleteDetailTableData(id, child, queryRunner);
}
}
if (id) {
let filter = {};
if (detailData.foreignKeyColumnName) {
filter[detailData.foreignKeyColumnName] = id;
} else {
filter[detailData.foreignKeyAssignmentColumnName.columnName] = id;
}
await queryRunner.manager.delete(detailData.repo.metadata.name, filter);
}
}
async deleteDetailData(body: T[], detailData: TransactionDetailDto, queryRunner: QueryRunner): Promise<T[]> {
if (detailData.childDetail && detailData.childDetail.length > 0) {
for (let child of detailData.childDetail) {
if (body && body.length > 0) {
for (let row of body) {
if (row["crud"] == "D") {
for (let detData of row[child.detailName]) {
detData["crud"] = "D";
}
}
row[child.detailName] = await this.deleteDetailData(row[child.detailName], child, queryRunner);
}
}
}
}
if (body) {
await queryRunner.manager.remove(detailData.repo.metadata.name, body.filter((row: any) => row.crud == 'D'));
body = body.filter((row: any) => row["crud"] != 'D');
return body;
} else {
return [];
}
}
async insertDetailData2ndLevel(body: T[], detailData: TransactionDetailDto, queryRunner: QueryRunner, headerData: T, detailHeaderData: T): Promise<void> {
let deatilInsResult: any;
let eagerCols: any = await this.getEagerColumns(detailData.repo);
if (body) {
for (let row of body) {
for (let col of eagerCols) {
delete row[col];
}
if (this.TXN_TYPE) row[this.DETAIL_DATA_FORMAT[0].transactionTypeColumnName] = this.TXN_TYPE;
if (detailData.foreignKeyColumnName) {
row[detailData.foreignKeyColumnName] = headerData[this.MAIN_KEY];
} else {
row[detailData.foreignKeyAssignmentColumnName.columnName]
= detailHeaderData[detailData.foreignKeyAssignmentColumnName.headerColumn];
}
row["createdBy"] = 'SYSTEM';
row["modifiedBy"] = 'SYSTEM';
if (detailData.addtionalSettingOfRowsInInsertion && detailData.addtionalSettingOfRowsInInsertion.length > 0) {
for (let addRow of detailData.addtionalSettingOfRowsInInsertion) {
row[addRow.columnName] = detailHeaderData[addRow.headerColumn];
}
}
deatilInsResult = await queryRunner.manager.save(detailData.repo.metadata.name, row);
if (detailData.childDetail && detailData.childDetail.length > 0) {
for (let child of detailData.childDetail) {
if (body && body.length > 0) {
await this.insertDetailData2ndLevel(row[child.detailName], child, queryRunner, headerData, deatilInsResult);
}
}
}
}
}
}
async getDetailData(result: any, filter: FindManyOptions, detailData: TransactionDetailDto[]): Promise<any> {
for (let row of detailData) {
result[row.detailName] = [];
let filterDetail: FindManyOptions = Object.assign({}, filter);
if (!filterDetail.where) filterDetail.where = {};
for (let filterRow of row.filter) {
filterDetail.where[filterRow.columnName] = filterRow.headerColumn ? result[filterRow.headerColumn] : filterRow.value;
};
if (row.orderByColumn) {
if (!filterDetail.order) filterDetail["order"] = {};
filterDetail.order[row.orderByColumn.columnName] = row.orderByColumn.sort;
}
result[row.detailName] = await row.repo.find(filterDetail);
if (row.childDetail && row.childDetail.length > 0) {
for (let detailRows of result[row.detailName])
detailRows = await this.getDetailData(detailRows, filter, row.childDetail);
}
};
return result;
}
/*-- To get the filter using primary key --*/
async getFilterWithPrimaryKey(body: T): Promise<FindManyOptions> {
const filter: FindManyOptions = { where: {} };
const PRIMARY_KEYS = await this.getPrimaryKeys();
await PRIMARY_KEYS.forEach((column) => {
filter.where[column] = body[column];
});
return filter;
}
/*-- To get the filter for delete --*/
async getDeleteFilter(whereFilter: FindManyOptions): Promise<any> {
const filter: FindManyOptions = {};
const PRIMARY_KEYS = await this.getPrimaryKeys();
await PRIMARY_KEYS.forEach((column) => {
filter[column] = whereFilter.where[column];
});
return filter;
}
/*-- To get the Primary Keys of the entity --*/
async getPrimaryKeys(): Promise<string[]> {
const PRIMARY_KEYS: string[] = [];
await this.repo.metadata.primaryColumns.forEach((row) => {
PRIMARY_KEYS.push(row.propertyName);
});
return PRIMARY_KEYS;
}
async getEagerColumns(repoDetail?: any): Promise<string[]> {
/*
For getting Eager true columns having Many to One relations.
We need to remove the eager columns before insertions or updations or it will not allow to save data (But save message will show, but data not updated)
*/
const COLUMNS: string[] = [];
for (let columnProperty of (repoDetail ? repoDetail.metadata.eagerRelations : this.repo.metadata.eagerRelations)) { //AJ
COLUMNS.push(columnProperty.propertyName);
}
return COLUMNS;
}
}

@ -0,0 +1,14 @@
export class PcdBaseDto {
createdBy: string;
createdDate: Date;
modifiedBy: string;
modifiedDate: Date;
versionNo: number;
sessionNo: number;
}

@ -0,0 +1,63 @@
import { CreateDateColumn, Column, UpdateDateColumn, VersionColumn, BaseEntity, Entity } from "typeorm";
export abstract class PcdBaseEntity extends BaseEntity {
@Column({
name: "created_by",
type: "varchar",
length: 12,
default:() => "'SYSTEM'",
})
createdBy: string;
// @Column({
// name: "created_country",
// type: "numeric",
// nullable: true
// })
// createdCountry: string;
@CreateDateColumn({
name: "created_date",
default:() => "CURRENT_TIMESTAMP",
})
createdDate: Date;
@Column({
name: "modified_by",
type: "varchar",
length: 12,
default:() => "'SYSTEM'",
})
modifiedBy: string;
// @Column({
// name: "modified_country",
// type: "numeric",
// nullable: true
// })
// modifiedCountry: string;
@UpdateDateColumn({
name: "modified_date",
default:() => "CURRENT_TIMESTAMP",
})
modifiedDate: Date;
@VersionColumn({
name: "version_no",
type: "number",
nullable: true
})
versionNo: number
@VersionColumn({
name: "session_no",
type: "number",
nullable: true
})
sessionNo: number
}

@ -0,0 +1,15 @@
import { BaseEntity, Column } from "typeorm";
export class PcdViewEntity extends BaseEntity {
@Column("string",{
name:"CREATED_BY"
})
createdBy:string;
@Column("date",{
name:"CREATED_DATE"
})
createdDate:Date;
}

@ -0,0 +1,23 @@
import { Repository } from "typeorm";
export class TransactionDetailDto {
detailName: string;
foreignKeyColumnName?: string;
foreignKeyAssignmentColumnName?: {columnName:string,headerColumn:string};
repo: Repository<any>;
filter: { columnName: string, value?: any, headerColumn?: string }[];
childDetail: TransactionDetailDto[];
addtionalSettingOfRowsInInsertion?: { columnName: string, value?: any, headerColumn?: string }[];
transactionTypeColumnName?:string;
orderByColumn?: {columnName : string, sort : "DESC" | "ASC" };
}

@ -0,0 +1,16 @@
import { FindManyOptions } from "typeorm";
import { PcduserDto } from "src/auth/dto/pcd-user.dto";
export interface PcdFormGridInterface {
findAll(filter: FindManyOptions, user: PcduserDto): Promise<any[]>;
findOne(filter: FindManyOptions, id: string | number, user: PcduserDto): Promise<any>;
createOne(body: any, user: PcduserDto): Promise<any>
updateOne(body: any, id: string | number, user: PcduserDto): Promise<any>;
deleteOne(filter: FindManyOptions, id: string | number, user: PcduserDto): Promise<any>;
}

@ -0,0 +1,8 @@
import { PcduserDto,} from "src/auth/dto/pcd-user.dto";
import { FindManyOptions } from "typeorm";
export interface PcdtTransactionInterface {
findList(filter: FindManyOptions, user: PcduserDto): Promise<any[]>;
}

@ -0,0 +1,20 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as config1 from 'config';
import { Logger } from '@nestjs/common';
import { urlencoded, json } from 'express';
async function bootstrap() {
const serverConfig = config1.get('server');
const logger = new Logger('bootstrap');
const app = await NestFactory.create(AppModule);
const port = serverConfig.port;
app.setGlobalPrefix('api/v1');
app.enableCors();
app.use(json({ limit: '50mb' }));
app.use(urlencoded({ extended: true, limit: '50mb' }));
await app.listen(port);
logger.log(`Application listing on port ${port}`) // for logging
}
bootstrap()

@ -0,0 +1,41 @@
import { BadRequestException } from '@nestjs/common';
import * as database from 'data/database.json';
const oracledb = require('oracledb');
export async function connectOraDatabase(VAN:string){
console.log('~~~~Bank Code',VAN);
let connection
let config = database.filter(data => {
return data.VAN == VAN
});
if (!config[0])
throw new BadRequestException('Invalid Bank Code')
let dbConfig = config[0]
try {
connection = await oracledb.getConnection({
user: dbConfig.username,
password: dbConfig.password,
connectString: `${dbConfig.host}/${dbConfig.sid}`
});
console.log(`created connection ${new Date} BANK:${VAN} NAME: ${dbConfig.tag}`);
} catch (err) {
console.error(err);
} finally {
return connection
}
}
export async function closeOraConnection(connection) {
if (connection) {
await connection.release(
function (err) {
console.log(`Releasing connection ${new Date}`);
if (err) { console.error(err.message); }
});
}
console.log(`clossed connection ${new Date()}`);
}

@ -0,0 +1,58 @@
export function convertDate(date: Date, format?: string): Date {
if (!date || date.toString() == "" || date.toString() == "null")
return null;
date = new Date(date);
if (!format)
format = "yyyy-MM-dd";
let day = ('0' + date.getDate()).slice(-2);
let month = ('0' + (date.getMonth() + 1)).slice(-2);
let year = date.getFullYear();
let hours = ('0' + date.getHours() || '00').slice(-2);
let minutes = ('0' + date.getMinutes() || '00').slice(-2);
let seconds = ('0' + date.getSeconds() || '00').slice(-2);
let stringDt = format;
if (format.includes("yyyy")) stringDt = stringDt.replace("yyyy", year.toString());
if (format.includes("MM")) stringDt = stringDt.replace("MM", month.toString());
if (format.includes("dd")) stringDt = stringDt.replace("dd", day.toString());
if (format.includes("hh")) stringDt = stringDt.replace("hh", hours.toString());
if (format.includes("mm")) stringDt = stringDt.replace("mm", minutes.toString());
if (format.includes("ss")) stringDt = stringDt.replace("ss", seconds.toString());
let convDate = new Date(stringDt);
return convDate;
}
export function convertDateString(date: Date, format?: string): string {
if (!date || date.toString() == "null")
return null;
date = new Date(date);
if (!format)
format = "yyyy-MM-dd";
let day = ('0' + date.getDate()).slice(-2);
let month = ('0' + (date.getMonth() + 1)).slice(-2);
let year = date.getFullYear();
let hours = ('0' + date.getHours() || '00').slice(-2);
let minutes = ('0' + date.getMinutes() || '00').slice(-2);
let seconds = ('0' + date.getSeconds() || '00').slice(-2);
let stringDt = format;
if (format.includes("yyyy")) stringDt = stringDt.replace("yyyy", year.toString());
if (format.includes("MM")) stringDt = stringDt.replace("MM", month.toString());
if (format.includes("dd")) stringDt = stringDt.replace("dd", day.toString());
if (format.includes("hh")) stringDt = stringDt.replace("hh", hours.toString());
if (format.includes("mm")) stringDt = stringDt.replace("mm", minutes.toString());
if (format.includes("ss")) stringDt = stringDt.replace("ss", seconds.toString());
if (format.includes("MON")) stringDt = stringDt.replace("MON", shortMonth[parseInt(month.toString()) - 1]);
if (format.includes("MONTH")) stringDt = stringDt.replace("MONTH", month[parseInt(month.toString()) - 1]);
return stringDt;
}
const month = ["JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"];
const shortMonth = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];

@ -0,0 +1,21 @@
import { Injectable, ArgumentMetadata, BadRequestException, ValidationPipe, UnprocessableEntityException } from '@nestjs/common';
@Injectable()
export class IctValidateInputPipe extends ValidationPipe {
public async transform(value, metadata: ArgumentMetadata) {
try {
return await super.transform(value, metadata);
} catch (e) {
if (e instanceof BadRequestException) {
// throw new UnprocessableEntityException(this.handleError(e.message)); //commented after migration
let err: Object = e.getResponse();
console.log("====err1====",err["message"]);
throw new UnprocessableEntityException(err["message"]);
}
}
}
private handleError(errors) {
return errors.map(error => error.constraints);
}
}

@ -0,0 +1,18 @@
import { Body, Controller, Post } from '@nestjs/common';
import { RtgsService } from './rtgs.service';
import { rtgsDto } from 'src/dto/rtgs.dto';
@Controller('rtgs')
export class RtgsController {
constructor(private readonly rtgsService: RtgsService) {}
@Post()
async createRtgs(@Body() rtgsDto: rtgsDto): Promise<any>{
return await this.rtgsService.rtgsEntryPosting(rtgsDto)
}
@Post('validation')
async validatingRtgs(@Body() rtgsDto: rtgsDto): Promise<any>{
return await this.rtgsService.validatingRtgs(rtgsDto)
}
}

@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { RtgsController } from './rtgs.controller';
import { RtgsService } from './rtgs.service';
@Module({
controllers: [RtgsController],
providers: [RtgsService]
})
export class RtgsModule {}

@ -0,0 +1,115 @@
import { Injectable } from '@nestjs/common';
import { rtgsDto } from 'src/dto/rtgs.dto';
import { closeOraConnection, connectOraDatabase } from 'src/pipe/connection.pipe';
const oracledb = require('oracledb');
@Injectable()
export class RtgsService {
async rtgsEntryPosting(data: rtgsDto) {
const connection = await this.createConnection(data.VAN);
console.log("hereeeee", data.date);
try {
let sql = `begin SIB_INWARD_INSERT(
'${data.clientCode}','${data.VAN}','${data.vCode}','${data.bankUTR}',null,to_date('${data.date}', 'DD-MM-YYYY'),null,null,null,null,
'${data.sendertoReceiverInformation}',null,'${data.remitterAccountnumber}','${data.remitterName}','${data.remitterIFSC}','${data.modeofTXN}','${data.amount}','${data.corpTXNID}','${data.corptxnStatus}','${data.statusCode}',
'${data.statusMessage}',null,null,null,null,null,null,null,null,null,
null,null,null, :OUT_IN_STATUS, :OUT_STATUS_CODE, :OUT_STATUS_MSG
);
end;`
// let res = await connection.execute(sql, [], { outFormat: oracledb.OBJECT });
let res = await connection.execute(
sql,
[
{ dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 100 }, // OUT_IN_STATUS
{ dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 100 }, // OUT_STATUS_CODE
{ dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 100 } // OUT_STATUS_MSG
],
{ outFormat: oracledb.OBJECT }
);
console.log("payload===== ",data);
console.log('OUT_IN_STATUS:', res.outBinds[0]);
console.log('OUT_STATUS_CODE:', res.outBinds[1]);
console.log('OUT_STATUS_MSG:', res.outBinds[2]);
if(res){
return {
OUT_IN_STATUS: res.outBinds[0],
OUT_STATUS_CODE: res.outBinds[1],
OUT_STATUS_MSG: res.outBinds[2]
};
}
}catch(err){
console.log(err);
await connection.rollback();
return err
} finally {
await this.closeConnection(connection)
}
}
async createConnection(VAN: string) {
return await connectOraDatabase(VAN);
}
async closeConnection(connection) {
await closeOraConnection(connection);
}
async validatingRtgs(data: rtgsDto) {
const connection = await this.createConnection(data.VAN);
try {
let sql = `begin SIB_INWARD_validation_api(
'${data.clientCode}','${data.VAN}','${data.vCode}',null,null,null,null,null,null,null,
null,null,null,null,null,null,'${data.amount}',null,null,null,
'${data.statusMessage}',null,null,null,null,null,null,null,null,null,
null,null,null, :OUT_IN_STATUS, :OUT_STATUS_CODE, :OUT_STATUS_MSG
);
end;`
// let res = await connection.execute(sql, [], { outFormat: oracledb.OBJECT });
let res = await connection.execute(
sql,
[
{ dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 100 }, // OUT_IN_STATUS
{ dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 100 }, // OUT_STATUS_CODE
{ dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 100 } // OUT_STATUS_MSG
],
{ outFormat: oracledb.OBJECT }
);
console.log("payload===== ",data);
console.log('OUT_IN_STATUS:', res.outBinds[0]);
console.log('OUT_STATUS_CODE:', res.outBinds[1]);
console.log('OUT_STATUS_MSG:', res.outBinds[2]);
if(res){
return {
clientCode : data.clientCode,
VAN : data.VAN,
vCode : data.vCode,
amount : data.amount,
corptxnStatus: res.outBinds[0],
statusCode: res.outBinds[1],
statusMessage: res.outBinds[2]
};
}
}catch(err){
console.log(err);
await connection.rollback();
return err
} finally {
await this.closeConnection(connection)
}
}
}

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist"]
}

@ -0,0 +1,16 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"resolveJsonModule": true,
}
}
Loading…
Cancel
Save