@strapi/utils 5.0.0-beta.0 → 5.0.0-beta.2

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,15 +2,16 @@
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");
13
13
  const slugify = require("@sindresorhus/slugify");
14
+ const zod = require("zod");
14
15
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
15
16
  function _interopNamespace(e) {
16
17
  if (e && e.__esModule)
@@ -50,8 +51,8 @@ function _mergeNamespaces(n, m) {
50
51
  return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
51
52
  }
52
53
  const ___default = /* @__PURE__ */ _interopDefault(_$1);
53
- const pMap__default = /* @__PURE__ */ _interopDefault(pMap);
54
54
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup$1);
55
+ const pMap__default = /* @__PURE__ */ _interopDefault(pMap);
55
56
  const execa__default = /* @__PURE__ */ _interopDefault(execa);
56
57
  const preferredPM__default = /* @__PURE__ */ _interopDefault(preferredPM);
57
58
  const slugify__default = /* @__PURE__ */ _interopDefault(slugify);
@@ -360,6 +361,17 @@ const getScalarAttributes = (schema) => {
360
361
  []
361
362
  );
362
363
  };
364
+ const getRelationalAttributes = (schema) => {
365
+ return ___default.default.reduce(
366
+ schema.attributes,
367
+ (acc, attr, attrName) => {
368
+ if (isRelationalAttribute(attr))
369
+ acc.push(attrName);
370
+ return acc;
371
+ },
372
+ []
373
+ );
374
+ };
363
375
  const isTypedAttribute = (attribute, type) => {
364
376
  return ___default.default.has(attribute, "type") && attribute.type === type;
365
377
  };
@@ -376,6 +388,7 @@ const contentTypes = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.define
376
388
  getNonWritableAttributes,
377
389
  getOptions,
378
390
  getPrivateAttributes,
391
+ getRelationalAttributes,
379
392
  getScalarAttributes,
380
393
  getTimestamps,
381
394
  getVisibleAttributes,
@@ -543,201 +556,32 @@ const providerFactory = (options = {}) => {
543
556
  }
544
557
  };
545
558
  };
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;
559
+ const traverseEntity = async (visitor2, options, entity) => {
560
+ const { path = { raw: null, attribute: null }, schema, getModel } = options;
561
+ const traverseMorphRelationTarget = async (visitor22, path2, entry) => {
562
+ const targetSchema = getModel(entry.__type);
563
+ const traverseOptions = { schema: targetSchema, path: path2, getModel };
564
+ return traverseEntity(visitor22, traverseOptions, entry);
554
565
  };
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
- }
566
+ const traverseRelationTarget = (schema2) => async (visitor22, path2, entry) => {
567
+ const traverseOptions = { schema: schema2, path: path2, getModel };
568
+ return traverseEntity(visitor22, traverseOptions, entry);
608
569
  };
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
- }
570
+ const traverseMediaTarget = async (visitor22, path2, entry) => {
571
+ const targetSchemaUID = "plugin::upload.file";
572
+ const targetSchema = getModel(targetSchemaUID);
573
+ const traverseOptions = { schema: targetSchema, path: path2, getModel };
574
+ return traverseEntity(visitor22, traverseOptions, entry);
575
+ };
576
+ const traverseComponent = async (visitor22, path2, schema2, entry) => {
577
+ const traverseOptions = { schema: schema2, path: path2, getModel };
578
+ return traverseEntity(visitor22, traverseOptions, entry);
579
+ };
580
+ const visitDynamicZoneEntry = async (visitor22, path2, entry) => {
581
+ const targetSchema = getModel(entry.__component);
582
+ const traverseOptions = { schema: targetSchema, path: path2, getModel };
583
+ return traverseEntity(visitor22, traverseOptions, entry);
615
584
  };
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
585
  if (!fp.isObject(entity) || fp.isNil(schema)) {
742
586
  return entity;
743
587
  }
@@ -761,7 +605,8 @@ const traverseEntity = async (visitor2, options, entity) => {
761
605
  key,
762
606
  value: copy[key],
763
607
  attribute,
764
- path: newPath
608
+ path: newPath,
609
+ getModel
765
610
  };
766
611
  await visitor2(visitorOptions, visitorUtils);
767
612
  const value = copy[key];
@@ -770,7 +615,7 @@ const traverseEntity = async (visitor2, options, entity) => {
770
615
  }
771
616
  if (isRelationalAttribute(attribute)) {
772
617
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
773
- const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(strapi.getModel(attribute.target));
618
+ const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
774
619
  if (fp.isArray(value)) {
775
620
  const res = new Array(value.length);
776
621
  for (let i2 = 0; i2 < value.length; i2 += 1) {
@@ -795,7 +640,7 @@ const traverseEntity = async (visitor2, options, entity) => {
795
640
  continue;
796
641
  }
797
642
  if (attribute.type === "component") {
798
- const targetSchema = strapi.getModel(attribute.component);
643
+ const targetSchema = getModel(attribute.component);
799
644
  if (fp.isArray(value)) {
800
645
  const res = new Array(value.length);
801
646
  for (let i2 = 0; i2 < value.length; i2 += 1) {
@@ -827,78 +672,851 @@ const createVisitorUtils = ({ data }) => ({
827
672
  }
828
673
  });
829
674
  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) {
675
+ function importDefault(modName) {
676
+ const mod = require(modName);
677
+ return mod && mod.__esModule ? mod.default : mod;
678
+ }
679
+ const machineId = () => {
680
+ try {
681
+ const deviceId = nodeMachineId.machineIdSync();
682
+ return deviceId;
683
+ } catch (error) {
684
+ const deviceId = crypto.randomUUID();
685
+ return deviceId;
686
+ }
687
+ };
688
+ const formatYupInnerError = (yupError) => ({
689
+ path: fp.toPath(yupError.path),
690
+ message: yupError.message,
691
+ name: yupError.name
692
+ });
693
+ const formatYupErrors = (yupError) => ({
694
+ errors: fp.isEmpty(yupError.inner) ? [formatYupInnerError(yupError)] : yupError.inner.map(formatYupInnerError),
695
+ message: yupError.message
696
+ });
697
+ class ApplicationError extends Error {
698
+ name;
699
+ details;
700
+ message;
701
+ constructor(message = "An application error occured", details = {}) {
702
+ super();
703
+ this.name = "ApplicationError";
704
+ this.message = message;
705
+ this.details = details;
706
+ }
707
+ }
708
+ class ValidationError extends ApplicationError {
709
+ constructor(message, details) {
710
+ super(message, details);
711
+ this.name = "ValidationError";
712
+ }
713
+ }
714
+ class YupValidationError extends ValidationError {
715
+ constructor(yupError, message) {
716
+ super("Validation");
717
+ const { errors: errors2, message: yupMessage } = formatYupErrors(yupError);
718
+ this.message = message || yupMessage;
719
+ this.details = { errors: errors2 };
720
+ }
721
+ }
722
+ class PaginationError extends ApplicationError {
723
+ constructor(message = "Invalid pagination", details) {
724
+ super(message, details);
725
+ this.name = "PaginationError";
726
+ this.message = message;
727
+ }
728
+ }
729
+ class NotFoundError extends ApplicationError {
730
+ constructor(message = "Entity not found", details) {
731
+ super(message, details);
732
+ this.name = "NotFoundError";
733
+ this.message = message;
734
+ }
735
+ }
736
+ class ForbiddenError extends ApplicationError {
737
+ constructor(message = "Forbidden access", details) {
738
+ super(message, details);
739
+ this.name = "ForbiddenError";
740
+ this.message = message;
741
+ }
742
+ }
743
+ class UnauthorizedError extends ApplicationError {
744
+ constructor(message = "Unauthorized", details) {
745
+ super(message, details);
746
+ this.name = "UnauthorizedError";
747
+ this.message = message;
748
+ }
749
+ }
750
+ class RateLimitError extends ApplicationError {
751
+ constructor(message = "Too many requests, please try again later.", details) {
752
+ super(message, details);
753
+ this.name = "RateLimitError";
754
+ this.message = message;
755
+ this.details = details || {};
756
+ }
757
+ }
758
+ class PayloadTooLargeError extends ApplicationError {
759
+ constructor(message = "Entity too large", details) {
760
+ super(message, details);
761
+ this.name = "PayloadTooLargeError";
762
+ this.message = message;
763
+ }
764
+ }
765
+ class PolicyError extends ForbiddenError {
766
+ constructor(message = "Policy Failed", details) {
767
+ super(message, details);
768
+ this.name = "PolicyError";
769
+ this.message = message;
770
+ this.details = details || {};
771
+ }
772
+ }
773
+ class NotImplementedError extends ApplicationError {
774
+ constructor(message = "This feature is not implemented yet", details) {
775
+ super(message, details);
776
+ this.name = "NotImplementedError";
777
+ this.message = message;
778
+ }
779
+ }
780
+ const errors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
781
+ __proto__: null,
782
+ ApplicationError,
783
+ ForbiddenError,
784
+ HttpError: httpErrors.HttpError,
785
+ NotFoundError,
786
+ NotImplementedError,
787
+ PaginationError,
788
+ PayloadTooLargeError,
789
+ PolicyError,
790
+ RateLimitError,
791
+ UnauthorizedError,
792
+ ValidationError,
793
+ YupValidationError
794
+ }, Symbol.toStringTag, { value: "Module" }));
795
+ const handleYupError = (error, errorMessage) => {
796
+ throw new YupValidationError(error, errorMessage);
797
+ };
798
+ const defaultValidationParam = { strict: true, abortEarly: false };
799
+ const validateYupSchema = (schema, options = {}) => async (body, errorMessage) => {
800
+ try {
801
+ const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
802
+ const result = await schema.validate(body, optionsWithDefaults);
803
+ return result;
804
+ } catch (e) {
805
+ if (e instanceof yup__namespace.ValidationError) {
806
+ handleYupError(e, errorMessage);
807
+ }
808
+ throw e;
809
+ }
810
+ };
811
+ const validateYupSchemaSync = (schema, options = {}) => (body, errorMessage) => {
812
+ try {
813
+ const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
814
+ return schema.validateSync(body, optionsWithDefaults);
815
+ } catch (e) {
816
+ if (e instanceof yup__namespace.ValidationError) {
817
+ handleYupError(e, errorMessage);
818
+ }
819
+ throw e;
820
+ }
821
+ };
822
+ const GROUP_OPERATORS = ["$and", "$or"];
823
+ const WHERE_OPERATORS = [
824
+ "$not",
825
+ "$in",
826
+ "$notIn",
827
+ "$eq",
828
+ "$eqi",
829
+ "$ne",
830
+ "$nei",
831
+ "$gt",
832
+ "$gte",
833
+ "$lt",
834
+ "$lte",
835
+ "$null",
836
+ "$notNull",
837
+ "$between",
838
+ "$startsWith",
839
+ "$endsWith",
840
+ "$startsWithi",
841
+ "$endsWithi",
842
+ "$contains",
843
+ "$notContains",
844
+ "$containsi",
845
+ "$notContainsi",
846
+ // Experimental, only for internal use
847
+ "$jsonSupersetOf"
848
+ ];
849
+ const CAST_OPERATORS = [
850
+ "$not",
851
+ "$in",
852
+ "$notIn",
853
+ "$eq",
854
+ "$ne",
855
+ "$gt",
856
+ "$gte",
857
+ "$lt",
858
+ "$lte",
859
+ "$between"
860
+ ];
861
+ const ARRAY_OPERATORS = ["$in", "$notIn", "$between"];
862
+ const OPERATORS = {
863
+ where: WHERE_OPERATORS,
864
+ cast: CAST_OPERATORS,
865
+ group: GROUP_OPERATORS,
866
+ array: ARRAY_OPERATORS
867
+ };
868
+ const OPERATORS_LOWERCASE = Object.fromEntries(
869
+ Object.entries(OPERATORS).map(([key, values]) => [
870
+ key,
871
+ values.map((value) => value.toLowerCase())
872
+ ])
873
+ );
874
+ const isObjKey = (key, obj) => {
875
+ return key in obj;
876
+ };
877
+ const isOperatorOfType = (type, key, ignoreCase = false) => {
878
+ if (ignoreCase) {
879
+ return OPERATORS_LOWERCASE[type]?.includes(key.toLowerCase()) ?? false;
880
+ }
881
+ if (isObjKey(type, OPERATORS)) {
882
+ return OPERATORS[type]?.includes(key) ?? false;
883
+ }
884
+ return false;
885
+ };
886
+ const isOperator = (key, ignoreCase = false) => {
887
+ return Object.keys(OPERATORS).some((type) => isOperatorOfType(type, key, ignoreCase));
888
+ };
889
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$3, PUBLISHED_AT_ATTRIBUTE } = constants$1;
890
+ class InvalidOrderError extends Error {
891
+ constructor() {
892
+ super();
893
+ this.message = "Invalid order. order can only be one of asc|desc|ASC|DESC";
894
+ }
895
+ }
896
+ class InvalidSortError extends Error {
897
+ constructor() {
898
+ super();
899
+ this.message = "Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects";
900
+ }
901
+ }
902
+ function validateOrder(order) {
903
+ if (!fp.isString(order) || !["asc", "desc"].includes(order.toLocaleLowerCase())) {
904
+ throw new InvalidOrderError();
905
+ }
906
+ }
907
+ const convertCountQueryParams = (countQuery) => {
908
+ return parseType({ type: "boolean", value: countQuery });
909
+ };
910
+ const convertOrderingQueryParams = (ordering) => {
911
+ return ordering;
912
+ };
913
+ const isPlainObject = (value) => ___default.default.isPlainObject(value);
914
+ const isStringArray$3 = (value) => fp.isArray(value) && value.every(fp.isString);
915
+ const createTransformer = ({ getModel }) => {
916
+ const convertSortQueryParams = (sortQuery) => {
917
+ if (typeof sortQuery === "string") {
918
+ return convertStringSortQueryParam(sortQuery);
919
+ }
920
+ if (isStringArray$3(sortQuery)) {
921
+ return sortQuery.flatMap((sortValue) => convertStringSortQueryParam(sortValue));
922
+ }
923
+ if (Array.isArray(sortQuery)) {
924
+ return sortQuery.map((sortValue) => convertNestedSortQueryParam(sortValue));
925
+ }
926
+ if (isPlainObject(sortQuery)) {
927
+ return convertNestedSortQueryParam(sortQuery);
928
+ }
929
+ throw new InvalidSortError();
930
+ };
931
+ const convertStringSortQueryParam = (sortQuery) => {
932
+ return sortQuery.split(",").map((value) => convertSingleSortQueryParam(value));
933
+ };
934
+ const convertSingleSortQueryParam = (sortQuery) => {
935
+ if (!sortQuery) {
936
+ return {};
937
+ }
938
+ if (!fp.isString(sortQuery)) {
939
+ throw new Error("Invalid sort query");
940
+ }
941
+ const [field, order = "asc"] = sortQuery.split(":");
942
+ if (field.length === 0) {
943
+ throw new Error("Field cannot be empty");
944
+ }
945
+ validateOrder(order);
946
+ return ___default.default.set({}, field, order);
947
+ };
948
+ const convertNestedSortQueryParam = (sortQuery) => {
949
+ const transformedSort = {};
950
+ for (const field of Object.keys(sortQuery)) {
951
+ const order = sortQuery[field];
952
+ if (isPlainObject(order)) {
953
+ transformedSort[field] = convertNestedSortQueryParam(order);
954
+ } else if (typeof order === "string") {
955
+ validateOrder(order);
956
+ transformedSort[field] = order;
957
+ } else {
958
+ throw Error(`Invalid sort type expected object or string got ${typeof order}`);
959
+ }
960
+ }
961
+ return transformedSort;
962
+ };
963
+ const convertStartQueryParams = (startQuery) => {
964
+ const startAsANumber = ___default.default.toNumber(startQuery);
965
+ if (!___default.default.isInteger(startAsANumber) || startAsANumber < 0) {
966
+ throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
967
+ }
968
+ return startAsANumber;
969
+ };
970
+ const convertLimitQueryParams = (limitQuery) => {
971
+ const limitAsANumber = ___default.default.toNumber(limitQuery);
972
+ if (!___default.default.isInteger(limitAsANumber) || limitAsANumber !== -1 && limitAsANumber < 0) {
973
+ throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
974
+ }
975
+ if (limitAsANumber === -1) {
976
+ return void 0;
977
+ }
978
+ return limitAsANumber;
979
+ };
980
+ const convertPageQueryParams = (page) => {
981
+ const pageVal = fp.toNumber(page);
982
+ if (!fp.isInteger(pageVal) || pageVal <= 0) {
983
+ throw new PaginationError(
984
+ `Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
985
+ );
986
+ }
987
+ return pageVal;
988
+ };
989
+ const convertPageSizeQueryParams = (pageSize, page) => {
990
+ const pageSizeVal = fp.toNumber(pageSize);
991
+ if (!fp.isInteger(pageSizeVal) || pageSizeVal <= 0) {
992
+ throw new PaginationError(
993
+ `Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
994
+ );
995
+ }
996
+ return pageSizeVal;
997
+ };
998
+ const validatePaginationParams = (page, pageSize, start, limit) => {
999
+ const isPagePagination = !fp.isNil(page) || !fp.isNil(pageSize);
1000
+ const isOffsetPagination = !fp.isNil(start) || !fp.isNil(limit);
1001
+ if (isPagePagination && isOffsetPagination) {
1002
+ throw new PaginationError(
1003
+ "Invalid pagination attributes. You cannot use page and offset pagination in the same query"
1004
+ );
1005
+ }
1006
+ };
1007
+ class InvalidPopulateError extends Error {
1008
+ constructor() {
1009
+ super();
1010
+ this.message = "Invalid populate parameter. Expected a string, an array of strings, a populate object";
1011
+ }
1012
+ }
1013
+ const convertPopulateQueryParams = (populate2, schema, depth = 0) => {
1014
+ if (depth === 0 && populate2 === "*") {
1015
+ return true;
1016
+ }
1017
+ if (typeof populate2 === "string") {
1018
+ return populate2.split(",").map((value) => ___default.default.trim(value));
1019
+ }
1020
+ if (Array.isArray(populate2)) {
1021
+ return ___default.default.uniq(
1022
+ populate2.flatMap((value) => {
1023
+ if (typeof value !== "string") {
1024
+ throw new InvalidPopulateError();
1025
+ }
1026
+ return value.split(",").map((value2) => ___default.default.trim(value2));
1027
+ })
1028
+ );
1029
+ }
1030
+ if (___default.default.isPlainObject(populate2)) {
1031
+ return convertPopulateObject(populate2, schema);
1032
+ }
1033
+ throw new InvalidPopulateError();
1034
+ };
1035
+ const hasFragmentPopulateDefined = (populate2) => {
1036
+ return typeof populate2 === "object" && "on" in populate2 && !fp.isNil(populate2.on);
1037
+ };
1038
+ const convertPopulateObject = (populate2, schema) => {
1039
+ if (!schema) {
1040
+ return {};
1041
+ }
1042
+ const { attributes } = schema;
1043
+ return Object.entries(populate2).reduce((acc, [key, subPopulate]) => {
1044
+ if (___default.default.isBoolean(subPopulate)) {
1045
+ return { ...acc, [key]: subPopulate };
1046
+ }
1047
+ const attribute = attributes[key];
1048
+ if (!attribute) {
1049
+ return acc;
1050
+ }
1051
+ const isAllowedAttributeForFragmentPopulate = isDynamicZoneAttribute(attribute) || isMorphToRelationalAttribute(attribute);
1052
+ if (isAllowedAttributeForFragmentPopulate && hasFragmentPopulateDefined(subPopulate)) {
1053
+ return {
1054
+ ...acc,
1055
+ [key]: {
1056
+ on: Object.entries(subPopulate.on).reduce(
1057
+ (acc2, [type, typeSubPopulate]) => ({
1058
+ ...acc2,
1059
+ [type]: convertNestedPopulate(typeSubPopulate, getModel(type))
1060
+ }),
1061
+ {}
1062
+ )
1063
+ }
1064
+ };
1065
+ }
1066
+ if (isDynamicZoneAttribute(attribute)) {
1067
+ const populates = attribute.components.map((uid) => getModel(uid)).map((schema2) => convertNestedPopulate(subPopulate, schema2)).map((populate22) => populate22 === true ? {} : populate22).filter((populate22) => populate22 !== false);
1068
+ if (fp.isEmpty(populates)) {
1069
+ return acc;
1070
+ }
1071
+ return {
1072
+ ...acc,
1073
+ [key]: fp.mergeAll(populates)
1074
+ };
1075
+ }
1076
+ if (isMorphToRelationalAttribute(attribute)) {
1077
+ return { ...acc, [key]: convertNestedPopulate(subPopulate, void 0) };
1078
+ }
1079
+ let targetSchemaUID;
1080
+ if (attribute.type === "relation") {
1081
+ targetSchemaUID = attribute.target;
1082
+ } else if (attribute.type === "component") {
1083
+ targetSchemaUID = attribute.component;
1084
+ } else if (attribute.type === "media") {
1085
+ targetSchemaUID = "plugin::upload.file";
1086
+ } else {
1087
+ return acc;
1088
+ }
1089
+ const targetSchema = getModel(targetSchemaUID);
1090
+ if (!targetSchema) {
1091
+ return acc;
1092
+ }
1093
+ const populateObject = convertNestedPopulate(subPopulate, targetSchema);
1094
+ if (!populateObject) {
1095
+ return acc;
1096
+ }
1097
+ return {
1098
+ ...acc,
1099
+ [key]: populateObject
1100
+ };
1101
+ }, {});
1102
+ };
1103
+ const convertNestedPopulate = (subPopulate, schema) => {
1104
+ if (___default.default.isString(subPopulate)) {
1105
+ return parseType({ type: "boolean", value: subPopulate, forceCast: true });
1106
+ }
1107
+ if (___default.default.isBoolean(subPopulate)) {
1108
+ return subPopulate;
1109
+ }
1110
+ if (!isPlainObject(subPopulate)) {
1111
+ throw new Error(`Invalid nested populate. Expected '*' or an object`);
1112
+ }
1113
+ const { sort: sort2, filters: filters2, fields: fields2, populate: populate2, count, ordering, page, pageSize, start, limit } = subPopulate;
1114
+ const query = {};
1115
+ if (sort2) {
1116
+ query.orderBy = convertSortQueryParams(sort2);
1117
+ }
1118
+ if (filters2) {
1119
+ query.where = convertFiltersQueryParams(filters2, schema);
1120
+ }
1121
+ if (fields2) {
1122
+ query.select = convertFieldsQueryParams(fields2);
1123
+ }
1124
+ if (populate2) {
1125
+ query.populate = convertPopulateQueryParams(populate2, schema);
1126
+ }
1127
+ if (count) {
1128
+ query.count = convertCountQueryParams(count);
1129
+ }
1130
+ if (ordering) {
1131
+ query.ordering = convertOrderingQueryParams(ordering);
1132
+ }
1133
+ validatePaginationParams(page, pageSize, start, limit);
1134
+ if (!fp.isNil(page)) {
1135
+ query.page = convertPageQueryParams(page);
1136
+ }
1137
+ if (!fp.isNil(pageSize)) {
1138
+ query.pageSize = convertPageSizeQueryParams(pageSize, page);
1139
+ }
1140
+ if (!fp.isNil(start)) {
1141
+ query.offset = convertStartQueryParams(start);
1142
+ }
1143
+ if (!fp.isNil(limit)) {
1144
+ query.limit = convertLimitQueryParams(limit);
1145
+ }
1146
+ return query;
1147
+ };
1148
+ const convertFieldsQueryParams = (fields2, depth = 0) => {
1149
+ if (depth === 0 && fields2 === "*") {
1150
+ return void 0;
1151
+ }
1152
+ if (typeof fields2 === "string") {
1153
+ const fieldsValues = fields2.split(",").map((value) => ___default.default.trim(value));
1154
+ return ___default.default.uniq([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3, ...fieldsValues]);
1155
+ }
1156
+ if (isStringArray$3(fields2)) {
1157
+ const fieldsValues = fields2.flatMap((value) => convertFieldsQueryParams(value, depth + 1)).filter((v) => !fp.isNil(v));
1158
+ return ___default.default.uniq([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3, ...fieldsValues]);
1159
+ }
1160
+ throw new Error("Invalid fields parameter. Expected a string or an array of strings");
1161
+ };
1162
+ const isValidSchemaAttribute = (key, schema) => {
1163
+ if ([DOC_ID_ATTRIBUTE$3, ID_ATTRIBUTE$3].includes(key)) {
1164
+ return true;
1165
+ }
1166
+ if (!schema) {
1167
+ return false;
1168
+ }
1169
+ return Object.keys(schema.attributes).includes(key);
1170
+ };
1171
+ const convertFiltersQueryParams = (filters2, schema) => {
1172
+ if (!fp.isObject(filters2)) {
1173
+ throw new Error("The filters parameter must be an object or an array");
1174
+ }
1175
+ const filtersCopy = fp.cloneDeep(filters2);
1176
+ return convertAndSanitizeFilters(filtersCopy, schema);
1177
+ };
1178
+ const convertAndSanitizeFilters = (filters2, schema) => {
1179
+ if (Array.isArray(filters2)) {
1180
+ return filters2.map((filter) => convertAndSanitizeFilters(filter, schema)).filter((filter) => !isPlainObject(filter) || !fp.isEmpty(filter));
1181
+ }
1182
+ if (!isPlainObject(filters2)) {
1183
+ return filters2;
1184
+ }
1185
+ const removeOperator = (operator) => delete filters2[operator];
1186
+ for (const [key, value] of Object.entries(filters2)) {
1187
+ const attribute = fp.get(key, schema?.attributes);
1188
+ const validKey = isOperator(key) || isValidSchemaAttribute(key, schema);
1189
+ if (!validKey) {
1190
+ removeOperator(key);
1191
+ } else if (attribute) {
1192
+ if (attribute.type === "relation") {
1193
+ filters2[key] = convertAndSanitizeFilters(value, getModel(attribute.target));
1194
+ } else if (attribute.type === "component") {
1195
+ filters2[key] = convertAndSanitizeFilters(value, getModel(attribute.component));
1196
+ } else if (attribute.type === "media") {
1197
+ filters2[key] = convertAndSanitizeFilters(value, getModel("plugin::upload.file"));
1198
+ } else if (attribute.type === "dynamiczone") {
1199
+ removeOperator(key);
1200
+ } else if (attribute.type === "password") {
1201
+ removeOperator(key);
1202
+ } else {
1203
+ filters2[key] = convertAndSanitizeFilters(value, schema);
1204
+ }
1205
+ } else if (["$null", "$notNull"].includes(key)) {
1206
+ filters2[key] = parseType({ type: "boolean", value: filters2[key], forceCast: true });
1207
+ } else if (fp.isObject(value)) {
1208
+ filters2[key] = convertAndSanitizeFilters(value, schema);
1209
+ }
1210
+ if (isPlainObject(filters2[key]) && fp.isEmpty(filters2[key])) {
1211
+ removeOperator(key);
1212
+ }
1213
+ }
1214
+ return filters2;
1215
+ };
1216
+ const convertStatusParams = (status, query = {}) => {
1217
+ query.filters = ({ meta }) => {
1218
+ const contentType = getModel(meta.uid);
1219
+ if (!contentType || !hasDraftAndPublish(contentType)) {
1220
+ return {};
1221
+ }
1222
+ return { [PUBLISHED_AT_ATTRIBUTE]: { $null: status === "draft" } };
1223
+ };
1224
+ };
1225
+ const transformQueryParams = (uid, params) => {
1226
+ const schema = getModel(uid);
1227
+ const query = {};
1228
+ const { _q, sort: sort2, filters: filters2, fields: fields2, populate: populate2, page, pageSize, start, limit, status, ...rest } = params;
1229
+ if (!fp.isNil(status)) {
1230
+ convertStatusParams(status, query);
1231
+ }
1232
+ if (!fp.isNil(_q)) {
1233
+ query._q = _q;
1234
+ }
1235
+ if (!fp.isNil(sort2)) {
1236
+ query.orderBy = convertSortQueryParams(sort2);
1237
+ }
1238
+ if (!fp.isNil(filters2)) {
1239
+ query.where = convertFiltersQueryParams(filters2, schema);
1240
+ }
1241
+ if (!fp.isNil(fields2)) {
1242
+ query.select = convertFieldsQueryParams(fields2);
1243
+ }
1244
+ if (!fp.isNil(populate2)) {
1245
+ query.populate = convertPopulateQueryParams(populate2, schema);
1246
+ }
1247
+ validatePaginationParams(page, pageSize, start, limit);
1248
+ if (!fp.isNil(page)) {
1249
+ query.page = convertPageQueryParams(page);
1250
+ }
1251
+ if (!fp.isNil(pageSize)) {
1252
+ query.pageSize = convertPageSizeQueryParams(pageSize, page);
1253
+ }
1254
+ if (!fp.isNil(start)) {
1255
+ query.offset = convertStartQueryParams(start);
1256
+ }
1257
+ if (!fp.isNil(limit)) {
1258
+ query.limit = convertLimitQueryParams(limit);
1259
+ }
1260
+ return {
1261
+ ...rest,
1262
+ ...query
1263
+ };
1264
+ };
1265
+ return {
1266
+ private_convertSortQueryParams: convertSortQueryParams,
1267
+ private_convertStartQueryParams: convertStartQueryParams,
1268
+ private_convertLimitQueryParams: convertLimitQueryParams,
1269
+ private_convertPopulateQueryParams: convertPopulateQueryParams,
1270
+ private_convertFiltersQueryParams: convertFiltersQueryParams,
1271
+ private_convertFieldsQueryParams: convertFieldsQueryParams,
1272
+ transformQueryParams
1273
+ };
1274
+ };
1275
+ const convertQueryParams = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1276
+ __proto__: null,
1277
+ createTransformer
1278
+ }, Symbol.toStringTag, { value: "Module" }));
1279
+ function pipe(...fns) {
1280
+ const [firstFn, ...fnRest] = fns;
1281
+ return async (...args) => {
1282
+ let res = await firstFn.apply(firstFn, args);
1283
+ for (let i = 0; i < fnRest.length; i += 1) {
1284
+ res = await fnRest[i](res);
1285
+ }
1286
+ return res;
1287
+ };
1288
+ }
1289
+ const map = fp.curry(pMap__default.default);
1290
+ const reduce = (mixedArray) => async (iteratee, initialValue) => {
1291
+ let acc = initialValue;
1292
+ for (let i = 0; i < mixedArray.length; i += 1) {
1293
+ acc = await iteratee(acc, await mixedArray[i], i);
1294
+ }
1295
+ return acc;
1296
+ };
1297
+ const async = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1298
+ __proto__: null,
1299
+ map,
1300
+ pipe,
1301
+ reduce
1302
+ }, Symbol.toStringTag, { value: "Module" }));
1303
+ const visitor$8 = ({ key, attribute }, { remove }) => {
1304
+ if (attribute?.type === "password") {
1305
+ remove(key);
1306
+ }
1307
+ };
1308
+ const visitor$7 = ({ schema, key, attribute }, { remove }) => {
1309
+ if (!attribute) {
1310
+ return;
1311
+ }
1312
+ const isPrivate = attribute.private === true || isPrivateAttribute(schema, key);
1313
+ if (isPrivate) {
1314
+ remove(key);
1315
+ }
1316
+ };
1317
+ const ACTIONS_TO_VERIFY$1 = ["find"];
1318
+ const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$1 } = constants$1;
1319
+ const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schema }, { remove, set }) => {
1320
+ if (!attribute) {
1321
+ return;
1322
+ }
1323
+ const isRelation = attribute.type === "relation";
1324
+ if (!isRelation) {
1325
+ return;
1326
+ }
1327
+ const handleMorphRelation = async () => {
1328
+ const newMorphValue = [];
1329
+ for (const element of data[key]) {
1330
+ const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
1331
+ const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
1332
+ if (isAllowed) {
1333
+ newMorphValue.push(element);
1334
+ }
1335
+ }
1336
+ if (newMorphValue.length === 0) {
1337
+ remove(key);
1338
+ } else {
1339
+ set(key, newMorphValue);
1340
+ }
1341
+ };
1342
+ const handleRegularRelation = async () => {
1343
+ const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${attribute.target}.${action}`);
1344
+ const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
1345
+ if (!isAllowed) {
1346
+ remove(key);
1347
+ }
1348
+ };
1349
+ const isCreatorRelation = [CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE$1].includes(key);
1350
+ if (isMorphToRelationalAttribute(attribute)) {
1351
+ await handleMorphRelation();
1352
+ return;
1353
+ }
1354
+ if (isCreatorRelation && schema.options?.populateCreatorFields) {
1355
+ return;
1356
+ }
1357
+ await handleRegularRelation();
1358
+ };
1359
+ const hasAccessToSomeScopes$1 = async (scopes, auth) => {
1360
+ for (const scope of scopes) {
1361
+ try {
1362
+ await strapi.auth.verify(auth, { scope });
1363
+ return true;
1364
+ } catch {
1365
+ continue;
1366
+ }
1367
+ }
1368
+ return false;
1369
+ };
1370
+ const visitor$6 = ({ key, attribute }, { remove }) => {
1371
+ if (isMorphToRelationalAttribute(attribute)) {
1372
+ remove(key);
1373
+ }
1374
+ };
1375
+ const visitor$5 = ({ key, attribute }, { remove }) => {
1376
+ if (isDynamicZoneAttribute(attribute)) {
1377
+ remove(key);
1378
+ }
1379
+ };
1380
+ const removeDisallowedFields = (allowedFields = null) => ({ key, path: { attribute: path } }, { remove }) => {
1381
+ if (allowedFields === null) {
1382
+ return;
1383
+ }
1384
+ if (!(fp.isArray(allowedFields) && allowedFields.every(fp.isString))) {
1385
+ throw new TypeError(
1386
+ `Expected array of strings for allowedFields but got "${typeof allowedFields}"`
1387
+ );
1388
+ }
1389
+ if (fp.isNil(path)) {
1390
+ return;
1391
+ }
1392
+ const containedPaths = getContainedPaths$1(path);
1393
+ const isPathAllowed = allowedFields.some(
1394
+ (p) => containedPaths.includes(p) || p.startsWith(`${path}.`)
1395
+ );
1396
+ if (isPathAllowed) {
1397
+ return;
1398
+ }
1399
+ remove(key);
1400
+ };
1401
+ const getContainedPaths$1 = (path) => {
1402
+ const parts = fp.toPath(path);
1403
+ return parts.reduce((acc, value, index2, list) => {
1404
+ return [...acc, list.slice(0, index2 + 1).join(".")];
1405
+ }, []);
1406
+ };
1407
+ const removeRestrictedFields = (restrictedFields = null) => ({ key, path: { attribute: path } }, { remove }) => {
1408
+ if (restrictedFields === null) {
1409
+ remove(key);
1410
+ return;
1411
+ }
1412
+ if (!(fp.isArray(restrictedFields) && restrictedFields.every(fp.isString))) {
1413
+ throw new TypeError(
1414
+ `Expected array of strings for restrictedFields but got "${typeof restrictedFields}"`
1415
+ );
1416
+ }
1417
+ if (restrictedFields.includes(path)) {
1418
+ remove(key);
1419
+ return;
1420
+ }
1421
+ const isRestrictedNested = restrictedFields.some(
1422
+ (allowedPath) => path?.toString().startsWith(`${allowedPath}.`)
1423
+ );
1424
+ if (isRestrictedNested) {
1425
+ remove(key);
1426
+ }
1427
+ };
1428
+ const visitor$4 = ({ schema, key, value }, { set }) => {
1429
+ if (key === "" && value === "*") {
1430
+ const { attributes } = schema;
1431
+ const newPopulateQuery = Object.entries(attributes).filter(
1432
+ ([, attribute]) => ["relation", "component", "media", "dynamiczone"].includes(attribute.type)
1433
+ ).reduce((acc, [key2]) => ({ ...acc, [key2]: true }), {});
1434
+ set("", newPopulateQuery);
1435
+ }
1436
+ };
1437
+ const index$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1438
+ __proto__: null,
1439
+ expandWildcardPopulate: visitor$4,
1440
+ removeDisallowedFields,
1441
+ removeDynamicZones: visitor$5,
1442
+ removeMorphToRelations: visitor$6,
1443
+ removePassword: visitor$8,
1444
+ removePrivate: visitor$7,
1445
+ removeRestrictedFields,
1446
+ removeRestrictedRelations
1447
+ }, Symbol.toStringTag, { value: "Module" }));
1448
+ const DEFAULT_PATH = { raw: null, attribute: null };
1449
+ const traverseFactory = () => {
1450
+ const state = {
1451
+ parsers: [],
1452
+ interceptors: [],
1453
+ ignore: [],
1454
+ handlers: {
1455
+ attributes: [],
1456
+ common: []
1457
+ }
1458
+ };
1459
+ const traverse = async (visitor2, options, data) => {
1460
+ const { path = DEFAULT_PATH, schema, getModel } = options ?? {};
1461
+ for (const { predicate, handler } of state.interceptors) {
1462
+ if (predicate(data)) {
1463
+ return handler(visitor2, options, data, { recurse: traverse });
1464
+ }
1465
+ }
1466
+ const parser = state.parsers.find((parser2) => parser2.predicate(data))?.parser;
1467
+ const utils2 = parser?.(data);
1468
+ if (!utils2) {
1469
+ return data;
1470
+ }
1471
+ let out = utils2.transform(data);
1472
+ const keys = utils2.keys(out);
1473
+ for (const key of keys) {
1474
+ const attribute = schema?.attributes?.[key];
1475
+ const newPath = { ...path };
1476
+ newPath.raw = fp.isNil(path.raw) ? key : `${path.raw}.${key}`;
1477
+ if (!fp.isNil(attribute)) {
1478
+ newPath.attribute = fp.isNil(path.attribute) ? key : `${path.attribute}.${key}`;
1479
+ }
1480
+ const visitorOptions = {
1481
+ key,
1482
+ value: utils2.get(key, out),
1483
+ attribute,
1484
+ schema,
1485
+ path: newPath,
1486
+ data: out,
1487
+ getModel
1488
+ };
1489
+ const transformUtils = {
1490
+ remove(key2) {
1491
+ out = utils2.remove(key2, out);
1492
+ },
1493
+ set(key2, value2) {
1494
+ out = utils2.set(key2, value2, out);
1495
+ },
1496
+ recurse: traverse
1497
+ };
1498
+ await visitor2(visitorOptions, fp.pick(["remove", "set"], transformUtils));
1499
+ const value = utils2.get(key, out);
1500
+ const createContext = () => ({
1501
+ key,
1502
+ value,
1503
+ attribute,
1504
+ schema,
1505
+ path: newPath,
1506
+ data: out,
1507
+ visitor: visitor2,
1508
+ getModel
1509
+ });
1510
+ const ignoreCtx = createContext();
1511
+ const shouldIgnore = state.ignore.some((predicate) => predicate(ignoreCtx));
1512
+ if (shouldIgnore) {
1513
+ continue;
1514
+ }
1515
+ const handlers = [...state.handlers.common, ...state.handlers.attributes];
1516
+ for await (const handler of handlers) {
1517
+ const ctx = createContext();
1518
+ const pass = await handler.predicate(ctx);
1519
+ if (pass) {
902
1520
  await handler.handler(ctx, fp.pick(["recurse", "set"], transformUtils));
903
1521
  }
904
1522
  }
@@ -976,33 +1594,33 @@ const filters = traverseFactory().intercept(
976
1594
  }
977
1595
  })).ignore(({ value }) => fp.isNil(value)).on(
978
1596
  ({ attribute }) => fp.isNil(attribute),
979
- async ({ key, visitor: visitor2, path, value, schema }, { set, recurse }) => {
980
- set(key, await recurse(visitor2, { schema, path }, value));
1597
+ async ({ key, visitor: visitor2, path, value, schema, getModel }, { set, recurse }) => {
1598
+ set(key, await recurse(visitor2, { schema, path, getModel }, value));
981
1599
  }
982
- ).onRelation(async ({ key, attribute, visitor: visitor2, path, value }, { set, recurse }) => {
1600
+ ).onRelation(async ({ key, attribute, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
983
1601
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
984
1602
  if (isMorphRelation) {
985
1603
  return;
986
1604
  }
987
1605
  const targetSchemaUID = attribute.target;
988
- const targetSchema = strapi.getModel(targetSchemaUID);
989
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1606
+ const targetSchema = getModel(targetSchemaUID);
1607
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
990
1608
  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);
1609
+ }).onComponent(async ({ key, attribute, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
1610
+ const targetSchema = getModel(attribute.component);
1611
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
994
1612
  set(key, newValue);
995
- }).onMedia(async ({ key, visitor: visitor2, path, value }, { set, recurse }) => {
1613
+ }).onMedia(async ({ key, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
996
1614
  const targetSchemaUID = "plugin::upload.file";
997
- const targetSchema = strapi.getModel(targetSchemaUID);
998
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1615
+ const targetSchema = getModel(targetSchemaUID);
1616
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
999
1617
  set(key, newValue);
1000
1618
  });
1001
1619
  const traverseQueryFilters = fp.curry(filters.traverse);
1002
1620
  const ORDERS = { asc: "asc", desc: "desc" };
1003
1621
  const ORDER_VALUES = Object.values(ORDERS);
1004
1622
  const isSortOrder = (value) => ORDER_VALUES.includes(value.toLowerCase());
1005
- const isStringArray$3 = (value) => Array.isArray(value) && value.every(fp.isString);
1623
+ const isStringArray$2 = (value) => Array.isArray(value) && value.every(fp.isString);
1006
1624
  const isObjectArray = (value) => Array.isArray(value) && value.every(fp.isObject);
1007
1625
  const isNestedSorts = (value) => fp.isString(value) && value.split(",").length > 1;
1008
1626
  const isObj$1 = (value) => fp.isObject(value);
@@ -1016,7 +1634,7 @@ const sort = traverseFactory().intercept(
1016
1634
  }
1017
1635
  ).intercept(
1018
1636
  // Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items
1019
- isStringArray$3,
1637
+ isStringArray$2,
1020
1638
  async (visitor2, options, sort2, { recurse }) => {
1021
1639
  return Promise.all(sort2.map((nestedSort) => recurse(visitor2, options, nestedSort))).then(
1022
1640
  (res) => res.filter((nestedSort) => !fp.isEmpty(nestedSort))
@@ -1083,23 +1701,23 @@ const sort = traverseFactory().intercept(
1083
1701
  get(key, data) {
1084
1702
  return data[key];
1085
1703
  }
1086
- })).onRelation(async ({ key, value, attribute, visitor: visitor2, path }, { set, recurse }) => {
1704
+ })).onRelation(async ({ key, value, attribute, visitor: visitor2, path, getModel }, { set, recurse }) => {
1087
1705
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
1088
1706
  if (isMorphRelation) {
1089
1707
  return;
1090
1708
  }
1091
1709
  const targetSchemaUID = attribute.target;
1092
- const targetSchema = strapi.getModel(targetSchemaUID);
1093
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1710
+ const targetSchema = getModel(targetSchemaUID);
1711
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1094
1712
  set(key, newValue);
1095
- }).onMedia(async ({ key, path, visitor: visitor2, value }, { recurse, set }) => {
1713
+ }).onMedia(async ({ key, path, visitor: visitor2, value, getModel }, { recurse, set }) => {
1096
1714
  const targetSchemaUID = "plugin::upload.file";
1097
- const targetSchema = strapi.getModel(targetSchemaUID);
1098
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1715
+ const targetSchema = getModel(targetSchemaUID);
1716
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1099
1717
  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);
1718
+ }).onComponent(async ({ key, value, visitor: visitor2, path, attribute, getModel }, { recurse, set }) => {
1719
+ const targetSchema = getModel(attribute.component);
1720
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1103
1721
  set(key, newValue);
1104
1722
  });
1105
1723
  const traverseQuerySort = fp.curry(sort.traverse);
@@ -1108,9 +1726,9 @@ const isKeyword = (keyword) => {
1108
1726
  return !attribute && keyword === key;
1109
1727
  };
1110
1728
  };
1111
- const isStringArray$2 = (value) => fp.isArray(value) && value.every(fp.isString);
1729
+ const isStringArray$1 = (value) => fp.isArray(value) && value.every(fp.isString);
1112
1730
  const isObj = (value) => fp.isObject(value);
1113
- const populate = traverseFactory().intercept(isStringArray$2, async (visitor2, options, populate2, { recurse }) => {
1731
+ const populate = traverseFactory().intercept(isStringArray$1, async (visitor2, options, populate2, { recurse }) => {
1114
1732
  const visitedPopulate = await Promise.all(
1115
1733
  populate2.map((nestedPopulate) => recurse(visitor2, options, nestedPopulate))
1116
1734
  );
@@ -1187,78 +1805,86 @@ const populate = traverseFactory().intercept(isStringArray$2, async (visitor2, o
1187
1805
  }).on(
1188
1806
  // Handle recursion on populate."populate"
1189
1807
  isKeyword("populate"),
1190
- async ({ key, visitor: visitor2, path, value, schema }, { set, recurse }) => {
1191
- const newValue = await recurse(visitor2, { schema, path }, value);
1808
+ async ({ key, visitor: visitor2, path, value, schema, getModel }, { set, recurse }) => {
1809
+ const newValue = await recurse(visitor2, { schema, path, getModel }, value);
1192
1810
  set(key, newValue);
1193
1811
  }
1194
- ).on(isKeyword("on"), async ({ key, visitor: visitor2, path, value }, { set, recurse }) => {
1812
+ ).on(isKeyword("on"), async ({ key, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
1195
1813
  const newOn = {};
1196
1814
  if (!isObj(value)) {
1197
1815
  return;
1198
1816
  }
1199
1817
  for (const [uid, subPopulate] of Object.entries(value)) {
1200
- const model = strapi.getModel(uid);
1818
+ const model = getModel(uid);
1201
1819
  const newPath = { ...path, raw: `${path.raw}[${uid}]` };
1202
- newOn[uid] = await recurse(visitor2, { schema: model, path: newPath }, subPopulate);
1820
+ newOn[uid] = await recurse(visitor2, { schema: model, path: newPath, getModel }, subPopulate);
1203
1821
  }
1204
1822
  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))) {
1823
+ }).onRelation(
1824
+ async ({ key, value, attribute, visitor: visitor2, path, schema, getModel }, { set, recurse }) => {
1825
+ if (fp.isNil(value)) {
1211
1826
  return;
1212
1827
  }
1213
- const newValue2 = await recurse(visitor2, { schema, path }, { on: value?.on });
1214
- set(key, { on: newValue2 });
1828
+ if (isMorphToRelationalAttribute(attribute)) {
1829
+ if (!fp.isObject(value) || !("on" in value && fp.isObject(value?.on))) {
1830
+ return;
1831
+ }
1832
+ const newValue2 = await recurse(visitor2, { schema, path, getModel }, { on: value?.on });
1833
+ set(key, { on: newValue2 });
1834
+ }
1835
+ const targetSchemaUID = attribute.target;
1836
+ const targetSchema = getModel(targetSchemaUID);
1837
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1838
+ set(key, newValue);
1215
1839
  }
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 }) => {
1840
+ ).onMedia(async ({ key, path, visitor: visitor2, value, getModel }, { recurse, set }) => {
1221
1841
  if (fp.isNil(value)) {
1222
1842
  return;
1223
1843
  }
1224
1844
  const targetSchemaUID = "plugin::upload.file";
1225
- const targetSchema = strapi.getModel(targetSchemaUID);
1226
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1845
+ const targetSchema = getModel(targetSchemaUID);
1846
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1227
1847
  set(key, newValue);
1228
- }).onComponent(async ({ key, value, visitor: visitor2, path, attribute }, { recurse, set }) => {
1848
+ }).onComponent(async ({ key, value, visitor: visitor2, path, attribute, getModel }, { recurse, set }) => {
1229
1849
  if (fp.isNil(value)) {
1230
1850
  return;
1231
1851
  }
1232
- const targetSchema = strapi.getModel(attribute.component);
1233
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1852
+ const targetSchema = getModel(attribute.component);
1853
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1234
1854
  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);
1855
+ }).onDynamicZone(
1856
+ async ({ key, value, attribute, schema, visitor: visitor2, path, getModel }, { set, recurse }) => {
1857
+ if (fp.isNil(value)) {
1858
+ return;
1247
1859
  }
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);
1860
+ if (fp.isObject(value)) {
1861
+ const { components } = attribute;
1862
+ const newValue = {};
1863
+ let newProperties = fp.omit("on", value);
1864
+ for (const componentUID of components) {
1865
+ const componentSchema = getModel(componentUID);
1866
+ const properties = await recurse(
1867
+ visitor2,
1868
+ { schema: componentSchema, path, getModel },
1869
+ value
1870
+ );
1871
+ newProperties = fp.merge(newProperties, properties);
1872
+ }
1873
+ Object.assign(newValue, newProperties);
1874
+ if ("on" in value && value.on) {
1875
+ const newOn = await recurse(visitor2, { schema, path, getModel }, { on: value.on });
1876
+ Object.assign(newValue, newOn);
1877
+ }
1878
+ set(key, newValue);
1879
+ } else {
1880
+ const newValue = await recurse(visitor2, { schema, path, getModel }, value);
1881
+ set(key, newValue);
1252
1882
  }
1253
- set(key, newValue);
1254
- } else {
1255
- const newValue = await recurse(visitor2, { schema, path }, value);
1256
- set(key, newValue);
1257
1883
  }
1258
- });
1884
+ );
1259
1885
  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 }) => {
1886
+ const isStringArray = (value) => fp.isArray(value) && value.every(fp.isString);
1887
+ const fields = traverseFactory().intercept(isStringArray, async (visitor2, options, fields2, { recurse }) => {
1262
1888
  return Promise.all(fields2.map((field) => recurse(visitor2, options, field)));
1263
1889
  }).intercept((value) => fp.eq("*", value), fp.constant("*")).parse(fp.isString, () => ({
1264
1890
  transform: fp.trim,
@@ -1276,90 +1902,22 @@ const fields = traverseFactory().intercept(isStringArray$1, async (visitor2, opt
1276
1902
  }
1277
1903
  }));
1278
1904
  const traverseQueryFields = fp.curry(fields.traverse);
1279
- const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1905
+ const index$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1280
1906
  __proto__: null,
1281
- factory: traverseFactory,
1282
1907
  traverseQueryFields,
1283
1908
  traverseQueryFilters,
1284
1909
  traverseQueryPopulate,
1285
1910
  traverseQuerySort
1286
1911
  }, 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) {
1912
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$2 } = constants$1;
1913
+ const sanitizePasswords = (ctx) => async (entity) => {
1914
+ if (!ctx.schema) {
1357
1915
  throw new Error("Missing schema in sanitizePasswords");
1358
1916
  }
1359
- return traverseEntity$1(visitor$8, { schema }, entity);
1917
+ return traverseEntity$1(visitor$8, ctx, entity);
1360
1918
  };
1361
- const defaultSanitizeOutput = async (schema, entity) => {
1362
- if (!schema) {
1919
+ const defaultSanitizeOutput = async (ctx, entity) => {
1920
+ if (!ctx.schema) {
1363
1921
  throw new Error("Missing schema in defaultSanitizeOutput");
1364
1922
  }
1365
1923
  return traverseEntity$1(
@@ -1367,139 +1925,121 @@ const defaultSanitizeOutput = async (schema, entity) => {
1367
1925
  visitor$8(...args);
1368
1926
  visitor$7(...args);
1369
1927
  },
1370
- { schema },
1928
+ ctx,
1371
1929
  entity
1372
1930
  );
1373
1931
  };
1374
- const defaultSanitizeFilters = fp.curry((schema, filters2) => {
1375
- if (!schema) {
1932
+ const defaultSanitizeFilters = fp.curry((ctx, filters2) => {
1933
+ if (!ctx.schema) {
1376
1934
  throw new Error("Missing schema in defaultSanitizeFilters");
1377
1935
  }
1378
1936
  return pipe(
1379
1937
  // 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
- ),
1938
+ traverseQueryFilters(({ key, attribute }, { remove }) => {
1939
+ const isAttribute = !!attribute;
1940
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1941
+ return;
1942
+ }
1943
+ if (!isAttribute && !isOperator(key)) {
1944
+ remove(key);
1945
+ }
1946
+ }, ctx),
1392
1947
  // Remove dynamic zones from filters
1393
- traverseQueryFilters(visitor$5, { schema }),
1948
+ traverseQueryFilters(visitor$5, ctx),
1394
1949
  // Remove morpTo relations from filters
1395
- traverseQueryFilters(visitor$6, { schema }),
1950
+ traverseQueryFilters(visitor$6, ctx),
1396
1951
  // Remove passwords from filters
1397
- traverseQueryFilters(visitor$8, { schema }),
1952
+ traverseQueryFilters(visitor$8, ctx),
1398
1953
  // Remove private from filters
1399
- traverseQueryFilters(visitor$7, { schema }),
1954
+ traverseQueryFilters(visitor$7, ctx),
1400
1955
  // 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
- )
1956
+ traverseQueryFilters(({ key, value }, { remove }) => {
1957
+ if (fp.isObject(value) && fp.isEmpty(value)) {
1958
+ remove(key);
1959
+ }
1960
+ }, ctx)
1409
1961
  )(filters2);
1410
1962
  });
1411
- const defaultSanitizeSort = fp.curry((schema, sort2) => {
1412
- if (!schema) {
1963
+ const defaultSanitizeSort = fp.curry((ctx, sort2) => {
1964
+ if (!ctx.schema) {
1413
1965
  throw new Error("Missing schema in defaultSanitizeSort");
1414
1966
  }
1415
1967
  return pipe(
1416
1968
  // 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
- ),
1969
+ traverseQuerySort(({ key, attribute }, { remove }) => {
1970
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1971
+ return;
1972
+ }
1973
+ if (!attribute) {
1974
+ remove(key);
1975
+ }
1976
+ }, ctx),
1428
1977
  // Remove dynamic zones from sort
1429
- traverseQuerySort(visitor$5, { schema }),
1978
+ traverseQuerySort(visitor$5, ctx),
1430
1979
  // Remove morpTo relations from sort
1431
- traverseQuerySort(visitor$6, { schema }),
1980
+ traverseQuerySort(visitor$6, ctx),
1432
1981
  // Remove private from sort
1433
- traverseQuerySort(visitor$7, { schema }),
1982
+ traverseQuerySort(visitor$7, ctx),
1434
1983
  // Remove passwords from filters
1435
- traverseQuerySort(visitor$8, { schema }),
1984
+ traverseQuerySort(visitor$8, ctx),
1436
1985
  // 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
- )
1986
+ traverseQuerySort(({ key, attribute, value }, { remove }) => {
1987
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1988
+ return;
1989
+ }
1990
+ if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
1991
+ remove(key);
1992
+ }
1993
+ }, ctx)
1448
1994
  )(sort2);
1449
1995
  });
1450
- const defaultSanitizeFields = fp.curry((schema, fields2) => {
1451
- if (!schema) {
1996
+ const defaultSanitizeFields = fp.curry((ctx, fields2) => {
1997
+ if (!ctx.schema) {
1452
1998
  throw new Error("Missing schema in defaultSanitizeFields");
1453
1999
  }
1454
2000
  return pipe(
1455
2001
  // 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
- ),
2002
+ traverseQueryFields(({ key, attribute }, { remove }) => {
2003
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
2004
+ return;
2005
+ }
2006
+ if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
2007
+ remove(key);
2008
+ }
2009
+ }, ctx),
1467
2010
  // Remove private fields
1468
- traverseQueryFields(visitor$7, { schema }),
2011
+ traverseQueryFields(visitor$7, ctx),
1469
2012
  // Remove password fields
1470
- traverseQueryFields(visitor$8, { schema }),
2013
+ traverseQueryFields(visitor$8, ctx),
1471
2014
  // Remove nil values from fields array
1472
2015
  (value) => fp.isArray(value) ? value.filter((field) => !fp.isNil(field)) : value
1473
2016
  )(fields2);
1474
2017
  });
1475
- const defaultSanitizePopulate = fp.curry((schema, populate2) => {
1476
- if (!schema) {
2018
+ const defaultSanitizePopulate = fp.curry((ctx, populate2) => {
2019
+ if (!ctx.schema) {
1477
2020
  throw new Error("Missing schema in defaultSanitizePopulate");
1478
2021
  }
1479
2022
  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
- ),
2023
+ traverseQueryPopulate(visitor$4, ctx),
2024
+ traverseQueryPopulate(async ({ key, value, schema, attribute, getModel }, { set }) => {
2025
+ if (attribute) {
2026
+ return;
2027
+ }
2028
+ if (key === "sort") {
2029
+ set(key, await defaultSanitizeSort({ schema, getModel }, value));
2030
+ }
2031
+ if (key === "filters") {
2032
+ set(key, await defaultSanitizeFilters({ schema, getModel }, value));
2033
+ }
2034
+ if (key === "fields") {
2035
+ set(key, await defaultSanitizeFields({ schema, getModel }, value));
2036
+ }
2037
+ if (key === "populate") {
2038
+ set(key, await defaultSanitizePopulate({ schema, getModel }, value));
2039
+ }
2040
+ }, ctx),
1501
2041
  // Remove private fields
1502
- traverseQueryPopulate(visitor$7, { schema })
2042
+ traverseQueryPopulate(visitor$7, ctx)
1503
2043
  )(populate2);
1504
2044
  });
1505
2045
  const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -1511,7 +2051,8 @@ const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
1511
2051
  defaultSanitizeSort,
1512
2052
  sanitizePasswords
1513
2053
  }, Symbol.toStringTag, { value: "Module" }));
1514
- const createContentAPISanitizers = () => {
2054
+ const createAPISanitizers = (opts) => {
2055
+ const { getModel } = opts;
1515
2056
  const sanitizeInput = (data, schema, { auth } = {}) => {
1516
2057
  if (!schema) {
1517
2058
  throw new Error("Missing schema in sanitizeInput");
@@ -1525,12 +2066,14 @@ const createContentAPISanitizers = () => {
1525
2066
  fp.omit(constants$1.ID_ATTRIBUTE),
1526
2067
  fp.omit(constants$1.DOC_ID_ATTRIBUTE),
1527
2068
  // Remove non-writable attributes
1528
- traverseEntity$1(removeRestrictedFields(nonWritableAttributes), { schema })
2069
+ traverseEntity$1(removeRestrictedFields(nonWritableAttributes), { schema, getModel })
1529
2070
  ];
1530
2071
  if (auth) {
1531
- transforms.push(traverseEntity$1(removeRestrictedRelations(auth), { schema }));
2072
+ transforms.push(
2073
+ traverseEntity$1(removeRestrictedRelations(auth), { schema, getModel })
2074
+ );
1532
2075
  }
1533
- strapi.sanitizers.get("content-api.input").forEach((sanitizer) => transforms.push(sanitizer(schema)));
2076
+ opts?.sanitizers?.input?.forEach((sanitizer) => transforms.push(sanitizer(schema)));
1534
2077
  return pipe(...transforms)(data);
1535
2078
  };
1536
2079
  const sanitizeOutput = async (data, schema, { auth } = {}) => {
@@ -1544,11 +2087,15 @@ const createContentAPISanitizers = () => {
1544
2087
  }
1545
2088
  return res;
1546
2089
  }
1547
- const transforms = [(data2) => defaultSanitizeOutput(schema, data2)];
2090
+ const transforms = [
2091
+ (data2) => defaultSanitizeOutput({ schema, getModel }, data2)
2092
+ ];
1548
2093
  if (auth) {
1549
- transforms.push(traverseEntity$1(removeRestrictedRelations(auth), { schema }));
2094
+ transforms.push(
2095
+ traverseEntity$1(removeRestrictedRelations(auth), { schema, getModel })
2096
+ );
1550
2097
  }
1551
- strapi.sanitizers.get("content-api.output").forEach((sanitizer) => transforms.push(sanitizer(schema)));
2098
+ opts?.sanitizers?.output?.forEach((sanitizer) => transforms.push(sanitizer(schema)));
1552
2099
  return pipe(...transforms)(data);
1553
2100
  };
1554
2101
  const sanitizeQuery = async (query, schema, { auth } = {}) => {
@@ -1578,9 +2125,11 @@ const createContentAPISanitizers = () => {
1578
2125
  if (fp.isArray(filters2)) {
1579
2126
  return Promise.all(filters2.map((filter) => sanitizeFilters(filter, schema, { auth })));
1580
2127
  }
1581
- const transforms = [defaultSanitizeFilters(schema)];
2128
+ const transforms = [defaultSanitizeFilters({ schema, getModel })];
1582
2129
  if (auth) {
1583
- transforms.push(traverseQueryFilters(removeRestrictedRelations(auth), { schema }));
2130
+ transforms.push(
2131
+ traverseQueryFilters(removeRestrictedRelations(auth), { schema, getModel })
2132
+ );
1584
2133
  }
1585
2134
  return pipe(...transforms)(filters2);
1586
2135
  };
@@ -1588,9 +2137,11 @@ const createContentAPISanitizers = () => {
1588
2137
  if (!schema) {
1589
2138
  throw new Error("Missing schema in sanitizeSort");
1590
2139
  }
1591
- const transforms = [defaultSanitizeSort(schema)];
2140
+ const transforms = [defaultSanitizeSort({ schema, getModel })];
1592
2141
  if (auth) {
1593
- transforms.push(traverseQuerySort(removeRestrictedRelations(auth), { schema }));
2142
+ transforms.push(
2143
+ traverseQuerySort(removeRestrictedRelations(auth), { schema, getModel })
2144
+ );
1594
2145
  }
1595
2146
  return pipe(...transforms)(sort2);
1596
2147
  };
@@ -1598,16 +2149,18 @@ const createContentAPISanitizers = () => {
1598
2149
  if (!schema) {
1599
2150
  throw new Error("Missing schema in sanitizeFields");
1600
2151
  }
1601
- const transforms = [defaultSanitizeFields(schema)];
2152
+ const transforms = [defaultSanitizeFields({ schema, getModel })];
1602
2153
  return pipe(...transforms)(fields2);
1603
2154
  };
1604
2155
  const sanitizePopulate = (populate2, schema, { auth } = {}) => {
1605
2156
  if (!schema) {
1606
2157
  throw new Error("Missing schema in sanitizePopulate");
1607
2158
  }
1608
- const transforms = [defaultSanitizePopulate(schema)];
2159
+ const transforms = [defaultSanitizePopulate({ schema, getModel })];
1609
2160
  if (auth) {
1610
- transforms.push(traverseQueryPopulate(removeRestrictedRelations(auth), { schema }));
2161
+ transforms.push(
2162
+ traverseQueryPopulate(removeRestrictedRelations(auth), { schema, getModel })
2163
+ );
1611
2164
  }
1612
2165
  return pipe(...transforms)(populate2);
1613
2166
  };
@@ -1621,118 +2174,11 @@ const createContentAPISanitizers = () => {
1621
2174
  populate: sanitizePopulate
1622
2175
  };
1623
2176
  };
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({
2177
+ const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1723
2178
  __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
2179
+ createAPISanitizers,
2180
+ sanitizers,
2181
+ visitors: index$4
1736
2182
  }, Symbol.toStringTag, { value: "Module" }));
1737
2183
  const throwInvalidParam = ({ key, path }) => {
1738
2184
  const msg = path && path !== key ? `Invalid parameter ${key} at ${path}` : `Invalid parameter ${key}`;
@@ -1855,7 +2301,7 @@ const throwRestrictedFields = (restrictedFields = null) => ({ key, path: { attri
1855
2301
  throwInvalidParam({ key, path });
1856
2302
  }
1857
2303
  };
1858
- const visitors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2304
+ const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1859
2305
  __proto__: null,
1860
2306
  throwDisallowedFields,
1861
2307
  throwDynamicZones: visitor,
@@ -1865,131 +2311,152 @@ const visitors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
1865
2311
  throwRestrictedFields,
1866
2312
  throwRestrictedRelations
1867
2313
  }, 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) {
2314
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$1 } = constants$1;
2315
+ const throwPasswords = (ctx) => async (entity) => {
2316
+ if (!ctx.schema) {
1871
2317
  throw new Error("Missing schema in throwPasswords");
1872
2318
  }
1873
- return traverseEntity$1(visitor$3, { schema }, entity);
2319
+ return traverseEntity$1(visitor$3, ctx, entity);
1874
2320
  };
1875
- const defaultValidateFilters = fp.curry((schema, filters2) => {
1876
- if (!schema) {
2321
+ const defaultValidateFilters = fp.curry((ctx, filters2) => {
2322
+ if (!ctx.schema) {
1877
2323
  throw new Error("Missing schema in defaultValidateFilters");
1878
2324
  }
1879
2325
  return pipe(
1880
2326
  // 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
- ),
2327
+ traverseQueryFilters(({ key, attribute, path }) => {
2328
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2329
+ return;
2330
+ }
2331
+ const isAttribute = !!attribute;
2332
+ if (!isAttribute && !isOperator(key)) {
2333
+ throwInvalidParam({ key, path: path.attribute });
2334
+ }
2335
+ }, ctx),
1893
2336
  // dynamic zones from filters
1894
- traverseQueryFilters(visitor, { schema }),
2337
+ traverseQueryFilters(visitor, ctx),
1895
2338
  // morphTo relations from filters; because you can't have deep filtering on morph relations
1896
- traverseQueryFilters(visitor$1, { schema }),
2339
+ traverseQueryFilters(visitor$1, ctx),
1897
2340
  // passwords from filters
1898
- traverseQueryFilters(visitor$3, { schema }),
2341
+ traverseQueryFilters(visitor$3, ctx),
1899
2342
  // private from filters
1900
- traverseQueryFilters(visitor$2, { schema })
2343
+ traverseQueryFilters(visitor$2, ctx)
1901
2344
  // we allow empty objects to validate and only sanitize them out, so that users may write "lazy" queries without checking their params exist
1902
2345
  )(filters2);
1903
2346
  });
1904
- const defaultValidateSort = fp.curry((schema, sort2) => {
1905
- if (!schema) {
2347
+ const defaultValidateSort = fp.curry((ctx, sort2) => {
2348
+ if (!ctx.schema) {
1906
2349
  throw new Error("Missing schema in defaultValidateSort");
1907
2350
  }
1908
2351
  return pipe(
1909
2352
  // 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
- ),
2353
+ traverseQuerySort(({ key, attribute, path }) => {
2354
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2355
+ return;
2356
+ }
2357
+ if (!attribute) {
2358
+ throwInvalidParam({ key, path: path.attribute });
2359
+ }
2360
+ }, ctx),
1921
2361
  // dynamic zones from sort
1922
- traverseQuerySort(visitor, { schema }),
2362
+ traverseQuerySort(visitor, ctx),
1923
2363
  // morphTo relations from sort
1924
- traverseQuerySort(visitor$1, { schema }),
2364
+ traverseQuerySort(visitor$1, ctx),
1925
2365
  // private from sort
1926
- traverseQuerySort(visitor$2, { schema }),
2366
+ traverseQuerySort(visitor$2, ctx),
1927
2367
  // passwords from filters
1928
- traverseQuerySort(visitor$3, { schema }),
2368
+ traverseQuerySort(visitor$3, ctx),
1929
2369
  // 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
- )
2370
+ traverseQuerySort(({ key, attribute, value, path }) => {
2371
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2372
+ return;
2373
+ }
2374
+ if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
2375
+ throwInvalidParam({ key, path: path.attribute });
2376
+ }
2377
+ }, ctx)
1941
2378
  )(sort2);
1942
2379
  });
1943
- const defaultValidateFields = fp.curry((schema, fields2) => {
1944
- if (!schema) {
2380
+ const defaultValidateFields = fp.curry((ctx, fields2) => {
2381
+ if (!ctx.schema) {
1945
2382
  throw new Error("Missing schema in defaultValidateFields");
1946
2383
  }
1947
2384
  return pipe(
1948
2385
  // 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
- ),
2386
+ traverseQueryFields(({ key, attribute, path }) => {
2387
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2388
+ return;
2389
+ }
2390
+ if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
2391
+ throwInvalidParam({ key, path: path.attribute });
2392
+ }
2393
+ }, ctx),
1960
2394
  // private fields
1961
- traverseQueryFields(visitor$2, { schema }),
2395
+ traverseQueryFields(visitor$2, ctx),
1962
2396
  // password fields
1963
- traverseQueryFields(visitor$3, { schema })
2397
+ traverseQueryFields(visitor$3, ctx)
1964
2398
  )(fields2);
1965
2399
  });
1966
- const defaultValidatePopulate = fp.curry((schema, populate2) => {
1967
- if (!schema) {
2400
+ const defaultValidatePopulate = fp.curry((ctx, populate2) => {
2401
+ if (!ctx.schema) {
1968
2402
  throw new Error("Missing schema in defaultValidatePopulate");
1969
2403
  }
1970
2404
  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
- ),
2405
+ traverseQueryPopulate(async ({ key, value, schema, attribute, getModel }, { set }) => {
2406
+ if (attribute) {
2407
+ return;
2408
+ }
2409
+ if (key === "sort") {
2410
+ set(
2411
+ key,
2412
+ await defaultValidateSort(
2413
+ {
2414
+ schema,
2415
+ getModel
2416
+ },
2417
+ value
2418
+ )
2419
+ );
2420
+ }
2421
+ if (key === "filters") {
2422
+ set(
2423
+ key,
2424
+ await defaultValidateFilters(
2425
+ {
2426
+ schema,
2427
+ getModel
2428
+ },
2429
+ value
2430
+ )
2431
+ );
2432
+ }
2433
+ if (key === "fields") {
2434
+ set(
2435
+ key,
2436
+ await defaultValidateFields(
2437
+ {
2438
+ schema,
2439
+ getModel
2440
+ },
2441
+ value
2442
+ )
2443
+ );
2444
+ }
2445
+ if (key === "populate") {
2446
+ set(
2447
+ key,
2448
+ await defaultValidatePopulate(
2449
+ {
2450
+ schema,
2451
+ getModel
2452
+ },
2453
+ value
2454
+ )
2455
+ );
2456
+ }
2457
+ }, ctx),
1991
2458
  // Remove private fields
1992
- traverseQueryPopulate(visitor$2, { schema })
2459
+ traverseQueryPopulate(visitor$2, ctx)
1993
2460
  )(populate2);
1994
2461
  });
1995
2462
  const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -2000,8 +2467,9 @@ const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
2000
2467
  defaultValidateSort,
2001
2468
  throwPasswords
2002
2469
  }, Symbol.toStringTag, { value: "Module" }));
2003
- const { ID_ATTRIBUTE: ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$1 } = constants$1;
2004
- const createContentAPIValidators = () => {
2470
+ const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants$1;
2471
+ const createAPIValidators = (opts) => {
2472
+ const { getModel } = opts || {};
2005
2473
  const validateInput = async (data, schema, { auth } = {}) => {
2006
2474
  if (!schema) {
2007
2475
  throw new Error("Missing schema in validateInput");
@@ -2014,21 +2482,26 @@ const createContentAPIValidators = () => {
2014
2482
  const transforms = [
2015
2483
  (data2) => {
2016
2484
  if (fp.isObject(data2)) {
2017
- if (ID_ATTRIBUTE$1 in data2) {
2018
- throwInvalidParam({ key: ID_ATTRIBUTE$1 });
2485
+ if (ID_ATTRIBUTE in data2) {
2486
+ throwInvalidParam({ key: ID_ATTRIBUTE });
2019
2487
  }
2020
- if (DOC_ID_ATTRIBUTE$1 in data2) {
2021
- throwInvalidParam({ key: DOC_ID_ATTRIBUTE$1 });
2488
+ if (DOC_ID_ATTRIBUTE in data2) {
2489
+ throwInvalidParam({ key: DOC_ID_ATTRIBUTE });
2022
2490
  }
2023
2491
  }
2024
2492
  },
2025
2493
  // non-writable attributes
2026
- traverseEntity$1(throwRestrictedFields(nonWritableAttributes), { schema })
2494
+ traverseEntity$1(throwRestrictedFields(nonWritableAttributes), { schema, getModel })
2027
2495
  ];
2028
2496
  if (auth) {
2029
- transforms.push(traverseEntity$1(throwRestrictedRelations(auth), { schema }));
2030
- }
2031
- strapi.validators.get("content-api.input").forEach((validator) => transforms.push(validator(schema)));
2497
+ transforms.push(
2498
+ traverseEntity$1(throwRestrictedRelations(auth), {
2499
+ schema,
2500
+ getModel
2501
+ })
2502
+ );
2503
+ }
2504
+ opts?.validators?.input?.forEach((validator) => transforms.push(validator(schema)));
2032
2505
  await pipe(...transforms)(data);
2033
2506
  };
2034
2507
  const validateQuery = async (query, schema, { auth } = {}) => {
@@ -2057,9 +2530,14 @@ const createContentAPIValidators = () => {
2057
2530
  await Promise.all(filters2.map((filter) => validateFilters(filter, schema, { auth })));
2058
2531
  return;
2059
2532
  }
2060
- const transforms = [defaultValidateFilters(schema)];
2533
+ const transforms = [defaultValidateFilters({ schema, getModel })];
2061
2534
  if (auth) {
2062
- transforms.push(traverseQueryFilters(throwRestrictedRelations(auth), { schema }));
2535
+ transforms.push(
2536
+ traverseQueryFilters(throwRestrictedRelations(auth), {
2537
+ schema,
2538
+ getModel
2539
+ })
2540
+ );
2063
2541
  }
2064
2542
  await pipe(...transforms)(filters2);
2065
2543
  };
@@ -2067,9 +2545,14 @@ const createContentAPIValidators = () => {
2067
2545
  if (!schema) {
2068
2546
  throw new Error("Missing schema in validateSort");
2069
2547
  }
2070
- const transforms = [defaultValidateSort(schema)];
2548
+ const transforms = [defaultValidateSort({ schema, getModel })];
2071
2549
  if (auth) {
2072
- transforms.push(traverseQuerySort(throwRestrictedRelations(auth), { schema }));
2550
+ transforms.push(
2551
+ traverseQuerySort(throwRestrictedRelations(auth), {
2552
+ schema,
2553
+ getModel
2554
+ })
2555
+ );
2073
2556
  }
2074
2557
  await pipe(...transforms)(sort2);
2075
2558
  };
@@ -2077,16 +2560,21 @@ const createContentAPIValidators = () => {
2077
2560
  if (!schema) {
2078
2561
  throw new Error("Missing schema in validateFields");
2079
2562
  }
2080
- const transforms = [defaultValidateFields(schema)];
2563
+ const transforms = [defaultValidateFields({ schema, getModel })];
2081
2564
  await pipe(...transforms)(fields2);
2082
2565
  };
2083
2566
  const validatePopulate = async (populate2, schema, { auth } = {}) => {
2084
2567
  if (!schema) {
2085
2568
  throw new Error("Missing schema in sanitizePopulate");
2086
2569
  }
2087
- const transforms = [defaultValidatePopulate(schema)];
2570
+ const transforms = [defaultValidatePopulate({ schema, getModel })];
2088
2571
  if (auth) {
2089
- transforms.push(traverseQueryPopulate(throwRestrictedRelations(auth), { schema }));
2572
+ transforms.push(
2573
+ traverseQueryPopulate(throwRestrictedRelations(auth), {
2574
+ schema,
2575
+ getModel
2576
+ })
2577
+ );
2090
2578
  }
2091
2579
  await pipe(...transforms)(populate2);
2092
2580
  };
@@ -2099,436 +2587,12 @@ const createContentAPIValidators = () => {
2099
2587
  populate: validatePopulate
2100
2588
  };
2101
2589
  };
2102
- const contentAPI = createContentAPIValidators();
2103
- const index = {
2104
- contentAPI,
2590
+ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2591
+ __proto__: null,
2592
+ createAPIValidators,
2105
2593
  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
- };
2594
+ visitors: index$1
2595
+ }, Symbol.toStringTag, { value: "Module" }));
2532
2596
  const STRAPI_DEFAULTS = {
2533
2597
  offset: {
2534
2598
  start: 0,
@@ -2680,72 +2744,6 @@ const file = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
2680
2744
  streamToBuffer,
2681
2745
  writableDiscardStream
2682
2746
  }, 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
2747
  const createPolicy = (options) => {
2750
2748
  const { name = "unnamed", validator, handler } = options;
2751
2749
  const wrappedValidator = (config) => {
@@ -2777,10 +2775,7 @@ const createPolicyContext = (type, ctx) => {
2777
2775
  const policy = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2778
2776
  __proto__: null,
2779
2777
  createPolicy,
2780
- createPolicyContext,
2781
- get: getPolicy,
2782
- globalPolicy,
2783
- resolve: resolvePolicies
2778
+ createPolicyContext
2784
2779
  }, Symbol.toStringTag, { value: "Module" }));
2785
2780
  const nameToSlug = (name, options = { separator: "-" }) => slugify__default.default(name, options);
2786
2781
  const nameToCollectionName = (name) => slugify__default.default(name, { separator: "_" });
@@ -3019,10 +3014,30 @@ const relations = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePro
3019
3014
  isManyToAny,
3020
3015
  isOneToAny
3021
3016
  }, Symbol.toStringTag, { value: "Module" }));
3017
+ const validateZod = (schema) => (data) => {
3018
+ try {
3019
+ return schema.parse(data);
3020
+ } catch (error) {
3021
+ if (error instanceof zod.z.ZodError) {
3022
+ const { message, errors: errors2 } = formatZodErrors(error);
3023
+ throw new ValidationError(message, { errors: errors2 });
3024
+ }
3025
+ throw error;
3026
+ }
3027
+ };
3028
+ const formatZodErrors = (zodError) => ({
3029
+ errors: zodError.errors.map((error) => {
3030
+ return {
3031
+ path: error.path,
3032
+ message: error.message,
3033
+ name: "ValidationError"
3034
+ };
3035
+ }),
3036
+ message: "Validation error"
3037
+ });
3022
3038
  exports.arrays = arrays;
3023
3039
  exports.async = async;
3024
3040
  exports.contentTypes = contentTypes;
3025
- exports.convertQueryParams = convertQueryParams;
3026
3041
  exports.dates = dates;
3027
3042
  exports.env = env;
3028
3043
  exports.errors = errors;
@@ -3038,15 +3053,17 @@ exports.pagination = pagination;
3038
3053
  exports.parseType = parseType;
3039
3054
  exports.policy = policy;
3040
3055
  exports.providerFactory = providerFactory;
3056
+ exports.queryParams = convertQueryParams;
3041
3057
  exports.relations = relations;
3042
- exports.sanitize = index$1;
3058
+ exports.sanitize = index$2;
3043
3059
  exports.setCreatorFields = setCreatorFields;
3044
3060
  exports.strings = strings;
3045
3061
  exports.template = template;
3046
- exports.traverse = index$2;
3062
+ exports.traverse = index$3;
3047
3063
  exports.traverseEntity = traverseEntity$1;
3048
3064
  exports.validate = index;
3049
3065
  exports.validateYupSchema = validateYupSchema;
3050
3066
  exports.validateYupSchemaSync = validateYupSchemaSync;
3067
+ exports.validateZod = validateZod;
3051
3068
  exports.yup = yup;
3052
3069
  //# sourceMappingURL=index.js.map