@codisolutions23/node-utils 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/index.d.mts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.js +32 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +31 -29
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @codisolutions23/node-utils
|
|
2
2
|
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- - Removed validate-request middleware file
|
|
8
|
+
- Removed validate-request middleware export from index
|
|
9
|
+
- Added startSession method to atlas utils
|
|
10
|
+
- Updated pagination utils for correct page range calculation
|
|
11
|
+
|
|
12
|
+
## 2.1.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- chore: add token revocation check to auth middleware
|
|
17
|
+
|
|
18
|
+
- Introduced an optional `isTokenRevoked` callback to the `authenticate` middleware, allowing revoked (blacklisted) JWTs to be detected and rejected.
|
|
19
|
+
- This enhances security by supporting token invalidation, such as for logout or compromised tokens.
|
|
20
|
+
|
|
3
21
|
## 2.0.0
|
|
4
22
|
|
|
5
23
|
### Major Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from 'express';
|
|
2
2
|
import jwt, { JwtPayload } from 'jsonwebtoken';
|
|
3
|
-
import
|
|
3
|
+
import * as mongodb from 'mongodb';
|
|
4
4
|
import { MongoClient, Db, ObjectId } from 'mongodb';
|
|
5
5
|
import Redis from 'ioredis';
|
|
6
6
|
import * as winston from 'winston';
|
|
@@ -13,7 +13,7 @@ interface AuthenticatedRequest extends Request {
|
|
|
13
13
|
};
|
|
14
14
|
token?: string;
|
|
15
15
|
}
|
|
16
|
-
declare function authenticate(secretKey?: string): (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
16
|
+
declare function authenticate(secretKey?: string, isTokenRevoked?: (jti: string) => Promise<boolean>): (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
17
17
|
|
|
18
18
|
declare class HttpError extends Error {
|
|
19
19
|
readonly statusCode: number;
|
|
@@ -44,8 +44,6 @@ declare class InternalServerError extends HttpError {
|
|
|
44
44
|
|
|
45
45
|
declare const errorHandler: (error: HttpError, req: Request, res: Response, next: NextFunction) => void;
|
|
46
46
|
|
|
47
|
-
declare function validate(schema: Schema): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
48
|
-
|
|
49
47
|
interface AtlasConfig {
|
|
50
48
|
uri: string;
|
|
51
49
|
db: string;
|
|
@@ -57,6 +55,7 @@ declare class useAtlas {
|
|
|
57
55
|
static connect(config: AtlasConfig): Promise<void>;
|
|
58
56
|
static getClient(): MongoClient | null;
|
|
59
57
|
static getDb(): Db | null;
|
|
58
|
+
static startSession(): mongodb.ClientSession;
|
|
60
59
|
static close(): Promise<void>;
|
|
61
60
|
}
|
|
62
61
|
|
|
@@ -155,4 +154,4 @@ declare class useS3 {
|
|
|
155
154
|
|
|
156
155
|
declare function hashToken(token: string): string;
|
|
157
156
|
|
|
158
|
-
export { type AuthenticatedRequest, BadRequestError, ConflictError, ForbiddenError, HttpError, InternalServerError, NotFoundError, UnauthorizedError, UnprocessableEntityError, authenticate, buildCacheKey, comparePasswords, errorHandler, getTemplatePath, hashPassword, hashToken, initRedisClient, logger, paginate, renderHandlebarsTemplate, signJwtToken, toObjectId, useAtlas, useCache, useMailer, useRedis, useRedisClient, useS3
|
|
157
|
+
export { type AuthenticatedRequest, BadRequestError, ConflictError, ForbiddenError, HttpError, InternalServerError, NotFoundError, UnauthorizedError, UnprocessableEntityError, authenticate, buildCacheKey, comparePasswords, errorHandler, getTemplatePath, hashPassword, hashToken, initRedisClient, logger, paginate, renderHandlebarsTemplate, signJwtToken, toObjectId, useAtlas, useCache, useMailer, useRedis, useRedisClient, useS3 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from 'express';
|
|
2
2
|
import jwt, { JwtPayload } from 'jsonwebtoken';
|
|
3
|
-
import
|
|
3
|
+
import * as mongodb from 'mongodb';
|
|
4
4
|
import { MongoClient, Db, ObjectId } from 'mongodb';
|
|
5
5
|
import Redis from 'ioredis';
|
|
6
6
|
import * as winston from 'winston';
|
|
@@ -13,7 +13,7 @@ interface AuthenticatedRequest extends Request {
|
|
|
13
13
|
};
|
|
14
14
|
token?: string;
|
|
15
15
|
}
|
|
16
|
-
declare function authenticate(secretKey?: string): (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
16
|
+
declare function authenticate(secretKey?: string, isTokenRevoked?: (jti: string) => Promise<boolean>): (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
17
17
|
|
|
18
18
|
declare class HttpError extends Error {
|
|
19
19
|
readonly statusCode: number;
|
|
@@ -44,8 +44,6 @@ declare class InternalServerError extends HttpError {
|
|
|
44
44
|
|
|
45
45
|
declare const errorHandler: (error: HttpError, req: Request, res: Response, next: NextFunction) => void;
|
|
46
46
|
|
|
47
|
-
declare function validate(schema: Schema): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
48
|
-
|
|
49
47
|
interface AtlasConfig {
|
|
50
48
|
uri: string;
|
|
51
49
|
db: string;
|
|
@@ -57,6 +55,7 @@ declare class useAtlas {
|
|
|
57
55
|
static connect(config: AtlasConfig): Promise<void>;
|
|
58
56
|
static getClient(): MongoClient | null;
|
|
59
57
|
static getDb(): Db | null;
|
|
58
|
+
static startSession(): mongodb.ClientSession;
|
|
60
59
|
static close(): Promise<void>;
|
|
61
60
|
}
|
|
62
61
|
|
|
@@ -155,4 +154,4 @@ declare class useS3 {
|
|
|
155
154
|
|
|
156
155
|
declare function hashToken(token: string): string;
|
|
157
156
|
|
|
158
|
-
export { type AuthenticatedRequest, BadRequestError, ConflictError, ForbiddenError, HttpError, InternalServerError, NotFoundError, UnauthorizedError, UnprocessableEntityError, authenticate, buildCacheKey, comparePasswords, errorHandler, getTemplatePath, hashPassword, hashToken, initRedisClient, logger, paginate, renderHandlebarsTemplate, signJwtToken, toObjectId, useAtlas, useCache, useMailer, useRedis, useRedisClient, useS3
|
|
157
|
+
export { type AuthenticatedRequest, BadRequestError, ConflictError, ForbiddenError, HttpError, InternalServerError, NotFoundError, UnauthorizedError, UnprocessableEntityError, authenticate, buildCacheKey, comparePasswords, errorHandler, getTemplatePath, hashPassword, hashToken, initRedisClient, logger, paginate, renderHandlebarsTemplate, signJwtToken, toObjectId, useAtlas, useCache, useMailer, useRedis, useRedisClient, useS3 };
|
package/dist/index.js
CHANGED
|
@@ -93,8 +93,7 @@ __export(index_exports, {
|
|
|
93
93
|
useMailer: () => useMailer,
|
|
94
94
|
useRedis: () => useRedis,
|
|
95
95
|
useRedisClient: () => useRedisClient,
|
|
96
|
-
useS3: () => useS3
|
|
97
|
-
validate: () => validate
|
|
96
|
+
useS3: () => useS3
|
|
98
97
|
});
|
|
99
98
|
module.exports = __toCommonJS(index_exports);
|
|
100
99
|
|
|
@@ -165,7 +164,7 @@ var InternalServerError = class extends HttpError {
|
|
|
165
164
|
};
|
|
166
165
|
|
|
167
166
|
// src/middleware/auth.middleware.ts
|
|
168
|
-
function authenticate(secretKey = process.env.ACCESS_TOKEN_SECRET || "") {
|
|
167
|
+
function authenticate(secretKey = process.env.ACCESS_TOKEN_SECRET || "", isTokenRevoked) {
|
|
169
168
|
return (req, res, next) => __async(null, null, function* () {
|
|
170
169
|
const authHeader = req.headers.authorization;
|
|
171
170
|
const token = authHeader == null ? void 0 : authHeader.split(" ")[1];
|
|
@@ -177,6 +176,16 @@ function authenticate(secretKey = process.env.ACCESS_TOKEN_SECRET || "") {
|
|
|
177
176
|
}
|
|
178
177
|
try {
|
|
179
178
|
const decoded = import_jsonwebtoken.default.verify(token, secretKey);
|
|
179
|
+
if (isTokenRevoked && decoded.jti && (yield isTokenRevoked(decoded.jti))) {
|
|
180
|
+
logger.warn("Access token is revoked (blacklisted).", {
|
|
181
|
+
jti: decoded.jti
|
|
182
|
+
});
|
|
183
|
+
return next(
|
|
184
|
+
new UnauthorizedError(
|
|
185
|
+
"Your session has expired or the token is invalid. Please log in again."
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
|
+
}
|
|
180
189
|
req.user = __spreadProps(__spreadValues({}, decoded), {
|
|
181
190
|
id: decoded.user || decoded.id
|
|
182
191
|
});
|
|
@@ -204,28 +213,6 @@ var errorHandler = (error, req, res, next) => {
|
|
|
204
213
|
return;
|
|
205
214
|
};
|
|
206
215
|
|
|
207
|
-
// src/middleware/validate-request.middleware.ts
|
|
208
|
-
function validate(schema) {
|
|
209
|
-
return (req, res, next) => __async(null, null, function* () {
|
|
210
|
-
try {
|
|
211
|
-
const validationOptions = {
|
|
212
|
-
abortEarly: false
|
|
213
|
-
// Return all validation errors
|
|
214
|
-
};
|
|
215
|
-
const { error, value } = schema.validate(req.body, validationOptions);
|
|
216
|
-
if (error) {
|
|
217
|
-
throw new BadRequestError(
|
|
218
|
-
`Request body validation failed: ${error.details.map((detail) => detail.message).join(", ")}`
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
req.body = value;
|
|
222
|
-
next();
|
|
223
|
-
} catch (error) {
|
|
224
|
-
next(error);
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
216
|
// src/utils/atlas.ts
|
|
230
217
|
var import_mongodb = require("mongodb");
|
|
231
218
|
var useAtlas = class {
|
|
@@ -274,6 +261,14 @@ var useAtlas = class {
|
|
|
274
261
|
}
|
|
275
262
|
return this.mongoDb;
|
|
276
263
|
}
|
|
264
|
+
static startSession() {
|
|
265
|
+
const client = this.getClient();
|
|
266
|
+
if (!client) {
|
|
267
|
+
logger.warn(`[MongoDB][StartSession] Client is not initialized.`);
|
|
268
|
+
throw new NotFoundError("MongoDB client is not initialized.");
|
|
269
|
+
}
|
|
270
|
+
return client.startSession();
|
|
271
|
+
}
|
|
277
272
|
static close() {
|
|
278
273
|
return __async(this, null, function* () {
|
|
279
274
|
if (this.mongoClient) {
|
|
@@ -569,14 +564,21 @@ function toObjectId(id) {
|
|
|
569
564
|
|
|
570
565
|
// src/utils/paginate.ts
|
|
571
566
|
function paginate(items, page = 0, limit = 10, total) {
|
|
572
|
-
if (total === 0) {
|
|
567
|
+
if (total === 0 || items.length === 0) {
|
|
573
568
|
return {
|
|
574
569
|
items: [],
|
|
575
|
-
pages:
|
|
576
|
-
pageRange:
|
|
570
|
+
pages: Math.ceil(total / limit),
|
|
571
|
+
pageRange: `0-0 of ${total}`
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
const startIndex = (page - 1) * limit + 1;
|
|
575
|
+
if (startIndex > total) {
|
|
576
|
+
return {
|
|
577
|
+
items,
|
|
578
|
+
pages: Math.ceil(total / limit),
|
|
579
|
+
pageRange: `0-0 of ${total}`
|
|
577
580
|
};
|
|
578
581
|
}
|
|
579
|
-
const startIndex = page * limit + 1;
|
|
580
582
|
const endIndex = Math.min(startIndex + items.length - 1, total);
|
|
581
583
|
return {
|
|
582
584
|
items,
|
|
@@ -772,7 +774,6 @@ function hashToken(token) {
|
|
|
772
774
|
useMailer,
|
|
773
775
|
useRedis,
|
|
774
776
|
useRedisClient,
|
|
775
|
-
useS3
|
|
776
|
-
validate
|
|
777
|
+
useS3
|
|
777
778
|
});
|
|
778
779
|
//# sourceMappingURL=index.js.map
|
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/middleware/validate-request.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 } from \"./../utils/http-error\";\r\n\r\nexport interface AuthenticatedRequest extends Request {\r\n user?: JwtPayload & { user?: string; id?: string };\r\n token?: string;\r\n}\r\n\r\nexport function authenticate(\r\n secretKey: string = process.env.ACCESS_TOKEN_SECRET || \"\"\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n const authHeader = req.headers.authorization;\r\n const token = authHeader?.split(\" \")[1];\r\n\r\n if (!token) {\r\n logger.error(\"No access token provided in the request.\");\r\n return next(\r\n new UnauthorizedError(\"Access token is required to proceed.\")\r\n );\r\n }\r\n\r\n try {\r\n const decoded = jwt.verify(token, secretKey) as JwtPayload & {\r\n user?: string;\r\n id?: string;\r\n };\r\n\r\n req.user = {\r\n ...(decoded as any),\r\n id: (decoded as any).user || (decoded as any).id,\r\n };\r\n req.token = token;\r\n next();\r\n } catch (error) {\r\n logger.error(\"Failed to verify access token.\", error);\r\n return next(\r\n 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}\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 { Request, Response, NextFunction } from \"express\";\r\nimport { Schema } from \"joi\";\r\nimport { BadRequestError } from \"./../utils/http-error\";\r\n\r\nexport function validate(schema: Schema) {\r\n return async (req: Request, res: Response, next: NextFunction) => {\r\n try {\r\n const validationOptions = {\r\n abortEarly: false, // Return all validation errors\r\n };\r\n\r\n // Validate request body\r\n const { error, value } = schema.validate(req.body, validationOptions);\r\n if (error) {\r\n throw new BadRequestError(\r\n `Request body validation failed: ${error.details\r\n .map((detail) => detail.message)\r\n .join(\", \")}`\r\n );\r\n }\r\n req.body = value;\r\n\r\n next();\r\n } catch (error) {\r\n next(error);\r\n }\r\n };\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 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 return path.resolve(directory, file);\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\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) {\r\n return {\r\n items: [],\r\n pages: 0,\r\n pageRange: \"0-0 of 0\",\r\n };\r\n }\r\n\r\n const startIndex = page * limit + 1;\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","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/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 } from \"./../utils/http-error\";\r\n\r\nexport interface AuthenticatedRequest extends Request {\r\n user?: JwtPayload & { user?: string; id?: string };\r\n token?: string;\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 authHeader = req.headers.authorization;\r\n const token = authHeader?.split(\" \")[1];\r\n\r\n if (!token) {\r\n logger.error(\"No access token provided in the request.\");\r\n return next(\r\n new UnauthorizedError(\"Access token is required to proceed.\")\r\n );\r\n }\r\n\r\n try {\r\n const decoded = jwt.verify(token, secretKey) as JwtPayload & {\r\n user?: string;\r\n id?: string;\r\n jti?: string;\r\n };\r\n\r\n if (\r\n isTokenRevoked &&\r\n decoded.jti &&\r\n (await isTokenRevoked(decoded.jti))\r\n ) {\r\n logger.warn(\"Access token is revoked (blacklisted).\", {\r\n jti: decoded.jti,\r\n });\r\n return next(\r\n 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 req.user = {\r\n ...(decoded as any),\r\n id: (decoded as any).user || (decoded as any).id,\r\n };\r\n req.token = token;\r\n next();\r\n } catch (error) {\r\n logger.error(\"Failed to verify access token.\", error);\r\n return next(\r\n 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}\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 return path.resolve(directory, file);\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\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","import_jsonwebtoken","jwt","config","import_mongodb","bcrypt","redisClient","config","crypto"]}
|
package/dist/index.mjs
CHANGED
|
@@ -105,7 +105,7 @@ var InternalServerError = class extends HttpError {
|
|
|
105
105
|
};
|
|
106
106
|
|
|
107
107
|
// src/middleware/auth.middleware.ts
|
|
108
|
-
function authenticate(secretKey = process.env.ACCESS_TOKEN_SECRET || "") {
|
|
108
|
+
function authenticate(secretKey = process.env.ACCESS_TOKEN_SECRET || "", isTokenRevoked) {
|
|
109
109
|
return (req, res, next) => __async(null, null, function* () {
|
|
110
110
|
const authHeader = req.headers.authorization;
|
|
111
111
|
const token = authHeader == null ? void 0 : authHeader.split(" ")[1];
|
|
@@ -117,6 +117,16 @@ function authenticate(secretKey = process.env.ACCESS_TOKEN_SECRET || "") {
|
|
|
117
117
|
}
|
|
118
118
|
try {
|
|
119
119
|
const decoded = jwt.verify(token, secretKey);
|
|
120
|
+
if (isTokenRevoked && decoded.jti && (yield isTokenRevoked(decoded.jti))) {
|
|
121
|
+
logger.warn("Access token is revoked (blacklisted).", {
|
|
122
|
+
jti: decoded.jti
|
|
123
|
+
});
|
|
124
|
+
return next(
|
|
125
|
+
new UnauthorizedError(
|
|
126
|
+
"Your session has expired or the token is invalid. Please log in again."
|
|
127
|
+
)
|
|
128
|
+
);
|
|
129
|
+
}
|
|
120
130
|
req.user = __spreadProps(__spreadValues({}, decoded), {
|
|
121
131
|
id: decoded.user || decoded.id
|
|
122
132
|
});
|
|
@@ -144,28 +154,6 @@ var errorHandler = (error, req, res, next) => {
|
|
|
144
154
|
return;
|
|
145
155
|
};
|
|
146
156
|
|
|
147
|
-
// src/middleware/validate-request.middleware.ts
|
|
148
|
-
function validate(schema) {
|
|
149
|
-
return (req, res, next) => __async(null, null, function* () {
|
|
150
|
-
try {
|
|
151
|
-
const validationOptions = {
|
|
152
|
-
abortEarly: false
|
|
153
|
-
// Return all validation errors
|
|
154
|
-
};
|
|
155
|
-
const { error, value } = schema.validate(req.body, validationOptions);
|
|
156
|
-
if (error) {
|
|
157
|
-
throw new BadRequestError(
|
|
158
|
-
`Request body validation failed: ${error.details.map((detail) => detail.message).join(", ")}`
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
req.body = value;
|
|
162
|
-
next();
|
|
163
|
-
} catch (error) {
|
|
164
|
-
next(error);
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
157
|
// src/utils/atlas.ts
|
|
170
158
|
import { MongoClient } from "mongodb";
|
|
171
159
|
var useAtlas = class {
|
|
@@ -214,6 +202,14 @@ var useAtlas = class {
|
|
|
214
202
|
}
|
|
215
203
|
return this.mongoDb;
|
|
216
204
|
}
|
|
205
|
+
static startSession() {
|
|
206
|
+
const client = this.getClient();
|
|
207
|
+
if (!client) {
|
|
208
|
+
logger.warn(`[MongoDB][StartSession] Client is not initialized.`);
|
|
209
|
+
throw new NotFoundError("MongoDB client is not initialized.");
|
|
210
|
+
}
|
|
211
|
+
return client.startSession();
|
|
212
|
+
}
|
|
217
213
|
static close() {
|
|
218
214
|
return __async(this, null, function* () {
|
|
219
215
|
if (this.mongoClient) {
|
|
@@ -509,14 +505,21 @@ function toObjectId(id) {
|
|
|
509
505
|
|
|
510
506
|
// src/utils/paginate.ts
|
|
511
507
|
function paginate(items, page = 0, limit = 10, total) {
|
|
512
|
-
if (total === 0) {
|
|
508
|
+
if (total === 0 || items.length === 0) {
|
|
513
509
|
return {
|
|
514
510
|
items: [],
|
|
515
|
-
pages:
|
|
516
|
-
pageRange:
|
|
511
|
+
pages: Math.ceil(total / limit),
|
|
512
|
+
pageRange: `0-0 of ${total}`
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
const startIndex = (page - 1) * limit + 1;
|
|
516
|
+
if (startIndex > total) {
|
|
517
|
+
return {
|
|
518
|
+
items,
|
|
519
|
+
pages: Math.ceil(total / limit),
|
|
520
|
+
pageRange: `0-0 of ${total}`
|
|
517
521
|
};
|
|
518
522
|
}
|
|
519
|
-
const startIndex = page * limit + 1;
|
|
520
523
|
const endIndex = Math.min(startIndex + items.length - 1, total);
|
|
521
524
|
return {
|
|
522
525
|
items,
|
|
@@ -715,7 +718,6 @@ export {
|
|
|
715
718
|
useMailer,
|
|
716
719
|
useRedis,
|
|
717
720
|
useRedisClient,
|
|
718
|
-
useS3
|
|
719
|
-
validate
|
|
721
|
+
useS3
|
|
720
722
|
};
|
|
721
723
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/middleware/auth.middleware.ts","../src/utils/logger.ts","../src/utils/http-error.ts","../src/middleware/error-handler.middleware.ts","../src/middleware/validate-request.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 } from \"./../utils/http-error\";\r\n\r\nexport interface AuthenticatedRequest extends Request {\r\n user?: JwtPayload & { user?: string; id?: string };\r\n token?: string;\r\n}\r\n\r\nexport function authenticate(\r\n secretKey: string = process.env.ACCESS_TOKEN_SECRET || \"\"\r\n) {\r\n return async (\r\n req: AuthenticatedRequest,\r\n res: Response,\r\n next: NextFunction\r\n ) => {\r\n const authHeader = req.headers.authorization;\r\n const token = authHeader?.split(\" \")[1];\r\n\r\n if (!token) {\r\n logger.error(\"No access token provided in the request.\");\r\n return next(\r\n new UnauthorizedError(\"Access token is required to proceed.\")\r\n );\r\n }\r\n\r\n try {\r\n const decoded = jwt.verify(token, secretKey) as JwtPayload & {\r\n user?: string;\r\n id?: string;\r\n };\r\n\r\n req.user = {\r\n ...(decoded as any),\r\n id: (decoded as any).user || (decoded as any).id,\r\n };\r\n req.token = token;\r\n next();\r\n } catch (error) {\r\n logger.error(\"Failed to verify access token.\", error);\r\n return next(\r\n 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}\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 { Request, Response, NextFunction } from \"express\";\r\nimport { Schema } from \"joi\";\r\nimport { BadRequestError } from \"./../utils/http-error\";\r\n\r\nexport function validate(schema: Schema) {\r\n return async (req: Request, res: Response, next: NextFunction) => {\r\n try {\r\n const validationOptions = {\r\n abortEarly: false, // Return all validation errors\r\n };\r\n\r\n // Validate request body\r\n const { error, value } = schema.validate(req.body, validationOptions);\r\n if (error) {\r\n throw new BadRequestError(\r\n `Request body validation failed: ${error.details\r\n .map((detail) => detail.message)\r\n .join(\", \")}`\r\n );\r\n }\r\n req.body = value;\r\n\r\n next();\r\n } catch (error) {\r\n next(error);\r\n }\r\n };\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 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 return path.resolve(directory, file);\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\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) {\r\n return {\r\n items: [],\r\n pages: 0,\r\n pageRange: \"0-0 of 0\",\r\n };\r\n }\r\n\r\n const startIndex = page * limit + 1;\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,OAAO,SAAyB;;;ACDhC,YAAY,aAAa;AAEzB,IAAMA,cAAa;AAAA,EACjB,IAAY,mBAAW,KAAK,EAAE,UAAU,aAAa,OAAO,QAAQ,CAAC;AAAA,EACrE,IAAY,mBAAW,KAAK,EAAE,UAAU,eAAe,CAAC;AAC1D;AAEO,IAAM,SAAiB,qBAAa;AAAA,EACzC,OAAO;AAAA,EACP,QAAgB,eAAO;AAAA,IACb,eAAO,UAAU;AAAA,IACjB,eAAO,KAAK;AAAA,EACtB;AAAA,EACA,YAAAA;AACF,CAAC;;;ACdM,IAAM,YAAN,cAAwB,MAAM;AAAA,EAInC,YACE,SACA,YACA,gBAAyB,MACzB;AACA,UAAM,OAAO;AAEb,WAAO,eAAe,MAAM,WAAW,SAAS;AAEhD,SAAK,aAAa;AAClB,SAAK,gBAAgB;AAErB,QAAI,MAAM,mBAAmB;AAC3B,YAAM,kBAAkB,MAAM,KAAK,WAAW;AAAA,IAChD;AAAA,EACF;AACF;AAEO,IAAM,kBAAN,cAA8B,UAAU;AAAA,EAC7C,YACE,UAAkB,+EAClB;AACA,UAAM,SAAS,KAAK,IAAI;AAAA,EAC1B;AACF;AAEO,IAAM,oBAAN,cAAgC,UAAU;AAAA,EAC/C,YACE,UAAkB,uDAClB;AACA,UAAM,SAAS,KAAK,IAAI;AAAA,EAC1B;AACF;AAEO,IAAM,iBAAN,cAA6B,UAAU;AAAA,EAC5C,YACE,UAAkB,qEAClB;AACA,UAAM,SAAS,KAAK,IAAI;AAAA,EAC1B;AACF;AAEO,IAAM,gBAAN,cAA4B,UAAU;AAAA,EAC3C,YAAY,UAAkB,8CAA8C;AAC1E,UAAM,SAAS,KAAK,IAAI;AAAA,EAC1B;AACF;AAEO,IAAM,gBAAN,cAA4B,UAAU;AAAA,EAC3C,YACE,UAAkB,uDAClB;AACA,UAAM,SAAS,KAAK,IAAI;AAAA,EAC1B;AACF;AAEO,IAAM,2BAAN,cAAuC,UAAU;AAAA,EACtD,YACE,UAAkB,gFAClB;AACA,UAAM,SAAS,KAAK,IAAI;AAAA,EAC1B;AACF;AAEO,IAAM,sBAAN,cAAkC,UAAU;AAAA,EACjD,YACE,UAAkB,8DAClB;AACA,UAAM,SAAS,KAAK,IAAI;AAAA,EAC1B;AACF;;;AFhEO,SAAS,aACd,YAAoB,QAAQ,IAAI,uBAAuB,IACvD;AACA,SAAO,CACL,KACA,KACA,SACG;AACH,UAAM,aAAa,IAAI,QAAQ;AAC/B,UAAM,QAAQ,yCAAY,MAAM,KAAK;AAErC,QAAI,CAAC,OAAO;AACV,aAAO,MAAM,0CAA0C;AACvD,aAAO;AAAA,QACL,IAAI,kBAAkB,sCAAsC;AAAA,MAC9D;AAAA,IACF;AAEA,QAAI;AACF,YAAM,UAAU,IAAI,OAAO,OAAO,SAAS;AAK3C,UAAI,OAAO,iCACL,UADK;AAAA,QAET,IAAK,QAAgB,QAAS,QAAgB;AAAA,MAChD;AACA,UAAI,QAAQ;AACZ,WAAK;AAAA,IACP,SAAS,OAAO;AACd,aAAO,MAAM,kCAAkC,KAAK;AACpD,aAAO;AAAA,QACL,IAAI;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AG7CO,IAAM,eAAe,CAC1B,OACA,KACA,KACA,SACG;AACH,MAAI,MAAM,eAAe;AACvB,QACG,OAAO,MAAM,UAAU,EACvB,KAAK,EAAE,QAAQ,SAAS,SAAS,MAAM,QAAQ,CAAC;AAAA,EACrD,OAAO;AACL,WAAO,MAAM,EAAE,SAAS,MAAM,QAAQ,CAAC;AACvC,QACG,OAAO,GAAG,EACV,KAAK,EAAE,QAAQ,SAAS,SAAS,IAAI,oBAAoB,EAAE,QAAQ,CAAC;AAAA,EACzE;AAEA;AACF;;;AClBO,SAAS,SAAS,QAAgB;AACvC,SAAO,CAAO,KAAc,KAAe,SAAuB;AAChE,QAAI;AACF,YAAM,oBAAoB;AAAA,QACxB,YAAY;AAAA;AAAA,MACd;AAGA,YAAM,EAAE,OAAO,MAAM,IAAI,OAAO,SAAS,IAAI,MAAM,iBAAiB;AACpE,UAAI,OAAO;AACT,cAAM,IAAI;AAAA,UACR,mCAAmC,MAAM,QACtC,IAAI,CAAC,WAAW,OAAO,OAAO,EAC9B,KAAK,IAAI,CAAC;AAAA,QACf;AAAA,MACF;AACA,UAAI,OAAO;AAEX,WAAK;AAAA,IACP,SAAS,OAAO;AACd,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AACF;;;AC3BA,SAAa,mBAAmB;AAczB,IAAM,WAAN,MAAe;AAAA,EAIpB,OAAoB,QAAQC,SAAoC;AAAA;AAC9D,UAAI,KAAK,aAAa;AACpB,eAAO;AAAA,UACL;AAAA,QACF;AACA,cAAM,IAAI,gBAAgB,8CAA8C;AAAA,MAC1E;AAEA,YAAM,EAAE,IAAI,IAAI,IAAIA;AACpB,WAAK,cAAc,IAAI,YAAY,KAAK;AAAA,QACtC,aAAa;AAAA,QACb,eAAe;AAAA,QACf,kBAAkB;AAAA,MACpB,CAAC;AAED,UAAI;AACF,cAAM,KAAK,YAAY,QAAQ;AAC/B,aAAK,UAAU,KAAK,YAAY,GAAG,EAAE;AAErC,eAAO;AAAA,UACL,6CAA6C,KAAK,QAAQ,YAAY;AAAA,QACxE;AAAA,MACF,SAAS,OAAO;AACd,aAAK,cAAc;AAEnB,eAAO;AAAA,UACL,yCACE,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,QACF;AACA,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAEA,OAAc,YAAgC;AAC5C,QAAI,CAAC,KAAK,aAAa;AACrB,aAAO,KAAK,iDAAiD;AAC7D,YAAM,IAAI,cAAc,oCAAoC;AAAA,IAC9D;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,OAAc,QAAmB;AAC/B,QAAI,CAAC,KAAK,SAAS;AACjB,aAAO,KAAK,sDAAsD;AAClE,YAAM,IAAI,cAAc,6CAA6C;AAAA,IACvE;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,OAAoB,QAAuB;AAAA;AACzC,UAAI,KAAK,aAAa;AACpB,YAAI;AACF,gBAAM,KAAK,YAAY,MAAM;AAE7B,iBAAO,KAAK,qCAAqC;AAAA,QACnD,SAAS,OAAO;AACd,iBAAO;AAAA,YACL,8CACE,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,UACF;AACA,gBAAM,IAAI,oBAAoB,qCAAqC;AAAA,QACrE,UAAE;AACA,eAAK,cAAc;AACnB,eAAK,UAAU;AAAA,QACjB;AAAA,MACF,OAAO;AACL,eAAO,KAAK,2CAA2C;AACvD,cAAM,IAAI,gBAAgB,wCAAwC;AAAA,MACpE;AAAA,IACF;AAAA;AACF;AAhFa,SACI,cAAkC;AADtC,SAEI,UAAqB;;;AChBtC,OAAO,WAAW;AAIlB,IAAI,cAA4B;AASzB,SAAS,WAAW;AACzB,WAAS,WAAW,SAAuB;AAd7C;AAeI,QAAI,aAAa;AACf,aAAO,KAAK,wDAAwD;AACpE,aAAO;AAAA,IACT;AAEA,YAAQ,QAAO,aAAQ,SAAR,YAAgB;AAC/B,YAAQ,QAAO,aAAQ,SAAR,YAAgB;AAC/B,YAAQ,YAAW,aAAQ,aAAR,YAAoB;AACvC,YAAQ,YAAW,aAAQ,aAAR,YAAoB;AAEvC,kBAAc,IAAI,MAAM;AAAA,MACtB,MAAM,QAAQ;AAAA,MACd,MAAM,QAAQ;AAAA,OACV,QAAQ,YAAY,EAAE,UAAU,QAAQ,SAAS,IACjD,QAAQ,YAAY,EAAE,UAAU,QAAQ,SAAS,EACtD;AAED,gBAAY,GAAG,WAAW,MAAM;AAC9B,aAAO;AAAA,QACL,8CAA8C,QAAQ,IAAI,IAAI,QAAQ,IAAI;AAAA,MAC5E;AAAA,IACF,CAAC;AAED,gBAAY,GAAG,SAAS,CAAC,UAAU;AACjC,aAAO;AAAA,QACL,qCACE,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AAEA,WAAS,YAAmB;AAC1B,QAAI,CAAC,aAAa;AAChB,aAAO;AAAA,QACL;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,WAAS,aAAa;AACpB,QAAI,aAAa;AACf,kBAAY,KAAK;AACjB,aAAO,KAAK,uDAAuD;AACnE,oBAAc;AAAA,IAChB,OAAO;AACL,aAAO,KAAK,oDAAoD;AAAA,IAClE;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC1EA,IAAM,cAAc;AAEb,SAAS,WAAW;AACzB,WAAS,iBAAiB;AACxB,WAAO,SAAS,EAAE,UAAU;AAAA,EAC9B;AAEA,WAAe,IAAiB,UAAqC;AAAA;AACnE,UAAI;AACF,cAAMC,eAAc,eAAe;AACnC,cAAM,QAAQ,MAAMA,aAAY,IAAI,QAAQ;AAE5C,eAAO,QAAS,KAAK,MAAM,KAAK,IAAU;AAAA,MAC5C,SAAS,OAAO;AACd,eAAO;AAAA,UACL,wCAAwC,QAAQ,MAC9C,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AAEA,WAAe,IACb,IACA,IAGe;AAAA,+CAJf,UACA,MACA,MAAc,aACd,OACe;AACf,UAAI;AACF,cAAMA,eAAc,eAAe;AACnC,cAAMA,aAAY,IAAI,UAAU,KAAK,UAAU,IAAI,GAAG,MAAM,GAAG;AAC/D,eAAO,KAAK,4BAA4B,QAAQ,cAAc,GAAG,IAAI;AAErE,YAAI,MAAO,OAAMA,aAAY,KAAK,eAAe,KAAK,IAAI,QAAQ;AAAA,MACpE,SAAS,OAAO;AACd,eAAO;AAAA,UACL,qCAAqC,QAAQ,MAC3C,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA;AAEA,WAAe,OAAO,UAAiC;AAAA;AACrD,UAAI;AACF,cAAMA,eAAc,eAAe;AACnC,cAAMA,aAAY,IAAI,QAAQ;AAC9B,eAAO,KAAK,wBAAwB,QAAQ,qBAAqB;AAAA,MACnE,SAAS,OAAO;AACd,eAAO;AAAA,UACL,yCAAyC,QAAQ,MAC/C,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA;AAEA,WAAe,WAAW,OAA8B;AAAA;AACtD,UAAI;AACF,cAAMA,eAAc,eAAe;AACnC,cAAM,OAAO,MAAMA,aAAY,SAAS,eAAe,KAAK,EAAE;AAC9D,YAAI,KAAK,OAAQ,OAAMA,aAAY,IAAI,GAAG,IAAI;AAE9C,cAAMA,aAAY,IAAI,eAAe,KAAK,EAAE;AAC5C,eAAO,KAAK,sCAAsC,KAAK,iBAAiB;AAAA,MAC1E,SAAS,OAAO;AACd,eAAO;AAAA,UACL,8CAA8C,KAAK,MACjD,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACrFO,SAAS,cACd,QACA,QACQ;AACR,QAAM,QAAQ,OAAO,QAAQ,MAAM,EAChC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,EACrC;AAAA,IACC,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,mBAAmB,CAAC,CAAC,IAAI,mBAAmB,OAAO,CAAC,CAAC,CAAC;AAAA,EACvE,EACC,KAAK,GAAG;AAEX,SAAO,GAAG,MAAM,IAAI,KAAK;AAC3B;;;ACZA,OAAO,UAAU;AAEV,SAAS,gBAAgB,WAAmB,UAAkB;AACnE,QAAM,MAAM;AACZ,QAAM,OAAO,SAAS,SAAS,GAAG,IAAI,WAAW,GAAG,QAAQ,GAAG,GAAG;AAClE,SAAO,KAAK,QAAQ,WAAW,IAAI;AACrC;;;ACNA,OAAO,gBAAgB;AACvB,SAAS,YAAY,UAAU;AAS/B,IAAM,0BAA0B,oBAAI,IAAyC;AAE7E,SAAsB,yBAAyB,IAGX;AAAA,6CAHW;AAAA,IAC7C,UAAU,CAAC;AAAA,IACX;AAAA,EACF,GAAoC;AAClC,QAAI;AACF,UAAI,mBAAmB,wBAAwB,IAAI,QAAQ;AAE3D,UAAI,CAAC,kBAAkB;AACrB,eAAO;AAAA,UACL,4DAA4D,QAAQ;AAAA,QACtE;AACA,cAAM,cAAc,MAAM,GAAG,SAAS,UAAU,MAAM;AACtD,2BAAmB,WAAW,QAAQ,WAAW;AACjD,gCAAwB,IAAI,UAAU,gBAAgB;AAAA,MACxD,OAAO;AACL,eAAO,KAAK,gDAAgD,QAAQ,IAAI;AAAA,MAC1E;AAEA,aAAO,iBAAiB,OAAO;AAAA,IACjC,SAAS,OAAO;AACd,aAAO;AAAA,QACL,iDAAiD,QAAQ,MACvD,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,MACF;AACA,YAAM,IAAI,oBAAoB,uCAAuC;AAAA,IACvE;AAAA,EACF;AAAA;;;ACvCA,OAAOC,UAAS;AAUT,SAAS,aAAa;AAAA,EAC3B,UAAU,CAAC;AAAA,EACX,YAAY;AAAA,EACZ,cAAc,CAAC;AACjB,GAA0B;AACxB,MAAI,CAAC,WAAW;AACd,WAAO,MAAM,uDAAuD;AACpE,UAAM,IAAI,gBAAgB,oCAAoC;AAAA,EAChE;AAEA,MAAI;AACF,WAAO,KAAK,gCAAgC;AAC5C,WAAOC,KAAI,KAAK,SAAS,WAAW,WAAW;AAAA,EACjD,SAAS,OAAO;AACd,WAAO;AAAA,MACL,yCACE,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;;;AC/BA,SAAS,uBAAqD;AAYvD,IAAM,YAAN,MAAgB;AAAA,EAGrB,YAAoBC,SAAsB;AAAtB,kBAAAA;AAClB,SAAK,cAAc,gBAAgB;AAAA,MACjC,MAAMA,QAAO;AAAA,MACb,MAAMA,QAAO;AAAA,MACb,QAAQA,QAAO;AAAA,MACf,MAAM,EAAE,MAAMA,QAAO,OAAO,MAAMA,QAAO,SAAS;AAAA,IACpD,CAAC;AAAA,EACH;AAAA,EAEM,SAAS,IAYK;AAAA,+CAZL;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,GAMoB;AAClB,YAAM,OAAO,SACT,GAAG,MAAM,KAAK,KAAK,OAAO,KAAK,MAC/B,KAAK,OAAO;AAEhB,YAAM,cAA+B;AAAA,QACnC;AAAA,QACA;AAAA,QACA;AAAA,SACI,QAAQ,EAAE,KAAK,IACf,QAAQ,EAAE,KAAK;AAGrB,UAAI;AACF,cAAM,KAAK,YAAY,SAAS,WAAW;AAC3C,eAAO;AAAA,UACL,iCAAiC,EAAE,mBAAmB,OAAO;AAAA,QAC/D;AAEA,eAAO;AAAA,MACT,SAAS,OAAO;AACd,eAAO;AAAA,UACL,2CAA2C,EAAE,mBAAmB,OAAO,MACrE,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,QACF;AACA,cAAM,IAAI,oBAAoB,uBAAuB;AAAA,MACvD;AAAA,IACF;AAAA;AACF;;;ACjEA,SAAS,gBAAgB;AAIlB,SAAS,WAAW,IAAiC;AAC1D,MAAI,CAAC,IAAI;AACP,WAAO;AAAA,MACL;AAAA,IACF;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI,cAAc,SAAU,QAAO;AAEnC,MAAI,CAAC,oBAAoB,KAAK,EAAE,GAAG;AACjC,WAAO;AAAA,MACL;AAAA,IACF;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACF,WAAO,IAAI,SAAS,EAAE;AAAA,EACxB,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,4DACE,eAAe,QAAQ,IAAI,UAAU,GACvC;AAAA,IACF;AACA,UAAM,IAAI,gBAAgB,gDAAgD;AAAA,EAC5E;AACF;;;ACnCO,SAAS,SACd,OACA,OAAe,GACf,QAAgB,IAChB,OACA;AACA,MAAI,UAAU,GAAG;AACf,WAAO;AAAA,MACL,OAAO,CAAC;AAAA,MACR,OAAO;AAAA,MACP,WAAW;AAAA,IACb;AAAA,EACF;AAEA,QAAM,aAAa,OAAO,QAAQ;AAClC,QAAM,WAAW,KAAK,IAAI,aAAa,MAAM,SAAS,GAAG,KAAK;AAE9D,SAAO;AAAA,IACL;AAAA,IACA,OAAO,KAAK,KAAK,QAAQ,KAAK;AAAA,IAC9B,WAAW,GAAG,UAAU,IAAI,QAAQ,OAAO,KAAK;AAAA,EAClD;AACF;;;ACtBA,OAAO,YAAY;AAInB,IAAM,sBAAsB;AAE5B,SAAsB,iBACpB,UACA,QACkB;AAAA;AAClB,QAAI;AACF,aAAO,MAAM,OAAO,QAAQ,UAAU,MAAM;AAAA,IAC9C,SAAS,OAAO;AACd,aAAO;AAAA,QACL,oDACE,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAEA,SAAsB,aACpB,IAEiB;AAAA,6CAFjB,UACA,aAAqB,qBACJ;AACjB,QAAI;AACF,aAAO,MAAM,OAAO,KAAK,UAAU,UAAU;AAAA,IAC/C,SAAS,OAAO;AACd,aAAO;AAAA,QACL,6CACE,iBAAiB,QAAQ,MAAM,UAAU,KAC3C;AAAA,MACF;AACA,YAAM,IAAI,oBAAoB,0BAA0B;AAAA,IAC1D;AAAA,EACF;AAAA;;;ACpCA,SAAS,oBAAqC;;;ACA9C,YAAY,YAAY;AAEjB,cAAO;AAEd,SAAS,OAAO,KAAa,UAA2B;AACtD,QAAM,QAAQ,QAAQ,IAAI,GAAG;AAC7B,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,aAAa,OAAW,QAAO;AACnC,QAAM,IAAI,MAAM,0CAA0C,GAAG,EAAE;AACjE;AAEA,SAAS,aAAa,KAAa,UAA2B;AAC5D,QAAM,QAAQ,QAAQ,IAAI,GAAG;AAC7B,MAAI,UAAU,OAAW,QAAO,OAAO,KAAK;AAC5C,MAAI,aAAa,OAAW,QAAO;AACnC,QAAM,IAAI,MAAM,0CAA0C,GAAG,EAAE;AACjE;AAEA,SAAS,cAAc,KAAa,UAA6B;AAC/D,QAAM,QAAQ,QAAQ,IAAI,GAAG;AAC7B,MAAI,UAAU,OAAW,QAAO,UAAU;AAC1C,MAAI,aAAa,OAAW,QAAO;AACnC,QAAM,IAAI,MAAM,0CAA0C,GAAG,EAAE;AACjE;AAGO,IAAM,aAAa,OAAO,YAAY;AACtC,IAAM,aAAa,aAAa,cAAc,IAAI;AAClD,IAAM,iBAAiB,OAAO,gBAAgB;AAC9C,IAAM,YAAY,cAAc,aAAa,IAAI;;;ADzBxD,IAAIC,eAAsC;AAE1C,SAAsB,kBAAkB;AAAA;AACtC,QAAIA,cAAa;AACf,aAAO,KAAK,wDAAwD;AACpE,aAAOA;AAAA,IACT;AAEA,IAAAA,eAAc,aAAa;AAAA,MACzB,UAAU;AAAA,MACV,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAEO,SAAS,iBAAkC;AAChD,MAAI,CAACA,cAAa;AAChB,WAAO;AAAA,MACL;AAAA,IACF;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAOA;AACT;;;AEhCA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gBAAgB;AAYlB,IAAM,QAAN,MAAY;AAAA,EAGjB,YAAoBC,SAAkB;AAAlB,kBAAAA;AAClB,SAAK,SAAS,IAAI,SAAS;AAAA,MACzB,UAAUA,QAAO;AAAA,MACjB,QAAQA,QAAO;AAAA,MACf,aAAa;AAAA,QACX,aAAaA,QAAO;AAAA,QACpB,iBAAiBA,QAAO;AAAA,MAC1B;AAAA,MACA,gBAAgBA,QAAO;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEM,aAAa,IAUC;AAAA,+CAVD;AAAA,MACjB;AAAA,MACA;AAAA,MACA,WAAW,CAAC;AAAA,MACZ;AAAA,IACF,GAKoB;AAClB,UAAI;AACF,cAAM,KAAK,OAAO;AAAA,UAChB,IAAI,iBAAiB;AAAA,YACnB,QAAQ,KAAK,OAAO;AAAA,YACpB,KAAK;AAAA,YACL,MACE,OAAO,SAAS,YAAY,OAAO,SAAS,IAAI,IAC5C,OACA,SAAS,KAAK,IAAI;AAAA,YACxB,KAAK;AAAA,YACL,UAAU;AAAA,YACV,aAAa;AAAA,YACb,eACE,OAAO,SAAS,WAAW,OAAO,WAAW,IAAI,IAAI,KAAK;AAAA,UAC9D,CAAC;AAAA,QACH;AAEA,eAAO;AAAA,UACL,0BAA0B,GAAG,gBAAgB,KAAK,OAAO,MAAM;AAAA,QACjE;AACA,eAAO;AAAA,MACT,SAAS,OAAO;AACd,eAAO;AAAA,UACL,yCAAyC,GAAG,gBAC1C,KAAK,OAAO,MACd,MAAM,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AAAA,QACtD;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA;AAAA,EAEM,aAAa,KAAa;AAAA;AAC9B,UAAI;AACF,cAAM,KAAK,OAAO;AAAA,UAChB,IAAI,oBAAoB,EAAE,KAAK,KAAK,QAAQ,KAAK,OAAO,OAAO,CAAC;AAAA,QAClE;AAEA,eAAO;AAAA,UACL,yBAAyB,GAAG,kBAAkB,KAAK,OAAO,MAAM;AAAA,QAClE;AACA,eAAO;AAAA,MACT,SAAS,OAAO;AACd,eAAO;AAAA,UACL,yCAAyC,GAAG,kBAC1C,KAAK,OAAO,MACd,MAAM,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AAAA,QACtD;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA;AACF;;;AC7FA,OAAO,YAAY;AAInB,IAAM,kBAAkB,QAAQ,IAAI,2BAA2B;AAExD,SAAS,UAAU,OAAuB;AAC/C,SAAO,OACJ,WAAW,QAAQ,EACnB,OAAO,kBAAkB,KAAK,EAC9B,OAAO,KAAK;AACjB;","names":["transports","config","redisClient","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/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 } from \"./../utils/http-error\";\r\n\r\nexport interface AuthenticatedRequest extends Request {\r\n user?: JwtPayload & { user?: string; id?: string };\r\n token?: string;\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 authHeader = req.headers.authorization;\r\n const token = authHeader?.split(\" \")[1];\r\n\r\n if (!token) {\r\n logger.error(\"No access token provided in the request.\");\r\n return next(\r\n new UnauthorizedError(\"Access token is required to proceed.\")\r\n );\r\n }\r\n\r\n try {\r\n const decoded = jwt.verify(token, secretKey) as JwtPayload & {\r\n user?: string;\r\n id?: string;\r\n jti?: string;\r\n };\r\n\r\n if (\r\n isTokenRevoked &&\r\n decoded.jti &&\r\n (await isTokenRevoked(decoded.jti))\r\n ) {\r\n logger.warn(\"Access token is revoked (blacklisted).\", {\r\n jti: decoded.jti,\r\n });\r\n return next(\r\n 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 req.user = {\r\n ...(decoded as any),\r\n id: (decoded as any).user || (decoded as any).id,\r\n };\r\n req.token = token;\r\n next();\r\n } catch (error) {\r\n logger.error(\"Failed to verify access token.\", error);\r\n return next(\r\n 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}\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 return path.resolve(directory, file);\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\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","jwt","jwt","config","redisClient","config"]}
|