@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.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 newMorphValue = [];
1333
- 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
+ }
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
- newMorphValue.push(element);
1395
+ allowedElements.push(element);
1338
1396
  }
1339
1397
  }
1340
- if (newMorphValue.length === 0) {
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) => isArray(value) && value.every(isString);
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((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, () => ({
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
- 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
+ }
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 defaultValidateFilters = curry((ctx, filters2) => {
2340
- if (!ctx.schema) {
2341
- 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);
2342
2484
  }
2343
- return pipe(
2344
- // keys that are not attributes or valid operators
2345
- traverseQueryFilters(({ key, attribute, path }) => {
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 defaultValidateSort = curry((ctx, sort2) => {
2366
- if (!ctx.schema) {
2367
- 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);
2368
2543
  }
2369
- return pipe(
2370
- // non attribute keys
2371
- traverseQuerySort(({ key, attribute, path }) => {
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 defaultValidateFields = curry((ctx, fields2) => {
2399
- if (!ctx.schema) {
2400
- 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);
2401
2577
  }
2402
- return pipe(
2403
- // Only allow scalar attributes
2404
- traverseQueryFields(({ key, attribute, path }) => {
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 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) => {
2419
2705
  if (!ctx.schema) {
2420
2706
  throw new Error("Missing schema in defaultValidatePopulate");
2421
2707
  }
2422
- return pipe(
2423
- traverseQueryPopulate(async ({ key, value, schema, attribute, getModel }, { set }) => {
2424
- if (attribute) {
2425
- return;
2426
- }
2427
- if (key === "sort") {
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 validateFilters(filters2, schema, { auth });
2784
+ await validateFilters2(filters2, schema, { auth });
2542
2785
  }
2543
2786
  if (sort2) {
2544
- await validateSort(sort2, schema, { auth });
2787
+ await validateSort2(sort2, schema, { auth });
2545
2788
  }
2546
2789
  if (fields2) {
2547
- await validateFields(fields2, schema);
2790
+ await validateFields2(fields2, schema);
2548
2791
  }
2549
2792
  if (populate2 && populate2 !== "*") {
2550
- await validatePopulate(populate2, schema);
2793
+ await validatePopulate2(populate2, schema);
2551
2794
  }
2552
2795
  };
2553
- const validateFilters = async (filters2, schema, { auth } = {}) => {
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) => validateFilters(filter, schema, { auth })));
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 validateSort = async (sort2, schema, { auth } = {}) => {
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 validateFields = async (fields2, schema) => {
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 validatePopulate = async (populate2, schema, { auth } = {}) => {
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: validateFilters,
2645
- sort: validateSort,
2646
- fields: validateFields,
2647
- populate: validatePopulate
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);