@strapi/utils 4.15.0-alpha.0 → 4.15.1

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