@strapi/utils 4.15.0-alpha.0 → 4.15.0
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 +1 -0
- package/dist/async.d.ts.map +1 -0
- package/dist/code-generator.d.ts +1 -0
- package/dist/code-generator.d.ts.map +1 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/content-types.d.ts +1 -0
- package/dist/content-types.d.ts.map +1 -0
- package/dist/convert-query-params.d.ts +1 -0
- package/dist/convert-query-params.d.ts.map +1 -0
- package/dist/env-helper.d.ts +1 -0
- package/dist/env-helper.d.ts.map +1 -0
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/file.d.ts +1 -0
- package/dist/file.d.ts.map +1 -0
- package/dist/format-yup-error.d.ts +1 -0
- package/dist/format-yup-error.d.ts.map +1 -0
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/import-default.d.ts +1 -0
- package/dist/import-default.d.ts.map +1 -0
- package/dist/index.d.ts +20 -143
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3036 -104
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3019 -0
- package/dist/index.mjs.map +1 -0
- package/dist/object-formatting.d.ts +1 -0
- package/dist/object-formatting.d.ts.map +1 -0
- package/dist/operators.d.ts +1 -0
- package/dist/operators.d.ts.map +1 -0
- package/dist/pagination.d.ts +1 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/parse-multipart.d.ts +2 -2
- package/dist/parse-multipart.d.ts.map +1 -0
- package/dist/parse-type.d.ts +1 -0
- package/dist/parse-type.d.ts.map +1 -0
- package/dist/policy.d.ts +1 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/print-value.d.ts +2 -1
- package/dist/print-value.d.ts.map +1 -0
- package/dist/provider-factory.d.ts +1 -0
- package/dist/provider-factory.d.ts.map +1 -0
- package/dist/relations.d.ts +1 -0
- package/dist/relations.d.ts.map +1 -0
- package/dist/sanitize/index.d.ts +1 -0
- package/dist/sanitize/index.d.ts.map +1 -0
- package/dist/sanitize/sanitizers.d.ts +1 -0
- package/dist/sanitize/sanitizers.d.ts.map +1 -0
- package/dist/sanitize/visitors/index.d.ts +1 -0
- package/dist/sanitize/visitors/index.d.ts.map +1 -0
- package/dist/sanitize/visitors/remove-disallowed-fields.d.ts +1 -0
- package/dist/sanitize/visitors/remove-disallowed-fields.d.ts.map +1 -0
- package/dist/sanitize/visitors/remove-dynamic-zones.d.ts +1 -0
- package/dist/sanitize/visitors/remove-dynamic-zones.d.ts.map +1 -0
- package/dist/sanitize/visitors/remove-morph-to-relations.d.ts +1 -0
- package/dist/sanitize/visitors/remove-morph-to-relations.d.ts.map +1 -0
- package/dist/sanitize/visitors/remove-password.d.ts +1 -0
- package/dist/sanitize/visitors/remove-password.d.ts.map +1 -0
- package/dist/sanitize/visitors/remove-private.d.ts +1 -0
- package/dist/sanitize/visitors/remove-private.d.ts.map +1 -0
- package/dist/sanitize/visitors/remove-restricted-fields.d.ts +1 -0
- package/dist/sanitize/visitors/remove-restricted-fields.d.ts.map +1 -0
- package/dist/sanitize/visitors/remove-restricted-relations.d.ts +1 -0
- package/dist/sanitize/visitors/remove-restricted-relations.d.ts.map +1 -0
- package/dist/set-creator-fields.d.ts +1 -0
- package/dist/set-creator-fields.d.ts.map +1 -0
- package/dist/string-formatting.d.ts +1 -0
- package/dist/string-formatting.d.ts.map +1 -0
- package/dist/template-configuration.d.ts +2 -1
- package/dist/template-configuration.d.ts.map +1 -0
- package/dist/template.d.ts +1 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/traverse/factory.d.ts +1 -0
- package/dist/traverse/factory.d.ts.map +1 -0
- package/dist/traverse/index.d.ts +1 -0
- package/dist/traverse/index.d.ts.map +1 -0
- package/dist/traverse/query-fields.d.ts +1 -0
- package/dist/traverse/query-fields.d.ts.map +1 -0
- package/dist/traverse/query-filters.d.ts +1 -0
- package/dist/traverse/query-filters.d.ts.map +1 -0
- package/dist/traverse/query-populate.d.ts +1 -0
- package/dist/traverse/query-populate.d.ts.map +1 -0
- package/dist/traverse/query-sort.d.ts +1 -0
- package/dist/traverse/query-sort.d.ts.map +1 -0
- package/dist/traverse-entity.d.ts +1 -0
- package/dist/traverse-entity.d.ts.map +1 -0
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -0
- package/dist/validate/index.d.ts +1 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/utils.d.ts +1 -0
- package/dist/validate/utils.d.ts.map +1 -0
- package/dist/validate/validators.d.ts +1 -0
- package/dist/validate/validators.d.ts.map +1 -0
- package/dist/validate/visitors/index.d.ts +1 -0
- package/dist/validate/visitors/index.d.ts.map +1 -0
- package/dist/validate/visitors/throw-disallowed-fields.d.ts +1 -0
- package/dist/validate/visitors/throw-disallowed-fields.d.ts.map +1 -0
- package/dist/validate/visitors/throw-dynamic-zones.d.ts +1 -0
- package/dist/validate/visitors/throw-dynamic-zones.d.ts.map +1 -0
- package/dist/validate/visitors/throw-morph-to-relations.d.ts +1 -0
- package/dist/validate/visitors/throw-morph-to-relations.d.ts.map +1 -0
- package/dist/validate/visitors/throw-password.d.ts +1 -0
- package/dist/validate/visitors/throw-password.d.ts.map +1 -0
- package/dist/validate/visitors/throw-private.d.ts +1 -0
- package/dist/validate/visitors/throw-private.d.ts.map +1 -0
- package/dist/validate/visitors/throw-restricted-fields.d.ts +1 -0
- package/dist/validate/visitors/throw-restricted-fields.d.ts.map +1 -0
- package/dist/validate/visitors/throw-restricted-relations.d.ts +1 -0
- package/dist/validate/visitors/throw-restricted-relations.d.ts.map +1 -0
- package/dist/validators.d.ts +1 -0
- package/dist/validators.d.ts.map +1 -0
- package/dist/webhook.d.ts +1 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/yup.d.ts +1 -0
- package/dist/yup.d.ts.map +1 -0
- package/package.json +13 -13
- package/dist/async.js +0 -33
- package/dist/async.js.map +0 -1
- package/dist/code-generator.js +0 -11
- package/dist/code-generator.js.map +0 -1
- package/dist/config.js +0 -79
- package/dist/config.js.map +0 -1
- package/dist/content-types.js +0 -162
- package/dist/content-types.js.map +0 -1
- package/dist/convert-query-params.js +0 -477
- package/dist/convert-query-params.js.map +0 -1
- package/dist/env-helper.js +0 -84
- package/dist/env-helper.js.map +0 -1
- package/dist/errors.js +0 -101
- package/dist/errors.js.map +0 -1
- package/dist/file.js +0 -54
- package/dist/file.js.map +0 -1
- package/dist/format-yup-error.js +0 -17
- package/dist/format-yup-error.js.map +0 -1
- package/dist/hooks.js +0 -89
- package/dist/hooks.js.map +0 -1
- package/dist/import-default.js +0 -9
- package/dist/import-default.js.map +0 -1
- package/dist/object-formatting.js +0 -14
- package/dist/object-formatting.js.map +0 -1
- package/dist/operators.js +0 -72
- package/dist/operators.js.map +0 -1
- package/dist/pagination.js +0 -80
- package/dist/pagination.js.map +0 -1
- package/dist/parse-multipart.js +0 -36
- package/dist/parse-multipart.js.map +0 -1
- package/dist/parse-type.js +0 -108
- package/dist/parse-type.js.map +0 -1
- package/dist/policy.js +0 -109
- package/dist/policy.js.map +0 -1
- package/dist/print-value.js +0 -50
- package/dist/print-value.js.map +0 -1
- package/dist/provider-factory.js +0 -80
- package/dist/provider-factory.js.map +0 -1
- package/dist/relations.js +0 -23
- package/dist/relations.js.map +0 -1
- package/dist/sanitize/index.js +0 -156
- package/dist/sanitize/index.js.map +0 -1
- package/dist/sanitize/sanitizers.js +0 -147
- package/dist/sanitize/sanitizers.js.map +0 -1
- package/dist/sanitize/visitors/index.js +0 -21
- package/dist/sanitize/visitors/index.js.map +0 -1
- package/dist/sanitize/visitors/remove-disallowed-fields.js +0 -83
- package/dist/sanitize/visitors/remove-disallowed-fields.js.map +0 -1
- package/dist/sanitize/visitors/remove-dynamic-zones.js +0 -10
- package/dist/sanitize/visitors/remove-dynamic-zones.js.map +0 -1
- package/dist/sanitize/visitors/remove-morph-to-relations.js +0 -10
- package/dist/sanitize/visitors/remove-morph-to-relations.js.map +0 -1
- package/dist/sanitize/visitors/remove-password.js +0 -9
- package/dist/sanitize/visitors/remove-password.js.map +0 -1
- package/dist/sanitize/visitors/remove-private.js +0 -14
- package/dist/sanitize/visitors/remove-private.js.map +0 -1
- package/dist/sanitize/visitors/remove-restricted-fields.js +0 -25
- package/dist/sanitize/visitors/remove-restricted-fields.js.map +0 -1
- package/dist/sanitize/visitors/remove-restricted-relations.js +0 -88
- package/dist/sanitize/visitors/remove-restricted-relations.js.map +0 -1
- package/dist/set-creator-fields.js +0 -39
- package/dist/set-creator-fields.js.map +0 -1
- package/dist/string-formatting.js +0 -85
- package/dist/string-formatting.js.map +0 -1
- package/dist/template-configuration.js +0 -30
- package/dist/template-configuration.js.map +0 -1
- package/dist/template.js +0 -20
- package/dist/template.js.map +0 -1
- package/dist/traverse/factory.js +0 -127
- package/dist/traverse/factory.js.map +0 -1
- package/dist/traverse/index.js +0 -17
- package/dist/traverse/index.js.map +0 -1
- package/dist/traverse/query-fields.js +0 -35
- package/dist/traverse/query-fields.js.map +0 -1
- package/dist/traverse/query-filters.js +0 -75
- package/dist/traverse/query-filters.js.map +0 -1
- package/dist/traverse/query-populate.js +0 -171
- package/dist/traverse/query-populate.js.map +0 -1
- package/dist/traverse/query-sort.js +0 -117
- package/dist/traverse/query-sort.js.map +0 -1
- package/dist/traverse-entity.js +0 -134
- package/dist/traverse-entity.js.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/dist/validate/index.js +0 -121
- package/dist/validate/index.js.map +0 -1
- package/dist/validate/utils.js +0 -9
- package/dist/validate/utils.js.map +0 -1
- package/dist/validate/validators.js +0 -111
- package/dist/validate/validators.js.map +0 -1
- package/dist/validate/visitors/index.js +0 -21
- package/dist/validate/visitors/index.js.map +0 -1
- package/dist/validate/visitors/throw-disallowed-fields.js +0 -84
- package/dist/validate/visitors/throw-disallowed-fields.js.map +0 -1
- package/dist/validate/visitors/throw-dynamic-zones.js +0 -11
- package/dist/validate/visitors/throw-dynamic-zones.js.map +0 -1
- package/dist/validate/visitors/throw-morph-to-relations.js +0 -11
- package/dist/validate/visitors/throw-morph-to-relations.js.map +0 -1
- package/dist/validate/visitors/throw-password.js +0 -10
- package/dist/validate/visitors/throw-password.js.map +0 -1
- package/dist/validate/visitors/throw-private.js +0 -15
- package/dist/validate/visitors/throw-private.js.map +0 -1
- package/dist/validate/visitors/throw-restricted-fields.js +0 -24
- package/dist/validate/visitors/throw-restricted-fields.js.map +0 -1
- package/dist/validate/visitors/throw-restricted-relations.js +0 -81
- package/dist/validate/visitors/throw-restricted-relations.js.map +0 -1
- package/dist/validators.js +0 -64
- package/dist/validators.js.map +0 -1
- package/dist/webhook.js +0 -27
- package/dist/webhook.js.map +0 -1
- package/dist/yup.js +0 -108
- package/dist/yup.js.map +0 -1
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,3019 @@
|
|
|
1
|
+
import _$1, { isString, isPlainObject as isPlainObject$1, kebabCase } from "lodash";
|
|
2
|
+
import { eq, isEmpty, toPath, defaults, trimChars, trimCharsEnd, trimCharsStart, get, isNumber, isInteger, has, union, getOr, assoc, assign, cloneDeep, remove, merge, isNil, pipe, omit, curry, isArray, isString as isString$1, isObject, clone, pick, trim, split, map, flatten, first, join, constant, mergeAll, toNumber } from "lodash/fp";
|
|
3
|
+
import * as yup$1 from "yup";
|
|
4
|
+
import { HttpError } from "http-errors";
|
|
5
|
+
import slugify from "@sindresorhus/slugify";
|
|
6
|
+
import pMap from "p-map";
|
|
7
|
+
import { Writable } from "node:stream";
|
|
8
|
+
function _mergeNamespaces(n, m) {
|
|
9
|
+
for (var i = 0; i < m.length; i++) {
|
|
10
|
+
const e = m[i];
|
|
11
|
+
if (typeof e !== "string" && !Array.isArray(e)) {
|
|
12
|
+
for (const k in e) {
|
|
13
|
+
if (k !== "default" && !(k in n)) {
|
|
14
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
if (d) {
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: () => e[k]
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
|
|
26
|
+
}
|
|
27
|
+
const parseMultipartData = (ctx) => {
|
|
28
|
+
if (!ctx.is("multipart")) {
|
|
29
|
+
return { data: ctx.request.body, files: {} };
|
|
30
|
+
}
|
|
31
|
+
const { body = {}, files = {} } = ctx.request;
|
|
32
|
+
if (!body.data) {
|
|
33
|
+
return ctx.badRequest(
|
|
34
|
+
`When using multipart/form-data you need to provide your data in a JSON 'data' field.`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
let data;
|
|
38
|
+
try {
|
|
39
|
+
data = JSON.parse(body.data);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return ctx.badRequest(`Invalid 'data' field. 'data' should be a valid JSON.`);
|
|
42
|
+
}
|
|
43
|
+
const filesToUpload = Object.keys(files).reduce((acc2, key2) => {
|
|
44
|
+
const fullPath = _$1.toPath(key2);
|
|
45
|
+
if (fullPath.length <= 1 || fullPath[0] !== "files") {
|
|
46
|
+
return ctx.badRequest(
|
|
47
|
+
`When using multipart/form-data you need to provide your files by prefixing them with the 'files'.
|
|
48
|
+
For example, when a media file is named "avatar", make sure the form key name is "files.avatar"`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
const path = _$1.tail(fullPath);
|
|
52
|
+
acc2[path.join(".")] = files[key2];
|
|
53
|
+
return acc2;
|
|
54
|
+
}, {});
|
|
55
|
+
return {
|
|
56
|
+
data,
|
|
57
|
+
files: filesToUpload
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
const _ = require("lodash");
|
|
61
|
+
const dates = require("date-fns");
|
|
62
|
+
const timeRegex = /^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]{1,3})?$/;
|
|
63
|
+
const isDate = (v) => {
|
|
64
|
+
return dates.isDate(v);
|
|
65
|
+
};
|
|
66
|
+
const parseTime = (value2) => {
|
|
67
|
+
if (isDate(value2)) {
|
|
68
|
+
return dates.format(value2, "HH:mm:ss.SSS");
|
|
69
|
+
}
|
|
70
|
+
if (typeof value2 !== "string") {
|
|
71
|
+
throw new Error(`Expected a string, got a ${typeof value2}`);
|
|
72
|
+
}
|
|
73
|
+
const result = value2.match(timeRegex);
|
|
74
|
+
if (result === null) {
|
|
75
|
+
throw new Error("Invalid time format, expected HH:mm:ss.SSS");
|
|
76
|
+
}
|
|
77
|
+
const [, hours, minutes, seconds, fraction = ".000"] = result;
|
|
78
|
+
const fractionPart = _.padEnd(fraction.slice(1), 3, "0");
|
|
79
|
+
return `${hours}:${minutes}:${seconds}.${fractionPart}`;
|
|
80
|
+
};
|
|
81
|
+
const parseDate = (value2) => {
|
|
82
|
+
if (isDate(value2)) {
|
|
83
|
+
return dates.format(value2, "yyyy-MM-dd");
|
|
84
|
+
}
|
|
85
|
+
if (typeof value2 !== "string") {
|
|
86
|
+
throw new Error(`Expected a string, got a ${typeof value2}`);
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const date = dates.parseISO(value2);
|
|
90
|
+
if (dates.isValid(date))
|
|
91
|
+
return dates.format(date, "yyyy-MM-dd");
|
|
92
|
+
throw new Error(`Invalid format, expected an ISO compatible date`);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
throw new Error(`Invalid format, expected an ISO compatible date`);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const parseDateTimeOrTimestamp = (value2) => {
|
|
98
|
+
if (isDate(value2)) {
|
|
99
|
+
return value2;
|
|
100
|
+
}
|
|
101
|
+
if (typeof value2 !== "string") {
|
|
102
|
+
throw new Error(`Expected a string, got a ${typeof value2}`);
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const date = dates.parseISO(value2);
|
|
106
|
+
if (dates.isValid(date))
|
|
107
|
+
return date;
|
|
108
|
+
const milliUnixDate = dates.parse(value2, "T", /* @__PURE__ */ new Date());
|
|
109
|
+
if (dates.isValid(milliUnixDate))
|
|
110
|
+
return milliUnixDate;
|
|
111
|
+
throw new Error(`Invalid format, expected a timestamp or an ISO date`);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
throw new Error(`Invalid format, expected a timestamp or an ISO date`);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const parseBoolean = (value2, options) => {
|
|
117
|
+
const { forceCast = false } = options;
|
|
118
|
+
if (typeof value2 === "boolean") {
|
|
119
|
+
return value2;
|
|
120
|
+
}
|
|
121
|
+
if (typeof value2 === "string" || typeof value2 === "number") {
|
|
122
|
+
if (["true", "t", "1", 1].includes(value2)) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
if (["false", "f", "0", 0].includes(value2)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (forceCast) {
|
|
130
|
+
return Boolean(value2);
|
|
131
|
+
}
|
|
132
|
+
throw new Error('Invalid boolean input. Expected "t","1","true","false","0","f"');
|
|
133
|
+
};
|
|
134
|
+
const parseType = (options) => {
|
|
135
|
+
const { type, value: value2, forceCast } = options;
|
|
136
|
+
switch (type) {
|
|
137
|
+
case "boolean":
|
|
138
|
+
return parseBoolean(value2, { forceCast });
|
|
139
|
+
case "integer":
|
|
140
|
+
case "biginteger":
|
|
141
|
+
case "float":
|
|
142
|
+
case "decimal": {
|
|
143
|
+
return _.toNumber(value2);
|
|
144
|
+
}
|
|
145
|
+
case "time": {
|
|
146
|
+
return parseTime(value2);
|
|
147
|
+
}
|
|
148
|
+
case "date": {
|
|
149
|
+
return parseDate(value2);
|
|
150
|
+
}
|
|
151
|
+
case "timestamp":
|
|
152
|
+
case "datetime": {
|
|
153
|
+
return parseDateTimeOrTimestamp(value2);
|
|
154
|
+
}
|
|
155
|
+
default:
|
|
156
|
+
return value2;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
const PLUGIN_PREFIX = "plugin::";
|
|
160
|
+
const API_PREFIX = "api::";
|
|
161
|
+
const parsePolicy = (policy2) => {
|
|
162
|
+
if (typeof policy2 === "string") {
|
|
163
|
+
return { policyName: policy2, config: {} };
|
|
164
|
+
}
|
|
165
|
+
const { name, config } = policy2;
|
|
166
|
+
return { policyName: name, config };
|
|
167
|
+
};
|
|
168
|
+
const searchLocalPolicy = (policyName, policyContext) => {
|
|
169
|
+
const { pluginName, apiName } = policyContext ?? {};
|
|
170
|
+
if (pluginName) {
|
|
171
|
+
return strapi.policy(`${PLUGIN_PREFIX}${pluginName}.${policyName}`);
|
|
172
|
+
}
|
|
173
|
+
if (apiName) {
|
|
174
|
+
return strapi.policy(`${API_PREFIX}${apiName}.${policyName}`);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
const globalPolicy = ({ method, endpoint, controller, action, plugin }) => {
|
|
178
|
+
return async (ctx, next) => {
|
|
179
|
+
ctx.request.route = {
|
|
180
|
+
endpoint: `${method} ${endpoint}`,
|
|
181
|
+
controller: _$1.toLower(controller),
|
|
182
|
+
action: _$1.toLower(action),
|
|
183
|
+
verb: _$1.toLower(method),
|
|
184
|
+
plugin
|
|
185
|
+
};
|
|
186
|
+
await next();
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
const resolvePolicies = (config, policyContext) => {
|
|
190
|
+
const { pluginName, apiName } = policyContext ?? {};
|
|
191
|
+
return config.map((policyConfig) => {
|
|
192
|
+
return {
|
|
193
|
+
handler: getPolicy(policyConfig, { pluginName, apiName }),
|
|
194
|
+
config: typeof policyConfig === "object" && policyConfig.config || {}
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
const findPolicy = (name, policyContext) => {
|
|
199
|
+
const { pluginName, apiName } = policyContext ?? {};
|
|
200
|
+
const resolvedPolicy = strapi.policy(name);
|
|
201
|
+
if (resolvedPolicy !== void 0) {
|
|
202
|
+
return resolvedPolicy;
|
|
203
|
+
}
|
|
204
|
+
const localPolicy = searchLocalPolicy(name, { pluginName, apiName });
|
|
205
|
+
if (localPolicy !== void 0) {
|
|
206
|
+
return localPolicy;
|
|
207
|
+
}
|
|
208
|
+
throw new Error(`Could not find policy "${name}"`);
|
|
209
|
+
};
|
|
210
|
+
const getPolicy = (policyConfig, policyContext) => {
|
|
211
|
+
const { pluginName, apiName } = policyContext ?? {};
|
|
212
|
+
if (typeof policyConfig === "function") {
|
|
213
|
+
return policyConfig;
|
|
214
|
+
}
|
|
215
|
+
const { policyName, config } = parsePolicy(policyConfig);
|
|
216
|
+
const policy2 = findPolicy(policyName, { pluginName, apiName });
|
|
217
|
+
if (typeof policy2 === "function") {
|
|
218
|
+
return policy2;
|
|
219
|
+
}
|
|
220
|
+
if (policy2.validator) {
|
|
221
|
+
policy2.validator(config);
|
|
222
|
+
}
|
|
223
|
+
return policy2.handler;
|
|
224
|
+
};
|
|
225
|
+
const createPolicy = (options) => {
|
|
226
|
+
const { name = "unnamed", validator, handler } = options;
|
|
227
|
+
const wrappedValidator = (config) => {
|
|
228
|
+
if (validator) {
|
|
229
|
+
try {
|
|
230
|
+
validator(config);
|
|
231
|
+
} catch (e) {
|
|
232
|
+
throw new Error(`Invalid config passed to "${name}" policy.`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
return {
|
|
237
|
+
name,
|
|
238
|
+
validator: wrappedValidator,
|
|
239
|
+
handler
|
|
240
|
+
};
|
|
241
|
+
};
|
|
242
|
+
const createPolicyContext = (type, ctx) => {
|
|
243
|
+
return Object.assign(
|
|
244
|
+
{
|
|
245
|
+
is: eq(type),
|
|
246
|
+
get type() {
|
|
247
|
+
return type;
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
ctx
|
|
251
|
+
);
|
|
252
|
+
};
|
|
253
|
+
const policy = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
254
|
+
__proto__: null,
|
|
255
|
+
createPolicy,
|
|
256
|
+
createPolicyContext,
|
|
257
|
+
get: getPolicy,
|
|
258
|
+
globalPolicy,
|
|
259
|
+
resolve: resolvePolicies
|
|
260
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
261
|
+
const regex = /\$\{[^()]*\}/g;
|
|
262
|
+
const excludeConfigPaths = ["info.scripts"];
|
|
263
|
+
const isObj$3 = (value2) => isPlainObject$1(value2);
|
|
264
|
+
const templateConfiguration = (obj, configPath = "") => {
|
|
265
|
+
return Object.keys(obj).reduce((acc, key) => {
|
|
266
|
+
const value = obj[key];
|
|
267
|
+
if (isObj$3(value) && !isString(value)) {
|
|
268
|
+
acc[key] = templateConfiguration(value, `${configPath}.${key}`);
|
|
269
|
+
} else if (isString(value) && !excludeConfigPaths.includes(configPath.substr(1)) && value.match(regex) !== null) {
|
|
270
|
+
acc[key] = eval("`" + value + "`");
|
|
271
|
+
} else {
|
|
272
|
+
acc[key] = value;
|
|
273
|
+
}
|
|
274
|
+
return acc;
|
|
275
|
+
}, {});
|
|
276
|
+
};
|
|
277
|
+
const formatYupInnerError = (yupError) => ({
|
|
278
|
+
path: toPath(yupError.path),
|
|
279
|
+
message: yupError.message,
|
|
280
|
+
name: yupError.name
|
|
281
|
+
});
|
|
282
|
+
const formatYupErrors = (yupError) => ({
|
|
283
|
+
errors: isEmpty(yupError.inner) ? [formatYupInnerError(yupError)] : yupError.inner.map(formatYupInnerError),
|
|
284
|
+
message: yupError.message
|
|
285
|
+
});
|
|
286
|
+
class ApplicationError extends Error {
|
|
287
|
+
details;
|
|
288
|
+
constructor(message = "An application error occured", details = {}) {
|
|
289
|
+
super();
|
|
290
|
+
this.name = "ApplicationError";
|
|
291
|
+
this.message = message;
|
|
292
|
+
this.details = details;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
class ValidationError extends ApplicationError {
|
|
296
|
+
constructor(message = "Validation error", details) {
|
|
297
|
+
super(message, details);
|
|
298
|
+
this.name = "ValidationError";
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
class YupValidationError extends ValidationError {
|
|
302
|
+
constructor(yupError, message) {
|
|
303
|
+
super("Validation");
|
|
304
|
+
const { errors: errors2, message: yupMessage } = formatYupErrors(yupError);
|
|
305
|
+
this.message = message || yupMessage;
|
|
306
|
+
this.details = { errors: errors2 };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
class PaginationError extends ApplicationError {
|
|
310
|
+
constructor(message = "Invalid pagination", details) {
|
|
311
|
+
super(message, details);
|
|
312
|
+
this.name = "PaginationError";
|
|
313
|
+
this.message = message;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
class NotFoundError extends ApplicationError {
|
|
317
|
+
constructor(message = "Entity not found", details) {
|
|
318
|
+
super(message, details);
|
|
319
|
+
this.name = "NotFoundError";
|
|
320
|
+
this.message = message;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
class ForbiddenError extends ApplicationError {
|
|
324
|
+
constructor(message = "Forbidden access", details) {
|
|
325
|
+
super(message, details);
|
|
326
|
+
this.name = "ForbiddenError";
|
|
327
|
+
this.message = message;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
class UnauthorizedError extends ApplicationError {
|
|
331
|
+
constructor(message = "Unauthorized", details) {
|
|
332
|
+
super(message, details);
|
|
333
|
+
this.name = "UnauthorizedError";
|
|
334
|
+
this.message = message;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
class RateLimitError extends ApplicationError {
|
|
338
|
+
constructor(message = "Too many requests, please try again later.", details) {
|
|
339
|
+
super(message, details);
|
|
340
|
+
this.name = "RateLimitError";
|
|
341
|
+
this.message = message;
|
|
342
|
+
this.details = details || {};
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
class PayloadTooLargeError extends ApplicationError {
|
|
346
|
+
constructor(message = "Entity too large", details) {
|
|
347
|
+
super(message, details);
|
|
348
|
+
this.name = "PayloadTooLargeError";
|
|
349
|
+
this.message = message;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
class PolicyError extends ForbiddenError {
|
|
353
|
+
constructor(message = "Policy Failed", details) {
|
|
354
|
+
super(message, details);
|
|
355
|
+
this.name = "PolicyError";
|
|
356
|
+
this.message = message;
|
|
357
|
+
this.details = details || {};
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
class NotImplementedError extends ApplicationError {
|
|
361
|
+
constructor(message = "This feature is not implemented yet", details) {
|
|
362
|
+
super(message, details);
|
|
363
|
+
this.name = "NotImplementedError";
|
|
364
|
+
this.message = message;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const errors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
368
|
+
__proto__: null,
|
|
369
|
+
ApplicationError,
|
|
370
|
+
ForbiddenError,
|
|
371
|
+
HttpError,
|
|
372
|
+
NotFoundError,
|
|
373
|
+
NotImplementedError,
|
|
374
|
+
PaginationError,
|
|
375
|
+
PayloadTooLargeError,
|
|
376
|
+
PolicyError,
|
|
377
|
+
RateLimitError,
|
|
378
|
+
UnauthorizedError,
|
|
379
|
+
ValidationError,
|
|
380
|
+
YupValidationError
|
|
381
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
382
|
+
const handleYupError = (error, errorMessage) => {
|
|
383
|
+
throw new YupValidationError(error, errorMessage);
|
|
384
|
+
};
|
|
385
|
+
const defaultValidationParam = { strict: true, abortEarly: false };
|
|
386
|
+
const validateYupSchema = (schema, options = {}) => async (body, errorMessage) => {
|
|
387
|
+
try {
|
|
388
|
+
const optionsWithDefaults = defaults(defaultValidationParam, options);
|
|
389
|
+
const result = await schema.validate(body, optionsWithDefaults);
|
|
390
|
+
return result;
|
|
391
|
+
} catch (e) {
|
|
392
|
+
if (e instanceof yup$1.ValidationError) {
|
|
393
|
+
handleYupError(e, errorMessage);
|
|
394
|
+
}
|
|
395
|
+
throw e;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
const validateYupSchemaSync = (schema, options = {}) => (body, errorMessage) => {
|
|
399
|
+
try {
|
|
400
|
+
const optionsWithDefaults = defaults(defaultValidationParam, options);
|
|
401
|
+
return schema.validateSync(body, optionsWithDefaults);
|
|
402
|
+
} catch (e) {
|
|
403
|
+
if (e instanceof yup$1.ValidationError) {
|
|
404
|
+
handleYupError(e, errorMessage);
|
|
405
|
+
}
|
|
406
|
+
throw e;
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
const nameToSlug = (name, options = { separator: "-" }) => slugify(name, options);
|
|
410
|
+
const nameToCollectionName = (name) => slugify(name, { separator: "_" });
|
|
411
|
+
const toRegressedEnumValue = (value2) => slugify(value2, {
|
|
412
|
+
decamelize: false,
|
|
413
|
+
lowercase: false,
|
|
414
|
+
separator: "_"
|
|
415
|
+
});
|
|
416
|
+
const getCommonBeginning = (...strings) => _$1.takeWhile(strings[0], (char, index2) => strings.every((string) => string[index2] === char)).join(
|
|
417
|
+
""
|
|
418
|
+
);
|
|
419
|
+
const getCommonPath = (...paths) => {
|
|
420
|
+
const [segments, ...otherSegments] = paths.map((it) => _$1.split(it, "/"));
|
|
421
|
+
return _$1.join(
|
|
422
|
+
_$1.takeWhile(segments, (str, index2) => otherSegments.every((it) => it[index2] === str)),
|
|
423
|
+
"/"
|
|
424
|
+
);
|
|
425
|
+
};
|
|
426
|
+
const escapeQuery = (query, charsToEscape, escapeChar = "\\") => {
|
|
427
|
+
return query.split("").reduce(
|
|
428
|
+
(escapedQuery, char) => charsToEscape.includes(char) ? `${escapedQuery}${escapeChar}${char}` : `${escapedQuery}${char}`,
|
|
429
|
+
""
|
|
430
|
+
);
|
|
431
|
+
};
|
|
432
|
+
const stringIncludes = (arr, val) => arr.map(String).includes(String(val));
|
|
433
|
+
const stringEquals = (a, b) => String(a) === String(b);
|
|
434
|
+
const isCamelCase = (value2) => /^[a-z][a-zA-Z0-9]+$/.test(value2);
|
|
435
|
+
const isKebabCase = (value2) => /^([a-z][a-z0-9]*)(-[a-z0-9]+)*$/.test(value2);
|
|
436
|
+
const startsWithANumber = (value2) => /^[0-9]/.test(value2);
|
|
437
|
+
const joinBy = (joint, ...args) => {
|
|
438
|
+
const trim2 = trimChars(joint);
|
|
439
|
+
const trimEnd = trimCharsEnd(joint);
|
|
440
|
+
const trimStart = trimCharsStart(joint);
|
|
441
|
+
return args.reduce((url, path, index2) => {
|
|
442
|
+
if (args.length === 1)
|
|
443
|
+
return path;
|
|
444
|
+
if (index2 === 0)
|
|
445
|
+
return trimEnd(path);
|
|
446
|
+
if (index2 === args.length - 1)
|
|
447
|
+
return url + joint + trimStart(path);
|
|
448
|
+
return url + joint + trim2(path);
|
|
449
|
+
}, "");
|
|
450
|
+
};
|
|
451
|
+
const toKebabCase = (value2) => kebabCase(value2);
|
|
452
|
+
const { toString } = Object.prototype;
|
|
453
|
+
const errorToString = Error.prototype.toString;
|
|
454
|
+
const regExpToString = RegExp.prototype.toString;
|
|
455
|
+
const symbolToString = typeof Symbol !== "undefined" ? Symbol.prototype.toString : () => "";
|
|
456
|
+
const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/;
|
|
457
|
+
function printNumber(val) {
|
|
458
|
+
if (val != +val)
|
|
459
|
+
return "NaN";
|
|
460
|
+
const isNegativeZero = val === 0 && 1 / val < 0;
|
|
461
|
+
return isNegativeZero ? "-0" : `${val}`;
|
|
462
|
+
}
|
|
463
|
+
function printSimpleValue(val, quoteStrings = false) {
|
|
464
|
+
if (val == null || val === true || val === false)
|
|
465
|
+
return `${val}`;
|
|
466
|
+
if (typeof val === "number")
|
|
467
|
+
return printNumber(val);
|
|
468
|
+
if (typeof val === "string")
|
|
469
|
+
return quoteStrings ? `"${val}"` : val;
|
|
470
|
+
if (typeof val === "function")
|
|
471
|
+
return `[Function ${val.name || "anonymous"}]`;
|
|
472
|
+
if (typeof val === "symbol")
|
|
473
|
+
return symbolToString.call(val).replace(SYMBOL_REGEXP, "Symbol($1)");
|
|
474
|
+
const tag = toString.call(val).slice(8, -1);
|
|
475
|
+
if (tag === "Date") {
|
|
476
|
+
const v = val;
|
|
477
|
+
return Number.isNaN(v.getTime()) ? `${v}` : v.toISOString();
|
|
478
|
+
}
|
|
479
|
+
if (tag === "Error" || val instanceof Error)
|
|
480
|
+
return `[${errorToString.call(val)}]`;
|
|
481
|
+
if (tag === "RegExp")
|
|
482
|
+
return regExpToString.call(val);
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
function printValue(value2, quoteStrings) {
|
|
486
|
+
const result = printSimpleValue(value2, quoteStrings);
|
|
487
|
+
if (result !== null)
|
|
488
|
+
return result;
|
|
489
|
+
return JSON.stringify(
|
|
490
|
+
value2,
|
|
491
|
+
function replacer(key2, value22) {
|
|
492
|
+
const result2 = printSimpleValue(this[key2], quoteStrings);
|
|
493
|
+
if (result2 !== null)
|
|
494
|
+
return result2;
|
|
495
|
+
return value22;
|
|
496
|
+
},
|
|
497
|
+
2
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
const strapiID = () => new StrapiIDSchema();
|
|
501
|
+
const isNotNilTest = (value2) => !_$1.isNil(value2);
|
|
502
|
+
const isNotNullTest = (value2) => !_$1.isNull(value2);
|
|
503
|
+
yup$1.addMethod(yup$1.mixed, "notNil", function isNotNill(msg = "${path} must be defined.") {
|
|
504
|
+
return this.test("defined", msg, isNotNilTest);
|
|
505
|
+
});
|
|
506
|
+
yup$1.addMethod(yup$1.mixed, "notNull", function isNotNull(msg = "${path} cannot be null.") {
|
|
507
|
+
return this.test("defined", msg, isNotNullTest);
|
|
508
|
+
});
|
|
509
|
+
yup$1.addMethod(yup$1.mixed, "isFunction", function isFunction(message = "${path} is not a function") {
|
|
510
|
+
return this.test(
|
|
511
|
+
"is a function",
|
|
512
|
+
message,
|
|
513
|
+
(value2) => _$1.isUndefined(value2) || _$1.isFunction(value2)
|
|
514
|
+
);
|
|
515
|
+
});
|
|
516
|
+
yup$1.addMethod(
|
|
517
|
+
yup$1.string,
|
|
518
|
+
"isCamelCase",
|
|
519
|
+
function isCamelCase$1(message = "${path} is not in camel case (anExampleOfCamelCase)") {
|
|
520
|
+
return this.test(
|
|
521
|
+
"is in camelCase",
|
|
522
|
+
message,
|
|
523
|
+
(value2) => value2 ? isCamelCase(value2) : true
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
);
|
|
527
|
+
yup$1.addMethod(
|
|
528
|
+
yup$1.string,
|
|
529
|
+
"isKebabCase",
|
|
530
|
+
function isKebabCase$1(message = "${path} is not in kebab case (an-example-of-kebab-case)") {
|
|
531
|
+
return this.test(
|
|
532
|
+
"is in kebab-case",
|
|
533
|
+
message,
|
|
534
|
+
(value2) => value2 ? isKebabCase(value2) : true
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
yup$1.addMethod(
|
|
539
|
+
yup$1.object,
|
|
540
|
+
"onlyContainsFunctions",
|
|
541
|
+
function onlyContainsFunctions(message = "${path} contains values that are not functions") {
|
|
542
|
+
return this.test(
|
|
543
|
+
"only contains functions",
|
|
544
|
+
message,
|
|
545
|
+
(value2) => _$1.isUndefined(value2) || value2 && Object.values(value2).every(_$1.isFunction)
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
);
|
|
549
|
+
yup$1.addMethod(
|
|
550
|
+
yup$1.array,
|
|
551
|
+
"uniqueProperty",
|
|
552
|
+
function uniqueProperty(propertyName, message) {
|
|
553
|
+
return this.test("unique", message, function unique(list) {
|
|
554
|
+
const errors2 = [];
|
|
555
|
+
list?.forEach((element, index2) => {
|
|
556
|
+
const sameElements = list.filter(
|
|
557
|
+
(e) => get(propertyName, e) === get(propertyName, element)
|
|
558
|
+
);
|
|
559
|
+
if (sameElements.length > 1) {
|
|
560
|
+
errors2.push(
|
|
561
|
+
this.createError({
|
|
562
|
+
path: `${this.path}[${index2}].${propertyName}`,
|
|
563
|
+
message
|
|
564
|
+
})
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
if (errors2.length) {
|
|
569
|
+
throw new yup$1.ValidationError(errors2);
|
|
570
|
+
}
|
|
571
|
+
return true;
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
);
|
|
575
|
+
class StrapiIDSchema extends yup$1.MixedSchema {
|
|
576
|
+
constructor() {
|
|
577
|
+
super({ type: "strapiID" });
|
|
578
|
+
}
|
|
579
|
+
_typeCheck(value2) {
|
|
580
|
+
return typeof value2 === "string" || isNumber(value2) && isInteger(value2) && value2 >= 0;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
yup$1.setLocale({
|
|
584
|
+
mixed: {
|
|
585
|
+
notType(options) {
|
|
586
|
+
const { path, type, value: value2, originalValue } = options;
|
|
587
|
+
const isCast = originalValue != null && originalValue !== value2;
|
|
588
|
+
const msg = `${path} must be a \`${type}\` type, but the final value was: \`${printValue(value2, true)}\`${isCast ? ` (cast from the value \`${printValue(originalValue, true)}\`).` : "."}`;
|
|
589
|
+
return msg;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
const yup = /* @__PURE__ */ _mergeNamespaces({
|
|
594
|
+
__proto__: null,
|
|
595
|
+
StrapiIDSchema,
|
|
596
|
+
strapiID
|
|
597
|
+
}, [yup$1]);
|
|
598
|
+
const removeUndefined = (obj2) => _$1.pickBy(obj2, (value2) => typeof value2 !== "undefined");
|
|
599
|
+
const keysDeep = (obj2, path = []) => !_$1.isObject(obj2) ? [path.join(".")] : _$1.reduce(
|
|
600
|
+
obj2,
|
|
601
|
+
(acc2, next, key2) => _$1.concat(acc2, keysDeep(next, [...path, key2])),
|
|
602
|
+
[]
|
|
603
|
+
);
|
|
604
|
+
const getConfigUrls = (config, forAdminBuild = false) => {
|
|
605
|
+
const serverConfig = config.get("server");
|
|
606
|
+
const adminConfig = config.get("admin");
|
|
607
|
+
let serverUrl = _$1.get(serverConfig, "url", "");
|
|
608
|
+
serverUrl = _$1.trim(serverUrl, "/ ");
|
|
609
|
+
if (typeof serverUrl !== "string") {
|
|
610
|
+
throw new Error("Invalid server url config. Make sure the url is a string.");
|
|
611
|
+
}
|
|
612
|
+
if (serverUrl.startsWith("http")) {
|
|
613
|
+
try {
|
|
614
|
+
serverUrl = _$1.trim(new URL(serverConfig.url).toString(), "/");
|
|
615
|
+
} catch (e) {
|
|
616
|
+
throw new Error(
|
|
617
|
+
"Invalid server url config. Make sure the url defined in server.js is valid."
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
} else if (serverUrl !== "") {
|
|
621
|
+
serverUrl = `/${serverUrl}`;
|
|
622
|
+
}
|
|
623
|
+
let adminUrl = _$1.get(adminConfig, "url", "/admin");
|
|
624
|
+
adminUrl = _$1.trim(adminUrl, "/ ");
|
|
625
|
+
if (typeof adminUrl !== "string") {
|
|
626
|
+
throw new Error("Invalid admin url config. Make sure the url is a non-empty string.");
|
|
627
|
+
}
|
|
628
|
+
if (adminUrl.startsWith("http")) {
|
|
629
|
+
try {
|
|
630
|
+
adminUrl = _$1.trim(new URL(adminUrl).toString(), "/");
|
|
631
|
+
} catch (e) {
|
|
632
|
+
throw new Error("Invalid admin url config. Make sure the url defined in server.js is valid.");
|
|
633
|
+
}
|
|
634
|
+
} else {
|
|
635
|
+
adminUrl = `${serverUrl}/${adminUrl}`;
|
|
636
|
+
}
|
|
637
|
+
let adminPath = adminUrl;
|
|
638
|
+
if (serverUrl.startsWith("http") && adminUrl.startsWith("http") && new URL(adminUrl).origin === new URL(serverUrl).origin && !forAdminBuild) {
|
|
639
|
+
adminPath = adminUrl.replace(getCommonPath(serverUrl, adminUrl), "");
|
|
640
|
+
adminPath = `/${_$1.trim(adminPath, "/")}`;
|
|
641
|
+
} else if (adminUrl.startsWith("http")) {
|
|
642
|
+
adminPath = new URL(adminUrl).pathname;
|
|
643
|
+
}
|
|
644
|
+
return {
|
|
645
|
+
serverUrl,
|
|
646
|
+
adminUrl,
|
|
647
|
+
adminPath
|
|
648
|
+
};
|
|
649
|
+
};
|
|
650
|
+
const getAbsoluteUrl = (adminOrServer) => (config, forAdminBuild = false) => {
|
|
651
|
+
const { serverUrl, adminUrl } = getConfigUrls(config, forAdminBuild);
|
|
652
|
+
const url = adminOrServer === "server" ? serverUrl : adminUrl;
|
|
653
|
+
if (url.startsWith("http")) {
|
|
654
|
+
return url;
|
|
655
|
+
}
|
|
656
|
+
const hostname = config.get("environment") === "development" && ["127.0.0.1", "0.0.0.0"].includes(config.get("server.host")) ? "localhost" : config.get("server.host");
|
|
657
|
+
return `http://${hostname}:${config.get("server.port")}${url}`;
|
|
658
|
+
};
|
|
659
|
+
const getAbsoluteAdminUrl = getAbsoluteUrl("admin");
|
|
660
|
+
const getAbsoluteServerUrl = getAbsoluteUrl("server");
|
|
661
|
+
const generateTimestampCode = (date) => {
|
|
662
|
+
const referDate = date || /* @__PURE__ */ new Date();
|
|
663
|
+
return referDate.getTime().toString(36);
|
|
664
|
+
};
|
|
665
|
+
const SINGLE_TYPE = "singleType";
|
|
666
|
+
const COLLECTION_TYPE = "collectionType";
|
|
667
|
+
const ID_ATTRIBUTE = "id";
|
|
668
|
+
const PUBLISHED_AT_ATTRIBUTE$1 = "publishedAt";
|
|
669
|
+
const CREATED_BY_ATTRIBUTE$3 = "createdBy";
|
|
670
|
+
const UPDATED_BY_ATTRIBUTE$3 = "updatedBy";
|
|
671
|
+
const CREATED_AT_ATTRIBUTE = "createdAt";
|
|
672
|
+
const UPDATED_AT_ATTRIBUTE = "updatedAt";
|
|
673
|
+
const DP_PUB_STATE_LIVE = "live";
|
|
674
|
+
const DP_PUB_STATE_PREVIEW = "preview";
|
|
675
|
+
const DP_PUB_STATES = [DP_PUB_STATE_LIVE, DP_PUB_STATE_PREVIEW];
|
|
676
|
+
const constants$1 = {
|
|
677
|
+
ID_ATTRIBUTE,
|
|
678
|
+
PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1,
|
|
679
|
+
CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$3,
|
|
680
|
+
UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$3,
|
|
681
|
+
CREATED_AT_ATTRIBUTE,
|
|
682
|
+
UPDATED_AT_ATTRIBUTE,
|
|
683
|
+
DP_PUB_STATES,
|
|
684
|
+
DP_PUB_STATE_LIVE,
|
|
685
|
+
DP_PUB_STATE_PREVIEW,
|
|
686
|
+
SINGLE_TYPE,
|
|
687
|
+
COLLECTION_TYPE
|
|
688
|
+
};
|
|
689
|
+
const getTimestamps = (model) => {
|
|
690
|
+
const attributes = [];
|
|
691
|
+
if (has(CREATED_AT_ATTRIBUTE, model.attributes)) {
|
|
692
|
+
attributes.push(CREATED_AT_ATTRIBUTE);
|
|
693
|
+
}
|
|
694
|
+
if (has(UPDATED_AT_ATTRIBUTE, model.attributes)) {
|
|
695
|
+
attributes.push(UPDATED_AT_ATTRIBUTE);
|
|
696
|
+
}
|
|
697
|
+
return attributes;
|
|
698
|
+
};
|
|
699
|
+
const getCreatorFields = (model) => {
|
|
700
|
+
const attributes = [];
|
|
701
|
+
if (has(CREATED_BY_ATTRIBUTE$3, model.attributes)) {
|
|
702
|
+
attributes.push(CREATED_BY_ATTRIBUTE$3);
|
|
703
|
+
}
|
|
704
|
+
if (has(UPDATED_BY_ATTRIBUTE$3, model.attributes)) {
|
|
705
|
+
attributes.push(UPDATED_BY_ATTRIBUTE$3);
|
|
706
|
+
}
|
|
707
|
+
return attributes;
|
|
708
|
+
};
|
|
709
|
+
const getNonWritableAttributes = (model) => {
|
|
710
|
+
if (!model)
|
|
711
|
+
return [];
|
|
712
|
+
const nonWritableAttributes = _$1.reduce(
|
|
713
|
+
model.attributes,
|
|
714
|
+
(acc2, attr, attrName) => attr.writable === false ? acc2.concat(attrName) : acc2,
|
|
715
|
+
[]
|
|
716
|
+
);
|
|
717
|
+
return _$1.uniq([ID_ATTRIBUTE, ...getTimestamps(model), ...nonWritableAttributes]);
|
|
718
|
+
};
|
|
719
|
+
const getWritableAttributes = (model) => {
|
|
720
|
+
if (!model)
|
|
721
|
+
return [];
|
|
722
|
+
return _$1.difference(Object.keys(model.attributes), getNonWritableAttributes(model));
|
|
723
|
+
};
|
|
724
|
+
const isWritableAttribute = (model, attributeName) => {
|
|
725
|
+
return getWritableAttributes(model).includes(attributeName);
|
|
726
|
+
};
|
|
727
|
+
const getNonVisibleAttributes = (model) => {
|
|
728
|
+
const nonVisibleAttributes = _$1.reduce(
|
|
729
|
+
model.attributes,
|
|
730
|
+
(acc2, attr, attrName) => attr.visible === false ? acc2.concat(attrName) : acc2,
|
|
731
|
+
[]
|
|
732
|
+
);
|
|
733
|
+
return _$1.uniq([ID_ATTRIBUTE, ...getTimestamps(model), ...nonVisibleAttributes]);
|
|
734
|
+
};
|
|
735
|
+
const getVisibleAttributes = (model) => {
|
|
736
|
+
return _$1.difference(_$1.keys(model.attributes), getNonVisibleAttributes(model));
|
|
737
|
+
};
|
|
738
|
+
const isVisibleAttribute = (model, attributeName) => {
|
|
739
|
+
return getVisibleAttributes(model).includes(attributeName);
|
|
740
|
+
};
|
|
741
|
+
const getOptions = (model) => _$1.assign({ draftAndPublish: false }, _$1.get(model, "options", {}));
|
|
742
|
+
const hasDraftAndPublish = (model) => _$1.get(model, "options.draftAndPublish", false) === true;
|
|
743
|
+
const isDraft = (data, model) => hasDraftAndPublish(model) && _$1.get(data, PUBLISHED_AT_ATTRIBUTE$1) === null;
|
|
744
|
+
const isSingleType = ({ kind = COLLECTION_TYPE }) => kind === SINGLE_TYPE;
|
|
745
|
+
const isCollectionType = ({ kind = COLLECTION_TYPE }) => kind === COLLECTION_TYPE;
|
|
746
|
+
const isKind = (kind) => (model) => model.kind === kind;
|
|
747
|
+
const getStoredPrivateAttributes = (model) => union(
|
|
748
|
+
strapi?.config?.get("api.responses.privateAttributes", []) ?? [],
|
|
749
|
+
getOr([], "options.privateAttributes", model)
|
|
750
|
+
);
|
|
751
|
+
const getPrivateAttributes = (model) => {
|
|
752
|
+
return _$1.union(
|
|
753
|
+
getStoredPrivateAttributes(model),
|
|
754
|
+
_$1.keys(_$1.pickBy(model.attributes, (attr) => !!attr.private))
|
|
755
|
+
);
|
|
756
|
+
};
|
|
757
|
+
const isPrivateAttribute = (model, attributeName) => {
|
|
758
|
+
if (model?.attributes?.[attributeName]?.private === true) {
|
|
759
|
+
return true;
|
|
760
|
+
}
|
|
761
|
+
return getStoredPrivateAttributes(model).includes(attributeName);
|
|
762
|
+
};
|
|
763
|
+
const isScalarAttribute = (attribute) => {
|
|
764
|
+
return !["media", "component", "relation", "dynamiczone"].includes(attribute?.type);
|
|
765
|
+
};
|
|
766
|
+
const isMediaAttribute = (attribute) => attribute?.type === "media";
|
|
767
|
+
const isRelationalAttribute = (attribute) => attribute?.type === "relation";
|
|
768
|
+
const isComponentAttribute = (attribute) => ["component", "dynamiczone"].includes(attribute?.type);
|
|
769
|
+
const isDynamicZoneAttribute = (attribute) => attribute?.type === "dynamiczone";
|
|
770
|
+
const isMorphToRelationalAttribute = (attribute) => {
|
|
771
|
+
return isRelationalAttribute(attribute) && attribute?.relation?.startsWith?.("morphTo");
|
|
772
|
+
};
|
|
773
|
+
const getComponentAttributes = (schema) => {
|
|
774
|
+
return _$1.reduce(
|
|
775
|
+
schema.attributes,
|
|
776
|
+
(acc2, attr, attrName) => {
|
|
777
|
+
if (isComponentAttribute(attr))
|
|
778
|
+
acc2.push(attrName);
|
|
779
|
+
return acc2;
|
|
780
|
+
},
|
|
781
|
+
[]
|
|
782
|
+
);
|
|
783
|
+
};
|
|
784
|
+
const getScalarAttributes = (schema) => {
|
|
785
|
+
return _$1.reduce(
|
|
786
|
+
schema.attributes,
|
|
787
|
+
(acc2, attr, attrName) => {
|
|
788
|
+
if (isScalarAttribute(attr))
|
|
789
|
+
acc2.push(attrName);
|
|
790
|
+
return acc2;
|
|
791
|
+
},
|
|
792
|
+
[]
|
|
793
|
+
);
|
|
794
|
+
};
|
|
795
|
+
const isTypedAttribute = (attribute, type) => {
|
|
796
|
+
return _$1.has(attribute, "type") && attribute.type === type;
|
|
797
|
+
};
|
|
798
|
+
const getContentTypeRoutePrefix = (contentType) => {
|
|
799
|
+
return isSingleType(contentType) ? _$1.kebabCase(contentType.info.singularName) : _$1.kebabCase(contentType.info.pluralName);
|
|
800
|
+
};
|
|
801
|
+
const contentTypes = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
802
|
+
__proto__: null,
|
|
803
|
+
constants: constants$1,
|
|
804
|
+
getComponentAttributes,
|
|
805
|
+
getContentTypeRoutePrefix,
|
|
806
|
+
getCreatorFields,
|
|
807
|
+
getNonVisibleAttributes,
|
|
808
|
+
getNonWritableAttributes,
|
|
809
|
+
getOptions,
|
|
810
|
+
getPrivateAttributes,
|
|
811
|
+
getScalarAttributes,
|
|
812
|
+
getTimestamps,
|
|
813
|
+
getVisibleAttributes,
|
|
814
|
+
getWritableAttributes,
|
|
815
|
+
hasDraftAndPublish,
|
|
816
|
+
isCollectionType,
|
|
817
|
+
isComponentAttribute,
|
|
818
|
+
isDraft,
|
|
819
|
+
isDynamicZoneAttribute,
|
|
820
|
+
isKind,
|
|
821
|
+
isMediaAttribute,
|
|
822
|
+
isMorphToRelationalAttribute,
|
|
823
|
+
isPrivateAttribute,
|
|
824
|
+
isRelationalAttribute,
|
|
825
|
+
isScalarAttribute,
|
|
826
|
+
isSingleType,
|
|
827
|
+
isTypedAttribute,
|
|
828
|
+
isVisibleAttribute,
|
|
829
|
+
isWritableAttribute
|
|
830
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
831
|
+
function envFn(key2, defaultValue) {
|
|
832
|
+
return _$1.has(process.env, key2) ? process.env[key2] : defaultValue;
|
|
833
|
+
}
|
|
834
|
+
function getKey(key2) {
|
|
835
|
+
return process.env[key2] ?? "";
|
|
836
|
+
}
|
|
837
|
+
const utils = {
|
|
838
|
+
int(key2, defaultValue) {
|
|
839
|
+
if (!_$1.has(process.env, key2)) {
|
|
840
|
+
return defaultValue;
|
|
841
|
+
}
|
|
842
|
+
return parseInt(getKey(key2), 10);
|
|
843
|
+
},
|
|
844
|
+
float(key2, defaultValue) {
|
|
845
|
+
if (!_$1.has(process.env, key2)) {
|
|
846
|
+
return defaultValue;
|
|
847
|
+
}
|
|
848
|
+
return parseFloat(getKey(key2));
|
|
849
|
+
},
|
|
850
|
+
bool(key2, defaultValue) {
|
|
851
|
+
if (!_$1.has(process.env, key2)) {
|
|
852
|
+
return defaultValue;
|
|
853
|
+
}
|
|
854
|
+
return getKey(key2) === "true";
|
|
855
|
+
},
|
|
856
|
+
json(key2, defaultValue) {
|
|
857
|
+
if (!_$1.has(process.env, key2)) {
|
|
858
|
+
return defaultValue;
|
|
859
|
+
}
|
|
860
|
+
try {
|
|
861
|
+
return JSON.parse(getKey(key2));
|
|
862
|
+
} catch (error) {
|
|
863
|
+
if (error instanceof Error) {
|
|
864
|
+
throw new Error(`Invalid json environment variable ${key2}: ${error.message}`);
|
|
865
|
+
}
|
|
866
|
+
throw error;
|
|
867
|
+
}
|
|
868
|
+
},
|
|
869
|
+
array(key2, defaultValue) {
|
|
870
|
+
if (!_$1.has(process.env, key2)) {
|
|
871
|
+
return defaultValue;
|
|
872
|
+
}
|
|
873
|
+
let value2 = getKey(key2);
|
|
874
|
+
if (value2.startsWith("[") && value2.endsWith("]")) {
|
|
875
|
+
value2 = value2.substring(1, value2.length - 1);
|
|
876
|
+
}
|
|
877
|
+
return value2.split(",").map((v) => {
|
|
878
|
+
return _$1.trim(_$1.trim(v, " "), '"');
|
|
879
|
+
});
|
|
880
|
+
},
|
|
881
|
+
date(key2, defaultValue) {
|
|
882
|
+
if (!_$1.has(process.env, key2)) {
|
|
883
|
+
return defaultValue;
|
|
884
|
+
}
|
|
885
|
+
return new Date(getKey(key2));
|
|
886
|
+
},
|
|
887
|
+
/**
|
|
888
|
+
* Gets a value from env that matches oneOf provided values
|
|
889
|
+
* @param {string} key
|
|
890
|
+
* @param {string[]} expectedValues
|
|
891
|
+
* @param {string|undefined} defaultValue
|
|
892
|
+
* @returns {string|undefined}
|
|
893
|
+
*/
|
|
894
|
+
oneOf(key2, expectedValues, defaultValue) {
|
|
895
|
+
if (!expectedValues) {
|
|
896
|
+
throw new Error(`env.oneOf requires expectedValues`);
|
|
897
|
+
}
|
|
898
|
+
if (defaultValue && !expectedValues.includes(defaultValue)) {
|
|
899
|
+
throw new Error(`env.oneOf requires defaultValue to be included in expectedValues`);
|
|
900
|
+
}
|
|
901
|
+
const rawValue = env(key2, defaultValue);
|
|
902
|
+
return expectedValues.includes(rawValue) ? rawValue : defaultValue;
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
const env = Object.assign(envFn, utils);
|
|
906
|
+
const MANY_RELATIONS = ["oneToMany", "manyToMany"];
|
|
907
|
+
const getRelationalFields = (contentType) => {
|
|
908
|
+
return Object.keys(contentType.attributes).filter((attributeName) => {
|
|
909
|
+
return contentType.attributes[attributeName].type === "relation";
|
|
910
|
+
});
|
|
911
|
+
};
|
|
912
|
+
const isOneToAny = (attribute) => isRelationalAttribute(attribute) && ["oneToOne", "oneToMany"].includes(attribute.relation);
|
|
913
|
+
const isManyToAny = (attribute) => isRelationalAttribute(attribute) && ["manyToMany", "manyToOne"].includes(attribute.relation);
|
|
914
|
+
const isAnyToOne = (attribute) => isRelationalAttribute(attribute) && ["oneToOne", "manyToOne"].includes(attribute.relation);
|
|
915
|
+
const isAnyToMany = (attribute) => isRelationalAttribute(attribute) && ["oneToMany", "manyToMany"].includes(attribute.relation);
|
|
916
|
+
const constants = {
|
|
917
|
+
MANY_RELATIONS
|
|
918
|
+
};
|
|
919
|
+
const relations = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
920
|
+
__proto__: null,
|
|
921
|
+
constants,
|
|
922
|
+
getRelationalFields,
|
|
923
|
+
isAnyToMany,
|
|
924
|
+
isAnyToOne,
|
|
925
|
+
isManyToAny,
|
|
926
|
+
isOneToAny
|
|
927
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
928
|
+
const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$2, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$2 } = constants$1;
|
|
929
|
+
const setCreatorFields = ({ user, isEdition = false }) => (data) => {
|
|
930
|
+
if (isEdition) {
|
|
931
|
+
return assoc(UPDATED_BY_ATTRIBUTE$2, user.id, data);
|
|
932
|
+
}
|
|
933
|
+
return assign(data, {
|
|
934
|
+
[CREATED_BY_ATTRIBUTE$2]: user.id,
|
|
935
|
+
[UPDATED_BY_ATTRIBUTE$2]: user.id
|
|
936
|
+
});
|
|
937
|
+
};
|
|
938
|
+
const createHook = () => {
|
|
939
|
+
const state = {
|
|
940
|
+
handlers: []
|
|
941
|
+
};
|
|
942
|
+
return {
|
|
943
|
+
getHandlers() {
|
|
944
|
+
return state.handlers;
|
|
945
|
+
},
|
|
946
|
+
register(handler) {
|
|
947
|
+
state.handlers.push(handler);
|
|
948
|
+
return this;
|
|
949
|
+
},
|
|
950
|
+
delete(handler) {
|
|
951
|
+
state.handlers = remove(eq(handler), state.handlers);
|
|
952
|
+
return this;
|
|
953
|
+
},
|
|
954
|
+
call() {
|
|
955
|
+
throw new Error("Method not implemented");
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
};
|
|
959
|
+
const createAsyncSeriesHook = () => ({
|
|
960
|
+
...createHook(),
|
|
961
|
+
async call(context) {
|
|
962
|
+
for (const handler of this.getHandlers()) {
|
|
963
|
+
await handler(context);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
const createAsyncSeriesWaterfallHook = () => ({
|
|
968
|
+
...createHook(),
|
|
969
|
+
async call(param) {
|
|
970
|
+
let res = param;
|
|
971
|
+
for (const handler of this.getHandlers()) {
|
|
972
|
+
res = await handler(res);
|
|
973
|
+
}
|
|
974
|
+
return res;
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
const createAsyncParallelHook = () => ({
|
|
978
|
+
...createHook(),
|
|
979
|
+
async call(context) {
|
|
980
|
+
const promises = this.getHandlers().map((handler) => handler(cloneDeep(context)));
|
|
981
|
+
return Promise.all(promises);
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
const createAsyncBailHook = () => ({
|
|
985
|
+
...createHook(),
|
|
986
|
+
async call(context) {
|
|
987
|
+
for (const handler of this.getHandlers()) {
|
|
988
|
+
const result = await handler(context);
|
|
989
|
+
if (result !== void 0) {
|
|
990
|
+
return result;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
});
|
|
995
|
+
const internals = {
|
|
996
|
+
// Internal utils
|
|
997
|
+
createHook
|
|
998
|
+
};
|
|
999
|
+
const hooks = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1000
|
+
__proto__: null,
|
|
1001
|
+
createAsyncBailHook,
|
|
1002
|
+
createAsyncParallelHook,
|
|
1003
|
+
createAsyncSeriesHook,
|
|
1004
|
+
createAsyncSeriesWaterfallHook,
|
|
1005
|
+
internals
|
|
1006
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1007
|
+
const createProviderHooksMap = () => ({
|
|
1008
|
+
// Register events
|
|
1009
|
+
willRegister: createAsyncSeriesHook(),
|
|
1010
|
+
didRegister: createAsyncParallelHook(),
|
|
1011
|
+
// Delete events
|
|
1012
|
+
willDelete: createAsyncParallelHook(),
|
|
1013
|
+
didDelete: createAsyncParallelHook()
|
|
1014
|
+
});
|
|
1015
|
+
const providerFactory = (options = {}) => {
|
|
1016
|
+
const { throwOnDuplicates = true } = options;
|
|
1017
|
+
const state = {
|
|
1018
|
+
hooks: createProviderHooksMap(),
|
|
1019
|
+
registry: /* @__PURE__ */ new Map()
|
|
1020
|
+
};
|
|
1021
|
+
return {
|
|
1022
|
+
hooks: state.hooks,
|
|
1023
|
+
async register(key2, item) {
|
|
1024
|
+
if (throwOnDuplicates && this.has(key2)) {
|
|
1025
|
+
throw new Error(`Duplicated item key: ${key2}`);
|
|
1026
|
+
}
|
|
1027
|
+
await state.hooks.willRegister.call({ key: key2, value: item });
|
|
1028
|
+
state.registry.set(key2, item);
|
|
1029
|
+
await state.hooks.didRegister.call({ key: key2, value: cloneDeep(item) });
|
|
1030
|
+
return this;
|
|
1031
|
+
},
|
|
1032
|
+
async delete(key2) {
|
|
1033
|
+
if (this.has(key2)) {
|
|
1034
|
+
const item = this.get(key2);
|
|
1035
|
+
await state.hooks.willDelete.call({ key: key2, value: cloneDeep(item) });
|
|
1036
|
+
state.registry.delete(key2);
|
|
1037
|
+
await state.hooks.didDelete.call({ key: key2, value: cloneDeep(item) });
|
|
1038
|
+
}
|
|
1039
|
+
return this;
|
|
1040
|
+
},
|
|
1041
|
+
get(key2) {
|
|
1042
|
+
return state.registry.get(key2);
|
|
1043
|
+
},
|
|
1044
|
+
getWhere(filters2 = {}) {
|
|
1045
|
+
const items = this.values();
|
|
1046
|
+
const filtersEntries = Object.entries(filters2);
|
|
1047
|
+
if (filtersEntries.length === 0) {
|
|
1048
|
+
return items;
|
|
1049
|
+
}
|
|
1050
|
+
return items.filter((item) => {
|
|
1051
|
+
return filtersEntries.every(([key2, value2]) => item[key2] === value2);
|
|
1052
|
+
});
|
|
1053
|
+
},
|
|
1054
|
+
values() {
|
|
1055
|
+
return Array.from(state.registry.values());
|
|
1056
|
+
},
|
|
1057
|
+
keys() {
|
|
1058
|
+
return Array.from(state.registry.keys());
|
|
1059
|
+
},
|
|
1060
|
+
has(key2) {
|
|
1061
|
+
return state.registry.has(key2);
|
|
1062
|
+
},
|
|
1063
|
+
size() {
|
|
1064
|
+
return state.registry.size;
|
|
1065
|
+
},
|
|
1066
|
+
async clear() {
|
|
1067
|
+
const keys = this.keys();
|
|
1068
|
+
for (const key2 of keys) {
|
|
1069
|
+
await this.delete(key2);
|
|
1070
|
+
}
|
|
1071
|
+
return this;
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
};
|
|
1075
|
+
const STRAPI_DEFAULTS = {
|
|
1076
|
+
offset: {
|
|
1077
|
+
start: 0,
|
|
1078
|
+
limit: 10
|
|
1079
|
+
},
|
|
1080
|
+
page: {
|
|
1081
|
+
page: 1,
|
|
1082
|
+
pageSize: 10
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
const paginationAttributes = ["start", "limit", "page", "pageSize"];
|
|
1086
|
+
const withMaxLimit = (limit, maxLimit = -1) => {
|
|
1087
|
+
if (maxLimit === -1 || limit < maxLimit) {
|
|
1088
|
+
return limit;
|
|
1089
|
+
}
|
|
1090
|
+
return maxLimit;
|
|
1091
|
+
};
|
|
1092
|
+
const ensureMinValues = ({ start, limit }) => ({
|
|
1093
|
+
start: Math.max(start, 0),
|
|
1094
|
+
limit: limit === -1 ? limit : Math.max(limit, 1)
|
|
1095
|
+
});
|
|
1096
|
+
const ensureMaxValues = (maxLimit = -1) => ({ start, limit }) => ({
|
|
1097
|
+
start,
|
|
1098
|
+
limit: withMaxLimit(limit, maxLimit)
|
|
1099
|
+
});
|
|
1100
|
+
const withNoLimit = (pagination2, maxLimit = -1) => ({
|
|
1101
|
+
...pagination2,
|
|
1102
|
+
limit: pagination2.limit === -1 ? maxLimit : pagination2.limit
|
|
1103
|
+
});
|
|
1104
|
+
const withDefaultPagination = (args, { defaults: defaults2 = {}, maxLimit = -1 } = {}) => {
|
|
1105
|
+
const defaultValues = merge(STRAPI_DEFAULTS, defaults2);
|
|
1106
|
+
const usePagePagination = !isNil(args.page) || !isNil(args.pageSize);
|
|
1107
|
+
const useOffsetPagination = !isNil(args.start) || !isNil(args.limit);
|
|
1108
|
+
const ensureValidValues = pipe(ensureMinValues, ensureMaxValues(maxLimit));
|
|
1109
|
+
if (!usePagePagination && !useOffsetPagination) {
|
|
1110
|
+
return merge(args, ensureValidValues(defaultValues.offset));
|
|
1111
|
+
}
|
|
1112
|
+
if (usePagePagination && useOffsetPagination) {
|
|
1113
|
+
throw new PaginationError("Cannot use both page & offset pagination in the same query");
|
|
1114
|
+
}
|
|
1115
|
+
const pagination2 = {
|
|
1116
|
+
start: 0,
|
|
1117
|
+
limit: 0
|
|
1118
|
+
};
|
|
1119
|
+
if (useOffsetPagination) {
|
|
1120
|
+
const { start, limit } = merge(defaultValues.offset, args);
|
|
1121
|
+
Object.assign(pagination2, { start, limit });
|
|
1122
|
+
}
|
|
1123
|
+
if (usePagePagination) {
|
|
1124
|
+
const { page, pageSize } = merge(defaultValues.page, {
|
|
1125
|
+
...args,
|
|
1126
|
+
pageSize: Math.max(1, args.pageSize ?? 0)
|
|
1127
|
+
});
|
|
1128
|
+
Object.assign(pagination2, {
|
|
1129
|
+
start: (page - 1) * pageSize,
|
|
1130
|
+
limit: pageSize
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
Object.assign(pagination2, withNoLimit(pagination2, maxLimit));
|
|
1134
|
+
const replacePaginationAttributes = pipe(
|
|
1135
|
+
// Remove pagination attributes
|
|
1136
|
+
omit(paginationAttributes),
|
|
1137
|
+
// Merge the object with the new pagination + ensure minimum & maximum values
|
|
1138
|
+
merge(ensureValidValues(pagination2))
|
|
1139
|
+
);
|
|
1140
|
+
return replacePaginationAttributes(args);
|
|
1141
|
+
};
|
|
1142
|
+
const pagination = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1143
|
+
__proto__: null,
|
|
1144
|
+
withDefaultPagination
|
|
1145
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1146
|
+
function pipeAsync(...fns) {
|
|
1147
|
+
const [firstFn, ...fnRest] = fns;
|
|
1148
|
+
return async (...args) => {
|
|
1149
|
+
let res = await firstFn.apply(firstFn, args);
|
|
1150
|
+
for (let i = 0; i < fnRest.length; i += 1) {
|
|
1151
|
+
res = await fnRest[i](res);
|
|
1152
|
+
}
|
|
1153
|
+
return res;
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
const mapAsync = curry(pMap);
|
|
1157
|
+
const reduceAsync = (mixedArray) => async (iteratee, initialValue) => {
|
|
1158
|
+
let acc2 = initialValue;
|
|
1159
|
+
for (let i = 0; i < mixedArray.length; i += 1) {
|
|
1160
|
+
acc2 = await iteratee(acc2, await mixedArray[i], i);
|
|
1161
|
+
}
|
|
1162
|
+
return acc2;
|
|
1163
|
+
};
|
|
1164
|
+
const forEachAsync = async (array, func, options) => {
|
|
1165
|
+
await pMap(array, func, options);
|
|
1166
|
+
};
|
|
1167
|
+
const visitor$7 = ({ key: key2, attribute }, { remove: remove2 }) => {
|
|
1168
|
+
if (attribute?.type === "password") {
|
|
1169
|
+
remove2(key2);
|
|
1170
|
+
}
|
|
1171
|
+
};
|
|
1172
|
+
const visitor$6 = ({ schema, key: key2, attribute }, { remove: remove2 }) => {
|
|
1173
|
+
if (!attribute) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
const isPrivate = attribute.private === true || isPrivateAttribute(schema, key2);
|
|
1177
|
+
if (isPrivate) {
|
|
1178
|
+
remove2(key2);
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
const ACTIONS_TO_VERIFY$1 = ["find"];
|
|
1182
|
+
const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$1 } = constants$1;
|
|
1183
|
+
const removeRestrictedRelations = (auth) => async ({ data, key: key2, attribute, schema }, { remove: remove2, set }) => {
|
|
1184
|
+
if (!attribute) {
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
const isRelation = attribute.type === "relation";
|
|
1188
|
+
if (!isRelation) {
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
const handleMorphRelation = async () => {
|
|
1192
|
+
const newMorphValue = [];
|
|
1193
|
+
for (const element of data[key2]) {
|
|
1194
|
+
const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
|
|
1195
|
+
const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
|
|
1196
|
+
if (isAllowed) {
|
|
1197
|
+
newMorphValue.push(element);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
if (newMorphValue.length === 0) {
|
|
1201
|
+
remove2(key2);
|
|
1202
|
+
} else {
|
|
1203
|
+
set(key2, newMorphValue);
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
const handleRegularRelation = async () => {
|
|
1207
|
+
const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${attribute.target}.${action}`);
|
|
1208
|
+
const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
|
|
1209
|
+
if (!isAllowed) {
|
|
1210
|
+
remove2(key2);
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
const isCreatorRelation = [CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE$1].includes(key2);
|
|
1214
|
+
if (isMorphToRelationalAttribute(attribute)) {
|
|
1215
|
+
await handleMorphRelation();
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
if (isCreatorRelation && schema.options?.populateCreatorFields) {
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
await handleRegularRelation();
|
|
1222
|
+
};
|
|
1223
|
+
const hasAccessToSomeScopes$1 = async (scopes, auth) => {
|
|
1224
|
+
for (const scope of scopes) {
|
|
1225
|
+
try {
|
|
1226
|
+
await strapi.auth.verify(auth, { scope });
|
|
1227
|
+
return true;
|
|
1228
|
+
} catch {
|
|
1229
|
+
continue;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
return false;
|
|
1233
|
+
};
|
|
1234
|
+
const visitor$5 = ({ key: key2, attribute }, { remove: remove2 }) => {
|
|
1235
|
+
if (isMorphToRelationalAttribute(attribute)) {
|
|
1236
|
+
remove2(key2);
|
|
1237
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
const visitor$4 = ({ key: key2, attribute }, { remove: remove2 }) => {
|
|
1240
|
+
if (isDynamicZoneAttribute(attribute)) {
|
|
1241
|
+
remove2(key2);
|
|
1242
|
+
}
|
|
1243
|
+
};
|
|
1244
|
+
const removeDisallowedFields = (allowedFields = null) => ({ key: key2, path: { attribute: path } }, { remove: remove2 }) => {
|
|
1245
|
+
if (allowedFields === null) {
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
if (!(isArray(allowedFields) && allowedFields.every(isString$1))) {
|
|
1249
|
+
throw new TypeError(
|
|
1250
|
+
`Expected array of strings for allowedFields but got "${typeof allowedFields}"`
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
if (isNil(path)) {
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
const containedPaths = getContainedPaths$1(path);
|
|
1257
|
+
const isPathAllowed = allowedFields.some(
|
|
1258
|
+
(p) => containedPaths.includes(p) || p.startsWith(`${path}.`)
|
|
1259
|
+
);
|
|
1260
|
+
if (isPathAllowed) {
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
remove2(key2);
|
|
1264
|
+
};
|
|
1265
|
+
const getContainedPaths$1 = (path) => {
|
|
1266
|
+
const parts = toPath(path);
|
|
1267
|
+
return parts.reduce((acc2, value2, index2, list) => {
|
|
1268
|
+
return [...acc2, list.slice(0, index2 + 1).join(".")];
|
|
1269
|
+
}, []);
|
|
1270
|
+
};
|
|
1271
|
+
const removeRestrictedFields = (restrictedFields = null) => ({ key: key2, path: { attribute: path } }, { remove: remove2 }) => {
|
|
1272
|
+
if (restrictedFields === null) {
|
|
1273
|
+
remove2(key2);
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
if (!(isArray(restrictedFields) && restrictedFields.every(isString$1))) {
|
|
1277
|
+
throw new TypeError(
|
|
1278
|
+
`Expected array of strings for restrictedFields but got "${typeof restrictedFields}"`
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
if (restrictedFields.includes(path)) {
|
|
1282
|
+
remove2(key2);
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
const isRestrictedNested = restrictedFields.some(
|
|
1286
|
+
(allowedPath) => path?.toString().startsWith(`${allowedPath}.`)
|
|
1287
|
+
);
|
|
1288
|
+
if (isRestrictedNested) {
|
|
1289
|
+
remove2(key2);
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
const visitors$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1293
|
+
__proto__: null,
|
|
1294
|
+
removeDisallowedFields,
|
|
1295
|
+
removeDynamicZones: visitor$4,
|
|
1296
|
+
removeMorphToRelations: visitor$5,
|
|
1297
|
+
removePassword: visitor$7,
|
|
1298
|
+
removePrivate: visitor$6,
|
|
1299
|
+
removeRestrictedFields,
|
|
1300
|
+
removeRestrictedRelations
|
|
1301
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1302
|
+
const traverseMorphRelationTarget = async (visitor2, path, entry) => {
|
|
1303
|
+
const targetSchema = strapi.getModel(entry.__type);
|
|
1304
|
+
const traverseOptions = { schema: targetSchema, path };
|
|
1305
|
+
return traverseEntity(visitor2, traverseOptions, entry);
|
|
1306
|
+
};
|
|
1307
|
+
const traverseRelationTarget = (schema) => async (visitor2, path, entry) => {
|
|
1308
|
+
const traverseOptions = { schema, path };
|
|
1309
|
+
return traverseEntity(visitor2, traverseOptions, entry);
|
|
1310
|
+
};
|
|
1311
|
+
const traverseMediaTarget = async (visitor2, path, entry) => {
|
|
1312
|
+
const targetSchemaUID = "plugin::upload.file";
|
|
1313
|
+
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
1314
|
+
const traverseOptions = { schema: targetSchema, path };
|
|
1315
|
+
return traverseEntity(visitor2, traverseOptions, entry);
|
|
1316
|
+
};
|
|
1317
|
+
const traverseComponent = async (visitor2, path, schema, entry) => {
|
|
1318
|
+
const traverseOptions = { schema, path };
|
|
1319
|
+
return traverseEntity(visitor2, traverseOptions, entry);
|
|
1320
|
+
};
|
|
1321
|
+
const visitDynamicZoneEntry = async (visitor2, path, entry) => {
|
|
1322
|
+
const targetSchema = strapi.getModel(entry.__component);
|
|
1323
|
+
const traverseOptions = { schema: targetSchema, path };
|
|
1324
|
+
return traverseEntity(visitor2, traverseOptions, entry);
|
|
1325
|
+
};
|
|
1326
|
+
const traverseEntity = async (visitor2, options, entity) => {
|
|
1327
|
+
const { path = { raw: null, attribute: null }, schema } = options;
|
|
1328
|
+
if (!isObject(entity) || isNil(schema)) {
|
|
1329
|
+
return entity;
|
|
1330
|
+
}
|
|
1331
|
+
const copy = clone(entity);
|
|
1332
|
+
const visitorUtils = createVisitorUtils({ data: copy });
|
|
1333
|
+
const keys = Object.keys(copy);
|
|
1334
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
1335
|
+
const key2 = keys[i];
|
|
1336
|
+
const attribute = schema.attributes[key2];
|
|
1337
|
+
if (isNil(attribute)) {
|
|
1338
|
+
continue;
|
|
1339
|
+
}
|
|
1340
|
+
const newPath = { ...path };
|
|
1341
|
+
newPath.raw = isNil(path.raw) ? key2 : `${path.raw}.${key2}`;
|
|
1342
|
+
if (!isNil(attribute)) {
|
|
1343
|
+
newPath.attribute = isNil(path.attribute) ? key2 : `${path.attribute}.${key2}`;
|
|
1344
|
+
}
|
|
1345
|
+
const visitorOptions = {
|
|
1346
|
+
data: copy,
|
|
1347
|
+
schema,
|
|
1348
|
+
key: key2,
|
|
1349
|
+
value: copy[key2],
|
|
1350
|
+
attribute,
|
|
1351
|
+
path: newPath
|
|
1352
|
+
};
|
|
1353
|
+
await visitor2(visitorOptions, visitorUtils);
|
|
1354
|
+
const value2 = copy[key2];
|
|
1355
|
+
if (isNil(value2)) {
|
|
1356
|
+
continue;
|
|
1357
|
+
}
|
|
1358
|
+
if (isRelationalAttribute(attribute)) {
|
|
1359
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
|
1360
|
+
const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(strapi.getModel(attribute.target));
|
|
1361
|
+
if (isArray(value2)) {
|
|
1362
|
+
const res = new Array(value2.length);
|
|
1363
|
+
for (let i2 = 0; i2 < value2.length; i2 += 1) {
|
|
1364
|
+
res[i2] = await method(visitor2, newPath, value2[i2]);
|
|
1365
|
+
}
|
|
1366
|
+
copy[key2] = res;
|
|
1367
|
+
} else {
|
|
1368
|
+
copy[key2] = await method(visitor2, newPath, value2);
|
|
1369
|
+
}
|
|
1370
|
+
continue;
|
|
1371
|
+
}
|
|
1372
|
+
if (isMediaAttribute(attribute)) {
|
|
1373
|
+
if (isArray(value2)) {
|
|
1374
|
+
const res = new Array(value2.length);
|
|
1375
|
+
for (let i2 = 0; i2 < value2.length; i2 += 1) {
|
|
1376
|
+
res[i2] = await traverseMediaTarget(visitor2, newPath, value2[i2]);
|
|
1377
|
+
}
|
|
1378
|
+
copy[key2] = res;
|
|
1379
|
+
} else {
|
|
1380
|
+
copy[key2] = await traverseMediaTarget(visitor2, newPath, value2);
|
|
1381
|
+
}
|
|
1382
|
+
continue;
|
|
1383
|
+
}
|
|
1384
|
+
if (attribute.type === "component") {
|
|
1385
|
+
const targetSchema = strapi.getModel(attribute.component);
|
|
1386
|
+
if (isArray(value2)) {
|
|
1387
|
+
const res = new Array(value2.length);
|
|
1388
|
+
for (let i2 = 0; i2 < value2.length; i2 += 1) {
|
|
1389
|
+
res[i2] = await traverseComponent(visitor2, newPath, targetSchema, value2[i2]);
|
|
1390
|
+
}
|
|
1391
|
+
copy[key2] = res;
|
|
1392
|
+
} else {
|
|
1393
|
+
copy[key2] = await traverseComponent(visitor2, newPath, targetSchema, value2);
|
|
1394
|
+
}
|
|
1395
|
+
continue;
|
|
1396
|
+
}
|
|
1397
|
+
if (attribute.type === "dynamiczone" && isArray(value2)) {
|
|
1398
|
+
const res = new Array(value2.length);
|
|
1399
|
+
for (let i2 = 0; i2 < value2.length; i2 += 1) {
|
|
1400
|
+
res[i2] = await visitDynamicZoneEntry(visitor2, newPath, value2[i2]);
|
|
1401
|
+
}
|
|
1402
|
+
copy[key2] = res;
|
|
1403
|
+
continue;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
return copy;
|
|
1407
|
+
};
|
|
1408
|
+
const createVisitorUtils = ({ data }) => ({
|
|
1409
|
+
remove(key2) {
|
|
1410
|
+
delete data[key2];
|
|
1411
|
+
},
|
|
1412
|
+
set(key2, value2) {
|
|
1413
|
+
data[key2] = value2;
|
|
1414
|
+
}
|
|
1415
|
+
});
|
|
1416
|
+
const traverseEntity$1 = curry(traverseEntity);
|
|
1417
|
+
const DEFAULT_PATH = { raw: null, attribute: null };
|
|
1418
|
+
const traverseFactory = () => {
|
|
1419
|
+
const state = {
|
|
1420
|
+
parsers: [],
|
|
1421
|
+
interceptors: [],
|
|
1422
|
+
ignore: [],
|
|
1423
|
+
handlers: {
|
|
1424
|
+
attributes: [],
|
|
1425
|
+
common: []
|
|
1426
|
+
}
|
|
1427
|
+
};
|
|
1428
|
+
const traverse = async (visitor2, options, data) => {
|
|
1429
|
+
const { path = DEFAULT_PATH, schema } = options ?? {};
|
|
1430
|
+
for (const { predicate, handler } of state.interceptors) {
|
|
1431
|
+
if (predicate(data)) {
|
|
1432
|
+
return handler(visitor2, options, data, { recurse: traverse });
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
const parser = state.parsers.find((parser2) => parser2.predicate(data))?.parser;
|
|
1436
|
+
const utils2 = parser?.(data);
|
|
1437
|
+
if (!utils2) {
|
|
1438
|
+
return data;
|
|
1439
|
+
}
|
|
1440
|
+
let out = utils2.transform(data);
|
|
1441
|
+
const keys = utils2.keys(out);
|
|
1442
|
+
for (const key2 of keys) {
|
|
1443
|
+
const attribute = schema?.attributes?.[key2] ?? // FIX: Needed to not break existing behavior on the API.
|
|
1444
|
+
// It looks for the attribute in the DB metadata when the key is in snake_case
|
|
1445
|
+
schema?.attributes?.[strapi.db.metadata.get(schema?.uid).columnToAttribute[key2]];
|
|
1446
|
+
const newPath = { ...path };
|
|
1447
|
+
newPath.raw = isNil(path.raw) ? key2 : `${path.raw}.${key2}`;
|
|
1448
|
+
if (!isNil(attribute)) {
|
|
1449
|
+
newPath.attribute = isNil(path.attribute) ? key2 : `${path.attribute}.${key2}`;
|
|
1450
|
+
}
|
|
1451
|
+
const visitorOptions = {
|
|
1452
|
+
key: key2,
|
|
1453
|
+
value: utils2.get(key2, out),
|
|
1454
|
+
attribute,
|
|
1455
|
+
schema,
|
|
1456
|
+
path: newPath,
|
|
1457
|
+
data: out
|
|
1458
|
+
};
|
|
1459
|
+
const transformUtils = {
|
|
1460
|
+
remove(key22) {
|
|
1461
|
+
out = utils2.remove(key22, out);
|
|
1462
|
+
},
|
|
1463
|
+
set(key22, value22) {
|
|
1464
|
+
out = utils2.set(key22, value22, out);
|
|
1465
|
+
},
|
|
1466
|
+
recurse: traverse
|
|
1467
|
+
};
|
|
1468
|
+
await visitor2(visitorOptions, pick(["remove", "set"], transformUtils));
|
|
1469
|
+
const value2 = utils2.get(key2, out);
|
|
1470
|
+
const createContext = () => ({
|
|
1471
|
+
key: key2,
|
|
1472
|
+
value: value2,
|
|
1473
|
+
attribute,
|
|
1474
|
+
schema,
|
|
1475
|
+
path: newPath,
|
|
1476
|
+
data: out,
|
|
1477
|
+
visitor: visitor2
|
|
1478
|
+
});
|
|
1479
|
+
const ignoreCtx = createContext();
|
|
1480
|
+
const shouldIgnore = state.ignore.some((predicate) => predicate(ignoreCtx));
|
|
1481
|
+
if (shouldIgnore) {
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1484
|
+
const handlers = [...state.handlers.common, ...state.handlers.attributes];
|
|
1485
|
+
for await (const handler of handlers) {
|
|
1486
|
+
const ctx = createContext();
|
|
1487
|
+
const pass = await handler.predicate(ctx);
|
|
1488
|
+
if (pass) {
|
|
1489
|
+
await handler.handler(ctx, pick(["recurse", "set"], transformUtils));
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
return out;
|
|
1494
|
+
};
|
|
1495
|
+
return {
|
|
1496
|
+
traverse,
|
|
1497
|
+
intercept(predicate, handler) {
|
|
1498
|
+
state.interceptors.push({ predicate, handler });
|
|
1499
|
+
return this;
|
|
1500
|
+
},
|
|
1501
|
+
parse(predicate, parser) {
|
|
1502
|
+
state.parsers.push({ predicate, parser });
|
|
1503
|
+
return this;
|
|
1504
|
+
},
|
|
1505
|
+
ignore(predicate) {
|
|
1506
|
+
state.ignore.push(predicate);
|
|
1507
|
+
return this;
|
|
1508
|
+
},
|
|
1509
|
+
on(predicate, handler) {
|
|
1510
|
+
state.handlers.common.push({ predicate, handler });
|
|
1511
|
+
return this;
|
|
1512
|
+
},
|
|
1513
|
+
onAttribute(predicate, handler) {
|
|
1514
|
+
state.handlers.attributes.push({ predicate, handler });
|
|
1515
|
+
return this;
|
|
1516
|
+
},
|
|
1517
|
+
onRelation(handler) {
|
|
1518
|
+
return this.onAttribute(({ attribute }) => attribute?.type === "relation", handler);
|
|
1519
|
+
},
|
|
1520
|
+
onMedia(handler) {
|
|
1521
|
+
return this.onAttribute(({ attribute }) => attribute?.type === "media", handler);
|
|
1522
|
+
},
|
|
1523
|
+
onComponent(handler) {
|
|
1524
|
+
return this.onAttribute(({ attribute }) => attribute?.type === "component", handler);
|
|
1525
|
+
},
|
|
1526
|
+
onDynamicZone(handler) {
|
|
1527
|
+
return this.onAttribute(({ attribute }) => attribute?.type === "dynamiczone", handler);
|
|
1528
|
+
}
|
|
1529
|
+
};
|
|
1530
|
+
};
|
|
1531
|
+
const isObj$2 = (value2) => isObject(value2);
|
|
1532
|
+
const filters = traverseFactory().intercept(
|
|
1533
|
+
// Intercept filters arrays and apply the traversal to each one individually
|
|
1534
|
+
isArray,
|
|
1535
|
+
async (visitor2, options, filters2, { recurse }) => {
|
|
1536
|
+
return Promise.all(
|
|
1537
|
+
filters2.map((filter, i) => {
|
|
1538
|
+
const newPath = options.path ? { ...options.path, raw: `${options.path.raw}[${i}]` } : options.path;
|
|
1539
|
+
return recurse(visitor2, { ...options, path: newPath }, filter);
|
|
1540
|
+
})
|
|
1541
|
+
// todo: move that to the visitors
|
|
1542
|
+
).then((res) => res.filter((val) => !(isObject(val) && isEmpty(val))));
|
|
1543
|
+
}
|
|
1544
|
+
).intercept(
|
|
1545
|
+
// Ignore non object filters and return the value as-is
|
|
1546
|
+
(filters2) => !isObject(filters2),
|
|
1547
|
+
(_2, __, filters2) => {
|
|
1548
|
+
return filters2;
|
|
1549
|
+
}
|
|
1550
|
+
).parse(isObj$2, () => ({
|
|
1551
|
+
transform: cloneDeep,
|
|
1552
|
+
remove(key2, data) {
|
|
1553
|
+
return omit(key2, data);
|
|
1554
|
+
},
|
|
1555
|
+
set(key2, value2, data) {
|
|
1556
|
+
return { ...data, [key2]: value2 };
|
|
1557
|
+
},
|
|
1558
|
+
keys(data) {
|
|
1559
|
+
return Object.keys(data);
|
|
1560
|
+
},
|
|
1561
|
+
get(key2, data) {
|
|
1562
|
+
return data[key2];
|
|
1563
|
+
}
|
|
1564
|
+
})).ignore(({ value: value2 }) => isNil(value2)).on(
|
|
1565
|
+
({ attribute }) => isNil(attribute),
|
|
1566
|
+
async ({ key: key2, visitor: visitor2, path, value: value2, schema }, { set, recurse }) => {
|
|
1567
|
+
set(key2, await recurse(visitor2, { schema, path }, value2));
|
|
1568
|
+
}
|
|
1569
|
+
).onRelation(async ({ key: key2, attribute, visitor: visitor2, path, value: value2 }, { set, recurse }) => {
|
|
1570
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
|
1571
|
+
if (isMorphRelation) {
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
const targetSchemaUID = attribute.target;
|
|
1575
|
+
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
1576
|
+
const newValue = await recurse(visitor2, { schema: targetSchema, path }, value2);
|
|
1577
|
+
set(key2, newValue);
|
|
1578
|
+
}).onComponent(async ({ key: key2, attribute, visitor: visitor2, path, value: value2 }, { set, recurse }) => {
|
|
1579
|
+
const targetSchema = strapi.getModel(attribute.component);
|
|
1580
|
+
const newValue = await recurse(visitor2, { schema: targetSchema, path }, value2);
|
|
1581
|
+
set(key2, newValue);
|
|
1582
|
+
}).onMedia(async ({ key: key2, visitor: visitor2, path, value: value2 }, { set, recurse }) => {
|
|
1583
|
+
const targetSchemaUID = "plugin::upload.file";
|
|
1584
|
+
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
1585
|
+
const newValue = await recurse(visitor2, { schema: targetSchema, path }, value2);
|
|
1586
|
+
set(key2, newValue);
|
|
1587
|
+
});
|
|
1588
|
+
const traverseQueryFilters = curry(filters.traverse);
|
|
1589
|
+
const ORDERS = { asc: "asc", desc: "desc" };
|
|
1590
|
+
const ORDER_VALUES = Object.values(ORDERS);
|
|
1591
|
+
const isSortOrder = (value2) => ORDER_VALUES.includes(value2.toLowerCase());
|
|
1592
|
+
const isStringArray$3 = (value2) => Array.isArray(value2) && value2.every(isString$1);
|
|
1593
|
+
const isObjectArray = (value2) => Array.isArray(value2) && value2.every(isObject);
|
|
1594
|
+
const isNestedSorts = (value2) => isString$1(value2) && value2.split(",").length > 1;
|
|
1595
|
+
const isObj$1 = (value2) => isObject(value2);
|
|
1596
|
+
const sort = traverseFactory().intercept(
|
|
1597
|
+
// String with chained sorts (foo,bar,foobar) => split, map(recurse), then recompose
|
|
1598
|
+
isNestedSorts,
|
|
1599
|
+
async (visitor2, options, sort2, { recurse }) => {
|
|
1600
|
+
return Promise.all(
|
|
1601
|
+
sort2.split(",").map(trim).map((nestedSort) => recurse(visitor2, options, nestedSort))
|
|
1602
|
+
).then((res) => res.filter((part) => !isEmpty(part)).join(","));
|
|
1603
|
+
}
|
|
1604
|
+
).intercept(
|
|
1605
|
+
// Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items
|
|
1606
|
+
isStringArray$3,
|
|
1607
|
+
async (visitor2, options, sort2, { recurse }) => {
|
|
1608
|
+
return Promise.all(sort2.map((nestedSort) => recurse(visitor2, options, nestedSort))).then(
|
|
1609
|
+
(res) => res.filter((nestedSort) => !isEmpty(nestedSort))
|
|
1610
|
+
);
|
|
1611
|
+
}
|
|
1612
|
+
).intercept(
|
|
1613
|
+
// Array of objects [{ foo: 'asc' }, { bar: 'desc', baz: 'asc' }] => map(recurse), then filter out empty items
|
|
1614
|
+
isObjectArray,
|
|
1615
|
+
async (visitor2, options, sort2, { recurse }) => {
|
|
1616
|
+
return Promise.all(sort2.map((nestedSort) => recurse(visitor2, options, nestedSort))).then(
|
|
1617
|
+
(res) => res.filter((nestedSort) => !isEmpty(nestedSort))
|
|
1618
|
+
);
|
|
1619
|
+
}
|
|
1620
|
+
).parse(isString$1, () => {
|
|
1621
|
+
const tokenize = pipe(split("."), map(split(":")), flatten);
|
|
1622
|
+
const recompose = (parts) => {
|
|
1623
|
+
if (parts.length === 0) {
|
|
1624
|
+
return void 0;
|
|
1625
|
+
}
|
|
1626
|
+
return parts.reduce((acc2, part) => {
|
|
1627
|
+
if (isEmpty(part)) {
|
|
1628
|
+
return acc2;
|
|
1629
|
+
}
|
|
1630
|
+
if (acc2 === "") {
|
|
1631
|
+
return part;
|
|
1632
|
+
}
|
|
1633
|
+
return isSortOrder(part) ? `${acc2}:${part}` : `${acc2}.${part}`;
|
|
1634
|
+
}, "");
|
|
1635
|
+
};
|
|
1636
|
+
return {
|
|
1637
|
+
transform: trim,
|
|
1638
|
+
remove(key2, data) {
|
|
1639
|
+
const [root] = tokenize(data);
|
|
1640
|
+
return root === key2 ? void 0 : data;
|
|
1641
|
+
},
|
|
1642
|
+
set(key2, value2, data) {
|
|
1643
|
+
const [root] = tokenize(data);
|
|
1644
|
+
if (root !== key2) {
|
|
1645
|
+
return data;
|
|
1646
|
+
}
|
|
1647
|
+
return isNil(value2) ? root : `${root}.${value2}`;
|
|
1648
|
+
},
|
|
1649
|
+
keys(data) {
|
|
1650
|
+
const v = first(tokenize(data));
|
|
1651
|
+
return v ? [v] : [];
|
|
1652
|
+
},
|
|
1653
|
+
get(key2, data) {
|
|
1654
|
+
const [root, ...rest] = tokenize(data);
|
|
1655
|
+
return key2 === root ? recompose(rest) : void 0;
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
}).parse(isObj$1, () => ({
|
|
1659
|
+
transform: cloneDeep,
|
|
1660
|
+
remove(key2, data) {
|
|
1661
|
+
const { [key2]: ignored, ...rest } = data;
|
|
1662
|
+
return rest;
|
|
1663
|
+
},
|
|
1664
|
+
set(key2, value2, data) {
|
|
1665
|
+
return { ...data, [key2]: value2 };
|
|
1666
|
+
},
|
|
1667
|
+
keys(data) {
|
|
1668
|
+
return Object.keys(data);
|
|
1669
|
+
},
|
|
1670
|
+
get(key2, data) {
|
|
1671
|
+
return data[key2];
|
|
1672
|
+
}
|
|
1673
|
+
})).onRelation(async ({ key: key2, value: value2, attribute, visitor: visitor2, path }, { set, recurse }) => {
|
|
1674
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
|
1675
|
+
if (isMorphRelation) {
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
const targetSchemaUID = attribute.target;
|
|
1679
|
+
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
1680
|
+
const newValue = await recurse(visitor2, { schema: targetSchema, path }, value2);
|
|
1681
|
+
set(key2, newValue);
|
|
1682
|
+
}).onMedia(async ({ key: key2, path, visitor: visitor2, value: value2 }, { recurse, set }) => {
|
|
1683
|
+
const targetSchemaUID = "plugin::upload.file";
|
|
1684
|
+
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
1685
|
+
const newValue = await recurse(visitor2, { schema: targetSchema, path }, value2);
|
|
1686
|
+
set(key2, newValue);
|
|
1687
|
+
}).onComponent(async ({ key: key2, value: value2, visitor: visitor2, path, attribute }, { recurse, set }) => {
|
|
1688
|
+
const targetSchema = strapi.getModel(attribute.component);
|
|
1689
|
+
const newValue = await recurse(visitor2, { schema: targetSchema, path }, value2);
|
|
1690
|
+
set(key2, newValue);
|
|
1691
|
+
});
|
|
1692
|
+
const traverseQuerySort = curry(sort.traverse);
|
|
1693
|
+
const isKeyword = (keyword) => {
|
|
1694
|
+
return ({ key: key2, attribute }) => {
|
|
1695
|
+
return !attribute && keyword === key2;
|
|
1696
|
+
};
|
|
1697
|
+
};
|
|
1698
|
+
const isStringArray$2 = (value2) => isArray(value2) && value2.every(isString$1);
|
|
1699
|
+
const isWildCardConstant = (value2) => value2 === "*";
|
|
1700
|
+
const isObj = (value2) => isObject(value2);
|
|
1701
|
+
const populate = traverseFactory().intercept(isStringArray$2, async (visitor2, options, populate2, { recurse }) => {
|
|
1702
|
+
const visitedPopulate = await Promise.all(
|
|
1703
|
+
populate2.map((nestedPopulate) => recurse(visitor2, options, nestedPopulate))
|
|
1704
|
+
);
|
|
1705
|
+
return visitedPopulate.filter((item) => !isNil(item));
|
|
1706
|
+
}).intercept(isWildCardConstant, (visitor2, options, _data, { recurse }) => {
|
|
1707
|
+
const attributes = options.schema?.attributes;
|
|
1708
|
+
if (!attributes) {
|
|
1709
|
+
return "*";
|
|
1710
|
+
}
|
|
1711
|
+
const parsedPopulate = Object.entries(attributes).filter(([, value2]) => ["relation", "component", "dynamiczone", "media"].includes(value2.type)).reduce((acc2, [key2]) => ({ ...acc2, [key2]: true }), {});
|
|
1712
|
+
return recurse(visitor2, options, parsedPopulate);
|
|
1713
|
+
}).parse(isString$1, () => {
|
|
1714
|
+
const tokenize = split(".");
|
|
1715
|
+
const recompose = join(".");
|
|
1716
|
+
return {
|
|
1717
|
+
transform: trim,
|
|
1718
|
+
remove(key2, data) {
|
|
1719
|
+
const [root] = tokenize(data);
|
|
1720
|
+
return root === key2 ? void 0 : data;
|
|
1721
|
+
},
|
|
1722
|
+
set(key2, value2, data) {
|
|
1723
|
+
const [root] = tokenize(data);
|
|
1724
|
+
if (root !== key2) {
|
|
1725
|
+
return data;
|
|
1726
|
+
}
|
|
1727
|
+
return isNil(value2) || isEmpty(value2) ? root : `${root}.${value2}`;
|
|
1728
|
+
},
|
|
1729
|
+
keys(data) {
|
|
1730
|
+
const v = first(tokenize(data));
|
|
1731
|
+
return v ? [v] : [];
|
|
1732
|
+
},
|
|
1733
|
+
get(key2, data) {
|
|
1734
|
+
const [root, ...rest] = tokenize(data);
|
|
1735
|
+
return key2 === root ? recompose(rest) : void 0;
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
}).parse(isObj, () => ({
|
|
1739
|
+
transform: cloneDeep,
|
|
1740
|
+
remove(key2, data) {
|
|
1741
|
+
const { [key2]: ignored, ...rest } = data;
|
|
1742
|
+
return rest;
|
|
1743
|
+
},
|
|
1744
|
+
set(key2, value2, data) {
|
|
1745
|
+
return { ...data, [key2]: value2 };
|
|
1746
|
+
},
|
|
1747
|
+
keys(data) {
|
|
1748
|
+
return Object.keys(data);
|
|
1749
|
+
},
|
|
1750
|
+
get(key2, data) {
|
|
1751
|
+
return data[key2];
|
|
1752
|
+
}
|
|
1753
|
+
})).ignore(({ key: key2, attribute }) => {
|
|
1754
|
+
return ["sort", "filters", "fields"].includes(key2) && !attribute;
|
|
1755
|
+
}).on(
|
|
1756
|
+
// Handle recursion on populate."populate"
|
|
1757
|
+
isKeyword("populate"),
|
|
1758
|
+
async ({ key: key2, visitor: visitor2, path, value: value2, schema }, { set, recurse }) => {
|
|
1759
|
+
const newValue = await recurse(visitor2, { schema, path }, value2);
|
|
1760
|
+
set(key2, newValue);
|
|
1761
|
+
}
|
|
1762
|
+
).on(isKeyword("on"), async ({ key: key2, visitor: visitor2, path, value: value2 }, { set, recurse }) => {
|
|
1763
|
+
const newOn = {};
|
|
1764
|
+
if (!isObj(value2)) {
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1767
|
+
for (const [uid, subPopulate] of Object.entries(value2)) {
|
|
1768
|
+
const model = strapi.getModel(uid);
|
|
1769
|
+
const newPath = { ...path, raw: `${path.raw}[${uid}]` };
|
|
1770
|
+
newOn[uid] = await recurse(visitor2, { schema: model, path: newPath }, subPopulate);
|
|
1771
|
+
}
|
|
1772
|
+
set(key2, newOn);
|
|
1773
|
+
}).onRelation(async ({ key: key2, value: value2, attribute, visitor: visitor2, path, schema }, { set, recurse }) => {
|
|
1774
|
+
if (isNil(value2)) {
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
if (isMorphToRelationalAttribute(attribute)) {
|
|
1778
|
+
if (!isObject(value2) || !("on" in value2 && isObject(value2?.on))) {
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
const newValue2 = await recurse(visitor2, { schema, path }, { on: value2?.on });
|
|
1782
|
+
set(key2, { on: newValue2 });
|
|
1783
|
+
}
|
|
1784
|
+
const targetSchemaUID = attribute.target;
|
|
1785
|
+
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
1786
|
+
const newValue = await recurse(visitor2, { schema: targetSchema, path }, value2);
|
|
1787
|
+
set(key2, newValue);
|
|
1788
|
+
}).onMedia(async ({ key: key2, path, visitor: visitor2, value: value2 }, { recurse, set }) => {
|
|
1789
|
+
if (isNil(value2)) {
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
const targetSchemaUID = "plugin::upload.file";
|
|
1793
|
+
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
1794
|
+
const newValue = await recurse(visitor2, { schema: targetSchema, path }, value2);
|
|
1795
|
+
set(key2, newValue);
|
|
1796
|
+
}).onComponent(async ({ key: key2, value: value2, visitor: visitor2, path, attribute }, { recurse, set }) => {
|
|
1797
|
+
if (isNil(value2)) {
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
const targetSchema = strapi.getModel(attribute.component);
|
|
1801
|
+
const newValue = await recurse(visitor2, { schema: targetSchema, path }, value2);
|
|
1802
|
+
set(key2, newValue);
|
|
1803
|
+
}).onDynamicZone(async ({ key: key2, value: value2, attribute, schema, visitor: visitor2, path }, { set, recurse }) => {
|
|
1804
|
+
if (isNil(value2)) {
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
if (isObject(value2)) {
|
|
1808
|
+
const { components } = attribute;
|
|
1809
|
+
const newValue = {};
|
|
1810
|
+
let newProperties = omit("on", value2);
|
|
1811
|
+
for (const componentUID of components) {
|
|
1812
|
+
const componentSchema = strapi.getModel(componentUID);
|
|
1813
|
+
newProperties = await recurse(visitor2, { schema: componentSchema, path }, newProperties);
|
|
1814
|
+
}
|
|
1815
|
+
Object.assign(newValue, newProperties);
|
|
1816
|
+
if ("on" in value2 && value2.on) {
|
|
1817
|
+
const newOn = await recurse(visitor2, { schema, path }, { on: value2.on });
|
|
1818
|
+
Object.assign(newValue, newOn);
|
|
1819
|
+
}
|
|
1820
|
+
set(key2, newValue);
|
|
1821
|
+
} else {
|
|
1822
|
+
const newValue = await recurse(visitor2, { schema, path }, value2);
|
|
1823
|
+
set(key2, newValue);
|
|
1824
|
+
}
|
|
1825
|
+
});
|
|
1826
|
+
const traverseQueryPopulate = curry(populate.traverse);
|
|
1827
|
+
const isStringArray$1 = (value2) => isArray(value2) && value2.every(isString$1);
|
|
1828
|
+
const fields = traverseFactory().intercept(isStringArray$1, async (visitor2, options, fields2, { recurse }) => {
|
|
1829
|
+
return Promise.all(fields2.map((field) => recurse(visitor2, options, field)));
|
|
1830
|
+
}).intercept((value2) => eq("*", value2), constant("*")).parse(isString$1, () => ({
|
|
1831
|
+
transform: trim,
|
|
1832
|
+
remove(key2, data) {
|
|
1833
|
+
return data === key2 ? void 0 : data;
|
|
1834
|
+
},
|
|
1835
|
+
set(_key, _value, data) {
|
|
1836
|
+
return data;
|
|
1837
|
+
},
|
|
1838
|
+
keys(data) {
|
|
1839
|
+
return [data];
|
|
1840
|
+
},
|
|
1841
|
+
get(key2, data) {
|
|
1842
|
+
return key2 === data ? data : void 0;
|
|
1843
|
+
}
|
|
1844
|
+
}));
|
|
1845
|
+
const traverseQueryFields = curry(fields.traverse);
|
|
1846
|
+
const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1847
|
+
__proto__: null,
|
|
1848
|
+
factory: traverseFactory,
|
|
1849
|
+
traverseQueryFields,
|
|
1850
|
+
traverseQueryFilters,
|
|
1851
|
+
traverseQueryPopulate,
|
|
1852
|
+
traverseQuerySort
|
|
1853
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1854
|
+
const GROUP_OPERATORS = ["$and", "$or"];
|
|
1855
|
+
const WHERE_OPERATORS = [
|
|
1856
|
+
"$not",
|
|
1857
|
+
"$in",
|
|
1858
|
+
"$notIn",
|
|
1859
|
+
"$eq",
|
|
1860
|
+
"$eqi",
|
|
1861
|
+
"$ne",
|
|
1862
|
+
"$nei",
|
|
1863
|
+
"$gt",
|
|
1864
|
+
"$gte",
|
|
1865
|
+
"$lt",
|
|
1866
|
+
"$lte",
|
|
1867
|
+
"$null",
|
|
1868
|
+
"$notNull",
|
|
1869
|
+
"$between",
|
|
1870
|
+
"$startsWith",
|
|
1871
|
+
"$endsWith",
|
|
1872
|
+
"$startsWithi",
|
|
1873
|
+
"$endsWithi",
|
|
1874
|
+
"$contains",
|
|
1875
|
+
"$notContains",
|
|
1876
|
+
"$containsi",
|
|
1877
|
+
"$notContainsi",
|
|
1878
|
+
// Experimental, only for internal use
|
|
1879
|
+
"$jsonSupersetOf"
|
|
1880
|
+
];
|
|
1881
|
+
const CAST_OPERATORS = [
|
|
1882
|
+
"$not",
|
|
1883
|
+
"$in",
|
|
1884
|
+
"$notIn",
|
|
1885
|
+
"$eq",
|
|
1886
|
+
"$ne",
|
|
1887
|
+
"$gt",
|
|
1888
|
+
"$gte",
|
|
1889
|
+
"$lt",
|
|
1890
|
+
"$lte",
|
|
1891
|
+
"$between"
|
|
1892
|
+
];
|
|
1893
|
+
const ARRAY_OPERATORS = ["$in", "$notIn", "$between"];
|
|
1894
|
+
const OPERATORS = {
|
|
1895
|
+
where: WHERE_OPERATORS,
|
|
1896
|
+
cast: CAST_OPERATORS,
|
|
1897
|
+
group: GROUP_OPERATORS,
|
|
1898
|
+
array: ARRAY_OPERATORS
|
|
1899
|
+
};
|
|
1900
|
+
const OPERATORS_LOWERCASE = Object.fromEntries(
|
|
1901
|
+
Object.entries(OPERATORS).map(([key2, values]) => [
|
|
1902
|
+
key2,
|
|
1903
|
+
values.map((value2) => value2.toLowerCase())
|
|
1904
|
+
])
|
|
1905
|
+
);
|
|
1906
|
+
const isObjKey = (key2, obj2) => {
|
|
1907
|
+
return key2 in obj2;
|
|
1908
|
+
};
|
|
1909
|
+
const isOperatorOfType = (type, key2, ignoreCase = false) => {
|
|
1910
|
+
if (ignoreCase) {
|
|
1911
|
+
return OPERATORS_LOWERCASE[type]?.includes(key2.toLowerCase()) ?? false;
|
|
1912
|
+
}
|
|
1913
|
+
if (isObjKey(type, OPERATORS)) {
|
|
1914
|
+
return OPERATORS[type]?.includes(key2) ?? false;
|
|
1915
|
+
}
|
|
1916
|
+
return false;
|
|
1917
|
+
};
|
|
1918
|
+
const isOperator = (key2, ignoreCase = false) => {
|
|
1919
|
+
return Object.keys(OPERATORS).some((type) => isOperatorOfType(type, key2, ignoreCase));
|
|
1920
|
+
};
|
|
1921
|
+
const sanitizePasswords = (schema) => async (entity) => {
|
|
1922
|
+
if (!schema) {
|
|
1923
|
+
throw new Error("Missing schema in sanitizePasswords");
|
|
1924
|
+
}
|
|
1925
|
+
return traverseEntity$1(visitor$7, { schema }, entity);
|
|
1926
|
+
};
|
|
1927
|
+
const defaultSanitizeOutput = async (schema, entity) => {
|
|
1928
|
+
if (!schema) {
|
|
1929
|
+
throw new Error("Missing schema in defaultSanitizeOutput");
|
|
1930
|
+
}
|
|
1931
|
+
return traverseEntity$1(
|
|
1932
|
+
(...args) => {
|
|
1933
|
+
visitor$7(...args);
|
|
1934
|
+
visitor$6(...args);
|
|
1935
|
+
},
|
|
1936
|
+
{ schema },
|
|
1937
|
+
entity
|
|
1938
|
+
);
|
|
1939
|
+
};
|
|
1940
|
+
const defaultSanitizeFilters = curry((schema, filters2) => {
|
|
1941
|
+
if (!schema) {
|
|
1942
|
+
throw new Error("Missing schema in defaultSanitizeFilters");
|
|
1943
|
+
}
|
|
1944
|
+
return pipeAsync(
|
|
1945
|
+
// Remove keys that are not attributes or valid operators
|
|
1946
|
+
traverseQueryFilters(
|
|
1947
|
+
({ key: key2, attribute }, { remove: remove2 }) => {
|
|
1948
|
+
const isAttribute = !!attribute;
|
|
1949
|
+
if (key2 === "id") {
|
|
1950
|
+
return;
|
|
1951
|
+
}
|
|
1952
|
+
if (!isAttribute && !isOperator(key2)) {
|
|
1953
|
+
remove2(key2);
|
|
1954
|
+
}
|
|
1955
|
+
},
|
|
1956
|
+
{ schema }
|
|
1957
|
+
),
|
|
1958
|
+
// Remove dynamic zones from filters
|
|
1959
|
+
traverseQueryFilters(visitor$4, { schema }),
|
|
1960
|
+
// Remove morpTo relations from filters
|
|
1961
|
+
traverseQueryFilters(visitor$5, { schema }),
|
|
1962
|
+
// Remove passwords from filters
|
|
1963
|
+
traverseQueryFilters(visitor$7, { schema }),
|
|
1964
|
+
// Remove private from filters
|
|
1965
|
+
traverseQueryFilters(visitor$6, { schema }),
|
|
1966
|
+
// Remove empty objects
|
|
1967
|
+
traverseQueryFilters(
|
|
1968
|
+
({ key: key2, value: value2 }, { remove: remove2 }) => {
|
|
1969
|
+
if (isObject(value2) && isEmpty(value2)) {
|
|
1970
|
+
remove2(key2);
|
|
1971
|
+
}
|
|
1972
|
+
},
|
|
1973
|
+
{ schema }
|
|
1974
|
+
)
|
|
1975
|
+
)(filters2);
|
|
1976
|
+
});
|
|
1977
|
+
const defaultSanitizeSort = curry((schema, sort2) => {
|
|
1978
|
+
if (!schema) {
|
|
1979
|
+
throw new Error("Missing schema in defaultSanitizeSort");
|
|
1980
|
+
}
|
|
1981
|
+
return pipeAsync(
|
|
1982
|
+
// Remove non attribute keys
|
|
1983
|
+
traverseQuerySort(
|
|
1984
|
+
({ key: key2, attribute }, { remove: remove2 }) => {
|
|
1985
|
+
if (key2 === "id") {
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
if (!attribute) {
|
|
1989
|
+
remove2(key2);
|
|
1990
|
+
}
|
|
1991
|
+
},
|
|
1992
|
+
{ schema }
|
|
1993
|
+
),
|
|
1994
|
+
// Remove dynamic zones from sort
|
|
1995
|
+
traverseQuerySort(visitor$4, { schema }),
|
|
1996
|
+
// Remove morpTo relations from sort
|
|
1997
|
+
traverseQuerySort(visitor$5, { schema }),
|
|
1998
|
+
// Remove private from sort
|
|
1999
|
+
traverseQuerySort(visitor$6, { schema }),
|
|
2000
|
+
// Remove passwords from filters
|
|
2001
|
+
traverseQuerySort(visitor$7, { schema }),
|
|
2002
|
+
// Remove keys for empty non-scalar values
|
|
2003
|
+
traverseQuerySort(
|
|
2004
|
+
({ key: key2, attribute, value: value2 }, { remove: remove2 }) => {
|
|
2005
|
+
if (key2 === "id") {
|
|
2006
|
+
return;
|
|
2007
|
+
}
|
|
2008
|
+
if (!isScalarAttribute(attribute) && isEmpty(value2)) {
|
|
2009
|
+
remove2(key2);
|
|
2010
|
+
}
|
|
2011
|
+
},
|
|
2012
|
+
{ schema }
|
|
2013
|
+
)
|
|
2014
|
+
)(sort2);
|
|
2015
|
+
});
|
|
2016
|
+
const defaultSanitizeFields = curry((schema, fields2) => {
|
|
2017
|
+
if (!schema) {
|
|
2018
|
+
throw new Error("Missing schema in defaultSanitizeFields");
|
|
2019
|
+
}
|
|
2020
|
+
return pipeAsync(
|
|
2021
|
+
// Only keep scalar attributes
|
|
2022
|
+
traverseQueryFields(
|
|
2023
|
+
({ key: key2, attribute }, { remove: remove2 }) => {
|
|
2024
|
+
if (key2 === "id") {
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
if (isNil(attribute) || !isScalarAttribute(attribute)) {
|
|
2028
|
+
remove2(key2);
|
|
2029
|
+
}
|
|
2030
|
+
},
|
|
2031
|
+
{ schema }
|
|
2032
|
+
),
|
|
2033
|
+
// Remove private fields
|
|
2034
|
+
traverseQueryFields(visitor$6, { schema }),
|
|
2035
|
+
// Remove password fields
|
|
2036
|
+
traverseQueryFields(visitor$7, { schema }),
|
|
2037
|
+
// Remove nil values from fields array
|
|
2038
|
+
(value2) => isArray(value2) ? value2.filter((field) => !isNil(field)) : value2
|
|
2039
|
+
)(fields2);
|
|
2040
|
+
});
|
|
2041
|
+
const defaultSanitizePopulate = curry((schema, populate2) => {
|
|
2042
|
+
if (!schema) {
|
|
2043
|
+
throw new Error("Missing schema in defaultSanitizePopulate");
|
|
2044
|
+
}
|
|
2045
|
+
return pipeAsync(
|
|
2046
|
+
traverseQueryPopulate(
|
|
2047
|
+
async ({ key: key2, value: value2, schema: schema2, attribute }, { set }) => {
|
|
2048
|
+
if (attribute) {
|
|
2049
|
+
return;
|
|
2050
|
+
}
|
|
2051
|
+
if (key2 === "sort") {
|
|
2052
|
+
set(key2, await defaultSanitizeSort(schema2, value2));
|
|
2053
|
+
}
|
|
2054
|
+
if (key2 === "filters") {
|
|
2055
|
+
set(key2, await defaultSanitizeFilters(schema2, value2));
|
|
2056
|
+
}
|
|
2057
|
+
if (key2 === "fields") {
|
|
2058
|
+
set(key2, await defaultSanitizeFields(schema2, value2));
|
|
2059
|
+
}
|
|
2060
|
+
},
|
|
2061
|
+
{ schema }
|
|
2062
|
+
),
|
|
2063
|
+
// Remove private fields
|
|
2064
|
+
traverseQueryPopulate(visitor$6, { schema })
|
|
2065
|
+
)(populate2);
|
|
2066
|
+
});
|
|
2067
|
+
const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2068
|
+
__proto__: null,
|
|
2069
|
+
defaultSanitizeFields,
|
|
2070
|
+
defaultSanitizeFilters,
|
|
2071
|
+
defaultSanitizeOutput,
|
|
2072
|
+
defaultSanitizePopulate,
|
|
2073
|
+
defaultSanitizeSort,
|
|
2074
|
+
sanitizePasswords
|
|
2075
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
2076
|
+
const createContentAPISanitizers = () => {
|
|
2077
|
+
const sanitizeInput = (data, schema, { auth } = {}) => {
|
|
2078
|
+
if (!schema) {
|
|
2079
|
+
throw new Error("Missing schema in sanitizeInput");
|
|
2080
|
+
}
|
|
2081
|
+
if (isArray(data)) {
|
|
2082
|
+
return Promise.all(data.map((entry) => sanitizeInput(entry, schema, { auth })));
|
|
2083
|
+
}
|
|
2084
|
+
const nonWritableAttributes = getNonWritableAttributes(schema);
|
|
2085
|
+
const transforms = [
|
|
2086
|
+
// Remove non writable attributes
|
|
2087
|
+
traverseEntity$1(removeRestrictedFields(nonWritableAttributes), { schema })
|
|
2088
|
+
];
|
|
2089
|
+
if (auth) {
|
|
2090
|
+
transforms.push(traverseEntity$1(removeRestrictedRelations(auth), { schema }));
|
|
2091
|
+
}
|
|
2092
|
+
strapi.sanitizers.get("content-api.input").forEach((sanitizer) => transforms.push(sanitizer(schema)));
|
|
2093
|
+
return pipeAsync(...transforms)(data);
|
|
2094
|
+
};
|
|
2095
|
+
const sanitizeOutput = async (data, schema, { auth } = {}) => {
|
|
2096
|
+
if (!schema) {
|
|
2097
|
+
throw new Error("Missing schema in sanitizeOutput");
|
|
2098
|
+
}
|
|
2099
|
+
if (isArray(data)) {
|
|
2100
|
+
const res = new Array(data.length);
|
|
2101
|
+
for (let i = 0; i < data.length; i += 1) {
|
|
2102
|
+
res[i] = await sanitizeOutput(data[i], schema, { auth });
|
|
2103
|
+
}
|
|
2104
|
+
return res;
|
|
2105
|
+
}
|
|
2106
|
+
const transforms = [(data2) => defaultSanitizeOutput(schema, data2)];
|
|
2107
|
+
if (auth) {
|
|
2108
|
+
transforms.push(traverseEntity$1(removeRestrictedRelations(auth), { schema }));
|
|
2109
|
+
}
|
|
2110
|
+
strapi.sanitizers.get("content-api.output").forEach((sanitizer) => transforms.push(sanitizer(schema)));
|
|
2111
|
+
return pipeAsync(...transforms)(data);
|
|
2112
|
+
};
|
|
2113
|
+
const sanitizeQuery = async (query, schema, { auth } = {}) => {
|
|
2114
|
+
if (!schema) {
|
|
2115
|
+
throw new Error("Missing schema in sanitizeQuery");
|
|
2116
|
+
}
|
|
2117
|
+
const { filters: filters2, sort: sort2, fields: fields2, populate: populate2 } = query;
|
|
2118
|
+
const sanitizedQuery = cloneDeep(query);
|
|
2119
|
+
if (filters2) {
|
|
2120
|
+
Object.assign(sanitizedQuery, { filters: await sanitizeFilters(filters2, schema, { auth }) });
|
|
2121
|
+
}
|
|
2122
|
+
if (sort2) {
|
|
2123
|
+
Object.assign(sanitizedQuery, { sort: await sanitizeSort(sort2, schema, { auth }) });
|
|
2124
|
+
}
|
|
2125
|
+
if (fields2) {
|
|
2126
|
+
Object.assign(sanitizedQuery, { fields: await sanitizeFields(fields2, schema) });
|
|
2127
|
+
}
|
|
2128
|
+
if (populate2) {
|
|
2129
|
+
Object.assign(sanitizedQuery, { populate: await sanitizePopulate(populate2, schema) });
|
|
2130
|
+
}
|
|
2131
|
+
return sanitizedQuery;
|
|
2132
|
+
};
|
|
2133
|
+
const sanitizeFilters = (filters2, schema, { auth } = {}) => {
|
|
2134
|
+
if (!schema) {
|
|
2135
|
+
throw new Error("Missing schema in sanitizeFilters");
|
|
2136
|
+
}
|
|
2137
|
+
if (isArray(filters2)) {
|
|
2138
|
+
return Promise.all(filters2.map((filter) => sanitizeFilters(filter, schema, { auth })));
|
|
2139
|
+
}
|
|
2140
|
+
const transforms = [defaultSanitizeFilters(schema)];
|
|
2141
|
+
if (auth) {
|
|
2142
|
+
transforms.push(traverseQueryFilters(removeRestrictedRelations(auth), { schema }));
|
|
2143
|
+
}
|
|
2144
|
+
return pipeAsync(...transforms)(filters2);
|
|
2145
|
+
};
|
|
2146
|
+
const sanitizeSort = (sort2, schema, { auth } = {}) => {
|
|
2147
|
+
if (!schema) {
|
|
2148
|
+
throw new Error("Missing schema in sanitizeSort");
|
|
2149
|
+
}
|
|
2150
|
+
const transforms = [defaultSanitizeSort(schema)];
|
|
2151
|
+
if (auth) {
|
|
2152
|
+
transforms.push(traverseQuerySort(removeRestrictedRelations(auth), { schema }));
|
|
2153
|
+
}
|
|
2154
|
+
return pipeAsync(...transforms)(sort2);
|
|
2155
|
+
};
|
|
2156
|
+
const sanitizeFields = (fields2, schema) => {
|
|
2157
|
+
if (!schema) {
|
|
2158
|
+
throw new Error("Missing schema in sanitizeFields");
|
|
2159
|
+
}
|
|
2160
|
+
const transforms = [defaultSanitizeFields(schema)];
|
|
2161
|
+
return pipeAsync(...transforms)(fields2);
|
|
2162
|
+
};
|
|
2163
|
+
const sanitizePopulate = (populate2, schema, { auth } = {}) => {
|
|
2164
|
+
if (!schema) {
|
|
2165
|
+
throw new Error("Missing schema in sanitizePopulate");
|
|
2166
|
+
}
|
|
2167
|
+
const transforms = [defaultSanitizePopulate(schema)];
|
|
2168
|
+
if (auth) {
|
|
2169
|
+
transforms.push(traverseQueryPopulate(removeRestrictedRelations(auth), { schema }));
|
|
2170
|
+
}
|
|
2171
|
+
return pipeAsync(...transforms)(populate2);
|
|
2172
|
+
};
|
|
2173
|
+
return {
|
|
2174
|
+
input: sanitizeInput,
|
|
2175
|
+
output: sanitizeOutput,
|
|
2176
|
+
query: sanitizeQuery,
|
|
2177
|
+
filters: sanitizeFilters,
|
|
2178
|
+
sort: sanitizeSort,
|
|
2179
|
+
fields: sanitizeFields,
|
|
2180
|
+
populate: sanitizePopulate
|
|
2181
|
+
};
|
|
2182
|
+
};
|
|
2183
|
+
const contentAPI$1 = createContentAPISanitizers();
|
|
2184
|
+
const index$1 = {
|
|
2185
|
+
contentAPI: contentAPI$1,
|
|
2186
|
+
sanitizers,
|
|
2187
|
+
visitors: visitors$1
|
|
2188
|
+
};
|
|
2189
|
+
const throwInvalidParam = ({ key: key2 }) => {
|
|
2190
|
+
throw new ValidationError(`Invalid parameter ${key2}`);
|
|
2191
|
+
};
|
|
2192
|
+
const visitor$3 = ({ key: key2, attribute }) => {
|
|
2193
|
+
if (attribute?.type === "password") {
|
|
2194
|
+
throwInvalidParam({ key: key2 });
|
|
2195
|
+
}
|
|
2196
|
+
};
|
|
2197
|
+
const visitor$2 = ({ schema, key: key2, attribute }) => {
|
|
2198
|
+
if (!attribute) {
|
|
2199
|
+
return;
|
|
2200
|
+
}
|
|
2201
|
+
const isPrivate = attribute.private === true || isPrivateAttribute(schema, key2);
|
|
2202
|
+
if (isPrivate) {
|
|
2203
|
+
throwInvalidParam({ key: key2 });
|
|
2204
|
+
}
|
|
2205
|
+
};
|
|
2206
|
+
const ACTIONS_TO_VERIFY = ["find"];
|
|
2207
|
+
const { CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE } = constants$1;
|
|
2208
|
+
const throwRestrictedRelations = (auth) => async ({ data, key: key2, attribute, schema }) => {
|
|
2209
|
+
if (!attribute) {
|
|
2210
|
+
return;
|
|
2211
|
+
}
|
|
2212
|
+
const isRelation = attribute.type === "relation";
|
|
2213
|
+
if (!isRelation) {
|
|
2214
|
+
return;
|
|
2215
|
+
}
|
|
2216
|
+
const handleMorphRelation = async () => {
|
|
2217
|
+
for (const element of data[key2]) {
|
|
2218
|
+
const scopes = ACTIONS_TO_VERIFY.map((action) => `${element.__type}.${action}`);
|
|
2219
|
+
const isAllowed = await hasAccessToSomeScopes(scopes, auth);
|
|
2220
|
+
if (!isAllowed) {
|
|
2221
|
+
throwInvalidParam({ key: key2 });
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
};
|
|
2225
|
+
const handleRegularRelation = async () => {
|
|
2226
|
+
const scopes = ACTIONS_TO_VERIFY.map((action) => `${attribute.target}.${action}`);
|
|
2227
|
+
const isAllowed = await hasAccessToSomeScopes(scopes, auth);
|
|
2228
|
+
if (!isAllowed) {
|
|
2229
|
+
throwInvalidParam({ key: key2 });
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
const isCreatorRelation = [CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE].includes(key2);
|
|
2233
|
+
if (isMorphToRelationalAttribute(attribute)) {
|
|
2234
|
+
await handleMorphRelation();
|
|
2235
|
+
return;
|
|
2236
|
+
}
|
|
2237
|
+
if (isCreatorRelation && schema.options?.populateCreatorFields) {
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
await handleRegularRelation();
|
|
2241
|
+
};
|
|
2242
|
+
const hasAccessToSomeScopes = async (scopes, auth) => {
|
|
2243
|
+
for (const scope of scopes) {
|
|
2244
|
+
try {
|
|
2245
|
+
await strapi.auth.verify(auth, { scope });
|
|
2246
|
+
return true;
|
|
2247
|
+
} catch {
|
|
2248
|
+
continue;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
return false;
|
|
2252
|
+
};
|
|
2253
|
+
const visitor$1 = ({ key: key2, attribute }) => {
|
|
2254
|
+
if (isMorphToRelationalAttribute(attribute)) {
|
|
2255
|
+
throwInvalidParam({ key: key2 });
|
|
2256
|
+
}
|
|
2257
|
+
};
|
|
2258
|
+
const visitor = ({ key: key2, attribute }) => {
|
|
2259
|
+
if (isDynamicZoneAttribute(attribute)) {
|
|
2260
|
+
throwInvalidParam({ key: key2 });
|
|
2261
|
+
}
|
|
2262
|
+
};
|
|
2263
|
+
const throwDisallowedFields = (allowedFields = null) => ({ key: key2, path: { attribute: path } }) => {
|
|
2264
|
+
if (allowedFields === null) {
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2267
|
+
if (!(isArray(allowedFields) && allowedFields.every(isString$1))) {
|
|
2268
|
+
throw new TypeError(
|
|
2269
|
+
`Expected array of strings for allowedFields but got "${typeof allowedFields}"`
|
|
2270
|
+
);
|
|
2271
|
+
}
|
|
2272
|
+
if (isNil(path)) {
|
|
2273
|
+
return;
|
|
2274
|
+
}
|
|
2275
|
+
const containedPaths = getContainedPaths(path);
|
|
2276
|
+
const isPathAllowed = allowedFields.some(
|
|
2277
|
+
(p) => containedPaths.includes(p) || p.startsWith(`${path}.`)
|
|
2278
|
+
);
|
|
2279
|
+
if (isPathAllowed) {
|
|
2280
|
+
return;
|
|
2281
|
+
}
|
|
2282
|
+
throwInvalidParam({ key: key2 });
|
|
2283
|
+
};
|
|
2284
|
+
const getContainedPaths = (path) => {
|
|
2285
|
+
const parts = toPath(path);
|
|
2286
|
+
return parts.reduce((acc2, value2, index2, list) => {
|
|
2287
|
+
return [...acc2, list.slice(0, index2 + 1).join(".")];
|
|
2288
|
+
}, []);
|
|
2289
|
+
};
|
|
2290
|
+
const throwRestrictedFields = (restrictedFields = null) => ({ key: key2, path: { attribute: path } }) => {
|
|
2291
|
+
if (restrictedFields === null) {
|
|
2292
|
+
throwInvalidParam({ key: key2 });
|
|
2293
|
+
}
|
|
2294
|
+
if (!(isArray(restrictedFields) && restrictedFields.every(isString$1))) {
|
|
2295
|
+
throw new TypeError(
|
|
2296
|
+
`Expected array of strings for restrictedFields but got "${typeof restrictedFields}"`
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2299
|
+
if (restrictedFields.includes(path)) {
|
|
2300
|
+
throwInvalidParam({ key: key2 });
|
|
2301
|
+
}
|
|
2302
|
+
const isRestrictedNested = restrictedFields.some(
|
|
2303
|
+
(allowedPath) => path?.toString().startsWith(`${allowedPath}.`)
|
|
2304
|
+
);
|
|
2305
|
+
if (isRestrictedNested) {
|
|
2306
|
+
throwInvalidParam({ key: key2 });
|
|
2307
|
+
}
|
|
2308
|
+
};
|
|
2309
|
+
const visitors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2310
|
+
__proto__: null,
|
|
2311
|
+
throwDisallowedFields,
|
|
2312
|
+
throwDynamicZones: visitor,
|
|
2313
|
+
throwMorphToRelations: visitor$1,
|
|
2314
|
+
throwPassword: visitor$3,
|
|
2315
|
+
throwPrivate: visitor$2,
|
|
2316
|
+
throwRestrictedFields,
|
|
2317
|
+
throwRestrictedRelations
|
|
2318
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
2319
|
+
const throwPasswords = (schema) => async (entity) => {
|
|
2320
|
+
if (!schema) {
|
|
2321
|
+
throw new Error("Missing schema in throwPasswords");
|
|
2322
|
+
}
|
|
2323
|
+
return traverseEntity$1(visitor$3, { schema }, entity);
|
|
2324
|
+
};
|
|
2325
|
+
const defaultValidateFilters = curry((schema, filters2) => {
|
|
2326
|
+
if (!schema) {
|
|
2327
|
+
throw new Error("Missing schema in defaultValidateFilters");
|
|
2328
|
+
}
|
|
2329
|
+
return pipeAsync(
|
|
2330
|
+
// keys that are not attributes or valid operators
|
|
2331
|
+
traverseQueryFilters(
|
|
2332
|
+
({ key: key2, attribute }) => {
|
|
2333
|
+
if (key2 === "id") {
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
const isAttribute = !!attribute;
|
|
2337
|
+
if (!isAttribute && !isOperator(key2)) {
|
|
2338
|
+
throwInvalidParam({ key: key2 });
|
|
2339
|
+
}
|
|
2340
|
+
},
|
|
2341
|
+
{ schema }
|
|
2342
|
+
),
|
|
2343
|
+
// dynamic zones from filters
|
|
2344
|
+
traverseQueryFilters(visitor, { schema }),
|
|
2345
|
+
// morphTo relations from filters; because you can't have deep filtering on morph relations
|
|
2346
|
+
traverseQueryFilters(visitor$1, { schema }),
|
|
2347
|
+
// passwords from filters
|
|
2348
|
+
traverseQueryFilters(visitor$3, { schema }),
|
|
2349
|
+
// private from filters
|
|
2350
|
+
traverseQueryFilters(visitor$2, { schema })
|
|
2351
|
+
// we allow empty objects to validate and only sanitize them out, so that users may write "lazy" queries without checking their params exist
|
|
2352
|
+
)(filters2);
|
|
2353
|
+
});
|
|
2354
|
+
const defaultValidateSort = curry((schema, sort2) => {
|
|
2355
|
+
if (!schema) {
|
|
2356
|
+
throw new Error("Missing schema in defaultValidateSort");
|
|
2357
|
+
}
|
|
2358
|
+
return pipeAsync(
|
|
2359
|
+
// non attribute keys
|
|
2360
|
+
traverseQuerySort(
|
|
2361
|
+
({ key: key2, attribute }) => {
|
|
2362
|
+
if (key2 === "id") {
|
|
2363
|
+
return;
|
|
2364
|
+
}
|
|
2365
|
+
if (!attribute) {
|
|
2366
|
+
throwInvalidParam({ key: key2 });
|
|
2367
|
+
}
|
|
2368
|
+
},
|
|
2369
|
+
{ schema }
|
|
2370
|
+
),
|
|
2371
|
+
// dynamic zones from sort
|
|
2372
|
+
traverseQuerySort(visitor, { schema }),
|
|
2373
|
+
// morphTo relations from sort
|
|
2374
|
+
traverseQuerySort(visitor$1, { schema }),
|
|
2375
|
+
// private from sort
|
|
2376
|
+
traverseQuerySort(visitor$2, { schema }),
|
|
2377
|
+
// passwords from filters
|
|
2378
|
+
traverseQuerySort(visitor$3, { schema }),
|
|
2379
|
+
// keys for empty non-scalar values
|
|
2380
|
+
traverseQuerySort(
|
|
2381
|
+
({ key: key2, attribute, value: value2 }) => {
|
|
2382
|
+
if (key2 === "id") {
|
|
2383
|
+
return;
|
|
2384
|
+
}
|
|
2385
|
+
if (!isScalarAttribute(attribute) && isEmpty(value2)) {
|
|
2386
|
+
throwInvalidParam({ key: key2 });
|
|
2387
|
+
}
|
|
2388
|
+
},
|
|
2389
|
+
{ schema }
|
|
2390
|
+
)
|
|
2391
|
+
)(sort2);
|
|
2392
|
+
});
|
|
2393
|
+
const defaultValidateFields = curry((schema, fields2) => {
|
|
2394
|
+
if (!schema) {
|
|
2395
|
+
throw new Error("Missing schema in defaultValidateFields");
|
|
2396
|
+
}
|
|
2397
|
+
return pipeAsync(
|
|
2398
|
+
// Only allow scalar attributes
|
|
2399
|
+
traverseQueryFields(
|
|
2400
|
+
({ key: key2, attribute }) => {
|
|
2401
|
+
if (key2 === "id") {
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
if (isNil(attribute) || !isScalarAttribute(attribute)) {
|
|
2405
|
+
throwInvalidParam({ key: key2 });
|
|
2406
|
+
}
|
|
2407
|
+
},
|
|
2408
|
+
{ schema }
|
|
2409
|
+
),
|
|
2410
|
+
// private fields
|
|
2411
|
+
traverseQueryFields(visitor$2, { schema }),
|
|
2412
|
+
// password fields
|
|
2413
|
+
traverseQueryFields(visitor$3, { schema })
|
|
2414
|
+
)(fields2);
|
|
2415
|
+
});
|
|
2416
|
+
const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2417
|
+
__proto__: null,
|
|
2418
|
+
defaultValidateFields,
|
|
2419
|
+
defaultValidateFilters,
|
|
2420
|
+
defaultValidateSort,
|
|
2421
|
+
throwPasswords
|
|
2422
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
2423
|
+
const createContentAPIValidators = () => {
|
|
2424
|
+
const validateInput = async (data, schema, { auth } = {}) => {
|
|
2425
|
+
if (!schema) {
|
|
2426
|
+
throw new Error("Missing schema in validateInput");
|
|
2427
|
+
}
|
|
2428
|
+
if (isArray(data)) {
|
|
2429
|
+
await Promise.all(data.map((entry) => validateInput(entry, schema, { auth })));
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
const nonWritableAttributes = getNonWritableAttributes(schema);
|
|
2433
|
+
const transforms = [
|
|
2434
|
+
// non writable attributes
|
|
2435
|
+
traverseEntity$1(throwRestrictedFields(nonWritableAttributes), { schema })
|
|
2436
|
+
];
|
|
2437
|
+
if (auth) {
|
|
2438
|
+
transforms.push(traverseEntity$1(throwRestrictedRelations(auth), { schema }));
|
|
2439
|
+
}
|
|
2440
|
+
strapi.validators.get("content-api.input").forEach((validator) => transforms.push(validator(schema)));
|
|
2441
|
+
pipeAsync(...transforms)(data);
|
|
2442
|
+
};
|
|
2443
|
+
const validateQuery = async (query, schema, { auth } = {}) => {
|
|
2444
|
+
if (!schema) {
|
|
2445
|
+
throw new Error("Missing schema in validateQuery");
|
|
2446
|
+
}
|
|
2447
|
+
const { filters: filters2, sort: sort2, fields: fields2 } = query;
|
|
2448
|
+
if (filters2) {
|
|
2449
|
+
await validateFilters(filters2, schema, { auth });
|
|
2450
|
+
}
|
|
2451
|
+
if (sort2) {
|
|
2452
|
+
await validateSort(sort2, schema, { auth });
|
|
2453
|
+
}
|
|
2454
|
+
if (fields2) {
|
|
2455
|
+
await validateFields(fields2, schema);
|
|
2456
|
+
}
|
|
2457
|
+
};
|
|
2458
|
+
const validateFilters = async (filters2, schema, { auth } = {}) => {
|
|
2459
|
+
if (!schema) {
|
|
2460
|
+
throw new Error("Missing schema in validateFilters");
|
|
2461
|
+
}
|
|
2462
|
+
if (isArray(filters2)) {
|
|
2463
|
+
await Promise.all(filters2.map((filter) => validateFilters(filter, schema, { auth })));
|
|
2464
|
+
return;
|
|
2465
|
+
}
|
|
2466
|
+
const transforms = [defaultValidateFilters(schema)];
|
|
2467
|
+
if (auth) {
|
|
2468
|
+
transforms.push(traverseQueryFilters(throwRestrictedRelations(auth), { schema }));
|
|
2469
|
+
}
|
|
2470
|
+
return pipeAsync(...transforms)(filters2);
|
|
2471
|
+
};
|
|
2472
|
+
const validateSort = async (sort2, schema, { auth } = {}) => {
|
|
2473
|
+
if (!schema) {
|
|
2474
|
+
throw new Error("Missing schema in validateSort");
|
|
2475
|
+
}
|
|
2476
|
+
const transforms = [defaultValidateSort(schema)];
|
|
2477
|
+
if (auth) {
|
|
2478
|
+
transforms.push(traverseQuerySort(throwRestrictedRelations(auth), { schema }));
|
|
2479
|
+
}
|
|
2480
|
+
return pipeAsync(...transforms)(sort2);
|
|
2481
|
+
};
|
|
2482
|
+
const validateFields = (fields2, schema) => {
|
|
2483
|
+
if (!schema) {
|
|
2484
|
+
throw new Error("Missing schema in validateFields");
|
|
2485
|
+
}
|
|
2486
|
+
const transforms = [defaultValidateFields(schema)];
|
|
2487
|
+
return pipeAsync(...transforms)(fields2);
|
|
2488
|
+
};
|
|
2489
|
+
return {
|
|
2490
|
+
input: validateInput,
|
|
2491
|
+
query: validateQuery,
|
|
2492
|
+
filters: validateFilters,
|
|
2493
|
+
sort: validateSort,
|
|
2494
|
+
fields: validateFields
|
|
2495
|
+
};
|
|
2496
|
+
};
|
|
2497
|
+
const contentAPI = createContentAPIValidators();
|
|
2498
|
+
const index = {
|
|
2499
|
+
contentAPI,
|
|
2500
|
+
validators,
|
|
2501
|
+
visitors
|
|
2502
|
+
};
|
|
2503
|
+
const { PUBLISHED_AT_ATTRIBUTE } = constants$1;
|
|
2504
|
+
class InvalidOrderError extends Error {
|
|
2505
|
+
constructor() {
|
|
2506
|
+
super();
|
|
2507
|
+
this.message = "Invalid order. order can only be one of asc|desc|ASC|DESC";
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
class InvalidSortError extends Error {
|
|
2511
|
+
constructor() {
|
|
2512
|
+
super();
|
|
2513
|
+
this.message = "Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects";
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
function validateOrder(order) {
|
|
2517
|
+
if (!isString$1(order) || !["asc", "desc"].includes(order.toLocaleLowerCase())) {
|
|
2518
|
+
throw new InvalidOrderError();
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
const convertCountQueryParams = (countQuery) => {
|
|
2522
|
+
return parseType({ type: "boolean", value: countQuery });
|
|
2523
|
+
};
|
|
2524
|
+
const convertOrderingQueryParams = (ordering) => {
|
|
2525
|
+
return ordering;
|
|
2526
|
+
};
|
|
2527
|
+
const isPlainObject = (value2) => _$1.isPlainObject(value2);
|
|
2528
|
+
const isStringArray = (value2) => isArray(value2) && value2.every(isString$1);
|
|
2529
|
+
const convertSortQueryParams = (sortQuery) => {
|
|
2530
|
+
if (typeof sortQuery === "string") {
|
|
2531
|
+
return convertStringSortQueryParam(sortQuery);
|
|
2532
|
+
}
|
|
2533
|
+
if (isStringArray(sortQuery)) {
|
|
2534
|
+
return sortQuery.flatMap((sortValue) => convertStringSortQueryParam(sortValue));
|
|
2535
|
+
}
|
|
2536
|
+
if (Array.isArray(sortQuery)) {
|
|
2537
|
+
return sortQuery.map((sortValue) => convertNestedSortQueryParam(sortValue));
|
|
2538
|
+
}
|
|
2539
|
+
if (isPlainObject(sortQuery)) {
|
|
2540
|
+
return convertNestedSortQueryParam(sortQuery);
|
|
2541
|
+
}
|
|
2542
|
+
throw new InvalidSortError();
|
|
2543
|
+
};
|
|
2544
|
+
const convertStringSortQueryParam = (sortQuery) => {
|
|
2545
|
+
return sortQuery.split(",").map((value2) => convertSingleSortQueryParam(value2));
|
|
2546
|
+
};
|
|
2547
|
+
const convertSingleSortQueryParam = (sortQuery) => {
|
|
2548
|
+
if (!sortQuery) {
|
|
2549
|
+
return {};
|
|
2550
|
+
}
|
|
2551
|
+
if (!isString$1(sortQuery)) {
|
|
2552
|
+
throw new Error("Invalid sort query");
|
|
2553
|
+
}
|
|
2554
|
+
const [field, order = "asc"] = sortQuery.split(":");
|
|
2555
|
+
if (field.length === 0) {
|
|
2556
|
+
throw new Error("Field cannot be empty");
|
|
2557
|
+
}
|
|
2558
|
+
validateOrder(order);
|
|
2559
|
+
return _$1.set({}, field, order);
|
|
2560
|
+
};
|
|
2561
|
+
const convertNestedSortQueryParam = (sortQuery) => {
|
|
2562
|
+
const transformedSort = {};
|
|
2563
|
+
for (const field of Object.keys(sortQuery)) {
|
|
2564
|
+
const order = sortQuery[field];
|
|
2565
|
+
if (isPlainObject(order)) {
|
|
2566
|
+
transformedSort[field] = convertNestedSortQueryParam(order);
|
|
2567
|
+
} else if (typeof order === "string") {
|
|
2568
|
+
validateOrder(order);
|
|
2569
|
+
transformedSort[field] = order;
|
|
2570
|
+
} else {
|
|
2571
|
+
throw Error(`Invalid sort type expected object or string got ${typeof order}`);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
return transformedSort;
|
|
2575
|
+
};
|
|
2576
|
+
const convertStartQueryParams = (startQuery) => {
|
|
2577
|
+
const startAsANumber = _$1.toNumber(startQuery);
|
|
2578
|
+
if (!_$1.isInteger(startAsANumber) || startAsANumber < 0) {
|
|
2579
|
+
throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
|
|
2580
|
+
}
|
|
2581
|
+
return startAsANumber;
|
|
2582
|
+
};
|
|
2583
|
+
const convertLimitQueryParams = (limitQuery) => {
|
|
2584
|
+
const limitAsANumber = _$1.toNumber(limitQuery);
|
|
2585
|
+
if (!_$1.isInteger(limitAsANumber) || limitAsANumber !== -1 && limitAsANumber < 0) {
|
|
2586
|
+
throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
|
|
2587
|
+
}
|
|
2588
|
+
if (limitAsANumber === -1) {
|
|
2589
|
+
return void 0;
|
|
2590
|
+
}
|
|
2591
|
+
return limitAsANumber;
|
|
2592
|
+
};
|
|
2593
|
+
const convertPageQueryParams = (page) => {
|
|
2594
|
+
const pageVal = toNumber(page);
|
|
2595
|
+
if (!isInteger(pageVal) || pageVal <= 0) {
|
|
2596
|
+
throw new PaginationError(
|
|
2597
|
+
`Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
|
|
2598
|
+
);
|
|
2599
|
+
}
|
|
2600
|
+
return pageVal;
|
|
2601
|
+
};
|
|
2602
|
+
const convertPageSizeQueryParams = (pageSize, page) => {
|
|
2603
|
+
const pageSizeVal = toNumber(pageSize);
|
|
2604
|
+
if (!isInteger(pageSizeVal) || pageSizeVal <= 0) {
|
|
2605
|
+
throw new PaginationError(
|
|
2606
|
+
`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
|
|
2607
|
+
);
|
|
2608
|
+
}
|
|
2609
|
+
return pageSizeVal;
|
|
2610
|
+
};
|
|
2611
|
+
const validatePaginationParams = (page, pageSize, start, limit) => {
|
|
2612
|
+
const isPagePagination = !isNil(page) || !isNil(pageSize);
|
|
2613
|
+
const isOffsetPagination = !isNil(start) || !isNil(limit);
|
|
2614
|
+
if (isPagePagination && isOffsetPagination) {
|
|
2615
|
+
throw new PaginationError(
|
|
2616
|
+
"Invalid pagination attributes. You cannot use page and offset pagination in the same query"
|
|
2617
|
+
);
|
|
2618
|
+
}
|
|
2619
|
+
};
|
|
2620
|
+
class InvalidPopulateError extends Error {
|
|
2621
|
+
constructor() {
|
|
2622
|
+
super();
|
|
2623
|
+
this.message = "Invalid populate parameter. Expected a string, an array of strings, a populate object";
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
const convertPopulateQueryParams = (populate2, schema, depth = 0) => {
|
|
2627
|
+
if (depth === 0 && populate2 === "*") {
|
|
2628
|
+
return true;
|
|
2629
|
+
}
|
|
2630
|
+
if (typeof populate2 === "string") {
|
|
2631
|
+
return populate2.split(",").map((value2) => _$1.trim(value2));
|
|
2632
|
+
}
|
|
2633
|
+
if (Array.isArray(populate2)) {
|
|
2634
|
+
return _$1.uniq(
|
|
2635
|
+
populate2.flatMap((value2) => {
|
|
2636
|
+
if (typeof value2 !== "string") {
|
|
2637
|
+
throw new InvalidPopulateError();
|
|
2638
|
+
}
|
|
2639
|
+
return value2.split(",").map((value22) => _$1.trim(value22));
|
|
2640
|
+
})
|
|
2641
|
+
);
|
|
2642
|
+
}
|
|
2643
|
+
if (_$1.isPlainObject(populate2)) {
|
|
2644
|
+
return convertPopulateObject(populate2, schema);
|
|
2645
|
+
}
|
|
2646
|
+
throw new InvalidPopulateError();
|
|
2647
|
+
};
|
|
2648
|
+
const convertPopulateObject = (populate2, schema) => {
|
|
2649
|
+
if (!schema) {
|
|
2650
|
+
return {};
|
|
2651
|
+
}
|
|
2652
|
+
const { attributes } = schema;
|
|
2653
|
+
return Object.entries(populate2).reduce((acc2, [key2, subPopulate]) => {
|
|
2654
|
+
const attribute = attributes[key2];
|
|
2655
|
+
if (!attribute) {
|
|
2656
|
+
return acc2;
|
|
2657
|
+
}
|
|
2658
|
+
const isAllowedAttributeForFragmentPopulate = isDynamicZoneAttribute(attribute) || isMorphToRelationalAttribute(attribute);
|
|
2659
|
+
const hasFragmentPopulateDefined = typeof subPopulate === "object" && "on" in subPopulate && !isNil(subPopulate.on);
|
|
2660
|
+
if (isAllowedAttributeForFragmentPopulate && hasFragmentPopulateDefined) {
|
|
2661
|
+
return {
|
|
2662
|
+
...acc2,
|
|
2663
|
+
[key2]: {
|
|
2664
|
+
on: Object.entries(subPopulate.on).reduce(
|
|
2665
|
+
(acc22, [type, typeSubPopulate]) => ({
|
|
2666
|
+
...acc22,
|
|
2667
|
+
[type]: convertNestedPopulate(typeSubPopulate, strapi.getModel(type))
|
|
2668
|
+
}),
|
|
2669
|
+
{}
|
|
2670
|
+
)
|
|
2671
|
+
}
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
if (isDynamicZoneAttribute(attribute)) {
|
|
2675
|
+
const populates = attribute.components.map((uid) => strapi.getModel(uid)).map((schema2) => convertNestedPopulate(subPopulate, schema2)).map((populate22) => populate22 === true ? {} : populate22).filter((populate22) => populate22 !== false);
|
|
2676
|
+
if (isEmpty(populates)) {
|
|
2677
|
+
return acc2;
|
|
2678
|
+
}
|
|
2679
|
+
return {
|
|
2680
|
+
...acc2,
|
|
2681
|
+
[key2]: mergeAll(populates)
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
if (isMorphToRelationalAttribute(attribute)) {
|
|
2685
|
+
return { ...acc2, [key2]: convertNestedPopulate(subPopulate, void 0) };
|
|
2686
|
+
}
|
|
2687
|
+
let targetSchemaUID;
|
|
2688
|
+
if (attribute.type === "relation") {
|
|
2689
|
+
targetSchemaUID = attribute.target;
|
|
2690
|
+
} else if (attribute.type === "component") {
|
|
2691
|
+
targetSchemaUID = attribute.component;
|
|
2692
|
+
} else if (attribute.type === "media") {
|
|
2693
|
+
targetSchemaUID = "plugin::upload.file";
|
|
2694
|
+
} else {
|
|
2695
|
+
return acc2;
|
|
2696
|
+
}
|
|
2697
|
+
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
2698
|
+
if (!targetSchema) {
|
|
2699
|
+
return acc2;
|
|
2700
|
+
}
|
|
2701
|
+
const populateObject = convertNestedPopulate(subPopulate, targetSchema);
|
|
2702
|
+
if (!populateObject) {
|
|
2703
|
+
return acc2;
|
|
2704
|
+
}
|
|
2705
|
+
return {
|
|
2706
|
+
...acc2,
|
|
2707
|
+
[key2]: populateObject
|
|
2708
|
+
};
|
|
2709
|
+
}, {});
|
|
2710
|
+
};
|
|
2711
|
+
const convertNestedPopulate = (subPopulate, schema) => {
|
|
2712
|
+
if (_$1.isString(subPopulate)) {
|
|
2713
|
+
return parseType({ type: "boolean", value: subPopulate, forceCast: true });
|
|
2714
|
+
}
|
|
2715
|
+
if (_$1.isBoolean(subPopulate)) {
|
|
2716
|
+
return subPopulate;
|
|
2717
|
+
}
|
|
2718
|
+
if (!isPlainObject(subPopulate)) {
|
|
2719
|
+
throw new Error(`Invalid nested populate. Expected '*' or an object`);
|
|
2720
|
+
}
|
|
2721
|
+
const { sort: sort2, filters: filters2, fields: fields2, populate: populate2, count, ordering, page, pageSize, start, limit } = subPopulate;
|
|
2722
|
+
const query = {};
|
|
2723
|
+
if (sort2) {
|
|
2724
|
+
query.orderBy = convertSortQueryParams(sort2);
|
|
2725
|
+
}
|
|
2726
|
+
if (filters2) {
|
|
2727
|
+
query.where = convertFiltersQueryParams(filters2, schema);
|
|
2728
|
+
}
|
|
2729
|
+
if (fields2) {
|
|
2730
|
+
query.select = convertFieldsQueryParams(fields2);
|
|
2731
|
+
}
|
|
2732
|
+
if (populate2) {
|
|
2733
|
+
query.populate = convertPopulateQueryParams(populate2, schema);
|
|
2734
|
+
}
|
|
2735
|
+
if (count) {
|
|
2736
|
+
query.count = convertCountQueryParams(count);
|
|
2737
|
+
}
|
|
2738
|
+
if (ordering) {
|
|
2739
|
+
query.ordering = convertOrderingQueryParams(ordering);
|
|
2740
|
+
}
|
|
2741
|
+
validatePaginationParams(page, pageSize, start, limit);
|
|
2742
|
+
if (!isNil(page)) {
|
|
2743
|
+
query.page = convertPageQueryParams(page);
|
|
2744
|
+
}
|
|
2745
|
+
if (!isNil(pageSize)) {
|
|
2746
|
+
query.pageSize = convertPageSizeQueryParams(pageSize, page);
|
|
2747
|
+
}
|
|
2748
|
+
if (!isNil(start)) {
|
|
2749
|
+
query.offset = convertStartQueryParams(start);
|
|
2750
|
+
}
|
|
2751
|
+
if (!isNil(limit)) {
|
|
2752
|
+
query.limit = convertLimitQueryParams(limit);
|
|
2753
|
+
}
|
|
2754
|
+
convertPublicationStateParams(schema, subPopulate, query);
|
|
2755
|
+
return query;
|
|
2756
|
+
};
|
|
2757
|
+
const convertFieldsQueryParams = (fields2, depth = 0) => {
|
|
2758
|
+
if (depth === 0 && fields2 === "*") {
|
|
2759
|
+
return void 0;
|
|
2760
|
+
}
|
|
2761
|
+
if (typeof fields2 === "string") {
|
|
2762
|
+
const fieldsValues = fields2.split(",").map((value2) => _$1.trim(value2));
|
|
2763
|
+
return _$1.uniq(["id", ...fieldsValues]);
|
|
2764
|
+
}
|
|
2765
|
+
if (isStringArray(fields2)) {
|
|
2766
|
+
const fieldsValues = fields2.flatMap((value2) => convertFieldsQueryParams(value2, depth + 1)).filter((v) => !isNil(v));
|
|
2767
|
+
return _$1.uniq(["id", ...fieldsValues]);
|
|
2768
|
+
}
|
|
2769
|
+
throw new Error("Invalid fields parameter. Expected a string or an array of strings");
|
|
2770
|
+
};
|
|
2771
|
+
const isValidSchemaAttribute = (key2, schema) => {
|
|
2772
|
+
if (key2 === "id") {
|
|
2773
|
+
return true;
|
|
2774
|
+
}
|
|
2775
|
+
if (!schema) {
|
|
2776
|
+
return false;
|
|
2777
|
+
}
|
|
2778
|
+
return Object.keys(schema.attributes).includes(key2);
|
|
2779
|
+
};
|
|
2780
|
+
const convertFiltersQueryParams = (filters2, schema) => {
|
|
2781
|
+
if (!isObject(filters2)) {
|
|
2782
|
+
throw new Error("The filters parameter must be an object or an array");
|
|
2783
|
+
}
|
|
2784
|
+
const filtersCopy = cloneDeep(filters2);
|
|
2785
|
+
return convertAndSanitizeFilters(filtersCopy, schema);
|
|
2786
|
+
};
|
|
2787
|
+
const convertAndSanitizeFilters = (filters2, schema) => {
|
|
2788
|
+
if (Array.isArray(filters2)) {
|
|
2789
|
+
return filters2.map((filter) => convertAndSanitizeFilters(filter, schema)).filter((filter) => !isPlainObject(filter) || !isEmpty(filter));
|
|
2790
|
+
}
|
|
2791
|
+
if (!isPlainObject(filters2)) {
|
|
2792
|
+
return filters2;
|
|
2793
|
+
}
|
|
2794
|
+
const removeOperator = (operator) => delete filters2[operator];
|
|
2795
|
+
for (const [key2, value2] of Object.entries(filters2)) {
|
|
2796
|
+
const attribute = get(key2, schema?.attributes);
|
|
2797
|
+
const validKey = isOperator(key2) || isValidSchemaAttribute(key2, schema);
|
|
2798
|
+
if (!validKey) {
|
|
2799
|
+
removeOperator(key2);
|
|
2800
|
+
} else if (attribute) {
|
|
2801
|
+
if (attribute.type === "relation") {
|
|
2802
|
+
filters2[key2] = convertAndSanitizeFilters(value2, strapi.getModel(attribute.target));
|
|
2803
|
+
} else if (attribute.type === "component") {
|
|
2804
|
+
filters2[key2] = convertAndSanitizeFilters(value2, strapi.getModel(attribute.component));
|
|
2805
|
+
} else if (attribute.type === "media") {
|
|
2806
|
+
filters2[key2] = convertAndSanitizeFilters(value2, strapi.getModel("plugin::upload.file"));
|
|
2807
|
+
} else if (attribute.type === "dynamiczone") {
|
|
2808
|
+
removeOperator(key2);
|
|
2809
|
+
} else if (attribute.type === "password") {
|
|
2810
|
+
removeOperator(key2);
|
|
2811
|
+
} else {
|
|
2812
|
+
filters2[key2] = convertAndSanitizeFilters(value2, schema);
|
|
2813
|
+
}
|
|
2814
|
+
} else if (["$null", "$notNull"].includes(key2)) {
|
|
2815
|
+
filters2[key2] = parseType({ type: "boolean", value: filters2[key2], forceCast: true });
|
|
2816
|
+
} else if (isObject(value2)) {
|
|
2817
|
+
filters2[key2] = convertAndSanitizeFilters(value2, schema);
|
|
2818
|
+
}
|
|
2819
|
+
if (isPlainObject(filters2[key2]) && isEmpty(filters2[key2])) {
|
|
2820
|
+
removeOperator(key2);
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
return filters2;
|
|
2824
|
+
};
|
|
2825
|
+
const convertPublicationStateParams = (schema, params = {}, query = {}) => {
|
|
2826
|
+
if (!schema) {
|
|
2827
|
+
return;
|
|
2828
|
+
}
|
|
2829
|
+
const { publicationState } = params;
|
|
2830
|
+
if (!_$1.isNil(publicationState)) {
|
|
2831
|
+
if (!constants$1.DP_PUB_STATES.includes(publicationState)) {
|
|
2832
|
+
throw new Error(
|
|
2833
|
+
`Invalid publicationState. Expected one of 'preview','live' received: ${publicationState}.`
|
|
2834
|
+
);
|
|
2835
|
+
}
|
|
2836
|
+
query.filters = ({ meta }) => {
|
|
2837
|
+
if (publicationState === "live" && has(PUBLISHED_AT_ATTRIBUTE, meta.attributes)) {
|
|
2838
|
+
return { [PUBLISHED_AT_ATTRIBUTE]: { $notNull: true } };
|
|
2839
|
+
}
|
|
2840
|
+
};
|
|
2841
|
+
}
|
|
2842
|
+
};
|
|
2843
|
+
const transformParamsToQuery = (uid, params) => {
|
|
2844
|
+
const schema = strapi.getModel(uid);
|
|
2845
|
+
const query = {};
|
|
2846
|
+
const { _q, sort: sort2, filters: filters2, fields: fields2, populate: populate2, page, pageSize, start, limit } = params;
|
|
2847
|
+
if (!isNil(_q)) {
|
|
2848
|
+
query._q = _q;
|
|
2849
|
+
}
|
|
2850
|
+
if (!isNil(sort2)) {
|
|
2851
|
+
query.orderBy = convertSortQueryParams(sort2);
|
|
2852
|
+
}
|
|
2853
|
+
if (!isNil(filters2)) {
|
|
2854
|
+
query.where = convertFiltersQueryParams(filters2, schema);
|
|
2855
|
+
}
|
|
2856
|
+
if (!isNil(fields2)) {
|
|
2857
|
+
query.select = convertFieldsQueryParams(fields2);
|
|
2858
|
+
}
|
|
2859
|
+
if (!isNil(populate2)) {
|
|
2860
|
+
query.populate = convertPopulateQueryParams(populate2, schema);
|
|
2861
|
+
}
|
|
2862
|
+
validatePaginationParams(page, pageSize, start, limit);
|
|
2863
|
+
if (!isNil(page)) {
|
|
2864
|
+
query.page = convertPageQueryParams(page);
|
|
2865
|
+
}
|
|
2866
|
+
if (!isNil(pageSize)) {
|
|
2867
|
+
query.pageSize = convertPageSizeQueryParams(pageSize, page);
|
|
2868
|
+
}
|
|
2869
|
+
if (!isNil(start)) {
|
|
2870
|
+
query.offset = convertStartQueryParams(start);
|
|
2871
|
+
}
|
|
2872
|
+
if (!isNil(limit)) {
|
|
2873
|
+
query.limit = convertLimitQueryParams(limit);
|
|
2874
|
+
}
|
|
2875
|
+
convertPublicationStateParams(schema, params, query);
|
|
2876
|
+
return query;
|
|
2877
|
+
};
|
|
2878
|
+
const convertQueryParams = {
|
|
2879
|
+
convertSortQueryParams,
|
|
2880
|
+
convertStartQueryParams,
|
|
2881
|
+
convertLimitQueryParams,
|
|
2882
|
+
convertPopulateQueryParams,
|
|
2883
|
+
convertFiltersQueryParams,
|
|
2884
|
+
convertFieldsQueryParams,
|
|
2885
|
+
convertPublicationStateParams,
|
|
2886
|
+
transformParamsToQuery
|
|
2887
|
+
};
|
|
2888
|
+
function importDefault(modName) {
|
|
2889
|
+
const mod = require(modName);
|
|
2890
|
+
return mod && mod.__esModule ? mod.default : mod;
|
|
2891
|
+
}
|
|
2892
|
+
const createStrictInterpolationRegExp = (allowedVariableNames, flags) => {
|
|
2893
|
+
const oneOfVariables = allowedVariableNames.join("|");
|
|
2894
|
+
return new RegExp(`<%=\\s*(${oneOfVariables})\\s*%>`, flags);
|
|
2895
|
+
};
|
|
2896
|
+
const createLooseInterpolationRegExp = (flags) => new RegExp(/<%=([\s\S]+?)%>/, flags);
|
|
2897
|
+
const template = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2898
|
+
__proto__: null,
|
|
2899
|
+
createLooseInterpolationRegExp,
|
|
2900
|
+
createStrictInterpolationRegExp
|
|
2901
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
2902
|
+
const kbytesToBytes = (kbytes) => kbytes * 1e3;
|
|
2903
|
+
const bytesToKbytes = (bytes) => Math.round(bytes / 1e3 * 100) / 100;
|
|
2904
|
+
const bytesToHumanReadable = (bytes) => {
|
|
2905
|
+
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
|
|
2906
|
+
if (bytes === 0)
|
|
2907
|
+
return "0 Bytes";
|
|
2908
|
+
const i = parseInt(`${Math.floor(Math.log(bytes) / Math.log(1e3))}`, 10);
|
|
2909
|
+
return `${Math.round(bytes / 1e3 ** i)} ${sizes[i]}`;
|
|
2910
|
+
};
|
|
2911
|
+
const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
2912
|
+
const chunks = [];
|
|
2913
|
+
stream.on("data", (chunk) => {
|
|
2914
|
+
chunks.push(chunk);
|
|
2915
|
+
});
|
|
2916
|
+
stream.on("end", () => {
|
|
2917
|
+
resolve(Buffer.concat(chunks));
|
|
2918
|
+
});
|
|
2919
|
+
stream.on("error", reject);
|
|
2920
|
+
});
|
|
2921
|
+
const getStreamSize = (stream) => new Promise((resolve, reject) => {
|
|
2922
|
+
let size = 0;
|
|
2923
|
+
stream.on("data", (chunk) => {
|
|
2924
|
+
size += Buffer.byteLength(chunk);
|
|
2925
|
+
});
|
|
2926
|
+
stream.on("close", () => resolve(size));
|
|
2927
|
+
stream.on("error", reject);
|
|
2928
|
+
stream.resume();
|
|
2929
|
+
});
|
|
2930
|
+
function writableDiscardStream(options) {
|
|
2931
|
+
return new Writable({
|
|
2932
|
+
...options,
|
|
2933
|
+
write(chunk, encding, callback) {
|
|
2934
|
+
setImmediate(callback);
|
|
2935
|
+
}
|
|
2936
|
+
});
|
|
2937
|
+
}
|
|
2938
|
+
const file = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2939
|
+
__proto__: null,
|
|
2940
|
+
bytesToHumanReadable,
|
|
2941
|
+
bytesToKbytes,
|
|
2942
|
+
getStreamSize,
|
|
2943
|
+
kbytesToBytes,
|
|
2944
|
+
streamToBuffer,
|
|
2945
|
+
writableDiscardStream
|
|
2946
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
2947
|
+
const webhookEvents = {
|
|
2948
|
+
ENTRY_CREATE: "entry.create",
|
|
2949
|
+
ENTRY_UPDATE: "entry.update",
|
|
2950
|
+
ENTRY_DELETE: "entry.delete",
|
|
2951
|
+
ENTRY_PUBLISH: "entry.publish",
|
|
2952
|
+
ENTRY_UNPUBLISH: "entry.unpublish",
|
|
2953
|
+
MEDIA_CREATE: "media.create",
|
|
2954
|
+
MEDIA_UPDATE: "media.update",
|
|
2955
|
+
MEDIA_DELETE: "media.delete"
|
|
2956
|
+
};
|
|
2957
|
+
const deprecatedWebhookEvents = new Proxy(webhookEvents, {
|
|
2958
|
+
get(target, prop) {
|
|
2959
|
+
console.warn(
|
|
2960
|
+
"[deprecated] @strapi/utils/webhook will no longer exist in the next major release of Strapi. Instead, the webhookEvents object can be retrieved from strapi.webhookStore.allowedEvents"
|
|
2961
|
+
);
|
|
2962
|
+
return target[prop];
|
|
2963
|
+
}
|
|
2964
|
+
});
|
|
2965
|
+
const webhook = {
|
|
2966
|
+
webhookEvents: deprecatedWebhookEvents
|
|
2967
|
+
};
|
|
2968
|
+
export {
|
|
2969
|
+
contentTypes,
|
|
2970
|
+
convertQueryParams,
|
|
2971
|
+
env,
|
|
2972
|
+
errors,
|
|
2973
|
+
escapeQuery,
|
|
2974
|
+
file,
|
|
2975
|
+
forEachAsync,
|
|
2976
|
+
generateTimestampCode,
|
|
2977
|
+
getAbsoluteAdminUrl,
|
|
2978
|
+
getAbsoluteServerUrl,
|
|
2979
|
+
getCommonBeginning,
|
|
2980
|
+
getConfigUrls,
|
|
2981
|
+
handleYupError,
|
|
2982
|
+
hooks,
|
|
2983
|
+
importDefault,
|
|
2984
|
+
isCamelCase,
|
|
2985
|
+
isKebabCase,
|
|
2986
|
+
isOperator,
|
|
2987
|
+
isOperatorOfType,
|
|
2988
|
+
joinBy,
|
|
2989
|
+
keysDeep,
|
|
2990
|
+
mapAsync,
|
|
2991
|
+
nameToCollectionName,
|
|
2992
|
+
nameToSlug,
|
|
2993
|
+
pagination,
|
|
2994
|
+
parseMultipartData,
|
|
2995
|
+
parseType,
|
|
2996
|
+
pipeAsync,
|
|
2997
|
+
policy,
|
|
2998
|
+
providerFactory,
|
|
2999
|
+
reduceAsync,
|
|
3000
|
+
relations,
|
|
3001
|
+
removeUndefined,
|
|
3002
|
+
index$1 as sanitize,
|
|
3003
|
+
setCreatorFields,
|
|
3004
|
+
startsWithANumber,
|
|
3005
|
+
stringEquals,
|
|
3006
|
+
stringIncludes,
|
|
3007
|
+
template,
|
|
3008
|
+
templateConfiguration,
|
|
3009
|
+
toKebabCase,
|
|
3010
|
+
toRegressedEnumValue,
|
|
3011
|
+
index$2 as traverse,
|
|
3012
|
+
traverseEntity$1 as traverseEntity,
|
|
3013
|
+
index as validate,
|
|
3014
|
+
validateYupSchema,
|
|
3015
|
+
validateYupSchemaSync,
|
|
3016
|
+
webhook,
|
|
3017
|
+
yup
|
|
3018
|
+
};
|
|
3019
|
+
//# sourceMappingURL=index.mjs.map
|