@akash-electron/ts-backend 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/README.md ADDED
@@ -0,0 +1,175 @@
1
+ ## 📦 Installation
2
+
3
+ ```bash
4
+ npm install @akash-electron/ts-backend
5
+ ```
6
+
7
+ ## 🚀 Usage
8
+
9
+ This package provides a set of utilities and middlewares to build robust TypeScript backends.
10
+
11
+ ### Global Error Handling
12
+
13
+ ```typescript
14
+ import express from "express";
15
+ import { globalErrorHandler, AppError, catchAsync } from "backlinks_backend";
16
+
17
+ const app = express();
18
+
19
+ // Your routes
20
+ app.get(
21
+ "/example",
22
+ catchAsync(async (req, res) => {
23
+ if (!req.query.id) {
24
+ throw new AppError("ID is required", 400);
25
+ }
26
+ res.json({ id: req.query.id });
27
+ }),
28
+ );
29
+
30
+ // Use the global error handler at the end
31
+ app.use(globalErrorHandler);
32
+ ```
33
+
34
+ ---
35
+
36
+ ## 📂 Folder Structure (Inherited)
37
+
38
+ ```text
39
+ src/
40
+ ├── config/ # Configuration files (env vars, database, etc.)
41
+ ├── controllers/ # Request handlers (processes input/output)
42
+ ├── middlewares/ # Custom Express middlewares (error, auth, validation)
43
+ ├── models/ # Data models/schemas (Prisma/Mongoose)
44
+ ├── routes/ # API route definitions
45
+ ├── services/ # Business logic (kept separate from controllers)
46
+ ├── utils/ # Helper functions and utility classes
47
+ ├── validations/ # Request validation schemas (Zod)
48
+ ├── types/ # Global TypeScript interfaces & types
49
+ ├── app.ts # Express application configuration
50
+ └── server.ts # Entry point and server initialization
51
+ ```
52
+
53
+ ---
54
+
55
+ ## 🛠️ Key Components & Implementation
56
+
57
+ ### 1. Global Error Handling
58
+
59
+ We use a centralized error handling mechanism to ensure consistent error responses across the entire application.
60
+
61
+ - **`AppError` Class**: A custom error class to handle operational errors.
62
+ - **`catchAsync` Utility**: A wrapper to eliminate the need for `try-catch` blocks in controllers.
63
+ - **Global Error Middleware**: The final destination for all errors.
64
+
65
+ ### 2. Request Validation
66
+
67
+ Using **Zod** for schema validation ensures that only valid data reaches your business logic. We validate:
68
+
69
+ - Request Body
70
+ - Query Parameters
71
+ - URL Parameters
72
+
73
+ ### 3. Business Logic (Services)
74
+
75
+ Controllers should only handle requests and responses. All "heavy lifting" and business rules are encapsulated in **Services**, making the code testable and reusable.
76
+
77
+ ### 4. Consistent API Responses
78
+
79
+ All successful responses follow a standard format:
80
+
81
+ ```json
82
+ {
83
+ "status": "success",
84
+ "data": { ... }
85
+ }
86
+ ```
87
+
88
+ ---
89
+
90
+ ## 🚀 Getting Started
91
+
92
+ ### Prerequisites
93
+
94
+ - Node.js (v18+)
95
+ - npm or pnpm
96
+
97
+ ### Initial Setup
98
+
99
+ 1. **Initialize Project**
100
+
101
+ ```bash
102
+ npm init -y
103
+ npm install typescript ts-node nodemon @types/node @types/express express dotenv
104
+ npx tsc --init
105
+ ```
106
+
107
+ 2. **Install Essentials**
108
+ ```bash
109
+ npm install zod cors helmet morgan winston
110
+ npm install -D @types/cors @types/morgan
111
+ ```
112
+
113
+ ---
114
+
115
+ ## 🛡️ Important Files (Quick Reference)
116
+
117
+ ### `src/utils/AppError.ts`
118
+
119
+ ```typescript
120
+ export class AppError extends Error {
121
+ public readonly statusCode: number;
122
+ public readonly isOperational: boolean;
123
+
124
+ constructor(message: string, statusCode: number) {
125
+ super(message);
126
+ this.statusCode = statusCode;
127
+ this.isOperational = true;
128
+ Error.captureStackTrace(this, this.constructor);
129
+ }
130
+ }
131
+ ```
132
+
133
+ ### `src/middlewares/errorMiddleware.ts`
134
+
135
+ ```typescript
136
+ import { Request, Response, NextFunction } from "express";
137
+ import { AppError } from "../utils/AppError";
138
+
139
+ export const globalErrorHandler = (
140
+ err: any,
141
+ req: Request,
142
+ res: Response,
143
+ next: NextFunction,
144
+ ) => {
145
+ err.statusCode = err.statusCode || 500;
146
+ err.status = err.status || "error";
147
+
148
+ res.status(err.statusCode).json({
149
+ status: err.status,
150
+ message: err.message,
151
+ ...(process.env.NODE_ENV === "development" && { stack: err.stack }),
152
+ });
153
+ };
154
+ ```
155
+
156
+ ### `src/utils/catchAsync.ts`
157
+
158
+ ```typescript
159
+ import { Request, Response, NextFunction } from "express";
160
+
161
+ export const catchAsync = (fn: Function) => {
162
+ return (req: Request, res: Response, next: NextFunction) => {
163
+ fn(req, res, next).catch(next);
164
+ };
165
+ };
166
+ ```
167
+
168
+ ---
169
+
170
+ ## 📝 Best Practices Included
171
+
172
+ - **Environment Safety**: Validate `.env` variables at startup.
173
+ - **Security Check**: Pre-configured with `helmet` for secure headers.
174
+ - **Clean Code**: Deep separation of concerns (Routes → Controllers → Services).
175
+ - **Graceful Shutdown**: Handles `SIGTERM` and `SIGINT` signals to close DB connections properly.
package/dist/app.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ declare const app: import("@types/express-serve-static-core").Express;
2
+ export default app;
package/dist/app.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const cors_1 = __importDefault(require("cors"));
7
+ const express_1 = __importDefault(require("express"));
8
+ const helmet_1 = __importDefault(require("helmet"));
9
+ const morgan_1 = __importDefault(require("morgan"));
10
+ const errorMiddleware_1 = require("./middlewares/errorMiddleware");
11
+ const AppError_1 = require("./utils/AppError");
12
+ const app = (0, express_1.default)();
13
+ // Security HTTP headers
14
+ app.use((0, helmet_1.default)());
15
+ // Development logging
16
+ if (process.env.NODE_ENV === "development") {
17
+ app.use((0, morgan_1.default)("dev"));
18
+ }
19
+ // Body parser
20
+ app.use(express_1.default.json({ limit: "10kb" }));
21
+ // CORS
22
+ app.use((0, cors_1.default)());
23
+ // Routes
24
+ // app.use('/api/v1/users', userRouter);
25
+ // Health check
26
+ app.get("/health", (req, res) => {
27
+ res.status(200).json({ status: "ok" });
28
+ });
29
+ // Handle undefined routes
30
+ app.all("*", (req, res, next) => {
31
+ next(new AppError_1.AppError(`Can't find ${req.originalUrl} on this server!`, 404));
32
+ });
33
+ // Global error handling middleware
34
+ app.use(errorMiddleware_1.globalErrorHandler);
35
+ exports.default = app;
@@ -0,0 +1,5 @@
1
+ export declare const env: {
2
+ NODE_ENV: "development" | "test" | "production";
3
+ PORT: number;
4
+ DATABASE_URL?: string | undefined;
5
+ };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.env = void 0;
7
+ const dotenv_1 = __importDefault(require("dotenv"));
8
+ const zod_1 = require("zod");
9
+ dotenv_1.default.config();
10
+ const envSchema = zod_1.z.object({
11
+ NODE_ENV: zod_1.z
12
+ .enum(["development", "test", "production"])
13
+ .default("development"),
14
+ PORT: zod_1.z.coerce.number().default(5000),
15
+ DATABASE_URL: zod_1.z.string().optional(),
16
+ });
17
+ const envVars = envSchema.safeParse(process.env);
18
+ if (!envVars.success) {
19
+ console.error("❌ Invalid environment variables:", envVars.error.format());
20
+ process.exit(1);
21
+ }
22
+ exports.env = envVars.data;
@@ -0,0 +1,4 @@
1
+ export * from "./config/env";
2
+ export * from "./middlewares/errorMiddleware";
3
+ export * from "./utils/AppError";
4
+ export * from "./utils/catchAsync";
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./config/env"), exports);
18
+ __exportStar(require("./middlewares/errorMiddleware"), exports);
19
+ __exportStar(require("./utils/AppError"), exports);
20
+ __exportStar(require("./utils/catchAsync"), exports);
@@ -0,0 +1,2 @@
1
+ import { NextFunction, Request, Response } from "express";
2
+ export declare const globalErrorHandler: (err: any, req: Request, res: Response, next: NextFunction) => void;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.globalErrorHandler = void 0;
4
+ const globalErrorHandler = (err, req, res, next) => {
5
+ err.statusCode = err.statusCode || 500;
6
+ err.status = err.status || "error";
7
+ if (process.env.NODE_ENV === "development") {
8
+ res.status(err.statusCode).json({
9
+ status: err.status,
10
+ error: err,
11
+ message: err.message,
12
+ stack: err.stack,
13
+ });
14
+ }
15
+ else {
16
+ if (err.isOperational) {
17
+ res.status(err.statusCode).json({
18
+ status: err.status,
19
+ message: err.message,
20
+ });
21
+ }
22
+ else {
23
+ console.error("ERROR 💥", err);
24
+ res.status(500).json({
25
+ status: "error",
26
+ message: "Something went very wrong!",
27
+ });
28
+ }
29
+ }
30
+ };
31
+ exports.globalErrorHandler = globalErrorHandler;
@@ -0,0 +1 @@
1
+ export {};
package/dist/server.js ADDED
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const app_1 = __importDefault(require("./app"));
7
+ const env_1 = require("./config/env");
8
+ const port = env_1.env.PORT || 5000;
9
+ const server = app_1.default.listen(port, () => {
10
+ console.log(`🚀 Server running in ${env_1.env.NODE_ENV} mode on port ${port}`);
11
+ });
12
+ // Handle unhandled rejections
13
+ process.on("unhandledRejection", (err) => {
14
+ console.log("UNHANDLED REJECTION! 💥 Shutting down...");
15
+ console.log(err.name, err.message);
16
+ server.close(() => {
17
+ process.exit(1);
18
+ });
19
+ });
20
+ // Handle uncaught exceptions
21
+ process.on("uncaughtException", (err) => {
22
+ console.log("UNCAUGHT EXCEPTION! 💥 Shutting down...");
23
+ console.log(err.name, err.message);
24
+ process.exit(1);
25
+ });
@@ -0,0 +1,6 @@
1
+ export declare class AppError extends Error {
2
+ readonly statusCode: number;
3
+ readonly status: string;
4
+ readonly isOperational: boolean;
5
+ constructor(message: string, statusCode: number);
6
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppError = void 0;
4
+ class AppError extends Error {
5
+ constructor(message, statusCode) {
6
+ super(message);
7
+ this.statusCode = statusCode;
8
+ this.status = `${statusCode}`.startsWith("4") ? "fail" : "error";
9
+ this.isOperational = true;
10
+ Error.captureStackTrace(this, this.constructor);
11
+ }
12
+ }
13
+ exports.AppError = AppError;
@@ -0,0 +1,2 @@
1
+ import { NextFunction, Request, Response } from "express";
2
+ export declare const catchAsync: (fn: Function) => (req: Request, res: Response, next: NextFunction) => void;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.catchAsync = void 0;
4
+ const catchAsync = (fn) => {
5
+ return (req, res, next) => {
6
+ fn(req, res, next).catch(next);
7
+ };
8
+ };
9
+ exports.catchAsync = catchAsync;
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@akash-electron/ts-backend",
3
+ "version": "1.0.0",
4
+ "description": "A robust, scalable, and production-ready starter template for building Node.js backends with TypeScript. This boilerplate follows industry best practices for architecture, error handling, and type safety.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "dev": "nodemon --exec ts-node src/server.ts",
12
+ "build": "tsc",
13
+ "start": "node dist/server.js",
14
+ "test": "echo \"Error: no test specified\" && exit 1"
15
+ },
16
+ "keywords": [],
17
+ "author": "",
18
+ "license": "MIT",
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "dependencies": {
23
+ "@types/cors": "^2.8.19",
24
+ "@types/express": "^5.0.6",
25
+ "@types/morgan": "^1.9.10",
26
+ "@types/node": "^25.2.2",
27
+ "cors": "^2.8.6",
28
+ "dotenv": "^17.2.4",
29
+ "express": "^5.2.1",
30
+ "helmet": "^8.1.0",
31
+ "morgan": "^1.10.1",
32
+ "nodemon": "^3.1.11",
33
+ "ts-node": "^10.9.2",
34
+ "typescript": "^5.9.3",
35
+ "winston": "^3.19.0",
36
+ "zod": "^4.3.6"
37
+ }
38
+ }