create-nodets-app-nish 1.0.1 → 1.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-nodets-app-nish",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Command line tool to create a new Node.js + Express + MongoDB + TypeScript project template",
5
5
  "license": "ISC",
6
6
  "author": "krish112407",
@@ -0,0 +1,12 @@
1
+ PORT=3000
2
+ MONGODB_URI=mongodb://localhost:27017/your-app-name
3
+ JWT_SECRET=your-secret-key-here
4
+ CORS_ORIGIN=http://localhost:3000
5
+
6
+ # Email Configuration
7
+ SMTP_HOST=smtp.gmail.com
8
+ SMTP_PORT=587
9
+ SMTP_SECURE=false
10
+ SMTP_USER=your-email@gmail.com
11
+ SMTP_PASS=your-app-password
12
+ SMTP_FROM=noreply@yourapp.com
@@ -0,0 +1,5 @@
1
+ import { Admin } from "../models/admin.models.js";
2
+
3
+ export const models = {
4
+ "Admin": Admin
5
+ }
@@ -0,0 +1,17 @@
1
+ import express from "express";
2
+ import cors from "cors";
3
+ import cookieParser from "cookie-parser";
4
+
5
+ const app = express();
6
+
7
+ app.use(cors({
8
+ origin: process.env.CORS_ORIGIN,
9
+ credentials: true
10
+ }))
11
+
12
+ app.use(express.json({limit:"16kb"}))
13
+ app.use(express.urlencoded({extended:true,limit:"16kb"}))
14
+ app.use(express.static("public"))
15
+ app.use(cookieParser())
16
+
17
+ export {app}
@@ -0,0 +1,13 @@
1
+ import mongosee from "mongoose"
2
+
3
+
4
+ async function connectDB(){
5
+ try {
6
+ await mongosee.connect(process.env.MONGODB_URI as string)
7
+ console.log("MongoDB connected")
8
+ } catch (error) {
9
+ console.log(error)
10
+ }
11
+ }
12
+
13
+ export {connectDB}
@@ -0,0 +1,16 @@
1
+ import { app } from "./app.js";
2
+ import dotenv from "dotenv";
3
+ import { connectDB } from "./db/index.js";
4
+
5
+ dotenv.config();
6
+
7
+ const port = process.env.PORT || 3000;
8
+
9
+ connectDB().then(() => {
10
+ app.listen(port, () => {
11
+ console.log(`Server is running on port ${port}`);
12
+ });
13
+ })
14
+ .catch((err) => {
15
+ console.log("Error connecting to database", err);
16
+ })
@@ -0,0 +1,12 @@
1
+ import { Document } from "mongoose";
2
+
3
+
4
+ interface IAdmin extends Document{
5
+ username:string;
6
+ email:string;
7
+ password:string;
8
+ generateAccessToken():string;
9
+ isPasswordCorrect(password:string):Promise<boolean>
10
+ }
11
+
12
+ export type { IAdmin }
@@ -0,0 +1,46 @@
1
+ import type { IAdmin } from "../interface/admin.interface.js";
2
+ import mongoose, { Document } from "mongoose";
3
+ import jwt from "jsonwebtoken";
4
+ import bcrypt from "bcrypt";
5
+
6
+ type AdminType = IAdmin & Document;
7
+
8
+
9
+ const AdminSchema = new mongoose.Schema<AdminType>({
10
+ username: {
11
+ type: String,
12
+ required: true,
13
+ unique: true
14
+ },
15
+ email: {
16
+ type: String,
17
+ required: true,
18
+ unique: true
19
+ },
20
+ password: {
21
+ type: String,
22
+ required: true
23
+ }
24
+ })
25
+
26
+ AdminSchema.pre("save", async function () {
27
+ if (this.isModified("password")) {
28
+ this.password = await bcrypt.hash(this.password, 10)
29
+ }
30
+ })
31
+
32
+ AdminSchema.methods.generateAccessToken = function (): string {
33
+ return jwt.sign({
34
+ _id: this._id,
35
+ username: this.username,
36
+ email: this.email
37
+ }, process.env.JWT_SECRET as string, {
38
+ expiresIn: "1d"
39
+ })
40
+ }
41
+
42
+ AdminSchema.methods.isPasswordCorrect = async function (password: string): Promise<boolean> {
43
+ return await bcrypt.compare(password, this.password)
44
+ }
45
+
46
+ export const Admin = mongoose.model<AdminType>("Admin", AdminSchema)
@@ -0,0 +1,22 @@
1
+ import type { Response } from "express";
2
+
3
+ class ApiResponse{
4
+ constructor(
5
+ public statusCode: number,
6
+ public message: string,
7
+ public data: any
8
+ ){
9
+ this.statusCode = statusCode
10
+ this.message = message
11
+ this.data = data
12
+ }
13
+ }
14
+
15
+
16
+ function returnResponse(res:Response,statusCode:number,message:string,data:any){
17
+ return res.status(statusCode).json(
18
+ new ApiResponse(statusCode,message,data)
19
+ )
20
+ }
21
+
22
+ export {returnResponse}
@@ -0,0 +1,9 @@
1
+ import type { Request, Response, NextFunction, RequestHandler } from "express";
2
+
3
+ function asyncHandler(fn: RequestHandler) {
4
+ return (req: Request, res: Response, next: NextFunction) => {
5
+ Promise.resolve(fn(req, res, next)).catch(next);
6
+ };
7
+ }
8
+
9
+ export { asyncHandler };
@@ -0,0 +1,43 @@
1
+ import type { Model } from "mongoose";
2
+ import * as modeldata from "../admin/model.register.js";
3
+
4
+ // Accepts either string or object for identifier
5
+ type Identifier = string | Record<string, any>;
6
+
7
+ async function login(
8
+ model: keyof typeof modeldata.models, // TS now knows only valid models can be used
9
+ uniqueIdentifier: Identifier,
10
+ password: string
11
+ ) {
12
+ const Model: Model<any> = modeldata.models[model]; // cast to Model<any> to avoid TS errors
13
+ if (!Model) {
14
+ throw new Error("Model not found");
15
+ }
16
+
17
+ // If uniqueIdentifier is a string, assume it's an 'id' search
18
+ const query = typeof uniqueIdentifier === "string"
19
+ ? { id: uniqueIdentifier }
20
+ : uniqueIdentifier;
21
+
22
+ const user = await Model.findOne(query);
23
+ if (!user) {
24
+ throw new Error("User not found");
25
+ }
26
+
27
+ // Check password
28
+ const isPasswordCorrect = await user.isPasswordCorrect(password);
29
+ if (!isPasswordCorrect) {
30
+ throw new Error("Password is not correct");
31
+ }
32
+
33
+ // Generate token
34
+ const token = user.generateAccessToken();
35
+
36
+ if (!token) {
37
+ throw new Error("Token not generated");
38
+ }
39
+ return token;
40
+ }
41
+
42
+
43
+ export { login }
@@ -0,0 +1,47 @@
1
+ import nodemailer from "nodemailer";
2
+ import type { Transporter } from "nodemailer";
3
+
4
+ interface MailOptions {
5
+ to: string;
6
+ subject: string;
7
+ text?: string;
8
+ html?: string;
9
+ from?: string;
10
+ }
11
+
12
+ let transporter: Transporter | null = null;
13
+
14
+ // Initialize transporter (only once)
15
+ function getTransporter(): Transporter {
16
+ if (!transporter) {
17
+ transporter = nodemailer.createTransport({
18
+ host: process.env.SMTP_HOST,
19
+ port: Number(process.env.SMTP_PORT) || 587,
20
+ secure: process.env.SMTP_SECURE === "true", // true for 465, false for other ports
21
+ auth: {
22
+ user: process.env.SMTP_USER,
23
+ pass: process.env.SMTP_PASS,
24
+ },
25
+ });
26
+ }
27
+ return transporter;
28
+ }
29
+
30
+ export async function sendMail(options: MailOptions): Promise<void> {
31
+ const mailOptions = {
32
+ from: options.from || process.env.SMTP_FROM || "no-reply@example.com",
33
+ to: options.to,
34
+ subject: options.subject,
35
+ text: options.text,
36
+ html: options.html,
37
+ };
38
+
39
+ try {
40
+ const transporter = getTransporter();
41
+ const info = await transporter.sendMail(mailOptions);
42
+ console.log("Email sent:", info.messageId);
43
+ } catch (error) {
44
+ console.error("Error sending email:", error);
45
+ throw new Error("Failed to send email");
46
+ }
47
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": "./src",
4
+ "outDir": "./dist",
5
+ "module": "nodenext",
6
+ "target": "esnext",
7
+ "types": [],
8
+ "sourceMap": true,
9
+ "declaration": true,
10
+ "declarationMap": true,
11
+ "emitDeclarationOnly": false,
12
+ "noUncheckedIndexedAccess": true,
13
+ "exactOptionalPropertyTypes": true,
14
+ "strict": true,
15
+ "jsx": "react-jsx",
16
+ "verbatimModuleSyntax": true,
17
+ "isolatedModules": true,
18
+ "noUncheckedSideEffectImports": true,
19
+ "moduleDetection": "force",
20
+ "skipLibCheck": true
21
+ },
22
+ "include": ["src/**/*"],
23
+ "exclude": ["node_modules", "dist"]
24
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "lib": ["ES2020"],
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true
13
+ },
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules"]
16
+ }