express-project-builder 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/dist/bin/index.d.ts +3 -0
- package/dist/bin/index.d.ts.map +1 -0
- package/dist/bin/index.js +177 -0
- package/dist/bin/index.js.map +1 -0
- package/dist/lib/config/createEnvExample.d.ts +3 -0
- package/dist/lib/config/createEnvExample.d.ts.map +1 -0
- package/dist/lib/config/createEnvExample.js +39 -0
- package/dist/lib/config/createEnvExample.js.map +1 -0
- package/dist/lib/config/createEslintConfig.d.ts +2 -0
- package/dist/lib/config/createEslintConfig.d.ts.map +1 -0
- package/dist/lib/config/createEslintConfig.js +48 -0
- package/dist/lib/config/createEslintConfig.js.map +1 -0
- package/dist/lib/config/createGitignore.d.ts +3 -0
- package/dist/lib/config/createGitignore.d.ts.map +1 -0
- package/dist/lib/config/createGitignore.js +51 -0
- package/dist/lib/config/createGitignore.js.map +1 -0
- package/dist/lib/config/createPackageJson.d.ts +3 -0
- package/dist/lib/config/createPackageJson.d.ts.map +1 -0
- package/dist/lib/config/createPackageJson.js +74 -0
- package/dist/lib/config/createPackageJson.js.map +1 -0
- package/dist/lib/config/createPrettierConfig.d.ts +2 -0
- package/dist/lib/config/createPrettierConfig.d.ts.map +1 -0
- package/dist/lib/config/createPrettierConfig.js +30 -0
- package/dist/lib/config/createPrettierConfig.js.map +1 -0
- package/dist/lib/config/createTsConfig.d.ts +2 -0
- package/dist/lib/config/createTsConfig.d.ts.map +1 -0
- package/dist/lib/config/createTsConfig.js +133 -0
- package/dist/lib/config/createTsConfig.js.map +1 -0
- package/dist/lib/prisma/create_Schema.Prisma.d.ts +3 -0
- package/dist/lib/prisma/create_Schema.Prisma.d.ts.map +1 -0
- package/dist/lib/prisma/create_Schema.Prisma.js +36 -0
- package/dist/lib/prisma/create_Schema.Prisma.js.map +1 -0
- package/dist/lib/src/builders/create_QueryBuilder_Helpers.d.ts +3 -0
- package/dist/lib/src/builders/create_QueryBuilder_Helpers.d.ts.map +1 -0
- package/dist/lib/src/builders/create_QueryBuilder_Helpers.js +292 -0
- package/dist/lib/src/builders/create_QueryBuilder_Helpers.js.map +1 -0
- package/dist/lib/src/config/create_Config_Index.d.ts +9 -0
- package/dist/lib/src/config/create_Config_Index.d.ts.map +1 -0
- package/dist/lib/src/config/create_Config_Index.js +92 -0
- package/dist/lib/src/config/create_Config_Index.js.map +1 -0
- package/dist/lib/src/constants/create_UserRole_Constant.d.ts +7 -0
- package/dist/lib/src/constants/create_UserRole_Constant.d.ts.map +1 -0
- package/dist/lib/src/constants/create_UserRole_Constant.js +39 -0
- package/dist/lib/src/constants/create_UserRole_Constant.js.map +1 -0
- package/dist/lib/src/createAppFile.d.ts +2 -0
- package/dist/lib/src/createAppFile.d.ts.map +1 -0
- package/dist/lib/src/createAppFile.js +122 -0
- package/dist/lib/src/createAppFile.js.map +1 -0
- package/dist/lib/src/createServerFile.d.ts +3 -0
- package/dist/lib/src/createServerFile.d.ts.map +1 -0
- package/dist/lib/src/createServerFile.js +75 -0
- package/dist/lib/src/createServerFile.js.map +1 -0
- package/dist/lib/src/createSrcStructure.d.ts +2 -0
- package/dist/lib/src/createSrcStructure.d.ts.map +1 -0
- package/dist/lib/src/createSrcStructure.js +50 -0
- package/dist/lib/src/createSrcStructure.js.map +1 -0
- package/dist/lib/src/errors/create_AppError_Class.d.ts +7 -0
- package/dist/lib/src/errors/create_AppError_Class.d.ts.map +1 -0
- package/dist/lib/src/errors/create_AppError_Class.js +65 -0
- package/dist/lib/src/errors/create_AppError_Class.js.map +1 -0
- package/dist/lib/src/errors/create_HandleCastError.d.ts +9 -0
- package/dist/lib/src/errors/create_HandleCastError.d.ts.map +1 -0
- package/dist/lib/src/errors/create_HandleCastError.js +101 -0
- package/dist/lib/src/errors/create_HandleCastError.js.map +1 -0
- package/dist/lib/src/errors/create_HandleDB_ValidationError.d.ts +9 -0
- package/dist/lib/src/errors/create_HandleDB_ValidationError.d.ts.map +1 -0
- package/dist/lib/src/errors/create_HandleDB_ValidationError.js +119 -0
- package/dist/lib/src/errors/create_HandleDB_ValidationError.js.map +1 -0
- package/dist/lib/src/errors/create_HandleDuplicateError.d.ts +9 -0
- package/dist/lib/src/errors/create_HandleDuplicateError.d.ts.map +1 -0
- package/dist/lib/src/errors/create_HandleDuplicateError.js +99 -0
- package/dist/lib/src/errors/create_HandleDuplicateError.js.map +1 -0
- package/dist/lib/src/errors/create_HandleZodValidationError.d.ts +7 -0
- package/dist/lib/src/errors/create_HandleZodValidationError.d.ts.map +1 -0
- package/dist/lib/src/errors/create_HandleZodValidationError.js +50 -0
- package/dist/lib/src/errors/create_HandleZodValidationError.js.map +1 -0
- package/dist/lib/src/interfaces/create_EmailFomat_type.d.ts +7 -0
- package/dist/lib/src/interfaces/create_EmailFomat_type.d.ts.map +1 -0
- package/dist/lib/src/interfaces/create_EmailFomat_type.js +34 -0
- package/dist/lib/src/interfaces/create_EmailFomat_type.js.map +1 -0
- package/dist/lib/src/interfaces/create_Errors_type.d.ts +7 -0
- package/dist/lib/src/interfaces/create_Errors_type.d.ts.map +1 -0
- package/dist/lib/src/interfaces/create_Errors_type.js +43 -0
- package/dist/lib/src/interfaces/create_Errors_type.js.map +1 -0
- package/dist/lib/src/interfaces/create_Index_d_type.d.ts +9 -0
- package/dist/lib/src/interfaces/create_Index_d_type.d.ts.map +1 -0
- package/dist/lib/src/interfaces/create_Index_d_type.js +45 -0
- package/dist/lib/src/interfaces/create_Index_d_type.js.map +1 -0
- package/dist/lib/src/interfaces/create_JWT_Token_type.d.ts +9 -0
- package/dist/lib/src/interfaces/create_JWT_Token_type.d.ts.map +1 -0
- package/dist/lib/src/interfaces/create_JWT_Token_type.js +33 -0
- package/dist/lib/src/interfaces/create_JWT_Token_type.js.map +1 -0
- package/dist/lib/src/interfaces/create_UserRole_type.d.ts +7 -0
- package/dist/lib/src/interfaces/create_UserRole_type.d.ts.map +1 -0
- package/dist/lib/src/interfaces/create_UserRole_type.js +33 -0
- package/dist/lib/src/interfaces/create_UserRole_type.js.map +1 -0
- package/dist/lib/src/middlewares/create_Auth_Gurad.d.ts +9 -0
- package/dist/lib/src/middlewares/create_Auth_Gurad.d.ts.map +1 -0
- package/dist/lib/src/middlewares/create_Auth_Gurad.js +99 -0
- package/dist/lib/src/middlewares/create_Auth_Gurad.js.map +1 -0
- package/dist/lib/src/middlewares/create_BigIntSerializer_Guard.d.ts +7 -0
- package/dist/lib/src/middlewares/create_BigIntSerializer_Guard.d.ts.map +1 -0
- package/dist/lib/src/middlewares/create_BigIntSerializer_Guard.js +64 -0
- package/dist/lib/src/middlewares/create_BigIntSerializer_Guard.js.map +1 -0
- package/dist/lib/src/middlewares/create_FormDataToSetJSONformatData_Guard.d.ts +7 -0
- package/dist/lib/src/middlewares/create_FormDataToSetJSONformatData_Guard.d.ts.map +1 -0
- package/dist/lib/src/middlewares/create_FormDataToSetJSONformatData_Guard.js +63 -0
- package/dist/lib/src/middlewares/create_FormDataToSetJSONformatData_Guard.js.map +1 -0
- package/dist/lib/src/middlewares/create_Global_ErrorHandler_Guard.d.ts +12 -0
- package/dist/lib/src/middlewares/create_Global_ErrorHandler_Guard.d.ts.map +1 -0
- package/dist/lib/src/middlewares/create_Global_ErrorHandler_Guard.js +375 -0
- package/dist/lib/src/middlewares/create_Global_ErrorHandler_Guard.js.map +1 -0
- package/dist/lib/src/middlewares/create_Handle_File_Upload_Middleware.d.ts +7 -0
- package/dist/lib/src/middlewares/create_Handle_File_Upload_Middleware.d.ts.map +1 -0
- package/dist/lib/src/middlewares/create_Handle_File_Upload_Middleware.js +260 -0
- package/dist/lib/src/middlewares/create_Handle_File_Upload_Middleware.js.map +1 -0
- package/dist/lib/src/middlewares/create_NotFound_Guard.d.ts +7 -0
- package/dist/lib/src/middlewares/create_NotFound_Guard.d.ts.map +1 -0
- package/dist/lib/src/middlewares/create_NotFound_Guard.js +47 -0
- package/dist/lib/src/middlewares/create_NotFound_Guard.js.map +1 -0
- package/dist/lib/src/middlewares/create_RateLimiting_Handler_Guard.d.ts +7 -0
- package/dist/lib/src/middlewares/create_RateLimiting_Handler_Guard.d.ts.map +1 -0
- package/dist/lib/src/middlewares/create_RateLimiting_Handler_Guard.js +270 -0
- package/dist/lib/src/middlewares/create_RateLimiting_Handler_Guard.js.map +1 -0
- package/dist/lib/src/middlewares/create_ValidateRequest_Guard.d.ts +7 -0
- package/dist/lib/src/middlewares/create_ValidateRequest_Guard.d.ts.map +1 -0
- package/dist/lib/src/middlewares/create_ValidateRequest_Guard.js +104 -0
- package/dist/lib/src/middlewares/create_ValidateRequest_Guard.js.map +1 -0
- package/dist/lib/src/modules/create_DemoModules_SrcStructure.d.ts +7 -0
- package/dist/lib/src/modules/create_DemoModules_SrcStructure.d.ts.map +1 -0
- package/dist/lib/src/modules/create_DemoModules_SrcStructure.js +367 -0
- package/dist/lib/src/modules/create_DemoModules_SrcStructure.js.map +1 -0
- package/dist/lib/src/routers/create_Router_Index_Path.d.ts +7 -0
- package/dist/lib/src/routers/create_Router_Index_Path.d.ts.map +1 -0
- package/dist/lib/src/routers/create_Router_Index_Path.js +54 -0
- package/dist/lib/src/routers/create_Router_Index_Path.js.map +1 -0
- package/dist/lib/src/shared/create_Prisma_Shated.d.ts +9 -0
- package/dist/lib/src/shared/create_Prisma_Shated.d.ts.map +1 -0
- package/dist/lib/src/shared/create_Prisma_Shated.js +34 -0
- package/dist/lib/src/shared/create_Prisma_Shated.js.map +1 -0
- package/dist/lib/src/utils/createCatchAsync_Utils.d.ts +7 -0
- package/dist/lib/src/utils/createCatchAsync_Utils.d.ts.map +1 -0
- package/dist/lib/src/utils/createCatchAsync_Utils.js +59 -0
- package/dist/lib/src/utils/createCatchAsync_Utils.js.map +1 -0
- package/dist/lib/src/utils/createLoggerFile.d.ts +7 -0
- package/dist/lib/src/utils/createLoggerFile.d.ts.map +1 -0
- package/dist/lib/src/utils/createLoggerFile.js +35 -0
- package/dist/lib/src/utils/createLoggerFile.js.map +1 -0
- package/dist/lib/src/utils/create_Common_Utils.d.ts +9 -0
- package/dist/lib/src/utils/create_Common_Utils.d.ts.map +1 -0
- package/dist/lib/src/utils/create_Common_Utils.js +262 -0
- package/dist/lib/src/utils/create_Common_Utils.js.map +1 -0
- package/dist/lib/src/utils/create_Date_Time_Validation_Utils.d.ts +7 -0
- package/dist/lib/src/utils/create_Date_Time_Validation_Utils.d.ts.map +1 -0
- package/dist/lib/src/utils/create_Date_Time_Validation_Utils.js +181 -0
- package/dist/lib/src/utils/create_Date_Time_Validation_Utils.js.map +1 -0
- package/dist/lib/src/utils/create_Node_Cache_Utils.d.ts +7 -0
- package/dist/lib/src/utils/create_Node_Cache_Utils.d.ts.map +1 -0
- package/dist/lib/src/utils/create_Node_Cache_Utils.js +149 -0
- package/dist/lib/src/utils/create_Node_Cache_Utils.js.map +1 -0
- package/dist/lib/src/utils/create_Remove_Uploaded_Files_Utils.d.ts +7 -0
- package/dist/lib/src/utils/create_Remove_Uploaded_Files_Utils.d.ts.map +1 -0
- package/dist/lib/src/utils/create_Remove_Uploaded_Files_Utils.js +162 -0
- package/dist/lib/src/utils/create_Remove_Uploaded_Files_Utils.js.map +1 -0
- package/dist/lib/src/utils/create_SendEmail_Utils.d.ts +7 -0
- package/dist/lib/src/utils/create_SendEmail_Utils.d.ts.map +1 -0
- package/dist/lib/src/utils/create_SendEmail_Utils.js +140 -0
- package/dist/lib/src/utils/create_SendEmail_Utils.js.map +1 -0
- package/dist/lib/src/utils/create_sendResponse_Utils.d.ts +7 -0
- package/dist/lib/src/utils/create_sendResponse_Utils.d.ts.map +1 -0
- package/dist/lib/src/utils/create_sendResponse_Utils.js +95 -0
- package/dist/lib/src/utils/create_sendResponse_Utils.js.map +1 -0
- package/dist/lib/utils/helpers.d.ts +5 -0
- package/dist/lib/utils/helpers.d.ts.map +1 -0
- package/dist/lib/utils/helpers.js +31 -0
- package/dist/lib/utils/helpers.js.map +1 -0
- package/dist/lib/utils/types.d.ts +5 -0
- package/dist/lib/utils/types.d.ts.map +1 -0
- package/dist/lib/utils/types.js +2 -0
- package/dist/lib/utils/types.js.map +1 -0
- package/package.json +87 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { createFile } from "../../utils/helpers.js";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a file upload middleware with dynamic field configuration
|
|
6
|
+
* @param projectPath - Absolute path to the project root
|
|
7
|
+
* @returns Promise that resolves when the file upload middleware file is created
|
|
8
|
+
*/
|
|
9
|
+
export const create_Handle_File_Upload_Middleware = async (projectPath) => {
|
|
10
|
+
try {
|
|
11
|
+
const handleFileUploadTemplate = `/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
12
|
+
import multer from 'multer';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import fs from 'fs/promises';
|
|
15
|
+
import { Request, Response, NextFunction } from 'express';
|
|
16
|
+
import AppError from '../errors/AppError';
|
|
17
|
+
import { removeUploadedFiles } from '../utils/removeUploadedFiles';
|
|
18
|
+
|
|
19
|
+
// Default constants
|
|
20
|
+
const DEFAULT_MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5MB
|
|
21
|
+
const DEFAULT_MAX_VIDEO_SIZE = 50 * 1024 * 1024; // 50MB
|
|
22
|
+
|
|
23
|
+
// Default allowed file types
|
|
24
|
+
const DEFAULT_ALLOWED_IMAGE_TYPES = [
|
|
25
|
+
'image/jpeg',
|
|
26
|
+
'image/png',
|
|
27
|
+
'image/gif',
|
|
28
|
+
'image/webp',
|
|
29
|
+
'image/bmp',
|
|
30
|
+
'image/svg+xml'
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const DEFAULT_ALLOWED_VIDEO_TYPES = [
|
|
34
|
+
'video/mp4',
|
|
35
|
+
'video/webm',
|
|
36
|
+
'video/mov',
|
|
37
|
+
'video/avi',
|
|
38
|
+
'video/mkv'
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// Helper function to ensure directory exists
|
|
42
|
+
async function ensureDirectoryExists(dirPath: string): Promise<void> {
|
|
43
|
+
try {
|
|
44
|
+
await fs.access(dirPath);
|
|
45
|
+
} catch {
|
|
46
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Dynamic storage configuration
|
|
51
|
+
const storage = multer.diskStorage({
|
|
52
|
+
destination: async (req: Request, file, cb) => {
|
|
53
|
+
let uploadPath: string;
|
|
54
|
+
|
|
55
|
+
// Determine upload path based on file type
|
|
56
|
+
if (file.mimetype.startsWith('image/')) {
|
|
57
|
+
uploadPath = path.join(process.cwd(), 'uploads/images');
|
|
58
|
+
} else if (file.mimetype.startsWith('video/')) {
|
|
59
|
+
uploadPath = path.join(process.cwd(), 'uploads/videos');
|
|
60
|
+
} else {
|
|
61
|
+
return cb(new AppError(400, '', 'Invalid file type'), '');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
await ensureDirectoryExists(uploadPath);
|
|
66
|
+
cb(null, uploadPath);
|
|
67
|
+
} catch (error: any) {
|
|
68
|
+
cb(error, '');
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
filename: (req: Request, file, cb) => {
|
|
72
|
+
const ext = path.extname(file.originalname);
|
|
73
|
+
const originalName = path.basename(file.originalname, ext);
|
|
74
|
+
// Use a more unique filename to avoid collisions
|
|
75
|
+
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
|
|
76
|
+
cb(null, \`\${originalName}-\${uniqueSuffix}\${ext}\`);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Multer instance with global file size limit
|
|
81
|
+
const upload = multer({
|
|
82
|
+
storage,
|
|
83
|
+
limits: { fileSize: DEFAULT_MAX_VIDEO_SIZE },
|
|
84
|
+
fileFilter: (req: Request, file, cb) => {
|
|
85
|
+
// Basic file type validation at the multer level
|
|
86
|
+
if (file.mimetype.startsWith('image/') || file.mimetype.startsWith('video/')) {
|
|
87
|
+
cb(null, true);
|
|
88
|
+
} else {
|
|
89
|
+
cb(new AppError(400, '', 'Invalid file type. Only images and videos are allowed.'));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Field configuration interface
|
|
95
|
+
interface FieldConfig {
|
|
96
|
+
fieldName: string;
|
|
97
|
+
fileType: 'image' | 'video';
|
|
98
|
+
maxCount?: number;
|
|
99
|
+
optional?: boolean;
|
|
100
|
+
maxImageSize?: number;
|
|
101
|
+
maxVideoSize?: number;
|
|
102
|
+
allowedImageTypes?: string[];
|
|
103
|
+
allowedVideoTypes?: string[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Main dynamic upload handler for multiple fields
|
|
107
|
+
export const handle_file_upload_middleware = (
|
|
108
|
+
fieldConfigs: FieldConfig[],
|
|
109
|
+
globalOptions?: {
|
|
110
|
+
maxImageSize?: number;
|
|
111
|
+
maxVideoSize?: number;
|
|
112
|
+
allowedImageTypes?: string[];
|
|
113
|
+
allowedVideoTypes?: string[];
|
|
114
|
+
}
|
|
115
|
+
) => {
|
|
116
|
+
// Set global defaults with options
|
|
117
|
+
const globalMaxImageSize = globalOptions?.maxImageSize || DEFAULT_MAX_IMAGE_SIZE;
|
|
118
|
+
const globalMaxVideoSize = globalOptions?.maxVideoSize || DEFAULT_MAX_VIDEO_SIZE;
|
|
119
|
+
const globalAllowedImageTypes = globalOptions?.allowedImageTypes || DEFAULT_ALLOWED_IMAGE_TYPES;
|
|
120
|
+
const globalAllowedVideoTypes = globalOptions?.allowedVideoTypes || DEFAULT_ALLOWED_VIDEO_TYPES;
|
|
121
|
+
|
|
122
|
+
return (req: Request, res: Response, next: NextFunction) => {
|
|
123
|
+
// Prepare multer fields configuration
|
|
124
|
+
const multerFields = fieldConfigs.map(config => ({
|
|
125
|
+
name: config.fieldName,
|
|
126
|
+
maxCount: config.maxCount || 1
|
|
127
|
+
}));
|
|
128
|
+
|
|
129
|
+
// Use multer's fields method to handle all dynamic fields
|
|
130
|
+
upload.fields(multerFields)(req, res, async (err: any) => {
|
|
131
|
+
if (err) {
|
|
132
|
+
// Handle multer errors
|
|
133
|
+
let errorMessage = '';
|
|
134
|
+
let fieldConfig: FieldConfig | undefined;
|
|
135
|
+
|
|
136
|
+
if (err instanceof multer.MulterError) {
|
|
137
|
+
switch (err.code) {
|
|
138
|
+
case 'LIMIT_FILE_SIZE':
|
|
139
|
+
fieldConfig = fieldConfigs.find(f => f.fieldName === err.field);
|
|
140
|
+
errorMessage = \`File size exceeds maximum limit for \${err.field}\`;
|
|
141
|
+
break;
|
|
142
|
+
case 'LIMIT_FILE_COUNT':
|
|
143
|
+
fieldConfig = fieldConfigs.find(f => f.fieldName === err.field);
|
|
144
|
+
errorMessage = \`Too many files uploaded for \${err.field} (max \${fieldConfig?.maxCount || 1})\`;
|
|
145
|
+
break;
|
|
146
|
+
case 'LIMIT_UNEXPECTED_FILE':
|
|
147
|
+
fieldConfig = fieldConfigs.find(f => f.fieldName === err.field);
|
|
148
|
+
if (fieldConfig) {
|
|
149
|
+
errorMessage = \`Too many files uploaded for \${err.field} (max \${fieldConfig.maxCount || 1})\`;
|
|
150
|
+
} else {
|
|
151
|
+
errorMessage = \`Unexpected field name: \${err.field}\`;
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
case 'LIMIT_FIELD_KEY':
|
|
155
|
+
errorMessage = 'Too many fields specified';
|
|
156
|
+
break;
|
|
157
|
+
case 'LIMIT_FIELD_VALUE':
|
|
158
|
+
errorMessage = 'Field value too long';
|
|
159
|
+
break;
|
|
160
|
+
case 'LIMIT_FIELD_COUNT':
|
|
161
|
+
errorMessage = 'Too many fields';
|
|
162
|
+
break;
|
|
163
|
+
case 'LIMIT_PART_COUNT':
|
|
164
|
+
errorMessage = 'Too many parts in form';
|
|
165
|
+
break;
|
|
166
|
+
default:
|
|
167
|
+
errorMessage = \`Upload error: \${err.message}\`;
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
errorMessage = err.message;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return next(new AppError(400, fieldConfig?.fieldName || '', errorMessage));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Get uploaded files with proper typing
|
|
177
|
+
const files = req.files as { [fieldname: string]: Express.Multer.File[] } | undefined;
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
// Check for required fields
|
|
181
|
+
for (const config of fieldConfigs) {
|
|
182
|
+
if (
|
|
183
|
+
!config.optional &&
|
|
184
|
+
(!files ||
|
|
185
|
+
!files[config.fieldName] ||
|
|
186
|
+
files[config.fieldName].length === 0)
|
|
187
|
+
) {
|
|
188
|
+
throw new AppError(
|
|
189
|
+
400,
|
|
190
|
+
config.fieldName,
|
|
191
|
+
\`\${config.fieldName} file field is required\`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Validate each file in each field
|
|
197
|
+
for (const config of fieldConfigs) {
|
|
198
|
+
const fieldFiles = files?.[config.fieldName] || [];
|
|
199
|
+
|
|
200
|
+
// Determine the max size for this field
|
|
201
|
+
const maxSize = config.fileType === 'image'
|
|
202
|
+
? (config.maxImageSize || globalMaxImageSize)
|
|
203
|
+
: (config.maxVideoSize || globalMaxVideoSize);
|
|
204
|
+
|
|
205
|
+
// Determine allowed types for this field
|
|
206
|
+
const allowedTypes = config.fileType === 'image'
|
|
207
|
+
? (config.allowedImageTypes || globalAllowedImageTypes)
|
|
208
|
+
: (config.allowedVideoTypes || globalAllowedVideoTypes);
|
|
209
|
+
|
|
210
|
+
for (const file of fieldFiles) {
|
|
211
|
+
// Validate file type
|
|
212
|
+
if (!allowedTypes.includes(file.mimetype)) {
|
|
213
|
+
// Create a user-friendly list of allowed extensions
|
|
214
|
+
const allowedExtensions = allowedTypes.map(type => {
|
|
215
|
+
const parts = type.split('/');
|
|
216
|
+
return parts[1] || type;
|
|
217
|
+
}).join(', ');
|
|
218
|
+
|
|
219
|
+
throw new AppError(
|
|
220
|
+
400,
|
|
221
|
+
config.fieldName,
|
|
222
|
+
\`Invalid file type for \${config.fieldName}. Only \${allowedExtensions} files are allowed\`
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Validate file size
|
|
227
|
+
if (file.size > maxSize) {
|
|
228
|
+
throw new AppError(
|
|
229
|
+
400,
|
|
230
|
+
config.fieldName,
|
|
231
|
+
\`File size exceeds maximum limit for \${config.fieldName} (\${maxSize / (1024 * 1024)}MB)\`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// If validation passes, proceed to next middleware
|
|
238
|
+
next();
|
|
239
|
+
} catch (validationError) {
|
|
240
|
+
// Clean up all uploaded files on validation error
|
|
241
|
+
if (files) {
|
|
242
|
+
await removeUploadedFiles(files);
|
|
243
|
+
}
|
|
244
|
+
next(validationError);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
};
|
|
248
|
+
};
|
|
249
|
+
`;
|
|
250
|
+
await createFile(path.join(projectPath, "src/app/middlewares", "handleFileUpload.ts"), handleFileUploadTemplate);
|
|
251
|
+
// Success message with green checkmark and text
|
|
252
|
+
console.log(chalk.green("✅ Handle File Upload Middleware file created successfully"));
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
// Error message with red cross and text
|
|
256
|
+
console.error(chalk.red("❌ Error creating Handle File Upload Middleware file:"), err);
|
|
257
|
+
throw err;
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
//# sourceMappingURL=create_Handle_File_Upload_Middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_Handle_File_Upload_Middleware.js","sourceRoot":"","sources":["../../../../src/lib/src/middlewares/create_Handle_File_Upload_Middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;GAIG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,KAAK,EACvD,WAAmB,EACJ,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8OpC,CAAC;QAEE,MAAM,UAAU,CACd,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,qBAAqB,EAAE,qBAAqB,CAAC,EACpE,wBAAwB,CACzB,CAAC;QAEF,gDAAgD;QAChD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,2DAA2D,CAAC,CACzE,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wCAAwC;QACxC,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,sDAAsD,CAAC,EACjE,GAAG,CACJ,CAAC;QACF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a not found middleware file for handling 404 errors
|
|
3
|
+
* @param projectPath - Absolute path to the project root
|
|
4
|
+
* @returns Promise that resolves when the not found middleware file is created
|
|
5
|
+
*/
|
|
6
|
+
export declare const create_NotFound_Guard: (projectPath: string) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=create_NotFound_Guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_NotFound_Guard.d.ts","sourceRoot":"","sources":["../../../../src/lib/src/middlewares/create_NotFound_Guard.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAChC,aAAa,MAAM,KAClB,OAAO,CAAC,IAAI,CA8Cd,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { createFile } from "../../utils/helpers.js";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a not found middleware file for handling 404 errors
|
|
6
|
+
* @param projectPath - Absolute path to the project root
|
|
7
|
+
* @returns Promise that resolves when the not found middleware file is created
|
|
8
|
+
*/
|
|
9
|
+
export const create_NotFound_Guard = async (projectPath) => {
|
|
10
|
+
try {
|
|
11
|
+
const notFoundMiddlewareTemplate = `/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
12
|
+
import { NextFunction, Request, Response } from 'express';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Not Found middleware
|
|
16
|
+
* Handles requests to non-existent routes and returns a consistent 404 response
|
|
17
|
+
*
|
|
18
|
+
* @param req - Express Request object
|
|
19
|
+
* @param res - Express Response object
|
|
20
|
+
* @param next - Express NextFunction
|
|
21
|
+
*/
|
|
22
|
+
const notFound = (req: Request, res: Response, next: NextFunction) => {
|
|
23
|
+
res.status(404).json({
|
|
24
|
+
status: 404,
|
|
25
|
+
success: false,
|
|
26
|
+
message: 'API Not Found!',
|
|
27
|
+
error: {
|
|
28
|
+
path: req.originalUrl,
|
|
29
|
+
message: 'Your requested API not found',
|
|
30
|
+
method: req.method
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default notFound;
|
|
36
|
+
`;
|
|
37
|
+
await createFile(path.join(projectPath, "src/app/middlewares", "notFound.ts"), notFoundMiddlewareTemplate);
|
|
38
|
+
// Success message with green checkmark and text
|
|
39
|
+
console.log(chalk.green("✅ Not Found Middleware file created successfully"));
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
// Error message with red cross and text
|
|
43
|
+
console.error(chalk.red("❌ Error creating Not Found Middleware file:"), err);
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=create_NotFound_Guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_NotFound_Guard.js","sourceRoot":"","sources":["../../../../src/lib/src/middlewares/create_NotFound_Guard.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EACxC,WAAmB,EACJ,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,0BAA0B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;CAyBtC,CAAC;QAEE,MAAM,UAAU,CACd,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,qBAAqB,EAAE,aAAa,CAAC,EAC5D,0BAA0B,CAC3B,CAAC;QAEF,gDAAgD;QAChD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAChE,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wCAAwC;QACxC,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,6CAA6C,CAAC,EACxD,GAAG,CACJ,CAAC;QACF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a progressive rate limiter middleware file
|
|
3
|
+
* @param projectPath - Absolute path to the project root
|
|
4
|
+
* @returns Promise that resolves when the rate limiting handler file is created
|
|
5
|
+
*/
|
|
6
|
+
export declare const create_RateLimiting_Handler_Guard: (projectPath: string) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=create_RateLimiting_Handler_Guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_RateLimiting_Handler_Guard.d.ts","sourceRoot":"","sources":["../../../../src/lib/src/middlewares/create_RateLimiting_Handler_Guard.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,GAC5C,aAAa,MAAM,KAClB,OAAO,CAAC,IAAI,CA6Qd,CAAC"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { createFile } from "../../utils/helpers.js";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a progressive rate limiter middleware file
|
|
6
|
+
* @param projectPath - Absolute path to the project root
|
|
7
|
+
* @returns Promise that resolves when the rate limiting handler file is created
|
|
8
|
+
*/
|
|
9
|
+
export const create_RateLimiting_Handler_Guard = async (projectPath) => {
|
|
10
|
+
try {
|
|
11
|
+
const rateLimitingHandlerTemplate = `import { NextFunction, Request, Response } from 'express';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a progressive rate limiter with increasing block durations
|
|
15
|
+
* @param options Configuration options
|
|
16
|
+
* @returns Express middleware function
|
|
17
|
+
*/
|
|
18
|
+
export const createProgressiveRateLimiter = (
|
|
19
|
+
options: {
|
|
20
|
+
initialWindowMs?: number; // Time window for counting requests
|
|
21
|
+
initialMax?: number; // Max requests per window
|
|
22
|
+
initialBlockMs?: number; // Initial block duration
|
|
23
|
+
message?: string | object; // Custom message when blocked
|
|
24
|
+
skipSuccessfulRequests?: boolean;
|
|
25
|
+
skipFailedRequests?: boolean;
|
|
26
|
+
keyGenerator?: (req: Request) => string;
|
|
27
|
+
} = {}
|
|
28
|
+
) => {
|
|
29
|
+
// Set default values
|
|
30
|
+
const {
|
|
31
|
+
initialWindowMs = 60 * 1000, // 1 minute by default
|
|
32
|
+
initialMax = 15, // 15 requests by default
|
|
33
|
+
initialBlockMs = 20 * 60 * 1000, // 20 minutes initial block
|
|
34
|
+
message = {
|
|
35
|
+
success: false,
|
|
36
|
+
message: 'Too many requests. You are temporarily blocked.'
|
|
37
|
+
},
|
|
38
|
+
skipSuccessfulRequests = false,
|
|
39
|
+
skipFailedRequests = false,
|
|
40
|
+
keyGenerator = (req: Request) =>
|
|
41
|
+
req.ip || req.connection.remoteAddress || 'unknown'
|
|
42
|
+
} = options;
|
|
43
|
+
|
|
44
|
+
// Store for tracking request counts and blocked IPs
|
|
45
|
+
const requestCounts = new Map<string, { count: number; resetTime: number }>();
|
|
46
|
+
const blockedIPs = new Map<
|
|
47
|
+
string,
|
|
48
|
+
{
|
|
49
|
+
unblockTime: number;
|
|
50
|
+
blockHistory: { duration: number; timestamp: number }[];
|
|
51
|
+
}
|
|
52
|
+
>();
|
|
53
|
+
|
|
54
|
+
// Cleanup function to remove old entries
|
|
55
|
+
const cleanup = () => {
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
|
|
58
|
+
// Clean up request counts
|
|
59
|
+
for (const [key, value] of requestCounts.entries()) {
|
|
60
|
+
if (value.resetTime < now) {
|
|
61
|
+
requestCounts.delete(key);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Clean up blocked IPs
|
|
66
|
+
for (const [key, value] of blockedIPs.entries()) {
|
|
67
|
+
if (value.unblockTime < now) {
|
|
68
|
+
// Keep block history but remove the block
|
|
69
|
+
blockedIPs.delete(key);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Run cleanup every minute
|
|
75
|
+
setInterval(cleanup, 60 * 1000);
|
|
76
|
+
|
|
77
|
+
// Function to determine next block duration based on history
|
|
78
|
+
const calculateNextBlockDuration = (
|
|
79
|
+
blockHistory: { duration: number; timestamp: number }[]
|
|
80
|
+
): number => {
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
|
|
83
|
+
// Filter out old blocks (older than 30 days)
|
|
84
|
+
const recentBlocks = blockHistory.filter(
|
|
85
|
+
block => now - block.timestamp < 30 * 24 * 60 * 60 * 1000
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// Count blocks by duration type
|
|
89
|
+
const twentyMinBlocks = recentBlocks.filter(
|
|
90
|
+
b => b.duration === initialBlockMs
|
|
91
|
+
).length;
|
|
92
|
+
const oneDayBlocks = recentBlocks.filter(
|
|
93
|
+
b => b.duration === 24 * 60 * 60 * 1000
|
|
94
|
+
).length;
|
|
95
|
+
const sevenDayBlocks = recentBlocks.filter(
|
|
96
|
+
b => b.duration === 7 * 24 * 60 * 60 * 1000
|
|
97
|
+
).length;
|
|
98
|
+
const oneMonthBlocks = recentBlocks.filter(
|
|
99
|
+
b => b.duration === 30 * 24 * 60 * 60 * 1000
|
|
100
|
+
).length;
|
|
101
|
+
|
|
102
|
+
// Progressive blocking logic
|
|
103
|
+
if (oneMonthBlocks >= 3) {
|
|
104
|
+
// 1 year block
|
|
105
|
+
return 365 * 24 * 60 * 60 * 1000;
|
|
106
|
+
} else if (sevenDayBlocks >= 3) {
|
|
107
|
+
// 1 month block
|
|
108
|
+
return 30 * 24 * 60 * 60 * 1000;
|
|
109
|
+
} else if (oneDayBlocks >= 3) {
|
|
110
|
+
// 7 days block
|
|
111
|
+
return 7 * 24 * 60 * 60 * 1000;
|
|
112
|
+
} else if (twentyMinBlocks >= 5) {
|
|
113
|
+
// 1 day block
|
|
114
|
+
return 24 * 60 * 60 * 1000;
|
|
115
|
+
} else {
|
|
116
|
+
// Default 20 minutes block
|
|
117
|
+
return initialBlockMs;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// Function to get block message based on duration
|
|
122
|
+
const getBlockMessage = (duration: number): string | object => {
|
|
123
|
+
if (typeof message === 'string') {
|
|
124
|
+
return message;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let blockDurationText = '';
|
|
128
|
+
if (duration >= 365 * 24 * 60 * 60 * 1000) {
|
|
129
|
+
blockDurationText = '1 year';
|
|
130
|
+
} else if (duration >= 30 * 24 * 60 * 60 * 1000) {
|
|
131
|
+
blockDurationText = '1 month';
|
|
132
|
+
} else if (duration >= 7 * 24 * 60 * 60 * 1000) {
|
|
133
|
+
blockDurationText = '7 days';
|
|
134
|
+
} else if (duration >= 24 * 60 * 60 * 1000) {
|
|
135
|
+
blockDurationText = '1 day';
|
|
136
|
+
} else {
|
|
137
|
+
blockDurationText = \`\${initialBlockMs ? initialBlockMs / 60000 : 20} minutes\`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
...message,
|
|
142
|
+
message: \`Too many requests. You are blocked for \${blockDurationText}.\`
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Helper function to set rate limit headers
|
|
147
|
+
const setRateLimitHeaders = (
|
|
148
|
+
res: Response,
|
|
149
|
+
limit: number,
|
|
150
|
+
remaining: number,
|
|
151
|
+
resetTime: number,
|
|
152
|
+
retryAfter?: number
|
|
153
|
+
) => {
|
|
154
|
+
res.setHeader('X-RateLimit-Limit', limit.toString());
|
|
155
|
+
res.setHeader('X-RateLimit-Remaining', remaining.toString());
|
|
156
|
+
res.setHeader('X-RateLimit-Reset', Math.ceil(resetTime / 1000).toString());
|
|
157
|
+
if (retryAfter) {
|
|
158
|
+
res.setHeader('Retry-After', retryAfter.toString());
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
return (req: Request, res: Response, next: NextFunction) => {
|
|
163
|
+
const key = keyGenerator(req);
|
|
164
|
+
const now = Date.now();
|
|
165
|
+
|
|
166
|
+
// Check if IP is blocked
|
|
167
|
+
if (blockedIPs.has(key)) {
|
|
168
|
+
const blockInfo = blockedIPs.get(key)!;
|
|
169
|
+
if (blockInfo.unblockTime > now) {
|
|
170
|
+
const retryAfter = Math.ceil((blockInfo.unblockTime - now) / 1000);
|
|
171
|
+
setRateLimitHeaders(
|
|
172
|
+
res,
|
|
173
|
+
initialMax,
|
|
174
|
+
0,
|
|
175
|
+
blockInfo.unblockTime,
|
|
176
|
+
retryAfter
|
|
177
|
+
);
|
|
178
|
+
res.status(429).json(getBlockMessage(blockInfo.unblockTime - now));
|
|
179
|
+
return;
|
|
180
|
+
} else {
|
|
181
|
+
// Unblock if time has passed
|
|
182
|
+
blockedIPs.delete(key);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Get or create request count info
|
|
187
|
+
let countInfo = requestCounts.get(key);
|
|
188
|
+
if (!countInfo || countInfo.resetTime < now) {
|
|
189
|
+
// New window
|
|
190
|
+
countInfo = {
|
|
191
|
+
count: 1,
|
|
192
|
+
resetTime: now + initialWindowMs
|
|
193
|
+
};
|
|
194
|
+
requestCounts.set(key, countInfo);
|
|
195
|
+
// Set headers for new window
|
|
196
|
+
setRateLimitHeaders(res, initialMax, initialMax - 1, countInfo.resetTime);
|
|
197
|
+
next();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Increment count
|
|
202
|
+
countInfo.count++;
|
|
203
|
+
|
|
204
|
+
// Set headers for existing window
|
|
205
|
+
setRateLimitHeaders(
|
|
206
|
+
res,
|
|
207
|
+
initialMax,
|
|
208
|
+
Math.max(0, initialMax - countInfo.count),
|
|
209
|
+
countInfo.resetTime
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// Check if we should skip counting this request
|
|
213
|
+
const isSuccess = res.statusCode < 400;
|
|
214
|
+
if (
|
|
215
|
+
(skipSuccessfulRequests && isSuccess) ||
|
|
216
|
+
(skipFailedRequests && !isSuccess)
|
|
217
|
+
) {
|
|
218
|
+
next();
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Check if limit exceeded
|
|
223
|
+
if (countInfo.count > initialMax) {
|
|
224
|
+
// Get existing block history or create new one
|
|
225
|
+
let blockHistory: { duration: number; timestamp: number }[] = [];
|
|
226
|
+
if (blockedIPs.has(key)) {
|
|
227
|
+
blockHistory = blockedIPs.get(key)!.blockHistory;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Calculate next block duration based on history
|
|
231
|
+
const blockDuration = calculateNextBlockDuration(blockHistory);
|
|
232
|
+
|
|
233
|
+
// Add this block to history
|
|
234
|
+
blockHistory.push({
|
|
235
|
+
duration: blockDuration,
|
|
236
|
+
timestamp: now
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Block the IP
|
|
240
|
+
const unblockTime = now + blockDuration;
|
|
241
|
+
blockedIPs.set(key, {
|
|
242
|
+
unblockTime,
|
|
243
|
+
blockHistory
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Remove from request counts to save memory
|
|
247
|
+
requestCounts.delete(key);
|
|
248
|
+
|
|
249
|
+
// Set headers for blocked IP
|
|
250
|
+
const retryAfter = Math.ceil(blockDuration / 1000);
|
|
251
|
+
setRateLimitHeaders(res, initialMax, 0, unblockTime, retryAfter);
|
|
252
|
+
res.status(429).json(getBlockMessage(blockDuration));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
next();
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
`;
|
|
260
|
+
await createFile(path.join(projectPath, "src/app/middlewares", "rateLimitingHandler.ts"), rateLimitingHandlerTemplate);
|
|
261
|
+
// Success message with green checkmark and text
|
|
262
|
+
console.log(chalk.green("✅ Rate Limiting Handler file created successfully"));
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
// Error message with red cross and text
|
|
266
|
+
console.error(chalk.red("❌ Error creating Rate Limiting Handler file:"), err);
|
|
267
|
+
throw err;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
//# sourceMappingURL=create_RateLimiting_Handler_Guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_RateLimiting_Handler_Guard.js","sourceRoot":"","sources":["../../../../src/lib/src/middlewares/create_RateLimiting_Handler_Guard.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;GAIG;AACH,MAAM,CAAC,MAAM,iCAAiC,GAAG,KAAK,EACpD,WAAmB,EACJ,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,2BAA2B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwPvC,CAAC;QAEE,MAAM,UAAU,CACd,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,qBAAqB,EAAE,wBAAwB,CAAC,EACvE,2BAA2B,CAC5B,CAAC;QAEF,gDAAgD;QAChD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,mDAAmD,CAAC,CACjE,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wCAAwC;QACxC,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,8CAA8C,CAAC,EACzD,GAAG,CACJ,CAAC;QACF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a request validation middleware file using Zod schemas
|
|
3
|
+
* @param projectPath - Absolute path to the project root
|
|
4
|
+
* @returns Promise that resolves when the validate request middleware file is created
|
|
5
|
+
*/
|
|
6
|
+
export declare const create_ValidateRequest_Guard: (projectPath: string) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=create_ValidateRequest_Guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_ValidateRequest_Guard.d.ts","sourceRoot":"","sources":["../../../../src/lib/src/middlewares/create_ValidateRequest_Guard.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,GACvC,aAAa,MAAM,KAClB,OAAO,CAAC,IAAI,CAuGd,CAAC"}
|