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

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