@codisolutions23/node-utils 3.1.0 → 3.2.1
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/.changeset/README.md +8 -8
- package/.changeset/config.json +11 -11
- package/CHANGELOG.md +104 -94
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +19 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +47 -44
- package/.changeset/shiny-donkeys-glow.md +0 -11
- package/dist/index.d.mts +0 -169
- package/dist/index.d.ts +0 -169
package/.changeset/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Changesets
|
|
2
|
-
|
|
3
|
-
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
4
|
-
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
5
|
-
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
|
6
|
-
|
|
7
|
-
We have a quick list of common questions to get you started engaging with this project in
|
|
8
|
-
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
|
1
|
+
# Changesets
|
|
2
|
+
|
|
3
|
+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
4
|
+
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
5
|
+
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
|
6
|
+
|
|
7
|
+
We have a quick list of common questions to get you started engaging with this project in
|
|
8
|
+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
package/.changeset/config.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
|
3
|
-
"changelog": "@changesets/cli/changelog",
|
|
4
|
-
"commit": false,
|
|
5
|
-
"fixed": [],
|
|
6
|
-
"linked": [],
|
|
7
|
-
"access": "restricted",
|
|
8
|
-
"baseBranch": "main",
|
|
9
|
-
"updateInternalDependencies": "patch",
|
|
10
|
-
"ignore": []
|
|
11
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
|
3
|
+
"changelog": "@changesets/cli/changelog",
|
|
4
|
+
"commit": false,
|
|
5
|
+
"fixed": [],
|
|
6
|
+
"linked": [],
|
|
7
|
+
"access": "restricted",
|
|
8
|
+
"baseBranch": "main",
|
|
9
|
+
"updateInternalDependencies": "patch",
|
|
10
|
+
"ignore": []
|
|
11
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,94 +1,104 @@
|
|
|
1
|
-
# @codisolutions23/node-utils
|
|
2
|
-
|
|
3
|
-
## 3.0
|
|
4
|
-
|
|
5
|
-
###
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- **
|
|
65
|
-
- **
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
##
|
|
93
|
-
|
|
94
|
-
-
|
|
1
|
+
# @codisolutions23/node-utils
|
|
2
|
+
|
|
3
|
+
## 3.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3e1d36f: Enhanced cache system with clearer function names (`getCache`, `setCache`, `delCache`, `delCacheGroup`) and configurable TTL via environment variables. Improved error handling by replacing generic Error with NotFoundError for missing environment variables. Optimized authentication middleware logging to reduce production noise. Updated AWS SDK dependencies to latest versions.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Extended `DecodedToken` and `AuthenticatedRequest` interfaces with index signatures to support additional JWT claims and user properties. This improves flexibility for handling custom data without TypeScript errors while maintaining backward compatibility.
|
|
12
|
+
|
|
13
|
+
## 3.0.2
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- c740901: **Patch Changes and Improvements**
|
|
18
|
+
|
|
19
|
+
- **Dependencies**: Upgraded @aws-sdk and @smithy packages from v3.883.0 to v3.890.0, bringing latest features, bug fixes, and security improvements
|
|
20
|
+
- **Template Resolution**: Enhanced getTemplatePath to check multiple locations (src/public, public, provided directory) with fallback to src/public for improved flexibility
|
|
21
|
+
- **Handlebars Helpers**: Added formatCurrency for Philippine peso formatting and formatDate for flexible date formatting
|
|
22
|
+
- **Authentication Middleware**: Refactored for better modularity, added admin and role-based access control, improved logging and error handling with token revocation checks
|
|
23
|
+
|
|
24
|
+
## 3.0.1
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Update dependencies
|
|
29
|
+
|
|
30
|
+
## 3.0.0
|
|
31
|
+
|
|
32
|
+
### Major Changes
|
|
33
|
+
|
|
34
|
+
- - Removed validate-request middleware file
|
|
35
|
+
- Removed validate-request middleware export from index
|
|
36
|
+
- Added startSession method to atlas utils
|
|
37
|
+
- Updated pagination utils for correct page range calculation
|
|
38
|
+
|
|
39
|
+
## 2.1.0
|
|
40
|
+
|
|
41
|
+
### Minor Changes
|
|
42
|
+
|
|
43
|
+
- chore: add token revocation check to auth middleware
|
|
44
|
+
|
|
45
|
+
- Introduced an optional `isTokenRevoked` callback to the `authenticate` middleware, allowing revoked (blacklisted) JWTs to be detected and rejected.
|
|
46
|
+
- This enhances security by supporting token invalidation, such as for logout or compromised tokens.
|
|
47
|
+
|
|
48
|
+
## 2.0.0
|
|
49
|
+
|
|
50
|
+
### Major Changes
|
|
51
|
+
|
|
52
|
+
- 03a36a6: - Moved `mongodb` and `@types/mongodb` from dependencies to peerDependencies. Consumers must now install these packages themselves.
|
|
53
|
+
- Refactored Redis client retrieval in `/utils/cache` to use a helper function, ensuring a fresh client instance for each cache operation and improving reliability.
|
|
54
|
+
- Updated `yarn.lock` to reflect dependency changes.
|
|
55
|
+
|
|
56
|
+
## 1.2.0
|
|
57
|
+
|
|
58
|
+
### Minor Changes
|
|
59
|
+
|
|
60
|
+
- 4ef458f: # 🚀 Comprehensive Package Enhancement
|
|
61
|
+
|
|
62
|
+
## ✨ New Features
|
|
63
|
+
|
|
64
|
+
- **NEW**: `ConflictError` class for HTTP 409 responses
|
|
65
|
+
- **NEW**: Enhanced `AuthenticatedRequest` interface with better TypeScript support
|
|
66
|
+
- **NEW**: Comprehensive README documentation with usage examples and API reference
|
|
67
|
+
|
|
68
|
+
## 🔧 Improvements
|
|
69
|
+
|
|
70
|
+
- **Enhanced**: Auth middleware with improved token handling and error messages
|
|
71
|
+
- **Improved**: Error handler middleware with better import paths
|
|
72
|
+
- **Simplified**: Configuration system for better flexibility
|
|
73
|
+
- **Updated**: All AWS SDK packages to latest versions (3.857.x → 3.859.x)
|
|
74
|
+
- **Updated**: Redis ecosystem packages (redis 5.6.1 → 5.8.0, ioredis 5.6.1 → 5.7.0)
|
|
75
|
+
- **Updated**: TypeScript to 5.9.2 for improved type safety
|
|
76
|
+
|
|
77
|
+
## 📚 Documentation
|
|
78
|
+
|
|
79
|
+
- Complete README overhaul with detailed usage examples
|
|
80
|
+
- API reference for all utilities and middleware
|
|
81
|
+
- Best practices and configuration guides
|
|
82
|
+
- Testing support examples and mock utilities
|
|
83
|
+
|
|
84
|
+
## 🛡️ Security & Performance
|
|
85
|
+
|
|
86
|
+
- Latest security patches through dependency updates
|
|
87
|
+
- Improved error handling and logging
|
|
88
|
+
- Better TypeScript type definitions
|
|
89
|
+
|
|
90
|
+
- f57eb57: # 🚀 Comprehensive Package Enhancement
|
|
91
|
+
|
|
92
|
+
## ✨ New Features
|
|
93
|
+
|
|
94
|
+
- **NEW**: Added `validate-request.middleware` for request validation
|
|
95
|
+
- **NEW**: Introduced `token.utils` for token-related operations
|
|
96
|
+
|
|
97
|
+
## 🔧 Improvements
|
|
98
|
+
|
|
99
|
+
- **Updated**: Configuration file with minor adjustments
|
|
100
|
+
- **Enhanced**: `auth.middleware` with better token handling and error responses
|
|
101
|
+
|
|
102
|
+
## 🛡️ Security & Performance
|
|
103
|
+
|
|
104
|
+
- Minor internal optimizations for better stability
|
package/dist/index.js
CHANGED
|
@@ -88,6 +88,7 @@ __export(index_exports, {
|
|
|
88
88
|
renderHandlebarsTemplate: () => renderHandlebarsTemplate,
|
|
89
89
|
requireAdmin: () => requireAdmin,
|
|
90
90
|
requireRole: () => requireRole,
|
|
91
|
+
scheduleCronJob: () => scheduleCronJob,
|
|
91
92
|
signJwtToken: () => signJwtToken,
|
|
92
93
|
toObjectId: () => toObjectId,
|
|
93
94
|
useAtlas: () => useAtlas,
|
|
@@ -564,6 +565,24 @@ function buildCacheKey(prefix, values) {
|
|
|
564
565
|
return `${prefix}:${query}`;
|
|
565
566
|
}
|
|
566
567
|
|
|
568
|
+
// src/utils/cron-job.ts
|
|
569
|
+
var import_node_cron = require("node-cron");
|
|
570
|
+
function scheduleCronJob(expression, timezone, task) {
|
|
571
|
+
return (0, import_node_cron.schedule)(
|
|
572
|
+
expression,
|
|
573
|
+
() => __async(null, null, function* () {
|
|
574
|
+
try {
|
|
575
|
+
yield task();
|
|
576
|
+
} catch (error) {
|
|
577
|
+
logger.error(
|
|
578
|
+
`[CronJob] Error: ${error instanceof Error ? error.message : error}`
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
}),
|
|
582
|
+
{ timezone }
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
|
|
567
586
|
// src/utils/get-template-path.ts
|
|
568
587
|
var import_path = __toESM(require("path"));
|
|
569
588
|
function getTemplatePath(directory, filePath) {
|
|
@@ -921,6 +940,7 @@ function hashToken(token) {
|
|
|
921
940
|
renderHandlebarsTemplate,
|
|
922
941
|
requireAdmin,
|
|
923
942
|
requireRole,
|
|
943
|
+
scheduleCronJob,
|
|
924
944
|
signJwtToken,
|
|
925
945
|
toObjectId,
|
|
926
946
|
useAtlas,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/middleware/auth.middleware.ts","../src/utils/logger.ts","../src/utils/http-error.ts","../src/middleware/error-handler.middleware.ts","../src/utils/atlas.ts","../src/config.ts","../src/utils/ioredis.ts","../src/utils/cache.ts","../src/utils/cache-key.ts","../src/utils/get-template-path.ts","../src/utils/handlebars-compiler.ts","../src/utils/jwt.ts","../src/utils/mailer.ts","../src/utils/objectid-converter.ts","../src/utils/paginate.ts","../src/utils/password.ts","../src/utils/redis.ts","../src/utils/s3.ts","../src/utils/token.ts"],"sourcesContent":["export * from \"./middleware\";\r\nexport * from \"./utils\";\r\n","import { NextFunction, Request, Response } from \"express\";\r\nimport jwt, { JwtPayload } from \"jsonwebtoken\";\r\nimport { logger } from \"./../utils/logger\";\r\nimport { UnauthorizedError, ForbiddenError } from \"./../utils/http-error\";\r\n\r\ninterface DecodedToken extends JwtPayload {\r\n user?: string;\r\n id?: string;\r\n jti?: string;\r\n role?: string;\r\n}\r\n\r\nexport interface AuthenticatedRequest extends Request {\r\n user?: DecodedToken & { id: string };\r\n token?: string;\r\n}\r\n\r\ninterface AuthOptions {\r\n secretKey?: string;\r\n isTokenRevoked?: (jti: string) => Promise<boolean>;\r\n requiredRole?: string;\r\n}\r\n\r\n// Helper function to extract token from Authorization header\r\nfunction extractToken(authHeader?: string): string | null {\r\n if (!authHeader) {\r\n return null;\r\n }\r\n\r\n if (!authHeader.startsWith(\"Bearer \")) {\r\n logger.warn(\"Invalid Authorization header format\", {\r\n format: \"Expected 'Bearer <token>'\",\r\n });\r\n return null;\r\n }\r\n\r\n return authHeader.split(\" \")[1] || null;\r\n}\r\n\r\n// Core authentication logic\r\nasync function authenticateToken(\r\n req: AuthenticatedRequest,\r\n options: AuthOptions\r\n): Promise<void> {\r\n const {\r\n secretKey = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked,\r\n requiredRole,\r\n } = options;\r\n const requestId = req.headers[\"x-request-id\"] || \"unknown\";\r\n\r\n const isDev = process.env.NODE_ENV === \"development\";\r\n\r\n if (isDev) {\r\n logger.debug(\"Starting authentication process\", {\r\n requestId,\r\n path: req.path,\r\n requiredRole,\r\n });\r\n }\r\n\r\n const token = extractToken(req.headers.authorization);\r\n if (!token) {\r\n logger.error(\"Authentication failed: No access token provided\", {\r\n requestId,\r\n path: req.path,\r\n });\r\n throw new UnauthorizedError(\"Access token is required to proceed.\");\r\n }\r\n\r\n let decoded: DecodedToken;\r\n try {\r\n decoded = jwt.verify(token, secretKey) as DecodedToken;\r\n\r\n if (isDev) {\r\n logger.debug(\"JWT token verified\", {\r\n requestId,\r\n userId: decoded.user || decoded.id,\r\n role: decoded.role,\r\n });\r\n }\r\n } catch (error) {\r\n logger.error(\"JWT verification failed\", {\r\n requestId,\r\n error: error instanceof Error ? error.message : \"Invalid token\",\r\n path: req.path,\r\n });\r\n throw new UnauthorizedError(\r\n \"Your session has expired or the token is invalid. Please log in again.\"\r\n );\r\n }\r\n\r\n // Check if token is revoked\r\n if (isTokenRevoked && decoded.jti) {\r\n const isRevoked = await isTokenRevoked(decoded.jti);\r\n if (isRevoked) {\r\n logger.warn(\"Authentication failed: Token is revoked\", {\r\n requestId,\r\n jti: decoded.jti,\r\n userId: decoded.user || decoded.id,\r\n });\r\n throw new UnauthorizedError(\r\n \"Your session has expired or the token is invalid. Please log in again.\"\r\n );\r\n }\r\n }\r\n\r\n // Check role requirements\r\n if (requiredRole && decoded.role !== requiredRole) {\r\n logger.warn(\"Authorization failed: Insufficient permissions\", {\r\n requestId,\r\n userId: decoded.user || decoded.id,\r\n userRole: decoded.role,\r\n requiredRole,\r\n path: req.path,\r\n });\r\n throw new ForbiddenError(\r\n \"Insufficient permissions to access this resource.\"\r\n );\r\n }\r\n\r\n // Set user data on request\r\n req.user = {\r\n ...decoded,\r\n id: decoded.user || decoded.id || \"\",\r\n };\r\n req.token = token;\r\n\r\n if (isDev) {\r\n logger.debug(\"Authentication completed successfully\", {\r\n requestId,\r\n userId: req.user.id,\r\n role: req.user.role,\r\n });\r\n }\r\n}\r\n\r\nexport function authenticate(\r\n secretKey: string = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked?: (jti: string) => Promise<boolean>\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, { secretKey, isTokenRevoked });\r\n next();\r\n } catch (error) {\r\n logger.error(\"Authenticate middleware failed\", {\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n\r\nexport function requireAdmin(\r\n secretKey: string = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked?: (jti: string) => Promise<boolean>\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, {\r\n secretKey,\r\n isTokenRevoked,\r\n requiredRole: \"admin\",\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireAdmin middleware failed\", {\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n\r\n// Additional helper middleware for role-based access\r\nexport function requireRole(\r\n role: string,\r\n options?: Omit<AuthOptions, \"requiredRole\">\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, {\r\n ...options,\r\n requiredRole: role,\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireRole middleware failed\", {\r\n requiredRole: role,\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n","import * as winston from \"winston\";\r\n\r\nconst transports = [\r\n new winston.transports.File({ filename: \"error.log\", level: \"error\" }),\r\n new winston.transports.File({ filename: \"combined.log\" }),\r\n];\r\n\r\nexport const logger = winston.createLogger({\r\n level: \"info\",\r\n format: winston.format.combine(\r\n winston.format.timestamp(),\r\n winston.format.json()\r\n ),\r\n transports,\r\n});\r\n","export class HttpError extends Error {\r\n public readonly statusCode: number;\r\n public readonly isOperational: boolean;\r\n\r\n constructor(\r\n message: string,\r\n statusCode: number,\r\n isOperational: boolean = true\r\n ) {\r\n super(message);\r\n\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n\r\n this.statusCode = statusCode;\r\n this.isOperational = isOperational;\r\n\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, this.constructor);\r\n }\r\n }\r\n}\r\n\r\nexport class BadRequestError extends HttpError {\r\n constructor(\r\n message: string = \"The request could not be processed. Please review your input and try again.\"\r\n ) {\r\n super(message, 400, true);\r\n }\r\n}\r\n\r\nexport class UnauthorizedError extends HttpError {\r\n constructor(\r\n message: string = \"Authentication is required to access this resource.\"\r\n ) {\r\n super(message, 401, true);\r\n }\r\n}\r\n\r\nexport class ForbiddenError extends HttpError {\r\n constructor(\r\n message: string = \"You do not have the necessary permissions to perform this action.\"\r\n ) {\r\n super(message, 403, true);\r\n }\r\n}\r\n\r\nexport class NotFoundError extends HttpError {\r\n constructor(message: string = \"The requested resource could not be found.\") {\r\n super(message, 404, true);\r\n }\r\n}\r\n\r\nexport class ConflictError extends HttpError {\r\n constructor(\r\n message: string = \"A resource with the provided values already exists.\"\r\n ) {\r\n super(message, 409, true);\r\n }\r\n}\r\n\r\nexport class UnprocessableEntityError extends HttpError {\r\n constructor(\r\n message: string = \"The request could not be completed due to invalid or incomplete information.\"\r\n ) {\r\n super(message, 422, true);\r\n }\r\n}\r\n\r\nexport class InternalServerError extends HttpError {\r\n constructor(\r\n message: string = \"An internal server error occurred. Please try again later.\"\r\n ) {\r\n super(message, 500, true);\r\n }\r\n}\r\n","import { NextFunction, Request, Response } from \"express\";\r\nimport { HttpError, InternalServerError } from \"./../utils/http-error\";\r\nimport { logger } from \"./../utils/logger\";\r\n\r\nexport const errorHandler = (\r\n error: HttpError,\r\n req: Request,\r\n res: Response,\r\n next: NextFunction\r\n) => {\r\n if (error.isOperational) {\r\n res\r\n .status(error.statusCode)\r\n .json({ status: \"error\", message: error.message });\r\n } else {\r\n logger.error({ message: error.message });\r\n res\r\n .status(500)\r\n .json({ status: \"error\", message: new InternalServerError().message });\r\n }\r\n\r\n return;\r\n};\r\n","import { Db, MongoClient } from \"mongodb\";\r\nimport { logger } from \"./logger\";\r\nimport {\r\n BadRequestError,\r\n InternalServerError,\r\n NotFoundError,\r\n} from \"./http-error\";\r\n\r\ninterface AtlasConfig {\r\n uri: string;\r\n db: string;\r\n name?: string;\r\n}\r\n\r\nexport class useAtlas {\r\n private static mongoClient: MongoClient | null = null;\r\n private static mongoDb: Db | null = null;\r\n\r\n public static async connect(config: AtlasConfig): Promise<void> {\r\n if (this.mongoClient) {\r\n logger.warn(\r\n \"[MongoDB][Connect] Client is already connected. Skipping new connection.\"\r\n );\r\n throw new BadRequestError(\"A MongoDB connection is already established.\");\r\n }\r\n\r\n const { db, uri } = config;\r\n this.mongoClient = new MongoClient(uri, {\r\n maxPoolSize: 10,\r\n maxIdleTimeMS: 60000,\r\n connectTimeoutMS: 60000,\r\n });\r\n\r\n try {\r\n await this.mongoClient.connect();\r\n this.mongoDb = this.mongoClient.db(db);\r\n\r\n logger.info(\r\n `[MongoDB][Connect] Connected to database \"${this.mongoDb.databaseName}\".`\r\n );\r\n } catch (error) {\r\n this.mongoClient = null;\r\n\r\n logger.error(\r\n `[MongoDB][Connect] Failed to connect: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\r\n \"Failed to connect to the database. Please try again later.\"\r\n );\r\n }\r\n }\r\n\r\n public static getClient(): MongoClient | null {\r\n if (!this.mongoClient) {\r\n logger.warn(`[MongoDB][GetClient] Client is not initialized.`);\r\n throw new NotFoundError(\"MongoDB client is not initialized.\");\r\n }\r\n\r\n return this.mongoClient;\r\n }\r\n\r\n public static getDb(): Db | null {\r\n if (!this.mongoDb) {\r\n logger.warn(`[MongoDB][GetDb] Database instance is not available.`);\r\n throw new NotFoundError(\"MongoDB database instance is not available.\");\r\n }\r\n\r\n return this.mongoDb;\r\n }\r\n\r\n public static startSession(): import(\"mongodb\").ClientSession {\r\n const client = this.getClient();\r\n\r\n if (!client) {\r\n logger.warn(`[MongoDB][StartSession] Client is not initialized.`);\r\n throw new NotFoundError(\"MongoDB client is not initialized.\");\r\n }\r\n\r\n return client.startSession();\r\n }\r\n\r\n public static async close(): Promise<void> {\r\n if (this.mongoClient) {\r\n try {\r\n await this.mongoClient.close();\r\n\r\n logger.info(`[MongoDB][Close] Connection closed.`);\r\n } catch (error) {\r\n logger.error(\r\n `[MongoDB][Close] Error closing connection: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to close MongoDB connection.\");\r\n } finally {\r\n this.mongoClient = null;\r\n this.mongoDb = null;\r\n }\r\n } else {\r\n logger.warn(`[MongoDB][Close] No client to disconnect.`);\r\n throw new BadRequestError(\"No MongoDB connection exists to close.\");\r\n }\r\n }\r\n}\r\n","import * as dotenv from \"dotenv\";\r\nimport { NotFoundError } from \"./utils/http-error\";\r\n\r\ndotenv.config();\r\n\r\nfunction getEnv(key: string, fallback?: string): string {\r\n const value = process.env[key];\r\n if (value !== undefined) return value as string;\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\nfunction getEnvNumber(key: string, fallback?: number): number {\r\n const value = process.env[key];\r\n if (value !== undefined) return Number(value);\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\nfunction getEnvBoolean(key: string, fallback?: boolean): boolean {\r\n const value = process.env[key];\r\n if (value !== undefined) return value === \"true\";\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\n// Redis\r\nexport const REDIS_HOST = getEnv(\"REDIS_HOST\");\r\nexport const REDIS_PORT = getEnvNumber(\"REDIS_PORT\", 6379);\r\nexport const REDIS_PASSWORD = getEnv(\"REDIS_PASSWORD\");\r\nexport const REDIS_TLS = getEnvBoolean(\"REDIS_TLS\", true);\r\n\r\n// Cache Settings\r\nexport const CACHE_SHORT_TTL = getEnvNumber(\"CACHE_SHORT_TTL\", 300);\r\nexport const CACHE_LONG_TTL = getEnvNumber(\"CACHE_LONG_TTL\", 3600);\r\n","import Redis from \"ioredis\";\r\nimport { logger } from \"./logger\";\r\nimport { BadRequestError } from \"./http-error\";\r\n\r\nlet redisClient: Redis | null = null;\r\n\r\ntype RedisOptions = {\r\n host?: string;\r\n port?: number;\r\n username?: string;\r\n password?: string;\r\n};\r\n\r\nexport function useRedis() {\r\n function initialize(options: RedisOptions) {\r\n if (redisClient) {\r\n logger.info(\"[Redis][Init] Redis connection is already established.\");\r\n return redisClient;\r\n }\r\n\r\n options.host = options.host ?? \"localhost\";\r\n options.port = options.port ?? 6379;\r\n options.username = options.username ?? \"default\";\r\n options.password = options.password ?? \"\";\r\n\r\n redisClient = new Redis({\r\n host: options.host,\r\n port: options.port,\r\n ...(options.username && { username: options.username }),\r\n ...(options.password && { password: options.password }),\r\n });\r\n\r\n redisClient.on(\"connect\", () => {\r\n logger.info(\r\n `[Redis][Connect] Redis client connected at ${options.host}:${options.port}.`\r\n );\r\n });\r\n\r\n redisClient.on(\"error\", (error) => {\r\n logger.error(\r\n `[Redis][Error] Failed to connect: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n });\r\n\r\n return redisClient;\r\n }\r\n\r\n function getClient(): Redis {\r\n if (!redisClient) {\r\n logger.error(\r\n \"[Redis][GetClient] Redis connection has not been initialized.\"\r\n );\r\n throw new BadRequestError(\r\n \"Redis connection is not initialized. Please call initialize() first.\"\r\n );\r\n }\r\n\r\n return redisClient;\r\n }\r\n\r\n function disconnect() {\r\n if (redisClient) {\r\n redisClient.quit();\r\n logger.info(\"[Redis][Disconnect] Redis connection has been closed.\");\r\n redisClient = null;\r\n } else {\r\n logger.warn(\"[Redis][Disconnect] No Redis client to disconnect.\");\r\n }\r\n }\r\n\r\n return {\r\n initialize,\r\n getClient,\r\n disconnect,\r\n };\r\n}\r\n","import { CACHE_LONG_TTL, CACHE_SHORT_TTL } from \"../config\";\r\nimport { useRedis } from \"./ioredis\";\r\nimport { logger } from \"./logger\";\r\n\r\nexport function useCache() {\r\n function getRedisClient() {\r\n return useRedis().getClient();\r\n }\r\n\r\n async function getCache<T = unknown>(cacheKey: string): Promise<T | null> {\r\n try {\r\n const redisClient = getRedisClient();\r\n const value = await redisClient.get(cacheKey);\r\n\r\n return value ? (JSON.parse(value) as T) : null;\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Get] Failed to retrieve key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n\r\n return null;\r\n }\r\n }\r\n\r\n async function setCache<T = unknown>(\r\n cacheKey: string,\r\n data: T,\r\n ttl: number = CACHE_SHORT_TTL,\r\n group?: string\r\n ): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n await redisClient.set(cacheKey, JSON.stringify(data), \"EX\", ttl);\r\n logger.info(`[Cache][Set] Stored key \"${cacheKey}\" with TTL ${ttl}s.`);\r\n\r\n if (group) {\r\n await redisClient.sadd(`cache:group:${group}`, cacheKey);\r\n await redisClient.expire(`cache:group:${group}`, CACHE_LONG_TTL);\r\n }\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Set] Failed to store key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n async function delCache(cacheKey: string): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n await redisClient.del(cacheKey);\r\n logger.info(`[Cache][Remove] Key \"${cacheKey}\" has been deleted.`);\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Remove] Failed to delete key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n async function delCacheGroup(group: string): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n const keys = await redisClient.smembers(`cache:group:${group}`);\r\n if (keys.length) await redisClient.del(...keys);\r\n\r\n await redisClient.del(`cache:group:${group}`);\r\n logger.info(`[Cache][ClearGroup] Cleared group \"${group}\" and its keys.`);\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][ClearGroup] Failed to clear group \"${group}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n return {\r\n getCache,\r\n setCache,\r\n delCache,\r\n delCacheGroup,\r\n };\r\n}\r\n","export function buildCacheKey(\r\n prefix: string,\r\n values: Record<string, any>\r\n): string {\r\n const query = Object.entries(values)\r\n .sort(([a], [b]) => a.localeCompare(b))\r\n .map(\r\n ([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`\r\n )\r\n .join(\"&\");\r\n\r\n return `${prefix}:${query}`;\r\n}\r\n","import path from \"path\";\r\n\r\nexport function getTemplatePath(directory: string, filePath: string) {\r\n const ext = \".hbs\";\r\n const file = filePath.endsWith(ext) ? filePath : `${filePath}${ext}`;\r\n\r\n // Resolve from project root, assuming templates are in src/public/templates or public/templates\r\n const possiblePaths = [\r\n path.join(process.cwd(), \"src\", \"public\", directory, file),\r\n path.join(process.cwd(), \"public\", directory, file),\r\n path.join(process.cwd(), directory, file),\r\n ];\r\n\r\n // Return the first path that exists, or default to src/public structure\r\n const fs = require(\"fs\");\r\n for (const templatePath of possiblePaths) {\r\n if (fs.existsSync(templatePath)) {\r\n return templatePath;\r\n }\r\n }\r\n\r\n // Default to src/public structure if none exist\r\n return possiblePaths[0];\r\n}\r\n","import Handlebars from \"handlebars\";\r\nimport { promises as fs } from \"fs\";\r\nimport { InternalServerError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface CompileOptions {\r\n context?: Record<string, any>;\r\n filePath: string;\r\n}\r\n\r\nconst handlebarsTemplateCache = new Map<string, Handlebars.TemplateDelegate>();\r\n\r\n// Register Handlebars helpers\r\nHandlebars.registerHelper(\"formatCurrency\", function (amount: number) {\r\n if (typeof amount !== \"number\") return \"0.00\";\r\n return new Intl.NumberFormat(\"en-PH\", {\r\n style: \"decimal\",\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: 2,\r\n }).format(amount);\r\n});\r\n\r\nHandlebars.registerHelper(\r\n \"formatDate\",\r\n function (date: Date | string, format: string) {\r\n if (!date) return \"N/A\";\r\n\r\n const dateObj = typeof date === \"string\" ? new Date(date) : date;\r\n if (isNaN(dateObj.getTime())) return \"N/A\";\r\n\r\n const options: Intl.DateTimeFormatOptions = {};\r\n\r\n if (format.includes(\"MMMM\")) options.month = \"long\";\r\n else if (format.includes(\"MMM\")) options.month = \"short\";\r\n else if (format.includes(\"MM\")) options.month = \"2-digit\";\r\n\r\n if (format.includes(\"D,\")) options.day = \"numeric\";\r\n else if (format.includes(\"DD\")) options.day = \"2-digit\";\r\n\r\n if (format.includes(\"YYYY\")) options.year = \"numeric\";\r\n else if (format.includes(\"YY\")) options.year = \"2-digit\";\r\n\r\n if (format.includes(\"h:mm A\")) {\r\n options.hour = \"numeric\";\r\n options.minute = \"2-digit\";\r\n options.hour12 = true;\r\n } else if (format.includes(\"HH:mm\")) {\r\n options.hour = \"2-digit\";\r\n options.minute = \"2-digit\";\r\n options.hour12 = false;\r\n }\r\n\r\n return new Intl.DateTimeFormat(\"en-US\", options).format(dateObj);\r\n }\r\n);\r\n\r\nexport async function renderHandlebarsTemplate({\r\n context = {},\r\n filePath,\r\n}: CompileOptions): Promise<string> {\r\n try {\r\n let compiledTemplate = handlebarsTemplateCache.get(filePath);\r\n\r\n if (!compiledTemplate) {\r\n logger.info(\r\n `[Template][Compile] Compiling and caching template from \"${filePath}\".`\r\n );\r\n const fileContent = await fs.readFile(filePath, \"utf8\");\r\n compiledTemplate = Handlebars.compile(fileContent);\r\n handlebarsTemplateCache.set(filePath, compiledTemplate);\r\n } else {\r\n logger.info(`[Template][Cache] Using cached template for \"${filePath}\".`);\r\n }\r\n\r\n return compiledTemplate(context);\r\n } catch (error) {\r\n logger.error(\r\n `[Template][Render] Failed to render template \"${filePath}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to render Handlebars template.\");\r\n }\r\n}\r\n","import jwt from \"jsonwebtoken\";\r\nimport { BadRequestError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface JwtSignParams {\r\n payload?: Record<string, unknown>;\r\n secretKey: string;\r\n signOptions?: jwt.SignOptions;\r\n}\r\n\r\nexport function signJwtToken({\r\n payload = {},\r\n secretKey = \"\",\r\n signOptions = {},\r\n}: JwtSignParams): string {\r\n if (!secretKey) {\r\n logger.error(`[JWT][Sign] Secret key is missing. Cannot sign token.`);\r\n throw new BadRequestError(\"A JWT secret key must be provided.\");\r\n }\r\n\r\n try {\r\n logger.info(`[JWT][Sign] Signing JWT token.`);\r\n return jwt.sign(payload, secretKey, signOptions);\r\n } catch (error) {\r\n logger.error(\r\n `[JWT][Sign] Failed to sign JWT token: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw error;\r\n }\r\n}\r\n","import { createTransport, SendMailOptions, Transporter } from \"nodemailer\";\r\nimport { logger } from \"./logger\";\r\nimport { InternalServerError } from \"./http-error\";\r\n\r\ninterface MailerConfig {\r\n email: string;\r\n password: string;\r\n host: string;\r\n port: number;\r\n secure: boolean;\r\n}\r\n\r\nexport class useMailer {\r\n private transporter: Transporter;\r\n\r\n constructor(private config: MailerConfig) {\r\n this.transporter = createTransport({\r\n host: config.host,\r\n port: config.port,\r\n secure: config.secure,\r\n auth: { user: config.email, pass: config.password },\r\n });\r\n }\r\n\r\n async sendMail({\r\n sender,\r\n to,\r\n subject,\r\n text,\r\n html,\r\n }: {\r\n sender?: string;\r\n to: string;\r\n subject: string;\r\n text?: string;\r\n html?: string;\r\n }): Promise<string> {\r\n const from = sender\r\n ? `${sender} <${this.config.email}>`\r\n : this.config.email;\r\n\r\n const mailOptions: SendMailOptions = {\r\n from,\r\n to,\r\n subject,\r\n ...(text && { text }),\r\n ...(html && { html }),\r\n };\r\n\r\n try {\r\n await this.transporter.sendMail(mailOptions);\r\n logger.info(\r\n `[Mailer][Send] Email sent to \"${to}\" with subject \"${subject}\".`\r\n );\r\n\r\n return \"Mail sent successfully.\";\r\n } catch (error) {\r\n logger.error(\r\n `[Mailer][Send] Failed to send email to \"${to}\" with subject \"${subject}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to send email.\");\r\n }\r\n }\r\n}\r\n","import { ObjectId } from \"mongodb\";\r\nimport { logger } from \"./logger\";\r\nimport { BadRequestError } from \"./http-error\";\r\n\r\nexport function toObjectId(id: string | ObjectId): ObjectId {\r\n if (!id) {\r\n logger.error(\r\n `[ObjectId][Convert] No value provided for MongoDB ObjectId conversion.`\r\n );\r\n throw new BadRequestError(\r\n \"A value must be provided for ObjectId conversion.\"\r\n );\r\n }\r\n\r\n if (id instanceof ObjectId) return id;\r\n\r\n if (!/^[0-9a-fA-F]{24}$/.test(id)) {\r\n logger.error(\r\n `[ObjectId][Convert] Provided value is not a valid 24-character hex string.`\r\n );\r\n throw new BadRequestError(\r\n \"Invalid ObjectId: must be a 24-character hexadecimal string.\"\r\n );\r\n }\r\n\r\n try {\r\n return new ObjectId(id);\r\n } catch (err) {\r\n logger.error(\r\n `[ObjectId][Convert] Failed to convert value to ObjectId: ${\r\n err instanceof Error ? err.message : err\r\n }`\r\n );\r\n throw new BadRequestError(\"Failed to convert value into a valid ObjectId.\");\r\n }\r\n}\r\n","export function paginate<T>(\r\n items: T[],\r\n page: number = 0,\r\n limit: number = 10,\r\n total: number\r\n) {\r\n if (total === 0 || items.length === 0) {\r\n return {\r\n items: [],\r\n pages: Math.ceil(total / limit),\r\n pageRange: `0-0 of ${total}`,\r\n };\r\n }\r\n\r\n const startIndex = (page - 1) * limit + 1;\r\n if (startIndex > total) {\r\n return {\r\n items,\r\n pages: Math.ceil(total / limit),\r\n pageRange: `0-0 of ${total}`,\r\n };\r\n }\r\n const endIndex = Math.min(startIndex + items.length - 1, total);\r\n\r\n return {\r\n items,\r\n pages: Math.ceil(total / limit),\r\n pageRange: `${startIndex}-${endIndex} of ${total}`,\r\n };\r\n}\r\n","import bcrypt from \"bcrypt\";\r\nimport { InternalServerError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\nconst DEFAULT_SALT_ROUNDS = 10;\r\n\r\nexport async function comparePasswords(\r\n password: string,\r\n hashed: string\r\n): Promise<boolean> {\r\n try {\r\n return await bcrypt.compare(password, hashed);\r\n } catch (error) {\r\n logger.error(\r\n `[Password][Compare] Failed to compare passwords: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n return false;\r\n }\r\n}\r\n\r\nexport async function hashPassword(\r\n password: string,\r\n saltRounds: number = DEFAULT_SALT_ROUNDS\r\n): Promise<string> {\r\n try {\r\n return await bcrypt.hash(password, saltRounds);\r\n } catch (error) {\r\n logger.error(\r\n `[Password][Hash] Failed to hash password: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to hash password.\");\r\n }\r\n}\r\n","import { createClient, RedisClientType } from \"redis\";\r\nimport { REDIS_HOST, REDIS_PASSWORD, REDIS_PORT } from \"./../config\";\r\nimport { logger } from \"./logger\";\r\n\r\nlet redisClient: RedisClientType | null = null;\r\n\r\nexport async function initRedisClient() {\r\n if (redisClient) {\r\n logger.info(\"[Redis][Init] Redis connection is already established.\");\r\n return redisClient;\r\n }\r\n\r\n redisClient = createClient({\r\n password: REDIS_PASSWORD,\r\n socket: {\r\n host: REDIS_HOST,\r\n port: REDIS_PORT,\r\n },\r\n });\r\n}\r\n\r\nexport function useRedisClient(): RedisClientType {\r\n if (!redisClient) {\r\n logger.error(\r\n \"[Redis][GetClient] Redis connection has not been initialized.\"\r\n );\r\n throw new Error(\r\n \"[Redis][GetClient] Redis connection is not initialized. Call initRedisClient() first.\"\r\n );\r\n }\r\n\r\n return redisClient;\r\n}\r\n","import {\r\n DeleteObjectCommand,\r\n PutObjectCommand,\r\n S3Client,\r\n} from \"@aws-sdk/client-s3\";\r\nimport { Readable } from \"stream\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface S3Config {\r\n accessKeyId: string;\r\n secretAccessKey: string;\r\n endpoint: string;\r\n region: string;\r\n bucket: string;\r\n forcePathStyle: boolean;\r\n}\r\n\r\nexport class useS3 {\r\n private client: S3Client;\r\n\r\n constructor(private config: S3Config) {\r\n this.client = new S3Client({\r\n endpoint: config.endpoint,\r\n region: config.region,\r\n credentials: {\r\n accessKeyId: config.accessKeyId,\r\n secretAccessKey: config.secretAccessKey,\r\n },\r\n forcePathStyle: config.forcePathStyle,\r\n });\r\n }\r\n\r\n async uploadObject({\r\n key,\r\n body,\r\n metadata = {},\r\n contentType,\r\n }: {\r\n key: string;\r\n body: string | Buffer;\r\n metadata?: Record<string, string>;\r\n contentType?: string;\r\n }): Promise<string> {\r\n try {\r\n await this.client.send(\r\n new PutObjectCommand({\r\n Bucket: this.config.bucket,\r\n Key: key,\r\n Body:\r\n typeof body === \"string\" || Buffer.isBuffer(body)\r\n ? body\r\n : Readable.from(body),\r\n ACL: \"public-read\",\r\n Metadata: metadata,\r\n ContentType: contentType,\r\n ContentLength:\r\n typeof body === \"string\" ? Buffer.byteLength(body) : body.length,\r\n })\r\n );\r\n\r\n logger.info(\r\n `[S3][Upload] Uploaded \"${key}\" to bucket \"${this.config.bucket}\".`\r\n );\r\n return \"Successfully uploaded file.\";\r\n } catch (error) {\r\n logger.error(\r\n `[S3][Upload][Error] Failed to upload \"${key}\" to bucket \"${\r\n this.config.bucket\r\n }\": ${error instanceof Error ? error.message : error}`\r\n );\r\n throw error;\r\n }\r\n }\r\n\r\n async deleteObject(key: string) {\r\n try {\r\n await this.client.send(\r\n new DeleteObjectCommand({ Key: key, Bucket: this.config.bucket })\r\n );\r\n\r\n logger.info(\r\n `[S3][Delete] Deleted \"${key}\" from bucket \"${this.config.bucket}\".`\r\n );\r\n return \"Successfully deleted file.\";\r\n } catch (error) {\r\n logger.error(\r\n `[S3][Delete][Error] Failed to delete \"${key}\" from bucket \"${\r\n this.config.bucket\r\n }\": ${error instanceof Error ? error.message : error}`\r\n );\r\n throw error;\r\n }\r\n }\r\n}\r\n","import crypto from \"crypto\";\r\n\r\n// Deterministic hash for tokens at rest (do NOT use bcrypt here)\r\n// Optionally salt via env if provided\r\nconst TOKEN_HASH_SALT = process.env.REFRESH_TOKEN_HASH_SALT || \"\";\r\n\r\nexport function hashToken(token: string): string {\r\n return crypto\r\n .createHash(\"sha256\")\r\n .update(TOKEN_HASH_SALT + token)\r\n .digest(\"hex\");\r\n}\r\n"],"mappings":"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","names":["transports","jwt","config","Redis","redisClient","path","fs","Handlebars","format","fs","import_jsonwebtoken","jwt","config","import_mongodb","bcrypt","redisClient","config","crypto"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/middleware/auth.middleware.ts","../src/utils/logger.ts","../src/utils/http-error.ts","../src/middleware/error-handler.middleware.ts","../src/utils/atlas.ts","../src/config.ts","../src/utils/ioredis.ts","../src/utils/cache.ts","../src/utils/cache-key.ts","../src/utils/cron-job.ts","../src/utils/get-template-path.ts","../src/utils/handlebars-compiler.ts","../src/utils/jwt.ts","../src/utils/mailer.ts","../src/utils/objectid-converter.ts","../src/utils/paginate.ts","../src/utils/password.ts","../src/utils/redis.ts","../src/utils/s3.ts","../src/utils/token.ts"],"sourcesContent":["export * from \"./middleware\";\r\nexport * from \"./utils\";\r\n","import { NextFunction, Request, Response } from \"express\";\r\nimport jwt, { JwtPayload } from \"jsonwebtoken\";\r\nimport { logger } from \"./../utils/logger\";\r\nimport { UnauthorizedError, ForbiddenError } from \"./../utils/http-error\";\r\n\r\ninterface DecodedToken extends JwtPayload {\r\n user?: string;\r\n id?: string;\r\n jti?: string;\r\n role?: string;\r\n [key: string]: any;\r\n}\r\n\r\nexport interface AuthenticatedRequest extends Request {\r\n user?: DecodedToken & { id: string; [key: string]: any };\r\n token?: string;\r\n}\r\n\r\ninterface AuthOptions {\r\n secretKey?: string;\r\n isTokenRevoked?: (jti: string) => Promise<boolean>;\r\n requiredRole?: string;\r\n}\r\n\r\n// Helper function to extract token from Authorization header\r\nfunction extractToken(authHeader?: string): string | null {\r\n if (!authHeader) {\r\n return null;\r\n }\r\n\r\n if (!authHeader.startsWith(\"Bearer \")) {\r\n logger.warn(\"Invalid Authorization header format\", {\r\n format: \"Expected 'Bearer <token>'\",\r\n });\r\n return null;\r\n }\r\n\r\n return authHeader.split(\" \")[1] || null;\r\n}\r\n\r\n// Core authentication logic\r\nasync function authenticateToken(\r\n req: AuthenticatedRequest,\r\n options: AuthOptions\r\n): Promise<void> {\r\n const {\r\n secretKey = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked,\r\n requiredRole,\r\n } = options;\r\n const requestId = req.headers[\"x-request-id\"] || \"unknown\";\r\n\r\n const isDev = process.env.NODE_ENV === \"development\";\r\n\r\n if (isDev) {\r\n logger.debug(\"Starting authentication process\", {\r\n requestId,\r\n path: req.path,\r\n requiredRole,\r\n });\r\n }\r\n\r\n const token = extractToken(req.headers.authorization);\r\n if (!token) {\r\n logger.error(\"Authentication failed: No access token provided\", {\r\n requestId,\r\n path: req.path,\r\n });\r\n throw new UnauthorizedError(\"Access token is required to proceed.\");\r\n }\r\n\r\n let decoded: DecodedToken;\r\n try {\r\n decoded = jwt.verify(token, secretKey) as DecodedToken;\r\n\r\n if (isDev) {\r\n logger.debug(\"JWT token verified\", {\r\n requestId,\r\n userId: decoded.user || decoded.id,\r\n role: decoded.role,\r\n });\r\n }\r\n } catch (error) {\r\n logger.error(\"JWT verification failed\", {\r\n requestId,\r\n error: error instanceof Error ? error.message : \"Invalid token\",\r\n path: req.path,\r\n });\r\n throw new UnauthorizedError(\r\n \"Your session has expired or the token is invalid. Please log in again.\"\r\n );\r\n }\r\n\r\n // Check if token is revoked\r\n if (isTokenRevoked && decoded.jti) {\r\n const isRevoked = await isTokenRevoked(decoded.jti);\r\n if (isRevoked) {\r\n logger.warn(\"Authentication failed: Token is revoked\", {\r\n requestId,\r\n jti: decoded.jti,\r\n userId: decoded.user || decoded.id,\r\n });\r\n throw new UnauthorizedError(\r\n \"Your session has expired or the token is invalid. Please log in again.\"\r\n );\r\n }\r\n }\r\n\r\n // Check role requirements\r\n if (requiredRole && decoded.role !== requiredRole) {\r\n logger.warn(\"Authorization failed: Insufficient permissions\", {\r\n requestId,\r\n userId: decoded.user || decoded.id,\r\n userRole: decoded.role,\r\n requiredRole,\r\n path: req.path,\r\n });\r\n throw new ForbiddenError(\r\n \"Insufficient permissions to access this resource.\"\r\n );\r\n }\r\n\r\n // Set user data on request\r\n req.user = {\r\n ...decoded,\r\n id: decoded.user || decoded.id || \"\",\r\n };\r\n req.token = token;\r\n\r\n if (isDev) {\r\n logger.debug(\"Authentication completed successfully\", {\r\n requestId,\r\n userId: req.user.id,\r\n role: req.user.role,\r\n });\r\n }\r\n}\r\n\r\nexport function authenticate(\r\n secretKey: string = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked?: (jti: string) => Promise<boolean>\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, { secretKey, isTokenRevoked });\r\n next();\r\n } catch (error) {\r\n logger.error(\"Authenticate middleware failed\", {\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n\r\nexport function requireAdmin(\r\n secretKey: string = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked?: (jti: string) => Promise<boolean>\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, {\r\n secretKey,\r\n isTokenRevoked,\r\n requiredRole: \"admin\",\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireAdmin middleware failed\", {\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n\r\n// Additional helper middleware for role-based access\r\nexport function requireRole(\r\n role: string,\r\n options?: Omit<AuthOptions, \"requiredRole\">\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, {\r\n ...options,\r\n requiredRole: role,\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireRole middleware failed\", {\r\n requiredRole: role,\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n","import * as winston from \"winston\";\r\n\r\nconst transports = [\r\n new winston.transports.File({ filename: \"error.log\", level: \"error\" }),\r\n new winston.transports.File({ filename: \"combined.log\" }),\r\n];\r\n\r\nexport const logger = winston.createLogger({\r\n level: \"info\",\r\n format: winston.format.combine(\r\n winston.format.timestamp(),\r\n winston.format.json()\r\n ),\r\n transports,\r\n});\r\n","export class HttpError extends Error {\r\n public readonly statusCode: number;\r\n public readonly isOperational: boolean;\r\n\r\n constructor(\r\n message: string,\r\n statusCode: number,\r\n isOperational: boolean = true\r\n ) {\r\n super(message);\r\n\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n\r\n this.statusCode = statusCode;\r\n this.isOperational = isOperational;\r\n\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, this.constructor);\r\n }\r\n }\r\n}\r\n\r\nexport class BadRequestError extends HttpError {\r\n constructor(\r\n message: string = \"The request could not be processed. Please review your input and try again.\"\r\n ) {\r\n super(message, 400, true);\r\n }\r\n}\r\n\r\nexport class UnauthorizedError extends HttpError {\r\n constructor(\r\n message: string = \"Authentication is required to access this resource.\"\r\n ) {\r\n super(message, 401, true);\r\n }\r\n}\r\n\r\nexport class ForbiddenError extends HttpError {\r\n constructor(\r\n message: string = \"You do not have the necessary permissions to perform this action.\"\r\n ) {\r\n super(message, 403, true);\r\n }\r\n}\r\n\r\nexport class NotFoundError extends HttpError {\r\n constructor(message: string = \"The requested resource could not be found.\") {\r\n super(message, 404, true);\r\n }\r\n}\r\n\r\nexport class ConflictError extends HttpError {\r\n constructor(\r\n message: string = \"A resource with the provided values already exists.\"\r\n ) {\r\n super(message, 409, true);\r\n }\r\n}\r\n\r\nexport class UnprocessableEntityError extends HttpError {\r\n constructor(\r\n message: string = \"The request could not be completed due to invalid or incomplete information.\"\r\n ) {\r\n super(message, 422, true);\r\n }\r\n}\r\n\r\nexport class InternalServerError extends HttpError {\r\n constructor(\r\n message: string = \"An internal server error occurred. Please try again later.\"\r\n ) {\r\n super(message, 500, true);\r\n }\r\n}\r\n","import { NextFunction, Request, Response } from \"express\";\r\nimport { HttpError, InternalServerError } from \"./../utils/http-error\";\r\nimport { logger } from \"./../utils/logger\";\r\n\r\nexport const errorHandler = (\r\n error: HttpError,\r\n req: Request,\r\n res: Response,\r\n next: NextFunction\r\n) => {\r\n if (error.isOperational) {\r\n res\r\n .status(error.statusCode)\r\n .json({ status: \"error\", message: error.message });\r\n } else {\r\n logger.error({ message: error.message });\r\n res\r\n .status(500)\r\n .json({ status: \"error\", message: new InternalServerError().message });\r\n }\r\n\r\n return;\r\n};\r\n","import { Db, MongoClient } from \"mongodb\";\r\nimport { logger } from \"./logger\";\r\nimport {\r\n BadRequestError,\r\n InternalServerError,\r\n NotFoundError,\r\n} from \"./http-error\";\r\n\r\ninterface AtlasConfig {\r\n uri: string;\r\n db: string;\r\n name?: string;\r\n}\r\n\r\nexport class useAtlas {\r\n private static mongoClient: MongoClient | null = null;\r\n private static mongoDb: Db | null = null;\r\n\r\n public static async connect(config: AtlasConfig): Promise<void> {\r\n if (this.mongoClient) {\r\n logger.warn(\r\n \"[MongoDB][Connect] Client is already connected. Skipping new connection.\"\r\n );\r\n throw new BadRequestError(\"A MongoDB connection is already established.\");\r\n }\r\n\r\n const { db, uri } = config;\r\n this.mongoClient = new MongoClient(uri, {\r\n maxPoolSize: 10,\r\n maxIdleTimeMS: 60000,\r\n connectTimeoutMS: 60000,\r\n });\r\n\r\n try {\r\n await this.mongoClient.connect();\r\n this.mongoDb = this.mongoClient.db(db);\r\n\r\n logger.info(\r\n `[MongoDB][Connect] Connected to database \"${this.mongoDb.databaseName}\".`\r\n );\r\n } catch (error) {\r\n this.mongoClient = null;\r\n\r\n logger.error(\r\n `[MongoDB][Connect] Failed to connect: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\r\n \"Failed to connect to the database. Please try again later.\"\r\n );\r\n }\r\n }\r\n\r\n public static getClient(): MongoClient | null {\r\n if (!this.mongoClient) {\r\n logger.warn(`[MongoDB][GetClient] Client is not initialized.`);\r\n throw new NotFoundError(\"MongoDB client is not initialized.\");\r\n }\r\n\r\n return this.mongoClient;\r\n }\r\n\r\n public static getDb(): Db | null {\r\n if (!this.mongoDb) {\r\n logger.warn(`[MongoDB][GetDb] Database instance is not available.`);\r\n throw new NotFoundError(\"MongoDB database instance is not available.\");\r\n }\r\n\r\n return this.mongoDb;\r\n }\r\n\r\n public static startSession(): import(\"mongodb\").ClientSession {\r\n const client = this.getClient();\r\n\r\n if (!client) {\r\n logger.warn(`[MongoDB][StartSession] Client is not initialized.`);\r\n throw new NotFoundError(\"MongoDB client is not initialized.\");\r\n }\r\n\r\n return client.startSession();\r\n }\r\n\r\n public static async close(): Promise<void> {\r\n if (this.mongoClient) {\r\n try {\r\n await this.mongoClient.close();\r\n\r\n logger.info(`[MongoDB][Close] Connection closed.`);\r\n } catch (error) {\r\n logger.error(\r\n `[MongoDB][Close] Error closing connection: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to close MongoDB connection.\");\r\n } finally {\r\n this.mongoClient = null;\r\n this.mongoDb = null;\r\n }\r\n } else {\r\n logger.warn(`[MongoDB][Close] No client to disconnect.`);\r\n throw new BadRequestError(\"No MongoDB connection exists to close.\");\r\n }\r\n }\r\n}\r\n","import * as dotenv from \"dotenv\";\r\nimport { NotFoundError } from \"./utils/http-error\";\r\n\r\ndotenv.config();\r\n\r\nfunction getEnv(key: string, fallback?: string): string {\r\n const value = process.env[key];\r\n if (value !== undefined) return value as string;\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\nfunction getEnvNumber(key: string, fallback?: number): number {\r\n const value = process.env[key];\r\n if (value !== undefined) return Number(value);\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\nfunction getEnvBoolean(key: string, fallback?: boolean): boolean {\r\n const value = process.env[key];\r\n if (value !== undefined) return value === \"true\";\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\n// Redis\r\nexport const REDIS_HOST = getEnv(\"REDIS_HOST\");\r\nexport const REDIS_PORT = getEnvNumber(\"REDIS_PORT\", 6379);\r\nexport const REDIS_PASSWORD = getEnv(\"REDIS_PASSWORD\");\r\nexport const REDIS_TLS = getEnvBoolean(\"REDIS_TLS\", true);\r\n\r\n// Cache Settings\r\nexport const CACHE_SHORT_TTL = getEnvNumber(\"CACHE_SHORT_TTL\", 300);\r\nexport const CACHE_LONG_TTL = getEnvNumber(\"CACHE_LONG_TTL\", 3600);\r\n","import Redis from \"ioredis\";\r\nimport { logger } from \"./logger\";\r\nimport { BadRequestError } from \"./http-error\";\r\n\r\nlet redisClient: Redis | null = null;\r\n\r\ntype RedisOptions = {\r\n host?: string;\r\n port?: number;\r\n username?: string;\r\n password?: string;\r\n};\r\n\r\nexport function useRedis() {\r\n function initialize(options: RedisOptions) {\r\n if (redisClient) {\r\n logger.info(\"[Redis][Init] Redis connection is already established.\");\r\n return redisClient;\r\n }\r\n\r\n options.host = options.host ?? \"localhost\";\r\n options.port = options.port ?? 6379;\r\n options.username = options.username ?? \"default\";\r\n options.password = options.password ?? \"\";\r\n\r\n redisClient = new Redis({\r\n host: options.host,\r\n port: options.port,\r\n ...(options.username && { username: options.username }),\r\n ...(options.password && { password: options.password }),\r\n });\r\n\r\n redisClient.on(\"connect\", () => {\r\n logger.info(\r\n `[Redis][Connect] Redis client connected at ${options.host}:${options.port}.`\r\n );\r\n });\r\n\r\n redisClient.on(\"error\", (error) => {\r\n logger.error(\r\n `[Redis][Error] Failed to connect: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n });\r\n\r\n return redisClient;\r\n }\r\n\r\n function getClient(): Redis {\r\n if (!redisClient) {\r\n logger.error(\r\n \"[Redis][GetClient] Redis connection has not been initialized.\"\r\n );\r\n throw new BadRequestError(\r\n \"Redis connection is not initialized. Please call initialize() first.\"\r\n );\r\n }\r\n\r\n return redisClient;\r\n }\r\n\r\n function disconnect() {\r\n if (redisClient) {\r\n redisClient.quit();\r\n logger.info(\"[Redis][Disconnect] Redis connection has been closed.\");\r\n redisClient = null;\r\n } else {\r\n logger.warn(\"[Redis][Disconnect] No Redis client to disconnect.\");\r\n }\r\n }\r\n\r\n return {\r\n initialize,\r\n getClient,\r\n disconnect,\r\n };\r\n}\r\n","import { CACHE_LONG_TTL, CACHE_SHORT_TTL } from \"../config\";\r\nimport { useRedis } from \"./ioredis\";\r\nimport { logger } from \"./logger\";\r\n\r\nexport function useCache() {\r\n function getRedisClient() {\r\n return useRedis().getClient();\r\n }\r\n\r\n async function getCache<T = unknown>(cacheKey: string): Promise<T | null> {\r\n try {\r\n const redisClient = getRedisClient();\r\n const value = await redisClient.get(cacheKey);\r\n\r\n return value ? (JSON.parse(value) as T) : null;\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Get] Failed to retrieve key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n\r\n return null;\r\n }\r\n }\r\n\r\n async function setCache<T = unknown>(\r\n cacheKey: string,\r\n data: T,\r\n ttl: number = CACHE_SHORT_TTL,\r\n group?: string\r\n ): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n await redisClient.set(cacheKey, JSON.stringify(data), \"EX\", ttl);\r\n logger.info(`[Cache][Set] Stored key \"${cacheKey}\" with TTL ${ttl}s.`);\r\n\r\n if (group) {\r\n await redisClient.sadd(`cache:group:${group}`, cacheKey);\r\n await redisClient.expire(`cache:group:${group}`, CACHE_LONG_TTL);\r\n }\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Set] Failed to store key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n async function delCache(cacheKey: string): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n await redisClient.del(cacheKey);\r\n logger.info(`[Cache][Remove] Key \"${cacheKey}\" has been deleted.`);\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Remove] Failed to delete key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n async function delCacheGroup(group: string): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n const keys = await redisClient.smembers(`cache:group:${group}`);\r\n if (keys.length) await redisClient.del(...keys);\r\n\r\n await redisClient.del(`cache:group:${group}`);\r\n logger.info(`[Cache][ClearGroup] Cleared group \"${group}\" and its keys.`);\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][ClearGroup] Failed to clear group \"${group}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n return {\r\n getCache,\r\n setCache,\r\n delCache,\r\n delCacheGroup,\r\n };\r\n}\r\n","export function buildCacheKey(\r\n prefix: string,\r\n values: Record<string, any>\r\n): string {\r\n const query = Object.entries(values)\r\n .sort(([a], [b]) => a.localeCompare(b))\r\n .map(\r\n ([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`\r\n )\r\n .join(\"&\");\r\n\r\n return `${prefix}:${query}`;\r\n}\r\n","import { schedule, ScheduledTask } from \"node-cron\";\r\nimport { logger } from \"./logger\";\r\n\r\nexport function scheduleCronJob(\r\n expression: string,\r\n timezone: string,\r\n task: () => void | Promise<void>\r\n): ScheduledTask {\r\n return schedule(\r\n expression,\r\n async () => {\r\n try {\r\n await task();\r\n } catch (error) {\r\n logger.error(\r\n `[CronJob] Error: ${error instanceof Error ? error.message : error}`\r\n );\r\n }\r\n },\r\n { timezone }\r\n );\r\n}\r\n","import path from \"path\";\r\n\r\nexport function getTemplatePath(directory: string, filePath: string) {\r\n const ext = \".hbs\";\r\n const file = filePath.endsWith(ext) ? filePath : `${filePath}${ext}`;\r\n\r\n // Resolve from project root, assuming templates are in src/public/templates or public/templates\r\n const possiblePaths = [\r\n path.join(process.cwd(), \"src\", \"public\", directory, file),\r\n path.join(process.cwd(), \"public\", directory, file),\r\n path.join(process.cwd(), directory, file),\r\n ];\r\n\r\n // Return the first path that exists, or default to src/public structure\r\n const fs = require(\"fs\");\r\n for (const templatePath of possiblePaths) {\r\n if (fs.existsSync(templatePath)) {\r\n return templatePath;\r\n }\r\n }\r\n\r\n // Default to src/public structure if none exist\r\n return possiblePaths[0];\r\n}\r\n","import Handlebars from \"handlebars\";\r\nimport { promises as fs } from \"fs\";\r\nimport { InternalServerError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface CompileOptions {\r\n context?: Record<string, any>;\r\n filePath: string;\r\n}\r\n\r\nconst handlebarsTemplateCache = new Map<string, Handlebars.TemplateDelegate>();\r\n\r\n// Register Handlebars helpers\r\nHandlebars.registerHelper(\"formatCurrency\", function (amount: number) {\r\n if (typeof amount !== \"number\") return \"0.00\";\r\n return new Intl.NumberFormat(\"en-PH\", {\r\n style: \"decimal\",\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: 2,\r\n }).format(amount);\r\n});\r\n\r\nHandlebars.registerHelper(\r\n \"formatDate\",\r\n function (date: Date | string, format: string) {\r\n if (!date) return \"N/A\";\r\n\r\n const dateObj = typeof date === \"string\" ? new Date(date) : date;\r\n if (isNaN(dateObj.getTime())) return \"N/A\";\r\n\r\n const options: Intl.DateTimeFormatOptions = {};\r\n\r\n if (format.includes(\"MMMM\")) options.month = \"long\";\r\n else if (format.includes(\"MMM\")) options.month = \"short\";\r\n else if (format.includes(\"MM\")) options.month = \"2-digit\";\r\n\r\n if (format.includes(\"D,\")) options.day = \"numeric\";\r\n else if (format.includes(\"DD\")) options.day = \"2-digit\";\r\n\r\n if (format.includes(\"YYYY\")) options.year = \"numeric\";\r\n else if (format.includes(\"YY\")) options.year = \"2-digit\";\r\n\r\n if (format.includes(\"h:mm A\")) {\r\n options.hour = \"numeric\";\r\n options.minute = \"2-digit\";\r\n options.hour12 = true;\r\n } else if (format.includes(\"HH:mm\")) {\r\n options.hour = \"2-digit\";\r\n options.minute = \"2-digit\";\r\n options.hour12 = false;\r\n }\r\n\r\n return new Intl.DateTimeFormat(\"en-US\", options).format(dateObj);\r\n }\r\n);\r\n\r\nexport async function renderHandlebarsTemplate({\r\n context = {},\r\n filePath,\r\n}: CompileOptions): Promise<string> {\r\n try {\r\n let compiledTemplate = handlebarsTemplateCache.get(filePath);\r\n\r\n if (!compiledTemplate) {\r\n logger.info(\r\n `[Template][Compile] Compiling and caching template from \"${filePath}\".`\r\n );\r\n const fileContent = await fs.readFile(filePath, \"utf8\");\r\n compiledTemplate = Handlebars.compile(fileContent);\r\n handlebarsTemplateCache.set(filePath, compiledTemplate);\r\n } else {\r\n logger.info(`[Template][Cache] Using cached template for \"${filePath}\".`);\r\n }\r\n\r\n return compiledTemplate(context);\r\n } catch (error) {\r\n logger.error(\r\n `[Template][Render] Failed to render template \"${filePath}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to render Handlebars template.\");\r\n }\r\n}\r\n","import jwt from \"jsonwebtoken\";\r\nimport { BadRequestError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface JwtSignParams {\r\n payload?: Record<string, unknown>;\r\n secretKey: string;\r\n signOptions?: jwt.SignOptions;\r\n}\r\n\r\nexport function signJwtToken({\r\n payload = {},\r\n secretKey = \"\",\r\n signOptions = {},\r\n}: JwtSignParams): string {\r\n if (!secretKey) {\r\n logger.error(`[JWT][Sign] Secret key is missing. Cannot sign token.`);\r\n throw new BadRequestError(\"A JWT secret key must be provided.\");\r\n }\r\n\r\n try {\r\n logger.info(`[JWT][Sign] Signing JWT token.`);\r\n return jwt.sign(payload, secretKey, signOptions);\r\n } catch (error) {\r\n logger.error(\r\n `[JWT][Sign] Failed to sign JWT token: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw error;\r\n }\r\n}\r\n","import { createTransport, SendMailOptions, Transporter } from \"nodemailer\";\r\nimport { logger } from \"./logger\";\r\nimport { InternalServerError } from \"./http-error\";\r\n\r\ninterface MailerConfig {\r\n email: string;\r\n password: string;\r\n host: string;\r\n port: number;\r\n secure: boolean;\r\n}\r\n\r\nexport class useMailer {\r\n private transporter: Transporter;\r\n\r\n constructor(private config: MailerConfig) {\r\n this.transporter = createTransport({\r\n host: config.host,\r\n port: config.port,\r\n secure: config.secure,\r\n auth: { user: config.email, pass: config.password },\r\n });\r\n }\r\n\r\n async sendMail({\r\n sender,\r\n to,\r\n subject,\r\n text,\r\n html,\r\n }: {\r\n sender?: string;\r\n to: string;\r\n subject: string;\r\n text?: string;\r\n html?: string;\r\n }): Promise<string> {\r\n const from = sender\r\n ? `${sender} <${this.config.email}>`\r\n : this.config.email;\r\n\r\n const mailOptions: SendMailOptions = {\r\n from,\r\n to,\r\n subject,\r\n ...(text && { text }),\r\n ...(html && { html }),\r\n };\r\n\r\n try {\r\n await this.transporter.sendMail(mailOptions);\r\n logger.info(\r\n `[Mailer][Send] Email sent to \"${to}\" with subject \"${subject}\".`\r\n );\r\n\r\n return \"Mail sent successfully.\";\r\n } catch (error) {\r\n logger.error(\r\n `[Mailer][Send] Failed to send email to \"${to}\" with subject \"${subject}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to send email.\");\r\n }\r\n }\r\n}\r\n","import { ObjectId } from \"mongodb\";\r\nimport { logger } from \"./logger\";\r\nimport { BadRequestError } from \"./http-error\";\r\n\r\nexport function toObjectId(id: string | ObjectId): ObjectId {\r\n if (!id) {\r\n logger.error(\r\n `[ObjectId][Convert] No value provided for MongoDB ObjectId conversion.`\r\n );\r\n throw new BadRequestError(\r\n \"A value must be provided for ObjectId conversion.\"\r\n );\r\n }\r\n\r\n if (id instanceof ObjectId) return id;\r\n\r\n if (!/^[0-9a-fA-F]{24}$/.test(id)) {\r\n logger.error(\r\n `[ObjectId][Convert] Provided value is not a valid 24-character hex string.`\r\n );\r\n throw new BadRequestError(\r\n \"Invalid ObjectId: must be a 24-character hexadecimal string.\"\r\n );\r\n }\r\n\r\n try {\r\n return new ObjectId(id);\r\n } catch (err) {\r\n logger.error(\r\n `[ObjectId][Convert] Failed to convert value to ObjectId: ${\r\n err instanceof Error ? err.message : err\r\n }`\r\n );\r\n throw new BadRequestError(\"Failed to convert value into a valid ObjectId.\");\r\n }\r\n}\r\n","export function paginate<T>(\r\n items: T[],\r\n page: number = 0,\r\n limit: number = 10,\r\n total: number\r\n) {\r\n if (total === 0 || items.length === 0) {\r\n return {\r\n items: [],\r\n pages: Math.ceil(total / limit),\r\n pageRange: `0-0 of ${total}`,\r\n };\r\n }\r\n\r\n const startIndex = (page - 1) * limit + 1;\r\n if (startIndex > total) {\r\n return {\r\n items,\r\n pages: Math.ceil(total / limit),\r\n pageRange: `0-0 of ${total}`,\r\n };\r\n }\r\n const endIndex = Math.min(startIndex + items.length - 1, total);\r\n\r\n return {\r\n items,\r\n pages: Math.ceil(total / limit),\r\n pageRange: `${startIndex}-${endIndex} of ${total}`,\r\n };\r\n}\r\n","import bcrypt from \"bcrypt\";\r\nimport { InternalServerError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\nconst DEFAULT_SALT_ROUNDS = 10;\r\n\r\nexport async function comparePasswords(\r\n password: string,\r\n hashed: string\r\n): Promise<boolean> {\r\n try {\r\n return await bcrypt.compare(password, hashed);\r\n } catch (error) {\r\n logger.error(\r\n `[Password][Compare] Failed to compare passwords: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n return false;\r\n }\r\n}\r\n\r\nexport async function hashPassword(\r\n password: string,\r\n saltRounds: number = DEFAULT_SALT_ROUNDS\r\n): Promise<string> {\r\n try {\r\n return await bcrypt.hash(password, saltRounds);\r\n } catch (error) {\r\n logger.error(\r\n `[Password][Hash] Failed to hash password: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to hash password.\");\r\n }\r\n}\r\n","import { createClient, RedisClientType } from \"redis\";\r\nimport { REDIS_HOST, REDIS_PASSWORD, REDIS_PORT } from \"./../config\";\r\nimport { logger } from \"./logger\";\r\n\r\nlet redisClient: RedisClientType | null = null;\r\n\r\nexport async function initRedisClient() {\r\n if (redisClient) {\r\n logger.info(\"[Redis][Init] Redis connection is already established.\");\r\n return redisClient;\r\n }\r\n\r\n redisClient = createClient({\r\n password: REDIS_PASSWORD,\r\n socket: {\r\n host: REDIS_HOST,\r\n port: REDIS_PORT,\r\n },\r\n });\r\n}\r\n\r\nexport function useRedisClient(): RedisClientType {\r\n if (!redisClient) {\r\n logger.error(\r\n \"[Redis][GetClient] Redis connection has not been initialized.\"\r\n );\r\n throw new Error(\r\n \"[Redis][GetClient] Redis connection is not initialized. Call initRedisClient() first.\"\r\n );\r\n }\r\n\r\n return redisClient;\r\n}\r\n","import {\r\n DeleteObjectCommand,\r\n PutObjectCommand,\r\n S3Client,\r\n} from \"@aws-sdk/client-s3\";\r\nimport { Readable } from \"stream\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface S3Config {\r\n accessKeyId: string;\r\n secretAccessKey: string;\r\n endpoint: string;\r\n region: string;\r\n bucket: string;\r\n forcePathStyle: boolean;\r\n}\r\n\r\nexport class useS3 {\r\n private client: S3Client;\r\n\r\n constructor(private config: S3Config) {\r\n this.client = new S3Client({\r\n endpoint: config.endpoint,\r\n region: config.region,\r\n credentials: {\r\n accessKeyId: config.accessKeyId,\r\n secretAccessKey: config.secretAccessKey,\r\n },\r\n forcePathStyle: config.forcePathStyle,\r\n });\r\n }\r\n\r\n async uploadObject({\r\n key,\r\n body,\r\n metadata = {},\r\n contentType,\r\n }: {\r\n key: string;\r\n body: string | Buffer;\r\n metadata?: Record<string, string>;\r\n contentType?: string;\r\n }): Promise<string> {\r\n try {\r\n await this.client.send(\r\n new PutObjectCommand({\r\n Bucket: this.config.bucket,\r\n Key: key,\r\n Body:\r\n typeof body === \"string\" || Buffer.isBuffer(body)\r\n ? body\r\n : Readable.from(body),\r\n ACL: \"public-read\",\r\n Metadata: metadata,\r\n ContentType: contentType,\r\n ContentLength:\r\n typeof body === \"string\" ? Buffer.byteLength(body) : body.length,\r\n })\r\n );\r\n\r\n logger.info(\r\n `[S3][Upload] Uploaded \"${key}\" to bucket \"${this.config.bucket}\".`\r\n );\r\n return \"Successfully uploaded file.\";\r\n } catch (error) {\r\n logger.error(\r\n `[S3][Upload][Error] Failed to upload \"${key}\" to bucket \"${\r\n this.config.bucket\r\n }\": ${error instanceof Error ? error.message : error}`\r\n );\r\n throw error;\r\n }\r\n }\r\n\r\n async deleteObject(key: string) {\r\n try {\r\n await this.client.send(\r\n new DeleteObjectCommand({ Key: key, Bucket: this.config.bucket })\r\n );\r\n\r\n logger.info(\r\n `[S3][Delete] Deleted \"${key}\" from bucket \"${this.config.bucket}\".`\r\n );\r\n return \"Successfully deleted file.\";\r\n } catch (error) {\r\n logger.error(\r\n `[S3][Delete][Error] Failed to delete \"${key}\" from bucket \"${\r\n this.config.bucket\r\n }\": ${error instanceof Error ? error.message : error}`\r\n );\r\n throw error;\r\n }\r\n }\r\n}\r\n","import crypto from \"crypto\";\r\n\r\n// Deterministic hash for tokens at rest (do NOT use bcrypt here)\r\n// Optionally salt via env if provided\r\nconst TOKEN_HASH_SALT = process.env.REFRESH_TOKEN_HASH_SALT || \"\";\r\n\r\nexport function hashToken(token: string): string {\r\n return crypto\r\n .createHash(\"sha256\")\r\n .update(TOKEN_HASH_SALT + token)\r\n .digest(\"hex\");\r\n}\r\n"],"mappings":"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","names":["transports","jwt","config","Redis","redisClient","path","fs","Handlebars","format","fs","import_jsonwebtoken","jwt","config","import_mongodb","bcrypt","redisClient","config","crypto"]}
|
package/dist/index.mjs
CHANGED
|
@@ -509,6 +509,24 @@ function buildCacheKey(prefix, values) {
|
|
|
509
509
|
return `${prefix}:${query}`;
|
|
510
510
|
}
|
|
511
511
|
|
|
512
|
+
// src/utils/cron-job.ts
|
|
513
|
+
import { schedule } from "node-cron";
|
|
514
|
+
function scheduleCronJob(expression, timezone, task) {
|
|
515
|
+
return schedule(
|
|
516
|
+
expression,
|
|
517
|
+
() => __async(null, null, function* () {
|
|
518
|
+
try {
|
|
519
|
+
yield task();
|
|
520
|
+
} catch (error) {
|
|
521
|
+
logger.error(
|
|
522
|
+
`[CronJob] Error: ${error instanceof Error ? error.message : error}`
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
}),
|
|
526
|
+
{ timezone }
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
|
|
512
530
|
// src/utils/get-template-path.ts
|
|
513
531
|
import path from "path";
|
|
514
532
|
function getTemplatePath(directory, filePath) {
|
|
@@ -869,6 +887,7 @@ export {
|
|
|
869
887
|
renderHandlebarsTemplate,
|
|
870
888
|
requireAdmin,
|
|
871
889
|
requireRole,
|
|
890
|
+
scheduleCronJob,
|
|
872
891
|
signJwtToken,
|
|
873
892
|
toObjectId,
|
|
874
893
|
useAtlas,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/middleware/auth.middleware.ts","../src/utils/logger.ts","../src/utils/http-error.ts","../src/middleware/error-handler.middleware.ts","../src/utils/atlas.ts","../src/config.ts","../src/utils/ioredis.ts","../src/utils/cache.ts","../src/utils/cache-key.ts","../src/utils/get-template-path.ts","../src/utils/handlebars-compiler.ts","../src/utils/jwt.ts","../src/utils/mailer.ts","../src/utils/objectid-converter.ts","../src/utils/paginate.ts","../src/utils/password.ts","../src/utils/redis.ts","../src/utils/s3.ts","../src/utils/token.ts"],"sourcesContent":["import { NextFunction, Request, Response } from \"express\";\r\nimport jwt, { JwtPayload } from \"jsonwebtoken\";\r\nimport { logger } from \"./../utils/logger\";\r\nimport { UnauthorizedError, ForbiddenError } from \"./../utils/http-error\";\r\n\r\ninterface DecodedToken extends JwtPayload {\r\n user?: string;\r\n id?: string;\r\n jti?: string;\r\n role?: string;\r\n}\r\n\r\nexport interface AuthenticatedRequest extends Request {\r\n user?: DecodedToken & { id: string };\r\n token?: string;\r\n}\r\n\r\ninterface AuthOptions {\r\n secretKey?: string;\r\n isTokenRevoked?: (jti: string) => Promise<boolean>;\r\n requiredRole?: string;\r\n}\r\n\r\n// Helper function to extract token from Authorization header\r\nfunction extractToken(authHeader?: string): string | null {\r\n if (!authHeader) {\r\n return null;\r\n }\r\n\r\n if (!authHeader.startsWith(\"Bearer \")) {\r\n logger.warn(\"Invalid Authorization header format\", {\r\n format: \"Expected 'Bearer <token>'\",\r\n });\r\n return null;\r\n }\r\n\r\n return authHeader.split(\" \")[1] || null;\r\n}\r\n\r\n// Core authentication logic\r\nasync function authenticateToken(\r\n req: AuthenticatedRequest,\r\n options: AuthOptions\r\n): Promise<void> {\r\n const {\r\n secretKey = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked,\r\n requiredRole,\r\n } = options;\r\n const requestId = req.headers[\"x-request-id\"] || \"unknown\";\r\n\r\n const isDev = process.env.NODE_ENV === \"development\";\r\n\r\n if (isDev) {\r\n logger.debug(\"Starting authentication process\", {\r\n requestId,\r\n path: req.path,\r\n requiredRole,\r\n });\r\n }\r\n\r\n const token = extractToken(req.headers.authorization);\r\n if (!token) {\r\n logger.error(\"Authentication failed: No access token provided\", {\r\n requestId,\r\n path: req.path,\r\n });\r\n throw new UnauthorizedError(\"Access token is required to proceed.\");\r\n }\r\n\r\n let decoded: DecodedToken;\r\n try {\r\n decoded = jwt.verify(token, secretKey) as DecodedToken;\r\n\r\n if (isDev) {\r\n logger.debug(\"JWT token verified\", {\r\n requestId,\r\n userId: decoded.user || decoded.id,\r\n role: decoded.role,\r\n });\r\n }\r\n } catch (error) {\r\n logger.error(\"JWT verification failed\", {\r\n requestId,\r\n error: error instanceof Error ? error.message : \"Invalid token\",\r\n path: req.path,\r\n });\r\n throw new UnauthorizedError(\r\n \"Your session has expired or the token is invalid. Please log in again.\"\r\n );\r\n }\r\n\r\n // Check if token is revoked\r\n if (isTokenRevoked && decoded.jti) {\r\n const isRevoked = await isTokenRevoked(decoded.jti);\r\n if (isRevoked) {\r\n logger.warn(\"Authentication failed: Token is revoked\", {\r\n requestId,\r\n jti: decoded.jti,\r\n userId: decoded.user || decoded.id,\r\n });\r\n throw new UnauthorizedError(\r\n \"Your session has expired or the token is invalid. Please log in again.\"\r\n );\r\n }\r\n }\r\n\r\n // Check role requirements\r\n if (requiredRole && decoded.role !== requiredRole) {\r\n logger.warn(\"Authorization failed: Insufficient permissions\", {\r\n requestId,\r\n userId: decoded.user || decoded.id,\r\n userRole: decoded.role,\r\n requiredRole,\r\n path: req.path,\r\n });\r\n throw new ForbiddenError(\r\n \"Insufficient permissions to access this resource.\"\r\n );\r\n }\r\n\r\n // Set user data on request\r\n req.user = {\r\n ...decoded,\r\n id: decoded.user || decoded.id || \"\",\r\n };\r\n req.token = token;\r\n\r\n if (isDev) {\r\n logger.debug(\"Authentication completed successfully\", {\r\n requestId,\r\n userId: req.user.id,\r\n role: req.user.role,\r\n });\r\n }\r\n}\r\n\r\nexport function authenticate(\r\n secretKey: string = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked?: (jti: string) => Promise<boolean>\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, { secretKey, isTokenRevoked });\r\n next();\r\n } catch (error) {\r\n logger.error(\"Authenticate middleware failed\", {\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n\r\nexport function requireAdmin(\r\n secretKey: string = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked?: (jti: string) => Promise<boolean>\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, {\r\n secretKey,\r\n isTokenRevoked,\r\n requiredRole: \"admin\",\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireAdmin middleware failed\", {\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n\r\n// Additional helper middleware for role-based access\r\nexport function requireRole(\r\n role: string,\r\n options?: Omit<AuthOptions, \"requiredRole\">\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, {\r\n ...options,\r\n requiredRole: role,\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireRole middleware failed\", {\r\n requiredRole: role,\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n","import * as winston from \"winston\";\r\n\r\nconst transports = [\r\n new winston.transports.File({ filename: \"error.log\", level: \"error\" }),\r\n new winston.transports.File({ filename: \"combined.log\" }),\r\n];\r\n\r\nexport const logger = winston.createLogger({\r\n level: \"info\",\r\n format: winston.format.combine(\r\n winston.format.timestamp(),\r\n winston.format.json()\r\n ),\r\n transports,\r\n});\r\n","export class HttpError extends Error {\r\n public readonly statusCode: number;\r\n public readonly isOperational: boolean;\r\n\r\n constructor(\r\n message: string,\r\n statusCode: number,\r\n isOperational: boolean = true\r\n ) {\r\n super(message);\r\n\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n\r\n this.statusCode = statusCode;\r\n this.isOperational = isOperational;\r\n\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, this.constructor);\r\n }\r\n }\r\n}\r\n\r\nexport class BadRequestError extends HttpError {\r\n constructor(\r\n message: string = \"The request could not be processed. Please review your input and try again.\"\r\n ) {\r\n super(message, 400, true);\r\n }\r\n}\r\n\r\nexport class UnauthorizedError extends HttpError {\r\n constructor(\r\n message: string = \"Authentication is required to access this resource.\"\r\n ) {\r\n super(message, 401, true);\r\n }\r\n}\r\n\r\nexport class ForbiddenError extends HttpError {\r\n constructor(\r\n message: string = \"You do not have the necessary permissions to perform this action.\"\r\n ) {\r\n super(message, 403, true);\r\n }\r\n}\r\n\r\nexport class NotFoundError extends HttpError {\r\n constructor(message: string = \"The requested resource could not be found.\") {\r\n super(message, 404, true);\r\n }\r\n}\r\n\r\nexport class ConflictError extends HttpError {\r\n constructor(\r\n message: string = \"A resource with the provided values already exists.\"\r\n ) {\r\n super(message, 409, true);\r\n }\r\n}\r\n\r\nexport class UnprocessableEntityError extends HttpError {\r\n constructor(\r\n message: string = \"The request could not be completed due to invalid or incomplete information.\"\r\n ) {\r\n super(message, 422, true);\r\n }\r\n}\r\n\r\nexport class InternalServerError extends HttpError {\r\n constructor(\r\n message: string = \"An internal server error occurred. Please try again later.\"\r\n ) {\r\n super(message, 500, true);\r\n }\r\n}\r\n","import { NextFunction, Request, Response } from \"express\";\r\nimport { HttpError, InternalServerError } from \"./../utils/http-error\";\r\nimport { logger } from \"./../utils/logger\";\r\n\r\nexport const errorHandler = (\r\n error: HttpError,\r\n req: Request,\r\n res: Response,\r\n next: NextFunction\r\n) => {\r\n if (error.isOperational) {\r\n res\r\n .status(error.statusCode)\r\n .json({ status: \"error\", message: error.message });\r\n } else {\r\n logger.error({ message: error.message });\r\n res\r\n .status(500)\r\n .json({ status: \"error\", message: new InternalServerError().message });\r\n }\r\n\r\n return;\r\n};\r\n","import { Db, MongoClient } from \"mongodb\";\r\nimport { logger } from \"./logger\";\r\nimport {\r\n BadRequestError,\r\n InternalServerError,\r\n NotFoundError,\r\n} from \"./http-error\";\r\n\r\ninterface AtlasConfig {\r\n uri: string;\r\n db: string;\r\n name?: string;\r\n}\r\n\r\nexport class useAtlas {\r\n private static mongoClient: MongoClient | null = null;\r\n private static mongoDb: Db | null = null;\r\n\r\n public static async connect(config: AtlasConfig): Promise<void> {\r\n if (this.mongoClient) {\r\n logger.warn(\r\n \"[MongoDB][Connect] Client is already connected. Skipping new connection.\"\r\n );\r\n throw new BadRequestError(\"A MongoDB connection is already established.\");\r\n }\r\n\r\n const { db, uri } = config;\r\n this.mongoClient = new MongoClient(uri, {\r\n maxPoolSize: 10,\r\n maxIdleTimeMS: 60000,\r\n connectTimeoutMS: 60000,\r\n });\r\n\r\n try {\r\n await this.mongoClient.connect();\r\n this.mongoDb = this.mongoClient.db(db);\r\n\r\n logger.info(\r\n `[MongoDB][Connect] Connected to database \"${this.mongoDb.databaseName}\".`\r\n );\r\n } catch (error) {\r\n this.mongoClient = null;\r\n\r\n logger.error(\r\n `[MongoDB][Connect] Failed to connect: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\r\n \"Failed to connect to the database. Please try again later.\"\r\n );\r\n }\r\n }\r\n\r\n public static getClient(): MongoClient | null {\r\n if (!this.mongoClient) {\r\n logger.warn(`[MongoDB][GetClient] Client is not initialized.`);\r\n throw new NotFoundError(\"MongoDB client is not initialized.\");\r\n }\r\n\r\n return this.mongoClient;\r\n }\r\n\r\n public static getDb(): Db | null {\r\n if (!this.mongoDb) {\r\n logger.warn(`[MongoDB][GetDb] Database instance is not available.`);\r\n throw new NotFoundError(\"MongoDB database instance is not available.\");\r\n }\r\n\r\n return this.mongoDb;\r\n }\r\n\r\n public static startSession(): import(\"mongodb\").ClientSession {\r\n const client = this.getClient();\r\n\r\n if (!client) {\r\n logger.warn(`[MongoDB][StartSession] Client is not initialized.`);\r\n throw new NotFoundError(\"MongoDB client is not initialized.\");\r\n }\r\n\r\n return client.startSession();\r\n }\r\n\r\n public static async close(): Promise<void> {\r\n if (this.mongoClient) {\r\n try {\r\n await this.mongoClient.close();\r\n\r\n logger.info(`[MongoDB][Close] Connection closed.`);\r\n } catch (error) {\r\n logger.error(\r\n `[MongoDB][Close] Error closing connection: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to close MongoDB connection.\");\r\n } finally {\r\n this.mongoClient = null;\r\n this.mongoDb = null;\r\n }\r\n } else {\r\n logger.warn(`[MongoDB][Close] No client to disconnect.`);\r\n throw new BadRequestError(\"No MongoDB connection exists to close.\");\r\n }\r\n }\r\n}\r\n","import * as dotenv from \"dotenv\";\r\nimport { NotFoundError } from \"./utils/http-error\";\r\n\r\ndotenv.config();\r\n\r\nfunction getEnv(key: string, fallback?: string): string {\r\n const value = process.env[key];\r\n if (value !== undefined) return value as string;\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\nfunction getEnvNumber(key: string, fallback?: number): number {\r\n const value = process.env[key];\r\n if (value !== undefined) return Number(value);\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\nfunction getEnvBoolean(key: string, fallback?: boolean): boolean {\r\n const value = process.env[key];\r\n if (value !== undefined) return value === \"true\";\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\n// Redis\r\nexport const REDIS_HOST = getEnv(\"REDIS_HOST\");\r\nexport const REDIS_PORT = getEnvNumber(\"REDIS_PORT\", 6379);\r\nexport const REDIS_PASSWORD = getEnv(\"REDIS_PASSWORD\");\r\nexport const REDIS_TLS = getEnvBoolean(\"REDIS_TLS\", true);\r\n\r\n// Cache Settings\r\nexport const CACHE_SHORT_TTL = getEnvNumber(\"CACHE_SHORT_TTL\", 300);\r\nexport const CACHE_LONG_TTL = getEnvNumber(\"CACHE_LONG_TTL\", 3600);\r\n","import Redis from \"ioredis\";\r\nimport { logger } from \"./logger\";\r\nimport { BadRequestError } from \"./http-error\";\r\n\r\nlet redisClient: Redis | null = null;\r\n\r\ntype RedisOptions = {\r\n host?: string;\r\n port?: number;\r\n username?: string;\r\n password?: string;\r\n};\r\n\r\nexport function useRedis() {\r\n function initialize(options: RedisOptions) {\r\n if (redisClient) {\r\n logger.info(\"[Redis][Init] Redis connection is already established.\");\r\n return redisClient;\r\n }\r\n\r\n options.host = options.host ?? \"localhost\";\r\n options.port = options.port ?? 6379;\r\n options.username = options.username ?? \"default\";\r\n options.password = options.password ?? \"\";\r\n\r\n redisClient = new Redis({\r\n host: options.host,\r\n port: options.port,\r\n ...(options.username && { username: options.username }),\r\n ...(options.password && { password: options.password }),\r\n });\r\n\r\n redisClient.on(\"connect\", () => {\r\n logger.info(\r\n `[Redis][Connect] Redis client connected at ${options.host}:${options.port}.`\r\n );\r\n });\r\n\r\n redisClient.on(\"error\", (error) => {\r\n logger.error(\r\n `[Redis][Error] Failed to connect: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n });\r\n\r\n return redisClient;\r\n }\r\n\r\n function getClient(): Redis {\r\n if (!redisClient) {\r\n logger.error(\r\n \"[Redis][GetClient] Redis connection has not been initialized.\"\r\n );\r\n throw new BadRequestError(\r\n \"Redis connection is not initialized. Please call initialize() first.\"\r\n );\r\n }\r\n\r\n return redisClient;\r\n }\r\n\r\n function disconnect() {\r\n if (redisClient) {\r\n redisClient.quit();\r\n logger.info(\"[Redis][Disconnect] Redis connection has been closed.\");\r\n redisClient = null;\r\n } else {\r\n logger.warn(\"[Redis][Disconnect] No Redis client to disconnect.\");\r\n }\r\n }\r\n\r\n return {\r\n initialize,\r\n getClient,\r\n disconnect,\r\n };\r\n}\r\n","import { CACHE_LONG_TTL, CACHE_SHORT_TTL } from \"../config\";\r\nimport { useRedis } from \"./ioredis\";\r\nimport { logger } from \"./logger\";\r\n\r\nexport function useCache() {\r\n function getRedisClient() {\r\n return useRedis().getClient();\r\n }\r\n\r\n async function getCache<T = unknown>(cacheKey: string): Promise<T | null> {\r\n try {\r\n const redisClient = getRedisClient();\r\n const value = await redisClient.get(cacheKey);\r\n\r\n return value ? (JSON.parse(value) as T) : null;\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Get] Failed to retrieve key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n\r\n return null;\r\n }\r\n }\r\n\r\n async function setCache<T = unknown>(\r\n cacheKey: string,\r\n data: T,\r\n ttl: number = CACHE_SHORT_TTL,\r\n group?: string\r\n ): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n await redisClient.set(cacheKey, JSON.stringify(data), \"EX\", ttl);\r\n logger.info(`[Cache][Set] Stored key \"${cacheKey}\" with TTL ${ttl}s.`);\r\n\r\n if (group) {\r\n await redisClient.sadd(`cache:group:${group}`, cacheKey);\r\n await redisClient.expire(`cache:group:${group}`, CACHE_LONG_TTL);\r\n }\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Set] Failed to store key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n async function delCache(cacheKey: string): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n await redisClient.del(cacheKey);\r\n logger.info(`[Cache][Remove] Key \"${cacheKey}\" has been deleted.`);\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Remove] Failed to delete key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n async function delCacheGroup(group: string): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n const keys = await redisClient.smembers(`cache:group:${group}`);\r\n if (keys.length) await redisClient.del(...keys);\r\n\r\n await redisClient.del(`cache:group:${group}`);\r\n logger.info(`[Cache][ClearGroup] Cleared group \"${group}\" and its keys.`);\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][ClearGroup] Failed to clear group \"${group}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n return {\r\n getCache,\r\n setCache,\r\n delCache,\r\n delCacheGroup,\r\n };\r\n}\r\n","export function buildCacheKey(\r\n prefix: string,\r\n values: Record<string, any>\r\n): string {\r\n const query = Object.entries(values)\r\n .sort(([a], [b]) => a.localeCompare(b))\r\n .map(\r\n ([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`\r\n )\r\n .join(\"&\");\r\n\r\n return `${prefix}:${query}`;\r\n}\r\n","import path from \"path\";\r\n\r\nexport function getTemplatePath(directory: string, filePath: string) {\r\n const ext = \".hbs\";\r\n const file = filePath.endsWith(ext) ? filePath : `${filePath}${ext}`;\r\n\r\n // Resolve from project root, assuming templates are in src/public/templates or public/templates\r\n const possiblePaths = [\r\n path.join(process.cwd(), \"src\", \"public\", directory, file),\r\n path.join(process.cwd(), \"public\", directory, file),\r\n path.join(process.cwd(), directory, file),\r\n ];\r\n\r\n // Return the first path that exists, or default to src/public structure\r\n const fs = require(\"fs\");\r\n for (const templatePath of possiblePaths) {\r\n if (fs.existsSync(templatePath)) {\r\n return templatePath;\r\n }\r\n }\r\n\r\n // Default to src/public structure if none exist\r\n return possiblePaths[0];\r\n}\r\n","import Handlebars from \"handlebars\";\r\nimport { promises as fs } from \"fs\";\r\nimport { InternalServerError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface CompileOptions {\r\n context?: Record<string, any>;\r\n filePath: string;\r\n}\r\n\r\nconst handlebarsTemplateCache = new Map<string, Handlebars.TemplateDelegate>();\r\n\r\n// Register Handlebars helpers\r\nHandlebars.registerHelper(\"formatCurrency\", function (amount: number) {\r\n if (typeof amount !== \"number\") return \"0.00\";\r\n return new Intl.NumberFormat(\"en-PH\", {\r\n style: \"decimal\",\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: 2,\r\n }).format(amount);\r\n});\r\n\r\nHandlebars.registerHelper(\r\n \"formatDate\",\r\n function (date: Date | string, format: string) {\r\n if (!date) return \"N/A\";\r\n\r\n const dateObj = typeof date === \"string\" ? new Date(date) : date;\r\n if (isNaN(dateObj.getTime())) return \"N/A\";\r\n\r\n const options: Intl.DateTimeFormatOptions = {};\r\n\r\n if (format.includes(\"MMMM\")) options.month = \"long\";\r\n else if (format.includes(\"MMM\")) options.month = \"short\";\r\n else if (format.includes(\"MM\")) options.month = \"2-digit\";\r\n\r\n if (format.includes(\"D,\")) options.day = \"numeric\";\r\n else if (format.includes(\"DD\")) options.day = \"2-digit\";\r\n\r\n if (format.includes(\"YYYY\")) options.year = \"numeric\";\r\n else if (format.includes(\"YY\")) options.year = \"2-digit\";\r\n\r\n if (format.includes(\"h:mm A\")) {\r\n options.hour = \"numeric\";\r\n options.minute = \"2-digit\";\r\n options.hour12 = true;\r\n } else if (format.includes(\"HH:mm\")) {\r\n options.hour = \"2-digit\";\r\n options.minute = \"2-digit\";\r\n options.hour12 = false;\r\n }\r\n\r\n return new Intl.DateTimeFormat(\"en-US\", options).format(dateObj);\r\n }\r\n);\r\n\r\nexport async function renderHandlebarsTemplate({\r\n context = {},\r\n filePath,\r\n}: CompileOptions): Promise<string> {\r\n try {\r\n let compiledTemplate = handlebarsTemplateCache.get(filePath);\r\n\r\n if (!compiledTemplate) {\r\n logger.info(\r\n `[Template][Compile] Compiling and caching template from \"${filePath}\".`\r\n );\r\n const fileContent = await fs.readFile(filePath, \"utf8\");\r\n compiledTemplate = Handlebars.compile(fileContent);\r\n handlebarsTemplateCache.set(filePath, compiledTemplate);\r\n } else {\r\n logger.info(`[Template][Cache] Using cached template for \"${filePath}\".`);\r\n }\r\n\r\n return compiledTemplate(context);\r\n } catch (error) {\r\n logger.error(\r\n `[Template][Render] Failed to render template \"${filePath}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to render Handlebars template.\");\r\n }\r\n}\r\n","import jwt from \"jsonwebtoken\";\r\nimport { BadRequestError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface JwtSignParams {\r\n payload?: Record<string, unknown>;\r\n secretKey: string;\r\n signOptions?: jwt.SignOptions;\r\n}\r\n\r\nexport function signJwtToken({\r\n payload = {},\r\n secretKey = \"\",\r\n signOptions = {},\r\n}: JwtSignParams): string {\r\n if (!secretKey) {\r\n logger.error(`[JWT][Sign] Secret key is missing. Cannot sign token.`);\r\n throw new BadRequestError(\"A JWT secret key must be provided.\");\r\n }\r\n\r\n try {\r\n logger.info(`[JWT][Sign] Signing JWT token.`);\r\n return jwt.sign(payload, secretKey, signOptions);\r\n } catch (error) {\r\n logger.error(\r\n `[JWT][Sign] Failed to sign JWT token: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw error;\r\n }\r\n}\r\n","import { createTransport, SendMailOptions, Transporter } from \"nodemailer\";\r\nimport { logger } from \"./logger\";\r\nimport { InternalServerError } from \"./http-error\";\r\n\r\ninterface MailerConfig {\r\n email: string;\r\n password: string;\r\n host: string;\r\n port: number;\r\n secure: boolean;\r\n}\r\n\r\nexport class useMailer {\r\n private transporter: Transporter;\r\n\r\n constructor(private config: MailerConfig) {\r\n this.transporter = createTransport({\r\n host: config.host,\r\n port: config.port,\r\n secure: config.secure,\r\n auth: { user: config.email, pass: config.password },\r\n });\r\n }\r\n\r\n async sendMail({\r\n sender,\r\n to,\r\n subject,\r\n text,\r\n html,\r\n }: {\r\n sender?: string;\r\n to: string;\r\n subject: string;\r\n text?: string;\r\n html?: string;\r\n }): Promise<string> {\r\n const from = sender\r\n ? `${sender} <${this.config.email}>`\r\n : this.config.email;\r\n\r\n const mailOptions: SendMailOptions = {\r\n from,\r\n to,\r\n subject,\r\n ...(text && { text }),\r\n ...(html && { html }),\r\n };\r\n\r\n try {\r\n await this.transporter.sendMail(mailOptions);\r\n logger.info(\r\n `[Mailer][Send] Email sent to \"${to}\" with subject \"${subject}\".`\r\n );\r\n\r\n return \"Mail sent successfully.\";\r\n } catch (error) {\r\n logger.error(\r\n `[Mailer][Send] Failed to send email to \"${to}\" with subject \"${subject}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to send email.\");\r\n }\r\n }\r\n}\r\n","import { ObjectId } from \"mongodb\";\r\nimport { logger } from \"./logger\";\r\nimport { BadRequestError } from \"./http-error\";\r\n\r\nexport function toObjectId(id: string | ObjectId): ObjectId {\r\n if (!id) {\r\n logger.error(\r\n `[ObjectId][Convert] No value provided for MongoDB ObjectId conversion.`\r\n );\r\n throw new BadRequestError(\r\n \"A value must be provided for ObjectId conversion.\"\r\n );\r\n }\r\n\r\n if (id instanceof ObjectId) return id;\r\n\r\n if (!/^[0-9a-fA-F]{24}$/.test(id)) {\r\n logger.error(\r\n `[ObjectId][Convert] Provided value is not a valid 24-character hex string.`\r\n );\r\n throw new BadRequestError(\r\n \"Invalid ObjectId: must be a 24-character hexadecimal string.\"\r\n );\r\n }\r\n\r\n try {\r\n return new ObjectId(id);\r\n } catch (err) {\r\n logger.error(\r\n `[ObjectId][Convert] Failed to convert value to ObjectId: ${\r\n err instanceof Error ? err.message : err\r\n }`\r\n );\r\n throw new BadRequestError(\"Failed to convert value into a valid ObjectId.\");\r\n }\r\n}\r\n","export function paginate<T>(\r\n items: T[],\r\n page: number = 0,\r\n limit: number = 10,\r\n total: number\r\n) {\r\n if (total === 0 || items.length === 0) {\r\n return {\r\n items: [],\r\n pages: Math.ceil(total / limit),\r\n pageRange: `0-0 of ${total}`,\r\n };\r\n }\r\n\r\n const startIndex = (page - 1) * limit + 1;\r\n if (startIndex > total) {\r\n return {\r\n items,\r\n pages: Math.ceil(total / limit),\r\n pageRange: `0-0 of ${total}`,\r\n };\r\n }\r\n const endIndex = Math.min(startIndex + items.length - 1, total);\r\n\r\n return {\r\n items,\r\n pages: Math.ceil(total / limit),\r\n pageRange: `${startIndex}-${endIndex} of ${total}`,\r\n };\r\n}\r\n","import bcrypt from \"bcrypt\";\r\nimport { InternalServerError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\nconst DEFAULT_SALT_ROUNDS = 10;\r\n\r\nexport async function comparePasswords(\r\n password: string,\r\n hashed: string\r\n): Promise<boolean> {\r\n try {\r\n return await bcrypt.compare(password, hashed);\r\n } catch (error) {\r\n logger.error(\r\n `[Password][Compare] Failed to compare passwords: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n return false;\r\n }\r\n}\r\n\r\nexport async function hashPassword(\r\n password: string,\r\n saltRounds: number = DEFAULT_SALT_ROUNDS\r\n): Promise<string> {\r\n try {\r\n return await bcrypt.hash(password, saltRounds);\r\n } catch (error) {\r\n logger.error(\r\n `[Password][Hash] Failed to hash password: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to hash password.\");\r\n }\r\n}\r\n","import { createClient, RedisClientType } from \"redis\";\r\nimport { REDIS_HOST, REDIS_PASSWORD, REDIS_PORT } from \"./../config\";\r\nimport { logger } from \"./logger\";\r\n\r\nlet redisClient: RedisClientType | null = null;\r\n\r\nexport async function initRedisClient() {\r\n if (redisClient) {\r\n logger.info(\"[Redis][Init] Redis connection is already established.\");\r\n return redisClient;\r\n }\r\n\r\n redisClient = createClient({\r\n password: REDIS_PASSWORD,\r\n socket: {\r\n host: REDIS_HOST,\r\n port: REDIS_PORT,\r\n },\r\n });\r\n}\r\n\r\nexport function useRedisClient(): RedisClientType {\r\n if (!redisClient) {\r\n logger.error(\r\n \"[Redis][GetClient] Redis connection has not been initialized.\"\r\n );\r\n throw new Error(\r\n \"[Redis][GetClient] Redis connection is not initialized. Call initRedisClient() first.\"\r\n );\r\n }\r\n\r\n return redisClient;\r\n}\r\n","import {\r\n DeleteObjectCommand,\r\n PutObjectCommand,\r\n S3Client,\r\n} from \"@aws-sdk/client-s3\";\r\nimport { Readable } from \"stream\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface S3Config {\r\n accessKeyId: string;\r\n secretAccessKey: string;\r\n endpoint: string;\r\n region: string;\r\n bucket: string;\r\n forcePathStyle: boolean;\r\n}\r\n\r\nexport class useS3 {\r\n private client: S3Client;\r\n\r\n constructor(private config: S3Config) {\r\n this.client = new S3Client({\r\n endpoint: config.endpoint,\r\n region: config.region,\r\n credentials: {\r\n accessKeyId: config.accessKeyId,\r\n secretAccessKey: config.secretAccessKey,\r\n },\r\n forcePathStyle: config.forcePathStyle,\r\n });\r\n }\r\n\r\n async uploadObject({\r\n key,\r\n body,\r\n metadata = {},\r\n contentType,\r\n }: {\r\n key: string;\r\n body: string | Buffer;\r\n metadata?: Record<string, string>;\r\n contentType?: string;\r\n }): Promise<string> {\r\n try {\r\n await this.client.send(\r\n new PutObjectCommand({\r\n Bucket: this.config.bucket,\r\n Key: key,\r\n Body:\r\n typeof body === \"string\" || Buffer.isBuffer(body)\r\n ? body\r\n : Readable.from(body),\r\n ACL: \"public-read\",\r\n Metadata: metadata,\r\n ContentType: contentType,\r\n ContentLength:\r\n typeof body === \"string\" ? Buffer.byteLength(body) : body.length,\r\n })\r\n );\r\n\r\n logger.info(\r\n `[S3][Upload] Uploaded \"${key}\" to bucket \"${this.config.bucket}\".`\r\n );\r\n return \"Successfully uploaded file.\";\r\n } catch (error) {\r\n logger.error(\r\n `[S3][Upload][Error] Failed to upload \"${key}\" to bucket \"${\r\n this.config.bucket\r\n }\": ${error instanceof Error ? error.message : error}`\r\n );\r\n throw error;\r\n }\r\n }\r\n\r\n async deleteObject(key: string) {\r\n try {\r\n await this.client.send(\r\n new DeleteObjectCommand({ Key: key, Bucket: this.config.bucket })\r\n );\r\n\r\n logger.info(\r\n `[S3][Delete] Deleted \"${key}\" from bucket \"${this.config.bucket}\".`\r\n );\r\n return \"Successfully deleted file.\";\r\n } catch (error) {\r\n logger.error(\r\n `[S3][Delete][Error] Failed to delete \"${key}\" from bucket \"${\r\n this.config.bucket\r\n }\": ${error instanceof Error ? error.message : error}`\r\n );\r\n throw error;\r\n }\r\n }\r\n}\r\n","import crypto from \"crypto\";\r\n\r\n// Deterministic hash for tokens at rest (do NOT use bcrypt here)\r\n// Optionally salt via env if provided\r\nconst TOKEN_HASH_SALT = process.env.REFRESH_TOKEN_HASH_SALT || \"\";\r\n\r\nexport function hashToken(token: string): string {\r\n return crypto\r\n .createHash(\"sha256\")\r\n .update(TOKEN_HASH_SALT + token)\r\n .digest(\"hex\");\r\n}\r\n"],"mappings":"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","names":["transports","config","redisClient","fs","format","jwt","jwt","config","redisClient","config"]}
|
|
1
|
+
{"version":3,"sources":["../src/middleware/auth.middleware.ts","../src/utils/logger.ts","../src/utils/http-error.ts","../src/middleware/error-handler.middleware.ts","../src/utils/atlas.ts","../src/config.ts","../src/utils/ioredis.ts","../src/utils/cache.ts","../src/utils/cache-key.ts","../src/utils/cron-job.ts","../src/utils/get-template-path.ts","../src/utils/handlebars-compiler.ts","../src/utils/jwt.ts","../src/utils/mailer.ts","../src/utils/objectid-converter.ts","../src/utils/paginate.ts","../src/utils/password.ts","../src/utils/redis.ts","../src/utils/s3.ts","../src/utils/token.ts"],"sourcesContent":["import { NextFunction, Request, Response } from \"express\";\r\nimport jwt, { JwtPayload } from \"jsonwebtoken\";\r\nimport { logger } from \"./../utils/logger\";\r\nimport { UnauthorizedError, ForbiddenError } from \"./../utils/http-error\";\r\n\r\ninterface DecodedToken extends JwtPayload {\r\n user?: string;\r\n id?: string;\r\n jti?: string;\r\n role?: string;\r\n [key: string]: any;\r\n}\r\n\r\nexport interface AuthenticatedRequest extends Request {\r\n user?: DecodedToken & { id: string; [key: string]: any };\r\n token?: string;\r\n}\r\n\r\ninterface AuthOptions {\r\n secretKey?: string;\r\n isTokenRevoked?: (jti: string) => Promise<boolean>;\r\n requiredRole?: string;\r\n}\r\n\r\n// Helper function to extract token from Authorization header\r\nfunction extractToken(authHeader?: string): string | null {\r\n if (!authHeader) {\r\n return null;\r\n }\r\n\r\n if (!authHeader.startsWith(\"Bearer \")) {\r\n logger.warn(\"Invalid Authorization header format\", {\r\n format: \"Expected 'Bearer <token>'\",\r\n });\r\n return null;\r\n }\r\n\r\n return authHeader.split(\" \")[1] || null;\r\n}\r\n\r\n// Core authentication logic\r\nasync function authenticateToken(\r\n req: AuthenticatedRequest,\r\n options: AuthOptions\r\n): Promise<void> {\r\n const {\r\n secretKey = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked,\r\n requiredRole,\r\n } = options;\r\n const requestId = req.headers[\"x-request-id\"] || \"unknown\";\r\n\r\n const isDev = process.env.NODE_ENV === \"development\";\r\n\r\n if (isDev) {\r\n logger.debug(\"Starting authentication process\", {\r\n requestId,\r\n path: req.path,\r\n requiredRole,\r\n });\r\n }\r\n\r\n const token = extractToken(req.headers.authorization);\r\n if (!token) {\r\n logger.error(\"Authentication failed: No access token provided\", {\r\n requestId,\r\n path: req.path,\r\n });\r\n throw new UnauthorizedError(\"Access token is required to proceed.\");\r\n }\r\n\r\n let decoded: DecodedToken;\r\n try {\r\n decoded = jwt.verify(token, secretKey) as DecodedToken;\r\n\r\n if (isDev) {\r\n logger.debug(\"JWT token verified\", {\r\n requestId,\r\n userId: decoded.user || decoded.id,\r\n role: decoded.role,\r\n });\r\n }\r\n } catch (error) {\r\n logger.error(\"JWT verification failed\", {\r\n requestId,\r\n error: error instanceof Error ? error.message : \"Invalid token\",\r\n path: req.path,\r\n });\r\n throw new UnauthorizedError(\r\n \"Your session has expired or the token is invalid. Please log in again.\"\r\n );\r\n }\r\n\r\n // Check if token is revoked\r\n if (isTokenRevoked && decoded.jti) {\r\n const isRevoked = await isTokenRevoked(decoded.jti);\r\n if (isRevoked) {\r\n logger.warn(\"Authentication failed: Token is revoked\", {\r\n requestId,\r\n jti: decoded.jti,\r\n userId: decoded.user || decoded.id,\r\n });\r\n throw new UnauthorizedError(\r\n \"Your session has expired or the token is invalid. Please log in again.\"\r\n );\r\n }\r\n }\r\n\r\n // Check role requirements\r\n if (requiredRole && decoded.role !== requiredRole) {\r\n logger.warn(\"Authorization failed: Insufficient permissions\", {\r\n requestId,\r\n userId: decoded.user || decoded.id,\r\n userRole: decoded.role,\r\n requiredRole,\r\n path: req.path,\r\n });\r\n throw new ForbiddenError(\r\n \"Insufficient permissions to access this resource.\"\r\n );\r\n }\r\n\r\n // Set user data on request\r\n req.user = {\r\n ...decoded,\r\n id: decoded.user || decoded.id || \"\",\r\n };\r\n req.token = token;\r\n\r\n if (isDev) {\r\n logger.debug(\"Authentication completed successfully\", {\r\n requestId,\r\n userId: req.user.id,\r\n role: req.user.role,\r\n });\r\n }\r\n}\r\n\r\nexport function authenticate(\r\n secretKey: string = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked?: (jti: string) => Promise<boolean>\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, { secretKey, isTokenRevoked });\r\n next();\r\n } catch (error) {\r\n logger.error(\"Authenticate middleware failed\", {\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n\r\nexport function requireAdmin(\r\n secretKey: string = process.env.ACCESS_TOKEN_SECRET || \"\",\r\n isTokenRevoked?: (jti: string) => Promise<boolean>\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, {\r\n secretKey,\r\n isTokenRevoked,\r\n requiredRole: \"admin\",\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireAdmin middleware failed\", {\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n\r\n// Additional helper middleware for role-based access\r\nexport function requireRole(\r\n role: string,\r\n options?: Omit<AuthOptions, \"requiredRole\">\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n try {\r\n await authenticateToken(req, {\r\n ...options,\r\n requiredRole: role,\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireRole middleware failed\", {\r\n requiredRole: role,\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n next(error);\r\n }\r\n };\r\n}\r\n","import * as winston from \"winston\";\r\n\r\nconst transports = [\r\n new winston.transports.File({ filename: \"error.log\", level: \"error\" }),\r\n new winston.transports.File({ filename: \"combined.log\" }),\r\n];\r\n\r\nexport const logger = winston.createLogger({\r\n level: \"info\",\r\n format: winston.format.combine(\r\n winston.format.timestamp(),\r\n winston.format.json()\r\n ),\r\n transports,\r\n});\r\n","export class HttpError extends Error {\r\n public readonly statusCode: number;\r\n public readonly isOperational: boolean;\r\n\r\n constructor(\r\n message: string,\r\n statusCode: number,\r\n isOperational: boolean = true\r\n ) {\r\n super(message);\r\n\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n\r\n this.statusCode = statusCode;\r\n this.isOperational = isOperational;\r\n\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, this.constructor);\r\n }\r\n }\r\n}\r\n\r\nexport class BadRequestError extends HttpError {\r\n constructor(\r\n message: string = \"The request could not be processed. Please review your input and try again.\"\r\n ) {\r\n super(message, 400, true);\r\n }\r\n}\r\n\r\nexport class UnauthorizedError extends HttpError {\r\n constructor(\r\n message: string = \"Authentication is required to access this resource.\"\r\n ) {\r\n super(message, 401, true);\r\n }\r\n}\r\n\r\nexport class ForbiddenError extends HttpError {\r\n constructor(\r\n message: string = \"You do not have the necessary permissions to perform this action.\"\r\n ) {\r\n super(message, 403, true);\r\n }\r\n}\r\n\r\nexport class NotFoundError extends HttpError {\r\n constructor(message: string = \"The requested resource could not be found.\") {\r\n super(message, 404, true);\r\n }\r\n}\r\n\r\nexport class ConflictError extends HttpError {\r\n constructor(\r\n message: string = \"A resource with the provided values already exists.\"\r\n ) {\r\n super(message, 409, true);\r\n }\r\n}\r\n\r\nexport class UnprocessableEntityError extends HttpError {\r\n constructor(\r\n message: string = \"The request could not be completed due to invalid or incomplete information.\"\r\n ) {\r\n super(message, 422, true);\r\n }\r\n}\r\n\r\nexport class InternalServerError extends HttpError {\r\n constructor(\r\n message: string = \"An internal server error occurred. Please try again later.\"\r\n ) {\r\n super(message, 500, true);\r\n }\r\n}\r\n","import { NextFunction, Request, Response } from \"express\";\r\nimport { HttpError, InternalServerError } from \"./../utils/http-error\";\r\nimport { logger } from \"./../utils/logger\";\r\n\r\nexport const errorHandler = (\r\n error: HttpError,\r\n req: Request,\r\n res: Response,\r\n next: NextFunction\r\n) => {\r\n if (error.isOperational) {\r\n res\r\n .status(error.statusCode)\r\n .json({ status: \"error\", message: error.message });\r\n } else {\r\n logger.error({ message: error.message });\r\n res\r\n .status(500)\r\n .json({ status: \"error\", message: new InternalServerError().message });\r\n }\r\n\r\n return;\r\n};\r\n","import { Db, MongoClient } from \"mongodb\";\r\nimport { logger } from \"./logger\";\r\nimport {\r\n BadRequestError,\r\n InternalServerError,\r\n NotFoundError,\r\n} from \"./http-error\";\r\n\r\ninterface AtlasConfig {\r\n uri: string;\r\n db: string;\r\n name?: string;\r\n}\r\n\r\nexport class useAtlas {\r\n private static mongoClient: MongoClient | null = null;\r\n private static mongoDb: Db | null = null;\r\n\r\n public static async connect(config: AtlasConfig): Promise<void> {\r\n if (this.mongoClient) {\r\n logger.warn(\r\n \"[MongoDB][Connect] Client is already connected. Skipping new connection.\"\r\n );\r\n throw new BadRequestError(\"A MongoDB connection is already established.\");\r\n }\r\n\r\n const { db, uri } = config;\r\n this.mongoClient = new MongoClient(uri, {\r\n maxPoolSize: 10,\r\n maxIdleTimeMS: 60000,\r\n connectTimeoutMS: 60000,\r\n });\r\n\r\n try {\r\n await this.mongoClient.connect();\r\n this.mongoDb = this.mongoClient.db(db);\r\n\r\n logger.info(\r\n `[MongoDB][Connect] Connected to database \"${this.mongoDb.databaseName}\".`\r\n );\r\n } catch (error) {\r\n this.mongoClient = null;\r\n\r\n logger.error(\r\n `[MongoDB][Connect] Failed to connect: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\r\n \"Failed to connect to the database. Please try again later.\"\r\n );\r\n }\r\n }\r\n\r\n public static getClient(): MongoClient | null {\r\n if (!this.mongoClient) {\r\n logger.warn(`[MongoDB][GetClient] Client is not initialized.`);\r\n throw new NotFoundError(\"MongoDB client is not initialized.\");\r\n }\r\n\r\n return this.mongoClient;\r\n }\r\n\r\n public static getDb(): Db | null {\r\n if (!this.mongoDb) {\r\n logger.warn(`[MongoDB][GetDb] Database instance is not available.`);\r\n throw new NotFoundError(\"MongoDB database instance is not available.\");\r\n }\r\n\r\n return this.mongoDb;\r\n }\r\n\r\n public static startSession(): import(\"mongodb\").ClientSession {\r\n const client = this.getClient();\r\n\r\n if (!client) {\r\n logger.warn(`[MongoDB][StartSession] Client is not initialized.`);\r\n throw new NotFoundError(\"MongoDB client is not initialized.\");\r\n }\r\n\r\n return client.startSession();\r\n }\r\n\r\n public static async close(): Promise<void> {\r\n if (this.mongoClient) {\r\n try {\r\n await this.mongoClient.close();\r\n\r\n logger.info(`[MongoDB][Close] Connection closed.`);\r\n } catch (error) {\r\n logger.error(\r\n `[MongoDB][Close] Error closing connection: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to close MongoDB connection.\");\r\n } finally {\r\n this.mongoClient = null;\r\n this.mongoDb = null;\r\n }\r\n } else {\r\n logger.warn(`[MongoDB][Close] No client to disconnect.`);\r\n throw new BadRequestError(\"No MongoDB connection exists to close.\");\r\n }\r\n }\r\n}\r\n","import * as dotenv from \"dotenv\";\r\nimport { NotFoundError } from \"./utils/http-error\";\r\n\r\ndotenv.config();\r\n\r\nfunction getEnv(key: string, fallback?: string): string {\r\n const value = process.env[key];\r\n if (value !== undefined) return value as string;\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\nfunction getEnvNumber(key: string, fallback?: number): number {\r\n const value = process.env[key];\r\n if (value !== undefined) return Number(value);\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\nfunction getEnvBoolean(key: string, fallback?: boolean): boolean {\r\n const value = process.env[key];\r\n if (value !== undefined) return value === \"true\";\r\n if (fallback !== undefined) return fallback;\r\n throw new NotFoundError(`Missing required environment variable: ${key}`);\r\n}\r\n\r\n// Redis\r\nexport const REDIS_HOST = getEnv(\"REDIS_HOST\");\r\nexport const REDIS_PORT = getEnvNumber(\"REDIS_PORT\", 6379);\r\nexport const REDIS_PASSWORD = getEnv(\"REDIS_PASSWORD\");\r\nexport const REDIS_TLS = getEnvBoolean(\"REDIS_TLS\", true);\r\n\r\n// Cache Settings\r\nexport const CACHE_SHORT_TTL = getEnvNumber(\"CACHE_SHORT_TTL\", 300);\r\nexport const CACHE_LONG_TTL = getEnvNumber(\"CACHE_LONG_TTL\", 3600);\r\n","import Redis from \"ioredis\";\r\nimport { logger } from \"./logger\";\r\nimport { BadRequestError } from \"./http-error\";\r\n\r\nlet redisClient: Redis | null = null;\r\n\r\ntype RedisOptions = {\r\n host?: string;\r\n port?: number;\r\n username?: string;\r\n password?: string;\r\n};\r\n\r\nexport function useRedis() {\r\n function initialize(options: RedisOptions) {\r\n if (redisClient) {\r\n logger.info(\"[Redis][Init] Redis connection is already established.\");\r\n return redisClient;\r\n }\r\n\r\n options.host = options.host ?? \"localhost\";\r\n options.port = options.port ?? 6379;\r\n options.username = options.username ?? \"default\";\r\n options.password = options.password ?? \"\";\r\n\r\n redisClient = new Redis({\r\n host: options.host,\r\n port: options.port,\r\n ...(options.username && { username: options.username }),\r\n ...(options.password && { password: options.password }),\r\n });\r\n\r\n redisClient.on(\"connect\", () => {\r\n logger.info(\r\n `[Redis][Connect] Redis client connected at ${options.host}:${options.port}.`\r\n );\r\n });\r\n\r\n redisClient.on(\"error\", (error) => {\r\n logger.error(\r\n `[Redis][Error] Failed to connect: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n });\r\n\r\n return redisClient;\r\n }\r\n\r\n function getClient(): Redis {\r\n if (!redisClient) {\r\n logger.error(\r\n \"[Redis][GetClient] Redis connection has not been initialized.\"\r\n );\r\n throw new BadRequestError(\r\n \"Redis connection is not initialized. Please call initialize() first.\"\r\n );\r\n }\r\n\r\n return redisClient;\r\n }\r\n\r\n function disconnect() {\r\n if (redisClient) {\r\n redisClient.quit();\r\n logger.info(\"[Redis][Disconnect] Redis connection has been closed.\");\r\n redisClient = null;\r\n } else {\r\n logger.warn(\"[Redis][Disconnect] No Redis client to disconnect.\");\r\n }\r\n }\r\n\r\n return {\r\n initialize,\r\n getClient,\r\n disconnect,\r\n };\r\n}\r\n","import { CACHE_LONG_TTL, CACHE_SHORT_TTL } from \"../config\";\r\nimport { useRedis } from \"./ioredis\";\r\nimport { logger } from \"./logger\";\r\n\r\nexport function useCache() {\r\n function getRedisClient() {\r\n return useRedis().getClient();\r\n }\r\n\r\n async function getCache<T = unknown>(cacheKey: string): Promise<T | null> {\r\n try {\r\n const redisClient = getRedisClient();\r\n const value = await redisClient.get(cacheKey);\r\n\r\n return value ? (JSON.parse(value) as T) : null;\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Get] Failed to retrieve key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n\r\n return null;\r\n }\r\n }\r\n\r\n async function setCache<T = unknown>(\r\n cacheKey: string,\r\n data: T,\r\n ttl: number = CACHE_SHORT_TTL,\r\n group?: string\r\n ): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n await redisClient.set(cacheKey, JSON.stringify(data), \"EX\", ttl);\r\n logger.info(`[Cache][Set] Stored key \"${cacheKey}\" with TTL ${ttl}s.`);\r\n\r\n if (group) {\r\n await redisClient.sadd(`cache:group:${group}`, cacheKey);\r\n await redisClient.expire(`cache:group:${group}`, CACHE_LONG_TTL);\r\n }\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Set] Failed to store key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n async function delCache(cacheKey: string): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n await redisClient.del(cacheKey);\r\n logger.info(`[Cache][Remove] Key \"${cacheKey}\" has been deleted.`);\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][Remove] Failed to delete key \"${cacheKey}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n async function delCacheGroup(group: string): Promise<void> {\r\n try {\r\n const redisClient = getRedisClient();\r\n const keys = await redisClient.smembers(`cache:group:${group}`);\r\n if (keys.length) await redisClient.del(...keys);\r\n\r\n await redisClient.del(`cache:group:${group}`);\r\n logger.info(`[Cache][ClearGroup] Cleared group \"${group}\" and its keys.`);\r\n } catch (error) {\r\n logger.error(\r\n `[Cache][ClearGroup] Failed to clear group \"${group}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n }\r\n }\r\n\r\n return {\r\n getCache,\r\n setCache,\r\n delCache,\r\n delCacheGroup,\r\n };\r\n}\r\n","export function buildCacheKey(\r\n prefix: string,\r\n values: Record<string, any>\r\n): string {\r\n const query = Object.entries(values)\r\n .sort(([a], [b]) => a.localeCompare(b))\r\n .map(\r\n ([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`\r\n )\r\n .join(\"&\");\r\n\r\n return `${prefix}:${query}`;\r\n}\r\n","import { schedule, ScheduledTask } from \"node-cron\";\r\nimport { logger } from \"./logger\";\r\n\r\nexport function scheduleCronJob(\r\n expression: string,\r\n timezone: string,\r\n task: () => void | Promise<void>\r\n): ScheduledTask {\r\n return schedule(\r\n expression,\r\n async () => {\r\n try {\r\n await task();\r\n } catch (error) {\r\n logger.error(\r\n `[CronJob] Error: ${error instanceof Error ? error.message : error}`\r\n );\r\n }\r\n },\r\n { timezone }\r\n );\r\n}\r\n","import path from \"path\";\r\n\r\nexport function getTemplatePath(directory: string, filePath: string) {\r\n const ext = \".hbs\";\r\n const file = filePath.endsWith(ext) ? filePath : `${filePath}${ext}`;\r\n\r\n // Resolve from project root, assuming templates are in src/public/templates or public/templates\r\n const possiblePaths = [\r\n path.join(process.cwd(), \"src\", \"public\", directory, file),\r\n path.join(process.cwd(), \"public\", directory, file),\r\n path.join(process.cwd(), directory, file),\r\n ];\r\n\r\n // Return the first path that exists, or default to src/public structure\r\n const fs = require(\"fs\");\r\n for (const templatePath of possiblePaths) {\r\n if (fs.existsSync(templatePath)) {\r\n return templatePath;\r\n }\r\n }\r\n\r\n // Default to src/public structure if none exist\r\n return possiblePaths[0];\r\n}\r\n","import Handlebars from \"handlebars\";\r\nimport { promises as fs } from \"fs\";\r\nimport { InternalServerError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface CompileOptions {\r\n context?: Record<string, any>;\r\n filePath: string;\r\n}\r\n\r\nconst handlebarsTemplateCache = new Map<string, Handlebars.TemplateDelegate>();\r\n\r\n// Register Handlebars helpers\r\nHandlebars.registerHelper(\"formatCurrency\", function (amount: number) {\r\n if (typeof amount !== \"number\") return \"0.00\";\r\n return new Intl.NumberFormat(\"en-PH\", {\r\n style: \"decimal\",\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: 2,\r\n }).format(amount);\r\n});\r\n\r\nHandlebars.registerHelper(\r\n \"formatDate\",\r\n function (date: Date | string, format: string) {\r\n if (!date) return \"N/A\";\r\n\r\n const dateObj = typeof date === \"string\" ? new Date(date) : date;\r\n if (isNaN(dateObj.getTime())) return \"N/A\";\r\n\r\n const options: Intl.DateTimeFormatOptions = {};\r\n\r\n if (format.includes(\"MMMM\")) options.month = \"long\";\r\n else if (format.includes(\"MMM\")) options.month = \"short\";\r\n else if (format.includes(\"MM\")) options.month = \"2-digit\";\r\n\r\n if (format.includes(\"D,\")) options.day = \"numeric\";\r\n else if (format.includes(\"DD\")) options.day = \"2-digit\";\r\n\r\n if (format.includes(\"YYYY\")) options.year = \"numeric\";\r\n else if (format.includes(\"YY\")) options.year = \"2-digit\";\r\n\r\n if (format.includes(\"h:mm A\")) {\r\n options.hour = \"numeric\";\r\n options.minute = \"2-digit\";\r\n options.hour12 = true;\r\n } else if (format.includes(\"HH:mm\")) {\r\n options.hour = \"2-digit\";\r\n options.minute = \"2-digit\";\r\n options.hour12 = false;\r\n }\r\n\r\n return new Intl.DateTimeFormat(\"en-US\", options).format(dateObj);\r\n }\r\n);\r\n\r\nexport async function renderHandlebarsTemplate({\r\n context = {},\r\n filePath,\r\n}: CompileOptions): Promise<string> {\r\n try {\r\n let compiledTemplate = handlebarsTemplateCache.get(filePath);\r\n\r\n if (!compiledTemplate) {\r\n logger.info(\r\n `[Template][Compile] Compiling and caching template from \"${filePath}\".`\r\n );\r\n const fileContent = await fs.readFile(filePath, \"utf8\");\r\n compiledTemplate = Handlebars.compile(fileContent);\r\n handlebarsTemplateCache.set(filePath, compiledTemplate);\r\n } else {\r\n logger.info(`[Template][Cache] Using cached template for \"${filePath}\".`);\r\n }\r\n\r\n return compiledTemplate(context);\r\n } catch (error) {\r\n logger.error(\r\n `[Template][Render] Failed to render template \"${filePath}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to render Handlebars template.\");\r\n }\r\n}\r\n","import jwt from \"jsonwebtoken\";\r\nimport { BadRequestError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface JwtSignParams {\r\n payload?: Record<string, unknown>;\r\n secretKey: string;\r\n signOptions?: jwt.SignOptions;\r\n}\r\n\r\nexport function signJwtToken({\r\n payload = {},\r\n secretKey = \"\",\r\n signOptions = {},\r\n}: JwtSignParams): string {\r\n if (!secretKey) {\r\n logger.error(`[JWT][Sign] Secret key is missing. Cannot sign token.`);\r\n throw new BadRequestError(\"A JWT secret key must be provided.\");\r\n }\r\n\r\n try {\r\n logger.info(`[JWT][Sign] Signing JWT token.`);\r\n return jwt.sign(payload, secretKey, signOptions);\r\n } catch (error) {\r\n logger.error(\r\n `[JWT][Sign] Failed to sign JWT token: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw error;\r\n }\r\n}\r\n","import { createTransport, SendMailOptions, Transporter } from \"nodemailer\";\r\nimport { logger } from \"./logger\";\r\nimport { InternalServerError } from \"./http-error\";\r\n\r\ninterface MailerConfig {\r\n email: string;\r\n password: string;\r\n host: string;\r\n port: number;\r\n secure: boolean;\r\n}\r\n\r\nexport class useMailer {\r\n private transporter: Transporter;\r\n\r\n constructor(private config: MailerConfig) {\r\n this.transporter = createTransport({\r\n host: config.host,\r\n port: config.port,\r\n secure: config.secure,\r\n auth: { user: config.email, pass: config.password },\r\n });\r\n }\r\n\r\n async sendMail({\r\n sender,\r\n to,\r\n subject,\r\n text,\r\n html,\r\n }: {\r\n sender?: string;\r\n to: string;\r\n subject: string;\r\n text?: string;\r\n html?: string;\r\n }): Promise<string> {\r\n const from = sender\r\n ? `${sender} <${this.config.email}>`\r\n : this.config.email;\r\n\r\n const mailOptions: SendMailOptions = {\r\n from,\r\n to,\r\n subject,\r\n ...(text && { text }),\r\n ...(html && { html }),\r\n };\r\n\r\n try {\r\n await this.transporter.sendMail(mailOptions);\r\n logger.info(\r\n `[Mailer][Send] Email sent to \"${to}\" with subject \"${subject}\".`\r\n );\r\n\r\n return \"Mail sent successfully.\";\r\n } catch (error) {\r\n logger.error(\r\n `[Mailer][Send] Failed to send email to \"${to}\" with subject \"${subject}\": ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to send email.\");\r\n }\r\n }\r\n}\r\n","import { ObjectId } from \"mongodb\";\r\nimport { logger } from \"./logger\";\r\nimport { BadRequestError } from \"./http-error\";\r\n\r\nexport function toObjectId(id: string | ObjectId): ObjectId {\r\n if (!id) {\r\n logger.error(\r\n `[ObjectId][Convert] No value provided for MongoDB ObjectId conversion.`\r\n );\r\n throw new BadRequestError(\r\n \"A value must be provided for ObjectId conversion.\"\r\n );\r\n }\r\n\r\n if (id instanceof ObjectId) return id;\r\n\r\n if (!/^[0-9a-fA-F]{24}$/.test(id)) {\r\n logger.error(\r\n `[ObjectId][Convert] Provided value is not a valid 24-character hex string.`\r\n );\r\n throw new BadRequestError(\r\n \"Invalid ObjectId: must be a 24-character hexadecimal string.\"\r\n );\r\n }\r\n\r\n try {\r\n return new ObjectId(id);\r\n } catch (err) {\r\n logger.error(\r\n `[ObjectId][Convert] Failed to convert value to ObjectId: ${\r\n err instanceof Error ? err.message : err\r\n }`\r\n );\r\n throw new BadRequestError(\"Failed to convert value into a valid ObjectId.\");\r\n }\r\n}\r\n","export function paginate<T>(\r\n items: T[],\r\n page: number = 0,\r\n limit: number = 10,\r\n total: number\r\n) {\r\n if (total === 0 || items.length === 0) {\r\n return {\r\n items: [],\r\n pages: Math.ceil(total / limit),\r\n pageRange: `0-0 of ${total}`,\r\n };\r\n }\r\n\r\n const startIndex = (page - 1) * limit + 1;\r\n if (startIndex > total) {\r\n return {\r\n items,\r\n pages: Math.ceil(total / limit),\r\n pageRange: `0-0 of ${total}`,\r\n };\r\n }\r\n const endIndex = Math.min(startIndex + items.length - 1, total);\r\n\r\n return {\r\n items,\r\n pages: Math.ceil(total / limit),\r\n pageRange: `${startIndex}-${endIndex} of ${total}`,\r\n };\r\n}\r\n","import bcrypt from \"bcrypt\";\r\nimport { InternalServerError } from \"./http-error\";\r\nimport { logger } from \"./logger\";\r\n\r\nconst DEFAULT_SALT_ROUNDS = 10;\r\n\r\nexport async function comparePasswords(\r\n password: string,\r\n hashed: string\r\n): Promise<boolean> {\r\n try {\r\n return await bcrypt.compare(password, hashed);\r\n } catch (error) {\r\n logger.error(\r\n `[Password][Compare] Failed to compare passwords: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n return false;\r\n }\r\n}\r\n\r\nexport async function hashPassword(\r\n password: string,\r\n saltRounds: number = DEFAULT_SALT_ROUNDS\r\n): Promise<string> {\r\n try {\r\n return await bcrypt.hash(password, saltRounds);\r\n } catch (error) {\r\n logger.error(\r\n `[Password][Hash] Failed to hash password: ${\r\n error instanceof Error ? error.message : error\r\n }`\r\n );\r\n throw new InternalServerError(\"Failed to hash password.\");\r\n }\r\n}\r\n","import { createClient, RedisClientType } from \"redis\";\r\nimport { REDIS_HOST, REDIS_PASSWORD, REDIS_PORT } from \"./../config\";\r\nimport { logger } from \"./logger\";\r\n\r\nlet redisClient: RedisClientType | null = null;\r\n\r\nexport async function initRedisClient() {\r\n if (redisClient) {\r\n logger.info(\"[Redis][Init] Redis connection is already established.\");\r\n return redisClient;\r\n }\r\n\r\n redisClient = createClient({\r\n password: REDIS_PASSWORD,\r\n socket: {\r\n host: REDIS_HOST,\r\n port: REDIS_PORT,\r\n },\r\n });\r\n}\r\n\r\nexport function useRedisClient(): RedisClientType {\r\n if (!redisClient) {\r\n logger.error(\r\n \"[Redis][GetClient] Redis connection has not been initialized.\"\r\n );\r\n throw new Error(\r\n \"[Redis][GetClient] Redis connection is not initialized. Call initRedisClient() first.\"\r\n );\r\n }\r\n\r\n return redisClient;\r\n}\r\n","import {\r\n DeleteObjectCommand,\r\n PutObjectCommand,\r\n S3Client,\r\n} from \"@aws-sdk/client-s3\";\r\nimport { Readable } from \"stream\";\r\nimport { logger } from \"./logger\";\r\n\r\ninterface S3Config {\r\n accessKeyId: string;\r\n secretAccessKey: string;\r\n endpoint: string;\r\n region: string;\r\n bucket: string;\r\n forcePathStyle: boolean;\r\n}\r\n\r\nexport class useS3 {\r\n private client: S3Client;\r\n\r\n constructor(private config: S3Config) {\r\n this.client = new S3Client({\r\n endpoint: config.endpoint,\r\n region: config.region,\r\n credentials: {\r\n accessKeyId: config.accessKeyId,\r\n secretAccessKey: config.secretAccessKey,\r\n },\r\n forcePathStyle: config.forcePathStyle,\r\n });\r\n }\r\n\r\n async uploadObject({\r\n key,\r\n body,\r\n metadata = {},\r\n contentType,\r\n }: {\r\n key: string;\r\n body: string | Buffer;\r\n metadata?: Record<string, string>;\r\n contentType?: string;\r\n }): Promise<string> {\r\n try {\r\n await this.client.send(\r\n new PutObjectCommand({\r\n Bucket: this.config.bucket,\r\n Key: key,\r\n Body:\r\n typeof body === \"string\" || Buffer.isBuffer(body)\r\n ? body\r\n : Readable.from(body),\r\n ACL: \"public-read\",\r\n Metadata: metadata,\r\n ContentType: contentType,\r\n ContentLength:\r\n typeof body === \"string\" ? Buffer.byteLength(body) : body.length,\r\n })\r\n );\r\n\r\n logger.info(\r\n `[S3][Upload] Uploaded \"${key}\" to bucket \"${this.config.bucket}\".`\r\n );\r\n return \"Successfully uploaded file.\";\r\n } catch (error) {\r\n logger.error(\r\n `[S3][Upload][Error] Failed to upload \"${key}\" to bucket \"${\r\n this.config.bucket\r\n }\": ${error instanceof Error ? error.message : error}`\r\n );\r\n throw error;\r\n }\r\n }\r\n\r\n async deleteObject(key: string) {\r\n try {\r\n await this.client.send(\r\n new DeleteObjectCommand({ Key: key, Bucket: this.config.bucket })\r\n );\r\n\r\n logger.info(\r\n `[S3][Delete] Deleted \"${key}\" from bucket \"${this.config.bucket}\".`\r\n );\r\n return \"Successfully deleted file.\";\r\n } catch (error) {\r\n logger.error(\r\n `[S3][Delete][Error] Failed to delete \"${key}\" from bucket \"${\r\n this.config.bucket\r\n }\": ${error instanceof Error ? error.message : error}`\r\n );\r\n throw error;\r\n }\r\n }\r\n}\r\n","import crypto from \"crypto\";\r\n\r\n// Deterministic hash for tokens at rest (do NOT use bcrypt here)\r\n// Optionally salt via env if provided\r\nconst TOKEN_HASH_SALT = process.env.REFRESH_TOKEN_HASH_SALT || \"\";\r\n\r\nexport function hashToken(token: string): string {\r\n return crypto\r\n .createHash(\"sha256\")\r\n .update(TOKEN_HASH_SALT + token)\r\n .digest(\"hex\");\r\n}\r\n"],"mappings":"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","names":["transports","config","redisClient","fs","format","jwt","jwt","config","redisClient","config"]}
|
package/package.json
CHANGED
|
@@ -1,44 +1,47 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@codisolutions23/node-utils",
|
|
3
|
-
"version": "3.1
|
|
4
|
-
"main": "dist/index.js",
|
|
5
|
-
"module": "dist/index.mjs",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
9
|
-
"release": "yarn run build && changeset publish",
|
|
10
|
-
"lint": "tsc"
|
|
11
|
-
},
|
|
12
|
-
"keywords": [],
|
|
13
|
-
"author": "",
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"description": "",
|
|
16
|
-
"devDependencies": {
|
|
17
|
-
"@changesets/cli": "^2.29.5",
|
|
18
|
-
"@types/bcrypt": "^5.0.2",
|
|
19
|
-
"@types/express": "^5.0.3",
|
|
20
|
-
"@types/jsonwebtoken": "^9.0.10",
|
|
21
|
-
"@types/
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
}
|
|
44
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@codisolutions23/node-utils",
|
|
3
|
+
"version": "3.2.1",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"module": "dist/index.mjs",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
9
|
+
"release": "yarn run build && yarn changeset publish",
|
|
10
|
+
"lint": "tsc"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [],
|
|
13
|
+
"author": "",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"description": "",
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@changesets/cli": "^2.29.5",
|
|
18
|
+
"@types/bcrypt": "^5.0.2",
|
|
19
|
+
"@types/express": "^5.0.3",
|
|
20
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
21
|
+
"@types/mongodb": "^4.0.6",
|
|
22
|
+
"@types/nodemailer": "^6.4.17",
|
|
23
|
+
"tsup": "^8.5.0",
|
|
24
|
+
"typescript": "^5.8.3"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@aws-sdk/client-s3": "^3.840.0",
|
|
28
|
+
"bcrypt": "^6.0.0",
|
|
29
|
+
"dotenv": "^17.0.1",
|
|
30
|
+
"express": "^5.1.0",
|
|
31
|
+
"handlebars": "^4.7.8",
|
|
32
|
+
"ioredis": "^5.6.1",
|
|
33
|
+
"jsonwebtoken": "^9.0.2",
|
|
34
|
+
"mongodb": "^6.17.0",
|
|
35
|
+
"node-cron": "^4.2.1",
|
|
36
|
+
"nodemailer": "^7.0.4",
|
|
37
|
+
"redis": "^5.5.6",
|
|
38
|
+
"winston": "^3.17.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@types/mongodb": "^4.0.6",
|
|
42
|
+
"mongodb": "^6.17.0"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
### Minor Changes
|
|
2
|
-
|
|
3
|
-
- **Cache System Improvements**: Enhanced cache utility with clearer function names (`getCache`, `setCache`, `delCache`, `delCacheGroup`) and configurable TTL settings via `CACHE_SHORT_TTL` and `CACHE_LONG_TTL` environment variables
|
|
4
|
-
|
|
5
|
-
- **Enhanced Error Handling**: Replaced generic Error with NotFoundError for missing environment variables, providing better error specificity and handling
|
|
6
|
-
|
|
7
|
-
- **Reduced Auth Logging**: Optimized authentication middleware logging to reduce production noise while maintaining debug capabilities in development
|
|
8
|
-
|
|
9
|
-
### Patch Changes
|
|
10
|
-
|
|
11
|
-
- **Dependencies**: Updated AWS SDK packages (@aws-sdk, @smithy) to latest versions (3.908.0, 4.x) for improved security and compatibility
|
package/dist/index.d.mts
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
import jwt, { JwtPayload } from 'jsonwebtoken';
|
|
3
|
-
import * as mongodb from 'mongodb';
|
|
4
|
-
import { MongoClient, Db, ObjectId } from 'mongodb';
|
|
5
|
-
import Redis from 'ioredis';
|
|
6
|
-
import * as winston from 'winston';
|
|
7
|
-
import { RedisClientType } from 'redis';
|
|
8
|
-
|
|
9
|
-
interface DecodedToken extends JwtPayload {
|
|
10
|
-
user?: string;
|
|
11
|
-
id?: string;
|
|
12
|
-
jti?: string;
|
|
13
|
-
role?: string;
|
|
14
|
-
}
|
|
15
|
-
interface AuthenticatedRequest extends Request {
|
|
16
|
-
user?: DecodedToken & {
|
|
17
|
-
id: string;
|
|
18
|
-
};
|
|
19
|
-
token?: string;
|
|
20
|
-
}
|
|
21
|
-
interface AuthOptions {
|
|
22
|
-
secretKey?: string;
|
|
23
|
-
isTokenRevoked?: (jti: string) => Promise<boolean>;
|
|
24
|
-
requiredRole?: string;
|
|
25
|
-
}
|
|
26
|
-
declare function authenticate(secretKey?: string, isTokenRevoked?: (jti: string) => Promise<boolean>): (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
27
|
-
declare function requireAdmin(secretKey?: string, isTokenRevoked?: (jti: string) => Promise<boolean>): (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
28
|
-
declare function requireRole(role: string, options?: Omit<AuthOptions, "requiredRole">): (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
29
|
-
|
|
30
|
-
declare class HttpError extends Error {
|
|
31
|
-
readonly statusCode: number;
|
|
32
|
-
readonly isOperational: boolean;
|
|
33
|
-
constructor(message: string, statusCode: number, isOperational?: boolean);
|
|
34
|
-
}
|
|
35
|
-
declare class BadRequestError extends HttpError {
|
|
36
|
-
constructor(message?: string);
|
|
37
|
-
}
|
|
38
|
-
declare class UnauthorizedError extends HttpError {
|
|
39
|
-
constructor(message?: string);
|
|
40
|
-
}
|
|
41
|
-
declare class ForbiddenError extends HttpError {
|
|
42
|
-
constructor(message?: string);
|
|
43
|
-
}
|
|
44
|
-
declare class NotFoundError extends HttpError {
|
|
45
|
-
constructor(message?: string);
|
|
46
|
-
}
|
|
47
|
-
declare class ConflictError extends HttpError {
|
|
48
|
-
constructor(message?: string);
|
|
49
|
-
}
|
|
50
|
-
declare class UnprocessableEntityError extends HttpError {
|
|
51
|
-
constructor(message?: string);
|
|
52
|
-
}
|
|
53
|
-
declare class InternalServerError extends HttpError {
|
|
54
|
-
constructor(message?: string);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
declare const errorHandler: (error: HttpError, req: Request, res: Response, next: NextFunction) => void;
|
|
58
|
-
|
|
59
|
-
interface AtlasConfig {
|
|
60
|
-
uri: string;
|
|
61
|
-
db: string;
|
|
62
|
-
name?: string;
|
|
63
|
-
}
|
|
64
|
-
declare class useAtlas {
|
|
65
|
-
private static mongoClient;
|
|
66
|
-
private static mongoDb;
|
|
67
|
-
static connect(config: AtlasConfig): Promise<void>;
|
|
68
|
-
static getClient(): MongoClient | null;
|
|
69
|
-
static getDb(): Db | null;
|
|
70
|
-
static startSession(): mongodb.ClientSession;
|
|
71
|
-
static close(): Promise<void>;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
declare function useCache(): {
|
|
75
|
-
getCache: <T = unknown>(cacheKey: string) => Promise<T | null>;
|
|
76
|
-
setCache: <T = unknown>(cacheKey: string, data: T, ttl?: number, group?: string) => Promise<void>;
|
|
77
|
-
delCache: (cacheKey: string) => Promise<void>;
|
|
78
|
-
delCacheGroup: (group: string) => Promise<void>;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
declare function buildCacheKey(prefix: string, values: Record<string, any>): string;
|
|
82
|
-
|
|
83
|
-
declare function getTemplatePath(directory: string, filePath: string): string;
|
|
84
|
-
|
|
85
|
-
interface CompileOptions {
|
|
86
|
-
context?: Record<string, any>;
|
|
87
|
-
filePath: string;
|
|
88
|
-
}
|
|
89
|
-
declare function renderHandlebarsTemplate({ context, filePath, }: CompileOptions): Promise<string>;
|
|
90
|
-
|
|
91
|
-
type RedisOptions = {
|
|
92
|
-
host?: string;
|
|
93
|
-
port?: number;
|
|
94
|
-
username?: string;
|
|
95
|
-
password?: string;
|
|
96
|
-
};
|
|
97
|
-
declare function useRedis(): {
|
|
98
|
-
initialize: (options: RedisOptions) => Redis;
|
|
99
|
-
getClient: () => Redis;
|
|
100
|
-
disconnect: () => void;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
interface JwtSignParams {
|
|
104
|
-
payload?: Record<string, unknown>;
|
|
105
|
-
secretKey: string;
|
|
106
|
-
signOptions?: jwt.SignOptions;
|
|
107
|
-
}
|
|
108
|
-
declare function signJwtToken({ payload, secretKey, signOptions, }: JwtSignParams): string;
|
|
109
|
-
|
|
110
|
-
declare const logger: winston.Logger;
|
|
111
|
-
|
|
112
|
-
interface MailerConfig {
|
|
113
|
-
email: string;
|
|
114
|
-
password: string;
|
|
115
|
-
host: string;
|
|
116
|
-
port: number;
|
|
117
|
-
secure: boolean;
|
|
118
|
-
}
|
|
119
|
-
declare class useMailer {
|
|
120
|
-
private config;
|
|
121
|
-
private transporter;
|
|
122
|
-
constructor(config: MailerConfig);
|
|
123
|
-
sendMail({ sender, to, subject, text, html, }: {
|
|
124
|
-
sender?: string;
|
|
125
|
-
to: string;
|
|
126
|
-
subject: string;
|
|
127
|
-
text?: string;
|
|
128
|
-
html?: string;
|
|
129
|
-
}): Promise<string>;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
declare function toObjectId(id: string | ObjectId): ObjectId;
|
|
133
|
-
|
|
134
|
-
declare function paginate<T>(items: T[], page: number | undefined, limit: number | undefined, total: number): {
|
|
135
|
-
items: T[];
|
|
136
|
-
pages: number;
|
|
137
|
-
pageRange: string;
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
declare function comparePasswords(password: string, hashed: string): Promise<boolean>;
|
|
141
|
-
declare function hashPassword(password: string, saltRounds?: number): Promise<string>;
|
|
142
|
-
|
|
143
|
-
declare function initRedisClient(): Promise<RedisClientType | undefined>;
|
|
144
|
-
declare function useRedisClient(): RedisClientType;
|
|
145
|
-
|
|
146
|
-
interface S3Config {
|
|
147
|
-
accessKeyId: string;
|
|
148
|
-
secretAccessKey: string;
|
|
149
|
-
endpoint: string;
|
|
150
|
-
region: string;
|
|
151
|
-
bucket: string;
|
|
152
|
-
forcePathStyle: boolean;
|
|
153
|
-
}
|
|
154
|
-
declare class useS3 {
|
|
155
|
-
private config;
|
|
156
|
-
private client;
|
|
157
|
-
constructor(config: S3Config);
|
|
158
|
-
uploadObject({ key, body, metadata, contentType, }: {
|
|
159
|
-
key: string;
|
|
160
|
-
body: string | Buffer;
|
|
161
|
-
metadata?: Record<string, string>;
|
|
162
|
-
contentType?: string;
|
|
163
|
-
}): Promise<string>;
|
|
164
|
-
deleteObject(key: string): Promise<string>;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
declare function hashToken(token: string): string;
|
|
168
|
-
|
|
169
|
-
export { type AuthenticatedRequest, BadRequestError, ConflictError, ForbiddenError, HttpError, InternalServerError, NotFoundError, UnauthorizedError, UnprocessableEntityError, authenticate, buildCacheKey, comparePasswords, errorHandler, getTemplatePath, hashPassword, hashToken, initRedisClient, logger, paginate, renderHandlebarsTemplate, requireAdmin, requireRole, signJwtToken, toObjectId, useAtlas, useCache, useMailer, useRedis, useRedisClient, useS3 };
|
package/dist/index.d.ts
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
import jwt, { JwtPayload } from 'jsonwebtoken';
|
|
3
|
-
import * as mongodb from 'mongodb';
|
|
4
|
-
import { MongoClient, Db, ObjectId } from 'mongodb';
|
|
5
|
-
import Redis from 'ioredis';
|
|
6
|
-
import * as winston from 'winston';
|
|
7
|
-
import { RedisClientType } from 'redis';
|
|
8
|
-
|
|
9
|
-
interface DecodedToken extends JwtPayload {
|
|
10
|
-
user?: string;
|
|
11
|
-
id?: string;
|
|
12
|
-
jti?: string;
|
|
13
|
-
role?: string;
|
|
14
|
-
}
|
|
15
|
-
interface AuthenticatedRequest extends Request {
|
|
16
|
-
user?: DecodedToken & {
|
|
17
|
-
id: string;
|
|
18
|
-
};
|
|
19
|
-
token?: string;
|
|
20
|
-
}
|
|
21
|
-
interface AuthOptions {
|
|
22
|
-
secretKey?: string;
|
|
23
|
-
isTokenRevoked?: (jti: string) => Promise<boolean>;
|
|
24
|
-
requiredRole?: string;
|
|
25
|
-
}
|
|
26
|
-
declare function authenticate(secretKey?: string, isTokenRevoked?: (jti: string) => Promise<boolean>): (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
27
|
-
declare function requireAdmin(secretKey?: string, isTokenRevoked?: (jti: string) => Promise<boolean>): (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
28
|
-
declare function requireRole(role: string, options?: Omit<AuthOptions, "requiredRole">): (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
29
|
-
|
|
30
|
-
declare class HttpError extends Error {
|
|
31
|
-
readonly statusCode: number;
|
|
32
|
-
readonly isOperational: boolean;
|
|
33
|
-
constructor(message: string, statusCode: number, isOperational?: boolean);
|
|
34
|
-
}
|
|
35
|
-
declare class BadRequestError extends HttpError {
|
|
36
|
-
constructor(message?: string);
|
|
37
|
-
}
|
|
38
|
-
declare class UnauthorizedError extends HttpError {
|
|
39
|
-
constructor(message?: string);
|
|
40
|
-
}
|
|
41
|
-
declare class ForbiddenError extends HttpError {
|
|
42
|
-
constructor(message?: string);
|
|
43
|
-
}
|
|
44
|
-
declare class NotFoundError extends HttpError {
|
|
45
|
-
constructor(message?: string);
|
|
46
|
-
}
|
|
47
|
-
declare class ConflictError extends HttpError {
|
|
48
|
-
constructor(message?: string);
|
|
49
|
-
}
|
|
50
|
-
declare class UnprocessableEntityError extends HttpError {
|
|
51
|
-
constructor(message?: string);
|
|
52
|
-
}
|
|
53
|
-
declare class InternalServerError extends HttpError {
|
|
54
|
-
constructor(message?: string);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
declare const errorHandler: (error: HttpError, req: Request, res: Response, next: NextFunction) => void;
|
|
58
|
-
|
|
59
|
-
interface AtlasConfig {
|
|
60
|
-
uri: string;
|
|
61
|
-
db: string;
|
|
62
|
-
name?: string;
|
|
63
|
-
}
|
|
64
|
-
declare class useAtlas {
|
|
65
|
-
private static mongoClient;
|
|
66
|
-
private static mongoDb;
|
|
67
|
-
static connect(config: AtlasConfig): Promise<void>;
|
|
68
|
-
static getClient(): MongoClient | null;
|
|
69
|
-
static getDb(): Db | null;
|
|
70
|
-
static startSession(): mongodb.ClientSession;
|
|
71
|
-
static close(): Promise<void>;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
declare function useCache(): {
|
|
75
|
-
getCache: <T = unknown>(cacheKey: string) => Promise<T | null>;
|
|
76
|
-
setCache: <T = unknown>(cacheKey: string, data: T, ttl?: number, group?: string) => Promise<void>;
|
|
77
|
-
delCache: (cacheKey: string) => Promise<void>;
|
|
78
|
-
delCacheGroup: (group: string) => Promise<void>;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
declare function buildCacheKey(prefix: string, values: Record<string, any>): string;
|
|
82
|
-
|
|
83
|
-
declare function getTemplatePath(directory: string, filePath: string): string;
|
|
84
|
-
|
|
85
|
-
interface CompileOptions {
|
|
86
|
-
context?: Record<string, any>;
|
|
87
|
-
filePath: string;
|
|
88
|
-
}
|
|
89
|
-
declare function renderHandlebarsTemplate({ context, filePath, }: CompileOptions): Promise<string>;
|
|
90
|
-
|
|
91
|
-
type RedisOptions = {
|
|
92
|
-
host?: string;
|
|
93
|
-
port?: number;
|
|
94
|
-
username?: string;
|
|
95
|
-
password?: string;
|
|
96
|
-
};
|
|
97
|
-
declare function useRedis(): {
|
|
98
|
-
initialize: (options: RedisOptions) => Redis;
|
|
99
|
-
getClient: () => Redis;
|
|
100
|
-
disconnect: () => void;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
interface JwtSignParams {
|
|
104
|
-
payload?: Record<string, unknown>;
|
|
105
|
-
secretKey: string;
|
|
106
|
-
signOptions?: jwt.SignOptions;
|
|
107
|
-
}
|
|
108
|
-
declare function signJwtToken({ payload, secretKey, signOptions, }: JwtSignParams): string;
|
|
109
|
-
|
|
110
|
-
declare const logger: winston.Logger;
|
|
111
|
-
|
|
112
|
-
interface MailerConfig {
|
|
113
|
-
email: string;
|
|
114
|
-
password: string;
|
|
115
|
-
host: string;
|
|
116
|
-
port: number;
|
|
117
|
-
secure: boolean;
|
|
118
|
-
}
|
|
119
|
-
declare class useMailer {
|
|
120
|
-
private config;
|
|
121
|
-
private transporter;
|
|
122
|
-
constructor(config: MailerConfig);
|
|
123
|
-
sendMail({ sender, to, subject, text, html, }: {
|
|
124
|
-
sender?: string;
|
|
125
|
-
to: string;
|
|
126
|
-
subject: string;
|
|
127
|
-
text?: string;
|
|
128
|
-
html?: string;
|
|
129
|
-
}): Promise<string>;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
declare function toObjectId(id: string | ObjectId): ObjectId;
|
|
133
|
-
|
|
134
|
-
declare function paginate<T>(items: T[], page: number | undefined, limit: number | undefined, total: number): {
|
|
135
|
-
items: T[];
|
|
136
|
-
pages: number;
|
|
137
|
-
pageRange: string;
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
declare function comparePasswords(password: string, hashed: string): Promise<boolean>;
|
|
141
|
-
declare function hashPassword(password: string, saltRounds?: number): Promise<string>;
|
|
142
|
-
|
|
143
|
-
declare function initRedisClient(): Promise<RedisClientType | undefined>;
|
|
144
|
-
declare function useRedisClient(): RedisClientType;
|
|
145
|
-
|
|
146
|
-
interface S3Config {
|
|
147
|
-
accessKeyId: string;
|
|
148
|
-
secretAccessKey: string;
|
|
149
|
-
endpoint: string;
|
|
150
|
-
region: string;
|
|
151
|
-
bucket: string;
|
|
152
|
-
forcePathStyle: boolean;
|
|
153
|
-
}
|
|
154
|
-
declare class useS3 {
|
|
155
|
-
private config;
|
|
156
|
-
private client;
|
|
157
|
-
constructor(config: S3Config);
|
|
158
|
-
uploadObject({ key, body, metadata, contentType, }: {
|
|
159
|
-
key: string;
|
|
160
|
-
body: string | Buffer;
|
|
161
|
-
metadata?: Record<string, string>;
|
|
162
|
-
contentType?: string;
|
|
163
|
-
}): Promise<string>;
|
|
164
|
-
deleteObject(key: string): Promise<string>;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
declare function hashToken(token: string): string;
|
|
168
|
-
|
|
169
|
-
export { type AuthenticatedRequest, BadRequestError, ConflictError, ForbiddenError, HttpError, InternalServerError, NotFoundError, UnauthorizedError, UnprocessableEntityError, authenticate, buildCacheKey, comparePasswords, errorHandler, getTemplatePath, hashPassword, hashToken, initRedisClient, logger, paginate, renderHandlebarsTemplate, requireAdmin, requireRole, signJwtToken, toObjectId, useAtlas, useCache, useMailer, useRedis, useRedisClient, useS3 };
|