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