@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 +114 -50
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +114 -49
- package/dist/index.mjs.map +1 -1
- package/dist/sanitize/index.d.ts.map +1 -1
- package/dist/sanitize/visitors/remove-restricted-relations.d.ts.map +1 -1
- package/dist/validate/index.d.ts +1 -0
- package/dist/validate/index.d.ts.map +1 -1
- package/dist/validate/validators.d.ts +2 -1
- package/dist/validate/validators.d.ts.map +1 -1
- package/dist/validate/visitors/throw-restricted-relations.d.ts.map +1 -1
- package/package.json +8 -8
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _$1, { isString, isPlainObject as isPlainObject$1, kebabCase } from "lodash";
|
|
2
|
-
import { eq, isEmpty, toPath, defaults, trimChars, trimCharsEnd, trimCharsStart, get, isNumber, isInteger,
|
|
2
|
+
import { eq, isEmpty, toPath, defaults, trimChars, trimCharsEnd, trimCharsStart, get, isNumber, isInteger, union, getOr, has, assoc, assign, cloneDeep, remove, merge, isNil, pipe, omit, curry, isArray, isString as isString$1, isObject, clone, pick, trim, split, map, flatten, first, join, constant, toNumber, mergeAll } from "lodash/fp";
|
|
3
3
|
import * as yup$1 from "yup";
|
|
4
4
|
import { HttpError } from "http-errors";
|
|
5
5
|
import slugify from "@sindresorhus/slugify";
|
|
@@ -87,8 +87,7 @@ const parseDate = (value2) => {
|
|
|
87
87
|
}
|
|
88
88
|
try {
|
|
89
89
|
const date = dates.parseISO(value2);
|
|
90
|
-
if (dates.isValid(date))
|
|
91
|
-
return dates.format(date, "yyyy-MM-dd");
|
|
90
|
+
if (dates.isValid(date)) return dates.format(date, "yyyy-MM-dd");
|
|
92
91
|
throw new Error(`Invalid format, expected an ISO compatible date`);
|
|
93
92
|
} catch (error) {
|
|
94
93
|
throw new Error(`Invalid format, expected an ISO compatible date`);
|
|
@@ -103,11 +102,9 @@ const parseDateTimeOrTimestamp = (value2) => {
|
|
|
103
102
|
}
|
|
104
103
|
try {
|
|
105
104
|
const date = dates.parseISO(value2);
|
|
106
|
-
if (dates.isValid(date))
|
|
107
|
-
return date;
|
|
105
|
+
if (dates.isValid(date)) return date;
|
|
108
106
|
const milliUnixDate = dates.parse(value2, "T", /* @__PURE__ */ new Date());
|
|
109
|
-
if (dates.isValid(milliUnixDate))
|
|
110
|
-
return milliUnixDate;
|
|
107
|
+
if (dates.isValid(milliUnixDate)) return milliUnixDate;
|
|
111
108
|
throw new Error(`Invalid format, expected a timestamp or an ISO date`);
|
|
112
109
|
} catch (error) {
|
|
113
110
|
throw new Error(`Invalid format, expected a timestamp or an ISO date`);
|
|
@@ -441,12 +438,9 @@ const joinBy = (joint, ...args) => {
|
|
|
441
438
|
const trimEnd = trimCharsEnd(joint);
|
|
442
439
|
const trimStart = trimCharsStart(joint);
|
|
443
440
|
return args.reduce((url, path, index2) => {
|
|
444
|
-
if (args.length === 1)
|
|
445
|
-
|
|
446
|
-
if (index2 ===
|
|
447
|
-
return trimEnd(path);
|
|
448
|
-
if (index2 === args.length - 1)
|
|
449
|
-
return url + joint + trimStart(path);
|
|
441
|
+
if (args.length === 1) return path;
|
|
442
|
+
if (index2 === 0) return trimEnd(path);
|
|
443
|
+
if (index2 === args.length - 1) return url + joint + trimStart(path);
|
|
450
444
|
return url + joint + trim2(path);
|
|
451
445
|
}, "");
|
|
452
446
|
};
|
|
@@ -457,43 +451,33 @@ const regExpToString = RegExp.prototype.toString;
|
|
|
457
451
|
const symbolToString = typeof Symbol !== "undefined" ? Symbol.prototype.toString : () => "";
|
|
458
452
|
const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/;
|
|
459
453
|
function printNumber(val) {
|
|
460
|
-
if (val != +val)
|
|
461
|
-
return "NaN";
|
|
454
|
+
if (val != +val) return "NaN";
|
|
462
455
|
const isNegativeZero = val === 0 && 1 / val < 0;
|
|
463
456
|
return isNegativeZero ? "-0" : `${val}`;
|
|
464
457
|
}
|
|
465
458
|
function printSimpleValue(val, quoteStrings = false) {
|
|
466
|
-
if (val == null || val === true || val === false)
|
|
467
|
-
|
|
468
|
-
if (typeof val === "
|
|
469
|
-
|
|
470
|
-
if (typeof val === "
|
|
471
|
-
return quoteStrings ? `"${val}"` : val;
|
|
472
|
-
if (typeof val === "function")
|
|
473
|
-
return `[Function ${val.name || "anonymous"}]`;
|
|
474
|
-
if (typeof val === "symbol")
|
|
475
|
-
return symbolToString.call(val).replace(SYMBOL_REGEXP, "Symbol($1)");
|
|
459
|
+
if (val == null || val === true || val === false) return `${val}`;
|
|
460
|
+
if (typeof val === "number") return printNumber(val);
|
|
461
|
+
if (typeof val === "string") return quoteStrings ? `"${val}"` : val;
|
|
462
|
+
if (typeof val === "function") return `[Function ${val.name || "anonymous"}]`;
|
|
463
|
+
if (typeof val === "symbol") return symbolToString.call(val).replace(SYMBOL_REGEXP, "Symbol($1)");
|
|
476
464
|
const tag = toString.call(val).slice(8, -1);
|
|
477
465
|
if (tag === "Date") {
|
|
478
466
|
const v = val;
|
|
479
467
|
return Number.isNaN(v.getTime()) ? `${v}` : v.toISOString();
|
|
480
468
|
}
|
|
481
|
-
if (tag === "Error" || val instanceof Error)
|
|
482
|
-
|
|
483
|
-
if (tag === "RegExp")
|
|
484
|
-
return regExpToString.call(val);
|
|
469
|
+
if (tag === "Error" || val instanceof Error) return `[${errorToString.call(val)}]`;
|
|
470
|
+
if (tag === "RegExp") return regExpToString.call(val);
|
|
485
471
|
return null;
|
|
486
472
|
}
|
|
487
473
|
function printValue(value2, quoteStrings) {
|
|
488
474
|
const result = printSimpleValue(value2, quoteStrings);
|
|
489
|
-
if (result !== null)
|
|
490
|
-
return result;
|
|
475
|
+
if (result !== null) return result;
|
|
491
476
|
return JSON.stringify(
|
|
492
477
|
value2,
|
|
493
478
|
function replacer(key2, value22) {
|
|
494
479
|
const result2 = printSimpleValue(this[key2], quoteStrings);
|
|
495
|
-
if (result2 !== null)
|
|
496
|
-
return result2;
|
|
480
|
+
if (result2 !== null) return result2;
|
|
497
481
|
return value22;
|
|
498
482
|
},
|
|
499
483
|
2
|
|
@@ -709,8 +693,7 @@ const getCreatorFields = (model) => {
|
|
|
709
693
|
return attributes;
|
|
710
694
|
};
|
|
711
695
|
const getNonWritableAttributes = (model) => {
|
|
712
|
-
if (!model)
|
|
713
|
-
return [];
|
|
696
|
+
if (!model) return [];
|
|
714
697
|
const nonWritableAttributes = _$1.reduce(
|
|
715
698
|
model.attributes,
|
|
716
699
|
(acc2, attr, attrName) => attr.writable === false ? acc2.concat(attrName) : acc2,
|
|
@@ -719,8 +702,7 @@ const getNonWritableAttributes = (model) => {
|
|
|
719
702
|
return _$1.uniq([ID_ATTRIBUTE, ...getTimestamps(model), ...nonWritableAttributes]);
|
|
720
703
|
};
|
|
721
704
|
const getWritableAttributes = (model) => {
|
|
722
|
-
if (!model)
|
|
723
|
-
return [];
|
|
705
|
+
if (!model) return [];
|
|
724
706
|
return _$1.difference(Object.keys(model.attributes), getNonWritableAttributes(model));
|
|
725
707
|
};
|
|
726
708
|
const isWritableAttribute = (model, attributeName) => {
|
|
@@ -776,8 +758,7 @@ const getComponentAttributes = (schema) => {
|
|
|
776
758
|
return _$1.reduce(
|
|
777
759
|
schema.attributes,
|
|
778
760
|
(acc2, attr, attrName) => {
|
|
779
|
-
if (isComponentAttribute(attr))
|
|
780
|
-
acc2.push(attrName);
|
|
761
|
+
if (isComponentAttribute(attr)) acc2.push(attrName);
|
|
781
762
|
return acc2;
|
|
782
763
|
},
|
|
783
764
|
[]
|
|
@@ -787,8 +768,7 @@ const getScalarAttributes = (schema) => {
|
|
|
787
768
|
return _$1.reduce(
|
|
788
769
|
schema.attributes,
|
|
789
770
|
(acc2, attr, attrName) => {
|
|
790
|
-
if (isScalarAttribute(attr))
|
|
791
|
-
acc2.push(attrName);
|
|
771
|
+
if (isScalarAttribute(attr)) acc2.push(attrName);
|
|
792
772
|
return acc2;
|
|
793
773
|
},
|
|
794
774
|
[]
|
|
@@ -1181,8 +1161,12 @@ const removeRestrictedRelations = (auth) => async ({ data, key: key2, attribute,
|
|
|
1181
1161
|
return;
|
|
1182
1162
|
}
|
|
1183
1163
|
const handleMorphRelation = async () => {
|
|
1164
|
+
const elements = data[key2];
|
|
1165
|
+
if (!Array.isArray(elements)) {
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1184
1168
|
const newMorphValue = [];
|
|
1185
|
-
for (const element of
|
|
1169
|
+
for (const element of elements) {
|
|
1186
1170
|
const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
|
|
1187
1171
|
const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
|
|
1188
1172
|
if (isAllowed) {
|
|
@@ -2121,7 +2105,9 @@ const createContentAPISanitizers = () => {
|
|
|
2121
2105
|
Object.assign(sanitizedQuery, { fields: await sanitizeFields(fields2, schema) });
|
|
2122
2106
|
}
|
|
2123
2107
|
if (populate2) {
|
|
2124
|
-
Object.assign(sanitizedQuery, {
|
|
2108
|
+
Object.assign(sanitizedQuery, {
|
|
2109
|
+
populate: await sanitizePopulate(populate2, schema, { auth })
|
|
2110
|
+
});
|
|
2125
2111
|
}
|
|
2126
2112
|
return sanitizedQuery;
|
|
2127
2113
|
};
|
|
@@ -2161,7 +2147,26 @@ const createContentAPISanitizers = () => {
|
|
|
2161
2147
|
}
|
|
2162
2148
|
const transforms = [defaultSanitizePopulate(schema)];
|
|
2163
2149
|
if (auth) {
|
|
2164
|
-
transforms.push(
|
|
2150
|
+
transforms.push(
|
|
2151
|
+
traverseQueryPopulate(removeRestrictedRelations(auth), { schema }),
|
|
2152
|
+
traverseQueryPopulate(
|
|
2153
|
+
async ({ key: key2, value: value2, schema: schema2, attribute }, { set }) => {
|
|
2154
|
+
if (attribute) {
|
|
2155
|
+
return;
|
|
2156
|
+
}
|
|
2157
|
+
if (key2 === "sort") {
|
|
2158
|
+
set(key2, await sanitizeSort(value2, schema2, { auth }));
|
|
2159
|
+
}
|
|
2160
|
+
if (key2 === "filters") {
|
|
2161
|
+
set(key2, await sanitizeFilters(value2, schema2, { auth }));
|
|
2162
|
+
}
|
|
2163
|
+
if (key2 === "fields") {
|
|
2164
|
+
set(key2, await sanitizeFields(value2, schema2));
|
|
2165
|
+
}
|
|
2166
|
+
},
|
|
2167
|
+
{ schema }
|
|
2168
|
+
)
|
|
2169
|
+
);
|
|
2165
2170
|
}
|
|
2166
2171
|
return pipeAsync(...transforms)(populate2);
|
|
2167
2172
|
};
|
|
@@ -2209,7 +2214,11 @@ const throwRestrictedRelations = (auth) => async ({ data, key: key2, attribute,
|
|
|
2209
2214
|
return;
|
|
2210
2215
|
}
|
|
2211
2216
|
const handleMorphRelation = async () => {
|
|
2212
|
-
|
|
2217
|
+
const elements = data[key2];
|
|
2218
|
+
if (!Array.isArray(elements)) {
|
|
2219
|
+
return;
|
|
2220
|
+
}
|
|
2221
|
+
for (const element of elements) {
|
|
2213
2222
|
const scopes = ACTIONS_TO_VERIFY.map((action) => `${element.__type}.${action}`);
|
|
2214
2223
|
const isAllowed = await hasAccessToSomeScopes(scopes, auth);
|
|
2215
2224
|
if (!isAllowed) {
|
|
@@ -2408,10 +2417,35 @@ const defaultValidateFields = curry((schema, fields2) => {
|
|
|
2408
2417
|
traverseQueryFields(visitor$3, { schema })
|
|
2409
2418
|
)(fields2);
|
|
2410
2419
|
});
|
|
2420
|
+
const defaultValidatePopulate = curry((schema, populate2) => {
|
|
2421
|
+
if (!schema) {
|
|
2422
|
+
throw new Error("Missing schema in defaultValidatePopulate");
|
|
2423
|
+
}
|
|
2424
|
+
return pipeAsync(
|
|
2425
|
+
traverseQueryPopulate(
|
|
2426
|
+
async ({ key: key2, value: value2, schema: schema2, attribute }) => {
|
|
2427
|
+
if (attribute) {
|
|
2428
|
+
return;
|
|
2429
|
+
}
|
|
2430
|
+
if (key2 === "sort") {
|
|
2431
|
+
await defaultValidateSort(schema2, value2);
|
|
2432
|
+
}
|
|
2433
|
+
if (key2 === "filters") {
|
|
2434
|
+
await defaultValidateFilters(schema2, value2);
|
|
2435
|
+
}
|
|
2436
|
+
if (key2 === "fields") {
|
|
2437
|
+
await defaultValidateFields(schema2, value2);
|
|
2438
|
+
}
|
|
2439
|
+
},
|
|
2440
|
+
{ schema }
|
|
2441
|
+
)
|
|
2442
|
+
)(populate2);
|
|
2443
|
+
});
|
|
2411
2444
|
const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2412
2445
|
__proto__: null,
|
|
2413
2446
|
defaultValidateFields,
|
|
2414
2447
|
defaultValidateFilters,
|
|
2448
|
+
defaultValidatePopulate,
|
|
2415
2449
|
defaultValidateSort,
|
|
2416
2450
|
throwPasswords
|
|
2417
2451
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
@@ -2444,7 +2478,7 @@ const createContentAPIValidators = () => {
|
|
|
2444
2478
|
if (!schema) {
|
|
2445
2479
|
throw new Error("Missing schema in validateQuery");
|
|
2446
2480
|
}
|
|
2447
|
-
const { filters: filters2, sort: sort2, fields: fields2 } = query;
|
|
2481
|
+
const { filters: filters2, sort: sort2, fields: fields2, populate: populate2 } = query;
|
|
2448
2482
|
if (filters2) {
|
|
2449
2483
|
await validateFilters(filters2, schema, { auth });
|
|
2450
2484
|
}
|
|
@@ -2454,6 +2488,9 @@ const createContentAPIValidators = () => {
|
|
|
2454
2488
|
if (fields2) {
|
|
2455
2489
|
await validateFields(fields2, schema);
|
|
2456
2490
|
}
|
|
2491
|
+
if (populate2 && populate2 !== "*") {
|
|
2492
|
+
await validatePopulate(populate2, schema, { auth });
|
|
2493
|
+
}
|
|
2457
2494
|
};
|
|
2458
2495
|
const validateFilters = async (filters2, schema, { auth } = {}) => {
|
|
2459
2496
|
if (!schema) {
|
|
@@ -2486,12 +2523,41 @@ const createContentAPIValidators = () => {
|
|
|
2486
2523
|
const transforms = [defaultValidateFields(schema)];
|
|
2487
2524
|
return pipeAsync(...transforms)(fields2);
|
|
2488
2525
|
};
|
|
2526
|
+
const validatePopulate = async (populate2, schema, { auth } = {}) => {
|
|
2527
|
+
if (!schema) {
|
|
2528
|
+
throw new Error("Missing schema in validatePopulate");
|
|
2529
|
+
}
|
|
2530
|
+
const transforms = [defaultValidatePopulate(schema)];
|
|
2531
|
+
if (auth) {
|
|
2532
|
+
transforms.push(
|
|
2533
|
+
traverseQueryPopulate(
|
|
2534
|
+
async ({ key: key2, value: value2, schema: schema2, attribute }) => {
|
|
2535
|
+
if (attribute) {
|
|
2536
|
+
return;
|
|
2537
|
+
}
|
|
2538
|
+
if (key2 === "sort") {
|
|
2539
|
+
await validateSort(value2, schema2, { auth });
|
|
2540
|
+
}
|
|
2541
|
+
if (key2 === "filters") {
|
|
2542
|
+
await validateFilters(value2, schema2, { auth });
|
|
2543
|
+
}
|
|
2544
|
+
if (key2 === "fields") {
|
|
2545
|
+
await validateFields(value2, schema2);
|
|
2546
|
+
}
|
|
2547
|
+
},
|
|
2548
|
+
{ schema }
|
|
2549
|
+
)
|
|
2550
|
+
);
|
|
2551
|
+
}
|
|
2552
|
+
return pipeAsync(...transforms)(populate2);
|
|
2553
|
+
};
|
|
2489
2554
|
return {
|
|
2490
2555
|
input: validateInput,
|
|
2491
2556
|
query: validateQuery,
|
|
2492
2557
|
filters: validateFilters,
|
|
2493
2558
|
sort: validateSort,
|
|
2494
|
-
fields: validateFields
|
|
2559
|
+
fields: validateFields,
|
|
2560
|
+
populate: validatePopulate
|
|
2495
2561
|
};
|
|
2496
2562
|
};
|
|
2497
2563
|
const contentAPI = createContentAPIValidators();
|
|
@@ -2903,8 +2969,7 @@ const kbytesToBytes = (kbytes) => kbytes * 1e3;
|
|
|
2903
2969
|
const bytesToKbytes = (bytes) => Math.round(bytes / 1e3 * 100) / 100;
|
|
2904
2970
|
const bytesToHumanReadable = (bytes) => {
|
|
2905
2971
|
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
|
|
2906
|
-
if (bytes === 0)
|
|
2907
|
-
return "0 Bytes";
|
|
2972
|
+
if (bytes === 0) return "0 Bytes";
|
|
2908
2973
|
const i = parseInt(`${Math.floor(Math.log(bytes) / Math.log(1e3))}`, 10);
|
|
2909
2974
|
return `${Math.round(bytes / 1e3 ** i)} ${sizes[i]}`;
|
|
2910
2975
|
};
|