@strapi/core 5.50.1 → 5.51.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.
Files changed (71) hide show
  1. package/dist/compile.d.ts +1 -1
  2. package/dist/core-api/routes/validation/common.d.ts +3 -3
  3. package/dist/core-api/routes/validation/common.d.ts.map +1 -1
  4. package/dist/core-api/service/collection-type.d.ts +2 -2
  5. package/dist/core-api/service/single-type.d.ts +2 -2
  6. package/dist/domain/content-type/index.d.ts +1 -1
  7. package/dist/domain/content-type/index.d.ts.map +1 -1
  8. package/dist/domain/content-type/index.js +9 -0
  9. package/dist/domain/content-type/index.js.map +1 -1
  10. package/dist/domain/content-type/index.mjs +9 -0
  11. package/dist/domain/content-type/index.mjs.map +1 -1
  12. package/dist/domain/content-type/validator.d.ts.map +1 -1
  13. package/dist/domain/content-type/validator.js.map +1 -1
  14. package/dist/domain/content-type/validator.mjs.map +1 -1
  15. package/dist/ee/index.js.map +1 -1
  16. package/dist/ee/index.mjs.map +1 -1
  17. package/dist/ee/license.d.ts +1 -1
  18. package/dist/ee/license.d.ts.map +1 -1
  19. package/dist/ee/license.js +51 -8
  20. package/dist/ee/license.js.map +1 -1
  21. package/dist/ee/license.mjs +32 -8
  22. package/dist/ee/license.mjs.map +1 -1
  23. package/dist/migrations/database/5.0.0-discard-drafts.d.ts.map +1 -1
  24. package/dist/migrations/database/5.0.0-discard-drafts.js +77 -7
  25. package/dist/migrations/database/5.0.0-discard-drafts.js.map +1 -1
  26. package/dist/migrations/database/5.0.0-discard-drafts.mjs +77 -7
  27. package/dist/migrations/database/5.0.0-discard-drafts.mjs.map +1 -1
  28. package/dist/package.json.js +18 -16
  29. package/dist/package.json.js.map +1 -1
  30. package/dist/package.json.mjs +18 -16
  31. package/dist/package.json.mjs.map +1 -1
  32. package/dist/services/document-service/attributes/index.d.ts +1 -1
  33. package/dist/services/document-service/attributes/index.d.ts.map +1 -1
  34. package/dist/services/document-service/components.d.ts +2 -2
  35. package/dist/services/document-service/components.d.ts.map +1 -1
  36. package/dist/services/document-service/first-published-at.d.ts.map +1 -1
  37. package/dist/services/document-service/first-published-at.js +9 -2
  38. package/dist/services/document-service/first-published-at.js.map +1 -1
  39. package/dist/services/document-service/first-published-at.mjs +9 -2
  40. package/dist/services/document-service/first-published-at.mjs.map +1 -1
  41. package/dist/services/document-service/repository.d.ts.map +1 -1
  42. package/dist/services/document-service/repository.js +31 -11
  43. package/dist/services/document-service/repository.js.map +1 -1
  44. package/dist/services/document-service/repository.mjs +30 -10
  45. package/dist/services/document-service/repository.mjs.map +1 -1
  46. package/dist/services/document-service/utils/clone-relations.d.ts +7 -0
  47. package/dist/services/document-service/utils/clone-relations.d.ts.map +1 -0
  48. package/dist/services/document-service/utils/clone-relations.js +124 -0
  49. package/dist/services/document-service/utils/clone-relations.js.map +1 -0
  50. package/dist/services/document-service/utils/clone-relations.mjs +121 -0
  51. package/dist/services/document-service/utils/clone-relations.mjs.map +1 -0
  52. package/dist/services/entity-validator/validators.d.ts.map +1 -1
  53. package/dist/services/entity-validator/validators.js +6 -0
  54. package/dist/services/entity-validator/validators.js.map +1 -1
  55. package/dist/services/entity-validator/validators.mjs +6 -0
  56. package/dist/services/entity-validator/validators.mjs.map +1 -1
  57. package/dist/services/mcp/tools/log.d.ts +2 -2
  58. package/dist/services/mcp/tools/log.d.ts.map +1 -1
  59. package/dist/utils/fetch.d.ts +1 -1
  60. package/dist/utils/fetch.d.ts.map +1 -1
  61. package/dist/utils/fetch.js +2 -2
  62. package/dist/utils/fetch.js.map +1 -1
  63. package/dist/utils/fetch.mjs +2 -2
  64. package/dist/utils/fetch.mjs.map +1 -1
  65. package/dist/utils/startup-logger.d.ts.map +1 -1
  66. package/dist/utils/startup-logger.js +8 -2
  67. package/dist/utils/startup-logger.js.map +1 -1
  68. package/dist/utils/startup-logger.mjs +8 -2
  69. package/dist/utils/startup-logger.mjs.map +1 -1
  70. package/dist/utils/transform-content-types-to-models.d.ts +9 -9
  71. package/package.json +18 -16
@@ -477,6 +477,62 @@ const recordClonedComponentPair = (clonedComponentPairsCache, componentUid, orig
477
477
  enqueueColumn(joinTable?.orderColumn, 'asc');
478
478
  enqueueColumn('id', 'asc');
479
479
  };
480
+ /**
481
+ * v4 join rows often only persisted order on one side of a bidirectional join table.
482
+ * When cloning relations for draft rows, derive missing order values from the other side
483
+ * so populate does not fall back to primary-key order.
484
+ */ const assignMissingOrderColumnFromFallback = (relations, { orderColumn, fallbackOrderColumn, groupByColumn, tieBreakerColumn })=>{
485
+ if (!orderColumn || !fallbackOrderColumn || relations.length === 0) {
486
+ return relations;
487
+ }
488
+ const byGroup = new Map();
489
+ for (const relation of relations){
490
+ const groupId = relation[groupByColumn];
491
+ const key = groupId ?? 'null';
492
+ const group = byGroup.get(key);
493
+ if (group) {
494
+ group.push(relation);
495
+ } else {
496
+ byGroup.set(key, [
497
+ relation
498
+ ]);
499
+ }
500
+ }
501
+ for (const group of byGroup.values()){
502
+ if (!group.some((relation)=>relation[orderColumn] == null)) {
503
+ continue;
504
+ }
505
+ const sorted = [
506
+ ...group
507
+ ].sort((left, right)=>{
508
+ const leftOrder = left[fallbackOrderColumn];
509
+ const rightOrder = right[fallbackOrderColumn];
510
+ if (leftOrder != null && rightOrder != null) {
511
+ if (leftOrder !== rightOrder) {
512
+ return leftOrder - rightOrder;
513
+ }
514
+ } else if (leftOrder != null) {
515
+ return -1;
516
+ } else if (rightOrder != null) {
517
+ return 1;
518
+ }
519
+ if (tieBreakerColumn) {
520
+ const leftTie = normalizeId(left[tieBreakerColumn]) ?? left[tieBreakerColumn];
521
+ const rightTie = normalizeId(right[tieBreakerColumn]) ?? right[tieBreakerColumn];
522
+ if (leftTie != null && rightTie != null && leftTie !== rightTie) {
523
+ return leftTie < rightTie ? -1 : 1;
524
+ }
525
+ }
526
+ return 0;
527
+ });
528
+ sorted.forEach((relation, index)=>{
529
+ if (relation[orderColumn] == null) {
530
+ relation[orderColumn] = index + 1;
531
+ }
532
+ });
533
+ }
534
+ return relations;
535
+ };
480
536
  /**
481
537
  * Builds a stable key for join-table relations to detect duplicates.
482
538
  * Key format: sourceId::targetId::field::componentType
@@ -488,14 +544,15 @@ const recordClonedComponentPair = (clonedComponentPairsCache, componentUid, orig
488
544
  };
489
545
  /**
490
546
  * Queries existing relations from a join table and builds a set of keys for duplicate detection.
491
- */ async function getExistingRelationKeys({ trx, joinTable, sourceColumnName, targetColumnName, sourceIds }) {
547
+ */ async function getExistingRelationKeys({ trx, joinTable, sourceColumnName, targetColumnName, filterIds, filterColumnName }) {
492
548
  const existingKeys = new Set();
493
- if (sourceIds.length === 0) {
549
+ const columnName = filterColumnName ?? sourceColumnName;
550
+ if (filterIds.length === 0) {
494
551
  return existingKeys;
495
552
  }
496
- const idChunks = chunkArray(sourceIds, getBatchSize(trx, 1000));
553
+ const idChunks = chunkArray(filterIds, getBatchSize(trx, 1000));
497
554
  for (const chunk of idChunks){
498
- const existingRelationsQuery = trx(joinTable.name).select('*').whereIn(sourceColumnName, chunk);
555
+ const existingRelationsQuery = trx(joinTable.name).select('*').whereIn(columnName, chunk);
499
556
  applyJoinTableOrdering(existingRelationsQuery, joinTable, sourceColumnName);
500
557
  const existingRelations = await existingRelationsQuery;
501
558
  for (const relation of existingRelations){
@@ -1440,7 +1497,7 @@ const debug = createDebug('strapi::migration::discard-drafts');
1440
1497
  joinTable,
1441
1498
  sourceColumnName,
1442
1499
  targetColumnName,
1443
- sourceIds: draftSourceIds
1500
+ filterIds: draftSourceIds
1444
1501
  });
1445
1502
  const relationsToInsert = newRelations.filter((relation)=>{
1446
1503
  const targetId = normalizeId(relation[targetColumnName]) ?? relation[targetColumnName];
@@ -1512,7 +1569,8 @@ const debug = createDebug('strapi::migration::discard-drafts');
1512
1569
  joinTable,
1513
1570
  sourceColumnName,
1514
1571
  targetColumnName,
1515
- sourceIds: draftTargetIds
1572
+ filterIds: draftTargetIds,
1573
+ filterColumnName: targetColumnName
1516
1574
  });
1517
1575
  const publishedIdChunks = chunkArray(publishedTargetIds, getBatchSize(trx, 1000));
1518
1576
  for (const chunk of publishedIdChunks){
@@ -1542,6 +1600,12 @@ const debug = createDebug('strapi::migration::discard-drafts');
1542
1600
  if (newRelations.length === 0) {
1543
1601
  continue;
1544
1602
  }
1603
+ assignMissingOrderColumnFromFallback(newRelations, {
1604
+ orderColumn: joinTable.inverseOrderColumnName,
1605
+ fallbackOrderColumn: joinTable.orderColumnName,
1606
+ groupByColumn: targetColumnName,
1607
+ tieBreakerColumn: sourceColumnName
1608
+ });
1545
1609
  await insertRelationsWithDuplicateHandling({
1546
1610
  trx,
1547
1611
  tableName: joinTable.name,
@@ -1657,7 +1721,7 @@ const debug = createDebug('strapi::migration::discard-drafts');
1657
1721
  joinTable,
1658
1722
  sourceColumnName,
1659
1723
  targetColumnName,
1660
- sourceIds: draftSourceIds
1724
+ filterIds: draftSourceIds
1661
1725
  });
1662
1726
  // Filter out relations that already exist
1663
1727
  const relationsToInsert = safeRelations.filter((relation)=>{
@@ -1666,6 +1730,12 @@ const debug = createDebug('strapi::migration::discard-drafts');
1666
1730
  return !existingKeys.has(key);
1667
1731
  });
1668
1732
  if (relationsToInsert.length > 0) {
1733
+ assignMissingOrderColumnFromFallback(relationsToInsert, {
1734
+ orderColumn: joinTable.orderColumnName,
1735
+ fallbackOrderColumn: joinTable.inverseOrderColumnName,
1736
+ groupByColumn: sourceColumnName,
1737
+ tieBreakerColumn: targetColumnName
1738
+ });
1669
1739
  await insertRelationsWithDuplicateHandling({
1670
1740
  trx,
1671
1741
  tableName: joinTable.name,