@exyconn/common 2.1.0 → 2.3.3

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 (142) hide show
  1. package/README.md +969 -261
  2. package/dist/client/hooks/index.d.mts +1042 -0
  3. package/dist/client/hooks/index.d.ts +1042 -0
  4. package/dist/client/hooks/index.js +2276 -0
  5. package/dist/client/hooks/index.js.map +1 -0
  6. package/dist/client/hooks/index.mjs +2217 -0
  7. package/dist/client/hooks/index.mjs.map +1 -0
  8. package/dist/client/http/index.d.mts +217 -49
  9. package/dist/client/http/index.d.ts +217 -49
  10. package/dist/client/http/index.js +473 -94
  11. package/dist/client/http/index.js.map +1 -1
  12. package/dist/client/http/index.mjs +441 -84
  13. package/dist/client/http/index.mjs.map +1 -1
  14. package/dist/client/index.d.mts +6 -4
  15. package/dist/client/index.d.ts +6 -4
  16. package/dist/client/index.js +481 -319
  17. package/dist/client/index.js.map +1 -1
  18. package/dist/client/index.mjs +449 -290
  19. package/dist/client/index.mjs.map +1 -1
  20. package/dist/client/utils/index.d.mts +3 -279
  21. package/dist/client/utils/index.d.ts +3 -279
  22. package/dist/client/web/index.d.mts +1461 -0
  23. package/dist/client/web/index.d.ts +1461 -0
  24. package/dist/client/web/index.js +2681 -0
  25. package/dist/client/web/index.js.map +1 -0
  26. package/dist/client/web/index.mjs +2618 -0
  27. package/dist/client/web/index.mjs.map +1 -0
  28. package/dist/data/brand-identity.d.mts +149 -0
  29. package/dist/data/brand-identity.d.ts +149 -0
  30. package/dist/data/brand-identity.js +235 -0
  31. package/dist/data/brand-identity.js.map +1 -0
  32. package/dist/data/brand-identity.mjs +220 -0
  33. package/dist/data/brand-identity.mjs.map +1 -0
  34. package/dist/data/countries.d.mts +61 -0
  35. package/dist/data/countries.d.ts +61 -0
  36. package/dist/data/countries.js +987 -0
  37. package/dist/data/countries.js.map +1 -0
  38. package/dist/data/countries.mjs +971 -0
  39. package/dist/data/countries.mjs.map +1 -0
  40. package/dist/data/currencies.d.mts +19 -0
  41. package/dist/data/currencies.d.ts +19 -0
  42. package/dist/data/currencies.js +162 -0
  43. package/dist/data/currencies.js.map +1 -0
  44. package/dist/data/currencies.mjs +153 -0
  45. package/dist/data/currencies.mjs.map +1 -0
  46. package/dist/data/index.d.mts +7 -0
  47. package/dist/data/index.d.ts +7 -0
  48. package/dist/data/index.js +2087 -0
  49. package/dist/data/index.js.map +1 -0
  50. package/dist/data/index.mjs +1948 -0
  51. package/dist/data/index.mjs.map +1 -0
  52. package/dist/data/phone-codes.d.mts +15 -0
  53. package/dist/data/phone-codes.d.ts +15 -0
  54. package/dist/data/phone-codes.js +219 -0
  55. package/dist/data/phone-codes.js.map +1 -0
  56. package/dist/data/phone-codes.mjs +211 -0
  57. package/dist/data/phone-codes.mjs.map +1 -0
  58. package/dist/data/regex.d.mts +287 -0
  59. package/dist/data/regex.d.ts +287 -0
  60. package/dist/data/regex.js +306 -0
  61. package/dist/data/regex.js.map +1 -0
  62. package/dist/data/regex.mjs +208 -0
  63. package/dist/data/regex.mjs.map +1 -0
  64. package/dist/data/timezones.d.mts +16 -0
  65. package/dist/data/timezones.d.ts +16 -0
  66. package/dist/data/timezones.js +98 -0
  67. package/dist/data/timezones.js.map +1 -0
  68. package/dist/data/timezones.mjs +89 -0
  69. package/dist/data/timezones.mjs.map +1 -0
  70. package/dist/index-BZf42T3R.d.mts +305 -0
  71. package/dist/index-CF0D8PGE.d.ts +305 -0
  72. package/dist/index-Ckhm_HaX.d.mts +138 -0
  73. package/dist/index-DKn4raO7.d.ts +222 -0
  74. package/dist/index-NS8dS0p9.d.mts +222 -0
  75. package/dist/index-Nqm5_lwT.d.ts +188 -0
  76. package/dist/index-br6POSyA.d.ts +138 -0
  77. package/dist/index-jBi3V6e5.d.mts +188 -0
  78. package/dist/index.d.mts +21 -580
  79. package/dist/index.d.ts +21 -580
  80. package/dist/index.js +1839 -347
  81. package/dist/index.js.map +1 -1
  82. package/dist/index.mjs +1850 -359
  83. package/dist/index.mjs.map +1 -1
  84. package/dist/packageCheck-B_qfsD6R.d.ts +280 -0
  85. package/dist/packageCheck-C2_FT_Rl.d.mts +280 -0
  86. package/dist/server/configs/index.d.mts +602 -0
  87. package/dist/server/configs/index.d.ts +602 -0
  88. package/dist/server/configs/index.js +707 -0
  89. package/dist/server/configs/index.js.map +1 -0
  90. package/dist/server/configs/index.mjs +665 -0
  91. package/dist/server/configs/index.mjs.map +1 -0
  92. package/dist/server/index.d.mts +4 -1
  93. package/dist/server/index.d.ts +4 -1
  94. package/dist/server/index.js +1330 -0
  95. package/dist/server/index.js.map +1 -1
  96. package/dist/server/index.mjs +1286 -2
  97. package/dist/server/index.mjs.map +1 -1
  98. package/dist/server/middleware/index.d.mts +283 -2
  99. package/dist/server/middleware/index.d.ts +283 -2
  100. package/dist/server/middleware/index.js +761 -0
  101. package/dist/server/middleware/index.js.map +1 -1
  102. package/dist/server/middleware/index.mjs +751 -1
  103. package/dist/server/middleware/index.mjs.map +1 -1
  104. package/dist/shared/config/index.d.mts +40 -0
  105. package/dist/shared/config/index.d.ts +40 -0
  106. package/dist/shared/config/index.js +58 -0
  107. package/dist/shared/config/index.js.map +1 -0
  108. package/dist/shared/config/index.mjs +51 -0
  109. package/dist/shared/config/index.mjs.map +1 -0
  110. package/dist/shared/constants/index.d.mts +593 -0
  111. package/dist/shared/constants/index.d.ts +593 -0
  112. package/dist/shared/constants/index.js +391 -0
  113. package/dist/shared/constants/index.js.map +1 -0
  114. package/dist/shared/constants/index.mjs +360 -0
  115. package/dist/shared/constants/index.mjs.map +1 -0
  116. package/dist/shared/index.d.mts +5 -1
  117. package/dist/shared/index.d.ts +5 -1
  118. package/dist/shared/types/index.d.mts +140 -0
  119. package/dist/shared/types/index.d.ts +140 -0
  120. package/dist/shared/types/index.js +4 -0
  121. package/dist/shared/types/index.js.map +1 -0
  122. package/dist/shared/types/index.mjs +3 -0
  123. package/dist/shared/types/index.mjs.map +1 -0
  124. package/dist/shared/utils/index.d.mts +255 -0
  125. package/dist/shared/utils/index.d.ts +255 -0
  126. package/dist/shared/utils/index.js +623 -0
  127. package/dist/shared/utils/index.js.map +1 -0
  128. package/dist/shared/utils/index.mjs +324 -0
  129. package/dist/shared/utils/index.mjs.map +1 -0
  130. package/dist/shared/validation/index.d.mts +258 -0
  131. package/dist/shared/validation/index.d.ts +258 -0
  132. package/dist/shared/validation/index.js +185 -0
  133. package/dist/shared/validation/index.js.map +1 -0
  134. package/dist/shared/validation/index.mjs +172 -0
  135. package/dist/shared/validation/index.mjs.map +1 -0
  136. package/package.json +127 -62
  137. package/dist/index-BcxL4_V4.d.ts +0 -2946
  138. package/dist/index-DEzgM15j.d.ts +0 -67
  139. package/dist/index-DNFVgQx8.d.ts +0 -1375
  140. package/dist/index-DbV04Dx8.d.mts +0 -67
  141. package/dist/index-DfqEP6Oe.d.mts +0 -1375
  142. package/dist/index-bvvCev9Q.d.mts +0 -2946
package/dist/index.mjs CHANGED
@@ -1,15 +1,16 @@
1
1
  import winston from 'winston';
2
2
  import DailyRotateFile from 'winston-daily-rotate-file';
3
3
  import path, { resolve } from 'path';
4
- import mongoose from 'mongoose';
4
+ import mongoose, { Types } from 'mongoose';
5
5
  import jwt from 'jsonwebtoken';
6
6
  import { existsSync, readFileSync } from 'fs';
7
+ import rateLimit from 'express-rate-limit';
7
8
  import axios from 'axios';
8
9
  import { createContext, useState, useCallback, useMemo, useRef, useEffect, useContext } from 'react';
9
10
  import { jsx, jsxs } from 'react/jsx-runtime';
10
11
  import * as Yup from 'yup';
11
12
  import { Formik, Form, Field, ErrorMessage } from 'formik';
12
- import { subYears, subWeeks, subMonths, subMinutes, subHours, subDays, startOfYear, startOfWeek, startOfMonth, startOfDay as startOfDay$1, setSeconds, setMinutes, setHours, parseISO, isYesterday, isValid, isTomorrow, isToday as isToday$1, isThisYear, isThisWeek, isThisMonth, isSameYear, isSameWeek, isSameMonth, isSameDay, isPast as isPast$1, isFuture as isFuture$1, isEqual, isBefore, isAfter, intervalToDuration, getYear, getSeconds, getMonth, getMinutes, getHours, getDay, getDate, formatRelative, formatDuration, formatDistanceToNow, formatDistance, format, endOfYear, endOfWeek, endOfMonth, endOfDay as endOfDay$1, eachWeekOfInterval, eachMonthOfInterval, eachDayOfInterval, differenceInYears, differenceInWeeks, differenceInSeconds, differenceInMonths, differenceInMinutes, differenceInHours, differenceInDays, addYears, addWeeks, addMonths, addMinutes, addHours, addDays as addDays$1 } from 'date-fns';
13
+ import { subYears, subWeeks, subMonths, subMinutes, subHours, subDays, startOfYear, startOfWeek, startOfMonth, startOfDay, setSeconds, setMinutes, setHours, parseISO, isYesterday, isValid, isTomorrow, isToday, isThisYear, isThisWeek, isThisMonth, isSameYear, isSameWeek, isSameMonth, isSameDay, isPast, isFuture, isEqual, isBefore, isAfter, intervalToDuration, getYear, getSeconds, getMonth, getMinutes, getHours, getDay, getDate, formatRelative, formatDuration, formatDistanceToNow, formatDistance, format, endOfYear, endOfWeek, endOfMonth, endOfDay, eachWeekOfInterval, eachMonthOfInterval, eachDayOfInterval, differenceInYears, differenceInWeeks, differenceInSeconds, differenceInMonths, differenceInMinutes, differenceInHours, differenceInDays, addYears, addWeeks, addMonths, addMinutes, addHours, addDays } from 'date-fns';
13
14
  import { toZonedTime, fromZonedTime, formatInTimeZone } from 'date-fns-tz';
14
15
 
15
16
  var __defProp = Object.defineProperty;
@@ -21,44 +22,89 @@ var __export = (target, all) => {
21
22
  // src/server/index.ts
22
23
  var server_exports = {};
23
24
  __export(server_exports, {
25
+ ConfigBuilder: () => ConfigBuilder,
26
+ DEFAULT_AUTH_CONFIG: () => DEFAULT_AUTH_CONFIG,
27
+ DEFAULT_CORS_CONFIG: () => DEFAULT_CORS_CONFIG,
28
+ DEFAULT_CORS_ORIGINS: () => DEFAULT_CORS_ORIGINS,
29
+ DEFAULT_DATABASE_CONFIG: () => DEFAULT_DATABASE_CONFIG,
30
+ DEFAULT_LOGGING_CONFIG: () => DEFAULT_LOGGING_CONFIG,
31
+ DEFAULT_RATE_LIMIT_CONFIG: () => DEFAULT_RATE_LIMIT_CONFIG,
32
+ DEFAULT_RATE_LIMIT_TIERS: () => DEFAULT_RATE_LIMIT_TIERS,
33
+ DEFAULT_SERVER_CONFIG: () => DEFAULT_SERVER_CONFIG,
34
+ EXYCONN_CORS_CONFIG: () => EXYCONN_CORS_CONFIG,
35
+ PERMISSIVE_CORS_CONFIG: () => PERMISSIVE_CORS_CONFIG,
36
+ RATE_LIMIT_CONFIG: () => RATE_LIMIT_CONFIG,
37
+ RateLimiterBuilder: () => RateLimiterBuilder,
38
+ STRICT_CORS_CONFIG: () => STRICT_CORS_CONFIG,
24
39
  StatusCode: () => StatusCode,
25
40
  StatusMessage: () => StatusMessage,
26
41
  authenticateApiKey: () => authenticateApiKey,
27
42
  authenticateJWT: () => authenticateJWT,
28
43
  badRequestResponse: () => badRequestResponse,
44
+ buildConfig: () => buildConfig,
45
+ buildDeleteFilter: () => buildDeleteFilter,
29
46
  buildFilter: () => buildFilter,
30
47
  buildPagination: () => buildPagination,
31
48
  buildPaginationMeta: () => buildPaginationMeta,
32
49
  checkPackageServer: () => checkPackageServer,
33
50
  conflictResponse: () => conflictResponse,
34
51
  connectDB: () => connectDB,
52
+ corsOptions: () => corsOptions,
53
+ createApiKeyGenerator: () => createApiKeyGenerator,
54
+ createApiRateLimiter: () => createApiRateLimiter,
55
+ createBrandCorsOptions: () => createBrandCorsOptions,
56
+ createBulkDeleteHandler: () => createBulkDeleteHandler,
57
+ createConfig: () => createConfig,
58
+ createCorsOptions: () => createCorsOptions,
59
+ createCrudControllers: () => createCrudControllers,
60
+ createDdosRateLimiter: () => createDdosRateLimiter,
35
61
  createLogger: () => createLogger,
36
62
  createMorganStream: () => createMorganStream,
63
+ createMultiBrandCorsOptions: () => createMultiBrandCorsOptions,
64
+ createPaginationMiddleware: () => createPaginationMiddleware,
65
+ createPrefixedKeyGenerator: () => createPrefixedKeyGenerator,
66
+ createRateLimiter: () => createRateLimiter,
67
+ createStandardRateLimiter: () => createStandardRateLimiter,
68
+ createStrictRateLimiter: () => createStrictRateLimiter,
69
+ createUserKeyGenerator: () => createUserKeyGenerator,
37
70
  createdResponse: () => createdResponse,
71
+ ddosProtectionLimiter: () => ddosProtectionLimiter,
72
+ defaultKeyGenerator: () => defaultKeyGenerator,
38
73
  disconnectDB: () => disconnectDB,
39
74
  errorResponse: () => errorResponse,
40
75
  extractColumns: () => extractColumns,
41
76
  extractOrganization: () => extractOrganization,
77
+ extractSchemaMeta: () => extractSchemaMeta,
42
78
  forbiddenResponse: () => forbiddenResponse,
43
79
  formatPackageCheckResult: () => formatPackageCheckResult,
44
80
  generateNcuCommand: () => generateNcuCommand,
45
81
  getConnectionStatus: () => getConnectionStatus,
82
+ getDatabaseOptions: () => getDatabaseOptions,
83
+ isDevelopment: () => isDevelopment,
84
+ isProduction: () => isProduction,
85
+ isTest: () => isTest,
46
86
  logger: () => logger,
47
87
  noContentResponse: () => noContentResponse,
48
88
  notFoundResponse: () => notFoundResponse,
49
89
  omitFields: () => omitFields,
50
90
  optionalAuthenticateJWT: () => optionalAuthenticateJWT,
51
91
  packageCheckServer: () => packageCheckServer,
92
+ parseBulkDelete: () => parseBulkDelete,
52
93
  pickFields: () => pickFields,
53
94
  printPackageCheckSummary: () => printPackageCheckSummary,
95
+ queryPagination: () => queryPagination,
96
+ queryParser: () => queryParser,
54
97
  rateLimitResponse: () => rateLimitResponse,
98
+ rateLimiter: () => rateLimiter,
55
99
  requireOrganization: () => requireOrganization,
56
100
  sanitizeDocument: () => sanitizeDocument,
57
101
  sanitizeUser: () => sanitizeUser,
58
102
  simpleLogger: () => simpleLogger,
103
+ standardRateLimiter: () => standardRateLimiter,
59
104
  statusCode: () => statusCode,
60
105
  statusMessage: () => statusMessage,
61
106
  stream: () => stream,
107
+ strictRateLimiter: () => strictRateLimiter,
62
108
  successResponse: () => successResponse,
63
109
  successResponseArr: () => successResponseArr,
64
110
  unauthorizedResponse: () => unauthorizedResponse,
@@ -341,37 +387,37 @@ var defaultOptions = {
341
387
  retryReads: true,
342
388
  w: "majority"
343
389
  };
344
- var connectDB = async (mongoUri, options = {}, logger2) => {
390
+ var connectDB = async (mongoUri, options = {}, logger3) => {
345
391
  if (mongoose.connection.readyState === 1) {
346
- logger2?.info("Database already connected, reusing connection");
392
+ logger3?.info("Database already connected, reusing connection");
347
393
  return mongoose;
348
394
  }
349
395
  const finalOptions = { ...defaultOptions, ...options };
350
396
  try {
351
397
  await mongoose.connect(mongoUri, finalOptions);
352
- logger2?.info("MongoDB connected successfully");
398
+ logger3?.info("MongoDB connected successfully");
353
399
  mongoose.connection.on("error", (err) => {
354
- logger2?.error("MongoDB connection error", err);
400
+ logger3?.error("MongoDB connection error", err);
355
401
  });
356
402
  mongoose.connection.on("disconnected", () => {
357
- logger2?.info("MongoDB disconnected");
403
+ logger3?.info("MongoDB disconnected");
358
404
  });
359
405
  mongoose.connection.on("reconnected", () => {
360
- logger2?.info("MongoDB reconnected");
406
+ logger3?.info("MongoDB reconnected");
361
407
  });
362
408
  return mongoose;
363
409
  } catch (error) {
364
410
  const errorMessage = error instanceof Error ? error.message : String(error);
365
- logger2?.error("MongoDB connection failed", { error: errorMessage });
411
+ logger3?.error("MongoDB connection failed", { error: errorMessage });
366
412
  throw error;
367
413
  }
368
414
  };
369
- var disconnectDB = async (logger2) => {
415
+ var disconnectDB = async (logger3) => {
370
416
  try {
371
417
  await mongoose.disconnect();
372
- logger2?.info("MongoDB disconnected successfully");
418
+ logger3?.info("MongoDB disconnected successfully");
373
419
  } catch (error) {
374
- logger2?.error("Error disconnecting from MongoDB", error);
420
+ logger3?.error("Error disconnecting from MongoDB", error);
375
421
  throw error;
376
422
  }
377
423
  };
@@ -476,6 +522,629 @@ var requireOrganization = (req, res, next) => {
476
522
  next();
477
523
  };
478
524
 
525
+ // src/server/middleware/queryParser.middleware.ts
526
+ var queryParser = (req, _, next) => {
527
+ const { page, limit, sort, sortBy, sortOrder, search, filter, ...otherParams } = req.query;
528
+ const parsed = {
529
+ page: Math.max(Number(page) || 1, 1),
530
+ limit: Math.min(Number(limit) || 10, 100),
531
+ filter: {}
532
+ };
533
+ if (typeof sort === "string") {
534
+ const [field, order] = sort.split(":");
535
+ parsed.sort = {
536
+ field,
537
+ order: order === "asc" ? "asc" : "desc"
538
+ };
539
+ } else if (typeof sortBy === "string") {
540
+ parsed.sort = {
541
+ field: sortBy,
542
+ order: sortOrder === "asc" ? "asc" : "desc"
543
+ };
544
+ }
545
+ if (typeof search === "string") {
546
+ parsed.search = search;
547
+ }
548
+ if (typeof filter === "object" && filter !== null) {
549
+ Object.entries(filter).forEach(([key, value]) => {
550
+ if (value !== "all") {
551
+ parsed.filter[key] = value;
552
+ }
553
+ });
554
+ }
555
+ Object.entries(otherParams).forEach(([key, value]) => {
556
+ if (typeof value === "string" && value !== "all" && !["page", "limit", "sort", "sortBy", "sortOrder", "search"].includes(key)) {
557
+ parsed.filter[key] = value;
558
+ }
559
+ });
560
+ req.parsedQuery = parsed;
561
+ next();
562
+ };
563
+
564
+ // src/server/middleware/utils/schemaMeta.util.ts
565
+ var getZodTypeName = (schema) => {
566
+ const typeName = schema._def?.typeName;
567
+ switch (typeName) {
568
+ case "ZodString":
569
+ return "string";
570
+ case "ZodNumber":
571
+ return "number";
572
+ case "ZodBoolean":
573
+ return "boolean";
574
+ case "ZodDate":
575
+ return "date";
576
+ case "ZodArray":
577
+ return "array";
578
+ case "ZodObject":
579
+ return "object";
580
+ case "ZodOptional":
581
+ case "ZodNullable":
582
+ return schema._def?.innerType ? getZodTypeName(schema._def.innerType) : "unknown";
583
+ case "ZodDefault":
584
+ return schema._def?.innerType ? getZodTypeName(schema._def.innerType) : "unknown";
585
+ case "ZodEnum":
586
+ return "enum";
587
+ case "ZodUnion":
588
+ return "union";
589
+ default:
590
+ return "unknown";
591
+ }
592
+ };
593
+ var isZodRequired = (schema) => {
594
+ const typeName = schema._def?.typeName;
595
+ return typeName !== "ZodOptional" && typeName !== "ZodNullable";
596
+ };
597
+ var extractSchemaMeta = (model, zodSchema) => {
598
+ const columns = [];
599
+ if (zodSchema && zodSchema.shape) {
600
+ const shape = zodSchema.shape;
601
+ for (const [key, value] of Object.entries(shape)) {
602
+ if (key.startsWith("_")) continue;
603
+ columns.push({
604
+ name: key,
605
+ datatype: getZodTypeName(value),
606
+ required: isZodRequired(value)
607
+ });
608
+ }
609
+ return columns;
610
+ }
611
+ try {
612
+ const schema = model.schema;
613
+ const paths = schema.paths;
614
+ for (const [key, pathInfo] of Object.entries(paths)) {
615
+ if (key.startsWith("_") || key === "__v") continue;
616
+ const schemaType = pathInfo;
617
+ columns.push({
618
+ name: key,
619
+ datatype: (schemaType.instance || "unknown").toLowerCase(),
620
+ required: schemaType.isRequired || false
621
+ });
622
+ }
623
+ } catch {
624
+ }
625
+ return columns;
626
+ };
627
+
628
+ // src/server/middleware/pagination.middleware.ts
629
+ var queryPagination = (model, options = {}, withOrgId = true) => {
630
+ return async (req, res, next) => {
631
+ try {
632
+ const { page, limit, sort, search, filter } = req.parsedQuery;
633
+ const query = {};
634
+ Object.entries(filter).forEach(([key, value]) => {
635
+ if (options.regexFilterFields?.includes(key)) {
636
+ query[key] = { $regex: value, $options: "i" };
637
+ } else {
638
+ query[key] = value;
639
+ }
640
+ });
641
+ const organizationId = req.headers["x-organization-id"];
642
+ if (organizationId && typeof organizationId === "string" && withOrgId) {
643
+ query.organizationId = organizationId;
644
+ }
645
+ if (search && options.searchFields?.length) {
646
+ query.$or = options.searchFields.map((field) => ({
647
+ [field]: { $regex: search, $options: "i" }
648
+ }));
649
+ }
650
+ const sortQuery = sort ? { [sort.field]: sort.order } : { createdAt: "desc" };
651
+ const skip = (page - 1) * limit;
652
+ const [data, total] = await Promise.all([
653
+ model.find(query).sort(sortQuery).skip(skip).limit(limit),
654
+ model.countDocuments(query)
655
+ ]);
656
+ res.paginatedResult = {
657
+ data,
658
+ meta: {
659
+ page,
660
+ limit,
661
+ total,
662
+ totalPages: Math.ceil(total / limit)
663
+ },
664
+ columns: extractSchemaMeta(model, options.validatorSchema)
665
+ };
666
+ next();
667
+ } catch (error) {
668
+ next(error);
669
+ }
670
+ };
671
+ };
672
+ var isZodError = (error) => {
673
+ return error !== null && typeof error === "object" && "errors" in error && Array.isArray(error.errors);
674
+ };
675
+ var getOrgId = (req, orgField = "organizationId") => {
676
+ const orgReq = req;
677
+ return orgReq.organizationId || req.headers["x-organization-id"] || req.query[orgField];
678
+ };
679
+ var buildOrgFilter = (req, config) => {
680
+ const filter = {};
681
+ if (config.withOrganization !== false) {
682
+ const orgId = getOrgId(req, config.orgField);
683
+ if (orgId) {
684
+ filter[config.orgField || "organizationId"] = orgId;
685
+ }
686
+ }
687
+ return filter;
688
+ };
689
+ var formatZodError = (error) => {
690
+ return error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
691
+ };
692
+ function createCrudControllers(config) {
693
+ const {
694
+ model,
695
+ resourceName,
696
+ createSchema,
697
+ updateSchema,
698
+ searchFields = [],
699
+ regexFilterFields = [],
700
+ withOrganization = true,
701
+ orgField = "organizationId",
702
+ transformCreate,
703
+ transformUpdate,
704
+ afterCreate,
705
+ afterUpdate,
706
+ afterDelete,
707
+ excludeFields = [],
708
+ populateFields = [],
709
+ buildQuery
710
+ } = config;
711
+ const getAll = async (req, res, _next) => {
712
+ try {
713
+ const paginatedRes = res;
714
+ if (paginatedRes.paginatedResult) {
715
+ successResponse(res, paginatedRes.paginatedResult, `${resourceName} list fetched successfully`);
716
+ return;
717
+ }
718
+ const page = parseInt(req.query.page) || 1;
719
+ const limit = parseInt(req.query.limit) || 10;
720
+ const sortField = req.query.sortBy || "createdAt";
721
+ const sortOrder = req.query.sortOrder || "desc";
722
+ const search = req.query.search;
723
+ let query = {};
724
+ if (withOrganization) {
725
+ const orgId = getOrgId(req, orgField);
726
+ if (orgId) {
727
+ query[orgField] = orgId;
728
+ }
729
+ }
730
+ if (search && searchFields.length > 0) {
731
+ query.$or = searchFields.map((field) => ({
732
+ [field]: { $regex: search, $options: "i" }
733
+ }));
734
+ }
735
+ const filterableParams = Object.keys(req.query).filter(
736
+ (key) => !["page", "limit", "sortBy", "sortOrder", "search"].includes(key)
737
+ );
738
+ filterableParams.forEach((key) => {
739
+ const value = req.query[key];
740
+ if (value !== void 0 && value !== "" && value !== "all") {
741
+ if (regexFilterFields.includes(key)) {
742
+ query[key] = { $regex: value, $options: "i" };
743
+ } else {
744
+ query[key] = value;
745
+ }
746
+ }
747
+ });
748
+ if (buildQuery) {
749
+ query = buildQuery(req, query);
750
+ }
751
+ const sortQuery = { [sortField]: sortOrder };
752
+ const skip = (page - 1) * limit;
753
+ let projection = {};
754
+ if (excludeFields.length > 0) {
755
+ projection = excludeFields.reduce(
756
+ (acc, field) => ({ ...acc, [field]: 0 }),
757
+ {}
758
+ );
759
+ }
760
+ let dbQuery = model.find(query, projection);
761
+ if (populateFields.length > 0) {
762
+ populateFields.forEach((field) => {
763
+ dbQuery = dbQuery.populate(field);
764
+ });
765
+ }
766
+ const [data, total] = await Promise.all([
767
+ dbQuery.sort(sortQuery).skip(skip).limit(limit),
768
+ model.countDocuments(query)
769
+ ]);
770
+ successResponse(
771
+ res,
772
+ {
773
+ data,
774
+ meta: {
775
+ page,
776
+ limit,
777
+ total,
778
+ totalPages: Math.ceil(total / limit)
779
+ },
780
+ columns: extractSchemaMeta(model, createSchema)
781
+ },
782
+ `${resourceName} list fetched successfully`
783
+ );
784
+ } catch (error) {
785
+ logger.error(`Error in getAll ${resourceName}`, {
786
+ error: error instanceof Error ? error.message : "Unknown error"
787
+ });
788
+ errorResponse(res, `Failed to fetch ${resourceName.toLowerCase()} list`);
789
+ }
790
+ };
791
+ const getById = async (req, res, _next) => {
792
+ try {
793
+ const { id } = req.params;
794
+ if (!id || !Types.ObjectId.isValid(id)) {
795
+ badRequestResponse(res, "Invalid ID format");
796
+ return;
797
+ }
798
+ const query = {
799
+ _id: new Types.ObjectId(id),
800
+ ...buildOrgFilter(req, { ...config, withOrganization, orgField })
801
+ };
802
+ let dbQuery = model.findOne(query);
803
+ if (populateFields.length > 0) {
804
+ populateFields.forEach((field) => {
805
+ dbQuery = dbQuery.populate(field);
806
+ });
807
+ }
808
+ const doc = await dbQuery;
809
+ if (!doc) {
810
+ notFoundResponse(res, `${resourceName} not found`);
811
+ return;
812
+ }
813
+ successResponse(res, doc, `${resourceName} fetched successfully`);
814
+ } catch (error) {
815
+ logger.error(`Error in getById ${resourceName}`, {
816
+ error: error instanceof Error ? error.message : "Unknown error",
817
+ id: req.params.id
818
+ });
819
+ errorResponse(res, `Failed to fetch ${resourceName.toLowerCase()}`);
820
+ }
821
+ };
822
+ const create = async (req, res, _next) => {
823
+ try {
824
+ let input = req.body;
825
+ if (createSchema) {
826
+ try {
827
+ input = createSchema.parse(input);
828
+ } catch (error) {
829
+ if (isZodError(error)) {
830
+ badRequestResponse(res, formatZodError(error));
831
+ return;
832
+ }
833
+ throw error;
834
+ }
835
+ }
836
+ if (transformCreate) {
837
+ input = transformCreate(input, req);
838
+ }
839
+ if (withOrganization) {
840
+ const orgId = getOrgId(req, orgField);
841
+ if (orgId) {
842
+ input[orgField] = orgId;
843
+ }
844
+ }
845
+ const doc = new model(input);
846
+ await doc.save();
847
+ if (afterCreate) {
848
+ await afterCreate(doc, req);
849
+ }
850
+ logger.info(`${resourceName} created successfully`, {
851
+ id: doc._id,
852
+ [orgField]: input[orgField]
853
+ });
854
+ createdResponse(res, doc, `${resourceName} created successfully`);
855
+ } catch (error) {
856
+ logger.error(`Error in create ${resourceName}`, {
857
+ error: error instanceof Error ? error.message : "Unknown error"
858
+ });
859
+ if (error.code === 11e3) {
860
+ badRequestResponse(res, `A ${resourceName.toLowerCase()} with this data already exists`);
861
+ return;
862
+ }
863
+ errorResponse(res, `Failed to create ${resourceName.toLowerCase()}`);
864
+ }
865
+ };
866
+ const update = async (req, res, _next) => {
867
+ try {
868
+ const { id } = req.params;
869
+ if (!id || !Types.ObjectId.isValid(id)) {
870
+ badRequestResponse(res, "Invalid ID format");
871
+ return;
872
+ }
873
+ let input = req.body;
874
+ if (updateSchema) {
875
+ try {
876
+ input = updateSchema.parse(input);
877
+ } catch (error) {
878
+ if (isZodError(error)) {
879
+ badRequestResponse(res, formatZodError(error));
880
+ return;
881
+ }
882
+ throw error;
883
+ }
884
+ }
885
+ if (transformUpdate) {
886
+ input = transformUpdate(input, req);
887
+ }
888
+ const query = {
889
+ _id: new Types.ObjectId(id),
890
+ ...buildOrgFilter(req, { ...config, withOrganization, orgField })
891
+ };
892
+ const doc = await model.findOneAndUpdate(query, { $set: input }, { new: true });
893
+ if (!doc) {
894
+ notFoundResponse(res, `${resourceName} not found`);
895
+ return;
896
+ }
897
+ if (afterUpdate) {
898
+ await afterUpdate(doc, req);
899
+ }
900
+ logger.info(`${resourceName} updated successfully`, { id });
901
+ successResponse(res, doc, `${resourceName} updated successfully`);
902
+ } catch (error) {
903
+ logger.error(`Error in update ${resourceName}`, {
904
+ error: error instanceof Error ? error.message : "Unknown error",
905
+ id: req.params.id
906
+ });
907
+ errorResponse(res, `Failed to update ${resourceName.toLowerCase()}`);
908
+ }
909
+ };
910
+ const deleteOne = async (req, res, _next) => {
911
+ try {
912
+ const { id } = req.params;
913
+ if (!id || !Types.ObjectId.isValid(id)) {
914
+ badRequestResponse(res, "Invalid ID format");
915
+ return;
916
+ }
917
+ const query = {
918
+ _id: new Types.ObjectId(id),
919
+ ...buildOrgFilter(req, { ...config, withOrganization, orgField })
920
+ };
921
+ const result = await model.deleteOne(query);
922
+ if (result.deletedCount === 0) {
923
+ notFoundResponse(res, `${resourceName} not found`);
924
+ return;
925
+ }
926
+ if (afterDelete) {
927
+ await afterDelete(id, req);
928
+ }
929
+ logger.info(`${resourceName} deleted successfully`, { id });
930
+ noContentResponse(res, null, `${resourceName} deleted successfully`);
931
+ } catch (error) {
932
+ logger.error(`Error in delete ${resourceName}`, {
933
+ error: error instanceof Error ? error.message : "Unknown error",
934
+ id: req.params.id
935
+ });
936
+ errorResponse(res, `Failed to delete ${resourceName.toLowerCase()}`);
937
+ }
938
+ };
939
+ const bulkDelete = async (req, res, _next) => {
940
+ try {
941
+ const bulkReq = req;
942
+ const { deleteIds = [], deleteAll = false } = bulkReq;
943
+ const baseFilter = buildOrgFilter(req, { ...config, withOrganization, orgField });
944
+ let filter;
945
+ if (deleteAll) {
946
+ filter = baseFilter;
947
+ } else if (deleteIds.length > 0) {
948
+ filter = {
949
+ ...baseFilter,
950
+ _id: { $in: deleteIds.map((id) => new Types.ObjectId(id)) }
951
+ };
952
+ } else {
953
+ badRequestResponse(res, "No IDs provided for deletion");
954
+ return;
955
+ }
956
+ const result = await model.deleteMany(filter);
957
+ if (afterDelete && deleteIds.length > 0) {
958
+ await Promise.all(deleteIds.map((id) => afterDelete(id, req)));
959
+ }
960
+ logger.info(`${resourceName}(s) bulk deleted successfully`, {
961
+ deletedCount: result.deletedCount,
962
+ deleteAll
963
+ });
964
+ successResponse(
965
+ res,
966
+ { deletedCount: result.deletedCount },
967
+ `${result.deletedCount} ${resourceName.toLowerCase()}(s) deleted successfully`
968
+ );
969
+ } catch (error) {
970
+ logger.error(`Error in bulkDelete ${resourceName}`, {
971
+ error: error instanceof Error ? error.message : "Unknown error"
972
+ });
973
+ errorResponse(res, `Failed to delete ${resourceName.toLowerCase()}(s)`);
974
+ }
975
+ };
976
+ return {
977
+ getAll,
978
+ getById,
979
+ create,
980
+ update,
981
+ deleteOne,
982
+ bulkDelete
983
+ };
984
+ }
985
+ function createPaginationMiddleware(model, config = {}) {
986
+ const {
987
+ searchFields = [],
988
+ regexFilterFields = [],
989
+ withOrganization = true,
990
+ orgField = "organizationId"
991
+ } = config;
992
+ return async (req, res, next) => {
993
+ try {
994
+ const page = parseInt(req.query.page) || 1;
995
+ const limit = parseInt(req.query.limit) || 10;
996
+ const sortField = req.query.sortBy || "createdAt";
997
+ const sortOrder = req.query.sortOrder || "desc";
998
+ const search = req.query.search;
999
+ const query = {};
1000
+ if (withOrganization) {
1001
+ const orgId = getOrgId(req, orgField);
1002
+ if (orgId) {
1003
+ query[orgField] = orgId;
1004
+ }
1005
+ }
1006
+ if (search && searchFields.length > 0) {
1007
+ query.$or = searchFields.map((field) => ({
1008
+ [field]: { $regex: search, $options: "i" }
1009
+ }));
1010
+ }
1011
+ const filterableParams = Object.keys(req.query).filter(
1012
+ (key) => !["page", "limit", "sortBy", "sortOrder", "search"].includes(key)
1013
+ );
1014
+ filterableParams.forEach((key) => {
1015
+ const value = req.query[key];
1016
+ if (value !== void 0 && value !== "" && value !== "all") {
1017
+ if (regexFilterFields.includes(key)) {
1018
+ query[key] = { $regex: value, $options: "i" };
1019
+ } else {
1020
+ query[key] = value;
1021
+ }
1022
+ }
1023
+ });
1024
+ const sortQuery = { [sortField]: sortOrder };
1025
+ const skip = (page - 1) * limit;
1026
+ const [data, total] = await Promise.all([
1027
+ model.find(query).sort(sortQuery).skip(skip).limit(limit),
1028
+ model.countDocuments(query)
1029
+ ]);
1030
+ const paginatedRes = res;
1031
+ paginatedRes.paginatedResult = {
1032
+ data,
1033
+ meta: {
1034
+ page,
1035
+ limit,
1036
+ total,
1037
+ totalPages: Math.ceil(total / limit)
1038
+ },
1039
+ columns: extractSchemaMeta(model, config.createSchema)
1040
+ };
1041
+ next();
1042
+ } catch (error) {
1043
+ next(error);
1044
+ }
1045
+ };
1046
+ }
1047
+ var parseBulkDelete = (req, res, next) => {
1048
+ try {
1049
+ const bulkReq = req;
1050
+ let ids = [];
1051
+ if (Array.isArray(req.body)) {
1052
+ ids = req.body;
1053
+ } else if (req.body && Array.isArray(req.body.ids)) {
1054
+ ids = req.body.ids;
1055
+ } else if (req.body && typeof req.body === "object") {
1056
+ if (Array.isArray(req.body.data)) {
1057
+ ids = req.body.data;
1058
+ }
1059
+ }
1060
+ if (ids.length === 0) {
1061
+ return badRequestResponse(
1062
+ res,
1063
+ 'Request body must contain an array of IDs. Use ["*"] to delete all records or ["id1", "id2"] to delete specific records.'
1064
+ );
1065
+ }
1066
+ if (ids.length === 1 && ids[0] === "*") {
1067
+ bulkReq.deleteAll = true;
1068
+ bulkReq.deleteIds = [];
1069
+ logger.info("Bulk delete: Deleting all records");
1070
+ return next();
1071
+ }
1072
+ const validIds = [];
1073
+ const invalidIds = [];
1074
+ for (const id of ids) {
1075
+ if (typeof id === "string" && Types.ObjectId.isValid(id)) {
1076
+ validIds.push(id);
1077
+ } else {
1078
+ invalidIds.push(id);
1079
+ }
1080
+ }
1081
+ if (invalidIds.length > 0) {
1082
+ return badRequestResponse(
1083
+ res,
1084
+ `Invalid ID format(s): ${invalidIds.slice(0, 5).join(", ")}${invalidIds.length > 5 ? "..." : ""}. All IDs must be valid MongoDB ObjectIds.`
1085
+ );
1086
+ }
1087
+ if (validIds.length === 0) {
1088
+ return badRequestResponse(res, "No valid IDs provided for deletion.");
1089
+ }
1090
+ bulkReq.deleteAll = false;
1091
+ bulkReq.deleteIds = validIds;
1092
+ logger.info(`Bulk delete: Deleting ${validIds.length} record(s)`);
1093
+ next();
1094
+ } catch (error) {
1095
+ logger.error("Error in parseBulkDelete middleware", error);
1096
+ return badRequestResponse(res, "Failed to parse delete request");
1097
+ }
1098
+ };
1099
+ var buildDeleteFilter = (req, organizationId) => {
1100
+ const filter = {
1101
+ organizationId: new Types.ObjectId(organizationId)
1102
+ };
1103
+ if (!req.deleteAll && req.deleteIds && req.deleteIds.length > 0) {
1104
+ filter._id = {
1105
+ $in: req.deleteIds.map((id) => new Types.ObjectId(id))
1106
+ };
1107
+ }
1108
+ return filter;
1109
+ };
1110
+ var createBulkDeleteHandler = (Model2, modelName) => {
1111
+ return async (req, res) => {
1112
+ const bulkReq = req;
1113
+ const organizationId = req.headers["x-organization-id"];
1114
+ if (!organizationId) {
1115
+ return badRequestResponse(res, "Organization ID is required");
1116
+ }
1117
+ try {
1118
+ const filter = buildDeleteFilter(bulkReq, organizationId);
1119
+ const result = await Model2.deleteMany(filter);
1120
+ const deletedCount = result.deletedCount || 0;
1121
+ logger.info(`Bulk delete completed: ${deletedCount} ${modelName}(s) deleted`, {
1122
+ organizationId,
1123
+ deleteAll: bulkReq.deleteAll,
1124
+ requestedIds: bulkReq.deleteIds?.length || "all",
1125
+ deletedCount
1126
+ });
1127
+ return res.status(200).json({
1128
+ message: `Successfully deleted ${deletedCount} ${modelName}(s)`,
1129
+ data: {
1130
+ deletedCount,
1131
+ deleteAll: bulkReq.deleteAll
1132
+ },
1133
+ status: "success",
1134
+ statusCode: 200
1135
+ });
1136
+ } catch (error) {
1137
+ logger.error(`Error in bulk delete ${modelName}`, error);
1138
+ return res.status(500).json({
1139
+ message: `Failed to delete ${modelName}(s)`,
1140
+ data: null,
1141
+ status: "error",
1142
+ statusCode: 500
1143
+ });
1144
+ }
1145
+ };
1146
+ };
1147
+
479
1148
  // src/server/utils/filter-builder.ts
480
1149
  var buildFilter = (options) => {
481
1150
  const {
@@ -770,45 +1439,704 @@ var packageCheckServer = {
770
1439
  print: printPackageCheckSummary
771
1440
  };
772
1441
 
1442
+ // src/server/configs/cors.config.ts
1443
+ var DEFAULT_CORS_CONFIG = {
1444
+ productionOrigins: [],
1445
+ developmentOrigins: [
1446
+ "http://localhost:3000",
1447
+ "http://localhost:4000",
1448
+ "http://localhost:5000",
1449
+ "http://localhost:5173",
1450
+ "http://localhost:8080",
1451
+ "http://127.0.0.1:3000",
1452
+ "http://127.0.0.1:4000",
1453
+ "http://127.0.0.1:5000",
1454
+ "http://127.0.0.1:5173",
1455
+ "http://127.0.0.1:8080"
1456
+ ],
1457
+ allowedSubdomains: [],
1458
+ originPatterns: [],
1459
+ allowNoOrigin: true,
1460
+ allowAllInDev: true,
1461
+ credentials: true,
1462
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"],
1463
+ allowedHeaders: [
1464
+ "Content-Type",
1465
+ "Authorization",
1466
+ "X-Requested-With",
1467
+ "Accept",
1468
+ "Origin",
1469
+ "X-API-Key",
1470
+ "X-Organization-Id",
1471
+ "X-Request-Id"
1472
+ ],
1473
+ exposedHeaders: [
1474
+ "Content-Range",
1475
+ "X-Content-Range",
1476
+ "X-Total-Count",
1477
+ "X-Request-Id"
1478
+ ],
1479
+ maxAge: 86400
1480
+ // 24 hours
1481
+ };
1482
+ var createCorsOptions = (config = {}) => {
1483
+ const finalConfig = { ...DEFAULT_CORS_CONFIG, ...config };
1484
+ const {
1485
+ productionOrigins,
1486
+ developmentOrigins,
1487
+ allowedSubdomains,
1488
+ originPatterns,
1489
+ allowNoOrigin,
1490
+ allowAllInDev,
1491
+ customValidator,
1492
+ credentials,
1493
+ methods,
1494
+ allowedHeaders,
1495
+ exposedHeaders,
1496
+ maxAge
1497
+ } = finalConfig;
1498
+ const allOrigins = /* @__PURE__ */ new Set([...productionOrigins, ...developmentOrigins]);
1499
+ const originHandler = (origin, callback) => {
1500
+ if (!origin) {
1501
+ callback(null, allowNoOrigin);
1502
+ return;
1503
+ }
1504
+ if (allOrigins.has(origin)) {
1505
+ callback(null, true);
1506
+ return;
1507
+ }
1508
+ if (allowedSubdomains.some((subdomain) => origin.endsWith(subdomain))) {
1509
+ callback(null, true);
1510
+ return;
1511
+ }
1512
+ if (originPatterns.some((pattern) => pattern.test(origin))) {
1513
+ callback(null, true);
1514
+ return;
1515
+ }
1516
+ if (customValidator && customValidator(origin)) {
1517
+ callback(null, true);
1518
+ return;
1519
+ }
1520
+ if (process.env.NODE_ENV !== "production" && allowAllInDev) {
1521
+ callback(null, true);
1522
+ return;
1523
+ }
1524
+ if (process.env.NODE_ENV === "production") {
1525
+ callback(new Error(`Origin ${origin} not allowed by CORS`));
1526
+ return;
1527
+ }
1528
+ callback(null, true);
1529
+ };
1530
+ return {
1531
+ origin: originHandler,
1532
+ credentials,
1533
+ methods,
1534
+ allowedHeaders,
1535
+ exposedHeaders,
1536
+ maxAge
1537
+ };
1538
+ };
1539
+ var createBrandCorsOptions = (brandDomain, additionalConfig = {}) => {
1540
+ const productionOrigins = [
1541
+ `https://${brandDomain}`,
1542
+ `https://www.${brandDomain}`
1543
+ ];
1544
+ const allowedSubdomains = [`.${brandDomain}`];
1545
+ return createCorsOptions({
1546
+ productionOrigins,
1547
+ allowedSubdomains,
1548
+ ...additionalConfig
1549
+ });
1550
+ };
1551
+ var createMultiBrandCorsOptions = (domains, additionalConfig = {}) => {
1552
+ const productionOrigins = domains.flatMap((domain) => [
1553
+ `https://${domain}`,
1554
+ `https://www.${domain}`
1555
+ ]);
1556
+ const allowedSubdomains = domains.map((domain) => `.${domain}`);
1557
+ return createCorsOptions({
1558
+ productionOrigins,
1559
+ allowedSubdomains,
1560
+ ...additionalConfig
1561
+ });
1562
+ };
1563
+ var EXYCONN_CORS_CONFIG = {
1564
+ productionOrigins: [
1565
+ "https://exyconn.com",
1566
+ "https://www.exyconn.com",
1567
+ "https://botify.life",
1568
+ "https://www.botify.life",
1569
+ "https://partywings.fun",
1570
+ "https://www.partywings.fun",
1571
+ "https://sibera.work",
1572
+ "https://www.sibera.work",
1573
+ "https://spentiva.com",
1574
+ "https://www.spentiva.com"
1575
+ ],
1576
+ allowedSubdomains: [
1577
+ ".exyconn.com",
1578
+ ".botify.life",
1579
+ ".partywings.fun",
1580
+ ".sibera.work",
1581
+ ".spentiva.com"
1582
+ ],
1583
+ developmentOrigins: [
1584
+ "http://localhost:3000",
1585
+ "http://localhost:4000",
1586
+ "http://localhost:4001",
1587
+ "http://localhost:4002",
1588
+ "http://localhost:4003",
1589
+ "http://localhost:4004",
1590
+ "http://localhost:4005",
1591
+ "http://localhost:5173",
1592
+ "http://127.0.0.1:3000",
1593
+ "http://127.0.0.1:4000",
1594
+ "http://127.0.0.1:5173"
1595
+ ]
1596
+ };
1597
+ var STRICT_CORS_CONFIG = {
1598
+ allowNoOrigin: false,
1599
+ allowAllInDev: false,
1600
+ methods: ["GET", "POST", "PUT", "DELETE"]
1601
+ };
1602
+ var PERMISSIVE_CORS_CONFIG = {
1603
+ allowNoOrigin: true,
1604
+ allowAllInDev: true,
1605
+ originPatterns: [/localhost/, /127\.0\.0\.1/]
1606
+ };
1607
+ var corsOptions = createCorsOptions(EXYCONN_CORS_CONFIG);
1608
+ var DEFAULT_RATE_LIMIT_TIERS = {
1609
+ STANDARD: {
1610
+ windowMs: 15 * 60 * 1e3,
1611
+ // 15 minutes
1612
+ maxRequests: 100,
1613
+ message: "Too many requests, please try again later.",
1614
+ skipSuccessfulRequests: false,
1615
+ skipFailedRequests: false
1616
+ },
1617
+ STRICT: {
1618
+ windowMs: 15 * 60 * 1e3,
1619
+ // 15 minutes
1620
+ maxRequests: 20,
1621
+ message: "Too many requests, please try again later.",
1622
+ skipSuccessfulRequests: false,
1623
+ skipFailedRequests: false
1624
+ },
1625
+ DDOS: {
1626
+ windowMs: 60 * 1e3,
1627
+ // 1 minute
1628
+ maxRequests: 60,
1629
+ message: "Rate limit exceeded. Please slow down.",
1630
+ skipSuccessfulRequests: false,
1631
+ skipFailedRequests: false
1632
+ },
1633
+ // Additional presets
1634
+ VERY_STRICT: {
1635
+ windowMs: 60 * 60 * 1e3,
1636
+ // 1 hour
1637
+ maxRequests: 5,
1638
+ message: "Too many attempts. Please try again in an hour.",
1639
+ skipSuccessfulRequests: false,
1640
+ skipFailedRequests: false
1641
+ },
1642
+ RELAXED: {
1643
+ windowMs: 15 * 60 * 1e3,
1644
+ // 15 minutes
1645
+ maxRequests: 500,
1646
+ message: "Rate limit exceeded.",
1647
+ skipSuccessfulRequests: false,
1648
+ skipFailedRequests: false
1649
+ },
1650
+ API: {
1651
+ windowMs: 60 * 1e3,
1652
+ // 1 minute
1653
+ maxRequests: 30,
1654
+ message: "API rate limit exceeded.",
1655
+ skipSuccessfulRequests: false,
1656
+ skipFailedRequests: false
1657
+ }
1658
+ };
1659
+ var defaultKeyGenerator = (req) => {
1660
+ const forwarded = req.headers["x-forwarded-for"];
1661
+ const ip = forwarded ? Array.isArray(forwarded) ? forwarded[0] : forwarded.split(",")[0].trim() : req.ip || req.socket.remoteAddress || "unknown";
1662
+ return ip;
1663
+ };
1664
+ var createPrefixedKeyGenerator = (prefix) => (req) => {
1665
+ return `${prefix}:${defaultKeyGenerator(req)}`;
1666
+ };
1667
+ var createUserKeyGenerator = (getUserId) => (req) => {
1668
+ const userId = getUserId(req);
1669
+ return userId || defaultKeyGenerator(req);
1670
+ };
1671
+ var createApiKeyGenerator = (headerName = "x-api-key") => (req) => {
1672
+ const apiKey = req.headers[headerName.toLowerCase()];
1673
+ return apiKey || defaultKeyGenerator(req);
1674
+ };
1675
+ var createRateLimitResponse = (message, retryAfter) => ({
1676
+ status: "error",
1677
+ statusCode: 429,
1678
+ message,
1679
+ ...retryAfter
1680
+ });
1681
+ var createRateLimiter = (tierConfig, options = {}) => {
1682
+ const {
1683
+ standardHeaders = true,
1684
+ legacyHeaders = false,
1685
+ keyGenerator = defaultKeyGenerator,
1686
+ skip,
1687
+ handler
1688
+ } = options;
1689
+ return rateLimit({
1690
+ windowMs: tierConfig.windowMs,
1691
+ max: tierConfig.maxRequests,
1692
+ message: createRateLimitResponse(tierConfig.message),
1693
+ standardHeaders,
1694
+ legacyHeaders,
1695
+ keyGenerator,
1696
+ skip,
1697
+ handler,
1698
+ skipSuccessfulRequests: tierConfig.skipSuccessfulRequests,
1699
+ skipFailedRequests: tierConfig.skipFailedRequests
1700
+ });
1701
+ };
1702
+ var createStandardRateLimiter = (config = {}, options = {}) => {
1703
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.STANDARD, ...config };
1704
+ return createRateLimiter(tierConfig, options);
1705
+ };
1706
+ var createStrictRateLimiter = (config = {}, options = {}) => {
1707
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.STRICT, ...config };
1708
+ return createRateLimiter(tierConfig, options);
1709
+ };
1710
+ var createDdosRateLimiter = (config = {}, options = {}) => {
1711
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.DDOS, ...config };
1712
+ return createRateLimiter(tierConfig, options);
1713
+ };
1714
+ var createApiRateLimiter = (config = {}, options = {}) => {
1715
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.API, ...config };
1716
+ return createRateLimiter(tierConfig, {
1717
+ keyGenerator: createApiKeyGenerator(),
1718
+ ...options
1719
+ });
1720
+ };
1721
+ var RateLimiterBuilder = class {
1722
+ constructor(preset = "STANDARD") {
1723
+ const presetConfig = DEFAULT_RATE_LIMIT_TIERS[preset];
1724
+ this.config = {
1725
+ windowMs: presetConfig.windowMs,
1726
+ maxRequests: presetConfig.maxRequests,
1727
+ message: presetConfig.message,
1728
+ skipSuccessfulRequests: presetConfig.skipSuccessfulRequests ?? false,
1729
+ skipFailedRequests: presetConfig.skipFailedRequests ?? false
1730
+ };
1731
+ this.options = {};
1732
+ }
1733
+ /**
1734
+ * Set window duration
1735
+ */
1736
+ windowMs(ms) {
1737
+ this.config.windowMs = ms;
1738
+ return this;
1739
+ }
1740
+ /**
1741
+ * Set window duration in minutes
1742
+ */
1743
+ windowMinutes(minutes) {
1744
+ this.config.windowMs = minutes * 60 * 1e3;
1745
+ return this;
1746
+ }
1747
+ /**
1748
+ * Set window duration in hours
1749
+ */
1750
+ windowHours(hours) {
1751
+ this.config.windowMs = hours * 60 * 60 * 1e3;
1752
+ return this;
1753
+ }
1754
+ /**
1755
+ * Set maximum requests
1756
+ */
1757
+ max(requests) {
1758
+ this.config.maxRequests = requests;
1759
+ return this;
1760
+ }
1761
+ /**
1762
+ * Set error message
1763
+ */
1764
+ message(msg) {
1765
+ this.config.message = msg;
1766
+ return this;
1767
+ }
1768
+ /**
1769
+ * Skip successful requests
1770
+ */
1771
+ skipSuccessful(skip = true) {
1772
+ this.config.skipSuccessfulRequests = skip;
1773
+ return this;
1774
+ }
1775
+ /**
1776
+ * Skip failed requests
1777
+ */
1778
+ skipFailed(skip = true) {
1779
+ this.config.skipFailedRequests = skip;
1780
+ return this;
1781
+ }
1782
+ /**
1783
+ * Set key generator
1784
+ */
1785
+ keyBy(generator) {
1786
+ this.options.keyGenerator = generator;
1787
+ return this;
1788
+ }
1789
+ /**
1790
+ * Key by IP (default)
1791
+ */
1792
+ keyByIp() {
1793
+ this.options.keyGenerator = defaultKeyGenerator;
1794
+ return this;
1795
+ }
1796
+ /**
1797
+ * Key by API key
1798
+ */
1799
+ keyByApiKey(headerName) {
1800
+ this.options.keyGenerator = createApiKeyGenerator(headerName);
1801
+ return this;
1802
+ }
1803
+ /**
1804
+ * Skip certain requests
1805
+ */
1806
+ skipWhen(predicate) {
1807
+ this.options.skip = predicate;
1808
+ return this;
1809
+ }
1810
+ /**
1811
+ * Build the rate limiter
1812
+ */
1813
+ build() {
1814
+ return createRateLimiter(this.config, this.options);
1815
+ }
1816
+ };
1817
+ var rateLimiter = (preset) => {
1818
+ return new RateLimiterBuilder(preset);
1819
+ };
1820
+ var RATE_LIMIT_CONFIG = {
1821
+ STANDARD: DEFAULT_RATE_LIMIT_TIERS.STANDARD,
1822
+ STRICT: DEFAULT_RATE_LIMIT_TIERS.STRICT,
1823
+ DDOS: DEFAULT_RATE_LIMIT_TIERS.DDOS
1824
+ };
1825
+ var standardRateLimiter = createStandardRateLimiter();
1826
+ var strictRateLimiter = createStrictRateLimiter();
1827
+ var ddosProtectionLimiter = createDdosRateLimiter();
1828
+
1829
+ // src/server/configs/server.config.ts
1830
+ var DEFAULT_SERVER_CONFIG = {
1831
+ name: "app-server",
1832
+ version: "1.0.0",
1833
+ environment: process.env.NODE_ENV || "development",
1834
+ port: parseInt(process.env.PORT || "3000", 10),
1835
+ host: process.env.HOST || "0.0.0.0",
1836
+ basePath: "/api",
1837
+ debug: process.env.DEBUG === "true",
1838
+ trustProxy: true
1839
+ };
1840
+ var DEFAULT_DATABASE_CONFIG = {
1841
+ uri: process.env.DATABASE_URL || process.env.MONGODB_URI || "",
1842
+ name: process.env.DATABASE_NAME || "app_db",
1843
+ maxPoolSize: process.env.NODE_ENV === "production" ? 50 : 10,
1844
+ minPoolSize: process.env.NODE_ENV === "production" ? 10 : 5,
1845
+ socketTimeoutMS: 45e3,
1846
+ serverSelectionTimeoutMS: 1e4,
1847
+ maxIdleTimeMS: 1e4,
1848
+ retryWrites: true,
1849
+ retryReads: true,
1850
+ writeConcern: "majority"
1851
+ };
1852
+ var DEFAULT_AUTH_CONFIG = {
1853
+ jwtSecret: process.env.JWT_SECRET || "",
1854
+ jwtExpiresIn: process.env.JWT_EXPIRES_IN || "7d",
1855
+ refreshTokenExpiresIn: process.env.REFRESH_TOKEN_EXPIRES_IN || "30d",
1856
+ enableRefreshTokens: true,
1857
+ apiKeyHeader: "x-api-key",
1858
+ orgHeader: "x-organization-id"
1859
+ };
1860
+ var DEFAULT_LOGGING_CONFIG = {
1861
+ level: process.env.LOG_LEVEL || "info",
1862
+ logsDir: process.env.LOGS_DIR || "logs",
1863
+ maxSize: "20m",
1864
+ maxFiles: "14d",
1865
+ errorMaxFiles: "30d",
1866
+ console: true,
1867
+ file: process.env.NODE_ENV === "production",
1868
+ json: process.env.NODE_ENV === "production"
1869
+ };
1870
+ var DEFAULT_CORS_ORIGINS = {
1871
+ production: [],
1872
+ development: [
1873
+ "http://localhost:3000",
1874
+ "http://localhost:4000",
1875
+ "http://localhost:5173",
1876
+ "http://127.0.0.1:3000",
1877
+ "http://127.0.0.1:4000",
1878
+ "http://127.0.0.1:5173"
1879
+ ],
1880
+ patterns: []
1881
+ };
1882
+ var DEFAULT_RATE_LIMIT_CONFIG = {
1883
+ enabled: true,
1884
+ standard: {
1885
+ windowMs: 15 * 60 * 1e3,
1886
+ // 15 minutes
1887
+ maxRequests: 100,
1888
+ message: "Too many requests, please try again later."
1889
+ },
1890
+ strict: {
1891
+ windowMs: 15 * 60 * 1e3,
1892
+ // 15 minutes
1893
+ maxRequests: 20,
1894
+ message: "Too many requests, please try again later."
1895
+ },
1896
+ ddos: {
1897
+ windowMs: 60 * 1e3,
1898
+ // 1 minute
1899
+ maxRequests: 60,
1900
+ message: "Rate limit exceeded. Please slow down.",
1901
+ skipSuccessfulRequests: false
1902
+ }
1903
+ };
1904
+ function deepMerge(target, source) {
1905
+ const result = { ...target };
1906
+ for (const key in source) {
1907
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1908
+ const sourceValue = source[key];
1909
+ const targetValue = target[key];
1910
+ if (sourceValue !== void 0 && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
1911
+ result[key] = deepMerge(
1912
+ targetValue,
1913
+ sourceValue
1914
+ );
1915
+ } else if (sourceValue !== void 0) {
1916
+ result[key] = sourceValue;
1917
+ }
1918
+ }
1919
+ }
1920
+ return result;
1921
+ }
1922
+ var ConfigBuilder = class {
1923
+ constructor() {
1924
+ this.config = {
1925
+ server: { ...DEFAULT_SERVER_CONFIG },
1926
+ database: { ...DEFAULT_DATABASE_CONFIG },
1927
+ auth: { ...DEFAULT_AUTH_CONFIG },
1928
+ logging: { ...DEFAULT_LOGGING_CONFIG },
1929
+ cors: { ...DEFAULT_CORS_ORIGINS },
1930
+ rateLimit: { ...DEFAULT_RATE_LIMIT_CONFIG }
1931
+ };
1932
+ }
1933
+ /**
1934
+ * Set server configuration
1935
+ */
1936
+ setServer(config) {
1937
+ this.config.server = deepMerge(this.config.server, config);
1938
+ return this;
1939
+ }
1940
+ /**
1941
+ * Set database configuration
1942
+ */
1943
+ setDatabase(config) {
1944
+ this.config.database = deepMerge(this.config.database, config);
1945
+ return this;
1946
+ }
1947
+ /**
1948
+ * Set auth configuration
1949
+ */
1950
+ setAuth(config) {
1951
+ this.config.auth = deepMerge(this.config.auth, config);
1952
+ return this;
1953
+ }
1954
+ /**
1955
+ * Set logging configuration
1956
+ */
1957
+ setLogging(config) {
1958
+ this.config.logging = deepMerge(this.config.logging, config);
1959
+ return this;
1960
+ }
1961
+ /**
1962
+ * Set CORS origins
1963
+ */
1964
+ setCorsOrigins(config) {
1965
+ this.config.cors = deepMerge(this.config.cors, config);
1966
+ return this;
1967
+ }
1968
+ /**
1969
+ * Add CORS production origin
1970
+ */
1971
+ addProductionOrigin(origin) {
1972
+ if (!this.config.cors.production.includes(origin)) {
1973
+ this.config.cors.production.push(origin);
1974
+ }
1975
+ return this;
1976
+ }
1977
+ /**
1978
+ * Add CORS development origin
1979
+ */
1980
+ addDevelopmentOrigin(origin) {
1981
+ if (!this.config.cors.development.includes(origin)) {
1982
+ this.config.cors.development.push(origin);
1983
+ }
1984
+ return this;
1985
+ }
1986
+ /**
1987
+ * Add CORS pattern
1988
+ */
1989
+ addCorsPattern(pattern) {
1990
+ if (!this.config.cors.patterns.includes(pattern)) {
1991
+ this.config.cors.patterns.push(pattern);
1992
+ }
1993
+ return this;
1994
+ }
1995
+ /**
1996
+ * Set rate limit configuration
1997
+ */
1998
+ setRateLimit(config) {
1999
+ this.config.rateLimit = deepMerge(this.config.rateLimit, config);
2000
+ return this;
2001
+ }
2002
+ /**
2003
+ * Add custom rate limit tier
2004
+ */
2005
+ addRateLimitTier(name, tier) {
2006
+ if (!this.config.rateLimit.custom) {
2007
+ this.config.rateLimit.custom = {};
2008
+ }
2009
+ this.config.rateLimit.custom[name] = tier;
2010
+ return this;
2011
+ }
2012
+ /**
2013
+ * Set custom configuration
2014
+ */
2015
+ setCustom(key, value) {
2016
+ if (!this.config.custom) {
2017
+ this.config.custom = {};
2018
+ }
2019
+ this.config.custom[key] = value;
2020
+ return this;
2021
+ }
2022
+ /**
2023
+ * Load configuration from environment variables
2024
+ */
2025
+ loadFromEnv() {
2026
+ if (process.env.SERVER_NAME) this.config.server.name = process.env.SERVER_NAME;
2027
+ if (process.env.SERVER_VERSION) this.config.server.version = process.env.SERVER_VERSION;
2028
+ if (process.env.PORT) this.config.server.port = parseInt(process.env.PORT, 10);
2029
+ if (process.env.HOST) this.config.server.host = process.env.HOST;
2030
+ if (process.env.BASE_PATH) this.config.server.basePath = process.env.BASE_PATH;
2031
+ if (process.env.DATABASE_URL) this.config.database.uri = process.env.DATABASE_URL;
2032
+ if (process.env.MONGODB_URI) this.config.database.uri = process.env.MONGODB_URI;
2033
+ if (process.env.DATABASE_NAME) this.config.database.name = process.env.DATABASE_NAME;
2034
+ if (process.env.JWT_SECRET) this.config.auth.jwtSecret = process.env.JWT_SECRET;
2035
+ if (process.env.JWT_EXPIRES_IN) this.config.auth.jwtExpiresIn = process.env.JWT_EXPIRES_IN;
2036
+ if (process.env.LOG_LEVEL) this.config.logging.level = process.env.LOG_LEVEL;
2037
+ if (process.env.LOGS_DIR) this.config.logging.logsDir = process.env.LOGS_DIR;
2038
+ if (process.env.CORS_ORIGINS) {
2039
+ const origins = process.env.CORS_ORIGINS.split(",").map((o) => o.trim());
2040
+ this.config.cors.production.push(...origins);
2041
+ }
2042
+ return this;
2043
+ }
2044
+ /**
2045
+ * Validate configuration
2046
+ */
2047
+ validate() {
2048
+ const errors = [];
2049
+ if (!this.config.server.name) errors.push("Server name is required");
2050
+ if (this.config.server.port < 1 || this.config.server.port > 65535) {
2051
+ errors.push("Server port must be between 1 and 65535");
2052
+ }
2053
+ if (this.config.server.environment === "production") {
2054
+ if (!this.config.auth.jwtSecret || this.config.auth.jwtSecret.length < 32) {
2055
+ errors.push("JWT secret must be at least 32 characters in production");
2056
+ }
2057
+ }
2058
+ return { valid: errors.length === 0, errors };
2059
+ }
2060
+ /**
2061
+ * Build the final configuration
2062
+ */
2063
+ build() {
2064
+ return { ...this.config };
2065
+ }
2066
+ };
2067
+ var createConfig = () => {
2068
+ return new ConfigBuilder();
2069
+ };
2070
+ var buildConfig = (partial = {}) => {
2071
+ const builder = createConfig().loadFromEnv();
2072
+ if (partial.server) builder.setServer(partial.server);
2073
+ if (partial.database) builder.setDatabase(partial.database);
2074
+ if (partial.auth) builder.setAuth(partial.auth);
2075
+ if (partial.logging) builder.setLogging(partial.logging);
2076
+ if (partial.cors) builder.setCorsOrigins(partial.cors);
2077
+ if (partial.rateLimit) builder.setRateLimit(partial.rateLimit);
2078
+ return builder.build();
2079
+ };
2080
+ var isProduction = (config) => {
2081
+ return (config?.environment || process.env.NODE_ENV) === "production";
2082
+ };
2083
+ var isDevelopment = (config) => {
2084
+ return (config?.environment || process.env.NODE_ENV) === "development";
2085
+ };
2086
+ var isTest = (config) => {
2087
+ return (config?.environment || process.env.NODE_ENV) === "test";
2088
+ };
2089
+ var getDatabaseOptions = (config) => {
2090
+ return {
2091
+ maxPoolSize: config.maxPoolSize,
2092
+ minPoolSize: config.minPoolSize,
2093
+ socketTimeoutMS: config.socketTimeoutMS,
2094
+ serverSelectionTimeoutMS: config.serverSelectionTimeoutMS,
2095
+ maxIdleTimeMS: config.maxIdleTimeMS,
2096
+ retryWrites: config.retryWrites,
2097
+ retryReads: config.retryReads,
2098
+ w: config.writeConcern
2099
+ };
2100
+ };
2101
+
773
2102
  // src/client/index.ts
774
2103
  var client_exports = {};
775
2104
  __export(client_exports, {
776
- ApiUrlBuilder: () => ApiUrlBuilder,
2105
+ API_BASE_URL: () => API_BASE_URL,
2106
+ API_PREFIX: () => API_PREFIX,
777
2107
  ClientLogger: () => ClientLogger,
778
2108
  ContactForm: () => ContactForm,
779
- EventEmitter: () => EventEmitter,
2109
+ ERROR_CODES: () => ERROR_CODES,
780
2110
  LoginForm: () => LoginForm,
781
2111
  NewsletterForm: () => NewsletterForm,
782
2112
  RegisterForm: () => RegisterForm,
2113
+ STATUS_CODES: () => STATUS_CODES,
2114
+ STATUS_MESSAGES: () => STATUS_MESSAGES,
2115
+ SUCCESS_CODES: () => SUCCESS_CODES,
783
2116
  ThemeContext: () => ThemeContext,
784
2117
  ThemeProvider: () => ThemeProvider,
785
2118
  ThemeToggle: () => ThemeToggle,
786
2119
  VALIDATION_MESSAGES: () => VALIDATION_MESSAGES,
787
- addDays: () => addDays,
788
2120
  adjustColor: () => adjustColor,
789
- appEvents: () => appEvents,
2121
+ axios: () => axiosInstance,
790
2122
  camelToKebab: () => camelToKebab,
791
2123
  capitalize: () => capitalize,
792
2124
  capitalizeWords: () => capitalizeWords,
793
- checkPackage: () => checkPackage,
794
2125
  clientLogger: () => clientLogger,
795
2126
  contactFormSchema: () => contactFormSchema,
796
2127
  copyToClipboard: () => copyToClipboard,
797
- createApiEndpoints: () => createApiEndpoints,
798
- createApiUrlBuilder: () => createApiUrlBuilder,
799
2128
  createClientLogger: () => createClientLogger,
800
2129
  createEmptyPaginationMeta: () => createEmptyPaginationMeta,
801
2130
  createErrorResponse: () => createErrorResponse,
802
- createEventEmitter: () => createEventEmitter,
803
- createHttpClient: () => createHttpClient,
804
2131
  createRegisterFormSchema: () => createRegisterFormSchema,
805
2132
  createSuccessResponse: () => createSuccessResponse,
806
2133
  createTheme: () => createTheme,
807
2134
  createThemeFromBrand: () => createThemeFromBrand,
808
2135
  cssVar: () => cssVar,
809
- deepMerge: () => deepMerge,
2136
+ deepMerge: () => deepMerge2,
810
2137
  defaultDarkTheme: () => defaultDarkTheme,
811
2138
  defaultLightTheme: () => defaultLightTheme,
2139
+ deleteRequest: () => deleteRequest,
812
2140
  dummyBannerData: () => dummyBannerData,
813
2141
  dummyFaqItems: () => dummyFaqItems,
814
2142
  dummyFeatures: () => dummyFeatures,
@@ -817,59 +2145,66 @@ __export(client_exports, {
817
2145
  dummyImage: () => dummyImage,
818
2146
  dummyPricingPlans: () => dummyPricingPlans,
819
2147
  dummyTestimonials: () => dummyTestimonials,
820
- endOfDay: () => endOfDay,
2148
+ extractData: () => extractData,
2149
+ extractMessage: () => extractMessage,
2150
+ extractNestedData: () => extractNestedData,
2151
+ extractPaginatedData: () => extractPaginatedData,
821
2152
  flattenToCssVars: () => flattenToCssVars,
822
2153
  formatDate: () => formatDate,
823
- formatDateForInput: () => formatDateForInput,
824
2154
  formatDateTime: () => formatDateTime,
825
- formatDateTimeForInput: () => formatDateTimeForInput,
826
- formatPackageCheckResult: () => formatPackageCheckResult2,
827
2155
  formatRelativeTime: () => formatRelativeTime,
828
2156
  generateCssVars: () => generateCssVars,
829
- generateNcuCommand: () => generateNcuCommand2,
2157
+ generateSlug: () => generateSlug,
2158
+ generateSnakeSlug: () => generateSnakeSlug,
2159
+ generateUrlSlug: () => generateUrlSlug,
830
2160
  getContrastColor: () => getContrastColor,
831
2161
  getErrorMessage: () => getErrorMessage,
832
2162
  getNextPage: () => getNextPage,
833
2163
  getPrevPage: () => getPrevPage,
2164
+ getRequest: () => getRequest,
834
2165
  getResponseData: () => getResponseData,
835
2166
  getSystemColorScheme: () => getSystemColorScheme,
836
2167
  hasData: () => hasData,
837
2168
  hasMorePages: () => hasMorePages,
838
2169
  hexToRgba: () => hexToRgba,
839
2170
  injectCssVars: () => injectCssVars,
840
- isClipboardAvailable: () => isClipboardAvailable,
841
2171
  isErrorResponse: () => isErrorResponse,
842
- isForbidden: () => isForbidden,
843
- isFuture: () => isFuture,
844
- isNotFound: () => isNotFound,
845
- isPast: () => isPast,
846
- isServerError: () => isServerError,
847
- isStatusError: () => isStatusError,
848
2172
  isSuccess: () => isSuccess,
849
2173
  isSuccessResponse: () => isSuccessResponse,
850
- isToday: () => isToday,
851
- isUnauthorized: () => isUnauthorized,
2174
+ isUtilErrorResponse: () => isErrorResponse2,
2175
+ isUtilSuccessResponse: () => isSuccessResponse2,
852
2176
  kebabToCamel: () => kebabToCamel,
853
2177
  loadThemeFromUrl: () => loadThemeFromUrl,
854
2178
  loadThemeMode: () => loadThemeMode,
2179
+ logger: () => logger2,
855
2180
  loginFormSchema: () => loginFormSchema,
856
2181
  loremIpsum: () => loremIpsum,
857
2182
  newsletterFormSchema: () => newsletterFormSchema,
858
2183
  packageCheck: () => packageCheck,
2184
+ parseAxiosErrorMessage: () => parseAxiosErrorMessage,
859
2185
  parseError: () => parseError,
860
- parseFullResponse: () => parseFullResponse,
861
- parseResponse: () => parseResponse,
862
- readFromClipboard: () => readFromClipboard,
2186
+ parsePaginatedResponse: () => parsePaginatedResponse,
2187
+ parseResponseData: () => parseResponseData,
2188
+ parseResponseMessage: () => parseResponseMessage,
2189
+ parseResponseStatus: () => parseResponseStatus,
2190
+ parseResponseStatusMessage: () => parseResponseStatusMessage,
2191
+ patchRequest: () => patchRequest,
2192
+ postRequest: () => postRequest,
2193
+ putRequest: () => putRequest,
863
2194
  registerFormSchema: () => registerFormSchema,
864
2195
  removeCssVars: () => removeCssVars,
865
2196
  resolveThemeMode: () => resolveThemeMode,
2197
+ safeJsonParse: () => safeJsonParse,
866
2198
  saveThemeMode: () => saveThemeMode,
2199
+ simpleMetaParseResponse: () => simpleMetaParseResponse,
2200
+ simpleParseDualDataResponse: () => simpleParseDualDataResponse,
2201
+ simpleParseResponse: () => simpleParseResponse,
867
2202
  slugify: () => slugify,
868
2203
  slugifyUnique: () => slugifyUnique,
869
- startOfDay: () => startOfDay,
870
2204
  truncate: () => truncate,
871
2205
  truncateWords: () => truncateWords,
872
2206
  unslugify: () => unslugify,
2207
+ uploadFile: () => uploadFile,
873
2208
  useBattery: () => useBattery_default,
874
2209
  useClickAway: () => useClickAway_default,
875
2210
  useContinuousRetry: () => useContinuousRetry_default,
@@ -929,112 +2264,466 @@ __export(client_exports, {
929
2264
  useToggle: () => useToggle_default,
930
2265
  useVisibilityChange: () => useVisibilityChange_default,
931
2266
  useWindowScroll: () => useWindowScroll_default,
932
- useWindowSize: () => useWindowSize_default,
933
- withAbortSignal: () => withAbortSignal,
934
- withFormData: () => withFormData,
935
- withTimeout: () => withTimeout
2267
+ useWindowSize: () => useWindowSize_default
936
2268
  });
937
- var createHttpClient = (options) => {
938
- const {
939
- baseURL,
940
- timeout = 3e4,
941
- withCredentials = true,
942
- getAuthToken,
943
- onUnauthorized,
944
- onServerError
945
- } = options;
946
- const instance = axios.create({
947
- baseURL,
948
- timeout,
949
- withCredentials,
950
- headers: {
951
- "Content-Type": "application/json"
2269
+
2270
+ // src/client/http/logger.ts
2271
+ var Logger = class {
2272
+ constructor() {
2273
+ this.isDevelopment = typeof window !== "undefined" && window.location.hostname === "localhost";
2274
+ }
2275
+ /**
2276
+ * Log informational messages
2277
+ */
2278
+ info(message, data, options) {
2279
+ if (this.isDevelopment) {
2280
+ const prefix = options?.context ? `[${options.context}]` : "";
2281
+ console.log(`${prefix} ${message}`, data ?? "");
2282
+ }
2283
+ }
2284
+ /**
2285
+ * Log warning messages
2286
+ */
2287
+ warn(message, data, options) {
2288
+ if (this.isDevelopment) {
2289
+ const prefix = options?.context ? `[${options.context}]` : "";
2290
+ console.warn(`${prefix} ${message}`, data ?? "");
952
2291
  }
953
- });
954
- instance.interceptors.request.use(
955
- (config) => {
956
- if (getAuthToken) {
957
- const token = getAuthToken();
958
- if (token && config.headers) {
959
- config.headers.Authorization = `Bearer ${token}`;
960
- }
2292
+ }
2293
+ /**
2294
+ * Log error messages
2295
+ */
2296
+ error(message, error, options) {
2297
+ const prefix = options?.context ? `[${options.context}]` : "";
2298
+ if (this.isDevelopment) {
2299
+ console.error(`${prefix} ${message}`, error, options?.metadata || "");
2300
+ }
2301
+ }
2302
+ /**
2303
+ * Log debug messages (only in development)
2304
+ */
2305
+ debug(message, data, options) {
2306
+ if (this.isDevelopment) {
2307
+ const prefix = options?.context ? `[${options.context}]` : "";
2308
+ console.debug(`${prefix} ${message}`, data || "");
2309
+ }
2310
+ }
2311
+ /**
2312
+ * Log API errors with structured information
2313
+ */
2314
+ apiError(endpoint, error, metadata) {
2315
+ this.error(`API Error: ${endpoint}`, error, {
2316
+ context: "API",
2317
+ metadata: {
2318
+ endpoint,
2319
+ ...metadata
961
2320
  }
962
- return config;
963
- },
964
- (error) => Promise.reject(error)
965
- );
966
- instance.interceptors.response.use(
967
- (response) => response,
968
- (error) => {
969
- if (error.response) {
970
- const status = error.response.status;
971
- if (status === 401 && onUnauthorized) {
972
- onUnauthorized();
973
- }
974
- if (status >= 500 && onServerError) {
975
- onServerError(error);
976
- }
2321
+ });
2322
+ }
2323
+ };
2324
+ var logger2 = new Logger();
2325
+
2326
+ // src/client/http/response-parser.ts
2327
+ var STATUS_CODES = {
2328
+ SUCCESS: 200,
2329
+ CREATED: 201,
2330
+ NO_CONTENT: 204,
2331
+ BAD_REQUEST: 400,
2332
+ UNAUTHORIZED: 401,
2333
+ FORBIDDEN: 403,
2334
+ NOT_FOUND: 404,
2335
+ CONFLICT: 409,
2336
+ ERROR: 500
2337
+ };
2338
+ var STATUS_MESSAGES = {
2339
+ SUCCESS: "success",
2340
+ CREATED: "created",
2341
+ NO_CONTENT: "no_content",
2342
+ BAD_REQUEST: "bad_request",
2343
+ UNAUTHORIZED: "unauthorized",
2344
+ FORBIDDEN: "forbidden",
2345
+ NOT_FOUND: "not_found",
2346
+ CONFLICT: "conflict",
2347
+ ERROR: "error"
2348
+ };
2349
+ var SUCCESS_CODES = [200, 201, 204];
2350
+ var ERROR_CODES = [400, 401, 403, 404, 409, 500];
2351
+ var parseResponseData = (response, fallback = null) => {
2352
+ try {
2353
+ if (!response || typeof response !== "object") {
2354
+ return fallback;
2355
+ }
2356
+ const resp = response;
2357
+ if ("data" in resp) {
2358
+ return resp["data"] ?? fallback;
2359
+ }
2360
+ return response;
2361
+ } catch (error) {
2362
+ logger2.error("Error parsing response data", error);
2363
+ return fallback;
2364
+ }
2365
+ };
2366
+ var parseResponseMessage = (response, fallback = "") => {
2367
+ try {
2368
+ if (!response || typeof response !== "object") {
2369
+ return fallback;
2370
+ }
2371
+ const resp = response;
2372
+ if ("message" in resp && typeof resp["message"] === "string") {
2373
+ return resp["message"];
2374
+ }
2375
+ return fallback;
2376
+ } catch (error) {
2377
+ logger2.error("Error parsing response message", error);
2378
+ return fallback;
2379
+ }
2380
+ };
2381
+ var parseResponseStatus = (response) => {
2382
+ try {
2383
+ if (!response || typeof response !== "object") {
2384
+ return null;
2385
+ }
2386
+ const resp = response;
2387
+ if ("statusCode" in resp && typeof resp["statusCode"] === "number") {
2388
+ return resp["statusCode"];
2389
+ }
2390
+ if ("status" in resp && typeof resp["status"] === "number") {
2391
+ return resp["status"];
2392
+ }
2393
+ return null;
2394
+ } catch (error) {
2395
+ logger2.error("Error parsing response status", error);
2396
+ return null;
2397
+ }
2398
+ };
2399
+ var parseResponseStatusMessage = (response, fallback = "") => {
2400
+ try {
2401
+ if (!response || typeof response !== "object") {
2402
+ return fallback;
2403
+ }
2404
+ const resp = response;
2405
+ if ("status" in resp && typeof resp["status"] === "string") {
2406
+ return resp["status"];
2407
+ }
2408
+ return fallback;
2409
+ } catch (error) {
2410
+ logger2.error("Error parsing response status message", error);
2411
+ return fallback;
2412
+ }
2413
+ };
2414
+ var isSuccessResponse = (response) => {
2415
+ try {
2416
+ const statusCode2 = parseResponseStatus(response);
2417
+ if (statusCode2 !== null) {
2418
+ return SUCCESS_CODES.includes(statusCode2);
2419
+ }
2420
+ const status = parseResponseStatusMessage(response);
2421
+ return [STATUS_MESSAGES.SUCCESS, STATUS_MESSAGES.CREATED, STATUS_MESSAGES.NO_CONTENT].includes(
2422
+ status
2423
+ );
2424
+ } catch (error) {
2425
+ logger2.error("Error checking response success", error);
2426
+ return false;
2427
+ }
2428
+ };
2429
+ var isErrorResponse = (response) => {
2430
+ try {
2431
+ const statusCode2 = parseResponseStatus(response);
2432
+ if (statusCode2 !== null) {
2433
+ return ERROR_CODES.includes(statusCode2);
2434
+ }
2435
+ return false;
2436
+ } catch (error) {
2437
+ logger2.error("Error checking response error", error);
2438
+ return false;
2439
+ }
2440
+ };
2441
+ var parsePaginatedResponse = (response) => {
2442
+ try {
2443
+ if (!response || typeof response !== "object") {
2444
+ return { items: [], total: 0, page: 1, limit: 10 };
2445
+ }
2446
+ const resp = response;
2447
+ let items = [];
2448
+ if ("data" in resp && Array.isArray(resp["data"])) {
2449
+ items = resp["data"];
2450
+ }
2451
+ let total = items.length;
2452
+ let page = 1;
2453
+ let limit = 10;
2454
+ let totalPages;
2455
+ if ("paginationData" in resp && resp["paginationData"] && typeof resp["paginationData"] === "object") {
2456
+ const paginationData = resp["paginationData"];
2457
+ if ("total" in paginationData && typeof paginationData["total"] === "number") {
2458
+ total = paginationData["total"];
2459
+ }
2460
+ if ("page" in paginationData && typeof paginationData["page"] === "number") {
2461
+ page = paginationData["page"];
2462
+ }
2463
+ if ("limit" in paginationData && typeof paginationData["limit"] === "number") {
2464
+ limit = paginationData["limit"];
2465
+ }
2466
+ if ("totalPages" in paginationData && typeof paginationData["totalPages"] === "number") {
2467
+ totalPages = paginationData["totalPages"];
977
2468
  }
978
- return Promise.reject(error);
979
2469
  }
980
- );
981
- return instance;
2470
+ let columns;
2471
+ if ("columns" in resp && Array.isArray(resp["columns"])) {
2472
+ columns = resp["columns"];
2473
+ }
2474
+ return {
2475
+ items,
2476
+ total,
2477
+ page,
2478
+ limit,
2479
+ ...totalPages !== void 0 && { totalPages },
2480
+ ...columns !== void 0 && { columns }
2481
+ };
2482
+ } catch (error) {
2483
+ logger2.error("Error parsing paginated response", error);
2484
+ return { items: [], total: 0, page: 1, limit: 10 };
2485
+ }
982
2486
  };
983
- var withFormData = () => ({
984
- headers: {
985
- "Content-Type": "multipart/form-data"
2487
+ var extractNestedData = (response, path2, fallback = null) => {
2488
+ try {
2489
+ const keys = path2.split(".");
2490
+ let current = response;
2491
+ for (const key of keys) {
2492
+ if (current && typeof current === "object" && key in current) {
2493
+ current = current[key];
2494
+ } else {
2495
+ return fallback;
2496
+ }
2497
+ }
2498
+ return current;
2499
+ } catch (error) {
2500
+ logger2.error("Error extracting nested data", error);
2501
+ return fallback;
986
2502
  }
987
- });
988
- var withTimeout = (ms) => ({
989
- timeout: ms
990
- });
991
- var withAbortSignal = (signal) => ({
992
- signal
993
- });
994
-
995
- // src/client/http/response-parser.ts
996
- var parseResponse = (response) => {
997
- if (response.data?.success && response.data?.data !== void 0) {
998
- return response.data.data;
2503
+ };
2504
+ var safeJsonParse = (json, fallback = null) => {
2505
+ try {
2506
+ return JSON.parse(json);
2507
+ } catch (error) {
2508
+ logger2.error("Error parsing JSON", error);
2509
+ return fallback;
999
2510
  }
1000
- return null;
1001
2511
  };
1002
- var parseFullResponse = (response) => {
1003
- return response.data;
2512
+ var parseAxiosErrorMessage = (error) => {
2513
+ try {
2514
+ if (!error || typeof error !== "object") {
2515
+ return "An unexpected error occurred";
2516
+ }
2517
+ const err = error;
2518
+ if ("response" in err && err["response"] && typeof err["response"] === "object") {
2519
+ const response = err["response"];
2520
+ if ("data" in response && response["data"] && typeof response["data"] === "object") {
2521
+ const data = response["data"];
2522
+ if ("data" in data && data["data"] && typeof data["data"] === "object") {
2523
+ const nestedData = data["data"];
2524
+ if ("message" in nestedData && typeof nestedData["message"] === "string") {
2525
+ return nestedData["message"];
2526
+ }
2527
+ }
2528
+ if ("message" in data && typeof data["message"] === "string") {
2529
+ return data["message"];
2530
+ }
2531
+ if ("error" in data && typeof data["error"] === "string") {
2532
+ return data["error"];
2533
+ }
2534
+ }
2535
+ }
2536
+ if ("message" in err && typeof err["message"] === "string") {
2537
+ return err["message"];
2538
+ }
2539
+ if (typeof error === "string") {
2540
+ return error;
2541
+ }
2542
+ return "An unexpected error occurred";
2543
+ } catch (parseError2) {
2544
+ logger2.error("Error parsing axios error message", parseError2);
2545
+ return "An unexpected error occurred";
2546
+ }
1004
2547
  };
1005
2548
  var parseError = (error) => {
1006
- if (error.response?.data?.message) {
1007
- return error.response.data.message;
2549
+ try {
2550
+ if (!error || typeof error !== "object") {
2551
+ return {
2552
+ message: "An unexpected error occurred",
2553
+ statusCode: null,
2554
+ data: null
2555
+ };
2556
+ }
2557
+ const err = error;
2558
+ let statusCode2 = null;
2559
+ let data = null;
2560
+ let status;
2561
+ if ("response" in err && err["response"] && typeof err["response"] === "object") {
2562
+ const response = err["response"];
2563
+ if ("status" in response && typeof response["status"] === "number") {
2564
+ statusCode2 = response["status"];
2565
+ }
2566
+ if ("data" in response && response["data"] !== void 0) {
2567
+ data = response["data"];
2568
+ if (data && typeof data === "object" && "status" in data) {
2569
+ const dataObj = data;
2570
+ if (typeof dataObj["status"] === "string") {
2571
+ status = dataObj["status"];
2572
+ }
2573
+ }
2574
+ }
2575
+ }
2576
+ if (statusCode2 === null && "statusCode" in err && typeof err["statusCode"] === "number") {
2577
+ statusCode2 = err["statusCode"];
2578
+ }
2579
+ if (data === null && "data" in err && err["data"] !== void 0) {
2580
+ data = err["data"];
2581
+ }
2582
+ if (!status && "status" in err && typeof err["status"] === "string") {
2583
+ status = err["status"];
2584
+ }
2585
+ return {
2586
+ message: parseAxiosErrorMessage(error),
2587
+ statusCode: statusCode2,
2588
+ data,
2589
+ ...status !== void 0 && { status }
2590
+ };
2591
+ } catch (err) {
2592
+ logger2.error("Error parsing error object", err);
2593
+ return {
2594
+ message: "An unexpected error occurred",
2595
+ statusCode: null,
2596
+ data: null
2597
+ };
2598
+ }
2599
+ };
2600
+ var simpleParseResponse = (response) => {
2601
+ return response?.data?.data?.data;
2602
+ };
2603
+ var simpleMetaParseResponse = (response) => {
2604
+ return response?.data?.data?.meta;
2605
+ };
2606
+ var simpleParseDualDataResponse = (response) => {
2607
+ return response?.data?.data;
2608
+ };
2609
+
2610
+ // src/client/http/http.ts
2611
+ var isDevelopment2 = typeof window !== "undefined" && window.location.hostname === "localhost";
2612
+ var API_BASE_URL = isDevelopment2 ? "http://localhost:4002" : "https://service-api.exyconn.com";
2613
+ var API_PREFIX = "/v1/api";
2614
+ var axiosInstance = axios.create({
2615
+ baseURL: API_BASE_URL,
2616
+ timeout: 3e4,
2617
+ // 30 seconds
2618
+ headers: {
2619
+ "Content-Type": "application/json"
1008
2620
  }
1009
- if (error.response?.data?.error) {
1010
- return error.response.data.error;
2621
+ });
2622
+ axiosInstance.interceptors.request.use(
2623
+ (config) => {
2624
+ try {
2625
+ if (typeof window !== "undefined" && window.localStorage) {
2626
+ const selectedOrg = localStorage.getItem("selectedOrganization");
2627
+ if (selectedOrg) {
2628
+ const org = JSON.parse(selectedOrg);
2629
+ if (org && org._id) {
2630
+ config.headers["x-organization-id"] = org._id;
2631
+ }
2632
+ }
2633
+ }
2634
+ } catch (error) {
2635
+ logger2.warn("Failed to read organization from localStorage", error);
2636
+ }
2637
+ return config;
2638
+ },
2639
+ (error) => {
2640
+ return Promise.reject(error);
1011
2641
  }
1012
- if (error.code === "ERR_NETWORK") {
1013
- return "Network error. Please check your connection.";
2642
+ );
2643
+ axiosInstance.interceptors.response.use(
2644
+ (response) => response,
2645
+ (error) => {
2646
+ const parsedError = parseError(error);
2647
+ logger2.error("API Error", parsedError);
2648
+ return Promise.reject(parsedError);
1014
2649
  }
1015
- if (error.code === "ECONNABORTED") {
1016
- return "Request timed out. Please try again.";
2650
+ );
2651
+ var buildHeaders = (customHeaders) => {
2652
+ const headers = {
2653
+ "Content-Type": "application/json",
2654
+ ...customHeaders
2655
+ };
2656
+ return headers;
2657
+ };
2658
+ var buildConfig2 = (params, customHeaders) => {
2659
+ const config = {
2660
+ headers: buildHeaders(customHeaders)
2661
+ };
2662
+ if (params) {
2663
+ config.params = params;
1017
2664
  }
1018
- return error.message || "An unexpected error occurred.";
2665
+ return config;
1019
2666
  };
1020
- var isSuccess = (response) => {
1021
- return response.data?.success === true;
2667
+ var getRequest = async (url, params, customHeaders) => {
2668
+ const config = buildConfig2(params, customHeaders);
2669
+ return axiosInstance.get(url, config);
2670
+ };
2671
+ var postRequest = async (url, data, customHeaders) => {
2672
+ const config = buildConfig2(void 0, customHeaders);
2673
+ return axiosInstance.post(url, data, config);
2674
+ };
2675
+ var putRequest = async (url, data, customHeaders) => {
2676
+ const config = buildConfig2(void 0, customHeaders);
2677
+ return axiosInstance.put(url, data, config);
2678
+ };
2679
+ var patchRequest = async (url, data, customHeaders) => {
2680
+ const config = buildConfig2(void 0, customHeaders);
2681
+ return axiosInstance.patch(url, data, config);
2682
+ };
2683
+ var deleteRequest = async (url, params, customHeaders) => {
2684
+ const config = buildConfig2(params, customHeaders);
2685
+ return axiosInstance.delete(url, config);
2686
+ };
2687
+ var uploadFile = async (url, file, additionalData) => {
2688
+ const formData = new FormData();
2689
+ formData.append("file", file);
2690
+ if (additionalData) {
2691
+ Object.entries(additionalData).forEach(([key, value]) => {
2692
+ formData.append(key, String(value));
2693
+ });
2694
+ }
2695
+ const config = {
2696
+ headers: {
2697
+ "Content-Type": "multipart/form-data"
2698
+ }
2699
+ };
2700
+ return axiosInstance.post(url, formData, config);
2701
+ };
2702
+ var extractData = (response) => {
2703
+ return parseResponseData(response.data);
2704
+ };
2705
+ var extractMessage = (response) => {
2706
+ return parseResponseMessage(response, "");
1022
2707
  };
1023
- var isStatusError = (error, statusCode2) => {
1024
- return error.response?.status === statusCode2;
2708
+ var isSuccess = (response) => {
2709
+ return response.status >= 200 && response.status < 300;
1025
2710
  };
1026
- var isUnauthorized = (error) => {
1027
- return isStatusError(error, 401);
2711
+ var extractPaginatedData = (response) => {
2712
+ return parsePaginatedResponse(response.data);
1028
2713
  };
1029
- var isForbidden = (error) => {
1030
- return isStatusError(error, 403);
2714
+
2715
+ // src/client/http/slug.ts
2716
+ var generateSlug = (text) => {
2717
+ if (!text) return "";
2718
+ return text.trim().replace(/[^\w\s]/g, "").replace(/\s+(.)/g, (_, char) => char.toUpperCase()).replace(/\s+/g, "").replace(/^(.)/, (_, char) => char.toLowerCase());
1031
2719
  };
1032
- var isNotFound = (error) => {
1033
- return isStatusError(error, 404);
2720
+ var generateUrlSlug = (text) => {
2721
+ if (!text) return "";
2722
+ return text.trim().toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
1034
2723
  };
1035
- var isServerError = (error) => {
1036
- const status = error.response?.status;
1037
- return status !== void 0 && status >= 500;
2724
+ var generateSnakeSlug = (text) => {
2725
+ if (!text) return "";
2726
+ return text.trim().toLowerCase().replace(/[^\w\s]/g, "").replace(/\s+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
1038
2727
  };
1039
2728
 
1040
2729
  // src/client/logger/client-logger.ts
@@ -1190,40 +2879,6 @@ var formatRelativeTime = (date) => {
1190
2879
  }
1191
2880
  return "just now";
1192
2881
  };
1193
- var formatDateForInput = (date) => {
1194
- const dateObj = new Date(date);
1195
- return dateObj.toISOString().split("T")[0];
1196
- };
1197
- var formatDateTimeForInput = (date) => {
1198
- const dateObj = new Date(date);
1199
- return dateObj.toISOString().slice(0, 16);
1200
- };
1201
- var isToday = (date) => {
1202
- const dateObj = new Date(date);
1203
- const today = /* @__PURE__ */ new Date();
1204
- return dateObj.getDate() === today.getDate() && dateObj.getMonth() === today.getMonth() && dateObj.getFullYear() === today.getFullYear();
1205
- };
1206
- var isPast = (date) => {
1207
- return new Date(date).getTime() < Date.now();
1208
- };
1209
- var isFuture = (date) => {
1210
- return new Date(date).getTime() > Date.now();
1211
- };
1212
- var addDays = (date, days) => {
1213
- const dateObj = new Date(date);
1214
- dateObj.setDate(dateObj.getDate() + days);
1215
- return dateObj;
1216
- };
1217
- var startOfDay = (date) => {
1218
- const dateObj = new Date(date);
1219
- dateObj.setHours(0, 0, 0, 0);
1220
- return dateObj;
1221
- };
1222
- var endOfDay = (date) => {
1223
- const dateObj = new Date(date);
1224
- dateObj.setHours(23, 59, 59, 999);
1225
- return dateObj;
1226
- };
1227
2882
 
1228
2883
  // src/client/utils/clipboard.ts
1229
2884
  var copyToClipboard = async (text) => {
@@ -1248,20 +2903,6 @@ var copyToClipboard = async (text) => {
1248
2903
  return false;
1249
2904
  }
1250
2905
  };
1251
- var readFromClipboard = async () => {
1252
- try {
1253
- if (navigator.clipboard && window.isSecureContext) {
1254
- return await navigator.clipboard.readText();
1255
- }
1256
- return null;
1257
- } catch (error) {
1258
- console.error("Failed to read from clipboard:", error);
1259
- return null;
1260
- }
1261
- };
1262
- var isClipboardAvailable = () => {
1263
- return !!(navigator.clipboard && window.isSecureContext);
1264
- };
1265
2906
 
1266
2907
  // src/client/utils/slug.ts
1267
2908
  var slugify = (text) => {
@@ -1298,165 +2939,15 @@ var kebabToCamel = (text) => {
1298
2939
  return text.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
1299
2940
  };
1300
2941
 
1301
- // src/client/utils/events.ts
1302
- var EventEmitter = class {
1303
- constructor() {
1304
- this.handlers = /* @__PURE__ */ new Map();
1305
- }
1306
- /**
1307
- * Subscribe to an event
1308
- * @returns Unsubscribe function
1309
- */
1310
- on(event, handler) {
1311
- if (!this.handlers.has(event)) {
1312
- this.handlers.set(event, /* @__PURE__ */ new Set());
1313
- }
1314
- this.handlers.get(event).add(handler);
1315
- return () => this.off(event, handler);
1316
- }
1317
- /**
1318
- * Subscribe to an event once
1319
- */
1320
- once(event, handler) {
1321
- const wrappedHandler = (data) => {
1322
- this.off(event, wrappedHandler);
1323
- handler(data);
1324
- };
1325
- return this.on(event, wrappedHandler);
1326
- }
1327
- /**
1328
- * Unsubscribe from an event
1329
- */
1330
- off(event, handler) {
1331
- const eventHandlers = this.handlers.get(event);
1332
- if (eventHandlers) {
1333
- eventHandlers.delete(handler);
1334
- }
1335
- }
1336
- /**
1337
- * Emit an event
1338
- */
1339
- emit(event, data) {
1340
- const eventHandlers = this.handlers.get(event);
1341
- if (eventHandlers) {
1342
- eventHandlers.forEach((handler) => {
1343
- try {
1344
- handler(data);
1345
- } catch (error) {
1346
- console.error(`Error in event handler for "${String(event)}":`, error);
1347
- }
1348
- });
1349
- }
1350
- }
1351
- /**
1352
- * Remove all handlers for an event (or all events)
1353
- */
1354
- removeAllListeners(event) {
1355
- if (event) {
1356
- this.handlers.delete(event);
1357
- } else {
1358
- this.handlers.clear();
1359
- }
1360
- }
1361
- /**
1362
- * Get count of listeners for an event
1363
- */
1364
- listenerCount(event) {
1365
- return this.handlers.get(event)?.size ?? 0;
1366
- }
1367
- };
1368
- var createEventEmitter = () => {
1369
- return new EventEmitter();
1370
- };
1371
- var appEvents = new EventEmitter();
1372
-
1373
- // src/client/utils/api-urls.ts
1374
- var ApiUrlBuilder = class {
1375
- constructor(config) {
1376
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
1377
- this.version = config.version || "";
1378
- }
1379
- /**
1380
- * Build full URL from path
1381
- */
1382
- build(path2) {
1383
- const normalizedPath = path2.startsWith("/") ? path2 : `/${path2}`;
1384
- const versionPath = this.version ? `/${this.version}` : "";
1385
- return `${this.baseUrl}${versionPath}${normalizedPath}`;
1386
- }
1387
- /**
1388
- * Build URL with query parameters
1389
- */
1390
- buildWithParams(path2, params) {
1391
- const url = this.build(path2);
1392
- const filteredParams = Object.entries(params).filter(([, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`).join("&");
1393
- return filteredParams ? `${url}?${filteredParams}` : url;
1394
- }
1395
- /**
1396
- * Build URL with path parameters
1397
- */
1398
- buildWithPathParams(template, params) {
1399
- let path2 = template;
1400
- Object.entries(params).forEach(([key, value]) => {
1401
- path2 = path2.replace(`:${key}`, String(value));
1402
- path2 = path2.replace(`{${key}}`, String(value));
1403
- });
1404
- return this.build(path2);
1405
- }
1406
- /**
1407
- * Get base URL
1408
- */
1409
- getBaseUrl() {
1410
- return this.baseUrl;
1411
- }
1412
- /**
1413
- * Set new base URL
1414
- */
1415
- setBaseUrl(baseUrl) {
1416
- this.baseUrl = baseUrl.replace(/\/$/, "");
1417
- }
1418
- };
1419
- var createApiUrlBuilder = (config) => {
1420
- return new ApiUrlBuilder(config);
1421
- };
1422
- var createApiEndpoints = (builder) => ({
1423
- // Auth endpoints
1424
- auth: {
1425
- login: () => builder.build("/auth/login"),
1426
- register: () => builder.build("/auth/register"),
1427
- logout: () => builder.build("/auth/logout"),
1428
- refresh: () => builder.build("/auth/refresh"),
1429
- me: () => builder.build("/auth/me"),
1430
- forgotPassword: () => builder.build("/auth/forgot-password"),
1431
- resetPassword: () => builder.build("/auth/reset-password")
1432
- },
1433
- // User endpoints
1434
- users: {
1435
- list: () => builder.build("/users"),
1436
- get: (id) => builder.buildWithPathParams("/users/:id", { id }),
1437
- create: () => builder.build("/users"),
1438
- update: (id) => builder.buildWithPathParams("/users/:id", { id }),
1439
- delete: (id) => builder.buildWithPathParams("/users/:id", { id })
1440
- },
1441
- // Generic CRUD factory
1442
- crud: (resource) => ({
1443
- list: () => builder.build(`/${resource}`),
1444
- get: (id) => builder.buildWithPathParams(`/${resource}/:id`, { id }),
1445
- create: () => builder.build(`/${resource}`),
1446
- update: (id) => builder.buildWithPathParams(`/${resource}/:id`, { id }),
1447
- delete: (id) => builder.buildWithPathParams(`/${resource}/:id`, { id })
1448
- })
1449
- });
1450
-
1451
2942
  // src/client/utils/response-parser.ts
1452
- var isSuccessResponse = (response) => {
2943
+ var isSuccessResponse2 = (response) => {
1453
2944
  return response.success === true;
1454
2945
  };
1455
- var isErrorResponse = (response) => {
2946
+ var isErrorResponse2 = (response) => {
1456
2947
  return response.success === false;
1457
2948
  };
1458
2949
  var getResponseData = (response, defaultValue) => {
1459
- if (isSuccessResponse(response) && response.data !== void 0) {
2950
+ if (isSuccessResponse2(response) && response.data !== void 0) {
1460
2951
  return response.data;
1461
2952
  }
1462
2953
  return defaultValue;
@@ -3697,18 +5188,18 @@ function useLogger(componentName, props, options = {}) {
3697
5188
  const {
3698
5189
  logProps = true,
3699
5190
  logLifecycle = true,
3700
- logger: logger2 = console.log
5191
+ logger: logger3 = console.log
3701
5192
  } = options;
3702
5193
  const previousProps = useRef(props);
3703
5194
  const renderCount = useRef(0);
3704
5195
  renderCount.current++;
3705
5196
  useEffect(() => {
3706
5197
  if (logLifecycle) {
3707
- logger2(`[${componentName}] Mounted`);
5198
+ logger3(`[${componentName}] Mounted`);
3708
5199
  }
3709
5200
  return () => {
3710
5201
  if (logLifecycle) {
3711
- logger2(`[${componentName}] Unmounted (rendered ${renderCount.current} times)`);
5202
+ logger3(`[${componentName}] Unmounted (rendered ${renderCount.current} times)`);
3712
5203
  }
3713
5204
  };
3714
5205
  }, []);
@@ -3740,12 +5231,12 @@ function useLogger(componentName, props, options = {}) {
3740
5231
  });
3741
5232
  }
3742
5233
  if (hasChanges) {
3743
- logger2(`[${componentName}] Props changed:`, changedProps);
5234
+ logger3(`[${componentName}] Props changed:`, changedProps);
3744
5235
  }
3745
5236
  previousProps.current = props;
3746
- }, [componentName, props, logProps, logger2]);
5237
+ }, [componentName, props, logProps, logger3]);
3747
5238
  if (process.env.NODE_ENV === "development") {
3748
- logger2(`[${componentName}] Render #${renderCount.current}`);
5239
+ logger3(`[${componentName}] Render #${renderCount.current}`);
3749
5240
  }
3750
5241
  }
3751
5242
  var useLogger_default = useLogger;
@@ -4943,14 +6434,14 @@ var defaultDarkTheme = {
4943
6434
  };
4944
6435
 
4945
6436
  // src/client/web/theme/theme-utils.ts
4946
- function deepMerge(target, source) {
6437
+ function deepMerge2(target, source) {
4947
6438
  const output = { ...target };
4948
6439
  for (const key in source) {
4949
6440
  if (Object.prototype.hasOwnProperty.call(source, key)) {
4950
6441
  const sourceValue = source[key];
4951
6442
  const targetValue = target[key];
4952
6443
  if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
4953
- output[key] = deepMerge(
6444
+ output[key] = deepMerge2(
4954
6445
  targetValue,
4955
6446
  sourceValue
4956
6447
  );
@@ -5016,7 +6507,7 @@ function createThemeFromBrand(brand, baseTheme = defaultLightTheme) {
5016
6507
  }
5017
6508
  }
5018
6509
  };
5019
- return deepMerge(baseTheme, brandOverrides);
6510
+ return deepMerge2(baseTheme, brandOverrides);
5020
6511
  }
5021
6512
  function adjustColor(hex, percent) {
5022
6513
  hex = hex.replace(/^#/, "");
@@ -5110,8 +6601,8 @@ async function createTheme(config = {}) {
5110
6601
  if (config.themeUrl) {
5111
6602
  const urlTheme = await loadThemeFromUrl(config.themeUrl);
5112
6603
  if (urlTheme) {
5113
- lightTheme = deepMerge(lightTheme, urlTheme);
5114
- darkTheme = deepMerge(darkTheme, urlTheme);
6604
+ lightTheme = deepMerge2(lightTheme, urlTheme);
6605
+ darkTheme = deepMerge2(darkTheme, urlTheme);
5115
6606
  }
5116
6607
  }
5117
6608
  if (config.brandIdentity) {
@@ -5119,10 +6610,10 @@ async function createTheme(config = {}) {
5119
6610
  darkTheme = createThemeFromBrand(config.brandIdentity, darkTheme);
5120
6611
  }
5121
6612
  if (config.light) {
5122
- lightTheme = deepMerge(lightTheme, config.light);
6613
+ lightTheme = deepMerge2(lightTheme, config.light);
5123
6614
  }
5124
6615
  if (config.dark) {
5125
- darkTheme = deepMerge(darkTheme, config.dark);
6616
+ darkTheme = deepMerge2(darkTheme, config.dark);
5126
6617
  }
5127
6618
  return { light: lightTheme, dark: darkTheme };
5128
6619
  }
@@ -5196,7 +6687,7 @@ function ThemeProvider({
5196
6687
  theme2 = createThemeFromBrand(brandIdentity, theme2);
5197
6688
  }
5198
6689
  if (lightOverrides) {
5199
- theme2 = deepMerge(theme2, lightOverrides);
6690
+ theme2 = deepMerge2(theme2, lightOverrides);
5200
6691
  }
5201
6692
  return theme2;
5202
6693
  });
@@ -5207,7 +6698,7 @@ function ThemeProvider({
5207
6698
  theme2 = createThemeFromBrand(brandIdentity, theme2);
5208
6699
  }
5209
6700
  if (darkOverrides) {
5210
- theme2 = deepMerge(theme2, darkOverrides);
6701
+ theme2 = deepMerge2(theme2, darkOverrides);
5211
6702
  }
5212
6703
  return theme2;
5213
6704
  });
@@ -5226,8 +6717,8 @@ function ThemeProvider({
5226
6717
  setError(null);
5227
6718
  loadThemeFromUrl(themeUrl).then((urlTheme) => {
5228
6719
  if (urlTheme) {
5229
- setLightTheme((prev) => deepMerge(prev, urlTheme));
5230
- setDarkTheme((prev) => deepMerge(prev, urlTheme));
6720
+ setLightTheme((prev) => deepMerge2(prev, urlTheme));
6721
+ setDarkTheme((prev) => deepMerge2(prev, urlTheme));
5231
6722
  }
5232
6723
  }).catch((err) => {
5233
6724
  setError(err instanceof Error ? err.message : "Failed to load theme");
@@ -5272,8 +6763,8 @@ function ThemeProvider({
5272
6763
  });
5273
6764
  }, []);
5274
6765
  const updateTheme = useCallback((updates) => {
5275
- setLightTheme((prev) => deepMerge(prev, updates));
5276
- setDarkTheme((prev) => deepMerge(prev, updates));
6766
+ setLightTheme((prev) => deepMerge2(prev, updates));
6767
+ setDarkTheme((prev) => deepMerge2(prev, updates));
5277
6768
  }, []);
5278
6769
  const resetTheme = useCallback(() => {
5279
6770
  let light = defaultLightTheme;
@@ -5283,10 +6774,10 @@ function ThemeProvider({
5283
6774
  dark = createThemeFromBrand(brandIdentity, dark);
5284
6775
  }
5285
6776
  if (lightOverrides) {
5286
- light = deepMerge(light, lightOverrides);
6777
+ light = deepMerge2(light, lightOverrides);
5287
6778
  }
5288
6779
  if (darkOverrides) {
5289
- dark = deepMerge(dark, darkOverrides);
6780
+ dark = deepMerge2(dark, darkOverrides);
5290
6781
  }
5291
6782
  setLightTheme(light);
5292
6783
  setDarkTheme(dark);
@@ -6569,7 +8060,7 @@ __export(shared_exports, {
6569
8060
  VALIDATION_PATTERNS: () => VALIDATION_PATTERNS,
6570
8061
  VALIDATION_RULES: () => VALIDATION_RULES,
6571
8062
  VISIBILITY: () => VISIBILITY,
6572
- addDays: () => addDays$1,
8063
+ addDays: () => addDays,
6573
8064
  addHours: () => addHours,
6574
8065
  addMinutes: () => addMinutes,
6575
8066
  addMonths: () => addMonths,
@@ -6591,7 +8082,7 @@ __export(shared_exports, {
6591
8082
  eachDayOfInterval: () => eachDayOfInterval,
6592
8083
  eachMonthOfInterval: () => eachMonthOfInterval,
6593
8084
  eachWeekOfInterval: () => eachWeekOfInterval,
6594
- endOfDay: () => endOfDay$1,
8085
+ endOfDay: () => endOfDay,
6595
8086
  endOfMonth: () => endOfMonth,
6596
8087
  endOfWeek: () => endOfWeek,
6597
8088
  endOfYear: () => endOfYear,
@@ -6634,18 +8125,18 @@ __export(shared_exports, {
6634
8125
  isDateBetween: () => isDateBetween,
6635
8126
  isDev: () => isDev,
6636
8127
  isEqual: () => isEqual,
6637
- isFuture: () => isFuture$1,
6638
- isPast: () => isPast$1,
8128
+ isFuture: () => isFuture,
8129
+ isPast: () => isPast,
6639
8130
  isProd: () => isProd,
6640
8131
  isSameDay: () => isSameDay,
6641
8132
  isSameMonth: () => isSameMonth,
6642
8133
  isSameWeek: () => isSameWeek,
6643
8134
  isSameYear: () => isSameYear,
6644
- isTest: () => isTest,
8135
+ isTest: () => isTest2,
6645
8136
  isThisMonth: () => isThisMonth,
6646
8137
  isThisWeek: () => isThisWeek,
6647
8138
  isThisYear: () => isThisYear,
6648
- isToday: () => isToday$1,
8139
+ isToday: () => isToday,
6649
8140
  isTomorrow: () => isTomorrow,
6650
8141
  isValid: () => isValid,
6651
8142
  isValidDate: () => isValidDate,
@@ -6665,7 +8156,7 @@ __export(shared_exports, {
6665
8156
  setMinutes: () => setMinutes,
6666
8157
  setSeconds: () => setSeconds,
6667
8158
  setTime: () => setTime,
6668
- startOfDay: () => startOfDay$1,
8159
+ startOfDay: () => startOfDay,
6669
8160
  startOfMonth: () => startOfMonth,
6670
8161
  startOfWeek: () => startOfWeek,
6671
8162
  startOfYear: () => startOfYear,
@@ -6720,7 +8211,7 @@ var isProd = () => {
6720
8211
  var isDev = () => {
6721
8212
  return process.env.NODE_ENV === "development";
6722
8213
  };
6723
- var isTest = () => {
8214
+ var isTest2 = () => {
6724
8215
  return process.env.NODE_ENV === "test";
6725
8216
  };
6726
8217
  var validateEnv = (requiredVars) => {
@@ -7159,7 +8650,7 @@ var formatRelativeTime2 = (date, baseDate) => {
7159
8650
  };
7160
8651
  var formatSmartDate = (date) => {
7161
8652
  const parsed = parseDate(date);
7162
- if (isToday$1(parsed)) {
8653
+ if (isToday(parsed)) {
7163
8654
  return `Today at ${format(parsed, DATE_FORMATS.TIME_SHORT)}`;
7164
8655
  }
7165
8656
  if (isYesterday(parsed)) {
@@ -7215,7 +8706,7 @@ var addTime = (date, amount, unit) => {
7215
8706
  case "hours":
7216
8707
  return addHours(parsed, amount);
7217
8708
  case "days":
7218
- return addDays$1(parsed, amount);
8709
+ return addDays(parsed, amount);
7219
8710
  case "weeks":
7220
8711
  return addWeeks(parsed, amount);
7221
8712
  case "months":
@@ -7282,8 +8773,8 @@ var getMonthsInRange = (start, end) => {
7282
8773
  var getDayBoundaries = (date) => {
7283
8774
  const parsed = parseDate(date);
7284
8775
  return {
7285
- start: startOfDay$1(parsed),
7286
- end: endOfDay$1(parsed)
8776
+ start: startOfDay(parsed),
8777
+ end: endOfDay(parsed)
7287
8778
  };
7288
8779
  };
7289
8780
  var getWeekBoundaries = (date, weekStartsOn = 0) => {