nexus-backend 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +28 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +54 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from 'express';
|
|
2
2
|
import NodeCache from 'node-cache';
|
|
3
|
+
import { Resend } from 'resend';
|
|
3
4
|
|
|
4
5
|
interface SuccessResponse<T = any> {
|
|
5
6
|
success: true;
|
|
@@ -82,4 +83,30 @@ declare class Cache extends NodeCache {
|
|
|
82
83
|
|
|
83
84
|
declare const cacheMemory: Cache;
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Generates a random numeric string of given length.
|
|
88
|
+
* Uses crypto for better randomness (production safe).
|
|
89
|
+
*
|
|
90
|
+
* @param digit - Length of the random number
|
|
91
|
+
* @returns string
|
|
92
|
+
*/
|
|
93
|
+
declare function random(digit: number): string;
|
|
94
|
+
|
|
95
|
+
interface MailerConfig {
|
|
96
|
+
brandName: string;
|
|
97
|
+
smtpProvider: Resend;
|
|
98
|
+
fromEmail: string;
|
|
99
|
+
}
|
|
100
|
+
interface EmailOptions {
|
|
101
|
+
to: string;
|
|
102
|
+
subject: string;
|
|
103
|
+
body: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
declare class Mailer {
|
|
107
|
+
private config;
|
|
108
|
+
constructor(mailerConfig: MailerConfig);
|
|
109
|
+
sendMail(options: EmailOptions): Promise<boolean>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { ApiError, BadRequestError, Cache, type EmailOptions, type ErrorResponse, ForbiddenError, Mailer, type MailerConfig, type MongoConfig, NotFoundError, type SuccessResponse, UnauthorizedError, ValidationError, cacheMemory, connectMongoDb, errorHandler as errorMiddleware, errorResponse, random, requiredEnv, successResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from 'express';
|
|
2
2
|
import NodeCache from 'node-cache';
|
|
3
|
+
import { Resend } from 'resend';
|
|
3
4
|
|
|
4
5
|
interface SuccessResponse<T = any> {
|
|
5
6
|
success: true;
|
|
@@ -82,4 +83,30 @@ declare class Cache extends NodeCache {
|
|
|
82
83
|
|
|
83
84
|
declare const cacheMemory: Cache;
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Generates a random numeric string of given length.
|
|
88
|
+
* Uses crypto for better randomness (production safe).
|
|
89
|
+
*
|
|
90
|
+
* @param digit - Length of the random number
|
|
91
|
+
* @returns string
|
|
92
|
+
*/
|
|
93
|
+
declare function random(digit: number): string;
|
|
94
|
+
|
|
95
|
+
interface MailerConfig {
|
|
96
|
+
brandName: string;
|
|
97
|
+
smtpProvider: Resend;
|
|
98
|
+
fromEmail: string;
|
|
99
|
+
}
|
|
100
|
+
interface EmailOptions {
|
|
101
|
+
to: string;
|
|
102
|
+
subject: string;
|
|
103
|
+
body: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
declare class Mailer {
|
|
107
|
+
private config;
|
|
108
|
+
constructor(mailerConfig: MailerConfig);
|
|
109
|
+
sendMail(options: EmailOptions): Promise<boolean>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { ApiError, BadRequestError, Cache, type EmailOptions, type ErrorResponse, ForbiddenError, Mailer, type MailerConfig, type MongoConfig, NotFoundError, type SuccessResponse, UnauthorizedError, ValidationError, cacheMemory, connectMongoDb, errorHandler as errorMiddleware, errorResponse, random, requiredEnv, successResponse };
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
BadRequestError: () => BadRequestError,
|
|
35
35
|
Cache: () => Cache,
|
|
36
36
|
ForbiddenError: () => ForbiddenError,
|
|
37
|
+
Mailer: () => mailer_default,
|
|
37
38
|
NotFoundError: () => NotFoundError,
|
|
38
39
|
UnauthorizedError: () => UnauthorizedError,
|
|
39
40
|
ValidationError: () => ValidationError,
|
|
@@ -41,6 +42,7 @@ __export(index_exports, {
|
|
|
41
42
|
connectMongoDb: () => connectMongoDb,
|
|
42
43
|
errorMiddleware: () => errorHandler_default,
|
|
43
44
|
errorResponse: () => errorResponse,
|
|
45
|
+
random: () => random,
|
|
44
46
|
requiredEnv: () => requiredEnv,
|
|
45
47
|
successResponse: () => successResponse
|
|
46
48
|
});
|
|
@@ -260,12 +262,65 @@ var Cache = class extends import_node_cache.default {
|
|
|
260
262
|
// src/utils/cacheMemory.ts
|
|
261
263
|
var cacheMemory = new Cache();
|
|
262
264
|
var cacheMemory_default = cacheMemory;
|
|
265
|
+
|
|
266
|
+
// src/utils/randomNum.ts
|
|
267
|
+
var import_crypto = __toESM(require("crypto"));
|
|
268
|
+
function random(digit) {
|
|
269
|
+
if (!Number.isInteger(digit) || digit <= 0) {
|
|
270
|
+
throw new Error("Digit must be a positive integer");
|
|
271
|
+
}
|
|
272
|
+
const min = 10 ** (digit - 1);
|
|
273
|
+
const max = 10 ** digit - 1;
|
|
274
|
+
const randomNumber = import_crypto.default.randomInt(min, max + 1);
|
|
275
|
+
return randomNumber.toString();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// src/utils/mailer.ts
|
|
279
|
+
var Mailer = class {
|
|
280
|
+
// 2. Use 'private' or 'readonly' to encapsulate the config data
|
|
281
|
+
constructor(mailerConfig) {
|
|
282
|
+
this.config = mailerConfig;
|
|
283
|
+
}
|
|
284
|
+
// 3. Defined the sendMail method with parameters and proper return type
|
|
285
|
+
async sendMail(options) {
|
|
286
|
+
const { to, subject, body } = options;
|
|
287
|
+
console.log(`Sending email via ${this.config.smtpProvider}...`);
|
|
288
|
+
console.log(`From: "${this.config.brandName}" <${this.config.fromEmail}>`);
|
|
289
|
+
console.log(`To: ${to}`);
|
|
290
|
+
console.log(`Subject: ${subject}`);
|
|
291
|
+
console.log(`Body: ${body}`);
|
|
292
|
+
try {
|
|
293
|
+
const response = await this.config.smtpProvider.emails.send({
|
|
294
|
+
from: `${this.config.brandName} <${this.config.fromEmail}>`,
|
|
295
|
+
to: [to],
|
|
296
|
+
subject,
|
|
297
|
+
html: body
|
|
298
|
+
// or 'text: body' depending on your needs
|
|
299
|
+
});
|
|
300
|
+
console.log("SMTP Response:", response);
|
|
301
|
+
if (response.error) {
|
|
302
|
+
console.error("SMTP API error:", response.error);
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
return true;
|
|
306
|
+
} catch (error) {
|
|
307
|
+
if (error instanceof Error) {
|
|
308
|
+
console.error("SMTP error:", error.message);
|
|
309
|
+
} else {
|
|
310
|
+
console.error("SMTP error:", error);
|
|
311
|
+
}
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
var mailer_default = Mailer;
|
|
263
317
|
// Annotate the CommonJS export names for ESM import in node:
|
|
264
318
|
0 && (module.exports = {
|
|
265
319
|
ApiError,
|
|
266
320
|
BadRequestError,
|
|
267
321
|
Cache,
|
|
268
322
|
ForbiddenError,
|
|
323
|
+
Mailer,
|
|
269
324
|
NotFoundError,
|
|
270
325
|
UnauthorizedError,
|
|
271
326
|
ValidationError,
|
|
@@ -273,6 +328,7 @@ var cacheMemory_default = cacheMemory;
|
|
|
273
328
|
connectMongoDb,
|
|
274
329
|
errorMiddleware,
|
|
275
330
|
errorResponse,
|
|
331
|
+
random,
|
|
276
332
|
requiredEnv,
|
|
277
333
|
successResponse
|
|
278
334
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/responses/successResponse.ts","../src/responses/errorResponse.ts","../src/utils/envManager.ts","../src/config/mongoConfig.ts","../src/errors/ApiError.ts","../src/errors/BadRequestError.ts","../src/errors/UnauthorisedError.ts","../src/errors/ForbiddenError.ts","../src/errors/NotFoundError.ts","../src/errors/ValidationError.ts","../src/handlers/errorHandler.ts","../src/utils/cache.ts","../src/utils/cacheMemory.ts"],"sourcesContent":["export { successResponse } from \"./responses/successResponse\";\nexport { errorResponse } from \"./responses/errorResponse\";\nexport { requiredEnv } from \"./utils/envManager\";\nexport { connectMongoDb } from \"./config/mongoConfig\";\nexport { default as ApiError } from \"./errors/ApiError\";\nexport { default as BadRequestError } from \"./errors/BadRequestError\";\nexport { default as UnauthorizedError } from \"./errors/UnauthorisedError\";\nexport { default as ForbiddenError } from \"./errors/ForbiddenError\";\nexport { default as NotFoundError } from \"./errors/NotFoundError\";\nexport { default as ValidationError } from \"./errors/ValidationError\";\nexport { default as errorMiddleware } from \"./handlers/errorHandler\";\nexport { Cache } from \"./utils/cache\";\nexport { default as cacheMemory } from \"./utils/cacheMemory\";\nexport type { SuccessResponse, ErrorResponse } from \"./types/response.types\";\nexport { type MongoConfig } from \"./types/mongoConfig.types\";\n","import { SuccessResponse } from \"../types/response.types\";\n\nexport const successResponse = <T>(\n data: T,\n message?: string\n): SuccessResponse<T> => ({\n success: true,\n data,\n message,\n});","import { ErrorResponse } from \"../types/response.types\";\n\nexport const errorResponse = (\n message: string,\n errors?: any,\n stack?: string\n): ErrorResponse => ({\n success: false,\n message,\n errors,\n stack,\n});","export const requiredEnv = (value: string | undefined, key: string): string => {\n if (!value) {\n throw new Error(`Missing required environment variable: ${key}`);\n }\n return value;\n};","import mongoose from \"mongoose\";\n\nimport type { MongoConfig } from \"../types/mongoConfig.types\";\n\nexport const connectMongoDb = async (config: MongoConfig) => {\n const { subDomain, userName, password, cluster, dbName } = config;\n // Primary +srv URL\n const srvURL = `mongodb+srv://${userName}:${password}@${cluster.toLowerCase()}.${subDomain}.mongodb.net/${dbName}?retryWrites=true&w=majority&appName=${cluster.toLowerCase()}`;\n // Fallback standard mongodb:// URL (you need to adjust hostnames from Atlas)\n const fallbackURL = `mongodb://${userName}:${password}@ac-hkntio7-shard-00-00.${subDomain}.mongodb.net:27017,ac-hkntio7-shard-00-01.${subDomain}.mongodb.net:27017,ac-hkntio7-shard-00-02.${subDomain}.mongodb.net:27017/${dbName}?ssl=true&replicaSet=atlas-cji6jk-shard-0&authSource=admin&appName=${cluster}`;\n try {\n console.log(\"Trying primary +srv connection...\");\n await mongoose.connect(srvURL);\n console.log(\"Connected to MongoDB Atlas via +srv URL\");\n return true;\n } catch (err: any) {\n console.warn(\"+srv connection failed:\", err.message);\n console.log(\"Trying fallback standard connection...\");\n try {\n await mongoose.connect(fallbackURL);\n console.log(\"Connected to MongoDB Atlas via fallback URL\");\n return true;\n } catch (fallbackErr: any) {\n console.error(\"Fallback connection failed:\", fallbackErr.message);\n return false;\n }\n }\n};","export default class ApiError extends Error {\n statusCode: number;\n isOperational: boolean;\n errors?: any;\n\n constructor(\n message: string,\n statusCode = 500,\n errors?: any,\n isOperational = true\n ) {\n super(message);\n\n this.statusCode = statusCode;\n this.errors = errors;\n this.isOperational = isOperational;\n\n Error.captureStackTrace(this, this.constructor);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class BadRequestError extends ApiError {\n constructor(message = \"Bad Request\", errors?: any) {\n super(message, 400, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class UnauthorizedError extends ApiError {\n constructor(message = \"Unauthorized\", errors?: any) {\n super(message, 401, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class ForbiddenError extends ApiError {\n constructor(message = \"Forbidden\", errors?: any) {\n super(message, 403, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class NotFoundError extends ApiError {\n constructor(message = \"Resource Not Found\", errors?: any) {\n super(message, 404, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class ValidationError extends ApiError {\n constructor(message = \"Validation Failed\", errors?: any) {\n super(message, 422, errors);\n }\n}","// errorHandler.ts\nimport { Request, Response, NextFunction } from \"express\";\nimport ApiError from \"../errors/ApiError\";\nimport { errorResponse } from \"../responses/errorResponse\";\n\nconst routeNotFoundHandler = (req: Request, _: Response, next: NextFunction) => {\n next(new ApiError(`Route ${req.originalUrl} not found`, 404));\n};\n\nconst globalErrorHandler = (err: any, req: Request, res: Response, next: NextFunction) => {\n console.error(\"Error:\", err);\n let statusCode = 500;\n let message = \"Internal Server Error\";\n let errors = undefined;\n let stack = undefined;\n\n if (err instanceof ApiError) {\n statusCode = err.statusCode;\n message = err.message;\n errors = err.errors;\n }\n\n if (process.env.NODE_ENV === \"development\") {\n stack = err.stack;\n }\n\n return res.status(statusCode).json(errorResponse(message, errors, stack));\n};\n\n// Export as a tuple with explicit types so spread works correctly\nconst errorHandler: [\n (req: Request, res: Response, next: NextFunction) => void,\n (err: any, req: Request, res: Response, next: NextFunction) => void\n] = [routeNotFoundHandler, globalErrorHandler];\n\nexport default errorHandler;","import NodeCache from \"node-cache\";\n\ntype CacheValue = unknown;\ntype ComputeFn<T> = () => Promise<T> | T;\n\nexport class Cache extends NodeCache {\n private namespaces: Set<string>;\n private tagMap: Map<string, Set<string>>;\n\n constructor(options: NodeCache.Options = {}) {\n const defaults: NodeCache.Options = {\n stdTTL: 60,\n checkperiod: 120,\n };\n\n super({ ...defaults, ...options });\n\n this.namespaces = new Set<string>();\n this.tagMap = new Map<string, Set<string>>();\n\n this.on(\"expired\", (key: string, value: unknown) => {\n console.log(`[Cache] Key expired: ${key} ->`, value);\n this.removeKeyFromTags(key);\n });\n }\n\n private getKey(key: string, namespace?: string): string {\n return namespace ? `${namespace}:${key}` : key;\n }\n\n private removeKeyFromTags(key: string): void {\n for (const [tag, keys] of this.tagMap.entries()) {\n if (keys.has(key)) {\n keys.delete(key);\n if (keys.size === 0) {\n this.tagMap.delete(tag);\n }\n }\n }\n }\n\n setItem(\n key: string,\n value: CacheValue,\n ttl: number =60,\n namespace?: string,\n tags: string[] = []\n ): void {\n const fullKey = this.getKey(key, namespace);\n\n if (namespace) {\n this.namespaces.add(namespace);\n }\n\n const storedValue =\n typeof value === \"string\" ? value : JSON.stringify(value);\n\n this.set(fullKey, storedValue, ttl);\n\n for (const tag of tags) {\n if (!this.tagMap.has(tag)) {\n this.tagMap.set(tag, new Set<string>());\n }\n this.tagMap.get(tag)!.add(fullKey);\n }\n }\n\n getItem<T = unknown>(key: string, namespace?: string): T | undefined {\n const fullKey = this.getKey(key, namespace);\n const value = this.get(fullKey);\n\n if (value === undefined) return undefined;\n\n try {\n return JSON.parse(value as string) as T;\n } catch {\n return value as T;\n }\n }\n\n async getOrSetItem<T>(\n key: string,\n computeFn: ComputeFn<T>,\n ttl?: number,\n namespace?: string,\n tags: string[] = []\n ): Promise<T> {\n let value = this.getItem<T>(key, namespace);\n\n if (value === undefined) {\n value = await computeFn();\n this.setItem(key, value, ttl, namespace, tags);\n }\n\n return value;\n }\n\n deleteItem(key: string, namespace?: string): number {\n const fullKey = this.getKey(key, namespace);\n this.removeKeyFromTags(fullKey);\n return this.del(fullKey);\n }\n\n clearNamespace(namespace?: string): void {\n if (!namespace) {\n this.flushAll();\n this.tagMap.clear();\n console.log(\"[Cache] All keys cleared\");\n return;\n }\n\n for (const key of this.keys()) {\n if (key.startsWith(`${namespace}:`)) {\n this.deleteItem(key);\n }\n }\n\n console.log(`[Cache] Namespace \"${namespace}\" cleared`);\n }\n\n /**\n * Delete all keys associated with a tag\n */\n clearTag(tag: string): void {\n const keys = this.tagMap.get(tag);\n if (!keys) return;\n\n for (const key of keys) {\n this.del(key);\n }\n\n this.tagMap.delete(tag);\n console.log(`[Cache] All keys with tag \"${tag}\" cleared`);\n }\n}\n","import { Cache } from \"./cache\";\n\nconst cacheMemory = new Cache();\n\nexport default cacheMemory;\n"],"mappings":"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","names":["mongoose","NodeCache"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/responses/successResponse.ts","../src/responses/errorResponse.ts","../src/utils/envManager.ts","../src/config/mongoConfig.ts","../src/errors/ApiError.ts","../src/errors/BadRequestError.ts","../src/errors/UnauthorisedError.ts","../src/errors/ForbiddenError.ts","../src/errors/NotFoundError.ts","../src/errors/ValidationError.ts","../src/handlers/errorHandler.ts","../src/utils/cache.ts","../src/utils/cacheMemory.ts","../src/utils/randomNum.ts","../src/utils/mailer.ts"],"sourcesContent":["export { successResponse } from \"./responses/successResponse\";\nexport { errorResponse } from \"./responses/errorResponse\";\nexport { requiredEnv } from \"./utils/envManager\";\nexport { connectMongoDb } from \"./config/mongoConfig\";\nexport { default as ApiError } from \"./errors/ApiError\";\nexport { default as BadRequestError } from \"./errors/BadRequestError\";\nexport { default as UnauthorizedError } from \"./errors/UnauthorisedError\";\nexport { default as ForbiddenError } from \"./errors/ForbiddenError\";\nexport { default as NotFoundError } from \"./errors/NotFoundError\";\nexport { default as ValidationError } from \"./errors/ValidationError\";\nexport { default as errorMiddleware } from \"./handlers/errorHandler\";\nexport { Cache } from \"./utils/cache\";\nexport { default as cacheMemory } from \"./utils/cacheMemory\";\nexport {default as random} from \"./utils/randomNum\";\nexport type { SuccessResponse, ErrorResponse } from \"./types/response.types\";\nexport { type MongoConfig } from \"./types/mongoConfig.types\";\nexport {type MailerConfig, EmailOptions} from \"./types/mailerConfig.types\";\nexport {default as Mailer} from \"./utils/mailer\";\n","import { SuccessResponse } from \"../types/response.types\";\n\nexport const successResponse = <T>(\n data: T,\n message?: string\n): SuccessResponse<T> => ({\n success: true,\n data,\n message,\n});","import { ErrorResponse } from \"../types/response.types\";\n\nexport const errorResponse = (\n message: string,\n errors?: any,\n stack?: string\n): ErrorResponse => ({\n success: false,\n message,\n errors,\n stack,\n});","export const requiredEnv = (value: string | undefined, key: string): string => {\n if (!value) {\n throw new Error(`Missing required environment variable: ${key}`);\n }\n return value;\n};","import mongoose from \"mongoose\";\n\nimport type { MongoConfig } from \"../types/mongoConfig.types\";\n\nexport const connectMongoDb = async (config: MongoConfig) => {\n const { subDomain, userName, password, cluster, dbName } = config;\n // Primary +srv URL\n const srvURL = `mongodb+srv://${userName}:${password}@${cluster.toLowerCase()}.${subDomain}.mongodb.net/${dbName}?retryWrites=true&w=majority&appName=${cluster.toLowerCase()}`;\n // Fallback standard mongodb:// URL (you need to adjust hostnames from Atlas)\n const fallbackURL = `mongodb://${userName}:${password}@ac-hkntio7-shard-00-00.${subDomain}.mongodb.net:27017,ac-hkntio7-shard-00-01.${subDomain}.mongodb.net:27017,ac-hkntio7-shard-00-02.${subDomain}.mongodb.net:27017/${dbName}?ssl=true&replicaSet=atlas-cji6jk-shard-0&authSource=admin&appName=${cluster}`;\n try {\n console.log(\"Trying primary +srv connection...\");\n await mongoose.connect(srvURL);\n console.log(\"Connected to MongoDB Atlas via +srv URL\");\n return true;\n } catch (err: any) {\n console.warn(\"+srv connection failed:\", err.message);\n console.log(\"Trying fallback standard connection...\");\n try {\n await mongoose.connect(fallbackURL);\n console.log(\"Connected to MongoDB Atlas via fallback URL\");\n return true;\n } catch (fallbackErr: any) {\n console.error(\"Fallback connection failed:\", fallbackErr.message);\n return false;\n }\n }\n};","export default class ApiError extends Error {\n statusCode: number;\n isOperational: boolean;\n errors?: any;\n\n constructor(\n message: string,\n statusCode = 500,\n errors?: any,\n isOperational = true\n ) {\n super(message);\n\n this.statusCode = statusCode;\n this.errors = errors;\n this.isOperational = isOperational;\n\n Error.captureStackTrace(this, this.constructor);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class BadRequestError extends ApiError {\n constructor(message = \"Bad Request\", errors?: any) {\n super(message, 400, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class UnauthorizedError extends ApiError {\n constructor(message = \"Unauthorized\", errors?: any) {\n super(message, 401, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class ForbiddenError extends ApiError {\n constructor(message = \"Forbidden\", errors?: any) {\n super(message, 403, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class NotFoundError extends ApiError {\n constructor(message = \"Resource Not Found\", errors?: any) {\n super(message, 404, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class ValidationError extends ApiError {\n constructor(message = \"Validation Failed\", errors?: any) {\n super(message, 422, errors);\n }\n}","// errorHandler.ts\nimport { Request, Response, NextFunction } from \"express\";\nimport ApiError from \"../errors/ApiError\";\nimport { errorResponse } from \"../responses/errorResponse\";\n\nconst routeNotFoundHandler = (req: Request, _: Response, next: NextFunction) => {\n next(new ApiError(`Route ${req.originalUrl} not found`, 404));\n};\n\nconst globalErrorHandler = (err: any, req: Request, res: Response, next: NextFunction) => {\n console.error(\"Error:\", err);\n let statusCode = 500;\n let message = \"Internal Server Error\";\n let errors = undefined;\n let stack = undefined;\n\n if (err instanceof ApiError) {\n statusCode = err.statusCode;\n message = err.message;\n errors = err.errors;\n }\n\n if (process.env.NODE_ENV === \"development\") {\n stack = err.stack;\n }\n\n return res.status(statusCode).json(errorResponse(message, errors, stack));\n};\n\n// Export as a tuple with explicit types so spread works correctly\nconst errorHandler: [\n (req: Request, res: Response, next: NextFunction) => void,\n (err: any, req: Request, res: Response, next: NextFunction) => void\n] = [routeNotFoundHandler, globalErrorHandler];\n\nexport default errorHandler;","import NodeCache from \"node-cache\";\n\ntype CacheValue = unknown;\ntype ComputeFn<T> = () => Promise<T> | T;\n\nexport class Cache extends NodeCache {\n private namespaces: Set<string>;\n private tagMap: Map<string, Set<string>>;\n\n constructor(options: NodeCache.Options = {}) {\n const defaults: NodeCache.Options = {\n stdTTL: 60,\n checkperiod: 120,\n };\n\n super({ ...defaults, ...options });\n\n this.namespaces = new Set<string>();\n this.tagMap = new Map<string, Set<string>>();\n\n this.on(\"expired\", (key: string, value: unknown) => {\n console.log(`[Cache] Key expired: ${key} ->`, value);\n this.removeKeyFromTags(key);\n });\n }\n\n private getKey(key: string, namespace?: string): string {\n return namespace ? `${namespace}:${key}` : key;\n }\n\n private removeKeyFromTags(key: string): void {\n for (const [tag, keys] of this.tagMap.entries()) {\n if (keys.has(key)) {\n keys.delete(key);\n if (keys.size === 0) {\n this.tagMap.delete(tag);\n }\n }\n }\n }\n\n setItem(\n key: string,\n value: CacheValue,\n ttl: number =60,\n namespace?: string,\n tags: string[] = []\n ): void {\n const fullKey = this.getKey(key, namespace);\n\n if (namespace) {\n this.namespaces.add(namespace);\n }\n\n const storedValue =\n typeof value === \"string\" ? value : JSON.stringify(value);\n\n this.set(fullKey, storedValue, ttl);\n\n for (const tag of tags) {\n if (!this.tagMap.has(tag)) {\n this.tagMap.set(tag, new Set<string>());\n }\n this.tagMap.get(tag)!.add(fullKey);\n }\n }\n\n getItem<T = unknown>(key: string, namespace?: string): T | undefined {\n const fullKey = this.getKey(key, namespace);\n const value = this.get(fullKey);\n\n if (value === undefined) return undefined;\n\n try {\n return JSON.parse(value as string) as T;\n } catch {\n return value as T;\n }\n }\n\n async getOrSetItem<T>(\n key: string,\n computeFn: ComputeFn<T>,\n ttl?: number,\n namespace?: string,\n tags: string[] = []\n ): Promise<T> {\n let value = this.getItem<T>(key, namespace);\n\n if (value === undefined) {\n value = await computeFn();\n this.setItem(key, value, ttl, namespace, tags);\n }\n\n return value;\n }\n\n deleteItem(key: string, namespace?: string): number {\n const fullKey = this.getKey(key, namespace);\n this.removeKeyFromTags(fullKey);\n return this.del(fullKey);\n }\n\n clearNamespace(namespace?: string): void {\n if (!namespace) {\n this.flushAll();\n this.tagMap.clear();\n console.log(\"[Cache] All keys cleared\");\n return;\n }\n\n for (const key of this.keys()) {\n if (key.startsWith(`${namespace}:`)) {\n this.deleteItem(key);\n }\n }\n\n console.log(`[Cache] Namespace \"${namespace}\" cleared`);\n }\n\n /**\n * Delete all keys associated with a tag\n */\n clearTag(tag: string): void {\n const keys = this.tagMap.get(tag);\n if (!keys) return;\n\n for (const key of keys) {\n this.del(key);\n }\n\n this.tagMap.delete(tag);\n console.log(`[Cache] All keys with tag \"${tag}\" cleared`);\n }\n}\n","import { Cache } from \"./cache\";\n\nconst cacheMemory = new Cache();\n\nexport default cacheMemory;\n","// src/utils/randomNum.ts\n\nimport crypto from \"crypto\";\n\n/**\n * Generates a random numeric string of given length.\n * Uses crypto for better randomness (production safe).\n *\n * @param digit - Length of the random number\n * @returns string\n */\nexport default function random(digit: number): string {\n if (!Number.isInteger(digit) || digit <= 0) {\n throw new Error(\"Digit must be a positive integer\");\n }\n\n const min = 10 ** (digit - 1);\n const max = 10 ** digit - 1;\n\n const randomNumber = crypto.randomInt(min, max + 1);\n\n return randomNumber.toString();\n}\n","import type { MailerConfig, EmailOptions } from \"../types/mailerConfig.types\";\n\nclass Mailer {\n // 1. In TS, you must explicitly declare class properties\n private config: MailerConfig;\n\n // 2. Use 'private' or 'readonly' to encapsulate the config data\n public constructor(mailerConfig: MailerConfig) {\n this.config = mailerConfig;\n }\n\n // 3. Defined the sendMail method with parameters and proper return type\n async sendMail(options: EmailOptions): Promise<boolean> {\n const { to, subject, body } = options;\n\n console.log(`Sending email via ${this.config.smtpProvider}...`);\n console.log(`From: \"${this.config.brandName}\" <${this.config.fromEmail}>`);\n console.log(`To: ${to}`);\n console.log(`Subject: ${subject}`);\n console.log(`Body: ${body}`);\n\n try {\n const response = await this.config.smtpProvider.emails.send({\n from: `${this.config.brandName} <${this.config.fromEmail}>`,\n to: [to],\n subject: subject,\n html: body, // or 'text: body' depending on your needs\n });\n\n console.log(\"SMTP Response:\", response);\n if (response.error) {\n console.error(\"SMTP API error:\", response.error);\n return false;\n }\n return true;\n } catch (error) {\n if (error instanceof Error) {\n console.error(\"SMTP error:\", error.message);\n } else {\n console.error(\"SMTP error:\", error);\n }\n return false;\n }\n }\n}\n\n\nexport default Mailer"],"mappings":"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","names":["mongoose","NodeCache","crypto"]}
|
package/dist/index.mjs
CHANGED
|
@@ -212,11 +212,64 @@ var Cache = class extends NodeCache {
|
|
|
212
212
|
// src/utils/cacheMemory.ts
|
|
213
213
|
var cacheMemory = new Cache();
|
|
214
214
|
var cacheMemory_default = cacheMemory;
|
|
215
|
+
|
|
216
|
+
// src/utils/randomNum.ts
|
|
217
|
+
import crypto from "crypto";
|
|
218
|
+
function random(digit) {
|
|
219
|
+
if (!Number.isInteger(digit) || digit <= 0) {
|
|
220
|
+
throw new Error("Digit must be a positive integer");
|
|
221
|
+
}
|
|
222
|
+
const min = 10 ** (digit - 1);
|
|
223
|
+
const max = 10 ** digit - 1;
|
|
224
|
+
const randomNumber = crypto.randomInt(min, max + 1);
|
|
225
|
+
return randomNumber.toString();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/utils/mailer.ts
|
|
229
|
+
var Mailer = class {
|
|
230
|
+
// 2. Use 'private' or 'readonly' to encapsulate the config data
|
|
231
|
+
constructor(mailerConfig) {
|
|
232
|
+
this.config = mailerConfig;
|
|
233
|
+
}
|
|
234
|
+
// 3. Defined the sendMail method with parameters and proper return type
|
|
235
|
+
async sendMail(options) {
|
|
236
|
+
const { to, subject, body } = options;
|
|
237
|
+
console.log(`Sending email via ${this.config.smtpProvider}...`);
|
|
238
|
+
console.log(`From: "${this.config.brandName}" <${this.config.fromEmail}>`);
|
|
239
|
+
console.log(`To: ${to}`);
|
|
240
|
+
console.log(`Subject: ${subject}`);
|
|
241
|
+
console.log(`Body: ${body}`);
|
|
242
|
+
try {
|
|
243
|
+
const response = await this.config.smtpProvider.emails.send({
|
|
244
|
+
from: `${this.config.brandName} <${this.config.fromEmail}>`,
|
|
245
|
+
to: [to],
|
|
246
|
+
subject,
|
|
247
|
+
html: body
|
|
248
|
+
// or 'text: body' depending on your needs
|
|
249
|
+
});
|
|
250
|
+
console.log("SMTP Response:", response);
|
|
251
|
+
if (response.error) {
|
|
252
|
+
console.error("SMTP API error:", response.error);
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
return true;
|
|
256
|
+
} catch (error) {
|
|
257
|
+
if (error instanceof Error) {
|
|
258
|
+
console.error("SMTP error:", error.message);
|
|
259
|
+
} else {
|
|
260
|
+
console.error("SMTP error:", error);
|
|
261
|
+
}
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
var mailer_default = Mailer;
|
|
215
267
|
export {
|
|
216
268
|
ApiError,
|
|
217
269
|
BadRequestError,
|
|
218
270
|
Cache,
|
|
219
271
|
ForbiddenError,
|
|
272
|
+
mailer_default as Mailer,
|
|
220
273
|
NotFoundError,
|
|
221
274
|
UnauthorizedError,
|
|
222
275
|
ValidationError,
|
|
@@ -224,6 +277,7 @@ export {
|
|
|
224
277
|
connectMongoDb,
|
|
225
278
|
errorHandler_default as errorMiddleware,
|
|
226
279
|
errorResponse,
|
|
280
|
+
random,
|
|
227
281
|
requiredEnv,
|
|
228
282
|
successResponse
|
|
229
283
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/responses/successResponse.ts","../src/responses/errorResponse.ts","../src/utils/envManager.ts","../src/config/mongoConfig.ts","../src/errors/ApiError.ts","../src/errors/BadRequestError.ts","../src/errors/UnauthorisedError.ts","../src/errors/ForbiddenError.ts","../src/errors/NotFoundError.ts","../src/errors/ValidationError.ts","../src/handlers/errorHandler.ts","../src/utils/cache.ts","../src/utils/cacheMemory.ts"],"sourcesContent":["import { SuccessResponse } from \"../types/response.types\";\n\nexport const successResponse = <T>(\n data: T,\n message?: string\n): SuccessResponse<T> => ({\n success: true,\n data,\n message,\n});","import { ErrorResponse } from \"../types/response.types\";\n\nexport const errorResponse = (\n message: string,\n errors?: any,\n stack?: string\n): ErrorResponse => ({\n success: false,\n message,\n errors,\n stack,\n});","export const requiredEnv = (value: string | undefined, key: string): string => {\n if (!value) {\n throw new Error(`Missing required environment variable: ${key}`);\n }\n return value;\n};","import mongoose from \"mongoose\";\n\nimport type { MongoConfig } from \"../types/mongoConfig.types\";\n\nexport const connectMongoDb = async (config: MongoConfig) => {\n const { subDomain, userName, password, cluster, dbName } = config;\n // Primary +srv URL\n const srvURL = `mongodb+srv://${userName}:${password}@${cluster.toLowerCase()}.${subDomain}.mongodb.net/${dbName}?retryWrites=true&w=majority&appName=${cluster.toLowerCase()}`;\n // Fallback standard mongodb:// URL (you need to adjust hostnames from Atlas)\n const fallbackURL = `mongodb://${userName}:${password}@ac-hkntio7-shard-00-00.${subDomain}.mongodb.net:27017,ac-hkntio7-shard-00-01.${subDomain}.mongodb.net:27017,ac-hkntio7-shard-00-02.${subDomain}.mongodb.net:27017/${dbName}?ssl=true&replicaSet=atlas-cji6jk-shard-0&authSource=admin&appName=${cluster}`;\n try {\n console.log(\"Trying primary +srv connection...\");\n await mongoose.connect(srvURL);\n console.log(\"Connected to MongoDB Atlas via +srv URL\");\n return true;\n } catch (err: any) {\n console.warn(\"+srv connection failed:\", err.message);\n console.log(\"Trying fallback standard connection...\");\n try {\n await mongoose.connect(fallbackURL);\n console.log(\"Connected to MongoDB Atlas via fallback URL\");\n return true;\n } catch (fallbackErr: any) {\n console.error(\"Fallback connection failed:\", fallbackErr.message);\n return false;\n }\n }\n};","export default class ApiError extends Error {\n statusCode: number;\n isOperational: boolean;\n errors?: any;\n\n constructor(\n message: string,\n statusCode = 500,\n errors?: any,\n isOperational = true\n ) {\n super(message);\n\n this.statusCode = statusCode;\n this.errors = errors;\n this.isOperational = isOperational;\n\n Error.captureStackTrace(this, this.constructor);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class BadRequestError extends ApiError {\n constructor(message = \"Bad Request\", errors?: any) {\n super(message, 400, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class UnauthorizedError extends ApiError {\n constructor(message = \"Unauthorized\", errors?: any) {\n super(message, 401, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class ForbiddenError extends ApiError {\n constructor(message = \"Forbidden\", errors?: any) {\n super(message, 403, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class NotFoundError extends ApiError {\n constructor(message = \"Resource Not Found\", errors?: any) {\n super(message, 404, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class ValidationError extends ApiError {\n constructor(message = \"Validation Failed\", errors?: any) {\n super(message, 422, errors);\n }\n}","// errorHandler.ts\nimport { Request, Response, NextFunction } from \"express\";\nimport ApiError from \"../errors/ApiError\";\nimport { errorResponse } from \"../responses/errorResponse\";\n\nconst routeNotFoundHandler = (req: Request, _: Response, next: NextFunction) => {\n next(new ApiError(`Route ${req.originalUrl} not found`, 404));\n};\n\nconst globalErrorHandler = (err: any, req: Request, res: Response, next: NextFunction) => {\n console.error(\"Error:\", err);\n let statusCode = 500;\n let message = \"Internal Server Error\";\n let errors = undefined;\n let stack = undefined;\n\n if (err instanceof ApiError) {\n statusCode = err.statusCode;\n message = err.message;\n errors = err.errors;\n }\n\n if (process.env.NODE_ENV === \"development\") {\n stack = err.stack;\n }\n\n return res.status(statusCode).json(errorResponse(message, errors, stack));\n};\n\n// Export as a tuple with explicit types so spread works correctly\nconst errorHandler: [\n (req: Request, res: Response, next: NextFunction) => void,\n (err: any, req: Request, res: Response, next: NextFunction) => void\n] = [routeNotFoundHandler, globalErrorHandler];\n\nexport default errorHandler;","import NodeCache from \"node-cache\";\n\ntype CacheValue = unknown;\ntype ComputeFn<T> = () => Promise<T> | T;\n\nexport class Cache extends NodeCache {\n private namespaces: Set<string>;\n private tagMap: Map<string, Set<string>>;\n\n constructor(options: NodeCache.Options = {}) {\n const defaults: NodeCache.Options = {\n stdTTL: 60,\n checkperiod: 120,\n };\n\n super({ ...defaults, ...options });\n\n this.namespaces = new Set<string>();\n this.tagMap = new Map<string, Set<string>>();\n\n this.on(\"expired\", (key: string, value: unknown) => {\n console.log(`[Cache] Key expired: ${key} ->`, value);\n this.removeKeyFromTags(key);\n });\n }\n\n private getKey(key: string, namespace?: string): string {\n return namespace ? `${namespace}:${key}` : key;\n }\n\n private removeKeyFromTags(key: string): void {\n for (const [tag, keys] of this.tagMap.entries()) {\n if (keys.has(key)) {\n keys.delete(key);\n if (keys.size === 0) {\n this.tagMap.delete(tag);\n }\n }\n }\n }\n\n setItem(\n key: string,\n value: CacheValue,\n ttl: number =60,\n namespace?: string,\n tags: string[] = []\n ): void {\n const fullKey = this.getKey(key, namespace);\n\n if (namespace) {\n this.namespaces.add(namespace);\n }\n\n const storedValue =\n typeof value === \"string\" ? value : JSON.stringify(value);\n\n this.set(fullKey, storedValue, ttl);\n\n for (const tag of tags) {\n if (!this.tagMap.has(tag)) {\n this.tagMap.set(tag, new Set<string>());\n }\n this.tagMap.get(tag)!.add(fullKey);\n }\n }\n\n getItem<T = unknown>(key: string, namespace?: string): T | undefined {\n const fullKey = this.getKey(key, namespace);\n const value = this.get(fullKey);\n\n if (value === undefined) return undefined;\n\n try {\n return JSON.parse(value as string) as T;\n } catch {\n return value as T;\n }\n }\n\n async getOrSetItem<T>(\n key: string,\n computeFn: ComputeFn<T>,\n ttl?: number,\n namespace?: string,\n tags: string[] = []\n ): Promise<T> {\n let value = this.getItem<T>(key, namespace);\n\n if (value === undefined) {\n value = await computeFn();\n this.setItem(key, value, ttl, namespace, tags);\n }\n\n return value;\n }\n\n deleteItem(key: string, namespace?: string): number {\n const fullKey = this.getKey(key, namespace);\n this.removeKeyFromTags(fullKey);\n return this.del(fullKey);\n }\n\n clearNamespace(namespace?: string): void {\n if (!namespace) {\n this.flushAll();\n this.tagMap.clear();\n console.log(\"[Cache] All keys cleared\");\n return;\n }\n\n for (const key of this.keys()) {\n if (key.startsWith(`${namespace}:`)) {\n this.deleteItem(key);\n }\n }\n\n console.log(`[Cache] Namespace \"${namespace}\" cleared`);\n }\n\n /**\n * Delete all keys associated with a tag\n */\n clearTag(tag: string): void {\n const keys = this.tagMap.get(tag);\n if (!keys) return;\n\n for (const key of keys) {\n this.del(key);\n }\n\n this.tagMap.delete(tag);\n console.log(`[Cache] All keys with tag \"${tag}\" cleared`);\n }\n}\n","import { Cache } from \"./cache\";\n\nconst cacheMemory = new Cache();\n\nexport default cacheMemory;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/responses/successResponse.ts","../src/responses/errorResponse.ts","../src/utils/envManager.ts","../src/config/mongoConfig.ts","../src/errors/ApiError.ts","../src/errors/BadRequestError.ts","../src/errors/UnauthorisedError.ts","../src/errors/ForbiddenError.ts","../src/errors/NotFoundError.ts","../src/errors/ValidationError.ts","../src/handlers/errorHandler.ts","../src/utils/cache.ts","../src/utils/cacheMemory.ts","../src/utils/randomNum.ts","../src/utils/mailer.ts"],"sourcesContent":["import { SuccessResponse } from \"../types/response.types\";\n\nexport const successResponse = <T>(\n data: T,\n message?: string\n): SuccessResponse<T> => ({\n success: true,\n data,\n message,\n});","import { ErrorResponse } from \"../types/response.types\";\n\nexport const errorResponse = (\n message: string,\n errors?: any,\n stack?: string\n): ErrorResponse => ({\n success: false,\n message,\n errors,\n stack,\n});","export const requiredEnv = (value: string | undefined, key: string): string => {\n if (!value) {\n throw new Error(`Missing required environment variable: ${key}`);\n }\n return value;\n};","import mongoose from \"mongoose\";\n\nimport type { MongoConfig } from \"../types/mongoConfig.types\";\n\nexport const connectMongoDb = async (config: MongoConfig) => {\n const { subDomain, userName, password, cluster, dbName } = config;\n // Primary +srv URL\n const srvURL = `mongodb+srv://${userName}:${password}@${cluster.toLowerCase()}.${subDomain}.mongodb.net/${dbName}?retryWrites=true&w=majority&appName=${cluster.toLowerCase()}`;\n // Fallback standard mongodb:// URL (you need to adjust hostnames from Atlas)\n const fallbackURL = `mongodb://${userName}:${password}@ac-hkntio7-shard-00-00.${subDomain}.mongodb.net:27017,ac-hkntio7-shard-00-01.${subDomain}.mongodb.net:27017,ac-hkntio7-shard-00-02.${subDomain}.mongodb.net:27017/${dbName}?ssl=true&replicaSet=atlas-cji6jk-shard-0&authSource=admin&appName=${cluster}`;\n try {\n console.log(\"Trying primary +srv connection...\");\n await mongoose.connect(srvURL);\n console.log(\"Connected to MongoDB Atlas via +srv URL\");\n return true;\n } catch (err: any) {\n console.warn(\"+srv connection failed:\", err.message);\n console.log(\"Trying fallback standard connection...\");\n try {\n await mongoose.connect(fallbackURL);\n console.log(\"Connected to MongoDB Atlas via fallback URL\");\n return true;\n } catch (fallbackErr: any) {\n console.error(\"Fallback connection failed:\", fallbackErr.message);\n return false;\n }\n }\n};","export default class ApiError extends Error {\n statusCode: number;\n isOperational: boolean;\n errors?: any;\n\n constructor(\n message: string,\n statusCode = 500,\n errors?: any,\n isOperational = true\n ) {\n super(message);\n\n this.statusCode = statusCode;\n this.errors = errors;\n this.isOperational = isOperational;\n\n Error.captureStackTrace(this, this.constructor);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class BadRequestError extends ApiError {\n constructor(message = \"Bad Request\", errors?: any) {\n super(message, 400, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class UnauthorizedError extends ApiError {\n constructor(message = \"Unauthorized\", errors?: any) {\n super(message, 401, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class ForbiddenError extends ApiError {\n constructor(message = \"Forbidden\", errors?: any) {\n super(message, 403, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class NotFoundError extends ApiError {\n constructor(message = \"Resource Not Found\", errors?: any) {\n super(message, 404, errors);\n }\n}","import ApiError from \"./ApiError\";\n\nexport default class ValidationError extends ApiError {\n constructor(message = \"Validation Failed\", errors?: any) {\n super(message, 422, errors);\n }\n}","// errorHandler.ts\nimport { Request, Response, NextFunction } from \"express\";\nimport ApiError from \"../errors/ApiError\";\nimport { errorResponse } from \"../responses/errorResponse\";\n\nconst routeNotFoundHandler = (req: Request, _: Response, next: NextFunction) => {\n next(new ApiError(`Route ${req.originalUrl} not found`, 404));\n};\n\nconst globalErrorHandler = (err: any, req: Request, res: Response, next: NextFunction) => {\n console.error(\"Error:\", err);\n let statusCode = 500;\n let message = \"Internal Server Error\";\n let errors = undefined;\n let stack = undefined;\n\n if (err instanceof ApiError) {\n statusCode = err.statusCode;\n message = err.message;\n errors = err.errors;\n }\n\n if (process.env.NODE_ENV === \"development\") {\n stack = err.stack;\n }\n\n return res.status(statusCode).json(errorResponse(message, errors, stack));\n};\n\n// Export as a tuple with explicit types so spread works correctly\nconst errorHandler: [\n (req: Request, res: Response, next: NextFunction) => void,\n (err: any, req: Request, res: Response, next: NextFunction) => void\n] = [routeNotFoundHandler, globalErrorHandler];\n\nexport default errorHandler;","import NodeCache from \"node-cache\";\n\ntype CacheValue = unknown;\ntype ComputeFn<T> = () => Promise<T> | T;\n\nexport class Cache extends NodeCache {\n private namespaces: Set<string>;\n private tagMap: Map<string, Set<string>>;\n\n constructor(options: NodeCache.Options = {}) {\n const defaults: NodeCache.Options = {\n stdTTL: 60,\n checkperiod: 120,\n };\n\n super({ ...defaults, ...options });\n\n this.namespaces = new Set<string>();\n this.tagMap = new Map<string, Set<string>>();\n\n this.on(\"expired\", (key: string, value: unknown) => {\n console.log(`[Cache] Key expired: ${key} ->`, value);\n this.removeKeyFromTags(key);\n });\n }\n\n private getKey(key: string, namespace?: string): string {\n return namespace ? `${namespace}:${key}` : key;\n }\n\n private removeKeyFromTags(key: string): void {\n for (const [tag, keys] of this.tagMap.entries()) {\n if (keys.has(key)) {\n keys.delete(key);\n if (keys.size === 0) {\n this.tagMap.delete(tag);\n }\n }\n }\n }\n\n setItem(\n key: string,\n value: CacheValue,\n ttl: number =60,\n namespace?: string,\n tags: string[] = []\n ): void {\n const fullKey = this.getKey(key, namespace);\n\n if (namespace) {\n this.namespaces.add(namespace);\n }\n\n const storedValue =\n typeof value === \"string\" ? value : JSON.stringify(value);\n\n this.set(fullKey, storedValue, ttl);\n\n for (const tag of tags) {\n if (!this.tagMap.has(tag)) {\n this.tagMap.set(tag, new Set<string>());\n }\n this.tagMap.get(tag)!.add(fullKey);\n }\n }\n\n getItem<T = unknown>(key: string, namespace?: string): T | undefined {\n const fullKey = this.getKey(key, namespace);\n const value = this.get(fullKey);\n\n if (value === undefined) return undefined;\n\n try {\n return JSON.parse(value as string) as T;\n } catch {\n return value as T;\n }\n }\n\n async getOrSetItem<T>(\n key: string,\n computeFn: ComputeFn<T>,\n ttl?: number,\n namespace?: string,\n tags: string[] = []\n ): Promise<T> {\n let value = this.getItem<T>(key, namespace);\n\n if (value === undefined) {\n value = await computeFn();\n this.setItem(key, value, ttl, namespace, tags);\n }\n\n return value;\n }\n\n deleteItem(key: string, namespace?: string): number {\n const fullKey = this.getKey(key, namespace);\n this.removeKeyFromTags(fullKey);\n return this.del(fullKey);\n }\n\n clearNamespace(namespace?: string): void {\n if (!namespace) {\n this.flushAll();\n this.tagMap.clear();\n console.log(\"[Cache] All keys cleared\");\n return;\n }\n\n for (const key of this.keys()) {\n if (key.startsWith(`${namespace}:`)) {\n this.deleteItem(key);\n }\n }\n\n console.log(`[Cache] Namespace \"${namespace}\" cleared`);\n }\n\n /**\n * Delete all keys associated with a tag\n */\n clearTag(tag: string): void {\n const keys = this.tagMap.get(tag);\n if (!keys) return;\n\n for (const key of keys) {\n this.del(key);\n }\n\n this.tagMap.delete(tag);\n console.log(`[Cache] All keys with tag \"${tag}\" cleared`);\n }\n}\n","import { Cache } from \"./cache\";\n\nconst cacheMemory = new Cache();\n\nexport default cacheMemory;\n","// src/utils/randomNum.ts\n\nimport crypto from \"crypto\";\n\n/**\n * Generates a random numeric string of given length.\n * Uses crypto for better randomness (production safe).\n *\n * @param digit - Length of the random number\n * @returns string\n */\nexport default function random(digit: number): string {\n if (!Number.isInteger(digit) || digit <= 0) {\n throw new Error(\"Digit must be a positive integer\");\n }\n\n const min = 10 ** (digit - 1);\n const max = 10 ** digit - 1;\n\n const randomNumber = crypto.randomInt(min, max + 1);\n\n return randomNumber.toString();\n}\n","import type { MailerConfig, EmailOptions } from \"../types/mailerConfig.types\";\n\nclass Mailer {\n // 1. In TS, you must explicitly declare class properties\n private config: MailerConfig;\n\n // 2. Use 'private' or 'readonly' to encapsulate the config data\n public constructor(mailerConfig: MailerConfig) {\n this.config = mailerConfig;\n }\n\n // 3. Defined the sendMail method with parameters and proper return type\n async sendMail(options: EmailOptions): Promise<boolean> {\n const { to, subject, body } = options;\n\n console.log(`Sending email via ${this.config.smtpProvider}...`);\n console.log(`From: \"${this.config.brandName}\" <${this.config.fromEmail}>`);\n console.log(`To: ${to}`);\n console.log(`Subject: ${subject}`);\n console.log(`Body: ${body}`);\n\n try {\n const response = await this.config.smtpProvider.emails.send({\n from: `${this.config.brandName} <${this.config.fromEmail}>`,\n to: [to],\n subject: subject,\n html: body, // or 'text: body' depending on your needs\n });\n\n console.log(\"SMTP Response:\", response);\n if (response.error) {\n console.error(\"SMTP API error:\", response.error);\n return false;\n }\n return true;\n } catch (error) {\n if (error instanceof Error) {\n console.error(\"SMTP error:\", error.message);\n } else {\n console.error(\"SMTP error:\", error);\n }\n return false;\n }\n }\n}\n\n\nexport default Mailer"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-backend",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Backend utility library for Express.js",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"mongoose": "^9.6.2",
|
|
21
21
|
"morgan": "^1.10.1",
|
|
22
22
|
"socket.io": "^4.8.3",
|
|
23
|
+
"resend": "^6.12.3",
|
|
23
24
|
"node-cache": "5.1.2"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|