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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,14 +1,15 @@
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";
11
11
  import slugify from "@sindresorhus/slugify";
12
+ import { z } from "zod";
12
13
  function _mergeNamespaces(n, m) {
13
14
  for (var i = 0; i < m.length; i++) {
14
15
  const e = m[i];
@@ -333,6 +334,17 @@ const getScalarAttributes = (schema) => {
333
334
  []
334
335
  );
335
336
  };
337
+ const getRelationalAttributes = (schema) => {
338
+ return _$1.reduce(
339
+ schema.attributes,
340
+ (acc, attr, attrName) => {
341
+ if (isRelationalAttribute(attr))
342
+ acc.push(attrName);
343
+ return acc;
344
+ },
345
+ []
346
+ );
347
+ };
336
348
  const isTypedAttribute = (attribute, type) => {
337
349
  return _$1.has(attribute, "type") && attribute.type === type;
338
350
  };
@@ -349,6 +361,7 @@ const contentTypes = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.define
349
361
  getNonWritableAttributes,
350
362
  getOptions,
351
363
  getPrivateAttributes,
364
+ getRelationalAttributes,
352
365
  getScalarAttributes,
353
366
  getTimestamps,
354
367
  getVisibleAttributes,
@@ -516,201 +529,32 @@ const providerFactory = (options = {}) => {
516
529
  }
517
530
  };
518
531
  };
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;
532
+ const traverseEntity = async (visitor2, options, entity) => {
533
+ const { path = { raw: null, attribute: null }, schema, getModel } = options;
534
+ const traverseMorphRelationTarget = async (visitor22, path2, entry) => {
535
+ const targetSchema = getModel(entry.__type);
536
+ const traverseOptions = { schema: targetSchema, path: path2, getModel };
537
+ return traverseEntity(visitor22, traverseOptions, entry);
527
538
  };
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
- }
539
+ const traverseRelationTarget = (schema2) => async (visitor22, path2, entry) => {
540
+ const traverseOptions = { schema: schema2, path: path2, getModel };
541
+ return traverseEntity(visitor22, traverseOptions, entry);
581
542
  };
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
- }
543
+ const traverseMediaTarget = async (visitor22, path2, entry) => {
544
+ const targetSchemaUID = "plugin::upload.file";
545
+ const targetSchema = getModel(targetSchemaUID);
546
+ const traverseOptions = { schema: targetSchema, path: path2, getModel };
547
+ return traverseEntity(visitor22, traverseOptions, entry);
548
+ };
549
+ const traverseComponent = async (visitor22, path2, schema2, entry) => {
550
+ const traverseOptions = { schema: schema2, path: path2, getModel };
551
+ return traverseEntity(visitor22, traverseOptions, entry);
552
+ };
553
+ const visitDynamicZoneEntry = async (visitor22, path2, entry) => {
554
+ const targetSchema = getModel(entry.__component);
555
+ const traverseOptions = { schema: targetSchema, path: path2, getModel };
556
+ return traverseEntity(visitor22, traverseOptions, entry);
588
557
  };
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
558
  if (!isObject(entity) || isNil(schema)) {
715
559
  return entity;
716
560
  }
@@ -734,7 +578,8 @@ const traverseEntity = async (visitor2, options, entity) => {
734
578
  key,
735
579
  value: copy[key],
736
580
  attribute,
737
- path: newPath
581
+ path: newPath,
582
+ getModel
738
583
  };
739
584
  await visitor2(visitorOptions, visitorUtils);
740
585
  const value = copy[key];
@@ -743,7 +588,7 @@ const traverseEntity = async (visitor2, options, entity) => {
743
588
  }
744
589
  if (isRelationalAttribute(attribute)) {
745
590
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
746
- const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(strapi.getModel(attribute.target));
591
+ const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
747
592
  if (isArray(value)) {
748
593
  const res = new Array(value.length);
749
594
  for (let i2 = 0; i2 < value.length; i2 += 1) {
@@ -768,7 +613,7 @@ const traverseEntity = async (visitor2, options, entity) => {
768
613
  continue;
769
614
  }
770
615
  if (attribute.type === "component") {
771
- const targetSchema = strapi.getModel(attribute.component);
616
+ const targetSchema = getModel(attribute.component);
772
617
  if (isArray(value)) {
773
618
  const res = new Array(value.length);
774
619
  for (let i2 = 0; i2 < value.length; i2 += 1) {
@@ -800,80 +645,853 @@ const createVisitorUtils = ({ data }) => ({
800
645
  }
801
646
  });
802
647
  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
- }
648
+ function importDefault(modName) {
649
+ const mod = require(modName);
650
+ return mod && mod.__esModule ? mod.default : mod;
651
+ }
652
+ const machineId = () => {
653
+ try {
654
+ const deviceId = machineIdSync();
655
+ return deviceId;
656
+ } catch (error) {
657
+ const deviceId = randomUUID();
658
+ return deviceId;
659
+ }
660
+ };
661
+ const formatYupInnerError = (yupError) => ({
662
+ path: toPath(yupError.path),
663
+ message: yupError.message,
664
+ name: yupError.name
665
+ });
666
+ const formatYupErrors = (yupError) => ({
667
+ errors: isEmpty(yupError.inner) ? [formatYupInnerError(yupError)] : yupError.inner.map(formatYupInnerError),
668
+ message: yupError.message
669
+ });
670
+ class ApplicationError extends Error {
671
+ name;
672
+ details;
673
+ message;
674
+ constructor(message = "An application error occured", details = {}) {
675
+ super();
676
+ this.name = "ApplicationError";
677
+ this.message = message;
678
+ this.details = details;
679
+ }
680
+ }
681
+ class ValidationError extends ApplicationError {
682
+ constructor(message, details) {
683
+ super(message, details);
684
+ this.name = "ValidationError";
685
+ }
686
+ }
687
+ class YupValidationError extends ValidationError {
688
+ constructor(yupError, message) {
689
+ super("Validation");
690
+ const { errors: errors2, message: yupMessage } = formatYupErrors(yupError);
691
+ this.message = message || yupMessage;
692
+ this.details = { errors: errors2 };
693
+ }
694
+ }
695
+ class PaginationError extends ApplicationError {
696
+ constructor(message = "Invalid pagination", details) {
697
+ super(message, details);
698
+ this.name = "PaginationError";
699
+ this.message = message;
700
+ }
701
+ }
702
+ class NotFoundError extends ApplicationError {
703
+ constructor(message = "Entity not found", details) {
704
+ super(message, details);
705
+ this.name = "NotFoundError";
706
+ this.message = message;
707
+ }
708
+ }
709
+ class ForbiddenError extends ApplicationError {
710
+ constructor(message = "Forbidden access", details) {
711
+ super(message, details);
712
+ this.name = "ForbiddenError";
713
+ this.message = message;
714
+ }
715
+ }
716
+ class UnauthorizedError extends ApplicationError {
717
+ constructor(message = "Unauthorized", details) {
718
+ super(message, details);
719
+ this.name = "UnauthorizedError";
720
+ this.message = message;
721
+ }
722
+ }
723
+ class RateLimitError extends ApplicationError {
724
+ constructor(message = "Too many requests, please try again later.", details) {
725
+ super(message, details);
726
+ this.name = "RateLimitError";
727
+ this.message = message;
728
+ this.details = details || {};
729
+ }
730
+ }
731
+ class PayloadTooLargeError extends ApplicationError {
732
+ constructor(message = "Entity too large", details) {
733
+ super(message, details);
734
+ this.name = "PayloadTooLargeError";
735
+ this.message = message;
736
+ }
737
+ }
738
+ class PolicyError extends ForbiddenError {
739
+ constructor(message = "Policy Failed", details) {
740
+ super(message, details);
741
+ this.name = "PolicyError";
742
+ this.message = message;
743
+ this.details = details || {};
744
+ }
745
+ }
746
+ class NotImplementedError extends ApplicationError {
747
+ constructor(message = "This feature is not implemented yet", details) {
748
+ super(message, details);
749
+ this.name = "NotImplementedError";
750
+ this.message = message;
751
+ }
752
+ }
753
+ const errors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
754
+ __proto__: null,
755
+ ApplicationError,
756
+ ForbiddenError,
757
+ HttpError,
758
+ NotFoundError,
759
+ NotImplementedError,
760
+ PaginationError,
761
+ PayloadTooLargeError,
762
+ PolicyError,
763
+ RateLimitError,
764
+ UnauthorizedError,
765
+ ValidationError,
766
+ YupValidationError
767
+ }, Symbol.toStringTag, { value: "Module" }));
768
+ const handleYupError = (error, errorMessage) => {
769
+ throw new YupValidationError(error, errorMessage);
770
+ };
771
+ const defaultValidationParam = { strict: true, abortEarly: false };
772
+ const validateYupSchema = (schema, options = {}) => async (body, errorMessage) => {
773
+ try {
774
+ const optionsWithDefaults = defaults(defaultValidationParam, options);
775
+ const result = await schema.validate(body, optionsWithDefaults);
776
+ return result;
777
+ } catch (e) {
778
+ if (e instanceof yup$1.ValidationError) {
779
+ handleYupError(e, errorMessage);
780
+ }
781
+ throw e;
782
+ }
783
+ };
784
+ const validateYupSchemaSync = (schema, options = {}) => (body, errorMessage) => {
785
+ try {
786
+ const optionsWithDefaults = defaults(defaultValidationParam, options);
787
+ return schema.validateSync(body, optionsWithDefaults);
788
+ } catch (e) {
789
+ if (e instanceof yup$1.ValidationError) {
790
+ handleYupError(e, errorMessage);
791
+ }
792
+ throw e;
793
+ }
794
+ };
795
+ const GROUP_OPERATORS = ["$and", "$or"];
796
+ const WHERE_OPERATORS = [
797
+ "$not",
798
+ "$in",
799
+ "$notIn",
800
+ "$eq",
801
+ "$eqi",
802
+ "$ne",
803
+ "$nei",
804
+ "$gt",
805
+ "$gte",
806
+ "$lt",
807
+ "$lte",
808
+ "$null",
809
+ "$notNull",
810
+ "$between",
811
+ "$startsWith",
812
+ "$endsWith",
813
+ "$startsWithi",
814
+ "$endsWithi",
815
+ "$contains",
816
+ "$notContains",
817
+ "$containsi",
818
+ "$notContainsi",
819
+ // Experimental, only for internal use
820
+ "$jsonSupersetOf"
821
+ ];
822
+ const CAST_OPERATORS = [
823
+ "$not",
824
+ "$in",
825
+ "$notIn",
826
+ "$eq",
827
+ "$ne",
828
+ "$gt",
829
+ "$gte",
830
+ "$lt",
831
+ "$lte",
832
+ "$between"
833
+ ];
834
+ const ARRAY_OPERATORS = ["$in", "$notIn", "$between"];
835
+ const OPERATORS = {
836
+ where: WHERE_OPERATORS,
837
+ cast: CAST_OPERATORS,
838
+ group: GROUP_OPERATORS,
839
+ array: ARRAY_OPERATORS
840
+ };
841
+ const OPERATORS_LOWERCASE = Object.fromEntries(
842
+ Object.entries(OPERATORS).map(([key, values]) => [
843
+ key,
844
+ values.map((value) => value.toLowerCase())
845
+ ])
846
+ );
847
+ const isObjKey = (key, obj) => {
848
+ return key in obj;
849
+ };
850
+ const isOperatorOfType = (type, key, ignoreCase = false) => {
851
+ if (ignoreCase) {
852
+ return OPERATORS_LOWERCASE[type]?.includes(key.toLowerCase()) ?? false;
853
+ }
854
+ if (isObjKey(type, OPERATORS)) {
855
+ return OPERATORS[type]?.includes(key) ?? false;
856
+ }
857
+ return false;
858
+ };
859
+ const isOperator = (key, ignoreCase = false) => {
860
+ return Object.keys(OPERATORS).some((type) => isOperatorOfType(type, key, ignoreCase));
861
+ };
862
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$3, PUBLISHED_AT_ATTRIBUTE } = constants$1;
863
+ class InvalidOrderError extends Error {
864
+ constructor() {
865
+ super();
866
+ this.message = "Invalid order. order can only be one of asc|desc|ASC|DESC";
867
+ }
868
+ }
869
+ class InvalidSortError extends Error {
870
+ constructor() {
871
+ super();
872
+ this.message = "Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects";
873
+ }
874
+ }
875
+ function validateOrder(order) {
876
+ if (!isString(order) || !["asc", "desc"].includes(order.toLocaleLowerCase())) {
877
+ throw new InvalidOrderError();
878
+ }
879
+ }
880
+ const convertCountQueryParams = (countQuery) => {
881
+ return parseType({ type: "boolean", value: countQuery });
882
+ };
883
+ const convertOrderingQueryParams = (ordering) => {
884
+ return ordering;
885
+ };
886
+ const isPlainObject = (value) => _$1.isPlainObject(value);
887
+ const isStringArray$3 = (value) => isArray(value) && value.every(isString);
888
+ const createTransformer = ({ getModel }) => {
889
+ const convertSortQueryParams = (sortQuery) => {
890
+ if (typeof sortQuery === "string") {
891
+ return convertStringSortQueryParam(sortQuery);
892
+ }
893
+ if (isStringArray$3(sortQuery)) {
894
+ return sortQuery.flatMap((sortValue) => convertStringSortQueryParam(sortValue));
895
+ }
896
+ if (Array.isArray(sortQuery)) {
897
+ return sortQuery.map((sortValue) => convertNestedSortQueryParam(sortValue));
898
+ }
899
+ if (isPlainObject(sortQuery)) {
900
+ return convertNestedSortQueryParam(sortQuery);
901
+ }
902
+ throw new InvalidSortError();
903
+ };
904
+ const convertStringSortQueryParam = (sortQuery) => {
905
+ return sortQuery.split(",").map((value) => convertSingleSortQueryParam(value));
906
+ };
907
+ const convertSingleSortQueryParam = (sortQuery) => {
908
+ if (!sortQuery) {
909
+ return {};
910
+ }
911
+ if (!isString(sortQuery)) {
912
+ throw new Error("Invalid sort query");
913
+ }
914
+ const [field, order = "asc"] = sortQuery.split(":");
915
+ if (field.length === 0) {
916
+ throw new Error("Field cannot be empty");
917
+ }
918
+ validateOrder(order);
919
+ return _$1.set({}, field, order);
920
+ };
921
+ const convertNestedSortQueryParam = (sortQuery) => {
922
+ const transformedSort = {};
923
+ for (const field of Object.keys(sortQuery)) {
924
+ const order = sortQuery[field];
925
+ if (isPlainObject(order)) {
926
+ transformedSort[field] = convertNestedSortQueryParam(order);
927
+ } else if (typeof order === "string") {
928
+ validateOrder(order);
929
+ transformedSort[field] = order;
930
+ } else {
931
+ throw Error(`Invalid sort type expected object or string got ${typeof order}`);
932
+ }
933
+ }
934
+ return transformedSort;
935
+ };
936
+ const convertStartQueryParams = (startQuery) => {
937
+ const startAsANumber = _$1.toNumber(startQuery);
938
+ if (!_$1.isInteger(startAsANumber) || startAsANumber < 0) {
939
+ throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
940
+ }
941
+ return startAsANumber;
942
+ };
943
+ const convertLimitQueryParams = (limitQuery) => {
944
+ const limitAsANumber = _$1.toNumber(limitQuery);
945
+ if (!_$1.isInteger(limitAsANumber) || limitAsANumber !== -1 && limitAsANumber < 0) {
946
+ throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
947
+ }
948
+ if (limitAsANumber === -1) {
949
+ return void 0;
950
+ }
951
+ return limitAsANumber;
952
+ };
953
+ const convertPageQueryParams = (page) => {
954
+ const pageVal = toNumber(page);
955
+ if (!isInteger(pageVal) || pageVal <= 0) {
956
+ throw new PaginationError(
957
+ `Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
958
+ );
959
+ }
960
+ return pageVal;
961
+ };
962
+ const convertPageSizeQueryParams = (pageSize, page) => {
963
+ const pageSizeVal = toNumber(pageSize);
964
+ if (!isInteger(pageSizeVal) || pageSizeVal <= 0) {
965
+ throw new PaginationError(
966
+ `Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
967
+ );
968
+ }
969
+ return pageSizeVal;
970
+ };
971
+ const validatePaginationParams = (page, pageSize, start, limit) => {
972
+ const isPagePagination = !isNil(page) || !isNil(pageSize);
973
+ const isOffsetPagination = !isNil(start) || !isNil(limit);
974
+ if (isPagePagination && isOffsetPagination) {
975
+ throw new PaginationError(
976
+ "Invalid pagination attributes. You cannot use page and offset pagination in the same query"
977
+ );
978
+ }
979
+ };
980
+ class InvalidPopulateError extends Error {
981
+ constructor() {
982
+ super();
983
+ this.message = "Invalid populate parameter. Expected a string, an array of strings, a populate object";
984
+ }
985
+ }
986
+ const convertPopulateQueryParams = (populate2, schema, depth = 0) => {
987
+ if (depth === 0 && populate2 === "*") {
988
+ return true;
989
+ }
990
+ if (typeof populate2 === "string") {
991
+ return populate2.split(",").map((value) => _$1.trim(value));
992
+ }
993
+ if (Array.isArray(populate2)) {
994
+ return _$1.uniq(
995
+ populate2.flatMap((value) => {
996
+ if (typeof value !== "string") {
997
+ throw new InvalidPopulateError();
998
+ }
999
+ return value.split(",").map((value2) => _$1.trim(value2));
1000
+ })
1001
+ );
1002
+ }
1003
+ if (_$1.isPlainObject(populate2)) {
1004
+ return convertPopulateObject(populate2, schema);
1005
+ }
1006
+ throw new InvalidPopulateError();
1007
+ };
1008
+ const hasFragmentPopulateDefined = (populate2) => {
1009
+ return typeof populate2 === "object" && "on" in populate2 && !isNil(populate2.on);
1010
+ };
1011
+ const convertPopulateObject = (populate2, schema) => {
1012
+ if (!schema) {
1013
+ return {};
1014
+ }
1015
+ const { attributes } = schema;
1016
+ return Object.entries(populate2).reduce((acc, [key, subPopulate]) => {
1017
+ if (_$1.isBoolean(subPopulate)) {
1018
+ return { ...acc, [key]: subPopulate };
1019
+ }
1020
+ const attribute = attributes[key];
1021
+ if (!attribute) {
1022
+ return acc;
1023
+ }
1024
+ const isAllowedAttributeForFragmentPopulate = isDynamicZoneAttribute(attribute) || isMorphToRelationalAttribute(attribute);
1025
+ if (isAllowedAttributeForFragmentPopulate && hasFragmentPopulateDefined(subPopulate)) {
1026
+ return {
1027
+ ...acc,
1028
+ [key]: {
1029
+ on: Object.entries(subPopulate.on).reduce(
1030
+ (acc2, [type, typeSubPopulate]) => ({
1031
+ ...acc2,
1032
+ [type]: convertNestedPopulate(typeSubPopulate, getModel(type))
1033
+ }),
1034
+ {}
1035
+ )
1036
+ }
1037
+ };
1038
+ }
1039
+ if (isDynamicZoneAttribute(attribute)) {
1040
+ const populates = attribute.components.map((uid) => getModel(uid)).map((schema2) => convertNestedPopulate(subPopulate, schema2)).map((populate22) => populate22 === true ? {} : populate22).filter((populate22) => populate22 !== false);
1041
+ if (isEmpty(populates)) {
1042
+ return acc;
1043
+ }
1044
+ return {
1045
+ ...acc,
1046
+ [key]: mergeAll(populates)
1047
+ };
1048
+ }
1049
+ if (isMorphToRelationalAttribute(attribute)) {
1050
+ return { ...acc, [key]: convertNestedPopulate(subPopulate, void 0) };
1051
+ }
1052
+ let targetSchemaUID;
1053
+ if (attribute.type === "relation") {
1054
+ targetSchemaUID = attribute.target;
1055
+ } else if (attribute.type === "component") {
1056
+ targetSchemaUID = attribute.component;
1057
+ } else if (attribute.type === "media") {
1058
+ targetSchemaUID = "plugin::upload.file";
1059
+ } else {
1060
+ return acc;
1061
+ }
1062
+ const targetSchema = getModel(targetSchemaUID);
1063
+ if (!targetSchema) {
1064
+ return acc;
1065
+ }
1066
+ const populateObject = convertNestedPopulate(subPopulate, targetSchema);
1067
+ if (!populateObject) {
1068
+ return acc;
1069
+ }
1070
+ return {
1071
+ ...acc,
1072
+ [key]: populateObject
1073
+ };
1074
+ }, {});
1075
+ };
1076
+ const convertNestedPopulate = (subPopulate, schema) => {
1077
+ if (_$1.isString(subPopulate)) {
1078
+ return parseType({ type: "boolean", value: subPopulate, forceCast: true });
1079
+ }
1080
+ if (_$1.isBoolean(subPopulate)) {
1081
+ return subPopulate;
1082
+ }
1083
+ if (!isPlainObject(subPopulate)) {
1084
+ throw new Error(`Invalid nested populate. Expected '*' or an object`);
1085
+ }
1086
+ const { sort: sort2, filters: filters2, fields: fields2, populate: populate2, count, ordering, page, pageSize, start, limit } = subPopulate;
1087
+ const query = {};
1088
+ if (sort2) {
1089
+ query.orderBy = convertSortQueryParams(sort2);
1090
+ }
1091
+ if (filters2) {
1092
+ query.where = convertFiltersQueryParams(filters2, schema);
1093
+ }
1094
+ if (fields2) {
1095
+ query.select = convertFieldsQueryParams(fields2);
1096
+ }
1097
+ if (populate2) {
1098
+ query.populate = convertPopulateQueryParams(populate2, schema);
1099
+ }
1100
+ if (count) {
1101
+ query.count = convertCountQueryParams(count);
1102
+ }
1103
+ if (ordering) {
1104
+ query.ordering = convertOrderingQueryParams(ordering);
1105
+ }
1106
+ validatePaginationParams(page, pageSize, start, limit);
1107
+ if (!isNil(page)) {
1108
+ query.page = convertPageQueryParams(page);
1109
+ }
1110
+ if (!isNil(pageSize)) {
1111
+ query.pageSize = convertPageSizeQueryParams(pageSize, page);
1112
+ }
1113
+ if (!isNil(start)) {
1114
+ query.offset = convertStartQueryParams(start);
1115
+ }
1116
+ if (!isNil(limit)) {
1117
+ query.limit = convertLimitQueryParams(limit);
1118
+ }
1119
+ return query;
1120
+ };
1121
+ const convertFieldsQueryParams = (fields2, depth = 0) => {
1122
+ if (depth === 0 && fields2 === "*") {
1123
+ return void 0;
1124
+ }
1125
+ if (typeof fields2 === "string") {
1126
+ const fieldsValues = fields2.split(",").map((value) => _$1.trim(value));
1127
+ return _$1.uniq([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3, ...fieldsValues]);
1128
+ }
1129
+ if (isStringArray$3(fields2)) {
1130
+ const fieldsValues = fields2.flatMap((value) => convertFieldsQueryParams(value, depth + 1)).filter((v) => !isNil(v));
1131
+ return _$1.uniq([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3, ...fieldsValues]);
1132
+ }
1133
+ throw new Error("Invalid fields parameter. Expected a string or an array of strings");
1134
+ };
1135
+ const isValidSchemaAttribute = (key, schema) => {
1136
+ if ([DOC_ID_ATTRIBUTE$3, ID_ATTRIBUTE$3].includes(key)) {
1137
+ return true;
1138
+ }
1139
+ if (!schema) {
1140
+ return false;
1141
+ }
1142
+ return Object.keys(schema.attributes).includes(key);
1143
+ };
1144
+ const convertFiltersQueryParams = (filters2, schema) => {
1145
+ if (!isObject(filters2)) {
1146
+ throw new Error("The filters parameter must be an object or an array");
1147
+ }
1148
+ const filtersCopy = cloneDeep(filters2);
1149
+ return convertAndSanitizeFilters(filtersCopy, schema);
1150
+ };
1151
+ const convertAndSanitizeFilters = (filters2, schema) => {
1152
+ if (Array.isArray(filters2)) {
1153
+ return filters2.map((filter) => convertAndSanitizeFilters(filter, schema)).filter((filter) => !isPlainObject(filter) || !isEmpty(filter));
1154
+ }
1155
+ if (!isPlainObject(filters2)) {
1156
+ return filters2;
1157
+ }
1158
+ const removeOperator = (operator) => delete filters2[operator];
1159
+ for (const [key, value] of Object.entries(filters2)) {
1160
+ const attribute = get(key, schema?.attributes);
1161
+ const validKey = isOperator(key) || isValidSchemaAttribute(key, schema);
1162
+ if (!validKey) {
1163
+ removeOperator(key);
1164
+ } else if (attribute) {
1165
+ if (attribute.type === "relation") {
1166
+ filters2[key] = convertAndSanitizeFilters(value, getModel(attribute.target));
1167
+ } else if (attribute.type === "component") {
1168
+ filters2[key] = convertAndSanitizeFilters(value, getModel(attribute.component));
1169
+ } else if (attribute.type === "media") {
1170
+ filters2[key] = convertAndSanitizeFilters(value, getModel("plugin::upload.file"));
1171
+ } else if (attribute.type === "dynamiczone") {
1172
+ removeOperator(key);
1173
+ } else if (attribute.type === "password") {
1174
+ removeOperator(key);
1175
+ } else {
1176
+ filters2[key] = convertAndSanitizeFilters(value, schema);
1177
+ }
1178
+ } else if (["$null", "$notNull"].includes(key)) {
1179
+ filters2[key] = parseType({ type: "boolean", value: filters2[key], forceCast: true });
1180
+ } else if (isObject(value)) {
1181
+ filters2[key] = convertAndSanitizeFilters(value, schema);
1182
+ }
1183
+ if (isPlainObject(filters2[key]) && isEmpty(filters2[key])) {
1184
+ removeOperator(key);
1185
+ }
1186
+ }
1187
+ return filters2;
1188
+ };
1189
+ const convertStatusParams = (status, query = {}) => {
1190
+ query.filters = ({ meta }) => {
1191
+ const contentType = getModel(meta.uid);
1192
+ if (!contentType || !hasDraftAndPublish(contentType)) {
1193
+ return {};
1194
+ }
1195
+ return { [PUBLISHED_AT_ATTRIBUTE]: { $null: status === "draft" } };
1196
+ };
1197
+ };
1198
+ const transformQueryParams = (uid, params) => {
1199
+ const schema = getModel(uid);
1200
+ const query = {};
1201
+ const { _q, sort: sort2, filters: filters2, fields: fields2, populate: populate2, page, pageSize, start, limit, status, ...rest } = params;
1202
+ if (!isNil(status)) {
1203
+ convertStatusParams(status, query);
1204
+ }
1205
+ if (!isNil(_q)) {
1206
+ query._q = _q;
1207
+ }
1208
+ if (!isNil(sort2)) {
1209
+ query.orderBy = convertSortQueryParams(sort2);
1210
+ }
1211
+ if (!isNil(filters2)) {
1212
+ query.where = convertFiltersQueryParams(filters2, schema);
1213
+ }
1214
+ if (!isNil(fields2)) {
1215
+ query.select = convertFieldsQueryParams(fields2);
1216
+ }
1217
+ if (!isNil(populate2)) {
1218
+ query.populate = convertPopulateQueryParams(populate2, schema);
1219
+ }
1220
+ validatePaginationParams(page, pageSize, start, limit);
1221
+ if (!isNil(page)) {
1222
+ query.page = convertPageQueryParams(page);
1223
+ }
1224
+ if (!isNil(pageSize)) {
1225
+ query.pageSize = convertPageSizeQueryParams(pageSize, page);
1226
+ }
1227
+ if (!isNil(start)) {
1228
+ query.offset = convertStartQueryParams(start);
1229
+ }
1230
+ if (!isNil(limit)) {
1231
+ query.limit = convertLimitQueryParams(limit);
1232
+ }
1233
+ return {
1234
+ ...rest,
1235
+ ...query
1236
+ };
1237
+ };
1238
+ return {
1239
+ private_convertSortQueryParams: convertSortQueryParams,
1240
+ private_convertStartQueryParams: convertStartQueryParams,
1241
+ private_convertLimitQueryParams: convertLimitQueryParams,
1242
+ private_convertPopulateQueryParams: convertPopulateQueryParams,
1243
+ private_convertFiltersQueryParams: convertFiltersQueryParams,
1244
+ private_convertFieldsQueryParams: convertFieldsQueryParams,
1245
+ transformQueryParams
1246
+ };
1247
+ };
1248
+ const convertQueryParams = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1249
+ __proto__: null,
1250
+ createTransformer
1251
+ }, Symbol.toStringTag, { value: "Module" }));
1252
+ function pipe(...fns) {
1253
+ const [firstFn, ...fnRest] = fns;
1254
+ return async (...args) => {
1255
+ let res = await firstFn.apply(firstFn, args);
1256
+ for (let i = 0; i < fnRest.length; i += 1) {
1257
+ res = await fnRest[i](res);
1258
+ }
1259
+ return res;
1260
+ };
1261
+ }
1262
+ const map = curry(pMap);
1263
+ const reduce = (mixedArray) => async (iteratee, initialValue) => {
1264
+ let acc = initialValue;
1265
+ for (let i = 0; i < mixedArray.length; i += 1) {
1266
+ acc = await iteratee(acc, await mixedArray[i], i);
1267
+ }
1268
+ return acc;
1269
+ };
1270
+ const async = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1271
+ __proto__: null,
1272
+ map,
1273
+ pipe,
1274
+ reduce
1275
+ }, Symbol.toStringTag, { value: "Module" }));
1276
+ const visitor$8 = ({ key, attribute }, { remove: remove2 }) => {
1277
+ if (attribute?.type === "password") {
1278
+ remove2(key);
1279
+ }
1280
+ };
1281
+ const visitor$7 = ({ schema, key, attribute }, { remove: remove2 }) => {
1282
+ if (!attribute) {
1283
+ return;
1284
+ }
1285
+ const isPrivate = attribute.private === true || isPrivateAttribute(schema, key);
1286
+ if (isPrivate) {
1287
+ remove2(key);
1288
+ }
1289
+ };
1290
+ const ACTIONS_TO_VERIFY$1 = ["find"];
1291
+ const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$1 } = constants$1;
1292
+ const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schema }, { remove: remove2, set }) => {
1293
+ if (!attribute) {
1294
+ return;
1295
+ }
1296
+ const isRelation = attribute.type === "relation";
1297
+ if (!isRelation) {
1298
+ return;
1299
+ }
1300
+ const handleMorphRelation = async () => {
1301
+ const newMorphValue = [];
1302
+ for (const element of data[key]) {
1303
+ const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
1304
+ const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
1305
+ if (isAllowed) {
1306
+ newMorphValue.push(element);
1307
+ }
1308
+ }
1309
+ if (newMorphValue.length === 0) {
1310
+ remove2(key);
1311
+ } else {
1312
+ set(key, newMorphValue);
1313
+ }
1314
+ };
1315
+ const handleRegularRelation = async () => {
1316
+ const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${attribute.target}.${action}`);
1317
+ const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
1318
+ if (!isAllowed) {
1319
+ remove2(key);
1320
+ }
1321
+ };
1322
+ const isCreatorRelation = [CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE$1].includes(key);
1323
+ if (isMorphToRelationalAttribute(attribute)) {
1324
+ await handleMorphRelation();
1325
+ return;
1326
+ }
1327
+ if (isCreatorRelation && schema.options?.populateCreatorFields) {
1328
+ return;
1329
+ }
1330
+ await handleRegularRelation();
1331
+ };
1332
+ const hasAccessToSomeScopes$1 = async (scopes, auth) => {
1333
+ for (const scope of scopes) {
1334
+ try {
1335
+ await strapi.auth.verify(auth, { scope });
1336
+ return true;
1337
+ } catch {
1338
+ continue;
1339
+ }
1340
+ }
1341
+ return false;
1342
+ };
1343
+ const visitor$6 = ({ key, attribute }, { remove: remove2 }) => {
1344
+ if (isMorphToRelationalAttribute(attribute)) {
1345
+ remove2(key);
1346
+ }
1347
+ };
1348
+ const visitor$5 = ({ key, attribute }, { remove: remove2 }) => {
1349
+ if (isDynamicZoneAttribute(attribute)) {
1350
+ remove2(key);
1351
+ }
1352
+ };
1353
+ const removeDisallowedFields = (allowedFields = null) => ({ key, path: { attribute: path } }, { remove: remove2 }) => {
1354
+ if (allowedFields === null) {
1355
+ return;
1356
+ }
1357
+ if (!(isArray(allowedFields) && allowedFields.every(isString))) {
1358
+ throw new TypeError(
1359
+ `Expected array of strings for allowedFields but got "${typeof allowedFields}"`
1360
+ );
1361
+ }
1362
+ if (isNil(path)) {
1363
+ return;
1364
+ }
1365
+ const containedPaths = getContainedPaths$1(path);
1366
+ const isPathAllowed = allowedFields.some(
1367
+ (p) => containedPaths.includes(p) || p.startsWith(`${path}.`)
1368
+ );
1369
+ if (isPathAllowed) {
1370
+ return;
1371
+ }
1372
+ remove2(key);
1373
+ };
1374
+ const getContainedPaths$1 = (path) => {
1375
+ const parts = toPath(path);
1376
+ return parts.reduce((acc, value, index2, list) => {
1377
+ return [...acc, list.slice(0, index2 + 1).join(".")];
1378
+ }, []);
1379
+ };
1380
+ const removeRestrictedFields = (restrictedFields = null) => ({ key, path: { attribute: path } }, { remove: remove2 }) => {
1381
+ if (restrictedFields === null) {
1382
+ remove2(key);
1383
+ return;
1384
+ }
1385
+ if (!(isArray(restrictedFields) && restrictedFields.every(isString))) {
1386
+ throw new TypeError(
1387
+ `Expected array of strings for restrictedFields but got "${typeof restrictedFields}"`
1388
+ );
1389
+ }
1390
+ if (restrictedFields.includes(path)) {
1391
+ remove2(key);
1392
+ return;
1393
+ }
1394
+ const isRestrictedNested = restrictedFields.some(
1395
+ (allowedPath) => path?.toString().startsWith(`${allowedPath}.`)
1396
+ );
1397
+ if (isRestrictedNested) {
1398
+ remove2(key);
1399
+ }
1400
+ };
1401
+ const visitor$4 = ({ schema, key, value }, { set }) => {
1402
+ if (key === "" && value === "*") {
1403
+ const { attributes } = schema;
1404
+ const newPopulateQuery = Object.entries(attributes).filter(
1405
+ ([, attribute]) => ["relation", "component", "media", "dynamiczone"].includes(attribute.type)
1406
+ ).reduce((acc, [key2]) => ({ ...acc, [key2]: true }), {});
1407
+ set("", newPopulateQuery);
1408
+ }
1409
+ };
1410
+ const index$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1411
+ __proto__: null,
1412
+ expandWildcardPopulate: visitor$4,
1413
+ removeDisallowedFields,
1414
+ removeDynamicZones: visitor$5,
1415
+ removeMorphToRelations: visitor$6,
1416
+ removePassword: visitor$8,
1417
+ removePrivate: visitor$7,
1418
+ removeRestrictedFields,
1419
+ removeRestrictedRelations
1420
+ }, Symbol.toStringTag, { value: "Module" }));
1421
+ const DEFAULT_PATH = { raw: null, attribute: null };
1422
+ const traverseFactory = () => {
1423
+ const state = {
1424
+ parsers: [],
1425
+ interceptors: [],
1426
+ ignore: [],
1427
+ handlers: {
1428
+ attributes: [],
1429
+ common: []
1430
+ }
1431
+ };
1432
+ const traverse = async (visitor2, options, data) => {
1433
+ const { path = DEFAULT_PATH, schema, getModel } = options ?? {};
1434
+ for (const { predicate, handler } of state.interceptors) {
1435
+ if (predicate(data)) {
1436
+ return handler(visitor2, options, data, { recurse: traverse });
1437
+ }
1438
+ }
1439
+ const parser = state.parsers.find((parser2) => parser2.predicate(data))?.parser;
1440
+ const utils2 = parser?.(data);
1441
+ if (!utils2) {
1442
+ return data;
1443
+ }
1444
+ let out = utils2.transform(data);
1445
+ const keys = utils2.keys(out);
1446
+ for (const key of keys) {
1447
+ const attribute = schema?.attributes?.[key];
1448
+ const newPath = { ...path };
1449
+ newPath.raw = isNil(path.raw) ? key : `${path.raw}.${key}`;
1450
+ if (!isNil(attribute)) {
1451
+ newPath.attribute = isNil(path.attribute) ? key : `${path.attribute}.${key}`;
1452
+ }
1453
+ const visitorOptions = {
1454
+ key,
1455
+ value: utils2.get(key, out),
1456
+ attribute,
1457
+ schema,
1458
+ path: newPath,
1459
+ data: out,
1460
+ getModel
1461
+ };
1462
+ const transformUtils = {
1463
+ remove(key2) {
1464
+ out = utils2.remove(key2, out);
1465
+ },
1466
+ set(key2, value2) {
1467
+ out = utils2.set(key2, value2, out);
1468
+ },
1469
+ recurse: traverse
1470
+ };
1471
+ await visitor2(visitorOptions, pick(["remove", "set"], transformUtils));
1472
+ const value = utils2.get(key, out);
1473
+ const createContext = () => ({
1474
+ key,
1475
+ value,
1476
+ attribute,
1477
+ schema,
1478
+ path: newPath,
1479
+ data: out,
1480
+ visitor: visitor2,
1481
+ getModel
1482
+ });
1483
+ const ignoreCtx = createContext();
1484
+ const shouldIgnore = state.ignore.some((predicate) => predicate(ignoreCtx));
1485
+ if (shouldIgnore) {
1486
+ continue;
1487
+ }
1488
+ const handlers = [...state.handlers.common, ...state.handlers.attributes];
1489
+ for await (const handler of handlers) {
1490
+ const ctx = createContext();
1491
+ const pass = await handler.predicate(ctx);
1492
+ if (pass) {
1493
+ await handler.handler(ctx, pick(["recurse", "set"], transformUtils));
1494
+ }
877
1495
  }
878
1496
  }
879
1497
  return out;
@@ -949,33 +1567,33 @@ const filters = traverseFactory().intercept(
949
1567
  }
950
1568
  })).ignore(({ value }) => isNil(value)).on(
951
1569
  ({ attribute }) => isNil(attribute),
952
- async ({ key, visitor: visitor2, path, value, schema }, { set, recurse }) => {
953
- set(key, await recurse(visitor2, { schema, path }, value));
1570
+ async ({ key, visitor: visitor2, path, value, schema, getModel }, { set, recurse }) => {
1571
+ set(key, await recurse(visitor2, { schema, path, getModel }, value));
954
1572
  }
955
- ).onRelation(async ({ key, attribute, visitor: visitor2, path, value }, { set, recurse }) => {
1573
+ ).onRelation(async ({ key, attribute, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
956
1574
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
957
1575
  if (isMorphRelation) {
958
1576
  return;
959
1577
  }
960
1578
  const targetSchemaUID = attribute.target;
961
- const targetSchema = strapi.getModel(targetSchemaUID);
962
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1579
+ const targetSchema = getModel(targetSchemaUID);
1580
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
963
1581
  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);
1582
+ }).onComponent(async ({ key, attribute, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
1583
+ const targetSchema = getModel(attribute.component);
1584
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
967
1585
  set(key, newValue);
968
- }).onMedia(async ({ key, visitor: visitor2, path, value }, { set, recurse }) => {
1586
+ }).onMedia(async ({ key, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
969
1587
  const targetSchemaUID = "plugin::upload.file";
970
- const targetSchema = strapi.getModel(targetSchemaUID);
971
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1588
+ const targetSchema = getModel(targetSchemaUID);
1589
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
972
1590
  set(key, newValue);
973
1591
  });
974
1592
  const traverseQueryFilters = curry(filters.traverse);
975
1593
  const ORDERS = { asc: "asc", desc: "desc" };
976
1594
  const ORDER_VALUES = Object.values(ORDERS);
977
1595
  const isSortOrder = (value) => ORDER_VALUES.includes(value.toLowerCase());
978
- const isStringArray$3 = (value) => Array.isArray(value) && value.every(isString);
1596
+ const isStringArray$2 = (value) => Array.isArray(value) && value.every(isString);
979
1597
  const isObjectArray = (value) => Array.isArray(value) && value.every(isObject);
980
1598
  const isNestedSorts = (value) => isString(value) && value.split(",").length > 1;
981
1599
  const isObj$1 = (value) => isObject(value);
@@ -989,7 +1607,7 @@ const sort = traverseFactory().intercept(
989
1607
  }
990
1608
  ).intercept(
991
1609
  // Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items
992
- isStringArray$3,
1610
+ isStringArray$2,
993
1611
  async (visitor2, options, sort2, { recurse }) => {
994
1612
  return Promise.all(sort2.map((nestedSort) => recurse(visitor2, options, nestedSort))).then(
995
1613
  (res) => res.filter((nestedSort) => !isEmpty(nestedSort))
@@ -1056,23 +1674,23 @@ const sort = traverseFactory().intercept(
1056
1674
  get(key, data) {
1057
1675
  return data[key];
1058
1676
  }
1059
- })).onRelation(async ({ key, value, attribute, visitor: visitor2, path }, { set, recurse }) => {
1677
+ })).onRelation(async ({ key, value, attribute, visitor: visitor2, path, getModel }, { set, recurse }) => {
1060
1678
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
1061
1679
  if (isMorphRelation) {
1062
1680
  return;
1063
1681
  }
1064
1682
  const targetSchemaUID = attribute.target;
1065
- const targetSchema = strapi.getModel(targetSchemaUID);
1066
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1683
+ const targetSchema = getModel(targetSchemaUID);
1684
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1067
1685
  set(key, newValue);
1068
- }).onMedia(async ({ key, path, visitor: visitor2, value }, { recurse, set }) => {
1686
+ }).onMedia(async ({ key, path, visitor: visitor2, value, getModel }, { recurse, set }) => {
1069
1687
  const targetSchemaUID = "plugin::upload.file";
1070
- const targetSchema = strapi.getModel(targetSchemaUID);
1071
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1688
+ const targetSchema = getModel(targetSchemaUID);
1689
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1072
1690
  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);
1691
+ }).onComponent(async ({ key, value, visitor: visitor2, path, attribute, getModel }, { recurse, set }) => {
1692
+ const targetSchema = getModel(attribute.component);
1693
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1076
1694
  set(key, newValue);
1077
1695
  });
1078
1696
  const traverseQuerySort = curry(sort.traverse);
@@ -1081,9 +1699,9 @@ const isKeyword = (keyword) => {
1081
1699
  return !attribute && keyword === key;
1082
1700
  };
1083
1701
  };
1084
- const isStringArray$2 = (value) => isArray(value) && value.every(isString);
1702
+ const isStringArray$1 = (value) => isArray(value) && value.every(isString);
1085
1703
  const isObj = (value) => isObject(value);
1086
- const populate = traverseFactory().intercept(isStringArray$2, async (visitor2, options, populate2, { recurse }) => {
1704
+ const populate = traverseFactory().intercept(isStringArray$1, async (visitor2, options, populate2, { recurse }) => {
1087
1705
  const visitedPopulate = await Promise.all(
1088
1706
  populate2.map((nestedPopulate) => recurse(visitor2, options, nestedPopulate))
1089
1707
  );
@@ -1160,78 +1778,86 @@ const populate = traverseFactory().intercept(isStringArray$2, async (visitor2, o
1160
1778
  }).on(
1161
1779
  // Handle recursion on populate."populate"
1162
1780
  isKeyword("populate"),
1163
- async ({ key, visitor: visitor2, path, value, schema }, { set, recurse }) => {
1164
- const newValue = await recurse(visitor2, { schema, path }, value);
1781
+ async ({ key, visitor: visitor2, path, value, schema, getModel }, { set, recurse }) => {
1782
+ const newValue = await recurse(visitor2, { schema, path, getModel }, value);
1165
1783
  set(key, newValue);
1166
1784
  }
1167
- ).on(isKeyword("on"), async ({ key, visitor: visitor2, path, value }, { set, recurse }) => {
1785
+ ).on(isKeyword("on"), async ({ key, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
1168
1786
  const newOn = {};
1169
1787
  if (!isObj(value)) {
1170
1788
  return;
1171
1789
  }
1172
1790
  for (const [uid, subPopulate] of Object.entries(value)) {
1173
- const model = strapi.getModel(uid);
1791
+ const model = getModel(uid);
1174
1792
  const newPath = { ...path, raw: `${path.raw}[${uid}]` };
1175
- newOn[uid] = await recurse(visitor2, { schema: model, path: newPath }, subPopulate);
1793
+ newOn[uid] = await recurse(visitor2, { schema: model, path: newPath, getModel }, subPopulate);
1176
1794
  }
1177
1795
  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))) {
1796
+ }).onRelation(
1797
+ async ({ key, value, attribute, visitor: visitor2, path, schema, getModel }, { set, recurse }) => {
1798
+ if (isNil(value)) {
1184
1799
  return;
1185
1800
  }
1186
- const newValue2 = await recurse(visitor2, { schema, path }, { on: value?.on });
1187
- set(key, { on: newValue2 });
1801
+ if (isMorphToRelationalAttribute(attribute)) {
1802
+ if (!isObject(value) || !("on" in value && isObject(value?.on))) {
1803
+ return;
1804
+ }
1805
+ const newValue2 = await recurse(visitor2, { schema, path, getModel }, { on: value?.on });
1806
+ set(key, { on: newValue2 });
1807
+ }
1808
+ const targetSchemaUID = attribute.target;
1809
+ const targetSchema = getModel(targetSchemaUID);
1810
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1811
+ set(key, newValue);
1188
1812
  }
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 }) => {
1813
+ ).onMedia(async ({ key, path, visitor: visitor2, value, getModel }, { recurse, set }) => {
1194
1814
  if (isNil(value)) {
1195
1815
  return;
1196
1816
  }
1197
1817
  const targetSchemaUID = "plugin::upload.file";
1198
- const targetSchema = strapi.getModel(targetSchemaUID);
1199
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1818
+ const targetSchema = getModel(targetSchemaUID);
1819
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1200
1820
  set(key, newValue);
1201
- }).onComponent(async ({ key, value, visitor: visitor2, path, attribute }, { recurse, set }) => {
1821
+ }).onComponent(async ({ key, value, visitor: visitor2, path, attribute, getModel }, { recurse, set }) => {
1202
1822
  if (isNil(value)) {
1203
1823
  return;
1204
1824
  }
1205
- const targetSchema = strapi.getModel(attribute.component);
1206
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1825
+ const targetSchema = getModel(attribute.component);
1826
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1207
1827
  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);
1828
+ }).onDynamicZone(
1829
+ async ({ key, value, attribute, schema, visitor: visitor2, path, getModel }, { set, recurse }) => {
1830
+ if (isNil(value)) {
1831
+ return;
1220
1832
  }
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);
1833
+ if (isObject(value)) {
1834
+ const { components } = attribute;
1835
+ const newValue = {};
1836
+ let newProperties = omit("on", value);
1837
+ for (const componentUID of components) {
1838
+ const componentSchema = getModel(componentUID);
1839
+ const properties = await recurse(
1840
+ visitor2,
1841
+ { schema: componentSchema, path, getModel },
1842
+ value
1843
+ );
1844
+ newProperties = merge(newProperties, properties);
1845
+ }
1846
+ Object.assign(newValue, newProperties);
1847
+ if ("on" in value && value.on) {
1848
+ const newOn = await recurse(visitor2, { schema, path, getModel }, { on: value.on });
1849
+ Object.assign(newValue, newOn);
1850
+ }
1851
+ set(key, newValue);
1852
+ } else {
1853
+ const newValue = await recurse(visitor2, { schema, path, getModel }, value);
1854
+ set(key, newValue);
1225
1855
  }
1226
- set(key, newValue);
1227
- } else {
1228
- const newValue = await recurse(visitor2, { schema, path }, value);
1229
- set(key, newValue);
1230
1856
  }
1231
- });
1857
+ );
1232
1858
  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 }) => {
1859
+ const isStringArray = (value) => isArray(value) && value.every(isString);
1860
+ const fields = traverseFactory().intercept(isStringArray, async (visitor2, options, fields2, { recurse }) => {
1235
1861
  return Promise.all(fields2.map((field) => recurse(visitor2, options, field)));
1236
1862
  }).intercept((value) => eq("*", value), constant("*")).parse(isString, () => ({
1237
1863
  transform: trim,
@@ -1249,90 +1875,22 @@ const fields = traverseFactory().intercept(isStringArray$1, async (visitor2, opt
1249
1875
  }
1250
1876
  }));
1251
1877
  const traverseQueryFields = curry(fields.traverse);
1252
- const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1878
+ const index$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1253
1879
  __proto__: null,
1254
- factory: traverseFactory,
1255
1880
  traverseQueryFields,
1256
1881
  traverseQueryFilters,
1257
1882
  traverseQueryPopulate,
1258
1883
  traverseQuerySort
1259
1884
  }, 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) {
1885
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$2 } = constants$1;
1886
+ const sanitizePasswords = (ctx) => async (entity) => {
1887
+ if (!ctx.schema) {
1330
1888
  throw new Error("Missing schema in sanitizePasswords");
1331
1889
  }
1332
- return traverseEntity$1(visitor$8, { schema }, entity);
1890
+ return traverseEntity$1(visitor$8, ctx, entity);
1333
1891
  };
1334
- const defaultSanitizeOutput = async (schema, entity) => {
1335
- if (!schema) {
1892
+ const defaultSanitizeOutput = async (ctx, entity) => {
1893
+ if (!ctx.schema) {
1336
1894
  throw new Error("Missing schema in defaultSanitizeOutput");
1337
1895
  }
1338
1896
  return traverseEntity$1(
@@ -1340,139 +1898,121 @@ const defaultSanitizeOutput = async (schema, entity) => {
1340
1898
  visitor$8(...args);
1341
1899
  visitor$7(...args);
1342
1900
  },
1343
- { schema },
1901
+ ctx,
1344
1902
  entity
1345
1903
  );
1346
1904
  };
1347
- const defaultSanitizeFilters = curry((schema, filters2) => {
1348
- if (!schema) {
1905
+ const defaultSanitizeFilters = curry((ctx, filters2) => {
1906
+ if (!ctx.schema) {
1349
1907
  throw new Error("Missing schema in defaultSanitizeFilters");
1350
1908
  }
1351
1909
  return pipe(
1352
1910
  // 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
- ),
1911
+ traverseQueryFilters(({ key, attribute }, { remove: remove2 }) => {
1912
+ const isAttribute = !!attribute;
1913
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1914
+ return;
1915
+ }
1916
+ if (!isAttribute && !isOperator(key)) {
1917
+ remove2(key);
1918
+ }
1919
+ }, ctx),
1365
1920
  // Remove dynamic zones from filters
1366
- traverseQueryFilters(visitor$5, { schema }),
1921
+ traverseQueryFilters(visitor$5, ctx),
1367
1922
  // Remove morpTo relations from filters
1368
- traverseQueryFilters(visitor$6, { schema }),
1923
+ traverseQueryFilters(visitor$6, ctx),
1369
1924
  // Remove passwords from filters
1370
- traverseQueryFilters(visitor$8, { schema }),
1925
+ traverseQueryFilters(visitor$8, ctx),
1371
1926
  // Remove private from filters
1372
- traverseQueryFilters(visitor$7, { schema }),
1927
+ traverseQueryFilters(visitor$7, ctx),
1373
1928
  // Remove empty objects
1374
- traverseQueryFilters(
1375
- ({ key, value }, { remove: remove2 }) => {
1376
- if (isObject(value) && isEmpty(value)) {
1377
- remove2(key);
1378
- }
1379
- },
1380
- { schema }
1381
- )
1929
+ traverseQueryFilters(({ key, value }, { remove: remove2 }) => {
1930
+ if (isObject(value) && isEmpty(value)) {
1931
+ remove2(key);
1932
+ }
1933
+ }, ctx)
1382
1934
  )(filters2);
1383
1935
  });
1384
- const defaultSanitizeSort = curry((schema, sort2) => {
1385
- if (!schema) {
1936
+ const defaultSanitizeSort = curry((ctx, sort2) => {
1937
+ if (!ctx.schema) {
1386
1938
  throw new Error("Missing schema in defaultSanitizeSort");
1387
1939
  }
1388
1940
  return pipe(
1389
1941
  // 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
- ),
1942
+ traverseQuerySort(({ key, attribute }, { remove: remove2 }) => {
1943
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1944
+ return;
1945
+ }
1946
+ if (!attribute) {
1947
+ remove2(key);
1948
+ }
1949
+ }, ctx),
1401
1950
  // Remove dynamic zones from sort
1402
- traverseQuerySort(visitor$5, { schema }),
1951
+ traverseQuerySort(visitor$5, ctx),
1403
1952
  // Remove morpTo relations from sort
1404
- traverseQuerySort(visitor$6, { schema }),
1953
+ traverseQuerySort(visitor$6, ctx),
1405
1954
  // Remove private from sort
1406
- traverseQuerySort(visitor$7, { schema }),
1955
+ traverseQuerySort(visitor$7, ctx),
1407
1956
  // Remove passwords from filters
1408
- traverseQuerySort(visitor$8, { schema }),
1957
+ traverseQuerySort(visitor$8, ctx),
1409
1958
  // 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
- )
1959
+ traverseQuerySort(({ key, attribute, value }, { remove: remove2 }) => {
1960
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1961
+ return;
1962
+ }
1963
+ if (!isScalarAttribute(attribute) && isEmpty(value)) {
1964
+ remove2(key);
1965
+ }
1966
+ }, ctx)
1421
1967
  )(sort2);
1422
1968
  });
1423
- const defaultSanitizeFields = curry((schema, fields2) => {
1424
- if (!schema) {
1969
+ const defaultSanitizeFields = curry((ctx, fields2) => {
1970
+ if (!ctx.schema) {
1425
1971
  throw new Error("Missing schema in defaultSanitizeFields");
1426
1972
  }
1427
1973
  return pipe(
1428
1974
  // 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
- ),
1975
+ traverseQueryFields(({ key, attribute }, { remove: remove2 }) => {
1976
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1977
+ return;
1978
+ }
1979
+ if (isNil(attribute) || !isScalarAttribute(attribute)) {
1980
+ remove2(key);
1981
+ }
1982
+ }, ctx),
1440
1983
  // Remove private fields
1441
- traverseQueryFields(visitor$7, { schema }),
1984
+ traverseQueryFields(visitor$7, ctx),
1442
1985
  // Remove password fields
1443
- traverseQueryFields(visitor$8, { schema }),
1986
+ traverseQueryFields(visitor$8, ctx),
1444
1987
  // Remove nil values from fields array
1445
1988
  (value) => isArray(value) ? value.filter((field) => !isNil(field)) : value
1446
1989
  )(fields2);
1447
1990
  });
1448
- const defaultSanitizePopulate = curry((schema, populate2) => {
1449
- if (!schema) {
1991
+ const defaultSanitizePopulate = curry((ctx, populate2) => {
1992
+ if (!ctx.schema) {
1450
1993
  throw new Error("Missing schema in defaultSanitizePopulate");
1451
1994
  }
1452
1995
  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
- ),
1996
+ traverseQueryPopulate(visitor$4, ctx),
1997
+ traverseQueryPopulate(async ({ key, value, schema, attribute, getModel }, { set }) => {
1998
+ if (attribute) {
1999
+ return;
2000
+ }
2001
+ if (key === "sort") {
2002
+ set(key, await defaultSanitizeSort({ schema, getModel }, value));
2003
+ }
2004
+ if (key === "filters") {
2005
+ set(key, await defaultSanitizeFilters({ schema, getModel }, value));
2006
+ }
2007
+ if (key === "fields") {
2008
+ set(key, await defaultSanitizeFields({ schema, getModel }, value));
2009
+ }
2010
+ if (key === "populate") {
2011
+ set(key, await defaultSanitizePopulate({ schema, getModel }, value));
2012
+ }
2013
+ }, ctx),
1474
2014
  // Remove private fields
1475
- traverseQueryPopulate(visitor$7, { schema })
2015
+ traverseQueryPopulate(visitor$7, ctx)
1476
2016
  )(populate2);
1477
2017
  });
1478
2018
  const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -1484,7 +2024,8 @@ const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
1484
2024
  defaultSanitizeSort,
1485
2025
  sanitizePasswords
1486
2026
  }, Symbol.toStringTag, { value: "Module" }));
1487
- const createContentAPISanitizers = () => {
2027
+ const createAPISanitizers = (opts) => {
2028
+ const { getModel } = opts;
1488
2029
  const sanitizeInput = (data, schema, { auth } = {}) => {
1489
2030
  if (!schema) {
1490
2031
  throw new Error("Missing schema in sanitizeInput");
@@ -1498,12 +2039,14 @@ const createContentAPISanitizers = () => {
1498
2039
  omit(constants$1.ID_ATTRIBUTE),
1499
2040
  omit(constants$1.DOC_ID_ATTRIBUTE),
1500
2041
  // Remove non-writable attributes
1501
- traverseEntity$1(removeRestrictedFields(nonWritableAttributes), { schema })
2042
+ traverseEntity$1(removeRestrictedFields(nonWritableAttributes), { schema, getModel })
1502
2043
  ];
1503
2044
  if (auth) {
1504
- transforms.push(traverseEntity$1(removeRestrictedRelations(auth), { schema }));
2045
+ transforms.push(
2046
+ traverseEntity$1(removeRestrictedRelations(auth), { schema, getModel })
2047
+ );
1505
2048
  }
1506
- strapi.sanitizers.get("content-api.input").forEach((sanitizer) => transforms.push(sanitizer(schema)));
2049
+ opts?.sanitizers?.input?.forEach((sanitizer) => transforms.push(sanitizer(schema)));
1507
2050
  return pipe(...transforms)(data);
1508
2051
  };
1509
2052
  const sanitizeOutput = async (data, schema, { auth } = {}) => {
@@ -1517,11 +2060,15 @@ const createContentAPISanitizers = () => {
1517
2060
  }
1518
2061
  return res;
1519
2062
  }
1520
- const transforms = [(data2) => defaultSanitizeOutput(schema, data2)];
2063
+ const transforms = [
2064
+ (data2) => defaultSanitizeOutput({ schema, getModel }, data2)
2065
+ ];
1521
2066
  if (auth) {
1522
- transforms.push(traverseEntity$1(removeRestrictedRelations(auth), { schema }));
2067
+ transforms.push(
2068
+ traverseEntity$1(removeRestrictedRelations(auth), { schema, getModel })
2069
+ );
1523
2070
  }
1524
- strapi.sanitizers.get("content-api.output").forEach((sanitizer) => transforms.push(sanitizer(schema)));
2071
+ opts?.sanitizers?.output?.forEach((sanitizer) => transforms.push(sanitizer(schema)));
1525
2072
  return pipe(...transforms)(data);
1526
2073
  };
1527
2074
  const sanitizeQuery = async (query, schema, { auth } = {}) => {
@@ -1551,9 +2098,11 @@ const createContentAPISanitizers = () => {
1551
2098
  if (isArray(filters2)) {
1552
2099
  return Promise.all(filters2.map((filter) => sanitizeFilters(filter, schema, { auth })));
1553
2100
  }
1554
- const transforms = [defaultSanitizeFilters(schema)];
2101
+ const transforms = [defaultSanitizeFilters({ schema, getModel })];
1555
2102
  if (auth) {
1556
- transforms.push(traverseQueryFilters(removeRestrictedRelations(auth), { schema }));
2103
+ transforms.push(
2104
+ traverseQueryFilters(removeRestrictedRelations(auth), { schema, getModel })
2105
+ );
1557
2106
  }
1558
2107
  return pipe(...transforms)(filters2);
1559
2108
  };
@@ -1561,9 +2110,11 @@ const createContentAPISanitizers = () => {
1561
2110
  if (!schema) {
1562
2111
  throw new Error("Missing schema in sanitizeSort");
1563
2112
  }
1564
- const transforms = [defaultSanitizeSort(schema)];
2113
+ const transforms = [defaultSanitizeSort({ schema, getModel })];
1565
2114
  if (auth) {
1566
- transforms.push(traverseQuerySort(removeRestrictedRelations(auth), { schema }));
2115
+ transforms.push(
2116
+ traverseQuerySort(removeRestrictedRelations(auth), { schema, getModel })
2117
+ );
1567
2118
  }
1568
2119
  return pipe(...transforms)(sort2);
1569
2120
  };
@@ -1571,16 +2122,18 @@ const createContentAPISanitizers = () => {
1571
2122
  if (!schema) {
1572
2123
  throw new Error("Missing schema in sanitizeFields");
1573
2124
  }
1574
- const transforms = [defaultSanitizeFields(schema)];
2125
+ const transforms = [defaultSanitizeFields({ schema, getModel })];
1575
2126
  return pipe(...transforms)(fields2);
1576
2127
  };
1577
2128
  const sanitizePopulate = (populate2, schema, { auth } = {}) => {
1578
2129
  if (!schema) {
1579
2130
  throw new Error("Missing schema in sanitizePopulate");
1580
2131
  }
1581
- const transforms = [defaultSanitizePopulate(schema)];
2132
+ const transforms = [defaultSanitizePopulate({ schema, getModel })];
1582
2133
  if (auth) {
1583
- transforms.push(traverseQueryPopulate(removeRestrictedRelations(auth), { schema }));
2134
+ transforms.push(
2135
+ traverseQueryPopulate(removeRestrictedRelations(auth), { schema, getModel })
2136
+ );
1584
2137
  }
1585
2138
  return pipe(...transforms)(populate2);
1586
2139
  };
@@ -1594,118 +2147,11 @@ const createContentAPISanitizers = () => {
1594
2147
  populate: sanitizePopulate
1595
2148
  };
1596
2149
  };
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({
2150
+ const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1696
2151
  __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
2152
+ createAPISanitizers,
2153
+ sanitizers,
2154
+ visitors: index$4
1709
2155
  }, Symbol.toStringTag, { value: "Module" }));
1710
2156
  const throwInvalidParam = ({ key, path }) => {
1711
2157
  const msg = path && path !== key ? `Invalid parameter ${key} at ${path}` : `Invalid parameter ${key}`;
@@ -1828,7 +2274,7 @@ const throwRestrictedFields = (restrictedFields = null) => ({ key, path: { attri
1828
2274
  throwInvalidParam({ key, path });
1829
2275
  }
1830
2276
  };
1831
- const visitors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2277
+ const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1832
2278
  __proto__: null,
1833
2279
  throwDisallowedFields,
1834
2280
  throwDynamicZones: visitor,
@@ -1838,131 +2284,152 @@ const visitors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
1838
2284
  throwRestrictedFields,
1839
2285
  throwRestrictedRelations
1840
2286
  }, 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) {
2287
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$1 } = constants$1;
2288
+ const throwPasswords = (ctx) => async (entity) => {
2289
+ if (!ctx.schema) {
1844
2290
  throw new Error("Missing schema in throwPasswords");
1845
2291
  }
1846
- return traverseEntity$1(visitor$3, { schema }, entity);
2292
+ return traverseEntity$1(visitor$3, ctx, entity);
1847
2293
  };
1848
- const defaultValidateFilters = curry((schema, filters2) => {
1849
- if (!schema) {
2294
+ const defaultValidateFilters = curry((ctx, filters2) => {
2295
+ if (!ctx.schema) {
1850
2296
  throw new Error("Missing schema in defaultValidateFilters");
1851
2297
  }
1852
2298
  return pipe(
1853
2299
  // 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
- ),
2300
+ traverseQueryFilters(({ key, attribute, path }) => {
2301
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2302
+ return;
2303
+ }
2304
+ const isAttribute = !!attribute;
2305
+ if (!isAttribute && !isOperator(key)) {
2306
+ throwInvalidParam({ key, path: path.attribute });
2307
+ }
2308
+ }, ctx),
1866
2309
  // dynamic zones from filters
1867
- traverseQueryFilters(visitor, { schema }),
2310
+ traverseQueryFilters(visitor, ctx),
1868
2311
  // morphTo relations from filters; because you can't have deep filtering on morph relations
1869
- traverseQueryFilters(visitor$1, { schema }),
2312
+ traverseQueryFilters(visitor$1, ctx),
1870
2313
  // passwords from filters
1871
- traverseQueryFilters(visitor$3, { schema }),
2314
+ traverseQueryFilters(visitor$3, ctx),
1872
2315
  // private from filters
1873
- traverseQueryFilters(visitor$2, { schema })
2316
+ traverseQueryFilters(visitor$2, ctx)
1874
2317
  // we allow empty objects to validate and only sanitize them out, so that users may write "lazy" queries without checking their params exist
1875
2318
  )(filters2);
1876
2319
  });
1877
- const defaultValidateSort = curry((schema, sort2) => {
1878
- if (!schema) {
2320
+ const defaultValidateSort = curry((ctx, sort2) => {
2321
+ if (!ctx.schema) {
1879
2322
  throw new Error("Missing schema in defaultValidateSort");
1880
2323
  }
1881
2324
  return pipe(
1882
2325
  // 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
- ),
2326
+ traverseQuerySort(({ key, attribute, path }) => {
2327
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2328
+ return;
2329
+ }
2330
+ if (!attribute) {
2331
+ throwInvalidParam({ key, path: path.attribute });
2332
+ }
2333
+ }, ctx),
1894
2334
  // dynamic zones from sort
1895
- traverseQuerySort(visitor, { schema }),
2335
+ traverseQuerySort(visitor, ctx),
1896
2336
  // morphTo relations from sort
1897
- traverseQuerySort(visitor$1, { schema }),
2337
+ traverseQuerySort(visitor$1, ctx),
1898
2338
  // private from sort
1899
- traverseQuerySort(visitor$2, { schema }),
2339
+ traverseQuerySort(visitor$2, ctx),
1900
2340
  // passwords from filters
1901
- traverseQuerySort(visitor$3, { schema }),
2341
+ traverseQuerySort(visitor$3, ctx),
1902
2342
  // 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
- )
2343
+ traverseQuerySort(({ key, attribute, value, path }) => {
2344
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2345
+ return;
2346
+ }
2347
+ if (!isScalarAttribute(attribute) && isEmpty(value)) {
2348
+ throwInvalidParam({ key, path: path.attribute });
2349
+ }
2350
+ }, ctx)
1914
2351
  )(sort2);
1915
2352
  });
1916
- const defaultValidateFields = curry((schema, fields2) => {
1917
- if (!schema) {
2353
+ const defaultValidateFields = curry((ctx, fields2) => {
2354
+ if (!ctx.schema) {
1918
2355
  throw new Error("Missing schema in defaultValidateFields");
1919
2356
  }
1920
2357
  return pipe(
1921
2358
  // 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
- ),
2359
+ traverseQueryFields(({ key, attribute, path }) => {
2360
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2361
+ return;
2362
+ }
2363
+ if (isNil(attribute) || !isScalarAttribute(attribute)) {
2364
+ throwInvalidParam({ key, path: path.attribute });
2365
+ }
2366
+ }, ctx),
1933
2367
  // private fields
1934
- traverseQueryFields(visitor$2, { schema }),
2368
+ traverseQueryFields(visitor$2, ctx),
1935
2369
  // password fields
1936
- traverseQueryFields(visitor$3, { schema })
2370
+ traverseQueryFields(visitor$3, ctx)
1937
2371
  )(fields2);
1938
2372
  });
1939
- const defaultValidatePopulate = curry((schema, populate2) => {
1940
- if (!schema) {
2373
+ const defaultValidatePopulate = curry((ctx, populate2) => {
2374
+ if (!ctx.schema) {
1941
2375
  throw new Error("Missing schema in defaultValidatePopulate");
1942
2376
  }
1943
2377
  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
- ),
2378
+ traverseQueryPopulate(async ({ key, value, schema, attribute, getModel }, { set }) => {
2379
+ if (attribute) {
2380
+ return;
2381
+ }
2382
+ if (key === "sort") {
2383
+ set(
2384
+ key,
2385
+ await defaultValidateSort(
2386
+ {
2387
+ schema,
2388
+ getModel
2389
+ },
2390
+ value
2391
+ )
2392
+ );
2393
+ }
2394
+ if (key === "filters") {
2395
+ set(
2396
+ key,
2397
+ await defaultValidateFilters(
2398
+ {
2399
+ schema,
2400
+ getModel
2401
+ },
2402
+ value
2403
+ )
2404
+ );
2405
+ }
2406
+ if (key === "fields") {
2407
+ set(
2408
+ key,
2409
+ await defaultValidateFields(
2410
+ {
2411
+ schema,
2412
+ getModel
2413
+ },
2414
+ value
2415
+ )
2416
+ );
2417
+ }
2418
+ if (key === "populate") {
2419
+ set(
2420
+ key,
2421
+ await defaultValidatePopulate(
2422
+ {
2423
+ schema,
2424
+ getModel
2425
+ },
2426
+ value
2427
+ )
2428
+ );
2429
+ }
2430
+ }, ctx),
1964
2431
  // Remove private fields
1965
- traverseQueryPopulate(visitor$2, { schema })
2432
+ traverseQueryPopulate(visitor$2, ctx)
1966
2433
  )(populate2);
1967
2434
  });
1968
2435
  const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -1973,8 +2440,9 @@ const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
1973
2440
  defaultValidateSort,
1974
2441
  throwPasswords
1975
2442
  }, Symbol.toStringTag, { value: "Module" }));
1976
- const { ID_ATTRIBUTE: ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$1 } = constants$1;
1977
- const createContentAPIValidators = () => {
2443
+ const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants$1;
2444
+ const createAPIValidators = (opts) => {
2445
+ const { getModel } = opts || {};
1978
2446
  const validateInput = async (data, schema, { auth } = {}) => {
1979
2447
  if (!schema) {
1980
2448
  throw new Error("Missing schema in validateInput");
@@ -1987,21 +2455,26 @@ const createContentAPIValidators = () => {
1987
2455
  const transforms = [
1988
2456
  (data2) => {
1989
2457
  if (isObject(data2)) {
1990
- if (ID_ATTRIBUTE$1 in data2) {
1991
- throwInvalidParam({ key: ID_ATTRIBUTE$1 });
2458
+ if (ID_ATTRIBUTE in data2) {
2459
+ throwInvalidParam({ key: ID_ATTRIBUTE });
1992
2460
  }
1993
- if (DOC_ID_ATTRIBUTE$1 in data2) {
1994
- throwInvalidParam({ key: DOC_ID_ATTRIBUTE$1 });
2461
+ if (DOC_ID_ATTRIBUTE in data2) {
2462
+ throwInvalidParam({ key: DOC_ID_ATTRIBUTE });
1995
2463
  }
1996
2464
  }
1997
2465
  },
1998
2466
  // non-writable attributes
1999
- traverseEntity$1(throwRestrictedFields(nonWritableAttributes), { schema })
2467
+ traverseEntity$1(throwRestrictedFields(nonWritableAttributes), { schema, getModel })
2000
2468
  ];
2001
2469
  if (auth) {
2002
- transforms.push(traverseEntity$1(throwRestrictedRelations(auth), { schema }));
2003
- }
2004
- strapi.validators.get("content-api.input").forEach((validator) => transforms.push(validator(schema)));
2470
+ transforms.push(
2471
+ traverseEntity$1(throwRestrictedRelations(auth), {
2472
+ schema,
2473
+ getModel
2474
+ })
2475
+ );
2476
+ }
2477
+ opts?.validators?.input?.forEach((validator) => transforms.push(validator(schema)));
2005
2478
  await pipe(...transforms)(data);
2006
2479
  };
2007
2480
  const validateQuery = async (query, schema, { auth } = {}) => {
@@ -2030,9 +2503,14 @@ const createContentAPIValidators = () => {
2030
2503
  await Promise.all(filters2.map((filter) => validateFilters(filter, schema, { auth })));
2031
2504
  return;
2032
2505
  }
2033
- const transforms = [defaultValidateFilters(schema)];
2506
+ const transforms = [defaultValidateFilters({ schema, getModel })];
2034
2507
  if (auth) {
2035
- transforms.push(traverseQueryFilters(throwRestrictedRelations(auth), { schema }));
2508
+ transforms.push(
2509
+ traverseQueryFilters(throwRestrictedRelations(auth), {
2510
+ schema,
2511
+ getModel
2512
+ })
2513
+ );
2036
2514
  }
2037
2515
  await pipe(...transforms)(filters2);
2038
2516
  };
@@ -2040,9 +2518,14 @@ const createContentAPIValidators = () => {
2040
2518
  if (!schema) {
2041
2519
  throw new Error("Missing schema in validateSort");
2042
2520
  }
2043
- const transforms = [defaultValidateSort(schema)];
2521
+ const transforms = [defaultValidateSort({ schema, getModel })];
2044
2522
  if (auth) {
2045
- transforms.push(traverseQuerySort(throwRestrictedRelations(auth), { schema }));
2523
+ transforms.push(
2524
+ traverseQuerySort(throwRestrictedRelations(auth), {
2525
+ schema,
2526
+ getModel
2527
+ })
2528
+ );
2046
2529
  }
2047
2530
  await pipe(...transforms)(sort2);
2048
2531
  };
@@ -2050,16 +2533,21 @@ const createContentAPIValidators = () => {
2050
2533
  if (!schema) {
2051
2534
  throw new Error("Missing schema in validateFields");
2052
2535
  }
2053
- const transforms = [defaultValidateFields(schema)];
2536
+ const transforms = [defaultValidateFields({ schema, getModel })];
2054
2537
  await pipe(...transforms)(fields2);
2055
2538
  };
2056
2539
  const validatePopulate = async (populate2, schema, { auth } = {}) => {
2057
2540
  if (!schema) {
2058
2541
  throw new Error("Missing schema in sanitizePopulate");
2059
2542
  }
2060
- const transforms = [defaultValidatePopulate(schema)];
2543
+ const transforms = [defaultValidatePopulate({ schema, getModel })];
2061
2544
  if (auth) {
2062
- transforms.push(traverseQueryPopulate(throwRestrictedRelations(auth), { schema }));
2545
+ transforms.push(
2546
+ traverseQueryPopulate(throwRestrictedRelations(auth), {
2547
+ schema,
2548
+ getModel
2549
+ })
2550
+ );
2063
2551
  }
2064
2552
  await pipe(...transforms)(populate2);
2065
2553
  };
@@ -2072,436 +2560,12 @@ const createContentAPIValidators = () => {
2072
2560
  populate: validatePopulate
2073
2561
  };
2074
2562
  };
2075
- const contentAPI = createContentAPIValidators();
2076
- const index = {
2077
- contentAPI,
2563
+ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2564
+ __proto__: null,
2565
+ createAPIValidators,
2078
2566
  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
- };
2567
+ visitors: index$1
2568
+ }, Symbol.toStringTag, { value: "Module" }));
2505
2569
  const STRAPI_DEFAULTS = {
2506
2570
  offset: {
2507
2571
  start: 0,
@@ -2653,72 +2717,6 @@ const file = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
2653
2717
  streamToBuffer,
2654
2718
  writableDiscardStream
2655
2719
  }, 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
2720
  const createPolicy = (options) => {
2723
2721
  const { name = "unnamed", validator, handler } = options;
2724
2722
  const wrappedValidator = (config) => {
@@ -2750,10 +2748,7 @@ const createPolicyContext = (type, ctx) => {
2750
2748
  const policy = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2751
2749
  __proto__: null,
2752
2750
  createPolicy,
2753
- createPolicyContext,
2754
- get: getPolicy,
2755
- globalPolicy,
2756
- resolve: resolvePolicies
2751
+ createPolicyContext
2757
2752
  }, Symbol.toStringTag, { value: "Module" }));
2758
2753
  const nameToSlug = (name, options = { separator: "-" }) => slugify(name, options);
2759
2754
  const nameToCollectionName = (name) => slugify(name, { separator: "_" });
@@ -2992,11 +2987,31 @@ const relations = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePro
2992
2987
  isManyToAny,
2993
2988
  isOneToAny
2994
2989
  }, Symbol.toStringTag, { value: "Module" }));
2990
+ const validateZod = (schema) => (data) => {
2991
+ try {
2992
+ return schema.parse(data);
2993
+ } catch (error) {
2994
+ if (error instanceof z.ZodError) {
2995
+ const { message, errors: errors2 } = formatZodErrors(error);
2996
+ throw new ValidationError(message, { errors: errors2 });
2997
+ }
2998
+ throw error;
2999
+ }
3000
+ };
3001
+ const formatZodErrors = (zodError) => ({
3002
+ errors: zodError.errors.map((error) => {
3003
+ return {
3004
+ path: error.path,
3005
+ message: error.message,
3006
+ name: "ValidationError"
3007
+ };
3008
+ }),
3009
+ message: "Validation error"
3010
+ });
2995
3011
  export {
2996
3012
  arrays,
2997
3013
  async,
2998
3014
  contentTypes,
2999
- convertQueryParams,
3000
3015
  dates,
3001
3016
  env,
3002
3017
  errors,
@@ -3012,16 +3027,18 @@ export {
3012
3027
  parseType,
3013
3028
  policy,
3014
3029
  providerFactory,
3030
+ convertQueryParams as queryParams,
3015
3031
  relations,
3016
- index$1 as sanitize,
3032
+ index$2 as sanitize,
3017
3033
  setCreatorFields,
3018
3034
  strings,
3019
3035
  template,
3020
- index$2 as traverse,
3036
+ index$3 as traverse,
3021
3037
  traverseEntity$1 as traverseEntity,
3022
3038
  index as validate,
3023
3039
  validateYupSchema,
3024
3040
  validateYupSchemaSync,
3041
+ validateZod,
3025
3042
  yup
3026
3043
  };
3027
3044
  //# sourceMappingURL=index.mjs.map