@strapi/utils 5.0.0-alpha.5 → 5.0.0-alpha.6

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.
package/dist/index.js CHANGED
@@ -2,11 +2,11 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const _$1 = require("lodash");
4
4
  const fp = require("lodash/fp");
5
- const pMap = require("p-map");
6
- const httpErrors = require("http-errors");
7
5
  const crypto = require("crypto");
8
6
  const nodeMachineId = require("node-machine-id");
9
7
  const yup$1 = require("yup");
8
+ const httpErrors = require("http-errors");
9
+ const pMap = require("p-map");
10
10
  const execa = require("execa");
11
11
  const preferredPM = require("preferred-pm");
12
12
  const node_stream = require("node:stream");
@@ -50,8 +50,8 @@ function _mergeNamespaces(n, m) {
50
50
  return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
51
51
  }
52
52
  const ___default = /* @__PURE__ */ _interopDefault(_$1);
53
- const pMap__default = /* @__PURE__ */ _interopDefault(pMap);
54
53
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup$1);
54
+ const pMap__default = /* @__PURE__ */ _interopDefault(pMap);
55
55
  const execa__default = /* @__PURE__ */ _interopDefault(execa);
56
56
  const preferredPM__default = /* @__PURE__ */ _interopDefault(preferredPM);
57
57
  const slugify__default = /* @__PURE__ */ _interopDefault(slugify);
@@ -543,201 +543,32 @@ const providerFactory = (options = {}) => {
543
543
  }
544
544
  };
545
545
  };
546
- function pipe(...fns) {
547
- const [firstFn, ...fnRest] = fns;
548
- return async (...args) => {
549
- let res = await firstFn.apply(firstFn, args);
550
- for (let i = 0; i < fnRest.length; i += 1) {
551
- res = await fnRest[i](res);
552
- }
553
- return res;
546
+ const traverseEntity = async (visitor2, options, entity) => {
547
+ const { path = { raw: null, attribute: null }, schema, getModel } = options;
548
+ const traverseMorphRelationTarget = async (visitor22, path2, entry) => {
549
+ const targetSchema = getModel(entry.__type);
550
+ const traverseOptions = { schema: targetSchema, path: path2, getModel };
551
+ return traverseEntity(visitor22, traverseOptions, entry);
554
552
  };
555
- }
556
- const map = fp.curry(pMap__default.default);
557
- const reduce = (mixedArray) => async (iteratee, initialValue) => {
558
- let acc = initialValue;
559
- for (let i = 0; i < mixedArray.length; i += 1) {
560
- acc = await iteratee(acc, await mixedArray[i], i);
561
- }
562
- return acc;
563
- };
564
- const async = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
565
- __proto__: null,
566
- map,
567
- pipe,
568
- reduce
569
- }, Symbol.toStringTag, { value: "Module" }));
570
- const visitor$8 = ({ key, attribute }, { remove }) => {
571
- if (attribute?.type === "password") {
572
- remove(key);
573
- }
574
- };
575
- const visitor$7 = ({ schema, key, attribute }, { remove }) => {
576
- if (!attribute) {
577
- return;
578
- }
579
- const isPrivate = attribute.private === true || isPrivateAttribute(schema, key);
580
- if (isPrivate) {
581
- remove(key);
582
- }
583
- };
584
- const ACTIONS_TO_VERIFY$1 = ["find"];
585
- const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$1 } = constants$1;
586
- const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schema }, { remove, set }) => {
587
- if (!attribute) {
588
- return;
589
- }
590
- const isRelation = attribute.type === "relation";
591
- if (!isRelation) {
592
- return;
593
- }
594
- const handleMorphRelation = async () => {
595
- const newMorphValue = [];
596
- for (const element of data[key]) {
597
- const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
598
- const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
599
- if (isAllowed) {
600
- newMorphValue.push(element);
601
- }
602
- }
603
- if (newMorphValue.length === 0) {
604
- remove(key);
605
- } else {
606
- set(key, newMorphValue);
607
- }
553
+ const traverseRelationTarget = (schema2) => async (visitor22, path2, entry) => {
554
+ const traverseOptions = { schema: schema2, path: path2, getModel };
555
+ return traverseEntity(visitor22, traverseOptions, entry);
608
556
  };
609
- const handleRegularRelation = async () => {
610
- const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${attribute.target}.${action}`);
611
- const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
612
- if (!isAllowed) {
613
- remove(key);
614
- }
557
+ const traverseMediaTarget = async (visitor22, path2, entry) => {
558
+ const targetSchemaUID = "plugin::upload.file";
559
+ const targetSchema = getModel(targetSchemaUID);
560
+ const traverseOptions = { schema: targetSchema, path: path2, getModel };
561
+ return traverseEntity(visitor22, traverseOptions, entry);
562
+ };
563
+ const traverseComponent = async (visitor22, path2, schema2, entry) => {
564
+ const traverseOptions = { schema: schema2, path: path2, getModel };
565
+ return traverseEntity(visitor22, traverseOptions, entry);
566
+ };
567
+ const visitDynamicZoneEntry = async (visitor22, path2, entry) => {
568
+ const targetSchema = getModel(entry.__component);
569
+ const traverseOptions = { schema: targetSchema, path: path2, getModel };
570
+ return traverseEntity(visitor22, traverseOptions, entry);
615
571
  };
616
- const isCreatorRelation = [CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE$1].includes(key);
617
- if (isMorphToRelationalAttribute(attribute)) {
618
- await handleMorphRelation();
619
- return;
620
- }
621
- if (isCreatorRelation && schema.options?.populateCreatorFields) {
622
- return;
623
- }
624
- await handleRegularRelation();
625
- };
626
- const hasAccessToSomeScopes$1 = async (scopes, auth) => {
627
- for (const scope of scopes) {
628
- try {
629
- await strapi.auth.verify(auth, { scope });
630
- return true;
631
- } catch {
632
- continue;
633
- }
634
- }
635
- return false;
636
- };
637
- const visitor$6 = ({ key, attribute }, { remove }) => {
638
- if (isMorphToRelationalAttribute(attribute)) {
639
- remove(key);
640
- }
641
- };
642
- const visitor$5 = ({ key, attribute }, { remove }) => {
643
- if (isDynamicZoneAttribute(attribute)) {
644
- remove(key);
645
- }
646
- };
647
- const removeDisallowedFields = (allowedFields = null) => ({ key, path: { attribute: path } }, { remove }) => {
648
- if (allowedFields === null) {
649
- return;
650
- }
651
- if (!(fp.isArray(allowedFields) && allowedFields.every(fp.isString))) {
652
- throw new TypeError(
653
- `Expected array of strings for allowedFields but got "${typeof allowedFields}"`
654
- );
655
- }
656
- if (fp.isNil(path)) {
657
- return;
658
- }
659
- const containedPaths = getContainedPaths$1(path);
660
- const isPathAllowed = allowedFields.some(
661
- (p) => containedPaths.includes(p) || p.startsWith(`${path}.`)
662
- );
663
- if (isPathAllowed) {
664
- return;
665
- }
666
- remove(key);
667
- };
668
- const getContainedPaths$1 = (path) => {
669
- const parts = fp.toPath(path);
670
- return parts.reduce((acc, value, index2, list) => {
671
- return [...acc, list.slice(0, index2 + 1).join(".")];
672
- }, []);
673
- };
674
- const removeRestrictedFields = (restrictedFields = null) => ({ key, path: { attribute: path } }, { remove }) => {
675
- if (restrictedFields === null) {
676
- remove(key);
677
- return;
678
- }
679
- if (!(fp.isArray(restrictedFields) && restrictedFields.every(fp.isString))) {
680
- throw new TypeError(
681
- `Expected array of strings for restrictedFields but got "${typeof restrictedFields}"`
682
- );
683
- }
684
- if (restrictedFields.includes(path)) {
685
- remove(key);
686
- return;
687
- }
688
- const isRestrictedNested = restrictedFields.some(
689
- (allowedPath) => path?.toString().startsWith(`${allowedPath}.`)
690
- );
691
- if (isRestrictedNested) {
692
- remove(key);
693
- }
694
- };
695
- const visitor$4 = ({ schema, key, value }, { set }) => {
696
- if (key === "" && value === "*") {
697
- const { attributes } = schema;
698
- const newPopulateQuery = Object.entries(attributes).filter(
699
- ([, attribute]) => ["relation", "component", "media", "dynamiczone"].includes(attribute.type)
700
- ).reduce((acc, [key2]) => ({ ...acc, [key2]: true }), {});
701
- set("", newPopulateQuery);
702
- }
703
- };
704
- const visitors$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
705
- __proto__: null,
706
- expandWildcardPopulate: visitor$4,
707
- removeDisallowedFields,
708
- removeDynamicZones: visitor$5,
709
- removeMorphToRelations: visitor$6,
710
- removePassword: visitor$8,
711
- removePrivate: visitor$7,
712
- removeRestrictedFields,
713
- removeRestrictedRelations
714
- }, Symbol.toStringTag, { value: "Module" }));
715
- const traverseMorphRelationTarget = async (visitor2, path, entry) => {
716
- const targetSchema = strapi.getModel(entry.__type);
717
- const traverseOptions = { schema: targetSchema, path };
718
- return traverseEntity(visitor2, traverseOptions, entry);
719
- };
720
- const traverseRelationTarget = (schema) => async (visitor2, path, entry) => {
721
- const traverseOptions = { schema, path };
722
- return traverseEntity(visitor2, traverseOptions, entry);
723
- };
724
- const traverseMediaTarget = async (visitor2, path, entry) => {
725
- const targetSchemaUID = "plugin::upload.file";
726
- const targetSchema = strapi.getModel(targetSchemaUID);
727
- const traverseOptions = { schema: targetSchema, path };
728
- return traverseEntity(visitor2, traverseOptions, entry);
729
- };
730
- const traverseComponent = async (visitor2, path, schema, entry) => {
731
- const traverseOptions = { schema, path };
732
- return traverseEntity(visitor2, traverseOptions, entry);
733
- };
734
- const visitDynamicZoneEntry = async (visitor2, path, entry) => {
735
- const targetSchema = strapi.getModel(entry.__component);
736
- const traverseOptions = { schema: targetSchema, path };
737
- return traverseEntity(visitor2, traverseOptions, entry);
738
- };
739
- const traverseEntity = async (visitor2, options, entity) => {
740
- const { path = { raw: null, attribute: null }, schema } = options;
741
572
  if (!fp.isObject(entity) || fp.isNil(schema)) {
742
573
  return entity;
743
574
  }
@@ -761,7 +592,8 @@ const traverseEntity = async (visitor2, options, entity) => {
761
592
  key,
762
593
  value: copy[key],
763
594
  attribute,
764
- path: newPath
595
+ path: newPath,
596
+ getModel
765
597
  };
766
598
  await visitor2(visitorOptions, visitorUtils);
767
599
  const value = copy[key];
@@ -770,7 +602,7 @@ const traverseEntity = async (visitor2, options, entity) => {
770
602
  }
771
603
  if (isRelationalAttribute(attribute)) {
772
604
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
773
- const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(strapi.getModel(attribute.target));
605
+ const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
774
606
  if (fp.isArray(value)) {
775
607
  const res = new Array(value.length);
776
608
  for (let i2 = 0; i2 < value.length; i2 += 1) {
@@ -795,7 +627,7 @@ const traverseEntity = async (visitor2, options, entity) => {
795
627
  continue;
796
628
  }
797
629
  if (attribute.type === "component") {
798
- const targetSchema = strapi.getModel(attribute.component);
630
+ const targetSchema = getModel(attribute.component);
799
631
  if (fp.isArray(value)) {
800
632
  const res = new Array(value.length);
801
633
  for (let i2 = 0; i2 < value.length; i2 += 1) {
@@ -827,87 +659,860 @@ const createVisitorUtils = ({ data }) => ({
827
659
  }
828
660
  });
829
661
  const traverseEntity$1 = fp.curry(traverseEntity);
830
- const DEFAULT_PATH = { raw: null, attribute: null };
831
- const traverseFactory = () => {
832
- const state = {
833
- parsers: [],
834
- interceptors: [],
835
- ignore: [],
836
- handlers: {
837
- attributes: [],
838
- common: []
839
- }
840
- };
841
- const traverse = async (visitor2, options, data) => {
842
- const { path = DEFAULT_PATH, schema } = options ?? {};
843
- for (const { predicate, handler } of state.interceptors) {
844
- if (predicate(data)) {
845
- return handler(visitor2, options, data, { recurse: traverse });
846
- }
847
- }
848
- const parser = state.parsers.find((parser2) => parser2.predicate(data))?.parser;
849
- const utils2 = parser?.(data);
850
- if (!utils2) {
851
- return data;
852
- }
853
- let out = utils2.transform(data);
854
- const keys = utils2.keys(out);
855
- for (const key of keys) {
856
- const attribute = schema?.attributes?.[key] ?? // FIX: Needed to not break existing behavior on the API.
857
- // It looks for the attribute in the DB metadata when the key is in snake_case
858
- schema?.attributes?.[strapi.db.metadata.get(schema?.uid).columnToAttribute[key]];
859
- const newPath = { ...path };
860
- newPath.raw = fp.isNil(path.raw) ? key : `${path.raw}.${key}`;
861
- if (!fp.isNil(attribute)) {
862
- newPath.attribute = fp.isNil(path.attribute) ? key : `${path.attribute}.${key}`;
863
- }
864
- const visitorOptions = {
865
- key,
866
- value: utils2.get(key, out),
867
- attribute,
868
- schema,
869
- path: newPath,
870
- data: out
871
- };
872
- const transformUtils = {
873
- remove(key2) {
874
- out = utils2.remove(key2, out);
875
- },
876
- set(key2, value2) {
877
- out = utils2.set(key2, value2, out);
878
- },
879
- recurse: traverse
880
- };
881
- await visitor2(visitorOptions, fp.pick(["remove", "set"], transformUtils));
882
- const value = utils2.get(key, out);
883
- const createContext = () => ({
884
- key,
885
- value,
886
- attribute,
887
- schema,
888
- path: newPath,
889
- data: out,
890
- visitor: visitor2
891
- });
892
- const ignoreCtx = createContext();
893
- const shouldIgnore = state.ignore.some((predicate) => predicate(ignoreCtx));
894
- if (shouldIgnore) {
895
- continue;
896
- }
897
- const handlers = [...state.handlers.common, ...state.handlers.attributes];
898
- for await (const handler of handlers) {
899
- const ctx = createContext();
900
- const pass = await handler.predicate(ctx);
901
- if (pass) {
902
- await handler.handler(ctx, fp.pick(["recurse", "set"], transformUtils));
903
- }
904
- }
905
- }
906
- return out;
907
- };
908
- return {
909
- traverse,
910
- intercept(predicate, handler) {
662
+ function importDefault(modName) {
663
+ const mod = require(modName);
664
+ return mod && mod.__esModule ? mod.default : mod;
665
+ }
666
+ const machineId = () => {
667
+ try {
668
+ const deviceId = nodeMachineId.machineIdSync();
669
+ return deviceId;
670
+ } catch (error) {
671
+ const deviceId = crypto.randomUUID();
672
+ return deviceId;
673
+ }
674
+ };
675
+ const formatYupInnerError = (yupError) => ({
676
+ path: fp.toPath(yupError.path),
677
+ message: yupError.message,
678
+ name: yupError.name
679
+ });
680
+ const formatYupErrors = (yupError) => ({
681
+ errors: fp.isEmpty(yupError.inner) ? [formatYupInnerError(yupError)] : yupError.inner.map(formatYupInnerError),
682
+ message: yupError.message
683
+ });
684
+ class ApplicationError extends Error {
685
+ name;
686
+ details;
687
+ message;
688
+ constructor(message = "An application error occured", details = {}) {
689
+ super();
690
+ this.name = "ApplicationError";
691
+ this.message = message;
692
+ this.details = details;
693
+ }
694
+ }
695
+ class ValidationError extends ApplicationError {
696
+ constructor(message, details) {
697
+ super(message, details);
698
+ this.name = "ValidationError";
699
+ }
700
+ }
701
+ class YupValidationError extends ValidationError {
702
+ constructor(yupError, message) {
703
+ super("Validation");
704
+ const { errors: errors2, message: yupMessage } = formatYupErrors(yupError);
705
+ this.message = message || yupMessage;
706
+ this.details = { errors: errors2 };
707
+ }
708
+ }
709
+ class PaginationError extends ApplicationError {
710
+ constructor(message = "Invalid pagination", details) {
711
+ super(message, details);
712
+ this.name = "PaginationError";
713
+ this.message = message;
714
+ }
715
+ }
716
+ class NotFoundError extends ApplicationError {
717
+ constructor(message = "Entity not found", details) {
718
+ super(message, details);
719
+ this.name = "NotFoundError";
720
+ this.message = message;
721
+ }
722
+ }
723
+ class ForbiddenError extends ApplicationError {
724
+ constructor(message = "Forbidden access", details) {
725
+ super(message, details);
726
+ this.name = "ForbiddenError";
727
+ this.message = message;
728
+ }
729
+ }
730
+ class UnauthorizedError extends ApplicationError {
731
+ constructor(message = "Unauthorized", details) {
732
+ super(message, details);
733
+ this.name = "UnauthorizedError";
734
+ this.message = message;
735
+ }
736
+ }
737
+ class RateLimitError extends ApplicationError {
738
+ constructor(message = "Too many requests, please try again later.", details) {
739
+ super(message, details);
740
+ this.name = "RateLimitError";
741
+ this.message = message;
742
+ this.details = details || {};
743
+ }
744
+ }
745
+ class PayloadTooLargeError extends ApplicationError {
746
+ constructor(message = "Entity too large", details) {
747
+ super(message, details);
748
+ this.name = "PayloadTooLargeError";
749
+ this.message = message;
750
+ }
751
+ }
752
+ class PolicyError extends ForbiddenError {
753
+ constructor(message = "Policy Failed", details) {
754
+ super(message, details);
755
+ this.name = "PolicyError";
756
+ this.message = message;
757
+ this.details = details || {};
758
+ }
759
+ }
760
+ class NotImplementedError extends ApplicationError {
761
+ constructor(message = "This feature is not implemented yet", details) {
762
+ super(message, details);
763
+ this.name = "NotImplementedError";
764
+ this.message = message;
765
+ }
766
+ }
767
+ const errors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
768
+ __proto__: null,
769
+ ApplicationError,
770
+ ForbiddenError,
771
+ HttpError: httpErrors.HttpError,
772
+ NotFoundError,
773
+ NotImplementedError,
774
+ PaginationError,
775
+ PayloadTooLargeError,
776
+ PolicyError,
777
+ RateLimitError,
778
+ UnauthorizedError,
779
+ ValidationError,
780
+ YupValidationError
781
+ }, Symbol.toStringTag, { value: "Module" }));
782
+ const handleYupError = (error, errorMessage) => {
783
+ throw new YupValidationError(error, errorMessage);
784
+ };
785
+ const defaultValidationParam = { strict: true, abortEarly: false };
786
+ const validateYupSchema = (schema, options = {}) => async (body, errorMessage) => {
787
+ try {
788
+ const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
789
+ const result = await schema.validate(body, optionsWithDefaults);
790
+ return result;
791
+ } catch (e) {
792
+ if (e instanceof yup__namespace.ValidationError) {
793
+ handleYupError(e, errorMessage);
794
+ }
795
+ throw e;
796
+ }
797
+ };
798
+ const validateYupSchemaSync = (schema, options = {}) => (body, errorMessage) => {
799
+ try {
800
+ const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
801
+ return schema.validateSync(body, optionsWithDefaults);
802
+ } catch (e) {
803
+ if (e instanceof yup__namespace.ValidationError) {
804
+ handleYupError(e, errorMessage);
805
+ }
806
+ throw e;
807
+ }
808
+ };
809
+ const GROUP_OPERATORS = ["$and", "$or"];
810
+ const WHERE_OPERATORS = [
811
+ "$not",
812
+ "$in",
813
+ "$notIn",
814
+ "$eq",
815
+ "$eqi",
816
+ "$ne",
817
+ "$nei",
818
+ "$gt",
819
+ "$gte",
820
+ "$lt",
821
+ "$lte",
822
+ "$null",
823
+ "$notNull",
824
+ "$between",
825
+ "$startsWith",
826
+ "$endsWith",
827
+ "$startsWithi",
828
+ "$endsWithi",
829
+ "$contains",
830
+ "$notContains",
831
+ "$containsi",
832
+ "$notContainsi",
833
+ // Experimental, only for internal use
834
+ "$jsonSupersetOf"
835
+ ];
836
+ const CAST_OPERATORS = [
837
+ "$not",
838
+ "$in",
839
+ "$notIn",
840
+ "$eq",
841
+ "$ne",
842
+ "$gt",
843
+ "$gte",
844
+ "$lt",
845
+ "$lte",
846
+ "$between"
847
+ ];
848
+ const ARRAY_OPERATORS = ["$in", "$notIn", "$between"];
849
+ const OPERATORS = {
850
+ where: WHERE_OPERATORS,
851
+ cast: CAST_OPERATORS,
852
+ group: GROUP_OPERATORS,
853
+ array: ARRAY_OPERATORS
854
+ };
855
+ const OPERATORS_LOWERCASE = Object.fromEntries(
856
+ Object.entries(OPERATORS).map(([key, values]) => [
857
+ key,
858
+ values.map((value) => value.toLowerCase())
859
+ ])
860
+ );
861
+ const isObjKey = (key, obj) => {
862
+ return key in obj;
863
+ };
864
+ const isOperatorOfType = (type, key, ignoreCase = false) => {
865
+ if (ignoreCase) {
866
+ return OPERATORS_LOWERCASE[type]?.includes(key.toLowerCase()) ?? false;
867
+ }
868
+ if (isObjKey(type, OPERATORS)) {
869
+ return OPERATORS[type]?.includes(key) ?? false;
870
+ }
871
+ return false;
872
+ };
873
+ const isOperator = (key, ignoreCase = false) => {
874
+ return Object.keys(OPERATORS).some((type) => isOperatorOfType(type, key, ignoreCase));
875
+ };
876
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$3, PUBLISHED_AT_ATTRIBUTE } = constants$1;
877
+ class InvalidOrderError extends Error {
878
+ constructor() {
879
+ super();
880
+ this.message = "Invalid order. order can only be one of asc|desc|ASC|DESC";
881
+ }
882
+ }
883
+ class InvalidSortError extends Error {
884
+ constructor() {
885
+ super();
886
+ this.message = "Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects";
887
+ }
888
+ }
889
+ function validateOrder(order) {
890
+ if (!fp.isString(order) || !["asc", "desc"].includes(order.toLocaleLowerCase())) {
891
+ throw new InvalidOrderError();
892
+ }
893
+ }
894
+ const convertCountQueryParams = (countQuery) => {
895
+ return parseType({ type: "boolean", value: countQuery });
896
+ };
897
+ const convertOrderingQueryParams = (ordering) => {
898
+ return ordering;
899
+ };
900
+ const isPlainObject = (value) => ___default.default.isPlainObject(value);
901
+ const isStringArray$3 = (value) => fp.isArray(value) && value.every(fp.isString);
902
+ const createTransformer = ({ getModel }) => {
903
+ const convertSortQueryParams = (sortQuery) => {
904
+ if (typeof sortQuery === "string") {
905
+ return convertStringSortQueryParam(sortQuery);
906
+ }
907
+ if (isStringArray$3(sortQuery)) {
908
+ return sortQuery.flatMap((sortValue) => convertStringSortQueryParam(sortValue));
909
+ }
910
+ if (Array.isArray(sortQuery)) {
911
+ return sortQuery.map((sortValue) => convertNestedSortQueryParam(sortValue));
912
+ }
913
+ if (isPlainObject(sortQuery)) {
914
+ return convertNestedSortQueryParam(sortQuery);
915
+ }
916
+ throw new InvalidSortError();
917
+ };
918
+ const convertStringSortQueryParam = (sortQuery) => {
919
+ return sortQuery.split(",").map((value) => convertSingleSortQueryParam(value));
920
+ };
921
+ const convertSingleSortQueryParam = (sortQuery) => {
922
+ if (!sortQuery) {
923
+ return {};
924
+ }
925
+ if (!fp.isString(sortQuery)) {
926
+ throw new Error("Invalid sort query");
927
+ }
928
+ const [field, order = "asc"] = sortQuery.split(":");
929
+ if (field.length === 0) {
930
+ throw new Error("Field cannot be empty");
931
+ }
932
+ validateOrder(order);
933
+ return ___default.default.set({}, field, order);
934
+ };
935
+ const convertNestedSortQueryParam = (sortQuery) => {
936
+ const transformedSort = {};
937
+ for (const field of Object.keys(sortQuery)) {
938
+ const order = sortQuery[field];
939
+ if (isPlainObject(order)) {
940
+ transformedSort[field] = convertNestedSortQueryParam(order);
941
+ } else if (typeof order === "string") {
942
+ validateOrder(order);
943
+ transformedSort[field] = order;
944
+ } else {
945
+ throw Error(`Invalid sort type expected object or string got ${typeof order}`);
946
+ }
947
+ }
948
+ return transformedSort;
949
+ };
950
+ const convertStartQueryParams = (startQuery) => {
951
+ const startAsANumber = ___default.default.toNumber(startQuery);
952
+ if (!___default.default.isInteger(startAsANumber) || startAsANumber < 0) {
953
+ throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
954
+ }
955
+ return startAsANumber;
956
+ };
957
+ const convertLimitQueryParams = (limitQuery) => {
958
+ const limitAsANumber = ___default.default.toNumber(limitQuery);
959
+ if (!___default.default.isInteger(limitAsANumber) || limitAsANumber !== -1 && limitAsANumber < 0) {
960
+ throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
961
+ }
962
+ if (limitAsANumber === -1) {
963
+ return void 0;
964
+ }
965
+ return limitAsANumber;
966
+ };
967
+ const convertPageQueryParams = (page) => {
968
+ const pageVal = fp.toNumber(page);
969
+ if (!fp.isInteger(pageVal) || pageVal <= 0) {
970
+ throw new PaginationError(
971
+ `Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
972
+ );
973
+ }
974
+ return pageVal;
975
+ };
976
+ const convertPageSizeQueryParams = (pageSize, page) => {
977
+ const pageSizeVal = fp.toNumber(pageSize);
978
+ if (!fp.isInteger(pageSizeVal) || pageSizeVal <= 0) {
979
+ throw new PaginationError(
980
+ `Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
981
+ );
982
+ }
983
+ return pageSizeVal;
984
+ };
985
+ const validatePaginationParams = (page, pageSize, start, limit) => {
986
+ const isPagePagination = !fp.isNil(page) || !fp.isNil(pageSize);
987
+ const isOffsetPagination = !fp.isNil(start) || !fp.isNil(limit);
988
+ if (isPagePagination && isOffsetPagination) {
989
+ throw new PaginationError(
990
+ "Invalid pagination attributes. You cannot use page and offset pagination in the same query"
991
+ );
992
+ }
993
+ };
994
+ class InvalidPopulateError extends Error {
995
+ constructor() {
996
+ super();
997
+ this.message = "Invalid populate parameter. Expected a string, an array of strings, a populate object";
998
+ }
999
+ }
1000
+ const convertPopulateQueryParams = (populate2, schema, depth = 0) => {
1001
+ if (depth === 0 && populate2 === "*") {
1002
+ return true;
1003
+ }
1004
+ if (typeof populate2 === "string") {
1005
+ return populate2.split(",").map((value) => ___default.default.trim(value));
1006
+ }
1007
+ if (Array.isArray(populate2)) {
1008
+ return ___default.default.uniq(
1009
+ populate2.flatMap((value) => {
1010
+ if (typeof value !== "string") {
1011
+ throw new InvalidPopulateError();
1012
+ }
1013
+ return value.split(",").map((value2) => ___default.default.trim(value2));
1014
+ })
1015
+ );
1016
+ }
1017
+ if (___default.default.isPlainObject(populate2)) {
1018
+ return convertPopulateObject(populate2, schema);
1019
+ }
1020
+ throw new InvalidPopulateError();
1021
+ };
1022
+ const hasFragmentPopulateDefined = (populate2) => {
1023
+ return typeof populate2 === "object" && "on" in populate2 && !fp.isNil(populate2.on);
1024
+ };
1025
+ const convertPopulateObject = (populate2, schema) => {
1026
+ if (!schema) {
1027
+ return {};
1028
+ }
1029
+ const { attributes } = schema;
1030
+ return Object.entries(populate2).reduce((acc, [key, subPopulate]) => {
1031
+ if (___default.default.isBoolean(subPopulate)) {
1032
+ return { ...acc, [key]: subPopulate };
1033
+ }
1034
+ const attribute = attributes[key];
1035
+ if (!attribute) {
1036
+ return acc;
1037
+ }
1038
+ const isAllowedAttributeForFragmentPopulate = isDynamicZoneAttribute(attribute) || isMorphToRelationalAttribute(attribute);
1039
+ if (isAllowedAttributeForFragmentPopulate && hasFragmentPopulateDefined(subPopulate)) {
1040
+ return {
1041
+ ...acc,
1042
+ [key]: {
1043
+ on: Object.entries(subPopulate.on).reduce(
1044
+ (acc2, [type, typeSubPopulate]) => ({
1045
+ ...acc2,
1046
+ [type]: convertNestedPopulate(typeSubPopulate, getModel(type))
1047
+ }),
1048
+ {}
1049
+ )
1050
+ }
1051
+ };
1052
+ }
1053
+ if (isDynamicZoneAttribute(attribute)) {
1054
+ const populates = attribute.components.map((uid) => getModel(uid)).map((schema2) => convertNestedPopulate(subPopulate, schema2)).map((populate22) => populate22 === true ? {} : populate22).filter((populate22) => populate22 !== false);
1055
+ if (fp.isEmpty(populates)) {
1056
+ return acc;
1057
+ }
1058
+ return {
1059
+ ...acc,
1060
+ [key]: fp.mergeAll(populates)
1061
+ };
1062
+ }
1063
+ if (isMorphToRelationalAttribute(attribute)) {
1064
+ return { ...acc, [key]: convertNestedPopulate(subPopulate, void 0) };
1065
+ }
1066
+ let targetSchemaUID;
1067
+ if (attribute.type === "relation") {
1068
+ targetSchemaUID = attribute.target;
1069
+ } else if (attribute.type === "component") {
1070
+ targetSchemaUID = attribute.component;
1071
+ } else if (attribute.type === "media") {
1072
+ targetSchemaUID = "plugin::upload.file";
1073
+ } else {
1074
+ return acc;
1075
+ }
1076
+ const targetSchema = getModel(targetSchemaUID);
1077
+ if (!targetSchema) {
1078
+ return acc;
1079
+ }
1080
+ const populateObject = convertNestedPopulate(subPopulate, targetSchema);
1081
+ if (!populateObject) {
1082
+ return acc;
1083
+ }
1084
+ return {
1085
+ ...acc,
1086
+ [key]: populateObject
1087
+ };
1088
+ }, {});
1089
+ };
1090
+ const convertNestedPopulate = (subPopulate, schema) => {
1091
+ if (___default.default.isString(subPopulate)) {
1092
+ return parseType({ type: "boolean", value: subPopulate, forceCast: true });
1093
+ }
1094
+ if (___default.default.isBoolean(subPopulate)) {
1095
+ return subPopulate;
1096
+ }
1097
+ if (!isPlainObject(subPopulate)) {
1098
+ throw new Error(`Invalid nested populate. Expected '*' or an object`);
1099
+ }
1100
+ const { sort: sort2, filters: filters2, fields: fields2, populate: populate2, count, ordering, page, pageSize, start, limit } = subPopulate;
1101
+ const query = {};
1102
+ if (sort2) {
1103
+ query.orderBy = convertSortQueryParams(sort2);
1104
+ }
1105
+ if (filters2) {
1106
+ query.where = convertFiltersQueryParams(filters2, schema);
1107
+ }
1108
+ if (fields2) {
1109
+ query.select = convertFieldsQueryParams(fields2);
1110
+ }
1111
+ if (populate2) {
1112
+ query.populate = convertPopulateQueryParams(populate2, schema);
1113
+ }
1114
+ if (count) {
1115
+ query.count = convertCountQueryParams(count);
1116
+ }
1117
+ if (ordering) {
1118
+ query.ordering = convertOrderingQueryParams(ordering);
1119
+ }
1120
+ validatePaginationParams(page, pageSize, start, limit);
1121
+ if (!fp.isNil(page)) {
1122
+ query.page = convertPageQueryParams(page);
1123
+ }
1124
+ if (!fp.isNil(pageSize)) {
1125
+ query.pageSize = convertPageSizeQueryParams(pageSize, page);
1126
+ }
1127
+ if (!fp.isNil(start)) {
1128
+ query.offset = convertStartQueryParams(start);
1129
+ }
1130
+ if (!fp.isNil(limit)) {
1131
+ query.limit = convertLimitQueryParams(limit);
1132
+ }
1133
+ return query;
1134
+ };
1135
+ const convertFieldsQueryParams = (fields2, depth = 0) => {
1136
+ if (depth === 0 && fields2 === "*") {
1137
+ return void 0;
1138
+ }
1139
+ if (typeof fields2 === "string") {
1140
+ const fieldsValues = fields2.split(",").map((value) => ___default.default.trim(value));
1141
+ return ___default.default.uniq([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3, ...fieldsValues]);
1142
+ }
1143
+ if (isStringArray$3(fields2)) {
1144
+ const fieldsValues = fields2.flatMap((value) => convertFieldsQueryParams(value, depth + 1)).filter((v) => !fp.isNil(v));
1145
+ return ___default.default.uniq([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3, ...fieldsValues]);
1146
+ }
1147
+ throw new Error("Invalid fields parameter. Expected a string or an array of strings");
1148
+ };
1149
+ const isValidSchemaAttribute = (key, schema) => {
1150
+ if ([DOC_ID_ATTRIBUTE$3, ID_ATTRIBUTE$3].includes(key)) {
1151
+ return true;
1152
+ }
1153
+ if (!schema) {
1154
+ return false;
1155
+ }
1156
+ return Object.keys(schema.attributes).includes(key);
1157
+ };
1158
+ const convertFiltersQueryParams = (filters2, schema) => {
1159
+ if (!fp.isObject(filters2)) {
1160
+ throw new Error("The filters parameter must be an object or an array");
1161
+ }
1162
+ const filtersCopy = fp.cloneDeep(filters2);
1163
+ return convertAndSanitizeFilters(filtersCopy, schema);
1164
+ };
1165
+ const convertAndSanitizeFilters = (filters2, schema) => {
1166
+ if (Array.isArray(filters2)) {
1167
+ return filters2.map((filter) => convertAndSanitizeFilters(filter, schema)).filter((filter) => !isPlainObject(filter) || !fp.isEmpty(filter));
1168
+ }
1169
+ if (!isPlainObject(filters2)) {
1170
+ return filters2;
1171
+ }
1172
+ const removeOperator = (operator) => delete filters2[operator];
1173
+ for (const [key, value] of Object.entries(filters2)) {
1174
+ const attribute = fp.get(key, schema?.attributes);
1175
+ const validKey = isOperator(key) || isValidSchemaAttribute(key, schema);
1176
+ if (!validKey) {
1177
+ removeOperator(key);
1178
+ } else if (attribute) {
1179
+ if (attribute.type === "relation") {
1180
+ filters2[key] = convertAndSanitizeFilters(value, getModel(attribute.target));
1181
+ } else if (attribute.type === "component") {
1182
+ filters2[key] = convertAndSanitizeFilters(value, getModel(attribute.component));
1183
+ } else if (attribute.type === "media") {
1184
+ filters2[key] = convertAndSanitizeFilters(value, getModel("plugin::upload.file"));
1185
+ } else if (attribute.type === "dynamiczone") {
1186
+ removeOperator(key);
1187
+ } else if (attribute.type === "password") {
1188
+ removeOperator(key);
1189
+ } else {
1190
+ filters2[key] = convertAndSanitizeFilters(value, schema);
1191
+ }
1192
+ } else if (["$null", "$notNull"].includes(key)) {
1193
+ filters2[key] = parseType({ type: "boolean", value: filters2[key], forceCast: true });
1194
+ } else if (fp.isObject(value)) {
1195
+ filters2[key] = convertAndSanitizeFilters(value, schema);
1196
+ }
1197
+ if (isPlainObject(filters2[key]) && fp.isEmpty(filters2[key])) {
1198
+ removeOperator(key);
1199
+ }
1200
+ }
1201
+ return filters2;
1202
+ };
1203
+ const convertStatusParams = (status, query = {}) => {
1204
+ query.filters = ({ meta }) => {
1205
+ const contentType = getModel(meta.uid);
1206
+ if (!contentType || !hasDraftAndPublish(contentType)) {
1207
+ return {};
1208
+ }
1209
+ return { [PUBLISHED_AT_ATTRIBUTE]: { $null: status === "draft" } };
1210
+ };
1211
+ };
1212
+ const transformQueryParams = (uid, params) => {
1213
+ const schema = getModel(uid);
1214
+ const query = {};
1215
+ const { _q, sort: sort2, filters: filters2, fields: fields2, populate: populate2, page, pageSize, start, limit, status, ...rest } = params;
1216
+ if (!fp.isNil(status)) {
1217
+ convertStatusParams(status, query);
1218
+ }
1219
+ if (!fp.isNil(_q)) {
1220
+ query._q = _q;
1221
+ }
1222
+ if (!fp.isNil(sort2)) {
1223
+ query.orderBy = convertSortQueryParams(sort2);
1224
+ }
1225
+ if (!fp.isNil(filters2)) {
1226
+ query.where = convertFiltersQueryParams(filters2, schema);
1227
+ }
1228
+ if (!fp.isNil(fields2)) {
1229
+ query.select = convertFieldsQueryParams(fields2);
1230
+ }
1231
+ if (!fp.isNil(populate2)) {
1232
+ query.populate = convertPopulateQueryParams(populate2, schema);
1233
+ }
1234
+ validatePaginationParams(page, pageSize, start, limit);
1235
+ if (!fp.isNil(page)) {
1236
+ query.page = convertPageQueryParams(page);
1237
+ }
1238
+ if (!fp.isNil(pageSize)) {
1239
+ query.pageSize = convertPageSizeQueryParams(pageSize, page);
1240
+ }
1241
+ if (!fp.isNil(start)) {
1242
+ query.offset = convertStartQueryParams(start);
1243
+ }
1244
+ if (!fp.isNil(limit)) {
1245
+ query.limit = convertLimitQueryParams(limit);
1246
+ }
1247
+ return {
1248
+ ...rest,
1249
+ ...query
1250
+ };
1251
+ };
1252
+ return {
1253
+ private_convertSortQueryParams: convertSortQueryParams,
1254
+ private_convertStartQueryParams: convertStartQueryParams,
1255
+ private_convertLimitQueryParams: convertLimitQueryParams,
1256
+ private_convertPopulateQueryParams: convertPopulateQueryParams,
1257
+ private_convertFiltersQueryParams: convertFiltersQueryParams,
1258
+ private_convertFieldsQueryParams: convertFieldsQueryParams,
1259
+ transformQueryParams
1260
+ };
1261
+ };
1262
+ const convertQueryParams = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1263
+ __proto__: null,
1264
+ createTransformer
1265
+ }, Symbol.toStringTag, { value: "Module" }));
1266
+ function pipe(...fns) {
1267
+ const [firstFn, ...fnRest] = fns;
1268
+ return async (...args) => {
1269
+ let res = await firstFn.apply(firstFn, args);
1270
+ for (let i = 0; i < fnRest.length; i += 1) {
1271
+ res = await fnRest[i](res);
1272
+ }
1273
+ return res;
1274
+ };
1275
+ }
1276
+ const map = fp.curry(pMap__default.default);
1277
+ const reduce = (mixedArray) => async (iteratee, initialValue) => {
1278
+ let acc = initialValue;
1279
+ for (let i = 0; i < mixedArray.length; i += 1) {
1280
+ acc = await iteratee(acc, await mixedArray[i], i);
1281
+ }
1282
+ return acc;
1283
+ };
1284
+ const async = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1285
+ __proto__: null,
1286
+ map,
1287
+ pipe,
1288
+ reduce
1289
+ }, Symbol.toStringTag, { value: "Module" }));
1290
+ const visitor$8 = ({ key, attribute }, { remove }) => {
1291
+ if (attribute?.type === "password") {
1292
+ remove(key);
1293
+ }
1294
+ };
1295
+ const visitor$7 = ({ schema, key, attribute }, { remove }) => {
1296
+ if (!attribute) {
1297
+ return;
1298
+ }
1299
+ const isPrivate = attribute.private === true || isPrivateAttribute(schema, key);
1300
+ if (isPrivate) {
1301
+ remove(key);
1302
+ }
1303
+ };
1304
+ const ACTIONS_TO_VERIFY$1 = ["find"];
1305
+ const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$1 } = constants$1;
1306
+ const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schema }, { remove, set }) => {
1307
+ if (!attribute) {
1308
+ return;
1309
+ }
1310
+ const isRelation = attribute.type === "relation";
1311
+ if (!isRelation) {
1312
+ return;
1313
+ }
1314
+ const handleMorphRelation = async () => {
1315
+ const newMorphValue = [];
1316
+ for (const element of data[key]) {
1317
+ const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
1318
+ const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
1319
+ if (isAllowed) {
1320
+ newMorphValue.push(element);
1321
+ }
1322
+ }
1323
+ if (newMorphValue.length === 0) {
1324
+ remove(key);
1325
+ } else {
1326
+ set(key, newMorphValue);
1327
+ }
1328
+ };
1329
+ const handleRegularRelation = async () => {
1330
+ const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${attribute.target}.${action}`);
1331
+ const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
1332
+ if (!isAllowed) {
1333
+ remove(key);
1334
+ }
1335
+ };
1336
+ const isCreatorRelation = [CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE$1].includes(key);
1337
+ if (isMorphToRelationalAttribute(attribute)) {
1338
+ await handleMorphRelation();
1339
+ return;
1340
+ }
1341
+ if (isCreatorRelation && schema.options?.populateCreatorFields) {
1342
+ return;
1343
+ }
1344
+ await handleRegularRelation();
1345
+ };
1346
+ const hasAccessToSomeScopes$1 = async (scopes, auth) => {
1347
+ for (const scope of scopes) {
1348
+ try {
1349
+ await strapi.auth.verify(auth, { scope });
1350
+ return true;
1351
+ } catch {
1352
+ continue;
1353
+ }
1354
+ }
1355
+ return false;
1356
+ };
1357
+ const visitor$6 = ({ key, attribute }, { remove }) => {
1358
+ if (isMorphToRelationalAttribute(attribute)) {
1359
+ remove(key);
1360
+ }
1361
+ };
1362
+ const visitor$5 = ({ key, attribute }, { remove }) => {
1363
+ if (isDynamicZoneAttribute(attribute)) {
1364
+ remove(key);
1365
+ }
1366
+ };
1367
+ const removeDisallowedFields = (allowedFields = null) => ({ key, path: { attribute: path } }, { remove }) => {
1368
+ if (allowedFields === null) {
1369
+ return;
1370
+ }
1371
+ if (!(fp.isArray(allowedFields) && allowedFields.every(fp.isString))) {
1372
+ throw new TypeError(
1373
+ `Expected array of strings for allowedFields but got "${typeof allowedFields}"`
1374
+ );
1375
+ }
1376
+ if (fp.isNil(path)) {
1377
+ return;
1378
+ }
1379
+ const containedPaths = getContainedPaths$1(path);
1380
+ const isPathAllowed = allowedFields.some(
1381
+ (p) => containedPaths.includes(p) || p.startsWith(`${path}.`)
1382
+ );
1383
+ if (isPathAllowed) {
1384
+ return;
1385
+ }
1386
+ remove(key);
1387
+ };
1388
+ const getContainedPaths$1 = (path) => {
1389
+ const parts = fp.toPath(path);
1390
+ return parts.reduce((acc, value, index2, list) => {
1391
+ return [...acc, list.slice(0, index2 + 1).join(".")];
1392
+ }, []);
1393
+ };
1394
+ const removeRestrictedFields = (restrictedFields = null) => ({ key, path: { attribute: path } }, { remove }) => {
1395
+ if (restrictedFields === null) {
1396
+ remove(key);
1397
+ return;
1398
+ }
1399
+ if (!(fp.isArray(restrictedFields) && restrictedFields.every(fp.isString))) {
1400
+ throw new TypeError(
1401
+ `Expected array of strings for restrictedFields but got "${typeof restrictedFields}"`
1402
+ );
1403
+ }
1404
+ if (restrictedFields.includes(path)) {
1405
+ remove(key);
1406
+ return;
1407
+ }
1408
+ const isRestrictedNested = restrictedFields.some(
1409
+ (allowedPath) => path?.toString().startsWith(`${allowedPath}.`)
1410
+ );
1411
+ if (isRestrictedNested) {
1412
+ remove(key);
1413
+ }
1414
+ };
1415
+ const visitor$4 = ({ schema, key, value }, { set }) => {
1416
+ if (key === "" && value === "*") {
1417
+ const { attributes } = schema;
1418
+ const newPopulateQuery = Object.entries(attributes).filter(
1419
+ ([, attribute]) => ["relation", "component", "media", "dynamiczone"].includes(attribute.type)
1420
+ ).reduce((acc, [key2]) => ({ ...acc, [key2]: true }), {});
1421
+ set("", newPopulateQuery);
1422
+ }
1423
+ };
1424
+ const index$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1425
+ __proto__: null,
1426
+ expandWildcardPopulate: visitor$4,
1427
+ removeDisallowedFields,
1428
+ removeDynamicZones: visitor$5,
1429
+ removeMorphToRelations: visitor$6,
1430
+ removePassword: visitor$8,
1431
+ removePrivate: visitor$7,
1432
+ removeRestrictedFields,
1433
+ removeRestrictedRelations
1434
+ }, Symbol.toStringTag, { value: "Module" }));
1435
+ const DEFAULT_PATH = { raw: null, attribute: null };
1436
+ const traverseFactory = () => {
1437
+ const state = {
1438
+ parsers: [],
1439
+ interceptors: [],
1440
+ ignore: [],
1441
+ handlers: {
1442
+ attributes: [],
1443
+ common: []
1444
+ }
1445
+ };
1446
+ const traverse = async (visitor2, options, data) => {
1447
+ const { path = DEFAULT_PATH, schema, getModel } = options ?? {};
1448
+ for (const { predicate, handler } of state.interceptors) {
1449
+ if (predicate(data)) {
1450
+ return handler(visitor2, options, data, { recurse: traverse });
1451
+ }
1452
+ }
1453
+ const parser = state.parsers.find((parser2) => parser2.predicate(data))?.parser;
1454
+ const utils2 = parser?.(data);
1455
+ if (!utils2) {
1456
+ return data;
1457
+ }
1458
+ let out = utils2.transform(data);
1459
+ const keys = utils2.keys(out);
1460
+ for (const key of keys) {
1461
+ const attribute = schema?.attributes?.[key];
1462
+ const newPath = { ...path };
1463
+ newPath.raw = fp.isNil(path.raw) ? key : `${path.raw}.${key}`;
1464
+ if (!fp.isNil(attribute)) {
1465
+ newPath.attribute = fp.isNil(path.attribute) ? key : `${path.attribute}.${key}`;
1466
+ }
1467
+ const visitorOptions = {
1468
+ key,
1469
+ value: utils2.get(key, out),
1470
+ attribute,
1471
+ schema,
1472
+ path: newPath,
1473
+ data: out,
1474
+ getModel
1475
+ };
1476
+ const transformUtils = {
1477
+ remove(key2) {
1478
+ out = utils2.remove(key2, out);
1479
+ },
1480
+ set(key2, value2) {
1481
+ out = utils2.set(key2, value2, out);
1482
+ },
1483
+ recurse: traverse
1484
+ };
1485
+ await visitor2(visitorOptions, fp.pick(["remove", "set"], transformUtils));
1486
+ const value = utils2.get(key, out);
1487
+ const createContext = () => ({
1488
+ key,
1489
+ value,
1490
+ attribute,
1491
+ schema,
1492
+ path: newPath,
1493
+ data: out,
1494
+ visitor: visitor2,
1495
+ getModel
1496
+ });
1497
+ const ignoreCtx = createContext();
1498
+ const shouldIgnore = state.ignore.some((predicate) => predicate(ignoreCtx));
1499
+ if (shouldIgnore) {
1500
+ continue;
1501
+ }
1502
+ const handlers = [...state.handlers.common, ...state.handlers.attributes];
1503
+ for await (const handler of handlers) {
1504
+ const ctx = createContext();
1505
+ const pass = await handler.predicate(ctx);
1506
+ if (pass) {
1507
+ await handler.handler(ctx, fp.pick(["recurse", "set"], transformUtils));
1508
+ }
1509
+ }
1510
+ }
1511
+ return out;
1512
+ };
1513
+ return {
1514
+ traverse,
1515
+ intercept(predicate, handler) {
911
1516
  state.interceptors.push({ predicate, handler });
912
1517
  return this;
913
1518
  },
@@ -976,33 +1581,33 @@ const filters = traverseFactory().intercept(
976
1581
  }
977
1582
  })).ignore(({ value }) => fp.isNil(value)).on(
978
1583
  ({ attribute }) => fp.isNil(attribute),
979
- async ({ key, visitor: visitor2, path, value, schema }, { set, recurse }) => {
980
- set(key, await recurse(visitor2, { schema, path }, value));
1584
+ async ({ key, visitor: visitor2, path, value, schema, getModel }, { set, recurse }) => {
1585
+ set(key, await recurse(visitor2, { schema, path, getModel }, value));
981
1586
  }
982
- ).onRelation(async ({ key, attribute, visitor: visitor2, path, value }, { set, recurse }) => {
1587
+ ).onRelation(async ({ key, attribute, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
983
1588
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
984
1589
  if (isMorphRelation) {
985
1590
  return;
986
1591
  }
987
1592
  const targetSchemaUID = attribute.target;
988
- const targetSchema = strapi.getModel(targetSchemaUID);
989
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1593
+ const targetSchema = getModel(targetSchemaUID);
1594
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
990
1595
  set(key, newValue);
991
- }).onComponent(async ({ key, attribute, visitor: visitor2, path, value }, { set, recurse }) => {
992
- const targetSchema = strapi.getModel(attribute.component);
993
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1596
+ }).onComponent(async ({ key, attribute, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
1597
+ const targetSchema = getModel(attribute.component);
1598
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
994
1599
  set(key, newValue);
995
- }).onMedia(async ({ key, visitor: visitor2, path, value }, { set, recurse }) => {
1600
+ }).onMedia(async ({ key, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
996
1601
  const targetSchemaUID = "plugin::upload.file";
997
- const targetSchema = strapi.getModel(targetSchemaUID);
998
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1602
+ const targetSchema = getModel(targetSchemaUID);
1603
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
999
1604
  set(key, newValue);
1000
1605
  });
1001
1606
  const traverseQueryFilters = fp.curry(filters.traverse);
1002
1607
  const ORDERS = { asc: "asc", desc: "desc" };
1003
1608
  const ORDER_VALUES = Object.values(ORDERS);
1004
1609
  const isSortOrder = (value) => ORDER_VALUES.includes(value.toLowerCase());
1005
- const isStringArray$3 = (value) => Array.isArray(value) && value.every(fp.isString);
1610
+ const isStringArray$2 = (value) => Array.isArray(value) && value.every(fp.isString);
1006
1611
  const isObjectArray = (value) => Array.isArray(value) && value.every(fp.isObject);
1007
1612
  const isNestedSorts = (value) => fp.isString(value) && value.split(",").length > 1;
1008
1613
  const isObj$1 = (value) => fp.isObject(value);
@@ -1016,7 +1621,7 @@ const sort = traverseFactory().intercept(
1016
1621
  }
1017
1622
  ).intercept(
1018
1623
  // Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items
1019
- isStringArray$3,
1624
+ isStringArray$2,
1020
1625
  async (visitor2, options, sort2, { recurse }) => {
1021
1626
  return Promise.all(sort2.map((nestedSort) => recurse(visitor2, options, nestedSort))).then(
1022
1627
  (res) => res.filter((nestedSort) => !fp.isEmpty(nestedSort))
@@ -1083,23 +1688,23 @@ const sort = traverseFactory().intercept(
1083
1688
  get(key, data) {
1084
1689
  return data[key];
1085
1690
  }
1086
- })).onRelation(async ({ key, value, attribute, visitor: visitor2, path }, { set, recurse }) => {
1691
+ })).onRelation(async ({ key, value, attribute, visitor: visitor2, path, getModel }, { set, recurse }) => {
1087
1692
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
1088
1693
  if (isMorphRelation) {
1089
1694
  return;
1090
1695
  }
1091
1696
  const targetSchemaUID = attribute.target;
1092
- const targetSchema = strapi.getModel(targetSchemaUID);
1093
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1697
+ const targetSchema = getModel(targetSchemaUID);
1698
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1094
1699
  set(key, newValue);
1095
- }).onMedia(async ({ key, path, visitor: visitor2, value }, { recurse, set }) => {
1700
+ }).onMedia(async ({ key, path, visitor: visitor2, value, getModel }, { recurse, set }) => {
1096
1701
  const targetSchemaUID = "plugin::upload.file";
1097
- const targetSchema = strapi.getModel(targetSchemaUID);
1098
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1702
+ const targetSchema = getModel(targetSchemaUID);
1703
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1099
1704
  set(key, newValue);
1100
- }).onComponent(async ({ key, value, visitor: visitor2, path, attribute }, { recurse, set }) => {
1101
- const targetSchema = strapi.getModel(attribute.component);
1102
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1705
+ }).onComponent(async ({ key, value, visitor: visitor2, path, attribute, getModel }, { recurse, set }) => {
1706
+ const targetSchema = getModel(attribute.component);
1707
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1103
1708
  set(key, newValue);
1104
1709
  });
1105
1710
  const traverseQuerySort = fp.curry(sort.traverse);
@@ -1108,9 +1713,9 @@ const isKeyword = (keyword) => {
1108
1713
  return !attribute && keyword === key;
1109
1714
  };
1110
1715
  };
1111
- const isStringArray$2 = (value) => fp.isArray(value) && value.every(fp.isString);
1716
+ const isStringArray$1 = (value) => fp.isArray(value) && value.every(fp.isString);
1112
1717
  const isObj = (value) => fp.isObject(value);
1113
- const populate = traverseFactory().intercept(isStringArray$2, async (visitor2, options, populate2, { recurse }) => {
1718
+ const populate = traverseFactory().intercept(isStringArray$1, async (visitor2, options, populate2, { recurse }) => {
1114
1719
  const visitedPopulate = await Promise.all(
1115
1720
  populate2.map((nestedPopulate) => recurse(visitor2, options, nestedPopulate))
1116
1721
  );
@@ -1187,78 +1792,86 @@ const populate = traverseFactory().intercept(isStringArray$2, async (visitor2, o
1187
1792
  }).on(
1188
1793
  // Handle recursion on populate."populate"
1189
1794
  isKeyword("populate"),
1190
- async ({ key, visitor: visitor2, path, value, schema }, { set, recurse }) => {
1191
- const newValue = await recurse(visitor2, { schema, path }, value);
1795
+ async ({ key, visitor: visitor2, path, value, schema, getModel }, { set, recurse }) => {
1796
+ const newValue = await recurse(visitor2, { schema, path, getModel }, value);
1192
1797
  set(key, newValue);
1193
1798
  }
1194
- ).on(isKeyword("on"), async ({ key, visitor: visitor2, path, value }, { set, recurse }) => {
1799
+ ).on(isKeyword("on"), async ({ key, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
1195
1800
  const newOn = {};
1196
1801
  if (!isObj(value)) {
1197
1802
  return;
1198
1803
  }
1199
1804
  for (const [uid, subPopulate] of Object.entries(value)) {
1200
- const model = strapi.getModel(uid);
1805
+ const model = getModel(uid);
1201
1806
  const newPath = { ...path, raw: `${path.raw}[${uid}]` };
1202
- newOn[uid] = await recurse(visitor2, { schema: model, path: newPath }, subPopulate);
1807
+ newOn[uid] = await recurse(visitor2, { schema: model, path: newPath, getModel }, subPopulate);
1203
1808
  }
1204
1809
  set(key, newOn);
1205
- }).onRelation(async ({ key, value, attribute, visitor: visitor2, path, schema }, { set, recurse }) => {
1206
- if (fp.isNil(value)) {
1207
- return;
1208
- }
1209
- if (isMorphToRelationalAttribute(attribute)) {
1210
- if (!fp.isObject(value) || !("on" in value && fp.isObject(value?.on))) {
1810
+ }).onRelation(
1811
+ async ({ key, value, attribute, visitor: visitor2, path, schema, getModel }, { set, recurse }) => {
1812
+ if (fp.isNil(value)) {
1211
1813
  return;
1212
1814
  }
1213
- const newValue2 = await recurse(visitor2, { schema, path }, { on: value?.on });
1214
- set(key, { on: newValue2 });
1815
+ if (isMorphToRelationalAttribute(attribute)) {
1816
+ if (!fp.isObject(value) || !("on" in value && fp.isObject(value?.on))) {
1817
+ return;
1818
+ }
1819
+ const newValue2 = await recurse(visitor2, { schema, path, getModel }, { on: value?.on });
1820
+ set(key, { on: newValue2 });
1821
+ }
1822
+ const targetSchemaUID = attribute.target;
1823
+ const targetSchema = getModel(targetSchemaUID);
1824
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1825
+ set(key, newValue);
1215
1826
  }
1216
- const targetSchemaUID = attribute.target;
1217
- const targetSchema = strapi.getModel(targetSchemaUID);
1218
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1219
- set(key, newValue);
1220
- }).onMedia(async ({ key, path, visitor: visitor2, value }, { recurse, set }) => {
1827
+ ).onMedia(async ({ key, path, visitor: visitor2, value, getModel }, { recurse, set }) => {
1221
1828
  if (fp.isNil(value)) {
1222
1829
  return;
1223
1830
  }
1224
1831
  const targetSchemaUID = "plugin::upload.file";
1225
- const targetSchema = strapi.getModel(targetSchemaUID);
1226
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1832
+ const targetSchema = getModel(targetSchemaUID);
1833
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1227
1834
  set(key, newValue);
1228
- }).onComponent(async ({ key, value, visitor: visitor2, path, attribute }, { recurse, set }) => {
1835
+ }).onComponent(async ({ key, value, visitor: visitor2, path, attribute, getModel }, { recurse, set }) => {
1229
1836
  if (fp.isNil(value)) {
1230
1837
  return;
1231
1838
  }
1232
- const targetSchema = strapi.getModel(attribute.component);
1233
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1839
+ const targetSchema = getModel(attribute.component);
1840
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1234
1841
  set(key, newValue);
1235
- }).onDynamicZone(async ({ key, value, attribute, schema, visitor: visitor2, path }, { set, recurse }) => {
1236
- if (fp.isNil(value)) {
1237
- return;
1238
- }
1239
- if (fp.isObject(value)) {
1240
- const { components } = attribute;
1241
- const newValue = {};
1242
- let newProperties = fp.omit("on", value);
1243
- for (const componentUID of components) {
1244
- const componentSchema = strapi.getModel(componentUID);
1245
- const properties = await recurse(visitor2, { schema: componentSchema, path }, value);
1246
- newProperties = fp.merge(newProperties, properties);
1842
+ }).onDynamicZone(
1843
+ async ({ key, value, attribute, schema, visitor: visitor2, path, getModel }, { set, recurse }) => {
1844
+ if (fp.isNil(value)) {
1845
+ return;
1247
1846
  }
1248
- Object.assign(newValue, newProperties);
1249
- if ("on" in value && value.on) {
1250
- const newOn = await recurse(visitor2, { schema, path }, { on: value.on });
1251
- Object.assign(newValue, newOn);
1847
+ if (fp.isObject(value)) {
1848
+ const { components } = attribute;
1849
+ const newValue = {};
1850
+ let newProperties = fp.omit("on", value);
1851
+ for (const componentUID of components) {
1852
+ const componentSchema = getModel(componentUID);
1853
+ const properties = await recurse(
1854
+ visitor2,
1855
+ { schema: componentSchema, path, getModel },
1856
+ value
1857
+ );
1858
+ newProperties = fp.merge(newProperties, properties);
1859
+ }
1860
+ Object.assign(newValue, newProperties);
1861
+ if ("on" in value && value.on) {
1862
+ const newOn = await recurse(visitor2, { schema, path, getModel }, { on: value.on });
1863
+ Object.assign(newValue, newOn);
1864
+ }
1865
+ set(key, newValue);
1866
+ } else {
1867
+ const newValue = await recurse(visitor2, { schema, path, getModel }, value);
1868
+ set(key, newValue);
1252
1869
  }
1253
- set(key, newValue);
1254
- } else {
1255
- const newValue = await recurse(visitor2, { schema, path }, value);
1256
- set(key, newValue);
1257
1870
  }
1258
- });
1871
+ );
1259
1872
  const traverseQueryPopulate = fp.curry(populate.traverse);
1260
- const isStringArray$1 = (value) => fp.isArray(value) && value.every(fp.isString);
1261
- const fields = traverseFactory().intercept(isStringArray$1, async (visitor2, options, fields2, { recurse }) => {
1873
+ const isStringArray = (value) => fp.isArray(value) && value.every(fp.isString);
1874
+ const fields = traverseFactory().intercept(isStringArray, async (visitor2, options, fields2, { recurse }) => {
1262
1875
  return Promise.all(fields2.map((field) => recurse(visitor2, options, field)));
1263
1876
  }).intercept((value) => fp.eq("*", value), fp.constant("*")).parse(fp.isString, () => ({
1264
1877
  transform: fp.trim,
@@ -1276,90 +1889,22 @@ const fields = traverseFactory().intercept(isStringArray$1, async (visitor2, opt
1276
1889
  }
1277
1890
  }));
1278
1891
  const traverseQueryFields = fp.curry(fields.traverse);
1279
- const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1892
+ const index$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1280
1893
  __proto__: null,
1281
- factory: traverseFactory,
1282
1894
  traverseQueryFields,
1283
1895
  traverseQueryFilters,
1284
1896
  traverseQueryPopulate,
1285
1897
  traverseQuerySort
1286
1898
  }, Symbol.toStringTag, { value: "Module" }));
1287
- const GROUP_OPERATORS = ["$and", "$or"];
1288
- const WHERE_OPERATORS = [
1289
- "$not",
1290
- "$in",
1291
- "$notIn",
1292
- "$eq",
1293
- "$eqi",
1294
- "$ne",
1295
- "$nei",
1296
- "$gt",
1297
- "$gte",
1298
- "$lt",
1299
- "$lte",
1300
- "$null",
1301
- "$notNull",
1302
- "$between",
1303
- "$startsWith",
1304
- "$endsWith",
1305
- "$startsWithi",
1306
- "$endsWithi",
1307
- "$contains",
1308
- "$notContains",
1309
- "$containsi",
1310
- "$notContainsi",
1311
- // Experimental, only for internal use
1312
- "$jsonSupersetOf"
1313
- ];
1314
- const CAST_OPERATORS = [
1315
- "$not",
1316
- "$in",
1317
- "$notIn",
1318
- "$eq",
1319
- "$ne",
1320
- "$gt",
1321
- "$gte",
1322
- "$lt",
1323
- "$lte",
1324
- "$between"
1325
- ];
1326
- const ARRAY_OPERATORS = ["$in", "$notIn", "$between"];
1327
- const OPERATORS = {
1328
- where: WHERE_OPERATORS,
1329
- cast: CAST_OPERATORS,
1330
- group: GROUP_OPERATORS,
1331
- array: ARRAY_OPERATORS
1332
- };
1333
- const OPERATORS_LOWERCASE = Object.fromEntries(
1334
- Object.entries(OPERATORS).map(([key, values]) => [
1335
- key,
1336
- values.map((value) => value.toLowerCase())
1337
- ])
1338
- );
1339
- const isObjKey = (key, obj) => {
1340
- return key in obj;
1341
- };
1342
- const isOperatorOfType = (type, key, ignoreCase = false) => {
1343
- if (ignoreCase) {
1344
- return OPERATORS_LOWERCASE[type]?.includes(key.toLowerCase()) ?? false;
1345
- }
1346
- if (isObjKey(type, OPERATORS)) {
1347
- return OPERATORS[type]?.includes(key) ?? false;
1348
- }
1349
- return false;
1350
- };
1351
- const isOperator = (key, ignoreCase = false) => {
1352
- return Object.keys(OPERATORS).some((type) => isOperatorOfType(type, key, ignoreCase));
1353
- };
1354
- const { ID_ATTRIBUTE: ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$3 } = constants$1;
1355
- const sanitizePasswords = (schema) => async (entity) => {
1356
- if (!schema) {
1899
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$2 } = constants$1;
1900
+ const sanitizePasswords = (ctx) => async (entity) => {
1901
+ if (!ctx.schema) {
1357
1902
  throw new Error("Missing schema in sanitizePasswords");
1358
1903
  }
1359
- return traverseEntity$1(visitor$8, { schema }, entity);
1904
+ return traverseEntity$1(visitor$8, ctx, entity);
1360
1905
  };
1361
- const defaultSanitizeOutput = async (schema, entity) => {
1362
- if (!schema) {
1906
+ const defaultSanitizeOutput = async (ctx, entity) => {
1907
+ if (!ctx.schema) {
1363
1908
  throw new Error("Missing schema in defaultSanitizeOutput");
1364
1909
  }
1365
1910
  return traverseEntity$1(
@@ -1367,139 +1912,121 @@ const defaultSanitizeOutput = async (schema, entity) => {
1367
1912
  visitor$8(...args);
1368
1913
  visitor$7(...args);
1369
1914
  },
1370
- { schema },
1915
+ ctx,
1371
1916
  entity
1372
1917
  );
1373
1918
  };
1374
- const defaultSanitizeFilters = fp.curry((schema, filters2) => {
1375
- if (!schema) {
1919
+ const defaultSanitizeFilters = fp.curry((ctx, filters2) => {
1920
+ if (!ctx.schema) {
1376
1921
  throw new Error("Missing schema in defaultSanitizeFilters");
1377
1922
  }
1378
1923
  return pipe(
1379
1924
  // Remove keys that are not attributes or valid operators
1380
- traverseQueryFilters(
1381
- ({ key, attribute }, { remove }) => {
1382
- const isAttribute = !!attribute;
1383
- if ([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3].includes(key)) {
1384
- return;
1385
- }
1386
- if (!isAttribute && !isOperator(key)) {
1387
- remove(key);
1388
- }
1389
- },
1390
- { schema }
1391
- ),
1925
+ traverseQueryFilters(({ key, attribute }, { remove }) => {
1926
+ const isAttribute = !!attribute;
1927
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1928
+ return;
1929
+ }
1930
+ if (!isAttribute && !isOperator(key)) {
1931
+ remove(key);
1932
+ }
1933
+ }, ctx),
1392
1934
  // Remove dynamic zones from filters
1393
- traverseQueryFilters(visitor$5, { schema }),
1935
+ traverseQueryFilters(visitor$5, ctx),
1394
1936
  // Remove morpTo relations from filters
1395
- traverseQueryFilters(visitor$6, { schema }),
1937
+ traverseQueryFilters(visitor$6, ctx),
1396
1938
  // Remove passwords from filters
1397
- traverseQueryFilters(visitor$8, { schema }),
1939
+ traverseQueryFilters(visitor$8, ctx),
1398
1940
  // Remove private from filters
1399
- traverseQueryFilters(visitor$7, { schema }),
1941
+ traverseQueryFilters(visitor$7, ctx),
1400
1942
  // Remove empty objects
1401
- traverseQueryFilters(
1402
- ({ key, value }, { remove }) => {
1403
- if (fp.isObject(value) && fp.isEmpty(value)) {
1404
- remove(key);
1405
- }
1406
- },
1407
- { schema }
1408
- )
1943
+ traverseQueryFilters(({ key, value }, { remove }) => {
1944
+ if (fp.isObject(value) && fp.isEmpty(value)) {
1945
+ remove(key);
1946
+ }
1947
+ }, ctx)
1409
1948
  )(filters2);
1410
1949
  });
1411
- const defaultSanitizeSort = fp.curry((schema, sort2) => {
1412
- if (!schema) {
1950
+ const defaultSanitizeSort = fp.curry((ctx, sort2) => {
1951
+ if (!ctx.schema) {
1413
1952
  throw new Error("Missing schema in defaultSanitizeSort");
1414
1953
  }
1415
1954
  return pipe(
1416
1955
  // Remove non attribute keys
1417
- traverseQuerySort(
1418
- ({ key, attribute }, { remove }) => {
1419
- if ([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3].includes(key)) {
1420
- return;
1421
- }
1422
- if (!attribute) {
1423
- remove(key);
1424
- }
1425
- },
1426
- { schema }
1427
- ),
1956
+ traverseQuerySort(({ key, attribute }, { remove }) => {
1957
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1958
+ return;
1959
+ }
1960
+ if (!attribute) {
1961
+ remove(key);
1962
+ }
1963
+ }, ctx),
1428
1964
  // Remove dynamic zones from sort
1429
- traverseQuerySort(visitor$5, { schema }),
1965
+ traverseQuerySort(visitor$5, ctx),
1430
1966
  // Remove morpTo relations from sort
1431
- traverseQuerySort(visitor$6, { schema }),
1967
+ traverseQuerySort(visitor$6, ctx),
1432
1968
  // Remove private from sort
1433
- traverseQuerySort(visitor$7, { schema }),
1969
+ traverseQuerySort(visitor$7, ctx),
1434
1970
  // Remove passwords from filters
1435
- traverseQuerySort(visitor$8, { schema }),
1971
+ traverseQuerySort(visitor$8, ctx),
1436
1972
  // Remove keys for empty non-scalar values
1437
- traverseQuerySort(
1438
- ({ key, attribute, value }, { remove }) => {
1439
- if ([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3].includes(key)) {
1440
- return;
1441
- }
1442
- if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
1443
- remove(key);
1444
- }
1445
- },
1446
- { schema }
1447
- )
1973
+ traverseQuerySort(({ key, attribute, value }, { remove }) => {
1974
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1975
+ return;
1976
+ }
1977
+ if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
1978
+ remove(key);
1979
+ }
1980
+ }, ctx)
1448
1981
  )(sort2);
1449
1982
  });
1450
- const defaultSanitizeFields = fp.curry((schema, fields2) => {
1451
- if (!schema) {
1983
+ const defaultSanitizeFields = fp.curry((ctx, fields2) => {
1984
+ if (!ctx.schema) {
1452
1985
  throw new Error("Missing schema in defaultSanitizeFields");
1453
1986
  }
1454
1987
  return pipe(
1455
1988
  // Only keep scalar attributes
1456
- traverseQueryFields(
1457
- ({ key, attribute }, { remove }) => {
1458
- if ([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3].includes(key)) {
1459
- return;
1460
- }
1461
- if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
1462
- remove(key);
1463
- }
1464
- },
1465
- { schema }
1466
- ),
1989
+ traverseQueryFields(({ key, attribute }, { remove }) => {
1990
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1991
+ return;
1992
+ }
1993
+ if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
1994
+ remove(key);
1995
+ }
1996
+ }, ctx),
1467
1997
  // Remove private fields
1468
- traverseQueryFields(visitor$7, { schema }),
1998
+ traverseQueryFields(visitor$7, ctx),
1469
1999
  // Remove password fields
1470
- traverseQueryFields(visitor$8, { schema }),
2000
+ traverseQueryFields(visitor$8, ctx),
1471
2001
  // Remove nil values from fields array
1472
2002
  (value) => fp.isArray(value) ? value.filter((field) => !fp.isNil(field)) : value
1473
2003
  )(fields2);
1474
2004
  });
1475
- const defaultSanitizePopulate = fp.curry((schema, populate2) => {
1476
- if (!schema) {
2005
+ const defaultSanitizePopulate = fp.curry((ctx, populate2) => {
2006
+ if (!ctx.schema) {
1477
2007
  throw new Error("Missing schema in defaultSanitizePopulate");
1478
2008
  }
1479
2009
  return pipe(
1480
- traverseQueryPopulate(visitor$4, { schema }),
1481
- traverseQueryPopulate(
1482
- async ({ key, value, schema: schema2, attribute }, { set }) => {
1483
- if (attribute) {
1484
- return;
1485
- }
1486
- if (key === "sort") {
1487
- set(key, await defaultSanitizeSort(schema2, value));
1488
- }
1489
- if (key === "filters") {
1490
- set(key, await defaultSanitizeFilters(schema2, value));
1491
- }
1492
- if (key === "fields") {
1493
- set(key, await defaultSanitizeFields(schema2, value));
1494
- }
1495
- if (key === "populate") {
1496
- set(key, await defaultSanitizePopulate(schema2, value));
1497
- }
1498
- },
1499
- { schema }
1500
- ),
2010
+ traverseQueryPopulate(visitor$4, ctx),
2011
+ traverseQueryPopulate(async ({ key, value, schema, attribute, getModel }, { set }) => {
2012
+ if (attribute) {
2013
+ return;
2014
+ }
2015
+ if (key === "sort") {
2016
+ set(key, await defaultSanitizeSort({ schema, getModel }, value));
2017
+ }
2018
+ if (key === "filters") {
2019
+ set(key, await defaultSanitizeFilters({ schema, getModel }, value));
2020
+ }
2021
+ if (key === "fields") {
2022
+ set(key, await defaultSanitizeFields({ schema, getModel }, value));
2023
+ }
2024
+ if (key === "populate") {
2025
+ set(key, await defaultSanitizePopulate({ schema, getModel }, value));
2026
+ }
2027
+ }, ctx),
1501
2028
  // Remove private fields
1502
- traverseQueryPopulate(visitor$7, { schema })
2029
+ traverseQueryPopulate(visitor$7, ctx)
1503
2030
  )(populate2);
1504
2031
  });
1505
2032
  const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -1511,7 +2038,8 @@ const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
1511
2038
  defaultSanitizeSort,
1512
2039
  sanitizePasswords
1513
2040
  }, Symbol.toStringTag, { value: "Module" }));
1514
- const createContentAPISanitizers = () => {
2041
+ const createAPISanitizers = (opts) => {
2042
+ const { getModel } = opts;
1515
2043
  const sanitizeInput = (data, schema, { auth } = {}) => {
1516
2044
  if (!schema) {
1517
2045
  throw new Error("Missing schema in sanitizeInput");
@@ -1525,12 +2053,14 @@ const createContentAPISanitizers = () => {
1525
2053
  fp.omit(constants$1.ID_ATTRIBUTE),
1526
2054
  fp.omit(constants$1.DOC_ID_ATTRIBUTE),
1527
2055
  // Remove non-writable attributes
1528
- traverseEntity$1(removeRestrictedFields(nonWritableAttributes), { schema })
2056
+ traverseEntity$1(removeRestrictedFields(nonWritableAttributes), { schema, getModel })
1529
2057
  ];
1530
2058
  if (auth) {
1531
- transforms.push(traverseEntity$1(removeRestrictedRelations(auth), { schema }));
2059
+ transforms.push(
2060
+ traverseEntity$1(removeRestrictedRelations(auth), { schema, getModel })
2061
+ );
1532
2062
  }
1533
- strapi.sanitizers.get("content-api.input").forEach((sanitizer) => transforms.push(sanitizer(schema)));
2063
+ opts?.sanitizers?.input?.forEach((sanitizer) => transforms.push(sanitizer(schema)));
1534
2064
  return pipe(...transforms)(data);
1535
2065
  };
1536
2066
  const sanitizeOutput = async (data, schema, { auth } = {}) => {
@@ -1544,11 +2074,15 @@ const createContentAPISanitizers = () => {
1544
2074
  }
1545
2075
  return res;
1546
2076
  }
1547
- const transforms = [(data2) => defaultSanitizeOutput(schema, data2)];
2077
+ const transforms = [
2078
+ (data2) => defaultSanitizeOutput({ schema, getModel }, data2)
2079
+ ];
1548
2080
  if (auth) {
1549
- transforms.push(traverseEntity$1(removeRestrictedRelations(auth), { schema }));
2081
+ transforms.push(
2082
+ traverseEntity$1(removeRestrictedRelations(auth), { schema, getModel })
2083
+ );
1550
2084
  }
1551
- strapi.sanitizers.get("content-api.output").forEach((sanitizer) => transforms.push(sanitizer(schema)));
2085
+ opts?.sanitizers?.output?.forEach((sanitizer) => transforms.push(sanitizer(schema)));
1552
2086
  return pipe(...transforms)(data);
1553
2087
  };
1554
2088
  const sanitizeQuery = async (query, schema, { auth } = {}) => {
@@ -1578,9 +2112,11 @@ const createContentAPISanitizers = () => {
1578
2112
  if (fp.isArray(filters2)) {
1579
2113
  return Promise.all(filters2.map((filter) => sanitizeFilters(filter, schema, { auth })));
1580
2114
  }
1581
- const transforms = [defaultSanitizeFilters(schema)];
2115
+ const transforms = [defaultSanitizeFilters({ schema, getModel })];
1582
2116
  if (auth) {
1583
- transforms.push(traverseQueryFilters(removeRestrictedRelations(auth), { schema }));
2117
+ transforms.push(
2118
+ traverseQueryFilters(removeRestrictedRelations(auth), { schema, getModel })
2119
+ );
1584
2120
  }
1585
2121
  return pipe(...transforms)(filters2);
1586
2122
  };
@@ -1588,9 +2124,11 @@ const createContentAPISanitizers = () => {
1588
2124
  if (!schema) {
1589
2125
  throw new Error("Missing schema in sanitizeSort");
1590
2126
  }
1591
- const transforms = [defaultSanitizeSort(schema)];
2127
+ const transforms = [defaultSanitizeSort({ schema, getModel })];
1592
2128
  if (auth) {
1593
- transforms.push(traverseQuerySort(removeRestrictedRelations(auth), { schema }));
2129
+ transforms.push(
2130
+ traverseQuerySort(removeRestrictedRelations(auth), { schema, getModel })
2131
+ );
1594
2132
  }
1595
2133
  return pipe(...transforms)(sort2);
1596
2134
  };
@@ -1598,16 +2136,18 @@ const createContentAPISanitizers = () => {
1598
2136
  if (!schema) {
1599
2137
  throw new Error("Missing schema in sanitizeFields");
1600
2138
  }
1601
- const transforms = [defaultSanitizeFields(schema)];
2139
+ const transforms = [defaultSanitizeFields({ schema, getModel })];
1602
2140
  return pipe(...transforms)(fields2);
1603
2141
  };
1604
2142
  const sanitizePopulate = (populate2, schema, { auth } = {}) => {
1605
2143
  if (!schema) {
1606
2144
  throw new Error("Missing schema in sanitizePopulate");
1607
2145
  }
1608
- const transforms = [defaultSanitizePopulate(schema)];
2146
+ const transforms = [defaultSanitizePopulate({ schema, getModel })];
1609
2147
  if (auth) {
1610
- transforms.push(traverseQueryPopulate(removeRestrictedRelations(auth), { schema }));
2148
+ transforms.push(
2149
+ traverseQueryPopulate(removeRestrictedRelations(auth), { schema, getModel })
2150
+ );
1611
2151
  }
1612
2152
  return pipe(...transforms)(populate2);
1613
2153
  };
@@ -1621,118 +2161,11 @@ const createContentAPISanitizers = () => {
1621
2161
  populate: sanitizePopulate
1622
2162
  };
1623
2163
  };
1624
- const contentAPI$1 = createContentAPISanitizers();
1625
- const index$1 = {
1626
- contentAPI: contentAPI$1,
1627
- sanitizers,
1628
- visitors: visitors$1
1629
- };
1630
- const formatYupInnerError = (yupError) => ({
1631
- path: fp.toPath(yupError.path),
1632
- message: yupError.message,
1633
- name: yupError.name
1634
- });
1635
- const formatYupErrors = (yupError) => ({
1636
- errors: fp.isEmpty(yupError.inner) ? [formatYupInnerError(yupError)] : yupError.inner.map(formatYupInnerError),
1637
- message: yupError.message
1638
- });
1639
- class ApplicationError extends Error {
1640
- name;
1641
- details;
1642
- message;
1643
- constructor(message = "An application error occured", details = {}) {
1644
- super();
1645
- this.name = "ApplicationError";
1646
- this.message = message;
1647
- this.details = details;
1648
- }
1649
- }
1650
- class ValidationError extends ApplicationError {
1651
- constructor(message, details) {
1652
- super(message, details);
1653
- this.name = "ValidationError";
1654
- }
1655
- }
1656
- class YupValidationError extends ValidationError {
1657
- constructor(yupError, message) {
1658
- super("Validation");
1659
- const { errors: errors2, message: yupMessage } = formatYupErrors(yupError);
1660
- this.message = message || yupMessage;
1661
- this.details = { errors: errors2 };
1662
- }
1663
- }
1664
- class PaginationError extends ApplicationError {
1665
- constructor(message = "Invalid pagination", details) {
1666
- super(message, details);
1667
- this.name = "PaginationError";
1668
- this.message = message;
1669
- }
1670
- }
1671
- class NotFoundError extends ApplicationError {
1672
- constructor(message = "Entity not found", details) {
1673
- super(message, details);
1674
- this.name = "NotFoundError";
1675
- this.message = message;
1676
- }
1677
- }
1678
- class ForbiddenError extends ApplicationError {
1679
- constructor(message = "Forbidden access", details) {
1680
- super(message, details);
1681
- this.name = "ForbiddenError";
1682
- this.message = message;
1683
- }
1684
- }
1685
- class UnauthorizedError extends ApplicationError {
1686
- constructor(message = "Unauthorized", details) {
1687
- super(message, details);
1688
- this.name = "UnauthorizedError";
1689
- this.message = message;
1690
- }
1691
- }
1692
- class RateLimitError extends ApplicationError {
1693
- constructor(message = "Too many requests, please try again later.", details) {
1694
- super(message, details);
1695
- this.name = "RateLimitError";
1696
- this.message = message;
1697
- this.details = details || {};
1698
- }
1699
- }
1700
- class PayloadTooLargeError extends ApplicationError {
1701
- constructor(message = "Entity too large", details) {
1702
- super(message, details);
1703
- this.name = "PayloadTooLargeError";
1704
- this.message = message;
1705
- }
1706
- }
1707
- class PolicyError extends ForbiddenError {
1708
- constructor(message = "Policy Failed", details) {
1709
- super(message, details);
1710
- this.name = "PolicyError";
1711
- this.message = message;
1712
- this.details = details || {};
1713
- }
1714
- }
1715
- class NotImplementedError extends ApplicationError {
1716
- constructor(message = "This feature is not implemented yet", details) {
1717
- super(message, details);
1718
- this.name = "NotImplementedError";
1719
- this.message = message;
1720
- }
1721
- }
1722
- const errors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2164
+ const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1723
2165
  __proto__: null,
1724
- ApplicationError,
1725
- ForbiddenError,
1726
- HttpError: httpErrors.HttpError,
1727
- NotFoundError,
1728
- NotImplementedError,
1729
- PaginationError,
1730
- PayloadTooLargeError,
1731
- PolicyError,
1732
- RateLimitError,
1733
- UnauthorizedError,
1734
- ValidationError,
1735
- YupValidationError
2166
+ createAPISanitizers,
2167
+ sanitizers,
2168
+ visitors: index$4
1736
2169
  }, Symbol.toStringTag, { value: "Module" }));
1737
2170
  const throwInvalidParam = ({ key, path }) => {
1738
2171
  const msg = path && path !== key ? `Invalid parameter ${key} at ${path}` : `Invalid parameter ${key}`;
@@ -1855,7 +2288,7 @@ const throwRestrictedFields = (restrictedFields = null) => ({ key, path: { attri
1855
2288
  throwInvalidParam({ key, path });
1856
2289
  }
1857
2290
  };
1858
- const visitors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2291
+ const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1859
2292
  __proto__: null,
1860
2293
  throwDisallowedFields,
1861
2294
  throwDynamicZones: visitor,
@@ -1865,131 +2298,152 @@ const visitors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
1865
2298
  throwRestrictedFields,
1866
2299
  throwRestrictedRelations
1867
2300
  }, Symbol.toStringTag, { value: "Module" }));
1868
- const { ID_ATTRIBUTE: ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$2 } = constants$1;
1869
- const throwPasswords = (schema) => async (entity) => {
1870
- if (!schema) {
2301
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$1 } = constants$1;
2302
+ const throwPasswords = (ctx) => async (entity) => {
2303
+ if (!ctx.schema) {
1871
2304
  throw new Error("Missing schema in throwPasswords");
1872
2305
  }
1873
- return traverseEntity$1(visitor$3, { schema }, entity);
2306
+ return traverseEntity$1(visitor$3, ctx, entity);
1874
2307
  };
1875
- const defaultValidateFilters = fp.curry((schema, filters2) => {
1876
- if (!schema) {
2308
+ const defaultValidateFilters = fp.curry((ctx, filters2) => {
2309
+ if (!ctx.schema) {
1877
2310
  throw new Error("Missing schema in defaultValidateFilters");
1878
2311
  }
1879
2312
  return pipe(
1880
2313
  // keys that are not attributes or valid operators
1881
- traverseQueryFilters(
1882
- ({ key, attribute, path }) => {
1883
- if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1884
- return;
1885
- }
1886
- const isAttribute = !!attribute;
1887
- if (!isAttribute && !isOperator(key)) {
1888
- throwInvalidParam({ key, path: path.attribute });
1889
- }
1890
- },
1891
- { schema }
1892
- ),
2314
+ traverseQueryFilters(({ key, attribute, path }) => {
2315
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2316
+ return;
2317
+ }
2318
+ const isAttribute = !!attribute;
2319
+ if (!isAttribute && !isOperator(key)) {
2320
+ throwInvalidParam({ key, path: path.attribute });
2321
+ }
2322
+ }, ctx),
1893
2323
  // dynamic zones from filters
1894
- traverseQueryFilters(visitor, { schema }),
2324
+ traverseQueryFilters(visitor, ctx),
1895
2325
  // morphTo relations from filters; because you can't have deep filtering on morph relations
1896
- traverseQueryFilters(visitor$1, { schema }),
2326
+ traverseQueryFilters(visitor$1, ctx),
1897
2327
  // passwords from filters
1898
- traverseQueryFilters(visitor$3, { schema }),
2328
+ traverseQueryFilters(visitor$3, ctx),
1899
2329
  // private from filters
1900
- traverseQueryFilters(visitor$2, { schema })
2330
+ traverseQueryFilters(visitor$2, ctx)
1901
2331
  // we allow empty objects to validate and only sanitize them out, so that users may write "lazy" queries without checking their params exist
1902
2332
  )(filters2);
1903
2333
  });
1904
- const defaultValidateSort = fp.curry((schema, sort2) => {
1905
- if (!schema) {
2334
+ const defaultValidateSort = fp.curry((ctx, sort2) => {
2335
+ if (!ctx.schema) {
1906
2336
  throw new Error("Missing schema in defaultValidateSort");
1907
2337
  }
1908
2338
  return pipe(
1909
2339
  // non attribute keys
1910
- traverseQuerySort(
1911
- ({ key, attribute, path }) => {
1912
- if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1913
- return;
1914
- }
1915
- if (!attribute) {
1916
- throwInvalidParam({ key, path: path.attribute });
1917
- }
1918
- },
1919
- { schema }
1920
- ),
2340
+ traverseQuerySort(({ key, attribute, path }) => {
2341
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2342
+ return;
2343
+ }
2344
+ if (!attribute) {
2345
+ throwInvalidParam({ key, path: path.attribute });
2346
+ }
2347
+ }, ctx),
1921
2348
  // dynamic zones from sort
1922
- traverseQuerySort(visitor, { schema }),
2349
+ traverseQuerySort(visitor, ctx),
1923
2350
  // morphTo relations from sort
1924
- traverseQuerySort(visitor$1, { schema }),
2351
+ traverseQuerySort(visitor$1, ctx),
1925
2352
  // private from sort
1926
- traverseQuerySort(visitor$2, { schema }),
2353
+ traverseQuerySort(visitor$2, ctx),
1927
2354
  // passwords from filters
1928
- traverseQuerySort(visitor$3, { schema }),
2355
+ traverseQuerySort(visitor$3, ctx),
1929
2356
  // keys for empty non-scalar values
1930
- traverseQuerySort(
1931
- ({ key, attribute, value, path }) => {
1932
- if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1933
- return;
1934
- }
1935
- if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
1936
- throwInvalidParam({ key, path: path.attribute });
1937
- }
1938
- },
1939
- { schema }
1940
- )
2357
+ traverseQuerySort(({ key, attribute, value, path }) => {
2358
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2359
+ return;
2360
+ }
2361
+ if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
2362
+ throwInvalidParam({ key, path: path.attribute });
2363
+ }
2364
+ }, ctx)
1941
2365
  )(sort2);
1942
2366
  });
1943
- const defaultValidateFields = fp.curry((schema, fields2) => {
1944
- if (!schema) {
2367
+ const defaultValidateFields = fp.curry((ctx, fields2) => {
2368
+ if (!ctx.schema) {
1945
2369
  throw new Error("Missing schema in defaultValidateFields");
1946
2370
  }
1947
2371
  return pipe(
1948
2372
  // Only allow scalar attributes
1949
- traverseQueryFields(
1950
- ({ key, attribute, path }) => {
1951
- if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1952
- return;
1953
- }
1954
- if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
1955
- throwInvalidParam({ key, path: path.attribute });
1956
- }
1957
- },
1958
- { schema }
1959
- ),
2373
+ traverseQueryFields(({ key, attribute, path }) => {
2374
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2375
+ return;
2376
+ }
2377
+ if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
2378
+ throwInvalidParam({ key, path: path.attribute });
2379
+ }
2380
+ }, ctx),
1960
2381
  // private fields
1961
- traverseQueryFields(visitor$2, { schema }),
2382
+ traverseQueryFields(visitor$2, ctx),
1962
2383
  // password fields
1963
- traverseQueryFields(visitor$3, { schema })
2384
+ traverseQueryFields(visitor$3, ctx)
1964
2385
  )(fields2);
1965
2386
  });
1966
- const defaultValidatePopulate = fp.curry((schema, populate2) => {
1967
- if (!schema) {
2387
+ const defaultValidatePopulate = fp.curry((ctx, populate2) => {
2388
+ if (!ctx.schema) {
1968
2389
  throw new Error("Missing schema in defaultValidatePopulate");
1969
2390
  }
1970
2391
  return pipe(
1971
- traverseQueryPopulate(
1972
- async ({ key, value, schema: schema2, attribute }, { set }) => {
1973
- if (attribute) {
1974
- return;
1975
- }
1976
- if (key === "sort") {
1977
- set(key, await defaultValidateSort(schema2, value));
1978
- }
1979
- if (key === "filters") {
1980
- set(key, await defaultValidateFilters(schema2, value));
1981
- }
1982
- if (key === "fields") {
1983
- set(key, await defaultValidateFields(schema2, value));
1984
- }
1985
- if (key === "populate") {
1986
- set(key, await defaultValidatePopulate(schema2, value));
1987
- }
1988
- },
1989
- { schema }
1990
- ),
2392
+ traverseQueryPopulate(async ({ key, value, schema, attribute, getModel }, { set }) => {
2393
+ if (attribute) {
2394
+ return;
2395
+ }
2396
+ if (key === "sort") {
2397
+ set(
2398
+ key,
2399
+ await defaultValidateSort(
2400
+ {
2401
+ schema,
2402
+ getModel
2403
+ },
2404
+ value
2405
+ )
2406
+ );
2407
+ }
2408
+ if (key === "filters") {
2409
+ set(
2410
+ key,
2411
+ await defaultValidateFilters(
2412
+ {
2413
+ schema,
2414
+ getModel
2415
+ },
2416
+ value
2417
+ )
2418
+ );
2419
+ }
2420
+ if (key === "fields") {
2421
+ set(
2422
+ key,
2423
+ await defaultValidateFields(
2424
+ {
2425
+ schema,
2426
+ getModel
2427
+ },
2428
+ value
2429
+ )
2430
+ );
2431
+ }
2432
+ if (key === "populate") {
2433
+ set(
2434
+ key,
2435
+ await defaultValidatePopulate(
2436
+ {
2437
+ schema,
2438
+ getModel
2439
+ },
2440
+ value
2441
+ )
2442
+ );
2443
+ }
2444
+ }, ctx),
1991
2445
  // Remove private fields
1992
- traverseQueryPopulate(visitor$2, { schema })
2446
+ traverseQueryPopulate(visitor$2, ctx)
1993
2447
  )(populate2);
1994
2448
  });
1995
2449
  const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -2000,8 +2454,9 @@ const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
2000
2454
  defaultValidateSort,
2001
2455
  throwPasswords
2002
2456
  }, Symbol.toStringTag, { value: "Module" }));
2003
- const { ID_ATTRIBUTE: ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$1 } = constants$1;
2004
- const createContentAPIValidators = () => {
2457
+ const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants$1;
2458
+ const createAPIValidators = (opts) => {
2459
+ const { getModel } = opts || {};
2005
2460
  const validateInput = async (data, schema, { auth } = {}) => {
2006
2461
  if (!schema) {
2007
2462
  throw new Error("Missing schema in validateInput");
@@ -2014,21 +2469,26 @@ const createContentAPIValidators = () => {
2014
2469
  const transforms = [
2015
2470
  (data2) => {
2016
2471
  if (fp.isObject(data2)) {
2017
- if (ID_ATTRIBUTE$1 in data2) {
2018
- throwInvalidParam({ key: ID_ATTRIBUTE$1 });
2472
+ if (ID_ATTRIBUTE in data2) {
2473
+ throwInvalidParam({ key: ID_ATTRIBUTE });
2019
2474
  }
2020
- if (DOC_ID_ATTRIBUTE$1 in data2) {
2021
- throwInvalidParam({ key: DOC_ID_ATTRIBUTE$1 });
2475
+ if (DOC_ID_ATTRIBUTE in data2) {
2476
+ throwInvalidParam({ key: DOC_ID_ATTRIBUTE });
2022
2477
  }
2023
2478
  }
2024
2479
  },
2025
2480
  // non-writable attributes
2026
- traverseEntity$1(throwRestrictedFields(nonWritableAttributes), { schema })
2481
+ traverseEntity$1(throwRestrictedFields(nonWritableAttributes), { schema, getModel })
2027
2482
  ];
2028
2483
  if (auth) {
2029
- transforms.push(traverseEntity$1(throwRestrictedRelations(auth), { schema }));
2030
- }
2031
- strapi.validators.get("content-api.input").forEach((validator) => transforms.push(validator(schema)));
2484
+ transforms.push(
2485
+ traverseEntity$1(throwRestrictedRelations(auth), {
2486
+ schema,
2487
+ getModel
2488
+ })
2489
+ );
2490
+ }
2491
+ opts?.validators?.input?.forEach((validator) => transforms.push(validator(schema)));
2032
2492
  await pipe(...transforms)(data);
2033
2493
  };
2034
2494
  const validateQuery = async (query, schema, { auth } = {}) => {
@@ -2057,9 +2517,14 @@ const createContentAPIValidators = () => {
2057
2517
  await Promise.all(filters2.map((filter) => validateFilters(filter, schema, { auth })));
2058
2518
  return;
2059
2519
  }
2060
- const transforms = [defaultValidateFilters(schema)];
2520
+ const transforms = [defaultValidateFilters({ schema, getModel })];
2061
2521
  if (auth) {
2062
- transforms.push(traverseQueryFilters(throwRestrictedRelations(auth), { schema }));
2522
+ transforms.push(
2523
+ traverseQueryFilters(throwRestrictedRelations(auth), {
2524
+ schema,
2525
+ getModel
2526
+ })
2527
+ );
2063
2528
  }
2064
2529
  await pipe(...transforms)(filters2);
2065
2530
  };
@@ -2067,9 +2532,14 @@ const createContentAPIValidators = () => {
2067
2532
  if (!schema) {
2068
2533
  throw new Error("Missing schema in validateSort");
2069
2534
  }
2070
- const transforms = [defaultValidateSort(schema)];
2535
+ const transforms = [defaultValidateSort({ schema, getModel })];
2071
2536
  if (auth) {
2072
- transforms.push(traverseQuerySort(throwRestrictedRelations(auth), { schema }));
2537
+ transforms.push(
2538
+ traverseQuerySort(throwRestrictedRelations(auth), {
2539
+ schema,
2540
+ getModel
2541
+ })
2542
+ );
2073
2543
  }
2074
2544
  await pipe(...transforms)(sort2);
2075
2545
  };
@@ -2077,16 +2547,21 @@ const createContentAPIValidators = () => {
2077
2547
  if (!schema) {
2078
2548
  throw new Error("Missing schema in validateFields");
2079
2549
  }
2080
- const transforms = [defaultValidateFields(schema)];
2550
+ const transforms = [defaultValidateFields({ schema, getModel })];
2081
2551
  await pipe(...transforms)(fields2);
2082
2552
  };
2083
2553
  const validatePopulate = async (populate2, schema, { auth } = {}) => {
2084
2554
  if (!schema) {
2085
2555
  throw new Error("Missing schema in sanitizePopulate");
2086
2556
  }
2087
- const transforms = [defaultValidatePopulate(schema)];
2557
+ const transforms = [defaultValidatePopulate({ schema, getModel })];
2088
2558
  if (auth) {
2089
- transforms.push(traverseQueryPopulate(throwRestrictedRelations(auth), { schema }));
2559
+ transforms.push(
2560
+ traverseQueryPopulate(throwRestrictedRelations(auth), {
2561
+ schema,
2562
+ getModel
2563
+ })
2564
+ );
2090
2565
  }
2091
2566
  await pipe(...transforms)(populate2);
2092
2567
  };
@@ -2099,436 +2574,12 @@ const createContentAPIValidators = () => {
2099
2574
  populate: validatePopulate
2100
2575
  };
2101
2576
  };
2102
- const contentAPI = createContentAPIValidators();
2103
- const index = {
2104
- contentAPI,
2577
+ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2578
+ __proto__: null,
2579
+ createAPIValidators,
2105
2580
  validators,
2106
- visitors
2107
- };
2108
- const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE, PUBLISHED_AT_ATTRIBUTE } = constants$1;
2109
- class InvalidOrderError extends Error {
2110
- constructor() {
2111
- super();
2112
- this.message = "Invalid order. order can only be one of asc|desc|ASC|DESC";
2113
- }
2114
- }
2115
- class InvalidSortError extends Error {
2116
- constructor() {
2117
- super();
2118
- this.message = "Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects";
2119
- }
2120
- }
2121
- function validateOrder(order) {
2122
- if (!fp.isString(order) || !["asc", "desc"].includes(order.toLocaleLowerCase())) {
2123
- throw new InvalidOrderError();
2124
- }
2125
- }
2126
- const convertCountQueryParams = (countQuery) => {
2127
- return parseType({ type: "boolean", value: countQuery });
2128
- };
2129
- const convertOrderingQueryParams = (ordering) => {
2130
- return ordering;
2131
- };
2132
- const isPlainObject = (value) => ___default.default.isPlainObject(value);
2133
- const isStringArray = (value) => fp.isArray(value) && value.every(fp.isString);
2134
- const convertSortQueryParams = (sortQuery) => {
2135
- if (typeof sortQuery === "string") {
2136
- return convertStringSortQueryParam(sortQuery);
2137
- }
2138
- if (isStringArray(sortQuery)) {
2139
- return sortQuery.flatMap((sortValue) => convertStringSortQueryParam(sortValue));
2140
- }
2141
- if (Array.isArray(sortQuery)) {
2142
- return sortQuery.map((sortValue) => convertNestedSortQueryParam(sortValue));
2143
- }
2144
- if (isPlainObject(sortQuery)) {
2145
- return convertNestedSortQueryParam(sortQuery);
2146
- }
2147
- throw new InvalidSortError();
2148
- };
2149
- const convertStringSortQueryParam = (sortQuery) => {
2150
- return sortQuery.split(",").map((value) => convertSingleSortQueryParam(value));
2151
- };
2152
- const convertSingleSortQueryParam = (sortQuery) => {
2153
- if (!sortQuery) {
2154
- return {};
2155
- }
2156
- if (!fp.isString(sortQuery)) {
2157
- throw new Error("Invalid sort query");
2158
- }
2159
- const [field, order = "asc"] = sortQuery.split(":");
2160
- if (field.length === 0) {
2161
- throw new Error("Field cannot be empty");
2162
- }
2163
- validateOrder(order);
2164
- return ___default.default.set({}, field, order);
2165
- };
2166
- const convertNestedSortQueryParam = (sortQuery) => {
2167
- const transformedSort = {};
2168
- for (const field of Object.keys(sortQuery)) {
2169
- const order = sortQuery[field];
2170
- if (isPlainObject(order)) {
2171
- transformedSort[field] = convertNestedSortQueryParam(order);
2172
- } else if (typeof order === "string") {
2173
- validateOrder(order);
2174
- transformedSort[field] = order;
2175
- } else {
2176
- throw Error(`Invalid sort type expected object or string got ${typeof order}`);
2177
- }
2178
- }
2179
- return transformedSort;
2180
- };
2181
- const convertStartQueryParams = (startQuery) => {
2182
- const startAsANumber = ___default.default.toNumber(startQuery);
2183
- if (!___default.default.isInteger(startAsANumber) || startAsANumber < 0) {
2184
- throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
2185
- }
2186
- return startAsANumber;
2187
- };
2188
- const convertLimitQueryParams = (limitQuery) => {
2189
- const limitAsANumber = ___default.default.toNumber(limitQuery);
2190
- if (!___default.default.isInteger(limitAsANumber) || limitAsANumber !== -1 && limitAsANumber < 0) {
2191
- throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
2192
- }
2193
- if (limitAsANumber === -1) {
2194
- return void 0;
2195
- }
2196
- return limitAsANumber;
2197
- };
2198
- const convertPageQueryParams = (page) => {
2199
- const pageVal = fp.toNumber(page);
2200
- if (!fp.isInteger(pageVal) || pageVal <= 0) {
2201
- throw new PaginationError(
2202
- `Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
2203
- );
2204
- }
2205
- return pageVal;
2206
- };
2207
- const convertPageSizeQueryParams = (pageSize, page) => {
2208
- const pageSizeVal = fp.toNumber(pageSize);
2209
- if (!fp.isInteger(pageSizeVal) || pageSizeVal <= 0) {
2210
- throw new PaginationError(
2211
- `Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
2212
- );
2213
- }
2214
- return pageSizeVal;
2215
- };
2216
- const validatePaginationParams = (page, pageSize, start, limit) => {
2217
- const isPagePagination = !fp.isNil(page) || !fp.isNil(pageSize);
2218
- const isOffsetPagination = !fp.isNil(start) || !fp.isNil(limit);
2219
- if (isPagePagination && isOffsetPagination) {
2220
- throw new PaginationError(
2221
- "Invalid pagination attributes. You cannot use page and offset pagination in the same query"
2222
- );
2223
- }
2224
- };
2225
- class InvalidPopulateError extends Error {
2226
- constructor() {
2227
- super();
2228
- this.message = "Invalid populate parameter. Expected a string, an array of strings, a populate object";
2229
- }
2230
- }
2231
- const convertPopulateQueryParams = (populate2, schema, depth = 0) => {
2232
- if (depth === 0 && populate2 === "*") {
2233
- return true;
2234
- }
2235
- if (typeof populate2 === "string") {
2236
- return populate2.split(",").map((value) => ___default.default.trim(value));
2237
- }
2238
- if (Array.isArray(populate2)) {
2239
- return ___default.default.uniq(
2240
- populate2.flatMap((value) => {
2241
- if (typeof value !== "string") {
2242
- throw new InvalidPopulateError();
2243
- }
2244
- return value.split(",").map((value2) => ___default.default.trim(value2));
2245
- })
2246
- );
2247
- }
2248
- if (___default.default.isPlainObject(populate2)) {
2249
- return convertPopulateObject(populate2, schema);
2250
- }
2251
- throw new InvalidPopulateError();
2252
- };
2253
- const hasFragmentPopulateDefined = (populate2) => {
2254
- return typeof populate2 === "object" && "on" in populate2 && !fp.isNil(populate2.on);
2255
- };
2256
- const convertPopulateObject = (populate2, schema) => {
2257
- if (!schema) {
2258
- return {};
2259
- }
2260
- const { attributes } = schema;
2261
- return Object.entries(populate2).reduce((acc, [key, subPopulate]) => {
2262
- if (___default.default.isBoolean(subPopulate)) {
2263
- return { ...acc, [key]: subPopulate };
2264
- }
2265
- const attribute = attributes[key];
2266
- if (!attribute) {
2267
- return acc;
2268
- }
2269
- const isAllowedAttributeForFragmentPopulate = isDynamicZoneAttribute(attribute) || isMorphToRelationalAttribute(attribute);
2270
- if (isAllowedAttributeForFragmentPopulate && hasFragmentPopulateDefined(subPopulate)) {
2271
- return {
2272
- ...acc,
2273
- [key]: {
2274
- on: Object.entries(subPopulate.on).reduce(
2275
- (acc2, [type, typeSubPopulate]) => ({
2276
- ...acc2,
2277
- [type]: convertNestedPopulate(typeSubPopulate, strapi.getModel(type))
2278
- }),
2279
- {}
2280
- )
2281
- }
2282
- };
2283
- }
2284
- if (isDynamicZoneAttribute(attribute)) {
2285
- const populates = attribute.components.map((uid) => strapi.getModel(uid)).map((schema2) => convertNestedPopulate(subPopulate, schema2)).map((populate22) => populate22 === true ? {} : populate22).filter((populate22) => populate22 !== false);
2286
- if (fp.isEmpty(populates)) {
2287
- return acc;
2288
- }
2289
- return {
2290
- ...acc,
2291
- [key]: fp.mergeAll(populates)
2292
- };
2293
- }
2294
- if (isMorphToRelationalAttribute(attribute)) {
2295
- return { ...acc, [key]: convertNestedPopulate(subPopulate, void 0) };
2296
- }
2297
- let targetSchemaUID;
2298
- if (attribute.type === "relation") {
2299
- targetSchemaUID = attribute.target;
2300
- } else if (attribute.type === "component") {
2301
- targetSchemaUID = attribute.component;
2302
- } else if (attribute.type === "media") {
2303
- targetSchemaUID = "plugin::upload.file";
2304
- } else {
2305
- return acc;
2306
- }
2307
- const targetSchema = strapi.getModel(targetSchemaUID);
2308
- if (!targetSchema) {
2309
- return acc;
2310
- }
2311
- const populateObject = convertNestedPopulate(subPopulate, targetSchema);
2312
- if (!populateObject) {
2313
- return acc;
2314
- }
2315
- return {
2316
- ...acc,
2317
- [key]: populateObject
2318
- };
2319
- }, {});
2320
- };
2321
- const convertNestedPopulate = (subPopulate, schema) => {
2322
- if (___default.default.isString(subPopulate)) {
2323
- return parseType({ type: "boolean", value: subPopulate, forceCast: true });
2324
- }
2325
- if (___default.default.isBoolean(subPopulate)) {
2326
- return subPopulate;
2327
- }
2328
- if (!isPlainObject(subPopulate)) {
2329
- throw new Error(`Invalid nested populate. Expected '*' or an object`);
2330
- }
2331
- const { sort: sort2, filters: filters2, fields: fields2, populate: populate2, count, ordering, page, pageSize, start, limit } = subPopulate;
2332
- const query = {};
2333
- if (sort2) {
2334
- query.orderBy = convertSortQueryParams(sort2);
2335
- }
2336
- if (filters2) {
2337
- query.where = convertFiltersQueryParams(filters2, schema);
2338
- }
2339
- if (fields2) {
2340
- query.select = convertFieldsQueryParams(fields2);
2341
- }
2342
- if (populate2) {
2343
- query.populate = convertPopulateQueryParams(populate2, schema);
2344
- }
2345
- if (count) {
2346
- query.count = convertCountQueryParams(count);
2347
- }
2348
- if (ordering) {
2349
- query.ordering = convertOrderingQueryParams(ordering);
2350
- }
2351
- validatePaginationParams(page, pageSize, start, limit);
2352
- if (!fp.isNil(page)) {
2353
- query.page = convertPageQueryParams(page);
2354
- }
2355
- if (!fp.isNil(pageSize)) {
2356
- query.pageSize = convertPageSizeQueryParams(pageSize, page);
2357
- }
2358
- if (!fp.isNil(start)) {
2359
- query.offset = convertStartQueryParams(start);
2360
- }
2361
- if (!fp.isNil(limit)) {
2362
- query.limit = convertLimitQueryParams(limit);
2363
- }
2364
- return query;
2365
- };
2366
- const convertFieldsQueryParams = (fields2, depth = 0) => {
2367
- if (depth === 0 && fields2 === "*") {
2368
- return void 0;
2369
- }
2370
- if (typeof fields2 === "string") {
2371
- const fieldsValues = fields2.split(",").map((value) => ___default.default.trim(value));
2372
- return ___default.default.uniq([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE, ...fieldsValues]);
2373
- }
2374
- if (isStringArray(fields2)) {
2375
- const fieldsValues = fields2.flatMap((value) => convertFieldsQueryParams(value, depth + 1)).filter((v) => !fp.isNil(v));
2376
- return ___default.default.uniq([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE, ...fieldsValues]);
2377
- }
2378
- throw new Error("Invalid fields parameter. Expected a string or an array of strings");
2379
- };
2380
- const isValidSchemaAttribute = (key, schema) => {
2381
- if ([DOC_ID_ATTRIBUTE, ID_ATTRIBUTE].includes(key)) {
2382
- return true;
2383
- }
2384
- if (!schema) {
2385
- return false;
2386
- }
2387
- return Object.keys(schema.attributes).includes(key);
2388
- };
2389
- const convertFiltersQueryParams = (filters2, schema) => {
2390
- if (!fp.isObject(filters2)) {
2391
- throw new Error("The filters parameter must be an object or an array");
2392
- }
2393
- const filtersCopy = fp.cloneDeep(filters2);
2394
- return convertAndSanitizeFilters(filtersCopy, schema);
2395
- };
2396
- const convertAndSanitizeFilters = (filters2, schema) => {
2397
- if (Array.isArray(filters2)) {
2398
- return filters2.map((filter) => convertAndSanitizeFilters(filter, schema)).filter((filter) => !isPlainObject(filter) || !fp.isEmpty(filter));
2399
- }
2400
- if (!isPlainObject(filters2)) {
2401
- return filters2;
2402
- }
2403
- const removeOperator = (operator) => delete filters2[operator];
2404
- for (const [key, value] of Object.entries(filters2)) {
2405
- const attribute = fp.get(key, schema?.attributes);
2406
- const validKey = isOperator(key) || isValidSchemaAttribute(key, schema);
2407
- if (!validKey) {
2408
- removeOperator(key);
2409
- } else if (attribute) {
2410
- if (attribute.type === "relation") {
2411
- filters2[key] = convertAndSanitizeFilters(value, strapi.getModel(attribute.target));
2412
- } else if (attribute.type === "component") {
2413
- filters2[key] = convertAndSanitizeFilters(value, strapi.getModel(attribute.component));
2414
- } else if (attribute.type === "media") {
2415
- filters2[key] = convertAndSanitizeFilters(value, strapi.getModel("plugin::upload.file"));
2416
- } else if (attribute.type === "dynamiczone") {
2417
- removeOperator(key);
2418
- } else if (attribute.type === "password") {
2419
- removeOperator(key);
2420
- } else {
2421
- filters2[key] = convertAndSanitizeFilters(value, schema);
2422
- }
2423
- } else if (["$null", "$notNull"].includes(key)) {
2424
- filters2[key] = parseType({ type: "boolean", value: filters2[key], forceCast: true });
2425
- } else if (fp.isObject(value)) {
2426
- filters2[key] = convertAndSanitizeFilters(value, schema);
2427
- }
2428
- if (isPlainObject(filters2[key]) && fp.isEmpty(filters2[key])) {
2429
- removeOperator(key);
2430
- }
2431
- }
2432
- return filters2;
2433
- };
2434
- const convertStatusParams = (status, query = {}) => {
2435
- query.filters = ({ meta }) => {
2436
- const contentType = strapi.contentTypes[meta.uid];
2437
- if (!contentType || !hasDraftAndPublish(contentType)) {
2438
- return {};
2439
- }
2440
- return { [PUBLISHED_AT_ATTRIBUTE]: { $null: status === "draft" } };
2441
- };
2442
- };
2443
- const transformParamsToQuery = (uid, params) => {
2444
- const schema = strapi.getModel(uid);
2445
- const query = {};
2446
- const { _q, sort: sort2, filters: filters2, fields: fields2, populate: populate2, page, pageSize, start, limit, status, ...rest } = params;
2447
- if (!fp.isNil(status)) {
2448
- convertStatusParams(status, query);
2449
- }
2450
- if (!fp.isNil(_q)) {
2451
- query._q = _q;
2452
- }
2453
- if (!fp.isNil(sort2)) {
2454
- query.orderBy = convertSortQueryParams(sort2);
2455
- }
2456
- if (!fp.isNil(filters2)) {
2457
- query.where = convertFiltersQueryParams(filters2, schema);
2458
- }
2459
- if (!fp.isNil(fields2)) {
2460
- query.select = convertFieldsQueryParams(fields2);
2461
- }
2462
- if (!fp.isNil(populate2)) {
2463
- query.populate = convertPopulateQueryParams(populate2, schema);
2464
- }
2465
- validatePaginationParams(page, pageSize, start, limit);
2466
- if (!fp.isNil(page)) {
2467
- query.page = convertPageQueryParams(page);
2468
- }
2469
- if (!fp.isNil(pageSize)) {
2470
- query.pageSize = convertPageSizeQueryParams(pageSize, page);
2471
- }
2472
- if (!fp.isNil(start)) {
2473
- query.offset = convertStartQueryParams(start);
2474
- }
2475
- if (!fp.isNil(limit)) {
2476
- query.limit = convertLimitQueryParams(limit);
2477
- }
2478
- return {
2479
- ...rest,
2480
- ...query
2481
- };
2482
- };
2483
- const convertQueryParams = {
2484
- convertSortQueryParams,
2485
- convertStartQueryParams,
2486
- convertLimitQueryParams,
2487
- convertPopulateQueryParams,
2488
- convertFiltersQueryParams,
2489
- convertFieldsQueryParams,
2490
- transformParamsToQuery
2491
- };
2492
- function importDefault(modName) {
2493
- const mod = require(modName);
2494
- return mod && mod.__esModule ? mod.default : mod;
2495
- }
2496
- const machineId = () => {
2497
- try {
2498
- const deviceId = nodeMachineId.machineIdSync();
2499
- return deviceId;
2500
- } catch (error) {
2501
- const deviceId = crypto.randomUUID();
2502
- return deviceId;
2503
- }
2504
- };
2505
- const handleYupError = (error, errorMessage) => {
2506
- throw new YupValidationError(error, errorMessage);
2507
- };
2508
- const defaultValidationParam = { strict: true, abortEarly: false };
2509
- const validateYupSchema = (schema, options = {}) => async (body, errorMessage) => {
2510
- try {
2511
- const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
2512
- const result = await schema.validate(body, optionsWithDefaults);
2513
- return result;
2514
- } catch (e) {
2515
- if (e instanceof yup__namespace.ValidationError) {
2516
- handleYupError(e, errorMessage);
2517
- }
2518
- throw e;
2519
- }
2520
- };
2521
- const validateYupSchemaSync = (schema, options = {}) => (body, errorMessage) => {
2522
- try {
2523
- const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
2524
- return schema.validateSync(body, optionsWithDefaults);
2525
- } catch (e) {
2526
- if (e instanceof yup__namespace.ValidationError) {
2527
- handleYupError(e, errorMessage);
2528
- }
2529
- throw e;
2530
- }
2531
- };
2581
+ visitors: index$1
2582
+ }, Symbol.toStringTag, { value: "Module" }));
2532
2583
  const STRAPI_DEFAULTS = {
2533
2584
  offset: {
2534
2585
  start: 0,
@@ -2680,72 +2731,6 @@ const file = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
2680
2731
  streamToBuffer,
2681
2732
  writableDiscardStream
2682
2733
  }, Symbol.toStringTag, { value: "Module" }));
2683
- const PLUGIN_PREFIX = "plugin::";
2684
- const API_PREFIX = "api::";
2685
- const parsePolicy = (policy2) => {
2686
- if (typeof policy2 === "string") {
2687
- return { policyName: policy2, config: {} };
2688
- }
2689
- const { name, config } = policy2;
2690
- return { policyName: name, config };
2691
- };
2692
- const searchLocalPolicy = (policyName, policyContext) => {
2693
- const { pluginName, apiName } = policyContext ?? {};
2694
- if (pluginName) {
2695
- return strapi.policy(`${PLUGIN_PREFIX}${pluginName}.${policyName}`);
2696
- }
2697
- if (apiName) {
2698
- return strapi.policy(`${API_PREFIX}${apiName}.${policyName}`);
2699
- }
2700
- };
2701
- const globalPolicy = ({ method, endpoint, controller, action, plugin }) => {
2702
- return async (ctx, next) => {
2703
- ctx.request.route = {
2704
- endpoint: `${method} ${endpoint}`,
2705
- controller: ___default.default.toLower(controller),
2706
- action: ___default.default.toLower(action),
2707
- verb: ___default.default.toLower(method),
2708
- plugin
2709
- };
2710
- await next();
2711
- };
2712
- };
2713
- const resolvePolicies = (config, policyContext) => {
2714
- const { pluginName, apiName } = policyContext ?? {};
2715
- return config.map((policyConfig) => {
2716
- return {
2717
- handler: getPolicy(policyConfig, { pluginName, apiName }),
2718
- config: typeof policyConfig === "object" && policyConfig.config || {}
2719
- };
2720
- });
2721
- };
2722
- const findPolicy = (name, policyContext) => {
2723
- const { pluginName, apiName } = policyContext ?? {};
2724
- const resolvedPolicy = strapi.policy(name);
2725
- if (resolvedPolicy !== void 0) {
2726
- return resolvedPolicy;
2727
- }
2728
- const localPolicy = searchLocalPolicy(name, { pluginName, apiName });
2729
- if (localPolicy !== void 0) {
2730
- return localPolicy;
2731
- }
2732
- throw new Error(`Could not find policy "${name}"`);
2733
- };
2734
- const getPolicy = (policyConfig, policyContext) => {
2735
- const { pluginName, apiName } = policyContext ?? {};
2736
- if (typeof policyConfig === "function") {
2737
- return policyConfig;
2738
- }
2739
- const { policyName, config } = parsePolicy(policyConfig);
2740
- const policy2 = findPolicy(policyName, { pluginName, apiName });
2741
- if (typeof policy2 === "function") {
2742
- return policy2;
2743
- }
2744
- if (policy2.validator) {
2745
- policy2.validator(config);
2746
- }
2747
- return policy2.handler;
2748
- };
2749
2734
  const createPolicy = (options) => {
2750
2735
  const { name = "unnamed", validator, handler } = options;
2751
2736
  const wrappedValidator = (config) => {
@@ -2777,10 +2762,7 @@ const createPolicyContext = (type, ctx) => {
2777
2762
  const policy = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2778
2763
  __proto__: null,
2779
2764
  createPolicy,
2780
- createPolicyContext,
2781
- get: getPolicy,
2782
- globalPolicy,
2783
- resolve: resolvePolicies
2765
+ createPolicyContext
2784
2766
  }, Symbol.toStringTag, { value: "Module" }));
2785
2767
  const nameToSlug = (name, options = { separator: "-" }) => slugify__default.default(name, options);
2786
2768
  const nameToCollectionName = (name) => slugify__default.default(name, { separator: "_" });
@@ -3022,7 +3004,6 @@ const relations = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePro
3022
3004
  exports.arrays = arrays;
3023
3005
  exports.async = async;
3024
3006
  exports.contentTypes = contentTypes;
3025
- exports.convertQueryParams = convertQueryParams;
3026
3007
  exports.dates = dates;
3027
3008
  exports.env = env;
3028
3009
  exports.errors = errors;
@@ -3038,12 +3019,13 @@ exports.pagination = pagination;
3038
3019
  exports.parseType = parseType;
3039
3020
  exports.policy = policy;
3040
3021
  exports.providerFactory = providerFactory;
3022
+ exports.queryParams = convertQueryParams;
3041
3023
  exports.relations = relations;
3042
- exports.sanitize = index$1;
3024
+ exports.sanitize = index$2;
3043
3025
  exports.setCreatorFields = setCreatorFields;
3044
3026
  exports.strings = strings;
3045
3027
  exports.template = template;
3046
- exports.traverse = index$2;
3028
+ exports.traverse = index$3;
3047
3029
  exports.traverseEntity = traverseEntity$1;
3048
3030
  exports.validate = index;
3049
3031
  exports.validateYupSchema = validateYupSchema;