3a-ecommerce-utils 1.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.
Files changed (45) hide show
  1. package/README.md +163 -0
  2. package/dist/chunk-PEAZVBSD.mjs +597 -0
  3. package/dist/client-DYGi_pyp.d.mts +87 -0
  4. package/dist/client-DYGi_pyp.d.ts +87 -0
  5. package/dist/index.d.mts +496 -0
  6. package/dist/index.d.ts +496 -0
  7. package/dist/index.js +17707 -0
  8. package/dist/index.mjs +17043 -0
  9. package/dist/validation/server.d.mts +50 -0
  10. package/dist/validation/server.d.ts +50 -0
  11. package/dist/validation/server.js +518 -0
  12. package/dist/validation/server.mjs +168 -0
  13. package/package.json +69 -0
  14. package/src/api/address.queries.ts +96 -0
  15. package/src/api/category.queries.ts +85 -0
  16. package/src/api/coupon.queries.ts +120 -0
  17. package/src/api/dashboard.queries.ts +35 -0
  18. package/src/api/errorHandler.ts +164 -0
  19. package/src/api/graphqlClient.ts +113 -0
  20. package/src/api/index.ts +10 -0
  21. package/src/api/logger.client.ts +89 -0
  22. package/src/api/logger.ts +135 -0
  23. package/src/api/order.queries.ts +211 -0
  24. package/src/api/product.queries.ts +144 -0
  25. package/src/api/review.queries.ts +56 -0
  26. package/src/api/user.queries.ts +232 -0
  27. package/src/assets/3A.png +0 -0
  28. package/src/assets/index.ts +1 -0
  29. package/src/assets.d.ts +29 -0
  30. package/src/auth.ts +176 -0
  31. package/src/config/jest.backend.config.js +42 -0
  32. package/src/config/jest.frontend.config.js +50 -0
  33. package/src/config/postcss.config.js +6 -0
  34. package/src/config/tailwind.config.ts +70 -0
  35. package/src/config/tsconfig.base.json +36 -0
  36. package/src/config/vite.config.ts +86 -0
  37. package/src/config/vitest.base.config.ts +74 -0
  38. package/src/config/webpack.base.config.ts +126 -0
  39. package/src/constants/index.ts +312 -0
  40. package/src/cookies.ts +104 -0
  41. package/src/helpers.ts +400 -0
  42. package/src/index.ts +32 -0
  43. package/src/validation/client.ts +287 -0
  44. package/src/validation/index.ts +3 -0
  45. package/src/validation/server.ts +32 -0
@@ -0,0 +1,50 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ export { y as batchValidate, h as isValidCouponCode, i as isValidEmail, p as isValidObjectId, a as isValidPassword, d as isValidPhone, f as isValidPostalCode, t as isValidSku, r as isValidUrl, j as validateCouponCode, w as validateDate, x as validateDateRange, n as validateDiscountPercentage, v as validateEmail, c as validateName, q as validateObjectId, o as validatePagination, b as validatePassword, e as validatePhone, g as validatePostalCode, k as validatePrice, l as validateQuantity, m as validateRating, u as validateSku, s as validateUrl } from '../client-DYGi_pyp.mjs';
3
+ import { LogLevel } from '@e-commerce/types';
4
+
5
+ /**
6
+ * Server-side Logger with file system support
7
+ * For frontend apps, use logger.client.ts instead
8
+ */
9
+
10
+ interface LogEntry {
11
+ level: LogLevel;
12
+ message: string;
13
+ timestamp: string;
14
+ data?: any;
15
+ context?: string;
16
+ }
17
+ declare class Logger {
18
+ private static logs;
19
+ private static maxLogs;
20
+ private static enableConsole;
21
+ private static enableFile;
22
+ private static logFilePath;
23
+ private static logLevel;
24
+ static configure(options: {
25
+ maxLogs?: number;
26
+ enableConsole?: boolean;
27
+ enableFile?: boolean;
28
+ logFilePath?: string;
29
+ logLevel?: LogLevel | string;
30
+ }): void;
31
+ private static shouldLog;
32
+ private static addLog;
33
+ private static format;
34
+ static debug(message: string, data?: any, context?: string): void;
35
+ static info(message: string, data?: any, context?: string): void;
36
+ static warn(message: string, data?: any, context?: string): void;
37
+ static error(message: string, error?: any, context?: string): void;
38
+ private static log;
39
+ static getLogs(level?: LogLevel): LogEntry[];
40
+ static clearLogs(): void;
41
+ }
42
+
43
+ /**
44
+ * Server-side only validation utilities
45
+ * These require Express and should only be used in backend services
46
+ */
47
+
48
+ declare const validate: (req: Request, res: Response, next: NextFunction) => void;
49
+
50
+ export { Logger, validate };
@@ -0,0 +1,50 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ export { y as batchValidate, h as isValidCouponCode, i as isValidEmail, p as isValidObjectId, a as isValidPassword, d as isValidPhone, f as isValidPostalCode, t as isValidSku, r as isValidUrl, j as validateCouponCode, w as validateDate, x as validateDateRange, n as validateDiscountPercentage, v as validateEmail, c as validateName, q as validateObjectId, o as validatePagination, b as validatePassword, e as validatePhone, g as validatePostalCode, k as validatePrice, l as validateQuantity, m as validateRating, u as validateSku, s as validateUrl } from '../client-DYGi_pyp.js';
3
+ import { LogLevel } from '@e-commerce/types';
4
+
5
+ /**
6
+ * Server-side Logger with file system support
7
+ * For frontend apps, use logger.client.ts instead
8
+ */
9
+
10
+ interface LogEntry {
11
+ level: LogLevel;
12
+ message: string;
13
+ timestamp: string;
14
+ data?: any;
15
+ context?: string;
16
+ }
17
+ declare class Logger {
18
+ private static logs;
19
+ private static maxLogs;
20
+ private static enableConsole;
21
+ private static enableFile;
22
+ private static logFilePath;
23
+ private static logLevel;
24
+ static configure(options: {
25
+ maxLogs?: number;
26
+ enableConsole?: boolean;
27
+ enableFile?: boolean;
28
+ logFilePath?: string;
29
+ logLevel?: LogLevel | string;
30
+ }): void;
31
+ private static shouldLog;
32
+ private static addLog;
33
+ private static format;
34
+ static debug(message: string, data?: any, context?: string): void;
35
+ static info(message: string, data?: any, context?: string): void;
36
+ static warn(message: string, data?: any, context?: string): void;
37
+ static error(message: string, error?: any, context?: string): void;
38
+ private static log;
39
+ static getLogs(level?: LogLevel): LogEntry[];
40
+ static clearLogs(): void;
41
+ }
42
+
43
+ /**
44
+ * Server-side only validation utilities
45
+ * These require Express and should only be used in backend services
46
+ */
47
+
48
+ declare const validate: (req: Request, res: Response, next: NextFunction) => void;
49
+
50
+ export { Logger, validate };
@@ -0,0 +1,518 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/validation/server.ts
31
+ var server_exports = {};
32
+ __export(server_exports, {
33
+ Logger: () => Logger,
34
+ batchValidate: () => batchValidate,
35
+ isValidCouponCode: () => isValidCouponCode,
36
+ isValidEmail: () => isValidEmail,
37
+ isValidObjectId: () => isValidObjectId,
38
+ isValidPassword: () => isValidPassword,
39
+ isValidPhone: () => isValidPhone,
40
+ isValidPostalCode: () => isValidPostalCode,
41
+ isValidSku: () => isValidSku,
42
+ isValidUrl: () => isValidUrl,
43
+ validate: () => validate,
44
+ validateCouponCode: () => validateCouponCode,
45
+ validateDate: () => validateDate,
46
+ validateDateRange: () => validateDateRange,
47
+ validateDiscountPercentage: () => validateDiscountPercentage,
48
+ validateEmail: () => validateEmail,
49
+ validateName: () => validateName,
50
+ validateObjectId: () => validateObjectId,
51
+ validatePagination: () => validatePagination,
52
+ validatePassword: () => validatePassword,
53
+ validatePhone: () => validatePhone,
54
+ validatePostalCode: () => validatePostalCode,
55
+ validatePrice: () => validatePrice,
56
+ validateQuantity: () => validateQuantity,
57
+ validateRating: () => validateRating,
58
+ validateSku: () => validateSku,
59
+ validateUrl: () => validateUrl
60
+ });
61
+ module.exports = __toCommonJS(server_exports);
62
+ var import_express_validator = require("express-validator");
63
+
64
+ // src/constants/index.ts
65
+ var PORT_CONFIG = {
66
+ AUTH_SERVICE: 3011,
67
+ CATEGORY_SERVICE: 3012,
68
+ COUPON_SERVICE: 3013,
69
+ PRODUCT_SERVICE: 3014,
70
+ ORDER_SERVICE: 3015,
71
+ GRAPHQL_GATEWAY: 4e3,
72
+ STOREFRONT_APP: 3e3,
73
+ ADMIN_APP: 3001,
74
+ SELLER_APP: 3002,
75
+ SHELL_APP: 3003
76
+ };
77
+ var SERVICE_URLS = {
78
+ AUTH_SERVICE: `http://localhost:${PORT_CONFIG.AUTH_SERVICE}`,
79
+ CATEGORY_SERVICE: `http://localhost:${PORT_CONFIG.CATEGORY_SERVICE}`,
80
+ COUPON_SERVICE: `http://localhost:${PORT_CONFIG.COUPON_SERVICE}`,
81
+ PRODUCT_SERVICE: `http://localhost:${PORT_CONFIG.PRODUCT_SERVICE}`,
82
+ ORDER_SERVICE: `http://localhost:${PORT_CONFIG.ORDER_SERVICE}`,
83
+ GRAPHQL_GATEWAY: `http://localhost:${PORT_CONFIG.GRAPHQL_GATEWAY}/graphql`,
84
+ AUTH_API: `http://localhost:${PORT_CONFIG.AUTH_SERVICE}/api`,
85
+ CATEGORY_API: `http://localhost:${PORT_CONFIG.CATEGORY_SERVICE}/api`,
86
+ COUPON_API: `http://localhost:${PORT_CONFIG.COUPON_SERVICE}/api`,
87
+ PRODUCT_API: `http://localhost:${PORT_CONFIG.PRODUCT_SERVICE}/api`,
88
+ ORDER_API: `http://localhost:${PORT_CONFIG.ORDER_SERVICE}/api`
89
+ };
90
+ var DEFAULT_CORS_ORIGINS = [
91
+ "http://localhost:3000",
92
+ "http://localhost:3001",
93
+ "http://localhost:3002",
94
+ "http://localhost:3003"
95
+ ];
96
+ var JWT_CONFIG = {
97
+ ACCESS_TOKEN_EXPIRY: "1h",
98
+ REFRESH_TOKEN_EXPIRY: "7d",
99
+ PASSWORD_MIN_LENGTH: 8,
100
+ PASSWORD_PATTERN: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
101
+ };
102
+ var PRODUCT_CONFIG = {
103
+ MIN_PRICE: 0,
104
+ MAX_PRICE: 999999.99,
105
+ MIN_STOCK: 0,
106
+ MAX_RATING: 5,
107
+ MIN_RATING: 0,
108
+ DEFAULT_RATING: 0,
109
+ MAX_IMAGE_SIZE: 5 * 1024 * 1024,
110
+ // 5MB
111
+ ALLOWED_IMAGE_TYPES: ["image/jpeg", "image/png", "image/webp"]
112
+ };
113
+ var TIMEOUT_CONFIG = {
114
+ API_REQUEST: 3e4,
115
+ // 30 seconds
116
+ DATABASE: 1e4,
117
+ // 10 seconds
118
+ GRAPHQL: 15e3
119
+ // 15 seconds
120
+ };
121
+ var REGEX_PATTERNS = {
122
+ EMAIL: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
123
+ PHONE: /^[\d\-\s()]{10,}$/,
124
+ POSTAL_CODE: /^\d{5,6}$/,
125
+ COUPON_CODE: /^[A-Z0-9]{6,20}$/,
126
+ PRODUCT_SKU: /^[A-Z0-9\-]{3,20}$/,
127
+ URL: /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w.-]*)*\/?$/
128
+ };
129
+ var ENV_PRESETS = {
130
+ DEVELOPMENT: {
131
+ corsOrigins: DEFAULT_CORS_ORIGINS,
132
+ logLevel: "debug",
133
+ apiTimeout: TIMEOUT_CONFIG.API_REQUEST
134
+ },
135
+ PRODUCTION: {
136
+ corsOrigins: ["https://ecommerce.example.com", "https://admin.ecommerce.example.com"],
137
+ logLevel: "info",
138
+ apiTimeout: TIMEOUT_CONFIG.API_REQUEST
139
+ },
140
+ TESTING: {
141
+ corsOrigins: ["http://localhost:*"],
142
+ logLevel: "error",
143
+ apiTimeout: TIMEOUT_CONFIG.API_REQUEST
144
+ }
145
+ };
146
+
147
+ // src/validation/client.ts
148
+ var isValidEmail = (email) => {
149
+ return REGEX_PATTERNS.EMAIL.test(email);
150
+ };
151
+ var validateEmail = (email) => {
152
+ if (!email || email.trim() === "") {
153
+ return { valid: false, error: "Email is required" };
154
+ }
155
+ if (!isValidEmail(email)) {
156
+ return { valid: false, error: "Invalid email format" };
157
+ }
158
+ if (email.length > 255) {
159
+ return { valid: false, error: "Email is too long" };
160
+ }
161
+ return { valid: true };
162
+ };
163
+ var isValidPassword = (password) => {
164
+ return JWT_CONFIG.PASSWORD_PATTERN.test(password);
165
+ };
166
+ var validatePassword = (password) => {
167
+ if (!password) {
168
+ return { valid: false, error: "Password is required" };
169
+ }
170
+ if (password.length < JWT_CONFIG.PASSWORD_MIN_LENGTH) {
171
+ return {
172
+ valid: false,
173
+ error: `Password must be at least ${JWT_CONFIG.PASSWORD_MIN_LENGTH} characters`
174
+ };
175
+ }
176
+ if (!isValidPassword(password)) {
177
+ return {
178
+ valid: false,
179
+ error: "Password must contain uppercase, lowercase, number, and special character (@$!%*?&)"
180
+ };
181
+ }
182
+ return { valid: true };
183
+ };
184
+ var validateName = (name) => {
185
+ if (!name || name.trim() === "") {
186
+ return { valid: false, error: "Name is required" };
187
+ }
188
+ if (name.length < 2) {
189
+ return { valid: false, error: "Name must be at least 2 characters" };
190
+ }
191
+ if (name.length > 100) {
192
+ return { valid: false, error: "Name is too long" };
193
+ }
194
+ if (!/^[a-zA-Z\s'-]+$/.test(name)) {
195
+ return {
196
+ valid: false,
197
+ error: "Name can only contain letters, spaces, hyphens, and apostrophes"
198
+ };
199
+ }
200
+ return { valid: true };
201
+ };
202
+ var isValidPhone = (phone) => {
203
+ return REGEX_PATTERNS.PHONE.test(phone);
204
+ };
205
+ var validatePhone = (phone) => {
206
+ if (!phone) {
207
+ return { valid: false, error: "Phone number is required" };
208
+ }
209
+ if (!isValidPhone(phone)) {
210
+ return { valid: false, error: "Invalid phone number format" };
211
+ }
212
+ return { valid: true };
213
+ };
214
+ var isValidPostalCode = (postalCode) => {
215
+ return REGEX_PATTERNS.POSTAL_CODE.test(postalCode);
216
+ };
217
+ var validatePostalCode = (postalCode) => {
218
+ if (!postalCode) {
219
+ return { valid: false, error: "Postal code is required" };
220
+ }
221
+ if (!isValidPostalCode(postalCode)) {
222
+ return { valid: false, error: "Invalid postal code format" };
223
+ }
224
+ return { valid: true };
225
+ };
226
+ var isValidCouponCode = (code) => {
227
+ return REGEX_PATTERNS.COUPON_CODE.test(code);
228
+ };
229
+ var validateCouponCode = (code) => {
230
+ if (!code) {
231
+ return { valid: false, error: "Coupon code is required" };
232
+ }
233
+ if (!isValidCouponCode(code)) {
234
+ return { valid: false, error: "Invalid coupon code format (6-20 alphanumeric characters)" };
235
+ }
236
+ return { valid: true };
237
+ };
238
+ var validatePrice = (price) => {
239
+ const numPrice = parseFloat(price);
240
+ if (isNaN(numPrice)) {
241
+ return { valid: false, error: "Price must be a valid number" };
242
+ }
243
+ if (numPrice < 0) {
244
+ return { valid: false, error: "Price cannot be negative" };
245
+ }
246
+ if (numPrice > 999999.99) {
247
+ return { valid: false, error: "Price exceeds maximum allowed value" };
248
+ }
249
+ return { valid: true };
250
+ };
251
+ var validateQuantity = (qty) => {
252
+ const numQty = parseInt(qty, 10);
253
+ if (isNaN(numQty)) {
254
+ return { valid: false, error: "Quantity must be a valid number" };
255
+ }
256
+ if (numQty < 0) {
257
+ return { valid: false, error: "Quantity cannot be negative" };
258
+ }
259
+ if (!Number.isInteger(numQty)) {
260
+ return { valid: false, error: "Quantity must be a whole number" };
261
+ }
262
+ return { valid: true };
263
+ };
264
+ var validateRating = (rating) => {
265
+ const numRating = parseFloat(rating);
266
+ if (isNaN(numRating)) {
267
+ return { valid: false, error: "Rating must be a valid number" };
268
+ }
269
+ if (numRating < 0 || numRating > 5) {
270
+ return { valid: false, error: "Rating must be between 0 and 5" };
271
+ }
272
+ return { valid: true };
273
+ };
274
+ var validateDiscountPercentage = (discount) => {
275
+ const numDiscount = parseFloat(discount);
276
+ if (isNaN(numDiscount)) {
277
+ return { valid: false, error: "Discount must be a valid number" };
278
+ }
279
+ if (numDiscount < 0 || numDiscount > 100) {
280
+ return { valid: false, error: "Discount percentage must be between 0 and 100" };
281
+ }
282
+ return { valid: true };
283
+ };
284
+ var validatePagination = (page, limit) => {
285
+ const numPage = parseInt(page, 10) || 1;
286
+ const numLimit = parseInt(limit, 10) || 10;
287
+ if (numPage < 1) {
288
+ return { valid: false, error: "Page must be greater than 0" };
289
+ }
290
+ if (numLimit < 1) {
291
+ return { valid: false, error: "Limit must be greater than 0" };
292
+ }
293
+ if (numLimit > 100) {
294
+ return { valid: false, error: "Limit cannot exceed 100" };
295
+ }
296
+ return { valid: true, page: numPage, limit: numLimit };
297
+ };
298
+ var isValidObjectId = (id) => {
299
+ return /^[0-9a-fA-F]{24}$/.test(id);
300
+ };
301
+ var validateObjectId = (id, fieldName = "ID") => {
302
+ if (!id) {
303
+ return { valid: false, error: `${fieldName} is required` };
304
+ }
305
+ if (!isValidObjectId(id)) {
306
+ return { valid: false, error: `Invalid ${fieldName} format` };
307
+ }
308
+ return { valid: true };
309
+ };
310
+ var isValidUrl = (url) => {
311
+ return REGEX_PATTERNS.URL.test(url);
312
+ };
313
+ var validateUrl = (url) => {
314
+ if (!url) {
315
+ return { valid: false, error: "URL is required" };
316
+ }
317
+ if (!isValidUrl(url)) {
318
+ return { valid: false, error: "Invalid URL format" };
319
+ }
320
+ return { valid: true };
321
+ };
322
+ var isValidSku = (sku) => {
323
+ return REGEX_PATTERNS.PRODUCT_SKU.test(sku);
324
+ };
325
+ var validateSku = (sku) => {
326
+ if (!sku) {
327
+ return { valid: false, error: "SKU is required" };
328
+ }
329
+ if (!isValidSku(sku)) {
330
+ return {
331
+ valid: false,
332
+ error: "Invalid SKU format (3-20 alphanumeric characters with hyphens)"
333
+ };
334
+ }
335
+ return { valid: true };
336
+ };
337
+ var validateDate = (date) => {
338
+ const dateObj = new Date(date);
339
+ if (isNaN(dateObj.getTime())) {
340
+ return { valid: false, error: "Invalid date format" };
341
+ }
342
+ return { valid: true };
343
+ };
344
+ var validateDateRange = (startDate, endDate) => {
345
+ const start = new Date(startDate);
346
+ const end = new Date(endDate);
347
+ if (isNaN(start.getTime())) {
348
+ return { valid: false, error: "Invalid start date" };
349
+ }
350
+ if (isNaN(end.getTime())) {
351
+ return { valid: false, error: "Invalid end date" };
352
+ }
353
+ if (start > end) {
354
+ return { valid: false, error: "Start date must be before end date" };
355
+ }
356
+ return { valid: true };
357
+ };
358
+ var batchValidate = (validations) => {
359
+ const errors = [];
360
+ for (const validation of validations) {
361
+ if (!validation.valid && validation.error) {
362
+ errors.push(validation.error);
363
+ }
364
+ }
365
+ return {
366
+ valid: errors.length === 0,
367
+ errors
368
+ };
369
+ };
370
+
371
+ // src/api/logger.ts
372
+ var import_fs = __toESM(require("fs"));
373
+ var import_path = __toESM(require("path"));
374
+
375
+ // ../types/dist/index.mjs
376
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
377
+ LogLevel2["DEBUG"] = "DEBUG";
378
+ LogLevel2["INFO"] = "INFO";
379
+ LogLevel2["WARN"] = "WARN";
380
+ LogLevel2["ERROR"] = "ERROR";
381
+ return LogLevel2;
382
+ })(LogLevel || {});
383
+
384
+ // src/api/logger.ts
385
+ var LOG_LEVEL_PRIORITY = {
386
+ [LogLevel.DEBUG]: 0,
387
+ [LogLevel.INFO]: 1,
388
+ [LogLevel.WARN]: 2,
389
+ [LogLevel.ERROR]: 3
390
+ };
391
+ var Logger = class {
392
+ static configure(options) {
393
+ if (options.maxLogs !== void 0) this.maxLogs = options.maxLogs;
394
+ if (options.enableConsole !== void 0) this.enableConsole = options.enableConsole;
395
+ if (options.enableFile !== void 0) this.enableFile = options.enableFile;
396
+ if (options.logFilePath) this.logFilePath = options.logFilePath;
397
+ if (options.logLevel) {
398
+ const level = typeof options.logLevel === "string" ? options.logLevel.toUpperCase() : options.logLevel;
399
+ if (Object.values(LogLevel).includes(level)) {
400
+ this.logLevel = level;
401
+ }
402
+ }
403
+ }
404
+ static shouldLog(level) {
405
+ return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[this.logLevel];
406
+ }
407
+ static addLog(entry) {
408
+ this.logs.push(entry);
409
+ if (this.logs.length > this.maxLogs) this.logs.shift();
410
+ if (this.enableFile) {
411
+ import_fs.default.mkdirSync(import_path.default.dirname(this.logFilePath), { recursive: true });
412
+ import_fs.default.appendFileSync(this.logFilePath, JSON.stringify(entry) + "\n");
413
+ }
414
+ }
415
+ static format(entry) {
416
+ return `[${entry.timestamp}] [${entry.level}]${entry.context ? ` [${entry.context}]` : ""}: ${entry.message}`;
417
+ }
418
+ static debug(message, data, context) {
419
+ this.log(LogLevel.DEBUG, message, data, context);
420
+ }
421
+ static info(message, data, context) {
422
+ this.log(LogLevel.INFO, message, data, context);
423
+ }
424
+ static warn(message, data, context) {
425
+ this.log(LogLevel.WARN, message, data, context);
426
+ }
427
+ static error(message, error, context) {
428
+ this.log(LogLevel.ERROR, message, error, context);
429
+ }
430
+ static log(level, message, data, context) {
431
+ if (!this.shouldLog(level)) return;
432
+ const entry = {
433
+ level,
434
+ message,
435
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
436
+ data,
437
+ context
438
+ };
439
+ this.addLog(entry);
440
+ if (!this.enableConsole) return;
441
+ const formatted = this.format(entry);
442
+ switch (level) {
443
+ case LogLevel.ERROR:
444
+ console.error(formatted, data ?? "");
445
+ break;
446
+ case LogLevel.WARN:
447
+ console.warn(formatted, data ?? "");
448
+ break;
449
+ case LogLevel.INFO:
450
+ console.info(formatted, data ?? "");
451
+ break;
452
+ default:
453
+ console.debug(formatted, data ?? "");
454
+ }
455
+ }
456
+ static getLogs(level) {
457
+ return level ? this.logs.filter((l) => l.level === level) : [...this.logs];
458
+ }
459
+ static clearLogs() {
460
+ this.logs = [];
461
+ if (this.enableFile && import_fs.default.existsSync(this.logFilePath)) {
462
+ import_fs.default.unlinkSync(this.logFilePath);
463
+ }
464
+ }
465
+ };
466
+ Logger.logs = [];
467
+ Logger.maxLogs = 1e3;
468
+ Logger.enableConsole = true;
469
+ Logger.enableFile = false;
470
+ Logger.logFilePath = import_path.default.join(process.cwd(), "logs/app.log");
471
+ Logger.logLevel = LogLevel.DEBUG;
472
+
473
+ // src/validation/server.ts
474
+ var validate = (req, res, next) => {
475
+ const errors = (0, import_express_validator.validationResult)(req);
476
+ if (!errors.isEmpty()) {
477
+ res.status(400).json({
478
+ success: false,
479
+ message: "Validation failed",
480
+ errors: errors.array().map((err) => ({
481
+ field: err.type === "field" ? err.path : void 0,
482
+ message: err.msg
483
+ }))
484
+ });
485
+ return;
486
+ }
487
+ next();
488
+ };
489
+ // Annotate the CommonJS export names for ESM import in node:
490
+ 0 && (module.exports = {
491
+ Logger,
492
+ batchValidate,
493
+ isValidCouponCode,
494
+ isValidEmail,
495
+ isValidObjectId,
496
+ isValidPassword,
497
+ isValidPhone,
498
+ isValidPostalCode,
499
+ isValidSku,
500
+ isValidUrl,
501
+ validate,
502
+ validateCouponCode,
503
+ validateDate,
504
+ validateDateRange,
505
+ validateDiscountPercentage,
506
+ validateEmail,
507
+ validateName,
508
+ validateObjectId,
509
+ validatePagination,
510
+ validatePassword,
511
+ validatePhone,
512
+ validatePostalCode,
513
+ validatePrice,
514
+ validateQuantity,
515
+ validateRating,
516
+ validateSku,
517
+ validateUrl
518
+ });