@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.js CHANGED
@@ -6,6 +6,7 @@ var path = require('path');
6
6
  var mongoose = require('mongoose');
7
7
  var jwt = require('jsonwebtoken');
8
8
  var fs = require('fs');
9
+ var rateLimit = require('express-rate-limit');
9
10
  var axios = require('axios');
10
11
  var react = require('react');
11
12
  var jsxRuntime = require('react/jsx-runtime');
@@ -39,6 +40,7 @@ var DailyRotateFile__default = /*#__PURE__*/_interopDefault(DailyRotateFile);
39
40
  var path__default = /*#__PURE__*/_interopDefault(path);
40
41
  var mongoose__default = /*#__PURE__*/_interopDefault(mongoose);
41
42
  var jwt__default = /*#__PURE__*/_interopDefault(jwt);
43
+ var rateLimit__default = /*#__PURE__*/_interopDefault(rateLimit);
42
44
  var axios__default = /*#__PURE__*/_interopDefault(axios);
43
45
  var Yup__namespace = /*#__PURE__*/_interopNamespace(Yup);
44
46
 
@@ -51,44 +53,89 @@ var __export = (target, all) => {
51
53
  // src/server/index.ts
52
54
  var server_exports = {};
53
55
  __export(server_exports, {
56
+ ConfigBuilder: () => ConfigBuilder,
57
+ DEFAULT_AUTH_CONFIG: () => DEFAULT_AUTH_CONFIG,
58
+ DEFAULT_CORS_CONFIG: () => DEFAULT_CORS_CONFIG,
59
+ DEFAULT_CORS_ORIGINS: () => DEFAULT_CORS_ORIGINS,
60
+ DEFAULT_DATABASE_CONFIG: () => DEFAULT_DATABASE_CONFIG,
61
+ DEFAULT_LOGGING_CONFIG: () => DEFAULT_LOGGING_CONFIG,
62
+ DEFAULT_RATE_LIMIT_CONFIG: () => DEFAULT_RATE_LIMIT_CONFIG,
63
+ DEFAULT_RATE_LIMIT_TIERS: () => DEFAULT_RATE_LIMIT_TIERS,
64
+ DEFAULT_SERVER_CONFIG: () => DEFAULT_SERVER_CONFIG,
65
+ EXYCONN_CORS_CONFIG: () => EXYCONN_CORS_CONFIG,
66
+ PERMISSIVE_CORS_CONFIG: () => PERMISSIVE_CORS_CONFIG,
67
+ RATE_LIMIT_CONFIG: () => RATE_LIMIT_CONFIG,
68
+ RateLimiterBuilder: () => RateLimiterBuilder,
69
+ STRICT_CORS_CONFIG: () => STRICT_CORS_CONFIG,
54
70
  StatusCode: () => StatusCode,
55
71
  StatusMessage: () => StatusMessage,
56
72
  authenticateApiKey: () => authenticateApiKey,
57
73
  authenticateJWT: () => authenticateJWT,
58
74
  badRequestResponse: () => badRequestResponse,
75
+ buildConfig: () => buildConfig,
76
+ buildDeleteFilter: () => buildDeleteFilter,
59
77
  buildFilter: () => buildFilter,
60
78
  buildPagination: () => buildPagination,
61
79
  buildPaginationMeta: () => buildPaginationMeta,
62
80
  checkPackageServer: () => checkPackageServer,
63
81
  conflictResponse: () => conflictResponse,
64
82
  connectDB: () => connectDB,
83
+ corsOptions: () => corsOptions,
84
+ createApiKeyGenerator: () => createApiKeyGenerator,
85
+ createApiRateLimiter: () => createApiRateLimiter,
86
+ createBrandCorsOptions: () => createBrandCorsOptions,
87
+ createBulkDeleteHandler: () => createBulkDeleteHandler,
88
+ createConfig: () => createConfig,
89
+ createCorsOptions: () => createCorsOptions,
90
+ createCrudControllers: () => createCrudControllers,
91
+ createDdosRateLimiter: () => createDdosRateLimiter,
65
92
  createLogger: () => createLogger,
66
93
  createMorganStream: () => createMorganStream,
94
+ createMultiBrandCorsOptions: () => createMultiBrandCorsOptions,
95
+ createPaginationMiddleware: () => createPaginationMiddleware,
96
+ createPrefixedKeyGenerator: () => createPrefixedKeyGenerator,
97
+ createRateLimiter: () => createRateLimiter,
98
+ createStandardRateLimiter: () => createStandardRateLimiter,
99
+ createStrictRateLimiter: () => createStrictRateLimiter,
100
+ createUserKeyGenerator: () => createUserKeyGenerator,
67
101
  createdResponse: () => createdResponse,
102
+ ddosProtectionLimiter: () => ddosProtectionLimiter,
103
+ defaultKeyGenerator: () => defaultKeyGenerator,
68
104
  disconnectDB: () => disconnectDB,
69
105
  errorResponse: () => errorResponse,
70
106
  extractColumns: () => extractColumns,
71
107
  extractOrganization: () => extractOrganization,
108
+ extractSchemaMeta: () => extractSchemaMeta,
72
109
  forbiddenResponse: () => forbiddenResponse,
73
110
  formatPackageCheckResult: () => formatPackageCheckResult,
74
111
  generateNcuCommand: () => generateNcuCommand,
75
112
  getConnectionStatus: () => getConnectionStatus,
113
+ getDatabaseOptions: () => getDatabaseOptions,
114
+ isDevelopment: () => isDevelopment,
115
+ isProduction: () => isProduction,
116
+ isTest: () => isTest,
76
117
  logger: () => logger,
77
118
  noContentResponse: () => noContentResponse,
78
119
  notFoundResponse: () => notFoundResponse,
79
120
  omitFields: () => omitFields,
80
121
  optionalAuthenticateJWT: () => optionalAuthenticateJWT,
81
122
  packageCheckServer: () => packageCheckServer,
123
+ parseBulkDelete: () => parseBulkDelete,
82
124
  pickFields: () => pickFields,
83
125
  printPackageCheckSummary: () => printPackageCheckSummary,
126
+ queryPagination: () => queryPagination,
127
+ queryParser: () => queryParser,
84
128
  rateLimitResponse: () => rateLimitResponse,
129
+ rateLimiter: () => rateLimiter,
85
130
  requireOrganization: () => requireOrganization,
86
131
  sanitizeDocument: () => sanitizeDocument,
87
132
  sanitizeUser: () => sanitizeUser,
88
133
  simpleLogger: () => simpleLogger,
134
+ standardRateLimiter: () => standardRateLimiter,
89
135
  statusCode: () => statusCode,
90
136
  statusMessage: () => statusMessage,
91
137
  stream: () => stream,
138
+ strictRateLimiter: () => strictRateLimiter,
92
139
  successResponse: () => successResponse,
93
140
  successResponseArr: () => successResponseArr,
94
141
  unauthorizedResponse: () => unauthorizedResponse,
@@ -371,37 +418,37 @@ var defaultOptions = {
371
418
  retryReads: true,
372
419
  w: "majority"
373
420
  };
374
- var connectDB = async (mongoUri, options = {}, logger2) => {
421
+ var connectDB = async (mongoUri, options = {}, logger3) => {
375
422
  if (mongoose__default.default.connection.readyState === 1) {
376
- logger2?.info("Database already connected, reusing connection");
423
+ logger3?.info("Database already connected, reusing connection");
377
424
  return mongoose__default.default;
378
425
  }
379
426
  const finalOptions = { ...defaultOptions, ...options };
380
427
  try {
381
428
  await mongoose__default.default.connect(mongoUri, finalOptions);
382
- logger2?.info("MongoDB connected successfully");
429
+ logger3?.info("MongoDB connected successfully");
383
430
  mongoose__default.default.connection.on("error", (err) => {
384
- logger2?.error("MongoDB connection error", err);
431
+ logger3?.error("MongoDB connection error", err);
385
432
  });
386
433
  mongoose__default.default.connection.on("disconnected", () => {
387
- logger2?.info("MongoDB disconnected");
434
+ logger3?.info("MongoDB disconnected");
388
435
  });
389
436
  mongoose__default.default.connection.on("reconnected", () => {
390
- logger2?.info("MongoDB reconnected");
437
+ logger3?.info("MongoDB reconnected");
391
438
  });
392
439
  return mongoose__default.default;
393
440
  } catch (error) {
394
441
  const errorMessage = error instanceof Error ? error.message : String(error);
395
- logger2?.error("MongoDB connection failed", { error: errorMessage });
442
+ logger3?.error("MongoDB connection failed", { error: errorMessage });
396
443
  throw error;
397
444
  }
398
445
  };
399
- var disconnectDB = async (logger2) => {
446
+ var disconnectDB = async (logger3) => {
400
447
  try {
401
448
  await mongoose__default.default.disconnect();
402
- logger2?.info("MongoDB disconnected successfully");
449
+ logger3?.info("MongoDB disconnected successfully");
403
450
  } catch (error) {
404
- logger2?.error("Error disconnecting from MongoDB", error);
451
+ logger3?.error("Error disconnecting from MongoDB", error);
405
452
  throw error;
406
453
  }
407
454
  };
@@ -506,6 +553,629 @@ var requireOrganization = (req, res, next) => {
506
553
  next();
507
554
  };
508
555
 
556
+ // src/server/middleware/queryParser.middleware.ts
557
+ var queryParser = (req, _, next) => {
558
+ const { page, limit, sort, sortBy, sortOrder, search, filter, ...otherParams } = req.query;
559
+ const parsed = {
560
+ page: Math.max(Number(page) || 1, 1),
561
+ limit: Math.min(Number(limit) || 10, 100),
562
+ filter: {}
563
+ };
564
+ if (typeof sort === "string") {
565
+ const [field, order] = sort.split(":");
566
+ parsed.sort = {
567
+ field,
568
+ order: order === "asc" ? "asc" : "desc"
569
+ };
570
+ } else if (typeof sortBy === "string") {
571
+ parsed.sort = {
572
+ field: sortBy,
573
+ order: sortOrder === "asc" ? "asc" : "desc"
574
+ };
575
+ }
576
+ if (typeof search === "string") {
577
+ parsed.search = search;
578
+ }
579
+ if (typeof filter === "object" && filter !== null) {
580
+ Object.entries(filter).forEach(([key, value]) => {
581
+ if (value !== "all") {
582
+ parsed.filter[key] = value;
583
+ }
584
+ });
585
+ }
586
+ Object.entries(otherParams).forEach(([key, value]) => {
587
+ if (typeof value === "string" && value !== "all" && !["page", "limit", "sort", "sortBy", "sortOrder", "search"].includes(key)) {
588
+ parsed.filter[key] = value;
589
+ }
590
+ });
591
+ req.parsedQuery = parsed;
592
+ next();
593
+ };
594
+
595
+ // src/server/middleware/utils/schemaMeta.util.ts
596
+ var getZodTypeName = (schema) => {
597
+ const typeName = schema._def?.typeName;
598
+ switch (typeName) {
599
+ case "ZodString":
600
+ return "string";
601
+ case "ZodNumber":
602
+ return "number";
603
+ case "ZodBoolean":
604
+ return "boolean";
605
+ case "ZodDate":
606
+ return "date";
607
+ case "ZodArray":
608
+ return "array";
609
+ case "ZodObject":
610
+ return "object";
611
+ case "ZodOptional":
612
+ case "ZodNullable":
613
+ return schema._def?.innerType ? getZodTypeName(schema._def.innerType) : "unknown";
614
+ case "ZodDefault":
615
+ return schema._def?.innerType ? getZodTypeName(schema._def.innerType) : "unknown";
616
+ case "ZodEnum":
617
+ return "enum";
618
+ case "ZodUnion":
619
+ return "union";
620
+ default:
621
+ return "unknown";
622
+ }
623
+ };
624
+ var isZodRequired = (schema) => {
625
+ const typeName = schema._def?.typeName;
626
+ return typeName !== "ZodOptional" && typeName !== "ZodNullable";
627
+ };
628
+ var extractSchemaMeta = (model, zodSchema) => {
629
+ const columns = [];
630
+ if (zodSchema && zodSchema.shape) {
631
+ const shape = zodSchema.shape;
632
+ for (const [key, value] of Object.entries(shape)) {
633
+ if (key.startsWith("_")) continue;
634
+ columns.push({
635
+ name: key,
636
+ datatype: getZodTypeName(value),
637
+ required: isZodRequired(value)
638
+ });
639
+ }
640
+ return columns;
641
+ }
642
+ try {
643
+ const schema = model.schema;
644
+ const paths = schema.paths;
645
+ for (const [key, pathInfo] of Object.entries(paths)) {
646
+ if (key.startsWith("_") || key === "__v") continue;
647
+ const schemaType = pathInfo;
648
+ columns.push({
649
+ name: key,
650
+ datatype: (schemaType.instance || "unknown").toLowerCase(),
651
+ required: schemaType.isRequired || false
652
+ });
653
+ }
654
+ } catch {
655
+ }
656
+ return columns;
657
+ };
658
+
659
+ // src/server/middleware/pagination.middleware.ts
660
+ var queryPagination = (model, options = {}, withOrgId = true) => {
661
+ return async (req, res, next) => {
662
+ try {
663
+ const { page, limit, sort, search, filter } = req.parsedQuery;
664
+ const query = {};
665
+ Object.entries(filter).forEach(([key, value]) => {
666
+ if (options.regexFilterFields?.includes(key)) {
667
+ query[key] = { $regex: value, $options: "i" };
668
+ } else {
669
+ query[key] = value;
670
+ }
671
+ });
672
+ const organizationId = req.headers["x-organization-id"];
673
+ if (organizationId && typeof organizationId === "string" && withOrgId) {
674
+ query.organizationId = organizationId;
675
+ }
676
+ if (search && options.searchFields?.length) {
677
+ query.$or = options.searchFields.map((field) => ({
678
+ [field]: { $regex: search, $options: "i" }
679
+ }));
680
+ }
681
+ const sortQuery = sort ? { [sort.field]: sort.order } : { createdAt: "desc" };
682
+ const skip = (page - 1) * limit;
683
+ const [data, total] = await Promise.all([
684
+ model.find(query).sort(sortQuery).skip(skip).limit(limit),
685
+ model.countDocuments(query)
686
+ ]);
687
+ res.paginatedResult = {
688
+ data,
689
+ meta: {
690
+ page,
691
+ limit,
692
+ total,
693
+ totalPages: Math.ceil(total / limit)
694
+ },
695
+ columns: extractSchemaMeta(model, options.validatorSchema)
696
+ };
697
+ next();
698
+ } catch (error) {
699
+ next(error);
700
+ }
701
+ };
702
+ };
703
+ var isZodError = (error) => {
704
+ return error !== null && typeof error === "object" && "errors" in error && Array.isArray(error.errors);
705
+ };
706
+ var getOrgId = (req, orgField = "organizationId") => {
707
+ const orgReq = req;
708
+ return orgReq.organizationId || req.headers["x-organization-id"] || req.query[orgField];
709
+ };
710
+ var buildOrgFilter = (req, config) => {
711
+ const filter = {};
712
+ if (config.withOrganization !== false) {
713
+ const orgId = getOrgId(req, config.orgField);
714
+ if (orgId) {
715
+ filter[config.orgField || "organizationId"] = orgId;
716
+ }
717
+ }
718
+ return filter;
719
+ };
720
+ var formatZodError = (error) => {
721
+ return error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
722
+ };
723
+ function createCrudControllers(config) {
724
+ const {
725
+ model,
726
+ resourceName,
727
+ createSchema,
728
+ updateSchema,
729
+ searchFields = [],
730
+ regexFilterFields = [],
731
+ withOrganization = true,
732
+ orgField = "organizationId",
733
+ transformCreate,
734
+ transformUpdate,
735
+ afterCreate,
736
+ afterUpdate,
737
+ afterDelete,
738
+ excludeFields = [],
739
+ populateFields = [],
740
+ buildQuery
741
+ } = config;
742
+ const getAll = async (req, res, _next) => {
743
+ try {
744
+ const paginatedRes = res;
745
+ if (paginatedRes.paginatedResult) {
746
+ successResponse(res, paginatedRes.paginatedResult, `${resourceName} list fetched successfully`);
747
+ return;
748
+ }
749
+ const page = parseInt(req.query.page) || 1;
750
+ const limit = parseInt(req.query.limit) || 10;
751
+ const sortField = req.query.sortBy || "createdAt";
752
+ const sortOrder = req.query.sortOrder || "desc";
753
+ const search = req.query.search;
754
+ let query = {};
755
+ if (withOrganization) {
756
+ const orgId = getOrgId(req, orgField);
757
+ if (orgId) {
758
+ query[orgField] = orgId;
759
+ }
760
+ }
761
+ if (search && searchFields.length > 0) {
762
+ query.$or = searchFields.map((field) => ({
763
+ [field]: { $regex: search, $options: "i" }
764
+ }));
765
+ }
766
+ const filterableParams = Object.keys(req.query).filter(
767
+ (key) => !["page", "limit", "sortBy", "sortOrder", "search"].includes(key)
768
+ );
769
+ filterableParams.forEach((key) => {
770
+ const value = req.query[key];
771
+ if (value !== void 0 && value !== "" && value !== "all") {
772
+ if (regexFilterFields.includes(key)) {
773
+ query[key] = { $regex: value, $options: "i" };
774
+ } else {
775
+ query[key] = value;
776
+ }
777
+ }
778
+ });
779
+ if (buildQuery) {
780
+ query = buildQuery(req, query);
781
+ }
782
+ const sortQuery = { [sortField]: sortOrder };
783
+ const skip = (page - 1) * limit;
784
+ let projection = {};
785
+ if (excludeFields.length > 0) {
786
+ projection = excludeFields.reduce(
787
+ (acc, field) => ({ ...acc, [field]: 0 }),
788
+ {}
789
+ );
790
+ }
791
+ let dbQuery = model.find(query, projection);
792
+ if (populateFields.length > 0) {
793
+ populateFields.forEach((field) => {
794
+ dbQuery = dbQuery.populate(field);
795
+ });
796
+ }
797
+ const [data, total] = await Promise.all([
798
+ dbQuery.sort(sortQuery).skip(skip).limit(limit),
799
+ model.countDocuments(query)
800
+ ]);
801
+ successResponse(
802
+ res,
803
+ {
804
+ data,
805
+ meta: {
806
+ page,
807
+ limit,
808
+ total,
809
+ totalPages: Math.ceil(total / limit)
810
+ },
811
+ columns: extractSchemaMeta(model, createSchema)
812
+ },
813
+ `${resourceName} list fetched successfully`
814
+ );
815
+ } catch (error) {
816
+ logger.error(`Error in getAll ${resourceName}`, {
817
+ error: error instanceof Error ? error.message : "Unknown error"
818
+ });
819
+ errorResponse(res, `Failed to fetch ${resourceName.toLowerCase()} list`);
820
+ }
821
+ };
822
+ const getById = async (req, res, _next) => {
823
+ try {
824
+ const { id } = req.params;
825
+ if (!id || !mongoose.Types.ObjectId.isValid(id)) {
826
+ badRequestResponse(res, "Invalid ID format");
827
+ return;
828
+ }
829
+ const query = {
830
+ _id: new mongoose.Types.ObjectId(id),
831
+ ...buildOrgFilter(req, { ...config, withOrganization, orgField })
832
+ };
833
+ let dbQuery = model.findOne(query);
834
+ if (populateFields.length > 0) {
835
+ populateFields.forEach((field) => {
836
+ dbQuery = dbQuery.populate(field);
837
+ });
838
+ }
839
+ const doc = await dbQuery;
840
+ if (!doc) {
841
+ notFoundResponse(res, `${resourceName} not found`);
842
+ return;
843
+ }
844
+ successResponse(res, doc, `${resourceName} fetched successfully`);
845
+ } catch (error) {
846
+ logger.error(`Error in getById ${resourceName}`, {
847
+ error: error instanceof Error ? error.message : "Unknown error",
848
+ id: req.params.id
849
+ });
850
+ errorResponse(res, `Failed to fetch ${resourceName.toLowerCase()}`);
851
+ }
852
+ };
853
+ const create = async (req, res, _next) => {
854
+ try {
855
+ let input = req.body;
856
+ if (createSchema) {
857
+ try {
858
+ input = createSchema.parse(input);
859
+ } catch (error) {
860
+ if (isZodError(error)) {
861
+ badRequestResponse(res, formatZodError(error));
862
+ return;
863
+ }
864
+ throw error;
865
+ }
866
+ }
867
+ if (transformCreate) {
868
+ input = transformCreate(input, req);
869
+ }
870
+ if (withOrganization) {
871
+ const orgId = getOrgId(req, orgField);
872
+ if (orgId) {
873
+ input[orgField] = orgId;
874
+ }
875
+ }
876
+ const doc = new model(input);
877
+ await doc.save();
878
+ if (afterCreate) {
879
+ await afterCreate(doc, req);
880
+ }
881
+ logger.info(`${resourceName} created successfully`, {
882
+ id: doc._id,
883
+ [orgField]: input[orgField]
884
+ });
885
+ createdResponse(res, doc, `${resourceName} created successfully`);
886
+ } catch (error) {
887
+ logger.error(`Error in create ${resourceName}`, {
888
+ error: error instanceof Error ? error.message : "Unknown error"
889
+ });
890
+ if (error.code === 11e3) {
891
+ badRequestResponse(res, `A ${resourceName.toLowerCase()} with this data already exists`);
892
+ return;
893
+ }
894
+ errorResponse(res, `Failed to create ${resourceName.toLowerCase()}`);
895
+ }
896
+ };
897
+ const update = async (req, res, _next) => {
898
+ try {
899
+ const { id } = req.params;
900
+ if (!id || !mongoose.Types.ObjectId.isValid(id)) {
901
+ badRequestResponse(res, "Invalid ID format");
902
+ return;
903
+ }
904
+ let input = req.body;
905
+ if (updateSchema) {
906
+ try {
907
+ input = updateSchema.parse(input);
908
+ } catch (error) {
909
+ if (isZodError(error)) {
910
+ badRequestResponse(res, formatZodError(error));
911
+ return;
912
+ }
913
+ throw error;
914
+ }
915
+ }
916
+ if (transformUpdate) {
917
+ input = transformUpdate(input, req);
918
+ }
919
+ const query = {
920
+ _id: new mongoose.Types.ObjectId(id),
921
+ ...buildOrgFilter(req, { ...config, withOrganization, orgField })
922
+ };
923
+ const doc = await model.findOneAndUpdate(query, { $set: input }, { new: true });
924
+ if (!doc) {
925
+ notFoundResponse(res, `${resourceName} not found`);
926
+ return;
927
+ }
928
+ if (afterUpdate) {
929
+ await afterUpdate(doc, req);
930
+ }
931
+ logger.info(`${resourceName} updated successfully`, { id });
932
+ successResponse(res, doc, `${resourceName} updated successfully`);
933
+ } catch (error) {
934
+ logger.error(`Error in update ${resourceName}`, {
935
+ error: error instanceof Error ? error.message : "Unknown error",
936
+ id: req.params.id
937
+ });
938
+ errorResponse(res, `Failed to update ${resourceName.toLowerCase()}`);
939
+ }
940
+ };
941
+ const deleteOne = async (req, res, _next) => {
942
+ try {
943
+ const { id } = req.params;
944
+ if (!id || !mongoose.Types.ObjectId.isValid(id)) {
945
+ badRequestResponse(res, "Invalid ID format");
946
+ return;
947
+ }
948
+ const query = {
949
+ _id: new mongoose.Types.ObjectId(id),
950
+ ...buildOrgFilter(req, { ...config, withOrganization, orgField })
951
+ };
952
+ const result = await model.deleteOne(query);
953
+ if (result.deletedCount === 0) {
954
+ notFoundResponse(res, `${resourceName} not found`);
955
+ return;
956
+ }
957
+ if (afterDelete) {
958
+ await afterDelete(id, req);
959
+ }
960
+ logger.info(`${resourceName} deleted successfully`, { id });
961
+ noContentResponse(res, null, `${resourceName} deleted successfully`);
962
+ } catch (error) {
963
+ logger.error(`Error in delete ${resourceName}`, {
964
+ error: error instanceof Error ? error.message : "Unknown error",
965
+ id: req.params.id
966
+ });
967
+ errorResponse(res, `Failed to delete ${resourceName.toLowerCase()}`);
968
+ }
969
+ };
970
+ const bulkDelete = async (req, res, _next) => {
971
+ try {
972
+ const bulkReq = req;
973
+ const { deleteIds = [], deleteAll = false } = bulkReq;
974
+ const baseFilter = buildOrgFilter(req, { ...config, withOrganization, orgField });
975
+ let filter;
976
+ if (deleteAll) {
977
+ filter = baseFilter;
978
+ } else if (deleteIds.length > 0) {
979
+ filter = {
980
+ ...baseFilter,
981
+ _id: { $in: deleteIds.map((id) => new mongoose.Types.ObjectId(id)) }
982
+ };
983
+ } else {
984
+ badRequestResponse(res, "No IDs provided for deletion");
985
+ return;
986
+ }
987
+ const result = await model.deleteMany(filter);
988
+ if (afterDelete && deleteIds.length > 0) {
989
+ await Promise.all(deleteIds.map((id) => afterDelete(id, req)));
990
+ }
991
+ logger.info(`${resourceName}(s) bulk deleted successfully`, {
992
+ deletedCount: result.deletedCount,
993
+ deleteAll
994
+ });
995
+ successResponse(
996
+ res,
997
+ { deletedCount: result.deletedCount },
998
+ `${result.deletedCount} ${resourceName.toLowerCase()}(s) deleted successfully`
999
+ );
1000
+ } catch (error) {
1001
+ logger.error(`Error in bulkDelete ${resourceName}`, {
1002
+ error: error instanceof Error ? error.message : "Unknown error"
1003
+ });
1004
+ errorResponse(res, `Failed to delete ${resourceName.toLowerCase()}(s)`);
1005
+ }
1006
+ };
1007
+ return {
1008
+ getAll,
1009
+ getById,
1010
+ create,
1011
+ update,
1012
+ deleteOne,
1013
+ bulkDelete
1014
+ };
1015
+ }
1016
+ function createPaginationMiddleware(model, config = {}) {
1017
+ const {
1018
+ searchFields = [],
1019
+ regexFilterFields = [],
1020
+ withOrganization = true,
1021
+ orgField = "organizationId"
1022
+ } = config;
1023
+ return async (req, res, next) => {
1024
+ try {
1025
+ const page = parseInt(req.query.page) || 1;
1026
+ const limit = parseInt(req.query.limit) || 10;
1027
+ const sortField = req.query.sortBy || "createdAt";
1028
+ const sortOrder = req.query.sortOrder || "desc";
1029
+ const search = req.query.search;
1030
+ const query = {};
1031
+ if (withOrganization) {
1032
+ const orgId = getOrgId(req, orgField);
1033
+ if (orgId) {
1034
+ query[orgField] = orgId;
1035
+ }
1036
+ }
1037
+ if (search && searchFields.length > 0) {
1038
+ query.$or = searchFields.map((field) => ({
1039
+ [field]: { $regex: search, $options: "i" }
1040
+ }));
1041
+ }
1042
+ const filterableParams = Object.keys(req.query).filter(
1043
+ (key) => !["page", "limit", "sortBy", "sortOrder", "search"].includes(key)
1044
+ );
1045
+ filterableParams.forEach((key) => {
1046
+ const value = req.query[key];
1047
+ if (value !== void 0 && value !== "" && value !== "all") {
1048
+ if (regexFilterFields.includes(key)) {
1049
+ query[key] = { $regex: value, $options: "i" };
1050
+ } else {
1051
+ query[key] = value;
1052
+ }
1053
+ }
1054
+ });
1055
+ const sortQuery = { [sortField]: sortOrder };
1056
+ const skip = (page - 1) * limit;
1057
+ const [data, total] = await Promise.all([
1058
+ model.find(query).sort(sortQuery).skip(skip).limit(limit),
1059
+ model.countDocuments(query)
1060
+ ]);
1061
+ const paginatedRes = res;
1062
+ paginatedRes.paginatedResult = {
1063
+ data,
1064
+ meta: {
1065
+ page,
1066
+ limit,
1067
+ total,
1068
+ totalPages: Math.ceil(total / limit)
1069
+ },
1070
+ columns: extractSchemaMeta(model, config.createSchema)
1071
+ };
1072
+ next();
1073
+ } catch (error) {
1074
+ next(error);
1075
+ }
1076
+ };
1077
+ }
1078
+ var parseBulkDelete = (req, res, next) => {
1079
+ try {
1080
+ const bulkReq = req;
1081
+ let ids = [];
1082
+ if (Array.isArray(req.body)) {
1083
+ ids = req.body;
1084
+ } else if (req.body && Array.isArray(req.body.ids)) {
1085
+ ids = req.body.ids;
1086
+ } else if (req.body && typeof req.body === "object") {
1087
+ if (Array.isArray(req.body.data)) {
1088
+ ids = req.body.data;
1089
+ }
1090
+ }
1091
+ if (ids.length === 0) {
1092
+ return badRequestResponse(
1093
+ res,
1094
+ 'Request body must contain an array of IDs. Use ["*"] to delete all records or ["id1", "id2"] to delete specific records.'
1095
+ );
1096
+ }
1097
+ if (ids.length === 1 && ids[0] === "*") {
1098
+ bulkReq.deleteAll = true;
1099
+ bulkReq.deleteIds = [];
1100
+ logger.info("Bulk delete: Deleting all records");
1101
+ return next();
1102
+ }
1103
+ const validIds = [];
1104
+ const invalidIds = [];
1105
+ for (const id of ids) {
1106
+ if (typeof id === "string" && mongoose.Types.ObjectId.isValid(id)) {
1107
+ validIds.push(id);
1108
+ } else {
1109
+ invalidIds.push(id);
1110
+ }
1111
+ }
1112
+ if (invalidIds.length > 0) {
1113
+ return badRequestResponse(
1114
+ res,
1115
+ `Invalid ID format(s): ${invalidIds.slice(0, 5).join(", ")}${invalidIds.length > 5 ? "..." : ""}. All IDs must be valid MongoDB ObjectIds.`
1116
+ );
1117
+ }
1118
+ if (validIds.length === 0) {
1119
+ return badRequestResponse(res, "No valid IDs provided for deletion.");
1120
+ }
1121
+ bulkReq.deleteAll = false;
1122
+ bulkReq.deleteIds = validIds;
1123
+ logger.info(`Bulk delete: Deleting ${validIds.length} record(s)`);
1124
+ next();
1125
+ } catch (error) {
1126
+ logger.error("Error in parseBulkDelete middleware", error);
1127
+ return badRequestResponse(res, "Failed to parse delete request");
1128
+ }
1129
+ };
1130
+ var buildDeleteFilter = (req, organizationId) => {
1131
+ const filter = {
1132
+ organizationId: new mongoose.Types.ObjectId(organizationId)
1133
+ };
1134
+ if (!req.deleteAll && req.deleteIds && req.deleteIds.length > 0) {
1135
+ filter._id = {
1136
+ $in: req.deleteIds.map((id) => new mongoose.Types.ObjectId(id))
1137
+ };
1138
+ }
1139
+ return filter;
1140
+ };
1141
+ var createBulkDeleteHandler = (Model2, modelName) => {
1142
+ return async (req, res) => {
1143
+ const bulkReq = req;
1144
+ const organizationId = req.headers["x-organization-id"];
1145
+ if (!organizationId) {
1146
+ return badRequestResponse(res, "Organization ID is required");
1147
+ }
1148
+ try {
1149
+ const filter = buildDeleteFilter(bulkReq, organizationId);
1150
+ const result = await Model2.deleteMany(filter);
1151
+ const deletedCount = result.deletedCount || 0;
1152
+ logger.info(`Bulk delete completed: ${deletedCount} ${modelName}(s) deleted`, {
1153
+ organizationId,
1154
+ deleteAll: bulkReq.deleteAll,
1155
+ requestedIds: bulkReq.deleteIds?.length || "all",
1156
+ deletedCount
1157
+ });
1158
+ return res.status(200).json({
1159
+ message: `Successfully deleted ${deletedCount} ${modelName}(s)`,
1160
+ data: {
1161
+ deletedCount,
1162
+ deleteAll: bulkReq.deleteAll
1163
+ },
1164
+ status: "success",
1165
+ statusCode: 200
1166
+ });
1167
+ } catch (error) {
1168
+ logger.error(`Error in bulk delete ${modelName}`, error);
1169
+ return res.status(500).json({
1170
+ message: `Failed to delete ${modelName}(s)`,
1171
+ data: null,
1172
+ status: "error",
1173
+ statusCode: 500
1174
+ });
1175
+ }
1176
+ };
1177
+ };
1178
+
509
1179
  // src/server/utils/filter-builder.ts
510
1180
  var buildFilter = (options) => {
511
1181
  const {
@@ -800,45 +1470,704 @@ var packageCheckServer = {
800
1470
  print: printPackageCheckSummary
801
1471
  };
802
1472
 
1473
+ // src/server/configs/cors.config.ts
1474
+ var DEFAULT_CORS_CONFIG = {
1475
+ productionOrigins: [],
1476
+ developmentOrigins: [
1477
+ "http://localhost:3000",
1478
+ "http://localhost:4000",
1479
+ "http://localhost:5000",
1480
+ "http://localhost:5173",
1481
+ "http://localhost:8080",
1482
+ "http://127.0.0.1:3000",
1483
+ "http://127.0.0.1:4000",
1484
+ "http://127.0.0.1:5000",
1485
+ "http://127.0.0.1:5173",
1486
+ "http://127.0.0.1:8080"
1487
+ ],
1488
+ allowedSubdomains: [],
1489
+ originPatterns: [],
1490
+ allowNoOrigin: true,
1491
+ allowAllInDev: true,
1492
+ credentials: true,
1493
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"],
1494
+ allowedHeaders: [
1495
+ "Content-Type",
1496
+ "Authorization",
1497
+ "X-Requested-With",
1498
+ "Accept",
1499
+ "Origin",
1500
+ "X-API-Key",
1501
+ "X-Organization-Id",
1502
+ "X-Request-Id"
1503
+ ],
1504
+ exposedHeaders: [
1505
+ "Content-Range",
1506
+ "X-Content-Range",
1507
+ "X-Total-Count",
1508
+ "X-Request-Id"
1509
+ ],
1510
+ maxAge: 86400
1511
+ // 24 hours
1512
+ };
1513
+ var createCorsOptions = (config = {}) => {
1514
+ const finalConfig = { ...DEFAULT_CORS_CONFIG, ...config };
1515
+ const {
1516
+ productionOrigins,
1517
+ developmentOrigins,
1518
+ allowedSubdomains,
1519
+ originPatterns,
1520
+ allowNoOrigin,
1521
+ allowAllInDev,
1522
+ customValidator,
1523
+ credentials,
1524
+ methods,
1525
+ allowedHeaders,
1526
+ exposedHeaders,
1527
+ maxAge
1528
+ } = finalConfig;
1529
+ const allOrigins = /* @__PURE__ */ new Set([...productionOrigins, ...developmentOrigins]);
1530
+ const originHandler = (origin, callback) => {
1531
+ if (!origin) {
1532
+ callback(null, allowNoOrigin);
1533
+ return;
1534
+ }
1535
+ if (allOrigins.has(origin)) {
1536
+ callback(null, true);
1537
+ return;
1538
+ }
1539
+ if (allowedSubdomains.some((subdomain) => origin.endsWith(subdomain))) {
1540
+ callback(null, true);
1541
+ return;
1542
+ }
1543
+ if (originPatterns.some((pattern) => pattern.test(origin))) {
1544
+ callback(null, true);
1545
+ return;
1546
+ }
1547
+ if (customValidator && customValidator(origin)) {
1548
+ callback(null, true);
1549
+ return;
1550
+ }
1551
+ if (process.env.NODE_ENV !== "production" && allowAllInDev) {
1552
+ callback(null, true);
1553
+ return;
1554
+ }
1555
+ if (process.env.NODE_ENV === "production") {
1556
+ callback(new Error(`Origin ${origin} not allowed by CORS`));
1557
+ return;
1558
+ }
1559
+ callback(null, true);
1560
+ };
1561
+ return {
1562
+ origin: originHandler,
1563
+ credentials,
1564
+ methods,
1565
+ allowedHeaders,
1566
+ exposedHeaders,
1567
+ maxAge
1568
+ };
1569
+ };
1570
+ var createBrandCorsOptions = (brandDomain, additionalConfig = {}) => {
1571
+ const productionOrigins = [
1572
+ `https://${brandDomain}`,
1573
+ `https://www.${brandDomain}`
1574
+ ];
1575
+ const allowedSubdomains = [`.${brandDomain}`];
1576
+ return createCorsOptions({
1577
+ productionOrigins,
1578
+ allowedSubdomains,
1579
+ ...additionalConfig
1580
+ });
1581
+ };
1582
+ var createMultiBrandCorsOptions = (domains, additionalConfig = {}) => {
1583
+ const productionOrigins = domains.flatMap((domain) => [
1584
+ `https://${domain}`,
1585
+ `https://www.${domain}`
1586
+ ]);
1587
+ const allowedSubdomains = domains.map((domain) => `.${domain}`);
1588
+ return createCorsOptions({
1589
+ productionOrigins,
1590
+ allowedSubdomains,
1591
+ ...additionalConfig
1592
+ });
1593
+ };
1594
+ var EXYCONN_CORS_CONFIG = {
1595
+ productionOrigins: [
1596
+ "https://exyconn.com",
1597
+ "https://www.exyconn.com",
1598
+ "https://botify.life",
1599
+ "https://www.botify.life",
1600
+ "https://partywings.fun",
1601
+ "https://www.partywings.fun",
1602
+ "https://sibera.work",
1603
+ "https://www.sibera.work",
1604
+ "https://spentiva.com",
1605
+ "https://www.spentiva.com"
1606
+ ],
1607
+ allowedSubdomains: [
1608
+ ".exyconn.com",
1609
+ ".botify.life",
1610
+ ".partywings.fun",
1611
+ ".sibera.work",
1612
+ ".spentiva.com"
1613
+ ],
1614
+ developmentOrigins: [
1615
+ "http://localhost:3000",
1616
+ "http://localhost:4000",
1617
+ "http://localhost:4001",
1618
+ "http://localhost:4002",
1619
+ "http://localhost:4003",
1620
+ "http://localhost:4004",
1621
+ "http://localhost:4005",
1622
+ "http://localhost:5173",
1623
+ "http://127.0.0.1:3000",
1624
+ "http://127.0.0.1:4000",
1625
+ "http://127.0.0.1:5173"
1626
+ ]
1627
+ };
1628
+ var STRICT_CORS_CONFIG = {
1629
+ allowNoOrigin: false,
1630
+ allowAllInDev: false,
1631
+ methods: ["GET", "POST", "PUT", "DELETE"]
1632
+ };
1633
+ var PERMISSIVE_CORS_CONFIG = {
1634
+ allowNoOrigin: true,
1635
+ allowAllInDev: true,
1636
+ originPatterns: [/localhost/, /127\.0\.0\.1/]
1637
+ };
1638
+ var corsOptions = createCorsOptions(EXYCONN_CORS_CONFIG);
1639
+ var DEFAULT_RATE_LIMIT_TIERS = {
1640
+ STANDARD: {
1641
+ windowMs: 15 * 60 * 1e3,
1642
+ // 15 minutes
1643
+ maxRequests: 100,
1644
+ message: "Too many requests, please try again later.",
1645
+ skipSuccessfulRequests: false,
1646
+ skipFailedRequests: false
1647
+ },
1648
+ STRICT: {
1649
+ windowMs: 15 * 60 * 1e3,
1650
+ // 15 minutes
1651
+ maxRequests: 20,
1652
+ message: "Too many requests, please try again later.",
1653
+ skipSuccessfulRequests: false,
1654
+ skipFailedRequests: false
1655
+ },
1656
+ DDOS: {
1657
+ windowMs: 60 * 1e3,
1658
+ // 1 minute
1659
+ maxRequests: 60,
1660
+ message: "Rate limit exceeded. Please slow down.",
1661
+ skipSuccessfulRequests: false,
1662
+ skipFailedRequests: false
1663
+ },
1664
+ // Additional presets
1665
+ VERY_STRICT: {
1666
+ windowMs: 60 * 60 * 1e3,
1667
+ // 1 hour
1668
+ maxRequests: 5,
1669
+ message: "Too many attempts. Please try again in an hour.",
1670
+ skipSuccessfulRequests: false,
1671
+ skipFailedRequests: false
1672
+ },
1673
+ RELAXED: {
1674
+ windowMs: 15 * 60 * 1e3,
1675
+ // 15 minutes
1676
+ maxRequests: 500,
1677
+ message: "Rate limit exceeded.",
1678
+ skipSuccessfulRequests: false,
1679
+ skipFailedRequests: false
1680
+ },
1681
+ API: {
1682
+ windowMs: 60 * 1e3,
1683
+ // 1 minute
1684
+ maxRequests: 30,
1685
+ message: "API rate limit exceeded.",
1686
+ skipSuccessfulRequests: false,
1687
+ skipFailedRequests: false
1688
+ }
1689
+ };
1690
+ var defaultKeyGenerator = (req) => {
1691
+ const forwarded = req.headers["x-forwarded-for"];
1692
+ const ip = forwarded ? Array.isArray(forwarded) ? forwarded[0] : forwarded.split(",")[0].trim() : req.ip || req.socket.remoteAddress || "unknown";
1693
+ return ip;
1694
+ };
1695
+ var createPrefixedKeyGenerator = (prefix) => (req) => {
1696
+ return `${prefix}:${defaultKeyGenerator(req)}`;
1697
+ };
1698
+ var createUserKeyGenerator = (getUserId) => (req) => {
1699
+ const userId = getUserId(req);
1700
+ return userId || defaultKeyGenerator(req);
1701
+ };
1702
+ var createApiKeyGenerator = (headerName = "x-api-key") => (req) => {
1703
+ const apiKey = req.headers[headerName.toLowerCase()];
1704
+ return apiKey || defaultKeyGenerator(req);
1705
+ };
1706
+ var createRateLimitResponse = (message, retryAfter) => ({
1707
+ status: "error",
1708
+ statusCode: 429,
1709
+ message,
1710
+ ...retryAfter
1711
+ });
1712
+ var createRateLimiter = (tierConfig, options = {}) => {
1713
+ const {
1714
+ standardHeaders = true,
1715
+ legacyHeaders = false,
1716
+ keyGenerator = defaultKeyGenerator,
1717
+ skip,
1718
+ handler
1719
+ } = options;
1720
+ return rateLimit__default.default({
1721
+ windowMs: tierConfig.windowMs,
1722
+ max: tierConfig.maxRequests,
1723
+ message: createRateLimitResponse(tierConfig.message),
1724
+ standardHeaders,
1725
+ legacyHeaders,
1726
+ keyGenerator,
1727
+ skip,
1728
+ handler,
1729
+ skipSuccessfulRequests: tierConfig.skipSuccessfulRequests,
1730
+ skipFailedRequests: tierConfig.skipFailedRequests
1731
+ });
1732
+ };
1733
+ var createStandardRateLimiter = (config = {}, options = {}) => {
1734
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.STANDARD, ...config };
1735
+ return createRateLimiter(tierConfig, options);
1736
+ };
1737
+ var createStrictRateLimiter = (config = {}, options = {}) => {
1738
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.STRICT, ...config };
1739
+ return createRateLimiter(tierConfig, options);
1740
+ };
1741
+ var createDdosRateLimiter = (config = {}, options = {}) => {
1742
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.DDOS, ...config };
1743
+ return createRateLimiter(tierConfig, options);
1744
+ };
1745
+ var createApiRateLimiter = (config = {}, options = {}) => {
1746
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.API, ...config };
1747
+ return createRateLimiter(tierConfig, {
1748
+ keyGenerator: createApiKeyGenerator(),
1749
+ ...options
1750
+ });
1751
+ };
1752
+ var RateLimiterBuilder = class {
1753
+ constructor(preset = "STANDARD") {
1754
+ const presetConfig = DEFAULT_RATE_LIMIT_TIERS[preset];
1755
+ this.config = {
1756
+ windowMs: presetConfig.windowMs,
1757
+ maxRequests: presetConfig.maxRequests,
1758
+ message: presetConfig.message,
1759
+ skipSuccessfulRequests: presetConfig.skipSuccessfulRequests ?? false,
1760
+ skipFailedRequests: presetConfig.skipFailedRequests ?? false
1761
+ };
1762
+ this.options = {};
1763
+ }
1764
+ /**
1765
+ * Set window duration
1766
+ */
1767
+ windowMs(ms) {
1768
+ this.config.windowMs = ms;
1769
+ return this;
1770
+ }
1771
+ /**
1772
+ * Set window duration in minutes
1773
+ */
1774
+ windowMinutes(minutes) {
1775
+ this.config.windowMs = minutes * 60 * 1e3;
1776
+ return this;
1777
+ }
1778
+ /**
1779
+ * Set window duration in hours
1780
+ */
1781
+ windowHours(hours) {
1782
+ this.config.windowMs = hours * 60 * 60 * 1e3;
1783
+ return this;
1784
+ }
1785
+ /**
1786
+ * Set maximum requests
1787
+ */
1788
+ max(requests) {
1789
+ this.config.maxRequests = requests;
1790
+ return this;
1791
+ }
1792
+ /**
1793
+ * Set error message
1794
+ */
1795
+ message(msg) {
1796
+ this.config.message = msg;
1797
+ return this;
1798
+ }
1799
+ /**
1800
+ * Skip successful requests
1801
+ */
1802
+ skipSuccessful(skip = true) {
1803
+ this.config.skipSuccessfulRequests = skip;
1804
+ return this;
1805
+ }
1806
+ /**
1807
+ * Skip failed requests
1808
+ */
1809
+ skipFailed(skip = true) {
1810
+ this.config.skipFailedRequests = skip;
1811
+ return this;
1812
+ }
1813
+ /**
1814
+ * Set key generator
1815
+ */
1816
+ keyBy(generator) {
1817
+ this.options.keyGenerator = generator;
1818
+ return this;
1819
+ }
1820
+ /**
1821
+ * Key by IP (default)
1822
+ */
1823
+ keyByIp() {
1824
+ this.options.keyGenerator = defaultKeyGenerator;
1825
+ return this;
1826
+ }
1827
+ /**
1828
+ * Key by API key
1829
+ */
1830
+ keyByApiKey(headerName) {
1831
+ this.options.keyGenerator = createApiKeyGenerator(headerName);
1832
+ return this;
1833
+ }
1834
+ /**
1835
+ * Skip certain requests
1836
+ */
1837
+ skipWhen(predicate) {
1838
+ this.options.skip = predicate;
1839
+ return this;
1840
+ }
1841
+ /**
1842
+ * Build the rate limiter
1843
+ */
1844
+ build() {
1845
+ return createRateLimiter(this.config, this.options);
1846
+ }
1847
+ };
1848
+ var rateLimiter = (preset) => {
1849
+ return new RateLimiterBuilder(preset);
1850
+ };
1851
+ var RATE_LIMIT_CONFIG = {
1852
+ STANDARD: DEFAULT_RATE_LIMIT_TIERS.STANDARD,
1853
+ STRICT: DEFAULT_RATE_LIMIT_TIERS.STRICT,
1854
+ DDOS: DEFAULT_RATE_LIMIT_TIERS.DDOS
1855
+ };
1856
+ var standardRateLimiter = createStandardRateLimiter();
1857
+ var strictRateLimiter = createStrictRateLimiter();
1858
+ var ddosProtectionLimiter = createDdosRateLimiter();
1859
+
1860
+ // src/server/configs/server.config.ts
1861
+ var DEFAULT_SERVER_CONFIG = {
1862
+ name: "app-server",
1863
+ version: "1.0.0",
1864
+ environment: process.env.NODE_ENV || "development",
1865
+ port: parseInt(process.env.PORT || "3000", 10),
1866
+ host: process.env.HOST || "0.0.0.0",
1867
+ basePath: "/api",
1868
+ debug: process.env.DEBUG === "true",
1869
+ trustProxy: true
1870
+ };
1871
+ var DEFAULT_DATABASE_CONFIG = {
1872
+ uri: process.env.DATABASE_URL || process.env.MONGODB_URI || "",
1873
+ name: process.env.DATABASE_NAME || "app_db",
1874
+ maxPoolSize: process.env.NODE_ENV === "production" ? 50 : 10,
1875
+ minPoolSize: process.env.NODE_ENV === "production" ? 10 : 5,
1876
+ socketTimeoutMS: 45e3,
1877
+ serverSelectionTimeoutMS: 1e4,
1878
+ maxIdleTimeMS: 1e4,
1879
+ retryWrites: true,
1880
+ retryReads: true,
1881
+ writeConcern: "majority"
1882
+ };
1883
+ var DEFAULT_AUTH_CONFIG = {
1884
+ jwtSecret: process.env.JWT_SECRET || "",
1885
+ jwtExpiresIn: process.env.JWT_EXPIRES_IN || "7d",
1886
+ refreshTokenExpiresIn: process.env.REFRESH_TOKEN_EXPIRES_IN || "30d",
1887
+ enableRefreshTokens: true,
1888
+ apiKeyHeader: "x-api-key",
1889
+ orgHeader: "x-organization-id"
1890
+ };
1891
+ var DEFAULT_LOGGING_CONFIG = {
1892
+ level: process.env.LOG_LEVEL || "info",
1893
+ logsDir: process.env.LOGS_DIR || "logs",
1894
+ maxSize: "20m",
1895
+ maxFiles: "14d",
1896
+ errorMaxFiles: "30d",
1897
+ console: true,
1898
+ file: process.env.NODE_ENV === "production",
1899
+ json: process.env.NODE_ENV === "production"
1900
+ };
1901
+ var DEFAULT_CORS_ORIGINS = {
1902
+ production: [],
1903
+ development: [
1904
+ "http://localhost:3000",
1905
+ "http://localhost:4000",
1906
+ "http://localhost:5173",
1907
+ "http://127.0.0.1:3000",
1908
+ "http://127.0.0.1:4000",
1909
+ "http://127.0.0.1:5173"
1910
+ ],
1911
+ patterns: []
1912
+ };
1913
+ var DEFAULT_RATE_LIMIT_CONFIG = {
1914
+ enabled: true,
1915
+ standard: {
1916
+ windowMs: 15 * 60 * 1e3,
1917
+ // 15 minutes
1918
+ maxRequests: 100,
1919
+ message: "Too many requests, please try again later."
1920
+ },
1921
+ strict: {
1922
+ windowMs: 15 * 60 * 1e3,
1923
+ // 15 minutes
1924
+ maxRequests: 20,
1925
+ message: "Too many requests, please try again later."
1926
+ },
1927
+ ddos: {
1928
+ windowMs: 60 * 1e3,
1929
+ // 1 minute
1930
+ maxRequests: 60,
1931
+ message: "Rate limit exceeded. Please slow down.",
1932
+ skipSuccessfulRequests: false
1933
+ }
1934
+ };
1935
+ function deepMerge(target, source) {
1936
+ const result = { ...target };
1937
+ for (const key in source) {
1938
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1939
+ const sourceValue = source[key];
1940
+ const targetValue = target[key];
1941
+ if (sourceValue !== void 0 && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
1942
+ result[key] = deepMerge(
1943
+ targetValue,
1944
+ sourceValue
1945
+ );
1946
+ } else if (sourceValue !== void 0) {
1947
+ result[key] = sourceValue;
1948
+ }
1949
+ }
1950
+ }
1951
+ return result;
1952
+ }
1953
+ var ConfigBuilder = class {
1954
+ constructor() {
1955
+ this.config = {
1956
+ server: { ...DEFAULT_SERVER_CONFIG },
1957
+ database: { ...DEFAULT_DATABASE_CONFIG },
1958
+ auth: { ...DEFAULT_AUTH_CONFIG },
1959
+ logging: { ...DEFAULT_LOGGING_CONFIG },
1960
+ cors: { ...DEFAULT_CORS_ORIGINS },
1961
+ rateLimit: { ...DEFAULT_RATE_LIMIT_CONFIG }
1962
+ };
1963
+ }
1964
+ /**
1965
+ * Set server configuration
1966
+ */
1967
+ setServer(config) {
1968
+ this.config.server = deepMerge(this.config.server, config);
1969
+ return this;
1970
+ }
1971
+ /**
1972
+ * Set database configuration
1973
+ */
1974
+ setDatabase(config) {
1975
+ this.config.database = deepMerge(this.config.database, config);
1976
+ return this;
1977
+ }
1978
+ /**
1979
+ * Set auth configuration
1980
+ */
1981
+ setAuth(config) {
1982
+ this.config.auth = deepMerge(this.config.auth, config);
1983
+ return this;
1984
+ }
1985
+ /**
1986
+ * Set logging configuration
1987
+ */
1988
+ setLogging(config) {
1989
+ this.config.logging = deepMerge(this.config.logging, config);
1990
+ return this;
1991
+ }
1992
+ /**
1993
+ * Set CORS origins
1994
+ */
1995
+ setCorsOrigins(config) {
1996
+ this.config.cors = deepMerge(this.config.cors, config);
1997
+ return this;
1998
+ }
1999
+ /**
2000
+ * Add CORS production origin
2001
+ */
2002
+ addProductionOrigin(origin) {
2003
+ if (!this.config.cors.production.includes(origin)) {
2004
+ this.config.cors.production.push(origin);
2005
+ }
2006
+ return this;
2007
+ }
2008
+ /**
2009
+ * Add CORS development origin
2010
+ */
2011
+ addDevelopmentOrigin(origin) {
2012
+ if (!this.config.cors.development.includes(origin)) {
2013
+ this.config.cors.development.push(origin);
2014
+ }
2015
+ return this;
2016
+ }
2017
+ /**
2018
+ * Add CORS pattern
2019
+ */
2020
+ addCorsPattern(pattern) {
2021
+ if (!this.config.cors.patterns.includes(pattern)) {
2022
+ this.config.cors.patterns.push(pattern);
2023
+ }
2024
+ return this;
2025
+ }
2026
+ /**
2027
+ * Set rate limit configuration
2028
+ */
2029
+ setRateLimit(config) {
2030
+ this.config.rateLimit = deepMerge(this.config.rateLimit, config);
2031
+ return this;
2032
+ }
2033
+ /**
2034
+ * Add custom rate limit tier
2035
+ */
2036
+ addRateLimitTier(name, tier) {
2037
+ if (!this.config.rateLimit.custom) {
2038
+ this.config.rateLimit.custom = {};
2039
+ }
2040
+ this.config.rateLimit.custom[name] = tier;
2041
+ return this;
2042
+ }
2043
+ /**
2044
+ * Set custom configuration
2045
+ */
2046
+ setCustom(key, value) {
2047
+ if (!this.config.custom) {
2048
+ this.config.custom = {};
2049
+ }
2050
+ this.config.custom[key] = value;
2051
+ return this;
2052
+ }
2053
+ /**
2054
+ * Load configuration from environment variables
2055
+ */
2056
+ loadFromEnv() {
2057
+ if (process.env.SERVER_NAME) this.config.server.name = process.env.SERVER_NAME;
2058
+ if (process.env.SERVER_VERSION) this.config.server.version = process.env.SERVER_VERSION;
2059
+ if (process.env.PORT) this.config.server.port = parseInt(process.env.PORT, 10);
2060
+ if (process.env.HOST) this.config.server.host = process.env.HOST;
2061
+ if (process.env.BASE_PATH) this.config.server.basePath = process.env.BASE_PATH;
2062
+ if (process.env.DATABASE_URL) this.config.database.uri = process.env.DATABASE_URL;
2063
+ if (process.env.MONGODB_URI) this.config.database.uri = process.env.MONGODB_URI;
2064
+ if (process.env.DATABASE_NAME) this.config.database.name = process.env.DATABASE_NAME;
2065
+ if (process.env.JWT_SECRET) this.config.auth.jwtSecret = process.env.JWT_SECRET;
2066
+ if (process.env.JWT_EXPIRES_IN) this.config.auth.jwtExpiresIn = process.env.JWT_EXPIRES_IN;
2067
+ if (process.env.LOG_LEVEL) this.config.logging.level = process.env.LOG_LEVEL;
2068
+ if (process.env.LOGS_DIR) this.config.logging.logsDir = process.env.LOGS_DIR;
2069
+ if (process.env.CORS_ORIGINS) {
2070
+ const origins = process.env.CORS_ORIGINS.split(",").map((o) => o.trim());
2071
+ this.config.cors.production.push(...origins);
2072
+ }
2073
+ return this;
2074
+ }
2075
+ /**
2076
+ * Validate configuration
2077
+ */
2078
+ validate() {
2079
+ const errors = [];
2080
+ if (!this.config.server.name) errors.push("Server name is required");
2081
+ if (this.config.server.port < 1 || this.config.server.port > 65535) {
2082
+ errors.push("Server port must be between 1 and 65535");
2083
+ }
2084
+ if (this.config.server.environment === "production") {
2085
+ if (!this.config.auth.jwtSecret || this.config.auth.jwtSecret.length < 32) {
2086
+ errors.push("JWT secret must be at least 32 characters in production");
2087
+ }
2088
+ }
2089
+ return { valid: errors.length === 0, errors };
2090
+ }
2091
+ /**
2092
+ * Build the final configuration
2093
+ */
2094
+ build() {
2095
+ return { ...this.config };
2096
+ }
2097
+ };
2098
+ var createConfig = () => {
2099
+ return new ConfigBuilder();
2100
+ };
2101
+ var buildConfig = (partial = {}) => {
2102
+ const builder = createConfig().loadFromEnv();
2103
+ if (partial.server) builder.setServer(partial.server);
2104
+ if (partial.database) builder.setDatabase(partial.database);
2105
+ if (partial.auth) builder.setAuth(partial.auth);
2106
+ if (partial.logging) builder.setLogging(partial.logging);
2107
+ if (partial.cors) builder.setCorsOrigins(partial.cors);
2108
+ if (partial.rateLimit) builder.setRateLimit(partial.rateLimit);
2109
+ return builder.build();
2110
+ };
2111
+ var isProduction = (config) => {
2112
+ return (config?.environment || process.env.NODE_ENV) === "production";
2113
+ };
2114
+ var isDevelopment = (config) => {
2115
+ return (config?.environment || process.env.NODE_ENV) === "development";
2116
+ };
2117
+ var isTest = (config) => {
2118
+ return (config?.environment || process.env.NODE_ENV) === "test";
2119
+ };
2120
+ var getDatabaseOptions = (config) => {
2121
+ return {
2122
+ maxPoolSize: config.maxPoolSize,
2123
+ minPoolSize: config.minPoolSize,
2124
+ socketTimeoutMS: config.socketTimeoutMS,
2125
+ serverSelectionTimeoutMS: config.serverSelectionTimeoutMS,
2126
+ maxIdleTimeMS: config.maxIdleTimeMS,
2127
+ retryWrites: config.retryWrites,
2128
+ retryReads: config.retryReads,
2129
+ w: config.writeConcern
2130
+ };
2131
+ };
2132
+
803
2133
  // src/client/index.ts
804
2134
  var client_exports = {};
805
2135
  __export(client_exports, {
806
- ApiUrlBuilder: () => ApiUrlBuilder,
2136
+ API_BASE_URL: () => API_BASE_URL,
2137
+ API_PREFIX: () => API_PREFIX,
807
2138
  ClientLogger: () => ClientLogger,
808
2139
  ContactForm: () => ContactForm,
809
- EventEmitter: () => EventEmitter,
2140
+ ERROR_CODES: () => ERROR_CODES,
810
2141
  LoginForm: () => LoginForm,
811
2142
  NewsletterForm: () => NewsletterForm,
812
2143
  RegisterForm: () => RegisterForm,
2144
+ STATUS_CODES: () => STATUS_CODES,
2145
+ STATUS_MESSAGES: () => STATUS_MESSAGES,
2146
+ SUCCESS_CODES: () => SUCCESS_CODES,
813
2147
  ThemeContext: () => ThemeContext,
814
2148
  ThemeProvider: () => ThemeProvider,
815
2149
  ThemeToggle: () => ThemeToggle,
816
2150
  VALIDATION_MESSAGES: () => VALIDATION_MESSAGES,
817
- addDays: () => addDays,
818
2151
  adjustColor: () => adjustColor,
819
- appEvents: () => appEvents,
2152
+ axios: () => axiosInstance,
820
2153
  camelToKebab: () => camelToKebab,
821
2154
  capitalize: () => capitalize,
822
2155
  capitalizeWords: () => capitalizeWords,
823
- checkPackage: () => checkPackage,
824
2156
  clientLogger: () => clientLogger,
825
2157
  contactFormSchema: () => contactFormSchema,
826
2158
  copyToClipboard: () => copyToClipboard,
827
- createApiEndpoints: () => createApiEndpoints,
828
- createApiUrlBuilder: () => createApiUrlBuilder,
829
2159
  createClientLogger: () => createClientLogger,
830
2160
  createEmptyPaginationMeta: () => createEmptyPaginationMeta,
831
2161
  createErrorResponse: () => createErrorResponse,
832
- createEventEmitter: () => createEventEmitter,
833
- createHttpClient: () => createHttpClient,
834
2162
  createRegisterFormSchema: () => createRegisterFormSchema,
835
2163
  createSuccessResponse: () => createSuccessResponse,
836
2164
  createTheme: () => createTheme,
837
2165
  createThemeFromBrand: () => createThemeFromBrand,
838
2166
  cssVar: () => cssVar,
839
- deepMerge: () => deepMerge,
2167
+ deepMerge: () => deepMerge2,
840
2168
  defaultDarkTheme: () => defaultDarkTheme,
841
2169
  defaultLightTheme: () => defaultLightTheme,
2170
+ deleteRequest: () => deleteRequest,
842
2171
  dummyBannerData: () => dummyBannerData,
843
2172
  dummyFaqItems: () => dummyFaqItems,
844
2173
  dummyFeatures: () => dummyFeatures,
@@ -847,59 +2176,66 @@ __export(client_exports, {
847
2176
  dummyImage: () => dummyImage,
848
2177
  dummyPricingPlans: () => dummyPricingPlans,
849
2178
  dummyTestimonials: () => dummyTestimonials,
850
- endOfDay: () => endOfDay,
2179
+ extractData: () => extractData,
2180
+ extractMessage: () => extractMessage,
2181
+ extractNestedData: () => extractNestedData,
2182
+ extractPaginatedData: () => extractPaginatedData,
851
2183
  flattenToCssVars: () => flattenToCssVars,
852
2184
  formatDate: () => formatDate,
853
- formatDateForInput: () => formatDateForInput,
854
2185
  formatDateTime: () => formatDateTime,
855
- formatDateTimeForInput: () => formatDateTimeForInput,
856
- formatPackageCheckResult: () => formatPackageCheckResult2,
857
2186
  formatRelativeTime: () => formatRelativeTime,
858
2187
  generateCssVars: () => generateCssVars,
859
- generateNcuCommand: () => generateNcuCommand2,
2188
+ generateSlug: () => generateSlug,
2189
+ generateSnakeSlug: () => generateSnakeSlug,
2190
+ generateUrlSlug: () => generateUrlSlug,
860
2191
  getContrastColor: () => getContrastColor,
861
2192
  getErrorMessage: () => getErrorMessage,
862
2193
  getNextPage: () => getNextPage,
863
2194
  getPrevPage: () => getPrevPage,
2195
+ getRequest: () => getRequest,
864
2196
  getResponseData: () => getResponseData,
865
2197
  getSystemColorScheme: () => getSystemColorScheme,
866
2198
  hasData: () => hasData,
867
2199
  hasMorePages: () => hasMorePages,
868
2200
  hexToRgba: () => hexToRgba,
869
2201
  injectCssVars: () => injectCssVars,
870
- isClipboardAvailable: () => isClipboardAvailable,
871
2202
  isErrorResponse: () => isErrorResponse,
872
- isForbidden: () => isForbidden,
873
- isFuture: () => isFuture,
874
- isNotFound: () => isNotFound,
875
- isPast: () => isPast,
876
- isServerError: () => isServerError,
877
- isStatusError: () => isStatusError,
878
2203
  isSuccess: () => isSuccess,
879
2204
  isSuccessResponse: () => isSuccessResponse,
880
- isToday: () => isToday,
881
- isUnauthorized: () => isUnauthorized,
2205
+ isUtilErrorResponse: () => isErrorResponse2,
2206
+ isUtilSuccessResponse: () => isSuccessResponse2,
882
2207
  kebabToCamel: () => kebabToCamel,
883
2208
  loadThemeFromUrl: () => loadThemeFromUrl,
884
2209
  loadThemeMode: () => loadThemeMode,
2210
+ logger: () => logger2,
885
2211
  loginFormSchema: () => loginFormSchema,
886
2212
  loremIpsum: () => loremIpsum,
887
2213
  newsletterFormSchema: () => newsletterFormSchema,
888
2214
  packageCheck: () => packageCheck,
2215
+ parseAxiosErrorMessage: () => parseAxiosErrorMessage,
889
2216
  parseError: () => parseError,
890
- parseFullResponse: () => parseFullResponse,
891
- parseResponse: () => parseResponse,
892
- readFromClipboard: () => readFromClipboard,
2217
+ parsePaginatedResponse: () => parsePaginatedResponse,
2218
+ parseResponseData: () => parseResponseData,
2219
+ parseResponseMessage: () => parseResponseMessage,
2220
+ parseResponseStatus: () => parseResponseStatus,
2221
+ parseResponseStatusMessage: () => parseResponseStatusMessage,
2222
+ patchRequest: () => patchRequest,
2223
+ postRequest: () => postRequest,
2224
+ putRequest: () => putRequest,
893
2225
  registerFormSchema: () => registerFormSchema,
894
2226
  removeCssVars: () => removeCssVars,
895
2227
  resolveThemeMode: () => resolveThemeMode,
2228
+ safeJsonParse: () => safeJsonParse,
896
2229
  saveThemeMode: () => saveThemeMode,
2230
+ simpleMetaParseResponse: () => simpleMetaParseResponse,
2231
+ simpleParseDualDataResponse: () => simpleParseDualDataResponse,
2232
+ simpleParseResponse: () => simpleParseResponse,
897
2233
  slugify: () => slugify,
898
2234
  slugifyUnique: () => slugifyUnique,
899
- startOfDay: () => startOfDay,
900
2235
  truncate: () => truncate,
901
2236
  truncateWords: () => truncateWords,
902
2237
  unslugify: () => unslugify,
2238
+ uploadFile: () => uploadFile,
903
2239
  useBattery: () => useBattery_default,
904
2240
  useClickAway: () => useClickAway_default,
905
2241
  useContinuousRetry: () => useContinuousRetry_default,
@@ -959,112 +2295,466 @@ __export(client_exports, {
959
2295
  useToggle: () => useToggle_default,
960
2296
  useVisibilityChange: () => useVisibilityChange_default,
961
2297
  useWindowScroll: () => useWindowScroll_default,
962
- useWindowSize: () => useWindowSize_default,
963
- withAbortSignal: () => withAbortSignal,
964
- withFormData: () => withFormData,
965
- withTimeout: () => withTimeout
2298
+ useWindowSize: () => useWindowSize_default
966
2299
  });
967
- var createHttpClient = (options) => {
968
- const {
969
- baseURL,
970
- timeout = 3e4,
971
- withCredentials = true,
972
- getAuthToken,
973
- onUnauthorized,
974
- onServerError
975
- } = options;
976
- const instance = axios__default.default.create({
977
- baseURL,
978
- timeout,
979
- withCredentials,
980
- headers: {
981
- "Content-Type": "application/json"
2300
+
2301
+ // src/client/http/logger.ts
2302
+ var Logger = class {
2303
+ constructor() {
2304
+ this.isDevelopment = typeof window !== "undefined" && window.location.hostname === "localhost";
2305
+ }
2306
+ /**
2307
+ * Log informational messages
2308
+ */
2309
+ info(message, data, options) {
2310
+ if (this.isDevelopment) {
2311
+ const prefix = options?.context ? `[${options.context}]` : "";
2312
+ console.log(`${prefix} ${message}`, data ?? "");
982
2313
  }
983
- });
984
- instance.interceptors.request.use(
985
- (config) => {
986
- if (getAuthToken) {
987
- const token = getAuthToken();
988
- if (token && config.headers) {
989
- config.headers.Authorization = `Bearer ${token}`;
990
- }
2314
+ }
2315
+ /**
2316
+ * Log warning messages
2317
+ */
2318
+ warn(message, data, options) {
2319
+ if (this.isDevelopment) {
2320
+ const prefix = options?.context ? `[${options.context}]` : "";
2321
+ console.warn(`${prefix} ${message}`, data ?? "");
2322
+ }
2323
+ }
2324
+ /**
2325
+ * Log error messages
2326
+ */
2327
+ error(message, error, options) {
2328
+ const prefix = options?.context ? `[${options.context}]` : "";
2329
+ if (this.isDevelopment) {
2330
+ console.error(`${prefix} ${message}`, error, options?.metadata || "");
2331
+ }
2332
+ }
2333
+ /**
2334
+ * Log debug messages (only in development)
2335
+ */
2336
+ debug(message, data, options) {
2337
+ if (this.isDevelopment) {
2338
+ const prefix = options?.context ? `[${options.context}]` : "";
2339
+ console.debug(`${prefix} ${message}`, data || "");
2340
+ }
2341
+ }
2342
+ /**
2343
+ * Log API errors with structured information
2344
+ */
2345
+ apiError(endpoint, error, metadata) {
2346
+ this.error(`API Error: ${endpoint}`, error, {
2347
+ context: "API",
2348
+ metadata: {
2349
+ endpoint,
2350
+ ...metadata
991
2351
  }
992
- return config;
993
- },
994
- (error) => Promise.reject(error)
995
- );
996
- instance.interceptors.response.use(
997
- (response) => response,
998
- (error) => {
999
- if (error.response) {
1000
- const status = error.response.status;
1001
- if (status === 401 && onUnauthorized) {
1002
- onUnauthorized();
1003
- }
1004
- if (status >= 500 && onServerError) {
1005
- onServerError(error);
1006
- }
2352
+ });
2353
+ }
2354
+ };
2355
+ var logger2 = new Logger();
2356
+
2357
+ // src/client/http/response-parser.ts
2358
+ var STATUS_CODES = {
2359
+ SUCCESS: 200,
2360
+ CREATED: 201,
2361
+ NO_CONTENT: 204,
2362
+ BAD_REQUEST: 400,
2363
+ UNAUTHORIZED: 401,
2364
+ FORBIDDEN: 403,
2365
+ NOT_FOUND: 404,
2366
+ CONFLICT: 409,
2367
+ ERROR: 500
2368
+ };
2369
+ var STATUS_MESSAGES = {
2370
+ SUCCESS: "success",
2371
+ CREATED: "created",
2372
+ NO_CONTENT: "no_content",
2373
+ BAD_REQUEST: "bad_request",
2374
+ UNAUTHORIZED: "unauthorized",
2375
+ FORBIDDEN: "forbidden",
2376
+ NOT_FOUND: "not_found",
2377
+ CONFLICT: "conflict",
2378
+ ERROR: "error"
2379
+ };
2380
+ var SUCCESS_CODES = [200, 201, 204];
2381
+ var ERROR_CODES = [400, 401, 403, 404, 409, 500];
2382
+ var parseResponseData = (response, fallback = null) => {
2383
+ try {
2384
+ if (!response || typeof response !== "object") {
2385
+ return fallback;
2386
+ }
2387
+ const resp = response;
2388
+ if ("data" in resp) {
2389
+ return resp["data"] ?? fallback;
2390
+ }
2391
+ return response;
2392
+ } catch (error) {
2393
+ logger2.error("Error parsing response data", error);
2394
+ return fallback;
2395
+ }
2396
+ };
2397
+ var parseResponseMessage = (response, fallback = "") => {
2398
+ try {
2399
+ if (!response || typeof response !== "object") {
2400
+ return fallback;
2401
+ }
2402
+ const resp = response;
2403
+ if ("message" in resp && typeof resp["message"] === "string") {
2404
+ return resp["message"];
2405
+ }
2406
+ return fallback;
2407
+ } catch (error) {
2408
+ logger2.error("Error parsing response message", error);
2409
+ return fallback;
2410
+ }
2411
+ };
2412
+ var parseResponseStatus = (response) => {
2413
+ try {
2414
+ if (!response || typeof response !== "object") {
2415
+ return null;
2416
+ }
2417
+ const resp = response;
2418
+ if ("statusCode" in resp && typeof resp["statusCode"] === "number") {
2419
+ return resp["statusCode"];
2420
+ }
2421
+ if ("status" in resp && typeof resp["status"] === "number") {
2422
+ return resp["status"];
2423
+ }
2424
+ return null;
2425
+ } catch (error) {
2426
+ logger2.error("Error parsing response status", error);
2427
+ return null;
2428
+ }
2429
+ };
2430
+ var parseResponseStatusMessage = (response, fallback = "") => {
2431
+ try {
2432
+ if (!response || typeof response !== "object") {
2433
+ return fallback;
2434
+ }
2435
+ const resp = response;
2436
+ if ("status" in resp && typeof resp["status"] === "string") {
2437
+ return resp["status"];
2438
+ }
2439
+ return fallback;
2440
+ } catch (error) {
2441
+ logger2.error("Error parsing response status message", error);
2442
+ return fallback;
2443
+ }
2444
+ };
2445
+ var isSuccessResponse = (response) => {
2446
+ try {
2447
+ const statusCode2 = parseResponseStatus(response);
2448
+ if (statusCode2 !== null) {
2449
+ return SUCCESS_CODES.includes(statusCode2);
2450
+ }
2451
+ const status = parseResponseStatusMessage(response);
2452
+ return [STATUS_MESSAGES.SUCCESS, STATUS_MESSAGES.CREATED, STATUS_MESSAGES.NO_CONTENT].includes(
2453
+ status
2454
+ );
2455
+ } catch (error) {
2456
+ logger2.error("Error checking response success", error);
2457
+ return false;
2458
+ }
2459
+ };
2460
+ var isErrorResponse = (response) => {
2461
+ try {
2462
+ const statusCode2 = parseResponseStatus(response);
2463
+ if (statusCode2 !== null) {
2464
+ return ERROR_CODES.includes(statusCode2);
2465
+ }
2466
+ return false;
2467
+ } catch (error) {
2468
+ logger2.error("Error checking response error", error);
2469
+ return false;
2470
+ }
2471
+ };
2472
+ var parsePaginatedResponse = (response) => {
2473
+ try {
2474
+ if (!response || typeof response !== "object") {
2475
+ return { items: [], total: 0, page: 1, limit: 10 };
2476
+ }
2477
+ const resp = response;
2478
+ let items = [];
2479
+ if ("data" in resp && Array.isArray(resp["data"])) {
2480
+ items = resp["data"];
2481
+ }
2482
+ let total = items.length;
2483
+ let page = 1;
2484
+ let limit = 10;
2485
+ let totalPages;
2486
+ if ("paginationData" in resp && resp["paginationData"] && typeof resp["paginationData"] === "object") {
2487
+ const paginationData = resp["paginationData"];
2488
+ if ("total" in paginationData && typeof paginationData["total"] === "number") {
2489
+ total = paginationData["total"];
2490
+ }
2491
+ if ("page" in paginationData && typeof paginationData["page"] === "number") {
2492
+ page = paginationData["page"];
2493
+ }
2494
+ if ("limit" in paginationData && typeof paginationData["limit"] === "number") {
2495
+ limit = paginationData["limit"];
2496
+ }
2497
+ if ("totalPages" in paginationData && typeof paginationData["totalPages"] === "number") {
2498
+ totalPages = paginationData["totalPages"];
1007
2499
  }
1008
- return Promise.reject(error);
1009
2500
  }
1010
- );
1011
- return instance;
2501
+ let columns;
2502
+ if ("columns" in resp && Array.isArray(resp["columns"])) {
2503
+ columns = resp["columns"];
2504
+ }
2505
+ return {
2506
+ items,
2507
+ total,
2508
+ page,
2509
+ limit,
2510
+ ...totalPages !== void 0 && { totalPages },
2511
+ ...columns !== void 0 && { columns }
2512
+ };
2513
+ } catch (error) {
2514
+ logger2.error("Error parsing paginated response", error);
2515
+ return { items: [], total: 0, page: 1, limit: 10 };
2516
+ }
1012
2517
  };
1013
- var withFormData = () => ({
1014
- headers: {
1015
- "Content-Type": "multipart/form-data"
2518
+ var extractNestedData = (response, path2, fallback = null) => {
2519
+ try {
2520
+ const keys = path2.split(".");
2521
+ let current = response;
2522
+ for (const key of keys) {
2523
+ if (current && typeof current === "object" && key in current) {
2524
+ current = current[key];
2525
+ } else {
2526
+ return fallback;
2527
+ }
2528
+ }
2529
+ return current;
2530
+ } catch (error) {
2531
+ logger2.error("Error extracting nested data", error);
2532
+ return fallback;
1016
2533
  }
1017
- });
1018
- var withTimeout = (ms) => ({
1019
- timeout: ms
1020
- });
1021
- var withAbortSignal = (signal) => ({
1022
- signal
1023
- });
1024
-
1025
- // src/client/http/response-parser.ts
1026
- var parseResponse = (response) => {
1027
- if (response.data?.success && response.data?.data !== void 0) {
1028
- return response.data.data;
2534
+ };
2535
+ var safeJsonParse = (json, fallback = null) => {
2536
+ try {
2537
+ return JSON.parse(json);
2538
+ } catch (error) {
2539
+ logger2.error("Error parsing JSON", error);
2540
+ return fallback;
1029
2541
  }
1030
- return null;
1031
2542
  };
1032
- var parseFullResponse = (response) => {
1033
- return response.data;
2543
+ var parseAxiosErrorMessage = (error) => {
2544
+ try {
2545
+ if (!error || typeof error !== "object") {
2546
+ return "An unexpected error occurred";
2547
+ }
2548
+ const err = error;
2549
+ if ("response" in err && err["response"] && typeof err["response"] === "object") {
2550
+ const response = err["response"];
2551
+ if ("data" in response && response["data"] && typeof response["data"] === "object") {
2552
+ const data = response["data"];
2553
+ if ("data" in data && data["data"] && typeof data["data"] === "object") {
2554
+ const nestedData = data["data"];
2555
+ if ("message" in nestedData && typeof nestedData["message"] === "string") {
2556
+ return nestedData["message"];
2557
+ }
2558
+ }
2559
+ if ("message" in data && typeof data["message"] === "string") {
2560
+ return data["message"];
2561
+ }
2562
+ if ("error" in data && typeof data["error"] === "string") {
2563
+ return data["error"];
2564
+ }
2565
+ }
2566
+ }
2567
+ if ("message" in err && typeof err["message"] === "string") {
2568
+ return err["message"];
2569
+ }
2570
+ if (typeof error === "string") {
2571
+ return error;
2572
+ }
2573
+ return "An unexpected error occurred";
2574
+ } catch (parseError2) {
2575
+ logger2.error("Error parsing axios error message", parseError2);
2576
+ return "An unexpected error occurred";
2577
+ }
1034
2578
  };
1035
2579
  var parseError = (error) => {
1036
- if (error.response?.data?.message) {
1037
- return error.response.data.message;
2580
+ try {
2581
+ if (!error || typeof error !== "object") {
2582
+ return {
2583
+ message: "An unexpected error occurred",
2584
+ statusCode: null,
2585
+ data: null
2586
+ };
2587
+ }
2588
+ const err = error;
2589
+ let statusCode2 = null;
2590
+ let data = null;
2591
+ let status;
2592
+ if ("response" in err && err["response"] && typeof err["response"] === "object") {
2593
+ const response = err["response"];
2594
+ if ("status" in response && typeof response["status"] === "number") {
2595
+ statusCode2 = response["status"];
2596
+ }
2597
+ if ("data" in response && response["data"] !== void 0) {
2598
+ data = response["data"];
2599
+ if (data && typeof data === "object" && "status" in data) {
2600
+ const dataObj = data;
2601
+ if (typeof dataObj["status"] === "string") {
2602
+ status = dataObj["status"];
2603
+ }
2604
+ }
2605
+ }
2606
+ }
2607
+ if (statusCode2 === null && "statusCode" in err && typeof err["statusCode"] === "number") {
2608
+ statusCode2 = err["statusCode"];
2609
+ }
2610
+ if (data === null && "data" in err && err["data"] !== void 0) {
2611
+ data = err["data"];
2612
+ }
2613
+ if (!status && "status" in err && typeof err["status"] === "string") {
2614
+ status = err["status"];
2615
+ }
2616
+ return {
2617
+ message: parseAxiosErrorMessage(error),
2618
+ statusCode: statusCode2,
2619
+ data,
2620
+ ...status !== void 0 && { status }
2621
+ };
2622
+ } catch (err) {
2623
+ logger2.error("Error parsing error object", err);
2624
+ return {
2625
+ message: "An unexpected error occurred",
2626
+ statusCode: null,
2627
+ data: null
2628
+ };
2629
+ }
2630
+ };
2631
+ var simpleParseResponse = (response) => {
2632
+ return response?.data?.data?.data;
2633
+ };
2634
+ var simpleMetaParseResponse = (response) => {
2635
+ return response?.data?.data?.meta;
2636
+ };
2637
+ var simpleParseDualDataResponse = (response) => {
2638
+ return response?.data?.data;
2639
+ };
2640
+
2641
+ // src/client/http/http.ts
2642
+ var isDevelopment2 = typeof window !== "undefined" && window.location.hostname === "localhost";
2643
+ var API_BASE_URL = isDevelopment2 ? "http://localhost:4002" : "https://service-api.exyconn.com";
2644
+ var API_PREFIX = "/v1/api";
2645
+ var axiosInstance = axios__default.default.create({
2646
+ baseURL: API_BASE_URL,
2647
+ timeout: 3e4,
2648
+ // 30 seconds
2649
+ headers: {
2650
+ "Content-Type": "application/json"
1038
2651
  }
1039
- if (error.response?.data?.error) {
1040
- return error.response.data.error;
2652
+ });
2653
+ axiosInstance.interceptors.request.use(
2654
+ (config) => {
2655
+ try {
2656
+ if (typeof window !== "undefined" && window.localStorage) {
2657
+ const selectedOrg = localStorage.getItem("selectedOrganization");
2658
+ if (selectedOrg) {
2659
+ const org = JSON.parse(selectedOrg);
2660
+ if (org && org._id) {
2661
+ config.headers["x-organization-id"] = org._id;
2662
+ }
2663
+ }
2664
+ }
2665
+ } catch (error) {
2666
+ logger2.warn("Failed to read organization from localStorage", error);
2667
+ }
2668
+ return config;
2669
+ },
2670
+ (error) => {
2671
+ return Promise.reject(error);
1041
2672
  }
1042
- if (error.code === "ERR_NETWORK") {
1043
- return "Network error. Please check your connection.";
2673
+ );
2674
+ axiosInstance.interceptors.response.use(
2675
+ (response) => response,
2676
+ (error) => {
2677
+ const parsedError = parseError(error);
2678
+ logger2.error("API Error", parsedError);
2679
+ return Promise.reject(parsedError);
1044
2680
  }
1045
- if (error.code === "ECONNABORTED") {
1046
- return "Request timed out. Please try again.";
2681
+ );
2682
+ var buildHeaders = (customHeaders) => {
2683
+ const headers = {
2684
+ "Content-Type": "application/json",
2685
+ ...customHeaders
2686
+ };
2687
+ return headers;
2688
+ };
2689
+ var buildConfig2 = (params, customHeaders) => {
2690
+ const config = {
2691
+ headers: buildHeaders(customHeaders)
2692
+ };
2693
+ if (params) {
2694
+ config.params = params;
1047
2695
  }
1048
- return error.message || "An unexpected error occurred.";
2696
+ return config;
1049
2697
  };
1050
- var isSuccess = (response) => {
1051
- return response.data?.success === true;
2698
+ var getRequest = async (url, params, customHeaders) => {
2699
+ const config = buildConfig2(params, customHeaders);
2700
+ return axiosInstance.get(url, config);
2701
+ };
2702
+ var postRequest = async (url, data, customHeaders) => {
2703
+ const config = buildConfig2(void 0, customHeaders);
2704
+ return axiosInstance.post(url, data, config);
2705
+ };
2706
+ var putRequest = async (url, data, customHeaders) => {
2707
+ const config = buildConfig2(void 0, customHeaders);
2708
+ return axiosInstance.put(url, data, config);
1052
2709
  };
1053
- var isStatusError = (error, statusCode2) => {
1054
- return error.response?.status === statusCode2;
2710
+ var patchRequest = async (url, data, customHeaders) => {
2711
+ const config = buildConfig2(void 0, customHeaders);
2712
+ return axiosInstance.patch(url, data, config);
1055
2713
  };
1056
- var isUnauthorized = (error) => {
1057
- return isStatusError(error, 401);
2714
+ var deleteRequest = async (url, params, customHeaders) => {
2715
+ const config = buildConfig2(params, customHeaders);
2716
+ return axiosInstance.delete(url, config);
1058
2717
  };
1059
- var isForbidden = (error) => {
1060
- return isStatusError(error, 403);
2718
+ var uploadFile = async (url, file, additionalData) => {
2719
+ const formData = new FormData();
2720
+ formData.append("file", file);
2721
+ if (additionalData) {
2722
+ Object.entries(additionalData).forEach(([key, value]) => {
2723
+ formData.append(key, String(value));
2724
+ });
2725
+ }
2726
+ const config = {
2727
+ headers: {
2728
+ "Content-Type": "multipart/form-data"
2729
+ }
2730
+ };
2731
+ return axiosInstance.post(url, formData, config);
2732
+ };
2733
+ var extractData = (response) => {
2734
+ return parseResponseData(response.data);
2735
+ };
2736
+ var extractMessage = (response) => {
2737
+ return parseResponseMessage(response, "");
2738
+ };
2739
+ var isSuccess = (response) => {
2740
+ return response.status >= 200 && response.status < 300;
2741
+ };
2742
+ var extractPaginatedData = (response) => {
2743
+ return parsePaginatedResponse(response.data);
2744
+ };
2745
+
2746
+ // src/client/http/slug.ts
2747
+ var generateSlug = (text) => {
2748
+ if (!text) return "";
2749
+ return text.trim().replace(/[^\w\s]/g, "").replace(/\s+(.)/g, (_, char) => char.toUpperCase()).replace(/\s+/g, "").replace(/^(.)/, (_, char) => char.toLowerCase());
1061
2750
  };
1062
- var isNotFound = (error) => {
1063
- return isStatusError(error, 404);
2751
+ var generateUrlSlug = (text) => {
2752
+ if (!text) return "";
2753
+ return text.trim().toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
1064
2754
  };
1065
- var isServerError = (error) => {
1066
- const status = error.response?.status;
1067
- return status !== void 0 && status >= 500;
2755
+ var generateSnakeSlug = (text) => {
2756
+ if (!text) return "";
2757
+ return text.trim().toLowerCase().replace(/[^\w\s]/g, "").replace(/\s+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
1068
2758
  };
1069
2759
 
1070
2760
  // src/client/logger/client-logger.ts
@@ -1220,40 +2910,6 @@ var formatRelativeTime = (date) => {
1220
2910
  }
1221
2911
  return "just now";
1222
2912
  };
1223
- var formatDateForInput = (date) => {
1224
- const dateObj = new Date(date);
1225
- return dateObj.toISOString().split("T")[0];
1226
- };
1227
- var formatDateTimeForInput = (date) => {
1228
- const dateObj = new Date(date);
1229
- return dateObj.toISOString().slice(0, 16);
1230
- };
1231
- var isToday = (date) => {
1232
- const dateObj = new Date(date);
1233
- const today = /* @__PURE__ */ new Date();
1234
- return dateObj.getDate() === today.getDate() && dateObj.getMonth() === today.getMonth() && dateObj.getFullYear() === today.getFullYear();
1235
- };
1236
- var isPast = (date) => {
1237
- return new Date(date).getTime() < Date.now();
1238
- };
1239
- var isFuture = (date) => {
1240
- return new Date(date).getTime() > Date.now();
1241
- };
1242
- var addDays = (date, days) => {
1243
- const dateObj = new Date(date);
1244
- dateObj.setDate(dateObj.getDate() + days);
1245
- return dateObj;
1246
- };
1247
- var startOfDay = (date) => {
1248
- const dateObj = new Date(date);
1249
- dateObj.setHours(0, 0, 0, 0);
1250
- return dateObj;
1251
- };
1252
- var endOfDay = (date) => {
1253
- const dateObj = new Date(date);
1254
- dateObj.setHours(23, 59, 59, 999);
1255
- return dateObj;
1256
- };
1257
2913
 
1258
2914
  // src/client/utils/clipboard.ts
1259
2915
  var copyToClipboard = async (text) => {
@@ -1278,20 +2934,6 @@ var copyToClipboard = async (text) => {
1278
2934
  return false;
1279
2935
  }
1280
2936
  };
1281
- var readFromClipboard = async () => {
1282
- try {
1283
- if (navigator.clipboard && window.isSecureContext) {
1284
- return await navigator.clipboard.readText();
1285
- }
1286
- return null;
1287
- } catch (error) {
1288
- console.error("Failed to read from clipboard:", error);
1289
- return null;
1290
- }
1291
- };
1292
- var isClipboardAvailable = () => {
1293
- return !!(navigator.clipboard && window.isSecureContext);
1294
- };
1295
2937
 
1296
2938
  // src/client/utils/slug.ts
1297
2939
  var slugify = (text) => {
@@ -1328,165 +2970,15 @@ var kebabToCamel = (text) => {
1328
2970
  return text.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
1329
2971
  };
1330
2972
 
1331
- // src/client/utils/events.ts
1332
- var EventEmitter = class {
1333
- constructor() {
1334
- this.handlers = /* @__PURE__ */ new Map();
1335
- }
1336
- /**
1337
- * Subscribe to an event
1338
- * @returns Unsubscribe function
1339
- */
1340
- on(event, handler) {
1341
- if (!this.handlers.has(event)) {
1342
- this.handlers.set(event, /* @__PURE__ */ new Set());
1343
- }
1344
- this.handlers.get(event).add(handler);
1345
- return () => this.off(event, handler);
1346
- }
1347
- /**
1348
- * Subscribe to an event once
1349
- */
1350
- once(event, handler) {
1351
- const wrappedHandler = (data) => {
1352
- this.off(event, wrappedHandler);
1353
- handler(data);
1354
- };
1355
- return this.on(event, wrappedHandler);
1356
- }
1357
- /**
1358
- * Unsubscribe from an event
1359
- */
1360
- off(event, handler) {
1361
- const eventHandlers = this.handlers.get(event);
1362
- if (eventHandlers) {
1363
- eventHandlers.delete(handler);
1364
- }
1365
- }
1366
- /**
1367
- * Emit an event
1368
- */
1369
- emit(event, data) {
1370
- const eventHandlers = this.handlers.get(event);
1371
- if (eventHandlers) {
1372
- eventHandlers.forEach((handler) => {
1373
- try {
1374
- handler(data);
1375
- } catch (error) {
1376
- console.error(`Error in event handler for "${String(event)}":`, error);
1377
- }
1378
- });
1379
- }
1380
- }
1381
- /**
1382
- * Remove all handlers for an event (or all events)
1383
- */
1384
- removeAllListeners(event) {
1385
- if (event) {
1386
- this.handlers.delete(event);
1387
- } else {
1388
- this.handlers.clear();
1389
- }
1390
- }
1391
- /**
1392
- * Get count of listeners for an event
1393
- */
1394
- listenerCount(event) {
1395
- return this.handlers.get(event)?.size ?? 0;
1396
- }
1397
- };
1398
- var createEventEmitter = () => {
1399
- return new EventEmitter();
1400
- };
1401
- var appEvents = new EventEmitter();
1402
-
1403
- // src/client/utils/api-urls.ts
1404
- var ApiUrlBuilder = class {
1405
- constructor(config) {
1406
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
1407
- this.version = config.version || "";
1408
- }
1409
- /**
1410
- * Build full URL from path
1411
- */
1412
- build(path2) {
1413
- const normalizedPath = path2.startsWith("/") ? path2 : `/${path2}`;
1414
- const versionPath = this.version ? `/${this.version}` : "";
1415
- return `${this.baseUrl}${versionPath}${normalizedPath}`;
1416
- }
1417
- /**
1418
- * Build URL with query parameters
1419
- */
1420
- buildWithParams(path2, params) {
1421
- const url = this.build(path2);
1422
- const filteredParams = Object.entries(params).filter(([, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`).join("&");
1423
- return filteredParams ? `${url}?${filteredParams}` : url;
1424
- }
1425
- /**
1426
- * Build URL with path parameters
1427
- */
1428
- buildWithPathParams(template, params) {
1429
- let path2 = template;
1430
- Object.entries(params).forEach(([key, value]) => {
1431
- path2 = path2.replace(`:${key}`, String(value));
1432
- path2 = path2.replace(`{${key}}`, String(value));
1433
- });
1434
- return this.build(path2);
1435
- }
1436
- /**
1437
- * Get base URL
1438
- */
1439
- getBaseUrl() {
1440
- return this.baseUrl;
1441
- }
1442
- /**
1443
- * Set new base URL
1444
- */
1445
- setBaseUrl(baseUrl) {
1446
- this.baseUrl = baseUrl.replace(/\/$/, "");
1447
- }
1448
- };
1449
- var createApiUrlBuilder = (config) => {
1450
- return new ApiUrlBuilder(config);
1451
- };
1452
- var createApiEndpoints = (builder) => ({
1453
- // Auth endpoints
1454
- auth: {
1455
- login: () => builder.build("/auth/login"),
1456
- register: () => builder.build("/auth/register"),
1457
- logout: () => builder.build("/auth/logout"),
1458
- refresh: () => builder.build("/auth/refresh"),
1459
- me: () => builder.build("/auth/me"),
1460
- forgotPassword: () => builder.build("/auth/forgot-password"),
1461
- resetPassword: () => builder.build("/auth/reset-password")
1462
- },
1463
- // User endpoints
1464
- users: {
1465
- list: () => builder.build("/users"),
1466
- get: (id) => builder.buildWithPathParams("/users/:id", { id }),
1467
- create: () => builder.build("/users"),
1468
- update: (id) => builder.buildWithPathParams("/users/:id", { id }),
1469
- delete: (id) => builder.buildWithPathParams("/users/:id", { id })
1470
- },
1471
- // Generic CRUD factory
1472
- crud: (resource) => ({
1473
- list: () => builder.build(`/${resource}`),
1474
- get: (id) => builder.buildWithPathParams(`/${resource}/:id`, { id }),
1475
- create: () => builder.build(`/${resource}`),
1476
- update: (id) => builder.buildWithPathParams(`/${resource}/:id`, { id }),
1477
- delete: (id) => builder.buildWithPathParams(`/${resource}/:id`, { id })
1478
- })
1479
- });
1480
-
1481
2973
  // src/client/utils/response-parser.ts
1482
- var isSuccessResponse = (response) => {
2974
+ var isSuccessResponse2 = (response) => {
1483
2975
  return response.success === true;
1484
2976
  };
1485
- var isErrorResponse = (response) => {
2977
+ var isErrorResponse2 = (response) => {
1486
2978
  return response.success === false;
1487
2979
  };
1488
2980
  var getResponseData = (response, defaultValue) => {
1489
- if (isSuccessResponse(response) && response.data !== void 0) {
2981
+ if (isSuccessResponse2(response) && response.data !== void 0) {
1490
2982
  return response.data;
1491
2983
  }
1492
2984
  return defaultValue;
@@ -3727,18 +5219,18 @@ function useLogger(componentName, props, options = {}) {
3727
5219
  const {
3728
5220
  logProps = true,
3729
5221
  logLifecycle = true,
3730
- logger: logger2 = console.log
5222
+ logger: logger3 = console.log
3731
5223
  } = options;
3732
5224
  const previousProps = react.useRef(props);
3733
5225
  const renderCount = react.useRef(0);
3734
5226
  renderCount.current++;
3735
5227
  react.useEffect(() => {
3736
5228
  if (logLifecycle) {
3737
- logger2(`[${componentName}] Mounted`);
5229
+ logger3(`[${componentName}] Mounted`);
3738
5230
  }
3739
5231
  return () => {
3740
5232
  if (logLifecycle) {
3741
- logger2(`[${componentName}] Unmounted (rendered ${renderCount.current} times)`);
5233
+ logger3(`[${componentName}] Unmounted (rendered ${renderCount.current} times)`);
3742
5234
  }
3743
5235
  };
3744
5236
  }, []);
@@ -3770,12 +5262,12 @@ function useLogger(componentName, props, options = {}) {
3770
5262
  });
3771
5263
  }
3772
5264
  if (hasChanges) {
3773
- logger2(`[${componentName}] Props changed:`, changedProps);
5265
+ logger3(`[${componentName}] Props changed:`, changedProps);
3774
5266
  }
3775
5267
  previousProps.current = props;
3776
- }, [componentName, props, logProps, logger2]);
5268
+ }, [componentName, props, logProps, logger3]);
3777
5269
  if (process.env.NODE_ENV === "development") {
3778
- logger2(`[${componentName}] Render #${renderCount.current}`);
5270
+ logger3(`[${componentName}] Render #${renderCount.current}`);
3779
5271
  }
3780
5272
  }
3781
5273
  var useLogger_default = useLogger;
@@ -4973,14 +6465,14 @@ var defaultDarkTheme = {
4973
6465
  };
4974
6466
 
4975
6467
  // src/client/web/theme/theme-utils.ts
4976
- function deepMerge(target, source) {
6468
+ function deepMerge2(target, source) {
4977
6469
  const output = { ...target };
4978
6470
  for (const key in source) {
4979
6471
  if (Object.prototype.hasOwnProperty.call(source, key)) {
4980
6472
  const sourceValue = source[key];
4981
6473
  const targetValue = target[key];
4982
6474
  if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
4983
- output[key] = deepMerge(
6475
+ output[key] = deepMerge2(
4984
6476
  targetValue,
4985
6477
  sourceValue
4986
6478
  );
@@ -5046,7 +6538,7 @@ function createThemeFromBrand(brand, baseTheme = defaultLightTheme) {
5046
6538
  }
5047
6539
  }
5048
6540
  };
5049
- return deepMerge(baseTheme, brandOverrides);
6541
+ return deepMerge2(baseTheme, brandOverrides);
5050
6542
  }
5051
6543
  function adjustColor(hex, percent) {
5052
6544
  hex = hex.replace(/^#/, "");
@@ -5140,8 +6632,8 @@ async function createTheme(config = {}) {
5140
6632
  if (config.themeUrl) {
5141
6633
  const urlTheme = await loadThemeFromUrl(config.themeUrl);
5142
6634
  if (urlTheme) {
5143
- lightTheme = deepMerge(lightTheme, urlTheme);
5144
- darkTheme = deepMerge(darkTheme, urlTheme);
6635
+ lightTheme = deepMerge2(lightTheme, urlTheme);
6636
+ darkTheme = deepMerge2(darkTheme, urlTheme);
5145
6637
  }
5146
6638
  }
5147
6639
  if (config.brandIdentity) {
@@ -5149,10 +6641,10 @@ async function createTheme(config = {}) {
5149
6641
  darkTheme = createThemeFromBrand(config.brandIdentity, darkTheme);
5150
6642
  }
5151
6643
  if (config.light) {
5152
- lightTheme = deepMerge(lightTheme, config.light);
6644
+ lightTheme = deepMerge2(lightTheme, config.light);
5153
6645
  }
5154
6646
  if (config.dark) {
5155
- darkTheme = deepMerge(darkTheme, config.dark);
6647
+ darkTheme = deepMerge2(darkTheme, config.dark);
5156
6648
  }
5157
6649
  return { light: lightTheme, dark: darkTheme };
5158
6650
  }
@@ -5226,7 +6718,7 @@ function ThemeProvider({
5226
6718
  theme2 = createThemeFromBrand(brandIdentity, theme2);
5227
6719
  }
5228
6720
  if (lightOverrides) {
5229
- theme2 = deepMerge(theme2, lightOverrides);
6721
+ theme2 = deepMerge2(theme2, lightOverrides);
5230
6722
  }
5231
6723
  return theme2;
5232
6724
  });
@@ -5237,7 +6729,7 @@ function ThemeProvider({
5237
6729
  theme2 = createThemeFromBrand(brandIdentity, theme2);
5238
6730
  }
5239
6731
  if (darkOverrides) {
5240
- theme2 = deepMerge(theme2, darkOverrides);
6732
+ theme2 = deepMerge2(theme2, darkOverrides);
5241
6733
  }
5242
6734
  return theme2;
5243
6735
  });
@@ -5256,8 +6748,8 @@ function ThemeProvider({
5256
6748
  setError(null);
5257
6749
  loadThemeFromUrl(themeUrl).then((urlTheme) => {
5258
6750
  if (urlTheme) {
5259
- setLightTheme((prev) => deepMerge(prev, urlTheme));
5260
- setDarkTheme((prev) => deepMerge(prev, urlTheme));
6751
+ setLightTheme((prev) => deepMerge2(prev, urlTheme));
6752
+ setDarkTheme((prev) => deepMerge2(prev, urlTheme));
5261
6753
  }
5262
6754
  }).catch((err) => {
5263
6755
  setError(err instanceof Error ? err.message : "Failed to load theme");
@@ -5302,8 +6794,8 @@ function ThemeProvider({
5302
6794
  });
5303
6795
  }, []);
5304
6796
  const updateTheme = react.useCallback((updates) => {
5305
- setLightTheme((prev) => deepMerge(prev, updates));
5306
- setDarkTheme((prev) => deepMerge(prev, updates));
6797
+ setLightTheme((prev) => deepMerge2(prev, updates));
6798
+ setDarkTheme((prev) => deepMerge2(prev, updates));
5307
6799
  }, []);
5308
6800
  const resetTheme = react.useCallback(() => {
5309
6801
  let light = defaultLightTheme;
@@ -5313,10 +6805,10 @@ function ThemeProvider({
5313
6805
  dark = createThemeFromBrand(brandIdentity, dark);
5314
6806
  }
5315
6807
  if (lightOverrides) {
5316
- light = deepMerge(light, lightOverrides);
6808
+ light = deepMerge2(light, lightOverrides);
5317
6809
  }
5318
6810
  if (darkOverrides) {
5319
- dark = deepMerge(dark, darkOverrides);
6811
+ dark = deepMerge2(dark, darkOverrides);
5320
6812
  }
5321
6813
  setLightTheme(light);
5322
6814
  setDarkTheme(dark);
@@ -6671,7 +8163,7 @@ __export(shared_exports, {
6671
8163
  isSameMonth: () => dateFns.isSameMonth,
6672
8164
  isSameWeek: () => dateFns.isSameWeek,
6673
8165
  isSameYear: () => dateFns.isSameYear,
6674
- isTest: () => isTest,
8166
+ isTest: () => isTest2,
6675
8167
  isThisMonth: () => dateFns.isThisMonth,
6676
8168
  isThisWeek: () => dateFns.isThisWeek,
6677
8169
  isThisYear: () => dateFns.isThisYear,
@@ -6750,7 +8242,7 @@ var isProd = () => {
6750
8242
  var isDev = () => {
6751
8243
  return process.env.NODE_ENV === "development";
6752
8244
  };
6753
- var isTest = () => {
8245
+ var isTest2 = () => {
6754
8246
  return process.env.NODE_ENV === "test";
6755
8247
  };
6756
8248
  var validateEnv = (requiredVars) => {