@strapi/utils 5.0.0-beta.0 → 5.0.0-beta.10

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 (49) hide show
  1. package/dist/async.d.ts +5 -11
  2. package/dist/async.d.ts.map +1 -1
  3. package/dist/content-types.d.ts +16 -6
  4. package/dist/content-types.d.ts.map +1 -1
  5. package/dist/convert-query-params.d.ts +12 -9
  6. package/dist/convert-query-params.d.ts.map +1 -1
  7. package/dist/file.d.ts +9 -4
  8. package/dist/file.d.ts.map +1 -1
  9. package/dist/hooks.d.ts.map +1 -1
  10. package/dist/index.d.ts +4 -3
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1507 -1354
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +1499 -1346
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/pagination.d.ts +34 -4
  17. package/dist/pagination.d.ts.map +1 -1
  18. package/dist/parse-type.d.ts.map +1 -1
  19. package/dist/policy.d.ts +1 -27
  20. package/dist/policy.d.ts.map +1 -1
  21. package/dist/sanitize/index.d.ts +23 -14
  22. package/dist/sanitize/index.d.ts.map +1 -1
  23. package/dist/sanitize/sanitizers.d.ts +10 -6
  24. package/dist/sanitize/sanitizers.d.ts.map +1 -1
  25. package/dist/set-creator-fields.d.ts.map +1 -1
  26. package/dist/traverse/factory.d.ts +5 -4
  27. package/dist/traverse/factory.d.ts.map +1 -1
  28. package/dist/traverse/index.d.ts +0 -1
  29. package/dist/traverse/index.d.ts.map +1 -1
  30. package/dist/traverse/query-populate.d.ts.map +1 -1
  31. package/dist/traverse-entity.d.ts +12 -2
  32. package/dist/traverse-entity.d.ts.map +1 -1
  33. package/dist/types.d.ts +3 -0
  34. package/dist/types.d.ts.map +1 -1
  35. package/dist/validate/index.d.ts +21 -13
  36. package/dist/validate/index.d.ts.map +1 -1
  37. package/dist/validate/utils.d.ts +2 -2
  38. package/dist/validate/utils.d.ts.map +1 -1
  39. package/dist/validate/validators.d.ts +9 -5
  40. package/dist/validate/validators.d.ts.map +1 -1
  41. package/dist/validate/visitors/index.d.ts +1 -0
  42. package/dist/validate/visitors/index.d.ts.map +1 -1
  43. package/dist/validate/visitors/throw-unrecognized-fields.d.ts +4 -0
  44. package/dist/validate/visitors/throw-unrecognized-fields.d.ts.map +1 -0
  45. package/dist/validators.d.ts +2 -2
  46. package/dist/validators.d.ts.map +1 -1
  47. package/dist/zod.d.ts +3 -0
  48. package/dist/zod.d.ts.map +1 -0
  49. package/package.json +11 -9
package/dist/index.js CHANGED
@@ -1,16 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const _$1 = require("lodash");
3
+ const _ = require("lodash");
4
+ const dates$1 = require("date-fns");
4
5
  const fp = require("lodash/fp");
5
- const pMap = require("p-map");
6
- const httpErrors = require("http-errors");
7
6
  const crypto = require("crypto");
8
7
  const nodeMachineId = require("node-machine-id");
9
8
  const yup$1 = require("yup");
9
+ const httpErrors = require("http-errors");
10
+ const pMap = require("p-map");
10
11
  const execa = require("execa");
11
12
  const preferredPM = require("preferred-pm");
12
13
  const node_stream = require("node:stream");
13
14
  const slugify = require("@sindresorhus/slugify");
15
+ const zod = require("zod");
14
16
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
15
17
  function _interopNamespace(e) {
16
18
  if (e && e.__esModule)
@@ -49,21 +51,20 @@ function _mergeNamespaces(n, m) {
49
51
  }
50
52
  return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
51
53
  }
52
- const ___default = /* @__PURE__ */ _interopDefault(_$1);
53
- const pMap__default = /* @__PURE__ */ _interopDefault(pMap);
54
+ const ___namespace = /* @__PURE__ */ _interopNamespace(_);
55
+ const dates__namespace = /* @__PURE__ */ _interopNamespace(dates$1);
54
56
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup$1);
57
+ const pMap__default = /* @__PURE__ */ _interopDefault(pMap);
55
58
  const execa__default = /* @__PURE__ */ _interopDefault(execa);
56
59
  const preferredPM__default = /* @__PURE__ */ _interopDefault(preferredPM);
57
60
  const slugify__default = /* @__PURE__ */ _interopDefault(slugify);
58
- const _ = require("lodash");
59
- const dates$1 = require("date-fns");
60
61
  const timeRegex = /^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]{1,3})?$/;
61
62
  const isDate = (v) => {
62
- return dates$1.isDate(v);
63
+ return dates__namespace.isDate(v);
63
64
  };
64
65
  const parseTime = (value) => {
65
66
  if (isDate(value)) {
66
- return dates$1.format(value, "HH:mm:ss.SSS");
67
+ return dates__namespace.format(value, "HH:mm:ss.SSS");
67
68
  }
68
69
  if (typeof value !== "string") {
69
70
  throw new Error(`Expected a string, got a ${typeof value}`);
@@ -73,20 +74,20 @@ const parseTime = (value) => {
73
74
  throw new Error("Invalid time format, expected HH:mm:ss.SSS");
74
75
  }
75
76
  const [, hours, minutes, seconds, fraction = ".000"] = result;
76
- const fractionPart = _.padEnd(fraction.slice(1), 3, "0");
77
+ const fractionPart = ___namespace.padEnd(fraction.slice(1), 3, "0");
77
78
  return `${hours}:${minutes}:${seconds}.${fractionPart}`;
78
79
  };
79
80
  const parseDate = (value) => {
80
81
  if (isDate(value)) {
81
- return dates$1.format(value, "yyyy-MM-dd");
82
+ return dates__namespace.format(value, "yyyy-MM-dd");
82
83
  }
83
84
  if (typeof value !== "string") {
84
85
  throw new Error(`Expected a string, got a ${typeof value}`);
85
86
  }
86
87
  try {
87
- const date = dates$1.parseISO(value);
88
- if (dates$1.isValid(date))
89
- return dates$1.format(date, "yyyy-MM-dd");
88
+ const date = dates__namespace.parseISO(value);
89
+ if (dates__namespace.isValid(date))
90
+ return dates__namespace.format(date, "yyyy-MM-dd");
90
91
  throw new Error(`Invalid format, expected an ISO compatible date`);
91
92
  } catch (error) {
92
93
  throw new Error(`Invalid format, expected an ISO compatible date`);
@@ -100,11 +101,11 @@ const parseDateTimeOrTimestamp = (value) => {
100
101
  throw new Error(`Expected a string, got a ${typeof value}`);
101
102
  }
102
103
  try {
103
- const date = dates$1.parseISO(value);
104
- if (dates$1.isValid(date))
104
+ const date = dates__namespace.parseISO(value);
105
+ if (dates__namespace.isValid(date))
105
106
  return date;
106
- const milliUnixDate = dates$1.parse(value, "T", /* @__PURE__ */ new Date());
107
- if (dates$1.isValid(milliUnixDate))
107
+ const milliUnixDate = dates__namespace.parse(value, "T", /* @__PURE__ */ new Date());
108
+ if (dates__namespace.isValid(milliUnixDate))
108
109
  return milliUnixDate;
109
110
  throw new Error(`Invalid format, expected a timestamp or an ISO date`);
110
111
  } catch (error) {
@@ -138,7 +139,7 @@ const parseType = (options) => {
138
139
  case "biginteger":
139
140
  case "float":
140
141
  case "decimal": {
141
- return _.toNumber(value);
142
+ return ___namespace.toNumber(value);
142
143
  }
143
144
  case "time": {
144
145
  return parseTime(value);
@@ -155,32 +156,32 @@ const parseType = (options) => {
155
156
  }
156
157
  };
157
158
  function envFn(key, defaultValue) {
158
- return ___default.default.has(process.env, key) ? process.env[key] : defaultValue;
159
+ return ___namespace.default.has(process.env, key) ? process.env[key] : defaultValue;
159
160
  }
160
161
  function getKey(key) {
161
162
  return process.env[key] ?? "";
162
163
  }
163
164
  const utils = {
164
165
  int(key, defaultValue) {
165
- if (!___default.default.has(process.env, key)) {
166
+ if (!___namespace.default.has(process.env, key)) {
166
167
  return defaultValue;
167
168
  }
168
169
  return parseInt(getKey(key), 10);
169
170
  },
170
171
  float(key, defaultValue) {
171
- if (!___default.default.has(process.env, key)) {
172
+ if (!___namespace.default.has(process.env, key)) {
172
173
  return defaultValue;
173
174
  }
174
175
  return parseFloat(getKey(key));
175
176
  },
176
177
  bool(key, defaultValue) {
177
- if (!___default.default.has(process.env, key)) {
178
+ if (!___namespace.default.has(process.env, key)) {
178
179
  return defaultValue;
179
180
  }
180
181
  return getKey(key) === "true";
181
182
  },
182
183
  json(key, defaultValue) {
183
- if (!___default.default.has(process.env, key)) {
184
+ if (!___namespace.default.has(process.env, key)) {
184
185
  return defaultValue;
185
186
  }
186
187
  try {
@@ -193,7 +194,7 @@ const utils = {
193
194
  }
194
195
  },
195
196
  array(key, defaultValue) {
196
- if (!___default.default.has(process.env, key)) {
197
+ if (!___namespace.default.has(process.env, key)) {
197
198
  return defaultValue;
198
199
  }
199
200
  let value = getKey(key);
@@ -201,11 +202,11 @@ const utils = {
201
202
  value = value.substring(1, value.length - 1);
202
203
  }
203
204
  return value.split(",").map((v) => {
204
- return ___default.default.trim(___default.default.trim(v, " "), '"');
205
+ return ___namespace.default.trim(___namespace.default.trim(v, " "), '"');
205
206
  });
206
207
  },
207
208
  date(key, defaultValue) {
208
- if (!___default.default.has(process.env, key)) {
209
+ if (!___namespace.default.has(process.env, key)) {
209
210
  return defaultValue;
210
211
  }
211
212
  return new Date(getKey(key));
@@ -272,12 +273,12 @@ const getCreatorFields = (model) => {
272
273
  const getNonWritableAttributes = (model) => {
273
274
  if (!model)
274
275
  return [];
275
- const nonWritableAttributes = ___default.default.reduce(
276
+ const nonWritableAttributes = ___namespace.default.reduce(
276
277
  model.attributes,
277
278
  (acc, attr, attrName) => attr.writable === false ? acc.concat(attrName) : acc,
278
279
  []
279
280
  );
280
- return ___default.default.uniq([
281
+ return ___namespace.default.uniq([
281
282
  ID_ATTRIBUTE$4,
282
283
  DOC_ID_ATTRIBUTE$4,
283
284
  ...getTimestamps(model),
@@ -287,28 +288,37 @@ const getNonWritableAttributes = (model) => {
287
288
  const getWritableAttributes = (model) => {
288
289
  if (!model)
289
290
  return [];
290
- return ___default.default.difference(Object.keys(model.attributes), getNonWritableAttributes(model));
291
+ return ___namespace.default.difference(Object.keys(model.attributes), getNonWritableAttributes(model));
291
292
  };
292
293
  const isWritableAttribute = (model, attributeName) => {
293
294
  return getWritableAttributes(model).includes(attributeName);
294
295
  };
295
296
  const getNonVisibleAttributes = (model) => {
296
- const nonVisibleAttributes = ___default.default.reduce(
297
+ const nonVisibleAttributes = ___namespace.default.reduce(
297
298
  model.attributes,
298
299
  (acc, attr, attrName) => attr.visible === false ? acc.concat(attrName) : acc,
299
300
  []
300
301
  );
301
- return ___default.default.uniq([ID_ATTRIBUTE$4, DOC_ID_ATTRIBUTE$4, ...getTimestamps(model), ...nonVisibleAttributes]);
302
+ return ___namespace.default.uniq([ID_ATTRIBUTE$4, DOC_ID_ATTRIBUTE$4, ...getTimestamps(model), ...nonVisibleAttributes]);
302
303
  };
303
304
  const getVisibleAttributes = (model) => {
304
- return ___default.default.difference(___default.default.keys(model.attributes), getNonVisibleAttributes(model));
305
+ return ___namespace.default.difference(___namespace.default.keys(model.attributes), getNonVisibleAttributes(model));
305
306
  };
306
307
  const isVisibleAttribute = (model, attributeName) => {
307
308
  return getVisibleAttributes(model).includes(attributeName);
308
309
  };
309
- const getOptions = (model) => ___default.default.assign({ draftAndPublish: false }, ___default.default.get(model, "options", {}));
310
- const hasDraftAndPublish = (model) => ___default.default.get(model, "options.draftAndPublish", false) === true;
311
- const isDraft = (data, model) => hasDraftAndPublish(model) && ___default.default.get(data, PUBLISHED_AT_ATTRIBUTE$1) === null;
310
+ const getOptions = (model) => ___namespace.default.assign({ draftAndPublish: false }, ___namespace.default.get(model, "options", {}));
311
+ const hasDraftAndPublish = (model) => ___namespace.default.get(model, "options.draftAndPublish", false) === true;
312
+ const isDraft = (data, model) => hasDraftAndPublish(model) && ___namespace.default.get(data, PUBLISHED_AT_ATTRIBUTE$1) === null;
313
+ const isSchema = (data) => {
314
+ return typeof data === "object" && data !== null && "modelType" in data && typeof data.modelType === "string" && ["component", "contentType"].includes(data.modelType);
315
+ };
316
+ const isComponentSchema = (data) => {
317
+ return isSchema(data) && data.modelType === "component";
318
+ };
319
+ const isContentTypeSchema = (data) => {
320
+ return isSchema(data) && data.modelType === "contentType";
321
+ };
312
322
  const isSingleType = ({ kind = COLLECTION_TYPE }) => kind === SINGLE_TYPE;
313
323
  const isCollectionType = ({ kind = COLLECTION_TYPE }) => kind === COLLECTION_TYPE;
314
324
  const isKind = (kind) => (model) => model.kind === kind;
@@ -317,9 +327,9 @@ const getStoredPrivateAttributes = (model) => fp.union(
317
327
  fp.getOr([], "options.privateAttributes", model)
318
328
  );
319
329
  const getPrivateAttributes = (model) => {
320
- return ___default.default.union(
330
+ return ___namespace.default.union(
321
331
  getStoredPrivateAttributes(model),
322
- ___default.default.keys(___default.default.pickBy(model.attributes, (attr) => !!attr.private))
332
+ ___namespace.default.keys(___namespace.default.pickBy(model.attributes, (attr) => !!attr.private))
323
333
  );
324
334
  };
325
335
  const isPrivateAttribute = (model, attributeName) => {
@@ -329,17 +339,22 @@ const isPrivateAttribute = (model, attributeName) => {
329
339
  return getStoredPrivateAttributes(model).includes(attributeName);
330
340
  };
331
341
  const isScalarAttribute = (attribute) => {
332
- return !["media", "component", "relation", "dynamiczone"].includes(attribute?.type);
342
+ return attribute && !["media", "component", "relation", "dynamiczone"].includes(attribute.type);
343
+ };
344
+ const getDoesAttributeRequireValidation = (attribute) => {
345
+ return attribute.required || attribute.unique || Object.prototype.hasOwnProperty.call(attribute, "max") || Object.prototype.hasOwnProperty.call(attribute, "min") || Object.prototype.hasOwnProperty.call(attribute, "maxLength") || Object.prototype.hasOwnProperty.call(attribute, "minLength");
333
346
  };
334
347
  const isMediaAttribute = (attribute) => attribute?.type === "media";
335
348
  const isRelationalAttribute = (attribute) => attribute?.type === "relation";
349
+ const HAS_RELATION_REORDERING = ["manyToMany", "manyToOne", "oneToMany"];
350
+ const hasRelationReordering = (attribute) => isRelationalAttribute(attribute) && HAS_RELATION_REORDERING.includes(attribute.relation);
336
351
  const isComponentAttribute = (attribute) => ["component", "dynamiczone"].includes(attribute?.type);
337
- const isDynamicZoneAttribute = (attribute) => attribute?.type === "dynamiczone";
352
+ const isDynamicZoneAttribute = (attribute) => !!attribute && attribute.type === "dynamiczone";
338
353
  const isMorphToRelationalAttribute = (attribute) => {
339
- return isRelationalAttribute(attribute) && attribute?.relation?.startsWith?.("morphTo");
354
+ return !!attribute && isRelationalAttribute(attribute) && attribute.relation?.startsWith?.("morphTo");
340
355
  };
341
356
  const getComponentAttributes = (schema) => {
342
- return ___default.default.reduce(
357
+ return ___namespace.default.reduce(
343
358
  schema.attributes,
344
359
  (acc, attr, attrName) => {
345
360
  if (isComponentAttribute(attr))
@@ -350,7 +365,7 @@ const getComponentAttributes = (schema) => {
350
365
  );
351
366
  };
352
367
  const getScalarAttributes = (schema) => {
353
- return ___default.default.reduce(
368
+ return ___namespace.default.reduce(
354
369
  schema.attributes,
355
370
  (acc, attr, attrName) => {
356
371
  if (isScalarAttribute(attr))
@@ -360,11 +375,22 @@ const getScalarAttributes = (schema) => {
360
375
  []
361
376
  );
362
377
  };
378
+ const getRelationalAttributes = (schema) => {
379
+ return ___namespace.default.reduce(
380
+ schema.attributes,
381
+ (acc, attr, attrName) => {
382
+ if (isRelationalAttribute(attr))
383
+ acc.push(attrName);
384
+ return acc;
385
+ },
386
+ []
387
+ );
388
+ };
363
389
  const isTypedAttribute = (attribute, type) => {
364
- return ___default.default.has(attribute, "type") && attribute.type === type;
390
+ return ___namespace.default.has(attribute, "type") && attribute.type === type;
365
391
  };
366
392
  const getContentTypeRoutePrefix = (contentType) => {
367
- return isSingleType(contentType) ? ___default.default.kebabCase(contentType.info.singularName) : ___default.default.kebabCase(contentType.info.pluralName);
393
+ return isSingleType(contentType) ? ___namespace.default.kebabCase(contentType.info.singularName) : ___namespace.default.kebabCase(contentType.info.pluralName);
368
394
  };
369
395
  const contentTypes = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
370
396
  __proto__: null,
@@ -372,17 +398,22 @@ const contentTypes = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.define
372
398
  getComponentAttributes,
373
399
  getContentTypeRoutePrefix,
374
400
  getCreatorFields,
401
+ getDoesAttributeRequireValidation,
375
402
  getNonVisibleAttributes,
376
403
  getNonWritableAttributes,
377
404
  getOptions,
378
405
  getPrivateAttributes,
406
+ getRelationalAttributes,
379
407
  getScalarAttributes,
380
408
  getTimestamps,
381
409
  getVisibleAttributes,
382
410
  getWritableAttributes,
383
411
  hasDraftAndPublish,
412
+ hasRelationReordering,
384
413
  isCollectionType,
385
414
  isComponentAttribute,
415
+ isComponentSchema,
416
+ isContentTypeSchema,
386
417
  isDraft,
387
418
  isDynamicZoneAttribute,
388
419
  isKind,
@@ -391,6 +422,7 @@ const contentTypes = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.define
391
422
  isPrivateAttribute,
392
423
  isRelationalAttribute,
393
424
  isScalarAttribute,
425
+ isSchema,
394
426
  isSingleType,
395
427
  isTypedAttribute,
396
428
  isVisibleAttribute,
@@ -543,201 +575,33 @@ const providerFactory = (options = {}) => {
543
575
  }
544
576
  };
545
577
  };
546
- function pipe(...fns) {
547
- const [firstFn, ...fnRest] = fns;
548
- return async (...args) => {
549
- let res = await firstFn.apply(firstFn, args);
550
- for (let i = 0; i < fnRest.length; i += 1) {
551
- res = await fnRest[i](res);
552
- }
553
- return res;
578
+ const traverseEntity = async (visitor2, options, entity) => {
579
+ const { path = { raw: null, attribute: null }, schema, getModel } = options;
580
+ let parent = options.parent;
581
+ const traverseMorphRelationTarget = async (visitor22, path2, entry) => {
582
+ const targetSchema = getModel(entry.__type);
583
+ const traverseOptions = { schema: targetSchema, path: path2, getModel, parent };
584
+ return traverseEntity(visitor22, traverseOptions, entry);
554
585
  };
555
- }
556
- const map = fp.curry(pMap__default.default);
557
- const reduce = (mixedArray) => async (iteratee, initialValue) => {
558
- let acc = initialValue;
559
- for (let i = 0; i < mixedArray.length; i += 1) {
560
- acc = await iteratee(acc, await mixedArray[i], i);
561
- }
562
- return acc;
563
- };
564
- const async = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
565
- __proto__: null,
566
- map,
567
- pipe,
568
- reduce
569
- }, Symbol.toStringTag, { value: "Module" }));
570
- const visitor$8 = ({ key, attribute }, { remove }) => {
571
- if (attribute?.type === "password") {
572
- remove(key);
573
- }
574
- };
575
- const visitor$7 = ({ schema, key, attribute }, { remove }) => {
576
- if (!attribute) {
577
- return;
578
- }
579
- const isPrivate = attribute.private === true || isPrivateAttribute(schema, key);
580
- if (isPrivate) {
581
- remove(key);
582
- }
583
- };
584
- const ACTIONS_TO_VERIFY$1 = ["find"];
585
- const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$1 } = constants$1;
586
- const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schema }, { remove, set }) => {
587
- if (!attribute) {
588
- return;
589
- }
590
- const isRelation = attribute.type === "relation";
591
- if (!isRelation) {
592
- return;
593
- }
594
- const handleMorphRelation = async () => {
595
- const newMorphValue = [];
596
- for (const element of data[key]) {
597
- const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
598
- const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
599
- if (isAllowed) {
600
- newMorphValue.push(element);
601
- }
602
- }
603
- if (newMorphValue.length === 0) {
604
- remove(key);
605
- } else {
606
- set(key, newMorphValue);
607
- }
586
+ const traverseRelationTarget = (schema2) => async (visitor22, path2, entry) => {
587
+ const traverseOptions = { schema: schema2, path: path2, getModel, parent };
588
+ return traverseEntity(visitor22, traverseOptions, entry);
608
589
  };
609
- const handleRegularRelation = async () => {
610
- const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${attribute.target}.${action}`);
611
- const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
612
- if (!isAllowed) {
613
- remove(key);
614
- }
590
+ const traverseMediaTarget = async (visitor22, path2, entry) => {
591
+ const targetSchemaUID = "plugin::upload.file";
592
+ const targetSchema = getModel(targetSchemaUID);
593
+ const traverseOptions = { schema: targetSchema, path: path2, getModel, parent };
594
+ return traverseEntity(visitor22, traverseOptions, entry);
595
+ };
596
+ const traverseComponent = async (visitor22, path2, schema2, entry) => {
597
+ const traverseOptions = { schema: schema2, path: path2, getModel, parent };
598
+ return traverseEntity(visitor22, traverseOptions, entry);
599
+ };
600
+ const visitDynamicZoneEntry = async (visitor22, path2, entry) => {
601
+ const targetSchema = getModel(entry.__component);
602
+ const traverseOptions = { schema: targetSchema, path: path2, getModel, parent };
603
+ return traverseEntity(visitor22, traverseOptions, entry);
615
604
  };
616
- const isCreatorRelation = [CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE$1].includes(key);
617
- if (isMorphToRelationalAttribute(attribute)) {
618
- await handleMorphRelation();
619
- return;
620
- }
621
- if (isCreatorRelation && schema.options?.populateCreatorFields) {
622
- return;
623
- }
624
- await handleRegularRelation();
625
- };
626
- const hasAccessToSomeScopes$1 = async (scopes, auth) => {
627
- for (const scope of scopes) {
628
- try {
629
- await strapi.auth.verify(auth, { scope });
630
- return true;
631
- } catch {
632
- continue;
633
- }
634
- }
635
- return false;
636
- };
637
- const visitor$6 = ({ key, attribute }, { remove }) => {
638
- if (isMorphToRelationalAttribute(attribute)) {
639
- remove(key);
640
- }
641
- };
642
- const visitor$5 = ({ key, attribute }, { remove }) => {
643
- if (isDynamicZoneAttribute(attribute)) {
644
- remove(key);
645
- }
646
- };
647
- const removeDisallowedFields = (allowedFields = null) => ({ key, path: { attribute: path } }, { remove }) => {
648
- if (allowedFields === null) {
649
- return;
650
- }
651
- if (!(fp.isArray(allowedFields) && allowedFields.every(fp.isString))) {
652
- throw new TypeError(
653
- `Expected array of strings for allowedFields but got "${typeof allowedFields}"`
654
- );
655
- }
656
- if (fp.isNil(path)) {
657
- return;
658
- }
659
- const containedPaths = getContainedPaths$1(path);
660
- const isPathAllowed = allowedFields.some(
661
- (p) => containedPaths.includes(p) || p.startsWith(`${path}.`)
662
- );
663
- if (isPathAllowed) {
664
- return;
665
- }
666
- remove(key);
667
- };
668
- const getContainedPaths$1 = (path) => {
669
- const parts = fp.toPath(path);
670
- return parts.reduce((acc, value, index2, list) => {
671
- return [...acc, list.slice(0, index2 + 1).join(".")];
672
- }, []);
673
- };
674
- const removeRestrictedFields = (restrictedFields = null) => ({ key, path: { attribute: path } }, { remove }) => {
675
- if (restrictedFields === null) {
676
- remove(key);
677
- return;
678
- }
679
- if (!(fp.isArray(restrictedFields) && restrictedFields.every(fp.isString))) {
680
- throw new TypeError(
681
- `Expected array of strings for restrictedFields but got "${typeof restrictedFields}"`
682
- );
683
- }
684
- if (restrictedFields.includes(path)) {
685
- remove(key);
686
- return;
687
- }
688
- const isRestrictedNested = restrictedFields.some(
689
- (allowedPath) => path?.toString().startsWith(`${allowedPath}.`)
690
- );
691
- if (isRestrictedNested) {
692
- remove(key);
693
- }
694
- };
695
- const visitor$4 = ({ schema, key, value }, { set }) => {
696
- if (key === "" && value === "*") {
697
- const { attributes } = schema;
698
- const newPopulateQuery = Object.entries(attributes).filter(
699
- ([, attribute]) => ["relation", "component", "media", "dynamiczone"].includes(attribute.type)
700
- ).reduce((acc, [key2]) => ({ ...acc, [key2]: true }), {});
701
- set("", newPopulateQuery);
702
- }
703
- };
704
- const visitors$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
705
- __proto__: null,
706
- expandWildcardPopulate: visitor$4,
707
- removeDisallowedFields,
708
- removeDynamicZones: visitor$5,
709
- removeMorphToRelations: visitor$6,
710
- removePassword: visitor$8,
711
- removePrivate: visitor$7,
712
- removeRestrictedFields,
713
- removeRestrictedRelations
714
- }, Symbol.toStringTag, { value: "Module" }));
715
- const traverseMorphRelationTarget = async (visitor2, path, entry) => {
716
- const targetSchema = strapi.getModel(entry.__type);
717
- const traverseOptions = { schema: targetSchema, path };
718
- return traverseEntity(visitor2, traverseOptions, entry);
719
- };
720
- const traverseRelationTarget = (schema) => async (visitor2, path, entry) => {
721
- const traverseOptions = { schema, path };
722
- return traverseEntity(visitor2, traverseOptions, entry);
723
- };
724
- const traverseMediaTarget = async (visitor2, path, entry) => {
725
- const targetSchemaUID = "plugin::upload.file";
726
- const targetSchema = strapi.getModel(targetSchemaUID);
727
- const traverseOptions = { schema: targetSchema, path };
728
- return traverseEntity(visitor2, traverseOptions, entry);
729
- };
730
- const traverseComponent = async (visitor2, path, schema, entry) => {
731
- const traverseOptions = { schema, path };
732
- return traverseEntity(visitor2, traverseOptions, entry);
733
- };
734
- const visitDynamicZoneEntry = async (visitor2, path, entry) => {
735
- const targetSchema = strapi.getModel(entry.__component);
736
- const traverseOptions = { schema: targetSchema, path };
737
- return traverseEntity(visitor2, traverseOptions, entry);
738
- };
739
- const traverseEntity = async (visitor2, options, entity) => {
740
- const { path = { raw: null, attribute: null }, schema } = options;
741
605
  if (!fp.isObject(entity) || fp.isNil(schema)) {
742
606
  return entity;
743
607
  }
@@ -747,9 +611,6 @@ const traverseEntity = async (visitor2, options, entity) => {
747
611
  for (let i = 0; i < keys.length; i += 1) {
748
612
  const key = keys[i];
749
613
  const attribute = schema.attributes[key];
750
- if (fp.isNil(attribute)) {
751
- continue;
752
- }
753
614
  const newPath = { ...path };
754
615
  newPath.raw = fp.isNil(path.raw) ? key : `${path.raw}.${key}`;
755
616
  if (!fp.isNil(attribute)) {
@@ -761,16 +622,19 @@ const traverseEntity = async (visitor2, options, entity) => {
761
622
  key,
762
623
  value: copy[key],
763
624
  attribute,
764
- path: newPath
625
+ path: newPath,
626
+ getModel,
627
+ parent
765
628
  };
766
629
  await visitor2(visitorOptions, visitorUtils);
767
630
  const value = copy[key];
768
- if (fp.isNil(value)) {
631
+ if (fp.isNil(value) || fp.isNil(attribute)) {
769
632
  continue;
770
633
  }
634
+ parent = { schema, key, attribute, path: newPath };
771
635
  if (isRelationalAttribute(attribute)) {
772
636
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
773
- const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(strapi.getModel(attribute.target));
637
+ const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
774
638
  if (fp.isArray(value)) {
775
639
  const res = new Array(value.length);
776
640
  for (let i2 = 0; i2 < value.length; i2 += 1) {
@@ -795,7 +659,7 @@ const traverseEntity = async (visitor2, options, entity) => {
795
659
  continue;
796
660
  }
797
661
  if (attribute.type === "component") {
798
- const targetSchema = strapi.getModel(attribute.component);
662
+ const targetSchema = getModel(attribute.component);
799
663
  if (fp.isArray(value)) {
800
664
  const res = new Array(value.length);
801
665
  for (let i2 = 0; i2 < value.length; i2 += 1) {
@@ -827,68 +691,853 @@ const createVisitorUtils = ({ data }) => ({
827
691
  }
828
692
  });
829
693
  const traverseEntity$1 = fp.curry(traverseEntity);
830
- const DEFAULT_PATH = { raw: null, attribute: null };
831
- const traverseFactory = () => {
832
- const state = {
833
- parsers: [],
834
- interceptors: [],
835
- ignore: [],
836
- handlers: {
837
- attributes: [],
838
- common: []
839
- }
840
- };
841
- const traverse = async (visitor2, options, data) => {
842
- const { path = DEFAULT_PATH, schema } = options ?? {};
843
- for (const { predicate, handler } of state.interceptors) {
844
- if (predicate(data)) {
845
- return handler(visitor2, options, data, { recurse: traverse });
846
- }
847
- }
848
- const parser = state.parsers.find((parser2) => parser2.predicate(data))?.parser;
849
- const utils2 = parser?.(data);
850
- if (!utils2) {
851
- return data;
852
- }
853
- let out = utils2.transform(data);
854
- const keys = utils2.keys(out);
855
- for (const key of keys) {
856
- const attribute = schema?.attributes?.[key] ?? // FIX: Needed to not break existing behavior on the API.
857
- // It looks for the attribute in the DB metadata when the key is in snake_case
858
- schema?.attributes?.[strapi.db.metadata.get(schema?.uid).columnToAttribute[key]];
859
- const newPath = { ...path };
860
- newPath.raw = fp.isNil(path.raw) ? key : `${path.raw}.${key}`;
861
- if (!fp.isNil(attribute)) {
862
- newPath.attribute = fp.isNil(path.attribute) ? key : `${path.attribute}.${key}`;
863
- }
864
- const visitorOptions = {
865
- key,
866
- value: utils2.get(key, out),
867
- attribute,
868
- schema,
869
- path: newPath,
870
- data: out
871
- };
872
- const transformUtils = {
873
- remove(key2) {
874
- out = utils2.remove(key2, out);
875
- },
876
- set(key2, value2) {
877
- out = utils2.set(key2, value2, out);
878
- },
879
- recurse: traverse
880
- };
881
- await visitor2(visitorOptions, fp.pick(["remove", "set"], transformUtils));
882
- const value = utils2.get(key, out);
883
- const createContext = () => ({
884
- key,
885
- value,
886
- attribute,
887
- schema,
888
- path: newPath,
889
- data: out,
890
- visitor: visitor2
891
- });
694
+ function importDefault(modName) {
695
+ const mod = require(modName);
696
+ return mod && mod.__esModule ? mod.default : mod;
697
+ }
698
+ const machineId = () => {
699
+ try {
700
+ const deviceId = nodeMachineId.machineIdSync();
701
+ return deviceId;
702
+ } catch (error) {
703
+ const deviceId = crypto.randomUUID();
704
+ return deviceId;
705
+ }
706
+ };
707
+ const formatYupInnerError = (yupError) => ({
708
+ path: fp.toPath(yupError.path),
709
+ message: yupError.message,
710
+ name: yupError.name
711
+ });
712
+ const formatYupErrors = (yupError) => ({
713
+ errors: fp.isEmpty(yupError.inner) ? [formatYupInnerError(yupError)] : yupError.inner.map(formatYupInnerError),
714
+ message: yupError.message
715
+ });
716
+ class ApplicationError extends Error {
717
+ name;
718
+ details;
719
+ message;
720
+ constructor(message = "An application error occured", details = {}) {
721
+ super();
722
+ this.name = "ApplicationError";
723
+ this.message = message;
724
+ this.details = details;
725
+ }
726
+ }
727
+ class ValidationError extends ApplicationError {
728
+ constructor(message, details) {
729
+ super(message, details);
730
+ this.name = "ValidationError";
731
+ }
732
+ }
733
+ class YupValidationError extends ValidationError {
734
+ constructor(yupError, message) {
735
+ super("Validation");
736
+ const { errors: errors2, message: yupMessage } = formatYupErrors(yupError);
737
+ this.message = message || yupMessage;
738
+ this.details = { errors: errors2 };
739
+ }
740
+ }
741
+ class PaginationError extends ApplicationError {
742
+ constructor(message = "Invalid pagination", details) {
743
+ super(message, details);
744
+ this.name = "PaginationError";
745
+ this.message = message;
746
+ }
747
+ }
748
+ class NotFoundError extends ApplicationError {
749
+ constructor(message = "Entity not found", details) {
750
+ super(message, details);
751
+ this.name = "NotFoundError";
752
+ this.message = message;
753
+ }
754
+ }
755
+ class ForbiddenError extends ApplicationError {
756
+ constructor(message = "Forbidden access", details) {
757
+ super(message, details);
758
+ this.name = "ForbiddenError";
759
+ this.message = message;
760
+ }
761
+ }
762
+ class UnauthorizedError extends ApplicationError {
763
+ constructor(message = "Unauthorized", details) {
764
+ super(message, details);
765
+ this.name = "UnauthorizedError";
766
+ this.message = message;
767
+ }
768
+ }
769
+ class RateLimitError extends ApplicationError {
770
+ constructor(message = "Too many requests, please try again later.", details) {
771
+ super(message, details);
772
+ this.name = "RateLimitError";
773
+ this.message = message;
774
+ this.details = details || {};
775
+ }
776
+ }
777
+ class PayloadTooLargeError extends ApplicationError {
778
+ constructor(message = "Entity too large", details) {
779
+ super(message, details);
780
+ this.name = "PayloadTooLargeError";
781
+ this.message = message;
782
+ }
783
+ }
784
+ class PolicyError extends ForbiddenError {
785
+ constructor(message = "Policy Failed", details) {
786
+ super(message, details);
787
+ this.name = "PolicyError";
788
+ this.message = message;
789
+ this.details = details || {};
790
+ }
791
+ }
792
+ class NotImplementedError extends ApplicationError {
793
+ constructor(message = "This feature is not implemented yet", details) {
794
+ super(message, details);
795
+ this.name = "NotImplementedError";
796
+ this.message = message;
797
+ }
798
+ }
799
+ const errors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
800
+ __proto__: null,
801
+ ApplicationError,
802
+ ForbiddenError,
803
+ HttpError: httpErrors.HttpError,
804
+ NotFoundError,
805
+ NotImplementedError,
806
+ PaginationError,
807
+ PayloadTooLargeError,
808
+ PolicyError,
809
+ RateLimitError,
810
+ UnauthorizedError,
811
+ ValidationError,
812
+ YupValidationError
813
+ }, Symbol.toStringTag, { value: "Module" }));
814
+ const handleYupError = (error, errorMessage) => {
815
+ throw new YupValidationError(error, errorMessage);
816
+ };
817
+ const defaultValidationParam = { strict: true, abortEarly: false };
818
+ const validateYupSchema = (schema, options = {}) => async (body, errorMessage) => {
819
+ try {
820
+ const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
821
+ const result = await schema.validate(body, optionsWithDefaults);
822
+ return result;
823
+ } catch (e) {
824
+ if (e instanceof yup__namespace.ValidationError) {
825
+ handleYupError(e, errorMessage);
826
+ }
827
+ throw e;
828
+ }
829
+ };
830
+ const validateYupSchemaSync = (schema, options = {}) => (body, errorMessage) => {
831
+ try {
832
+ const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
833
+ return schema.validateSync(body, optionsWithDefaults);
834
+ } catch (e) {
835
+ if (e instanceof yup__namespace.ValidationError) {
836
+ handleYupError(e, errorMessage);
837
+ }
838
+ throw e;
839
+ }
840
+ };
841
+ const GROUP_OPERATORS = ["$and", "$or"];
842
+ const WHERE_OPERATORS = [
843
+ "$not",
844
+ "$in",
845
+ "$notIn",
846
+ "$eq",
847
+ "$eqi",
848
+ "$ne",
849
+ "$nei",
850
+ "$gt",
851
+ "$gte",
852
+ "$lt",
853
+ "$lte",
854
+ "$null",
855
+ "$notNull",
856
+ "$between",
857
+ "$startsWith",
858
+ "$endsWith",
859
+ "$startsWithi",
860
+ "$endsWithi",
861
+ "$contains",
862
+ "$notContains",
863
+ "$containsi",
864
+ "$notContainsi",
865
+ // Experimental, only for internal use
866
+ "$jsonSupersetOf"
867
+ ];
868
+ const CAST_OPERATORS = [
869
+ "$not",
870
+ "$in",
871
+ "$notIn",
872
+ "$eq",
873
+ "$ne",
874
+ "$gt",
875
+ "$gte",
876
+ "$lt",
877
+ "$lte",
878
+ "$between"
879
+ ];
880
+ const ARRAY_OPERATORS = ["$in", "$notIn", "$between"];
881
+ const OPERATORS = {
882
+ where: WHERE_OPERATORS,
883
+ cast: CAST_OPERATORS,
884
+ group: GROUP_OPERATORS,
885
+ array: ARRAY_OPERATORS
886
+ };
887
+ const OPERATORS_LOWERCASE = Object.fromEntries(
888
+ Object.entries(OPERATORS).map(([key, values]) => [
889
+ key,
890
+ values.map((value) => value.toLowerCase())
891
+ ])
892
+ );
893
+ const isObjKey = (key, obj) => {
894
+ return key in obj;
895
+ };
896
+ const isOperatorOfType = (type, key, ignoreCase = false) => {
897
+ if (ignoreCase) {
898
+ return OPERATORS_LOWERCASE[type]?.includes(key.toLowerCase()) ?? false;
899
+ }
900
+ if (isObjKey(type, OPERATORS)) {
901
+ return OPERATORS[type]?.includes(key) ?? false;
902
+ }
903
+ return false;
904
+ };
905
+ const isOperator = (key, ignoreCase = false) => {
906
+ return Object.keys(OPERATORS).some((type) => isOperatorOfType(type, key, ignoreCase));
907
+ };
908
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$3, PUBLISHED_AT_ATTRIBUTE } = constants$1;
909
+ class InvalidOrderError extends Error {
910
+ constructor() {
911
+ super();
912
+ this.message = "Invalid order. order can only be one of asc|desc|ASC|DESC";
913
+ }
914
+ }
915
+ class InvalidSortError extends Error {
916
+ constructor() {
917
+ super();
918
+ this.message = "Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects";
919
+ }
920
+ }
921
+ function validateOrder(order) {
922
+ if (!fp.isString(order) || !["asc", "desc"].includes(order.toLocaleLowerCase())) {
923
+ throw new InvalidOrderError();
924
+ }
925
+ }
926
+ const convertCountQueryParams = (countQuery) => {
927
+ return parseType({ type: "boolean", value: countQuery });
928
+ };
929
+ const convertOrderingQueryParams = (ordering) => {
930
+ return ordering;
931
+ };
932
+ const isPlainObject = (value) => ___namespace.default.isPlainObject(value);
933
+ const isStringArray$3 = (value) => fp.isArray(value) && value.every(fp.isString);
934
+ const createTransformer = ({ getModel }) => {
935
+ const convertSortQueryParams = (sortQuery) => {
936
+ if (typeof sortQuery === "string") {
937
+ return convertStringSortQueryParam(sortQuery);
938
+ }
939
+ if (isStringArray$3(sortQuery)) {
940
+ return sortQuery.flatMap((sortValue) => convertStringSortQueryParam(sortValue));
941
+ }
942
+ if (Array.isArray(sortQuery)) {
943
+ return sortQuery.map((sortValue) => convertNestedSortQueryParam(sortValue));
944
+ }
945
+ if (isPlainObject(sortQuery)) {
946
+ return convertNestedSortQueryParam(sortQuery);
947
+ }
948
+ throw new InvalidSortError();
949
+ };
950
+ const convertStringSortQueryParam = (sortQuery) => {
951
+ return sortQuery.split(",").map((value) => convertSingleSortQueryParam(value));
952
+ };
953
+ const convertSingleSortQueryParam = (sortQuery) => {
954
+ if (!sortQuery) {
955
+ return {};
956
+ }
957
+ if (!fp.isString(sortQuery)) {
958
+ throw new Error("Invalid sort query");
959
+ }
960
+ const [field, order = "asc"] = sortQuery.split(":");
961
+ if (field.length === 0) {
962
+ throw new Error("Field cannot be empty");
963
+ }
964
+ validateOrder(order);
965
+ return ___namespace.default.set({}, field, order);
966
+ };
967
+ const convertNestedSortQueryParam = (sortQuery) => {
968
+ const transformedSort = {};
969
+ for (const field of Object.keys(sortQuery)) {
970
+ const order = sortQuery[field];
971
+ if (isPlainObject(order)) {
972
+ transformedSort[field] = convertNestedSortQueryParam(order);
973
+ } else if (typeof order === "string") {
974
+ validateOrder(order);
975
+ transformedSort[field] = order;
976
+ } else {
977
+ throw Error(`Invalid sort type expected object or string got ${typeof order}`);
978
+ }
979
+ }
980
+ return transformedSort;
981
+ };
982
+ const convertStartQueryParams = (startQuery) => {
983
+ const startAsANumber = ___namespace.default.toNumber(startQuery);
984
+ if (!___namespace.default.isInteger(startAsANumber) || startAsANumber < 0) {
985
+ throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
986
+ }
987
+ return startAsANumber;
988
+ };
989
+ const convertLimitQueryParams = (limitQuery) => {
990
+ const limitAsANumber = ___namespace.default.toNumber(limitQuery);
991
+ if (!___namespace.default.isInteger(limitAsANumber) || limitAsANumber !== -1 && limitAsANumber < 0) {
992
+ throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
993
+ }
994
+ if (limitAsANumber === -1) {
995
+ return void 0;
996
+ }
997
+ return limitAsANumber;
998
+ };
999
+ const convertPageQueryParams = (page) => {
1000
+ const pageVal = fp.toNumber(page);
1001
+ if (!fp.isInteger(pageVal) || pageVal <= 0) {
1002
+ throw new PaginationError(
1003
+ `Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
1004
+ );
1005
+ }
1006
+ return pageVal;
1007
+ };
1008
+ const convertPageSizeQueryParams = (pageSize, page) => {
1009
+ const pageSizeVal = fp.toNumber(pageSize);
1010
+ if (!fp.isInteger(pageSizeVal) || pageSizeVal <= 0) {
1011
+ throw new PaginationError(
1012
+ `Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
1013
+ );
1014
+ }
1015
+ return pageSizeVal;
1016
+ };
1017
+ const validatePaginationParams = (page, pageSize, start, limit) => {
1018
+ const isPagePagination = !fp.isNil(page) || !fp.isNil(pageSize);
1019
+ const isOffsetPagination = !fp.isNil(start) || !fp.isNil(limit);
1020
+ if (isPagePagination && isOffsetPagination) {
1021
+ throw new PaginationError(
1022
+ "Invalid pagination attributes. You cannot use page and offset pagination in the same query"
1023
+ );
1024
+ }
1025
+ };
1026
+ class InvalidPopulateError extends Error {
1027
+ constructor() {
1028
+ super();
1029
+ this.message = "Invalid populate parameter. Expected a string, an array of strings, a populate object";
1030
+ }
1031
+ }
1032
+ const convertPopulateQueryParams = (populate2, schema, depth = 0) => {
1033
+ if (depth === 0 && populate2 === "*") {
1034
+ return true;
1035
+ }
1036
+ if (typeof populate2 === "string") {
1037
+ return populate2.split(",").map((value) => ___namespace.default.trim(value));
1038
+ }
1039
+ if (Array.isArray(populate2)) {
1040
+ return ___namespace.default.uniq(
1041
+ populate2.flatMap((value) => {
1042
+ if (typeof value !== "string") {
1043
+ throw new InvalidPopulateError();
1044
+ }
1045
+ return value.split(",").map((value2) => ___namespace.default.trim(value2));
1046
+ })
1047
+ );
1048
+ }
1049
+ if (___namespace.default.isPlainObject(populate2)) {
1050
+ return convertPopulateObject(populate2, schema);
1051
+ }
1052
+ throw new InvalidPopulateError();
1053
+ };
1054
+ const hasPopulateFragmentDefined = (populate2) => {
1055
+ return typeof populate2 === "object" && "on" in populate2 && !fp.isNil(populate2.on);
1056
+ };
1057
+ const hasCountDefined = (populate2) => {
1058
+ return typeof populate2 === "object" && "count" in populate2 && typeof populate2.count === "boolean";
1059
+ };
1060
+ const convertPopulateObject = (populate2, schema) => {
1061
+ if (!schema) {
1062
+ return {};
1063
+ }
1064
+ const { attributes } = schema;
1065
+ return Object.entries(populate2).reduce((acc, [key, subPopulate]) => {
1066
+ if (___namespace.default.isString(subPopulate)) {
1067
+ try {
1068
+ const subPopulateAsBoolean = parseType({ type: "boolean", value: subPopulate });
1069
+ return subPopulateAsBoolean === true ? { ...acc, [key]: true } : acc;
1070
+ } catch {
1071
+ }
1072
+ }
1073
+ if (___namespace.default.isBoolean(subPopulate)) {
1074
+ return subPopulate === true ? { ...acc, [key]: true } : acc;
1075
+ }
1076
+ const attribute = attributes[key];
1077
+ if (!attribute) {
1078
+ return acc;
1079
+ }
1080
+ const isMorphLikeRelationalAttribute = isDynamicZoneAttribute(attribute) || isMorphToRelationalAttribute(attribute);
1081
+ if (isMorphLikeRelationalAttribute) {
1082
+ const hasInvalidProperties = Object.keys(subPopulate).some(
1083
+ (key2) => !["on", "count"].includes(key2)
1084
+ );
1085
+ if (hasInvalidProperties) {
1086
+ throw new Error(
1087
+ `Invalid nested populate for ${schema.info?.singularName}.${key} (${schema.uid}). Expected a fragment ("on") or "count" but found ${JSON.stringify(subPopulate)}`
1088
+ );
1089
+ }
1090
+ const newSubPopulate = {};
1091
+ if (hasPopulateFragmentDefined(subPopulate)) {
1092
+ Object.assign(newSubPopulate, {
1093
+ on: Object.entries(subPopulate.on).reduce(
1094
+ (acc2, [type, typeSubPopulate]) => ({
1095
+ ...acc2,
1096
+ [type]: convertNestedPopulate(typeSubPopulate, getModel(type))
1097
+ }),
1098
+ {}
1099
+ )
1100
+ });
1101
+ }
1102
+ if (hasCountDefined(subPopulate)) {
1103
+ Object.assign(newSubPopulate, { count: subPopulate.count });
1104
+ }
1105
+ return { ...acc, [key]: newSubPopulate };
1106
+ }
1107
+ if (!isMorphLikeRelationalAttribute && hasPopulateFragmentDefined(subPopulate)) {
1108
+ throw new Error(`Using fragments is not permitted to populate "${key}" in "${schema.uid}"`);
1109
+ }
1110
+ let targetSchemaUID;
1111
+ if (attribute.type === "relation") {
1112
+ targetSchemaUID = attribute.target;
1113
+ } else if (attribute.type === "component") {
1114
+ targetSchemaUID = attribute.component;
1115
+ } else if (attribute.type === "media") {
1116
+ targetSchemaUID = "plugin::upload.file";
1117
+ } else {
1118
+ return acc;
1119
+ }
1120
+ const targetSchema = getModel(targetSchemaUID);
1121
+ if (!targetSchema) {
1122
+ return acc;
1123
+ }
1124
+ const populateObject = convertNestedPopulate(subPopulate, targetSchema);
1125
+ if (!populateObject) {
1126
+ return acc;
1127
+ }
1128
+ return {
1129
+ ...acc,
1130
+ [key]: populateObject
1131
+ };
1132
+ }, {});
1133
+ };
1134
+ const convertNestedPopulate = (subPopulate, schema) => {
1135
+ if (___namespace.default.isString(subPopulate)) {
1136
+ return parseType({ type: "boolean", value: subPopulate, forceCast: true });
1137
+ }
1138
+ if (___namespace.default.isBoolean(subPopulate)) {
1139
+ return subPopulate;
1140
+ }
1141
+ if (!isPlainObject(subPopulate)) {
1142
+ throw new Error(`Invalid nested populate. Expected '*' or an object`);
1143
+ }
1144
+ const { sort: sort2, filters: filters2, fields: fields2, populate: populate2, count, ordering, page, pageSize, start, limit } = subPopulate;
1145
+ const query = {};
1146
+ if (sort2) {
1147
+ query.orderBy = convertSortQueryParams(sort2);
1148
+ }
1149
+ if (filters2) {
1150
+ query.where = convertFiltersQueryParams(filters2, schema);
1151
+ }
1152
+ if (fields2) {
1153
+ query.select = convertFieldsQueryParams(fields2);
1154
+ }
1155
+ if (populate2) {
1156
+ query.populate = convertPopulateQueryParams(populate2, schema);
1157
+ }
1158
+ if (count) {
1159
+ query.count = convertCountQueryParams(count);
1160
+ }
1161
+ if (ordering) {
1162
+ query.ordering = convertOrderingQueryParams(ordering);
1163
+ }
1164
+ validatePaginationParams(page, pageSize, start, limit);
1165
+ if (!fp.isNil(page)) {
1166
+ query.page = convertPageQueryParams(page);
1167
+ }
1168
+ if (!fp.isNil(pageSize)) {
1169
+ query.pageSize = convertPageSizeQueryParams(pageSize, page);
1170
+ }
1171
+ if (!fp.isNil(start)) {
1172
+ query.offset = convertStartQueryParams(start);
1173
+ }
1174
+ if (!fp.isNil(limit)) {
1175
+ query.limit = convertLimitQueryParams(limit);
1176
+ }
1177
+ return query;
1178
+ };
1179
+ const convertFieldsQueryParams = (fields2, depth = 0) => {
1180
+ if (depth === 0 && fields2 === "*") {
1181
+ return void 0;
1182
+ }
1183
+ if (typeof fields2 === "string") {
1184
+ const fieldsValues = fields2.split(",").map((value) => ___namespace.default.trim(value));
1185
+ return ___namespace.default.uniq([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3, ...fieldsValues]);
1186
+ }
1187
+ if (isStringArray$3(fields2)) {
1188
+ const fieldsValues = fields2.flatMap((value) => convertFieldsQueryParams(value, depth + 1)).filter((v) => !fp.isNil(v));
1189
+ return ___namespace.default.uniq([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3, ...fieldsValues]);
1190
+ }
1191
+ throw new Error("Invalid fields parameter. Expected a string or an array of strings");
1192
+ };
1193
+ const isValidSchemaAttribute = (key, schema) => {
1194
+ if ([DOC_ID_ATTRIBUTE$3, ID_ATTRIBUTE$3].includes(key)) {
1195
+ return true;
1196
+ }
1197
+ if (!schema) {
1198
+ return false;
1199
+ }
1200
+ return Object.keys(schema.attributes).includes(key);
1201
+ };
1202
+ const convertFiltersQueryParams = (filters2, schema) => {
1203
+ if (!fp.isObject(filters2)) {
1204
+ throw new Error("The filters parameter must be an object or an array");
1205
+ }
1206
+ const filtersCopy = fp.cloneDeep(filters2);
1207
+ return convertAndSanitizeFilters(filtersCopy, schema);
1208
+ };
1209
+ const convertAndSanitizeFilters = (filters2, schema) => {
1210
+ if (Array.isArray(filters2)) {
1211
+ return filters2.map((filter) => convertAndSanitizeFilters(filter, schema)).filter((filter) => !isPlainObject(filter) || !fp.isEmpty(filter));
1212
+ }
1213
+ if (!isPlainObject(filters2)) {
1214
+ return filters2;
1215
+ }
1216
+ const removeOperator = (operator) => delete filters2[operator];
1217
+ for (const [key, value] of Object.entries(filters2)) {
1218
+ const attribute = fp.get(key, schema?.attributes);
1219
+ const validKey = isOperator(key) || isValidSchemaAttribute(key, schema);
1220
+ if (!validKey) {
1221
+ removeOperator(key);
1222
+ } else if (attribute) {
1223
+ if (attribute.type === "relation") {
1224
+ filters2[key] = convertAndSanitizeFilters(value, getModel(attribute.target));
1225
+ } else if (attribute.type === "component") {
1226
+ filters2[key] = convertAndSanitizeFilters(value, getModel(attribute.component));
1227
+ } else if (attribute.type === "media") {
1228
+ filters2[key] = convertAndSanitizeFilters(value, getModel("plugin::upload.file"));
1229
+ } else if (attribute.type === "dynamiczone") {
1230
+ removeOperator(key);
1231
+ } else if (attribute.type === "password") {
1232
+ removeOperator(key);
1233
+ } else {
1234
+ filters2[key] = convertAndSanitizeFilters(value, schema);
1235
+ }
1236
+ } else if (["$null", "$notNull"].includes(key)) {
1237
+ filters2[key] = parseType({ type: "boolean", value: filters2[key], forceCast: true });
1238
+ } else if (fp.isObject(value)) {
1239
+ filters2[key] = convertAndSanitizeFilters(value, schema);
1240
+ }
1241
+ if (isPlainObject(filters2[key]) && fp.isEmpty(filters2[key])) {
1242
+ removeOperator(key);
1243
+ }
1244
+ }
1245
+ return filters2;
1246
+ };
1247
+ const convertStatusParams = (status, query = {}) => {
1248
+ query.filters = ({ meta }) => {
1249
+ const contentType = getModel(meta.uid);
1250
+ if (!contentType || !hasDraftAndPublish(contentType)) {
1251
+ return {};
1252
+ }
1253
+ return { [PUBLISHED_AT_ATTRIBUTE]: { $null: status === "draft" } };
1254
+ };
1255
+ };
1256
+ const transformQueryParams = (uid, params) => {
1257
+ const schema = getModel(uid);
1258
+ const query = {};
1259
+ const { _q, sort: sort2, filters: filters2, fields: fields2, populate: populate2, page, pageSize, start, limit, status, ...rest } = params;
1260
+ if (!fp.isNil(status)) {
1261
+ convertStatusParams(status, query);
1262
+ }
1263
+ if (!fp.isNil(_q)) {
1264
+ query._q = _q;
1265
+ }
1266
+ if (!fp.isNil(sort2)) {
1267
+ query.orderBy = convertSortQueryParams(sort2);
1268
+ }
1269
+ if (!fp.isNil(filters2)) {
1270
+ query.where = convertFiltersQueryParams(filters2, schema);
1271
+ }
1272
+ if (!fp.isNil(fields2)) {
1273
+ query.select = convertFieldsQueryParams(fields2);
1274
+ }
1275
+ if (!fp.isNil(populate2)) {
1276
+ query.populate = convertPopulateQueryParams(populate2, schema);
1277
+ }
1278
+ validatePaginationParams(page, pageSize, start, limit);
1279
+ if (!fp.isNil(page)) {
1280
+ query.page = convertPageQueryParams(page);
1281
+ }
1282
+ if (!fp.isNil(pageSize)) {
1283
+ query.pageSize = convertPageSizeQueryParams(pageSize, page);
1284
+ }
1285
+ if (!fp.isNil(start)) {
1286
+ query.offset = convertStartQueryParams(start);
1287
+ }
1288
+ if (!fp.isNil(limit)) {
1289
+ query.limit = convertLimitQueryParams(limit);
1290
+ }
1291
+ return {
1292
+ ...rest,
1293
+ ...query
1294
+ };
1295
+ };
1296
+ return {
1297
+ private_convertSortQueryParams: convertSortQueryParams,
1298
+ private_convertStartQueryParams: convertStartQueryParams,
1299
+ private_convertLimitQueryParams: convertLimitQueryParams,
1300
+ private_convertPopulateQueryParams: convertPopulateQueryParams,
1301
+ private_convertFiltersQueryParams: convertFiltersQueryParams,
1302
+ private_convertFieldsQueryParams: convertFieldsQueryParams,
1303
+ transformQueryParams
1304
+ };
1305
+ };
1306
+ const convertQueryParams = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1307
+ __proto__: null,
1308
+ createTransformer
1309
+ }, Symbol.toStringTag, { value: "Module" }));
1310
+ function pipe(...fns) {
1311
+ const [firstFn, ...fnRest] = fns;
1312
+ return async (...args) => {
1313
+ let res = await firstFn.apply(firstFn, args);
1314
+ for (let i = 0; i < fnRest.length; i += 1) {
1315
+ res = await fnRest[i](res);
1316
+ }
1317
+ return res;
1318
+ };
1319
+ }
1320
+ const map = fp.curry(pMap__default.default);
1321
+ const reduce = (mixedArray) => async (iteratee, initialValue) => {
1322
+ let acc = initialValue;
1323
+ for (let i = 0; i < mixedArray.length; i += 1) {
1324
+ acc = await iteratee(acc, await mixedArray[i], i);
1325
+ }
1326
+ return acc;
1327
+ };
1328
+ const async = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1329
+ __proto__: null,
1330
+ map,
1331
+ pipe,
1332
+ reduce
1333
+ }, Symbol.toStringTag, { value: "Module" }));
1334
+ const visitor$8 = ({ key, attribute }, { remove }) => {
1335
+ if (attribute?.type === "password") {
1336
+ remove(key);
1337
+ }
1338
+ };
1339
+ const visitor$7 = ({ schema, key, attribute }, { remove }) => {
1340
+ if (!attribute) {
1341
+ return;
1342
+ }
1343
+ const isPrivate = attribute.private === true || isPrivateAttribute(schema, key);
1344
+ if (isPrivate) {
1345
+ remove(key);
1346
+ }
1347
+ };
1348
+ const ACTIONS_TO_VERIFY$1 = ["find"];
1349
+ const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$1 } = constants$1;
1350
+ const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schema }, { remove, set }) => {
1351
+ if (!attribute) {
1352
+ return;
1353
+ }
1354
+ const isRelation = attribute.type === "relation";
1355
+ if (!isRelation) {
1356
+ return;
1357
+ }
1358
+ const handleMorphRelation = async () => {
1359
+ const newMorphValue = [];
1360
+ for (const element of data[key]) {
1361
+ const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
1362
+ const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
1363
+ if (isAllowed) {
1364
+ newMorphValue.push(element);
1365
+ }
1366
+ }
1367
+ if (newMorphValue.length === 0) {
1368
+ remove(key);
1369
+ } else {
1370
+ set(key, newMorphValue);
1371
+ }
1372
+ };
1373
+ const handleRegularRelation = async () => {
1374
+ const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${attribute.target}.${action}`);
1375
+ const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
1376
+ if (!isAllowed) {
1377
+ remove(key);
1378
+ }
1379
+ };
1380
+ const isCreatorRelation = [CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE$1].includes(key);
1381
+ if (isMorphToRelationalAttribute(attribute)) {
1382
+ await handleMorphRelation();
1383
+ return;
1384
+ }
1385
+ if (isCreatorRelation && schema.options?.populateCreatorFields) {
1386
+ return;
1387
+ }
1388
+ await handleRegularRelation();
1389
+ };
1390
+ const hasAccessToSomeScopes$1 = async (scopes, auth) => {
1391
+ for (const scope of scopes) {
1392
+ try {
1393
+ await strapi.auth.verify(auth, { scope });
1394
+ return true;
1395
+ } catch {
1396
+ continue;
1397
+ }
1398
+ }
1399
+ return false;
1400
+ };
1401
+ const visitor$6 = ({ key, attribute }, { remove }) => {
1402
+ if (isMorphToRelationalAttribute(attribute)) {
1403
+ remove(key);
1404
+ }
1405
+ };
1406
+ const visitor$5 = ({ key, attribute }, { remove }) => {
1407
+ if (isDynamicZoneAttribute(attribute)) {
1408
+ remove(key);
1409
+ }
1410
+ };
1411
+ const removeDisallowedFields = (allowedFields = null) => ({ key, path: { attribute: path } }, { remove }) => {
1412
+ if (allowedFields === null) {
1413
+ return;
1414
+ }
1415
+ if (!(fp.isArray(allowedFields) && allowedFields.every(fp.isString))) {
1416
+ throw new TypeError(
1417
+ `Expected array of strings for allowedFields but got "${typeof allowedFields}"`
1418
+ );
1419
+ }
1420
+ if (fp.isNil(path)) {
1421
+ return;
1422
+ }
1423
+ const containedPaths = getContainedPaths$1(path);
1424
+ const isPathAllowed = allowedFields.some(
1425
+ (p) => containedPaths.includes(p) || p.startsWith(`${path}.`)
1426
+ );
1427
+ if (isPathAllowed) {
1428
+ return;
1429
+ }
1430
+ remove(key);
1431
+ };
1432
+ const getContainedPaths$1 = (path) => {
1433
+ const parts = fp.toPath(path);
1434
+ return parts.reduce((acc, value, index2, list) => {
1435
+ return [...acc, list.slice(0, index2 + 1).join(".")];
1436
+ }, []);
1437
+ };
1438
+ const removeRestrictedFields = (restrictedFields = null) => ({ key, path: { attribute: path } }, { remove }) => {
1439
+ if (restrictedFields === null) {
1440
+ remove(key);
1441
+ return;
1442
+ }
1443
+ if (!(fp.isArray(restrictedFields) && restrictedFields.every(fp.isString))) {
1444
+ throw new TypeError(
1445
+ `Expected array of strings for restrictedFields but got "${typeof restrictedFields}"`
1446
+ );
1447
+ }
1448
+ if (restrictedFields.includes(path)) {
1449
+ remove(key);
1450
+ return;
1451
+ }
1452
+ const isRestrictedNested = restrictedFields.some(
1453
+ (allowedPath) => path?.toString().startsWith(`${allowedPath}.`)
1454
+ );
1455
+ if (isRestrictedNested) {
1456
+ remove(key);
1457
+ }
1458
+ };
1459
+ const visitor$4 = ({ schema, key, value }, { set }) => {
1460
+ if (key === "" && value === "*") {
1461
+ const { attributes } = schema;
1462
+ const newPopulateQuery = Object.entries(attributes).filter(
1463
+ ([, attribute]) => ["relation", "component", "media", "dynamiczone"].includes(attribute.type)
1464
+ ).reduce((acc, [key2]) => ({ ...acc, [key2]: true }), {});
1465
+ set("", newPopulateQuery);
1466
+ }
1467
+ };
1468
+ const index$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1469
+ __proto__: null,
1470
+ expandWildcardPopulate: visitor$4,
1471
+ removeDisallowedFields,
1472
+ removeDynamicZones: visitor$5,
1473
+ removeMorphToRelations: visitor$6,
1474
+ removePassword: visitor$8,
1475
+ removePrivate: visitor$7,
1476
+ removeRestrictedFields,
1477
+ removeRestrictedRelations
1478
+ }, Symbol.toStringTag, { value: "Module" }));
1479
+ const DEFAULT_PATH = { raw: null, attribute: null };
1480
+ const traverseFactory = () => {
1481
+ const state = {
1482
+ parsers: [],
1483
+ interceptors: [],
1484
+ ignore: [],
1485
+ handlers: {
1486
+ attributes: [],
1487
+ common: []
1488
+ }
1489
+ };
1490
+ const traverse = async (visitor2, options, data) => {
1491
+ const { path = DEFAULT_PATH, schema, getModel } = options ?? {};
1492
+ for (const { predicate, handler } of state.interceptors) {
1493
+ if (predicate(data)) {
1494
+ return handler(visitor2, options, data, { recurse: traverse });
1495
+ }
1496
+ }
1497
+ const parser = state.parsers.find((parser2) => parser2.predicate(data))?.parser;
1498
+ const utils2 = parser?.(data);
1499
+ if (!utils2) {
1500
+ return data;
1501
+ }
1502
+ let out = utils2.transform(data);
1503
+ const keys = utils2.keys(out);
1504
+ for (const key of keys) {
1505
+ const attribute = schema?.attributes?.[key];
1506
+ const newPath = { ...path };
1507
+ newPath.raw = fp.isNil(path.raw) ? key : `${path.raw}.${key}`;
1508
+ if (!fp.isNil(attribute)) {
1509
+ newPath.attribute = fp.isNil(path.attribute) ? key : `${path.attribute}.${key}`;
1510
+ }
1511
+ const visitorOptions = {
1512
+ key,
1513
+ value: utils2.get(key, out),
1514
+ attribute,
1515
+ schema,
1516
+ path: newPath,
1517
+ data: out,
1518
+ getModel
1519
+ };
1520
+ const transformUtils = {
1521
+ remove(key2) {
1522
+ out = utils2.remove(key2, out);
1523
+ },
1524
+ set(key2, value2) {
1525
+ out = utils2.set(key2, value2, out);
1526
+ },
1527
+ recurse: traverse
1528
+ };
1529
+ await visitor2(visitorOptions, fp.pick(["remove", "set"], transformUtils));
1530
+ const value = utils2.get(key, out);
1531
+ const createContext = () => ({
1532
+ key,
1533
+ value,
1534
+ attribute,
1535
+ schema,
1536
+ path: newPath,
1537
+ data: out,
1538
+ visitor: visitor2,
1539
+ getModel
1540
+ });
892
1541
  const ignoreCtx = createContext();
893
1542
  const shouldIgnore = state.ignore.some((predicate) => predicate(ignoreCtx));
894
1543
  if (shouldIgnore) {
@@ -976,33 +1625,33 @@ const filters = traverseFactory().intercept(
976
1625
  }
977
1626
  })).ignore(({ value }) => fp.isNil(value)).on(
978
1627
  ({ attribute }) => fp.isNil(attribute),
979
- async ({ key, visitor: visitor2, path, value, schema }, { set, recurse }) => {
980
- set(key, await recurse(visitor2, { schema, path }, value));
1628
+ async ({ key, visitor: visitor2, path, value, schema, getModel }, { set, recurse }) => {
1629
+ set(key, await recurse(visitor2, { schema, path, getModel }, value));
981
1630
  }
982
- ).onRelation(async ({ key, attribute, visitor: visitor2, path, value }, { set, recurse }) => {
1631
+ ).onRelation(async ({ key, attribute, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
983
1632
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
984
1633
  if (isMorphRelation) {
985
1634
  return;
986
1635
  }
987
1636
  const targetSchemaUID = attribute.target;
988
- const targetSchema = strapi.getModel(targetSchemaUID);
989
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1637
+ const targetSchema = getModel(targetSchemaUID);
1638
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
990
1639
  set(key, newValue);
991
- }).onComponent(async ({ key, attribute, visitor: visitor2, path, value }, { set, recurse }) => {
992
- const targetSchema = strapi.getModel(attribute.component);
993
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1640
+ }).onComponent(async ({ key, attribute, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
1641
+ const targetSchema = getModel(attribute.component);
1642
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
994
1643
  set(key, newValue);
995
- }).onMedia(async ({ key, visitor: visitor2, path, value }, { set, recurse }) => {
1644
+ }).onMedia(async ({ key, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
996
1645
  const targetSchemaUID = "plugin::upload.file";
997
- const targetSchema = strapi.getModel(targetSchemaUID);
998
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1646
+ const targetSchema = getModel(targetSchemaUID);
1647
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
999
1648
  set(key, newValue);
1000
1649
  });
1001
1650
  const traverseQueryFilters = fp.curry(filters.traverse);
1002
1651
  const ORDERS = { asc: "asc", desc: "desc" };
1003
1652
  const ORDER_VALUES = Object.values(ORDERS);
1004
1653
  const isSortOrder = (value) => ORDER_VALUES.includes(value.toLowerCase());
1005
- const isStringArray$3 = (value) => Array.isArray(value) && value.every(fp.isString);
1654
+ const isStringArray$2 = (value) => Array.isArray(value) && value.every(fp.isString);
1006
1655
  const isObjectArray = (value) => Array.isArray(value) && value.every(fp.isObject);
1007
1656
  const isNestedSorts = (value) => fp.isString(value) && value.split(",").length > 1;
1008
1657
  const isObj$1 = (value) => fp.isObject(value);
@@ -1016,7 +1665,7 @@ const sort = traverseFactory().intercept(
1016
1665
  }
1017
1666
  ).intercept(
1018
1667
  // Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items
1019
- isStringArray$3,
1668
+ isStringArray$2,
1020
1669
  async (visitor2, options, sort2, { recurse }) => {
1021
1670
  return Promise.all(sort2.map((nestedSort) => recurse(visitor2, options, nestedSort))).then(
1022
1671
  (res) => res.filter((nestedSort) => !fp.isEmpty(nestedSort))
@@ -1083,23 +1732,23 @@ const sort = traverseFactory().intercept(
1083
1732
  get(key, data) {
1084
1733
  return data[key];
1085
1734
  }
1086
- })).onRelation(async ({ key, value, attribute, visitor: visitor2, path }, { set, recurse }) => {
1735
+ })).onRelation(async ({ key, value, attribute, visitor: visitor2, path, getModel }, { set, recurse }) => {
1087
1736
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
1088
1737
  if (isMorphRelation) {
1089
1738
  return;
1090
1739
  }
1091
1740
  const targetSchemaUID = attribute.target;
1092
- const targetSchema = strapi.getModel(targetSchemaUID);
1093
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1741
+ const targetSchema = getModel(targetSchemaUID);
1742
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1094
1743
  set(key, newValue);
1095
- }).onMedia(async ({ key, path, visitor: visitor2, value }, { recurse, set }) => {
1744
+ }).onMedia(async ({ key, path, visitor: visitor2, value, getModel }, { recurse, set }) => {
1096
1745
  const targetSchemaUID = "plugin::upload.file";
1097
- const targetSchema = strapi.getModel(targetSchemaUID);
1098
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1746
+ const targetSchema = getModel(targetSchemaUID);
1747
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1099
1748
  set(key, newValue);
1100
- }).onComponent(async ({ key, value, visitor: visitor2, path, attribute }, { recurse, set }) => {
1101
- const targetSchema = strapi.getModel(attribute.component);
1102
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1749
+ }).onComponent(async ({ key, value, visitor: visitor2, path, attribute, getModel }, { recurse, set }) => {
1750
+ const targetSchema = getModel(attribute.component);
1751
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1103
1752
  set(key, newValue);
1104
1753
  });
1105
1754
  const traverseQuerySort = fp.curry(sort.traverse);
@@ -1108,9 +1757,9 @@ const isKeyword = (keyword) => {
1108
1757
  return !attribute && keyword === key;
1109
1758
  };
1110
1759
  };
1111
- const isStringArray$2 = (value) => fp.isArray(value) && value.every(fp.isString);
1760
+ const isStringArray$1 = (value) => fp.isArray(value) && value.every(fp.isString);
1112
1761
  const isObj = (value) => fp.isObject(value);
1113
- const populate = traverseFactory().intercept(isStringArray$2, async (visitor2, options, populate2, { recurse }) => {
1762
+ const populate = traverseFactory().intercept(isStringArray$1, async (visitor2, options, populate2, { recurse }) => {
1114
1763
  const visitedPopulate = await Promise.all(
1115
1764
  populate2.map((nestedPopulate) => recurse(visitor2, options, nestedPopulate))
1116
1765
  );
@@ -1186,180 +1835,100 @@ const populate = traverseFactory().intercept(isStringArray$2, async (visitor2, o
1186
1835
  return ["sort", "filters", "fields"].includes(key) && !attribute;
1187
1836
  }).on(
1188
1837
  // Handle recursion on populate."populate"
1189
- isKeyword("populate"),
1190
- async ({ key, visitor: visitor2, path, value, schema }, { set, recurse }) => {
1191
- const newValue = await recurse(visitor2, { schema, path }, value);
1192
- set(key, newValue);
1193
- }
1194
- ).on(isKeyword("on"), async ({ key, visitor: visitor2, path, value }, { set, recurse }) => {
1195
- const newOn = {};
1196
- if (!isObj(value)) {
1197
- return;
1198
- }
1199
- for (const [uid, subPopulate] of Object.entries(value)) {
1200
- const model = strapi.getModel(uid);
1201
- const newPath = { ...path, raw: `${path.raw}[${uid}]` };
1202
- newOn[uid] = await recurse(visitor2, { schema: model, path: newPath }, subPopulate);
1203
- }
1204
- set(key, newOn);
1205
- }).onRelation(async ({ key, value, attribute, visitor: visitor2, path, schema }, { set, recurse }) => {
1206
- if (fp.isNil(value)) {
1207
- return;
1208
- }
1209
- if (isMorphToRelationalAttribute(attribute)) {
1210
- if (!fp.isObject(value) || !("on" in value && fp.isObject(value?.on))) {
1211
- return;
1212
- }
1213
- const newValue2 = await recurse(visitor2, { schema, path }, { on: value?.on });
1214
- set(key, { on: newValue2 });
1215
- }
1216
- const targetSchemaUID = attribute.target;
1217
- const targetSchema = strapi.getModel(targetSchemaUID);
1218
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1219
- set(key, newValue);
1220
- }).onMedia(async ({ key, path, visitor: visitor2, value }, { recurse, set }) => {
1221
- if (fp.isNil(value)) {
1222
- return;
1223
- }
1224
- const targetSchemaUID = "plugin::upload.file";
1225
- const targetSchema = strapi.getModel(targetSchemaUID);
1226
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1227
- set(key, newValue);
1228
- }).onComponent(async ({ key, value, visitor: visitor2, path, attribute }, { recurse, set }) => {
1229
- if (fp.isNil(value)) {
1230
- return;
1231
- }
1232
- const targetSchema = strapi.getModel(attribute.component);
1233
- const newValue = await recurse(visitor2, { schema: targetSchema, path }, value);
1234
- set(key, newValue);
1235
- }).onDynamicZone(async ({ key, value, attribute, schema, visitor: visitor2, path }, { set, recurse }) => {
1236
- if (fp.isNil(value)) {
1237
- return;
1238
- }
1239
- if (fp.isObject(value)) {
1240
- const { components } = attribute;
1241
- const newValue = {};
1242
- let newProperties = fp.omit("on", value);
1243
- for (const componentUID of components) {
1244
- const componentSchema = strapi.getModel(componentUID);
1245
- const properties = await recurse(visitor2, { schema: componentSchema, path }, value);
1246
- newProperties = fp.merge(newProperties, properties);
1247
- }
1248
- Object.assign(newValue, newProperties);
1249
- if ("on" in value && value.on) {
1250
- const newOn = await recurse(visitor2, { schema, path }, { on: value.on });
1251
- Object.assign(newValue, newOn);
1252
- }
1253
- set(key, newValue);
1254
- } else {
1255
- const newValue = await recurse(visitor2, { schema, path }, value);
1256
- set(key, newValue);
1257
- }
1258
- });
1259
- const traverseQueryPopulate = fp.curry(populate.traverse);
1260
- const isStringArray$1 = (value) => fp.isArray(value) && value.every(fp.isString);
1261
- const fields = traverseFactory().intercept(isStringArray$1, async (visitor2, options, fields2, { recurse }) => {
1262
- return Promise.all(fields2.map((field) => recurse(visitor2, options, field)));
1263
- }).intercept((value) => fp.eq("*", value), fp.constant("*")).parse(fp.isString, () => ({
1264
- transform: fp.trim,
1265
- remove(key, data) {
1266
- return data === key ? void 0 : data;
1267
- },
1268
- set(_key, _value, data) {
1269
- return data;
1270
- },
1271
- keys(data) {
1272
- return [data];
1273
- },
1274
- get(key, data) {
1275
- return key === data ? data : void 0;
1276
- }
1277
- }));
1278
- const traverseQueryFields = fp.curry(fields.traverse);
1279
- const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1280
- __proto__: null,
1281
- factory: traverseFactory,
1282
- traverseQueryFields,
1283
- traverseQueryFilters,
1284
- traverseQueryPopulate,
1285
- traverseQuerySort
1286
- }, Symbol.toStringTag, { value: "Module" }));
1287
- const GROUP_OPERATORS = ["$and", "$or"];
1288
- const WHERE_OPERATORS = [
1289
- "$not",
1290
- "$in",
1291
- "$notIn",
1292
- "$eq",
1293
- "$eqi",
1294
- "$ne",
1295
- "$nei",
1296
- "$gt",
1297
- "$gte",
1298
- "$lt",
1299
- "$lte",
1300
- "$null",
1301
- "$notNull",
1302
- "$between",
1303
- "$startsWith",
1304
- "$endsWith",
1305
- "$startsWithi",
1306
- "$endsWithi",
1307
- "$contains",
1308
- "$notContains",
1309
- "$containsi",
1310
- "$notContainsi",
1311
- // Experimental, only for internal use
1312
- "$jsonSupersetOf"
1313
- ];
1314
- const CAST_OPERATORS = [
1315
- "$not",
1316
- "$in",
1317
- "$notIn",
1318
- "$eq",
1319
- "$ne",
1320
- "$gt",
1321
- "$gte",
1322
- "$lt",
1323
- "$lte",
1324
- "$between"
1325
- ];
1326
- const ARRAY_OPERATORS = ["$in", "$notIn", "$between"];
1327
- const OPERATORS = {
1328
- where: WHERE_OPERATORS,
1329
- cast: CAST_OPERATORS,
1330
- group: GROUP_OPERATORS,
1331
- array: ARRAY_OPERATORS
1332
- };
1333
- const OPERATORS_LOWERCASE = Object.fromEntries(
1334
- Object.entries(OPERATORS).map(([key, values]) => [
1335
- key,
1336
- values.map((value) => value.toLowerCase())
1337
- ])
1338
- );
1339
- const isObjKey = (key, obj) => {
1340
- return key in obj;
1341
- };
1342
- const isOperatorOfType = (type, key, ignoreCase = false) => {
1343
- if (ignoreCase) {
1344
- return OPERATORS_LOWERCASE[type]?.includes(key.toLowerCase()) ?? false;
1838
+ isKeyword("populate"),
1839
+ async ({ key, visitor: visitor2, path, value, schema, getModel }, { set, recurse }) => {
1840
+ const newValue = await recurse(visitor2, { schema, path, getModel }, value);
1841
+ set(key, newValue);
1345
1842
  }
1346
- if (isObjKey(type, OPERATORS)) {
1347
- return OPERATORS[type]?.includes(key) ?? false;
1843
+ ).on(isKeyword("on"), async ({ key, visitor: visitor2, path, value, getModel }, { set, recurse }) => {
1844
+ const newOn = {};
1845
+ if (!isObj(value)) {
1846
+ return;
1348
1847
  }
1349
- return false;
1350
- };
1351
- const isOperator = (key, ignoreCase = false) => {
1352
- return Object.keys(OPERATORS).some((type) => isOperatorOfType(type, key, ignoreCase));
1353
- };
1354
- const { ID_ATTRIBUTE: ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$3 } = constants$1;
1355
- const sanitizePasswords = (schema) => async (entity) => {
1356
- if (!schema) {
1848
+ for (const [uid, subPopulate] of Object.entries(value)) {
1849
+ const model = getModel(uid);
1850
+ const newPath = { ...path, raw: `${path.raw}[${uid}]` };
1851
+ newOn[uid] = await recurse(visitor2, { schema: model, path: newPath, getModel }, subPopulate);
1852
+ }
1853
+ set(key, newOn);
1854
+ }).onRelation(
1855
+ async ({ key, value, attribute, visitor: visitor2, path, schema, getModel }, { set, recurse }) => {
1856
+ if (fp.isNil(value)) {
1857
+ return;
1858
+ }
1859
+ if (isMorphToRelationalAttribute(attribute)) {
1860
+ if (!fp.isObject(value) || !("on" in value && fp.isObject(value?.on))) {
1861
+ return;
1862
+ }
1863
+ const newValue2 = await recurse(visitor2, { schema, path, getModel }, { on: value?.on });
1864
+ set(key, newValue2);
1865
+ return;
1866
+ }
1867
+ const targetSchemaUID = attribute.target;
1868
+ const targetSchema = getModel(targetSchemaUID);
1869
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1870
+ set(key, newValue);
1871
+ }
1872
+ ).onMedia(async ({ key, path, visitor: visitor2, value, getModel }, { recurse, set }) => {
1873
+ if (fp.isNil(value)) {
1874
+ return;
1875
+ }
1876
+ const targetSchemaUID = "plugin::upload.file";
1877
+ const targetSchema = getModel(targetSchemaUID);
1878
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1879
+ set(key, newValue);
1880
+ }).onComponent(async ({ key, value, visitor: visitor2, path, attribute, getModel }, { recurse, set }) => {
1881
+ if (fp.isNil(value)) {
1882
+ return;
1883
+ }
1884
+ const targetSchema = getModel(attribute.component);
1885
+ const newValue = await recurse(visitor2, { schema: targetSchema, path, getModel }, value);
1886
+ set(key, newValue);
1887
+ }).onDynamicZone(async ({ key, value, schema, visitor: visitor2, path, getModel }, { set, recurse }) => {
1888
+ if (fp.isNil(value) || !fp.isObject(value)) {
1889
+ return;
1890
+ }
1891
+ if ("on" in value && value.on) {
1892
+ const newOn = await recurse(visitor2, { schema, path, getModel }, { on: value.on });
1893
+ set(key, newOn);
1894
+ }
1895
+ });
1896
+ const traverseQueryPopulate = fp.curry(populate.traverse);
1897
+ const isStringArray = (value) => fp.isArray(value) && value.every(fp.isString);
1898
+ const fields = traverseFactory().intercept(isStringArray, async (visitor2, options, fields2, { recurse }) => {
1899
+ return Promise.all(fields2.map((field) => recurse(visitor2, options, field)));
1900
+ }).intercept((value) => fp.eq("*", value), fp.constant("*")).parse(fp.isString, () => ({
1901
+ transform: fp.trim,
1902
+ remove(key, data) {
1903
+ return data === key ? void 0 : data;
1904
+ },
1905
+ set(_key, _value, data) {
1906
+ return data;
1907
+ },
1908
+ keys(data) {
1909
+ return [data];
1910
+ },
1911
+ get(key, data) {
1912
+ return key === data ? data : void 0;
1913
+ }
1914
+ }));
1915
+ const traverseQueryFields = fp.curry(fields.traverse);
1916
+ const index$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1917
+ __proto__: null,
1918
+ traverseQueryFields,
1919
+ traverseQueryFilters,
1920
+ traverseQueryPopulate,
1921
+ traverseQuerySort
1922
+ }, Symbol.toStringTag, { value: "Module" }));
1923
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$2 } = constants$1;
1924
+ const sanitizePasswords = (ctx) => async (entity) => {
1925
+ if (!ctx.schema) {
1357
1926
  throw new Error("Missing schema in sanitizePasswords");
1358
1927
  }
1359
- return traverseEntity$1(visitor$8, { schema }, entity);
1928
+ return traverseEntity$1(visitor$8, ctx, entity);
1360
1929
  };
1361
- const defaultSanitizeOutput = async (schema, entity) => {
1362
- if (!schema) {
1930
+ const defaultSanitizeOutput = async (ctx, entity) => {
1931
+ if (!ctx.schema) {
1363
1932
  throw new Error("Missing schema in defaultSanitizeOutput");
1364
1933
  }
1365
1934
  return traverseEntity$1(
@@ -1367,139 +1936,121 @@ const defaultSanitizeOutput = async (schema, entity) => {
1367
1936
  visitor$8(...args);
1368
1937
  visitor$7(...args);
1369
1938
  },
1370
- { schema },
1939
+ ctx,
1371
1940
  entity
1372
1941
  );
1373
1942
  };
1374
- const defaultSanitizeFilters = fp.curry((schema, filters2) => {
1375
- if (!schema) {
1943
+ const defaultSanitizeFilters = fp.curry((ctx, filters2) => {
1944
+ if (!ctx.schema) {
1376
1945
  throw new Error("Missing schema in defaultSanitizeFilters");
1377
1946
  }
1378
1947
  return pipe(
1379
1948
  // Remove keys that are not attributes or valid operators
1380
- traverseQueryFilters(
1381
- ({ key, attribute }, { remove }) => {
1382
- const isAttribute = !!attribute;
1383
- if ([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3].includes(key)) {
1384
- return;
1385
- }
1386
- if (!isAttribute && !isOperator(key)) {
1387
- remove(key);
1388
- }
1389
- },
1390
- { schema }
1391
- ),
1949
+ traverseQueryFilters(({ key, attribute }, { remove }) => {
1950
+ const isAttribute = !!attribute;
1951
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1952
+ return;
1953
+ }
1954
+ if (!isAttribute && !isOperator(key)) {
1955
+ remove(key);
1956
+ }
1957
+ }, ctx),
1392
1958
  // Remove dynamic zones from filters
1393
- traverseQueryFilters(visitor$5, { schema }),
1959
+ traverseQueryFilters(visitor$5, ctx),
1394
1960
  // Remove morpTo relations from filters
1395
- traverseQueryFilters(visitor$6, { schema }),
1961
+ traverseQueryFilters(visitor$6, ctx),
1396
1962
  // Remove passwords from filters
1397
- traverseQueryFilters(visitor$8, { schema }),
1963
+ traverseQueryFilters(visitor$8, ctx),
1398
1964
  // Remove private from filters
1399
- traverseQueryFilters(visitor$7, { schema }),
1965
+ traverseQueryFilters(visitor$7, ctx),
1400
1966
  // Remove empty objects
1401
- traverseQueryFilters(
1402
- ({ key, value }, { remove }) => {
1403
- if (fp.isObject(value) && fp.isEmpty(value)) {
1404
- remove(key);
1405
- }
1406
- },
1407
- { schema }
1408
- )
1967
+ traverseQueryFilters(({ key, value }, { remove }) => {
1968
+ if (fp.isObject(value) && fp.isEmpty(value)) {
1969
+ remove(key);
1970
+ }
1971
+ }, ctx)
1409
1972
  )(filters2);
1410
1973
  });
1411
- const defaultSanitizeSort = fp.curry((schema, sort2) => {
1412
- if (!schema) {
1974
+ const defaultSanitizeSort = fp.curry((ctx, sort2) => {
1975
+ if (!ctx.schema) {
1413
1976
  throw new Error("Missing schema in defaultSanitizeSort");
1414
1977
  }
1415
1978
  return pipe(
1416
1979
  // Remove non attribute keys
1417
- traverseQuerySort(
1418
- ({ key, attribute }, { remove }) => {
1419
- if ([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3].includes(key)) {
1420
- return;
1421
- }
1422
- if (!attribute) {
1423
- remove(key);
1424
- }
1425
- },
1426
- { schema }
1427
- ),
1980
+ traverseQuerySort(({ key, attribute }, { remove }) => {
1981
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1982
+ return;
1983
+ }
1984
+ if (!attribute) {
1985
+ remove(key);
1986
+ }
1987
+ }, ctx),
1428
1988
  // Remove dynamic zones from sort
1429
- traverseQuerySort(visitor$5, { schema }),
1989
+ traverseQuerySort(visitor$5, ctx),
1430
1990
  // Remove morpTo relations from sort
1431
- traverseQuerySort(visitor$6, { schema }),
1991
+ traverseQuerySort(visitor$6, ctx),
1432
1992
  // Remove private from sort
1433
- traverseQuerySort(visitor$7, { schema }),
1993
+ traverseQuerySort(visitor$7, ctx),
1434
1994
  // Remove passwords from filters
1435
- traverseQuerySort(visitor$8, { schema }),
1995
+ traverseQuerySort(visitor$8, ctx),
1436
1996
  // Remove keys for empty non-scalar values
1437
- traverseQuerySort(
1438
- ({ key, attribute, value }, { remove }) => {
1439
- if ([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3].includes(key)) {
1440
- return;
1441
- }
1442
- if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
1443
- remove(key);
1444
- }
1445
- },
1446
- { schema }
1447
- )
1997
+ traverseQuerySort(({ key, attribute, value }, { remove }) => {
1998
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1999
+ return;
2000
+ }
2001
+ if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
2002
+ remove(key);
2003
+ }
2004
+ }, ctx)
1448
2005
  )(sort2);
1449
2006
  });
1450
- const defaultSanitizeFields = fp.curry((schema, fields2) => {
1451
- if (!schema) {
2007
+ const defaultSanitizeFields = fp.curry((ctx, fields2) => {
2008
+ if (!ctx.schema) {
1452
2009
  throw new Error("Missing schema in defaultSanitizeFields");
1453
2010
  }
1454
2011
  return pipe(
1455
2012
  // Only keep scalar attributes
1456
- traverseQueryFields(
1457
- ({ key, attribute }, { remove }) => {
1458
- if ([ID_ATTRIBUTE$3, DOC_ID_ATTRIBUTE$3].includes(key)) {
1459
- return;
1460
- }
1461
- if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
1462
- remove(key);
1463
- }
1464
- },
1465
- { schema }
1466
- ),
2013
+ traverseQueryFields(({ key, attribute }, { remove }) => {
2014
+ if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
2015
+ return;
2016
+ }
2017
+ if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
2018
+ remove(key);
2019
+ }
2020
+ }, ctx),
1467
2021
  // Remove private fields
1468
- traverseQueryFields(visitor$7, { schema }),
2022
+ traverseQueryFields(visitor$7, ctx),
1469
2023
  // Remove password fields
1470
- traverseQueryFields(visitor$8, { schema }),
2024
+ traverseQueryFields(visitor$8, ctx),
1471
2025
  // Remove nil values from fields array
1472
2026
  (value) => fp.isArray(value) ? value.filter((field) => !fp.isNil(field)) : value
1473
2027
  )(fields2);
1474
2028
  });
1475
- const defaultSanitizePopulate = fp.curry((schema, populate2) => {
1476
- if (!schema) {
2029
+ const defaultSanitizePopulate = fp.curry((ctx, populate2) => {
2030
+ if (!ctx.schema) {
1477
2031
  throw new Error("Missing schema in defaultSanitizePopulate");
1478
2032
  }
1479
2033
  return pipe(
1480
- traverseQueryPopulate(visitor$4, { schema }),
1481
- traverseQueryPopulate(
1482
- async ({ key, value, schema: schema2, attribute }, { set }) => {
1483
- if (attribute) {
1484
- return;
1485
- }
1486
- if (key === "sort") {
1487
- set(key, await defaultSanitizeSort(schema2, value));
1488
- }
1489
- if (key === "filters") {
1490
- set(key, await defaultSanitizeFilters(schema2, value));
1491
- }
1492
- if (key === "fields") {
1493
- set(key, await defaultSanitizeFields(schema2, value));
1494
- }
1495
- if (key === "populate") {
1496
- set(key, await defaultSanitizePopulate(schema2, value));
1497
- }
1498
- },
1499
- { schema }
1500
- ),
2034
+ traverseQueryPopulate(visitor$4, ctx),
2035
+ traverseQueryPopulate(async ({ key, value, schema, attribute, getModel }, { set }) => {
2036
+ if (attribute) {
2037
+ return;
2038
+ }
2039
+ if (key === "sort") {
2040
+ set(key, await defaultSanitizeSort({ schema, getModel }, value));
2041
+ }
2042
+ if (key === "filters") {
2043
+ set(key, await defaultSanitizeFilters({ schema, getModel }, value));
2044
+ }
2045
+ if (key === "fields") {
2046
+ set(key, await defaultSanitizeFields({ schema, getModel }, value));
2047
+ }
2048
+ if (key === "populate") {
2049
+ set(key, await defaultSanitizePopulate({ schema, getModel }, value));
2050
+ }
2051
+ }, ctx),
1501
2052
  // Remove private fields
1502
- traverseQueryPopulate(visitor$7, { schema })
2053
+ traverseQueryPopulate(visitor$7, ctx)
1503
2054
  )(populate2);
1504
2055
  });
1505
2056
  const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -1511,7 +2062,8 @@ const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
1511
2062
  defaultSanitizeSort,
1512
2063
  sanitizePasswords
1513
2064
  }, Symbol.toStringTag, { value: "Module" }));
1514
- const createContentAPISanitizers = () => {
2065
+ const createAPISanitizers = (opts) => {
2066
+ const { getModel } = opts;
1515
2067
  const sanitizeInput = (data, schema, { auth } = {}) => {
1516
2068
  if (!schema) {
1517
2069
  throw new Error("Missing schema in sanitizeInput");
@@ -1525,12 +2077,14 @@ const createContentAPISanitizers = () => {
1525
2077
  fp.omit(constants$1.ID_ATTRIBUTE),
1526
2078
  fp.omit(constants$1.DOC_ID_ATTRIBUTE),
1527
2079
  // Remove non-writable attributes
1528
- traverseEntity$1(removeRestrictedFields(nonWritableAttributes), { schema })
2080
+ traverseEntity$1(removeRestrictedFields(nonWritableAttributes), { schema, getModel })
1529
2081
  ];
1530
2082
  if (auth) {
1531
- transforms.push(traverseEntity$1(removeRestrictedRelations(auth), { schema }));
2083
+ transforms.push(
2084
+ traverseEntity$1(removeRestrictedRelations(auth), { schema, getModel })
2085
+ );
1532
2086
  }
1533
- strapi.sanitizers.get("content-api.input").forEach((sanitizer) => transforms.push(sanitizer(schema)));
2087
+ opts?.sanitizers?.input?.forEach((sanitizer) => transforms.push(sanitizer(schema)));
1534
2088
  return pipe(...transforms)(data);
1535
2089
  };
1536
2090
  const sanitizeOutput = async (data, schema, { auth } = {}) => {
@@ -1544,11 +2098,15 @@ const createContentAPISanitizers = () => {
1544
2098
  }
1545
2099
  return res;
1546
2100
  }
1547
- const transforms = [(data2) => defaultSanitizeOutput(schema, data2)];
2101
+ const transforms = [
2102
+ (data2) => defaultSanitizeOutput({ schema, getModel }, data2)
2103
+ ];
1548
2104
  if (auth) {
1549
- transforms.push(traverseEntity$1(removeRestrictedRelations(auth), { schema }));
2105
+ transforms.push(
2106
+ traverseEntity$1(removeRestrictedRelations(auth), { schema, getModel })
2107
+ );
1550
2108
  }
1551
- strapi.sanitizers.get("content-api.output").forEach((sanitizer) => transforms.push(sanitizer(schema)));
2109
+ opts?.sanitizers?.output?.forEach((sanitizer) => transforms.push(sanitizer(schema)));
1552
2110
  return pipe(...transforms)(data);
1553
2111
  };
1554
2112
  const sanitizeQuery = async (query, schema, { auth } = {}) => {
@@ -1578,9 +2136,11 @@ const createContentAPISanitizers = () => {
1578
2136
  if (fp.isArray(filters2)) {
1579
2137
  return Promise.all(filters2.map((filter) => sanitizeFilters(filter, schema, { auth })));
1580
2138
  }
1581
- const transforms = [defaultSanitizeFilters(schema)];
2139
+ const transforms = [defaultSanitizeFilters({ schema, getModel })];
1582
2140
  if (auth) {
1583
- transforms.push(traverseQueryFilters(removeRestrictedRelations(auth), { schema }));
2141
+ transforms.push(
2142
+ traverseQueryFilters(removeRestrictedRelations(auth), { schema, getModel })
2143
+ );
1584
2144
  }
1585
2145
  return pipe(...transforms)(filters2);
1586
2146
  };
@@ -1588,9 +2148,11 @@ const createContentAPISanitizers = () => {
1588
2148
  if (!schema) {
1589
2149
  throw new Error("Missing schema in sanitizeSort");
1590
2150
  }
1591
- const transforms = [defaultSanitizeSort(schema)];
2151
+ const transforms = [defaultSanitizeSort({ schema, getModel })];
1592
2152
  if (auth) {
1593
- transforms.push(traverseQuerySort(removeRestrictedRelations(auth), { schema }));
2153
+ transforms.push(
2154
+ traverseQuerySort(removeRestrictedRelations(auth), { schema, getModel })
2155
+ );
1594
2156
  }
1595
2157
  return pipe(...transforms)(sort2);
1596
2158
  };
@@ -1598,16 +2160,18 @@ const createContentAPISanitizers = () => {
1598
2160
  if (!schema) {
1599
2161
  throw new Error("Missing schema in sanitizeFields");
1600
2162
  }
1601
- const transforms = [defaultSanitizeFields(schema)];
2163
+ const transforms = [defaultSanitizeFields({ schema, getModel })];
1602
2164
  return pipe(...transforms)(fields2);
1603
2165
  };
1604
2166
  const sanitizePopulate = (populate2, schema, { auth } = {}) => {
1605
2167
  if (!schema) {
1606
2168
  throw new Error("Missing schema in sanitizePopulate");
1607
2169
  }
1608
- const transforms = [defaultSanitizePopulate(schema)];
2170
+ const transforms = [defaultSanitizePopulate({ schema, getModel })];
1609
2171
  if (auth) {
1610
- transforms.push(traverseQueryPopulate(removeRestrictedRelations(auth), { schema }));
2172
+ transforms.push(
2173
+ traverseQueryPopulate(removeRestrictedRelations(auth), { schema, getModel })
2174
+ );
1611
2175
  }
1612
2176
  return pipe(...transforms)(populate2);
1613
2177
  };
@@ -1621,126 +2185,22 @@ const createContentAPISanitizers = () => {
1621
2185
  populate: sanitizePopulate
1622
2186
  };
1623
2187
  };
1624
- const contentAPI$1 = createContentAPISanitizers();
1625
- const index$1 = {
1626
- contentAPI: contentAPI$1,
1627
- sanitizers,
1628
- visitors: visitors$1
1629
- };
1630
- const formatYupInnerError = (yupError) => ({
1631
- path: fp.toPath(yupError.path),
1632
- message: yupError.message,
1633
- name: yupError.name
1634
- });
1635
- const formatYupErrors = (yupError) => ({
1636
- errors: fp.isEmpty(yupError.inner) ? [formatYupInnerError(yupError)] : yupError.inner.map(formatYupInnerError),
1637
- message: yupError.message
1638
- });
1639
- class ApplicationError extends Error {
1640
- name;
1641
- details;
1642
- message;
1643
- constructor(message = "An application error occured", details = {}) {
1644
- super();
1645
- this.name = "ApplicationError";
1646
- this.message = message;
1647
- this.details = details;
1648
- }
1649
- }
1650
- class ValidationError extends ApplicationError {
1651
- constructor(message, details) {
1652
- super(message, details);
1653
- this.name = "ValidationError";
1654
- }
1655
- }
1656
- class YupValidationError extends ValidationError {
1657
- constructor(yupError, message) {
1658
- super("Validation");
1659
- const { errors: errors2, message: yupMessage } = formatYupErrors(yupError);
1660
- this.message = message || yupMessage;
1661
- this.details = { errors: errors2 };
1662
- }
1663
- }
1664
- class PaginationError extends ApplicationError {
1665
- constructor(message = "Invalid pagination", details) {
1666
- super(message, details);
1667
- this.name = "PaginationError";
1668
- this.message = message;
1669
- }
1670
- }
1671
- class NotFoundError extends ApplicationError {
1672
- constructor(message = "Entity not found", details) {
1673
- super(message, details);
1674
- this.name = "NotFoundError";
1675
- this.message = message;
1676
- }
1677
- }
1678
- class ForbiddenError extends ApplicationError {
1679
- constructor(message = "Forbidden access", details) {
1680
- super(message, details);
1681
- this.name = "ForbiddenError";
1682
- this.message = message;
1683
- }
1684
- }
1685
- class UnauthorizedError extends ApplicationError {
1686
- constructor(message = "Unauthorized", details) {
1687
- super(message, details);
1688
- this.name = "UnauthorizedError";
1689
- this.message = message;
1690
- }
1691
- }
1692
- class RateLimitError extends ApplicationError {
1693
- constructor(message = "Too many requests, please try again later.", details) {
1694
- super(message, details);
1695
- this.name = "RateLimitError";
1696
- this.message = message;
1697
- this.details = details || {};
1698
- }
1699
- }
1700
- class PayloadTooLargeError extends ApplicationError {
1701
- constructor(message = "Entity too large", details) {
1702
- super(message, details);
1703
- this.name = "PayloadTooLargeError";
1704
- this.message = message;
1705
- }
1706
- }
1707
- class PolicyError extends ForbiddenError {
1708
- constructor(message = "Policy Failed", details) {
1709
- super(message, details);
1710
- this.name = "PolicyError";
1711
- this.message = message;
1712
- this.details = details || {};
1713
- }
1714
- }
1715
- class NotImplementedError extends ApplicationError {
1716
- constructor(message = "This feature is not implemented yet", details) {
1717
- super(message, details);
1718
- this.name = "NotImplementedError";
1719
- this.message = message;
1720
- }
1721
- }
1722
- const errors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2188
+ const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1723
2189
  __proto__: null,
1724
- ApplicationError,
1725
- ForbiddenError,
1726
- HttpError: httpErrors.HttpError,
1727
- NotFoundError,
1728
- NotImplementedError,
1729
- PaginationError,
1730
- PayloadTooLargeError,
1731
- PolicyError,
1732
- RateLimitError,
1733
- UnauthorizedError,
1734
- ValidationError,
1735
- YupValidationError
2190
+ createAPISanitizers,
2191
+ sanitizers,
2192
+ visitors: index$4
1736
2193
  }, Symbol.toStringTag, { value: "Module" }));
1737
- const throwInvalidParam = ({ key, path }) => {
1738
- const msg = path && path !== key ? `Invalid parameter ${key} at ${path}` : `Invalid parameter ${key}`;
1739
- throw new ValidationError(msg);
2194
+ const throwInvalidKey = ({ key, path }) => {
2195
+ const msg = path && path !== key ? `Invalid key ${key} at ${path}` : `Invalid key ${key}`;
2196
+ throw new ValidationError(msg, {
2197
+ key,
2198
+ path
2199
+ });
1740
2200
  };
1741
2201
  const visitor$3 = ({ key, attribute, path }) => {
1742
2202
  if (attribute?.type === "password") {
1743
- throwInvalidParam({ key, path: path.attribute });
2203
+ throwInvalidKey({ key, path: path.attribute });
1744
2204
  }
1745
2205
  };
1746
2206
  const visitor$2 = ({ schema, key, attribute, path }) => {
@@ -1749,7 +2209,7 @@ const visitor$2 = ({ schema, key, attribute, path }) => {
1749
2209
  }
1750
2210
  const isPrivate = attribute.private === true || isPrivateAttribute(schema, key);
1751
2211
  if (isPrivate) {
1752
- throwInvalidParam({ key, path: path.attribute });
2212
+ throwInvalidKey({ key, path: path.attribute });
1753
2213
  }
1754
2214
  };
1755
2215
  const ACTIONS_TO_VERIFY = ["find"];
@@ -1767,7 +2227,7 @@ const throwRestrictedRelations = (auth) => async ({ data, key, attribute, schema
1767
2227
  const scopes = ACTIONS_TO_VERIFY.map((action) => `${element.__type}.${action}`);
1768
2228
  const isAllowed = await hasAccessToSomeScopes(scopes, auth);
1769
2229
  if (!isAllowed) {
1770
- throwInvalidParam({ key, path: path.attribute });
2230
+ throwInvalidKey({ key, path: path.attribute });
1771
2231
  }
1772
2232
  }
1773
2233
  };
@@ -1775,7 +2235,7 @@ const throwRestrictedRelations = (auth) => async ({ data, key, attribute, schema
1775
2235
  const scopes = ACTIONS_TO_VERIFY.map((action) => `${attribute.target}.${action}`);
1776
2236
  const isAllowed = await hasAccessToSomeScopes(scopes, auth);
1777
2237
  if (!isAllowed) {
1778
- throwInvalidParam({ key, path: path.attribute });
2238
+ throwInvalidKey({ key, path: path.attribute });
1779
2239
  }
1780
2240
  };
1781
2241
  const isCreatorRelation = [CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE].includes(key);
@@ -1801,12 +2261,12 @@ const hasAccessToSomeScopes = async (scopes, auth) => {
1801
2261
  };
1802
2262
  const visitor$1 = ({ key, attribute, path }) => {
1803
2263
  if (isMorphToRelationalAttribute(attribute)) {
1804
- throwInvalidParam({ key, path: path.attribute });
2264
+ throwInvalidKey({ key, path: path.attribute });
1805
2265
  }
1806
2266
  };
1807
2267
  const visitor = ({ key, attribute, path }) => {
1808
2268
  if (isDynamicZoneAttribute(attribute)) {
1809
- throwInvalidParam({ key, path: path.attribute });
2269
+ throwInvalidKey({ key, path: path.attribute });
1810
2270
  }
1811
2271
  };
1812
2272
  const throwDisallowedFields = (allowedFields = null) => ({ key, path: { attribute: path } }) => {
@@ -1828,7 +2288,7 @@ const throwDisallowedFields = (allowedFields = null) => ({ key, path: { attribut
1828
2288
  if (isPathAllowed) {
1829
2289
  return;
1830
2290
  }
1831
- throwInvalidParam({ key, path });
2291
+ throwInvalidKey({ key, path });
1832
2292
  };
1833
2293
  const getContainedPaths = (path) => {
1834
2294
  const parts = fp.toPath(path);
@@ -1838,7 +2298,7 @@ const getContainedPaths = (path) => {
1838
2298
  };
1839
2299
  const throwRestrictedFields = (restrictedFields = null) => ({ key, path: { attribute: path } }) => {
1840
2300
  if (restrictedFields === null) {
1841
- throwInvalidParam({ key, path });
2301
+ throwInvalidKey({ key, path });
1842
2302
  }
1843
2303
  if (!(fp.isArray(restrictedFields) && restrictedFields.every(fp.isString))) {
1844
2304
  throw new TypeError(
@@ -1846,16 +2306,46 @@ const throwRestrictedFields = (restrictedFields = null) => ({ key, path: { attri
1846
2306
  );
1847
2307
  }
1848
2308
  if (restrictedFields.includes(path)) {
1849
- throwInvalidParam({ key, path });
2309
+ throwInvalidKey({ key, path });
1850
2310
  }
1851
2311
  const isRestrictedNested = restrictedFields.some(
1852
2312
  (allowedPath) => path?.toString().startsWith(`${allowedPath}.`)
1853
2313
  );
1854
2314
  if (isRestrictedNested) {
1855
- throwInvalidParam({ key, path });
2315
+ throwInvalidKey({ key, path });
2316
+ }
2317
+ };
2318
+ const ID_FIELDS = [constants$1.DOC_ID_ATTRIBUTE, constants$1.DOC_ID_ATTRIBUTE];
2319
+ const ALLOWED_ROOT_LEVEL_FIELDS = [...ID_FIELDS];
2320
+ const MORPH_TO_ALLOWED_FIELDS = ["__type"];
2321
+ const DYNAMIC_ZONE_ALLOWED_FIELDS = ["__component"];
2322
+ const RELATION_REORDERING_FIELDS = ["connect", "disconnect", "set", "options"];
2323
+ const throwUnrecognizedFields = ({ key, attribute, path, schema, parent }) => {
2324
+ if (attribute) {
2325
+ return;
2326
+ }
2327
+ if (path.attribute === null) {
2328
+ if (ALLOWED_ROOT_LEVEL_FIELDS.includes(key)) {
2329
+ return;
2330
+ }
2331
+ return throwInvalidKey({ key, path: attribute });
2332
+ }
2333
+ if (isMorphToRelationalAttribute(parent?.attribute) && MORPH_TO_ALLOWED_FIELDS.includes(key)) {
2334
+ return;
2335
+ }
2336
+ if (isComponentSchema(schema) && isDynamicZoneAttribute(parent?.attribute) && DYNAMIC_ZONE_ALLOWED_FIELDS.includes(key)) {
2337
+ return;
2338
+ }
2339
+ if (hasRelationReordering(parent?.attribute) && RELATION_REORDERING_FIELDS.includes(key)) {
2340
+ return;
2341
+ }
2342
+ const canUseID = isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute);
2343
+ if (canUseID && !ID_FIELDS.includes(key)) {
2344
+ return;
1856
2345
  }
2346
+ throwInvalidKey({ key, path: attribute });
1857
2347
  };
1858
- const visitors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2348
+ const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1859
2349
  __proto__: null,
1860
2350
  throwDisallowedFields,
1861
2351
  throwDynamicZones: visitor,
@@ -1863,133 +2353,155 @@ const visitors = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
1863
2353
  throwPassword: visitor$3,
1864
2354
  throwPrivate: visitor$2,
1865
2355
  throwRestrictedFields,
1866
- throwRestrictedRelations
2356
+ throwRestrictedRelations,
2357
+ throwUnrecognizedFields
1867
2358
  }, Symbol.toStringTag, { value: "Module" }));
1868
- const { ID_ATTRIBUTE: ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$2 } = constants$1;
1869
- const throwPasswords = (schema) => async (entity) => {
1870
- if (!schema) {
2359
+ const { ID_ATTRIBUTE: ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$1 } = constants$1;
2360
+ const throwPasswords = (ctx) => async (entity) => {
2361
+ if (!ctx.schema) {
1871
2362
  throw new Error("Missing schema in throwPasswords");
1872
2363
  }
1873
- return traverseEntity$1(visitor$3, { schema }, entity);
2364
+ return traverseEntity$1(visitor$3, ctx, entity);
1874
2365
  };
1875
- const defaultValidateFilters = fp.curry((schema, filters2) => {
1876
- if (!schema) {
2366
+ const defaultValidateFilters = fp.curry((ctx, filters2) => {
2367
+ if (!ctx.schema) {
1877
2368
  throw new Error("Missing schema in defaultValidateFilters");
1878
2369
  }
1879
2370
  return pipe(
1880
2371
  // keys that are not attributes or valid operators
1881
- traverseQueryFilters(
1882
- ({ key, attribute, path }) => {
1883
- if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1884
- return;
1885
- }
1886
- const isAttribute = !!attribute;
1887
- if (!isAttribute && !isOperator(key)) {
1888
- throwInvalidParam({ key, path: path.attribute });
1889
- }
1890
- },
1891
- { schema }
1892
- ),
2372
+ traverseQueryFilters(({ key, attribute, path }) => {
2373
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2374
+ return;
2375
+ }
2376
+ const isAttribute = !!attribute;
2377
+ if (!isAttribute && !isOperator(key)) {
2378
+ throwInvalidKey({ key, path: path.attribute });
2379
+ }
2380
+ }, ctx),
1893
2381
  // dynamic zones from filters
1894
- traverseQueryFilters(visitor, { schema }),
2382
+ traverseQueryFilters(visitor, ctx),
1895
2383
  // morphTo relations from filters; because you can't have deep filtering on morph relations
1896
- traverseQueryFilters(visitor$1, { schema }),
2384
+ traverseQueryFilters(visitor$1, ctx),
1897
2385
  // passwords from filters
1898
- traverseQueryFilters(visitor$3, { schema }),
2386
+ traverseQueryFilters(visitor$3, ctx),
1899
2387
  // private from filters
1900
- traverseQueryFilters(visitor$2, { schema })
2388
+ traverseQueryFilters(visitor$2, ctx)
1901
2389
  // we allow empty objects to validate and only sanitize them out, so that users may write "lazy" queries without checking their params exist
1902
2390
  )(filters2);
1903
2391
  });
1904
- const defaultValidateSort = fp.curry((schema, sort2) => {
1905
- if (!schema) {
2392
+ const defaultValidateSort = fp.curry((ctx, sort2) => {
2393
+ if (!ctx.schema) {
1906
2394
  throw new Error("Missing schema in defaultValidateSort");
1907
2395
  }
1908
2396
  return pipe(
1909
2397
  // non attribute keys
1910
- traverseQuerySort(
1911
- ({ key, attribute, path }) => {
1912
- if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1913
- return;
1914
- }
1915
- if (!attribute) {
1916
- throwInvalidParam({ key, path: path.attribute });
1917
- }
1918
- },
1919
- { schema }
1920
- ),
2398
+ traverseQuerySort(({ key, attribute, path }) => {
2399
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2400
+ return;
2401
+ }
2402
+ if (!attribute) {
2403
+ throwInvalidKey({ key, path: path.attribute });
2404
+ }
2405
+ }, ctx),
1921
2406
  // dynamic zones from sort
1922
- traverseQuerySort(visitor, { schema }),
2407
+ traverseQuerySort(visitor, ctx),
1923
2408
  // morphTo relations from sort
1924
- traverseQuerySort(visitor$1, { schema }),
2409
+ traverseQuerySort(visitor$1, ctx),
1925
2410
  // private from sort
1926
- traverseQuerySort(visitor$2, { schema }),
2411
+ traverseQuerySort(visitor$2, ctx),
1927
2412
  // passwords from filters
1928
- traverseQuerySort(visitor$3, { schema }),
2413
+ traverseQuerySort(visitor$3, ctx),
1929
2414
  // keys for empty non-scalar values
1930
- traverseQuerySort(
1931
- ({ key, attribute, value, path }) => {
1932
- if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1933
- return;
1934
- }
1935
- if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
1936
- throwInvalidParam({ key, path: path.attribute });
1937
- }
1938
- },
1939
- { schema }
1940
- )
2415
+ traverseQuerySort(({ key, attribute, value, path }) => {
2416
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2417
+ return;
2418
+ }
2419
+ if (!isScalarAttribute(attribute) && fp.isEmpty(value)) {
2420
+ throwInvalidKey({ key, path: path.attribute });
2421
+ }
2422
+ }, ctx)
1941
2423
  )(sort2);
1942
2424
  });
1943
- const defaultValidateFields = fp.curry((schema, fields2) => {
1944
- if (!schema) {
2425
+ const defaultValidateFields = fp.curry((ctx, fields2) => {
2426
+ if (!ctx.schema) {
1945
2427
  throw new Error("Missing schema in defaultValidateFields");
1946
2428
  }
1947
2429
  return pipe(
1948
2430
  // Only allow scalar attributes
1949
- traverseQueryFields(
1950
- ({ key, attribute, path }) => {
1951
- if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
1952
- return;
1953
- }
1954
- if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
1955
- throwInvalidParam({ key, path: path.attribute });
1956
- }
1957
- },
1958
- { schema }
1959
- ),
2431
+ traverseQueryFields(({ key, attribute, path }) => {
2432
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2433
+ return;
2434
+ }
2435
+ if (fp.isNil(attribute) || !isScalarAttribute(attribute)) {
2436
+ throwInvalidKey({ key, path: path.attribute });
2437
+ }
2438
+ }, ctx),
1960
2439
  // private fields
1961
- traverseQueryFields(visitor$2, { schema }),
2440
+ traverseQueryFields(visitor$2, ctx),
1962
2441
  // password fields
1963
- traverseQueryFields(visitor$3, { schema })
2442
+ traverseQueryFields(visitor$3, ctx)
1964
2443
  )(fields2);
1965
2444
  });
1966
- const defaultValidatePopulate = fp.curry((schema, populate2) => {
1967
- if (!schema) {
2445
+ const defaultValidatePopulate = fp.curry((ctx, populate2) => {
2446
+ if (!ctx.schema) {
1968
2447
  throw new Error("Missing schema in defaultValidatePopulate");
1969
2448
  }
1970
2449
  return pipe(
1971
- traverseQueryPopulate(
1972
- async ({ key, value, schema: schema2, attribute }, { set }) => {
1973
- if (attribute) {
1974
- return;
1975
- }
1976
- if (key === "sort") {
1977
- set(key, await defaultValidateSort(schema2, value));
1978
- }
1979
- if (key === "filters") {
1980
- set(key, await defaultValidateFilters(schema2, value));
1981
- }
1982
- if (key === "fields") {
1983
- set(key, await defaultValidateFields(schema2, value));
1984
- }
1985
- if (key === "populate") {
1986
- set(key, await defaultValidatePopulate(schema2, value));
1987
- }
1988
- },
1989
- { schema }
1990
- ),
2450
+ traverseQueryPopulate(async ({ key, value, schema, attribute, getModel }, { set }) => {
2451
+ if (attribute) {
2452
+ return;
2453
+ }
2454
+ if (key === "sort") {
2455
+ set(
2456
+ key,
2457
+ await defaultValidateSort(
2458
+ {
2459
+ schema,
2460
+ getModel
2461
+ },
2462
+ value
2463
+ )
2464
+ );
2465
+ }
2466
+ if (key === "filters") {
2467
+ set(
2468
+ key,
2469
+ await defaultValidateFilters(
2470
+ {
2471
+ schema,
2472
+ getModel
2473
+ },
2474
+ value
2475
+ )
2476
+ );
2477
+ }
2478
+ if (key === "fields") {
2479
+ set(
2480
+ key,
2481
+ await defaultValidateFields(
2482
+ {
2483
+ schema,
2484
+ getModel
2485
+ },
2486
+ value
2487
+ )
2488
+ );
2489
+ }
2490
+ if (key === "populate") {
2491
+ set(
2492
+ key,
2493
+ await defaultValidatePopulate(
2494
+ {
2495
+ schema,
2496
+ getModel
2497
+ },
2498
+ value
2499
+ )
2500
+ );
2501
+ }
2502
+ }, ctx),
1991
2503
  // Remove private fields
1992
- traverseQueryPopulate(visitor$2, { schema })
2504
+ traverseQueryPopulate(visitor$2, ctx)
1993
2505
  )(populate2);
1994
2506
  });
1995
2507
  const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -2000,8 +2512,9 @@ const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
2000
2512
  defaultValidateSort,
2001
2513
  throwPasswords
2002
2514
  }, Symbol.toStringTag, { value: "Module" }));
2003
- const { ID_ATTRIBUTE: ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE: DOC_ID_ATTRIBUTE$1 } = constants$1;
2004
- const createContentAPIValidators = () => {
2515
+ const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants$1;
2516
+ const createAPIValidators = (opts) => {
2517
+ const { getModel } = opts || {};
2005
2518
  const validateInput = async (data, schema, { auth } = {}) => {
2006
2519
  if (!schema) {
2007
2520
  throw new Error("Missing schema in validateInput");
@@ -2014,22 +2527,37 @@ const createContentAPIValidators = () => {
2014
2527
  const transforms = [
2015
2528
  (data2) => {
2016
2529
  if (fp.isObject(data2)) {
2017
- if (ID_ATTRIBUTE$1 in data2) {
2018
- throwInvalidParam({ key: ID_ATTRIBUTE$1 });
2530
+ if (ID_ATTRIBUTE in data2) {
2531
+ throwInvalidKey({ key: ID_ATTRIBUTE });
2019
2532
  }
2020
- if (DOC_ID_ATTRIBUTE$1 in data2) {
2021
- throwInvalidParam({ key: DOC_ID_ATTRIBUTE$1 });
2533
+ if (DOC_ID_ATTRIBUTE in data2) {
2534
+ throwInvalidKey({ key: DOC_ID_ATTRIBUTE });
2022
2535
  }
2023
2536
  }
2537
+ return data2;
2024
2538
  },
2025
2539
  // non-writable attributes
2026
- traverseEntity$1(throwRestrictedFields(nonWritableAttributes), { schema })
2540
+ traverseEntity$1(throwRestrictedFields(nonWritableAttributes), { schema, getModel }),
2541
+ // unrecognized attributes
2542
+ traverseEntity$1(throwUnrecognizedFields, { schema, getModel })
2027
2543
  ];
2028
2544
  if (auth) {
2029
- transforms.push(traverseEntity$1(throwRestrictedRelations(auth), { schema }));
2545
+ transforms.push(
2546
+ traverseEntity$1(throwRestrictedRelations(auth), {
2547
+ schema,
2548
+ getModel
2549
+ })
2550
+ );
2551
+ }
2552
+ opts?.validators?.input?.forEach((validator) => transforms.push(validator(schema)));
2553
+ try {
2554
+ await pipe(...transforms)(data);
2555
+ } catch (e) {
2556
+ if (e instanceof ValidationError) {
2557
+ e.details.source = "body";
2558
+ }
2559
+ throw e;
2030
2560
  }
2031
- strapi.validators.get("content-api.input").forEach((validator) => transforms.push(validator(schema)));
2032
- await pipe(...transforms)(data);
2033
2561
  };
2034
2562
  const validateQuery = async (query, schema, { auth } = {}) => {
2035
2563
  if (!schema) {
@@ -2057,38 +2585,85 @@ const createContentAPIValidators = () => {
2057
2585
  await Promise.all(filters2.map((filter) => validateFilters(filter, schema, { auth })));
2058
2586
  return;
2059
2587
  }
2060
- const transforms = [defaultValidateFilters(schema)];
2588
+ const transforms = [defaultValidateFilters({ schema, getModel })];
2061
2589
  if (auth) {
2062
- transforms.push(traverseQueryFilters(throwRestrictedRelations(auth), { schema }));
2590
+ transforms.push(
2591
+ traverseQueryFilters(throwRestrictedRelations(auth), {
2592
+ schema,
2593
+ getModel
2594
+ })
2595
+ );
2596
+ }
2597
+ try {
2598
+ await pipe(...transforms)(filters2);
2599
+ } catch (e) {
2600
+ if (e instanceof ValidationError) {
2601
+ e.details.source = "query";
2602
+ e.details.param = "filters";
2603
+ }
2604
+ throw e;
2063
2605
  }
2064
- await pipe(...transforms)(filters2);
2065
2606
  };
2066
2607
  const validateSort = async (sort2, schema, { auth } = {}) => {
2067
2608
  if (!schema) {
2068
2609
  throw new Error("Missing schema in validateSort");
2069
2610
  }
2070
- const transforms = [defaultValidateSort(schema)];
2611
+ const transforms = [defaultValidateSort({ schema, getModel })];
2071
2612
  if (auth) {
2072
- transforms.push(traverseQuerySort(throwRestrictedRelations(auth), { schema }));
2613
+ transforms.push(
2614
+ traverseQuerySort(throwRestrictedRelations(auth), {
2615
+ schema,
2616
+ getModel
2617
+ })
2618
+ );
2619
+ }
2620
+ try {
2621
+ await pipe(...transforms)(sort2);
2622
+ } catch (e) {
2623
+ if (e instanceof ValidationError) {
2624
+ e.details.source = "query";
2625
+ e.details.param = "sort";
2626
+ }
2627
+ throw e;
2073
2628
  }
2074
- await pipe(...transforms)(sort2);
2075
2629
  };
2076
2630
  const validateFields = async (fields2, schema) => {
2077
2631
  if (!schema) {
2078
2632
  throw new Error("Missing schema in validateFields");
2079
2633
  }
2080
- const transforms = [defaultValidateFields(schema)];
2081
- await pipe(...transforms)(fields2);
2634
+ const transforms = [defaultValidateFields({ schema, getModel })];
2635
+ try {
2636
+ await pipe(...transforms)(fields2);
2637
+ } catch (e) {
2638
+ if (e instanceof ValidationError) {
2639
+ e.details.source = "query";
2640
+ e.details.param = "fields";
2641
+ }
2642
+ throw e;
2643
+ }
2082
2644
  };
2083
2645
  const validatePopulate = async (populate2, schema, { auth } = {}) => {
2084
2646
  if (!schema) {
2085
2647
  throw new Error("Missing schema in sanitizePopulate");
2086
2648
  }
2087
- const transforms = [defaultValidatePopulate(schema)];
2649
+ const transforms = [defaultValidatePopulate({ schema, getModel })];
2088
2650
  if (auth) {
2089
- transforms.push(traverseQueryPopulate(throwRestrictedRelations(auth), { schema }));
2651
+ transforms.push(
2652
+ traverseQueryPopulate(throwRestrictedRelations(auth), {
2653
+ schema,
2654
+ getModel
2655
+ })
2656
+ );
2657
+ }
2658
+ try {
2659
+ await pipe(...transforms)(populate2);
2660
+ } catch (e) {
2661
+ if (e instanceof ValidationError) {
2662
+ e.details.source = "query";
2663
+ e.details.param = "populate";
2664
+ }
2665
+ throw e;
2090
2666
  }
2091
- await pipe(...transforms)(populate2);
2092
2667
  };
2093
2668
  return {
2094
2669
  input: validateInput,
@@ -2099,436 +2674,12 @@ const createContentAPIValidators = () => {
2099
2674
  populate: validatePopulate
2100
2675
  };
2101
2676
  };
2102
- const contentAPI = createContentAPIValidators();
2103
- const index = {
2104
- contentAPI,
2677
+ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2678
+ __proto__: null,
2679
+ createAPIValidators,
2105
2680
  validators,
2106
- visitors
2107
- };
2108
- const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE, PUBLISHED_AT_ATTRIBUTE } = constants$1;
2109
- class InvalidOrderError extends Error {
2110
- constructor() {
2111
- super();
2112
- this.message = "Invalid order. order can only be one of asc|desc|ASC|DESC";
2113
- }
2114
- }
2115
- class InvalidSortError extends Error {
2116
- constructor() {
2117
- super();
2118
- this.message = "Invalid sort parameter. Expected a string, an array of strings, a sort object or an array of sort objects";
2119
- }
2120
- }
2121
- function validateOrder(order) {
2122
- if (!fp.isString(order) || !["asc", "desc"].includes(order.toLocaleLowerCase())) {
2123
- throw new InvalidOrderError();
2124
- }
2125
- }
2126
- const convertCountQueryParams = (countQuery) => {
2127
- return parseType({ type: "boolean", value: countQuery });
2128
- };
2129
- const convertOrderingQueryParams = (ordering) => {
2130
- return ordering;
2131
- };
2132
- const isPlainObject = (value) => ___default.default.isPlainObject(value);
2133
- const isStringArray = (value) => fp.isArray(value) && value.every(fp.isString);
2134
- const convertSortQueryParams = (sortQuery) => {
2135
- if (typeof sortQuery === "string") {
2136
- return convertStringSortQueryParam(sortQuery);
2137
- }
2138
- if (isStringArray(sortQuery)) {
2139
- return sortQuery.flatMap((sortValue) => convertStringSortQueryParam(sortValue));
2140
- }
2141
- if (Array.isArray(sortQuery)) {
2142
- return sortQuery.map((sortValue) => convertNestedSortQueryParam(sortValue));
2143
- }
2144
- if (isPlainObject(sortQuery)) {
2145
- return convertNestedSortQueryParam(sortQuery);
2146
- }
2147
- throw new InvalidSortError();
2148
- };
2149
- const convertStringSortQueryParam = (sortQuery) => {
2150
- return sortQuery.split(",").map((value) => convertSingleSortQueryParam(value));
2151
- };
2152
- const convertSingleSortQueryParam = (sortQuery) => {
2153
- if (!sortQuery) {
2154
- return {};
2155
- }
2156
- if (!fp.isString(sortQuery)) {
2157
- throw new Error("Invalid sort query");
2158
- }
2159
- const [field, order = "asc"] = sortQuery.split(":");
2160
- if (field.length === 0) {
2161
- throw new Error("Field cannot be empty");
2162
- }
2163
- validateOrder(order);
2164
- return ___default.default.set({}, field, order);
2165
- };
2166
- const convertNestedSortQueryParam = (sortQuery) => {
2167
- const transformedSort = {};
2168
- for (const field of Object.keys(sortQuery)) {
2169
- const order = sortQuery[field];
2170
- if (isPlainObject(order)) {
2171
- transformedSort[field] = convertNestedSortQueryParam(order);
2172
- } else if (typeof order === "string") {
2173
- validateOrder(order);
2174
- transformedSort[field] = order;
2175
- } else {
2176
- throw Error(`Invalid sort type expected object or string got ${typeof order}`);
2177
- }
2178
- }
2179
- return transformedSort;
2180
- };
2181
- const convertStartQueryParams = (startQuery) => {
2182
- const startAsANumber = ___default.default.toNumber(startQuery);
2183
- if (!___default.default.isInteger(startAsANumber) || startAsANumber < 0) {
2184
- throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
2185
- }
2186
- return startAsANumber;
2187
- };
2188
- const convertLimitQueryParams = (limitQuery) => {
2189
- const limitAsANumber = ___default.default.toNumber(limitQuery);
2190
- if (!___default.default.isInteger(limitAsANumber) || limitAsANumber !== -1 && limitAsANumber < 0) {
2191
- throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
2192
- }
2193
- if (limitAsANumber === -1) {
2194
- return void 0;
2195
- }
2196
- return limitAsANumber;
2197
- };
2198
- const convertPageQueryParams = (page) => {
2199
- const pageVal = fp.toNumber(page);
2200
- if (!fp.isInteger(pageVal) || pageVal <= 0) {
2201
- throw new PaginationError(
2202
- `Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
2203
- );
2204
- }
2205
- return pageVal;
2206
- };
2207
- const convertPageSizeQueryParams = (pageSize, page) => {
2208
- const pageSizeVal = fp.toNumber(pageSize);
2209
- if (!fp.isInteger(pageSizeVal) || pageSizeVal <= 0) {
2210
- throw new PaginationError(
2211
- `Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
2212
- );
2213
- }
2214
- return pageSizeVal;
2215
- };
2216
- const validatePaginationParams = (page, pageSize, start, limit) => {
2217
- const isPagePagination = !fp.isNil(page) || !fp.isNil(pageSize);
2218
- const isOffsetPagination = !fp.isNil(start) || !fp.isNil(limit);
2219
- if (isPagePagination && isOffsetPagination) {
2220
- throw new PaginationError(
2221
- "Invalid pagination attributes. You cannot use page and offset pagination in the same query"
2222
- );
2223
- }
2224
- };
2225
- class InvalidPopulateError extends Error {
2226
- constructor() {
2227
- super();
2228
- this.message = "Invalid populate parameter. Expected a string, an array of strings, a populate object";
2229
- }
2230
- }
2231
- const convertPopulateQueryParams = (populate2, schema, depth = 0) => {
2232
- if (depth === 0 && populate2 === "*") {
2233
- return true;
2234
- }
2235
- if (typeof populate2 === "string") {
2236
- return populate2.split(",").map((value) => ___default.default.trim(value));
2237
- }
2238
- if (Array.isArray(populate2)) {
2239
- return ___default.default.uniq(
2240
- populate2.flatMap((value) => {
2241
- if (typeof value !== "string") {
2242
- throw new InvalidPopulateError();
2243
- }
2244
- return value.split(",").map((value2) => ___default.default.trim(value2));
2245
- })
2246
- );
2247
- }
2248
- if (___default.default.isPlainObject(populate2)) {
2249
- return convertPopulateObject(populate2, schema);
2250
- }
2251
- throw new InvalidPopulateError();
2252
- };
2253
- const hasFragmentPopulateDefined = (populate2) => {
2254
- return typeof populate2 === "object" && "on" in populate2 && !fp.isNil(populate2.on);
2255
- };
2256
- const convertPopulateObject = (populate2, schema) => {
2257
- if (!schema) {
2258
- return {};
2259
- }
2260
- const { attributes } = schema;
2261
- return Object.entries(populate2).reduce((acc, [key, subPopulate]) => {
2262
- if (___default.default.isBoolean(subPopulate)) {
2263
- return { ...acc, [key]: subPopulate };
2264
- }
2265
- const attribute = attributes[key];
2266
- if (!attribute) {
2267
- return acc;
2268
- }
2269
- const isAllowedAttributeForFragmentPopulate = isDynamicZoneAttribute(attribute) || isMorphToRelationalAttribute(attribute);
2270
- if (isAllowedAttributeForFragmentPopulate && hasFragmentPopulateDefined(subPopulate)) {
2271
- return {
2272
- ...acc,
2273
- [key]: {
2274
- on: Object.entries(subPopulate.on).reduce(
2275
- (acc2, [type, typeSubPopulate]) => ({
2276
- ...acc2,
2277
- [type]: convertNestedPopulate(typeSubPopulate, strapi.getModel(type))
2278
- }),
2279
- {}
2280
- )
2281
- }
2282
- };
2283
- }
2284
- if (isDynamicZoneAttribute(attribute)) {
2285
- const populates = attribute.components.map((uid) => strapi.getModel(uid)).map((schema2) => convertNestedPopulate(subPopulate, schema2)).map((populate22) => populate22 === true ? {} : populate22).filter((populate22) => populate22 !== false);
2286
- if (fp.isEmpty(populates)) {
2287
- return acc;
2288
- }
2289
- return {
2290
- ...acc,
2291
- [key]: fp.mergeAll(populates)
2292
- };
2293
- }
2294
- if (isMorphToRelationalAttribute(attribute)) {
2295
- return { ...acc, [key]: convertNestedPopulate(subPopulate, void 0) };
2296
- }
2297
- let targetSchemaUID;
2298
- if (attribute.type === "relation") {
2299
- targetSchemaUID = attribute.target;
2300
- } else if (attribute.type === "component") {
2301
- targetSchemaUID = attribute.component;
2302
- } else if (attribute.type === "media") {
2303
- targetSchemaUID = "plugin::upload.file";
2304
- } else {
2305
- return acc;
2306
- }
2307
- const targetSchema = strapi.getModel(targetSchemaUID);
2308
- if (!targetSchema) {
2309
- return acc;
2310
- }
2311
- const populateObject = convertNestedPopulate(subPopulate, targetSchema);
2312
- if (!populateObject) {
2313
- return acc;
2314
- }
2315
- return {
2316
- ...acc,
2317
- [key]: populateObject
2318
- };
2319
- }, {});
2320
- };
2321
- const convertNestedPopulate = (subPopulate, schema) => {
2322
- if (___default.default.isString(subPopulate)) {
2323
- return parseType({ type: "boolean", value: subPopulate, forceCast: true });
2324
- }
2325
- if (___default.default.isBoolean(subPopulate)) {
2326
- return subPopulate;
2327
- }
2328
- if (!isPlainObject(subPopulate)) {
2329
- throw new Error(`Invalid nested populate. Expected '*' or an object`);
2330
- }
2331
- const { sort: sort2, filters: filters2, fields: fields2, populate: populate2, count, ordering, page, pageSize, start, limit } = subPopulate;
2332
- const query = {};
2333
- if (sort2) {
2334
- query.orderBy = convertSortQueryParams(sort2);
2335
- }
2336
- if (filters2) {
2337
- query.where = convertFiltersQueryParams(filters2, schema);
2338
- }
2339
- if (fields2) {
2340
- query.select = convertFieldsQueryParams(fields2);
2341
- }
2342
- if (populate2) {
2343
- query.populate = convertPopulateQueryParams(populate2, schema);
2344
- }
2345
- if (count) {
2346
- query.count = convertCountQueryParams(count);
2347
- }
2348
- if (ordering) {
2349
- query.ordering = convertOrderingQueryParams(ordering);
2350
- }
2351
- validatePaginationParams(page, pageSize, start, limit);
2352
- if (!fp.isNil(page)) {
2353
- query.page = convertPageQueryParams(page);
2354
- }
2355
- if (!fp.isNil(pageSize)) {
2356
- query.pageSize = convertPageSizeQueryParams(pageSize, page);
2357
- }
2358
- if (!fp.isNil(start)) {
2359
- query.offset = convertStartQueryParams(start);
2360
- }
2361
- if (!fp.isNil(limit)) {
2362
- query.limit = convertLimitQueryParams(limit);
2363
- }
2364
- return query;
2365
- };
2366
- const convertFieldsQueryParams = (fields2, depth = 0) => {
2367
- if (depth === 0 && fields2 === "*") {
2368
- return void 0;
2369
- }
2370
- if (typeof fields2 === "string") {
2371
- const fieldsValues = fields2.split(",").map((value) => ___default.default.trim(value));
2372
- return ___default.default.uniq([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE, ...fieldsValues]);
2373
- }
2374
- if (isStringArray(fields2)) {
2375
- const fieldsValues = fields2.flatMap((value) => convertFieldsQueryParams(value, depth + 1)).filter((v) => !fp.isNil(v));
2376
- return ___default.default.uniq([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE, ...fieldsValues]);
2377
- }
2378
- throw new Error("Invalid fields parameter. Expected a string or an array of strings");
2379
- };
2380
- const isValidSchemaAttribute = (key, schema) => {
2381
- if ([DOC_ID_ATTRIBUTE, ID_ATTRIBUTE].includes(key)) {
2382
- return true;
2383
- }
2384
- if (!schema) {
2385
- return false;
2386
- }
2387
- return Object.keys(schema.attributes).includes(key);
2388
- };
2389
- const convertFiltersQueryParams = (filters2, schema) => {
2390
- if (!fp.isObject(filters2)) {
2391
- throw new Error("The filters parameter must be an object or an array");
2392
- }
2393
- const filtersCopy = fp.cloneDeep(filters2);
2394
- return convertAndSanitizeFilters(filtersCopy, schema);
2395
- };
2396
- const convertAndSanitizeFilters = (filters2, schema) => {
2397
- if (Array.isArray(filters2)) {
2398
- return filters2.map((filter) => convertAndSanitizeFilters(filter, schema)).filter((filter) => !isPlainObject(filter) || !fp.isEmpty(filter));
2399
- }
2400
- if (!isPlainObject(filters2)) {
2401
- return filters2;
2402
- }
2403
- const removeOperator = (operator) => delete filters2[operator];
2404
- for (const [key, value] of Object.entries(filters2)) {
2405
- const attribute = fp.get(key, schema?.attributes);
2406
- const validKey = isOperator(key) || isValidSchemaAttribute(key, schema);
2407
- if (!validKey) {
2408
- removeOperator(key);
2409
- } else if (attribute) {
2410
- if (attribute.type === "relation") {
2411
- filters2[key] = convertAndSanitizeFilters(value, strapi.getModel(attribute.target));
2412
- } else if (attribute.type === "component") {
2413
- filters2[key] = convertAndSanitizeFilters(value, strapi.getModel(attribute.component));
2414
- } else if (attribute.type === "media") {
2415
- filters2[key] = convertAndSanitizeFilters(value, strapi.getModel("plugin::upload.file"));
2416
- } else if (attribute.type === "dynamiczone") {
2417
- removeOperator(key);
2418
- } else if (attribute.type === "password") {
2419
- removeOperator(key);
2420
- } else {
2421
- filters2[key] = convertAndSanitizeFilters(value, schema);
2422
- }
2423
- } else if (["$null", "$notNull"].includes(key)) {
2424
- filters2[key] = parseType({ type: "boolean", value: filters2[key], forceCast: true });
2425
- } else if (fp.isObject(value)) {
2426
- filters2[key] = convertAndSanitizeFilters(value, schema);
2427
- }
2428
- if (isPlainObject(filters2[key]) && fp.isEmpty(filters2[key])) {
2429
- removeOperator(key);
2430
- }
2431
- }
2432
- return filters2;
2433
- };
2434
- const convertStatusParams = (status, query = {}) => {
2435
- query.filters = ({ meta }) => {
2436
- const contentType = strapi.contentTypes[meta.uid];
2437
- if (!contentType || !hasDraftAndPublish(contentType)) {
2438
- return {};
2439
- }
2440
- return { [PUBLISHED_AT_ATTRIBUTE]: { $null: status === "draft" } };
2441
- };
2442
- };
2443
- const transformParamsToQuery = (uid, params) => {
2444
- const schema = strapi.getModel(uid);
2445
- const query = {};
2446
- const { _q, sort: sort2, filters: filters2, fields: fields2, populate: populate2, page, pageSize, start, limit, status, ...rest } = params;
2447
- if (!fp.isNil(status)) {
2448
- convertStatusParams(status, query);
2449
- }
2450
- if (!fp.isNil(_q)) {
2451
- query._q = _q;
2452
- }
2453
- if (!fp.isNil(sort2)) {
2454
- query.orderBy = convertSortQueryParams(sort2);
2455
- }
2456
- if (!fp.isNil(filters2)) {
2457
- query.where = convertFiltersQueryParams(filters2, schema);
2458
- }
2459
- if (!fp.isNil(fields2)) {
2460
- query.select = convertFieldsQueryParams(fields2);
2461
- }
2462
- if (!fp.isNil(populate2)) {
2463
- query.populate = convertPopulateQueryParams(populate2, schema);
2464
- }
2465
- validatePaginationParams(page, pageSize, start, limit);
2466
- if (!fp.isNil(page)) {
2467
- query.page = convertPageQueryParams(page);
2468
- }
2469
- if (!fp.isNil(pageSize)) {
2470
- query.pageSize = convertPageSizeQueryParams(pageSize, page);
2471
- }
2472
- if (!fp.isNil(start)) {
2473
- query.offset = convertStartQueryParams(start);
2474
- }
2475
- if (!fp.isNil(limit)) {
2476
- query.limit = convertLimitQueryParams(limit);
2477
- }
2478
- return {
2479
- ...rest,
2480
- ...query
2481
- };
2482
- };
2483
- const convertQueryParams = {
2484
- convertSortQueryParams,
2485
- convertStartQueryParams,
2486
- convertLimitQueryParams,
2487
- convertPopulateQueryParams,
2488
- convertFiltersQueryParams,
2489
- convertFieldsQueryParams,
2490
- transformParamsToQuery
2491
- };
2492
- function importDefault(modName) {
2493
- const mod = require(modName);
2494
- return mod && mod.__esModule ? mod.default : mod;
2495
- }
2496
- const machineId = () => {
2497
- try {
2498
- const deviceId = nodeMachineId.machineIdSync();
2499
- return deviceId;
2500
- } catch (error) {
2501
- const deviceId = crypto.randomUUID();
2502
- return deviceId;
2503
- }
2504
- };
2505
- const handleYupError = (error, errorMessage) => {
2506
- throw new YupValidationError(error, errorMessage);
2507
- };
2508
- const defaultValidationParam = { strict: true, abortEarly: false };
2509
- const validateYupSchema = (schema, options = {}) => async (body, errorMessage) => {
2510
- try {
2511
- const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
2512
- const result = await schema.validate(body, optionsWithDefaults);
2513
- return result;
2514
- } catch (e) {
2515
- if (e instanceof yup__namespace.ValidationError) {
2516
- handleYupError(e, errorMessage);
2517
- }
2518
- throw e;
2519
- }
2520
- };
2521
- const validateYupSchemaSync = (schema, options = {}) => (body, errorMessage) => {
2522
- try {
2523
- const optionsWithDefaults = fp.defaults(defaultValidationParam, options);
2524
- return schema.validateSync(body, optionsWithDefaults);
2525
- } catch (e) {
2526
- if (e instanceof yup__namespace.ValidationError) {
2527
- handleYupError(e, errorMessage);
2528
- }
2529
- throw e;
2530
- }
2531
- };
2681
+ visitors: index$1
2682
+ }, Symbol.toStringTag, { value: "Module" }));
2532
2683
  const STRAPI_DEFAULTS = {
2533
2684
  offset: {
2534
2685
  start: 0,
@@ -2596,8 +2747,57 @@ const withDefaultPagination = (args, { defaults = {}, maxLimit = -1 } = {}) => {
2596
2747
  );
2597
2748
  return replacePaginationAttributes(args);
2598
2749
  };
2750
+ const transformPagedPaginationInfo = (paginationInfo, total) => {
2751
+ if (!fp.isNil(paginationInfo.page)) {
2752
+ const page = paginationInfo.page;
2753
+ const pageSize = paginationInfo.pageSize ?? total;
2754
+ return {
2755
+ page,
2756
+ pageSize,
2757
+ pageCount: pageSize > 0 ? Math.ceil(total / pageSize) : 0,
2758
+ total
2759
+ };
2760
+ }
2761
+ if (!fp.isNil(paginationInfo.start)) {
2762
+ const start = paginationInfo.start;
2763
+ const limit = paginationInfo.limit ?? total;
2764
+ return {
2765
+ page: Math.floor(start / limit) + 1,
2766
+ pageSize: limit,
2767
+ pageCount: limit > 0 ? Math.ceil(total / limit) : 0,
2768
+ total
2769
+ };
2770
+ }
2771
+ return {
2772
+ ...paginationInfo,
2773
+ page: 1,
2774
+ pageSize: 10,
2775
+ pageCount: 1,
2776
+ total
2777
+ };
2778
+ };
2779
+ const transformOffsetPaginationInfo = (paginationInfo, total) => {
2780
+ if (!fp.isNil(paginationInfo.page)) {
2781
+ const limit = paginationInfo.pageSize ?? total;
2782
+ const start = (paginationInfo.page - 1) * limit;
2783
+ return { start, limit, total };
2784
+ }
2785
+ if (!fp.isNil(paginationInfo.start)) {
2786
+ const start = paginationInfo.start;
2787
+ const limit = paginationInfo.limit ?? total;
2788
+ return { start, limit, total };
2789
+ }
2790
+ return {
2791
+ ...paginationInfo,
2792
+ start: 0,
2793
+ limit: 10,
2794
+ total
2795
+ };
2796
+ };
2599
2797
  const pagination = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2600
2798
  __proto__: null,
2799
+ transformOffsetPaginationInfo,
2800
+ transformPagedPaginationInfo,
2601
2801
  withDefaultPagination
2602
2802
  }, Symbol.toStringTag, { value: "Module" }));
2603
2803
  const SUPPORTED_PACKAGE_MANAGERS = ["npm", "yarn"];
@@ -2680,72 +2880,6 @@ const file = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
2680
2880
  streamToBuffer,
2681
2881
  writableDiscardStream
2682
2882
  }, Symbol.toStringTag, { value: "Module" }));
2683
- const PLUGIN_PREFIX = "plugin::";
2684
- const API_PREFIX = "api::";
2685
- const parsePolicy = (policy2) => {
2686
- if (typeof policy2 === "string") {
2687
- return { policyName: policy2, config: {} };
2688
- }
2689
- const { name, config } = policy2;
2690
- return { policyName: name, config };
2691
- };
2692
- const searchLocalPolicy = (policyName, policyContext) => {
2693
- const { pluginName, apiName } = policyContext ?? {};
2694
- if (pluginName) {
2695
- return strapi.policy(`${PLUGIN_PREFIX}${pluginName}.${policyName}`);
2696
- }
2697
- if (apiName) {
2698
- return strapi.policy(`${API_PREFIX}${apiName}.${policyName}`);
2699
- }
2700
- };
2701
- const globalPolicy = ({ method, endpoint, controller, action, plugin }) => {
2702
- return async (ctx, next) => {
2703
- ctx.request.route = {
2704
- endpoint: `${method} ${endpoint}`,
2705
- controller: ___default.default.toLower(controller),
2706
- action: ___default.default.toLower(action),
2707
- verb: ___default.default.toLower(method),
2708
- plugin
2709
- };
2710
- await next();
2711
- };
2712
- };
2713
- const resolvePolicies = (config, policyContext) => {
2714
- const { pluginName, apiName } = policyContext ?? {};
2715
- return config.map((policyConfig) => {
2716
- return {
2717
- handler: getPolicy(policyConfig, { pluginName, apiName }),
2718
- config: typeof policyConfig === "object" && policyConfig.config || {}
2719
- };
2720
- });
2721
- };
2722
- const findPolicy = (name, policyContext) => {
2723
- const { pluginName, apiName } = policyContext ?? {};
2724
- const resolvedPolicy = strapi.policy(name);
2725
- if (resolvedPolicy !== void 0) {
2726
- return resolvedPolicy;
2727
- }
2728
- const localPolicy = searchLocalPolicy(name, { pluginName, apiName });
2729
- if (localPolicy !== void 0) {
2730
- return localPolicy;
2731
- }
2732
- throw new Error(`Could not find policy "${name}"`);
2733
- };
2734
- const getPolicy = (policyConfig, policyContext) => {
2735
- const { pluginName, apiName } = policyContext ?? {};
2736
- if (typeof policyConfig === "function") {
2737
- return policyConfig;
2738
- }
2739
- const { policyName, config } = parsePolicy(policyConfig);
2740
- const policy2 = findPolicy(policyName, { pluginName, apiName });
2741
- if (typeof policy2 === "function") {
2742
- return policy2;
2743
- }
2744
- if (policy2.validator) {
2745
- policy2.validator(config);
2746
- }
2747
- return policy2.handler;
2748
- };
2749
2883
  const createPolicy = (options) => {
2750
2884
  const { name = "unnamed", validator, handler } = options;
2751
2885
  const wrappedValidator = (config) => {
@@ -2777,10 +2911,7 @@ const createPolicyContext = (type, ctx) => {
2777
2911
  const policy = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2778
2912
  __proto__: null,
2779
2913
  createPolicy,
2780
- createPolicyContext,
2781
- get: getPolicy,
2782
- globalPolicy,
2783
- resolve: resolvePolicies
2914
+ createPolicyContext
2784
2915
  }, Symbol.toStringTag, { value: "Module" }));
2785
2916
  const nameToSlug = (name, options = { separator: "-" }) => slugify__default.default(name, options);
2786
2917
  const nameToCollectionName = (name) => slugify__default.default(name, { separator: "_" });
@@ -2790,9 +2921,9 @@ const toRegressedEnumValue = (value) => slugify__default.default(value, {
2790
2921
  separator: "_"
2791
2922
  });
2792
2923
  const getCommonPath = (...paths) => {
2793
- const [segments, ...otherSegments] = paths.map((it) => ___default.default.split(it, "/"));
2794
- return ___default.default.join(
2795
- ___default.default.takeWhile(segments, (str, index2) => otherSegments.every((it) => it[index2] === str)),
2924
+ const [segments, ...otherSegments] = paths.map((it) => ___namespace.default.split(it, "/"));
2925
+ return ___namespace.default.join(
2926
+ ___namespace.default.takeWhile(segments, (str, index2) => otherSegments.every((it) => it[index2] === str)),
2796
2927
  "/"
2797
2928
  );
2798
2929
  };
@@ -2814,7 +2945,7 @@ const joinBy = (joint, ...args) => {
2814
2945
  return url + joint + trim(path);
2815
2946
  }, "");
2816
2947
  };
2817
- const toKebabCase = (value) => _$1.kebabCase(value);
2948
+ const toKebabCase = (value) => _.kebabCase(value);
2818
2949
  const strings = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2819
2950
  __proto__: null,
2820
2951
  getCommonPath,
@@ -2834,9 +2965,9 @@ const arrays = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
2834
2965
  __proto__: null,
2835
2966
  includesString
2836
2967
  }, Symbol.toStringTag, { value: "Module" }));
2837
- const keysDeep = (obj, path = []) => !___default.default.isObject(obj) ? [path.join(".")] : ___default.default.reduce(
2968
+ const keysDeep = (obj, path = []) => !___namespace.default.isObject(obj) ? [path.join(".")] : ___namespace.default.reduce(
2838
2969
  obj,
2839
- (acc, next, key) => ___default.default.concat(acc, keysDeep(next, [...path, key])),
2970
+ (acc, next, key) => ___namespace.default.concat(acc, keysDeep(next, [...path, key])),
2840
2971
  []
2841
2972
  );
2842
2973
  const objects = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -2900,8 +3031,8 @@ function printValue(value, quoteStrings) {
2900
3031
  );
2901
3032
  }
2902
3033
  const strapiID = () => new StrapiIDSchema();
2903
- const isNotNilTest = (value) => !___default.default.isNil(value);
2904
- const isNotNullTest = (value) => !___default.default.isNull(value);
3034
+ const isNotNilTest = (value) => !___namespace.default.isNil(value);
3035
+ const isNotNullTest = (value) => !___namespace.default.isNull(value);
2905
3036
  yup__namespace.addMethod(yup__namespace.mixed, "notNil", function isNotNill(msg = "${path} must be defined.") {
2906
3037
  return this.test("defined", msg, isNotNilTest);
2907
3038
  });
@@ -2912,7 +3043,7 @@ yup__namespace.addMethod(yup__namespace.mixed, "isFunction", function isFunction
2912
3043
  return this.test(
2913
3044
  "is a function",
2914
3045
  message,
2915
- (value) => ___default.default.isUndefined(value) || ___default.default.isFunction(value)
3046
+ (value) => ___namespace.default.isUndefined(value) || ___namespace.default.isFunction(value)
2916
3047
  );
2917
3048
  });
2918
3049
  yup__namespace.addMethod(
@@ -2944,7 +3075,7 @@ yup__namespace.addMethod(
2944
3075
  return this.test(
2945
3076
  "only contains functions",
2946
3077
  message,
2947
- (value) => ___default.default.isUndefined(value) || value && Object.values(value).every(___default.default.isFunction)
3078
+ (value) => ___namespace.default.isUndefined(value) || value && Object.values(value).every(___namespace.default.isFunction)
2948
3079
  );
2949
3080
  }
2950
3081
  );
@@ -3019,10 +3150,30 @@ const relations = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePro
3019
3150
  isManyToAny,
3020
3151
  isOneToAny
3021
3152
  }, Symbol.toStringTag, { value: "Module" }));
3153
+ const validateZod = (schema) => (data) => {
3154
+ try {
3155
+ return schema.parse(data);
3156
+ } catch (error) {
3157
+ if (error instanceof zod.z.ZodError) {
3158
+ const { message, errors: errors2 } = formatZodErrors(error);
3159
+ throw new ValidationError(message, { errors: errors2 });
3160
+ }
3161
+ throw error;
3162
+ }
3163
+ };
3164
+ const formatZodErrors = (zodError) => ({
3165
+ errors: zodError.errors.map((error) => {
3166
+ return {
3167
+ path: error.path,
3168
+ message: error.message,
3169
+ name: "ValidationError"
3170
+ };
3171
+ }),
3172
+ message: "Validation error"
3173
+ });
3022
3174
  exports.arrays = arrays;
3023
3175
  exports.async = async;
3024
3176
  exports.contentTypes = contentTypes;
3025
- exports.convertQueryParams = convertQueryParams;
3026
3177
  exports.dates = dates;
3027
3178
  exports.env = env;
3028
3179
  exports.errors = errors;
@@ -3038,15 +3189,17 @@ exports.pagination = pagination;
3038
3189
  exports.parseType = parseType;
3039
3190
  exports.policy = policy;
3040
3191
  exports.providerFactory = providerFactory;
3192
+ exports.queryParams = convertQueryParams;
3041
3193
  exports.relations = relations;
3042
- exports.sanitize = index$1;
3194
+ exports.sanitize = index$2;
3043
3195
  exports.setCreatorFields = setCreatorFields;
3044
3196
  exports.strings = strings;
3045
3197
  exports.template = template;
3046
- exports.traverse = index$2;
3198
+ exports.traverse = index$3;
3047
3199
  exports.traverseEntity = traverseEntity$1;
3048
3200
  exports.validate = index;
3049
3201
  exports.validateYupSchema = validateYupSchema;
3050
3202
  exports.validateYupSchemaSync = validateYupSchemaSync;
3203
+ exports.validateZod = validateZod;
3051
3204
  exports.yup = yup;
3052
3205
  //# sourceMappingURL=index.js.map