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