@strapi/utils 5.0.0-rc.8 → 5.0.0
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 +409 -188
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +410 -189
- package/dist/index.mjs.map +1 -1
- package/dist/provider-factory.d.ts +7 -8
- package/dist/provider-factory.d.ts.map +1 -1
- package/dist/relations.d.ts +3 -0
- package/dist/relations.d.ts.map +1 -1
- package/dist/sanitize/visitors/remove-restricted-relations.d.ts.map +1 -1
- package/dist/traverse/factory.d.ts +1 -1
- package/dist/traverse/query-fields.d.ts.map +1 -1
- package/dist/traverse/query-populate.d.ts.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validate/utils.d.ts +1 -0
- package/dist/validate/utils.d.ts.map +1 -1
- package/dist/validate/validators.d.ts +19 -7
- package/dist/validate/validators.d.ts.map +1 -1
- package/dist/validate/visitors/throw-restricted-relations.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _ from "lodash";
|
|
2
2
|
import ___default, { kebabCase } from "lodash";
|
|
3
3
|
import * as dates$1 from "date-fns";
|
|
4
|
-
import { has, union, getOr, assoc, assign, cloneDeep, remove, eq, curry, isObject, isNil, clone, isArray, isEmpty, toPath, defaults, isString, get, toNumber, isInteger, pick, omit, trim, pipe as pipe$1, split, map as map$1, flatten, first, identity, constant, join, merge, trimChars, trimCharsEnd, trimCharsStart, isNumber } from "lodash/fp";
|
|
4
|
+
import { has, union, getOr, assoc, assign, cloneDeep, remove, eq, curry, isObject, isNil, clone, isArray, isEmpty, toPath, defaults, isString, get, toNumber, isInteger, isBoolean, pick, omit, trim, pipe as pipe$1, split, map as map$1, flatten, first, identity, constant, join, merge, trimChars, trimCharsEnd, trimCharsStart, isNumber } from "lodash/fp";
|
|
5
5
|
import { randomUUID } from "crypto";
|
|
6
6
|
import { machineIdSync } from "node-machine-id";
|
|
7
7
|
import * as yup$1 from "yup";
|
|
@@ -517,16 +517,6 @@ const providerFactory = (options = {}) => {
|
|
|
517
517
|
get(key) {
|
|
518
518
|
return state.registry.get(key);
|
|
519
519
|
},
|
|
520
|
-
getWhere(filters2 = {}) {
|
|
521
|
-
const items = this.values();
|
|
522
|
-
const filtersEntries = Object.entries(filters2);
|
|
523
|
-
if (filtersEntries.length === 0) {
|
|
524
|
-
return items;
|
|
525
|
-
}
|
|
526
|
-
return items.filter((item) => {
|
|
527
|
-
return filtersEntries.every(([key, value]) => item[key] === value);
|
|
528
|
-
});
|
|
529
|
-
},
|
|
530
520
|
values() {
|
|
531
521
|
return Array.from(state.registry.values());
|
|
532
522
|
},
|
|
@@ -1318,6 +1308,32 @@ const visitor$7 = ({ schema, key, attribute }, { remove: remove2 }) => {
|
|
|
1318
1308
|
remove2(key);
|
|
1319
1309
|
}
|
|
1320
1310
|
};
|
|
1311
|
+
const MANY_RELATIONS = ["oneToMany", "manyToMany"];
|
|
1312
|
+
const getRelationalFields = (contentType) => {
|
|
1313
|
+
return Object.keys(contentType.attributes).filter((attributeName) => {
|
|
1314
|
+
return contentType.attributes[attributeName].type === "relation";
|
|
1315
|
+
});
|
|
1316
|
+
};
|
|
1317
|
+
const isOneToAny = (attribute) => isRelationalAttribute(attribute) && ["oneToOne", "oneToMany"].includes(attribute.relation);
|
|
1318
|
+
const isManyToAny = (attribute) => isRelationalAttribute(attribute) && ["manyToMany", "manyToOne"].includes(attribute.relation);
|
|
1319
|
+
const isAnyToOne = (attribute) => isRelationalAttribute(attribute) && ["oneToOne", "manyToOne"].includes(attribute.relation);
|
|
1320
|
+
const isAnyToMany = (attribute) => isRelationalAttribute(attribute) && ["oneToMany", "manyToMany"].includes(attribute.relation);
|
|
1321
|
+
const constants = {
|
|
1322
|
+
MANY_RELATIONS
|
|
1323
|
+
};
|
|
1324
|
+
const VALID_RELATION_ORDERING_KEYS = {
|
|
1325
|
+
strict: isBoolean
|
|
1326
|
+
};
|
|
1327
|
+
const relations = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1328
|
+
__proto__: null,
|
|
1329
|
+
VALID_RELATION_ORDERING_KEYS,
|
|
1330
|
+
constants,
|
|
1331
|
+
getRelationalFields,
|
|
1332
|
+
isAnyToMany,
|
|
1333
|
+
isAnyToOne,
|
|
1334
|
+
isManyToAny,
|
|
1335
|
+
isOneToAny
|
|
1336
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1321
1337
|
const ACTIONS_TO_VERIFY$1 = ["find"];
|
|
1322
1338
|
const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$1 } = constants$1;
|
|
1323
1339
|
const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schema }, { remove: remove2, set }) => {
|
|
@@ -1329,19 +1345,57 @@ const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schem
|
|
|
1329
1345
|
return;
|
|
1330
1346
|
}
|
|
1331
1347
|
const handleMorphRelation = async () => {
|
|
1332
|
-
const
|
|
1333
|
-
|
|
1348
|
+
const elements = data[key];
|
|
1349
|
+
if ("connect" in elements || "set" in elements || "disconnect" in elements) {
|
|
1350
|
+
const newValue = {};
|
|
1351
|
+
const connect = await handleMorphElements(elements.connect || []);
|
|
1352
|
+
const relSet = await handleMorphElements(elements.set || []);
|
|
1353
|
+
const disconnect = await handleMorphElements(elements.disconnect || []);
|
|
1354
|
+
if (connect.length > 0) {
|
|
1355
|
+
newValue.connect = connect;
|
|
1356
|
+
}
|
|
1357
|
+
if (relSet.length > 0) {
|
|
1358
|
+
newValue.set = relSet;
|
|
1359
|
+
}
|
|
1360
|
+
if (disconnect.length > 0) {
|
|
1361
|
+
newValue.disconnect = disconnect;
|
|
1362
|
+
}
|
|
1363
|
+
if ("options" in elements && typeof elements.options === "object" && elements.options !== null) {
|
|
1364
|
+
const filteredOptions = {};
|
|
1365
|
+
Object.keys(elements.options).forEach((key2) => {
|
|
1366
|
+
const validator = VALID_RELATION_ORDERING_KEYS[key2];
|
|
1367
|
+
if (validator && validator(elements.options[key2])) {
|
|
1368
|
+
filteredOptions[key2] = elements.options[key2];
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1371
|
+
newValue.options = filteredOptions;
|
|
1372
|
+
}
|
|
1373
|
+
set(key, newValue);
|
|
1374
|
+
} else {
|
|
1375
|
+
const newMorphValue = await handleMorphElements(elements);
|
|
1376
|
+
if (newMorphValue.length === 0) {
|
|
1377
|
+
remove2(key);
|
|
1378
|
+
} else {
|
|
1379
|
+
set(key, newMorphValue);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
};
|
|
1383
|
+
const handleMorphElements = async (elements) => {
|
|
1384
|
+
const allowedElements = [];
|
|
1385
|
+
if (!isArray(elements)) {
|
|
1386
|
+
return allowedElements;
|
|
1387
|
+
}
|
|
1388
|
+
for (const element of elements) {
|
|
1389
|
+
if (!isObject(element) || !("__type" in element)) {
|
|
1390
|
+
continue;
|
|
1391
|
+
}
|
|
1334
1392
|
const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
|
|
1335
1393
|
const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
|
|
1336
1394
|
if (isAllowed) {
|
|
1337
|
-
|
|
1395
|
+
allowedElements.push(element);
|
|
1338
1396
|
}
|
|
1339
1397
|
}
|
|
1340
|
-
|
|
1341
|
-
remove2(key);
|
|
1342
|
-
} else {
|
|
1343
|
-
set(key, newMorphValue);
|
|
1344
|
-
}
|
|
1398
|
+
return allowedElements;
|
|
1345
1399
|
};
|
|
1346
1400
|
const handleRegularRelation = async () => {
|
|
1347
1401
|
const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${attribute.target}.${action}`);
|
|
@@ -1867,10 +1921,17 @@ const populate = traverseFactory().intercept(isStringArray$1, async (visitor2, o
|
|
|
1867
1921
|
}
|
|
1868
1922
|
});
|
|
1869
1923
|
const traverseQueryPopulate = curry(populate.traverse);
|
|
1870
|
-
const isStringArray = (value) =>
|
|
1924
|
+
const isStringArray = (value) => {
|
|
1925
|
+
return isArray(value) && value.every(isString);
|
|
1926
|
+
};
|
|
1871
1927
|
const fields = traverseFactory().intercept(isStringArray, async (visitor2, options, fields2, { recurse }) => {
|
|
1872
1928
|
return Promise.all(fields2.map((field) => recurse(visitor2, options, field)));
|
|
1873
|
-
}).intercept(
|
|
1929
|
+
}).intercept(
|
|
1930
|
+
(value) => isString(value) && value.includes(","),
|
|
1931
|
+
(visitor2, options, fields2, { recurse }) => {
|
|
1932
|
+
return Promise.all(fields2.split(",").map((field) => recurse(visitor2, options, field)));
|
|
1933
|
+
}
|
|
1934
|
+
).intercept((value) => eq("*", value), constant("*")).parse(isString, () => ({
|
|
1874
1935
|
transform: trim,
|
|
1875
1936
|
remove(key, data) {
|
|
1876
1937
|
return data === key ? void 0 : data;
|
|
@@ -2171,6 +2232,15 @@ const throwInvalidKey = ({ key, path }) => {
|
|
|
2171
2232
|
path
|
|
2172
2233
|
});
|
|
2173
2234
|
};
|
|
2235
|
+
const asyncCurry = (fn) => {
|
|
2236
|
+
const curried = (...args) => {
|
|
2237
|
+
if (args.length >= fn.length) {
|
|
2238
|
+
return fn(...args);
|
|
2239
|
+
}
|
|
2240
|
+
return (...moreArgs) => curried(...args, ...moreArgs);
|
|
2241
|
+
};
|
|
2242
|
+
return curried;
|
|
2243
|
+
};
|
|
2174
2244
|
const visitor$3 = ({ key, attribute, path }) => {
|
|
2175
2245
|
if (attribute?.type === "password") {
|
|
2176
2246
|
throwInvalidKey({ key, path: path.attribute });
|
|
@@ -2196,7 +2266,40 @@ const throwRestrictedRelations = (auth) => async ({ data, key, attribute, schema
|
|
|
2196
2266
|
return;
|
|
2197
2267
|
}
|
|
2198
2268
|
const handleMorphRelation = async () => {
|
|
2199
|
-
|
|
2269
|
+
const elements = data[key];
|
|
2270
|
+
if ("connect" in elements || "set" in elements || "disconnect" in elements || "options" in elements) {
|
|
2271
|
+
await handleMorphElements(elements.connect || []);
|
|
2272
|
+
await handleMorphElements(elements.set || []);
|
|
2273
|
+
await handleMorphElements(elements.disconnect || []);
|
|
2274
|
+
if ("options" in elements) {
|
|
2275
|
+
if (elements.options === null || elements.options === void 0) {
|
|
2276
|
+
return;
|
|
2277
|
+
}
|
|
2278
|
+
if (typeof elements.options !== "object") {
|
|
2279
|
+
throwInvalidKey({ key, path: path.attribute });
|
|
2280
|
+
}
|
|
2281
|
+
const optionKeys = Object.keys(elements.options);
|
|
2282
|
+
for (const key2 of optionKeys) {
|
|
2283
|
+
if (!(key2 in VALID_RELATION_ORDERING_KEYS)) {
|
|
2284
|
+
throwInvalidKey({ key: key2, path: path.attribute });
|
|
2285
|
+
}
|
|
2286
|
+
if (!VALID_RELATION_ORDERING_KEYS[key2](elements.options[key2])) {
|
|
2287
|
+
throwInvalidKey({ key: key2, path: path.attribute });
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
} else {
|
|
2292
|
+
await handleMorphElements(elements);
|
|
2293
|
+
}
|
|
2294
|
+
};
|
|
2295
|
+
const handleMorphElements = async (elements) => {
|
|
2296
|
+
if (!isArray(elements)) {
|
|
2297
|
+
throwInvalidKey({ key, path: path.attribute });
|
|
2298
|
+
}
|
|
2299
|
+
for (const element of elements) {
|
|
2300
|
+
if (!isObject(element) || !("__type" in element)) {
|
|
2301
|
+
throwInvalidKey({ key, path: path.attribute });
|
|
2302
|
+
}
|
|
2200
2303
|
const scopes = ACTIONS_TO_VERIFY.map((action) => `${element.__type}.${action}`);
|
|
2201
2304
|
const isAllowed = await hasAccessToSomeScopes(scopes, auth);
|
|
2202
2305
|
if (!isAllowed) {
|
|
@@ -2336,154 +2439,294 @@ const throwPasswords = (ctx) => async (entity) => {
|
|
|
2336
2439
|
}
|
|
2337
2440
|
return traverseEntity$1(visitor$3, ctx, entity);
|
|
2338
2441
|
};
|
|
2339
|
-
const
|
|
2340
|
-
|
|
2341
|
-
|
|
2442
|
+
const FILTER_TRAVERSALS = [
|
|
2443
|
+
"nonAttributesOperators",
|
|
2444
|
+
"dynamicZones",
|
|
2445
|
+
"morphRelations",
|
|
2446
|
+
"passwords",
|
|
2447
|
+
"private"
|
|
2448
|
+
];
|
|
2449
|
+
const validateFilters = asyncCurry(
|
|
2450
|
+
async (ctx, filters2, include) => {
|
|
2451
|
+
if (!ctx.schema) {
|
|
2452
|
+
throw new Error("Missing schema in defaultValidateFilters");
|
|
2453
|
+
}
|
|
2454
|
+
const functionsToApply = [];
|
|
2455
|
+
if (include.includes("nonAttributesOperators")) {
|
|
2456
|
+
functionsToApply.push(
|
|
2457
|
+
traverseQueryFilters(({ key, attribute, path }) => {
|
|
2458
|
+
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2459
|
+
return;
|
|
2460
|
+
}
|
|
2461
|
+
const isAttribute = !!attribute;
|
|
2462
|
+
if (!isAttribute && !isOperator(key)) {
|
|
2463
|
+
throwInvalidKey({ key, path: path.attribute });
|
|
2464
|
+
}
|
|
2465
|
+
}, ctx)
|
|
2466
|
+
);
|
|
2467
|
+
}
|
|
2468
|
+
if (include.includes("dynamicZones")) {
|
|
2469
|
+
functionsToApply.push(traverseQueryFilters(visitor, ctx));
|
|
2470
|
+
}
|
|
2471
|
+
if (include.includes("morphRelations")) {
|
|
2472
|
+
functionsToApply.push(traverseQueryFilters(visitor$1, ctx));
|
|
2473
|
+
}
|
|
2474
|
+
if (include.includes("passwords")) {
|
|
2475
|
+
functionsToApply.push(traverseQueryFilters(visitor$3, ctx));
|
|
2476
|
+
}
|
|
2477
|
+
if (include.includes("private")) {
|
|
2478
|
+
functionsToApply.push(traverseQueryFilters(visitor$2, ctx));
|
|
2479
|
+
}
|
|
2480
|
+
if (functionsToApply.length === 0) {
|
|
2481
|
+
return filters2;
|
|
2482
|
+
}
|
|
2483
|
+
return pipe(...functionsToApply)(filters2);
|
|
2342
2484
|
}
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2347
|
-
return;
|
|
2348
|
-
}
|
|
2349
|
-
const isAttribute = !!attribute;
|
|
2350
|
-
if (!isAttribute && !isOperator(key)) {
|
|
2351
|
-
throwInvalidKey({ key, path: path.attribute });
|
|
2352
|
-
}
|
|
2353
|
-
}, ctx),
|
|
2354
|
-
// dynamic zones from filters
|
|
2355
|
-
traverseQueryFilters(visitor, ctx),
|
|
2356
|
-
// morphTo relations from filters; because you can't have deep filtering on morph relations
|
|
2357
|
-
traverseQueryFilters(visitor$1, ctx),
|
|
2358
|
-
// passwords from filters
|
|
2359
|
-
traverseQueryFilters(visitor$3, ctx),
|
|
2360
|
-
// private from filters
|
|
2361
|
-
traverseQueryFilters(visitor$2, ctx)
|
|
2362
|
-
// we allow empty objects to validate and only sanitize them out, so that users may write "lazy" queries without checking their params exist
|
|
2363
|
-
)(filters2);
|
|
2485
|
+
);
|
|
2486
|
+
const defaultValidateFilters = asyncCurry(async (ctx, filters2) => {
|
|
2487
|
+
return validateFilters(ctx, filters2, FILTER_TRAVERSALS);
|
|
2364
2488
|
});
|
|
2365
|
-
const
|
|
2366
|
-
|
|
2367
|
-
|
|
2489
|
+
const SORT_TRAVERSALS = [
|
|
2490
|
+
"nonAttributesOperators",
|
|
2491
|
+
"dynamicZones",
|
|
2492
|
+
"morphRelations",
|
|
2493
|
+
"passwords",
|
|
2494
|
+
"private",
|
|
2495
|
+
"nonScalarEmptyKeys"
|
|
2496
|
+
];
|
|
2497
|
+
const validateSort = asyncCurry(
|
|
2498
|
+
async (ctx, sort2, include) => {
|
|
2499
|
+
if (!ctx.schema) {
|
|
2500
|
+
throw new Error("Missing schema in defaultValidateSort");
|
|
2501
|
+
}
|
|
2502
|
+
const functionsToApply = [];
|
|
2503
|
+
if (include.includes("nonAttributesOperators")) {
|
|
2504
|
+
functionsToApply.push(
|
|
2505
|
+
traverseQuerySort(({ key, attribute, path }) => {
|
|
2506
|
+
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2507
|
+
return;
|
|
2508
|
+
}
|
|
2509
|
+
if (!attribute) {
|
|
2510
|
+
throwInvalidKey({ key, path: path.attribute });
|
|
2511
|
+
}
|
|
2512
|
+
}, ctx)
|
|
2513
|
+
);
|
|
2514
|
+
}
|
|
2515
|
+
if (include.includes("dynamicZones")) {
|
|
2516
|
+
functionsToApply.push(traverseQuerySort(visitor, ctx));
|
|
2517
|
+
}
|
|
2518
|
+
if (include.includes("morphRelations")) {
|
|
2519
|
+
functionsToApply.push(traverseQuerySort(visitor$1, ctx));
|
|
2520
|
+
}
|
|
2521
|
+
if (include.includes("passwords")) {
|
|
2522
|
+
functionsToApply.push(traverseQuerySort(visitor$3, ctx));
|
|
2523
|
+
}
|
|
2524
|
+
if (include.includes("private")) {
|
|
2525
|
+
functionsToApply.push(traverseQuerySort(visitor$2, ctx));
|
|
2526
|
+
}
|
|
2527
|
+
if (include.includes("nonScalarEmptyKeys")) {
|
|
2528
|
+
functionsToApply.push(
|
|
2529
|
+
traverseQuerySort(({ key, attribute, value, path }) => {
|
|
2530
|
+
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2531
|
+
return;
|
|
2532
|
+
}
|
|
2533
|
+
if (!isScalarAttribute(attribute) && isEmpty(value)) {
|
|
2534
|
+
throwInvalidKey({ key, path: path.attribute });
|
|
2535
|
+
}
|
|
2536
|
+
}, ctx)
|
|
2537
|
+
);
|
|
2538
|
+
}
|
|
2539
|
+
if (functionsToApply.length === 0) {
|
|
2540
|
+
return sort2;
|
|
2541
|
+
}
|
|
2542
|
+
return pipe(...functionsToApply)(sort2);
|
|
2368
2543
|
}
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2373
|
-
return;
|
|
2374
|
-
}
|
|
2375
|
-
if (!attribute) {
|
|
2376
|
-
throwInvalidKey({ key, path: path.attribute });
|
|
2377
|
-
}
|
|
2378
|
-
}, ctx),
|
|
2379
|
-
// dynamic zones from sort
|
|
2380
|
-
traverseQuerySort(visitor, ctx),
|
|
2381
|
-
// morphTo relations from sort
|
|
2382
|
-
traverseQuerySort(visitor$1, ctx),
|
|
2383
|
-
// private from sort
|
|
2384
|
-
traverseQuerySort(visitor$2, ctx),
|
|
2385
|
-
// passwords from filters
|
|
2386
|
-
traverseQuerySort(visitor$3, ctx),
|
|
2387
|
-
// keys for empty non-scalar values
|
|
2388
|
-
traverseQuerySort(({ key, attribute, value, path }) => {
|
|
2389
|
-
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2390
|
-
return;
|
|
2391
|
-
}
|
|
2392
|
-
if (!isScalarAttribute(attribute) && isEmpty(value)) {
|
|
2393
|
-
throwInvalidKey({ key, path: path.attribute });
|
|
2394
|
-
}
|
|
2395
|
-
}, ctx)
|
|
2396
|
-
)(sort2);
|
|
2544
|
+
);
|
|
2545
|
+
const defaultValidateSort = asyncCurry(async (ctx, sort2) => {
|
|
2546
|
+
return validateSort(ctx, sort2, SORT_TRAVERSALS);
|
|
2397
2547
|
});
|
|
2398
|
-
const
|
|
2399
|
-
|
|
2400
|
-
|
|
2548
|
+
const FIELDS_TRAVERSALS = ["scalarAttributes", "privateFields", "passwordFields"];
|
|
2549
|
+
const validateFields = asyncCurry(
|
|
2550
|
+
async (ctx, fields2, include) => {
|
|
2551
|
+
if (!ctx.schema) {
|
|
2552
|
+
throw new Error("Missing schema in defaultValidateFields");
|
|
2553
|
+
}
|
|
2554
|
+
const functionsToApply = [];
|
|
2555
|
+
if (include.includes("scalarAttributes")) {
|
|
2556
|
+
functionsToApply.push(
|
|
2557
|
+
traverseQueryFields(({ key, attribute, path }) => {
|
|
2558
|
+
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2559
|
+
return;
|
|
2560
|
+
}
|
|
2561
|
+
if (isNil(attribute) || !isScalarAttribute(attribute)) {
|
|
2562
|
+
throwInvalidKey({ key, path: path.attribute });
|
|
2563
|
+
}
|
|
2564
|
+
}, ctx)
|
|
2565
|
+
);
|
|
2566
|
+
}
|
|
2567
|
+
if (include.includes("privateFields")) {
|
|
2568
|
+
functionsToApply.push(traverseQueryFields(visitor$2, ctx));
|
|
2569
|
+
}
|
|
2570
|
+
if (include.includes("passwordFields")) {
|
|
2571
|
+
functionsToApply.push(traverseQueryFields(visitor$3, ctx));
|
|
2572
|
+
}
|
|
2573
|
+
if (functionsToApply.length === 0) {
|
|
2574
|
+
return fields2;
|
|
2575
|
+
}
|
|
2576
|
+
return pipe(...functionsToApply)(fields2);
|
|
2401
2577
|
}
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2406
|
-
return;
|
|
2407
|
-
}
|
|
2408
|
-
if (isNil(attribute) || !isScalarAttribute(attribute)) {
|
|
2409
|
-
throwInvalidKey({ key, path: path.attribute });
|
|
2410
|
-
}
|
|
2411
|
-
}, ctx),
|
|
2412
|
-
// private fields
|
|
2413
|
-
traverseQueryFields(visitor$2, ctx),
|
|
2414
|
-
// password fields
|
|
2415
|
-
traverseQueryFields(visitor$3, ctx)
|
|
2416
|
-
)(fields2);
|
|
2578
|
+
);
|
|
2579
|
+
const defaultValidateFields = asyncCurry(async (ctx, fields2) => {
|
|
2580
|
+
return validateFields(ctx, fields2, FIELDS_TRAVERSALS);
|
|
2417
2581
|
});
|
|
2418
|
-
const
|
|
2582
|
+
const POPULATE_TRAVERSALS = ["nonAttributesOperators", "private"];
|
|
2583
|
+
const validatePopulate = asyncCurry(
|
|
2584
|
+
async (ctx, populate2, includes) => {
|
|
2585
|
+
if (!ctx.schema) {
|
|
2586
|
+
throw new Error("Missing schema in defaultValidatePopulate");
|
|
2587
|
+
}
|
|
2588
|
+
const functionsToApply = [];
|
|
2589
|
+
functionsToApply.push(
|
|
2590
|
+
traverseQueryPopulate(async ({ key, path, value, schema, attribute, getModel }, { set }) => {
|
|
2591
|
+
if (attribute) {
|
|
2592
|
+
const isPopulatableAttribute = ["relation", "dynamiczone", "component", "media"].includes(
|
|
2593
|
+
attribute.type
|
|
2594
|
+
);
|
|
2595
|
+
if (!isPopulatableAttribute) {
|
|
2596
|
+
throwInvalidKey({ key, path: path.raw });
|
|
2597
|
+
}
|
|
2598
|
+
return;
|
|
2599
|
+
}
|
|
2600
|
+
if (key === "on") {
|
|
2601
|
+
if (!isObject(value)) {
|
|
2602
|
+
return throwInvalidKey({ key, path: path.raw });
|
|
2603
|
+
}
|
|
2604
|
+
const targets = Object.keys(value);
|
|
2605
|
+
for (const target of targets) {
|
|
2606
|
+
const model = getModel(target);
|
|
2607
|
+
if (!model) {
|
|
2608
|
+
throwInvalidKey({ key: target, path: `${path.raw}.${target}` });
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
return;
|
|
2612
|
+
}
|
|
2613
|
+
if (key === "" && value === "*") {
|
|
2614
|
+
return;
|
|
2615
|
+
}
|
|
2616
|
+
if (key === "count") {
|
|
2617
|
+
try {
|
|
2618
|
+
parseType({ type: "boolean", value });
|
|
2619
|
+
return;
|
|
2620
|
+
} catch {
|
|
2621
|
+
throwInvalidKey({ key, path: path.attribute });
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
try {
|
|
2625
|
+
parseType({ type: "boolean", value: key });
|
|
2626
|
+
return;
|
|
2627
|
+
} catch {
|
|
2628
|
+
}
|
|
2629
|
+
if (key === "sort") {
|
|
2630
|
+
set(
|
|
2631
|
+
key,
|
|
2632
|
+
await validateSort(
|
|
2633
|
+
{
|
|
2634
|
+
schema,
|
|
2635
|
+
getModel
|
|
2636
|
+
},
|
|
2637
|
+
value,
|
|
2638
|
+
// pass the sort value
|
|
2639
|
+
includes?.sort || SORT_TRAVERSALS
|
|
2640
|
+
)
|
|
2641
|
+
);
|
|
2642
|
+
return;
|
|
2643
|
+
}
|
|
2644
|
+
if (key === "filters") {
|
|
2645
|
+
set(
|
|
2646
|
+
key,
|
|
2647
|
+
await validateFilters(
|
|
2648
|
+
{
|
|
2649
|
+
schema,
|
|
2650
|
+
getModel
|
|
2651
|
+
},
|
|
2652
|
+
value,
|
|
2653
|
+
// pass the filters value
|
|
2654
|
+
includes?.filters || FILTER_TRAVERSALS
|
|
2655
|
+
)
|
|
2656
|
+
);
|
|
2657
|
+
return;
|
|
2658
|
+
}
|
|
2659
|
+
if (key === "fields") {
|
|
2660
|
+
set(
|
|
2661
|
+
key,
|
|
2662
|
+
await validateFields(
|
|
2663
|
+
{
|
|
2664
|
+
schema,
|
|
2665
|
+
getModel
|
|
2666
|
+
},
|
|
2667
|
+
value,
|
|
2668
|
+
// pass the fields value
|
|
2669
|
+
includes?.fields || FIELDS_TRAVERSALS
|
|
2670
|
+
)
|
|
2671
|
+
);
|
|
2672
|
+
return;
|
|
2673
|
+
}
|
|
2674
|
+
if (key === "populate") {
|
|
2675
|
+
set(
|
|
2676
|
+
key,
|
|
2677
|
+
await validatePopulate(
|
|
2678
|
+
{
|
|
2679
|
+
schema,
|
|
2680
|
+
getModel
|
|
2681
|
+
},
|
|
2682
|
+
value,
|
|
2683
|
+
// pass the nested populate value
|
|
2684
|
+
includes
|
|
2685
|
+
// pass down the same includes object
|
|
2686
|
+
)
|
|
2687
|
+
);
|
|
2688
|
+
return;
|
|
2689
|
+
}
|
|
2690
|
+
if (includes?.populate?.includes("nonAttributesOperators")) {
|
|
2691
|
+
throwInvalidKey({ key, path: path.attribute });
|
|
2692
|
+
}
|
|
2693
|
+
}, ctx)
|
|
2694
|
+
);
|
|
2695
|
+
if (includes?.populate?.includes("private")) {
|
|
2696
|
+
functionsToApply.push(traverseQueryPopulate(visitor$2, ctx));
|
|
2697
|
+
}
|
|
2698
|
+
if (functionsToApply.length === 0) {
|
|
2699
|
+
return populate2;
|
|
2700
|
+
}
|
|
2701
|
+
return pipe(...functionsToApply)(populate2);
|
|
2702
|
+
}
|
|
2703
|
+
);
|
|
2704
|
+
const defaultValidatePopulate = asyncCurry(async (ctx, populate2) => {
|
|
2419
2705
|
if (!ctx.schema) {
|
|
2420
2706
|
throw new Error("Missing schema in defaultValidatePopulate");
|
|
2421
2707
|
}
|
|
2422
|
-
return
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
set(
|
|
2429
|
-
key,
|
|
2430
|
-
await defaultValidateSort(
|
|
2431
|
-
{
|
|
2432
|
-
schema,
|
|
2433
|
-
getModel
|
|
2434
|
-
},
|
|
2435
|
-
value
|
|
2436
|
-
)
|
|
2437
|
-
);
|
|
2438
|
-
}
|
|
2439
|
-
if (key === "filters") {
|
|
2440
|
-
set(
|
|
2441
|
-
key,
|
|
2442
|
-
await defaultValidateFilters(
|
|
2443
|
-
{
|
|
2444
|
-
schema,
|
|
2445
|
-
getModel
|
|
2446
|
-
},
|
|
2447
|
-
value
|
|
2448
|
-
)
|
|
2449
|
-
);
|
|
2450
|
-
}
|
|
2451
|
-
if (key === "fields") {
|
|
2452
|
-
set(
|
|
2453
|
-
key,
|
|
2454
|
-
await defaultValidateFields(
|
|
2455
|
-
{
|
|
2456
|
-
schema,
|
|
2457
|
-
getModel
|
|
2458
|
-
},
|
|
2459
|
-
value
|
|
2460
|
-
)
|
|
2461
|
-
);
|
|
2462
|
-
}
|
|
2463
|
-
if (key === "populate") {
|
|
2464
|
-
set(
|
|
2465
|
-
key,
|
|
2466
|
-
await defaultValidatePopulate(
|
|
2467
|
-
{
|
|
2468
|
-
schema,
|
|
2469
|
-
getModel
|
|
2470
|
-
},
|
|
2471
|
-
value
|
|
2472
|
-
)
|
|
2473
|
-
);
|
|
2474
|
-
}
|
|
2475
|
-
}, ctx),
|
|
2476
|
-
// Remove private fields
|
|
2477
|
-
traverseQueryPopulate(visitor$2, ctx)
|
|
2478
|
-
)(populate2);
|
|
2708
|
+
return validatePopulate(ctx, populate2, {
|
|
2709
|
+
filters: FILTER_TRAVERSALS,
|
|
2710
|
+
sort: SORT_TRAVERSALS,
|
|
2711
|
+
fields: FIELDS_TRAVERSALS,
|
|
2712
|
+
populate: POPULATE_TRAVERSALS
|
|
2713
|
+
});
|
|
2479
2714
|
});
|
|
2480
2715
|
const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2481
2716
|
__proto__: null,
|
|
2717
|
+
FIELDS_TRAVERSALS,
|
|
2718
|
+
FILTER_TRAVERSALS,
|
|
2719
|
+
POPULATE_TRAVERSALS,
|
|
2720
|
+
SORT_TRAVERSALS,
|
|
2482
2721
|
defaultValidateFields,
|
|
2483
2722
|
defaultValidateFilters,
|
|
2484
2723
|
defaultValidatePopulate,
|
|
2485
2724
|
defaultValidateSort,
|
|
2486
|
-
throwPasswords
|
|
2725
|
+
throwPasswords,
|
|
2726
|
+
validateFields,
|
|
2727
|
+
validateFilters,
|
|
2728
|
+
validatePopulate,
|
|
2729
|
+
validateSort
|
|
2487
2730
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
2488
2731
|
const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants$1;
|
|
2489
2732
|
const createAPIValidators = (opts) => {
|
|
@@ -2538,24 +2781,24 @@ const createAPIValidators = (opts) => {
|
|
|
2538
2781
|
}
|
|
2539
2782
|
const { filters: filters2, sort: sort2, fields: fields2, populate: populate2 } = query;
|
|
2540
2783
|
if (filters2) {
|
|
2541
|
-
await
|
|
2784
|
+
await validateFilters2(filters2, schema, { auth });
|
|
2542
2785
|
}
|
|
2543
2786
|
if (sort2) {
|
|
2544
|
-
await
|
|
2787
|
+
await validateSort2(sort2, schema, { auth });
|
|
2545
2788
|
}
|
|
2546
2789
|
if (fields2) {
|
|
2547
|
-
await
|
|
2790
|
+
await validateFields2(fields2, schema);
|
|
2548
2791
|
}
|
|
2549
2792
|
if (populate2 && populate2 !== "*") {
|
|
2550
|
-
await
|
|
2793
|
+
await validatePopulate2(populate2, schema);
|
|
2551
2794
|
}
|
|
2552
2795
|
};
|
|
2553
|
-
const
|
|
2796
|
+
const validateFilters2 = async (filters2, schema, { auth } = {}) => {
|
|
2554
2797
|
if (!schema) {
|
|
2555
2798
|
throw new Error("Missing schema in validateFilters");
|
|
2556
2799
|
}
|
|
2557
2800
|
if (isArray(filters2)) {
|
|
2558
|
-
await Promise.all(filters2.map((filter) =>
|
|
2801
|
+
await Promise.all(filters2.map((filter) => validateFilters2(filter, schema, { auth })));
|
|
2559
2802
|
return;
|
|
2560
2803
|
}
|
|
2561
2804
|
const transforms = [defaultValidateFilters({ schema, getModel })];
|
|
@@ -2577,7 +2820,7 @@ const createAPIValidators = (opts) => {
|
|
|
2577
2820
|
throw e;
|
|
2578
2821
|
}
|
|
2579
2822
|
};
|
|
2580
|
-
const
|
|
2823
|
+
const validateSort2 = async (sort2, schema, { auth } = {}) => {
|
|
2581
2824
|
if (!schema) {
|
|
2582
2825
|
throw new Error("Missing schema in validateSort");
|
|
2583
2826
|
}
|
|
@@ -2600,7 +2843,7 @@ const createAPIValidators = (opts) => {
|
|
|
2600
2843
|
throw e;
|
|
2601
2844
|
}
|
|
2602
2845
|
};
|
|
2603
|
-
const
|
|
2846
|
+
const validateFields2 = async (fields2, schema) => {
|
|
2604
2847
|
if (!schema) {
|
|
2605
2848
|
throw new Error("Missing schema in validateFields");
|
|
2606
2849
|
}
|
|
@@ -2615,7 +2858,7 @@ const createAPIValidators = (opts) => {
|
|
|
2615
2858
|
throw e;
|
|
2616
2859
|
}
|
|
2617
2860
|
};
|
|
2618
|
-
const
|
|
2861
|
+
const validatePopulate2 = async (populate2, schema, { auth } = {}) => {
|
|
2619
2862
|
if (!schema) {
|
|
2620
2863
|
throw new Error("Missing schema in sanitizePopulate");
|
|
2621
2864
|
}
|
|
@@ -2641,10 +2884,10 @@ const createAPIValidators = (opts) => {
|
|
|
2641
2884
|
return {
|
|
2642
2885
|
input: validateInput,
|
|
2643
2886
|
query: validateQuery,
|
|
2644
|
-
filters:
|
|
2645
|
-
sort:
|
|
2646
|
-
fields:
|
|
2647
|
-
populate:
|
|
2887
|
+
filters: validateFilters2,
|
|
2888
|
+
sort: validateSort2,
|
|
2889
|
+
fields: validateFields2,
|
|
2890
|
+
populate: validatePopulate2
|
|
2648
2891
|
};
|
|
2649
2892
|
};
|
|
2650
2893
|
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -3101,28 +3344,6 @@ const yup = /* @__PURE__ */ _mergeNamespaces({
|
|
|
3101
3344
|
StrapiIDSchema,
|
|
3102
3345
|
strapiID
|
|
3103
3346
|
}, [yup$1]);
|
|
3104
|
-
const MANY_RELATIONS = ["oneToMany", "manyToMany"];
|
|
3105
|
-
const getRelationalFields = (contentType) => {
|
|
3106
|
-
return Object.keys(contentType.attributes).filter((attributeName) => {
|
|
3107
|
-
return contentType.attributes[attributeName].type === "relation";
|
|
3108
|
-
});
|
|
3109
|
-
};
|
|
3110
|
-
const isOneToAny = (attribute) => isRelationalAttribute(attribute) && ["oneToOne", "oneToMany"].includes(attribute.relation);
|
|
3111
|
-
const isManyToAny = (attribute) => isRelationalAttribute(attribute) && ["manyToMany", "manyToOne"].includes(attribute.relation);
|
|
3112
|
-
const isAnyToOne = (attribute) => isRelationalAttribute(attribute) && ["oneToOne", "manyToOne"].includes(attribute.relation);
|
|
3113
|
-
const isAnyToMany = (attribute) => isRelationalAttribute(attribute) && ["oneToMany", "manyToMany"].includes(attribute.relation);
|
|
3114
|
-
const constants = {
|
|
3115
|
-
MANY_RELATIONS
|
|
3116
|
-
};
|
|
3117
|
-
const relations = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
3118
|
-
__proto__: null,
|
|
3119
|
-
constants,
|
|
3120
|
-
getRelationalFields,
|
|
3121
|
-
isAnyToMany,
|
|
3122
|
-
isAnyToOne,
|
|
3123
|
-
isManyToAny,
|
|
3124
|
-
isOneToAny
|
|
3125
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
3126
3347
|
const validateZod = (schema) => (data) => {
|
|
3127
3348
|
try {
|
|
3128
3349
|
return schema.parse(data);
|