@exyconn/common 2.3.2 → 2.3.3
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 +117 -12
- package/dist/client/http/index.d.mts +217 -49
- package/dist/client/http/index.d.ts +217 -49
- package/dist/client/http/index.js +473 -94
- package/dist/client/http/index.js.map +1 -1
- package/dist/client/http/index.mjs +441 -84
- package/dist/client/http/index.mjs.map +1 -1
- package/dist/client/index.d.mts +3 -3
- package/dist/client/index.d.ts +3 -3
- package/dist/client/index.js +481 -319
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +449 -290
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/utils/index.d.mts +3 -279
- package/dist/client/utils/index.d.ts +3 -279
- package/dist/{index-DuxL84IW.d.mts → index-BZf42T3R.d.mts} +39 -39
- package/dist/{index-D9a9oxQy.d.ts → index-CF0D8PGE.d.ts} +39 -39
- package/dist/{index-D3yCCjBZ.d.mts → index-Ckhm_HaX.d.mts} +21 -2
- package/dist/{index-01hoqibP.d.ts → index-br6POSyA.d.ts} +21 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1122 -329
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1134 -341
- package/dist/index.mjs.map +1 -1
- package/dist/packageCheck-B_qfsD6R.d.ts +280 -0
- package/dist/packageCheck-C2_FT_Rl.d.mts +280 -0
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +631 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +625 -2
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/middleware/index.d.mts +283 -2
- package/dist/server/middleware/index.d.ts +283 -2
- package/dist/server/middleware/index.js +761 -0
- package/dist/server/middleware/index.js.map +1 -1
- package/dist/server/middleware/index.mjs +751 -1
- package/dist/server/middleware/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/response/response-object.ts","../../../src/server/middleware/auth.middleware.ts"],"names":["jwt"],"mappings":"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","file":"index.js","sourcesContent":["import type { Response } from 'express';\r\nimport { StatusCode, StatusMessage } from '../enums/status';\r\n\r\n/**\r\n * Standard API Response Interface\r\n */\r\nexport interface ApiResponse<T = unknown> {\r\n message: string;\r\n data: T | null;\r\n status: string;\r\n statusCode: number;\r\n paginationData?: PaginationData;\r\n columns?: ColumnMetadata[];\r\n}\r\n\r\n/**\r\n * Pagination Data Interface\r\n */\r\nexport interface PaginationData {\r\n total?: number;\r\n page?: number;\r\n limit?: number;\r\n totalPages?: number;\r\n hasNextPage?: boolean;\r\n hasPrevPage?: boolean;\r\n}\r\n\r\n/**\r\n * Column Metadata Interface (for dynamic tables)\r\n */\r\nexport interface ColumnMetadata {\r\n name: string;\r\n datatype: string;\r\n required: boolean;\r\n}\r\n\r\n/**\r\n * Extract column metadata from data array\r\n */\r\nexport const extractColumns = <T extends Record<string, unknown>>(\r\n data: T[]\r\n): ColumnMetadata[] => {\r\n if (!Array.isArray(data) || data.length === 0) {\r\n return [];\r\n }\r\n\r\n const sample = data[0];\r\n return Object.entries(sample).map(([key, value]) => {\r\n let datatype: string = typeof value;\r\n\r\n if (value === null) {\r\n datatype = 'null';\r\n } else if (Array.isArray(value)) {\r\n datatype = 'array';\r\n } else if (value instanceof Date) {\r\n datatype = 'date';\r\n } else if (typeof value === 'object') {\r\n datatype = 'object';\r\n }\r\n\r\n return {\r\n name: key,\r\n datatype,\r\n required: value !== null && value !== undefined,\r\n };\r\n });\r\n};\r\n\r\n/**\r\n * Success Response (200)\r\n */\r\nexport const successResponse = <T>(\r\n res: Response,\r\n data: T,\r\n message = 'Operation successful'\r\n): Response => {\r\n return res.status(StatusCode.SUCCESS).json({\r\n message,\r\n data,\r\n status: StatusMessage.SUCCESS,\r\n statusCode: StatusCode.SUCCESS,\r\n });\r\n};\r\n\r\n/**\r\n * Success Response with Array & Pagination (200)\r\n */\r\nexport const successResponseArr = <T>(\r\n res: Response,\r\n data: T[],\r\n paginationData: PaginationData = {},\r\n message = 'Operation successful'\r\n): Response => {\r\n return res.status(StatusCode.SUCCESS).json({\r\n message,\r\n data,\r\n columns: extractColumns(data as Record<string, unknown>[]),\r\n paginationData,\r\n status: StatusMessage.SUCCESS,\r\n statusCode: StatusCode.SUCCESS,\r\n });\r\n};\r\n\r\n/**\r\n * Created Response (201)\r\n */\r\nexport const createdResponse = <T>(\r\n res: Response,\r\n data: T,\r\n message = 'Resource created successfully'\r\n): Response => {\r\n return res.status(StatusCode.CREATED).json({\r\n message,\r\n data,\r\n status: StatusMessage.CREATED,\r\n statusCode: StatusCode.CREATED,\r\n });\r\n};\r\n\r\n/**\r\n * No Content Response (204 as 200 with message)\r\n */\r\nexport const noContentResponse = <T = null>(\r\n res: Response,\r\n data: T = null as T,\r\n message = 'No data found'\r\n): Response => {\r\n return res.status(StatusCode.SUCCESS).json({\r\n message,\r\n data,\r\n status: StatusMessage.NO_CONTENT,\r\n statusCode: StatusCode.NO_CONTENT,\r\n });\r\n};\r\n\r\n/**\r\n * Bad Request Response (400)\r\n */\r\nexport const badRequestResponse = (\r\n res: Response,\r\n message = 'Bad request',\r\n errors: unknown = null\r\n): Response => {\r\n return res.status(StatusCode.BAD_REQUEST).json({\r\n message,\r\n data: errors,\r\n status: StatusMessage.BAD_REQUEST,\r\n statusCode: StatusCode.BAD_REQUEST,\r\n });\r\n};\r\n\r\n/**\r\n * Unauthorized Response (401)\r\n */\r\nexport const unauthorizedResponse = (\r\n res: Response,\r\n message = 'Unauthorized access'\r\n): Response => {\r\n return res.status(StatusCode.UNAUTHORIZED).json({\r\n message,\r\n data: null,\r\n status: StatusMessage.UNAUTHORIZED,\r\n statusCode: StatusCode.UNAUTHORIZED,\r\n });\r\n};\r\n\r\n/**\r\n * Forbidden Response (403)\r\n */\r\nexport const forbiddenResponse = (\r\n res: Response,\r\n message = 'Access forbidden'\r\n): Response => {\r\n return res.status(StatusCode.FORBIDDEN).json({\r\n message,\r\n data: null,\r\n status: StatusMessage.FORBIDDEN,\r\n statusCode: StatusCode.FORBIDDEN,\r\n });\r\n};\r\n\r\n/**\r\n * Not Found Response (404)\r\n */\r\nexport const notFoundResponse = (\r\n res: Response,\r\n message = 'Resource not found'\r\n): Response => {\r\n return res.status(StatusCode.NOT_FOUND).json({\r\n message,\r\n data: null,\r\n status: StatusMessage.NOT_FOUND,\r\n statusCode: StatusCode.NOT_FOUND,\r\n });\r\n};\r\n\r\n/**\r\n * Conflict Response (409)\r\n */\r\nexport const conflictResponse = (\r\n res: Response,\r\n message = 'Resource conflict'\r\n): Response => {\r\n return res.status(StatusCode.CONFLICT).json({\r\n message,\r\n data: null,\r\n status: StatusMessage.CONFLICT,\r\n statusCode: StatusCode.CONFLICT,\r\n });\r\n};\r\n\r\n/**\r\n * Validation Error Response (422)\r\n */\r\nexport const validationErrorResponse = (\r\n res: Response,\r\n errors: unknown,\r\n message = 'Validation failed'\r\n): Response => {\r\n return res.status(StatusCode.UNPROCESSABLE_ENTITY).json({\r\n message,\r\n data: errors,\r\n status: StatusMessage.UNPROCESSABLE_ENTITY,\r\n statusCode: StatusCode.UNPROCESSABLE_ENTITY,\r\n });\r\n};\r\n\r\n/**\r\n * Error Response (500)\r\n */\r\nexport const errorResponse = (\r\n res: Response,\r\n error: unknown = null,\r\n message = 'Something went wrong'\r\n): Response => {\r\n return res.status(StatusCode.INTERNAL_ERROR).json({\r\n message,\r\n data: error,\r\n status: StatusMessage.INTERNAL_ERROR,\r\n statusCode: StatusCode.INTERNAL_ERROR,\r\n });\r\n};\r\n\r\n/**\r\n * Rate Limit Response (429)\r\n */\r\nexport const rateLimitResponse = (\r\n res: Response,\r\n message = 'Too many requests, please try again later'\r\n): Response => {\r\n return res.status(StatusCode.TOO_MANY_REQUESTS).json({\r\n message,\r\n data: null,\r\n status: StatusMessage.TOO_MANY_REQUESTS,\r\n statusCode: StatusCode.TOO_MANY_REQUESTS,\r\n });\r\n};\r\n\r\nexport default {\r\n successResponse,\r\n successResponseArr,\r\n createdResponse,\r\n noContentResponse,\r\n badRequestResponse,\r\n unauthorizedResponse,\r\n forbiddenResponse,\r\n notFoundResponse,\r\n conflictResponse,\r\n validationErrorResponse,\r\n errorResponse,\r\n rateLimitResponse,\r\n extractColumns,\r\n};\r\n","import type { Request, Response, NextFunction } from 'express';\r\nimport jwt from 'jsonwebtoken';\r\nimport { unauthorizedResponse, forbiddenResponse } from '../response/response-object';\r\n\r\n/**\r\n * Extended Request with auth information\r\n */\r\nexport interface AuthRequest extends Request {\r\n userId?: string;\r\n organizationId?: string;\r\n apiKey?: { _id: string; name: string };\r\n user?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * JWT Payload Interface\r\n */\r\nexport interface JWTPayload {\r\n userId: string;\r\n organizationId?: string;\r\n email?: string;\r\n role?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * JWT Authentication Middleware\r\n * Validates Bearer token from Authorization header\r\n */\r\nexport const authenticateJWT = (secretKey: string) => {\r\n return (req: AuthRequest, res: Response, next: NextFunction): void => {\r\n const authHeader = req.headers.authorization;\r\n\r\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\r\n unauthorizedResponse(res, 'Authorization header missing or malformed');\r\n return;\r\n }\r\n\r\n const token = authHeader.split(' ')[1];\r\n\r\n try {\r\n const decoded = jwt.verify(token, secretKey) as JWTPayload;\r\n\r\n req.userId = decoded.userId;\r\n req.organizationId = decoded.organizationId;\r\n req.user = decoded as Record<string, unknown>;\r\n\r\n if (!decoded.userId) {\r\n unauthorizedResponse(res, 'User ID not found in token');\r\n return;\r\n }\r\n\r\n next();\r\n } catch (err) {\r\n if (err instanceof jwt.TokenExpiredError) {\r\n unauthorizedResponse(res, 'Token has expired');\r\n return;\r\n }\r\n if (err instanceof jwt.JsonWebTokenError) {\r\n forbiddenResponse(res, 'Invalid token');\r\n return;\r\n }\r\n unauthorizedResponse(res, 'Token validation failed');\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Optional JWT Authentication Middleware\r\n * Validates token if present, but doesn't require it\r\n */\r\nexport const optionalAuthenticateJWT = (secretKey: string) => {\r\n return (req: AuthRequest, _res: Response, next: NextFunction): void => {\r\n const authHeader = req.headers.authorization;\r\n\r\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\r\n next();\r\n return;\r\n }\r\n\r\n const token = authHeader.split(' ')[1];\r\n\r\n try {\r\n const decoded = jwt.verify(token, secretKey) as JWTPayload;\r\n req.userId = decoded.userId;\r\n req.organizationId = decoded.organizationId;\r\n req.user = decoded as Record<string, unknown>;\r\n } catch {\r\n // Token invalid, but continue without auth\r\n }\r\n\r\n next();\r\n };\r\n};\r\n\r\n/**\r\n * API Key Authentication Middleware\r\n * Validates x-api-key header\r\n */\r\nexport const authenticateApiKey = (\r\n validateKeyFn: (key: string) => Promise<{\r\n valid: boolean;\r\n organizationId?: string;\r\n keyId?: string;\r\n keyName?: string;\r\n }>\r\n) => {\r\n return async (req: AuthRequest, res: Response, next: NextFunction): Promise<void> => {\r\n try {\r\n const apiKey = req.headers['x-api-key'] as string;\r\n\r\n if (!apiKey) {\r\n unauthorizedResponse(res, 'API key is required. Please provide x-api-key header');\r\n return;\r\n }\r\n\r\n const validation = await validateKeyFn(apiKey);\r\n\r\n if (!validation.valid) {\r\n unauthorizedResponse(res, 'Invalid or inactive API key');\r\n return;\r\n }\r\n\r\n if (validation.organizationId) {\r\n req.organizationId = validation.organizationId;\r\n }\r\n if (validation.keyId && validation.keyName) {\r\n req.apiKey = {\r\n _id: validation.keyId,\r\n name: validation.keyName,\r\n };\r\n }\r\n\r\n next();\r\n } catch {\r\n unauthorizedResponse(res, 'API key validation failed');\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Organization Header Middleware\r\n * Extracts organization ID from x-organization-id header\r\n */\r\nexport const extractOrganization = (req: AuthRequest, _res: Response, next: NextFunction): void => {\r\n const orgId = req.headers['x-organization-id'] as string;\r\n\r\n if (orgId) {\r\n req.organizationId = orgId;\r\n }\r\n\r\n next();\r\n};\r\n\r\n/**\r\n * Require Organization Middleware\r\n * Ensures organizationId is present in request\r\n */\r\nexport const requireOrganization = (req: AuthRequest, res: Response, next: NextFunction): void => {\r\n if (!req.organizationId) {\r\n unauthorizedResponse(res, 'Organization ID is required');\r\n return;\r\n }\r\n next();\r\n};\r\n\r\nexport default {\r\n authenticateJWT,\r\n optionalAuthenticateJWT,\r\n authenticateApiKey,\r\n extractOrganization,\r\n requireOrganization,\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/server/response/response-object.ts","../../../src/server/middleware/auth.middleware.ts","../../../src/server/middleware/queryParser.middleware.ts","../../../src/server/middleware/utils/schemaMeta.util.ts","../../../src/server/middleware/pagination.middleware.ts","../../../src/server/logger/winston-logger.ts","../../../src/server/middleware/crud.middleware.ts","../../../src/server/middleware/bulkDelete.middleware.ts"],"names":["jwt","winston","DailyRotateFile","path","Types","Model"],"mappings":"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","file":"index.js","sourcesContent":["import type { Response } from 'express';\r\nimport { StatusCode, StatusMessage } from '../enums/status';\r\n\r\n/**\r\n * Standard API Response Interface\r\n */\r\nexport interface ApiResponse<T = unknown> {\r\n message: string;\r\n data: T | null;\r\n status: string;\r\n statusCode: number;\r\n paginationData?: PaginationData;\r\n columns?: ColumnMetadata[];\r\n}\r\n\r\n/**\r\n * Pagination Data Interface\r\n */\r\nexport interface PaginationData {\r\n total?: number;\r\n page?: number;\r\n limit?: number;\r\n totalPages?: number;\r\n hasNextPage?: boolean;\r\n hasPrevPage?: boolean;\r\n}\r\n\r\n/**\r\n * Column Metadata Interface (for dynamic tables)\r\n */\r\nexport interface ColumnMetadata {\r\n name: string;\r\n datatype: string;\r\n required: boolean;\r\n}\r\n\r\n/**\r\n * Extract column metadata from data array\r\n */\r\nexport const extractColumns = <T extends Record<string, unknown>>(\r\n data: T[]\r\n): ColumnMetadata[] => {\r\n if (!Array.isArray(data) || data.length === 0) {\r\n return [];\r\n }\r\n\r\n const sample = data[0];\r\n return Object.entries(sample).map(([key, value]) => {\r\n let datatype: string = typeof value;\r\n\r\n if (value === null) {\r\n datatype = 'null';\r\n } else if (Array.isArray(value)) {\r\n datatype = 'array';\r\n } else if (value instanceof Date) {\r\n datatype = 'date';\r\n } else if (typeof value === 'object') {\r\n datatype = 'object';\r\n }\r\n\r\n return {\r\n name: key,\r\n datatype,\r\n required: value !== null && value !== undefined,\r\n };\r\n });\r\n};\r\n\r\n/**\r\n * Success Response (200)\r\n */\r\nexport const successResponse = <T>(\r\n res: Response,\r\n data: T,\r\n message = 'Operation successful'\r\n): Response => {\r\n return res.status(StatusCode.SUCCESS).json({\r\n message,\r\n data,\r\n status: StatusMessage.SUCCESS,\r\n statusCode: StatusCode.SUCCESS,\r\n });\r\n};\r\n\r\n/**\r\n * Success Response with Array & Pagination (200)\r\n */\r\nexport const successResponseArr = <T>(\r\n res: Response,\r\n data: T[],\r\n paginationData: PaginationData = {},\r\n message = 'Operation successful'\r\n): Response => {\r\n return res.status(StatusCode.SUCCESS).json({\r\n message,\r\n data,\r\n columns: extractColumns(data as Record<string, unknown>[]),\r\n paginationData,\r\n status: StatusMessage.SUCCESS,\r\n statusCode: StatusCode.SUCCESS,\r\n });\r\n};\r\n\r\n/**\r\n * Created Response (201)\r\n */\r\nexport const createdResponse = <T>(\r\n res: Response,\r\n data: T,\r\n message = 'Resource created successfully'\r\n): Response => {\r\n return res.status(StatusCode.CREATED).json({\r\n message,\r\n data,\r\n status: StatusMessage.CREATED,\r\n statusCode: StatusCode.CREATED,\r\n });\r\n};\r\n\r\n/**\r\n * No Content Response (204 as 200 with message)\r\n */\r\nexport const noContentResponse = <T = null>(\r\n res: Response,\r\n data: T = null as T,\r\n message = 'No data found'\r\n): Response => {\r\n return res.status(StatusCode.SUCCESS).json({\r\n message,\r\n data,\r\n status: StatusMessage.NO_CONTENT,\r\n statusCode: StatusCode.NO_CONTENT,\r\n });\r\n};\r\n\r\n/**\r\n * Bad Request Response (400)\r\n */\r\nexport const badRequestResponse = (\r\n res: Response,\r\n message = 'Bad request',\r\n errors: unknown = null\r\n): Response => {\r\n return res.status(StatusCode.BAD_REQUEST).json({\r\n message,\r\n data: errors,\r\n status: StatusMessage.BAD_REQUEST,\r\n statusCode: StatusCode.BAD_REQUEST,\r\n });\r\n};\r\n\r\n/**\r\n * Unauthorized Response (401)\r\n */\r\nexport const unauthorizedResponse = (\r\n res: Response,\r\n message = 'Unauthorized access'\r\n): Response => {\r\n return res.status(StatusCode.UNAUTHORIZED).json({\r\n message,\r\n data: null,\r\n status: StatusMessage.UNAUTHORIZED,\r\n statusCode: StatusCode.UNAUTHORIZED,\r\n });\r\n};\r\n\r\n/**\r\n * Forbidden Response (403)\r\n */\r\nexport const forbiddenResponse = (\r\n res: Response,\r\n message = 'Access forbidden'\r\n): Response => {\r\n return res.status(StatusCode.FORBIDDEN).json({\r\n message,\r\n data: null,\r\n status: StatusMessage.FORBIDDEN,\r\n statusCode: StatusCode.FORBIDDEN,\r\n });\r\n};\r\n\r\n/**\r\n * Not Found Response (404)\r\n */\r\nexport const notFoundResponse = (\r\n res: Response,\r\n message = 'Resource not found'\r\n): Response => {\r\n return res.status(StatusCode.NOT_FOUND).json({\r\n message,\r\n data: null,\r\n status: StatusMessage.NOT_FOUND,\r\n statusCode: StatusCode.NOT_FOUND,\r\n });\r\n};\r\n\r\n/**\r\n * Conflict Response (409)\r\n */\r\nexport const conflictResponse = (\r\n res: Response,\r\n message = 'Resource conflict'\r\n): Response => {\r\n return res.status(StatusCode.CONFLICT).json({\r\n message,\r\n data: null,\r\n status: StatusMessage.CONFLICT,\r\n statusCode: StatusCode.CONFLICT,\r\n });\r\n};\r\n\r\n/**\r\n * Validation Error Response (422)\r\n */\r\nexport const validationErrorResponse = (\r\n res: Response,\r\n errors: unknown,\r\n message = 'Validation failed'\r\n): Response => {\r\n return res.status(StatusCode.UNPROCESSABLE_ENTITY).json({\r\n message,\r\n data: errors,\r\n status: StatusMessage.UNPROCESSABLE_ENTITY,\r\n statusCode: StatusCode.UNPROCESSABLE_ENTITY,\r\n });\r\n};\r\n\r\n/**\r\n * Error Response (500)\r\n */\r\nexport const errorResponse = (\r\n res: Response,\r\n error: unknown = null,\r\n message = 'Something went wrong'\r\n): Response => {\r\n return res.status(StatusCode.INTERNAL_ERROR).json({\r\n message,\r\n data: error,\r\n status: StatusMessage.INTERNAL_ERROR,\r\n statusCode: StatusCode.INTERNAL_ERROR,\r\n });\r\n};\r\n\r\n/**\r\n * Rate Limit Response (429)\r\n */\r\nexport const rateLimitResponse = (\r\n res: Response,\r\n message = 'Too many requests, please try again later'\r\n): Response => {\r\n return res.status(StatusCode.TOO_MANY_REQUESTS).json({\r\n message,\r\n data: null,\r\n status: StatusMessage.TOO_MANY_REQUESTS,\r\n statusCode: StatusCode.TOO_MANY_REQUESTS,\r\n });\r\n};\r\n\r\nexport default {\r\n successResponse,\r\n successResponseArr,\r\n createdResponse,\r\n noContentResponse,\r\n badRequestResponse,\r\n unauthorizedResponse,\r\n forbiddenResponse,\r\n notFoundResponse,\r\n conflictResponse,\r\n validationErrorResponse,\r\n errorResponse,\r\n rateLimitResponse,\r\n extractColumns,\r\n};\r\n","import type { Request, Response, NextFunction } from 'express';\r\nimport jwt from 'jsonwebtoken';\r\nimport { unauthorizedResponse, forbiddenResponse } from '../response/response-object';\r\n\r\n/**\r\n * Extended Request with auth information\r\n */\r\nexport interface AuthRequest extends Request {\r\n userId?: string;\r\n organizationId?: string;\r\n apiKey?: { _id: string; name: string };\r\n user?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * JWT Payload Interface\r\n */\r\nexport interface JWTPayload {\r\n userId: string;\r\n organizationId?: string;\r\n email?: string;\r\n role?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * JWT Authentication Middleware\r\n * Validates Bearer token from Authorization header\r\n */\r\nexport const authenticateJWT = (secretKey: string) => {\r\n return (req: AuthRequest, res: Response, next: NextFunction): void => {\r\n const authHeader = req.headers.authorization;\r\n\r\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\r\n unauthorizedResponse(res, 'Authorization header missing or malformed');\r\n return;\r\n }\r\n\r\n const token = authHeader.split(' ')[1];\r\n\r\n try {\r\n const decoded = jwt.verify(token, secretKey) as JWTPayload;\r\n\r\n req.userId = decoded.userId;\r\n req.organizationId = decoded.organizationId;\r\n req.user = decoded as Record<string, unknown>;\r\n\r\n if (!decoded.userId) {\r\n unauthorizedResponse(res, 'User ID not found in token');\r\n return;\r\n }\r\n\r\n next();\r\n } catch (err) {\r\n if (err instanceof jwt.TokenExpiredError) {\r\n unauthorizedResponse(res, 'Token has expired');\r\n return;\r\n }\r\n if (err instanceof jwt.JsonWebTokenError) {\r\n forbiddenResponse(res, 'Invalid token');\r\n return;\r\n }\r\n unauthorizedResponse(res, 'Token validation failed');\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Optional JWT Authentication Middleware\r\n * Validates token if present, but doesn't require it\r\n */\r\nexport const optionalAuthenticateJWT = (secretKey: string) => {\r\n return (req: AuthRequest, _res: Response, next: NextFunction): void => {\r\n const authHeader = req.headers.authorization;\r\n\r\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\r\n next();\r\n return;\r\n }\r\n\r\n const token = authHeader.split(' ')[1];\r\n\r\n try {\r\n const decoded = jwt.verify(token, secretKey) as JWTPayload;\r\n req.userId = decoded.userId;\r\n req.organizationId = decoded.organizationId;\r\n req.user = decoded as Record<string, unknown>;\r\n } catch {\r\n // Token invalid, but continue without auth\r\n }\r\n\r\n next();\r\n };\r\n};\r\n\r\n/**\r\n * API Key Authentication Middleware\r\n * Validates x-api-key header\r\n */\r\nexport const authenticateApiKey = (\r\n validateKeyFn: (key: string) => Promise<{\r\n valid: boolean;\r\n organizationId?: string;\r\n keyId?: string;\r\n keyName?: string;\r\n }>\r\n) => {\r\n return async (req: AuthRequest, res: Response, next: NextFunction): Promise<void> => {\r\n try {\r\n const apiKey = req.headers['x-api-key'] as string;\r\n\r\n if (!apiKey) {\r\n unauthorizedResponse(res, 'API key is required. Please provide x-api-key header');\r\n return;\r\n }\r\n\r\n const validation = await validateKeyFn(apiKey);\r\n\r\n if (!validation.valid) {\r\n unauthorizedResponse(res, 'Invalid or inactive API key');\r\n return;\r\n }\r\n\r\n if (validation.organizationId) {\r\n req.organizationId = validation.organizationId;\r\n }\r\n if (validation.keyId && validation.keyName) {\r\n req.apiKey = {\r\n _id: validation.keyId,\r\n name: validation.keyName,\r\n };\r\n }\r\n\r\n next();\r\n } catch {\r\n unauthorizedResponse(res, 'API key validation failed');\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Organization Header Middleware\r\n * Extracts organization ID from x-organization-id header\r\n */\r\nexport const extractOrganization = (req: AuthRequest, _res: Response, next: NextFunction): void => {\r\n const orgId = req.headers['x-organization-id'] as string;\r\n\r\n if (orgId) {\r\n req.organizationId = orgId;\r\n }\r\n\r\n next();\r\n};\r\n\r\n/**\r\n * Require Organization Middleware\r\n * Ensures organizationId is present in request\r\n */\r\nexport const requireOrganization = (req: AuthRequest, res: Response, next: NextFunction): void => {\r\n if (!req.organizationId) {\r\n unauthorizedResponse(res, 'Organization ID is required');\r\n return;\r\n }\r\n next();\r\n};\r\n\r\nexport default {\r\n authenticateJWT,\r\n optionalAuthenticateJWT,\r\n authenticateApiKey,\r\n extractOrganization,\r\n requireOrganization,\r\n};\r\n","/**\r\n * Query Parser Middleware\r\n *\r\n * Parses query parameters into a standardized format for pagination and filtering.\r\n */\r\n\r\nimport { Request, Response, NextFunction } from 'express';\r\nimport type { ParsedQuery } from './types/pagination.types';\r\n\r\n/**\r\n * Parse query parameters from request\r\n * Supports:\r\n * - page, limit for pagination\r\n * - sort or sortBy/sortOrder for sorting\r\n * - search for text search\r\n * - filter object or direct query params for filtering\r\n */\r\nexport const queryParser = (req: Request, _: Response, next: NextFunction): void => {\r\n const { page, limit, sort, sortBy, sortOrder, search, filter, ...otherParams } = req.query;\r\n\r\n const parsed: ParsedQuery = {\r\n page: Math.max(Number(page) || 1, 1),\r\n limit: Math.min(Number(limit) || 10, 100),\r\n filter: {},\r\n };\r\n\r\n // Handle sort parameter (supports both \"field:order\" and separate sortBy/sortOrder)\r\n if (typeof sort === 'string') {\r\n const [field, order] = sort.split(':');\r\n parsed.sort = {\r\n field,\r\n order: order === 'asc' ? 'asc' : 'desc',\r\n };\r\n } else if (typeof sortBy === 'string') {\r\n parsed.sort = {\r\n field: sortBy,\r\n order: (sortOrder === 'asc' ? 'asc' : 'desc') as 'asc' | 'desc',\r\n };\r\n }\r\n\r\n if (typeof search === 'string') {\r\n parsed.search = search;\r\n }\r\n\r\n // Handle filter object\r\n if (typeof filter === 'object' && filter !== null) {\r\n Object.entries(filter).forEach(([key, value]) => {\r\n if (value !== 'all') {\r\n parsed.filter[key] = value as string;\r\n }\r\n });\r\n }\r\n\r\n // Handle additional filter parameters passed directly in query\r\n Object.entries(otherParams).forEach(([key, value]) => {\r\n if (\r\n typeof value === 'string' &&\r\n value !== 'all' &&\r\n !['page', 'limit', 'sort', 'sortBy', 'sortOrder', 'search'].includes(key)\r\n ) {\r\n parsed.filter[key] = value;\r\n }\r\n });\r\n\r\n req.parsedQuery = parsed;\r\n next();\r\n};\r\n\r\nexport default queryParser;\r\n","/**\r\n * Schema Meta Extraction Utility\r\n * Extracts column metadata from Mongoose models and Zod schemas\r\n */\r\n\r\nimport { Model } from 'mongoose';\r\n\r\n// Zod-compatible type definitions for optional peer dependency\r\ninterface ZodTypeAny {\r\n _def?: {\r\n typeName?: string;\r\n innerType?: ZodTypeAny;\r\n values?: unknown[];\r\n };\r\n}\r\n\r\ntype ZodObject<T = unknown> = {\r\n shape?: Record<string, ZodTypeAny>;\r\n parse: (data: unknown) => T;\r\n};\r\n\r\n/**\r\n * Column metadata interface\r\n */\r\nexport interface ColumnMeta {\r\n name: string;\r\n datatype: string;\r\n required: boolean;\r\n}\r\n\r\n/**\r\n * Get Zod type name\r\n */\r\nconst getZodTypeName = (schema: ZodTypeAny): string => {\r\n const typeName = schema._def?.typeName;\r\n\r\n switch (typeName) {\r\n case 'ZodString':\r\n return 'string';\r\n case 'ZodNumber':\r\n return 'number';\r\n case 'ZodBoolean':\r\n return 'boolean';\r\n case 'ZodDate':\r\n return 'date';\r\n case 'ZodArray':\r\n return 'array';\r\n case 'ZodObject':\r\n return 'object';\r\n case 'ZodOptional':\r\n case 'ZodNullable':\r\n return schema._def?.innerType ? getZodTypeName(schema._def.innerType) : 'unknown';\r\n case 'ZodDefault':\r\n return schema._def?.innerType ? getZodTypeName(schema._def.innerType) : 'unknown';\r\n case 'ZodEnum':\r\n return 'enum';\r\n case 'ZodUnion':\r\n return 'union';\r\n default:\r\n return 'unknown';\r\n }\r\n};\r\n\r\n/**\r\n * Check if Zod schema field is required\r\n */\r\nconst isZodRequired = (schema: ZodTypeAny): boolean => {\r\n const typeName = schema._def?.typeName;\r\n return typeName !== 'ZodOptional' && typeName !== 'ZodNullable';\r\n};\r\n\r\n/**\r\n * Extract column metadata from Mongoose model and optional Zod schema\r\n */\r\nexport const extractSchemaMeta = <T>(\r\n model: Model<T>,\r\n zodSchema?: ZodObject<unknown>\r\n): ColumnMeta[] => {\r\n const columns: ColumnMeta[] = [];\r\n\r\n // Extract from Zod schema if provided (preferred)\r\n if (zodSchema && zodSchema.shape) {\r\n const shape = zodSchema.shape;\r\n for (const [key, value] of Object.entries(shape)) {\r\n if (key.startsWith('_')) continue; // Skip internal fields\r\n\r\n columns.push({\r\n name: key,\r\n datatype: getZodTypeName(value as ZodTypeAny),\r\n required: isZodRequired(value as ZodTypeAny),\r\n });\r\n }\r\n return columns;\r\n }\r\n\r\n // Fallback: Extract from Mongoose schema\r\n try {\r\n const schema = model.schema;\r\n const paths = schema.paths;\r\n\r\n for (const [key, pathInfo] of Object.entries(paths)) {\r\n // Skip internal Mongoose fields\r\n if (key.startsWith('_') || key === '__v') continue;\r\n\r\n const schemaType = pathInfo as { instance?: string; isRequired?: boolean };\r\n\r\n columns.push({\r\n name: key,\r\n datatype: (schemaType.instance || 'unknown').toLowerCase(),\r\n required: schemaType.isRequired || false,\r\n });\r\n }\r\n } catch {\r\n // If schema extraction fails, return empty array\r\n }\r\n\r\n return columns;\r\n};\r\n\r\nexport default extractSchemaMeta;\r\n","/**\r\n * Query Pagination Middleware\r\n *\r\n * Provides standardized pagination for Mongoose models.\r\n * Works with queryParser middleware for parsed query parameters.\r\n */\r\n\r\nimport { Request, Response, NextFunction } from 'express';\r\nimport { Model, SortOrder } from 'mongoose';\r\n\r\n// Zod-compatible type definitions for optional peer dependency\r\ntype ZodObject<T = Record<string, unknown>> = {\r\n parse: (data: unknown) => T;\r\n safeParse: (data: unknown) => { success: boolean; data?: T; error?: Error };\r\n};\r\nimport { extractSchemaMeta } from './utils/schemaMeta.util';\r\n\r\ninterface PaginationOptions {\r\n searchFields?: string[];\r\n validatorSchema?: ZodObject<unknown>;\r\n regexFilterFields?: string[]; // Fields that should use regex matching for filters\r\n}\r\n\r\n/**\r\n * Creates a pagination middleware for a Mongoose model\r\n *\r\n * @param model - The Mongoose model to paginate\r\n * @param options - Pagination options\r\n * @param withOrgId - Whether to filter by organization ID from header\r\n */\r\nexport const queryPagination = <T>(\r\n model: Model<T>,\r\n options: PaginationOptions = {},\r\n withOrgId = true\r\n) => {\r\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\r\n try {\r\n const { page, limit, sort, search, filter } = req.parsedQuery;\r\n\r\n const query: Record<string, unknown> = {};\r\n\r\n // Process filter values - apply regex for specified fields\r\n Object.entries(filter).forEach(([key, value]) => {\r\n if (options.regexFilterFields?.includes(key)) {\r\n // Use regex for partial matching\r\n query[key] = { $regex: value, $options: 'i' };\r\n } else {\r\n query[key] = value;\r\n }\r\n });\r\n\r\n // Add organization filter if x-organization-id header is present\r\n const organizationId = req.headers['x-organization-id'];\r\n if (organizationId && typeof organizationId === 'string' && withOrgId) {\r\n query.organizationId = organizationId;\r\n }\r\n\r\n if (search && options.searchFields?.length) {\r\n query.$or = options.searchFields.map(field => ({\r\n [field]: { $regex: search, $options: 'i' },\r\n }));\r\n }\r\n\r\n const sortQuery: Record<string, SortOrder> = sort\r\n ? { [sort.field]: sort.order }\r\n : { createdAt: 'desc' };\r\n\r\n const skip = (page - 1) * limit;\r\n\r\n const [data, total] = await Promise.all([\r\n model.find(query).sort(sortQuery).skip(skip).limit(limit),\r\n model.countDocuments(query),\r\n ]);\r\n\r\n res.paginatedResult = {\r\n data,\r\n meta: {\r\n page,\r\n limit,\r\n total,\r\n totalPages: Math.ceil(total / limit),\r\n },\r\n columns: extractSchemaMeta(model, options.validatorSchema),\r\n };\r\n\r\n next();\r\n } catch (error) {\r\n next(error);\r\n }\r\n };\r\n};\r\n\r\nexport default queryPagination;\r\n","import winston from 'winston';\r\nimport DailyRotateFile from 'winston-daily-rotate-file';\r\nimport path from 'path';\r\n\r\n/**\r\n * Logger Configuration Options\r\n */\r\nexport interface LoggerConfig {\r\n level?: string;\r\n logsDir?: string;\r\n maxSize?: string;\r\n maxFiles?: string;\r\n errorMaxFiles?: string;\r\n}\r\n\r\n/**\r\n * Default logger configuration\r\n */\r\nconst defaultConfig: LoggerConfig = {\r\n level: process.env.LOG_LEVEL || 'info',\r\n logsDir: 'logs',\r\n maxSize: '20m',\r\n maxFiles: '14d',\r\n errorMaxFiles: '30d',\r\n};\r\n\r\n// Define log levels\r\nconst levels = {\r\n error: 0,\r\n warn: 1,\r\n info: 2,\r\n http: 3,\r\n debug: 4,\r\n};\r\n\r\n// Define colors for each level\r\nconst colors = {\r\n error: 'red',\r\n warn: 'yellow',\r\n info: 'green',\r\n http: 'magenta',\r\n debug: 'blue',\r\n};\r\n\r\nwinston.addColors(colors);\r\n\r\n// JSON format for file logs\r\nconst fileFormat = winston.format.combine(\r\n winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),\r\n winston.format.errors({ stack: true }),\r\n winston.format.splat(),\r\n winston.format.json()\r\n);\r\n\r\n// Colorized format for console\r\nconst consoleFormat = winston.format.combine(\r\n winston.format.colorize({ all: true }),\r\n winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),\r\n winston.format.printf((info) => {\r\n const timestamp = info.timestamp as string | undefined;\r\n const level = info.level as string;\r\n const message = info.message as string;\r\n const stack = info.stack as string | undefined;\r\n return `${timestamp} [${level}]: ${message}${stack ? '\\n' + stack : ''}`;\r\n })\r\n);\r\n\r\n/**\r\n * Create a configured Winston logger instance\r\n */\r\nexport const createLogger = (config: LoggerConfig = {}) => {\r\n const finalConfig = { ...defaultConfig, ...config };\r\n\r\n const transports: winston.transport[] = [\r\n // Console transport\r\n new winston.transports.Console({\r\n format: consoleFormat,\r\n }),\r\n\r\n // Combined logs (all levels)\r\n new DailyRotateFile({\r\n filename: path.join(finalConfig.logsDir!, 'combined-%DATE%.log'),\r\n datePattern: 'YYYY-MM-DD',\r\n maxSize: finalConfig.maxSize,\r\n maxFiles: finalConfig.maxFiles,\r\n format: fileFormat,\r\n }),\r\n\r\n // Error logs only\r\n new DailyRotateFile({\r\n filename: path.join(finalConfig.logsDir!, 'error-%DATE%.log'),\r\n datePattern: 'YYYY-MM-DD',\r\n level: 'error',\r\n maxSize: finalConfig.maxSize,\r\n maxFiles: finalConfig.errorMaxFiles,\r\n format: fileFormat,\r\n }),\r\n ];\r\n\r\n return winston.createLogger({\r\n level: finalConfig.level,\r\n levels,\r\n format: fileFormat,\r\n transports,\r\n exitOnError: false,\r\n });\r\n};\r\n\r\n// Default logger instance\r\nexport const logger = createLogger();\r\n\r\n/**\r\n * Create a stream for Morgan HTTP logger\r\n */\r\nexport const createMorganStream = (loggerInstance: winston.Logger) => ({\r\n write: (message: string) => {\r\n loggerInstance.http(message.trim());\r\n },\r\n});\r\n\r\nexport const stream = createMorganStream(logger);\r\n\r\n/**\r\n * Simple logger for development (no file output)\r\n */\r\nconst serializeMeta = (meta: unknown): string => {\r\n if (meta === undefined || meta === null) return '';\r\n if (meta instanceof Error) {\r\n return JSON.stringify({ message: meta.message, stack: meta.stack }, null, 2);\r\n }\r\n try {\r\n return JSON.stringify(meta, null, 2);\r\n } catch {\r\n return String(meta);\r\n }\r\n};\r\n\r\nexport const simpleLogger = {\r\n info: (message: string, meta?: unknown) => {\r\n console.log(`[INFO] ${message}`, serializeMeta(meta));\r\n },\r\n error: (message: string, meta?: unknown) => {\r\n console.error(`[ERROR] ${message}`, serializeMeta(meta));\r\n },\r\n warn: (message: string, meta?: unknown) => {\r\n console.warn(`[WARN] ${message}`, serializeMeta(meta));\r\n },\r\n debug: (message: string, meta?: unknown) => {\r\n console.debug(`[DEBUG] ${message}`, serializeMeta(meta));\r\n },\r\n};\r\n\r\nexport default logger;\r\n","/**\r\n * CRUD Middleware Factory\r\n *\r\n * High-configuration middleware for standardized CRUD operations.\r\n * Provides consistent API patterns across all services.\r\n *\r\n * Features:\r\n * - getAll with pagination, search, filters, sorting\r\n * - getById with validation\r\n * - create with validation and auto-response\r\n * - update with validation and auto-response\r\n * - delete (single and bulk)\r\n * - Organization-scoped queries\r\n */\r\n\r\nimport { Request, Response, NextFunction, RequestHandler } from 'express';\r\nimport { Model, Types, SortOrder, Document } from 'mongoose';\r\n\r\n// Zod-compatible type definitions for optional peer dependency\r\ninterface ZodIssue {\r\n path: (string | number)[];\r\n message: string;\r\n}\r\n\r\ninterface ZodError extends Error {\r\n errors: ZodIssue[];\r\n}\r\n\r\ninterface ZodSchema<T = unknown> {\r\n parse: (data: unknown) => T;\r\n safeParse: (data: unknown) => { success: boolean; data?: T; error?: ZodError };\r\n}\r\n\r\ntype ZodObject<T = Record<string, unknown>> = ZodSchema<T>;\r\n\r\n/**\r\n * Check if an error is a Zod validation error (duck typing)\r\n */\r\nconst isZodError = (error: unknown): error is ZodError => {\r\n return (\r\n error !== null &&\r\n typeof error === 'object' &&\r\n 'errors' in error &&\r\n Array.isArray((error as ZodError).errors)\r\n );\r\n};\r\nimport { logger } from '../logger';\r\nimport {\r\n successResponse,\r\n createdResponse,\r\n noContentResponse,\r\n badRequestResponse,\r\n notFoundResponse,\r\n errorResponse,\r\n} from '../response/response-object';\r\nimport { extractSchemaMeta } from './utils/schemaMeta.util';\r\nimport type { BulkDeleteRequest } from './bulkDelete.middleware';\r\n\r\n// ==================== Types ====================\r\n\r\n/**\r\n * Extended request with organization ID\r\n */\r\nexport interface OrgRequest extends Request {\r\n organizationId?: string;\r\n}\r\n\r\n/**\r\n * Extended response with paginated result\r\n */\r\nexport interface PaginatedResponse extends Response {\r\n paginatedResult?: {\r\n data: unknown[];\r\n meta: {\r\n page: number;\r\n limit: number;\r\n total: number;\r\n totalPages: number;\r\n };\r\n columns?: unknown[];\r\n };\r\n}\r\n\r\n/**\r\n * CRUD controller configuration\r\n */\r\nexport interface CrudConfig<T> {\r\n /** Mongoose model */\r\n model: Model<T>;\r\n /** Resource name for logging and messages */\r\n resourceName: string;\r\n /** Zod schema for create validation */\r\n createSchema?: ZodObject<unknown>;\r\n /** Zod schema for update validation */\r\n updateSchema?: ZodObject<unknown>;\r\n /** Fields to search on (for getAll) */\r\n searchFields?: string[];\r\n /** Fields that use regex matching for filters */\r\n regexFilterFields?: string[];\r\n /** Whether to scope by organizationId (default: true) */\r\n withOrganization?: boolean;\r\n /** Field to use as the organization reference (default: 'organizationId') */\r\n orgField?: string;\r\n /** Custom transform for create input */\r\n transformCreate?: (input: unknown, req: OrgRequest) => unknown;\r\n /** Custom transform for update input */\r\n transformUpdate?: (input: unknown, req: OrgRequest) => unknown;\r\n /** Custom post-create hook */\r\n afterCreate?: (doc: Document, req: OrgRequest) => Promise<void> | void;\r\n /** Custom post-update hook */\r\n afterUpdate?: (doc: Document, req: OrgRequest) => Promise<void> | void;\r\n /** Custom post-delete hook */\r\n afterDelete?: (id: string, req: OrgRequest) => Promise<void> | void;\r\n /** Fields to exclude from response */\r\n excludeFields?: string[];\r\n /** Fields to populate in queries */\r\n populateFields?: string[];\r\n /** Custom query builder for getAll */\r\n buildQuery?: (req: OrgRequest, baseQuery: Record<string, unknown>) => Record<string, unknown>;\r\n}\r\n\r\n// ==================== Helper Functions ====================\r\n\r\n/**\r\n * Get organization ID from request\r\n */\r\nconst getOrgId = (req: Request, orgField = 'organizationId'): string | undefined => {\r\n const orgReq = req as OrgRequest;\r\n return (\r\n orgReq.organizationId ||\r\n (req.headers['x-organization-id'] as string) ||\r\n (req.query[orgField] as string)\r\n );\r\n};\r\n\r\n/**\r\n * Build organization filter\r\n */\r\nconst buildOrgFilter = (req: Request, config: { withOrganization?: boolean; orgField?: string }): Record<string, unknown> => {\r\n const filter: Record<string, unknown> = {};\r\n\r\n if (config.withOrganization !== false) {\r\n const orgId = getOrgId(req, config.orgField);\r\n if (orgId) {\r\n filter[config.orgField || 'organizationId'] = orgId;\r\n }\r\n }\r\n\r\n return filter;\r\n};\r\n\r\n/**\r\n * Format Zod validation errors\r\n */\r\nconst formatZodError = (error: ZodError): string => {\r\n return error.errors.map((e: ZodIssue) => `${e.path.join('.')}: ${e.message}`).join(', ');\r\n};\r\n\r\n// ==================== Middleware Factory ====================\r\n\r\n/**\r\n * Creates standardized CRUD controller handlers\r\n */\r\nexport function createCrudControllers<T extends Document>(\r\n config: CrudConfig<T>\r\n): {\r\n getAll: RequestHandler;\r\n getById: RequestHandler;\r\n create: RequestHandler;\r\n update: RequestHandler;\r\n deleteOne: RequestHandler;\r\n bulkDelete: RequestHandler;\r\n} {\r\n const {\r\n model,\r\n resourceName,\r\n createSchema,\r\n updateSchema,\r\n searchFields = [],\r\n regexFilterFields = [],\r\n withOrganization = true,\r\n orgField = 'organizationId',\r\n transformCreate,\r\n transformUpdate,\r\n afterCreate,\r\n afterUpdate,\r\n afterDelete,\r\n excludeFields = [],\r\n populateFields = [],\r\n buildQuery,\r\n } = config;\r\n\r\n /**\r\n * GET /\r\n * Get all resources with pagination, search, filters, sorting\r\n */\r\n const getAll: RequestHandler = async (req, res, _next): Promise<void> => {\r\n try {\r\n const paginatedRes = res as PaginatedResponse;\r\n\r\n // If pagination middleware already ran, return its result\r\n if (paginatedRes.paginatedResult) {\r\n successResponse(res, paginatedRes.paginatedResult, `${resourceName} list fetched successfully`);\r\n return;\r\n }\r\n\r\n // Manual pagination if middleware didn't run\r\n const page = parseInt(req.query.page as string) || 1;\r\n const limit = parseInt(req.query.limit as string) || 10;\r\n const sortField = (req.query.sortBy as string) || 'createdAt';\r\n const sortOrder = ((req.query.sortOrder as string) || 'desc') as SortOrder;\r\n const search = req.query.search as string;\r\n\r\n let query: Record<string, unknown> = {};\r\n\r\n // Add organization filter\r\n if (withOrganization) {\r\n const orgId = getOrgId(req, orgField);\r\n if (orgId) {\r\n query[orgField] = orgId;\r\n }\r\n }\r\n\r\n // Add search filter\r\n if (search && searchFields.length > 0) {\r\n query.$or = searchFields.map((field) => ({\r\n [field]: { $regex: search, $options: 'i' },\r\n }));\r\n }\r\n\r\n // Add custom filters from query params\r\n const filterableParams = Object.keys(req.query).filter(\r\n (key) => !['page', 'limit', 'sortBy', 'sortOrder', 'search'].includes(key)\r\n );\r\n\r\n filterableParams.forEach((key) => {\r\n const value = req.query[key];\r\n if (value !== undefined && value !== '' && value !== 'all') {\r\n if (regexFilterFields.includes(key)) {\r\n query[key] = { $regex: value, $options: 'i' };\r\n } else {\r\n query[key] = value;\r\n }\r\n }\r\n });\r\n\r\n // Apply custom query builder if provided\r\n if (buildQuery) {\r\n query = buildQuery(req as OrgRequest, query);\r\n }\r\n\r\n const sortQuery: Record<string, SortOrder> = { [sortField]: sortOrder };\r\n const skip = (page - 1) * limit;\r\n\r\n // Build the query with projection\r\n let projection: Record<string, 0> = {};\r\n if (excludeFields.length > 0) {\r\n projection = excludeFields.reduce(\r\n (acc, field) => ({ ...acc, [field]: 0 }),\r\n {} as Record<string, 0>\r\n );\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n let dbQuery: any = model.find(query, projection);\r\n\r\n // Apply population if configured\r\n if (populateFields.length > 0) {\r\n populateFields.forEach((field) => {\r\n dbQuery = dbQuery.populate(field);\r\n });\r\n }\r\n\r\n const [data, total] = await Promise.all([\r\n dbQuery.sort(sortQuery).skip(skip).limit(limit),\r\n model.countDocuments(query),\r\n ]);\r\n\r\n successResponse(\r\n res,\r\n {\r\n data,\r\n meta: {\r\n page,\r\n limit,\r\n total,\r\n totalPages: Math.ceil(total / limit),\r\n },\r\n columns: extractSchemaMeta(model, createSchema),\r\n },\r\n `${resourceName} list fetched successfully`\r\n );\r\n } catch (error) {\r\n logger.error(`Error in getAll ${resourceName}`, {\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n });\r\n errorResponse(res, `Failed to fetch ${resourceName.toLowerCase()} list`);\r\n }\r\n };\r\n\r\n /**\r\n * GET /:id\r\n * Get single resource by ID\r\n */\r\n const getById: RequestHandler = async (req, res, _next): Promise<void> => {\r\n try {\r\n const { id } = req.params;\r\n\r\n if (!id || !Types.ObjectId.isValid(id)) {\r\n badRequestResponse(res, 'Invalid ID format');\r\n return;\r\n }\r\n\r\n const query: Record<string, unknown> = {\r\n _id: new Types.ObjectId(id),\r\n ...buildOrgFilter(req, { ...config, withOrganization, orgField }),\r\n };\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n let dbQuery: any = model.findOne(query);\r\n\r\n if (populateFields.length > 0) {\r\n populateFields.forEach((field) => {\r\n dbQuery = dbQuery.populate(field);\r\n });\r\n }\r\n\r\n const doc = await dbQuery;\r\n\r\n if (!doc) {\r\n notFoundResponse(res, `${resourceName} not found`);\r\n return;\r\n }\r\n\r\n successResponse(res, doc, `${resourceName} fetched successfully`);\r\n } catch (error) {\r\n logger.error(`Error in getById ${resourceName}`, {\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n id: req.params.id,\r\n });\r\n errorResponse(res, `Failed to fetch ${resourceName.toLowerCase()}`);\r\n }\r\n };\r\n\r\n /**\r\n * POST /\r\n * Create new resource\r\n */\r\n const create: RequestHandler = async (req, res, _next): Promise<void> => {\r\n try {\r\n let input = req.body;\r\n\r\n // Validate with Zod if schema provided\r\n if (createSchema) {\r\n try {\r\n input = createSchema.parse(input);\r\n } catch (error) {\r\n if (isZodError(error)) {\r\n badRequestResponse(res, formatZodError(error));\r\n return;\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n // Transform input if custom transformer provided\r\n if (transformCreate) {\r\n input = transformCreate(input, req as OrgRequest);\r\n }\r\n\r\n // Add organization ID\r\n if (withOrganization) {\r\n const orgId = getOrgId(req, orgField);\r\n if (orgId) {\r\n input[orgField] = orgId;\r\n }\r\n }\r\n\r\n const doc = new model(input);\r\n await doc.save();\r\n\r\n // Run post-create hook\r\n if (afterCreate) {\r\n await afterCreate(doc, req as OrgRequest);\r\n }\r\n\r\n logger.info(`${resourceName} created successfully`, {\r\n id: doc._id,\r\n [orgField]: input[orgField],\r\n });\r\n\r\n createdResponse(res, doc, `${resourceName} created successfully`);\r\n } catch (error) {\r\n logger.error(`Error in create ${resourceName}`, {\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n });\r\n\r\n // Handle duplicate key errors\r\n if ((error as { code?: number }).code === 11000) {\r\n badRequestResponse(res, `A ${resourceName.toLowerCase()} with this data already exists`);\r\n return;\r\n }\r\n\r\n errorResponse(res, `Failed to create ${resourceName.toLowerCase()}`);\r\n }\r\n };\r\n\r\n /**\r\n * PUT /:id\r\n * Update resource\r\n */\r\n const update: RequestHandler = async (req, res, _next): Promise<void> => {\r\n try {\r\n const { id } = req.params;\r\n\r\n if (!id || !Types.ObjectId.isValid(id)) {\r\n badRequestResponse(res, 'Invalid ID format');\r\n return;\r\n }\r\n\r\n let input = req.body;\r\n\r\n // Validate with Zod if schema provided\r\n if (updateSchema) {\r\n try {\r\n input = updateSchema.parse(input);\r\n } catch (error) {\r\n if (isZodError(error)) {\r\n badRequestResponse(res, formatZodError(error));\r\n return;\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n // Transform input if custom transformer provided\r\n if (transformUpdate) {\r\n input = transformUpdate(input, req as OrgRequest);\r\n }\r\n\r\n const query: Record<string, unknown> = {\r\n _id: new Types.ObjectId(id),\r\n ...buildOrgFilter(req, { ...config, withOrganization, orgField }),\r\n };\r\n\r\n const doc = await model.findOneAndUpdate(query, { $set: input }, { new: true });\r\n\r\n if (!doc) {\r\n notFoundResponse(res, `${resourceName} not found`);\r\n return;\r\n }\r\n\r\n // Run post-update hook\r\n if (afterUpdate) {\r\n await afterUpdate(doc, req as OrgRequest);\r\n }\r\n\r\n logger.info(`${resourceName} updated successfully`, { id });\r\n successResponse(res, doc, `${resourceName} updated successfully`);\r\n } catch (error) {\r\n logger.error(`Error in update ${resourceName}`, {\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n id: req.params.id,\r\n });\r\n errorResponse(res, `Failed to update ${resourceName.toLowerCase()}`);\r\n }\r\n };\r\n\r\n /**\r\n * DELETE /:id\r\n * Delete single resource\r\n */\r\n const deleteOne: RequestHandler = async (req, res, _next): Promise<void> => {\r\n try {\r\n const { id } = req.params;\r\n\r\n if (!id || !Types.ObjectId.isValid(id)) {\r\n badRequestResponse(res, 'Invalid ID format');\r\n return;\r\n }\r\n\r\n const query: Record<string, unknown> = {\r\n _id: new Types.ObjectId(id),\r\n ...buildOrgFilter(req, { ...config, withOrganization, orgField }),\r\n };\r\n\r\n const result = await model.deleteOne(query);\r\n\r\n if (result.deletedCount === 0) {\r\n notFoundResponse(res, `${resourceName} not found`);\r\n return;\r\n }\r\n\r\n // Run post-delete hook\r\n if (afterDelete) {\r\n await afterDelete(id, req as OrgRequest);\r\n }\r\n\r\n logger.info(`${resourceName} deleted successfully`, { id });\r\n noContentResponse(res, null, `${resourceName} deleted successfully`);\r\n } catch (error) {\r\n logger.error(`Error in delete ${resourceName}`, {\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n id: req.params.id,\r\n });\r\n errorResponse(res, `Failed to delete ${resourceName.toLowerCase()}`);\r\n }\r\n };\r\n\r\n /**\r\n * DELETE /bulk or DELETE /\r\n * Bulk delete resources\r\n */\r\n const bulkDelete: RequestHandler = async (req, res, _next): Promise<void> => {\r\n try {\r\n const bulkReq = req as BulkDeleteRequest;\r\n const { deleteIds = [], deleteAll = false } = bulkReq;\r\n\r\n const baseFilter = buildOrgFilter(req, { ...config, withOrganization, orgField });\r\n\r\n let filter: Record<string, unknown>;\r\n\r\n if (deleteAll) {\r\n filter = baseFilter;\r\n } else if (deleteIds.length > 0) {\r\n filter = {\r\n ...baseFilter,\r\n _id: { $in: deleteIds.map((id) => new Types.ObjectId(id)) },\r\n };\r\n } else {\r\n badRequestResponse(res, 'No IDs provided for deletion');\r\n return;\r\n }\r\n\r\n const result = await model.deleteMany(filter);\r\n\r\n // Run post-delete hooks\r\n if (afterDelete && deleteIds.length > 0) {\r\n await Promise.all(deleteIds.map((id) => afterDelete(id, req as OrgRequest)));\r\n }\r\n\r\n logger.info(`${resourceName}(s) bulk deleted successfully`, {\r\n deletedCount: result.deletedCount,\r\n deleteAll,\r\n });\r\n\r\n successResponse(\r\n res,\r\n { deletedCount: result.deletedCount },\r\n `${result.deletedCount} ${resourceName.toLowerCase()}(s) deleted successfully`\r\n );\r\n } catch (error) {\r\n logger.error(`Error in bulkDelete ${resourceName}`, {\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n });\r\n errorResponse(res, `Failed to delete ${resourceName.toLowerCase()}(s)`);\r\n }\r\n };\r\n\r\n return {\r\n getAll,\r\n getById,\r\n create,\r\n update,\r\n deleteOne,\r\n bulkDelete,\r\n };\r\n}\r\n\r\n/**\r\n * Creates a standardized pagination middleware for a model\r\n */\r\nexport function createPaginationMiddleware<T>(\r\n model: Model<T>,\r\n config: Partial<CrudConfig<T>> = {}\r\n): RequestHandler {\r\n const {\r\n searchFields = [],\r\n regexFilterFields = [],\r\n withOrganization = true,\r\n orgField = 'organizationId',\r\n } = config;\r\n\r\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\r\n try {\r\n const page = parseInt(req.query.page as string) || 1;\r\n const limit = parseInt(req.query.limit as string) || 10;\r\n const sortField = (req.query.sortBy as string) || 'createdAt';\r\n const sortOrder = ((req.query.sortOrder as string) || 'desc') as SortOrder;\r\n const search = req.query.search as string;\r\n\r\n const query: Record<string, unknown> = {};\r\n\r\n // Add organization filter\r\n if (withOrganization) {\r\n const orgId = getOrgId(req, orgField);\r\n if (orgId) {\r\n query[orgField] = orgId;\r\n }\r\n }\r\n\r\n // Add search filter\r\n if (search && searchFields.length > 0) {\r\n query.$or = searchFields.map((field) => ({\r\n [field]: { $regex: search, $options: 'i' },\r\n }));\r\n }\r\n\r\n // Add other filters\r\n const filterableParams = Object.keys(req.query).filter(\r\n (key) => !['page', 'limit', 'sortBy', 'sortOrder', 'search'].includes(key)\r\n );\r\n\r\n filterableParams.forEach((key) => {\r\n const value = req.query[key];\r\n if (value !== undefined && value !== '' && value !== 'all') {\r\n if (regexFilterFields.includes(key)) {\r\n query[key] = { $regex: value, $options: 'i' };\r\n } else {\r\n query[key] = value;\r\n }\r\n }\r\n });\r\n\r\n const sortQuery: Record<string, SortOrder> = { [sortField]: sortOrder };\r\n const skip = (page - 1) * limit;\r\n\r\n const [data, total] = await Promise.all([\r\n model.find(query).sort(sortQuery).skip(skip).limit(limit),\r\n model.countDocuments(query),\r\n ]);\r\n\r\n const paginatedRes = res as PaginatedResponse;\r\n paginatedRes.paginatedResult = {\r\n data,\r\n meta: {\r\n page,\r\n limit,\r\n total,\r\n totalPages: Math.ceil(total / limit),\r\n },\r\n columns: extractSchemaMeta(model, config.createSchema),\r\n };\r\n\r\n next();\r\n } catch (error) {\r\n next(error);\r\n }\r\n };\r\n}\r\n\r\nexport default createCrudControllers;\r\n","/**\r\n * Bulk Delete Middleware\r\n *\r\n * Common delete middleware for all services.\r\n * Supports:\r\n * - ['*'] → delete all records\r\n * - ['id1', 'id2', ...] → delete multiple records\r\n * - Single ID deletion as subset of multiple\r\n */\r\n\r\nimport { Request, Response, NextFunction } from 'express';\r\nimport { Types } from 'mongoose';\r\nimport { badRequestResponse } from '../response/response-object';\r\nimport { logger } from '../logger';\r\n\r\n/**\r\n * Extended request interface with parsed delete IDs\r\n */\r\nexport interface BulkDeleteRequest extends Request {\r\n deleteIds?: string[];\r\n deleteAll?: boolean;\r\n}\r\n\r\n/**\r\n * Validates and parses bulk delete request body\r\n *\r\n * Expected request body formats:\r\n * - { \"ids\": [\"*\"] } or [\"*\"] → delete all\r\n * - { \"ids\": [\"id1\", \"id2\"] } or [\"id1\", \"id2\"] → delete specific records\r\n */\r\nexport const parseBulkDelete = (\r\n req: Request,\r\n res: Response,\r\n next: NextFunction\r\n): void | Response => {\r\n try {\r\n const bulkReq = req as BulkDeleteRequest;\r\n\r\n // Get IDs from body - support both { ids: [...] } and [...] formats\r\n let ids: unknown[] = [];\r\n\r\n if (Array.isArray(req.body)) {\r\n ids = req.body;\r\n } else if (req.body && Array.isArray(req.body.ids)) {\r\n ids = req.body.ids;\r\n } else if (req.body && typeof req.body === 'object') {\r\n // Check for data property (common pattern)\r\n if (Array.isArray(req.body.data)) {\r\n ids = req.body.data;\r\n }\r\n }\r\n\r\n // Validate that we have IDs\r\n if (ids.length === 0) {\r\n return badRequestResponse(\r\n res,\r\n 'Request body must contain an array of IDs. Use [\"*\"] to delete all records or [\"id1\", \"id2\"] to delete specific records.'\r\n );\r\n }\r\n\r\n // Check for delete all\r\n if (ids.length === 1 && ids[0] === '*') {\r\n bulkReq.deleteAll = true;\r\n bulkReq.deleteIds = [];\r\n logger.info('Bulk delete: Deleting all records');\r\n return next();\r\n }\r\n\r\n // Validate all IDs are valid MongoDB ObjectIds\r\n const validIds: string[] = [];\r\n const invalidIds: unknown[] = [];\r\n\r\n for (const id of ids) {\r\n if (typeof id === 'string' && Types.ObjectId.isValid(id)) {\r\n validIds.push(id);\r\n } else {\r\n invalidIds.push(id);\r\n }\r\n }\r\n\r\n if (invalidIds.length > 0) {\r\n return badRequestResponse(\r\n res,\r\n `Invalid ID format(s): ${invalidIds.slice(0, 5).join(', ')}${invalidIds.length > 5 ? '...' : ''}. All IDs must be valid MongoDB ObjectIds.`\r\n );\r\n }\r\n\r\n if (validIds.length === 0) {\r\n return badRequestResponse(res, 'No valid IDs provided for deletion.');\r\n }\r\n\r\n bulkReq.deleteAll = false;\r\n bulkReq.deleteIds = validIds;\r\n logger.info(`Bulk delete: Deleting ${validIds.length} record(s)`);\r\n\r\n next();\r\n } catch (error) {\r\n logger.error('Error in parseBulkDelete middleware', error);\r\n return badRequestResponse(res, 'Failed to parse delete request');\r\n }\r\n};\r\n\r\n/**\r\n * Helper function to build delete filter for MongoDB\r\n */\r\nexport const buildDeleteFilter = (\r\n req: BulkDeleteRequest,\r\n organizationId: string\r\n): Record<string, unknown> => {\r\n const filter: Record<string, unknown> = {\r\n organizationId: new Types.ObjectId(organizationId),\r\n };\r\n\r\n if (!req.deleteAll && req.deleteIds && req.deleteIds.length > 0) {\r\n filter._id = {\r\n $in: req.deleteIds.map((id) => new Types.ObjectId(id)),\r\n };\r\n }\r\n\r\n return filter;\r\n};\r\n\r\n/**\r\n * Generic bulk delete handler factory\r\n *\r\n * Creates a controller function that handles bulk delete operations\r\n * for any Mongoose model.\r\n */\r\nexport const createBulkDeleteHandler = (\r\n Model: { deleteMany: (filter: Record<string, unknown>) => Promise<{ deletedCount?: number }> },\r\n modelName: string\r\n) => {\r\n return async (req: Request, res: Response): Promise<Response> => {\r\n const bulkReq = req as BulkDeleteRequest;\r\n const organizationId = req.headers['x-organization-id'] as string;\r\n\r\n if (!organizationId) {\r\n return badRequestResponse(res, 'Organization ID is required');\r\n }\r\n\r\n try {\r\n const filter = buildDeleteFilter(bulkReq, organizationId);\r\n const result = await Model.deleteMany(filter);\r\n\r\n const deletedCount = result.deletedCount || 0;\r\n\r\n logger.info(`Bulk delete completed: ${deletedCount} ${modelName}(s) deleted`, {\r\n organizationId,\r\n deleteAll: bulkReq.deleteAll,\r\n requestedIds: bulkReq.deleteIds?.length || 'all',\r\n deletedCount,\r\n });\r\n\r\n return res.status(200).json({\r\n message: `Successfully deleted ${deletedCount} ${modelName}(s)`,\r\n data: {\r\n deletedCount,\r\n deleteAll: bulkReq.deleteAll,\r\n },\r\n status: 'success',\r\n statusCode: 200,\r\n });\r\n } catch (error) {\r\n logger.error(`Error in bulk delete ${modelName}`, error);\r\n return res.status(500).json({\r\n message: `Failed to delete ${modelName}(s)`,\r\n data: null,\r\n status: 'error',\r\n statusCode: 500,\r\n });\r\n }\r\n };\r\n};\r\n\r\nexport default {\r\n parseBulkDelete,\r\n buildDeleteFilter,\r\n createBulkDeleteHandler,\r\n};\r\n"]}
|