@strapi/utils 4.26.1 → 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.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
|
-
|
|
471
|
-
if (index2 ===
|
|
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
|
-
|
|
493
|
-
if (typeof val === "
|
|
494
|
-
|
|
495
|
-
if (typeof val === "
|
|
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
|
-
|
|
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
|
|
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, {
|
|
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(
|
|
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
|
-
|
|
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
|
};
|