@codisolutions23/node-utils 3.0.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
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 CHANGED
@@ -72,10 +72,10 @@ declare class useAtlas {
72
72
  }
73
73
 
74
74
  declare function useCache(): {
75
- get: <T = unknown>(cacheKey: string) => Promise<T | null>;
76
- set: <T = unknown>(cacheKey: string, data: T, ttl?: number, group?: string) => Promise<void>;
77
- remove: (cacheKey: string) => Promise<void>;
78
- clearGroup: (group: string) => Promise<void>;
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
79
  };
80
80
 
81
81
  declare function buildCacheKey(prefix: string, values: Record<string, any>): string;
package/dist/index.d.ts CHANGED
@@ -72,10 +72,10 @@ declare class useAtlas {
72
72
  }
73
73
 
74
74
  declare function useCache(): {
75
- get: <T = unknown>(cacheKey: string) => Promise<T | null>;
76
- set: <T = unknown>(cacheKey: string, data: T, ttl?: number, group?: string) => Promise<void>;
77
- remove: (cacheKey: string) => Promise<void>;
78
- clearGroup: (group: string) => Promise<void>;
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
79
  };
80
80
 
81
81
  declare function buildCacheKey(prefix: string, values: Record<string, any>): string;
package/dist/index.js CHANGED
@@ -167,23 +167,16 @@ var InternalServerError = class extends HttpError {
167
167
 
168
168
  // src/middleware/auth.middleware.ts
169
169
  function extractToken(authHeader) {
170
- logger.debug("Attempting to extract token from Authorization header");
171
170
  if (!authHeader) {
172
- logger.debug("No Authorization header provided");
173
171
  return null;
174
172
  }
175
173
  if (!authHeader.startsWith("Bearer ")) {
176
- logger.warn("Authorization header does not start with 'Bearer '", {
177
- authHeader: authHeader.substring(0, 20) + "..."
174
+ logger.warn("Invalid Authorization header format", {
175
+ format: "Expected 'Bearer <token>'"
178
176
  });
179
177
  return null;
180
178
  }
181
- const token = authHeader.split(" ")[1] || null;
182
- logger.debug("Token extraction result", {
183
- hasToken: !!token,
184
- tokenLength: token == null ? void 0 : token.length
185
- });
186
- return token;
179
+ return authHeader.split(" ")[1] || null;
187
180
  }
188
181
  function authenticateToken(req, options) {
189
182
  return __async(this, null, function* () {
@@ -193,13 +186,14 @@ function authenticateToken(req, options) {
193
186
  requiredRole
194
187
  } = options;
195
188
  const requestId = req.headers["x-request-id"] || "unknown";
196
- logger.info("Starting authentication process", {
197
- requestId,
198
- path: req.path,
199
- method: req.method,
200
- requiredRole,
201
- hasRevocationCheck: !!isTokenRevoked
202
- });
189
+ const isDev = process.env.NODE_ENV === "development";
190
+ if (isDev) {
191
+ logger.debug("Starting authentication process", {
192
+ requestId,
193
+ path: req.path,
194
+ requiredRole
195
+ });
196
+ }
203
197
  const token = extractToken(req.headers.authorization);
204
198
  if (!token) {
205
199
  logger.error("Authentication failed: No access token provided", {
@@ -208,36 +202,27 @@ function authenticateToken(req, options) {
208
202
  });
209
203
  throw new UnauthorizedError("Access token is required to proceed.");
210
204
  }
211
- logger.debug("Token extracted successfully, proceeding with verification", {
212
- requestId,
213
- tokenLength: token.length
214
- });
215
205
  let decoded;
216
206
  try {
217
- logger.debug("Verifying JWT token", { requestId });
218
207
  decoded = import_jsonwebtoken.default.verify(token, secretKey);
219
- logger.info("JWT token verified successfully", {
220
- requestId,
221
- userId: decoded.user || decoded.id,
222
- role: decoded.role,
223
- jti: decoded.jti,
224
- exp: decoded.exp ? new Date(decoded.exp * 1e3).toISOString() : "unknown"
225
- });
208
+ if (isDev) {
209
+ logger.debug("JWT token verified", {
210
+ requestId,
211
+ userId: decoded.user || decoded.id,
212
+ role: decoded.role
213
+ });
214
+ }
226
215
  } catch (error) {
227
216
  logger.error("JWT verification failed", {
228
217
  requestId,
229
- error: error instanceof Error ? error.message : "Unknown error",
230
- tokenLength: token.length
218
+ error: error instanceof Error ? error.message : "Invalid token",
219
+ path: req.path
231
220
  });
232
221
  throw new UnauthorizedError(
233
222
  "Your session has expired or the token is invalid. Please log in again."
234
223
  );
235
224
  }
236
225
  if (isTokenRevoked && decoded.jti) {
237
- logger.debug("Checking token revocation status", {
238
- requestId,
239
- jti: decoded.jti
240
- });
241
226
  const isRevoked = yield isTokenRevoked(decoded.jti);
242
227
  if (isRevoked) {
243
228
  logger.warn("Authentication failed: Token is revoked", {
@@ -249,10 +234,6 @@ function authenticateToken(req, options) {
249
234
  "Your session has expired or the token is invalid. Please log in again."
250
235
  );
251
236
  }
252
- logger.debug("Token revocation check passed", {
253
- requestId,
254
- jti: decoded.jti
255
- });
256
237
  }
257
238
  if (requiredRole && decoded.role !== requiredRole) {
258
239
  logger.warn("Authorization failed: Insufficient permissions", {
@@ -270,31 +251,22 @@ function authenticateToken(req, options) {
270
251
  id: decoded.user || decoded.id || ""
271
252
  });
272
253
  req.token = token;
273
- logger.info("Authentication completed successfully", {
274
- requestId,
275
- userId: req.user.id,
276
- role: req.user.role,
277
- path: req.path,
278
- method: req.method
279
- });
254
+ if (isDev) {
255
+ logger.debug("Authentication completed successfully", {
256
+ requestId,
257
+ userId: req.user.id,
258
+ role: req.user.role
259
+ });
260
+ }
280
261
  });
281
262
  }
282
263
  function authenticate(secretKey = process.env.ACCESS_TOKEN_SECRET || "", isTokenRevoked) {
283
264
  return (req, res, next) => __async(null, null, function* () {
284
- const requestId = req.headers["x-request-id"] || "unknown";
285
- logger.debug("Authenticate middleware invoked", {
286
- requestId,
287
- path: req.path
288
- });
289
265
  try {
290
266
  yield authenticateToken(req, { secretKey, isTokenRevoked });
291
- logger.debug("Authenticate middleware completed successfully", {
292
- requestId
293
- });
294
267
  next();
295
268
  } catch (error) {
296
269
  logger.error("Authenticate middleware failed", {
297
- requestId,
298
270
  error: error instanceof Error ? error.message : "Unknown error"
299
271
  });
300
272
  next(error);
@@ -303,24 +275,15 @@ function authenticate(secretKey = process.env.ACCESS_TOKEN_SECRET || "", isToken
303
275
  }
304
276
  function requireAdmin(secretKey = process.env.ACCESS_TOKEN_SECRET || "", isTokenRevoked) {
305
277
  return (req, res, next) => __async(null, null, function* () {
306
- const requestId = req.headers["x-request-id"] || "unknown";
307
- logger.debug("RequireAdmin middleware invoked", {
308
- requestId,
309
- path: req.path
310
- });
311
278
  try {
312
279
  yield authenticateToken(req, {
313
280
  secretKey,
314
281
  isTokenRevoked,
315
282
  requiredRole: "admin"
316
283
  });
317
- logger.debug("RequireAdmin middleware completed successfully", {
318
- requestId
319
- });
320
284
  next();
321
285
  } catch (error) {
322
286
  logger.error("RequireAdmin middleware failed", {
323
- requestId,
324
287
  error: error instanceof Error ? error.message : "Unknown error"
325
288
  });
326
289
  next(error);
@@ -329,24 +292,13 @@ function requireAdmin(secretKey = process.env.ACCESS_TOKEN_SECRET || "", isToken
329
292
  }
330
293
  function requireRole(role, options) {
331
294
  return (req, res, next) => __async(null, null, function* () {
332
- const requestId = req.headers["x-request-id"] || "unknown";
333
- logger.debug("RequireRole middleware invoked", {
334
- requestId,
335
- path: req.path,
336
- requiredRole: role
337
- });
338
295
  try {
339
296
  yield authenticateToken(req, __spreadProps(__spreadValues({}, options), {
340
297
  requiredRole: role
341
298
  }));
342
- logger.debug("RequireRole middleware completed successfully", {
343
- requestId,
344
- role
345
- });
346
299
  next();
347
300
  } catch (error) {
348
301
  logger.error("RequireRole middleware failed", {
349
- requestId,
350
302
  requiredRole: role,
351
303
  error: error instanceof Error ? error.message : "Unknown error"
352
304
  });
@@ -447,6 +399,34 @@ var useAtlas = class {
447
399
  useAtlas.mongoClient = null;
448
400
  useAtlas.mongoDb = null;
449
401
 
402
+ // src/config.ts
403
+ var dotenv = __toESM(require("dotenv"));
404
+ dotenv.config();
405
+ function getEnv(key, fallback) {
406
+ const value = process.env[key];
407
+ if (value !== void 0) return value;
408
+ if (fallback !== void 0) return fallback;
409
+ throw new NotFoundError(`Missing required environment variable: ${key}`);
410
+ }
411
+ function getEnvNumber(key, fallback) {
412
+ const value = process.env[key];
413
+ if (value !== void 0) return Number(value);
414
+ if (fallback !== void 0) return fallback;
415
+ throw new NotFoundError(`Missing required environment variable: ${key}`);
416
+ }
417
+ function getEnvBoolean(key, fallback) {
418
+ const value = process.env[key];
419
+ if (value !== void 0) return value === "true";
420
+ if (fallback !== void 0) return fallback;
421
+ throw new NotFoundError(`Missing required environment variable: ${key}`);
422
+ }
423
+ var REDIS_HOST = getEnv("REDIS_HOST");
424
+ var REDIS_PORT = getEnvNumber("REDIS_PORT", 6379);
425
+ var REDIS_PASSWORD = getEnv("REDIS_PASSWORD");
426
+ var REDIS_TLS = getEnvBoolean("REDIS_TLS", true);
427
+ var CACHE_SHORT_TTL = getEnvNumber("CACHE_SHORT_TTL", 300);
428
+ var CACHE_LONG_TTL = getEnvNumber("CACHE_LONG_TTL", 3600);
429
+
450
430
  // src/utils/ioredis.ts
451
431
  var import_ioredis = __toESM(require("ioredis"));
452
432
  var redisClient = null;
@@ -505,12 +485,11 @@ function useRedis() {
505
485
  }
506
486
 
507
487
  // src/utils/cache.ts
508
- var DEFAULT_TTL = 300;
509
488
  function useCache() {
510
489
  function getRedisClient() {
511
490
  return useRedis().getClient();
512
491
  }
513
- function get(cacheKey) {
492
+ function getCache(cacheKey) {
514
493
  return __async(this, null, function* () {
515
494
  try {
516
495
  const redisClient3 = getRedisClient();
@@ -524,13 +503,16 @@ function useCache() {
524
503
  }
525
504
  });
526
505
  }
527
- function set(_0, _1) {
528
- return __async(this, arguments, function* (cacheKey, data, ttl = DEFAULT_TTL, group) {
506
+ function setCache(_0, _1) {
507
+ return __async(this, arguments, function* (cacheKey, data, ttl = CACHE_SHORT_TTL, group) {
529
508
  try {
530
509
  const redisClient3 = getRedisClient();
531
510
  yield redisClient3.set(cacheKey, JSON.stringify(data), "EX", ttl);
532
511
  logger.info(`[Cache][Set] Stored key "${cacheKey}" with TTL ${ttl}s.`);
533
- if (group) yield redisClient3.sadd(`cache:group:${group}`, cacheKey);
512
+ if (group) {
513
+ yield redisClient3.sadd(`cache:group:${group}`, cacheKey);
514
+ yield redisClient3.expire(`cache:group:${group}`, CACHE_LONG_TTL);
515
+ }
534
516
  } catch (error) {
535
517
  logger.error(
536
518
  `[Cache][Set] Failed to store key "${cacheKey}": ${error instanceof Error ? error.message : error}`
@@ -538,7 +520,7 @@ function useCache() {
538
520
  }
539
521
  });
540
522
  }
541
- function remove(cacheKey) {
523
+ function delCache(cacheKey) {
542
524
  return __async(this, null, function* () {
543
525
  try {
544
526
  const redisClient3 = getRedisClient();
@@ -551,7 +533,7 @@ function useCache() {
551
533
  }
552
534
  });
553
535
  }
554
- function clearGroup(group) {
536
+ function delCacheGroup(group) {
555
537
  return __async(this, null, function* () {
556
538
  try {
557
539
  const redisClient3 = getRedisClient();
@@ -567,10 +549,10 @@ function useCache() {
567
549
  });
568
550
  }
569
551
  return {
570
- get,
571
- set,
572
- remove,
573
- clearGroup
552
+ getCache,
553
+ setCache,
554
+ delCache,
555
+ delCacheGroup
574
556
  };
575
557
  }
576
558
 
@@ -815,34 +797,6 @@ function hashPassword(_0) {
815
797
 
816
798
  // src/utils/redis.ts
817
799
  var import_redis = require("redis");
818
-
819
- // src/config.ts
820
- var dotenv = __toESM(require("dotenv"));
821
- dotenv.config();
822
- function getEnv(key, fallback) {
823
- const value = process.env[key];
824
- if (value !== void 0) return value;
825
- if (fallback !== void 0) return fallback;
826
- throw new Error(`Missing required environment variable: ${key}`);
827
- }
828
- function getEnvNumber(key, fallback) {
829
- const value = process.env[key];
830
- if (value !== void 0) return Number(value);
831
- if (fallback !== void 0) return fallback;
832
- throw new Error(`Missing required environment variable: ${key}`);
833
- }
834
- function getEnvBoolean(key, fallback) {
835
- const value = process.env[key];
836
- if (value !== void 0) return value === "true";
837
- if (fallback !== void 0) return fallback;
838
- throw new Error(`Missing required environment variable: ${key}`);
839
- }
840
- var REDIS_HOST = getEnv("REDIS_HOST");
841
- var REDIS_PORT = getEnvNumber("REDIS_PORT", 6379);
842
- var REDIS_PASSWORD = getEnv("REDIS_PASSWORD");
843
- var REDIS_TLS = getEnvBoolean("REDIS_TLS", true);
844
-
845
- // src/utils/redis.ts
846
800
  var redisClient2 = null;
847
801
  function initRedisClient() {
848
802
  return __async(this, null, function* () {
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/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/config.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 logger.debug(\"Attempting to extract token from Authorization header\");\r\n\r\n if (!authHeader) {\r\n logger.debug(\"No Authorization header provided\");\r\n return null;\r\n }\r\n\r\n if (!authHeader.startsWith(\"Bearer \")) {\r\n logger.warn(\"Authorization header does not start with 'Bearer '\", {\r\n authHeader: authHeader.substring(0, 20) + \"...\",\r\n });\r\n return null;\r\n }\r\n\r\n const token = authHeader.split(\" \")[1] || null;\r\n logger.debug(\"Token extraction result\", {\r\n hasToken: !!token,\r\n tokenLength: token?.length,\r\n });\r\n return token;\r\n}\r\n\r\n// Core authentication logic - DRY principle\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 logger.info(\"Starting authentication process\", {\r\n requestId,\r\n path: req.path,\r\n method: req.method,\r\n requiredRole,\r\n hasRevocationCheck: !!isTokenRevoked,\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 logger.debug(\"Token extracted successfully, proceeding with verification\", {\r\n requestId,\r\n tokenLength: token.length,\r\n });\r\n\r\n let decoded: DecodedToken;\r\n try {\r\n logger.debug(\"Verifying JWT token\", { requestId });\r\n decoded = jwt.verify(token, secretKey) as DecodedToken;\r\n logger.info(\"JWT token verified successfully\", {\r\n requestId,\r\n userId: decoded.user || decoded.id,\r\n role: decoded.role,\r\n jti: decoded.jti,\r\n exp: decoded.exp ? new Date(decoded.exp * 1000).toISOString() : \"unknown\",\r\n });\r\n } catch (error) {\r\n logger.error(\"JWT verification failed\", {\r\n requestId,\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n tokenLength: token.length,\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 logger.debug(\"Checking token revocation status\", {\r\n requestId,\r\n jti: decoded.jti,\r\n });\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 logger.debug(\"Token revocation check passed\", {\r\n requestId,\r\n jti: decoded.jti,\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 logger.info(\"Authentication completed successfully\", {\r\n requestId,\r\n userId: req.user.id,\r\n role: req.user.role,\r\n path: req.path,\r\n method: req.method,\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 const requestId = req.headers[\"x-request-id\"] || \"unknown\";\r\n logger.debug(\"Authenticate middleware invoked\", {\r\n requestId,\r\n path: req.path,\r\n });\r\n\r\n try {\r\n await authenticateToken(req, { secretKey, isTokenRevoked });\r\n logger.debug(\"Authenticate middleware completed successfully\", {\r\n requestId,\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"Authenticate middleware failed\", {\r\n requestId,\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 const requestId = req.headers[\"x-request-id\"] || \"unknown\";\r\n logger.debug(\"RequireAdmin middleware invoked\", {\r\n requestId,\r\n path: req.path,\r\n });\r\n\r\n try {\r\n await authenticateToken(req, {\r\n secretKey,\r\n isTokenRevoked,\r\n requiredRole: \"admin\",\r\n });\r\n logger.debug(\"RequireAdmin middleware completed successfully\", {\r\n requestId,\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireAdmin middleware failed\", {\r\n requestId,\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 const requestId = req.headers[\"x-request-id\"] || \"unknown\";\r\n logger.debug(\"RequireRole middleware invoked\", {\r\n requestId,\r\n path: req.path,\r\n requiredRole: role,\r\n });\r\n\r\n try {\r\n await authenticateToken(req, {\r\n ...options,\r\n requiredRole: role,\r\n });\r\n logger.debug(\"RequireRole middleware completed successfully\", {\r\n requestId,\r\n role,\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireRole middleware failed\", {\r\n requestId,\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 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 { useRedis } from \"./ioredis\";\r\nimport { logger } from \"./logger\";\r\n\r\nconst DEFAULT_TTL = 300;\r\n\r\nexport function useCache() {\r\n function getRedisClient() {\r\n return useRedis().getClient();\r\n }\r\n\r\n async function get<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 set<T = unknown>(\r\n cacheKey: string,\r\n data: T,\r\n ttl: number = DEFAULT_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) await redisClient.sadd(`cache:group:${group}`, cacheKey);\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 remove(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 clearGroup(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 get,\r\n set,\r\n remove,\r\n clearGroup,\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 * as dotenv from \"dotenv\";\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 Error(`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 Error(`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 Error(`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","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/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"]}
package/dist/index.mjs CHANGED
@@ -112,23 +112,16 @@ var InternalServerError = class extends HttpError {
112
112
 
113
113
  // src/middleware/auth.middleware.ts
114
114
  function extractToken(authHeader) {
115
- logger.debug("Attempting to extract token from Authorization header");
116
115
  if (!authHeader) {
117
- logger.debug("No Authorization header provided");
118
116
  return null;
119
117
  }
120
118
  if (!authHeader.startsWith("Bearer ")) {
121
- logger.warn("Authorization header does not start with 'Bearer '", {
122
- authHeader: authHeader.substring(0, 20) + "..."
119
+ logger.warn("Invalid Authorization header format", {
120
+ format: "Expected 'Bearer <token>'"
123
121
  });
124
122
  return null;
125
123
  }
126
- const token = authHeader.split(" ")[1] || null;
127
- logger.debug("Token extraction result", {
128
- hasToken: !!token,
129
- tokenLength: token == null ? void 0 : token.length
130
- });
131
- return token;
124
+ return authHeader.split(" ")[1] || null;
132
125
  }
133
126
  function authenticateToken(req, options) {
134
127
  return __async(this, null, function* () {
@@ -138,13 +131,14 @@ function authenticateToken(req, options) {
138
131
  requiredRole
139
132
  } = options;
140
133
  const requestId = req.headers["x-request-id"] || "unknown";
141
- logger.info("Starting authentication process", {
142
- requestId,
143
- path: req.path,
144
- method: req.method,
145
- requiredRole,
146
- hasRevocationCheck: !!isTokenRevoked
147
- });
134
+ const isDev = process.env.NODE_ENV === "development";
135
+ if (isDev) {
136
+ logger.debug("Starting authentication process", {
137
+ requestId,
138
+ path: req.path,
139
+ requiredRole
140
+ });
141
+ }
148
142
  const token = extractToken(req.headers.authorization);
149
143
  if (!token) {
150
144
  logger.error("Authentication failed: No access token provided", {
@@ -153,36 +147,27 @@ function authenticateToken(req, options) {
153
147
  });
154
148
  throw new UnauthorizedError("Access token is required to proceed.");
155
149
  }
156
- logger.debug("Token extracted successfully, proceeding with verification", {
157
- requestId,
158
- tokenLength: token.length
159
- });
160
150
  let decoded;
161
151
  try {
162
- logger.debug("Verifying JWT token", { requestId });
163
152
  decoded = jwt.verify(token, secretKey);
164
- logger.info("JWT token verified successfully", {
165
- requestId,
166
- userId: decoded.user || decoded.id,
167
- role: decoded.role,
168
- jti: decoded.jti,
169
- exp: decoded.exp ? new Date(decoded.exp * 1e3).toISOString() : "unknown"
170
- });
153
+ if (isDev) {
154
+ logger.debug("JWT token verified", {
155
+ requestId,
156
+ userId: decoded.user || decoded.id,
157
+ role: decoded.role
158
+ });
159
+ }
171
160
  } catch (error) {
172
161
  logger.error("JWT verification failed", {
173
162
  requestId,
174
- error: error instanceof Error ? error.message : "Unknown error",
175
- tokenLength: token.length
163
+ error: error instanceof Error ? error.message : "Invalid token",
164
+ path: req.path
176
165
  });
177
166
  throw new UnauthorizedError(
178
167
  "Your session has expired or the token is invalid. Please log in again."
179
168
  );
180
169
  }
181
170
  if (isTokenRevoked && decoded.jti) {
182
- logger.debug("Checking token revocation status", {
183
- requestId,
184
- jti: decoded.jti
185
- });
186
171
  const isRevoked = yield isTokenRevoked(decoded.jti);
187
172
  if (isRevoked) {
188
173
  logger.warn("Authentication failed: Token is revoked", {
@@ -194,10 +179,6 @@ function authenticateToken(req, options) {
194
179
  "Your session has expired or the token is invalid. Please log in again."
195
180
  );
196
181
  }
197
- logger.debug("Token revocation check passed", {
198
- requestId,
199
- jti: decoded.jti
200
- });
201
182
  }
202
183
  if (requiredRole && decoded.role !== requiredRole) {
203
184
  logger.warn("Authorization failed: Insufficient permissions", {
@@ -215,31 +196,22 @@ function authenticateToken(req, options) {
215
196
  id: decoded.user || decoded.id || ""
216
197
  });
217
198
  req.token = token;
218
- logger.info("Authentication completed successfully", {
219
- requestId,
220
- userId: req.user.id,
221
- role: req.user.role,
222
- path: req.path,
223
- method: req.method
224
- });
199
+ if (isDev) {
200
+ logger.debug("Authentication completed successfully", {
201
+ requestId,
202
+ userId: req.user.id,
203
+ role: req.user.role
204
+ });
205
+ }
225
206
  });
226
207
  }
227
208
  function authenticate(secretKey = process.env.ACCESS_TOKEN_SECRET || "", isTokenRevoked) {
228
209
  return (req, res, next) => __async(null, null, function* () {
229
- const requestId = req.headers["x-request-id"] || "unknown";
230
- logger.debug("Authenticate middleware invoked", {
231
- requestId,
232
- path: req.path
233
- });
234
210
  try {
235
211
  yield authenticateToken(req, { secretKey, isTokenRevoked });
236
- logger.debug("Authenticate middleware completed successfully", {
237
- requestId
238
- });
239
212
  next();
240
213
  } catch (error) {
241
214
  logger.error("Authenticate middleware failed", {
242
- requestId,
243
215
  error: error instanceof Error ? error.message : "Unknown error"
244
216
  });
245
217
  next(error);
@@ -248,24 +220,15 @@ function authenticate(secretKey = process.env.ACCESS_TOKEN_SECRET || "", isToken
248
220
  }
249
221
  function requireAdmin(secretKey = process.env.ACCESS_TOKEN_SECRET || "", isTokenRevoked) {
250
222
  return (req, res, next) => __async(null, null, function* () {
251
- const requestId = req.headers["x-request-id"] || "unknown";
252
- logger.debug("RequireAdmin middleware invoked", {
253
- requestId,
254
- path: req.path
255
- });
256
223
  try {
257
224
  yield authenticateToken(req, {
258
225
  secretKey,
259
226
  isTokenRevoked,
260
227
  requiredRole: "admin"
261
228
  });
262
- logger.debug("RequireAdmin middleware completed successfully", {
263
- requestId
264
- });
265
229
  next();
266
230
  } catch (error) {
267
231
  logger.error("RequireAdmin middleware failed", {
268
- requestId,
269
232
  error: error instanceof Error ? error.message : "Unknown error"
270
233
  });
271
234
  next(error);
@@ -274,24 +237,13 @@ function requireAdmin(secretKey = process.env.ACCESS_TOKEN_SECRET || "", isToken
274
237
  }
275
238
  function requireRole(role, options) {
276
239
  return (req, res, next) => __async(null, null, function* () {
277
- const requestId = req.headers["x-request-id"] || "unknown";
278
- logger.debug("RequireRole middleware invoked", {
279
- requestId,
280
- path: req.path,
281
- requiredRole: role
282
- });
283
240
  try {
284
241
  yield authenticateToken(req, __spreadProps(__spreadValues({}, options), {
285
242
  requiredRole: role
286
243
  }));
287
- logger.debug("RequireRole middleware completed successfully", {
288
- requestId,
289
- role
290
- });
291
244
  next();
292
245
  } catch (error) {
293
246
  logger.error("RequireRole middleware failed", {
294
- requestId,
295
247
  requiredRole: role,
296
248
  error: error instanceof Error ? error.message : "Unknown error"
297
249
  });
@@ -392,6 +344,34 @@ var useAtlas = class {
392
344
  useAtlas.mongoClient = null;
393
345
  useAtlas.mongoDb = null;
394
346
 
347
+ // src/config.ts
348
+ import * as dotenv from "dotenv";
349
+ dotenv.config();
350
+ function getEnv(key, fallback) {
351
+ const value = process.env[key];
352
+ if (value !== void 0) return value;
353
+ if (fallback !== void 0) return fallback;
354
+ throw new NotFoundError(`Missing required environment variable: ${key}`);
355
+ }
356
+ function getEnvNumber(key, fallback) {
357
+ const value = process.env[key];
358
+ if (value !== void 0) return Number(value);
359
+ if (fallback !== void 0) return fallback;
360
+ throw new NotFoundError(`Missing required environment variable: ${key}`);
361
+ }
362
+ function getEnvBoolean(key, fallback) {
363
+ const value = process.env[key];
364
+ if (value !== void 0) return value === "true";
365
+ if (fallback !== void 0) return fallback;
366
+ throw new NotFoundError(`Missing required environment variable: ${key}`);
367
+ }
368
+ var REDIS_HOST = getEnv("REDIS_HOST");
369
+ var REDIS_PORT = getEnvNumber("REDIS_PORT", 6379);
370
+ var REDIS_PASSWORD = getEnv("REDIS_PASSWORD");
371
+ var REDIS_TLS = getEnvBoolean("REDIS_TLS", true);
372
+ var CACHE_SHORT_TTL = getEnvNumber("CACHE_SHORT_TTL", 300);
373
+ var CACHE_LONG_TTL = getEnvNumber("CACHE_LONG_TTL", 3600);
374
+
395
375
  // src/utils/ioredis.ts
396
376
  import Redis from "ioredis";
397
377
  var redisClient = null;
@@ -450,12 +430,11 @@ function useRedis() {
450
430
  }
451
431
 
452
432
  // src/utils/cache.ts
453
- var DEFAULT_TTL = 300;
454
433
  function useCache() {
455
434
  function getRedisClient() {
456
435
  return useRedis().getClient();
457
436
  }
458
- function get(cacheKey) {
437
+ function getCache(cacheKey) {
459
438
  return __async(this, null, function* () {
460
439
  try {
461
440
  const redisClient3 = getRedisClient();
@@ -469,13 +448,16 @@ function useCache() {
469
448
  }
470
449
  });
471
450
  }
472
- function set(_0, _1) {
473
- return __async(this, arguments, function* (cacheKey, data, ttl = DEFAULT_TTL, group) {
451
+ function setCache(_0, _1) {
452
+ return __async(this, arguments, function* (cacheKey, data, ttl = CACHE_SHORT_TTL, group) {
474
453
  try {
475
454
  const redisClient3 = getRedisClient();
476
455
  yield redisClient3.set(cacheKey, JSON.stringify(data), "EX", ttl);
477
456
  logger.info(`[Cache][Set] Stored key "${cacheKey}" with TTL ${ttl}s.`);
478
- if (group) yield redisClient3.sadd(`cache:group:${group}`, cacheKey);
457
+ if (group) {
458
+ yield redisClient3.sadd(`cache:group:${group}`, cacheKey);
459
+ yield redisClient3.expire(`cache:group:${group}`, CACHE_LONG_TTL);
460
+ }
479
461
  } catch (error) {
480
462
  logger.error(
481
463
  `[Cache][Set] Failed to store key "${cacheKey}": ${error instanceof Error ? error.message : error}`
@@ -483,7 +465,7 @@ function useCache() {
483
465
  }
484
466
  });
485
467
  }
486
- function remove(cacheKey) {
468
+ function delCache(cacheKey) {
487
469
  return __async(this, null, function* () {
488
470
  try {
489
471
  const redisClient3 = getRedisClient();
@@ -496,7 +478,7 @@ function useCache() {
496
478
  }
497
479
  });
498
480
  }
499
- function clearGroup(group) {
481
+ function delCacheGroup(group) {
500
482
  return __async(this, null, function* () {
501
483
  try {
502
484
  const redisClient3 = getRedisClient();
@@ -512,10 +494,10 @@ function useCache() {
512
494
  });
513
495
  }
514
496
  return {
515
- get,
516
- set,
517
- remove,
518
- clearGroup
497
+ getCache,
498
+ setCache,
499
+ delCache,
500
+ delCacheGroup
519
501
  };
520
502
  }
521
503
 
@@ -760,34 +742,6 @@ function hashPassword(_0) {
760
742
 
761
743
  // src/utils/redis.ts
762
744
  import { createClient } from "redis";
763
-
764
- // src/config.ts
765
- import * as dotenv from "dotenv";
766
- dotenv.config();
767
- function getEnv(key, fallback) {
768
- const value = process.env[key];
769
- if (value !== void 0) return value;
770
- if (fallback !== void 0) return fallback;
771
- throw new Error(`Missing required environment variable: ${key}`);
772
- }
773
- function getEnvNumber(key, fallback) {
774
- const value = process.env[key];
775
- if (value !== void 0) return Number(value);
776
- if (fallback !== void 0) return fallback;
777
- throw new Error(`Missing required environment variable: ${key}`);
778
- }
779
- function getEnvBoolean(key, fallback) {
780
- const value = process.env[key];
781
- if (value !== void 0) return value === "true";
782
- if (fallback !== void 0) return fallback;
783
- throw new Error(`Missing required environment variable: ${key}`);
784
- }
785
- var REDIS_HOST = getEnv("REDIS_HOST");
786
- var REDIS_PORT = getEnvNumber("REDIS_PORT", 6379);
787
- var REDIS_PASSWORD = getEnv("REDIS_PASSWORD");
788
- var REDIS_TLS = getEnvBoolean("REDIS_TLS", true);
789
-
790
- // src/utils/redis.ts
791
745
  var redisClient2 = null;
792
746
  function initRedisClient() {
793
747
  return __async(this, null, function* () {
@@ -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/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/config.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 logger.debug(\"Attempting to extract token from Authorization header\");\r\n\r\n if (!authHeader) {\r\n logger.debug(\"No Authorization header provided\");\r\n return null;\r\n }\r\n\r\n if (!authHeader.startsWith(\"Bearer \")) {\r\n logger.warn(\"Authorization header does not start with 'Bearer '\", {\r\n authHeader: authHeader.substring(0, 20) + \"...\",\r\n });\r\n return null;\r\n }\r\n\r\n const token = authHeader.split(\" \")[1] || null;\r\n logger.debug(\"Token extraction result\", {\r\n hasToken: !!token,\r\n tokenLength: token?.length,\r\n });\r\n return token;\r\n}\r\n\r\n// Core authentication logic - DRY principle\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 logger.info(\"Starting authentication process\", {\r\n requestId,\r\n path: req.path,\r\n method: req.method,\r\n requiredRole,\r\n hasRevocationCheck: !!isTokenRevoked,\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 logger.debug(\"Token extracted successfully, proceeding with verification\", {\r\n requestId,\r\n tokenLength: token.length,\r\n });\r\n\r\n let decoded: DecodedToken;\r\n try {\r\n logger.debug(\"Verifying JWT token\", { requestId });\r\n decoded = jwt.verify(token, secretKey) as DecodedToken;\r\n logger.info(\"JWT token verified successfully\", {\r\n requestId,\r\n userId: decoded.user || decoded.id,\r\n role: decoded.role,\r\n jti: decoded.jti,\r\n exp: decoded.exp ? new Date(decoded.exp * 1000).toISOString() : \"unknown\",\r\n });\r\n } catch (error) {\r\n logger.error(\"JWT verification failed\", {\r\n requestId,\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n tokenLength: token.length,\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 logger.debug(\"Checking token revocation status\", {\r\n requestId,\r\n jti: decoded.jti,\r\n });\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 logger.debug(\"Token revocation check passed\", {\r\n requestId,\r\n jti: decoded.jti,\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 logger.info(\"Authentication completed successfully\", {\r\n requestId,\r\n userId: req.user.id,\r\n role: req.user.role,\r\n path: req.path,\r\n method: req.method,\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 const requestId = req.headers[\"x-request-id\"] || \"unknown\";\r\n logger.debug(\"Authenticate middleware invoked\", {\r\n requestId,\r\n path: req.path,\r\n });\r\n\r\n try {\r\n await authenticateToken(req, { secretKey, isTokenRevoked });\r\n logger.debug(\"Authenticate middleware completed successfully\", {\r\n requestId,\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"Authenticate middleware failed\", {\r\n requestId,\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 const requestId = req.headers[\"x-request-id\"] || \"unknown\";\r\n logger.debug(\"RequireAdmin middleware invoked\", {\r\n requestId,\r\n path: req.path,\r\n });\r\n\r\n try {\r\n await authenticateToken(req, {\r\n secretKey,\r\n isTokenRevoked,\r\n requiredRole: \"admin\",\r\n });\r\n logger.debug(\"RequireAdmin middleware completed successfully\", {\r\n requestId,\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireAdmin middleware failed\", {\r\n requestId,\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 const requestId = req.headers[\"x-request-id\"] || \"unknown\";\r\n logger.debug(\"RequireRole middleware invoked\", {\r\n requestId,\r\n path: req.path,\r\n requiredRole: role,\r\n });\r\n\r\n try {\r\n await authenticateToken(req, {\r\n ...options,\r\n requiredRole: role,\r\n });\r\n logger.debug(\"RequireRole middleware completed successfully\", {\r\n requestId,\r\n role,\r\n });\r\n next();\r\n } catch (error) {\r\n logger.error(\"RequireRole middleware failed\", {\r\n requestId,\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 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 { useRedis } from \"./ioredis\";\r\nimport { logger } from \"./logger\";\r\n\r\nconst DEFAULT_TTL = 300;\r\n\r\nexport function useCache() {\r\n function getRedisClient() {\r\n return useRedis().getClient();\r\n }\r\n\r\n async function get<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 set<T = unknown>(\r\n cacheKey: string,\r\n data: T,\r\n ttl: number = DEFAULT_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) await redisClient.sadd(`cache:group:${group}`, cacheKey);\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 remove(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 clearGroup(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 get,\r\n set,\r\n remove,\r\n clearGroup,\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 * as dotenv from \"dotenv\";\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 Error(`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 Error(`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 Error(`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","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/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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codisolutions23/node-utils",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",