@strapi/utils 5.0.0-rc.9 → 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 -178
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +410 -179
- package/dist/index.mjs.map +1 -1
- package/dist/provider-factory.d.ts +1 -1
- 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";
|
|
@@ -1308,6 +1308,32 @@ const visitor$7 = ({ schema, key, attribute }, { remove: remove2 }) => {
|
|
|
1308
1308
|
remove2(key);
|
|
1309
1309
|
}
|
|
1310
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" }));
|
|
1311
1337
|
const ACTIONS_TO_VERIFY$1 = ["find"];
|
|
1312
1338
|
const { CREATED_BY_ATTRIBUTE: CREATED_BY_ATTRIBUTE$1, UPDATED_BY_ATTRIBUTE: UPDATED_BY_ATTRIBUTE$1 } = constants$1;
|
|
1313
1339
|
const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schema }, { remove: remove2, set }) => {
|
|
@@ -1319,19 +1345,57 @@ const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schem
|
|
|
1319
1345
|
return;
|
|
1320
1346
|
}
|
|
1321
1347
|
const handleMorphRelation = async () => {
|
|
1322
|
-
const
|
|
1323
|
-
|
|
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
|
+
}
|
|
1324
1392
|
const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
|
|
1325
1393
|
const isAllowed = await hasAccessToSomeScopes$1(scopes, auth);
|
|
1326
1394
|
if (isAllowed) {
|
|
1327
|
-
|
|
1395
|
+
allowedElements.push(element);
|
|
1328
1396
|
}
|
|
1329
1397
|
}
|
|
1330
|
-
|
|
1331
|
-
remove2(key);
|
|
1332
|
-
} else {
|
|
1333
|
-
set(key, newMorphValue);
|
|
1334
|
-
}
|
|
1398
|
+
return allowedElements;
|
|
1335
1399
|
};
|
|
1336
1400
|
const handleRegularRelation = async () => {
|
|
1337
1401
|
const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${attribute.target}.${action}`);
|
|
@@ -1857,10 +1921,17 @@ const populate = traverseFactory().intercept(isStringArray$1, async (visitor2, o
|
|
|
1857
1921
|
}
|
|
1858
1922
|
});
|
|
1859
1923
|
const traverseQueryPopulate = curry(populate.traverse);
|
|
1860
|
-
const isStringArray = (value) =>
|
|
1924
|
+
const isStringArray = (value) => {
|
|
1925
|
+
return isArray(value) && value.every(isString);
|
|
1926
|
+
};
|
|
1861
1927
|
const fields = traverseFactory().intercept(isStringArray, async (visitor2, options, fields2, { recurse }) => {
|
|
1862
1928
|
return Promise.all(fields2.map((field) => recurse(visitor2, options, field)));
|
|
1863
|
-
}).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, () => ({
|
|
1864
1935
|
transform: trim,
|
|
1865
1936
|
remove(key, data) {
|
|
1866
1937
|
return data === key ? void 0 : data;
|
|
@@ -2161,6 +2232,15 @@ const throwInvalidKey = ({ key, path }) => {
|
|
|
2161
2232
|
path
|
|
2162
2233
|
});
|
|
2163
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
|
+
};
|
|
2164
2244
|
const visitor$3 = ({ key, attribute, path }) => {
|
|
2165
2245
|
if (attribute?.type === "password") {
|
|
2166
2246
|
throwInvalidKey({ key, path: path.attribute });
|
|
@@ -2186,7 +2266,40 @@ const throwRestrictedRelations = (auth) => async ({ data, key, attribute, schema
|
|
|
2186
2266
|
return;
|
|
2187
2267
|
}
|
|
2188
2268
|
const handleMorphRelation = async () => {
|
|
2189
|
-
|
|
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
|
+
}
|
|
2190
2303
|
const scopes = ACTIONS_TO_VERIFY.map((action) => `${element.__type}.${action}`);
|
|
2191
2304
|
const isAllowed = await hasAccessToSomeScopes(scopes, auth);
|
|
2192
2305
|
if (!isAllowed) {
|
|
@@ -2326,154 +2439,294 @@ const throwPasswords = (ctx) => async (entity) => {
|
|
|
2326
2439
|
}
|
|
2327
2440
|
return traverseEntity$1(visitor$3, ctx, entity);
|
|
2328
2441
|
};
|
|
2329
|
-
const
|
|
2330
|
-
|
|
2331
|
-
|
|
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);
|
|
2332
2484
|
}
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2337
|
-
return;
|
|
2338
|
-
}
|
|
2339
|
-
const isAttribute = !!attribute;
|
|
2340
|
-
if (!isAttribute && !isOperator(key)) {
|
|
2341
|
-
throwInvalidKey({ key, path: path.attribute });
|
|
2342
|
-
}
|
|
2343
|
-
}, ctx),
|
|
2344
|
-
// dynamic zones from filters
|
|
2345
|
-
traverseQueryFilters(visitor, ctx),
|
|
2346
|
-
// morphTo relations from filters; because you can't have deep filtering on morph relations
|
|
2347
|
-
traverseQueryFilters(visitor$1, ctx),
|
|
2348
|
-
// passwords from filters
|
|
2349
|
-
traverseQueryFilters(visitor$3, ctx),
|
|
2350
|
-
// private from filters
|
|
2351
|
-
traverseQueryFilters(visitor$2, ctx)
|
|
2352
|
-
// we allow empty objects to validate and only sanitize them out, so that users may write "lazy" queries without checking their params exist
|
|
2353
|
-
)(filters2);
|
|
2485
|
+
);
|
|
2486
|
+
const defaultValidateFilters = asyncCurry(async (ctx, filters2) => {
|
|
2487
|
+
return validateFilters(ctx, filters2, FILTER_TRAVERSALS);
|
|
2354
2488
|
});
|
|
2355
|
-
const
|
|
2356
|
-
|
|
2357
|
-
|
|
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);
|
|
2358
2543
|
}
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2363
|
-
return;
|
|
2364
|
-
}
|
|
2365
|
-
if (!attribute) {
|
|
2366
|
-
throwInvalidKey({ key, path: path.attribute });
|
|
2367
|
-
}
|
|
2368
|
-
}, ctx),
|
|
2369
|
-
// dynamic zones from sort
|
|
2370
|
-
traverseQuerySort(visitor, ctx),
|
|
2371
|
-
// morphTo relations from sort
|
|
2372
|
-
traverseQuerySort(visitor$1, ctx),
|
|
2373
|
-
// private from sort
|
|
2374
|
-
traverseQuerySort(visitor$2, ctx),
|
|
2375
|
-
// passwords from filters
|
|
2376
|
-
traverseQuerySort(visitor$3, ctx),
|
|
2377
|
-
// keys for empty non-scalar values
|
|
2378
|
-
traverseQuerySort(({ key, attribute, value, path }) => {
|
|
2379
|
-
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2380
|
-
return;
|
|
2381
|
-
}
|
|
2382
|
-
if (!isScalarAttribute(attribute) && isEmpty(value)) {
|
|
2383
|
-
throwInvalidKey({ key, path: path.attribute });
|
|
2384
|
-
}
|
|
2385
|
-
}, ctx)
|
|
2386
|
-
)(sort2);
|
|
2544
|
+
);
|
|
2545
|
+
const defaultValidateSort = asyncCurry(async (ctx, sort2) => {
|
|
2546
|
+
return validateSort(ctx, sort2, SORT_TRAVERSALS);
|
|
2387
2547
|
});
|
|
2388
|
-
const
|
|
2389
|
-
|
|
2390
|
-
|
|
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);
|
|
2391
2577
|
}
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
|
|
2396
|
-
return;
|
|
2397
|
-
}
|
|
2398
|
-
if (isNil(attribute) || !isScalarAttribute(attribute)) {
|
|
2399
|
-
throwInvalidKey({ key, path: path.attribute });
|
|
2400
|
-
}
|
|
2401
|
-
}, ctx),
|
|
2402
|
-
// private fields
|
|
2403
|
-
traverseQueryFields(visitor$2, ctx),
|
|
2404
|
-
// password fields
|
|
2405
|
-
traverseQueryFields(visitor$3, ctx)
|
|
2406
|
-
)(fields2);
|
|
2578
|
+
);
|
|
2579
|
+
const defaultValidateFields = asyncCurry(async (ctx, fields2) => {
|
|
2580
|
+
return validateFields(ctx, fields2, FIELDS_TRAVERSALS);
|
|
2407
2581
|
});
|
|
2408
|
-
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) => {
|
|
2409
2705
|
if (!ctx.schema) {
|
|
2410
2706
|
throw new Error("Missing schema in defaultValidatePopulate");
|
|
2411
2707
|
}
|
|
2412
|
-
return
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
set(
|
|
2419
|
-
key,
|
|
2420
|
-
await defaultValidateSort(
|
|
2421
|
-
{
|
|
2422
|
-
schema,
|
|
2423
|
-
getModel
|
|
2424
|
-
},
|
|
2425
|
-
value
|
|
2426
|
-
)
|
|
2427
|
-
);
|
|
2428
|
-
}
|
|
2429
|
-
if (key === "filters") {
|
|
2430
|
-
set(
|
|
2431
|
-
key,
|
|
2432
|
-
await defaultValidateFilters(
|
|
2433
|
-
{
|
|
2434
|
-
schema,
|
|
2435
|
-
getModel
|
|
2436
|
-
},
|
|
2437
|
-
value
|
|
2438
|
-
)
|
|
2439
|
-
);
|
|
2440
|
-
}
|
|
2441
|
-
if (key === "fields") {
|
|
2442
|
-
set(
|
|
2443
|
-
key,
|
|
2444
|
-
await defaultValidateFields(
|
|
2445
|
-
{
|
|
2446
|
-
schema,
|
|
2447
|
-
getModel
|
|
2448
|
-
},
|
|
2449
|
-
value
|
|
2450
|
-
)
|
|
2451
|
-
);
|
|
2452
|
-
}
|
|
2453
|
-
if (key === "populate") {
|
|
2454
|
-
set(
|
|
2455
|
-
key,
|
|
2456
|
-
await defaultValidatePopulate(
|
|
2457
|
-
{
|
|
2458
|
-
schema,
|
|
2459
|
-
getModel
|
|
2460
|
-
},
|
|
2461
|
-
value
|
|
2462
|
-
)
|
|
2463
|
-
);
|
|
2464
|
-
}
|
|
2465
|
-
}, ctx),
|
|
2466
|
-
// Remove private fields
|
|
2467
|
-
traverseQueryPopulate(visitor$2, ctx)
|
|
2468
|
-
)(populate2);
|
|
2708
|
+
return validatePopulate(ctx, populate2, {
|
|
2709
|
+
filters: FILTER_TRAVERSALS,
|
|
2710
|
+
sort: SORT_TRAVERSALS,
|
|
2711
|
+
fields: FIELDS_TRAVERSALS,
|
|
2712
|
+
populate: POPULATE_TRAVERSALS
|
|
2713
|
+
});
|
|
2469
2714
|
});
|
|
2470
2715
|
const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2471
2716
|
__proto__: null,
|
|
2717
|
+
FIELDS_TRAVERSALS,
|
|
2718
|
+
FILTER_TRAVERSALS,
|
|
2719
|
+
POPULATE_TRAVERSALS,
|
|
2720
|
+
SORT_TRAVERSALS,
|
|
2472
2721
|
defaultValidateFields,
|
|
2473
2722
|
defaultValidateFilters,
|
|
2474
2723
|
defaultValidatePopulate,
|
|
2475
2724
|
defaultValidateSort,
|
|
2476
|
-
throwPasswords
|
|
2725
|
+
throwPasswords,
|
|
2726
|
+
validateFields,
|
|
2727
|
+
validateFilters,
|
|
2728
|
+
validatePopulate,
|
|
2729
|
+
validateSort
|
|
2477
2730
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
2478
2731
|
const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants$1;
|
|
2479
2732
|
const createAPIValidators = (opts) => {
|
|
@@ -2528,24 +2781,24 @@ const createAPIValidators = (opts) => {
|
|
|
2528
2781
|
}
|
|
2529
2782
|
const { filters: filters2, sort: sort2, fields: fields2, populate: populate2 } = query;
|
|
2530
2783
|
if (filters2) {
|
|
2531
|
-
await
|
|
2784
|
+
await validateFilters2(filters2, schema, { auth });
|
|
2532
2785
|
}
|
|
2533
2786
|
if (sort2) {
|
|
2534
|
-
await
|
|
2787
|
+
await validateSort2(sort2, schema, { auth });
|
|
2535
2788
|
}
|
|
2536
2789
|
if (fields2) {
|
|
2537
|
-
await
|
|
2790
|
+
await validateFields2(fields2, schema);
|
|
2538
2791
|
}
|
|
2539
2792
|
if (populate2 && populate2 !== "*") {
|
|
2540
|
-
await
|
|
2793
|
+
await validatePopulate2(populate2, schema);
|
|
2541
2794
|
}
|
|
2542
2795
|
};
|
|
2543
|
-
const
|
|
2796
|
+
const validateFilters2 = async (filters2, schema, { auth } = {}) => {
|
|
2544
2797
|
if (!schema) {
|
|
2545
2798
|
throw new Error("Missing schema in validateFilters");
|
|
2546
2799
|
}
|
|
2547
2800
|
if (isArray(filters2)) {
|
|
2548
|
-
await Promise.all(filters2.map((filter) =>
|
|
2801
|
+
await Promise.all(filters2.map((filter) => validateFilters2(filter, schema, { auth })));
|
|
2549
2802
|
return;
|
|
2550
2803
|
}
|
|
2551
2804
|
const transforms = [defaultValidateFilters({ schema, getModel })];
|
|
@@ -2567,7 +2820,7 @@ const createAPIValidators = (opts) => {
|
|
|
2567
2820
|
throw e;
|
|
2568
2821
|
}
|
|
2569
2822
|
};
|
|
2570
|
-
const
|
|
2823
|
+
const validateSort2 = async (sort2, schema, { auth } = {}) => {
|
|
2571
2824
|
if (!schema) {
|
|
2572
2825
|
throw new Error("Missing schema in validateSort");
|
|
2573
2826
|
}
|
|
@@ -2590,7 +2843,7 @@ const createAPIValidators = (opts) => {
|
|
|
2590
2843
|
throw e;
|
|
2591
2844
|
}
|
|
2592
2845
|
};
|
|
2593
|
-
const
|
|
2846
|
+
const validateFields2 = async (fields2, schema) => {
|
|
2594
2847
|
if (!schema) {
|
|
2595
2848
|
throw new Error("Missing schema in validateFields");
|
|
2596
2849
|
}
|
|
@@ -2605,7 +2858,7 @@ const createAPIValidators = (opts) => {
|
|
|
2605
2858
|
throw e;
|
|
2606
2859
|
}
|
|
2607
2860
|
};
|
|
2608
|
-
const
|
|
2861
|
+
const validatePopulate2 = async (populate2, schema, { auth } = {}) => {
|
|
2609
2862
|
if (!schema) {
|
|
2610
2863
|
throw new Error("Missing schema in sanitizePopulate");
|
|
2611
2864
|
}
|
|
@@ -2631,10 +2884,10 @@ const createAPIValidators = (opts) => {
|
|
|
2631
2884
|
return {
|
|
2632
2885
|
input: validateInput,
|
|
2633
2886
|
query: validateQuery,
|
|
2634
|
-
filters:
|
|
2635
|
-
sort:
|
|
2636
|
-
fields:
|
|
2637
|
-
populate:
|
|
2887
|
+
filters: validateFilters2,
|
|
2888
|
+
sort: validateSort2,
|
|
2889
|
+
fields: validateFields2,
|
|
2890
|
+
populate: validatePopulate2
|
|
2638
2891
|
};
|
|
2639
2892
|
};
|
|
2640
2893
|
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -3091,28 +3344,6 @@ const yup = /* @__PURE__ */ _mergeNamespaces({
|
|
|
3091
3344
|
StrapiIDSchema,
|
|
3092
3345
|
strapiID
|
|
3093
3346
|
}, [yup$1]);
|
|
3094
|
-
const MANY_RELATIONS = ["oneToMany", "manyToMany"];
|
|
3095
|
-
const getRelationalFields = (contentType) => {
|
|
3096
|
-
return Object.keys(contentType.attributes).filter((attributeName) => {
|
|
3097
|
-
return contentType.attributes[attributeName].type === "relation";
|
|
3098
|
-
});
|
|
3099
|
-
};
|
|
3100
|
-
const isOneToAny = (attribute) => isRelationalAttribute(attribute) && ["oneToOne", "oneToMany"].includes(attribute.relation);
|
|
3101
|
-
const isManyToAny = (attribute) => isRelationalAttribute(attribute) && ["manyToMany", "manyToOne"].includes(attribute.relation);
|
|
3102
|
-
const isAnyToOne = (attribute) => isRelationalAttribute(attribute) && ["oneToOne", "manyToOne"].includes(attribute.relation);
|
|
3103
|
-
const isAnyToMany = (attribute) => isRelationalAttribute(attribute) && ["oneToMany", "manyToMany"].includes(attribute.relation);
|
|
3104
|
-
const constants = {
|
|
3105
|
-
MANY_RELATIONS
|
|
3106
|
-
};
|
|
3107
|
-
const relations = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
3108
|
-
__proto__: null,
|
|
3109
|
-
constants,
|
|
3110
|
-
getRelationalFields,
|
|
3111
|
-
isAnyToMany,
|
|
3112
|
-
isAnyToOne,
|
|
3113
|
-
isManyToAny,
|
|
3114
|
-
isOneToAny
|
|
3115
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
3116
3347
|
const validateZod = (schema) => (data) => {
|
|
3117
3348
|
try {
|
|
3118
3349
|
return schema.parse(data);
|