Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at vinayaksarawagi25@gmail.com. All
reported by contacting the project team at hi@squareboat.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Expand Down
5 changes: 3 additions & 2 deletions cli
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ function checkFileExistsSync(filepath) {
return flag;
}

if (!checkFileExistsSync('./dist/src/app.js')) {
const fileName = './dist/src/app'; // CHANGE THE FILE NAME IF NEEDED
if (!checkFileExistsSync(`${fileName}.js`)) {
// CHANGE THE FILE TO CHECK IF NEEDED
console_1.Logger.error(' PLEASE BUILD THE CLI PROJECT FIRST ');
console_1.Logger.info('🪄 Run command: `npm run build` '); // CHANGE THE BUILD COMMAND IF NEEDED
return process.exit();
}

const app_1 = require('./dist/src/app'); // CHANGE THE IMPORT IF NEEDED
const app_1 = require(fileName); // CHANGE THE IMPORT IF NEEDED

async function bootstrap() {
const app = await core_1.NestFactory.createApplicationContext(
Expand Down
31 changes: 0 additions & 31 deletions config/database.ts

This file was deleted.

3 changes: 1 addition & 2 deletions config/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import app from './app';
import db from './database';
import settings from './settings';
import services from './services';

export default [app, db, settings, services];
export default [app, settings, services];
30 changes: 30 additions & 0 deletions database/utils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
exports.timestamps = function (knex, table) {
table
.timestamp('created_at')
.notNullable()
.defaultTo(knex.raw('CURRENT_TIMESTAMP'));

table
.timestamp('updated_at')
.notNullable()
.defaultTo(knex.raw('CURRENT_TIMESTAMP'));
};

exports.onUpdateTrigger = (table) => `
CREATE TRIGGER ${table}_updated_at
BEFORE UPDATE ON ${table}
FOR EACH ROW
EXECUTE PROCEDURE on_update_timestamp();
`;

exports.ON_UPDATE_TIMESTAMP_FUNCTION = `
CREATE OR REPLACE FUNCTION on_update_timestamp()
RETURNS trigger AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ language 'plpgsql';
`;

exports.DROP_ON_UPDATE_TIMESTAMP_FUNCTION = `DROP FUNCTION on_update_timestamp`;
1 change: 1 addition & 0 deletions libs/boat/src/commands/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './init';
134 changes: 134 additions & 0 deletions libs/boat/src/commands/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { Injectable } from '@nestjs/common';
import { Command, ConsoleIO } from '@squareboat/nest-console';
import { spawn } from 'child_process';
import * as fs from 'fs/promises';
import { BuildUtils } from '../utils';

@Injectable()
@Command('init {db}', { desc: 'Command to initialize the project' })
export class Init {
async handle(_cli: ConsoleIO): Promise<void> {
try {
const db = _cli.argument('db');
let dbconf: string;

if (db === 'pg') {
dbconf = `import { registerAs } from '@nestjs/config';
import { DatabaseOptions } from '@squareboat/nestjs-objection';
import { knexSnakeCaseMappers } from 'objection';

export default registerAs(
'db',
() =>
({
isGlobal: true,
default: 'pg',
connections: {
pg: {
client: 'pg',
debug: !!+process.env.DB_DEBUG,
connection: {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_DATABASE,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
charset: 'utf8',
},
useNullAsDefault: true,
migrations: {
directory: './database/migrations',
},
...knexSnakeCaseMappers(),
},
},
} as DatabaseOptions),
);`;
} else if (db === 'mysql') {
dbconf = `import { knexSnakeCaseMappers } from 'objection';
import { registerAs } from '@nestjs/config';
import { DatabaseOptions } from '@squareboat/nestjs-objection';

export default registerAs(
'db',
() =>
({
isGlobal: true,
default: 'mysql',
connections: {
mysql: {
client: 'mysql2',
debug: !!+process.env.DB_DEBUG,
connection: {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_DATABASE,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
charset: 'utf8',
timezone: process.env.DB_TIMEZONE,
},
useNullAsDefault: true,
...knexSnakeCaseMappers(),
},
},
} as DatabaseOptions),
);`;
} else {
_cli.error('Invalid database type');
return;
}

await BuildUtils.writeFile('config/database.ts', dbconf);

let config = await BuildUtils.readFile('config/index.ts');
config = config.replace(
`import services from './services';`,
`import services from './services';\nimport db from './database';`
);
config = config.replace(`services]`, `services, db]`);
await BuildUtils.writeFile('config/index.ts', config);

let app = await BuildUtils.readFile('src/app.ts');
app = app.replace(
`import { BoatModule } from '@libs/boat';`,
`import { BoatModule } from '@libs/boat';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { ObjectionModule } from '@squareboat/nestjs-objection';`
);
app = app.replace(
`BoatModule,`,
`ObjectionModule.registerAsync({
isGlobal: true,
imports: [ConfigModule],
useFactory: (config: ConfigService) => config.get('db'),
inject: [ConfigService]
}),
BoatModule,`
);
await BuildUtils.writeFile('src/app.ts', app);

await BuildUtils.deleteFile('CONTRIBUTING.md');
await BuildUtils.deleteFile('LICENSE.MD');
await BuildUtils.deleteFile('README.md');
await BuildUtils.deleteFile('CODE_OF_CONDUCT.md');
await BuildUtils.deleteFile('cover.jpg');

await new Promise((resolve, reject) => {
const command = process.platform === 'win32' ? 'copy' : 'cp';
const childProcess = spawn(command, ['.env.example', '.env'], { shell: true });
childProcess.on('close', (code) => (code === 0 ? resolve(0) : reject()));
});

let module = await BuildUtils.readFile('libs/boat/src/module.ts');
module = module.replace(`import { Init } from './commands';`, '');
module = module.replace(', Init', '');
await BuildUtils.writeFile('libs/boat/src/module.ts', module);

await fs.rm('libs/boat/src/commands', { recursive: true, force: true });
await fs.rm('test', { recursive: true, force: true });
_cli.success('Project initialized successfully');
} catch (error) {
console.error('Error initializing project:', error);
}
}

}
1 change: 1 addition & 0 deletions libs/boat/src/dtos/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './paginateRequest';
19 changes: 19 additions & 0 deletions libs/boat/src/dtos/paginateRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { LoadRelSchema } from '@squareboat/nestjs-objection';
import { Type } from 'class-transformer';
import { IsInt, IsOptional, Min } from 'class-validator';

export class PaginateRequest {
@IsInt()
@Min(1)
@IsOptional()
@Type(() => Number)
page = 1;

@IsInt()
@Min(1)
@IsOptional()
@Type(() => Number)
perPage = 15;

eager: LoadRelSchema;
}
5 changes: 5 additions & 0 deletions libs/boat/src/exceptions/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import { BaseExceptionFilter } from '@nestjs/core';
import { ValidationFailed, InvalidCredentials, GenericException } from '.';
import { Unauthorized } from './unauthorized';
import * as Sentry from '@sentry/node';

@Catch()
export class ExceptionFilter extends BaseExceptionFilter {
Expand Down Expand Up @@ -42,6 +43,10 @@ export class ExceptionFilter extends BaseExceptionFilter {
const status = exception.status ? exception.status : 500;
message = exception.status ? message : 'Internal Server Error';

if (status === 500) {
Sentry.captureException(exception);
}

return response.status(status).json({
success: false,
code: status,
Expand Down
14 changes: 14 additions & 0 deletions libs/boat/src/exceptions/forbiddenException.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { HttpException, HttpStatus } from '@nestjs/common';

export class ForbiddenException extends HttpException {
private errors: Record<string, any>;
constructor(errors: Record<string, any>) {
super(errors.msg || 'forbidden exception occurred', HttpStatus.FORBIDDEN);

this.errors = errors;
}

getErrors(): Record<string, any> {
return this.errors;
}
}
2 changes: 2 additions & 0 deletions libs/boat/src/exceptions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export * from './invalidCredentials';
export * from './validationfailed';
export * from './genericException';
export * from './filter';
export * from './forbiddenException';
export * from './notFoundException';
8 changes: 8 additions & 0 deletions libs/boat/src/exceptions/notFoundException.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { HttpException } from '@nestjs/common';

export class NotFoundException extends HttpException {
constructor(message?: string) {
message = message ? message : 'Record Not found!';
super(message, 404);
}
}
9 changes: 6 additions & 3 deletions libs/boat/src/exceptions/unauthorized.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { HttpException } from '@nestjs/common';
import { HttpException, HttpStatus } from '@nestjs/common';

export class Unauthorized extends HttpException {
constructor() {
super('Unauthorized.', 401);
constructor(message?: string) {
super(
message || 'Unauthorized exception occurred',
HttpStatus.UNAUTHORIZED,
);
}
}
1 change: 1 addition & 0 deletions libs/boat/src/guards/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './throttler';
18 changes: 18 additions & 0 deletions libs/boat/src/guards/throttler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ExecutionContext, Injectable } from '@nestjs/common';
import { ThrottlerGuard } from '@nestjs/throttler';
import { AppConfig } from '../utils';

@Injectable()
export class CustomThrottlerGuard extends ThrottlerGuard {
async handleRequest({context, limit, ttl}) {
const req = context.switchToHttp().getRequest();

const allowedKeys = AppConfig.get('app.apiKeys');
const key = req.headers['x-api-key'];

// skipping rate limit for allowed clients
if (allowedKeys.includes(key)) return true;

return super.handleRequest({context, limit, ttl, throttler: this.throttlers[0], blockDuration: 0, getTracker: this.commonOptions.getTracker, generateKey: this.commonOptions.generateKey});
}
}
Loading