namune
v1.0.27
Published
A Quick Setup Express API.
Downloads
43
Maintainers
Readme
namune
A production-ready Express.js library with built-in authentication, middleware configuration, and route management.
Features
- 🔐 Built-in authentication system (register, login, logout, verification)
- ⚙️ Configurable middleware stack (CORS, sessions, body parsing)
- 🗃️ MongoDB integration with Mongoose
- 🛣️ Automatic route loading and management
- 🔒 Passport.js integration for local authentication
- 🚀 Production-ready error handling and security practices
- 🧩 Modular architecture for easy extension
- 🖂 Mail Sending
- < > Advanced Pagination
- 💳 Payments with payfast
- 📁 Cloud File Uploads (To AWS S3)
Installation
npm install -g namune
# or
yarn global add namuneQuick Start
nmn create
# or
nmn create myproject# For hot reload when you save changes
npm run dev
# or for manual reload
npm startAPI Reference
Middleware Configuration (MidsConfigs)
new MidsConfigs(app)
app(Express): Express application instance
Methods
registerMiddlewares(options)
Registers all middleware.
options = {
dbConfig: { database_name: "myapp" },
usePassportLogin: true,
passportConfig: {
// Add your seperate custom local strategies for login authentication to the list
// Make sure to seperate strategyName with one dash (e.g user-local)
strategyList: [
{
strategyName: "user-local",
model: sharedDependencies.models.User, // Make sure this is included in shared.deps.js file
usernameField: "email", // Change relevant logic in routes/auth/api.routes.js to match your username field
verifyAccount: (user) => {
if (!user.accountActive) return "Please verify your email first.";
return null;
},
},
],
},
};Authentication Middleware
ensureAuthenticated(req, res, next)
Middleware that checks if a user is authenticated. Returns 401 if not.
Authentication Routes (Can't be overwritten)
POST /v1/auth/register- User registrationPOST /v1/auth/verify/account- Account verificationPOST /v1/auth/login- User loginGET /v1/auth/logout- User logoutPOST /v1/auth/verify-email- Email verification for password resetPOST /v1/auth/reset-password- Password resetPOST /v1/auth/delete-account- Account deletion
Hooks
AUTH Hooks: Returns a response
Response Structure: {success: boolean, message: string, data: any}
onSuccessRegister
onFailRegister
onSuccessVerifyUser
onFailVerifyUser
onSuccessLogin
onFailLogin
onSuccessLogout
onFailLogout
onSuccessDeleteUser
onFailDeleteUser
onSuccessVerify
onFailVerify
onSuccessChangePassword
onFailChangePassword
Example
// deps.js
module.exports = {
global: {},
models: {},
utils: {},
hooks: {
onSuccessRegister: yourCustomFunction, // Fires when user successfully registers (/auth/register)
onFailRegister: yourCustomFunction, // Fires when user fails to register (/auth/register)
},
};Route Management
Routes are automatically loaded from the routes directory. Use this pattern:
// routes/example/api.routes.js
class ExampleRoute {
constructor(router, dependencies) {
this.router = router;
this.dependencies = dependencies;
}
exampleHandler(req, res) {
res.json({ message: "Success" });
}
registerRoutes() {
this.router.get("/", this.exampleHandler);
}
}
module.exports = ExampleRoute;Configuration
Environment Variables
GENERAL
| Variable | Default | Description |
| --------------- | ------------------------- | ---------------------------------------- |
| PORT | 8000 | Server port |
| MONGODB_URI | mongodb://localhost:27017 | MongoDB connection string |
| DATABASE_NAME | example-db | Database name |
| NODE_ENV | development | Runtime environment |
| STAGING_ENV | undefined | Runtime environment |
| STAGING_URL | undefined | URL for your staging client/frontend |
| PROD_URL | undefined | URL for your production client/frontend |
| DEV_URL | http://localhost:3000 | URL for your development client/frontend |
PAYMENTS (Using Payfast)
| Variable | Default | Description |
| ------------------------------------ | ------------------------ | ------------------------------------- |
| NGROK_SERVER_URL | http://localhost:8000/v1 | ngrok server url |
| NGROK_CLIENT_URL | http://localhost:3000 | ngrok client url |
| PAYFAST_PASS_PHRASE | undefined | Payfast Pass Phrase |
| PAYFAST_MERCHANT_ID | 10000100 | Payfast Merchant ID |
| PAYFAST_MERCHANT_KEY | 46f0cd694581a | Payfast Merchant Key |
| PROD_API_URL | undefined | Production Api URL |
| PAYFAST_PAYMENT_CONFIRM_EMAIL | undefined | Email to send payment confirmation to |
| process.env.PAYFAST_PAYMENT_METHOD | cc | Payfast Payment method |
Middleware Options
You can configure:
- Database name
- Passport.js integration
- Session storage
- CORS settings
- Body parser limits
Error Handling
- Authentication failures return
401 - Database errors return
500 - Invalid requests return
400 - Route not found returns
404 - JSON responses include
successandmessagefields - Detailed errors in
developmentenvironment
Examples
Custom Route Implementation
// routes/custom/api.routes.js
const { Router } = require("express");
class CustomRoute {
constructor(router, dependencies) {
this.router = router;
this.dependencies = dependencies;
}
getData(req, res) {
res.json({ data: "Protected resource", user: req.user });
}
registerRoutes() {
const { authenticate } = this.dependencies.global;
this.router.get("/data", authenticate, this.getData);
}
}
module.exports = CustomRoute;Generating Hash (for any string)
// namune/utils/gen-hash.js
const genHash = require("namune/utils/gen-hash.js");
const hash = genHash({ password: "12345" });Send an email (Uses nodemailer)
// namune/utils/sendMail.js
const sendMail = require("namune/utils/sendMail.js");
// Optional: Transport options. (Below is the dafault setup)
const transportOptions = {
host: "mail.smtp2go.com",
port: 80, // 25, 587, and 8025 can also be used (or 2525).
};
// IMPRTANT:
// Make sure you have USER and PASS in the .env file for authenticating your email for transport
// Options
const from = "[email protected]";
const to = "[email protected]";
const subject = "Verify account";
const subject = "Verify account";
const attachments = [
{
filename: "emailBanner.png",
path: process.cwd() + "/public/img/emailBanner.png",
cid: "[email protected]",
},
];
const html = "<h1> Hi, please verify your account </h1>";
const mailOptions = {
from,
to,
subject,
attachments,
html,
};
sendMail(mailOptions);Lazy-Load Dependencies to avoid circular loop errors
module.exports = {
global: {},
models: {},
utils: {
get myUtil() {
return require("./utils/myUtil");
},
},
hooks: {
get onFailRegister() {
return require("./hooks/register.fail");
},
},
};Pagination
Input
// For non-routes
const paginate = require('namune/utils/paginate');
// For routes (api.routes.js)
// const paginate = this.dependencies.utils.paginate
const data = [
{ user: { name: "Alice" }, score: 91 },
{ user: { name: "Charlie" }, score: 82 },
{ user: { name: "Bob" }, score: 75 },
];
// Sort by nested property `user.name`
const result = paginate(data, {
page: 1,
limit: 2,
sortBy: 'user.name',
order: 'asc'
filterFn: (item) => item.score > 50
});
console.log(result);✅ Output Sample
{
data: [
{ user: { name: "Alice" }, score: 91 },
{ user: { name: "Bob" }, score: 75 }
],
paginationMeta: {
page: 1,
limit: 2,
totalItems: 3,
totalPages: 2,
hasNext: true,
hasPrevious: false,
nextPage: 2,
previousPage: null
}
}Options
page: Number Page to go to - Optional (Default is 0)
limit: Number Number of items - Optional (Default is 10)
sortBy: String Sort the data. Allows for nested properties - Optional (Default is null)
order Order the Items by "asc" or "desc" - Optional (Default is "asc")
filterFn Filter Function to filter data - Optional (Default is null)
Upload Files to cloud (Uses AWS S3)
// Non routes
const { uploadBase64ImageToS3 } = require("namune/utils/cloudFileUpload");
// For routes (api.routes.js)
// const {uploadBase64ImageToS3} = this.dependencies.utils.cloudFileUpload
let base64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA..."; // A base64 image
uploadBase64ImageToS3(base64).then(console.log);Options (Second Parameter after base64)
ACL: String For Access Control - Optional (Default is "public-read")
appendKey: String Folder in bucket - Optional (Default is "image-upload")
region: String Your S3 bucket region - Optional (Default is "eu-north-1")
Other functions (supports multipart/form-data)
uploadImage
uploadVideo
uploadAudio
Example
const multer = require("multer");
const upload = multer(); // memoryStorage by default
// ... Class logic for routes
registerRoutes(){
this.router.post("/upload/image", upload.single("file"), async (req, res) => {
const result = await this.dependencies.utils.cloudFileUpload.uploadImage(req.file);
res.json(result);
});
this.router.post("/upload/video", upload.single("file"), async (req, res) => {
const result = await this.dependencies.utils.cloudFileUpload.uploadVideo(req.file);
res.json(result);
});
this.router.post("/upload/audio", upload.single("file"), async (req, res) => {
const result = await this.dependencies.utils.cloudFileUpload.uploadAudio(req.file);
res.json(result);
});
}Options for the above functions:
buffer: Buffer - File buffer
originalName: String - Original file name (e.g. image.jpg)
folder: String - Folder in bucket (e.g. images, audio, videos)
options: {ACL: String, ContentType: String} - Optional: ACL, ContentType
Delete uploaded files
deleteFile - Expects a file param
deleteMultipleFiles - Expects an array of AWS keys (e.g. ['images/image.jpg', 'images/image2.jpg'])
deleteAllFilesInFolder - Expects a prefix (e.g. "images/user123/")
Options
file: {Key: String, VersionId: any, Location: String} - File object uploaded. versionId is optional
keys: String[] - Array of Keys
Example
// Delete specific files
await deleteMultipleFiles(["images/abc.jpg", "videos/test.mp4"]);
// Delete everything under a folder
await deleteAllFilesInFolder("images/user123/");Payments Using Payfast
Example
// In Routes context
// Making the payment signature
this.router.get("/order", (req, res) => {
const payfast = this.dependencies.utils.payfast;
const { data, html } = payfast.sig({
firstname: order.customerFirstName, // Required
lastname: order.customerLastName, // Required
email: order.customerEmail, // Required
payment_id: `${order.orderNumber}`, // Required
amount: `${order.totalPrice}`, // Required
order_num: `#${order.orderNumber}`, // Required
phone: order.customerPhoneNumber, // Optional
address: order.customerAddress, // Optional
});
return res.status(200).json({
success: true,
message: "Successful!",
data: { data, html },
});
/* Data returned from payfast.sig:
merchant_id,
merchant_key,
return_url,
cancel_url,
notify_url,
name_first,
name_last,
email_address,
m_payment_id,
amount,
item_name,
email_confirmation,
confirmation_address,
payment_method,
signature
*/
});
// Request from Payfast after cancellation or successful payment
this.router.post("/notify", async (req, res) => {
const { m_payment_id, amount_gross } = await req.body;
const payfast = this.dependencies.utils.payfast;
// Notify/Confirmation
payfast.confirm(req, amount_gross);
return res.status(200).json({
success: true,
message: "Successful!",
data: null,
});
});Minimal Working Example
// server.js
require("dotenv").config();
const express = require("express");
const app = express();
const http = require("http").createServer(app);
const MidsConfigs = require("namune/config/mids-configs");
const mids = new MidsConfigs(app);
mids.registerMiddlewares({
dbConfig: { database_name: "myapp" },
usePassportLogin: true,
passportConfig: {
userModel: require("./models/User"),
usernameField: "email",
},
});
app.use("/api", require("namune/routes/api"));
const PORT = process.env.PORT || 8000;
http.listen(PORT, () => console.log(`Server running on port ${PORT}`));Contributing
Contributions are welcome!
- Fork the repository
- Create your feature branch:
git checkout -b feature/your-feature - Commit your changes:
git commit -am 'Add some feature' - Push to the branch:
git push origin feature/your-feature - Open a pull request
License
This project is licensed under the MIT License.
