@strapi/utils 5.12.1 → 5.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/async.js +28 -0
- package/dist/async.js.map +1 -0
- package/dist/async.mjs +24 -0
- package/dist/async.mjs.map +1 -0
- package/dist/content-types.js +201 -0
- package/dist/content-types.js.map +1 -0
- package/dist/content-types.mjs +167 -0
- package/dist/content-types.mjs.map +1 -0
- package/dist/convert-query-params.js +512 -0
- package/dist/convert-query-params.js.map +1 -0
- package/dist/convert-query-params.mjs +510 -0
- package/dist/convert-query-params.mjs.map +1 -0
- package/dist/env-helper.js +81 -0
- package/dist/env-helper.js.map +1 -0
- package/dist/env-helper.mjs +79 -0
- package/dist/env-helper.mjs.map +1 -0
- package/dist/errors.js +104 -0
- package/dist/errors.js.map +1 -0
- package/dist/errors.mjs +88 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/file.js +57 -0
- package/dist/file.js.map +1 -0
- package/dist/file.mjs +50 -0
- package/dist/file.mjs.map +1 -0
- package/dist/format-yup-error.js +19 -0
- package/dist/format-yup-error.js.map +1 -0
- package/dist/format-yup-error.mjs +17 -0
- package/dist/format-yup-error.mjs.map +1 -0
- package/dist/hooks.js +86 -0
- package/dist/hooks.js.map +1 -0
- package/dist/hooks.mjs +80 -0
- package/dist/hooks.mjs.map +1 -0
- package/dist/import-default.js +9 -0
- package/dist/import-default.js.map +1 -0
- package/dist/import-default.mjs +7 -0
- package/dist/import-default.mjs.map +1 -0
- package/dist/index.js +54 -4358
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +48 -4317
- package/dist/index.mjs.map +1 -1
- package/dist/machine-id.js +17 -0
- package/dist/machine-id.js.map +1 -0
- package/dist/machine-id.mjs +15 -0
- package/dist/machine-id.mjs.map +1 -0
- package/dist/operators.js +79 -0
- package/dist/operators.js.map +1 -0
- package/dist/operators.mjs +76 -0
- package/dist/operators.mjs.map +1 -0
- package/dist/package-manager.js +36 -0
- package/dist/package-manager.js.map +1 -0
- package/dist/package-manager.mjs +33 -0
- package/dist/package-manager.mjs.map +1 -0
- package/dist/pagination.js +163 -0
- package/dist/pagination.js.map +1 -0
- package/dist/pagination.mjs +159 -0
- package/dist/pagination.mjs.map +1 -0
- package/dist/parse-type.js +140 -0
- package/dist/parse-type.js.map +1 -0
- package/dist/parse-type.mjs +118 -0
- package/dist/parse-type.mjs.map +1 -0
- package/dist/policy.js +33 -0
- package/dist/policy.js.map +1 -0
- package/dist/policy.mjs +30 -0
- package/dist/policy.mjs.map +1 -0
- package/dist/primitives/arrays.js +7 -0
- package/dist/primitives/arrays.js.map +1 -0
- package/dist/primitives/arrays.mjs +5 -0
- package/dist/primitives/arrays.mjs.map +1 -0
- package/dist/primitives/dates.js +11 -0
- package/dist/primitives/dates.js.map +1 -0
- package/dist/primitives/dates.mjs +9 -0
- package/dist/primitives/dates.mjs.map +1 -0
- package/dist/primitives/objects.js +13 -0
- package/dist/primitives/objects.js.map +1 -0
- package/dist/primitives/objects.mjs +11 -0
- package/dist/primitives/objects.mjs.map +1 -0
- package/dist/primitives/strings.js +49 -0
- package/dist/primitives/strings.js.map +1 -0
- package/dist/primitives/strings.mjs +38 -0
- package/dist/primitives/strings.mjs.map +1 -0
- package/dist/print-value.js +42 -0
- package/dist/print-value.js.map +1 -0
- package/dist/print-value.mjs +40 -0
- package/dist/print-value.mjs.map +1 -0
- package/dist/provider-factory.js +82 -0
- package/dist/provider-factory.js.map +1 -0
- package/dist/provider-factory.mjs +80 -0
- package/dist/provider-factory.mjs.map +1 -0
- package/dist/relations.js +54 -0
- package/dist/relations.js.map +1 -0
- package/dist/relations.mjs +45 -0
- package/dist/relations.mjs.map +1 -0
- package/dist/sanitize/index.js +195 -0
- package/dist/sanitize/index.js.map +1 -0
- package/dist/sanitize/index.mjs +194 -0
- package/dist/sanitize/index.mjs.map +1 -0
- package/dist/sanitize/sanitizers.js +173 -0
- package/dist/sanitize/sanitizers.js.map +1 -0
- package/dist/sanitize/sanitizers.mjs +166 -0
- package/dist/sanitize/sanitizers.mjs.map +1 -0
- package/dist/sanitize/visitors/expand-wildcard-populate.js +20 -0
- package/dist/sanitize/visitors/expand-wildcard-populate.js.map +1 -0
- package/dist/sanitize/visitors/expand-wildcard-populate.mjs +18 -0
- package/dist/sanitize/visitors/expand-wildcard-populate.mjs.map +1 -0
- package/dist/sanitize/visitors/index.js +22 -0
- package/dist/sanitize/visitors/index.js.map +1 -0
- package/dist/sanitize/visitors/index.mjs +9 -0
- package/dist/sanitize/visitors/index.mjs.map +1 -0
- package/dist/sanitize/visitors/remove-disallowed-fields.js +87 -0
- package/dist/sanitize/visitors/remove-disallowed-fields.js.map +1 -0
- package/dist/sanitize/visitors/remove-disallowed-fields.mjs +85 -0
- package/dist/sanitize/visitors/remove-disallowed-fields.mjs.map +1 -0
- package/dist/sanitize/visitors/remove-dynamic-zones.js +12 -0
- package/dist/sanitize/visitors/remove-dynamic-zones.js.map +1 -0
- package/dist/sanitize/visitors/remove-dynamic-zones.mjs +10 -0
- package/dist/sanitize/visitors/remove-dynamic-zones.mjs.map +1 -0
- package/dist/sanitize/visitors/remove-morph-to-relations.js +12 -0
- package/dist/sanitize/visitors/remove-morph-to-relations.js.map +1 -0
- package/dist/sanitize/visitors/remove-morph-to-relations.mjs +10 -0
- package/dist/sanitize/visitors/remove-morph-to-relations.mjs.map +1 -0
- package/dist/sanitize/visitors/remove-password.js +10 -0
- package/dist/sanitize/visitors/remove-password.js.map +1 -0
- package/dist/sanitize/visitors/remove-password.mjs +8 -0
- package/dist/sanitize/visitors/remove-password.mjs.map +1 -0
- package/dist/sanitize/visitors/remove-private.js +16 -0
- package/dist/sanitize/visitors/remove-private.js.map +1 -0
- package/dist/sanitize/visitors/remove-private.mjs +14 -0
- package/dist/sanitize/visitors/remove-private.mjs.map +1 -0
- package/dist/sanitize/visitors/remove-restricted-fields.js +28 -0
- package/dist/sanitize/visitors/remove-restricted-fields.js.map +1 -0
- package/dist/sanitize/visitors/remove-restricted-fields.mjs +26 -0
- package/dist/sanitize/visitors/remove-restricted-fields.mjs.map +1 -0
- package/dist/sanitize/visitors/remove-restricted-relations.js +116 -0
- package/dist/sanitize/visitors/remove-restricted-relations.js.map +1 -0
- package/dist/sanitize/visitors/remove-restricted-relations.mjs +114 -0
- package/dist/sanitize/visitors/remove-restricted-relations.mjs.map +1 -0
- package/dist/set-creator-fields.js +18 -0
- package/dist/set-creator-fields.js.map +1 -0
- package/dist/set-creator-fields.mjs +16 -0
- package/dist/set-creator-fields.mjs.map +1 -0
- package/dist/template.js +18 -0
- package/dist/template.js.map +1 -0
- package/dist/template.mjs +15 -0
- package/dist/template.mjs.map +1 -0
- package/dist/traverse/factory.js +158 -0
- package/dist/traverse/factory.js.map +1 -0
- package/dist/traverse/factory.mjs +156 -0
- package/dist/traverse/factory.mjs.map +1 -0
- package/dist/traverse/index.js +14 -0
- package/dist/traverse/index.js.map +1 -0
- package/dist/traverse/index.mjs +5 -0
- package/dist/traverse/index.mjs.map +1 -0
- package/dist/traverse/query-fields.js +41 -0
- package/dist/traverse/query-fields.js.map +1 -0
- package/dist/traverse/query-fields.mjs +39 -0
- package/dist/traverse/query-fields.mjs.map +1 -0
- package/dist/traverse/query-filters.js +114 -0
- package/dist/traverse/query-filters.js.map +1 -0
- package/dist/traverse/query-filters.mjs +112 -0
- package/dist/traverse/query-filters.mjs.map +1 -0
- package/dist/traverse/query-populate.js +280 -0
- package/dist/traverse/query-populate.js.map +1 -0
- package/dist/traverse/query-populate.mjs +278 -0
- package/dist/traverse/query-populate.mjs.map +1 -0
- package/dist/traverse/query-sort.js +144 -0
- package/dist/traverse/query-sort.js.map +1 -0
- package/dist/traverse/query-sort.mjs +142 -0
- package/dist/traverse/query-sort.mjs.map +1 -0
- package/dist/traverse-entity.js +170 -0
- package/dist/traverse-entity.js.map +1 -0
- package/dist/traverse-entity.mjs +168 -0
- package/dist/traverse-entity.mjs.map +1 -0
- package/dist/validate/index.js +218 -0
- package/dist/validate/index.js.map +1 -0
- package/dist/validate/index.mjs +217 -0
- package/dist/validate/index.mjs.map +1 -0
- package/dist/validate/utils.js +27 -0
- package/dist/validate/utils.js.map +1 -0
- package/dist/validate/utils.mjs +24 -0
- package/dist/validate/utils.mjs.map +1 -0
- package/dist/validate/validators.js +369 -0
- package/dist/validate/validators.js.map +1 -0
- package/dist/validate/validators.mjs +356 -0
- package/dist/validate/validators.mjs.map +1 -0
- package/dist/validate/visitors/index.js +22 -0
- package/dist/validate/visitors/index.js.map +1 -0
- package/dist/validate/visitors/index.mjs +9 -0
- package/dist/validate/visitors/index.mjs.map +1 -0
- package/dist/validate/visitors/throw-disallowed-fields.js +91 -0
- package/dist/validate/visitors/throw-disallowed-fields.js.map +1 -0
- package/dist/validate/visitors/throw-disallowed-fields.mjs +89 -0
- package/dist/validate/visitors/throw-disallowed-fields.mjs.map +1 -0
- package/dist/validate/visitors/throw-dynamic-zones.js +16 -0
- package/dist/validate/visitors/throw-dynamic-zones.js.map +1 -0
- package/dist/validate/visitors/throw-dynamic-zones.mjs +14 -0
- package/dist/validate/visitors/throw-dynamic-zones.mjs.map +1 -0
- package/dist/validate/visitors/throw-morph-to-relations.js +16 -0
- package/dist/validate/visitors/throw-morph-to-relations.js.map +1 -0
- package/dist/validate/visitors/throw-morph-to-relations.mjs +14 -0
- package/dist/validate/visitors/throw-morph-to-relations.mjs.map +1 -0
- package/dist/validate/visitors/throw-password.js +15 -0
- package/dist/validate/visitors/throw-password.js.map +1 -0
- package/dist/validate/visitors/throw-password.mjs +13 -0
- package/dist/validate/visitors/throw-password.mjs.map +1 -0
- package/dist/validate/visitors/throw-private.js +20 -0
- package/dist/validate/visitors/throw-private.js.map +1 -0
- package/dist/validate/visitors/throw-private.mjs +18 -0
- package/dist/validate/visitors/throw-private.mjs.map +1 -0
- package/dist/validate/visitors/throw-restricted-fields.js +36 -0
- package/dist/validate/visitors/throw-restricted-fields.js.map +1 -0
- package/dist/validate/visitors/throw-restricted-fields.mjs +34 -0
- package/dist/validate/visitors/throw-restricted-fields.mjs.map +1 -0
- package/dist/validate/visitors/throw-restricted-relations.js +125 -0
- package/dist/validate/visitors/throw-restricted-relations.js.map +1 -0
- package/dist/validate/visitors/throw-restricted-relations.mjs +123 -0
- package/dist/validate/visitors/throw-restricted-relations.mjs.map +1 -0
- package/dist/validate/visitors/throw-unrecognized-fields.js +66 -0
- package/dist/validate/visitors/throw-unrecognized-fields.js.map +1 -0
- package/dist/validate/visitors/throw-unrecognized-fields.mjs +64 -0
- package/dist/validate/visitors/throw-unrecognized-fields.mjs.map +1 -0
- package/dist/validators.js +60 -0
- package/dist/validators.js.map +1 -0
- package/dist/validators.mjs +37 -0
- package/dist/validators.mjs.map +1 -0
- package/dist/yup.js +101 -0
- package/dist/yup.js.map +1 -0
- package/dist/yup.mjs +74 -0
- package/dist/yup.mjs.map +1 -0
- package/dist/zod.js +31 -0
- package/dist/zod.js.map +1 -0
- package/dist/zod.mjs +29 -0
- package/dist/zod.mjs.map +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,4370 +1,66 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
var
|
|
14
|
-
var
|
|
15
|
-
var
|
|
3
|
+
var parseType = require('./parse-type.js');
|
|
4
|
+
var envHelper = require('./env-helper.js');
|
|
5
|
+
var setCreatorFields = require('./set-creator-fields.js');
|
|
6
|
+
var providerFactory = require('./provider-factory.js');
|
|
7
|
+
var traverseEntity = require('./traverse-entity.js');
|
|
8
|
+
var importDefault = require('./import-default.js');
|
|
9
|
+
var machineId = require('./machine-id.js');
|
|
10
|
+
var validators = require('./validators.js');
|
|
11
|
+
var operators = require('./operators.js');
|
|
12
|
+
var convertQueryParams = require('./convert-query-params.js');
|
|
13
|
+
var index = require('./sanitize/index.js');
|
|
14
|
+
var index$1 = require('./validate/index.js');
|
|
15
|
+
var pagination = require('./pagination.js');
|
|
16
|
+
var packageManager = require('./package-manager.js');
|
|
17
|
+
var index$2 = require('./traverse/index.js');
|
|
18
|
+
var template = require('./template.js');
|
|
19
|
+
var file = require('./file.js');
|
|
20
|
+
var async = require('./async.js');
|
|
21
|
+
var policy = require('./policy.js');
|
|
22
|
+
var yup = require('./yup.js');
|
|
23
|
+
var errors = require('./errors.js');
|
|
24
|
+
var contentTypes = require('./content-types.js');
|
|
25
|
+
var relations = require('./relations.js');
|
|
26
|
+
var hooks = require('./hooks.js');
|
|
27
|
+
var zod = require('./zod.js');
|
|
28
|
+
var strings = require('./primitives/strings.js');
|
|
29
|
+
var arrays = require('./primitives/arrays.js');
|
|
30
|
+
var objects = require('./primitives/objects.js');
|
|
31
|
+
var dates = require('./primitives/dates.js');
|
|
16
32
|
|
|
17
|
-
function _interopNamespaceDefault(e) {
|
|
18
|
-
var n = Object.create(null);
|
|
19
|
-
if (e) {
|
|
20
|
-
Object.keys(e).forEach(function (k) {
|
|
21
|
-
if (k !== 'default') {
|
|
22
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
23
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
24
|
-
enumerable: true,
|
|
25
|
-
get: function () { return e[k]; }
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
n.default = e;
|
|
31
|
-
return Object.freeze(n);
|
|
32
|
-
}
|
|
33
33
|
|
|
34
|
-
function _mergeNamespaces(n, m) {
|
|
35
|
-
m.forEach(function (e) {
|
|
36
|
-
e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
|
|
37
|
-
if (k !== 'default' && !(k in n)) {
|
|
38
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
39
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
40
|
-
enumerable: true,
|
|
41
|
-
get: function () { return e[k]; }
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
return Object.freeze(n);
|
|
47
|
-
}
|
|
48
34
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const isDate = (v)=>{
|
|
55
|
-
return dates__namespace.isDate(v);
|
|
56
|
-
};
|
|
57
|
-
const parseTime = (value)=>{
|
|
58
|
-
if (isDate(value)) {
|
|
59
|
-
return dates__namespace.format(value, 'HH:mm:ss.SSS');
|
|
60
|
-
}
|
|
61
|
-
if (typeof value !== 'string') {
|
|
62
|
-
throw new Error(`Expected a string, got a ${typeof value}`);
|
|
63
|
-
}
|
|
64
|
-
const result = value.match(timeRegex);
|
|
65
|
-
if (result === null) {
|
|
66
|
-
throw new Error('Invalid time format, expected HH:mm:ss.SSS');
|
|
67
|
-
}
|
|
68
|
-
const [, hours, minutes, seconds, fraction = '.000'] = result;
|
|
69
|
-
const fractionPart = ___namespace.padEnd(fraction.slice(1), 3, '0');
|
|
70
|
-
return `${hours}:${minutes}:${seconds}.${fractionPart}`;
|
|
71
|
-
};
|
|
72
|
-
const parseDate = (value)=>{
|
|
73
|
-
if (isDate(value)) {
|
|
74
|
-
return dates__namespace.format(value, 'yyyy-MM-dd');
|
|
75
|
-
}
|
|
76
|
-
if (typeof value !== 'string') {
|
|
77
|
-
throw new Error(`Expected a string, got a ${typeof value}`);
|
|
78
|
-
}
|
|
79
|
-
try {
|
|
80
|
-
const date = dates__namespace.parseISO(value);
|
|
81
|
-
if (dates__namespace.isValid(date)) return dates__namespace.format(date, 'yyyy-MM-dd');
|
|
82
|
-
throw new Error(`Invalid format, expected an ISO compatible date`);
|
|
83
|
-
} catch (error) {
|
|
84
|
-
throw new Error(`Invalid format, expected an ISO compatible date`);
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
const parseDateTimeOrTimestamp = (value)=>{
|
|
88
|
-
if (isDate(value)) {
|
|
89
|
-
return value;
|
|
90
|
-
}
|
|
91
|
-
if (typeof value !== 'string') {
|
|
92
|
-
throw new Error(`Expected a string, got a ${typeof value}`);
|
|
93
|
-
}
|
|
94
|
-
try {
|
|
95
|
-
const date = dates__namespace.parseISO(value);
|
|
96
|
-
if (dates__namespace.isValid(date)) return date;
|
|
97
|
-
const milliUnixDate = dates__namespace.parse(value, 'T', new Date());
|
|
98
|
-
if (dates__namespace.isValid(milliUnixDate)) return milliUnixDate;
|
|
99
|
-
throw new Error(`Invalid format, expected a timestamp or an ISO date`);
|
|
100
|
-
} catch (error) {
|
|
101
|
-
throw new Error(`Invalid format, expected a timestamp or an ISO date`);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
const parseBoolean = (value, options)=>{
|
|
105
|
-
const { forceCast = false } = options;
|
|
106
|
-
if (typeof value === 'boolean') {
|
|
107
|
-
return value;
|
|
108
|
-
}
|
|
109
|
-
if (typeof value === 'string' || typeof value === 'number') {
|
|
110
|
-
if ([
|
|
111
|
-
'true',
|
|
112
|
-
't',
|
|
113
|
-
'1',
|
|
114
|
-
1
|
|
115
|
-
].includes(value)) {
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
if ([
|
|
119
|
-
'false',
|
|
120
|
-
'f',
|
|
121
|
-
'0',
|
|
122
|
-
0
|
|
123
|
-
].includes(value)) {
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
if (forceCast) {
|
|
128
|
-
return Boolean(value);
|
|
129
|
-
}
|
|
130
|
-
throw new Error('Invalid boolean input. Expected "t","1","true","false","0","f"');
|
|
131
|
-
};
|
|
132
|
-
/**
|
|
133
|
-
* Cast basic values based on attribute type
|
|
134
|
-
*/ const parseType = (options)=>{
|
|
135
|
-
const { type, value, forceCast } = options;
|
|
136
|
-
switch(type){
|
|
137
|
-
case 'boolean':
|
|
138
|
-
return parseBoolean(value, {
|
|
139
|
-
forceCast
|
|
140
|
-
});
|
|
141
|
-
case 'integer':
|
|
142
|
-
case 'biginteger':
|
|
143
|
-
case 'float':
|
|
144
|
-
case 'decimal':
|
|
145
|
-
{
|
|
146
|
-
return ___namespace.toNumber(value);
|
|
147
|
-
}
|
|
148
|
-
case 'time':
|
|
149
|
-
{
|
|
150
|
-
return parseTime(value);
|
|
151
|
-
}
|
|
152
|
-
case 'date':
|
|
153
|
-
{
|
|
154
|
-
return parseDate(value);
|
|
155
|
-
}
|
|
156
|
-
case 'timestamp':
|
|
157
|
-
case 'datetime':
|
|
158
|
-
{
|
|
159
|
-
return parseDateTimeOrTimestamp(value);
|
|
160
|
-
}
|
|
161
|
-
default:
|
|
162
|
-
return value;
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
function envFn(key, defaultValue) {
|
|
167
|
-
return _.has(process.env, key) ? process.env[key] : defaultValue;
|
|
168
|
-
}
|
|
169
|
-
function getKey(key) {
|
|
170
|
-
return process.env[key] ?? '';
|
|
171
|
-
}
|
|
172
|
-
const utils = {
|
|
173
|
-
int (key, defaultValue) {
|
|
174
|
-
if (!_.has(process.env, key)) {
|
|
175
|
-
return defaultValue;
|
|
176
|
-
}
|
|
177
|
-
return parseInt(getKey(key), 10);
|
|
178
|
-
},
|
|
179
|
-
float (key, defaultValue) {
|
|
180
|
-
if (!_.has(process.env, key)) {
|
|
181
|
-
return defaultValue;
|
|
182
|
-
}
|
|
183
|
-
return parseFloat(getKey(key));
|
|
184
|
-
},
|
|
185
|
-
bool (key, defaultValue) {
|
|
186
|
-
if (!_.has(process.env, key)) {
|
|
187
|
-
return defaultValue;
|
|
188
|
-
}
|
|
189
|
-
return getKey(key) === 'true';
|
|
190
|
-
},
|
|
191
|
-
json (key, defaultValue) {
|
|
192
|
-
if (!_.has(process.env, key)) {
|
|
193
|
-
return defaultValue;
|
|
194
|
-
}
|
|
195
|
-
try {
|
|
196
|
-
return JSON.parse(getKey(key));
|
|
197
|
-
} catch (error) {
|
|
198
|
-
if (error instanceof Error) {
|
|
199
|
-
throw new Error(`Invalid json environment variable ${key}: ${error.message}`);
|
|
200
|
-
}
|
|
201
|
-
throw error;
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
array (key, defaultValue) {
|
|
205
|
-
if (!_.has(process.env, key)) {
|
|
206
|
-
return defaultValue;
|
|
207
|
-
}
|
|
208
|
-
let value = getKey(key);
|
|
209
|
-
if (value.startsWith('[') && value.endsWith(']')) {
|
|
210
|
-
value = value.substring(1, value.length - 1);
|
|
211
|
-
}
|
|
212
|
-
return value.split(',').map((v)=>{
|
|
213
|
-
return _.trim(_.trim(v, ' '), '"');
|
|
214
|
-
});
|
|
215
|
-
},
|
|
216
|
-
date (key, defaultValue) {
|
|
217
|
-
if (!_.has(process.env, key)) {
|
|
218
|
-
return defaultValue;
|
|
219
|
-
}
|
|
220
|
-
return new Date(getKey(key));
|
|
221
|
-
},
|
|
222
|
-
/**
|
|
223
|
-
* Gets a value from env that matches oneOf provided values
|
|
224
|
-
* @param {string} key
|
|
225
|
-
* @param {string[]} expectedValues
|
|
226
|
-
* @param {string|undefined} defaultValue
|
|
227
|
-
* @returns {string|undefined}
|
|
228
|
-
*/ oneOf (key, expectedValues, defaultValue) {
|
|
229
|
-
if (!expectedValues) {
|
|
230
|
-
throw new Error(`env.oneOf requires expectedValues`);
|
|
231
|
-
}
|
|
232
|
-
if (defaultValue && !expectedValues.includes(defaultValue)) {
|
|
233
|
-
throw new Error(`env.oneOf requires defaultValue to be included in expectedValues`);
|
|
234
|
-
}
|
|
235
|
-
const rawValue = env(key, defaultValue);
|
|
236
|
-
return expectedValues.includes(rawValue) ? rawValue : defaultValue;
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
const env = Object.assign(envFn, utils);
|
|
240
|
-
|
|
241
|
-
const SINGLE_TYPE = 'singleType';
|
|
242
|
-
const COLLECTION_TYPE = 'collectionType';
|
|
243
|
-
const ID_ATTRIBUTE$4 = 'id';
|
|
244
|
-
const DOC_ID_ATTRIBUTE$4 = 'documentId';
|
|
245
|
-
const PUBLISHED_AT_ATTRIBUTE$1 = 'publishedAt';
|
|
246
|
-
const CREATED_BY_ATTRIBUTE$3 = 'createdBy';
|
|
247
|
-
const UPDATED_BY_ATTRIBUTE$3 = 'updatedBy';
|
|
248
|
-
const CREATED_AT_ATTRIBUTE = 'createdAt';
|
|
249
|
-
const UPDATED_AT_ATTRIBUTE = 'updatedAt';
|
|
250
|
-
const constants$1 = {
|
|
251
|
-
ID_ATTRIBUTE: ID_ATTRIBUTE$4,
|
|
252
|
-
DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$4,
|
|
253
|
-
PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1,
|
|
254
|
-
CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$3,
|
|
255
|
-
UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$3,
|
|
256
|
-
CREATED_AT_ATTRIBUTE,
|
|
257
|
-
UPDATED_AT_ATTRIBUTE,
|
|
258
|
-
SINGLE_TYPE,
|
|
259
|
-
COLLECTION_TYPE
|
|
260
|
-
};
|
|
261
|
-
const getTimestamps = (model)=>{
|
|
262
|
-
const attributes = [];
|
|
263
|
-
if (fp.has(CREATED_AT_ATTRIBUTE, model.attributes)) {
|
|
264
|
-
attributes.push(CREATED_AT_ATTRIBUTE);
|
|
265
|
-
}
|
|
266
|
-
if (fp.has(UPDATED_AT_ATTRIBUTE, model.attributes)) {
|
|
267
|
-
attributes.push(UPDATED_AT_ATTRIBUTE);
|
|
268
|
-
}
|
|
269
|
-
return attributes;
|
|
270
|
-
};
|
|
271
|
-
const getCreatorFields = (model)=>{
|
|
272
|
-
const attributes = [];
|
|
273
|
-
if (fp.has(CREATED_BY_ATTRIBUTE$3, model.attributes)) {
|
|
274
|
-
attributes.push(CREATED_BY_ATTRIBUTE$3);
|
|
275
|
-
}
|
|
276
|
-
if (fp.has(UPDATED_BY_ATTRIBUTE$3, model.attributes)) {
|
|
277
|
-
attributes.push(UPDATED_BY_ATTRIBUTE$3);
|
|
278
|
-
}
|
|
279
|
-
return attributes;
|
|
280
|
-
};
|
|
281
|
-
const getNonWritableAttributes = (model)=>{
|
|
282
|
-
if (!model) return [];
|
|
283
|
-
const nonWritableAttributes = _.reduce(model.attributes, (acc, attr, attrName)=>attr.writable === false ? acc.concat(attrName) : acc, []);
|
|
284
|
-
return _.uniq([
|
|
285
|
-
ID_ATTRIBUTE$4,
|
|
286
|
-
DOC_ID_ATTRIBUTE$4,
|
|
287
|
-
...getTimestamps(model),
|
|
288
|
-
...nonWritableAttributes
|
|
289
|
-
]);
|
|
290
|
-
};
|
|
291
|
-
const getWritableAttributes = (model)=>{
|
|
292
|
-
if (!model) return [];
|
|
293
|
-
return _.difference(Object.keys(model.attributes), getNonWritableAttributes(model));
|
|
294
|
-
};
|
|
295
|
-
const isWritableAttribute = (model, attributeName)=>{
|
|
296
|
-
return getWritableAttributes(model).includes(attributeName);
|
|
297
|
-
};
|
|
298
|
-
const getNonVisibleAttributes = (model)=>{
|
|
299
|
-
const nonVisibleAttributes = _.reduce(model.attributes, (acc, attr, attrName)=>attr.visible === false ? acc.concat(attrName) : acc, []);
|
|
300
|
-
return _.uniq([
|
|
301
|
-
ID_ATTRIBUTE$4,
|
|
302
|
-
DOC_ID_ATTRIBUTE$4,
|
|
303
|
-
...getTimestamps(model),
|
|
304
|
-
...nonVisibleAttributes
|
|
305
|
-
]);
|
|
306
|
-
};
|
|
307
|
-
const getVisibleAttributes = (model)=>{
|
|
308
|
-
return _.difference(_.keys(model.attributes), getNonVisibleAttributes(model));
|
|
309
|
-
};
|
|
310
|
-
const isVisibleAttribute = (model, attributeName)=>{
|
|
311
|
-
return getVisibleAttributes(model).includes(attributeName);
|
|
312
|
-
};
|
|
313
|
-
const getOptions = (model)=>_.assign({
|
|
314
|
-
draftAndPublish: false
|
|
315
|
-
}, _.get(model, 'options', {}));
|
|
316
|
-
const hasDraftAndPublish = (model)=>_.get(model, 'options.draftAndPublish', false) === true;
|
|
317
|
-
const isDraft = (data, model)=>hasDraftAndPublish(model) && _.get(data, PUBLISHED_AT_ATTRIBUTE$1) === null;
|
|
318
|
-
const isSchema = (data)=>{
|
|
319
|
-
return typeof data === 'object' && data !== null && 'modelType' in data && typeof data.modelType === 'string' && [
|
|
320
|
-
'component',
|
|
321
|
-
'contentType'
|
|
322
|
-
].includes(data.modelType);
|
|
323
|
-
};
|
|
324
|
-
const isComponentSchema = (data)=>{
|
|
325
|
-
return isSchema(data) && data.modelType === 'component';
|
|
326
|
-
};
|
|
327
|
-
const isContentTypeSchema = (data)=>{
|
|
328
|
-
return isSchema(data) && data.modelType === 'contentType';
|
|
329
|
-
};
|
|
330
|
-
const isSingleType = ({ kind = COLLECTION_TYPE })=>kind === SINGLE_TYPE;
|
|
331
|
-
const isCollectionType = ({ kind = COLLECTION_TYPE })=>kind === COLLECTION_TYPE;
|
|
332
|
-
const isKind = (kind)=>(model)=>model.kind === kind;
|
|
333
|
-
const getStoredPrivateAttributes = (model)=>fp.union(strapi?.config?.get('api.responses.privateAttributes', []) ?? [], fp.getOr([], 'options.privateAttributes', model));
|
|
334
|
-
const getPrivateAttributes = (model)=>{
|
|
335
|
-
return _.union(getStoredPrivateAttributes(model), _.keys(_.pickBy(model.attributes, (attr)=>!!attr.private)));
|
|
336
|
-
};
|
|
337
|
-
const isPrivateAttribute = (model, attributeName)=>{
|
|
338
|
-
if (model?.attributes?.[attributeName]?.private === true) {
|
|
339
|
-
return true;
|
|
340
|
-
}
|
|
341
|
-
return getStoredPrivateAttributes(model).includes(attributeName);
|
|
342
|
-
};
|
|
343
|
-
const isScalarAttribute = (attribute)=>{
|
|
344
|
-
return attribute && ![
|
|
345
|
-
'media',
|
|
346
|
-
'component',
|
|
347
|
-
'relation',
|
|
348
|
-
'dynamiczone'
|
|
349
|
-
].includes(attribute.type);
|
|
350
|
-
};
|
|
351
|
-
const getDoesAttributeRequireValidation = (attribute)=>{
|
|
352
|
-
return attribute.required || attribute.unique || Object.prototype.hasOwnProperty.call(attribute, 'max') || Object.prototype.hasOwnProperty.call(attribute, 'min') || Object.prototype.hasOwnProperty.call(attribute, 'maxLength') || Object.prototype.hasOwnProperty.call(attribute, 'minLength');
|
|
353
|
-
};
|
|
354
|
-
const isMediaAttribute = (attribute)=>attribute?.type === 'media';
|
|
355
|
-
const isRelationalAttribute = (attribute)=>attribute?.type === 'relation';
|
|
356
|
-
const HAS_RELATION_REORDERING = [
|
|
357
|
-
'manyToMany',
|
|
358
|
-
'manyToOne',
|
|
359
|
-
'oneToMany'
|
|
360
|
-
];
|
|
361
|
-
const hasRelationReordering = (attribute)=>isRelationalAttribute(attribute) && HAS_RELATION_REORDERING.includes(attribute.relation);
|
|
362
|
-
const isComponentAttribute = (attribute)=>[
|
|
363
|
-
'component',
|
|
364
|
-
'dynamiczone'
|
|
365
|
-
].includes(attribute?.type);
|
|
366
|
-
const isDynamicZoneAttribute = (attribute)=>!!attribute && attribute.type === 'dynamiczone';
|
|
367
|
-
const isMorphToRelationalAttribute = (attribute)=>{
|
|
368
|
-
return !!attribute && isRelationalAttribute(attribute) && attribute.relation?.startsWith?.('morphTo');
|
|
369
|
-
};
|
|
370
|
-
const getComponentAttributes = (schema)=>{
|
|
371
|
-
return _.reduce(schema.attributes, (acc, attr, attrName)=>{
|
|
372
|
-
if (isComponentAttribute(attr)) acc.push(attrName);
|
|
373
|
-
return acc;
|
|
374
|
-
}, []);
|
|
375
|
-
};
|
|
376
|
-
const getScalarAttributes = (schema)=>{
|
|
377
|
-
return _.reduce(schema.attributes, (acc, attr, attrName)=>{
|
|
378
|
-
if (isScalarAttribute(attr)) acc.push(attrName);
|
|
379
|
-
return acc;
|
|
380
|
-
}, []);
|
|
381
|
-
};
|
|
382
|
-
const getRelationalAttributes = (schema)=>{
|
|
383
|
-
return _.reduce(schema.attributes, (acc, attr, attrName)=>{
|
|
384
|
-
if (isRelationalAttribute(attr)) acc.push(attrName);
|
|
385
|
-
return acc;
|
|
386
|
-
}, []);
|
|
387
|
-
};
|
|
388
|
-
/**
|
|
389
|
-
* Checks if an attribute is of type `type`
|
|
390
|
-
* @param {object} attribute
|
|
391
|
-
* @param {string} type
|
|
392
|
-
*/ const isTypedAttribute = (attribute, type)=>{
|
|
393
|
-
return _.has(attribute, 'type') && attribute.type === type;
|
|
394
|
-
};
|
|
395
|
-
/**
|
|
396
|
-
* Returns a route prefix for a contentType
|
|
397
|
-
* @param {object} contentType
|
|
398
|
-
* @returns {string}
|
|
399
|
-
*/ const getContentTypeRoutePrefix = (contentType)=>{
|
|
400
|
-
return isSingleType(contentType) ? _.kebabCase(contentType.info.singularName) : _.kebabCase(contentType.info.pluralName);
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
var contentTypes = /*#__PURE__*/Object.freeze({
|
|
404
|
-
__proto__: null,
|
|
405
|
-
constants: constants$1,
|
|
406
|
-
getComponentAttributes: getComponentAttributes,
|
|
407
|
-
getContentTypeRoutePrefix: getContentTypeRoutePrefix,
|
|
408
|
-
getCreatorFields: getCreatorFields,
|
|
409
|
-
getDoesAttributeRequireValidation: getDoesAttributeRequireValidation,
|
|
410
|
-
getNonVisibleAttributes: getNonVisibleAttributes,
|
|
411
|
-
getNonWritableAttributes: getNonWritableAttributes,
|
|
412
|
-
getOptions: getOptions,
|
|
413
|
-
getPrivateAttributes: getPrivateAttributes,
|
|
414
|
-
getRelationalAttributes: getRelationalAttributes,
|
|
415
|
-
getScalarAttributes: getScalarAttributes,
|
|
416
|
-
getTimestamps: getTimestamps,
|
|
417
|
-
getVisibleAttributes: getVisibleAttributes,
|
|
418
|
-
getWritableAttributes: getWritableAttributes,
|
|
419
|
-
hasDraftAndPublish: hasDraftAndPublish,
|
|
420
|
-
hasRelationReordering: hasRelationReordering,
|
|
421
|
-
isCollectionType: isCollectionType,
|
|
422
|
-
isComponentAttribute: isComponentAttribute,
|
|
423
|
-
isComponentSchema: isComponentSchema,
|
|
424
|
-
isContentTypeSchema: isContentTypeSchema,
|
|
425
|
-
isDraft: isDraft,
|
|
426
|
-
isDynamicZoneAttribute: isDynamicZoneAttribute,
|
|
427
|
-
isKind: isKind,
|
|
428
|
-
isMediaAttribute: isMediaAttribute,
|
|
429
|
-
isMorphToRelationalAttribute: isMorphToRelationalAttribute,
|
|
430
|
-
isPrivateAttribute: isPrivateAttribute,
|
|
431
|
-
isRelationalAttribute: isRelationalAttribute,
|
|
432
|
-
isScalarAttribute: isScalarAttribute,
|
|
433
|
-
isSchema: isSchema,
|
|
434
|
-
isSingleType: isSingleType,
|
|
435
|
-
isTypedAttribute: isTypedAttribute,
|
|
436
|
-
isVisibleAttribute: isVisibleAttribute,
|
|
437
|
-
isWritableAttribute: isWritableAttribute
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$2, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$2 } = constants$1;
|
|
441
|
-
const setCreatorFields = ({ user, isEdition = false })=>(data)=>{
|
|
442
|
-
if (isEdition) {
|
|
443
|
-
return fp.assoc(UPDATED_BY_ATTRIBUTE$2, user.id, data);
|
|
444
|
-
}
|
|
445
|
-
return fp.assign(data, {
|
|
446
|
-
[CREATED_BY_ATTRIBUTE$2]: user.id,
|
|
447
|
-
[UPDATED_BY_ATTRIBUTE$2]: user.id
|
|
448
|
-
});
|
|
449
|
-
};
|
|
450
|
-
|
|
451
|
-
/**
|
|
452
|
-
* Create a default Strapi hook
|
|
453
|
-
*/ const createHook = ()=>{
|
|
454
|
-
const state = {
|
|
455
|
-
handlers: []
|
|
456
|
-
};
|
|
457
|
-
return {
|
|
458
|
-
getHandlers () {
|
|
459
|
-
return state.handlers;
|
|
460
|
-
},
|
|
461
|
-
register (handler) {
|
|
462
|
-
state.handlers.push(handler);
|
|
463
|
-
return this;
|
|
464
|
-
},
|
|
465
|
-
delete (handler) {
|
|
466
|
-
state.handlers = fp.remove(fp.eq(handler), state.handlers);
|
|
467
|
-
return this;
|
|
468
|
-
},
|
|
469
|
-
call () {
|
|
470
|
-
throw new Error('Method not implemented');
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
};
|
|
474
|
-
/**
|
|
475
|
-
* Create an async series hook.
|
|
476
|
-
* Upon execution, it will execute every handler in order with the same context
|
|
477
|
-
*/ const createAsyncSeriesHook = ()=>({
|
|
478
|
-
...createHook(),
|
|
479
|
-
async call (context) {
|
|
480
|
-
for (const handler of this.getHandlers()){
|
|
481
|
-
await handler(context);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
});
|
|
485
|
-
/**
|
|
486
|
-
* Create an async series waterfall hook.
|
|
487
|
-
* Upon execution, it will execute every handler in order and pass the return value of the last handler to the next one
|
|
488
|
-
*/ const createAsyncSeriesWaterfallHook = ()=>({
|
|
489
|
-
...createHook(),
|
|
490
|
-
async call (param) {
|
|
491
|
-
let res = param;
|
|
492
|
-
for (const handler of this.getHandlers()){
|
|
493
|
-
res = await handler(res);
|
|
494
|
-
}
|
|
495
|
-
return res;
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
/**
|
|
499
|
-
* Create an async parallel hook.
|
|
500
|
-
* Upon execution, it will execute every registered handler in band.
|
|
501
|
-
*/ const createAsyncParallelHook = ()=>({
|
|
502
|
-
...createHook(),
|
|
503
|
-
async call (context) {
|
|
504
|
-
const promises = this.getHandlers().map((handler)=>handler(fp.cloneDeep(context)));
|
|
505
|
-
return Promise.all(promises);
|
|
506
|
-
}
|
|
507
|
-
});
|
|
508
|
-
/**
|
|
509
|
-
* Create an async parallel hook.
|
|
510
|
-
* Upon execution, it will execute every registered handler in serie and return the first result found.
|
|
511
|
-
*/ const createAsyncBailHook = ()=>({
|
|
512
|
-
...createHook(),
|
|
513
|
-
async call (context) {
|
|
514
|
-
for (const handler of this.getHandlers()){
|
|
515
|
-
const result = await handler(context);
|
|
516
|
-
if (result !== undefined) {
|
|
517
|
-
return result;
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
});
|
|
522
|
-
const internals = {
|
|
523
|
-
// Internal utils
|
|
524
|
-
createHook
|
|
525
|
-
};
|
|
526
|
-
|
|
527
|
-
var hooks = /*#__PURE__*/Object.freeze({
|
|
528
|
-
__proto__: null,
|
|
529
|
-
createAsyncBailHook: createAsyncBailHook,
|
|
530
|
-
createAsyncParallelHook: createAsyncParallelHook,
|
|
531
|
-
createAsyncSeriesHook: createAsyncSeriesHook,
|
|
532
|
-
createAsyncSeriesWaterfallHook: createAsyncSeriesWaterfallHook,
|
|
533
|
-
internals: internals
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
/**
|
|
537
|
-
* Creates a new object containing various hooks used by the providers
|
|
538
|
-
*/ const createProviderHooksMap = ()=>({
|
|
539
|
-
// Register events
|
|
540
|
-
willRegister: createAsyncSeriesHook(),
|
|
541
|
-
didRegister: createAsyncParallelHook(),
|
|
542
|
-
// Delete events
|
|
543
|
-
willDelete: createAsyncParallelHook(),
|
|
544
|
-
didDelete: createAsyncParallelHook()
|
|
545
|
-
});
|
|
546
|
-
/**
|
|
547
|
-
* A Provider factory
|
|
548
|
-
*/ const providerFactory = (options = {})=>{
|
|
549
|
-
const { throwOnDuplicates = true } = options;
|
|
550
|
-
const state = {
|
|
551
|
-
hooks: createProviderHooksMap(),
|
|
552
|
-
registry: new Map()
|
|
553
|
-
};
|
|
554
|
-
return {
|
|
555
|
-
hooks: state.hooks,
|
|
556
|
-
async register (key, item) {
|
|
557
|
-
if (throwOnDuplicates && this.has(key)) {
|
|
558
|
-
throw new Error(`Duplicated item key: ${key}`);
|
|
559
|
-
}
|
|
560
|
-
await state.hooks.willRegister.call({
|
|
561
|
-
key,
|
|
562
|
-
value: item
|
|
563
|
-
});
|
|
564
|
-
state.registry.set(key, item);
|
|
565
|
-
await state.hooks.didRegister.call({
|
|
566
|
-
key,
|
|
567
|
-
value: fp.cloneDeep(item)
|
|
568
|
-
});
|
|
569
|
-
return this;
|
|
570
|
-
},
|
|
571
|
-
async delete (key) {
|
|
572
|
-
if (this.has(key)) {
|
|
573
|
-
const item = this.get(key);
|
|
574
|
-
await state.hooks.willDelete.call({
|
|
575
|
-
key,
|
|
576
|
-
value: fp.cloneDeep(item)
|
|
577
|
-
});
|
|
578
|
-
state.registry.delete(key);
|
|
579
|
-
await state.hooks.didDelete.call({
|
|
580
|
-
key,
|
|
581
|
-
value: fp.cloneDeep(item)
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
return this;
|
|
585
|
-
},
|
|
586
|
-
get (key) {
|
|
587
|
-
return state.registry.get(key);
|
|
588
|
-
},
|
|
589
|
-
values () {
|
|
590
|
-
return Array.from(state.registry.values());
|
|
591
|
-
},
|
|
592
|
-
keys () {
|
|
593
|
-
return Array.from(state.registry.keys());
|
|
594
|
-
},
|
|
595
|
-
has (key) {
|
|
596
|
-
return state.registry.has(key);
|
|
597
|
-
},
|
|
598
|
-
size () {
|
|
599
|
-
return state.registry.size;
|
|
600
|
-
},
|
|
601
|
-
async clear () {
|
|
602
|
-
const keys = this.keys();
|
|
603
|
-
for (const key of keys){
|
|
604
|
-
await this.delete(key);
|
|
605
|
-
}
|
|
606
|
-
return this;
|
|
607
|
-
}
|
|
608
|
-
};
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
const traverseEntity = async (visitor, options, entity)=>{
|
|
612
|
-
const { path = {
|
|
613
|
-
raw: null,
|
|
614
|
-
attribute: null
|
|
615
|
-
}, schema, getModel } = options;
|
|
616
|
-
let parent = options.parent;
|
|
617
|
-
const traverseMorphRelationTarget = async (visitor, path, entry)=>{
|
|
618
|
-
const targetSchema = getModel(entry.__type);
|
|
619
|
-
const traverseOptions = {
|
|
620
|
-
schema: targetSchema,
|
|
621
|
-
path,
|
|
622
|
-
getModel,
|
|
623
|
-
parent
|
|
624
|
-
};
|
|
625
|
-
return traverseEntity(visitor, traverseOptions, entry);
|
|
626
|
-
};
|
|
627
|
-
const traverseRelationTarget = (schema)=>async (visitor, path, entry)=>{
|
|
628
|
-
const traverseOptions = {
|
|
629
|
-
schema,
|
|
630
|
-
path,
|
|
631
|
-
getModel,
|
|
632
|
-
parent
|
|
633
|
-
};
|
|
634
|
-
return traverseEntity(visitor, traverseOptions, entry);
|
|
635
|
-
};
|
|
636
|
-
const traverseMediaTarget = async (visitor, path, entry)=>{
|
|
637
|
-
const targetSchemaUID = 'plugin::upload.file';
|
|
638
|
-
const targetSchema = getModel(targetSchemaUID);
|
|
639
|
-
const traverseOptions = {
|
|
640
|
-
schema: targetSchema,
|
|
641
|
-
path,
|
|
642
|
-
getModel,
|
|
643
|
-
parent
|
|
644
|
-
};
|
|
645
|
-
return traverseEntity(visitor, traverseOptions, entry);
|
|
646
|
-
};
|
|
647
|
-
const traverseComponent = async (visitor, path, schema, entry)=>{
|
|
648
|
-
const traverseOptions = {
|
|
649
|
-
schema,
|
|
650
|
-
path,
|
|
651
|
-
getModel,
|
|
652
|
-
parent
|
|
653
|
-
};
|
|
654
|
-
return traverseEntity(visitor, traverseOptions, entry);
|
|
655
|
-
};
|
|
656
|
-
const visitDynamicZoneEntry = async (visitor, path, entry)=>{
|
|
657
|
-
const targetSchema = getModel(entry.__component);
|
|
658
|
-
const traverseOptions = {
|
|
659
|
-
schema: targetSchema,
|
|
660
|
-
path,
|
|
661
|
-
getModel,
|
|
662
|
-
parent
|
|
663
|
-
};
|
|
664
|
-
return traverseEntity(visitor, traverseOptions, entry);
|
|
665
|
-
};
|
|
666
|
-
// End recursion
|
|
667
|
-
if (!fp.isObject(entity) || fp.isNil(schema)) {
|
|
668
|
-
return entity;
|
|
669
|
-
}
|
|
670
|
-
// Don't mutate the original entity object
|
|
671
|
-
// only clone at 1st level as the next level will get clone when traversed
|
|
672
|
-
const copy = fp.clone(entity);
|
|
673
|
-
const visitorUtils = createVisitorUtils({
|
|
674
|
-
data: copy
|
|
675
|
-
});
|
|
676
|
-
const keys = Object.keys(copy);
|
|
677
|
-
for(let i = 0; i < keys.length; i += 1){
|
|
678
|
-
const key = keys[i];
|
|
679
|
-
// Retrieve the attribute definition associated to the key from the schema
|
|
680
|
-
const attribute = schema.attributes[key];
|
|
681
|
-
const newPath = {
|
|
682
|
-
...path
|
|
683
|
-
};
|
|
684
|
-
newPath.raw = fp.isNil(path.raw) ? key : `${path.raw}.${key}`;
|
|
685
|
-
if (!fp.isNil(attribute)) {
|
|
686
|
-
newPath.attribute = fp.isNil(path.attribute) ? key : `${path.attribute}.${key}`;
|
|
687
|
-
}
|
|
688
|
-
// Visit the current attribute
|
|
689
|
-
const visitorOptions = {
|
|
690
|
-
data: copy,
|
|
691
|
-
schema,
|
|
692
|
-
key,
|
|
693
|
-
value: copy[key],
|
|
694
|
-
attribute,
|
|
695
|
-
path: newPath,
|
|
696
|
-
getModel,
|
|
697
|
-
parent
|
|
698
|
-
};
|
|
699
|
-
await visitor(visitorOptions, visitorUtils);
|
|
700
|
-
// Extract the value for the current key (after calling the visitor)
|
|
701
|
-
const value = copy[key];
|
|
702
|
-
// Ignore Nil values or attributes
|
|
703
|
-
if (fp.isNil(value) || fp.isNil(attribute)) {
|
|
704
|
-
continue;
|
|
705
|
-
}
|
|
706
|
-
// The current attribute becomes the parent once visited
|
|
707
|
-
parent = {
|
|
708
|
-
schema,
|
|
709
|
-
key,
|
|
710
|
-
attribute,
|
|
711
|
-
path: newPath
|
|
712
|
-
};
|
|
713
|
-
if (isRelationalAttribute(attribute)) {
|
|
714
|
-
const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');
|
|
715
|
-
const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
|
|
716
|
-
if (fp.isArray(value)) {
|
|
717
|
-
const res = new Array(value.length);
|
|
718
|
-
for(let i = 0; i < value.length; i += 1){
|
|
719
|
-
res[i] = await method(visitor, newPath, value[i]);
|
|
720
|
-
}
|
|
721
|
-
copy[key] = res;
|
|
722
|
-
} else {
|
|
723
|
-
copy[key] = await method(visitor, newPath, value);
|
|
724
|
-
}
|
|
725
|
-
continue;
|
|
726
|
-
}
|
|
727
|
-
if (isMediaAttribute(attribute)) {
|
|
728
|
-
// need to update copy
|
|
729
|
-
if (fp.isArray(value)) {
|
|
730
|
-
const res = new Array(value.length);
|
|
731
|
-
for(let i = 0; i < value.length; i += 1){
|
|
732
|
-
res[i] = await traverseMediaTarget(visitor, newPath, value[i]);
|
|
733
|
-
}
|
|
734
|
-
copy[key] = res;
|
|
735
|
-
} else {
|
|
736
|
-
copy[key] = await traverseMediaTarget(visitor, newPath, value);
|
|
737
|
-
}
|
|
738
|
-
continue;
|
|
739
|
-
}
|
|
740
|
-
if (attribute.type === 'component') {
|
|
741
|
-
const targetSchema = getModel(attribute.component);
|
|
742
|
-
if (fp.isArray(value)) {
|
|
743
|
-
const res = new Array(value.length);
|
|
744
|
-
for(let i = 0; i < value.length; i += 1){
|
|
745
|
-
res[i] = await traverseComponent(visitor, newPath, targetSchema, value[i]);
|
|
746
|
-
}
|
|
747
|
-
copy[key] = res;
|
|
748
|
-
} else {
|
|
749
|
-
copy[key] = await traverseComponent(visitor, newPath, targetSchema, value);
|
|
750
|
-
}
|
|
751
|
-
continue;
|
|
752
|
-
}
|
|
753
|
-
if (attribute.type === 'dynamiczone' && fp.isArray(value)) {
|
|
754
|
-
const res = new Array(value.length);
|
|
755
|
-
for(let i = 0; i < value.length; i += 1){
|
|
756
|
-
res[i] = await visitDynamicZoneEntry(visitor, newPath, value[i]);
|
|
757
|
-
}
|
|
758
|
-
copy[key] = res;
|
|
759
|
-
continue;
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
return copy;
|
|
763
|
-
};
|
|
764
|
-
const createVisitorUtils = ({ data })=>({
|
|
765
|
-
remove (key) {
|
|
766
|
-
delete data[key];
|
|
767
|
-
},
|
|
768
|
-
set (key, value) {
|
|
769
|
-
data[key] = value;
|
|
770
|
-
}
|
|
771
|
-
});
|
|
772
|
-
var traverseEntity$1 = fp.curry(traverseEntity);
|
|
773
|
-
|
|
774
|
-
/* eslint-disable @typescript-eslint/no-var-requires */ function importDefault(modName) {
|
|
775
|
-
const mod = require(modName);
|
|
776
|
-
return mod && mod.__esModule ? mod.default : mod;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
var machineId = (()=>{
|
|
780
|
-
try {
|
|
781
|
-
const deviceId = nodeMachineId.machineIdSync();
|
|
782
|
-
return deviceId;
|
|
783
|
-
} catch (error) {
|
|
784
|
-
const deviceId = crypto.randomUUID();
|
|
785
|
-
return deviceId;
|
|
786
|
-
}
|
|
787
|
-
});
|
|
788
|
-
|
|
789
|
-
const formatYupInnerError = (yupError)=>({
|
|
790
|
-
path: fp.toPath(yupError.path),
|
|
791
|
-
message: yupError.message,
|
|
792
|
-
name: yupError.name,
|
|
793
|
-
value: yupError.value
|
|
794
|
-
});
|
|
795
|
-
const formatYupErrors = (yupError)=>({
|
|
796
|
-
errors: fp.isEmpty(yupError.inner) ? [
|
|
797
|
-
formatYupInnerError(yupError)
|
|
798
|
-
] : yupError.inner.map(formatYupInnerError),
|
|
799
|
-
message: yupError.message
|
|
800
|
-
});
|
|
801
|
-
|
|
802
|
-
/* ApplicationError */ class ApplicationError extends Error {
|
|
803
|
-
constructor(message = 'An application error occured', details = {}){
|
|
804
|
-
super();
|
|
805
|
-
this.name = 'ApplicationError';
|
|
806
|
-
this.message = message;
|
|
807
|
-
this.details = details;
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
class ValidationError extends ApplicationError {
|
|
811
|
-
constructor(message, details){
|
|
812
|
-
super(message, details);
|
|
813
|
-
this.name = 'ValidationError';
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
class YupValidationError extends ValidationError {
|
|
817
|
-
constructor(yupError, message){
|
|
818
|
-
super('Validation');
|
|
819
|
-
const { errors, message: yupMessage } = formatYupErrors(yupError);
|
|
820
|
-
this.message = message || yupMessage;
|
|
821
|
-
this.details = {
|
|
822
|
-
errors
|
|
823
|
-
};
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
class PaginationError extends ApplicationError {
|
|
827
|
-
constructor(message = 'Invalid pagination', details){
|
|
828
|
-
super(message, details);
|
|
829
|
-
this.name = 'PaginationError';
|
|
830
|
-
this.message = message;
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
class NotFoundError extends ApplicationError {
|
|
834
|
-
constructor(message = 'Entity not found', details){
|
|
835
|
-
super(message, details);
|
|
836
|
-
this.name = 'NotFoundError';
|
|
837
|
-
this.message = message;
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
class ForbiddenError extends ApplicationError {
|
|
841
|
-
constructor(message = 'Forbidden access', details){
|
|
842
|
-
super(message, details);
|
|
843
|
-
this.name = 'ForbiddenError';
|
|
844
|
-
this.message = message;
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
class UnauthorizedError extends ApplicationError {
|
|
848
|
-
constructor(message = 'Unauthorized', details){
|
|
849
|
-
super(message, details);
|
|
850
|
-
this.name = 'UnauthorizedError';
|
|
851
|
-
this.message = message;
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
class RateLimitError extends ApplicationError {
|
|
855
|
-
constructor(message = 'Too many requests, please try again later.', details){
|
|
856
|
-
super(message, details);
|
|
857
|
-
this.name = 'RateLimitError';
|
|
858
|
-
this.message = message;
|
|
859
|
-
this.details = details || {};
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
class PayloadTooLargeError extends ApplicationError {
|
|
863
|
-
constructor(message = 'Entity too large', details){
|
|
864
|
-
super(message, details);
|
|
865
|
-
this.name = 'PayloadTooLargeError';
|
|
866
|
-
this.message = message;
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
class PolicyError extends ForbiddenError {
|
|
870
|
-
constructor(message = 'Policy Failed', details){
|
|
871
|
-
super(message, details);
|
|
872
|
-
this.name = 'PolicyError';
|
|
873
|
-
this.message = message;
|
|
874
|
-
this.details = details || {};
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
class NotImplementedError extends ApplicationError {
|
|
878
|
-
constructor(message = 'This feature is not implemented yet', details){
|
|
879
|
-
super(message, details);
|
|
880
|
-
this.name = 'NotImplementedError';
|
|
881
|
-
this.message = message;
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
var errors = /*#__PURE__*/Object.freeze({
|
|
886
|
-
__proto__: null,
|
|
887
|
-
ApplicationError: ApplicationError,
|
|
888
|
-
ForbiddenError: ForbiddenError,
|
|
889
|
-
HttpError: httpErrors.HttpError,
|
|
890
|
-
NotFoundError: NotFoundError,
|
|
891
|
-
NotImplementedError: NotImplementedError,
|
|
892
|
-
PaginationError: PaginationError,
|
|
893
|
-
PayloadTooLargeError: PayloadTooLargeError,
|
|
894
|
-
PolicyError: PolicyError,
|
|
895
|
-
RateLimitError: RateLimitError,
|
|
896
|
-
UnauthorizedError: UnauthorizedError,
|
|
897
|
-
ValidationError: ValidationError,
|
|
898
|
-
YupValidationError: YupValidationError
|
|
899
|
-
});
|
|
900
|
-
|
|
901
|
-
const handleYupError = (error, errorMessage)=>{
|
|
902
|
-
throw new YupValidationError(error, errorMessage);
|
|
903
|
-
};
|
|
904
|
-
const defaultValidationParam = {
|
|
905
|
-
strict: true,
|
|
906
|
-
abortEarly: false
|
|
907
|
-
};
|
|
908
|
-
const validateYupSchema = (schema, options = {})=>async (body, errorMessage)=>{
|
|
909
|
-
try {
|
|
910
|
-
const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
|
|
911
|
-
const result = await schema.validate(body, optionsWithDefaults);
|
|
912
|
-
return result;
|
|
913
|
-
} catch (e) {
|
|
914
|
-
if (e instanceof yup__namespace.ValidationError) {
|
|
915
|
-
handleYupError(e, errorMessage);
|
|
916
|
-
}
|
|
917
|
-
throw e;
|
|
918
|
-
}
|
|
919
|
-
};
|
|
920
|
-
const validateYupSchemaSync = (schema, options = {})=>(body, errorMessage)=>{
|
|
921
|
-
try {
|
|
922
|
-
const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
|
|
923
|
-
return schema.validateSync(body, optionsWithDefaults);
|
|
924
|
-
} catch (e) {
|
|
925
|
-
if (e instanceof yup__namespace.ValidationError) {
|
|
926
|
-
handleYupError(e, errorMessage);
|
|
927
|
-
}
|
|
928
|
-
throw e;
|
|
929
|
-
}
|
|
930
|
-
};
|
|
931
|
-
|
|
932
|
-
const GROUP_OPERATORS = [
|
|
933
|
-
'$and',
|
|
934
|
-
'$or'
|
|
935
|
-
];
|
|
936
|
-
const WHERE_OPERATORS = [
|
|
937
|
-
'$not',
|
|
938
|
-
'$in',
|
|
939
|
-
'$notIn',
|
|
940
|
-
'$eq',
|
|
941
|
-
'$eqi',
|
|
942
|
-
'$ne',
|
|
943
|
-
'$nei',
|
|
944
|
-
'$gt',
|
|
945
|
-
'$gte',
|
|
946
|
-
'$lt',
|
|
947
|
-
'$lte',
|
|
948
|
-
'$null',
|
|
949
|
-
'$notNull',
|
|
950
|
-
'$between',
|
|
951
|
-
'$startsWith',
|
|
952
|
-
'$endsWith',
|
|
953
|
-
'$startsWithi',
|
|
954
|
-
'$endsWithi',
|
|
955
|
-
'$contains',
|
|
956
|
-
'$notContains',
|
|
957
|
-
'$containsi',
|
|
958
|
-
'$notContainsi',
|
|
959
|
-
// Experimental, only for internal use
|
|
960
|
-
'$jsonSupersetOf'
|
|
961
|
-
];
|
|
962
|
-
const CAST_OPERATORS = [
|
|
963
|
-
'$not',
|
|
964
|
-
'$in',
|
|
965
|
-
'$notIn',
|
|
966
|
-
'$eq',
|
|
967
|
-
'$ne',
|
|
968
|
-
'$gt',
|
|
969
|
-
'$gte',
|
|
970
|
-
'$lt',
|
|
971
|
-
'$lte',
|
|
972
|
-
'$between'
|
|
973
|
-
];
|
|
974
|
-
const ARRAY_OPERATORS = [
|
|
975
|
-
'$in',
|
|
976
|
-
'$notIn',
|
|
977
|
-
'$between'
|
|
978
|
-
];
|
|
979
|
-
const OPERATORS = {
|
|
980
|
-
where: WHERE_OPERATORS,
|
|
981
|
-
cast: CAST_OPERATORS,
|
|
982
|
-
group: GROUP_OPERATORS,
|
|
983
|
-
array: ARRAY_OPERATORS
|
|
984
|
-
};
|
|
985
|
-
// for performance, cache all operators in lowercase
|
|
986
|
-
const OPERATORS_LOWERCASE = Object.fromEntries(Object.entries(OPERATORS).map(([key, values])=>[
|
|
987
|
-
key,
|
|
988
|
-
values.map((value)=>value.toLowerCase())
|
|
989
|
-
]));
|
|
990
|
-
const isObjKey = (key, obj)=>{
|
|
991
|
-
return key in obj;
|
|
992
|
-
};
|
|
993
|
-
const isOperatorOfType = (type, key, ignoreCase = false)=>{
|
|
994
|
-
if (ignoreCase) {
|
|
995
|
-
return OPERATORS_LOWERCASE[type]?.includes(key.toLowerCase()) ?? false;
|
|
996
|
-
}
|
|
997
|
-
if (isObjKey(type, OPERATORS)) {
|
|
998
|
-
return OPERATORS[type]?.includes(key) ?? false;
|
|
999
|
-
}
|
|
1000
|
-
return false;
|
|
1001
|
-
};
|
|
1002
|
-
const isOperator = (key, ignoreCase = false)=>{
|
|
1003
|
-
return Object.keys(OPERATORS).some((type)=>isOperatorOfType(type, key, ignoreCase));
|
|
1004
|
-
};
|
|
1005
|
-
|
|
1006
|
-
const { ID_ATTRIBUTE: ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$3, PUBLISHED_AT_ATTRIBUTE } = constants$1;
|
|
1007
|
-
class InvalidOrderError extends Error {
|
|
1008
|
-
constructor(){
|
|
1009
|
-
super();
|
|
1010
|
-
this.message = 'Invalid order. order can only be one of asc|desc|ASC|DESC';
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
class InvalidSortError extends Error {
|
|
1014
|
-
constructor(){
|
|
1015
|
-
super();
|
|
1016
|
-
this.message = 'Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects';
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
function validateOrder(order) {
|
|
1020
|
-
if (!fp.isString(order) || ![
|
|
1021
|
-
'asc',
|
|
1022
|
-
'desc'
|
|
1023
|
-
].includes(order.toLocaleLowerCase())) {
|
|
1024
|
-
throw new InvalidOrderError();
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
const convertCountQueryParams = (countQuery)=>{
|
|
1028
|
-
return parseType({
|
|
1029
|
-
type: 'boolean',
|
|
1030
|
-
value: countQuery
|
|
1031
|
-
});
|
|
1032
|
-
};
|
|
1033
|
-
const convertOrderingQueryParams = (ordering)=>{
|
|
1034
|
-
return ordering;
|
|
1035
|
-
};
|
|
1036
|
-
const isPlainObject = (value)=>_.isPlainObject(value);
|
|
1037
|
-
const isStringArray$3 = (value)=>fp.isArray(value) && value.every(fp.isString);
|
|
1038
|
-
const createTransformer = ({ getModel })=>{
|
|
1039
|
-
/**
|
|
1040
|
-
* Sort query parser
|
|
1041
|
-
*/ const convertSortQueryParams = (sortQuery)=>{
|
|
1042
|
-
if (typeof sortQuery === 'string') {
|
|
1043
|
-
return convertStringSortQueryParam(sortQuery);
|
|
1044
|
-
}
|
|
1045
|
-
if (isStringArray$3(sortQuery)) {
|
|
1046
|
-
return sortQuery.flatMap((sortValue)=>convertStringSortQueryParam(sortValue));
|
|
1047
|
-
}
|
|
1048
|
-
if (Array.isArray(sortQuery)) {
|
|
1049
|
-
return sortQuery.map((sortValue)=>convertNestedSortQueryParam(sortValue));
|
|
1050
|
-
}
|
|
1051
|
-
if (isPlainObject(sortQuery)) {
|
|
1052
|
-
return convertNestedSortQueryParam(sortQuery);
|
|
1053
|
-
}
|
|
1054
|
-
throw new InvalidSortError();
|
|
1055
|
-
};
|
|
1056
|
-
const convertStringSortQueryParam = (sortQuery)=>{
|
|
1057
|
-
return sortQuery.split(',').map((value)=>convertSingleSortQueryParam(value));
|
|
1058
|
-
};
|
|
1059
|
-
const convertSingleSortQueryParam = (sortQuery)=>{
|
|
1060
|
-
if (!sortQuery) {
|
|
1061
|
-
return {};
|
|
1062
|
-
}
|
|
1063
|
-
if (!fp.isString(sortQuery)) {
|
|
1064
|
-
throw new Error('Invalid sort query');
|
|
1065
|
-
}
|
|
1066
|
-
// split field and order param with default order to ascending
|
|
1067
|
-
const [field, order = 'asc'] = sortQuery.split(':');
|
|
1068
|
-
if (field.length === 0) {
|
|
1069
|
-
throw new Error('Field cannot be empty');
|
|
1070
|
-
}
|
|
1071
|
-
validateOrder(order);
|
|
1072
|
-
// TODO: field should be a valid path on an object model
|
|
1073
|
-
return _.set({}, field, order);
|
|
1074
|
-
};
|
|
1075
|
-
const convertNestedSortQueryParam = (sortQuery)=>{
|
|
1076
|
-
const transformedSort = {};
|
|
1077
|
-
for (const field of Object.keys(sortQuery)){
|
|
1078
|
-
const order = sortQuery[field];
|
|
1079
|
-
// this is a deep sort
|
|
1080
|
-
if (isPlainObject(order)) {
|
|
1081
|
-
transformedSort[field] = convertNestedSortQueryParam(order);
|
|
1082
|
-
} else if (typeof order === 'string') {
|
|
1083
|
-
validateOrder(order);
|
|
1084
|
-
transformedSort[field] = order;
|
|
1085
|
-
} else {
|
|
1086
|
-
throw Error(`Invalid sort type expected object or string got ${typeof order}`);
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
return transformedSort;
|
|
1090
|
-
};
|
|
1091
|
-
/**
|
|
1092
|
-
* Start query parser
|
|
1093
|
-
*/ const convertStartQueryParams = (startQuery)=>{
|
|
1094
|
-
const startAsANumber = fp.toNumber(startQuery);
|
|
1095
|
-
if (!_.isInteger(startAsANumber) || startAsANumber < 0) {
|
|
1096
|
-
throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
|
|
1097
|
-
}
|
|
1098
|
-
return startAsANumber;
|
|
1099
|
-
};
|
|
1100
|
-
/**
|
|
1101
|
-
* Limit query parser
|
|
1102
|
-
*/ const convertLimitQueryParams = (limitQuery)=>{
|
|
1103
|
-
const limitAsANumber = fp.toNumber(limitQuery);
|
|
1104
|
-
if (!_.isInteger(limitAsANumber) || limitAsANumber !== -1 && limitAsANumber < 0) {
|
|
1105
|
-
throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
|
|
1106
|
-
}
|
|
1107
|
-
if (limitAsANumber === -1) {
|
|
1108
|
-
return undefined;
|
|
1109
|
-
}
|
|
1110
|
-
return limitAsANumber;
|
|
1111
|
-
};
|
|
1112
|
-
const convertPageQueryParams = (page)=>{
|
|
1113
|
-
const pageVal = fp.toNumber(page);
|
|
1114
|
-
if (!fp.isInteger(pageVal) || pageVal <= 0) {
|
|
1115
|
-
throw new PaginationError(`Invalid 'page' parameter. Expected an integer > 0, received: ${page}`);
|
|
1116
|
-
}
|
|
1117
|
-
return pageVal;
|
|
1118
|
-
};
|
|
1119
|
-
const convertPageSizeQueryParams = (pageSize, page)=>{
|
|
1120
|
-
const pageSizeVal = fp.toNumber(pageSize);
|
|
1121
|
-
if (!fp.isInteger(pageSizeVal) || pageSizeVal <= 0) {
|
|
1122
|
-
throw new PaginationError(`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`);
|
|
1123
|
-
}
|
|
1124
|
-
return pageSizeVal;
|
|
1125
|
-
};
|
|
1126
|
-
const validatePaginationParams = (page, pageSize, start, limit)=>{
|
|
1127
|
-
const isPagePagination = !fp.isNil(page) || !fp.isNil(pageSize);
|
|
1128
|
-
const isOffsetPagination = !fp.isNil(start) || !fp.isNil(limit);
|
|
1129
|
-
if (isPagePagination && isOffsetPagination) {
|
|
1130
|
-
throw new PaginationError('Invalid pagination attributes. The page parameters are incorrect and must be in the pagination object');
|
|
1131
|
-
}
|
|
1132
|
-
};
|
|
1133
|
-
class InvalidPopulateError extends Error {
|
|
1134
|
-
constructor(){
|
|
1135
|
-
super();
|
|
1136
|
-
this.message = 'Invalid populate parameter. Expected a string, an array of strings, a populate object';
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
// NOTE: we could support foo.* or foo.bar.* etc later on
|
|
1140
|
-
const convertPopulateQueryParams = (populate, schema, depth = 0)=>{
|
|
1141
|
-
if (depth === 0 && populate === '*') {
|
|
1142
|
-
return true;
|
|
1143
|
-
}
|
|
1144
|
-
if (typeof populate === 'string') {
|
|
1145
|
-
return populate.split(',').map((value)=>_.trim(value));
|
|
1146
|
-
}
|
|
1147
|
-
if (Array.isArray(populate)) {
|
|
1148
|
-
// map convert
|
|
1149
|
-
return _.uniq(populate.flatMap((value)=>{
|
|
1150
|
-
if (typeof value !== 'string') {
|
|
1151
|
-
throw new InvalidPopulateError();
|
|
1152
|
-
}
|
|
1153
|
-
return value.split(',').map((value)=>_.trim(value));
|
|
1154
|
-
}));
|
|
1155
|
-
}
|
|
1156
|
-
if (_.isPlainObject(populate)) {
|
|
1157
|
-
return convertPopulateObject(populate, schema);
|
|
1158
|
-
}
|
|
1159
|
-
throw new InvalidPopulateError();
|
|
1160
|
-
};
|
|
1161
|
-
const hasPopulateFragmentDefined = (populate)=>{
|
|
1162
|
-
return typeof populate === 'object' && 'on' in populate && !fp.isNil(populate.on);
|
|
1163
|
-
};
|
|
1164
|
-
const hasCountDefined = (populate)=>{
|
|
1165
|
-
return typeof populate === 'object' && 'count' in populate && typeof populate.count === 'boolean';
|
|
1166
|
-
};
|
|
1167
|
-
const convertPopulateObject = (populate, schema)=>{
|
|
1168
|
-
if (!schema) {
|
|
1169
|
-
return {};
|
|
1170
|
-
}
|
|
1171
|
-
const { attributes } = schema;
|
|
1172
|
-
return Object.entries(populate).reduce((acc, [key, subPopulate])=>{
|
|
1173
|
-
// Try converting strings to regular booleans if possible
|
|
1174
|
-
if (_.isString(subPopulate)) {
|
|
1175
|
-
try {
|
|
1176
|
-
const subPopulateAsBoolean = parseType({
|
|
1177
|
-
type: 'boolean',
|
|
1178
|
-
value: subPopulate
|
|
1179
|
-
});
|
|
1180
|
-
// Only true is accepted as a boolean populate value
|
|
1181
|
-
return subPopulateAsBoolean ? {
|
|
1182
|
-
...acc,
|
|
1183
|
-
[key]: true
|
|
1184
|
-
} : acc;
|
|
1185
|
-
} catch {
|
|
1186
|
-
// ignore
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
if (_.isBoolean(subPopulate)) {
|
|
1190
|
-
// Only true is accepted as a boolean populate value
|
|
1191
|
-
return subPopulate === true ? {
|
|
1192
|
-
...acc,
|
|
1193
|
-
[key]: true
|
|
1194
|
-
} : acc;
|
|
1195
|
-
}
|
|
1196
|
-
const attribute = attributes[key];
|
|
1197
|
-
if (!attribute) {
|
|
1198
|
-
return acc;
|
|
1199
|
-
}
|
|
1200
|
-
// Allow adding an 'on' strategy to populate queries for morphTo relations and dynamic zones
|
|
1201
|
-
const isMorphLikeRelationalAttribute = isDynamicZoneAttribute(attribute) || isMorphToRelationalAttribute(attribute);
|
|
1202
|
-
if (isMorphLikeRelationalAttribute) {
|
|
1203
|
-
const hasInvalidProperties = Object.keys(subPopulate).some((key)=>![
|
|
1204
|
-
'populate',
|
|
1205
|
-
'on',
|
|
1206
|
-
'count'
|
|
1207
|
-
].includes(key));
|
|
1208
|
-
if (hasInvalidProperties) {
|
|
1209
|
-
throw new Error(`Invalid nested populate for ${schema.info?.singularName}.${key} (${schema.uid}). Expected a fragment ("on") or "count" but found ${JSON.stringify(subPopulate)}`);
|
|
1210
|
-
}
|
|
1211
|
-
/**
|
|
1212
|
-
* Validate nested population queries in the context of a polymorphic attribute (dynamic zone, morph relation).
|
|
1213
|
-
*
|
|
1214
|
-
* If 'populate' exists in subPopulate, its value should be constrained to a wildcard ('*').
|
|
1215
|
-
*/ if ('populate' in subPopulate && subPopulate.populate !== '*') {
|
|
1216
|
-
throw new Error(`Invalid nested population query detected. When using 'populate' within polymorphic structures, ` + `its value must be '*' to indicate all second level links. Specific field targeting is not supported here. ` + `Consider using the fragment API for more granular population control.`);
|
|
1217
|
-
}
|
|
1218
|
-
// TODO: Remove the possibility to have multiple properties at the same time (on/count/populate)
|
|
1219
|
-
const newSubPopulate = {};
|
|
1220
|
-
// case: { populate: '*' }
|
|
1221
|
-
if ('populate' in subPopulate) {
|
|
1222
|
-
Object.assign(newSubPopulate, {
|
|
1223
|
-
populate: true
|
|
1224
|
-
});
|
|
1225
|
-
}
|
|
1226
|
-
// case: { on: { <clauses> } }
|
|
1227
|
-
if (hasPopulateFragmentDefined(subPopulate)) {
|
|
1228
|
-
// If the fragment API is used, it applies the transformation to every
|
|
1229
|
-
// sub-populate, then assign the result to the new sub-populate
|
|
1230
|
-
Object.assign(newSubPopulate, {
|
|
1231
|
-
on: Object.entries(subPopulate.on).reduce((acc, [type, typeSubPopulate])=>({
|
|
1232
|
-
...acc,
|
|
1233
|
-
[type]: convertNestedPopulate(typeSubPopulate, getModel(type))
|
|
1234
|
-
}), {})
|
|
1235
|
-
});
|
|
1236
|
-
}
|
|
1237
|
-
// case: { count: true | false }
|
|
1238
|
-
if (hasCountDefined(subPopulate)) {
|
|
1239
|
-
Object.assign(newSubPopulate, {
|
|
1240
|
-
count: subPopulate.count
|
|
1241
|
-
});
|
|
1242
|
-
}
|
|
1243
|
-
return {
|
|
1244
|
-
...acc,
|
|
1245
|
-
[key]: newSubPopulate
|
|
1246
|
-
};
|
|
1247
|
-
}
|
|
1248
|
-
// Edge case when trying to use the fragment ('on') on a non-morph like attribute
|
|
1249
|
-
if (!isMorphLikeRelationalAttribute && hasPopulateFragmentDefined(subPopulate)) {
|
|
1250
|
-
throw new Error(`Using fragments is not permitted to populate "${key}" in "${schema.uid}"`);
|
|
1251
|
-
}
|
|
1252
|
-
// NOTE: Retrieve the target schema UID.
|
|
1253
|
-
// Only handles basic relations, medias and component since it's not possible
|
|
1254
|
-
// to populate with options for a dynamic zone or a polymorphic relation
|
|
1255
|
-
let targetSchemaUID;
|
|
1256
|
-
if (attribute.type === 'relation') {
|
|
1257
|
-
targetSchemaUID = attribute.target;
|
|
1258
|
-
} else if (attribute.type === 'component') {
|
|
1259
|
-
targetSchemaUID = attribute.component;
|
|
1260
|
-
} else if (attribute.type === 'media') {
|
|
1261
|
-
targetSchemaUID = 'plugin::upload.file';
|
|
1262
|
-
} else {
|
|
1263
|
-
return acc;
|
|
1264
|
-
}
|
|
1265
|
-
const targetSchema = getModel(targetSchemaUID);
|
|
1266
|
-
// ignore the sub-populate for the current key if there is no schema associated
|
|
1267
|
-
if (!targetSchema) {
|
|
1268
|
-
return acc;
|
|
1269
|
-
}
|
|
1270
|
-
const populateObject = convertNestedPopulate(subPopulate, targetSchema);
|
|
1271
|
-
if (!populateObject) {
|
|
1272
|
-
return acc;
|
|
1273
|
-
}
|
|
1274
|
-
return {
|
|
1275
|
-
...acc,
|
|
1276
|
-
[key]: populateObject
|
|
1277
|
-
};
|
|
1278
|
-
}, {});
|
|
1279
|
-
};
|
|
1280
|
-
const convertNestedPopulate = (subPopulate, schema)=>{
|
|
1281
|
-
if (_.isString(subPopulate)) {
|
|
1282
|
-
return parseType({
|
|
1283
|
-
type: 'boolean',
|
|
1284
|
-
value: subPopulate,
|
|
1285
|
-
forceCast: true
|
|
1286
|
-
});
|
|
1287
|
-
}
|
|
1288
|
-
if (_.isBoolean(subPopulate)) {
|
|
1289
|
-
return subPopulate;
|
|
1290
|
-
}
|
|
1291
|
-
if (!isPlainObject(subPopulate)) {
|
|
1292
|
-
throw new Error(`Invalid nested populate. Expected '*' or an object`);
|
|
1293
|
-
}
|
|
1294
|
-
const { sort, filters, fields, populate, count, ordering, page, pageSize, start, limit } = subPopulate;
|
|
1295
|
-
const query = {};
|
|
1296
|
-
if (sort) {
|
|
1297
|
-
query.orderBy = convertSortQueryParams(sort);
|
|
1298
|
-
}
|
|
1299
|
-
if (filters) {
|
|
1300
|
-
query.where = convertFiltersQueryParams(filters, schema);
|
|
1301
|
-
}
|
|
1302
|
-
if (fields) {
|
|
1303
|
-
query.select = convertFieldsQueryParams(fields, schema);
|
|
1304
|
-
}
|
|
1305
|
-
if (populate) {
|
|
1306
|
-
query.populate = convertPopulateQueryParams(populate, schema);
|
|
1307
|
-
}
|
|
1308
|
-
if (count) {
|
|
1309
|
-
query.count = convertCountQueryParams(count);
|
|
1310
|
-
}
|
|
1311
|
-
if (ordering) {
|
|
1312
|
-
query.ordering = convertOrderingQueryParams(ordering);
|
|
1313
|
-
}
|
|
1314
|
-
validatePaginationParams(page, pageSize, start, limit);
|
|
1315
|
-
if (!fp.isNil(page)) {
|
|
1316
|
-
query.page = convertPageQueryParams(page);
|
|
1317
|
-
}
|
|
1318
|
-
if (!fp.isNil(pageSize)) {
|
|
1319
|
-
query.pageSize = convertPageSizeQueryParams(pageSize, page);
|
|
1320
|
-
}
|
|
1321
|
-
if (!fp.isNil(start)) {
|
|
1322
|
-
query.offset = convertStartQueryParams(start);
|
|
1323
|
-
}
|
|
1324
|
-
if (!fp.isNil(limit)) {
|
|
1325
|
-
query.limit = convertLimitQueryParams(limit);
|
|
1326
|
-
}
|
|
1327
|
-
return query;
|
|
1328
|
-
};
|
|
1329
|
-
// TODO: ensure field is valid in content types (will probably have to check strapi.contentTypes since it can be a string.path)
|
|
1330
|
-
const convertFieldsQueryParams = (fields, schema, depth = 0)=>{
|
|
1331
|
-
if (depth === 0 && fields === '*') {
|
|
1332
|
-
return undefined;
|
|
1333
|
-
}
|
|
1334
|
-
if (typeof fields === 'string') {
|
|
1335
|
-
const fieldsValues = fields.split(',').map((value)=>_.trim(value));
|
|
1336
|
-
// NOTE: Only include the doc id if it's a content type
|
|
1337
|
-
if (schema?.modelType === 'contentType') {
|
|
1338
|
-
return _.uniq([
|
|
1339
|
-
ID_ATTRIBUTE$3,
|
|
1340
|
-
DOC_ID_ATTRIBUTE$3,
|
|
1341
|
-
...fieldsValues
|
|
1342
|
-
]);
|
|
1343
|
-
}
|
|
1344
|
-
return _.uniq([
|
|
1345
|
-
ID_ATTRIBUTE$3,
|
|
1346
|
-
...fieldsValues
|
|
1347
|
-
]);
|
|
1348
|
-
}
|
|
1349
|
-
if (isStringArray$3(fields)) {
|
|
1350
|
-
// map convert
|
|
1351
|
-
const fieldsValues = fields.flatMap((value)=>convertFieldsQueryParams(value, schema, depth + 1)).filter((v)=>!fp.isNil(v));
|
|
1352
|
-
// NOTE: Only include the doc id if it's a content type
|
|
1353
|
-
if (schema?.modelType === 'contentType') {
|
|
1354
|
-
return _.uniq([
|
|
1355
|
-
ID_ATTRIBUTE$3,
|
|
1356
|
-
DOC_ID_ATTRIBUTE$3,
|
|
1357
|
-
...fieldsValues
|
|
1358
|
-
]);
|
|
1359
|
-
}
|
|
1360
|
-
return _.uniq([
|
|
1361
|
-
ID_ATTRIBUTE$3,
|
|
1362
|
-
...fieldsValues
|
|
1363
|
-
]);
|
|
1364
|
-
}
|
|
1365
|
-
throw new Error('Invalid fields parameter. Expected a string or an array of strings');
|
|
1366
|
-
};
|
|
1367
|
-
const isValidSchemaAttribute = (key, schema)=>{
|
|
1368
|
-
if ([
|
|
1369
|
-
DOC_ID_ATTRIBUTE$3,
|
|
1370
|
-
ID_ATTRIBUTE$3
|
|
1371
|
-
].includes(key)) {
|
|
1372
|
-
return true;
|
|
1373
|
-
}
|
|
1374
|
-
if (!schema) {
|
|
1375
|
-
return false;
|
|
1376
|
-
}
|
|
1377
|
-
return Object.keys(schema.attributes).includes(key);
|
|
1378
|
-
};
|
|
1379
|
-
const convertFiltersQueryParams = (filters, schema)=>{
|
|
1380
|
-
// Filters need to be either an array or an object
|
|
1381
|
-
// Here we're only checking for 'object' type since typeof [] => object and typeof {} => object
|
|
1382
|
-
if (!fp.isObject(filters)) {
|
|
1383
|
-
throw new Error('The filters parameter must be an object or an array');
|
|
1384
|
-
}
|
|
1385
|
-
// Don't mutate the original object
|
|
1386
|
-
const filtersCopy = fp.cloneDeep(filters);
|
|
1387
|
-
return convertAndSanitizeFilters(filtersCopy, schema);
|
|
1388
|
-
};
|
|
1389
|
-
const convertAndSanitizeFilters = (filters, schema)=>{
|
|
1390
|
-
if (Array.isArray(filters)) {
|
|
1391
|
-
return filters// Sanitize each filter
|
|
1392
|
-
.map((filter)=>convertAndSanitizeFilters(filter, schema))// Filter out empty filters
|
|
1393
|
-
.filter((filter)=>!isPlainObject(filter) || !fp.isEmpty(filter));
|
|
1394
|
-
}
|
|
1395
|
-
if (!isPlainObject(filters)) {
|
|
1396
|
-
return filters;
|
|
1397
|
-
}
|
|
1398
|
-
const removeOperator = (operator)=>delete filters[operator];
|
|
1399
|
-
// Here, `key` can either be an operator or an attribute name
|
|
1400
|
-
for (const [key, value] of Object.entries(filters)){
|
|
1401
|
-
const attribute = fp.get(key, schema?.attributes);
|
|
1402
|
-
const validKey = isOperator(key) || isValidSchemaAttribute(key, schema);
|
|
1403
|
-
if (!validKey) {
|
|
1404
|
-
removeOperator(key);
|
|
1405
|
-
} else if (attribute) {
|
|
1406
|
-
// Relations
|
|
1407
|
-
if (attribute.type === 'relation') {
|
|
1408
|
-
filters[key] = convertAndSanitizeFilters(value, getModel(attribute.target));
|
|
1409
|
-
} else if (attribute.type === 'component') {
|
|
1410
|
-
filters[key] = convertAndSanitizeFilters(value, getModel(attribute.component));
|
|
1411
|
-
} else if (attribute.type === 'media') {
|
|
1412
|
-
filters[key] = convertAndSanitizeFilters(value, getModel('plugin::upload.file'));
|
|
1413
|
-
} else if (attribute.type === 'dynamiczone') {
|
|
1414
|
-
removeOperator(key);
|
|
1415
|
-
} else if (attribute.type === 'password') {
|
|
1416
|
-
// Always remove password attributes from filters object
|
|
1417
|
-
removeOperator(key);
|
|
1418
|
-
} else {
|
|
1419
|
-
filters[key] = convertAndSanitizeFilters(value, schema);
|
|
1420
|
-
}
|
|
1421
|
-
} else if ([
|
|
1422
|
-
'$null',
|
|
1423
|
-
'$notNull'
|
|
1424
|
-
].includes(key)) {
|
|
1425
|
-
filters[key] = parseType({
|
|
1426
|
-
type: 'boolean',
|
|
1427
|
-
value: filters[key],
|
|
1428
|
-
forceCast: true
|
|
1429
|
-
});
|
|
1430
|
-
} else if (fp.isObject(value)) {
|
|
1431
|
-
filters[key] = convertAndSanitizeFilters(value, schema);
|
|
1432
|
-
}
|
|
1433
|
-
// Remove empty objects & arrays
|
|
1434
|
-
if (isPlainObject(filters[key]) && fp.isEmpty(filters[key])) {
|
|
1435
|
-
removeOperator(key);
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
return filters;
|
|
1439
|
-
};
|
|
1440
|
-
const convertStatusParams = (status, query = {})=>{
|
|
1441
|
-
// NOTE: this is the query layer filters not the document/entity service filters
|
|
1442
|
-
query.filters = ({ meta })=>{
|
|
1443
|
-
const contentType = getModel(meta.uid);
|
|
1444
|
-
// Ignore if target model has disabled DP, as it doesn't make sense to filter by its status
|
|
1445
|
-
if (!contentType || !hasDraftAndPublish(contentType)) {
|
|
1446
|
-
return {};
|
|
1447
|
-
}
|
|
1448
|
-
return {
|
|
1449
|
-
[PUBLISHED_AT_ATTRIBUTE]: {
|
|
1450
|
-
$null: status === 'draft'
|
|
1451
|
-
}
|
|
1452
|
-
};
|
|
1453
|
-
};
|
|
1454
|
-
};
|
|
1455
|
-
const transformQueryParams = (uid, params)=>{
|
|
1456
|
-
// NOTE: can be a CT, a Compo or nothing in the case of polymorphism (DZ & morph relations)
|
|
1457
|
-
const schema = getModel(uid);
|
|
1458
|
-
const query = {};
|
|
1459
|
-
const { _q, sort, filters, fields, populate, page, pageSize, start, limit, status, ...rest } = params;
|
|
1460
|
-
if (!fp.isNil(status)) {
|
|
1461
|
-
convertStatusParams(status, query);
|
|
1462
|
-
}
|
|
1463
|
-
if (!fp.isNil(_q)) {
|
|
1464
|
-
query._q = _q;
|
|
1465
|
-
}
|
|
1466
|
-
if (!fp.isNil(sort)) {
|
|
1467
|
-
query.orderBy = convertSortQueryParams(sort);
|
|
1468
|
-
}
|
|
1469
|
-
if (!fp.isNil(filters)) {
|
|
1470
|
-
query.where = convertFiltersQueryParams(filters, schema);
|
|
1471
|
-
}
|
|
1472
|
-
if (!fp.isNil(fields)) {
|
|
1473
|
-
query.select = convertFieldsQueryParams(fields, schema);
|
|
1474
|
-
}
|
|
1475
|
-
if (!fp.isNil(populate)) {
|
|
1476
|
-
query.populate = convertPopulateQueryParams(populate, schema);
|
|
1477
|
-
}
|
|
1478
|
-
validatePaginationParams(page, pageSize, start, limit);
|
|
1479
|
-
if (!fp.isNil(page)) {
|
|
1480
|
-
query.page = convertPageQueryParams(page);
|
|
1481
|
-
}
|
|
1482
|
-
if (!fp.isNil(pageSize)) {
|
|
1483
|
-
query.pageSize = convertPageSizeQueryParams(pageSize, page);
|
|
1484
|
-
}
|
|
1485
|
-
if (!fp.isNil(start)) {
|
|
1486
|
-
query.offset = convertStartQueryParams(start);
|
|
1487
|
-
}
|
|
1488
|
-
if (!fp.isNil(limit)) {
|
|
1489
|
-
query.limit = convertLimitQueryParams(limit);
|
|
1490
|
-
}
|
|
1491
|
-
return {
|
|
1492
|
-
...rest,
|
|
1493
|
-
...query
|
|
1494
|
-
};
|
|
1495
|
-
};
|
|
1496
|
-
return {
|
|
1497
|
-
private_convertSortQueryParams: convertSortQueryParams,
|
|
1498
|
-
private_convertStartQueryParams: convertStartQueryParams,
|
|
1499
|
-
private_convertLimitQueryParams: convertLimitQueryParams,
|
|
1500
|
-
private_convertPopulateQueryParams: convertPopulateQueryParams,
|
|
1501
|
-
private_convertFiltersQueryParams: convertFiltersQueryParams,
|
|
1502
|
-
private_convertFieldsQueryParams: convertFieldsQueryParams,
|
|
1503
|
-
transformQueryParams
|
|
1504
|
-
};
|
|
1505
|
-
};
|
|
1506
|
-
|
|
1507
|
-
var convertQueryParams = /*#__PURE__*/Object.freeze({
|
|
1508
|
-
__proto__: null,
|
|
1509
|
-
createTransformer: createTransformer
|
|
1510
|
-
});
|
|
1511
|
-
|
|
1512
|
-
function pipe(...fns) {
|
|
1513
|
-
const [firstFn, ...fnRest] = fns;
|
|
1514
|
-
return async (...args)=>{
|
|
1515
|
-
let res = await firstFn.apply(firstFn, args);
|
|
1516
|
-
for(let i = 0; i < fnRest.length; i += 1){
|
|
1517
|
-
res = await fnRest[i](res);
|
|
1518
|
-
}
|
|
1519
|
-
return res;
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
const map = fp.curry(pMap);
|
|
1523
|
-
const reduce = (mixedArray)=>async (iteratee, initialValue)=>{
|
|
1524
|
-
let acc = initialValue;
|
|
1525
|
-
for(let i = 0; i < mixedArray.length; i += 1){
|
|
1526
|
-
acc = await iteratee(acc, await mixedArray[i], i);
|
|
1527
|
-
}
|
|
1528
|
-
return acc;
|
|
1529
|
-
};
|
|
1530
|
-
|
|
1531
|
-
var async = /*#__PURE__*/Object.freeze({
|
|
1532
|
-
__proto__: null,
|
|
1533
|
-
map: map,
|
|
1534
|
-
pipe: pipe,
|
|
1535
|
-
reduce: reduce
|
|
1536
|
-
});
|
|
1537
|
-
|
|
1538
|
-
const visitor$8 = ({ key, attribute }, { remove })=>{
|
|
1539
|
-
if (attribute?.type === 'password') {
|
|
1540
|
-
remove(key);
|
|
1541
|
-
}
|
|
1542
|
-
};
|
|
1543
|
-
|
|
1544
|
-
const visitor$7 = ({ schema, key, attribute }, { remove })=>{
|
|
1545
|
-
if (!attribute) {
|
|
1546
|
-
return;
|
|
1547
|
-
}
|
|
1548
|
-
const isPrivate = attribute.private === true || isPrivateAttribute(schema, key);
|
|
1549
|
-
if (isPrivate) {
|
|
1550
|
-
remove(key);
|
|
1551
|
-
}
|
|
1552
|
-
};
|
|
1553
|
-
|
|
1554
|
-
const MANY_RELATIONS = [
|
|
1555
|
-
'oneToMany',
|
|
1556
|
-
'manyToMany'
|
|
1557
|
-
];
|
|
1558
|
-
const getRelationalFields = (contentType)=>{
|
|
1559
|
-
return Object.keys(contentType.attributes).filter((attributeName)=>{
|
|
1560
|
-
return contentType.attributes[attributeName].type === 'relation';
|
|
1561
|
-
});
|
|
1562
|
-
};
|
|
1563
|
-
const isOneToAny = (attribute)=>isRelationalAttribute(attribute) && [
|
|
1564
|
-
'oneToOne',
|
|
1565
|
-
'oneToMany'
|
|
1566
|
-
].includes(attribute.relation);
|
|
1567
|
-
const isManyToAny = (attribute)=>isRelationalAttribute(attribute) && [
|
|
1568
|
-
'manyToMany',
|
|
1569
|
-
'manyToOne'
|
|
1570
|
-
].includes(attribute.relation);
|
|
1571
|
-
const isAnyToOne = (attribute)=>isRelationalAttribute(attribute) && [
|
|
1572
|
-
'oneToOne',
|
|
1573
|
-
'manyToOne'
|
|
1574
|
-
].includes(attribute.relation);
|
|
1575
|
-
const isAnyToMany = (attribute)=>isRelationalAttribute(attribute) && [
|
|
1576
|
-
'oneToMany',
|
|
1577
|
-
'manyToMany'
|
|
1578
|
-
].includes(attribute.relation);
|
|
1579
|
-
const isPolymorphic = (attribute)=>[
|
|
1580
|
-
'morphOne',
|
|
1581
|
-
'morphMany',
|
|
1582
|
-
'morphToOne',
|
|
1583
|
-
'morphToMany'
|
|
1584
|
-
].includes(attribute.relation);
|
|
1585
|
-
const constants = {
|
|
1586
|
-
MANY_RELATIONS
|
|
1587
|
-
};
|
|
1588
|
-
// Valid keys in the `options` property of relations reordering
|
|
1589
|
-
// The value for each key must be a function that returns true if it is a valid value
|
|
1590
|
-
const VALID_RELATION_ORDERING_KEYS = {
|
|
1591
|
-
strict: fp.isBoolean
|
|
1592
|
-
};
|
|
1593
|
-
|
|
1594
|
-
var relations = /*#__PURE__*/Object.freeze({
|
|
1595
|
-
__proto__: null,
|
|
1596
|
-
VALID_RELATION_ORDERING_KEYS: VALID_RELATION_ORDERING_KEYS,
|
|
1597
|
-
constants: constants,
|
|
1598
|
-
getRelationalFields: getRelationalFields,
|
|
1599
|
-
isAnyToMany: isAnyToMany,
|
|
1600
|
-
isAnyToOne: isAnyToOne,
|
|
1601
|
-
isManyToAny: isManyToAny,
|
|
1602
|
-
isOneToAny: isOneToAny,
|
|
1603
|
-
isPolymorphic: isPolymorphic
|
|
1604
|
-
});
|
|
1605
|
-
|
|
1606
|
-
const ACTIONS_TO_VERIFY$1 = [
|
|
1607
|
-
'find'
|
|
1608
|
-
];
|
|
1609
|
-
const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$1 } = constants$1;
|
|
1610
|
-
var removeRestrictedRelations = ((auth)=>async ({ data, key, attribute, schema }, { remove, set })=>{
|
|
1611
|
-
if (!attribute) {
|
|
1612
|
-
return;
|
|
1613
|
-
}
|
|
1614
|
-
const isRelation = attribute.type === 'relation';
|
|
1615
|
-
if (!isRelation) {
|
|
1616
|
-
return;
|
|
1617
|
-
}
|
|
1618
|
-
const handleMorphRelation = async ()=>{
|
|
1619
|
-
const elements = data[key];
|
|
1620
|
-
if ('connect' in elements || 'set' in elements || 'disconnect' in elements) {
|
|
1621
|
-
const newValue = {};
|
|
1622
|
-
const connect = await handleMorphElements(elements.connect || []);
|
|
1623
|
-
const relSet = await handleMorphElements(elements.set || []);
|
|
1624
|
-
const disconnect = await handleMorphElements(elements.disconnect || []);
|
|
1625
|
-
if (connect.length > 0) {
|
|
1626
|
-
newValue.connect = connect;
|
|
1627
|
-
}
|
|
1628
|
-
if (relSet.length > 0) {
|
|
1629
|
-
newValue.set = relSet;
|
|
1630
|
-
}
|
|
1631
|
-
if (disconnect.length > 0) {
|
|
1632
|
-
newValue.disconnect = disconnect;
|
|
1633
|
-
}
|
|
1634
|
-
// TODO: this should technically be in its own visitor to check morph options, but for now we'll handle it here
|
|
1635
|
-
if ('options' in elements && typeof elements.options === 'object' && elements.options !== null) {
|
|
1636
|
-
const filteredOptions = {};
|
|
1637
|
-
// Iterate through the keys of elements.options
|
|
1638
|
-
Object.keys(elements.options).forEach((key)=>{
|
|
1639
|
-
const validator = VALID_RELATION_ORDERING_KEYS[key];
|
|
1640
|
-
// Ensure the key exists in VALID_RELATION_ORDERING_KEYS and the validator is defined before calling it
|
|
1641
|
-
if (validator && validator(elements.options[key])) {
|
|
1642
|
-
filteredOptions[key] = elements.options[key];
|
|
1643
|
-
}
|
|
1644
|
-
});
|
|
1645
|
-
// Assign the filtered options back to newValue
|
|
1646
|
-
newValue.options = filteredOptions;
|
|
1647
|
-
} else {
|
|
1648
|
-
newValue.options = {};
|
|
1649
|
-
}
|
|
1650
|
-
set(key, newValue);
|
|
1651
|
-
} else {
|
|
1652
|
-
const newMorphValue = await handleMorphElements(elements);
|
|
1653
|
-
if (newMorphValue.length) {
|
|
1654
|
-
set(key, newMorphValue);
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
};
|
|
1658
|
-
const handleMorphElements = async (elements)=>{
|
|
1659
|
-
const allowedElements = [];
|
|
1660
|
-
if (!fp.isArray(elements)) {
|
|
1661
|
-
return allowedElements;
|
|
1662
|
-
}
|
|
1663
|
-
for (const element of elements){
|
|
1664
|
-
if (!fp.isObject(element) || !('__type' in element)) {
|
|
1665
|
-
continue;
|
|
1666
|
-
}
|
|
1667
|
-
const scopes = ACTIONS_TO_VERIFY$1.map((action)=>`${element.__type}.${action}`);
|
|
1668
|
-
const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
|
|
1669
|
-
if (isAllowed) {
|
|
1670
|
-
allowedElements.push(element);
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
return allowedElements;
|
|
1674
|
-
};
|
|
1675
|
-
const handleRegularRelation = async ()=>{
|
|
1676
|
-
const scopes = ACTIONS_TO_VERIFY$1.map((action)=>`${attribute.target}.${action}`);
|
|
1677
|
-
const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
|
|
1678
|
-
// If the authenticated user don't have access to any of the scopes, then remove the field
|
|
1679
|
-
if (!isAllowed) {
|
|
1680
|
-
remove(key);
|
|
1681
|
-
}
|
|
1682
|
-
};
|
|
1683
|
-
const isCreatorRelation = [
|
|
1684
|
-
CREATED_BY_ATTRIBUTE$1,
|
|
1685
|
-
UPDATED_BY_ATTRIBUTE$1
|
|
1686
|
-
].includes(key);
|
|
1687
|
-
// Polymorphic relations
|
|
1688
|
-
if (isMorphToRelationalAttribute(attribute)) {
|
|
1689
|
-
await handleMorphRelation();
|
|
1690
|
-
return;
|
|
1691
|
-
}
|
|
1692
|
-
// Creator relations
|
|
1693
|
-
if (isCreatorRelation && schema.options?.populateCreatorFields) {
|
|
1694
|
-
// do nothing
|
|
1695
|
-
return;
|
|
1696
|
-
}
|
|
1697
|
-
// Regular relations
|
|
1698
|
-
await handleRegularRelation();
|
|
1699
|
-
});
|
|
1700
|
-
const hasAccessToSomeScopes$1 = async (scopes, auth)=>{
|
|
1701
|
-
for (const scope of scopes){
|
|
1702
|
-
try {
|
|
1703
|
-
await strapi.auth.verify(auth, {
|
|
1704
|
-
scope
|
|
1705
|
-
});
|
|
1706
|
-
return true;
|
|
1707
|
-
} catch {
|
|
1708
|
-
continue;
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
return false;
|
|
1712
|
-
};
|
|
1713
|
-
|
|
1714
|
-
const visitor$6 = ({ key, attribute }, { remove })=>{
|
|
1715
|
-
if (isMorphToRelationalAttribute(attribute)) {
|
|
1716
|
-
remove(key);
|
|
1717
|
-
}
|
|
1718
|
-
};
|
|
1719
|
-
|
|
1720
|
-
const visitor$5 = ({ key, attribute }, { remove })=>{
|
|
1721
|
-
if (isDynamicZoneAttribute(attribute)) {
|
|
1722
|
-
remove(key);
|
|
1723
|
-
}
|
|
1724
|
-
};
|
|
1725
|
-
|
|
1726
|
-
var removeDisallowedFields = ((allowedFields = null)=>({ key, path: { attribute: path } }, { remove })=>{
|
|
1727
|
-
// All fields are allowed
|
|
1728
|
-
if (allowedFields === null) {
|
|
1729
|
-
return;
|
|
1730
|
-
}
|
|
1731
|
-
// Throw on invalid formats
|
|
1732
|
-
if (!(fp.isArray(allowedFields) && allowedFields.every(fp.isString))) {
|
|
1733
|
-
throw new TypeError(`Expected array of strings for allowedFields but got "${typeof allowedFields}"`);
|
|
1734
|
-
}
|
|
1735
|
-
if (fp.isNil(path)) {
|
|
1736
|
-
return;
|
|
1737
|
-
}
|
|
1738
|
-
const containedPaths = getContainedPaths$1(path);
|
|
1739
|
-
/**
|
|
1740
|
-
* Tells if the current path should be kept or not based
|
|
1741
|
-
* on the success of the check functions for any of the allowed paths.
|
|
1742
|
-
*
|
|
1743
|
-
* The check functions are defined as follow:
|
|
1744
|
-
*
|
|
1745
|
-
* `containedPaths.includes(p)`
|
|
1746
|
-
* @example
|
|
1747
|
-
* ```js
|
|
1748
|
-
* const path = 'foo.bar.field';
|
|
1749
|
-
* const p = 'foo.bar';
|
|
1750
|
-
* // it should match
|
|
1751
|
-
*
|
|
1752
|
-
* const path = 'foo.bar.field';
|
|
1753
|
-
* const p = 'bar.foo';
|
|
1754
|
-
* // it shouldn't match
|
|
1755
|
-
*
|
|
1756
|
-
* const path = 'foo.bar';
|
|
1757
|
-
* const p = 'foo.bar.field';
|
|
1758
|
-
* // it should match but isn't handled by this check
|
|
1759
|
-
* ```
|
|
1760
|
-
*
|
|
1761
|
-
* `p.startsWith(`${path}.`)`
|
|
1762
|
-
* @example
|
|
1763
|
-
* ```js
|
|
1764
|
-
* const path = 'foo.bar';
|
|
1765
|
-
* const p = 'foo.bar.field';
|
|
1766
|
-
* // it should match
|
|
1767
|
-
*
|
|
1768
|
-
* const path = 'foo.bar.field';
|
|
1769
|
-
* const p = 'bar.foo';
|
|
1770
|
-
* // it shouldn't match
|
|
1771
|
-
*
|
|
1772
|
-
* const path = 'foo.bar.field';
|
|
1773
|
-
* const p = 'foo.bar';
|
|
1774
|
-
* // it should match but isn't handled by this check
|
|
1775
|
-
* ```
|
|
1776
|
-
*/ const isPathAllowed = allowedFields.some((p)=>containedPaths.includes(p) || p.startsWith(`${path}.`));
|
|
1777
|
-
if (isPathAllowed) {
|
|
1778
|
-
return;
|
|
1779
|
-
}
|
|
1780
|
-
// Remove otherwise
|
|
1781
|
-
remove(key);
|
|
1782
|
-
});
|
|
1783
|
-
/**
|
|
1784
|
-
* Retrieve the list of allowed paths based on the given path
|
|
1785
|
-
*
|
|
1786
|
-
* @example
|
|
1787
|
-
* ```js
|
|
1788
|
-
* const containedPaths = getContainedPaths('foo');
|
|
1789
|
-
* // ['foo']
|
|
1790
|
-
*
|
|
1791
|
-
* * const containedPaths = getContainedPaths('foo.bar');
|
|
1792
|
-
* // ['foo', 'foo.bar']
|
|
1793
|
-
*
|
|
1794
|
-
* * const containedPaths = getContainedPaths('foo.bar.field');
|
|
1795
|
-
* // ['foo', 'foo.bar', 'foo.bar.field']
|
|
1796
|
-
* ```
|
|
1797
|
-
*/ const getContainedPaths$1 = (path)=>{
|
|
1798
|
-
const parts = fp.toPath(path);
|
|
1799
|
-
return parts.reduce((acc, value, index, list)=>{
|
|
1800
|
-
return [
|
|
1801
|
-
...acc,
|
|
1802
|
-
list.slice(0, index + 1).join('.')
|
|
1803
|
-
];
|
|
1804
|
-
}, []);
|
|
1805
|
-
};
|
|
1806
|
-
|
|
1807
|
-
var removeRestrictedFields = ((restrictedFields = null)=>({ key, path: { attribute: path } }, { remove })=>{
|
|
1808
|
-
// Remove all fields
|
|
1809
|
-
if (restrictedFields === null) {
|
|
1810
|
-
remove(key);
|
|
1811
|
-
return;
|
|
1812
|
-
}
|
|
1813
|
-
// Throw on invalid formats
|
|
1814
|
-
if (!(fp.isArray(restrictedFields) && restrictedFields.every(fp.isString))) {
|
|
1815
|
-
throw new TypeError(`Expected array of strings for restrictedFields but got "${typeof restrictedFields}"`);
|
|
1816
|
-
}
|
|
1817
|
-
// Remove if an exact match was found
|
|
1818
|
-
if (restrictedFields.includes(path)) {
|
|
1819
|
-
remove(key);
|
|
1820
|
-
return;
|
|
1821
|
-
}
|
|
1822
|
-
// Remove nested matches
|
|
1823
|
-
const isRestrictedNested = restrictedFields.some((allowedPath)=>path?.toString().startsWith(`${allowedPath}.`));
|
|
1824
|
-
if (isRestrictedNested) {
|
|
1825
|
-
remove(key);
|
|
1826
|
-
}
|
|
1827
|
-
});
|
|
1828
|
-
|
|
1829
|
-
const visitor$4 = ({ schema, key, value }, { set })=>{
|
|
1830
|
-
if (key === '' && value === '*') {
|
|
1831
|
-
const { attributes } = schema;
|
|
1832
|
-
const newPopulateQuery = Object.entries(attributes).filter(([, attribute])=>[
|
|
1833
|
-
'relation',
|
|
1834
|
-
'component',
|
|
1835
|
-
'media',
|
|
1836
|
-
'dynamiczone'
|
|
1837
|
-
].includes(attribute.type)).reduce((acc, [key])=>({
|
|
1838
|
-
...acc,
|
|
1839
|
-
[key]: true
|
|
1840
|
-
}), {});
|
|
1841
|
-
set('', newPopulateQuery);
|
|
1842
|
-
}
|
|
1843
|
-
};
|
|
1844
|
-
|
|
1845
|
-
var index$4 = /*#__PURE__*/Object.freeze({
|
|
1846
|
-
__proto__: null,
|
|
1847
|
-
expandWildcardPopulate: visitor$4,
|
|
1848
|
-
removeDisallowedFields: removeDisallowedFields,
|
|
1849
|
-
removeDynamicZones: visitor$5,
|
|
1850
|
-
removeMorphToRelations: visitor$6,
|
|
1851
|
-
removePassword: visitor$8,
|
|
1852
|
-
removePrivate: visitor$7,
|
|
1853
|
-
removeRestrictedFields: removeRestrictedFields,
|
|
1854
|
-
removeRestrictedRelations: removeRestrictedRelations
|
|
1855
|
-
});
|
|
1856
|
-
|
|
1857
|
-
const DEFAULT_PATH = {
|
|
1858
|
-
raw: null,
|
|
1859
|
-
attribute: null
|
|
1860
|
-
};
|
|
1861
|
-
var traverseFactory = (()=>{
|
|
1862
|
-
const state = {
|
|
1863
|
-
parsers: [],
|
|
1864
|
-
interceptors: [],
|
|
1865
|
-
ignore: [],
|
|
1866
|
-
handlers: {
|
|
1867
|
-
attributes: [],
|
|
1868
|
-
common: []
|
|
1869
|
-
}
|
|
1870
|
-
};
|
|
1871
|
-
const traverse = async (visitor, options, data)=>{
|
|
1872
|
-
const { path = DEFAULT_PATH, parent, schema, getModel } = options ?? {};
|
|
1873
|
-
// interceptors
|
|
1874
|
-
for (const { predicate, handler } of state.interceptors){
|
|
1875
|
-
if (predicate(data)) {
|
|
1876
|
-
return handler(visitor, options, data, {
|
|
1877
|
-
recurse: traverse
|
|
1878
|
-
});
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
// parsers
|
|
1882
|
-
const parser = state.parsers.find((parser)=>parser.predicate(data))?.parser;
|
|
1883
|
-
const utils = parser?.(data);
|
|
1884
|
-
// Return the data untouched if we don't know how to traverse it
|
|
1885
|
-
if (!utils) {
|
|
1886
|
-
return data;
|
|
1887
|
-
}
|
|
1888
|
-
// main loop
|
|
1889
|
-
let out = utils.transform(data);
|
|
1890
|
-
const keys = utils.keys(out);
|
|
1891
|
-
for (const key of keys){
|
|
1892
|
-
const attribute = schema?.attributes?.[key];
|
|
1893
|
-
const newPath = {
|
|
1894
|
-
...path
|
|
1895
|
-
};
|
|
1896
|
-
newPath.raw = fp.isNil(path.raw) ? key : `${path.raw}.${key}`;
|
|
1897
|
-
if (!fp.isNil(attribute)) {
|
|
1898
|
-
newPath.attribute = fp.isNil(path.attribute) ? key : `${path.attribute}.${key}`;
|
|
1899
|
-
}
|
|
1900
|
-
// visitors
|
|
1901
|
-
const visitorOptions = {
|
|
1902
|
-
key,
|
|
1903
|
-
value: utils.get(key, out),
|
|
1904
|
-
attribute,
|
|
1905
|
-
schema,
|
|
1906
|
-
path: newPath,
|
|
1907
|
-
data: out,
|
|
1908
|
-
getModel,
|
|
1909
|
-
parent
|
|
1910
|
-
};
|
|
1911
|
-
const transformUtils = {
|
|
1912
|
-
remove (key) {
|
|
1913
|
-
out = utils.remove(key, out);
|
|
1914
|
-
},
|
|
1915
|
-
set (key, value) {
|
|
1916
|
-
out = utils.set(key, value, out);
|
|
1917
|
-
},
|
|
1918
|
-
recurse: traverse
|
|
1919
|
-
};
|
|
1920
|
-
await visitor(visitorOptions, fp.pick([
|
|
1921
|
-
'remove',
|
|
1922
|
-
'set'
|
|
1923
|
-
], transformUtils));
|
|
1924
|
-
const value = utils.get(key, out);
|
|
1925
|
-
const createContext = ()=>({
|
|
1926
|
-
key,
|
|
1927
|
-
value,
|
|
1928
|
-
attribute,
|
|
1929
|
-
schema,
|
|
1930
|
-
path: newPath,
|
|
1931
|
-
data: out,
|
|
1932
|
-
visitor,
|
|
1933
|
-
getModel,
|
|
1934
|
-
parent
|
|
1935
|
-
});
|
|
1936
|
-
// ignore
|
|
1937
|
-
const ignoreCtx = createContext();
|
|
1938
|
-
const shouldIgnore = state.ignore.some((predicate)=>predicate(ignoreCtx));
|
|
1939
|
-
if (shouldIgnore) {
|
|
1940
|
-
continue;
|
|
1941
|
-
}
|
|
1942
|
-
// handlers
|
|
1943
|
-
const handlers = [
|
|
1944
|
-
...state.handlers.common,
|
|
1945
|
-
...state.handlers.attributes
|
|
1946
|
-
];
|
|
1947
|
-
for await (const handler of handlers){
|
|
1948
|
-
const ctx = createContext();
|
|
1949
|
-
const pass = await handler.predicate(ctx);
|
|
1950
|
-
if (pass) {
|
|
1951
|
-
await handler.handler(ctx, fp.pick([
|
|
1952
|
-
'recurse',
|
|
1953
|
-
'set'
|
|
1954
|
-
], transformUtils));
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
return out;
|
|
1959
|
-
};
|
|
1960
|
-
return {
|
|
1961
|
-
traverse,
|
|
1962
|
-
intercept (predicate, handler) {
|
|
1963
|
-
state.interceptors.push({
|
|
1964
|
-
predicate,
|
|
1965
|
-
handler
|
|
1966
|
-
});
|
|
1967
|
-
return this;
|
|
1968
|
-
},
|
|
1969
|
-
parse (predicate, parser) {
|
|
1970
|
-
state.parsers.push({
|
|
1971
|
-
predicate,
|
|
1972
|
-
parser
|
|
1973
|
-
});
|
|
1974
|
-
return this;
|
|
1975
|
-
},
|
|
1976
|
-
ignore (predicate) {
|
|
1977
|
-
state.ignore.push(predicate);
|
|
1978
|
-
return this;
|
|
1979
|
-
},
|
|
1980
|
-
on (predicate, handler) {
|
|
1981
|
-
state.handlers.common.push({
|
|
1982
|
-
predicate,
|
|
1983
|
-
handler
|
|
1984
|
-
});
|
|
1985
|
-
return this;
|
|
1986
|
-
},
|
|
1987
|
-
onAttribute (predicate, handler) {
|
|
1988
|
-
state.handlers.attributes.push({
|
|
1989
|
-
predicate,
|
|
1990
|
-
handler
|
|
1991
|
-
});
|
|
1992
|
-
return this;
|
|
1993
|
-
},
|
|
1994
|
-
onRelation (handler) {
|
|
1995
|
-
return this.onAttribute(({ attribute })=>attribute?.type === 'relation', handler);
|
|
1996
|
-
},
|
|
1997
|
-
onMedia (handler) {
|
|
1998
|
-
return this.onAttribute(({ attribute })=>attribute?.type === 'media', handler);
|
|
1999
|
-
},
|
|
2000
|
-
onComponent (handler) {
|
|
2001
|
-
return this.onAttribute(({ attribute })=>attribute?.type === 'component', handler);
|
|
2002
|
-
},
|
|
2003
|
-
onDynamicZone (handler) {
|
|
2004
|
-
return this.onAttribute(({ attribute })=>attribute?.type === 'dynamiczone', handler);
|
|
2005
|
-
}
|
|
2006
|
-
};
|
|
2007
|
-
});
|
|
2008
|
-
|
|
2009
|
-
const isObj$2 = (value)=>fp.isObject(value);
|
|
2010
|
-
const filters = traverseFactory().intercept(// Intercept filters arrays and apply the traversal to each one individually
|
|
2011
|
-
fp.isArray, async (visitor, options, filters, { recurse })=>{
|
|
2012
|
-
return Promise.all(filters.map((filter, i)=>{
|
|
2013
|
-
// In filters, only operators such as $and, $in, $notIn or $or and implicit operators like [...]
|
|
2014
|
-
// can have a value array, thus we can update the raw path but not the attribute one
|
|
2015
|
-
const newPath = options.path ? {
|
|
2016
|
-
...options.path,
|
|
2017
|
-
raw: `${options.path.raw}[${i}]`
|
|
2018
|
-
} : options.path;
|
|
2019
|
-
return recurse(visitor, {
|
|
2020
|
-
...options,
|
|
2021
|
-
path: newPath
|
|
2022
|
-
}, filter);
|
|
2023
|
-
})).then((res)=>res.filter((val)=>!(fp.isObject(val) && fp.isEmpty(val))));
|
|
2024
|
-
}).intercept(// Ignore non object filters and return the value as-is
|
|
2025
|
-
(filters)=>!fp.isObject(filters), (_, __, filters)=>{
|
|
2026
|
-
return filters;
|
|
2027
|
-
})// Parse object values
|
|
2028
|
-
.parse(isObj$2, ()=>({
|
|
2029
|
-
transform: fp.cloneDeep,
|
|
2030
|
-
remove (key, data) {
|
|
2031
|
-
return fp.omit(key, data);
|
|
2032
|
-
},
|
|
2033
|
-
set (key, value, data) {
|
|
2034
|
-
return {
|
|
2035
|
-
...data,
|
|
2036
|
-
[key]: value
|
|
2037
|
-
};
|
|
2038
|
-
},
|
|
2039
|
-
keys (data) {
|
|
2040
|
-
return Object.keys(data);
|
|
2041
|
-
},
|
|
2042
|
-
get (key, data) {
|
|
2043
|
-
return data[key];
|
|
2044
|
-
}
|
|
2045
|
-
}))// Ignore null or undefined values
|
|
2046
|
-
.ignore(({ value })=>fp.isNil(value))// Recursion on operators (non attributes)
|
|
2047
|
-
.on(({ attribute })=>fp.isNil(attribute), async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse })=>{
|
|
2048
|
-
const parent = {
|
|
2049
|
-
key,
|
|
2050
|
-
path,
|
|
2051
|
-
schema,
|
|
2052
|
-
attribute
|
|
2053
|
-
};
|
|
2054
|
-
set(key, await recurse(visitor, {
|
|
2055
|
-
schema,
|
|
2056
|
-
path,
|
|
2057
|
-
getModel,
|
|
2058
|
-
parent
|
|
2059
|
-
}, value));
|
|
2060
|
-
})// Handle relation recursion
|
|
2061
|
-
.onRelation(async ({ key, attribute, visitor, path, value, schema, getModel }, { set, recurse })=>{
|
|
2062
|
-
const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');
|
|
2063
|
-
if (isMorphRelation) {
|
|
2064
|
-
return;
|
|
2065
|
-
}
|
|
2066
|
-
const parent = {
|
|
2067
|
-
key,
|
|
2068
|
-
path,
|
|
2069
|
-
schema,
|
|
2070
|
-
attribute
|
|
2071
|
-
};
|
|
2072
|
-
const targetSchemaUID = attribute.target;
|
|
2073
|
-
const targetSchema = getModel(targetSchemaUID);
|
|
2074
|
-
const newValue = await recurse(visitor, {
|
|
2075
|
-
schema: targetSchema,
|
|
2076
|
-
path,
|
|
2077
|
-
getModel,
|
|
2078
|
-
parent
|
|
2079
|
-
}, value);
|
|
2080
|
-
set(key, newValue);
|
|
2081
|
-
}).onComponent(async ({ key, attribute, visitor, path, schema, value, getModel }, { set, recurse })=>{
|
|
2082
|
-
const parent = {
|
|
2083
|
-
key,
|
|
2084
|
-
path,
|
|
2085
|
-
schema,
|
|
2086
|
-
attribute
|
|
2087
|
-
};
|
|
2088
|
-
const targetSchema = getModel(attribute.component);
|
|
2089
|
-
const newValue = await recurse(visitor, {
|
|
2090
|
-
schema: targetSchema,
|
|
2091
|
-
path,
|
|
2092
|
-
getModel,
|
|
2093
|
-
parent
|
|
2094
|
-
}, value);
|
|
2095
|
-
set(key, newValue);
|
|
2096
|
-
})// Handle media recursion
|
|
2097
|
-
.onMedia(async ({ key, visitor, path, schema, attribute, value, getModel }, { set, recurse })=>{
|
|
2098
|
-
const parent = {
|
|
2099
|
-
key,
|
|
2100
|
-
path,
|
|
2101
|
-
schema,
|
|
2102
|
-
attribute
|
|
2103
|
-
};
|
|
2104
|
-
const targetSchemaUID = 'plugin::upload.file';
|
|
2105
|
-
const targetSchema = getModel(targetSchemaUID);
|
|
2106
|
-
const newValue = await recurse(visitor, {
|
|
2107
|
-
schema: targetSchema,
|
|
2108
|
-
path,
|
|
2109
|
-
getModel,
|
|
2110
|
-
parent
|
|
2111
|
-
}, value);
|
|
2112
|
-
set(key, newValue);
|
|
2113
|
-
});
|
|
2114
|
-
var traverseQueryFilters = fp.curry(filters.traverse);
|
|
2115
|
-
|
|
2116
|
-
const ORDERS = {
|
|
2117
|
-
asc: 'asc',
|
|
2118
|
-
desc: 'desc'
|
|
2119
|
-
};
|
|
2120
|
-
const ORDER_VALUES = Object.values(ORDERS);
|
|
2121
|
-
const isSortOrder = (value)=>ORDER_VALUES.includes(value.toLowerCase());
|
|
2122
|
-
const isStringArray$2 = (value)=>Array.isArray(value) && value.every(fp.isString);
|
|
2123
|
-
const isObjectArray = (value)=>Array.isArray(value) && value.every(fp.isObject);
|
|
2124
|
-
const isNestedSorts = (value)=>fp.isString(value) && value.split(',').length > 1;
|
|
2125
|
-
const isObj$1 = (value)=>fp.isObject(value);
|
|
2126
|
-
const sort = traverseFactory().intercept(// String with chained sorts (foo,bar,foobar) => split, map(recurse), then recompose
|
|
2127
|
-
isNestedSorts, async (visitor, options, sort, { recurse })=>{
|
|
2128
|
-
return Promise.all(sort.split(',').map(fp.trim).map((nestedSort)=>recurse(visitor, options, nestedSort))).then((res)=>res.filter((part)=>!fp.isEmpty(part)).join(','));
|
|
2129
|
-
}).intercept(// Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items
|
|
2130
|
-
isStringArray$2, async (visitor, options, sort, { recurse })=>{
|
|
2131
|
-
return Promise.all(sort.map((nestedSort)=>recurse(visitor, options, nestedSort))).then((res)=>res.filter((nestedSort)=>!fp.isEmpty(nestedSort)));
|
|
2132
|
-
}).intercept(// Array of objects [{ foo: 'asc' }, { bar: 'desc', baz: 'asc' }] => map(recurse), then filter out empty items
|
|
2133
|
-
isObjectArray, async (visitor, options, sort, { recurse })=>{
|
|
2134
|
-
return Promise.all(sort.map((nestedSort)=>recurse(visitor, options, nestedSort))).then((res)=>res.filter((nestedSort)=>!fp.isEmpty(nestedSort)));
|
|
2135
|
-
})// Parse string values
|
|
2136
|
-
.parse(fp.isString, ()=>{
|
|
2137
|
-
const tokenize = fp.pipe(fp.split('.'), fp.map(fp.split(':')), fp.flatten);
|
|
2138
|
-
const recompose = (parts)=>{
|
|
2139
|
-
if (parts.length === 0) {
|
|
2140
|
-
return undefined;
|
|
2141
|
-
}
|
|
2142
|
-
return parts.reduce((acc, part)=>{
|
|
2143
|
-
if (fp.isEmpty(part)) {
|
|
2144
|
-
return acc;
|
|
2145
|
-
}
|
|
2146
|
-
if (acc === '') {
|
|
2147
|
-
return part;
|
|
2148
|
-
}
|
|
2149
|
-
return isSortOrder(part) ? `${acc}:${part}` : `${acc}.${part}`;
|
|
2150
|
-
}, '');
|
|
2151
|
-
};
|
|
2152
|
-
return {
|
|
2153
|
-
transform: fp.trim,
|
|
2154
|
-
remove (key, data) {
|
|
2155
|
-
const [root] = tokenize(data);
|
|
2156
|
-
return root === key ? undefined : data;
|
|
2157
|
-
},
|
|
2158
|
-
set (key, value, data) {
|
|
2159
|
-
const [root] = tokenize(data);
|
|
2160
|
-
if (root !== key) {
|
|
2161
|
-
return data;
|
|
2162
|
-
}
|
|
2163
|
-
return fp.isNil(value) ? root : `${root}.${value}`;
|
|
2164
|
-
},
|
|
2165
|
-
keys (data) {
|
|
2166
|
-
const v = fp.first(tokenize(data));
|
|
2167
|
-
return v ? [
|
|
2168
|
-
v
|
|
2169
|
-
] : [];
|
|
2170
|
-
},
|
|
2171
|
-
get (key, data) {
|
|
2172
|
-
const [root, ...rest] = tokenize(data);
|
|
2173
|
-
return key === root ? recompose(rest) : undefined;
|
|
2174
|
-
}
|
|
2175
|
-
};
|
|
2176
|
-
})// Parse object values
|
|
2177
|
-
.parse(isObj$1, ()=>({
|
|
2178
|
-
transform: fp.cloneDeep,
|
|
2179
|
-
remove (key, data) {
|
|
2180
|
-
// eslint-disable-next-line no-unused-vars
|
|
2181
|
-
const { [key]: ignored, ...rest } = data;
|
|
2182
|
-
return rest;
|
|
2183
|
-
},
|
|
2184
|
-
set (key, value, data) {
|
|
2185
|
-
return {
|
|
2186
|
-
...data,
|
|
2187
|
-
[key]: value
|
|
2188
|
-
};
|
|
2189
|
-
},
|
|
2190
|
-
keys (data) {
|
|
2191
|
-
return Object.keys(data);
|
|
2192
|
-
},
|
|
2193
|
-
get (key, data) {
|
|
2194
|
-
return data[key];
|
|
2195
|
-
}
|
|
2196
|
-
}))// Handle deep sort on relation
|
|
2197
|
-
.onRelation(async ({ key, value, attribute, visitor, path, getModel, schema }, { set, recurse })=>{
|
|
2198
|
-
const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');
|
|
2199
|
-
if (isMorphRelation) {
|
|
2200
|
-
return;
|
|
2201
|
-
}
|
|
2202
|
-
const parent = {
|
|
2203
|
-
key,
|
|
2204
|
-
path,
|
|
2205
|
-
schema,
|
|
2206
|
-
attribute
|
|
2207
|
-
};
|
|
2208
|
-
const targetSchemaUID = attribute.target;
|
|
2209
|
-
const targetSchema = getModel(targetSchemaUID);
|
|
2210
|
-
const newValue = await recurse(visitor, {
|
|
2211
|
-
schema: targetSchema,
|
|
2212
|
-
path,
|
|
2213
|
-
getModel,
|
|
2214
|
-
parent
|
|
2215
|
-
}, value);
|
|
2216
|
-
set(key, newValue);
|
|
2217
|
-
})// Handle deep sort on media
|
|
2218
|
-
.onMedia(async ({ key, path, schema, attribute, visitor, value, getModel }, { recurse, set })=>{
|
|
2219
|
-
const parent = {
|
|
2220
|
-
key,
|
|
2221
|
-
path,
|
|
2222
|
-
schema,
|
|
2223
|
-
attribute
|
|
2224
|
-
};
|
|
2225
|
-
const targetSchemaUID = 'plugin::upload.file';
|
|
2226
|
-
const targetSchema = getModel(targetSchemaUID);
|
|
2227
|
-
const newValue = await recurse(visitor, {
|
|
2228
|
-
schema: targetSchema,
|
|
2229
|
-
path,
|
|
2230
|
-
getModel,
|
|
2231
|
-
parent
|
|
2232
|
-
}, value);
|
|
2233
|
-
set(key, newValue);
|
|
2234
|
-
})// Handle deep sort on components
|
|
2235
|
-
.onComponent(async ({ key, value, visitor, path, schema, attribute, getModel }, { recurse, set })=>{
|
|
2236
|
-
const parent = {
|
|
2237
|
-
key,
|
|
2238
|
-
path,
|
|
2239
|
-
schema,
|
|
2240
|
-
attribute
|
|
2241
|
-
};
|
|
2242
|
-
const targetSchema = getModel(attribute.component);
|
|
2243
|
-
const newValue = await recurse(visitor, {
|
|
2244
|
-
schema: targetSchema,
|
|
2245
|
-
path,
|
|
2246
|
-
getModel,
|
|
2247
|
-
parent
|
|
2248
|
-
}, value);
|
|
2249
|
-
set(key, newValue);
|
|
2250
|
-
});
|
|
2251
|
-
var traverseQuerySort = fp.curry(sort.traverse);
|
|
2252
|
-
|
|
2253
|
-
const isKeyword = (keyword)=>{
|
|
2254
|
-
return ({ key, attribute })=>{
|
|
2255
|
-
return !attribute && keyword === key;
|
|
2256
|
-
};
|
|
2257
|
-
};
|
|
2258
|
-
const isWildcard = (value)=>value === '*';
|
|
2259
|
-
const isPopulateString = (value)=>{
|
|
2260
|
-
return fp.isString(value) && !isWildcard(value);
|
|
2261
|
-
};
|
|
2262
|
-
const isStringArray$1 = (value)=>fp.isArray(value) && value.every(fp.isString);
|
|
2263
|
-
const isObj = (value)=>fp.isObject(value);
|
|
2264
|
-
const populate = traverseFactory().intercept(isPopulateString, async (visitor, options, populate, { recurse })=>{
|
|
2265
|
-
/**
|
|
2266
|
-
* Ensure the populate clause its in the extended format ( { populate: { ... } }, and not just a string)
|
|
2267
|
-
* This gives a consistent structure to track the "parent" node of each nested populate clause
|
|
2268
|
-
*/ const populateObject = pathsToObjectPopulate([
|
|
2269
|
-
populate
|
|
2270
|
-
]);
|
|
2271
|
-
const traversedPopulate = await recurse(visitor, options, populateObject);
|
|
2272
|
-
const [result] = objectPopulateToPaths(traversedPopulate);
|
|
2273
|
-
return result;
|
|
2274
|
-
})// Array of strings ['foo', 'bar.baz'] => map(recurse), then filter out empty items
|
|
2275
|
-
.intercept(isStringArray$1, async (visitor, options, populate, { recurse })=>{
|
|
2276
|
-
const paths = await Promise.all(populate.map((subClause)=>recurse(visitor, options, subClause)));
|
|
2277
|
-
return paths.filter((item)=>!fp.isNil(item));
|
|
2278
|
-
})// for wildcard, generate custom utilities to modify the values
|
|
2279
|
-
.parse(isWildcard, ()=>({
|
|
2280
|
-
/**
|
|
2281
|
-
* Since value is '*', we don't need to transform it
|
|
2282
|
-
*/ transform: fp.identity,
|
|
2283
|
-
/**
|
|
2284
|
-
* '*' isn't a key/value structure, so regardless
|
|
2285
|
-
* of the given key, it returns the data ('*')
|
|
2286
|
-
*/ get: (_key, data)=>data,
|
|
2287
|
-
/**
|
|
2288
|
-
* '*' isn't a key/value structure, so regardless
|
|
2289
|
-
* of the given `key`, use `value` as the new `data`
|
|
2290
|
-
*/ set: (_key, value)=>value,
|
|
2291
|
-
/**
|
|
2292
|
-
* '*' isn't a key/value structure, but we need to simulate at least one to enable
|
|
2293
|
-
* the data traversal. We're using '' since it represents a falsy string value
|
|
2294
|
-
*/ keys: fp.constant([
|
|
2295
|
-
''
|
|
2296
|
-
]),
|
|
2297
|
-
/**
|
|
2298
|
-
* Removing '*' means setting it to undefined, regardless of the given key
|
|
2299
|
-
*/ remove: fp.constant(undefined)
|
|
2300
|
-
}))// Parse string values
|
|
2301
|
-
.parse(fp.isString, ()=>{
|
|
2302
|
-
const tokenize = fp.split('.');
|
|
2303
|
-
const recompose = fp.join('.');
|
|
2304
|
-
return {
|
|
2305
|
-
transform: fp.trim,
|
|
2306
|
-
remove (key, data) {
|
|
2307
|
-
const [root] = tokenize(data);
|
|
2308
|
-
return root === key ? undefined : data;
|
|
2309
|
-
},
|
|
2310
|
-
set (key, value, data) {
|
|
2311
|
-
const [root] = tokenize(data);
|
|
2312
|
-
if (root !== key) {
|
|
2313
|
-
return data;
|
|
2314
|
-
}
|
|
2315
|
-
return fp.isNil(value) || fp.isEmpty(value) ? root : `${root}.${value}`;
|
|
2316
|
-
},
|
|
2317
|
-
keys (data) {
|
|
2318
|
-
const v = fp.first(tokenize(data));
|
|
2319
|
-
return v ? [
|
|
2320
|
-
v
|
|
2321
|
-
] : [];
|
|
2322
|
-
},
|
|
2323
|
-
get (key, data) {
|
|
2324
|
-
const [root, ...rest] = tokenize(data);
|
|
2325
|
-
return key === root ? recompose(rest) : undefined;
|
|
2326
|
-
}
|
|
2327
|
-
};
|
|
2328
|
-
})// Parse object values
|
|
2329
|
-
.parse(isObj, ()=>({
|
|
2330
|
-
transform: fp.cloneDeep,
|
|
2331
|
-
remove (key, data) {
|
|
2332
|
-
// eslint-disable-next-line no-unused-vars
|
|
2333
|
-
const { [key]: ignored, ...rest } = data;
|
|
2334
|
-
return rest;
|
|
2335
|
-
},
|
|
2336
|
-
set (key, value, data) {
|
|
2337
|
-
return {
|
|
2338
|
-
...data,
|
|
2339
|
-
[key]: value
|
|
2340
|
-
};
|
|
2341
|
-
},
|
|
2342
|
-
keys (data) {
|
|
2343
|
-
return Object.keys(data);
|
|
2344
|
-
},
|
|
2345
|
-
get (key, data) {
|
|
2346
|
-
return data[key];
|
|
2347
|
-
}
|
|
2348
|
-
})).ignore(({ key, attribute })=>{
|
|
2349
|
-
// we don't want to recurse using traversePopulate and instead let
|
|
2350
|
-
// the visitors recurse with the appropriate traversal (sort, filters, etc...)
|
|
2351
|
-
return [
|
|
2352
|
-
'sort',
|
|
2353
|
-
'filters',
|
|
2354
|
-
'fields'
|
|
2355
|
-
].includes(key) && !attribute;
|
|
2356
|
-
}).on(// Handle recursion on populate."populate"
|
|
2357
|
-
isKeyword('populate'), async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse })=>{
|
|
2358
|
-
const parent = {
|
|
2359
|
-
key,
|
|
2360
|
-
path,
|
|
2361
|
-
schema,
|
|
2362
|
-
attribute
|
|
2363
|
-
};
|
|
2364
|
-
const newValue = await recurse(visitor, {
|
|
2365
|
-
schema,
|
|
2366
|
-
path,
|
|
2367
|
-
getModel,
|
|
2368
|
-
parent
|
|
2369
|
-
}, value);
|
|
2370
|
-
set(key, newValue);
|
|
2371
|
-
}).on(isKeyword('on'), async ({ key, visitor, path, value, getModel, parent }, { set, recurse })=>{
|
|
2372
|
-
const newOn = {};
|
|
2373
|
-
if (!isObj(value)) {
|
|
2374
|
-
return;
|
|
2375
|
-
}
|
|
2376
|
-
for (const [uid, subPopulate] of Object.entries(value)){
|
|
2377
|
-
const model = getModel(uid);
|
|
2378
|
-
const newPath = {
|
|
2379
|
-
...path,
|
|
2380
|
-
raw: `${path.raw}[${uid}]`
|
|
2381
|
-
};
|
|
2382
|
-
newOn[uid] = await recurse(visitor, {
|
|
2383
|
-
schema: model,
|
|
2384
|
-
path: newPath,
|
|
2385
|
-
getModel,
|
|
2386
|
-
parent
|
|
2387
|
-
}, subPopulate);
|
|
2388
|
-
}
|
|
2389
|
-
set(key, newOn);
|
|
2390
|
-
})// Handle populate on relation
|
|
2391
|
-
.onRelation(async ({ key, value, attribute, visitor, path, schema, getModel }, { set, recurse })=>{
|
|
2392
|
-
if (fp.isNil(value)) {
|
|
2393
|
-
return;
|
|
2394
|
-
}
|
|
2395
|
-
const parent = {
|
|
2396
|
-
key,
|
|
2397
|
-
path,
|
|
2398
|
-
schema,
|
|
2399
|
-
attribute
|
|
2400
|
-
};
|
|
2401
|
-
if (isMorphToRelationalAttribute(attribute)) {
|
|
2402
|
-
// Don't traverse values that cannot be parsed
|
|
2403
|
-
if (!fp.isObject(value) || !('on' in value && fp.isObject(value?.on))) {
|
|
2404
|
-
return;
|
|
2405
|
-
}
|
|
2406
|
-
// If there is a populate fragment defined, traverse it
|
|
2407
|
-
const newValue = await recurse(visitor, {
|
|
2408
|
-
schema,
|
|
2409
|
-
path,
|
|
2410
|
-
getModel,
|
|
2411
|
-
parent
|
|
2412
|
-
}, {
|
|
2413
|
-
on: value?.on
|
|
2414
|
-
});
|
|
2415
|
-
set(key, newValue);
|
|
2416
|
-
return;
|
|
2417
|
-
}
|
|
2418
|
-
const targetSchemaUID = attribute.target;
|
|
2419
|
-
const targetSchema = getModel(targetSchemaUID);
|
|
2420
|
-
const newValue = await recurse(visitor, {
|
|
2421
|
-
schema: targetSchema,
|
|
2422
|
-
path,
|
|
2423
|
-
getModel,
|
|
2424
|
-
parent
|
|
2425
|
-
}, value);
|
|
2426
|
-
set(key, newValue);
|
|
2427
|
-
})// Handle populate on media
|
|
2428
|
-
.onMedia(async ({ key, path, schema, attribute, visitor, value, getModel }, { recurse, set })=>{
|
|
2429
|
-
if (fp.isNil(value)) {
|
|
2430
|
-
return;
|
|
2431
|
-
}
|
|
2432
|
-
const parent = {
|
|
2433
|
-
key,
|
|
2434
|
-
path,
|
|
2435
|
-
schema,
|
|
2436
|
-
attribute
|
|
2437
|
-
};
|
|
2438
|
-
const targetSchemaUID = 'plugin::upload.file';
|
|
2439
|
-
const targetSchema = getModel(targetSchemaUID);
|
|
2440
|
-
const newValue = await recurse(visitor, {
|
|
2441
|
-
schema: targetSchema,
|
|
2442
|
-
path,
|
|
2443
|
-
getModel,
|
|
2444
|
-
parent
|
|
2445
|
-
}, value);
|
|
2446
|
-
set(key, newValue);
|
|
2447
|
-
})// Handle populate on components
|
|
2448
|
-
.onComponent(async ({ key, value, schema, visitor, path, attribute, getModel }, { recurse, set })=>{
|
|
2449
|
-
if (fp.isNil(value)) {
|
|
2450
|
-
return;
|
|
2451
|
-
}
|
|
2452
|
-
const parent = {
|
|
2453
|
-
key,
|
|
2454
|
-
path,
|
|
2455
|
-
schema,
|
|
2456
|
-
attribute
|
|
2457
|
-
};
|
|
2458
|
-
const targetSchema = getModel(attribute.component);
|
|
2459
|
-
const newValue = await recurse(visitor, {
|
|
2460
|
-
schema: targetSchema,
|
|
2461
|
-
path,
|
|
2462
|
-
getModel,
|
|
2463
|
-
parent
|
|
2464
|
-
}, value);
|
|
2465
|
-
set(key, newValue);
|
|
2466
|
-
})// Handle populate on dynamic zones
|
|
2467
|
-
.onDynamicZone(async ({ key, value, schema, visitor, path, attribute, getModel }, { set, recurse })=>{
|
|
2468
|
-
if (fp.isNil(value) || !fp.isObject(value)) {
|
|
2469
|
-
return;
|
|
2470
|
-
}
|
|
2471
|
-
const parent = {
|
|
2472
|
-
key,
|
|
2473
|
-
path,
|
|
2474
|
-
schema,
|
|
2475
|
-
attribute
|
|
2476
|
-
};
|
|
2477
|
-
// Handle fragment syntax
|
|
2478
|
-
if ('on' in value && value.on) {
|
|
2479
|
-
const newOn = await recurse(visitor, {
|
|
2480
|
-
schema,
|
|
2481
|
-
path,
|
|
2482
|
-
getModel,
|
|
2483
|
-
parent
|
|
2484
|
-
}, {
|
|
2485
|
-
on: value.on
|
|
2486
|
-
});
|
|
2487
|
-
set(key, newOn);
|
|
2488
|
-
}
|
|
2489
|
-
});
|
|
2490
|
-
var traverseQueryPopulate = fp.curry(populate.traverse);
|
|
2491
|
-
const objectPopulateToPaths = (input)=>{
|
|
2492
|
-
const paths = [];
|
|
2493
|
-
function traverse(currentObj, parentPath) {
|
|
2494
|
-
for (const [key, value] of Object.entries(currentObj)){
|
|
2495
|
-
const currentPath = parentPath ? `${parentPath}.${key}` : key;
|
|
2496
|
-
if (value === true) {
|
|
2497
|
-
paths.push(currentPath);
|
|
2498
|
-
} else {
|
|
2499
|
-
traverse(value.populate, currentPath);
|
|
2500
|
-
}
|
|
2501
|
-
}
|
|
2502
|
-
}
|
|
2503
|
-
traverse(input, '');
|
|
2504
|
-
return paths;
|
|
2505
|
-
};
|
|
2506
|
-
const pathsToObjectPopulate = (input)=>{
|
|
2507
|
-
const result = {};
|
|
2508
|
-
function traverse(object, keys) {
|
|
2509
|
-
const [first, ...rest] = keys;
|
|
2510
|
-
if (rest.length === 0) {
|
|
2511
|
-
object[first] = true;
|
|
2512
|
-
} else {
|
|
2513
|
-
if (!object[first] || typeof object[first] === 'boolean') {
|
|
2514
|
-
object[first] = {
|
|
2515
|
-
populate: {}
|
|
2516
|
-
};
|
|
2517
|
-
}
|
|
2518
|
-
traverse(object[first].populate, rest);
|
|
2519
|
-
}
|
|
2520
|
-
}
|
|
2521
|
-
input.forEach((clause)=>traverse(result, clause.split('.')));
|
|
2522
|
-
return result;
|
|
2523
|
-
};
|
|
2524
|
-
|
|
2525
|
-
const isStringArray = (value)=>{
|
|
2526
|
-
return fp.isArray(value) && value.every(fp.isString);
|
|
2527
|
-
};
|
|
2528
|
-
const fields = traverseFactory()// Intercept array of strings
|
|
2529
|
-
// e.g. fields=['title', 'description']
|
|
2530
|
-
.intercept(isStringArray, async (visitor, options, fields, { recurse })=>{
|
|
2531
|
-
return Promise.all(fields.map((field)=>recurse(visitor, options, field)));
|
|
2532
|
-
})// Intercept comma separated fields (as string)
|
|
2533
|
-
// e.g. fields='title,description'
|
|
2534
|
-
.intercept((value)=>fp.isString(value) && value.includes(','), (visitor, options, fields, { recurse })=>{
|
|
2535
|
-
return Promise.all(fields.split(',').map((field)=>recurse(visitor, options, field)));
|
|
2536
|
-
})// Return wildcards as is
|
|
2537
|
-
.intercept((value)=>fp.eq('*', value), fp.constant('*'))// Parse string values
|
|
2538
|
-
// Since we're parsing strings only, each value should be an attribute name (and it's value, undefined),
|
|
2539
|
-
// thus it shouldn't be possible to set a new value, and get should return the whole data if key === data
|
|
2540
|
-
.parse(fp.isString, ()=>({
|
|
2541
|
-
transform: fp.trim,
|
|
2542
|
-
remove (key, data) {
|
|
2543
|
-
return data === key ? undefined : data;
|
|
2544
|
-
},
|
|
2545
|
-
set (_key, _value, data) {
|
|
2546
|
-
return data;
|
|
2547
|
-
},
|
|
2548
|
-
keys (data) {
|
|
2549
|
-
return [
|
|
2550
|
-
data
|
|
2551
|
-
];
|
|
2552
|
-
},
|
|
2553
|
-
get (key, data) {
|
|
2554
|
-
return key === data ? data : undefined;
|
|
2555
|
-
}
|
|
2556
|
-
}));
|
|
2557
|
-
var traverseQueryFields = fp.curry(fields.traverse);
|
|
2558
|
-
|
|
2559
|
-
var index$3 = /*#__PURE__*/Object.freeze({
|
|
2560
|
-
__proto__: null,
|
|
2561
|
-
traverseQueryFields: traverseQueryFields,
|
|
2562
|
-
traverseQueryFilters: traverseQueryFilters,
|
|
2563
|
-
traverseQueryPopulate: traverseQueryPopulate,
|
|
2564
|
-
traverseQuerySort: traverseQuerySort
|
|
2565
|
-
});
|
|
2566
|
-
|
|
2567
|
-
const { ID_ATTRIBUTE: ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$2 } = constants$1;
|
|
2568
|
-
const sanitizePasswords = (ctx)=>async (entity)=>{
|
|
2569
|
-
if (!ctx.schema) {
|
|
2570
|
-
throw new Error('Missing schema in sanitizePasswords');
|
|
2571
|
-
}
|
|
2572
|
-
return traverseEntity$1(visitor$8, ctx, entity);
|
|
2573
|
-
};
|
|
2574
|
-
const defaultSanitizeOutput = async (ctx, entity)=>{
|
|
2575
|
-
if (!ctx.schema) {
|
|
2576
|
-
throw new Error('Missing schema in defaultSanitizeOutput');
|
|
2577
|
-
}
|
|
2578
|
-
return traverseEntity$1((...args)=>{
|
|
2579
|
-
visitor$8(...args);
|
|
2580
|
-
visitor$7(...args);
|
|
2581
|
-
}, ctx, entity);
|
|
2582
|
-
};
|
|
2583
|
-
const defaultSanitizeFilters = fp.curry((ctx, filters)=>{
|
|
2584
|
-
if (!ctx.schema) {
|
|
2585
|
-
throw new Error('Missing schema in defaultSanitizeFilters');
|
|
2586
|
-
}
|
|
2587
|
-
return pipe(// Remove keys that are not attributes or valid operators
|
|
2588
|
-
traverseQueryFilters(({ key, attribute }, { remove })=>{
|
|
2589
|
-
const isAttribute = !!attribute;
|
|
2590
|
-
// ID is not an attribute per se, so we need to make
|
|
2591
|
-
// an extra check to ensure we're not checking it
|
|
2592
|
-
if ([
|
|
2593
|
-
ID_ATTRIBUTE$2,
|
|
2594
|
-
DOC_ID_ATTRIBUTE$2
|
|
2595
|
-
].includes(key)) {
|
|
2596
|
-
return;
|
|
2597
|
-
}
|
|
2598
|
-
if (!isAttribute && !isOperator(key)) {
|
|
2599
|
-
remove(key);
|
|
2600
|
-
}
|
|
2601
|
-
}, ctx), // Remove dynamic zones from filters
|
|
2602
|
-
traverseQueryFilters(visitor$5, ctx), // Remove morpTo relations from filters
|
|
2603
|
-
traverseQueryFilters(visitor$6, ctx), // Remove passwords from filters
|
|
2604
|
-
traverseQueryFilters(visitor$8, ctx), // Remove private from filters
|
|
2605
|
-
traverseQueryFilters(visitor$7, ctx), // Remove empty objects
|
|
2606
|
-
traverseQueryFilters(({ key, value }, { remove })=>{
|
|
2607
|
-
if (fp.isObject(value) && fp.isEmpty(value)) {
|
|
2608
|
-
remove(key);
|
|
2609
|
-
}
|
|
2610
|
-
}, ctx))(filters);
|
|
2611
|
-
});
|
|
2612
|
-
const defaultSanitizeSort = fp.curry((ctx, sort)=>{
|
|
2613
|
-
if (!ctx.schema) {
|
|
2614
|
-
throw new Error('Missing schema in defaultSanitizeSort');
|
|
2615
|
-
}
|
|
2616
|
-
return pipe(// Remove non attribute keys
|
|
2617
|
-
traverseQuerySort(({ key, attribute }, { remove })=>{
|
|
2618
|
-
// ID is not an attribute per se, so we need to make
|
|
2619
|
-
// an extra check to ensure we're not checking it
|
|
2620
|
-
if ([
|
|
2621
|
-
ID_ATTRIBUTE$2,
|
|
2622
|
-
DOC_ID_ATTRIBUTE$2
|
|
2623
|
-
].includes(key)) {
|
|
2624
|
-
return;
|
|
2625
|
-
}
|
|
2626
|
-
if (!attribute) {
|
|
2627
|
-
remove(key);
|
|
2628
|
-
}
|
|
2629
|
-
}, ctx), // Remove dynamic zones from sort
|
|
2630
|
-
traverseQuerySort(visitor$5, ctx), // Remove morpTo relations from sort
|
|
2631
|
-
traverseQuerySort(visitor$6, ctx), // Remove private from sort
|
|
2632
|
-
traverseQuerySort(visitor$7, ctx), // Remove passwords from filters
|
|
2633
|
-
traverseQuerySort(visitor$8, ctx), // Remove keys for empty non-scalar values
|
|
2634
|
-
traverseQuerySort(({ key, attribute, value }, { remove })=>{
|
|
2635
|
-
// ID is not an attribute per se, so we need to make
|
|
2636
|
-
// an extra check to ensure we're not removing it
|
|
2637
|
-
if ([
|
|
2638
|
-
ID_ATTRIBUTE$2,
|
|
2639
|
-
DOC_ID_ATTRIBUTE$2
|
|
2640
|
-
].includes(key)) {
|
|
2641
|
-
return;
|
|
2642
|
-
}
|
|
2643
|
-
if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
|
|
2644
|
-
remove(key);
|
|
2645
|
-
}
|
|
2646
|
-
}, ctx))(sort);
|
|
2647
|
-
});
|
|
2648
|
-
const defaultSanitizeFields = fp.curry((ctx, fields)=>{
|
|
2649
|
-
if (!ctx.schema) {
|
|
2650
|
-
throw new Error('Missing schema in defaultSanitizeFields');
|
|
2651
|
-
}
|
|
2652
|
-
return pipe(// Only keep scalar attributes
|
|
2653
|
-
traverseQueryFields(({ key, attribute }, { remove })=>{
|
|
2654
|
-
// ID is not an attribute per se, so we need to make
|
|
2655
|
-
// an extra check to ensure we're not checking it
|
|
2656
|
-
if ([
|
|
2657
|
-
ID_ATTRIBUTE$2,
|
|
2658
|
-
DOC_ID_ATTRIBUTE$2
|
|
2659
|
-
].includes(key)) {
|
|
2660
|
-
return;
|
|
2661
|
-
}
|
|
2662
|
-
if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
|
|
2663
|
-
remove(key);
|
|
2664
|
-
}
|
|
2665
|
-
}, ctx), // Remove private fields
|
|
2666
|
-
traverseQueryFields(visitor$7, ctx), // Remove password fields
|
|
2667
|
-
traverseQueryFields(visitor$8, ctx), // Remove nil values from fields array
|
|
2668
|
-
(value)=>fp.isArray(value) ? value.filter((field)=>!fp.isNil(field)) : value)(fields);
|
|
2669
|
-
});
|
|
2670
|
-
const defaultSanitizePopulate = fp.curry((ctx, populate)=>{
|
|
2671
|
-
if (!ctx.schema) {
|
|
2672
|
-
throw new Error('Missing schema in defaultSanitizePopulate');
|
|
2673
|
-
}
|
|
2674
|
-
return pipe(traverseQueryPopulate(visitor$4, ctx), traverseQueryPopulate(async ({ key, value, schema, attribute, getModel, path }, { set })=>{
|
|
2675
|
-
if (attribute) {
|
|
2676
|
-
return;
|
|
2677
|
-
}
|
|
2678
|
-
const parent = {
|
|
2679
|
-
key,
|
|
2680
|
-
path,
|
|
2681
|
-
schema,
|
|
2682
|
-
attribute
|
|
2683
|
-
};
|
|
2684
|
-
if (key === 'sort') {
|
|
2685
|
-
set(key, await defaultSanitizeSort({
|
|
2686
|
-
schema,
|
|
2687
|
-
getModel,
|
|
2688
|
-
parent
|
|
2689
|
-
}, value));
|
|
2690
|
-
}
|
|
2691
|
-
if (key === 'filters') {
|
|
2692
|
-
set(key, await defaultSanitizeFilters({
|
|
2693
|
-
schema,
|
|
2694
|
-
getModel,
|
|
2695
|
-
parent
|
|
2696
|
-
}, value));
|
|
2697
|
-
}
|
|
2698
|
-
if (key === 'fields') {
|
|
2699
|
-
set(key, await defaultSanitizeFields({
|
|
2700
|
-
schema,
|
|
2701
|
-
getModel,
|
|
2702
|
-
parent
|
|
2703
|
-
}, value));
|
|
2704
|
-
}
|
|
2705
|
-
if (key === 'populate') {
|
|
2706
|
-
set(key, await defaultSanitizePopulate({
|
|
2707
|
-
schema,
|
|
2708
|
-
getModel,
|
|
2709
|
-
parent
|
|
2710
|
-
}, value));
|
|
2711
|
-
}
|
|
2712
|
-
}, ctx), // Remove private fields
|
|
2713
|
-
traverseQueryPopulate(visitor$7, ctx))(populate);
|
|
2714
|
-
});
|
|
2715
|
-
|
|
2716
|
-
var sanitizers = /*#__PURE__*/Object.freeze({
|
|
2717
|
-
__proto__: null,
|
|
2718
|
-
defaultSanitizeFields: defaultSanitizeFields,
|
|
2719
|
-
defaultSanitizeFilters: defaultSanitizeFilters,
|
|
2720
|
-
defaultSanitizeOutput: defaultSanitizeOutput,
|
|
2721
|
-
defaultSanitizePopulate: defaultSanitizePopulate,
|
|
2722
|
-
defaultSanitizeSort: defaultSanitizeSort,
|
|
2723
|
-
sanitizePasswords: sanitizePasswords
|
|
2724
|
-
});
|
|
2725
|
-
|
|
2726
|
-
const createAPISanitizers = (opts)=>{
|
|
2727
|
-
const { getModel } = opts;
|
|
2728
|
-
const sanitizeInput = (data, schema, { auth } = {})=>{
|
|
2729
|
-
if (!schema) {
|
|
2730
|
-
throw new Error('Missing schema in sanitizeInput');
|
|
2731
|
-
}
|
|
2732
|
-
if (fp.isArray(data)) {
|
|
2733
|
-
return Promise.all(data.map((entry)=>sanitizeInput(entry, schema, {
|
|
2734
|
-
auth
|
|
2735
|
-
})));
|
|
2736
|
-
}
|
|
2737
|
-
const nonWritableAttributes = getNonWritableAttributes(schema);
|
|
2738
|
-
const transforms = [
|
|
2739
|
-
// Remove first level ID in inputs
|
|
2740
|
-
fp.omit(constants$1.ID_ATTRIBUTE),
|
|
2741
|
-
fp.omit(constants$1.DOC_ID_ATTRIBUTE),
|
|
2742
|
-
// Remove non-writable attributes
|
|
2743
|
-
traverseEntity$1(removeRestrictedFields(nonWritableAttributes), {
|
|
2744
|
-
schema,
|
|
2745
|
-
getModel
|
|
2746
|
-
})
|
|
2747
|
-
];
|
|
2748
|
-
if (auth) {
|
|
2749
|
-
// Remove restricted relations
|
|
2750
|
-
transforms.push(traverseEntity$1(removeRestrictedRelations(auth), {
|
|
2751
|
-
schema,
|
|
2752
|
-
getModel
|
|
2753
|
-
}));
|
|
2754
|
-
}
|
|
2755
|
-
// Apply sanitizers from registry if exists
|
|
2756
|
-
opts?.sanitizers?.input?.forEach((sanitizer)=>transforms.push(sanitizer(schema)));
|
|
2757
|
-
return pipe(...transforms)(data);
|
|
2758
|
-
};
|
|
2759
|
-
const sanitizeOutput = async (data, schema, { auth } = {})=>{
|
|
2760
|
-
if (!schema) {
|
|
2761
|
-
throw new Error('Missing schema in sanitizeOutput');
|
|
2762
|
-
}
|
|
2763
|
-
if (fp.isArray(data)) {
|
|
2764
|
-
const res = new Array(data.length);
|
|
2765
|
-
for(let i = 0; i < data.length; i += 1){
|
|
2766
|
-
res[i] = await sanitizeOutput(data[i], schema, {
|
|
2767
|
-
auth
|
|
2768
|
-
});
|
|
2769
|
-
}
|
|
2770
|
-
return res;
|
|
2771
|
-
}
|
|
2772
|
-
const transforms = [
|
|
2773
|
-
(data)=>defaultSanitizeOutput({
|
|
2774
|
-
schema,
|
|
2775
|
-
getModel
|
|
2776
|
-
}, data)
|
|
2777
|
-
];
|
|
2778
|
-
if (auth) {
|
|
2779
|
-
transforms.push(traverseEntity$1(removeRestrictedRelations(auth), {
|
|
2780
|
-
schema,
|
|
2781
|
-
getModel
|
|
2782
|
-
}));
|
|
2783
|
-
}
|
|
2784
|
-
// Apply sanitizers from registry if exists
|
|
2785
|
-
opts?.sanitizers?.output?.forEach((sanitizer)=>transforms.push(sanitizer(schema)));
|
|
2786
|
-
return pipe(...transforms)(data);
|
|
2787
|
-
};
|
|
2788
|
-
const sanitizeQuery = async (query, schema, { auth } = {})=>{
|
|
2789
|
-
if (!schema) {
|
|
2790
|
-
throw new Error('Missing schema in sanitizeQuery');
|
|
2791
|
-
}
|
|
2792
|
-
const { filters, sort, fields, populate } = query;
|
|
2793
|
-
const sanitizedQuery = fp.cloneDeep(query);
|
|
2794
|
-
if (filters) {
|
|
2795
|
-
Object.assign(sanitizedQuery, {
|
|
2796
|
-
filters: await sanitizeFilters(filters, schema, {
|
|
2797
|
-
auth
|
|
2798
|
-
})
|
|
2799
|
-
});
|
|
2800
|
-
}
|
|
2801
|
-
if (sort) {
|
|
2802
|
-
Object.assign(sanitizedQuery, {
|
|
2803
|
-
sort: await sanitizeSort(sort, schema, {
|
|
2804
|
-
auth
|
|
2805
|
-
})
|
|
2806
|
-
});
|
|
2807
|
-
}
|
|
2808
|
-
if (fields) {
|
|
2809
|
-
Object.assign(sanitizedQuery, {
|
|
2810
|
-
fields: await sanitizeFields(fields, schema)
|
|
2811
|
-
});
|
|
2812
|
-
}
|
|
2813
|
-
if (populate) {
|
|
2814
|
-
Object.assign(sanitizedQuery, {
|
|
2815
|
-
populate: await sanitizePopulate(populate, schema)
|
|
2816
|
-
});
|
|
2817
|
-
}
|
|
2818
|
-
return sanitizedQuery;
|
|
2819
|
-
};
|
|
2820
|
-
const sanitizeFilters = (filters, schema, { auth } = {})=>{
|
|
2821
|
-
if (!schema) {
|
|
2822
|
-
throw new Error('Missing schema in sanitizeFilters');
|
|
2823
|
-
}
|
|
2824
|
-
if (fp.isArray(filters)) {
|
|
2825
|
-
return Promise.all(filters.map((filter)=>sanitizeFilters(filter, schema, {
|
|
2826
|
-
auth
|
|
2827
|
-
})));
|
|
2828
|
-
}
|
|
2829
|
-
const transforms = [
|
|
2830
|
-
defaultSanitizeFilters({
|
|
2831
|
-
schema,
|
|
2832
|
-
getModel
|
|
2833
|
-
})
|
|
2834
|
-
];
|
|
2835
|
-
if (auth) {
|
|
2836
|
-
transforms.push(traverseQueryFilters(removeRestrictedRelations(auth), {
|
|
2837
|
-
schema,
|
|
2838
|
-
getModel
|
|
2839
|
-
}));
|
|
2840
|
-
}
|
|
2841
|
-
return pipe(...transforms)(filters);
|
|
2842
|
-
};
|
|
2843
|
-
const sanitizeSort = (sort, schema, { auth } = {})=>{
|
|
2844
|
-
if (!schema) {
|
|
2845
|
-
throw new Error('Missing schema in sanitizeSort');
|
|
2846
|
-
}
|
|
2847
|
-
const transforms = [
|
|
2848
|
-
defaultSanitizeSort({
|
|
2849
|
-
schema,
|
|
2850
|
-
getModel
|
|
2851
|
-
})
|
|
2852
|
-
];
|
|
2853
|
-
if (auth) {
|
|
2854
|
-
transforms.push(traverseQuerySort(removeRestrictedRelations(auth), {
|
|
2855
|
-
schema,
|
|
2856
|
-
getModel
|
|
2857
|
-
}));
|
|
2858
|
-
}
|
|
2859
|
-
return pipe(...transforms)(sort);
|
|
2860
|
-
};
|
|
2861
|
-
const sanitizeFields = (fields, schema)=>{
|
|
2862
|
-
if (!schema) {
|
|
2863
|
-
throw new Error('Missing schema in sanitizeFields');
|
|
2864
|
-
}
|
|
2865
|
-
const transforms = [
|
|
2866
|
-
defaultSanitizeFields({
|
|
2867
|
-
schema,
|
|
2868
|
-
getModel
|
|
2869
|
-
})
|
|
2870
|
-
];
|
|
2871
|
-
return pipe(...transforms)(fields);
|
|
2872
|
-
};
|
|
2873
|
-
const sanitizePopulate = (populate, schema, { auth } = {})=>{
|
|
2874
|
-
if (!schema) {
|
|
2875
|
-
throw new Error('Missing schema in sanitizePopulate');
|
|
2876
|
-
}
|
|
2877
|
-
const transforms = [
|
|
2878
|
-
defaultSanitizePopulate({
|
|
2879
|
-
schema,
|
|
2880
|
-
getModel
|
|
2881
|
-
})
|
|
2882
|
-
];
|
|
2883
|
-
if (auth) {
|
|
2884
|
-
transforms.push(traverseQueryPopulate(removeRestrictedRelations(auth), {
|
|
2885
|
-
schema,
|
|
2886
|
-
getModel
|
|
2887
|
-
}));
|
|
2888
|
-
}
|
|
2889
|
-
return pipe(...transforms)(populate);
|
|
2890
|
-
};
|
|
2891
|
-
return {
|
|
2892
|
-
input: sanitizeInput,
|
|
2893
|
-
output: sanitizeOutput,
|
|
2894
|
-
query: sanitizeQuery,
|
|
2895
|
-
filters: sanitizeFilters,
|
|
2896
|
-
sort: sanitizeSort,
|
|
2897
|
-
fields: sanitizeFields,
|
|
2898
|
-
populate: sanitizePopulate
|
|
2899
|
-
};
|
|
2900
|
-
};
|
|
2901
|
-
|
|
2902
|
-
var index$2 = /*#__PURE__*/Object.freeze({
|
|
2903
|
-
__proto__: null,
|
|
2904
|
-
createAPISanitizers: createAPISanitizers,
|
|
2905
|
-
sanitizers: sanitizers,
|
|
2906
|
-
visitors: index$4
|
|
2907
|
-
});
|
|
2908
|
-
|
|
2909
|
-
// lodash/fp curry does not handle async functions properly, and creates very "ugly" types,
|
|
2910
|
-
// so we will use our own version to ensure curried functions are typed correctly
|
|
2911
|
-
// TODO: Export this from root @strapi/utils so we don't have copies of it between packages
|
|
2912
|
-
const throwInvalidKey = ({ key, path })=>{
|
|
2913
|
-
const msg = path && path !== key ? `Invalid key ${key} at ${path}` : `Invalid key ${key}`;
|
|
2914
|
-
throw new ValidationError(msg, {
|
|
2915
|
-
key,
|
|
2916
|
-
path
|
|
2917
|
-
});
|
|
2918
|
-
};
|
|
2919
|
-
const asyncCurry = (fn)=>{
|
|
2920
|
-
const curried = (...args)=>{
|
|
2921
|
-
if (args.length >= fn.length) {
|
|
2922
|
-
return fn(...args);
|
|
2923
|
-
}
|
|
2924
|
-
return (...moreArgs)=>curried(...args, ...moreArgs);
|
|
2925
|
-
};
|
|
2926
|
-
return curried;
|
|
2927
|
-
};
|
|
2928
|
-
|
|
2929
|
-
const visitor$3 = ({ key, attribute, path })=>{
|
|
2930
|
-
if (attribute?.type === 'password') {
|
|
2931
|
-
throwInvalidKey({
|
|
2932
|
-
key,
|
|
2933
|
-
path: path.attribute
|
|
2934
|
-
});
|
|
2935
|
-
}
|
|
2936
|
-
};
|
|
2937
|
-
|
|
2938
|
-
const visitor$2 = ({ schema, key, attribute, path })=>{
|
|
2939
|
-
if (!attribute) {
|
|
2940
|
-
return;
|
|
2941
|
-
}
|
|
2942
|
-
const isPrivate = attribute.private === true || isPrivateAttribute(schema, key);
|
|
2943
|
-
if (isPrivate) {
|
|
2944
|
-
throwInvalidKey({
|
|
2945
|
-
key,
|
|
2946
|
-
path: path.attribute
|
|
2947
|
-
});
|
|
2948
|
-
}
|
|
2949
|
-
};
|
|
2950
|
-
|
|
2951
|
-
const ACTIONS_TO_VERIFY = [
|
|
2952
|
-
'find'
|
|
2953
|
-
];
|
|
2954
|
-
const { CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE } = constants$1;
|
|
2955
|
-
var throwRestrictedRelations = ((auth)=>async ({ data, key, attribute, schema, path })=>{
|
|
2956
|
-
if (!attribute) {
|
|
2957
|
-
return;
|
|
2958
|
-
}
|
|
2959
|
-
const isRelation = attribute.type === 'relation';
|
|
2960
|
-
if (!isRelation) {
|
|
2961
|
-
return;
|
|
2962
|
-
}
|
|
2963
|
-
const handleMorphRelation = async ()=>{
|
|
2964
|
-
const elements = data[key];
|
|
2965
|
-
if ('connect' in elements || 'set' in elements || 'disconnect' in elements || 'options' in elements) {
|
|
2966
|
-
await handleMorphElements(elements.connect || []);
|
|
2967
|
-
await handleMorphElements(elements.set || []);
|
|
2968
|
-
await handleMorphElements(elements.disconnect || []);
|
|
2969
|
-
// TODO: this should technically be in its own visitor to check morph options, but for now we'll handle it here
|
|
2970
|
-
if ('options' in elements) {
|
|
2971
|
-
if (elements.options === null || elements.options === undefined) {
|
|
2972
|
-
return;
|
|
2973
|
-
}
|
|
2974
|
-
if (typeof elements.options !== 'object') {
|
|
2975
|
-
throwInvalidKey({
|
|
2976
|
-
key,
|
|
2977
|
-
path: path.attribute
|
|
2978
|
-
});
|
|
2979
|
-
}
|
|
2980
|
-
const optionKeys = Object.keys(elements.options);
|
|
2981
|
-
// Validate each key based on its validator function
|
|
2982
|
-
for (const key of optionKeys){
|
|
2983
|
-
if (!(key in VALID_RELATION_ORDERING_KEYS)) {
|
|
2984
|
-
throwInvalidKey({
|
|
2985
|
-
key,
|
|
2986
|
-
path: path.attribute
|
|
2987
|
-
});
|
|
2988
|
-
}
|
|
2989
|
-
if (!VALID_RELATION_ORDERING_KEYS[key](elements.options[key])) {
|
|
2990
|
-
throwInvalidKey({
|
|
2991
|
-
key,
|
|
2992
|
-
path: path.attribute
|
|
2993
|
-
});
|
|
2994
|
-
}
|
|
2995
|
-
}
|
|
2996
|
-
}
|
|
2997
|
-
} else {
|
|
2998
|
-
await handleMorphElements(elements);
|
|
2999
|
-
}
|
|
3000
|
-
};
|
|
3001
|
-
const handleMorphElements = async (elements)=>{
|
|
3002
|
-
if (!fp.isArray(elements)) {
|
|
3003
|
-
throwInvalidKey({
|
|
3004
|
-
key,
|
|
3005
|
-
path: path.attribute
|
|
3006
|
-
});
|
|
3007
|
-
}
|
|
3008
|
-
for (const element of elements){
|
|
3009
|
-
if (!fp.isObject(element) || !('__type' in element)) {
|
|
3010
|
-
throwInvalidKey({
|
|
3011
|
-
key,
|
|
3012
|
-
path: path.attribute
|
|
3013
|
-
});
|
|
3014
|
-
}
|
|
3015
|
-
const scopes = ACTIONS_TO_VERIFY.map((action)=>`${element.__type}.${action}`);
|
|
3016
|
-
const isAllowed = await hasAccessToSomeScopes(scopes, auth);
|
|
3017
|
-
if (!isAllowed) {
|
|
3018
|
-
throwInvalidKey({
|
|
3019
|
-
key,
|
|
3020
|
-
path: path.attribute
|
|
3021
|
-
});
|
|
3022
|
-
}
|
|
3023
|
-
}
|
|
3024
|
-
};
|
|
3025
|
-
const handleRegularRelation = async ()=>{
|
|
3026
|
-
const scopes = ACTIONS_TO_VERIFY.map((action)=>`${attribute.target}.${action}`);
|
|
3027
|
-
const isAllowed = await hasAccessToSomeScopes(scopes, auth);
|
|
3028
|
-
// If the authenticated user don't have access to any of the scopes
|
|
3029
|
-
if (!isAllowed) {
|
|
3030
|
-
throwInvalidKey({
|
|
3031
|
-
key,
|
|
3032
|
-
path: path.attribute
|
|
3033
|
-
});
|
|
3034
|
-
}
|
|
3035
|
-
};
|
|
3036
|
-
const isCreatorRelation = [
|
|
3037
|
-
CREATED_BY_ATTRIBUTE,
|
|
3038
|
-
UPDATED_BY_ATTRIBUTE
|
|
3039
|
-
].includes(key);
|
|
3040
|
-
// Polymorphic relations
|
|
3041
|
-
if (isMorphToRelationalAttribute(attribute)) {
|
|
3042
|
-
await handleMorphRelation();
|
|
3043
|
-
return;
|
|
3044
|
-
}
|
|
3045
|
-
// Creator relations
|
|
3046
|
-
if (isCreatorRelation && schema.options?.populateCreatorFields) {
|
|
3047
|
-
// do nothing
|
|
3048
|
-
return;
|
|
3049
|
-
}
|
|
3050
|
-
// Regular relations
|
|
3051
|
-
await handleRegularRelation();
|
|
3052
|
-
});
|
|
3053
|
-
const hasAccessToSomeScopes = async (scopes, auth)=>{
|
|
3054
|
-
for (const scope of scopes){
|
|
3055
|
-
try {
|
|
3056
|
-
await strapi.auth.verify(auth, {
|
|
3057
|
-
scope
|
|
3058
|
-
});
|
|
3059
|
-
return true;
|
|
3060
|
-
} catch {
|
|
3061
|
-
continue;
|
|
3062
|
-
}
|
|
3063
|
-
}
|
|
3064
|
-
return false;
|
|
3065
|
-
};
|
|
3066
|
-
|
|
3067
|
-
const visitor$1 = ({ key, attribute, path })=>{
|
|
3068
|
-
if (isMorphToRelationalAttribute(attribute)) {
|
|
3069
|
-
throwInvalidKey({
|
|
3070
|
-
key,
|
|
3071
|
-
path: path.attribute
|
|
3072
|
-
});
|
|
3073
|
-
}
|
|
3074
|
-
};
|
|
3075
|
-
|
|
3076
|
-
const visitor = ({ key, attribute, path })=>{
|
|
3077
|
-
if (isDynamicZoneAttribute(attribute)) {
|
|
3078
|
-
throwInvalidKey({
|
|
3079
|
-
key,
|
|
3080
|
-
path: path.attribute
|
|
3081
|
-
});
|
|
3082
|
-
}
|
|
3083
|
-
};
|
|
3084
|
-
|
|
3085
|
-
var throwDisallowedFields = ((allowedFields = null)=>({ key, path: { attribute: path } })=>{
|
|
3086
|
-
// All fields are allowed
|
|
3087
|
-
if (allowedFields === null) {
|
|
3088
|
-
return;
|
|
3089
|
-
}
|
|
3090
|
-
// Throw on invalid formats
|
|
3091
|
-
if (!(fp.isArray(allowedFields) && allowedFields.every(fp.isString))) {
|
|
3092
|
-
throw new TypeError(`Expected array of strings for allowedFields but got "${typeof allowedFields}"`);
|
|
3093
|
-
}
|
|
3094
|
-
if (fp.isNil(path)) {
|
|
3095
|
-
return;
|
|
3096
|
-
}
|
|
3097
|
-
const containedPaths = getContainedPaths(path);
|
|
3098
|
-
/**
|
|
3099
|
-
* Tells if the current path should be kept or not based
|
|
3100
|
-
* on the success of the check functions for any of the allowed paths.
|
|
3101
|
-
*
|
|
3102
|
-
* The check functions are defined as follow:
|
|
3103
|
-
*
|
|
3104
|
-
* `containedPaths.includes(p)`
|
|
3105
|
-
* @example
|
|
3106
|
-
* ```js
|
|
3107
|
-
* const path = 'foo.bar.field';
|
|
3108
|
-
* const p = 'foo.bar';
|
|
3109
|
-
* // it should match
|
|
3110
|
-
*
|
|
3111
|
-
* const path = 'foo.bar.field';
|
|
3112
|
-
* const p = 'bar.foo';
|
|
3113
|
-
* // it shouldn't match
|
|
3114
|
-
*
|
|
3115
|
-
* const path = 'foo.bar';
|
|
3116
|
-
* const p = 'foo.bar.field';
|
|
3117
|
-
* // it should match but isn't handled by this check
|
|
3118
|
-
* ```
|
|
3119
|
-
*
|
|
3120
|
-
* `p.startsWith(`${path}.`)`
|
|
3121
|
-
* @example
|
|
3122
|
-
* ```js
|
|
3123
|
-
* const path = 'foo.bar';
|
|
3124
|
-
* const p = 'foo.bar.field';
|
|
3125
|
-
* // it should match
|
|
3126
|
-
*
|
|
3127
|
-
* const path = 'foo.bar.field';
|
|
3128
|
-
* const p = 'bar.foo';
|
|
3129
|
-
* // it shouldn't match
|
|
3130
|
-
*
|
|
3131
|
-
* const path = 'foo.bar.field';
|
|
3132
|
-
* const p = 'foo.bar';
|
|
3133
|
-
* // it should match but isn't handled by this check
|
|
3134
|
-
* ```
|
|
3135
|
-
*/ const isPathAllowed = allowedFields.some((p)=>containedPaths.includes(p) || p.startsWith(`${path}.`));
|
|
3136
|
-
if (isPathAllowed) {
|
|
3137
|
-
return;
|
|
3138
|
-
}
|
|
3139
|
-
// throw otherwise
|
|
3140
|
-
throwInvalidKey({
|
|
3141
|
-
key,
|
|
3142
|
-
path
|
|
3143
|
-
});
|
|
3144
|
-
});
|
|
3145
|
-
/**
|
|
3146
|
-
* Retrieve the list of allowed paths based on the given path
|
|
3147
|
-
*
|
|
3148
|
-
* @example
|
|
3149
|
-
* ```js
|
|
3150
|
-
* const containedPaths = getContainedPaths('foo');
|
|
3151
|
-
* // ['foo']
|
|
3152
|
-
*
|
|
3153
|
-
* * const containedPaths = getContainedPaths('foo.bar');
|
|
3154
|
-
* // ['foo', 'foo.bar']
|
|
3155
|
-
*
|
|
3156
|
-
* * const containedPaths = getContainedPaths('foo.bar.field');
|
|
3157
|
-
* // ['foo', 'foo.bar', 'foo.bar.field']
|
|
3158
|
-
* ```
|
|
3159
|
-
*/ const getContainedPaths = (path)=>{
|
|
3160
|
-
const parts = fp.toPath(path);
|
|
3161
|
-
return parts.reduce((acc, value, index, list)=>{
|
|
3162
|
-
return [
|
|
3163
|
-
...acc,
|
|
3164
|
-
list.slice(0, index + 1).join('.')
|
|
3165
|
-
];
|
|
3166
|
-
}, []);
|
|
3167
|
-
};
|
|
3168
|
-
|
|
3169
|
-
var throwRestrictedFields = ((restrictedFields = null)=>({ key, path: { attribute: path } })=>{
|
|
3170
|
-
// all fields
|
|
3171
|
-
if (restrictedFields === null) {
|
|
3172
|
-
throwInvalidKey({
|
|
3173
|
-
key,
|
|
3174
|
-
path
|
|
3175
|
-
});
|
|
3176
|
-
}
|
|
3177
|
-
// Throw on invalid formats
|
|
3178
|
-
if (!(fp.isArray(restrictedFields) && restrictedFields.every(fp.isString))) {
|
|
3179
|
-
throw new TypeError(`Expected array of strings for restrictedFields but got "${typeof restrictedFields}"`);
|
|
3180
|
-
}
|
|
3181
|
-
// if an exact match was found
|
|
3182
|
-
if (restrictedFields.includes(path)) {
|
|
3183
|
-
throwInvalidKey({
|
|
3184
|
-
key,
|
|
3185
|
-
path
|
|
3186
|
-
});
|
|
3187
|
-
}
|
|
3188
|
-
// nested matches
|
|
3189
|
-
const isRestrictedNested = restrictedFields.some((allowedPath)=>path?.toString().startsWith(`${allowedPath}.`));
|
|
3190
|
-
if (isRestrictedNested) {
|
|
3191
|
-
throwInvalidKey({
|
|
3192
|
-
key,
|
|
3193
|
-
path
|
|
3194
|
-
});
|
|
3195
|
-
}
|
|
3196
|
-
});
|
|
3197
|
-
|
|
3198
|
-
// TODO these should all be centralized somewhere instead of maintaining a list
|
|
3199
|
-
const ID_FIELDS = [
|
|
3200
|
-
constants$1.DOC_ID_ATTRIBUTE,
|
|
3201
|
-
constants$1.DOC_ID_ATTRIBUTE
|
|
3202
|
-
];
|
|
3203
|
-
const ALLOWED_ROOT_LEVEL_FIELDS = [
|
|
3204
|
-
...ID_FIELDS
|
|
3205
|
-
];
|
|
3206
|
-
const MORPH_TO_ALLOWED_FIELDS = [
|
|
3207
|
-
'__type'
|
|
3208
|
-
];
|
|
3209
|
-
const DYNAMIC_ZONE_ALLOWED_FIELDS = [
|
|
3210
|
-
'__component'
|
|
3211
|
-
];
|
|
3212
|
-
const RELATION_REORDERING_FIELDS = [
|
|
3213
|
-
'connect',
|
|
3214
|
-
'disconnect',
|
|
3215
|
-
'set',
|
|
3216
|
-
'options'
|
|
3217
|
-
];
|
|
3218
|
-
const throwUnrecognizedFields = ({ key, attribute, path, schema, parent })=>{
|
|
3219
|
-
// We only look at properties that are not attributes
|
|
3220
|
-
if (attribute) {
|
|
3221
|
-
return;
|
|
3222
|
-
}
|
|
3223
|
-
// At root level (path.attribute === null), only accept allowed fields
|
|
3224
|
-
if (path.attribute === null) {
|
|
3225
|
-
if (ALLOWED_ROOT_LEVEL_FIELDS.includes(key)) {
|
|
3226
|
-
return;
|
|
3227
|
-
}
|
|
3228
|
-
return throwInvalidKey({
|
|
3229
|
-
key,
|
|
3230
|
-
path: attribute
|
|
3231
|
-
});
|
|
3232
|
-
}
|
|
3233
|
-
// allow special morphTo keys
|
|
3234
|
-
if (isMorphToRelationalAttribute(parent?.attribute) && MORPH_TO_ALLOWED_FIELDS.includes(key)) {
|
|
3235
|
-
return;
|
|
3236
|
-
}
|
|
3237
|
-
// allow special dz keys
|
|
3238
|
-
if (isComponentSchema(schema) && isDynamicZoneAttribute(parent?.attribute) && DYNAMIC_ZONE_ALLOWED_FIELDS.includes(key)) {
|
|
3239
|
-
return;
|
|
3240
|
-
}
|
|
3241
|
-
// allow special relation reordering keys in manyToX and XtoMany relations
|
|
3242
|
-
if (hasRelationReordering(parent?.attribute) && RELATION_REORDERING_FIELDS.includes(key)) {
|
|
3243
|
-
return;
|
|
3244
|
-
}
|
|
3245
|
-
// allow id fields where it is needed for setting a relational id rather than trying to create with a given id
|
|
3246
|
-
const canUseID = isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute);
|
|
3247
|
-
if (canUseID && !ID_FIELDS.includes(key)) {
|
|
3248
|
-
return;
|
|
3249
|
-
}
|
|
3250
|
-
// if we couldn't find any reason for it to be here, throw
|
|
3251
|
-
throwInvalidKey({
|
|
3252
|
-
key,
|
|
3253
|
-
path: attribute
|
|
3254
|
-
});
|
|
3255
|
-
};
|
|
3256
|
-
|
|
3257
|
-
var index$1 = /*#__PURE__*/Object.freeze({
|
|
3258
|
-
__proto__: null,
|
|
3259
|
-
throwDisallowedFields: throwDisallowedFields,
|
|
3260
|
-
throwDynamicZones: visitor,
|
|
3261
|
-
throwMorphToRelations: visitor$1,
|
|
3262
|
-
throwPassword: visitor$3,
|
|
3263
|
-
throwPrivate: visitor$2,
|
|
3264
|
-
throwRestrictedFields: throwRestrictedFields,
|
|
3265
|
-
throwRestrictedRelations: throwRestrictedRelations,
|
|
3266
|
-
throwUnrecognizedFields: throwUnrecognizedFields
|
|
3267
|
-
});
|
|
3268
|
-
|
|
3269
|
-
const { ID_ATTRIBUTE: ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$1 } = constants$1;
|
|
3270
|
-
const FILTER_TRAVERSALS = [
|
|
3271
|
-
'nonAttributesOperators',
|
|
3272
|
-
'dynamicZones',
|
|
3273
|
-
'morphRelations',
|
|
3274
|
-
'passwords',
|
|
3275
|
-
'private'
|
|
3276
|
-
];
|
|
3277
|
-
const validateFilters = asyncCurry(async (ctx, filters, include)=>{
|
|
3278
|
-
// TODO: schema checks should check that it is a valid schema with yup
|
|
3279
|
-
if (!ctx.schema) {
|
|
3280
|
-
throw new Error('Missing schema in defaultValidateFilters');
|
|
3281
|
-
}
|
|
3282
|
-
// Build the list of functions conditionally
|
|
3283
|
-
const functionsToApply = [];
|
|
3284
|
-
// keys that are not attributes or valid operators
|
|
3285
|
-
if (include.includes('nonAttributesOperators')) {
|
|
3286
|
-
functionsToApply.push(traverseQueryFilters(({ key, attribute, path })=>{
|
|
3287
|
-
// ID is not an attribute per se, so we need to make
|
|
3288
|
-
// an extra check to ensure we're not removing it
|
|
3289
|
-
if ([
|
|
3290
|
-
ID_ATTRIBUTE$1,
|
|
3291
|
-
DOC_ID_ATTRIBUTE$1
|
|
3292
|
-
].includes(key)) {
|
|
3293
|
-
return;
|
|
3294
|
-
}
|
|
3295
|
-
const isAttribute = !!attribute;
|
|
3296
|
-
if (!isAttribute && !isOperator(key)) {
|
|
3297
|
-
throwInvalidKey({
|
|
3298
|
-
key,
|
|
3299
|
-
path: path.attribute
|
|
3300
|
-
});
|
|
3301
|
-
}
|
|
3302
|
-
}, ctx));
|
|
3303
|
-
}
|
|
3304
|
-
if (include.includes('dynamicZones')) {
|
|
3305
|
-
functionsToApply.push(traverseQueryFilters(visitor, ctx));
|
|
3306
|
-
}
|
|
3307
|
-
if (include.includes('morphRelations')) {
|
|
3308
|
-
functionsToApply.push(traverseQueryFilters(visitor$1, ctx));
|
|
3309
|
-
}
|
|
3310
|
-
if (include.includes('passwords')) {
|
|
3311
|
-
functionsToApply.push(traverseQueryFilters(visitor$3, ctx));
|
|
3312
|
-
}
|
|
3313
|
-
if (include.includes('private')) {
|
|
3314
|
-
functionsToApply.push(traverseQueryFilters(visitor$2, ctx));
|
|
3315
|
-
}
|
|
3316
|
-
// Return directly if no validation functions are provided
|
|
3317
|
-
if (functionsToApply.length === 0) {
|
|
3318
|
-
return filters;
|
|
3319
|
-
}
|
|
3320
|
-
return pipe(...functionsToApply)(filters);
|
|
3321
|
-
});
|
|
3322
|
-
const defaultValidateFilters = asyncCurry(async (ctx, filters)=>{
|
|
3323
|
-
return validateFilters(ctx, filters, FILTER_TRAVERSALS);
|
|
3324
|
-
});
|
|
3325
|
-
const SORT_TRAVERSALS = [
|
|
3326
|
-
'nonAttributesOperators',
|
|
3327
|
-
'dynamicZones',
|
|
3328
|
-
'morphRelations',
|
|
3329
|
-
'passwords',
|
|
3330
|
-
'private',
|
|
3331
|
-
'nonScalarEmptyKeys'
|
|
3332
|
-
];
|
|
3333
|
-
const validateSort = asyncCurry(async (ctx, sort, include)=>{
|
|
3334
|
-
if (!ctx.schema) {
|
|
3335
|
-
throw new Error('Missing schema in defaultValidateSort');
|
|
3336
|
-
}
|
|
3337
|
-
// Build the list of functions conditionally based on the include array
|
|
3338
|
-
const functionsToApply = [];
|
|
3339
|
-
// Validate non attribute keys
|
|
3340
|
-
if (include.includes('nonAttributesOperators')) {
|
|
3341
|
-
functionsToApply.push(traverseQuerySort(({ key, attribute, path })=>{
|
|
3342
|
-
// ID is not an attribute per se, so we need to make
|
|
3343
|
-
// an extra check to ensure we're not removing it
|
|
3344
|
-
if ([
|
|
3345
|
-
ID_ATTRIBUTE$1,
|
|
3346
|
-
DOC_ID_ATTRIBUTE$1
|
|
3347
|
-
].includes(key)) {
|
|
3348
|
-
return;
|
|
3349
|
-
}
|
|
3350
|
-
if (!attribute) {
|
|
3351
|
-
throwInvalidKey({
|
|
3352
|
-
key,
|
|
3353
|
-
path: path.attribute
|
|
3354
|
-
});
|
|
3355
|
-
}
|
|
3356
|
-
}, ctx));
|
|
3357
|
-
}
|
|
3358
|
-
// Validate dynamic zones from sort
|
|
3359
|
-
if (include.includes('dynamicZones')) {
|
|
3360
|
-
functionsToApply.push(traverseQuerySort(visitor, ctx));
|
|
3361
|
-
}
|
|
3362
|
-
// Validate morphTo relations from sort
|
|
3363
|
-
if (include.includes('morphRelations')) {
|
|
3364
|
-
functionsToApply.push(traverseQuerySort(visitor$1, ctx));
|
|
3365
|
-
}
|
|
3366
|
-
// Validate passwords from sort
|
|
3367
|
-
if (include.includes('passwords')) {
|
|
3368
|
-
functionsToApply.push(traverseQuerySort(visitor$3, ctx));
|
|
3369
|
-
}
|
|
3370
|
-
// Validate private from sort
|
|
3371
|
-
if (include.includes('private')) {
|
|
3372
|
-
functionsToApply.push(traverseQuerySort(visitor$2, ctx));
|
|
3373
|
-
}
|
|
3374
|
-
// Validate non-scalar empty keys
|
|
3375
|
-
if (include.includes('nonScalarEmptyKeys')) {
|
|
3376
|
-
functionsToApply.push(traverseQuerySort(({ key, attribute, value, path })=>{
|
|
3377
|
-
// ID is not an attribute per se, so we need to make
|
|
3378
|
-
// an extra check to ensure we're not removing it
|
|
3379
|
-
if ([
|
|
3380
|
-
ID_ATTRIBUTE$1,
|
|
3381
|
-
DOC_ID_ATTRIBUTE$1
|
|
3382
|
-
].includes(key)) {
|
|
3383
|
-
return;
|
|
3384
|
-
}
|
|
3385
|
-
if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
|
|
3386
|
-
throwInvalidKey({
|
|
3387
|
-
key,
|
|
3388
|
-
path: path.attribute
|
|
3389
|
-
});
|
|
3390
|
-
}
|
|
3391
|
-
}, ctx));
|
|
3392
|
-
}
|
|
3393
|
-
// Return directly if no validation functions are provided
|
|
3394
|
-
if (functionsToApply.length === 0) {
|
|
3395
|
-
return sort;
|
|
3396
|
-
}
|
|
3397
|
-
return pipe(...functionsToApply)(sort);
|
|
3398
|
-
});
|
|
3399
|
-
const defaultValidateSort = asyncCurry(async (ctx, sort)=>{
|
|
3400
|
-
return validateSort(ctx, sort, SORT_TRAVERSALS);
|
|
3401
|
-
});
|
|
3402
|
-
const FIELDS_TRAVERSALS = [
|
|
3403
|
-
'scalarAttributes',
|
|
3404
|
-
'privateFields',
|
|
3405
|
-
'passwordFields'
|
|
3406
|
-
];
|
|
3407
|
-
const validateFields = asyncCurry(async (ctx, fields, include)=>{
|
|
3408
|
-
if (!ctx.schema) {
|
|
3409
|
-
throw new Error('Missing schema in defaultValidateFields');
|
|
3410
|
-
}
|
|
3411
|
-
// Build the list of functions conditionally based on the include array
|
|
3412
|
-
const functionsToApply = [];
|
|
3413
|
-
// Only allow scalar attributes
|
|
3414
|
-
if (include.includes('scalarAttributes')) {
|
|
3415
|
-
functionsToApply.push(traverseQueryFields(({ key, attribute, path })=>{
|
|
3416
|
-
// ID is not an attribute per se, so we need to make
|
|
3417
|
-
// an extra check to ensure we're not throwing because of it
|
|
3418
|
-
if ([
|
|
3419
|
-
ID_ATTRIBUTE$1,
|
|
3420
|
-
DOC_ID_ATTRIBUTE$1
|
|
3421
|
-
].includes(key)) {
|
|
3422
|
-
return;
|
|
3423
|
-
}
|
|
3424
|
-
if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
|
|
3425
|
-
throwInvalidKey({
|
|
3426
|
-
key,
|
|
3427
|
-
path: path.attribute
|
|
3428
|
-
});
|
|
3429
|
-
}
|
|
3430
|
-
}, ctx));
|
|
3431
|
-
}
|
|
3432
|
-
// Private fields
|
|
3433
|
-
if (include.includes('privateFields')) {
|
|
3434
|
-
functionsToApply.push(traverseQueryFields(visitor$2, ctx));
|
|
3435
|
-
}
|
|
3436
|
-
// Password fields
|
|
3437
|
-
if (include.includes('passwordFields')) {
|
|
3438
|
-
functionsToApply.push(traverseQueryFields(visitor$3, ctx));
|
|
3439
|
-
}
|
|
3440
|
-
// Return directly if no validation functions are provided
|
|
3441
|
-
if (functionsToApply.length === 0) {
|
|
3442
|
-
return fields;
|
|
3443
|
-
}
|
|
3444
|
-
return pipe(...functionsToApply)(fields);
|
|
3445
|
-
});
|
|
3446
|
-
const defaultValidateFields = asyncCurry(async (ctx, fields)=>{
|
|
3447
|
-
return validateFields(ctx, fields, FIELDS_TRAVERSALS);
|
|
3448
|
-
});
|
|
3449
|
-
const POPULATE_TRAVERSALS = [
|
|
3450
|
-
'nonAttributesOperators',
|
|
3451
|
-
'private'
|
|
3452
|
-
];
|
|
3453
|
-
const validatePopulate = asyncCurry(async (ctx, populate, includes)=>{
|
|
3454
|
-
if (!ctx.schema) {
|
|
3455
|
-
throw new Error('Missing schema in defaultValidatePopulate');
|
|
3456
|
-
}
|
|
3457
|
-
// Build the list of functions conditionally based on the include array
|
|
3458
|
-
const functionsToApply = [];
|
|
3459
|
-
// Always include the main traversal function
|
|
3460
|
-
functionsToApply.push(traverseQueryPopulate(async ({ key, path, value, schema, attribute, getModel, parent }, { set })=>{
|
|
3461
|
-
/**
|
|
3462
|
-
* NOTE: The parent check is done to support "filters" (and the rest of keys) as valid attribute names.
|
|
3463
|
-
*
|
|
3464
|
-
* The parent will not be an attribute when its a "populate" / "filters" / "sort" ... key.
|
|
3465
|
-
* Only in those scenarios the node will be an attribute.
|
|
3466
|
-
*/ if (!parent?.attribute && attribute) {
|
|
3467
|
-
const isPopulatableAttribute = [
|
|
3468
|
-
'relation',
|
|
3469
|
-
'dynamiczone',
|
|
3470
|
-
'component',
|
|
3471
|
-
'media'
|
|
3472
|
-
].includes(attribute.type);
|
|
3473
|
-
// Throw on non-populate attributes
|
|
3474
|
-
if (!isPopulatableAttribute) {
|
|
3475
|
-
throwInvalidKey({
|
|
3476
|
-
key,
|
|
3477
|
-
path: path.raw
|
|
3478
|
-
});
|
|
3479
|
-
}
|
|
3480
|
-
// Valid populatable attribute, so return
|
|
3481
|
-
return;
|
|
3482
|
-
}
|
|
3483
|
-
// If we're looking at a populate fragment, ensure its target is valid
|
|
3484
|
-
if (key === 'on') {
|
|
3485
|
-
// Populate fragment should always be an object
|
|
3486
|
-
if (!fp.isObject(value)) {
|
|
3487
|
-
return throwInvalidKey({
|
|
3488
|
-
key,
|
|
3489
|
-
path: path.raw
|
|
3490
|
-
});
|
|
3491
|
-
}
|
|
3492
|
-
const targets = Object.keys(value);
|
|
3493
|
-
for (const target of targets){
|
|
3494
|
-
const model = getModel(target);
|
|
3495
|
-
// If a target is invalid (no matching model), then raise an error
|
|
3496
|
-
if (!model) {
|
|
3497
|
-
throwInvalidKey({
|
|
3498
|
-
key: target,
|
|
3499
|
-
path: `${path.raw}.${target}`
|
|
3500
|
-
});
|
|
3501
|
-
}
|
|
3502
|
-
}
|
|
3503
|
-
// If the fragment's target is fine, then let it pass
|
|
3504
|
-
return;
|
|
3505
|
-
}
|
|
3506
|
-
// Ignore plain wildcards
|
|
3507
|
-
if (key === '' && value === '*') {
|
|
3508
|
-
return;
|
|
3509
|
-
}
|
|
3510
|
-
// Ensure count is a boolean
|
|
3511
|
-
if (key === 'count') {
|
|
3512
|
-
try {
|
|
3513
|
-
parseType({
|
|
3514
|
-
type: 'boolean',
|
|
3515
|
-
value
|
|
3516
|
-
});
|
|
3517
|
-
return;
|
|
3518
|
-
} catch {
|
|
3519
|
-
throwInvalidKey({
|
|
3520
|
-
key,
|
|
3521
|
-
path: path.attribute
|
|
3522
|
-
});
|
|
3523
|
-
}
|
|
3524
|
-
}
|
|
3525
|
-
// Allowed boolean-like keywords should be ignored
|
|
3526
|
-
try {
|
|
3527
|
-
parseType({
|
|
3528
|
-
type: 'boolean',
|
|
3529
|
-
value: key
|
|
3530
|
-
});
|
|
3531
|
-
// Key is an allowed boolean-like keyword, skipping validation...
|
|
3532
|
-
return;
|
|
3533
|
-
} catch {
|
|
3534
|
-
// Continue, because it's not a boolean-like
|
|
3535
|
-
}
|
|
3536
|
-
// Handle nested `sort` validation with custom or default traversals
|
|
3537
|
-
if (key === 'sort') {
|
|
3538
|
-
set(key, await validateSort({
|
|
3539
|
-
schema,
|
|
3540
|
-
getModel
|
|
3541
|
-
}, value, includes?.sort || SORT_TRAVERSALS));
|
|
3542
|
-
return;
|
|
3543
|
-
}
|
|
3544
|
-
// Handle nested `filters` validation with custom or default traversals
|
|
3545
|
-
if (key === 'filters') {
|
|
3546
|
-
set(key, await validateFilters({
|
|
3547
|
-
schema,
|
|
3548
|
-
getModel
|
|
3549
|
-
}, value, includes?.filters || FILTER_TRAVERSALS));
|
|
3550
|
-
return;
|
|
3551
|
-
}
|
|
3552
|
-
// Handle nested `fields` validation with custom or default traversals
|
|
3553
|
-
if (key === 'fields') {
|
|
3554
|
-
set(key, await validateFields({
|
|
3555
|
-
schema,
|
|
3556
|
-
getModel
|
|
3557
|
-
}, value, includes?.fields || FIELDS_TRAVERSALS));
|
|
3558
|
-
return;
|
|
3559
|
-
}
|
|
3560
|
-
// Handle recursive nested `populate` validation with the same include object
|
|
3561
|
-
if (key === 'populate') {
|
|
3562
|
-
set(key, await validatePopulate({
|
|
3563
|
-
schema,
|
|
3564
|
-
getModel,
|
|
3565
|
-
parent: {
|
|
3566
|
-
key,
|
|
3567
|
-
path,
|
|
3568
|
-
schema,
|
|
3569
|
-
attribute
|
|
3570
|
-
},
|
|
3571
|
-
path
|
|
3572
|
-
}, value, includes // pass down the same includes object
|
|
3573
|
-
));
|
|
3574
|
-
return;
|
|
3575
|
-
}
|
|
3576
|
-
// Throw an error if non-attribute operators are included in the populate array
|
|
3577
|
-
if (includes?.populate?.includes('nonAttributesOperators')) {
|
|
3578
|
-
throwInvalidKey({
|
|
3579
|
-
key,
|
|
3580
|
-
path: path.attribute
|
|
3581
|
-
});
|
|
3582
|
-
}
|
|
3583
|
-
}, ctx));
|
|
3584
|
-
// Conditionally traverse for private fields only if 'private' is included
|
|
3585
|
-
if (includes?.populate?.includes('private')) {
|
|
3586
|
-
functionsToApply.push(traverseQueryPopulate(visitor$2, ctx));
|
|
3587
|
-
}
|
|
3588
|
-
// Return directly if no validation functions are provided
|
|
3589
|
-
if (functionsToApply.length === 0) {
|
|
3590
|
-
return populate;
|
|
3591
|
-
}
|
|
3592
|
-
return pipe(...functionsToApply)(populate);
|
|
3593
|
-
});
|
|
3594
|
-
const defaultValidatePopulate = asyncCurry(async (ctx, populate)=>{
|
|
3595
|
-
if (!ctx.schema) {
|
|
3596
|
-
throw new Error('Missing schema in defaultValidatePopulate');
|
|
3597
|
-
}
|
|
3598
|
-
// Call validatePopulate and include all validations by passing in full traversal arrays
|
|
3599
|
-
return validatePopulate(ctx, populate, {
|
|
3600
|
-
filters: FILTER_TRAVERSALS,
|
|
3601
|
-
sort: SORT_TRAVERSALS,
|
|
3602
|
-
fields: FIELDS_TRAVERSALS,
|
|
3603
|
-
populate: POPULATE_TRAVERSALS
|
|
3604
|
-
});
|
|
3605
|
-
});
|
|
3606
|
-
|
|
3607
|
-
var validators = /*#__PURE__*/Object.freeze({
|
|
3608
|
-
__proto__: null,
|
|
3609
|
-
FIELDS_TRAVERSALS: FIELDS_TRAVERSALS,
|
|
3610
|
-
FILTER_TRAVERSALS: FILTER_TRAVERSALS,
|
|
3611
|
-
POPULATE_TRAVERSALS: POPULATE_TRAVERSALS,
|
|
3612
|
-
SORT_TRAVERSALS: SORT_TRAVERSALS,
|
|
3613
|
-
defaultValidateFields: defaultValidateFields,
|
|
3614
|
-
defaultValidateFilters: defaultValidateFilters,
|
|
3615
|
-
defaultValidatePopulate: defaultValidatePopulate,
|
|
3616
|
-
defaultValidateSort: defaultValidateSort,
|
|
3617
|
-
validateFields: validateFields,
|
|
3618
|
-
validateFilters: validateFilters,
|
|
3619
|
-
validatePopulate: validatePopulate,
|
|
3620
|
-
validateSort: validateSort
|
|
3621
|
-
});
|
|
3622
|
-
|
|
3623
|
-
const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants$1;
|
|
3624
|
-
const createAPIValidators = (opts)=>{
|
|
3625
|
-
const { getModel } = opts || {};
|
|
3626
|
-
const validateInput = async (data, schema, { auth } = {})=>{
|
|
3627
|
-
if (!schema) {
|
|
3628
|
-
throw new Error('Missing schema in validateInput');
|
|
3629
|
-
}
|
|
3630
|
-
if (fp.isArray(data)) {
|
|
3631
|
-
await Promise.all(data.map((entry)=>validateInput(entry, schema, {
|
|
3632
|
-
auth
|
|
3633
|
-
})));
|
|
3634
|
-
return;
|
|
3635
|
-
}
|
|
3636
|
-
const nonWritableAttributes = getNonWritableAttributes(schema);
|
|
3637
|
-
const transforms = [
|
|
3638
|
-
(data)=>{
|
|
3639
|
-
if (fp.isObject(data)) {
|
|
3640
|
-
if (ID_ATTRIBUTE in data) {
|
|
3641
|
-
throwInvalidKey({
|
|
3642
|
-
key: ID_ATTRIBUTE
|
|
3643
|
-
});
|
|
3644
|
-
}
|
|
3645
|
-
if (DOC_ID_ATTRIBUTE in data) {
|
|
3646
|
-
throwInvalidKey({
|
|
3647
|
-
key: DOC_ID_ATTRIBUTE
|
|
3648
|
-
});
|
|
3649
|
-
}
|
|
3650
|
-
}
|
|
3651
|
-
return data;
|
|
3652
|
-
},
|
|
3653
|
-
// non-writable attributes
|
|
3654
|
-
traverseEntity$1(throwRestrictedFields(nonWritableAttributes), {
|
|
3655
|
-
schema,
|
|
3656
|
-
getModel
|
|
3657
|
-
}),
|
|
3658
|
-
// unrecognized attributes
|
|
3659
|
-
traverseEntity$1(throwUnrecognizedFields, {
|
|
3660
|
-
schema,
|
|
3661
|
-
getModel
|
|
3662
|
-
})
|
|
3663
|
-
];
|
|
3664
|
-
if (auth) {
|
|
3665
|
-
// restricted relations
|
|
3666
|
-
transforms.push(traverseEntity$1(throwRestrictedRelations(auth), {
|
|
3667
|
-
schema,
|
|
3668
|
-
getModel
|
|
3669
|
-
}));
|
|
3670
|
-
}
|
|
3671
|
-
// Apply validators from registry if exists
|
|
3672
|
-
opts?.validators?.input?.forEach((validator)=>transforms.push(validator(schema)));
|
|
3673
|
-
try {
|
|
3674
|
-
await pipe(...transforms)(data);
|
|
3675
|
-
} catch (e) {
|
|
3676
|
-
if (e instanceof ValidationError) {
|
|
3677
|
-
e.details.source = 'body';
|
|
3678
|
-
}
|
|
3679
|
-
throw e;
|
|
3680
|
-
}
|
|
3681
|
-
};
|
|
3682
|
-
const validateQuery = async (query, schema, { auth } = {})=>{
|
|
3683
|
-
if (!schema) {
|
|
3684
|
-
throw new Error('Missing schema in validateQuery');
|
|
3685
|
-
}
|
|
3686
|
-
const { filters, sort, fields, populate } = query;
|
|
3687
|
-
if (filters) {
|
|
3688
|
-
await validateFilters(filters, schema, {
|
|
3689
|
-
auth
|
|
3690
|
-
});
|
|
3691
|
-
}
|
|
3692
|
-
if (sort) {
|
|
3693
|
-
await validateSort(sort, schema, {
|
|
3694
|
-
auth
|
|
3695
|
-
});
|
|
3696
|
-
}
|
|
3697
|
-
if (fields) {
|
|
3698
|
-
await validateFields(fields, schema);
|
|
3699
|
-
}
|
|
3700
|
-
// a wildcard is always valid; its conversion will be handled by the entity service and can be optimized with sanitizer
|
|
3701
|
-
if (populate && populate !== '*') {
|
|
3702
|
-
await validatePopulate(populate, schema);
|
|
3703
|
-
}
|
|
3704
|
-
};
|
|
3705
|
-
const validateFilters = async (filters, schema, { auth } = {})=>{
|
|
3706
|
-
if (!schema) {
|
|
3707
|
-
throw new Error('Missing schema in validateFilters');
|
|
3708
|
-
}
|
|
3709
|
-
if (fp.isArray(filters)) {
|
|
3710
|
-
await Promise.all(filters.map((filter)=>validateFilters(filter, schema, {
|
|
3711
|
-
auth
|
|
3712
|
-
})));
|
|
3713
|
-
return;
|
|
3714
|
-
}
|
|
3715
|
-
const transforms = [
|
|
3716
|
-
defaultValidateFilters({
|
|
3717
|
-
schema,
|
|
3718
|
-
getModel
|
|
3719
|
-
})
|
|
3720
|
-
];
|
|
3721
|
-
if (auth) {
|
|
3722
|
-
transforms.push(traverseQueryFilters(throwRestrictedRelations(auth), {
|
|
3723
|
-
schema,
|
|
3724
|
-
getModel
|
|
3725
|
-
}));
|
|
3726
|
-
}
|
|
3727
|
-
try {
|
|
3728
|
-
await pipe(...transforms)(filters);
|
|
3729
|
-
} catch (e) {
|
|
3730
|
-
if (e instanceof ValidationError) {
|
|
3731
|
-
e.details.source = 'query';
|
|
3732
|
-
e.details.param = 'filters';
|
|
3733
|
-
}
|
|
3734
|
-
throw e;
|
|
3735
|
-
}
|
|
3736
|
-
};
|
|
3737
|
-
const validateSort = async (sort, schema, { auth } = {})=>{
|
|
3738
|
-
if (!schema) {
|
|
3739
|
-
throw new Error('Missing schema in validateSort');
|
|
3740
|
-
}
|
|
3741
|
-
const transforms = [
|
|
3742
|
-
defaultValidateSort({
|
|
3743
|
-
schema,
|
|
3744
|
-
getModel
|
|
3745
|
-
})
|
|
3746
|
-
];
|
|
3747
|
-
if (auth) {
|
|
3748
|
-
transforms.push(traverseQuerySort(throwRestrictedRelations(auth), {
|
|
3749
|
-
schema,
|
|
3750
|
-
getModel
|
|
3751
|
-
}));
|
|
3752
|
-
}
|
|
3753
|
-
try {
|
|
3754
|
-
await pipe(...transforms)(sort);
|
|
3755
|
-
} catch (e) {
|
|
3756
|
-
if (e instanceof ValidationError) {
|
|
3757
|
-
e.details.source = 'query';
|
|
3758
|
-
e.details.param = 'sort';
|
|
3759
|
-
}
|
|
3760
|
-
throw e;
|
|
3761
|
-
}
|
|
3762
|
-
};
|
|
3763
|
-
const validateFields = async (fields, schema)=>{
|
|
3764
|
-
if (!schema) {
|
|
3765
|
-
throw new Error('Missing schema in validateFields');
|
|
3766
|
-
}
|
|
3767
|
-
const transforms = [
|
|
3768
|
-
defaultValidateFields({
|
|
3769
|
-
schema,
|
|
3770
|
-
getModel
|
|
3771
|
-
})
|
|
3772
|
-
];
|
|
3773
|
-
try {
|
|
3774
|
-
await pipe(...transforms)(fields);
|
|
3775
|
-
} catch (e) {
|
|
3776
|
-
if (e instanceof ValidationError) {
|
|
3777
|
-
e.details.source = 'query';
|
|
3778
|
-
e.details.param = 'fields';
|
|
3779
|
-
}
|
|
3780
|
-
throw e;
|
|
3781
|
-
}
|
|
3782
|
-
};
|
|
3783
|
-
const validatePopulate = async (populate, schema, { auth } = {})=>{
|
|
3784
|
-
if (!schema) {
|
|
3785
|
-
throw new Error('Missing schema in sanitizePopulate');
|
|
3786
|
-
}
|
|
3787
|
-
const transforms = [
|
|
3788
|
-
defaultValidatePopulate({
|
|
3789
|
-
schema,
|
|
3790
|
-
getModel
|
|
3791
|
-
})
|
|
3792
|
-
];
|
|
3793
|
-
if (auth) {
|
|
3794
|
-
transforms.push(traverseQueryPopulate(throwRestrictedRelations(auth), {
|
|
3795
|
-
schema,
|
|
3796
|
-
getModel
|
|
3797
|
-
}));
|
|
3798
|
-
}
|
|
3799
|
-
try {
|
|
3800
|
-
await pipe(...transforms)(populate);
|
|
3801
|
-
} catch (e) {
|
|
3802
|
-
if (e instanceof ValidationError) {
|
|
3803
|
-
e.details.source = 'query';
|
|
3804
|
-
e.details.param = 'populate';
|
|
3805
|
-
}
|
|
3806
|
-
throw e;
|
|
3807
|
-
}
|
|
3808
|
-
};
|
|
3809
|
-
return {
|
|
3810
|
-
input: validateInput,
|
|
3811
|
-
query: validateQuery,
|
|
3812
|
-
filters: validateFilters,
|
|
3813
|
-
sort: validateSort,
|
|
3814
|
-
fields: validateFields,
|
|
3815
|
-
populate: validatePopulate
|
|
3816
|
-
};
|
|
3817
|
-
};
|
|
3818
|
-
|
|
3819
|
-
var index = /*#__PURE__*/Object.freeze({
|
|
3820
|
-
__proto__: null,
|
|
3821
|
-
createAPIValidators: createAPIValidators,
|
|
3822
|
-
validators: validators,
|
|
3823
|
-
visitors: index$1
|
|
3824
|
-
});
|
|
3825
|
-
|
|
3826
|
-
const STRAPI_DEFAULTS = {
|
|
3827
|
-
offset: {
|
|
3828
|
-
start: 0,
|
|
3829
|
-
limit: 10
|
|
3830
|
-
},
|
|
3831
|
-
page: {
|
|
3832
|
-
page: 1,
|
|
3833
|
-
pageSize: 10
|
|
3834
|
-
}
|
|
3835
|
-
};
|
|
3836
|
-
const paginationAttributes = [
|
|
3837
|
-
'start',
|
|
3838
|
-
'limit',
|
|
3839
|
-
'page',
|
|
3840
|
-
'pageSize'
|
|
3841
|
-
];
|
|
3842
|
-
const withMaxLimit = (limit, maxLimit = -1)=>{
|
|
3843
|
-
if (maxLimit === -1 || limit < maxLimit) {
|
|
3844
|
-
return limit;
|
|
3845
|
-
}
|
|
3846
|
-
return maxLimit;
|
|
3847
|
-
};
|
|
3848
|
-
// Ensure minimum page & pageSize values (page >= 1, pageSize >= 0, start >= 0, limit >= 0)
|
|
3849
|
-
const ensureMinValues = ({ start, limit })=>({
|
|
3850
|
-
start: Math.max(start, 0),
|
|
3851
|
-
limit: limit === -1 ? limit : Math.max(limit, 1)
|
|
3852
|
-
});
|
|
3853
|
-
const ensureMaxValues = (maxLimit = -1)=>({ start, limit })=>({
|
|
3854
|
-
start,
|
|
3855
|
-
limit: withMaxLimit(limit, maxLimit)
|
|
3856
|
-
});
|
|
3857
|
-
// Apply maxLimit as the limit when limit is -1
|
|
3858
|
-
const withNoLimit = (pagination, maxLimit = -1)=>({
|
|
3859
|
-
...pagination,
|
|
3860
|
-
limit: pagination.limit === -1 ? maxLimit : pagination.limit
|
|
3861
|
-
});
|
|
3862
|
-
const withDefaultPagination = (args, { defaults = {}, maxLimit = -1 } = {})=>{
|
|
3863
|
-
const defaultValues = fp.merge(STRAPI_DEFAULTS, defaults);
|
|
3864
|
-
const usePagePagination = !fp.isNil(args.page) || !fp.isNil(args.pageSize);
|
|
3865
|
-
const useOffsetPagination = !fp.isNil(args.start) || !fp.isNil(args.limit);
|
|
3866
|
-
const ensureValidValues = fp.pipe(ensureMinValues, ensureMaxValues(maxLimit));
|
|
3867
|
-
// If there is no pagination attribute, don't modify the payload
|
|
3868
|
-
if (!usePagePagination && !useOffsetPagination) {
|
|
3869
|
-
return fp.merge(args, ensureValidValues(defaultValues.offset));
|
|
3870
|
-
}
|
|
3871
|
-
// If there is page & offset pagination attributes, throw an error
|
|
3872
|
-
if (usePagePagination && useOffsetPagination) {
|
|
3873
|
-
throw new PaginationError('Cannot use both page & offset pagination in the same query');
|
|
3874
|
-
}
|
|
3875
|
-
const pagination = {
|
|
3876
|
-
start: 0,
|
|
3877
|
-
limit: 0
|
|
3878
|
-
};
|
|
3879
|
-
// Start / Limit
|
|
3880
|
-
if (useOffsetPagination) {
|
|
3881
|
-
const { start, limit } = fp.merge(defaultValues.offset, args);
|
|
3882
|
-
Object.assign(pagination, {
|
|
3883
|
-
start,
|
|
3884
|
-
limit
|
|
3885
|
-
});
|
|
3886
|
-
}
|
|
3887
|
-
// Page / PageSize
|
|
3888
|
-
if (usePagePagination) {
|
|
3889
|
-
const { page, pageSize } = fp.merge(defaultValues.page, {
|
|
3890
|
-
...args,
|
|
3891
|
-
pageSize: Math.max(1, args.pageSize ?? 0)
|
|
3892
|
-
});
|
|
3893
|
-
Object.assign(pagination, {
|
|
3894
|
-
start: (page - 1) * pageSize,
|
|
3895
|
-
limit: pageSize
|
|
3896
|
-
});
|
|
3897
|
-
}
|
|
3898
|
-
// Handle -1 limit
|
|
3899
|
-
Object.assign(pagination, withNoLimit(pagination, maxLimit));
|
|
3900
|
-
const replacePaginationAttributes = fp.pipe(// Remove pagination attributes
|
|
3901
|
-
fp.omit(paginationAttributes), // Merge the object with the new pagination + ensure minimum & maximum values
|
|
3902
|
-
fp.merge(ensureValidValues(pagination)));
|
|
3903
|
-
return replacePaginationAttributes(args);
|
|
3904
|
-
};
|
|
3905
|
-
/**
|
|
3906
|
-
* Transform pagination information into a paginated response:
|
|
3907
|
-
* {
|
|
3908
|
-
* page: number,
|
|
3909
|
-
* pageSize: number,
|
|
3910
|
-
* pageCount: number,
|
|
3911
|
-
* total: number
|
|
3912
|
-
* }
|
|
3913
|
-
*/ const transformPagedPaginationInfo = (paginationInfo, total)=>{
|
|
3914
|
-
if (!fp.isNil(paginationInfo.page)) {
|
|
3915
|
-
const page = paginationInfo.page;
|
|
3916
|
-
const pageSize = paginationInfo.pageSize ?? total;
|
|
3917
|
-
return {
|
|
3918
|
-
page,
|
|
3919
|
-
pageSize,
|
|
3920
|
-
pageCount: pageSize > 0 ? Math.ceil(total / pageSize) : 0,
|
|
3921
|
-
total
|
|
3922
|
-
};
|
|
3923
|
-
}
|
|
3924
|
-
if (!fp.isNil(paginationInfo.start)) {
|
|
3925
|
-
const start = paginationInfo.start;
|
|
3926
|
-
const limit = paginationInfo.limit ?? total;
|
|
3927
|
-
// Start limit to page page size
|
|
3928
|
-
return {
|
|
3929
|
-
page: Math.floor(start / limit) + 1,
|
|
3930
|
-
pageSize: limit,
|
|
3931
|
-
pageCount: limit > 0 ? Math.ceil(total / limit) : 0,
|
|
3932
|
-
total
|
|
3933
|
-
};
|
|
3934
|
-
}
|
|
3935
|
-
// Default pagination
|
|
3936
|
-
return {
|
|
3937
|
-
...paginationInfo,
|
|
3938
|
-
page: 1,
|
|
3939
|
-
pageSize: 10,
|
|
3940
|
-
pageCount: 1,
|
|
3941
|
-
total
|
|
3942
|
-
};
|
|
3943
|
-
};
|
|
3944
|
-
/**
|
|
3945
|
-
* Transform pagination information into a offset response:
|
|
3946
|
-
* {
|
|
3947
|
-
* start: number,
|
|
3948
|
-
* limit: number,
|
|
3949
|
-
* total: number
|
|
3950
|
-
* }
|
|
3951
|
-
*/ const transformOffsetPaginationInfo = (paginationInfo, total)=>{
|
|
3952
|
-
if (!fp.isNil(paginationInfo.page)) {
|
|
3953
|
-
const limit = paginationInfo.pageSize ?? total;
|
|
3954
|
-
const start = (paginationInfo.page - 1) * limit;
|
|
3955
|
-
return {
|
|
3956
|
-
start,
|
|
3957
|
-
limit,
|
|
3958
|
-
total
|
|
3959
|
-
};
|
|
3960
|
-
}
|
|
3961
|
-
if (!fp.isNil(paginationInfo.start)) {
|
|
3962
|
-
const start = paginationInfo.start;
|
|
3963
|
-
const limit = paginationInfo.limit ?? total;
|
|
3964
|
-
// Start limit to page page size
|
|
3965
|
-
return {
|
|
3966
|
-
start,
|
|
3967
|
-
limit,
|
|
3968
|
-
total
|
|
3969
|
-
};
|
|
3970
|
-
}
|
|
3971
|
-
// Default pagination
|
|
3972
|
-
return {
|
|
3973
|
-
...paginationInfo,
|
|
3974
|
-
start: 0,
|
|
3975
|
-
limit: 10,
|
|
3976
|
-
total
|
|
3977
|
-
};
|
|
3978
|
-
};
|
|
3979
|
-
|
|
3980
|
-
var pagination = /*#__PURE__*/Object.freeze({
|
|
3981
|
-
__proto__: null,
|
|
3982
|
-
transformOffsetPaginationInfo: transformOffsetPaginationInfo,
|
|
3983
|
-
transformPagedPaginationInfo: transformPagedPaginationInfo,
|
|
3984
|
-
withDefaultPagination: withDefaultPagination
|
|
3985
|
-
});
|
|
3986
|
-
|
|
3987
|
-
const SUPPORTED_PACKAGE_MANAGERS = [
|
|
3988
|
-
'npm',
|
|
3989
|
-
'yarn'
|
|
3990
|
-
];
|
|
3991
|
-
const DEFAULT_PACKAGE_MANAGER = 'npm';
|
|
3992
|
-
const getPreferred = async (pkgPath)=>{
|
|
3993
|
-
const pm = await preferredPM(pkgPath);
|
|
3994
|
-
const hasPackageManager = pm !== undefined;
|
|
3995
|
-
if (!hasPackageManager) {
|
|
3996
|
-
throw new Error(`Couldn't find a package manager in your project.`);
|
|
3997
|
-
}
|
|
3998
|
-
const isPackageManagerSupported = SUPPORTED_PACKAGE_MANAGERS.includes(pm.name);
|
|
3999
|
-
if (!isPackageManagerSupported) {
|
|
4000
|
-
process.emitWarning(`We detected your package manager (${pm.name} v${pm.version}), but it's not officially supported by Strapi yet. Defaulting to npm instead.`);
|
|
4001
|
-
return DEFAULT_PACKAGE_MANAGER;
|
|
4002
|
-
}
|
|
4003
|
-
return pm.name;
|
|
4004
|
-
};
|
|
4005
|
-
const installDependencies = (path, packageManager, options = {})=>{
|
|
4006
|
-
return execa(packageManager, [
|
|
4007
|
-
'install'
|
|
4008
|
-
], {
|
|
4009
|
-
...options,
|
|
4010
|
-
cwd: path,
|
|
4011
|
-
stdin: 'ignore'
|
|
4012
|
-
});
|
|
4013
|
-
};
|
|
4014
|
-
|
|
4015
|
-
var packageManager = /*#__PURE__*/Object.freeze({
|
|
4016
|
-
__proto__: null,
|
|
4017
|
-
getPreferred: getPreferred,
|
|
4018
|
-
installDependencies: installDependencies
|
|
4019
|
-
});
|
|
4020
|
-
|
|
4021
|
-
/**
|
|
4022
|
-
* Create a strict interpolation RegExp based on the given variables' name
|
|
4023
|
-
*/ const createStrictInterpolationRegExp = (allowedVariableNames, flags)=>{
|
|
4024
|
-
const oneOfVariables = allowedVariableNames.join('|');
|
|
4025
|
-
// 1. We need to match the delimiters: <%= ... %>
|
|
4026
|
-
// 2. We accept any number of whitespaces characters before and/or after the variable name: \s* ... \s*
|
|
4027
|
-
// 3. We only accept values from the variable list as interpolation variables' name: : (${oneOfVariables})
|
|
4028
|
-
return new RegExp(`<%=\\s*(${oneOfVariables})\\s*%>`, flags);
|
|
4029
|
-
};
|
|
4030
|
-
/**
|
|
4031
|
-
* Create a loose interpolation RegExp to match as many groups as possible
|
|
4032
|
-
*/ const createLooseInterpolationRegExp = (flags)=>new RegExp(/<%=([\s\S]+?)%>/, flags);
|
|
4033
|
-
|
|
4034
|
-
var template = /*#__PURE__*/Object.freeze({
|
|
4035
|
-
__proto__: null,
|
|
4036
|
-
createLooseInterpolationRegExp: createLooseInterpolationRegExp,
|
|
4037
|
-
createStrictInterpolationRegExp: createStrictInterpolationRegExp
|
|
4038
|
-
});
|
|
4039
|
-
|
|
4040
|
-
const kbytesToBytes = (kbytes)=>kbytes * 1000;
|
|
4041
|
-
const bytesToKbytes = (bytes)=>Math.round(bytes / 1000 * 100) / 100;
|
|
4042
|
-
const bytesToHumanReadable = (bytes)=>{
|
|
4043
|
-
const sizes = [
|
|
4044
|
-
'Bytes',
|
|
4045
|
-
'KB',
|
|
4046
|
-
'MB',
|
|
4047
|
-
'GB',
|
|
4048
|
-
'TB',
|
|
4049
|
-
'PB'
|
|
4050
|
-
];
|
|
4051
|
-
if (bytes === 0) return '0 Bytes';
|
|
4052
|
-
const i = parseInt(`${Math.floor(Math.log(bytes) / Math.log(1000))}`, 10);
|
|
4053
|
-
return `${Math.round(bytes / 1000 ** i)} ${sizes[i]}`;
|
|
4054
|
-
};
|
|
4055
|
-
const streamToBuffer = (stream)=>new Promise((resolve, reject)=>{
|
|
4056
|
-
const chunks = [];
|
|
4057
|
-
stream.on('data', (chunk)=>{
|
|
4058
|
-
chunks.push(chunk);
|
|
4059
|
-
});
|
|
4060
|
-
stream.on('end', ()=>{
|
|
4061
|
-
resolve(Buffer.concat(chunks));
|
|
4062
|
-
});
|
|
4063
|
-
stream.on('error', reject);
|
|
4064
|
-
});
|
|
4065
|
-
const getStreamSize = (stream)=>new Promise((resolve, reject)=>{
|
|
4066
|
-
let size = 0;
|
|
4067
|
-
stream.on('data', (chunk)=>{
|
|
4068
|
-
size += Buffer.byteLength(chunk);
|
|
4069
|
-
});
|
|
4070
|
-
stream.on('close', ()=>resolve(size));
|
|
4071
|
-
stream.on('error', reject);
|
|
4072
|
-
stream.resume();
|
|
4073
|
-
});
|
|
4074
|
-
/**
|
|
4075
|
-
* Create a writeable Node.js stream that discards received data.
|
|
4076
|
-
* Useful for testing, draining a stream of data, etc.
|
|
4077
|
-
*/ function writableDiscardStream(options) {
|
|
4078
|
-
return new node_stream.Writable({
|
|
4079
|
-
...options,
|
|
4080
|
-
write (chunk, encding, callback) {
|
|
4081
|
-
setImmediate(callback);
|
|
4082
|
-
}
|
|
4083
|
-
});
|
|
4084
|
-
}
|
|
4085
|
-
|
|
4086
|
-
var file = /*#__PURE__*/Object.freeze({
|
|
4087
|
-
__proto__: null,
|
|
4088
|
-
bytesToHumanReadable: bytesToHumanReadable,
|
|
4089
|
-
bytesToKbytes: bytesToKbytes,
|
|
4090
|
-
getStreamSize: getStreamSize,
|
|
4091
|
-
kbytesToBytes: kbytesToBytes,
|
|
4092
|
-
streamToBuffer: streamToBuffer,
|
|
4093
|
-
writableDiscardStream: writableDiscardStream
|
|
4094
|
-
});
|
|
4095
|
-
|
|
4096
|
-
const createPolicy = (options)=>{
|
|
4097
|
-
const { name = 'unnamed', validator, handler } = options;
|
|
4098
|
-
const wrappedValidator = (config)=>{
|
|
4099
|
-
if (validator) {
|
|
4100
|
-
try {
|
|
4101
|
-
validator(config);
|
|
4102
|
-
} catch (e) {
|
|
4103
|
-
throw new Error(`Invalid config passed to "${name}" policy.`);
|
|
4104
|
-
}
|
|
4105
|
-
}
|
|
4106
|
-
};
|
|
4107
|
-
return {
|
|
4108
|
-
name,
|
|
4109
|
-
validator: wrappedValidator,
|
|
4110
|
-
handler
|
|
4111
|
-
};
|
|
4112
|
-
};
|
|
4113
|
-
const createPolicyContext = (type, ctx)=>{
|
|
4114
|
-
return Object.assign({
|
|
4115
|
-
is: fp.eq(type),
|
|
4116
|
-
get type () {
|
|
4117
|
-
return type;
|
|
4118
|
-
}
|
|
4119
|
-
}, ctx);
|
|
4120
|
-
};
|
|
4121
|
-
|
|
4122
|
-
var policy = /*#__PURE__*/Object.freeze({
|
|
4123
|
-
__proto__: null,
|
|
4124
|
-
createPolicy: createPolicy,
|
|
4125
|
-
createPolicyContext: createPolicyContext
|
|
4126
|
-
});
|
|
4127
|
-
|
|
4128
|
-
const nameToSlug = (name, options = {
|
|
4129
|
-
separator: '-'
|
|
4130
|
-
})=>slugify(name, options);
|
|
4131
|
-
const nameToCollectionName = (name)=>slugify(name, {
|
|
4132
|
-
separator: '_'
|
|
4133
|
-
});
|
|
4134
|
-
const toRegressedEnumValue = (value)=>slugify(value, {
|
|
4135
|
-
decamelize: false,
|
|
4136
|
-
lowercase: false,
|
|
4137
|
-
separator: '_'
|
|
4138
|
-
});
|
|
4139
|
-
const getCommonPath = (...paths)=>{
|
|
4140
|
-
const [segments, ...otherSegments] = paths.map((it)=>_.split(it, '/'));
|
|
4141
|
-
return _.join(_.takeWhile(segments, (str, index)=>otherSegments.every((it)=>it[index] === str)), '/');
|
|
4142
|
-
};
|
|
4143
|
-
const isEqual = (a, b)=>String(a) === String(b);
|
|
4144
|
-
const isCamelCase = (value)=>/^[a-z][a-zA-Z0-9]+$/.test(value);
|
|
4145
|
-
const isKebabCase = (value)=>/^([a-z][a-z0-9]*)(-[a-z0-9]+)*$/.test(value);
|
|
4146
|
-
const startsWithANumber = (value)=>/^[0-9]/.test(value);
|
|
4147
|
-
const joinBy = (joint, ...args)=>{
|
|
4148
|
-
const trim = fp.trimChars(joint);
|
|
4149
|
-
const trimEnd = fp.trimCharsEnd(joint);
|
|
4150
|
-
const trimStart = fp.trimCharsStart(joint);
|
|
4151
|
-
return args.reduce((url, path, index)=>{
|
|
4152
|
-
if (args.length === 1) return path;
|
|
4153
|
-
if (index === 0) return trimEnd(path);
|
|
4154
|
-
if (index === args.length - 1) return url + joint + trimStart(path);
|
|
4155
|
-
return url + joint + trim(path);
|
|
4156
|
-
}, '');
|
|
4157
|
-
};
|
|
4158
|
-
const toKebabCase = (value)=>_.kebabCase(value);
|
|
4159
|
-
|
|
4160
|
-
var strings = /*#__PURE__*/Object.freeze({
|
|
4161
|
-
__proto__: null,
|
|
4162
|
-
getCommonPath: getCommonPath,
|
|
4163
|
-
isCamelCase: isCamelCase,
|
|
4164
|
-
isEqual: isEqual,
|
|
4165
|
-
isKebabCase: isKebabCase,
|
|
4166
|
-
joinBy: joinBy,
|
|
4167
|
-
nameToCollectionName: nameToCollectionName,
|
|
4168
|
-
nameToSlug: nameToSlug,
|
|
4169
|
-
startsWithANumber: startsWithANumber,
|
|
4170
|
-
toKebabCase: toKebabCase,
|
|
4171
|
-
toRegressedEnumValue: toRegressedEnumValue
|
|
4172
|
-
});
|
|
4173
|
-
|
|
4174
|
-
const castIncludes = (arr, val, cast)=>arr.map((val)=>cast(val)).includes(cast(val));
|
|
4175
|
-
const includesString = (arr, val)=>castIncludes(arr, val, String);
|
|
4176
|
-
|
|
4177
|
-
var arrays = /*#__PURE__*/Object.freeze({
|
|
4178
|
-
__proto__: null,
|
|
4179
|
-
includesString: includesString
|
|
4180
|
-
});
|
|
4181
|
-
|
|
4182
|
-
const keysDeep = (obj, path = [])=>!_.isObject(obj) ? [
|
|
4183
|
-
path.join('.')
|
|
4184
|
-
] : _.reduce(obj, (acc, next, key)=>_.concat(acc, keysDeep(next, [
|
|
4185
|
-
...path,
|
|
4186
|
-
key
|
|
4187
|
-
])), []);
|
|
4188
|
-
|
|
4189
|
-
var objects = /*#__PURE__*/Object.freeze({
|
|
4190
|
-
__proto__: null,
|
|
4191
|
-
keysDeep: keysDeep
|
|
4192
|
-
});
|
|
4193
|
-
|
|
4194
|
-
// Using timestamp (milliseconds) to be sure it is unique
|
|
4195
|
-
// + converting timestamp to base 36 for better readibility
|
|
4196
|
-
const timestampCode = (date)=>{
|
|
4197
|
-
const referDate = date ?? new Date();
|
|
4198
|
-
return referDate.getTime().toString(36);
|
|
4199
|
-
};
|
|
4200
|
-
|
|
4201
|
-
var dates = /*#__PURE__*/Object.freeze({
|
|
4202
|
-
__proto__: null,
|
|
4203
|
-
timestampCode: timestampCode
|
|
4204
|
-
});
|
|
4205
|
-
|
|
4206
|
-
// Code copied from the yup library (https://github.com/jquense/yup)
|
|
4207
|
-
// https://github.com/jquense/yup/blob/2778b88bdacd5260d593c6468793da2e77daf21f/src/util/printValue.ts
|
|
4208
|
-
const { toString } = Object.prototype;
|
|
4209
|
-
const errorToString = Error.prototype.toString;
|
|
4210
|
-
const regExpToString = RegExp.prototype.toString;
|
|
4211
|
-
const symbolToString = typeof Symbol !== 'undefined' ? Symbol.prototype.toString : ()=>'';
|
|
4212
|
-
const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/;
|
|
4213
|
-
function printNumber(val) {
|
|
4214
|
-
// eslint-disable-next-line eqeqeq
|
|
4215
|
-
if (val != +val) return 'NaN';
|
|
4216
|
-
const isNegativeZero = val === 0 && 1 / val < 0;
|
|
4217
|
-
return isNegativeZero ? '-0' : `${val}`;
|
|
4218
|
-
}
|
|
4219
|
-
function printSimpleValue(val, quoteStrings = false) {
|
|
4220
|
-
if (val == null || val === true || val === false) return `${val}`;
|
|
4221
|
-
if (typeof val === 'number') return printNumber(val);
|
|
4222
|
-
if (typeof val === 'string') return quoteStrings ? `"${val}"` : val;
|
|
4223
|
-
if (typeof val === 'function') return `[Function ${val.name || 'anonymous'}]`;
|
|
4224
|
-
if (typeof val === 'symbol') return symbolToString.call(val).replace(SYMBOL_REGEXP, 'Symbol($1)');
|
|
4225
|
-
const tag = toString.call(val).slice(8, -1);
|
|
4226
|
-
if (tag === 'Date') {
|
|
4227
|
-
const v = val;
|
|
4228
|
-
return Number.isNaN(v.getTime()) ? `${v}` : v.toISOString();
|
|
4229
|
-
}
|
|
4230
|
-
if (tag === 'Error' || val instanceof Error) return `[${errorToString.call(val)}]`;
|
|
4231
|
-
if (tag === 'RegExp') return regExpToString.call(val);
|
|
4232
|
-
return null;
|
|
4233
|
-
}
|
|
4234
|
-
function printValue(value, quoteStrings) {
|
|
4235
|
-
const result = printSimpleValue(value, quoteStrings);
|
|
4236
|
-
if (result !== null) return result;
|
|
4237
|
-
return JSON.stringify(value, function replacer(key, value) {
|
|
4238
|
-
const result = printSimpleValue(this[key], quoteStrings);
|
|
4239
|
-
if (result !== null) return result;
|
|
4240
|
-
return value;
|
|
4241
|
-
}, 2);
|
|
4242
|
-
}
|
|
4243
|
-
|
|
4244
|
-
const strapiID = ()=>new StrapiIDSchema();
|
|
4245
|
-
const isNotNilTest = (value)=>!_.isNil(value);
|
|
4246
|
-
const isNotNullTest = (value)=>!_.isNull(value);
|
|
4247
|
-
yup__namespace.addMethod(yup__namespace.mixed, 'notNil', function isNotNill(msg = '${path} must be defined.') {
|
|
4248
|
-
return this.test('defined', msg, isNotNilTest);
|
|
4249
|
-
});
|
|
4250
|
-
yup__namespace.addMethod(yup__namespace.mixed, 'notNull', function isNotNull(msg = '${path} cannot be null.') {
|
|
4251
|
-
return this.test('defined', msg, isNotNullTest);
|
|
4252
|
-
});
|
|
4253
|
-
yup__namespace.addMethod(yup__namespace.mixed, 'isFunction', function isFunction(message = '${path} is not a function') {
|
|
4254
|
-
return this.test('is a function', message, (value)=>_.isUndefined(value) || _.isFunction(value));
|
|
4255
|
-
});
|
|
4256
|
-
yup__namespace.addMethod(yup__namespace.string, 'isCamelCase', function isCamelCase$1(message = '${path} is not in camel case (anExampleOfCamelCase)') {
|
|
4257
|
-
return this.test('is in camelCase', message, (value)=>value ? isCamelCase(value) : true);
|
|
4258
|
-
});
|
|
4259
|
-
yup__namespace.addMethod(yup__namespace.string, 'isKebabCase', function isKebabCase$1(message = '${path} is not in kebab case (an-example-of-kebab-case)') {
|
|
4260
|
-
return this.test('is in kebab-case', message, (value)=>value ? isKebabCase(value) : true);
|
|
4261
|
-
});
|
|
4262
|
-
yup__namespace.addMethod(yup__namespace.object, 'onlyContainsFunctions', function onlyContainsFunctions(message = '${path} contains values that are not functions') {
|
|
4263
|
-
return this.test('only contains functions', message, (value)=>_.isUndefined(value) || value && Object.values(value).every(_.isFunction));
|
|
4264
|
-
});
|
|
4265
|
-
yup__namespace.addMethod(yup__namespace.array, 'uniqueProperty', function uniqueProperty(propertyName, message) {
|
|
4266
|
-
return this.test('unique', message, function unique(list) {
|
|
4267
|
-
const errors = [];
|
|
4268
|
-
list?.forEach((element, index)=>{
|
|
4269
|
-
const sameElements = list.filter((e)=>fp.get(propertyName, e) === fp.get(propertyName, element));
|
|
4270
|
-
if (sameElements.length > 1) {
|
|
4271
|
-
errors.push(this.createError({
|
|
4272
|
-
path: `${this.path}[${index}].${propertyName}`,
|
|
4273
|
-
message
|
|
4274
|
-
}));
|
|
4275
|
-
}
|
|
4276
|
-
});
|
|
4277
|
-
if (errors.length) {
|
|
4278
|
-
throw new yup__namespace.ValidationError(errors);
|
|
4279
|
-
}
|
|
4280
|
-
return true;
|
|
4281
|
-
});
|
|
4282
|
-
});
|
|
4283
|
-
class StrapiIDSchema extends yup__namespace.MixedSchema {
|
|
4284
|
-
_typeCheck(value) {
|
|
4285
|
-
return typeof value === 'string' || fp.isNumber(value) && fp.isInteger(value) && value >= 0;
|
|
4286
|
-
}
|
|
4287
|
-
constructor(){
|
|
4288
|
-
super({
|
|
4289
|
-
type: 'strapiID'
|
|
4290
|
-
});
|
|
4291
|
-
}
|
|
4292
|
-
}
|
|
4293
|
-
// Temporary fix of this issue : https://github.com/jquense/yup/issues/616
|
|
4294
|
-
yup__namespace.setLocale({
|
|
4295
|
-
mixed: {
|
|
4296
|
-
notType (options) {
|
|
4297
|
-
const { path, type, value, originalValue } = options;
|
|
4298
|
-
const isCast = originalValue != null && originalValue !== value;
|
|
4299
|
-
const msg = `${path} must be a \`${type}\` type, ` + `but the final value was: \`${printValue(value, true)}\`${isCast ? ` (cast from the value \`${printValue(originalValue, true)}\`).` : '.'}`;
|
|
4300
|
-
/* Remove comment that is not supposed to be seen by the enduser
|
|
4301
|
-
if (value === null) {
|
|
4302
|
-
msg += `\n If "null" is intended as an empty value be sure to mark the schema as \`.nullable()\``;
|
|
4303
|
-
}
|
|
4304
|
-
*/ return msg;
|
|
4305
|
-
}
|
|
4306
|
-
}
|
|
4307
|
-
});
|
|
4308
|
-
|
|
4309
|
-
var yup = /*#__PURE__*/_mergeNamespaces({
|
|
4310
|
-
__proto__: null,
|
|
4311
|
-
StrapiIDSchema: StrapiIDSchema,
|
|
4312
|
-
strapiID: strapiID
|
|
4313
|
-
}, [yup__namespace]);
|
|
4314
|
-
|
|
4315
|
-
const validateZod = (schema)=>(data)=>{
|
|
4316
|
-
try {
|
|
4317
|
-
return schema.parse(data);
|
|
4318
|
-
} catch (error) {
|
|
4319
|
-
if (error instanceof zod.z.ZodError) {
|
|
4320
|
-
const { message, errors } = formatZodErrors(error);
|
|
4321
|
-
throw new ValidationError(message, {
|
|
4322
|
-
errors
|
|
4323
|
-
});
|
|
4324
|
-
}
|
|
4325
|
-
throw error;
|
|
4326
|
-
}
|
|
4327
|
-
};
|
|
4328
|
-
const formatZodErrors = (zodError)=>({
|
|
4329
|
-
errors: zodError.errors.map((error)=>{
|
|
4330
|
-
return {
|
|
4331
|
-
path: error.path,
|
|
4332
|
-
message: error.message,
|
|
4333
|
-
name: 'ValidationError'
|
|
4334
|
-
};
|
|
4335
|
-
}),
|
|
4336
|
-
message: 'Validation error'
|
|
4337
|
-
});
|
|
4338
|
-
|
|
4339
|
-
exports.arrays = arrays;
|
|
4340
|
-
exports.async = async;
|
|
4341
|
-
exports.contentTypes = contentTypes;
|
|
4342
|
-
exports.dates = dates;
|
|
4343
|
-
exports.env = env;
|
|
4344
|
-
exports.errors = errors;
|
|
4345
|
-
exports.file = file;
|
|
4346
|
-
exports.hooks = hooks;
|
|
35
|
+
exports.parseType = parseType;
|
|
36
|
+
exports.env = envHelper;
|
|
37
|
+
exports.setCreatorFields = setCreatorFields;
|
|
38
|
+
exports.providerFactory = providerFactory;
|
|
39
|
+
exports.traverseEntity = traverseEntity;
|
|
4347
40
|
exports.importDefault = importDefault;
|
|
4348
|
-
exports.isOperator = isOperator;
|
|
4349
|
-
exports.isOperatorOfType = isOperatorOfType;
|
|
4350
41
|
exports.machineID = machineId;
|
|
4351
|
-
exports.
|
|
4352
|
-
exports.
|
|
42
|
+
exports.validateYupSchema = validators.validateYupSchema;
|
|
43
|
+
exports.validateYupSchemaSync = validators.validateYupSchemaSync;
|
|
44
|
+
exports.isOperator = operators.isOperator;
|
|
45
|
+
exports.isOperatorOfType = operators.isOperatorOfType;
|
|
46
|
+
exports.queryParams = convertQueryParams;
|
|
47
|
+
exports.sanitize = index;
|
|
48
|
+
exports.validate = index$1;
|
|
4353
49
|
exports.pagination = pagination;
|
|
4354
|
-
exports.
|
|
50
|
+
exports.packageManager = packageManager;
|
|
51
|
+
exports.traverse = index$2;
|
|
52
|
+
exports.template = template;
|
|
53
|
+
exports.file = file;
|
|
54
|
+
exports.async = async;
|
|
4355
55
|
exports.policy = policy;
|
|
4356
|
-
exports.
|
|
4357
|
-
exports.
|
|
56
|
+
exports.yup = yup;
|
|
57
|
+
exports.errors = errors;
|
|
58
|
+
exports.contentTypes = contentTypes;
|
|
4358
59
|
exports.relations = relations;
|
|
4359
|
-
exports.
|
|
4360
|
-
exports.
|
|
60
|
+
exports.hooks = hooks;
|
|
61
|
+
exports.validateZod = zod.validateZod;
|
|
4361
62
|
exports.strings = strings;
|
|
4362
|
-
exports.
|
|
4363
|
-
exports.
|
|
4364
|
-
exports.
|
|
4365
|
-
exports.validate = index;
|
|
4366
|
-
exports.validateYupSchema = validateYupSchema;
|
|
4367
|
-
exports.validateYupSchemaSync = validateYupSchemaSync;
|
|
4368
|
-
exports.validateZod = validateZod;
|
|
4369
|
-
exports.yup = yup;
|
|
63
|
+
exports.arrays = arrays;
|
|
64
|
+
exports.objects = objects;
|
|
65
|
+
exports.dates = dates;
|
|
4370
66
|
//# sourceMappingURL=index.js.map
|