@exyconn/common 2.3.2 → 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 (40) hide show
  1. package/README.md +117 -12
  2. package/dist/client/http/index.d.mts +217 -49
  3. package/dist/client/http/index.d.ts +217 -49
  4. package/dist/client/http/index.js +473 -94
  5. package/dist/client/http/index.js.map +1 -1
  6. package/dist/client/http/index.mjs +441 -84
  7. package/dist/client/http/index.mjs.map +1 -1
  8. package/dist/client/index.d.mts +3 -3
  9. package/dist/client/index.d.ts +3 -3
  10. package/dist/client/index.js +481 -319
  11. package/dist/client/index.js.map +1 -1
  12. package/dist/client/index.mjs +449 -290
  13. package/dist/client/index.mjs.map +1 -1
  14. package/dist/client/utils/index.d.mts +3 -279
  15. package/dist/client/utils/index.d.ts +3 -279
  16. package/dist/{index-DuxL84IW.d.mts → index-BZf42T3R.d.mts} +39 -39
  17. package/dist/{index-D9a9oxQy.d.ts → index-CF0D8PGE.d.ts} +39 -39
  18. package/dist/{index-D3yCCjBZ.d.mts → index-Ckhm_HaX.d.mts} +21 -2
  19. package/dist/{index-01hoqibP.d.ts → index-br6POSyA.d.ts} +21 -2
  20. package/dist/index.d.mts +3 -3
  21. package/dist/index.d.ts +3 -3
  22. package/dist/index.js +1122 -329
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.mjs +1134 -341
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/packageCheck-B_qfsD6R.d.ts +280 -0
  27. package/dist/packageCheck-C2_FT_Rl.d.mts +280 -0
  28. package/dist/server/index.d.mts +1 -1
  29. package/dist/server/index.d.ts +1 -1
  30. package/dist/server/index.js +631 -0
  31. package/dist/server/index.js.map +1 -1
  32. package/dist/server/index.mjs +625 -2
  33. package/dist/server/index.mjs.map +1 -1
  34. package/dist/server/middleware/index.d.mts +283 -2
  35. package/dist/server/middleware/index.d.ts +283 -2
  36. package/dist/server/middleware/index.js +761 -0
  37. package/dist/server/middleware/index.js.map +1 -1
  38. package/dist/server/middleware/index.mjs +751 -1
  39. package/dist/server/middleware/index.mjs.map +1 -1
  40. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -73,6 +73,7 @@ __export(server_exports, {
73
73
  authenticateJWT: () => authenticateJWT,
74
74
  badRequestResponse: () => badRequestResponse,
75
75
  buildConfig: () => buildConfig,
76
+ buildDeleteFilter: () => buildDeleteFilter,
76
77
  buildFilter: () => buildFilter,
77
78
  buildPagination: () => buildPagination,
78
79
  buildPaginationMeta: () => buildPaginationMeta,
@@ -83,12 +84,15 @@ __export(server_exports, {
83
84
  createApiKeyGenerator: () => createApiKeyGenerator,
84
85
  createApiRateLimiter: () => createApiRateLimiter,
85
86
  createBrandCorsOptions: () => createBrandCorsOptions,
87
+ createBulkDeleteHandler: () => createBulkDeleteHandler,
86
88
  createConfig: () => createConfig,
87
89
  createCorsOptions: () => createCorsOptions,
90
+ createCrudControllers: () => createCrudControllers,
88
91
  createDdosRateLimiter: () => createDdosRateLimiter,
89
92
  createLogger: () => createLogger,
90
93
  createMorganStream: () => createMorganStream,
91
94
  createMultiBrandCorsOptions: () => createMultiBrandCorsOptions,
95
+ createPaginationMiddleware: () => createPaginationMiddleware,
92
96
  createPrefixedKeyGenerator: () => createPrefixedKeyGenerator,
93
97
  createRateLimiter: () => createRateLimiter,
94
98
  createStandardRateLimiter: () => createStandardRateLimiter,
@@ -101,6 +105,7 @@ __export(server_exports, {
101
105
  errorResponse: () => errorResponse,
102
106
  extractColumns: () => extractColumns,
103
107
  extractOrganization: () => extractOrganization,
108
+ extractSchemaMeta: () => extractSchemaMeta,
104
109
  forbiddenResponse: () => forbiddenResponse,
105
110
  formatPackageCheckResult: () => formatPackageCheckResult,
106
111
  generateNcuCommand: () => generateNcuCommand,
@@ -115,8 +120,11 @@ __export(server_exports, {
115
120
  omitFields: () => omitFields,
116
121
  optionalAuthenticateJWT: () => optionalAuthenticateJWT,
117
122
  packageCheckServer: () => packageCheckServer,
123
+ parseBulkDelete: () => parseBulkDelete,
118
124
  pickFields: () => pickFields,
119
125
  printPackageCheckSummary: () => printPackageCheckSummary,
126
+ queryPagination: () => queryPagination,
127
+ queryParser: () => queryParser,
120
128
  rateLimitResponse: () => rateLimitResponse,
121
129
  rateLimiter: () => rateLimiter,
122
130
  requireOrganization: () => requireOrganization,
@@ -410,37 +418,37 @@ var defaultOptions = {
410
418
  retryReads: true,
411
419
  w: "majority"
412
420
  };
413
- var connectDB = async (mongoUri, options = {}, logger2) => {
421
+ var connectDB = async (mongoUri, options = {}, logger3) => {
414
422
  if (mongoose__default.default.connection.readyState === 1) {
415
- logger2?.info("Database already connected, reusing connection");
423
+ logger3?.info("Database already connected, reusing connection");
416
424
  return mongoose__default.default;
417
425
  }
418
426
  const finalOptions = { ...defaultOptions, ...options };
419
427
  try {
420
428
  await mongoose__default.default.connect(mongoUri, finalOptions);
421
- logger2?.info("MongoDB connected successfully");
429
+ logger3?.info("MongoDB connected successfully");
422
430
  mongoose__default.default.connection.on("error", (err) => {
423
- logger2?.error("MongoDB connection error", err);
431
+ logger3?.error("MongoDB connection error", err);
424
432
  });
425
433
  mongoose__default.default.connection.on("disconnected", () => {
426
- logger2?.info("MongoDB disconnected");
434
+ logger3?.info("MongoDB disconnected");
427
435
  });
428
436
  mongoose__default.default.connection.on("reconnected", () => {
429
- logger2?.info("MongoDB reconnected");
437
+ logger3?.info("MongoDB reconnected");
430
438
  });
431
439
  return mongoose__default.default;
432
440
  } catch (error) {
433
441
  const errorMessage = error instanceof Error ? error.message : String(error);
434
- logger2?.error("MongoDB connection failed", { error: errorMessage });
442
+ logger3?.error("MongoDB connection failed", { error: errorMessage });
435
443
  throw error;
436
444
  }
437
445
  };
438
- var disconnectDB = async (logger2) => {
446
+ var disconnectDB = async (logger3) => {
439
447
  try {
440
448
  await mongoose__default.default.disconnect();
441
- logger2?.info("MongoDB disconnected successfully");
449
+ logger3?.info("MongoDB disconnected successfully");
442
450
  } catch (error) {
443
- logger2?.error("Error disconnecting from MongoDB", error);
451
+ logger3?.error("Error disconnecting from MongoDB", error);
444
452
  throw error;
445
453
  }
446
454
  };
@@ -545,6 +553,629 @@ var requireOrganization = (req, res, next) => {
545
553
  next();
546
554
  };
547
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
+
548
1179
  // src/server/utils/filter-builder.ts
549
1180
  var buildFilter = (options) => {
550
1181
  const {
@@ -1502,34 +2133,32 @@ var getDatabaseOptions = (config) => {
1502
2133
  // src/client/index.ts
1503
2134
  var client_exports = {};
1504
2135
  __export(client_exports, {
1505
- ApiUrlBuilder: () => ApiUrlBuilder,
2136
+ API_BASE_URL: () => API_BASE_URL,
2137
+ API_PREFIX: () => API_PREFIX,
1506
2138
  ClientLogger: () => ClientLogger,
1507
2139
  ContactForm: () => ContactForm,
1508
- EventEmitter: () => EventEmitter,
2140
+ ERROR_CODES: () => ERROR_CODES,
1509
2141
  LoginForm: () => LoginForm,
1510
2142
  NewsletterForm: () => NewsletterForm,
1511
2143
  RegisterForm: () => RegisterForm,
2144
+ STATUS_CODES: () => STATUS_CODES,
2145
+ STATUS_MESSAGES: () => STATUS_MESSAGES,
2146
+ SUCCESS_CODES: () => SUCCESS_CODES,
1512
2147
  ThemeContext: () => ThemeContext,
1513
2148
  ThemeProvider: () => ThemeProvider,
1514
2149
  ThemeToggle: () => ThemeToggle,
1515
2150
  VALIDATION_MESSAGES: () => VALIDATION_MESSAGES,
1516
- addDays: () => addDays,
1517
2151
  adjustColor: () => adjustColor,
1518
- appEvents: () => appEvents,
2152
+ axios: () => axiosInstance,
1519
2153
  camelToKebab: () => camelToKebab,
1520
2154
  capitalize: () => capitalize,
1521
2155
  capitalizeWords: () => capitalizeWords,
1522
- checkPackage: () => checkPackage,
1523
2156
  clientLogger: () => clientLogger,
1524
2157
  contactFormSchema: () => contactFormSchema,
1525
2158
  copyToClipboard: () => copyToClipboard,
1526
- createApiEndpoints: () => createApiEndpoints,
1527
- createApiUrlBuilder: () => createApiUrlBuilder,
1528
2159
  createClientLogger: () => createClientLogger,
1529
2160
  createEmptyPaginationMeta: () => createEmptyPaginationMeta,
1530
2161
  createErrorResponse: () => createErrorResponse,
1531
- createEventEmitter: () => createEventEmitter,
1532
- createHttpClient: () => createHttpClient,
1533
2162
  createRegisterFormSchema: () => createRegisterFormSchema,
1534
2163
  createSuccessResponse: () => createSuccessResponse,
1535
2164
  createTheme: () => createTheme,
@@ -1538,6 +2167,7 @@ __export(client_exports, {
1538
2167
  deepMerge: () => deepMerge2,
1539
2168
  defaultDarkTheme: () => defaultDarkTheme,
1540
2169
  defaultLightTheme: () => defaultLightTheme,
2170
+ deleteRequest: () => deleteRequest,
1541
2171
  dummyBannerData: () => dummyBannerData,
1542
2172
  dummyFaqItems: () => dummyFaqItems,
1543
2173
  dummyFeatures: () => dummyFeatures,
@@ -1546,59 +2176,66 @@ __export(client_exports, {
1546
2176
  dummyImage: () => dummyImage,
1547
2177
  dummyPricingPlans: () => dummyPricingPlans,
1548
2178
  dummyTestimonials: () => dummyTestimonials,
1549
- endOfDay: () => endOfDay,
2179
+ extractData: () => extractData,
2180
+ extractMessage: () => extractMessage,
2181
+ extractNestedData: () => extractNestedData,
2182
+ extractPaginatedData: () => extractPaginatedData,
1550
2183
  flattenToCssVars: () => flattenToCssVars,
1551
2184
  formatDate: () => formatDate,
1552
- formatDateForInput: () => formatDateForInput,
1553
2185
  formatDateTime: () => formatDateTime,
1554
- formatDateTimeForInput: () => formatDateTimeForInput,
1555
- formatPackageCheckResult: () => formatPackageCheckResult2,
1556
2186
  formatRelativeTime: () => formatRelativeTime,
1557
2187
  generateCssVars: () => generateCssVars,
1558
- generateNcuCommand: () => generateNcuCommand2,
2188
+ generateSlug: () => generateSlug,
2189
+ generateSnakeSlug: () => generateSnakeSlug,
2190
+ generateUrlSlug: () => generateUrlSlug,
1559
2191
  getContrastColor: () => getContrastColor,
1560
2192
  getErrorMessage: () => getErrorMessage,
1561
2193
  getNextPage: () => getNextPage,
1562
2194
  getPrevPage: () => getPrevPage,
2195
+ getRequest: () => getRequest,
1563
2196
  getResponseData: () => getResponseData,
1564
2197
  getSystemColorScheme: () => getSystemColorScheme,
1565
2198
  hasData: () => hasData,
1566
2199
  hasMorePages: () => hasMorePages,
1567
2200
  hexToRgba: () => hexToRgba,
1568
2201
  injectCssVars: () => injectCssVars,
1569
- isClipboardAvailable: () => isClipboardAvailable,
1570
2202
  isErrorResponse: () => isErrorResponse,
1571
- isForbidden: () => isForbidden,
1572
- isFuture: () => isFuture,
1573
- isNotFound: () => isNotFound,
1574
- isPast: () => isPast,
1575
- isServerError: () => isServerError,
1576
- isStatusError: () => isStatusError,
1577
2203
  isSuccess: () => isSuccess,
1578
2204
  isSuccessResponse: () => isSuccessResponse,
1579
- isToday: () => isToday,
1580
- isUnauthorized: () => isUnauthorized,
2205
+ isUtilErrorResponse: () => isErrorResponse2,
2206
+ isUtilSuccessResponse: () => isSuccessResponse2,
1581
2207
  kebabToCamel: () => kebabToCamel,
1582
2208
  loadThemeFromUrl: () => loadThemeFromUrl,
1583
2209
  loadThemeMode: () => loadThemeMode,
2210
+ logger: () => logger2,
1584
2211
  loginFormSchema: () => loginFormSchema,
1585
2212
  loremIpsum: () => loremIpsum,
1586
2213
  newsletterFormSchema: () => newsletterFormSchema,
1587
2214
  packageCheck: () => packageCheck,
2215
+ parseAxiosErrorMessage: () => parseAxiosErrorMessage,
1588
2216
  parseError: () => parseError,
1589
- parseFullResponse: () => parseFullResponse,
1590
- parseResponse: () => parseResponse,
1591
- 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,
1592
2225
  registerFormSchema: () => registerFormSchema,
1593
2226
  removeCssVars: () => removeCssVars,
1594
2227
  resolveThemeMode: () => resolveThemeMode,
2228
+ safeJsonParse: () => safeJsonParse,
1595
2229
  saveThemeMode: () => saveThemeMode,
2230
+ simpleMetaParseResponse: () => simpleMetaParseResponse,
2231
+ simpleParseDualDataResponse: () => simpleParseDualDataResponse,
2232
+ simpleParseResponse: () => simpleParseResponse,
1596
2233
  slugify: () => slugify,
1597
2234
  slugifyUnique: () => slugifyUnique,
1598
- startOfDay: () => startOfDay,
1599
2235
  truncate: () => truncate,
1600
2236
  truncateWords: () => truncateWords,
1601
2237
  unslugify: () => unslugify,
2238
+ uploadFile: () => uploadFile,
1602
2239
  useBattery: () => useBattery_default,
1603
2240
  useClickAway: () => useClickAway_default,
1604
2241
  useContinuousRetry: () => useContinuousRetry_default,
@@ -1658,112 +2295,466 @@ __export(client_exports, {
1658
2295
  useToggle: () => useToggle_default,
1659
2296
  useVisibilityChange: () => useVisibilityChange_default,
1660
2297
  useWindowScroll: () => useWindowScroll_default,
1661
- useWindowSize: () => useWindowSize_default,
1662
- withAbortSignal: () => withAbortSignal,
1663
- withFormData: () => withFormData,
1664
- withTimeout: () => withTimeout
2298
+ useWindowSize: () => useWindowSize_default
1665
2299
  });
1666
- var createHttpClient = (options) => {
1667
- const {
1668
- baseURL,
1669
- timeout = 3e4,
1670
- withCredentials = true,
1671
- getAuthToken,
1672
- onUnauthorized,
1673
- onServerError
1674
- } = options;
1675
- const instance = axios__default.default.create({
1676
- baseURL,
1677
- timeout,
1678
- withCredentials,
1679
- headers: {
1680
- "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 ?? "");
1681
2313
  }
1682
- });
1683
- instance.interceptors.request.use(
1684
- (config) => {
1685
- if (getAuthToken) {
1686
- const token = getAuthToken();
1687
- if (token && config.headers) {
1688
- config.headers.Authorization = `Bearer ${token}`;
1689
- }
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
1690
2351
  }
1691
- return config;
1692
- },
1693
- (error) => Promise.reject(error)
1694
- );
1695
- instance.interceptors.response.use(
1696
- (response) => response,
1697
- (error) => {
1698
- if (error.response) {
1699
- const status = error.response.status;
1700
- if (status === 401 && onUnauthorized) {
1701
- onUnauthorized();
1702
- }
1703
- if (status >= 500 && onServerError) {
1704
- onServerError(error);
1705
- }
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"];
1706
2499
  }
1707
- return Promise.reject(error);
1708
2500
  }
1709
- );
1710
- 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
+ }
1711
2517
  };
1712
- var withFormData = () => ({
1713
- headers: {
1714
- "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;
1715
2533
  }
1716
- });
1717
- var withTimeout = (ms) => ({
1718
- timeout: ms
1719
- });
1720
- var withAbortSignal = (signal) => ({
1721
- signal
1722
- });
1723
-
1724
- // src/client/http/response-parser.ts
1725
- var parseResponse = (response) => {
1726
- if (response.data?.success && response.data?.data !== void 0) {
1727
- 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;
1728
2541
  }
1729
- return null;
1730
2542
  };
1731
- var parseFullResponse = (response) => {
1732
- 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
+ }
1733
2578
  };
1734
2579
  var parseError = (error) => {
1735
- if (error.response?.data?.message) {
1736
- 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"
1737
2651
  }
1738
- if (error.response?.data?.error) {
1739
- 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);
1740
2672
  }
1741
- if (error.code === "ERR_NETWORK") {
1742
- 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);
1743
2680
  }
1744
- if (error.code === "ECONNABORTED") {
1745
- 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;
1746
2695
  }
1747
- return error.message || "An unexpected error occurred.";
2696
+ return config;
1748
2697
  };
1749
- var isSuccess = (response) => {
1750
- 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);
1751
2709
  };
1752
- var isStatusError = (error, statusCode2) => {
1753
- 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);
2713
+ };
2714
+ var deleteRequest = async (url, params, customHeaders) => {
2715
+ const config = buildConfig2(params, customHeaders);
2716
+ return axiosInstance.delete(url, config);
2717
+ };
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);
1754
2732
  };
1755
- var isUnauthorized = (error) => {
1756
- return isStatusError(error, 401);
2733
+ var extractData = (response) => {
2734
+ return parseResponseData(response.data);
1757
2735
  };
1758
- var isForbidden = (error) => {
1759
- return isStatusError(error, 403);
2736
+ var extractMessage = (response) => {
2737
+ return parseResponseMessage(response, "");
1760
2738
  };
1761
- var isNotFound = (error) => {
1762
- return isStatusError(error, 404);
2739
+ var isSuccess = (response) => {
2740
+ return response.status >= 200 && response.status < 300;
1763
2741
  };
1764
- var isServerError = (error) => {
1765
- const status = error.response?.status;
1766
- return status !== void 0 && status >= 500;
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());
2750
+ };
2751
+ var generateUrlSlug = (text) => {
2752
+ if (!text) return "";
2753
+ return text.trim().toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
2754
+ };
2755
+ var generateSnakeSlug = (text) => {
2756
+ if (!text) return "";
2757
+ return text.trim().toLowerCase().replace(/[^\w\s]/g, "").replace(/\s+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
1767
2758
  };
1768
2759
 
1769
2760
  // src/client/logger/client-logger.ts
@@ -1919,40 +2910,6 @@ var formatRelativeTime = (date) => {
1919
2910
  }
1920
2911
  return "just now";
1921
2912
  };
1922
- var formatDateForInput = (date) => {
1923
- const dateObj = new Date(date);
1924
- return dateObj.toISOString().split("T")[0];
1925
- };
1926
- var formatDateTimeForInput = (date) => {
1927
- const dateObj = new Date(date);
1928
- return dateObj.toISOString().slice(0, 16);
1929
- };
1930
- var isToday = (date) => {
1931
- const dateObj = new Date(date);
1932
- const today = /* @__PURE__ */ new Date();
1933
- return dateObj.getDate() === today.getDate() && dateObj.getMonth() === today.getMonth() && dateObj.getFullYear() === today.getFullYear();
1934
- };
1935
- var isPast = (date) => {
1936
- return new Date(date).getTime() < Date.now();
1937
- };
1938
- var isFuture = (date) => {
1939
- return new Date(date).getTime() > Date.now();
1940
- };
1941
- var addDays = (date, days) => {
1942
- const dateObj = new Date(date);
1943
- dateObj.setDate(dateObj.getDate() + days);
1944
- return dateObj;
1945
- };
1946
- var startOfDay = (date) => {
1947
- const dateObj = new Date(date);
1948
- dateObj.setHours(0, 0, 0, 0);
1949
- return dateObj;
1950
- };
1951
- var endOfDay = (date) => {
1952
- const dateObj = new Date(date);
1953
- dateObj.setHours(23, 59, 59, 999);
1954
- return dateObj;
1955
- };
1956
2913
 
1957
2914
  // src/client/utils/clipboard.ts
1958
2915
  var copyToClipboard = async (text) => {
@@ -1977,20 +2934,6 @@ var copyToClipboard = async (text) => {
1977
2934
  return false;
1978
2935
  }
1979
2936
  };
1980
- var readFromClipboard = async () => {
1981
- try {
1982
- if (navigator.clipboard && window.isSecureContext) {
1983
- return await navigator.clipboard.readText();
1984
- }
1985
- return null;
1986
- } catch (error) {
1987
- console.error("Failed to read from clipboard:", error);
1988
- return null;
1989
- }
1990
- };
1991
- var isClipboardAvailable = () => {
1992
- return !!(navigator.clipboard && window.isSecureContext);
1993
- };
1994
2937
 
1995
2938
  // src/client/utils/slug.ts
1996
2939
  var slugify = (text) => {
@@ -2027,165 +2970,15 @@ var kebabToCamel = (text) => {
2027
2970
  return text.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
2028
2971
  };
2029
2972
 
2030
- // src/client/utils/events.ts
2031
- var EventEmitter = class {
2032
- constructor() {
2033
- this.handlers = /* @__PURE__ */ new Map();
2034
- }
2035
- /**
2036
- * Subscribe to an event
2037
- * @returns Unsubscribe function
2038
- */
2039
- on(event, handler) {
2040
- if (!this.handlers.has(event)) {
2041
- this.handlers.set(event, /* @__PURE__ */ new Set());
2042
- }
2043
- this.handlers.get(event).add(handler);
2044
- return () => this.off(event, handler);
2045
- }
2046
- /**
2047
- * Subscribe to an event once
2048
- */
2049
- once(event, handler) {
2050
- const wrappedHandler = (data) => {
2051
- this.off(event, wrappedHandler);
2052
- handler(data);
2053
- };
2054
- return this.on(event, wrappedHandler);
2055
- }
2056
- /**
2057
- * Unsubscribe from an event
2058
- */
2059
- off(event, handler) {
2060
- const eventHandlers = this.handlers.get(event);
2061
- if (eventHandlers) {
2062
- eventHandlers.delete(handler);
2063
- }
2064
- }
2065
- /**
2066
- * Emit an event
2067
- */
2068
- emit(event, data) {
2069
- const eventHandlers = this.handlers.get(event);
2070
- if (eventHandlers) {
2071
- eventHandlers.forEach((handler) => {
2072
- try {
2073
- handler(data);
2074
- } catch (error) {
2075
- console.error(`Error in event handler for "${String(event)}":`, error);
2076
- }
2077
- });
2078
- }
2079
- }
2080
- /**
2081
- * Remove all handlers for an event (or all events)
2082
- */
2083
- removeAllListeners(event) {
2084
- if (event) {
2085
- this.handlers.delete(event);
2086
- } else {
2087
- this.handlers.clear();
2088
- }
2089
- }
2090
- /**
2091
- * Get count of listeners for an event
2092
- */
2093
- listenerCount(event) {
2094
- return this.handlers.get(event)?.size ?? 0;
2095
- }
2096
- };
2097
- var createEventEmitter = () => {
2098
- return new EventEmitter();
2099
- };
2100
- var appEvents = new EventEmitter();
2101
-
2102
- // src/client/utils/api-urls.ts
2103
- var ApiUrlBuilder = class {
2104
- constructor(config) {
2105
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
2106
- this.version = config.version || "";
2107
- }
2108
- /**
2109
- * Build full URL from path
2110
- */
2111
- build(path2) {
2112
- const normalizedPath = path2.startsWith("/") ? path2 : `/${path2}`;
2113
- const versionPath = this.version ? `/${this.version}` : "";
2114
- return `${this.baseUrl}${versionPath}${normalizedPath}`;
2115
- }
2116
- /**
2117
- * Build URL with query parameters
2118
- */
2119
- buildWithParams(path2, params) {
2120
- const url = this.build(path2);
2121
- const filteredParams = Object.entries(params).filter(([, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`).join("&");
2122
- return filteredParams ? `${url}?${filteredParams}` : url;
2123
- }
2124
- /**
2125
- * Build URL with path parameters
2126
- */
2127
- buildWithPathParams(template, params) {
2128
- let path2 = template;
2129
- Object.entries(params).forEach(([key, value]) => {
2130
- path2 = path2.replace(`:${key}`, String(value));
2131
- path2 = path2.replace(`{${key}}`, String(value));
2132
- });
2133
- return this.build(path2);
2134
- }
2135
- /**
2136
- * Get base URL
2137
- */
2138
- getBaseUrl() {
2139
- return this.baseUrl;
2140
- }
2141
- /**
2142
- * Set new base URL
2143
- */
2144
- setBaseUrl(baseUrl) {
2145
- this.baseUrl = baseUrl.replace(/\/$/, "");
2146
- }
2147
- };
2148
- var createApiUrlBuilder = (config) => {
2149
- return new ApiUrlBuilder(config);
2150
- };
2151
- var createApiEndpoints = (builder) => ({
2152
- // Auth endpoints
2153
- auth: {
2154
- login: () => builder.build("/auth/login"),
2155
- register: () => builder.build("/auth/register"),
2156
- logout: () => builder.build("/auth/logout"),
2157
- refresh: () => builder.build("/auth/refresh"),
2158
- me: () => builder.build("/auth/me"),
2159
- forgotPassword: () => builder.build("/auth/forgot-password"),
2160
- resetPassword: () => builder.build("/auth/reset-password")
2161
- },
2162
- // User endpoints
2163
- users: {
2164
- list: () => builder.build("/users"),
2165
- get: (id) => builder.buildWithPathParams("/users/:id", { id }),
2166
- create: () => builder.build("/users"),
2167
- update: (id) => builder.buildWithPathParams("/users/:id", { id }),
2168
- delete: (id) => builder.buildWithPathParams("/users/:id", { id })
2169
- },
2170
- // Generic CRUD factory
2171
- crud: (resource) => ({
2172
- list: () => builder.build(`/${resource}`),
2173
- get: (id) => builder.buildWithPathParams(`/${resource}/:id`, { id }),
2174
- create: () => builder.build(`/${resource}`),
2175
- update: (id) => builder.buildWithPathParams(`/${resource}/:id`, { id }),
2176
- delete: (id) => builder.buildWithPathParams(`/${resource}/:id`, { id })
2177
- })
2178
- });
2179
-
2180
2973
  // src/client/utils/response-parser.ts
2181
- var isSuccessResponse = (response) => {
2974
+ var isSuccessResponse2 = (response) => {
2182
2975
  return response.success === true;
2183
2976
  };
2184
- var isErrorResponse = (response) => {
2977
+ var isErrorResponse2 = (response) => {
2185
2978
  return response.success === false;
2186
2979
  };
2187
2980
  var getResponseData = (response, defaultValue) => {
2188
- if (isSuccessResponse(response) && response.data !== void 0) {
2981
+ if (isSuccessResponse2(response) && response.data !== void 0) {
2189
2982
  return response.data;
2190
2983
  }
2191
2984
  return defaultValue;
@@ -4426,18 +5219,18 @@ function useLogger(componentName, props, options = {}) {
4426
5219
  const {
4427
5220
  logProps = true,
4428
5221
  logLifecycle = true,
4429
- logger: logger2 = console.log
5222
+ logger: logger3 = console.log
4430
5223
  } = options;
4431
5224
  const previousProps = react.useRef(props);
4432
5225
  const renderCount = react.useRef(0);
4433
5226
  renderCount.current++;
4434
5227
  react.useEffect(() => {
4435
5228
  if (logLifecycle) {
4436
- logger2(`[${componentName}] Mounted`);
5229
+ logger3(`[${componentName}] Mounted`);
4437
5230
  }
4438
5231
  return () => {
4439
5232
  if (logLifecycle) {
4440
- logger2(`[${componentName}] Unmounted (rendered ${renderCount.current} times)`);
5233
+ logger3(`[${componentName}] Unmounted (rendered ${renderCount.current} times)`);
4441
5234
  }
4442
5235
  };
4443
5236
  }, []);
@@ -4469,12 +5262,12 @@ function useLogger(componentName, props, options = {}) {
4469
5262
  });
4470
5263
  }
4471
5264
  if (hasChanges) {
4472
- logger2(`[${componentName}] Props changed:`, changedProps);
5265
+ logger3(`[${componentName}] Props changed:`, changedProps);
4473
5266
  }
4474
5267
  previousProps.current = props;
4475
- }, [componentName, props, logProps, logger2]);
5268
+ }, [componentName, props, logProps, logger3]);
4476
5269
  if (process.env.NODE_ENV === "development") {
4477
- logger2(`[${componentName}] Render #${renderCount.current}`);
5270
+ logger3(`[${componentName}] Render #${renderCount.current}`);
4478
5271
  }
4479
5272
  }
4480
5273
  var useLogger_default = useLogger;