@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.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 newMorphValue = [];
1323
- for (const element of data[key]) {
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
- newMorphValue.push(element);
1395
+ allowedElements.push(element);
1328
1396
  }
1329
1397
  }
1330
- if (newMorphValue.length === 0) {
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) => isArray(value) && value.every(isString);
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((value) => eq("*", value), constant("*")).parse(isString, () => ({
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
- for (const element of data[key]) {
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 defaultValidateFilters = curry((ctx, filters2) => {
2330
- if (!ctx.schema) {
2331
- throw new Error("Missing schema in defaultValidateFilters");
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
- return pipe(
2334
- // keys that are not attributes or valid operators
2335
- traverseQueryFilters(({ key, attribute, path }) => {
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 defaultValidateSort = curry((ctx, sort2) => {
2356
- if (!ctx.schema) {
2357
- throw new Error("Missing schema in defaultValidateSort");
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
- return pipe(
2360
- // non attribute keys
2361
- traverseQuerySort(({ key, attribute, path }) => {
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 defaultValidateFields = curry((ctx, fields2) => {
2389
- if (!ctx.schema) {
2390
- throw new Error("Missing schema in defaultValidateFields");
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
- return pipe(
2393
- // Only allow scalar attributes
2394
- traverseQueryFields(({ key, attribute, path }) => {
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 defaultValidatePopulate = curry((ctx, populate2) => {
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 pipe(
2413
- traverseQueryPopulate(async ({ key, value, schema, attribute, getModel }, { set }) => {
2414
- if (attribute) {
2415
- return;
2416
- }
2417
- if (key === "sort") {
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 validateFilters(filters2, schema, { auth });
2784
+ await validateFilters2(filters2, schema, { auth });
2532
2785
  }
2533
2786
  if (sort2) {
2534
- await validateSort(sort2, schema, { auth });
2787
+ await validateSort2(sort2, schema, { auth });
2535
2788
  }
2536
2789
  if (fields2) {
2537
- await validateFields(fields2, schema);
2790
+ await validateFields2(fields2, schema);
2538
2791
  }
2539
2792
  if (populate2 && populate2 !== "*") {
2540
- await validatePopulate(populate2, schema);
2793
+ await validatePopulate2(populate2, schema);
2541
2794
  }
2542
2795
  };
2543
- const validateFilters = async (filters2, schema, { auth } = {}) => {
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) => validateFilters(filter, schema, { auth })));
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 validateSort = async (sort2, schema, { auth } = {}) => {
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 validateFields = async (fields2, schema) => {
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 validatePopulate = async (populate2, schema, { auth } = {}) => {
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: validateFilters,
2635
- sort: validateSort,
2636
- fields: validateFields,
2637
- populate: validatePopulate
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);