@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
@@ -1,9 +1,10 @@
1
1
  import winston from 'winston';
2
2
  import DailyRotateFile from 'winston-daily-rotate-file';
3
3
  import path, { resolve } from 'path';
4
- import mongoose from 'mongoose';
4
+ import mongoose, { Types } from 'mongoose';
5
5
  import jwt from 'jsonwebtoken';
6
6
  import { existsSync, readFileSync } from 'fs';
7
+ import rateLimit from 'express-rate-limit';
7
8
 
8
9
  // src/server/enums/status.ts
9
10
  var StatusCode = /* @__PURE__ */ ((StatusCode2) => {
@@ -416,6 +417,629 @@ var requireOrganization = (req, res, next) => {
416
417
  next();
417
418
  };
418
419
 
420
+ // src/server/middleware/queryParser.middleware.ts
421
+ var queryParser = (req, _, next) => {
422
+ const { page, limit, sort, sortBy, sortOrder, search, filter, ...otherParams } = req.query;
423
+ const parsed = {
424
+ page: Math.max(Number(page) || 1, 1),
425
+ limit: Math.min(Number(limit) || 10, 100),
426
+ filter: {}
427
+ };
428
+ if (typeof sort === "string") {
429
+ const [field, order] = sort.split(":");
430
+ parsed.sort = {
431
+ field,
432
+ order: order === "asc" ? "asc" : "desc"
433
+ };
434
+ } else if (typeof sortBy === "string") {
435
+ parsed.sort = {
436
+ field: sortBy,
437
+ order: sortOrder === "asc" ? "asc" : "desc"
438
+ };
439
+ }
440
+ if (typeof search === "string") {
441
+ parsed.search = search;
442
+ }
443
+ if (typeof filter === "object" && filter !== null) {
444
+ Object.entries(filter).forEach(([key, value]) => {
445
+ if (value !== "all") {
446
+ parsed.filter[key] = value;
447
+ }
448
+ });
449
+ }
450
+ Object.entries(otherParams).forEach(([key, value]) => {
451
+ if (typeof value === "string" && value !== "all" && !["page", "limit", "sort", "sortBy", "sortOrder", "search"].includes(key)) {
452
+ parsed.filter[key] = value;
453
+ }
454
+ });
455
+ req.parsedQuery = parsed;
456
+ next();
457
+ };
458
+
459
+ // src/server/middleware/utils/schemaMeta.util.ts
460
+ var getZodTypeName = (schema) => {
461
+ const typeName = schema._def?.typeName;
462
+ switch (typeName) {
463
+ case "ZodString":
464
+ return "string";
465
+ case "ZodNumber":
466
+ return "number";
467
+ case "ZodBoolean":
468
+ return "boolean";
469
+ case "ZodDate":
470
+ return "date";
471
+ case "ZodArray":
472
+ return "array";
473
+ case "ZodObject":
474
+ return "object";
475
+ case "ZodOptional":
476
+ case "ZodNullable":
477
+ return schema._def?.innerType ? getZodTypeName(schema._def.innerType) : "unknown";
478
+ case "ZodDefault":
479
+ return schema._def?.innerType ? getZodTypeName(schema._def.innerType) : "unknown";
480
+ case "ZodEnum":
481
+ return "enum";
482
+ case "ZodUnion":
483
+ return "union";
484
+ default:
485
+ return "unknown";
486
+ }
487
+ };
488
+ var isZodRequired = (schema) => {
489
+ const typeName = schema._def?.typeName;
490
+ return typeName !== "ZodOptional" && typeName !== "ZodNullable";
491
+ };
492
+ var extractSchemaMeta = (model, zodSchema) => {
493
+ const columns = [];
494
+ if (zodSchema && zodSchema.shape) {
495
+ const shape = zodSchema.shape;
496
+ for (const [key, value] of Object.entries(shape)) {
497
+ if (key.startsWith("_")) continue;
498
+ columns.push({
499
+ name: key,
500
+ datatype: getZodTypeName(value),
501
+ required: isZodRequired(value)
502
+ });
503
+ }
504
+ return columns;
505
+ }
506
+ try {
507
+ const schema = model.schema;
508
+ const paths = schema.paths;
509
+ for (const [key, pathInfo] of Object.entries(paths)) {
510
+ if (key.startsWith("_") || key === "__v") continue;
511
+ const schemaType = pathInfo;
512
+ columns.push({
513
+ name: key,
514
+ datatype: (schemaType.instance || "unknown").toLowerCase(),
515
+ required: schemaType.isRequired || false
516
+ });
517
+ }
518
+ } catch {
519
+ }
520
+ return columns;
521
+ };
522
+
523
+ // src/server/middleware/pagination.middleware.ts
524
+ var queryPagination = (model, options = {}, withOrgId = true) => {
525
+ return async (req, res, next) => {
526
+ try {
527
+ const { page, limit, sort, search, filter } = req.parsedQuery;
528
+ const query = {};
529
+ Object.entries(filter).forEach(([key, value]) => {
530
+ if (options.regexFilterFields?.includes(key)) {
531
+ query[key] = { $regex: value, $options: "i" };
532
+ } else {
533
+ query[key] = value;
534
+ }
535
+ });
536
+ const organizationId = req.headers["x-organization-id"];
537
+ if (organizationId && typeof organizationId === "string" && withOrgId) {
538
+ query.organizationId = organizationId;
539
+ }
540
+ if (search && options.searchFields?.length) {
541
+ query.$or = options.searchFields.map((field) => ({
542
+ [field]: { $regex: search, $options: "i" }
543
+ }));
544
+ }
545
+ const sortQuery = sort ? { [sort.field]: sort.order } : { createdAt: "desc" };
546
+ const skip = (page - 1) * limit;
547
+ const [data, total] = await Promise.all([
548
+ model.find(query).sort(sortQuery).skip(skip).limit(limit),
549
+ model.countDocuments(query)
550
+ ]);
551
+ res.paginatedResult = {
552
+ data,
553
+ meta: {
554
+ page,
555
+ limit,
556
+ total,
557
+ totalPages: Math.ceil(total / limit)
558
+ },
559
+ columns: extractSchemaMeta(model, options.validatorSchema)
560
+ };
561
+ next();
562
+ } catch (error) {
563
+ next(error);
564
+ }
565
+ };
566
+ };
567
+ var isZodError = (error) => {
568
+ return error !== null && typeof error === "object" && "errors" in error && Array.isArray(error.errors);
569
+ };
570
+ var getOrgId = (req, orgField = "organizationId") => {
571
+ const orgReq = req;
572
+ return orgReq.organizationId || req.headers["x-organization-id"] || req.query[orgField];
573
+ };
574
+ var buildOrgFilter = (req, config) => {
575
+ const filter = {};
576
+ if (config.withOrganization !== false) {
577
+ const orgId = getOrgId(req, config.orgField);
578
+ if (orgId) {
579
+ filter[config.orgField || "organizationId"] = orgId;
580
+ }
581
+ }
582
+ return filter;
583
+ };
584
+ var formatZodError = (error) => {
585
+ return error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
586
+ };
587
+ function createCrudControllers(config) {
588
+ const {
589
+ model,
590
+ resourceName,
591
+ createSchema,
592
+ updateSchema,
593
+ searchFields = [],
594
+ regexFilterFields = [],
595
+ withOrganization = true,
596
+ orgField = "organizationId",
597
+ transformCreate,
598
+ transformUpdate,
599
+ afterCreate,
600
+ afterUpdate,
601
+ afterDelete,
602
+ excludeFields = [],
603
+ populateFields = [],
604
+ buildQuery
605
+ } = config;
606
+ const getAll = async (req, res, _next) => {
607
+ try {
608
+ const paginatedRes = res;
609
+ if (paginatedRes.paginatedResult) {
610
+ successResponse(res, paginatedRes.paginatedResult, `${resourceName} list fetched successfully`);
611
+ return;
612
+ }
613
+ const page = parseInt(req.query.page) || 1;
614
+ const limit = parseInt(req.query.limit) || 10;
615
+ const sortField = req.query.sortBy || "createdAt";
616
+ const sortOrder = req.query.sortOrder || "desc";
617
+ const search = req.query.search;
618
+ let query = {};
619
+ if (withOrganization) {
620
+ const orgId = getOrgId(req, orgField);
621
+ if (orgId) {
622
+ query[orgField] = orgId;
623
+ }
624
+ }
625
+ if (search && searchFields.length > 0) {
626
+ query.$or = searchFields.map((field) => ({
627
+ [field]: { $regex: search, $options: "i" }
628
+ }));
629
+ }
630
+ const filterableParams = Object.keys(req.query).filter(
631
+ (key) => !["page", "limit", "sortBy", "sortOrder", "search"].includes(key)
632
+ );
633
+ filterableParams.forEach((key) => {
634
+ const value = req.query[key];
635
+ if (value !== void 0 && value !== "" && value !== "all") {
636
+ if (regexFilterFields.includes(key)) {
637
+ query[key] = { $regex: value, $options: "i" };
638
+ } else {
639
+ query[key] = value;
640
+ }
641
+ }
642
+ });
643
+ if (buildQuery) {
644
+ query = buildQuery(req, query);
645
+ }
646
+ const sortQuery = { [sortField]: sortOrder };
647
+ const skip = (page - 1) * limit;
648
+ let projection = {};
649
+ if (excludeFields.length > 0) {
650
+ projection = excludeFields.reduce(
651
+ (acc, field) => ({ ...acc, [field]: 0 }),
652
+ {}
653
+ );
654
+ }
655
+ let dbQuery = model.find(query, projection);
656
+ if (populateFields.length > 0) {
657
+ populateFields.forEach((field) => {
658
+ dbQuery = dbQuery.populate(field);
659
+ });
660
+ }
661
+ const [data, total] = await Promise.all([
662
+ dbQuery.sort(sortQuery).skip(skip).limit(limit),
663
+ model.countDocuments(query)
664
+ ]);
665
+ successResponse(
666
+ res,
667
+ {
668
+ data,
669
+ meta: {
670
+ page,
671
+ limit,
672
+ total,
673
+ totalPages: Math.ceil(total / limit)
674
+ },
675
+ columns: extractSchemaMeta(model, createSchema)
676
+ },
677
+ `${resourceName} list fetched successfully`
678
+ );
679
+ } catch (error) {
680
+ logger.error(`Error in getAll ${resourceName}`, {
681
+ error: error instanceof Error ? error.message : "Unknown error"
682
+ });
683
+ errorResponse(res, `Failed to fetch ${resourceName.toLowerCase()} list`);
684
+ }
685
+ };
686
+ const getById = async (req, res, _next) => {
687
+ try {
688
+ const { id } = req.params;
689
+ if (!id || !Types.ObjectId.isValid(id)) {
690
+ badRequestResponse(res, "Invalid ID format");
691
+ return;
692
+ }
693
+ const query = {
694
+ _id: new Types.ObjectId(id),
695
+ ...buildOrgFilter(req, { ...config, withOrganization, orgField })
696
+ };
697
+ let dbQuery = model.findOne(query);
698
+ if (populateFields.length > 0) {
699
+ populateFields.forEach((field) => {
700
+ dbQuery = dbQuery.populate(field);
701
+ });
702
+ }
703
+ const doc = await dbQuery;
704
+ if (!doc) {
705
+ notFoundResponse(res, `${resourceName} not found`);
706
+ return;
707
+ }
708
+ successResponse(res, doc, `${resourceName} fetched successfully`);
709
+ } catch (error) {
710
+ logger.error(`Error in getById ${resourceName}`, {
711
+ error: error instanceof Error ? error.message : "Unknown error",
712
+ id: req.params.id
713
+ });
714
+ errorResponse(res, `Failed to fetch ${resourceName.toLowerCase()}`);
715
+ }
716
+ };
717
+ const create = async (req, res, _next) => {
718
+ try {
719
+ let input = req.body;
720
+ if (createSchema) {
721
+ try {
722
+ input = createSchema.parse(input);
723
+ } catch (error) {
724
+ if (isZodError(error)) {
725
+ badRequestResponse(res, formatZodError(error));
726
+ return;
727
+ }
728
+ throw error;
729
+ }
730
+ }
731
+ if (transformCreate) {
732
+ input = transformCreate(input, req);
733
+ }
734
+ if (withOrganization) {
735
+ const orgId = getOrgId(req, orgField);
736
+ if (orgId) {
737
+ input[orgField] = orgId;
738
+ }
739
+ }
740
+ const doc = new model(input);
741
+ await doc.save();
742
+ if (afterCreate) {
743
+ await afterCreate(doc, req);
744
+ }
745
+ logger.info(`${resourceName} created successfully`, {
746
+ id: doc._id,
747
+ [orgField]: input[orgField]
748
+ });
749
+ createdResponse(res, doc, `${resourceName} created successfully`);
750
+ } catch (error) {
751
+ logger.error(`Error in create ${resourceName}`, {
752
+ error: error instanceof Error ? error.message : "Unknown error"
753
+ });
754
+ if (error.code === 11e3) {
755
+ badRequestResponse(res, `A ${resourceName.toLowerCase()} with this data already exists`);
756
+ return;
757
+ }
758
+ errorResponse(res, `Failed to create ${resourceName.toLowerCase()}`);
759
+ }
760
+ };
761
+ const update = async (req, res, _next) => {
762
+ try {
763
+ const { id } = req.params;
764
+ if (!id || !Types.ObjectId.isValid(id)) {
765
+ badRequestResponse(res, "Invalid ID format");
766
+ return;
767
+ }
768
+ let input = req.body;
769
+ if (updateSchema) {
770
+ try {
771
+ input = updateSchema.parse(input);
772
+ } catch (error) {
773
+ if (isZodError(error)) {
774
+ badRequestResponse(res, formatZodError(error));
775
+ return;
776
+ }
777
+ throw error;
778
+ }
779
+ }
780
+ if (transformUpdate) {
781
+ input = transformUpdate(input, req);
782
+ }
783
+ const query = {
784
+ _id: new Types.ObjectId(id),
785
+ ...buildOrgFilter(req, { ...config, withOrganization, orgField })
786
+ };
787
+ const doc = await model.findOneAndUpdate(query, { $set: input }, { new: true });
788
+ if (!doc) {
789
+ notFoundResponse(res, `${resourceName} not found`);
790
+ return;
791
+ }
792
+ if (afterUpdate) {
793
+ await afterUpdate(doc, req);
794
+ }
795
+ logger.info(`${resourceName} updated successfully`, { id });
796
+ successResponse(res, doc, `${resourceName} updated successfully`);
797
+ } catch (error) {
798
+ logger.error(`Error in update ${resourceName}`, {
799
+ error: error instanceof Error ? error.message : "Unknown error",
800
+ id: req.params.id
801
+ });
802
+ errorResponse(res, `Failed to update ${resourceName.toLowerCase()}`);
803
+ }
804
+ };
805
+ const deleteOne = async (req, res, _next) => {
806
+ try {
807
+ const { id } = req.params;
808
+ if (!id || !Types.ObjectId.isValid(id)) {
809
+ badRequestResponse(res, "Invalid ID format");
810
+ return;
811
+ }
812
+ const query = {
813
+ _id: new Types.ObjectId(id),
814
+ ...buildOrgFilter(req, { ...config, withOrganization, orgField })
815
+ };
816
+ const result = await model.deleteOne(query);
817
+ if (result.deletedCount === 0) {
818
+ notFoundResponse(res, `${resourceName} not found`);
819
+ return;
820
+ }
821
+ if (afterDelete) {
822
+ await afterDelete(id, req);
823
+ }
824
+ logger.info(`${resourceName} deleted successfully`, { id });
825
+ noContentResponse(res, null, `${resourceName} deleted successfully`);
826
+ } catch (error) {
827
+ logger.error(`Error in delete ${resourceName}`, {
828
+ error: error instanceof Error ? error.message : "Unknown error",
829
+ id: req.params.id
830
+ });
831
+ errorResponse(res, `Failed to delete ${resourceName.toLowerCase()}`);
832
+ }
833
+ };
834
+ const bulkDelete = async (req, res, _next) => {
835
+ try {
836
+ const bulkReq = req;
837
+ const { deleteIds = [], deleteAll = false } = bulkReq;
838
+ const baseFilter = buildOrgFilter(req, { ...config, withOrganization, orgField });
839
+ let filter;
840
+ if (deleteAll) {
841
+ filter = baseFilter;
842
+ } else if (deleteIds.length > 0) {
843
+ filter = {
844
+ ...baseFilter,
845
+ _id: { $in: deleteIds.map((id) => new Types.ObjectId(id)) }
846
+ };
847
+ } else {
848
+ badRequestResponse(res, "No IDs provided for deletion");
849
+ return;
850
+ }
851
+ const result = await model.deleteMany(filter);
852
+ if (afterDelete && deleteIds.length > 0) {
853
+ await Promise.all(deleteIds.map((id) => afterDelete(id, req)));
854
+ }
855
+ logger.info(`${resourceName}(s) bulk deleted successfully`, {
856
+ deletedCount: result.deletedCount,
857
+ deleteAll
858
+ });
859
+ successResponse(
860
+ res,
861
+ { deletedCount: result.deletedCount },
862
+ `${result.deletedCount} ${resourceName.toLowerCase()}(s) deleted successfully`
863
+ );
864
+ } catch (error) {
865
+ logger.error(`Error in bulkDelete ${resourceName}`, {
866
+ error: error instanceof Error ? error.message : "Unknown error"
867
+ });
868
+ errorResponse(res, `Failed to delete ${resourceName.toLowerCase()}(s)`);
869
+ }
870
+ };
871
+ return {
872
+ getAll,
873
+ getById,
874
+ create,
875
+ update,
876
+ deleteOne,
877
+ bulkDelete
878
+ };
879
+ }
880
+ function createPaginationMiddleware(model, config = {}) {
881
+ const {
882
+ searchFields = [],
883
+ regexFilterFields = [],
884
+ withOrganization = true,
885
+ orgField = "organizationId"
886
+ } = config;
887
+ return async (req, res, next) => {
888
+ try {
889
+ const page = parseInt(req.query.page) || 1;
890
+ const limit = parseInt(req.query.limit) || 10;
891
+ const sortField = req.query.sortBy || "createdAt";
892
+ const sortOrder = req.query.sortOrder || "desc";
893
+ const search = req.query.search;
894
+ const query = {};
895
+ if (withOrganization) {
896
+ const orgId = getOrgId(req, orgField);
897
+ if (orgId) {
898
+ query[orgField] = orgId;
899
+ }
900
+ }
901
+ if (search && searchFields.length > 0) {
902
+ query.$or = searchFields.map((field) => ({
903
+ [field]: { $regex: search, $options: "i" }
904
+ }));
905
+ }
906
+ const filterableParams = Object.keys(req.query).filter(
907
+ (key) => !["page", "limit", "sortBy", "sortOrder", "search"].includes(key)
908
+ );
909
+ filterableParams.forEach((key) => {
910
+ const value = req.query[key];
911
+ if (value !== void 0 && value !== "" && value !== "all") {
912
+ if (regexFilterFields.includes(key)) {
913
+ query[key] = { $regex: value, $options: "i" };
914
+ } else {
915
+ query[key] = value;
916
+ }
917
+ }
918
+ });
919
+ const sortQuery = { [sortField]: sortOrder };
920
+ const skip = (page - 1) * limit;
921
+ const [data, total] = await Promise.all([
922
+ model.find(query).sort(sortQuery).skip(skip).limit(limit),
923
+ model.countDocuments(query)
924
+ ]);
925
+ const paginatedRes = res;
926
+ paginatedRes.paginatedResult = {
927
+ data,
928
+ meta: {
929
+ page,
930
+ limit,
931
+ total,
932
+ totalPages: Math.ceil(total / limit)
933
+ },
934
+ columns: extractSchemaMeta(model, config.createSchema)
935
+ };
936
+ next();
937
+ } catch (error) {
938
+ next(error);
939
+ }
940
+ };
941
+ }
942
+ var parseBulkDelete = (req, res, next) => {
943
+ try {
944
+ const bulkReq = req;
945
+ let ids = [];
946
+ if (Array.isArray(req.body)) {
947
+ ids = req.body;
948
+ } else if (req.body && Array.isArray(req.body.ids)) {
949
+ ids = req.body.ids;
950
+ } else if (req.body && typeof req.body === "object") {
951
+ if (Array.isArray(req.body.data)) {
952
+ ids = req.body.data;
953
+ }
954
+ }
955
+ if (ids.length === 0) {
956
+ return badRequestResponse(
957
+ res,
958
+ 'Request body must contain an array of IDs. Use ["*"] to delete all records or ["id1", "id2"] to delete specific records.'
959
+ );
960
+ }
961
+ if (ids.length === 1 && ids[0] === "*") {
962
+ bulkReq.deleteAll = true;
963
+ bulkReq.deleteIds = [];
964
+ logger.info("Bulk delete: Deleting all records");
965
+ return next();
966
+ }
967
+ const validIds = [];
968
+ const invalidIds = [];
969
+ for (const id of ids) {
970
+ if (typeof id === "string" && Types.ObjectId.isValid(id)) {
971
+ validIds.push(id);
972
+ } else {
973
+ invalidIds.push(id);
974
+ }
975
+ }
976
+ if (invalidIds.length > 0) {
977
+ return badRequestResponse(
978
+ res,
979
+ `Invalid ID format(s): ${invalidIds.slice(0, 5).join(", ")}${invalidIds.length > 5 ? "..." : ""}. All IDs must be valid MongoDB ObjectIds.`
980
+ );
981
+ }
982
+ if (validIds.length === 0) {
983
+ return badRequestResponse(res, "No valid IDs provided for deletion.");
984
+ }
985
+ bulkReq.deleteAll = false;
986
+ bulkReq.deleteIds = validIds;
987
+ logger.info(`Bulk delete: Deleting ${validIds.length} record(s)`);
988
+ next();
989
+ } catch (error) {
990
+ logger.error("Error in parseBulkDelete middleware", error);
991
+ return badRequestResponse(res, "Failed to parse delete request");
992
+ }
993
+ };
994
+ var buildDeleteFilter = (req, organizationId) => {
995
+ const filter = {
996
+ organizationId: new Types.ObjectId(organizationId)
997
+ };
998
+ if (!req.deleteAll && req.deleteIds && req.deleteIds.length > 0) {
999
+ filter._id = {
1000
+ $in: req.deleteIds.map((id) => new Types.ObjectId(id))
1001
+ };
1002
+ }
1003
+ return filter;
1004
+ };
1005
+ var createBulkDeleteHandler = (Model2, modelName) => {
1006
+ return async (req, res) => {
1007
+ const bulkReq = req;
1008
+ const organizationId = req.headers["x-organization-id"];
1009
+ if (!organizationId) {
1010
+ return badRequestResponse(res, "Organization ID is required");
1011
+ }
1012
+ try {
1013
+ const filter = buildDeleteFilter(bulkReq, organizationId);
1014
+ const result = await Model2.deleteMany(filter);
1015
+ const deletedCount = result.deletedCount || 0;
1016
+ logger.info(`Bulk delete completed: ${deletedCount} ${modelName}(s) deleted`, {
1017
+ organizationId,
1018
+ deleteAll: bulkReq.deleteAll,
1019
+ requestedIds: bulkReq.deleteIds?.length || "all",
1020
+ deletedCount
1021
+ });
1022
+ return res.status(200).json({
1023
+ message: `Successfully deleted ${deletedCount} ${modelName}(s)`,
1024
+ data: {
1025
+ deletedCount,
1026
+ deleteAll: bulkReq.deleteAll
1027
+ },
1028
+ status: "success",
1029
+ statusCode: 200
1030
+ });
1031
+ } catch (error) {
1032
+ logger.error(`Error in bulk delete ${modelName}`, error);
1033
+ return res.status(500).json({
1034
+ message: `Failed to delete ${modelName}(s)`,
1035
+ data: null,
1036
+ status: "error",
1037
+ statusCode: 500
1038
+ });
1039
+ }
1040
+ };
1041
+ };
1042
+
419
1043
  // src/server/utils/filter-builder.ts
420
1044
  var buildFilter = (options) => {
421
1045
  const {
@@ -710,6 +1334,666 @@ var packageCheckServer = {
710
1334
  print: printPackageCheckSummary
711
1335
  };
712
1336
 
713
- export { StatusCode, StatusMessage, authenticateApiKey, authenticateJWT, badRequestResponse, buildFilter, buildPagination, buildPaginationMeta, checkPackageServer, conflictResponse, connectDB, createLogger, createMorganStream, createdResponse, disconnectDB, errorResponse, extractColumns, extractOrganization, forbiddenResponse, formatPackageCheckResult, generateNcuCommand, getConnectionStatus, logger, noContentResponse, notFoundResponse, omitFields, optionalAuthenticateJWT, packageCheckServer, pickFields, printPackageCheckSummary, rateLimitResponse, requireOrganization, sanitizeDocument, sanitizeUser, simpleLogger, statusCode, statusMessage, stream, successResponse, successResponseArr, unauthorizedResponse, validationErrorResponse };
1337
+ // src/server/configs/cors.config.ts
1338
+ var DEFAULT_CORS_CONFIG = {
1339
+ productionOrigins: [],
1340
+ developmentOrigins: [
1341
+ "http://localhost:3000",
1342
+ "http://localhost:4000",
1343
+ "http://localhost:5000",
1344
+ "http://localhost:5173",
1345
+ "http://localhost:8080",
1346
+ "http://127.0.0.1:3000",
1347
+ "http://127.0.0.1:4000",
1348
+ "http://127.0.0.1:5000",
1349
+ "http://127.0.0.1:5173",
1350
+ "http://127.0.0.1:8080"
1351
+ ],
1352
+ allowedSubdomains: [],
1353
+ originPatterns: [],
1354
+ allowNoOrigin: true,
1355
+ allowAllInDev: true,
1356
+ credentials: true,
1357
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"],
1358
+ allowedHeaders: [
1359
+ "Content-Type",
1360
+ "Authorization",
1361
+ "X-Requested-With",
1362
+ "Accept",
1363
+ "Origin",
1364
+ "X-API-Key",
1365
+ "X-Organization-Id",
1366
+ "X-Request-Id"
1367
+ ],
1368
+ exposedHeaders: [
1369
+ "Content-Range",
1370
+ "X-Content-Range",
1371
+ "X-Total-Count",
1372
+ "X-Request-Id"
1373
+ ],
1374
+ maxAge: 86400
1375
+ // 24 hours
1376
+ };
1377
+ var createCorsOptions = (config = {}) => {
1378
+ const finalConfig = { ...DEFAULT_CORS_CONFIG, ...config };
1379
+ const {
1380
+ productionOrigins,
1381
+ developmentOrigins,
1382
+ allowedSubdomains,
1383
+ originPatterns,
1384
+ allowNoOrigin,
1385
+ allowAllInDev,
1386
+ customValidator,
1387
+ credentials,
1388
+ methods,
1389
+ allowedHeaders,
1390
+ exposedHeaders,
1391
+ maxAge
1392
+ } = finalConfig;
1393
+ const allOrigins = /* @__PURE__ */ new Set([...productionOrigins, ...developmentOrigins]);
1394
+ const originHandler = (origin, callback) => {
1395
+ if (!origin) {
1396
+ callback(null, allowNoOrigin);
1397
+ return;
1398
+ }
1399
+ if (allOrigins.has(origin)) {
1400
+ callback(null, true);
1401
+ return;
1402
+ }
1403
+ if (allowedSubdomains.some((subdomain) => origin.endsWith(subdomain))) {
1404
+ callback(null, true);
1405
+ return;
1406
+ }
1407
+ if (originPatterns.some((pattern) => pattern.test(origin))) {
1408
+ callback(null, true);
1409
+ return;
1410
+ }
1411
+ if (customValidator && customValidator(origin)) {
1412
+ callback(null, true);
1413
+ return;
1414
+ }
1415
+ if (process.env.NODE_ENV !== "production" && allowAllInDev) {
1416
+ callback(null, true);
1417
+ return;
1418
+ }
1419
+ if (process.env.NODE_ENV === "production") {
1420
+ callback(new Error(`Origin ${origin} not allowed by CORS`));
1421
+ return;
1422
+ }
1423
+ callback(null, true);
1424
+ };
1425
+ return {
1426
+ origin: originHandler,
1427
+ credentials,
1428
+ methods,
1429
+ allowedHeaders,
1430
+ exposedHeaders,
1431
+ maxAge
1432
+ };
1433
+ };
1434
+ var createBrandCorsOptions = (brandDomain, additionalConfig = {}) => {
1435
+ const productionOrigins = [
1436
+ `https://${brandDomain}`,
1437
+ `https://www.${brandDomain}`
1438
+ ];
1439
+ const allowedSubdomains = [`.${brandDomain}`];
1440
+ return createCorsOptions({
1441
+ productionOrigins,
1442
+ allowedSubdomains,
1443
+ ...additionalConfig
1444
+ });
1445
+ };
1446
+ var createMultiBrandCorsOptions = (domains, additionalConfig = {}) => {
1447
+ const productionOrigins = domains.flatMap((domain) => [
1448
+ `https://${domain}`,
1449
+ `https://www.${domain}`
1450
+ ]);
1451
+ const allowedSubdomains = domains.map((domain) => `.${domain}`);
1452
+ return createCorsOptions({
1453
+ productionOrigins,
1454
+ allowedSubdomains,
1455
+ ...additionalConfig
1456
+ });
1457
+ };
1458
+ var EXYCONN_CORS_CONFIG = {
1459
+ productionOrigins: [
1460
+ "https://exyconn.com",
1461
+ "https://www.exyconn.com",
1462
+ "https://botify.life",
1463
+ "https://www.botify.life",
1464
+ "https://partywings.fun",
1465
+ "https://www.partywings.fun",
1466
+ "https://sibera.work",
1467
+ "https://www.sibera.work",
1468
+ "https://spentiva.com",
1469
+ "https://www.spentiva.com"
1470
+ ],
1471
+ allowedSubdomains: [
1472
+ ".exyconn.com",
1473
+ ".botify.life",
1474
+ ".partywings.fun",
1475
+ ".sibera.work",
1476
+ ".spentiva.com"
1477
+ ],
1478
+ developmentOrigins: [
1479
+ "http://localhost:3000",
1480
+ "http://localhost:4000",
1481
+ "http://localhost:4001",
1482
+ "http://localhost:4002",
1483
+ "http://localhost:4003",
1484
+ "http://localhost:4004",
1485
+ "http://localhost:4005",
1486
+ "http://localhost:5173",
1487
+ "http://127.0.0.1:3000",
1488
+ "http://127.0.0.1:4000",
1489
+ "http://127.0.0.1:5173"
1490
+ ]
1491
+ };
1492
+ var STRICT_CORS_CONFIG = {
1493
+ allowNoOrigin: false,
1494
+ allowAllInDev: false,
1495
+ methods: ["GET", "POST", "PUT", "DELETE"]
1496
+ };
1497
+ var PERMISSIVE_CORS_CONFIG = {
1498
+ allowNoOrigin: true,
1499
+ allowAllInDev: true,
1500
+ originPatterns: [/localhost/, /127\.0\.0\.1/]
1501
+ };
1502
+ var corsOptions = createCorsOptions(EXYCONN_CORS_CONFIG);
1503
+ var DEFAULT_RATE_LIMIT_TIERS = {
1504
+ STANDARD: {
1505
+ windowMs: 15 * 60 * 1e3,
1506
+ // 15 minutes
1507
+ maxRequests: 100,
1508
+ message: "Too many requests, please try again later.",
1509
+ skipSuccessfulRequests: false,
1510
+ skipFailedRequests: false
1511
+ },
1512
+ STRICT: {
1513
+ windowMs: 15 * 60 * 1e3,
1514
+ // 15 minutes
1515
+ maxRequests: 20,
1516
+ message: "Too many requests, please try again later.",
1517
+ skipSuccessfulRequests: false,
1518
+ skipFailedRequests: false
1519
+ },
1520
+ DDOS: {
1521
+ windowMs: 60 * 1e3,
1522
+ // 1 minute
1523
+ maxRequests: 60,
1524
+ message: "Rate limit exceeded. Please slow down.",
1525
+ skipSuccessfulRequests: false,
1526
+ skipFailedRequests: false
1527
+ },
1528
+ // Additional presets
1529
+ VERY_STRICT: {
1530
+ windowMs: 60 * 60 * 1e3,
1531
+ // 1 hour
1532
+ maxRequests: 5,
1533
+ message: "Too many attempts. Please try again in an hour.",
1534
+ skipSuccessfulRequests: false,
1535
+ skipFailedRequests: false
1536
+ },
1537
+ RELAXED: {
1538
+ windowMs: 15 * 60 * 1e3,
1539
+ // 15 minutes
1540
+ maxRequests: 500,
1541
+ message: "Rate limit exceeded.",
1542
+ skipSuccessfulRequests: false,
1543
+ skipFailedRequests: false
1544
+ },
1545
+ API: {
1546
+ windowMs: 60 * 1e3,
1547
+ // 1 minute
1548
+ maxRequests: 30,
1549
+ message: "API rate limit exceeded.",
1550
+ skipSuccessfulRequests: false,
1551
+ skipFailedRequests: false
1552
+ }
1553
+ };
1554
+ var defaultKeyGenerator = (req) => {
1555
+ const forwarded = req.headers["x-forwarded-for"];
1556
+ const ip = forwarded ? Array.isArray(forwarded) ? forwarded[0] : forwarded.split(",")[0].trim() : req.ip || req.socket.remoteAddress || "unknown";
1557
+ return ip;
1558
+ };
1559
+ var createPrefixedKeyGenerator = (prefix) => (req) => {
1560
+ return `${prefix}:${defaultKeyGenerator(req)}`;
1561
+ };
1562
+ var createUserKeyGenerator = (getUserId) => (req) => {
1563
+ const userId = getUserId(req);
1564
+ return userId || defaultKeyGenerator(req);
1565
+ };
1566
+ var createApiKeyGenerator = (headerName = "x-api-key") => (req) => {
1567
+ const apiKey = req.headers[headerName.toLowerCase()];
1568
+ return apiKey || defaultKeyGenerator(req);
1569
+ };
1570
+ var createRateLimitResponse = (message, retryAfter) => ({
1571
+ status: "error",
1572
+ statusCode: 429,
1573
+ message,
1574
+ ...retryAfter
1575
+ });
1576
+ var createRateLimiter = (tierConfig, options = {}) => {
1577
+ const {
1578
+ standardHeaders = true,
1579
+ legacyHeaders = false,
1580
+ keyGenerator = defaultKeyGenerator,
1581
+ skip,
1582
+ handler
1583
+ } = options;
1584
+ return rateLimit({
1585
+ windowMs: tierConfig.windowMs,
1586
+ max: tierConfig.maxRequests,
1587
+ message: createRateLimitResponse(tierConfig.message),
1588
+ standardHeaders,
1589
+ legacyHeaders,
1590
+ keyGenerator,
1591
+ skip,
1592
+ handler,
1593
+ skipSuccessfulRequests: tierConfig.skipSuccessfulRequests,
1594
+ skipFailedRequests: tierConfig.skipFailedRequests
1595
+ });
1596
+ };
1597
+ var createStandardRateLimiter = (config = {}, options = {}) => {
1598
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.STANDARD, ...config };
1599
+ return createRateLimiter(tierConfig, options);
1600
+ };
1601
+ var createStrictRateLimiter = (config = {}, options = {}) => {
1602
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.STRICT, ...config };
1603
+ return createRateLimiter(tierConfig, options);
1604
+ };
1605
+ var createDdosRateLimiter = (config = {}, options = {}) => {
1606
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.DDOS, ...config };
1607
+ return createRateLimiter(tierConfig, options);
1608
+ };
1609
+ var createApiRateLimiter = (config = {}, options = {}) => {
1610
+ const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.API, ...config };
1611
+ return createRateLimiter(tierConfig, {
1612
+ keyGenerator: createApiKeyGenerator(),
1613
+ ...options
1614
+ });
1615
+ };
1616
+ var RateLimiterBuilder = class {
1617
+ constructor(preset = "STANDARD") {
1618
+ const presetConfig = DEFAULT_RATE_LIMIT_TIERS[preset];
1619
+ this.config = {
1620
+ windowMs: presetConfig.windowMs,
1621
+ maxRequests: presetConfig.maxRequests,
1622
+ message: presetConfig.message,
1623
+ skipSuccessfulRequests: presetConfig.skipSuccessfulRequests ?? false,
1624
+ skipFailedRequests: presetConfig.skipFailedRequests ?? false
1625
+ };
1626
+ this.options = {};
1627
+ }
1628
+ /**
1629
+ * Set window duration
1630
+ */
1631
+ windowMs(ms) {
1632
+ this.config.windowMs = ms;
1633
+ return this;
1634
+ }
1635
+ /**
1636
+ * Set window duration in minutes
1637
+ */
1638
+ windowMinutes(minutes) {
1639
+ this.config.windowMs = minutes * 60 * 1e3;
1640
+ return this;
1641
+ }
1642
+ /**
1643
+ * Set window duration in hours
1644
+ */
1645
+ windowHours(hours) {
1646
+ this.config.windowMs = hours * 60 * 60 * 1e3;
1647
+ return this;
1648
+ }
1649
+ /**
1650
+ * Set maximum requests
1651
+ */
1652
+ max(requests) {
1653
+ this.config.maxRequests = requests;
1654
+ return this;
1655
+ }
1656
+ /**
1657
+ * Set error message
1658
+ */
1659
+ message(msg) {
1660
+ this.config.message = msg;
1661
+ return this;
1662
+ }
1663
+ /**
1664
+ * Skip successful requests
1665
+ */
1666
+ skipSuccessful(skip = true) {
1667
+ this.config.skipSuccessfulRequests = skip;
1668
+ return this;
1669
+ }
1670
+ /**
1671
+ * Skip failed requests
1672
+ */
1673
+ skipFailed(skip = true) {
1674
+ this.config.skipFailedRequests = skip;
1675
+ return this;
1676
+ }
1677
+ /**
1678
+ * Set key generator
1679
+ */
1680
+ keyBy(generator) {
1681
+ this.options.keyGenerator = generator;
1682
+ return this;
1683
+ }
1684
+ /**
1685
+ * Key by IP (default)
1686
+ */
1687
+ keyByIp() {
1688
+ this.options.keyGenerator = defaultKeyGenerator;
1689
+ return this;
1690
+ }
1691
+ /**
1692
+ * Key by API key
1693
+ */
1694
+ keyByApiKey(headerName) {
1695
+ this.options.keyGenerator = createApiKeyGenerator(headerName);
1696
+ return this;
1697
+ }
1698
+ /**
1699
+ * Skip certain requests
1700
+ */
1701
+ skipWhen(predicate) {
1702
+ this.options.skip = predicate;
1703
+ return this;
1704
+ }
1705
+ /**
1706
+ * Build the rate limiter
1707
+ */
1708
+ build() {
1709
+ return createRateLimiter(this.config, this.options);
1710
+ }
1711
+ };
1712
+ var rateLimiter = (preset) => {
1713
+ return new RateLimiterBuilder(preset);
1714
+ };
1715
+ var RATE_LIMIT_CONFIG = {
1716
+ STANDARD: DEFAULT_RATE_LIMIT_TIERS.STANDARD,
1717
+ STRICT: DEFAULT_RATE_LIMIT_TIERS.STRICT,
1718
+ DDOS: DEFAULT_RATE_LIMIT_TIERS.DDOS
1719
+ };
1720
+ var standardRateLimiter = createStandardRateLimiter();
1721
+ var strictRateLimiter = createStrictRateLimiter();
1722
+ var ddosProtectionLimiter = createDdosRateLimiter();
1723
+
1724
+ // src/server/configs/server.config.ts
1725
+ var DEFAULT_SERVER_CONFIG = {
1726
+ name: "app-server",
1727
+ version: "1.0.0",
1728
+ environment: process.env.NODE_ENV || "development",
1729
+ port: parseInt(process.env.PORT || "3000", 10),
1730
+ host: process.env.HOST || "0.0.0.0",
1731
+ basePath: "/api",
1732
+ debug: process.env.DEBUG === "true",
1733
+ trustProxy: true
1734
+ };
1735
+ var DEFAULT_DATABASE_CONFIG = {
1736
+ uri: process.env.DATABASE_URL || process.env.MONGODB_URI || "",
1737
+ name: process.env.DATABASE_NAME || "app_db",
1738
+ maxPoolSize: process.env.NODE_ENV === "production" ? 50 : 10,
1739
+ minPoolSize: process.env.NODE_ENV === "production" ? 10 : 5,
1740
+ socketTimeoutMS: 45e3,
1741
+ serverSelectionTimeoutMS: 1e4,
1742
+ maxIdleTimeMS: 1e4,
1743
+ retryWrites: true,
1744
+ retryReads: true,
1745
+ writeConcern: "majority"
1746
+ };
1747
+ var DEFAULT_AUTH_CONFIG = {
1748
+ jwtSecret: process.env.JWT_SECRET || "",
1749
+ jwtExpiresIn: process.env.JWT_EXPIRES_IN || "7d",
1750
+ refreshTokenExpiresIn: process.env.REFRESH_TOKEN_EXPIRES_IN || "30d",
1751
+ enableRefreshTokens: true,
1752
+ apiKeyHeader: "x-api-key",
1753
+ orgHeader: "x-organization-id"
1754
+ };
1755
+ var DEFAULT_LOGGING_CONFIG = {
1756
+ level: process.env.LOG_LEVEL || "info",
1757
+ logsDir: process.env.LOGS_DIR || "logs",
1758
+ maxSize: "20m",
1759
+ maxFiles: "14d",
1760
+ errorMaxFiles: "30d",
1761
+ console: true,
1762
+ file: process.env.NODE_ENV === "production",
1763
+ json: process.env.NODE_ENV === "production"
1764
+ };
1765
+ var DEFAULT_CORS_ORIGINS = {
1766
+ production: [],
1767
+ development: [
1768
+ "http://localhost:3000",
1769
+ "http://localhost:4000",
1770
+ "http://localhost:5173",
1771
+ "http://127.0.0.1:3000",
1772
+ "http://127.0.0.1:4000",
1773
+ "http://127.0.0.1:5173"
1774
+ ],
1775
+ patterns: []
1776
+ };
1777
+ var DEFAULT_RATE_LIMIT_CONFIG = {
1778
+ enabled: true,
1779
+ standard: {
1780
+ windowMs: 15 * 60 * 1e3,
1781
+ // 15 minutes
1782
+ maxRequests: 100,
1783
+ message: "Too many requests, please try again later."
1784
+ },
1785
+ strict: {
1786
+ windowMs: 15 * 60 * 1e3,
1787
+ // 15 minutes
1788
+ maxRequests: 20,
1789
+ message: "Too many requests, please try again later."
1790
+ },
1791
+ ddos: {
1792
+ windowMs: 60 * 1e3,
1793
+ // 1 minute
1794
+ maxRequests: 60,
1795
+ message: "Rate limit exceeded. Please slow down.",
1796
+ skipSuccessfulRequests: false
1797
+ }
1798
+ };
1799
+ function deepMerge(target, source) {
1800
+ const result = { ...target };
1801
+ for (const key in source) {
1802
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1803
+ const sourceValue = source[key];
1804
+ const targetValue = target[key];
1805
+ if (sourceValue !== void 0 && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
1806
+ result[key] = deepMerge(
1807
+ targetValue,
1808
+ sourceValue
1809
+ );
1810
+ } else if (sourceValue !== void 0) {
1811
+ result[key] = sourceValue;
1812
+ }
1813
+ }
1814
+ }
1815
+ return result;
1816
+ }
1817
+ var ConfigBuilder = class {
1818
+ constructor() {
1819
+ this.config = {
1820
+ server: { ...DEFAULT_SERVER_CONFIG },
1821
+ database: { ...DEFAULT_DATABASE_CONFIG },
1822
+ auth: { ...DEFAULT_AUTH_CONFIG },
1823
+ logging: { ...DEFAULT_LOGGING_CONFIG },
1824
+ cors: { ...DEFAULT_CORS_ORIGINS },
1825
+ rateLimit: { ...DEFAULT_RATE_LIMIT_CONFIG }
1826
+ };
1827
+ }
1828
+ /**
1829
+ * Set server configuration
1830
+ */
1831
+ setServer(config) {
1832
+ this.config.server = deepMerge(this.config.server, config);
1833
+ return this;
1834
+ }
1835
+ /**
1836
+ * Set database configuration
1837
+ */
1838
+ setDatabase(config) {
1839
+ this.config.database = deepMerge(this.config.database, config);
1840
+ return this;
1841
+ }
1842
+ /**
1843
+ * Set auth configuration
1844
+ */
1845
+ setAuth(config) {
1846
+ this.config.auth = deepMerge(this.config.auth, config);
1847
+ return this;
1848
+ }
1849
+ /**
1850
+ * Set logging configuration
1851
+ */
1852
+ setLogging(config) {
1853
+ this.config.logging = deepMerge(this.config.logging, config);
1854
+ return this;
1855
+ }
1856
+ /**
1857
+ * Set CORS origins
1858
+ */
1859
+ setCorsOrigins(config) {
1860
+ this.config.cors = deepMerge(this.config.cors, config);
1861
+ return this;
1862
+ }
1863
+ /**
1864
+ * Add CORS production origin
1865
+ */
1866
+ addProductionOrigin(origin) {
1867
+ if (!this.config.cors.production.includes(origin)) {
1868
+ this.config.cors.production.push(origin);
1869
+ }
1870
+ return this;
1871
+ }
1872
+ /**
1873
+ * Add CORS development origin
1874
+ */
1875
+ addDevelopmentOrigin(origin) {
1876
+ if (!this.config.cors.development.includes(origin)) {
1877
+ this.config.cors.development.push(origin);
1878
+ }
1879
+ return this;
1880
+ }
1881
+ /**
1882
+ * Add CORS pattern
1883
+ */
1884
+ addCorsPattern(pattern) {
1885
+ if (!this.config.cors.patterns.includes(pattern)) {
1886
+ this.config.cors.patterns.push(pattern);
1887
+ }
1888
+ return this;
1889
+ }
1890
+ /**
1891
+ * Set rate limit configuration
1892
+ */
1893
+ setRateLimit(config) {
1894
+ this.config.rateLimit = deepMerge(this.config.rateLimit, config);
1895
+ return this;
1896
+ }
1897
+ /**
1898
+ * Add custom rate limit tier
1899
+ */
1900
+ addRateLimitTier(name, tier) {
1901
+ if (!this.config.rateLimit.custom) {
1902
+ this.config.rateLimit.custom = {};
1903
+ }
1904
+ this.config.rateLimit.custom[name] = tier;
1905
+ return this;
1906
+ }
1907
+ /**
1908
+ * Set custom configuration
1909
+ */
1910
+ setCustom(key, value) {
1911
+ if (!this.config.custom) {
1912
+ this.config.custom = {};
1913
+ }
1914
+ this.config.custom[key] = value;
1915
+ return this;
1916
+ }
1917
+ /**
1918
+ * Load configuration from environment variables
1919
+ */
1920
+ loadFromEnv() {
1921
+ if (process.env.SERVER_NAME) this.config.server.name = process.env.SERVER_NAME;
1922
+ if (process.env.SERVER_VERSION) this.config.server.version = process.env.SERVER_VERSION;
1923
+ if (process.env.PORT) this.config.server.port = parseInt(process.env.PORT, 10);
1924
+ if (process.env.HOST) this.config.server.host = process.env.HOST;
1925
+ if (process.env.BASE_PATH) this.config.server.basePath = process.env.BASE_PATH;
1926
+ if (process.env.DATABASE_URL) this.config.database.uri = process.env.DATABASE_URL;
1927
+ if (process.env.MONGODB_URI) this.config.database.uri = process.env.MONGODB_URI;
1928
+ if (process.env.DATABASE_NAME) this.config.database.name = process.env.DATABASE_NAME;
1929
+ if (process.env.JWT_SECRET) this.config.auth.jwtSecret = process.env.JWT_SECRET;
1930
+ if (process.env.JWT_EXPIRES_IN) this.config.auth.jwtExpiresIn = process.env.JWT_EXPIRES_IN;
1931
+ if (process.env.LOG_LEVEL) this.config.logging.level = process.env.LOG_LEVEL;
1932
+ if (process.env.LOGS_DIR) this.config.logging.logsDir = process.env.LOGS_DIR;
1933
+ if (process.env.CORS_ORIGINS) {
1934
+ const origins = process.env.CORS_ORIGINS.split(",").map((o) => o.trim());
1935
+ this.config.cors.production.push(...origins);
1936
+ }
1937
+ return this;
1938
+ }
1939
+ /**
1940
+ * Validate configuration
1941
+ */
1942
+ validate() {
1943
+ const errors = [];
1944
+ if (!this.config.server.name) errors.push("Server name is required");
1945
+ if (this.config.server.port < 1 || this.config.server.port > 65535) {
1946
+ errors.push("Server port must be between 1 and 65535");
1947
+ }
1948
+ if (this.config.server.environment === "production") {
1949
+ if (!this.config.auth.jwtSecret || this.config.auth.jwtSecret.length < 32) {
1950
+ errors.push("JWT secret must be at least 32 characters in production");
1951
+ }
1952
+ }
1953
+ return { valid: errors.length === 0, errors };
1954
+ }
1955
+ /**
1956
+ * Build the final configuration
1957
+ */
1958
+ build() {
1959
+ return { ...this.config };
1960
+ }
1961
+ };
1962
+ var createConfig = () => {
1963
+ return new ConfigBuilder();
1964
+ };
1965
+ var buildConfig = (partial = {}) => {
1966
+ const builder = createConfig().loadFromEnv();
1967
+ if (partial.server) builder.setServer(partial.server);
1968
+ if (partial.database) builder.setDatabase(partial.database);
1969
+ if (partial.auth) builder.setAuth(partial.auth);
1970
+ if (partial.logging) builder.setLogging(partial.logging);
1971
+ if (partial.cors) builder.setCorsOrigins(partial.cors);
1972
+ if (partial.rateLimit) builder.setRateLimit(partial.rateLimit);
1973
+ return builder.build();
1974
+ };
1975
+ var isProduction = (config) => {
1976
+ return (config?.environment || process.env.NODE_ENV) === "production";
1977
+ };
1978
+ var isDevelopment = (config) => {
1979
+ return (config?.environment || process.env.NODE_ENV) === "development";
1980
+ };
1981
+ var isTest = (config) => {
1982
+ return (config?.environment || process.env.NODE_ENV) === "test";
1983
+ };
1984
+ var getDatabaseOptions = (config) => {
1985
+ return {
1986
+ maxPoolSize: config.maxPoolSize,
1987
+ minPoolSize: config.minPoolSize,
1988
+ socketTimeoutMS: config.socketTimeoutMS,
1989
+ serverSelectionTimeoutMS: config.serverSelectionTimeoutMS,
1990
+ maxIdleTimeMS: config.maxIdleTimeMS,
1991
+ retryWrites: config.retryWrites,
1992
+ retryReads: config.retryReads,
1993
+ w: config.writeConcern
1994
+ };
1995
+ };
1996
+
1997
+ export { ConfigBuilder, DEFAULT_AUTH_CONFIG, DEFAULT_CORS_CONFIG, DEFAULT_CORS_ORIGINS, DEFAULT_DATABASE_CONFIG, DEFAULT_LOGGING_CONFIG, DEFAULT_RATE_LIMIT_CONFIG, DEFAULT_RATE_LIMIT_TIERS, DEFAULT_SERVER_CONFIG, EXYCONN_CORS_CONFIG, PERMISSIVE_CORS_CONFIG, RATE_LIMIT_CONFIG, RateLimiterBuilder, STRICT_CORS_CONFIG, StatusCode, StatusMessage, authenticateApiKey, authenticateJWT, badRequestResponse, buildConfig, buildDeleteFilter, buildFilter, buildPagination, buildPaginationMeta, checkPackageServer, conflictResponse, connectDB, corsOptions, createApiKeyGenerator, createApiRateLimiter, createBrandCorsOptions, createBulkDeleteHandler, createConfig, createCorsOptions, createCrudControllers, createDdosRateLimiter, createLogger, createMorganStream, createMultiBrandCorsOptions, createPaginationMiddleware, createPrefixedKeyGenerator, createRateLimiter, createStandardRateLimiter, createStrictRateLimiter, createUserKeyGenerator, createdResponse, ddosProtectionLimiter, defaultKeyGenerator, disconnectDB, errorResponse, extractColumns, extractOrganization, extractSchemaMeta, forbiddenResponse, formatPackageCheckResult, generateNcuCommand, getConnectionStatus, getDatabaseOptions, isDevelopment, isProduction, isTest, logger, noContentResponse, notFoundResponse, omitFields, optionalAuthenticateJWT, packageCheckServer, parseBulkDelete, pickFields, printPackageCheckSummary, queryPagination, queryParser, rateLimitResponse, rateLimiter, requireOrganization, sanitizeDocument, sanitizeUser, simpleLogger, standardRateLimiter, statusCode, statusMessage, stream, strictRateLimiter, successResponse, successResponseArr, unauthorizedResponse, validationErrorResponse };
714
1998
  //# sourceMappingURL=index.mjs.map
715
1999
  //# sourceMappingURL=index.mjs.map