@strapi/utils 4.26.0 → 4.26.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -9,8 +9,7 @@ const pMap = require("p-map");
9
9
  const node_stream = require("node:stream");
10
10
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
11
11
  function _interopNamespace(e) {
12
- if (e && e.__esModule)
13
- return e;
12
+ if (e && e.__esModule) return e;
14
13
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
15
14
  if (e) {
16
15
  for (const k in e) {
@@ -112,8 +111,7 @@ const parseDate = (value2) => {
112
111
  }
113
112
  try {
114
113
  const date = dates.parseISO(value2);
115
- if (dates.isValid(date))
116
- return dates.format(date, "yyyy-MM-dd");
114
+ if (dates.isValid(date)) return dates.format(date, "yyyy-MM-dd");
117
115
  throw new Error(`Invalid format, expected an ISO compatible date`);
118
116
  } catch (error) {
119
117
  throw new Error(`Invalid format, expected an ISO compatible date`);
@@ -128,11 +126,9 @@ const parseDateTimeOrTimestamp = (value2) => {
128
126
  }
129
127
  try {
130
128
  const date = dates.parseISO(value2);
131
- if (dates.isValid(date))
132
- return date;
129
+ if (dates.isValid(date)) return date;
133
130
  const milliUnixDate = dates.parse(value2, "T", /* @__PURE__ */ new Date());
134
- if (dates.isValid(milliUnixDate))
135
- return milliUnixDate;
131
+ if (dates.isValid(milliUnixDate)) return milliUnixDate;
136
132
  throw new Error(`Invalid format, expected a timestamp or an ISO date`);
137
133
  } catch (error) {
138
134
  throw new Error(`Invalid format, expected a timestamp or an ISO date`);
@@ -466,12 +462,9 @@ const joinBy = (joint, ...args) => {
466
462
  const trimEnd = fp.trimCharsEnd(joint);
467
463
  const trimStart = fp.trimCharsStart(joint);
468
464
  return args.reduce((url, path, index2) => {
469
- if (args.length === 1)
470
- return path;
471
- if (index2 === 0)
472
- return trimEnd(path);
473
- if (index2 === args.length - 1)
474
- return url + joint + trimStart(path);
465
+ if (args.length === 1) return path;
466
+ if (index2 === 0) return trimEnd(path);
467
+ if (index2 === args.length - 1) return url + joint + trimStart(path);
475
468
  return url + joint + trim(path);
476
469
  }, "");
477
470
  };
@@ -482,43 +475,33 @@ const regExpToString = RegExp.prototype.toString;
482
475
  const symbolToString = typeof Symbol !== "undefined" ? Symbol.prototype.toString : () => "";
483
476
  const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/;
484
477
  function printNumber(val) {
485
- if (val != +val)
486
- return "NaN";
478
+ if (val != +val) return "NaN";
487
479
  const isNegativeZero = val === 0 && 1 / val < 0;
488
480
  return isNegativeZero ? "-0" : `${val}`;
489
481
  }
490
482
  function printSimpleValue(val, quoteStrings = false) {
491
- if (val == null || val === true || val === false)
492
- return `${val}`;
493
- if (typeof val === "number")
494
- return printNumber(val);
495
- if (typeof val === "string")
496
- return quoteStrings ? `"${val}"` : val;
497
- if (typeof val === "function")
498
- return `[Function ${val.name || "anonymous"}]`;
499
- if (typeof val === "symbol")
500
- return symbolToString.call(val).replace(SYMBOL_REGEXP, "Symbol($1)");
483
+ if (val == null || val === true || val === false) return `${val}`;
484
+ if (typeof val === "number") return printNumber(val);
485
+ if (typeof val === "string") return quoteStrings ? `"${val}"` : val;
486
+ if (typeof val === "function") return `[Function ${val.name || "anonymous"}]`;
487
+ if (typeof val === "symbol") return symbolToString.call(val).replace(SYMBOL_REGEXP, "Symbol($1)");
501
488
  const tag = toString.call(val).slice(8, -1);
502
489
  if (tag === "Date") {
503
490
  const v = val;
504
491
  return Number.isNaN(v.getTime()) ? `${v}` : v.toISOString();
505
492
  }
506
- if (tag === "Error" || val instanceof Error)
507
- return `[${errorToString.call(val)}]`;
508
- if (tag === "RegExp")
509
- return regExpToString.call(val);
493
+ if (tag === "Error" || val instanceof Error) return `[${errorToString.call(val)}]`;
494
+ if (tag === "RegExp") return regExpToString.call(val);
510
495
  return null;
511
496
  }
512
497
  function printValue(value2, quoteStrings) {
513
498
  const result = printSimpleValue(value2, quoteStrings);
514
- if (result !== null)
515
- return result;
499
+ if (result !== null) return result;
516
500
  return JSON.stringify(
517
501
  value2,
518
502
  function replacer(key2, value22) {
519
503
  const result2 = printSimpleValue(this[key2], quoteStrings);
520
- if (result2 !== null)
521
- return result2;
504
+ if (result2 !== null) return result2;
522
505
  return value22;
523
506
  },
524
507
  2
@@ -734,8 +717,7 @@ const getCreatorFields = (model) => {
734
717
  return attributes;
735
718
  };
736
719
  const getNonWritableAttributes = (model) => {
737
- if (!model)
738
- return [];
720
+ if (!model) return [];
739
721
  const nonWritableAttributes = ___default.default.reduce(
740
722
  model.attributes,
741
723
  (acc2, attr, attrName) => attr.writable === false ? acc2.concat(attrName) : acc2,
@@ -744,8 +726,7 @@ const getNonWritableAttributes = (model) => {
744
726
  return ___default.default.uniq([ID_ATTRIBUTE, ...getTimestamps(model), ...nonWritableAttributes]);
745
727
  };
746
728
  const getWritableAttributes = (model) => {
747
- if (!model)
748
- return [];
729
+ if (!model) return [];
749
730
  return ___default.default.difference(Object.keys(model.attributes), getNonWritableAttributes(model));
750
731
  };
751
732
  const isWritableAttribute = (model, attributeName) => {
@@ -801,8 +782,7 @@ const getComponentAttributes = (schema) => {
801
782
  return ___default.default.reduce(
802
783
  schema.attributes,
803
784
  (acc2, attr, attrName) => {
804
- if (isComponentAttribute(attr))
805
- acc2.push(attrName);
785
+ if (isComponentAttribute(attr)) acc2.push(attrName);
806
786
  return acc2;
807
787
  },
808
788
  []
@@ -812,8 +792,7 @@ const getScalarAttributes = (schema) => {
812
792
  return ___default.default.reduce(
813
793
  schema.attributes,
814
794
  (acc2, attr, attrName) => {
815
- if (isScalarAttribute(attr))
816
- acc2.push(attrName);
795
+ if (isScalarAttribute(attr)) acc2.push(attrName);
817
796
  return acc2;
818
797
  },
819
798
  []
@@ -1206,8 +1185,12 @@ const removeRestrictedRelations = (auth) => async ({ data, key: key2, attribute,
1206
1185
  return;
1207
1186
  }
1208
1187
  const handleMorphRelation = async () => {
1188
+ const elements = data[key2];
1189
+ if (!Array.isArray(elements)) {
1190
+ return;
1191
+ }
1209
1192
  const newMorphValue = [];
1210
- for (const element of data[key2]) {
1193
+ for (const element of elements) {
1211
1194
  const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
1212
1195
  const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
1213
1196
  if (isAllowed) {
@@ -2146,7 +2129,9 @@ const createContentAPISanitizers = () => {
2146
2129
  Object.assign(sanitizedQuery, { fields: await sanitizeFields(fields2, schema) });
2147
2130
  }
2148
2131
  if (populate2) {
2149
- Object.assign(sanitizedQuery, { populate: await sanitizePopulate(populate2, schema) });
2132
+ Object.assign(sanitizedQuery, {
2133
+ populate: await sanitizePopulate(populate2, schema, { auth })
2134
+ });
2150
2135
  }
2151
2136
  return sanitizedQuery;
2152
2137
  };
@@ -2186,7 +2171,26 @@ const createContentAPISanitizers = () => {
2186
2171
  }
2187
2172
  const transforms = [defaultSanitizePopulate(schema)];
2188
2173
  if (auth) {
2189
- transforms.push(traverseQueryPopulate(removeRestrictedRelations(auth), { schema }));
2174
+ transforms.push(
2175
+ traverseQueryPopulate(removeRestrictedRelations(auth), { schema }),
2176
+ traverseQueryPopulate(
2177
+ async ({ key: key2, value: value2, schema: schema2, attribute }, { set }) => {
2178
+ if (attribute) {
2179
+ return;
2180
+ }
2181
+ if (key2 === "sort") {
2182
+ set(key2, await sanitizeSort(value2, schema2, { auth }));
2183
+ }
2184
+ if (key2 === "filters") {
2185
+ set(key2, await sanitizeFilters(value2, schema2, { auth }));
2186
+ }
2187
+ if (key2 === "fields") {
2188
+ set(key2, await sanitizeFields(value2, schema2));
2189
+ }
2190
+ },
2191
+ { schema }
2192
+ )
2193
+ );
2190
2194
  }
2191
2195
  return pipeAsync(...transforms)(populate2);
2192
2196
  };
@@ -2234,7 +2238,11 @@ const throwRestrictedRelations = (auth) => async ({ data, key: key2, attribute,
2234
2238
  return;
2235
2239
  }
2236
2240
  const handleMorphRelation = async () => {
2237
- for (const element of data[key2]) {
2241
+ const elements = data[key2];
2242
+ if (!Array.isArray(elements)) {
2243
+ return;
2244
+ }
2245
+ for (const element of elements) {
2238
2246
  const scopes = ACTIONS_TO_VERIFY.map((action) => `${element.__type}.${action}`);
2239
2247
  const isAllowed = await hasAccessToSomeScopes(scopes, auth);
2240
2248
  if (!isAllowed) {
@@ -2433,10 +2441,35 @@ const defaultValidateFields = fp.curry((schema, fields2) => {
2433
2441
  traverseQueryFields(visitor$3, { schema })
2434
2442
  )(fields2);
2435
2443
  });
2444
+ const defaultValidatePopulate = fp.curry((schema, populate2) => {
2445
+ if (!schema) {
2446
+ throw new Error("Missing schema in defaultValidatePopulate");
2447
+ }
2448
+ return pipeAsync(
2449
+ traverseQueryPopulate(
2450
+ async ({ key: key2, value: value2, schema: schema2, attribute }) => {
2451
+ if (attribute) {
2452
+ return;
2453
+ }
2454
+ if (key2 === "sort") {
2455
+ await defaultValidateSort(schema2, value2);
2456
+ }
2457
+ if (key2 === "filters") {
2458
+ await defaultValidateFilters(schema2, value2);
2459
+ }
2460
+ if (key2 === "fields") {
2461
+ await defaultValidateFields(schema2, value2);
2462
+ }
2463
+ },
2464
+ { schema }
2465
+ )
2466
+ )(populate2);
2467
+ });
2436
2468
  const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2437
2469
  __proto__: null,
2438
2470
  defaultValidateFields,
2439
2471
  defaultValidateFilters,
2472
+ defaultValidatePopulate,
2440
2473
  defaultValidateSort,
2441
2474
  throwPasswords
2442
2475
  }, Symbol.toStringTag, { value: "Module" }));
@@ -2469,7 +2502,7 @@ const createContentAPIValidators = () => {
2469
2502
  if (!schema) {
2470
2503
  throw new Error("Missing schema in validateQuery");
2471
2504
  }
2472
- const { filters: filters2, sort: sort2, fields: fields2 } = query;
2505
+ const { filters: filters2, sort: sort2, fields: fields2, populate: populate2 } = query;
2473
2506
  if (filters2) {
2474
2507
  await validateFilters(filters2, schema, { auth });
2475
2508
  }
@@ -2479,6 +2512,9 @@ const createContentAPIValidators = () => {
2479
2512
  if (fields2) {
2480
2513
  await validateFields(fields2, schema);
2481
2514
  }
2515
+ if (populate2 && populate2 !== "*") {
2516
+ await validatePopulate(populate2, schema, { auth });
2517
+ }
2482
2518
  };
2483
2519
  const validateFilters = async (filters2, schema, { auth } = {}) => {
2484
2520
  if (!schema) {
@@ -2511,12 +2547,41 @@ const createContentAPIValidators = () => {
2511
2547
  const transforms = [defaultValidateFields(schema)];
2512
2548
  return pipeAsync(...transforms)(fields2);
2513
2549
  };
2550
+ const validatePopulate = async (populate2, schema, { auth } = {}) => {
2551
+ if (!schema) {
2552
+ throw new Error("Missing schema in validatePopulate");
2553
+ }
2554
+ const transforms = [defaultValidatePopulate(schema)];
2555
+ if (auth) {
2556
+ transforms.push(
2557
+ traverseQueryPopulate(
2558
+ async ({ key: key2, value: value2, schema: schema2, attribute }) => {
2559
+ if (attribute) {
2560
+ return;
2561
+ }
2562
+ if (key2 === "sort") {
2563
+ await validateSort(value2, schema2, { auth });
2564
+ }
2565
+ if (key2 === "filters") {
2566
+ await validateFilters(value2, schema2, { auth });
2567
+ }
2568
+ if (key2 === "fields") {
2569
+ await validateFields(value2, schema2);
2570
+ }
2571
+ },
2572
+ { schema }
2573
+ )
2574
+ );
2575
+ }
2576
+ return pipeAsync(...transforms)(populate2);
2577
+ };
2514
2578
  return {
2515
2579
  input: validateInput,
2516
2580
  query: validateQuery,
2517
2581
  filters: validateFilters,
2518
2582
  sort: validateSort,
2519
- fields: validateFields
2583
+ fields: validateFields,
2584
+ populate: validatePopulate
2520
2585
  };
2521
2586
  };
2522
2587
  const contentAPI = createContentAPIValidators();
@@ -2928,8 +2993,7 @@ const kbytesToBytes = (kbytes) => kbytes * 1e3;
2928
2993
  const bytesToKbytes = (bytes) => Math.round(bytes / 1e3 * 100) / 100;
2929
2994
  const bytesToHumanReadable = (bytes) => {
2930
2995
  const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
2931
- if (bytes === 0)
2932
- return "0 Bytes";
2996
+ if (bytes === 0) return "0 Bytes";
2933
2997
  const i = parseInt(`${Math.floor(Math.log(bytes) / Math.log(1e3))}`, 10);
2934
2998
  return `${Math.round(bytes / 1e3 ** i)} ${sizes[i]}`;
2935
2999
  };