express-project-builder 1.0.36 → 1.0.38
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 +16 -13
- package/dist/lib/src/builders/create_QueryBuilder_Helpers.js +42 -42
- package/dist/lib/src/errors/create_HandleCastError.js +1 -1
- package/dist/lib/src/errors/create_HandleDB_ValidationError.js +3 -3
- package/dist/lib/src/errors/create_HandleDuplicateError.js +1 -1
- package/dist/lib/src/middlewares/create_Global_ErrorHandler_Guard.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -137,6 +137,7 @@ my-test-project/
|
|
|
137
137
|
├── eslint.config.mjs
|
|
138
138
|
├── package-lock.json
|
|
139
139
|
├── package.json
|
|
140
|
+
├── prisma.config.ts
|
|
140
141
|
└── tsconfig.json
|
|
141
142
|
```
|
|
142
143
|
|
|
@@ -152,11 +153,13 @@ my-test-project/
|
|
|
152
153
|
- [eslint-plugin-prettier (5.5.4)](https://www.npmjs.com/package/eslint-plugin-prettier)
|
|
153
154
|
- [express (5.1.0)](https://www.npmjs.com/package/express)
|
|
154
155
|
- [jsonwebtoken (9.0.2)](https://www.npmjs.com/package/jsonwebtoken)
|
|
155
|
-
- [mongoose (
|
|
156
|
+
- [mongoose (9.1.5)](https://www.npmjs.com/package/mongoose)
|
|
156
157
|
- [multer (2.0.2-lts.1)](https://www.npmjs.com/package/multer)
|
|
157
158
|
- [node-cache (5.1.2)](https://www.npmjs.com/package/node-cache)
|
|
158
159
|
- [nodemailer (7.0.6)](https://www.npmjs.com/package/nodemailer)
|
|
159
|
-
- [@prisma/client (
|
|
160
|
+
- [@prisma/client (7.3.0)](https://www.npmjs.com/package/@prisma/client)
|
|
161
|
+
- [@prisma/adapter-pg (7.3.0)](https://www.npmjs.com/package/@prisma/adapter-ppg)
|
|
162
|
+
- [pg (8.18.0)](https://www.npmjs.com/package/pg)
|
|
160
163
|
- [zod (3.24.1)](https://www.npmjs.com/package/zod)
|
|
161
164
|
|
|
162
165
|
### Development Dependencies
|
|
@@ -173,7 +176,7 @@ my-test-project/
|
|
|
173
176
|
- [eslint (9.35.0)](https://www.npmjs.com/package/eslint)
|
|
174
177
|
- [eslint-config-prettier (10.1.8)](https://www.npmjs.com/package/eslint-config-prettier)
|
|
175
178
|
- [globals (16.4.0)](https://www.npmjs.com/package/globals)
|
|
176
|
-
- [prisma (
|
|
179
|
+
- [prisma (7.3.0)](https://www.npmjs.com/package/prisma)
|
|
177
180
|
- [prettier (3.6.2)](https://www.npmjs.com/package/prettier)
|
|
178
181
|
- [ts-node-dev (2.0.0)](https://www.npmjs.com/package/ts-node-dev)
|
|
179
182
|
- [typescript (5.9.2)](https://www.npmjs.com/package/typescript)
|
|
@@ -301,14 +304,14 @@ import auth from "../../middlewares/auth";
|
|
|
301
304
|
router.get(
|
|
302
305
|
"/users",
|
|
303
306
|
auth("user", "admin", "superAdmin", "developer"), // Only users with these roles can access
|
|
304
|
-
UsersControllers.getAllUsers
|
|
307
|
+
UsersControllers.getAllUsers,
|
|
305
308
|
);
|
|
306
309
|
|
|
307
310
|
// Protect a route without role checking (just verify token)
|
|
308
311
|
router.get(
|
|
309
312
|
"/profile",
|
|
310
313
|
auth("user", "admin", "superAdmin", "developer", true), // Any authenticated user can access
|
|
311
|
-
UsersController.getUserProfile
|
|
314
|
+
UsersController.getUserProfile,
|
|
312
315
|
);
|
|
313
316
|
```
|
|
314
317
|
|
|
@@ -380,7 +383,7 @@ router.post(
|
|
|
380
383
|
},
|
|
381
384
|
]),
|
|
382
385
|
formDataToSetJSONformatData, // Convert form data to JSON
|
|
383
|
-
ProductController.createProduct
|
|
386
|
+
ProductController.createProduct,
|
|
384
387
|
);
|
|
385
388
|
```
|
|
386
389
|
|
|
@@ -428,7 +431,7 @@ import { ProductValidation } from "../../app/models/product_validationZodSchema"
|
|
|
428
431
|
router.post(
|
|
429
432
|
"/create",
|
|
430
433
|
validateRequest(ProductValidation.createProduct_ValidationZodSchema),
|
|
431
|
-
ProductControllers.createProduct
|
|
434
|
+
ProductControllers.createProduct,
|
|
432
435
|
);
|
|
433
436
|
|
|
434
437
|
// /src/app/models/product_validationZodSchema.ts
|
|
@@ -508,7 +511,7 @@ const get_All_Products = catchAsync(async (req, res) => {
|
|
|
508
511
|
// Your async controller logic here
|
|
509
512
|
const result = await Product_Services.get_All_Products_FromDB(
|
|
510
513
|
req.body,
|
|
511
|
-
req.query
|
|
514
|
+
req.query,
|
|
512
515
|
);
|
|
513
516
|
|
|
514
517
|
res.status(200).json({
|
|
@@ -579,7 +582,7 @@ const barcodeId = generateRandomBarcodeId(); // Returns: "153.04.55.022"
|
|
|
579
582
|
const token = createToken(
|
|
580
583
|
{ user_id: "123", role: "admin" },
|
|
581
584
|
config.jwt_access_token_secret,
|
|
582
|
-
config.jwt_access_token_expires_in
|
|
585
|
+
config.jwt_access_token_expires_in,
|
|
583
586
|
); // Returns JWT token
|
|
584
587
|
|
|
585
588
|
// JWT Token Verify and Decode
|
|
@@ -606,7 +609,7 @@ const isInvalid = isValidDate(payload.date); // Returns: false
|
|
|
606
609
|
// Validate and normalize start and end dates
|
|
607
610
|
const { start, end } = Start_End_DateTime_Validation(
|
|
608
611
|
payload.start_date,
|
|
609
|
-
payload.end_date
|
|
612
|
+
payload.end_date,
|
|
610
613
|
);
|
|
611
614
|
// Returns: { start: Date, end: Date } with proper date objects
|
|
612
615
|
|
|
@@ -621,7 +624,7 @@ const isoDate = formatDateToISOString(new Date());
|
|
|
621
624
|
const daysDiff = getDateDifference(
|
|
622
625
|
payload.start_date,
|
|
623
626
|
payload.end_date,
|
|
624
|
-
"days"
|
|
627
|
+
"days",
|
|
625
628
|
); // Returns: 9
|
|
626
629
|
```
|
|
627
630
|
|
|
@@ -729,7 +732,7 @@ import sendResponse from "../../utils/sendResponse";
|
|
|
729
732
|
const get_AllProducts = catchAsync(async (req, res) => {
|
|
730
733
|
const result = await Product_Services.fetch_AllProductsFromDB(
|
|
731
734
|
req.params.user_id,
|
|
732
|
-
req.query
|
|
735
|
+
req.query,
|
|
733
736
|
);
|
|
734
737
|
|
|
735
738
|
res.status(200).json({
|
|
@@ -744,7 +747,7 @@ const get_AllProducts = catchAsync(async (req, res) => {
|
|
|
744
747
|
const get_AllProducts = catchAsync(async (req, res) => {
|
|
745
748
|
const result = await Product_Services.fetch_AllProductsFromDB(
|
|
746
749
|
req.params.user_id,
|
|
747
|
-
req.query
|
|
750
|
+
req.query,
|
|
748
751
|
);
|
|
749
752
|
|
|
750
753
|
sendResponse(res, {
|
|
@@ -6,16 +6,16 @@ export const create_QueryBuilder_Helpers = async (projectPath, answers) => {
|
|
|
6
6
|
try {
|
|
7
7
|
// Create MongoDB QueryBuilder if MongoDB is selected
|
|
8
8
|
if (answers.database === "MongoDB with Mongoose") {
|
|
9
|
-
const mongoQueryBuilderTemplate = `import {
|
|
9
|
+
const mongoQueryBuilderTemplate = `import { Query } from 'mongoose'
|
|
10
10
|
/**
|
|
11
11
|
* MongoDB Query Builder class for building complex queries with chaining methods
|
|
12
12
|
*/
|
|
13
13
|
class QueryBuilder<T> {
|
|
14
|
-
public modelQuery: Query<T[], T
|
|
15
|
-
public query: Record<string, unknown
|
|
14
|
+
public modelQuery: Query<T[], T>
|
|
15
|
+
public query: Record<string, unknown>
|
|
16
16
|
constructor(modelQuery: Query<T[], T>, query: Record<string, unknown>) {
|
|
17
|
-
this.modelQuery = modelQuery
|
|
18
|
-
this.query = query
|
|
17
|
+
this.modelQuery = modelQuery
|
|
18
|
+
this.query = query
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Add search functionality to the query
|
|
@@ -23,82 +23,82 @@ class QueryBuilder<T> {
|
|
|
23
23
|
* @returns QueryBuilder instance for chaining
|
|
24
24
|
*/
|
|
25
25
|
search(searchableFields: string[]): this {
|
|
26
|
-
const searchTerm = this.query.search as string
|
|
26
|
+
const searchTerm = this.query.search as string
|
|
27
27
|
if (searchTerm) {
|
|
28
28
|
this.modelQuery = this.modelQuery.find({
|
|
29
|
-
$or: searchableFields.map(
|
|
30
|
-
field
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
)
|
|
34
|
-
});
|
|
29
|
+
$or: searchableFields.map(field => ({
|
|
30
|
+
[field]: { $regex: searchTerm, $options: 'i' }
|
|
31
|
+
}))
|
|
32
|
+
})
|
|
35
33
|
}
|
|
36
|
-
return this
|
|
34
|
+
return this
|
|
37
35
|
}
|
|
38
36
|
/**
|
|
39
37
|
* Add filtering to the query
|
|
40
38
|
* @returns QueryBuilder instance for chaining
|
|
41
39
|
*/
|
|
42
40
|
filter(): this {
|
|
43
|
-
const queryObj = { ...this.query }
|
|
44
|
-
const excludeFields = ['search', 'sort', 'page', 'limit', 'fields']
|
|
45
|
-
excludeFields.forEach(el => delete queryObj[el])
|
|
46
|
-
|
|
47
|
-
this.modelQuery = this.modelQuery.find(queryObj
|
|
48
|
-
return this
|
|
41
|
+
const queryObj = { ...this.query }
|
|
42
|
+
const excludeFields = ['search', 'sort', 'page', 'limit', 'fields']
|
|
43
|
+
excludeFields.forEach(el => delete queryObj[el])
|
|
44
|
+
|
|
45
|
+
this.modelQuery = this.modelQuery.find(queryObj)
|
|
46
|
+
return this
|
|
49
47
|
}
|
|
50
48
|
/**
|
|
51
49
|
* Add sorting to the query
|
|
52
50
|
* @returns QueryBuilder instance for chaining
|
|
53
51
|
*/
|
|
54
52
|
sort(): this {
|
|
55
|
-
const sortField =
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
const sortField =
|
|
54
|
+
(this.query.sort as string)?.split(',')?.join(' ') || '-createdAt'
|
|
55
|
+
this.modelQuery = this.modelQuery.sort(sortField)
|
|
56
|
+
return this
|
|
58
57
|
}
|
|
59
58
|
/**
|
|
60
59
|
* Add pagination to the query
|
|
61
60
|
* @returns QueryBuilder instance for chaining
|
|
62
61
|
*/
|
|
63
62
|
paginate(): this {
|
|
64
|
-
const page = Number(this.query.page) || 1
|
|
65
|
-
const limit = Number(this.query.limit) || 10
|
|
66
|
-
const skip = (page - 1) * limit
|
|
67
|
-
|
|
68
|
-
this.modelQuery = this.modelQuery.skip(skip).limit(limit)
|
|
69
|
-
return this
|
|
63
|
+
const page = Number(this.query.page) || 1
|
|
64
|
+
const limit = Number(this.query.limit) || 10
|
|
65
|
+
const skip = (page - 1) * limit
|
|
66
|
+
|
|
67
|
+
this.modelQuery = this.modelQuery.skip(skip).limit(limit)
|
|
68
|
+
return this
|
|
70
69
|
}
|
|
71
70
|
/**
|
|
72
71
|
* Field selection to include/exclude specific fields
|
|
73
72
|
* @returns QueryBuilder instance for chaining
|
|
74
73
|
*/
|
|
75
74
|
fields(): this {
|
|
76
|
-
const fields =
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
const fields =
|
|
76
|
+
(this.query.fields as string)?.split(',')?.join(' ') || '-__v'
|
|
77
|
+
this.modelQuery = this.modelQuery.select(fields)
|
|
78
|
+
return this
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* Get total count and pagination metadata
|
|
82
82
|
* @returns Object with pagination metadata
|
|
83
83
|
*/
|
|
84
84
|
async countTotal(): Promise<{
|
|
85
|
-
page: number
|
|
86
|
-
limit: number
|
|
87
|
-
totalData: number
|
|
88
|
-
totalPage: number
|
|
85
|
+
page: number
|
|
86
|
+
limit: number
|
|
87
|
+
totalData: number
|
|
88
|
+
totalPage: number
|
|
89
89
|
}> {
|
|
90
|
-
const totalQueries = this.modelQuery.getFilter()
|
|
91
|
-
const totalData = await this.modelQuery.model.countDocuments(totalQueries)
|
|
92
|
-
const page = Number(this.query.page) || 1
|
|
93
|
-
const limit = Number(this.query.limit) || 10
|
|
94
|
-
const totalPage = Math.ceil(totalData / limit)
|
|
95
|
-
|
|
90
|
+
const totalQueries = this.modelQuery.getFilter()
|
|
91
|
+
const totalData = await this.modelQuery.model.countDocuments(totalQueries)
|
|
92
|
+
const page = Number(this.query.page) || 1
|
|
93
|
+
const limit = Number(this.query.limit) || 10
|
|
94
|
+
const totalPage = Math.ceil(totalData / limit)
|
|
95
|
+
|
|
96
96
|
return {
|
|
97
97
|
page,
|
|
98
98
|
limit,
|
|
99
99
|
totalData,
|
|
100
100
|
totalPage
|
|
101
|
-
}
|
|
101
|
+
}
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
export default QueryBuilder;
|
|
@@ -40,7 +40,7 @@ export default handleMongooseCastError;
|
|
|
40
40
|
await createFile(path.join(projectPath, "src/app/errors", "handleMongooseCastError.ts"), handleMongooseCastErrorTemplate);
|
|
41
41
|
}
|
|
42
42
|
if (answers.database === "PostgreSQL with Prisma") {
|
|
43
|
-
const handlePrismaCastErrorTemplate = `import { PrismaClientKnownRequestError } from '
|
|
43
|
+
const handlePrismaCastErrorTemplate = `import { PrismaClientKnownRequestError } from '../../generated/prisma/internal/prismaNamespace';
|
|
44
44
|
import { TErrorSource, TGenericErrorResponse } from '../interfaces/errors'
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -43,9 +43,9 @@ export default handleMongooseValidationError;
|
|
|
43
43
|
}
|
|
44
44
|
if (answers.database === "PostgreSQL with Prisma") {
|
|
45
45
|
const handlePrismaValidationErrorTemplate = `import {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
} from '
|
|
46
|
+
PrismaClientKnownRequestError,
|
|
47
|
+
PrismaClientValidationError
|
|
48
|
+
} from '../../generated/prisma/internal/prismaNamespace';
|
|
49
49
|
import { TErrorSource, TGenericErrorResponse } from '../interfaces/errors'
|
|
50
50
|
|
|
51
51
|
/**
|
|
@@ -43,7 +43,7 @@ export default handleMongooseDuplicateError;
|
|
|
43
43
|
await createFile(path.join(projectPath, "src/app/errors", "handleMongooseDuplicateError.ts"), handleMongooseDuplicateErrorTemplate);
|
|
44
44
|
}
|
|
45
45
|
if (answers.database === "PostgreSQL with Prisma") {
|
|
46
|
-
const handlePrismaDuplicateErrorTemplate = `import { PrismaClientKnownRequestError } from '
|
|
46
|
+
const handlePrismaDuplicateErrorTemplate = `import { PrismaClientKnownRequestError } from '../../generated/prisma/internal/prismaNamespace';
|
|
47
47
|
import { TErrorSource, TGenericErrorResponse } from '../interfaces/errors'
|
|
48
48
|
|
|
49
49
|
/**
|
|
@@ -135,7 +135,7 @@ import { NextFunction, Request, Response } from 'express'
|
|
|
135
135
|
import {
|
|
136
136
|
PrismaClientKnownRequestError,
|
|
137
137
|
PrismaClientValidationError
|
|
138
|
-
} from '
|
|
138
|
+
} from '../../generated/prisma/internal/prismaNamespace';
|
|
139
139
|
import { TErrorSource, TGenericErrorResponse } from '../interfaces/errors'
|
|
140
140
|
import { ZodError } from 'zod'
|
|
141
141
|
import handleZodValidationError from '../errors/handleZodValidationError'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-project-builder",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.38",
|
|
4
4
|
"description": "A powerful and professional Express.js project generator CLI that instantly scaffolds a production-ready backend with TypeScript, modular architecture, and built-in support for MongoDB (Mongoose) or PostgreSQL (Prisma). Includes authentication, error handling, rate limiting, file upload, caching, and utility functions—so you can focus on building features instead of boilerplate. Perfect for kickstarting your next Express.js API project with best practices and modern tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/bin/index.js",
|