broll-express 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.babelrc ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "presets": [
3
+ "@babel/preset-env"
4
+ ]
5
+ }
6
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Ananda krishnan g r
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "broll-express",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "type": "module",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "dev": " env-cmd -f .env.development node --no-warnings --watch --loader @babel/register ./start.js"
9
+ },
10
+ "author": "anandakrishnangr",
11
+ "license": "ISC",
12
+ "description": "",
13
+ "dependencies": {
14
+ "babel-node": "^0.0.1-security",
15
+ "bcryptjs": "^2.4.3",
16
+ "body-parser": "^1.20.3",
17
+ "cors": "^2.8.5",
18
+ "env-cmd": "^10.1.0",
19
+ "express": "^4.21.1",
20
+ "joi": "^17.13.3",
21
+ "jsonwebtoken": "^9.0.2",
22
+ "mongoose": "^8.7.1",
23
+ "swagger-jsdoc": "^6.2.8",
24
+ "swagger-ui-express": "^5.0.1"
25
+ },
26
+ "devDependencies": {
27
+ "@babel/core": "^7.25.8",
28
+ "@babel/node": "^7.25.7",
29
+ "@babel/preset-env": "^7.25.8",
30
+ "@babel/register": "^7.25.7"
31
+ }
32
+ }
package/src/app.js ADDED
@@ -0,0 +1,32 @@
1
+ import express from 'express';
2
+ import { connectMongoose } from './config/mongoConfig.js'
3
+ import bodyParser from 'body-parser';
4
+ import { createUser } from './controllers/signup.controller.js';
5
+ import authRoute from './routes/auth.routes.js'
6
+ import { validateRequest } from './middlewares/payloadValidation.middleware.js';
7
+ import cors from 'cors'
8
+ import { swaggerSpecs } from "./config/swaggerConfig.js";
9
+ import swaggerUi from "swagger-ui-express"
10
+
11
+ const app = express();
12
+ connectMongoose()
13
+ // Middleware to parse JSON requests
14
+ app.use(cors());
15
+ app.use(express.json());
16
+ app.use(bodyParser.json({
17
+ limit: '5mb'
18
+ }));
19
+ app.use(bodyParser.urlencoded({ extended: false }))
20
+ app.use(bodyParser.json())
21
+ app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
22
+
23
+ app.use(validateRequest)
24
+ app.get('/', (req, res) => {
25
+ res.send('Welcome to the Demo App!');
26
+ });
27
+
28
+ app.post('/test', createUser)
29
+ // app.post('/business',)
30
+ app.use("/auth", authRoute)
31
+
32
+ export default app // Export the app for use in server.js
@@ -0,0 +1,9 @@
1
+ import { default as mongoose } from "mongoose";
2
+
3
+ export const connectMongoose =async () => {
4
+ return mongoose.connect("").then((res) => {
5
+ console.log("connected")
6
+ }).catch((err) => {
7
+ console.log("err")
8
+ })
9
+ }
@@ -0,0 +1,27 @@
1
+ import swaggerJsdoc from 'swagger-jsdoc'
2
+ import { fileURLToPath } from 'url';
3
+ import packageDetails from '../../package.json' assert {type: 'json'}
4
+ import path from 'path';
5
+ const PORT = process.env.PORT
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ const options = {
9
+ definition: {
10
+ openapi: "3.0.0",
11
+ info: {
12
+ title: "Ecom API with Swagger",
13
+ version: packageDetails.version,
14
+ description: "A simple CRUD API application made with Express and documented with Swagger",
15
+ },
16
+ servers: [
17
+ {
18
+ url: `http://localhost:${PORT}`, // Replace with your server URL
19
+ },
20
+ ],
21
+ },
22
+ apis: [path.join(__dirname, "../routes/*.js")],
23
+ };
24
+
25
+ export const swaggerSpecs = swaggerJsdoc(options);
26
+
27
+
@@ -0,0 +1,22 @@
1
+ import Login from "../models/auth.models.js"
2
+
3
+ export const register = async (req, res, next) => {
4
+ try {
5
+ let { password, email } = req.body
6
+ await Login.create({ password, email })
7
+ res.send(200)
8
+ } catch (error) {
9
+ next(error)
10
+ }
11
+ }
12
+
13
+ export const login = async (req, res, next) => {
14
+ try {
15
+ let { password, email } = req.body
16
+ await Login.isUserAuthenticated(email, password)
17
+ res.send(200)
18
+ } catch (error) {
19
+ console.log(error)
20
+ next(error)
21
+ }
22
+ }
@@ -0,0 +1,31 @@
1
+ import mongoose from "mongoose"
2
+ import user from "../models/user.models.js";
3
+
4
+
5
+ export const createUser = async(req, res) => {
6
+ const session = await mongoose.startSession();
7
+
8
+ try {
9
+ session.startTransaction();
10
+
11
+ // Create a new address
12
+ const newUser = await user.create([{
13
+ firstName:"ananda",
14
+ lastName:"krishnan",
15
+ gender:"male"
16
+ }], { session });
17
+
18
+ // Commit the transaction
19
+ throw Error
20
+ await session.commitTransaction();
21
+ console.log('Transaction committed:', newUser);
22
+ } catch (error) {
23
+ // If an error occurs, abort the transaction
24
+ await session.abortTransaction();
25
+ console.error('Transaction aborted due to error:', error);
26
+ } finally {
27
+ session.endSession();
28
+ }
29
+
30
+
31
+ }
@@ -0,0 +1,4 @@
1
+ import bcryptjs from 'bcryptjs'
2
+
3
+ export const hashPassword = async (password) => bcryptjs.hash(password, await bcryptjs.genSalt(10))
4
+ export const comparePassword = async (password, hash) => bcryptjs.compare(password, hash)
@@ -0,0 +1,11 @@
1
+ class AppError extends Error {
2
+ constructor({ message, data, statusCode }) {
3
+ super(data);
4
+ this.data = data
5
+ this.message = message
6
+ this.statusCode = statusCode;
7
+ this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
8
+ this.isOperational = true; // Flag to indicate it's an expected error
9
+ }
10
+ }
11
+ export default AppError
@@ -0,0 +1,19 @@
1
+ function globalErrorHandler(err, req, res, next) {
2
+ let statusCode = err.statusCode || 500;
3
+ let message = err.message || 'Internal Server Error';
4
+ let data = err.data || {};
5
+ console.log(err.name)
6
+ if (err.name === 'ValidationError') {
7
+ message = Object.values(err.errors).map(err => err.message);
8
+ console.error('Validation Errors:', message);
9
+ } else {
10
+
11
+ }
12
+ res.status(statusCode).json({
13
+ status: err.status || 'error',
14
+ message,
15
+ data
16
+ });
17
+ }
18
+
19
+ export default globalErrorHandler
@@ -0,0 +1,19 @@
1
+ import { schemaLookup } from "../validations/validations.schema.js";
2
+
3
+ export const validateRequest = (req, res, next) => {
4
+ const { method, path } = req;
5
+ console.log(path, method)
6
+
7
+ const schema = schemaLookup[`${method}:${path}`] || Object.keys(schemaLookup).find(key => {
8
+ const regex = new RegExp(`^${key.split(':')[1].replace(':id', '\\d+')}$`);
9
+ return regex.test(path) && key.startsWith(method);
10
+ });
11
+ if (schema) {
12
+ const { error } = schema.validate(req.body);
13
+ if (error) {
14
+ return res.status(400).json({ message: error.details[0].message });
15
+ }
16
+ }
17
+ next(); // Proceed to the next middleware or route handler
18
+ };
19
+
@@ -0,0 +1,63 @@
1
+ import mongoose from "mongoose";
2
+ import { VerificationDetailsSchema } from "./common.schema.js";
3
+ import { comparePassword, hashPassword } from "../library/auth.lib.js";
4
+ import AppError from "../library/error.lib.js";
5
+
6
+ const LoginSchema = mongoose.Schema({
7
+ email: {
8
+ type: String,
9
+ unique: true,
10
+ trim: true,
11
+ required: [true, 'Email is required'],
12
+ match: [/.+@.+\..+/, 'Please enter a valid email address'],
13
+ lowercase: true,
14
+ },
15
+ phone: {
16
+ type: Number,
17
+ trim: true,
18
+ required: false,
19
+ min: 10
20
+ },
21
+ password: {
22
+ type: String,
23
+ trim: true,
24
+ required: [true, 'Password is required'],
25
+ minlength: [6, 'Password must be at least 6 characters long'],
26
+ },
27
+ email_verification_Details: VerificationDetailsSchema,
28
+ phone_verification_Details: VerificationDetailsSchema
29
+ }, {
30
+ timestamps: true
31
+ });
32
+
33
+ LoginSchema.pre('save', async function (next) {
34
+ this.password = await hashPassword(this.password)
35
+ next();
36
+ });
37
+
38
+ LoginSchema.post(['find', 'findOne'], async function (docs) {
39
+ const _includePassword = this.options.includePassword
40
+ if (_includePassword) {
41
+ return docs
42
+ }
43
+ if (Array.isArray(docs)) {
44
+ docs.forEach(doc => {
45
+ doc.password = undefined; // Remove password from each document
46
+ });
47
+ } else if (docs) {
48
+ docs.password = undefined; // Remove password from the single document
49
+ }
50
+ });
51
+
52
+ LoginSchema.statics.isUserAuthenticated = async function (email, password) {
53
+ let user = await this.findOne({ email }).setOptions({ includePassword: true });
54
+ if (!user) {
55
+ throw new AppError({ message: 'User Not Found !', statusCode: 401 })
56
+ }
57
+ const isMatch = await comparePassword(password, user.password)
58
+ if (!isMatch) throw new AppError({ message: 'Incorrect password', statusCode: 400 })
59
+ return isMatch
60
+ }
61
+
62
+ const Login = mongoose.model("Loginsf", LoginSchema);
63
+ export default Login;
@@ -0,0 +1,10 @@
1
+ import mongoose from "mongoose";
2
+
3
+ export const VerificationDetailsSchema = mongoose.Schema({
4
+ status: {
5
+ type: Boolean,
6
+ default: false,
7
+ },
8
+ }, {
9
+ timestamps: true
10
+ });
@@ -0,0 +1,30 @@
1
+ import mongoose from "mongoose";
2
+
3
+ const userSchema = mongoose.Schema({
4
+ firstName:{
5
+ type:String,
6
+ required:true,
7
+ trim:true
8
+ },
9
+ lastName:{
10
+ type:String,
11
+ trim:true
12
+ },
13
+ LastUpdatedAt:{
14
+ type: Date,
15
+ default: Date.now,
16
+ },
17
+ createdAt: {
18
+ type: Date,
19
+ default: Date.now,
20
+ },
21
+ gender: {
22
+ type: String,
23
+ enum: ['male', 'female'], // Enum values for gender
24
+ required: true,
25
+ },
26
+ })
27
+
28
+
29
+ const user = mongoose.model('customerUser', userSchema);
30
+ export default user;
@@ -0,0 +1,30 @@
1
+ import express from 'express';
2
+ import { register, login } from '../controllers/auth.controller.js';
3
+
4
+ const router = express.Router();
5
+
6
+ /**
7
+ * @swagger
8
+ * /auth/register:
9
+ * post:
10
+ * summary: Register a new user
11
+ * responses:
12
+ * 200:
13
+ * description: User registered successfully.
14
+ * 400:
15
+ * description: Bad request
16
+ */
17
+ router.post('/register', register);
18
+
19
+ /**
20
+ * @swagger
21
+ * /auth/login:
22
+ * post:
23
+ * summary: User login
24
+ * responses:
25
+ * 200:
26
+ * description: User logged in successfully.
27
+ */
28
+ router.post('/login', login);
29
+
30
+ export default router;
@@ -0,0 +1,5 @@
1
+ import express from 'express'
2
+
3
+ export const app = express()
4
+
5
+ app.post('/',login)
@@ -0,0 +1,2 @@
1
+
2
+
File without changes
package/src/server.js ADDED
@@ -0,0 +1,13 @@
1
+ import app from "./app.js"
2
+
3
+ import globalErrorHandler from "./middlewares/errorHandler.middleware.js";
4
+ const PORT = process.env.PORT || 3000;
5
+ const ENV = process.env.NODE_ENV
6
+
7
+
8
+ app.use(globalErrorHandler)
9
+
10
+
11
+ app.listen(PORT, () => {
12
+ console.log(`Server is running on http://localhost:${PORT} at ${ENV}`);
13
+ });
@@ -0,0 +1,53 @@
1
+ import Joi from 'joi';
2
+
3
+ // Define your schemas (same as before)
4
+ const userSchema = Joi.object({
5
+ email: Joi.string()
6
+ .email()
7
+ .optional()
8
+ .messages({
9
+ 'string.email': 'Please enter a valid email address',
10
+ }),
11
+ phone: Joi.number()
12
+ .optional()
13
+ .min(1000000000)
14
+ .max(9999999999)
15
+ .messages({
16
+ 'number.min': 'Phone number must be at least 10 digits',
17
+ 'number.max': 'Phone number must be at most 10 digits',
18
+ }),
19
+ password: Joi.string()
20
+ .min(6)
21
+ .optional()
22
+ .pattern(/^[a-zA-Z0-9]{3,30}$/)
23
+ .messages({
24
+ 'string.min': 'Password must be at least 6 characters long',
25
+ 'string.pattern.base': 'Password can only contain alphanumeric characters',
26
+ }),
27
+ }).xor('email', 'phone')
28
+ .messages({
29
+ 'object.xor': 'Either email or phone number must be provided.',
30
+ });
31
+
32
+ // Schema configuration mapping
33
+ const schemaConfig = [
34
+ {
35
+ methods: ['POST', 'PUT'],
36
+ paths: ['/auth/login', '/users/:id'],
37
+ schema: userSchema,
38
+ },
39
+ // Add more route configurations as needed
40
+ ];
41
+
42
+ // Preprocess the schema configuration into a lookup map
43
+ const schemaLookup = {};
44
+
45
+ schemaConfig.forEach(route => {
46
+ route.methods.forEach(method => {
47
+ route.paths.forEach(path => {
48
+ schemaLookup[`${method}:${path}`] = route.schema;
49
+ });
50
+ });
51
+ });
52
+
53
+ export { schemaLookup, userSchema };
package/start.js ADDED
@@ -0,0 +1,11 @@
1
+ // start.mjs
2
+ import register from '@babel/register';
3
+
4
+ register({
5
+ extensions: ['.js', '.mjs'], // Specify the extensions you want Babel to transpile
6
+ });
7
+
8
+ import('./src/server.js').catch(err => {
9
+ console.error(err);
10
+ process.exit(1);
11
+ });