@strapi/utils 4.14.3 → 4.14.5

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