@strapi/utils 5.0.0-rc.2 → 5.0.0-rc.21

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
@@ -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
  },
@@ -1867,10 +1857,17 @@ const populate = traverseFactory().intercept(isStringArray$1, async (visitor2, o
1867
1857
  }
1868
1858
  });
1869
1859
  const traverseQueryPopulate = curry(populate.traverse);
1870
- const isStringArray = (value) => isArray(value) && value.every(isString);
1860
+ const isStringArray = (value) => {
1861
+ return isArray(value) && value.every(isString);
1862
+ };
1871
1863
  const fields = traverseFactory().intercept(isStringArray, async (visitor2, options, fields2, { recurse }) => {
1872
1864
  return Promise.all(fields2.map((field) => recurse(visitor2, options, field)));
1873
- }).intercept((value) => eq("*", value), constant("*")).parse(isString, () => ({
1865
+ }).intercept(
1866
+ (value) => isString(value) && value.includes(","),
1867
+ (visitor2, options, fields2, { recurse }) => {
1868
+ return Promise.all(fields2.split(",").map((field) => recurse(visitor2, options, field)));
1869
+ }
1870
+ ).intercept((value) => eq("*", value), constant("*")).parse(isString, () => ({
1874
1871
  transform: trim,
1875
1872
  remove(key, data) {
1876
1873
  return data === key ? void 0 : data;
@@ -2171,6 +2168,15 @@ const throwInvalidKey = ({ key, path }) => {
2171
2168
  path
2172
2169
  });
2173
2170
  };
2171
+ const asyncCurry = (fn) => {
2172
+ const curried = (...args) => {
2173
+ if (args.length >= fn.length) {
2174
+ return fn(...args);
2175
+ }
2176
+ return (...moreArgs) => curried(...args, ...moreArgs);
2177
+ };
2178
+ return curried;
2179
+ };
2174
2180
  const visitor$3 = ({ key, attribute, path }) => {
2175
2181
  if (attribute?.type === "password") {
2176
2182
  throwInvalidKey({ key, path: path.attribute });
@@ -2336,154 +2342,294 @@ const throwPasswords = (ctx) => async (entity) => {
2336
2342
  }
2337
2343
  return traverseEntity$1(visitor$3, ctx, entity);
2338
2344
  };
2339
- const defaultValidateFilters = curry((ctx, filters2) => {
2340
- if (!ctx.schema) {
2341
- throw new Error("Missing schema in defaultValidateFilters");
2345
+ const FILTER_TRAVERSALS = [
2346
+ "nonAttributesOperators",
2347
+ "dynamicZones",
2348
+ "morphRelations",
2349
+ "passwords",
2350
+ "private"
2351
+ ];
2352
+ const validateFilters = asyncCurry(
2353
+ async (ctx, filters2, include) => {
2354
+ if (!ctx.schema) {
2355
+ throw new Error("Missing schema in defaultValidateFilters");
2356
+ }
2357
+ const functionsToApply = [];
2358
+ if (include.includes("nonAttributesOperators")) {
2359
+ functionsToApply.push(
2360
+ traverseQueryFilters(({ key, attribute, path }) => {
2361
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2362
+ return;
2363
+ }
2364
+ const isAttribute = !!attribute;
2365
+ if (!isAttribute && !isOperator(key)) {
2366
+ throwInvalidKey({ key, path: path.attribute });
2367
+ }
2368
+ }, ctx)
2369
+ );
2370
+ }
2371
+ if (include.includes("dynamicZones")) {
2372
+ functionsToApply.push(traverseQueryFilters(visitor, ctx));
2373
+ }
2374
+ if (include.includes("morphRelations")) {
2375
+ functionsToApply.push(traverseQueryFilters(visitor$1, ctx));
2376
+ }
2377
+ if (include.includes("passwords")) {
2378
+ functionsToApply.push(traverseQueryFilters(visitor$3, ctx));
2379
+ }
2380
+ if (include.includes("private")) {
2381
+ functionsToApply.push(traverseQueryFilters(visitor$2, ctx));
2382
+ }
2383
+ if (functionsToApply.length === 0) {
2384
+ return filters2;
2385
+ }
2386
+ return pipe(...functionsToApply)(filters2);
2342
2387
  }
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);
2388
+ );
2389
+ const defaultValidateFilters = asyncCurry(async (ctx, filters2) => {
2390
+ return validateFilters(ctx, filters2, FILTER_TRAVERSALS);
2364
2391
  });
2365
- const defaultValidateSort = curry((ctx, sort2) => {
2366
- if (!ctx.schema) {
2367
- throw new Error("Missing schema in defaultValidateSort");
2392
+ const SORT_TRAVERSALS = [
2393
+ "nonAttributesOperators",
2394
+ "dynamicZones",
2395
+ "morphRelations",
2396
+ "passwords",
2397
+ "private",
2398
+ "nonScalarEmptyKeys"
2399
+ ];
2400
+ const validateSort = asyncCurry(
2401
+ async (ctx, sort2, include) => {
2402
+ if (!ctx.schema) {
2403
+ throw new Error("Missing schema in defaultValidateSort");
2404
+ }
2405
+ const functionsToApply = [];
2406
+ if (include.includes("nonAttributesOperators")) {
2407
+ functionsToApply.push(
2408
+ traverseQuerySort(({ key, attribute, path }) => {
2409
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2410
+ return;
2411
+ }
2412
+ if (!attribute) {
2413
+ throwInvalidKey({ key, path: path.attribute });
2414
+ }
2415
+ }, ctx)
2416
+ );
2417
+ }
2418
+ if (include.includes("dynamicZones")) {
2419
+ functionsToApply.push(traverseQuerySort(visitor, ctx));
2420
+ }
2421
+ if (include.includes("morphRelations")) {
2422
+ functionsToApply.push(traverseQuerySort(visitor$1, ctx));
2423
+ }
2424
+ if (include.includes("passwords")) {
2425
+ functionsToApply.push(traverseQuerySort(visitor$3, ctx));
2426
+ }
2427
+ if (include.includes("private")) {
2428
+ functionsToApply.push(traverseQuerySort(visitor$2, ctx));
2429
+ }
2430
+ if (include.includes("nonScalarEmptyKeys")) {
2431
+ functionsToApply.push(
2432
+ traverseQuerySort(({ key, attribute, value, path }) => {
2433
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2434
+ return;
2435
+ }
2436
+ if (!isScalarAttribute(attribute) && isEmpty(value)) {
2437
+ throwInvalidKey({ key, path: path.attribute });
2438
+ }
2439
+ }, ctx)
2440
+ );
2441
+ }
2442
+ if (functionsToApply.length === 0) {
2443
+ return sort2;
2444
+ }
2445
+ return pipe(...functionsToApply)(sort2);
2368
2446
  }
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);
2447
+ );
2448
+ const defaultValidateSort = asyncCurry(async (ctx, sort2) => {
2449
+ return validateSort(ctx, sort2, SORT_TRAVERSALS);
2397
2450
  });
2398
- const defaultValidateFields = curry((ctx, fields2) => {
2399
- if (!ctx.schema) {
2400
- throw new Error("Missing schema in defaultValidateFields");
2451
+ const FIELDS_TRAVERSALS = ["scalarAttributes", "privateFields", "passwordFields"];
2452
+ const validateFields = asyncCurry(
2453
+ async (ctx, fields2, include) => {
2454
+ if (!ctx.schema) {
2455
+ throw new Error("Missing schema in defaultValidateFields");
2456
+ }
2457
+ const functionsToApply = [];
2458
+ if (include.includes("scalarAttributes")) {
2459
+ functionsToApply.push(
2460
+ traverseQueryFields(({ key, attribute, path }) => {
2461
+ if ([ID_ATTRIBUTE$1, DOC_ID_ATTRIBUTE$1].includes(key)) {
2462
+ return;
2463
+ }
2464
+ if (isNil(attribute) || !isScalarAttribute(attribute)) {
2465
+ throwInvalidKey({ key, path: path.attribute });
2466
+ }
2467
+ }, ctx)
2468
+ );
2469
+ }
2470
+ if (include.includes("privateFields")) {
2471
+ functionsToApply.push(traverseQueryFields(visitor$2, ctx));
2472
+ }
2473
+ if (include.includes("passwordFields")) {
2474
+ functionsToApply.push(traverseQueryFields(visitor$3, ctx));
2475
+ }
2476
+ if (functionsToApply.length === 0) {
2477
+ return fields2;
2478
+ }
2479
+ return pipe(...functionsToApply)(fields2);
2401
2480
  }
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);
2481
+ );
2482
+ const defaultValidateFields = asyncCurry(async (ctx, fields2) => {
2483
+ return validateFields(ctx, fields2, FIELDS_TRAVERSALS);
2417
2484
  });
2418
- const defaultValidatePopulate = curry((ctx, populate2) => {
2485
+ const POPULATE_TRAVERSALS = ["nonAttributesOperators", "private"];
2486
+ const validatePopulate = asyncCurry(
2487
+ async (ctx, populate2, includes) => {
2488
+ if (!ctx.schema) {
2489
+ throw new Error("Missing schema in defaultValidatePopulate");
2490
+ }
2491
+ const functionsToApply = [];
2492
+ functionsToApply.push(
2493
+ traverseQueryPopulate(async ({ key, path, value, schema, attribute, getModel }, { set }) => {
2494
+ if (attribute) {
2495
+ const isPopulatableAttribute = ["relation", "dynamiczone", "component", "media"].includes(
2496
+ attribute.type
2497
+ );
2498
+ if (!isPopulatableAttribute) {
2499
+ throwInvalidKey({ key, path: path.raw });
2500
+ }
2501
+ return;
2502
+ }
2503
+ if (key === "on") {
2504
+ if (!isObject(value)) {
2505
+ return throwInvalidKey({ key, path: path.raw });
2506
+ }
2507
+ const targets = Object.keys(value);
2508
+ for (const target of targets) {
2509
+ const model = getModel(target);
2510
+ if (!model) {
2511
+ throwInvalidKey({ key: target, path: `${path.raw}.${target}` });
2512
+ }
2513
+ }
2514
+ return;
2515
+ }
2516
+ if (key === "" && value === "*") {
2517
+ return;
2518
+ }
2519
+ if (key === "count") {
2520
+ try {
2521
+ parseType({ type: "boolean", value });
2522
+ return;
2523
+ } catch {
2524
+ throwInvalidKey({ key, path: path.attribute });
2525
+ }
2526
+ }
2527
+ try {
2528
+ parseType({ type: "boolean", value: key });
2529
+ return;
2530
+ } catch {
2531
+ }
2532
+ if (key === "sort") {
2533
+ set(
2534
+ key,
2535
+ await validateSort(
2536
+ {
2537
+ schema,
2538
+ getModel
2539
+ },
2540
+ value,
2541
+ // pass the sort value
2542
+ includes?.sort || SORT_TRAVERSALS
2543
+ )
2544
+ );
2545
+ return;
2546
+ }
2547
+ if (key === "filters") {
2548
+ set(
2549
+ key,
2550
+ await validateFilters(
2551
+ {
2552
+ schema,
2553
+ getModel
2554
+ },
2555
+ value,
2556
+ // pass the filters value
2557
+ includes?.filters || FILTER_TRAVERSALS
2558
+ )
2559
+ );
2560
+ return;
2561
+ }
2562
+ if (key === "fields") {
2563
+ set(
2564
+ key,
2565
+ await validateFields(
2566
+ {
2567
+ schema,
2568
+ getModel
2569
+ },
2570
+ value,
2571
+ // pass the fields value
2572
+ includes?.fields || FIELDS_TRAVERSALS
2573
+ )
2574
+ );
2575
+ return;
2576
+ }
2577
+ if (key === "populate") {
2578
+ set(
2579
+ key,
2580
+ await validatePopulate(
2581
+ {
2582
+ schema,
2583
+ getModel
2584
+ },
2585
+ value,
2586
+ // pass the nested populate value
2587
+ includes
2588
+ // pass down the same includes object
2589
+ )
2590
+ );
2591
+ return;
2592
+ }
2593
+ if (includes?.populate?.includes("nonAttributesOperators")) {
2594
+ throwInvalidKey({ key, path: path.attribute });
2595
+ }
2596
+ }, ctx)
2597
+ );
2598
+ if (includes?.populate?.includes("private")) {
2599
+ functionsToApply.push(traverseQueryPopulate(visitor$2, ctx));
2600
+ }
2601
+ if (functionsToApply.length === 0) {
2602
+ return populate2;
2603
+ }
2604
+ return pipe(...functionsToApply)(populate2);
2605
+ }
2606
+ );
2607
+ const defaultValidatePopulate = asyncCurry(async (ctx, populate2) => {
2419
2608
  if (!ctx.schema) {
2420
2609
  throw new Error("Missing schema in defaultValidatePopulate");
2421
2610
  }
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);
2611
+ return validatePopulate(ctx, populate2, {
2612
+ filters: FILTER_TRAVERSALS,
2613
+ sort: SORT_TRAVERSALS,
2614
+ fields: FIELDS_TRAVERSALS,
2615
+ populate: POPULATE_TRAVERSALS
2616
+ });
2479
2617
  });
2480
2618
  const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2481
2619
  __proto__: null,
2620
+ FIELDS_TRAVERSALS,
2621
+ FILTER_TRAVERSALS,
2622
+ POPULATE_TRAVERSALS,
2623
+ SORT_TRAVERSALS,
2482
2624
  defaultValidateFields,
2483
2625
  defaultValidateFilters,
2484
2626
  defaultValidatePopulate,
2485
2627
  defaultValidateSort,
2486
- throwPasswords
2628
+ throwPasswords,
2629
+ validateFields,
2630
+ validateFilters,
2631
+ validatePopulate,
2632
+ validateSort
2487
2633
  }, Symbol.toStringTag, { value: "Module" }));
2488
2634
  const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants$1;
2489
2635
  const createAPIValidators = (opts) => {
@@ -2538,24 +2684,24 @@ const createAPIValidators = (opts) => {
2538
2684
  }
2539
2685
  const { filters: filters2, sort: sort2, fields: fields2, populate: populate2 } = query;
2540
2686
  if (filters2) {
2541
- await validateFilters(filters2, schema, { auth });
2687
+ await validateFilters2(filters2, schema, { auth });
2542
2688
  }
2543
2689
  if (sort2) {
2544
- await validateSort(sort2, schema, { auth });
2690
+ await validateSort2(sort2, schema, { auth });
2545
2691
  }
2546
2692
  if (fields2) {
2547
- await validateFields(fields2, schema);
2693
+ await validateFields2(fields2, schema);
2548
2694
  }
2549
2695
  if (populate2 && populate2 !== "*") {
2550
- await validatePopulate(populate2, schema);
2696
+ await validatePopulate2(populate2, schema);
2551
2697
  }
2552
2698
  };
2553
- const validateFilters = async (filters2, schema, { auth } = {}) => {
2699
+ const validateFilters2 = async (filters2, schema, { auth } = {}) => {
2554
2700
  if (!schema) {
2555
2701
  throw new Error("Missing schema in validateFilters");
2556
2702
  }
2557
2703
  if (isArray(filters2)) {
2558
- await Promise.all(filters2.map((filter) => validateFilters(filter, schema, { auth })));
2704
+ await Promise.all(filters2.map((filter) => validateFilters2(filter, schema, { auth })));
2559
2705
  return;
2560
2706
  }
2561
2707
  const transforms = [defaultValidateFilters({ schema, getModel })];
@@ -2577,7 +2723,7 @@ const createAPIValidators = (opts) => {
2577
2723
  throw e;
2578
2724
  }
2579
2725
  };
2580
- const validateSort = async (sort2, schema, { auth } = {}) => {
2726
+ const validateSort2 = async (sort2, schema, { auth } = {}) => {
2581
2727
  if (!schema) {
2582
2728
  throw new Error("Missing schema in validateSort");
2583
2729
  }
@@ -2600,7 +2746,7 @@ const createAPIValidators = (opts) => {
2600
2746
  throw e;
2601
2747
  }
2602
2748
  };
2603
- const validateFields = async (fields2, schema) => {
2749
+ const validateFields2 = async (fields2, schema) => {
2604
2750
  if (!schema) {
2605
2751
  throw new Error("Missing schema in validateFields");
2606
2752
  }
@@ -2615,7 +2761,7 @@ const createAPIValidators = (opts) => {
2615
2761
  throw e;
2616
2762
  }
2617
2763
  };
2618
- const validatePopulate = async (populate2, schema, { auth } = {}) => {
2764
+ const validatePopulate2 = async (populate2, schema, { auth } = {}) => {
2619
2765
  if (!schema) {
2620
2766
  throw new Error("Missing schema in sanitizePopulate");
2621
2767
  }
@@ -2641,10 +2787,10 @@ const createAPIValidators = (opts) => {
2641
2787
  return {
2642
2788
  input: validateInput,
2643
2789
  query: validateQuery,
2644
- filters: validateFilters,
2645
- sort: validateSort,
2646
- fields: validateFields,
2647
- populate: validatePopulate
2790
+ filters: validateFilters2,
2791
+ sort: validateSort2,
2792
+ fields: validateFields2,
2793
+ populate: validatePopulate2
2648
2794
  };
2649
2795
  };
2650
2796
  const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({