@strapi/content-manager 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813 → 0.0.0-experimental.f75e3c6d67cc47c64ab37479efdbb7b43be50b78

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 (165) hide show
  1. package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
  2. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
  3. package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
  4. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
  5. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs → ComponentConfigurationPage-CuWgXugY.mjs} +3 -3
  6. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs.map → ComponentConfigurationPage-CuWgXugY.mjs.map} +1 -1
  7. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js → ComponentConfigurationPage-by0e_kNd.js} +3 -3
  8. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js.map → ComponentConfigurationPage-by0e_kNd.js.map} +1 -1
  9. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
  10. package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
  11. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  12. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  13. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js → EditConfigurationPage-CqBeCPGH.js} +3 -3
  14. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js.map → EditConfigurationPage-CqBeCPGH.js.map} +1 -1
  15. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs → EditConfigurationPage-DbI4KMyz.mjs} +3 -3
  16. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs.map → EditConfigurationPage-DbI4KMyz.mjs.map} +1 -1
  17. package/dist/_chunks/{EditViewPage-DvNpQkam.js → EditViewPage-ChgloMyO.js} +7 -9
  18. package/dist/_chunks/EditViewPage-ChgloMyO.js.map +1 -0
  19. package/dist/_chunks/{EditViewPage-DDS6H9HO.mjs → EditViewPage-dFPBya9U.mjs} +6 -6
  20. package/dist/_chunks/EditViewPage-dFPBya9U.mjs.map +1 -0
  21. package/dist/_chunks/{Field-6gvGdPBV.mjs → Field-C1nUKcdS.mjs} +500 -608
  22. package/dist/_chunks/Field-C1nUKcdS.mjs.map +1 -0
  23. package/dist/_chunks/{Field-DmVKIAOo.js → Field-dLk-vgLL.js} +552 -661
  24. package/dist/_chunks/Field-dLk-vgLL.js.map +1 -0
  25. package/dist/_chunks/{Form-CPZC9vWa.js → Form-CbXtmHC_.js} +18 -16
  26. package/dist/_chunks/Form-CbXtmHC_.js.map +1 -0
  27. package/dist/_chunks/{Form-DW6K1IH-.mjs → Form-DOlpi7Js.mjs} +16 -13
  28. package/dist/_chunks/Form-DOlpi7Js.mjs.map +1 -0
  29. package/dist/_chunks/{History-Dmr9fmUA.mjs → History-BFNUAiGc.mjs} +29 -40
  30. package/dist/_chunks/History-BFNUAiGc.mjs.map +1 -0
  31. package/dist/_chunks/{History-DeAPlvtv.js → History-BjDfohBr.js} +30 -42
  32. package/dist/_chunks/History-BjDfohBr.js.map +1 -0
  33. package/dist/_chunks/{ListConfigurationPage-DhwvYcNv.mjs → ListConfigurationPage-DDi0KqFm.mjs} +9 -9
  34. package/dist/_chunks/ListConfigurationPage-DDi0KqFm.mjs.map +1 -0
  35. package/dist/_chunks/{ListConfigurationPage-DPCwW5Vr.js → ListConfigurationPage-IQBgWTaa.js} +14 -16
  36. package/dist/_chunks/ListConfigurationPage-IQBgWTaa.js.map +1 -0
  37. package/dist/_chunks/{ListViewPage-BtAwuYLE.mjs → ListViewPage-BPjljUsH.mjs} +21 -41
  38. package/dist/_chunks/ListViewPage-BPjljUsH.mjs.map +1 -0
  39. package/dist/_chunks/{ListViewPage-5ySZ-VUs.js → ListViewPage-CZYGqlvF.js} +28 -48
  40. package/dist/_chunks/ListViewPage-CZYGqlvF.js.map +1 -0
  41. package/dist/_chunks/{NoContentTypePage-DOC_yWOf.js → NoContentTypePage-BOAI6VZ1.js} +3 -3
  42. package/dist/_chunks/NoContentTypePage-BOAI6VZ1.js.map +1 -0
  43. package/dist/_chunks/{NoContentTypePage-DSPxnxxp.mjs → NoContentTypePage-DaWw67K-.mjs} +3 -3
  44. package/dist/_chunks/NoContentTypePage-DaWw67K-.mjs.map +1 -0
  45. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs → NoPermissionsPage-CZrJH00p.mjs} +2 -2
  46. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs.map → NoPermissionsPage-CZrJH00p.mjs.map} +1 -1
  47. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js → NoPermissionsPage-cYEtLc_e.js} +2 -2
  48. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js.map → NoPermissionsPage-cYEtLc_e.js.map} +1 -1
  49. package/dist/_chunks/{Relations-J8cscLlR.mjs → Relations-DTowyge2.mjs} +66 -56
  50. package/dist/_chunks/Relations-DTowyge2.mjs.map +1 -0
  51. package/dist/_chunks/{Relations-CgWtgnPe.js → Relations-DU6B7irU.js} +70 -61
  52. package/dist/_chunks/Relations-DU6B7irU.js.map +1 -0
  53. package/dist/_chunks/{en-C-V1_90f.js → en-DTULi5-d.js} +3 -1
  54. package/dist/_chunks/{en-C-V1_90f.js.map → en-DTULi5-d.js.map} +1 -1
  55. package/dist/_chunks/{en-MBPul9Su.mjs → en-GCOTL6jR.mjs} +3 -1
  56. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-GCOTL6jR.mjs.map} +1 -1
  57. package/dist/_chunks/{index-CwRRo1V9.mjs → index-BaGHmIir.mjs} +507 -202
  58. package/dist/_chunks/index-BaGHmIir.mjs.map +1 -0
  59. package/dist/_chunks/{index-C6AH2hEl.js → index-CCJeB7Rw.js} +502 -198
  60. package/dist/_chunks/index-CCJeB7Rw.js.map +1 -0
  61. package/dist/_chunks/{layout-jIDzX0Fp.mjs → layout-BinjszSQ.mjs} +10 -10
  62. package/dist/_chunks/layout-BinjszSQ.mjs.map +1 -0
  63. package/dist/_chunks/{layout-B_SXLhqf.js → layout-ni_L9kT1.js} +12 -14
  64. package/dist/_chunks/layout-ni_L9kT1.js.map +1 -0
  65. package/dist/_chunks/{relations-iBMa_OFG.js → relations-CeJAJc5I.js} +2 -2
  66. package/dist/_chunks/{relations-iBMa_OFG.js.map → relations-CeJAJc5I.js.map} +1 -1
  67. package/dist/_chunks/{relations-CuvIgCqI.mjs → relations-c91ji5eR.mjs} +2 -2
  68. package/dist/_chunks/{relations-CuvIgCqI.mjs.map → relations-c91ji5eR.mjs.map} +1 -1
  69. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
  70. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
  71. package/dist/_chunks/usePrev-B9w_-eYc.js +15 -0
  72. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  73. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  74. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  75. package/dist/admin/index.js +2 -1
  76. package/dist/admin/index.js.map +1 -1
  77. package/dist/admin/index.mjs +5 -4
  78. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  79. package/dist/admin/src/content-manager.d.ts +3 -3
  80. package/dist/admin/src/exports.d.ts +1 -0
  81. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  82. package/dist/admin/src/hooks/useDocument.d.ts +5 -8
  83. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  84. package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
  85. package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
  86. package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  87. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +3 -1
  88. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  89. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  90. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  91. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
  92. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +10 -18
  93. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  94. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  95. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  96. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +67 -52
  97. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  98. package/dist/admin/src/services/api.d.ts +2 -3
  99. package/dist/admin/src/services/components.d.ts +2 -2
  100. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  101. package/dist/admin/src/services/documents.d.ts +29 -17
  102. package/dist/admin/src/services/init.d.ts +2 -2
  103. package/dist/admin/src/services/relations.d.ts +3 -3
  104. package/dist/admin/src/services/uid.d.ts +3 -3
  105. package/dist/admin/src/utils/api.d.ts +4 -18
  106. package/dist/admin/src/utils/validation.d.ts +1 -6
  107. package/dist/server/index.js +273 -196
  108. package/dist/server/index.js.map +1 -1
  109. package/dist/server/index.mjs +281 -204
  110. package/dist/server/index.mjs.map +1 -1
  111. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  112. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  113. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  114. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  115. package/dist/server/src/controllers/validation/dimensions.d.ts +9 -0
  116. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  117. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  118. package/dist/server/src/history/services/history.d.ts.map +1 -1
  119. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  120. package/dist/server/src/index.d.ts +18 -39
  121. package/dist/server/src/index.d.ts.map +1 -1
  122. package/dist/server/src/services/document-manager.d.ts +13 -12
  123. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  124. package/dist/server/src/services/document-metadata.d.ts +8 -29
  125. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  126. package/dist/server/src/services/index.d.ts +18 -39
  127. package/dist/server/src/services/index.d.ts.map +1 -1
  128. package/dist/server/src/services/utils/populate.d.ts +8 -1
  129. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  130. package/dist/shared/contracts/collection-types.d.ts +14 -6
  131. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  132. package/dist/shared/contracts/relations.d.ts +2 -2
  133. package/dist/shared/contracts/relations.d.ts.map +1 -1
  134. package/package.json +13 -14
  135. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  136. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  137. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  138. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  139. package/dist/_chunks/EditViewPage-DDS6H9HO.mjs.map +0 -1
  140. package/dist/_chunks/EditViewPage-DvNpQkam.js.map +0 -1
  141. package/dist/_chunks/Field-6gvGdPBV.mjs.map +0 -1
  142. package/dist/_chunks/Field-DmVKIAOo.js.map +0 -1
  143. package/dist/_chunks/Form-CPZC9vWa.js.map +0 -1
  144. package/dist/_chunks/Form-DW6K1IH-.mjs.map +0 -1
  145. package/dist/_chunks/History-DeAPlvtv.js.map +0 -1
  146. package/dist/_chunks/History-Dmr9fmUA.mjs.map +0 -1
  147. package/dist/_chunks/ListConfigurationPage-DPCwW5Vr.js.map +0 -1
  148. package/dist/_chunks/ListConfigurationPage-DhwvYcNv.mjs.map +0 -1
  149. package/dist/_chunks/ListViewPage-5ySZ-VUs.js.map +0 -1
  150. package/dist/_chunks/ListViewPage-BtAwuYLE.mjs.map +0 -1
  151. package/dist/_chunks/NoContentTypePage-DOC_yWOf.js.map +0 -1
  152. package/dist/_chunks/NoContentTypePage-DSPxnxxp.mjs.map +0 -1
  153. package/dist/_chunks/Relations-CgWtgnPe.js.map +0 -1
  154. package/dist/_chunks/Relations-J8cscLlR.mjs.map +0 -1
  155. package/dist/_chunks/index-C6AH2hEl.js.map +0 -1
  156. package/dist/_chunks/index-CwRRo1V9.mjs.map +0 -1
  157. package/dist/_chunks/layout-B_SXLhqf.js.map +0 -1
  158. package/dist/_chunks/layout-jIDzX0Fp.mjs.map +0 -1
  159. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  160. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  161. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  162. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  163. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +0 -31
  164. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  165. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
@@ -518,6 +518,12 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
518
518
  const documentContext = context.action === "create" ? { documentId: result.documentId, locale: context.params?.locale } : { documentId: context.params.documentId, locale: context.params?.locale };
519
519
  const defaultLocale = await serviceUtils.getDefaultLocale();
520
520
  const locale = documentContext.locale || defaultLocale;
521
+ if (Array.isArray(locale)) {
522
+ strapi2.log.warn(
523
+ "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
524
+ );
525
+ return next();
526
+ }
521
527
  const document = await strapi2.documents(contentTypeUid).findOne({
522
528
  documentId: documentContext.documentId,
523
529
  locale,
@@ -1478,7 +1484,7 @@ const { PaginationError, ValidationError } = strapiUtils.errors;
1478
1484
  const TYPES = ["singleType", "collectionType"];
1479
1485
  const kindSchema = strapiUtils.yup.string().oneOf(TYPES).nullable();
1480
1486
  const bulkActionInputSchema = strapiUtils.yup.object({
1481
- ids: strapiUtils.yup.array().of(strapiUtils.yup.strapiID()).min(1).required()
1487
+ documentIds: strapiUtils.yup.array().of(strapiUtils.yup.strapiID()).min(1).required()
1482
1488
  }).required();
1483
1489
  const generateUIDInputSchema = strapiUtils.yup.object({
1484
1490
  contentTypeUID: strapiUtils.yup.string().required(),
@@ -1577,15 +1583,47 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1577
1583
  }
1578
1584
  }, body);
1579
1585
  };
1580
- const getDocumentLocaleAndStatus = (request) => {
1586
+ const singleLocaleSchema = strapiUtils.yup.string().nullable();
1587
+ const multipleLocaleSchema = strapiUtils.yup.lazy(
1588
+ (value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1589
+ );
1590
+ const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
1591
+ const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
1592
+ const { allowMultipleLocales } = opts;
1581
1593
  const { locale, status, ...rest } = request || {};
1582
- if (!fp.isNil(locale) && typeof locale !== "string") {
1583
- throw new strapiUtils.errors.ValidationError(`Invalid locale: ${locale}`);
1584
- }
1585
- if (!fp.isNil(status) && !["draft", "published"].includes(status)) {
1586
- throw new strapiUtils.errors.ValidationError(`Invalid status: ${status}`);
1594
+ const schema = strapiUtils.yup.object().shape({
1595
+ locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1596
+ status: statusSchema
1597
+ });
1598
+ try {
1599
+ await strapiUtils.validateYupSchema(schema, { strict: true, abortEarly: false })(request);
1600
+ return { locale, status, ...rest };
1601
+ } catch (error) {
1602
+ throw new strapiUtils.errors.ValidationError(`Validation error: ${error.message}`);
1587
1603
  }
1588
- return { locale, status, ...rest };
1604
+ };
1605
+ const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1606
+ const documentMetadata2 = getService$1("document-metadata");
1607
+ const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1608
+ let {
1609
+ meta: { availableLocales, availableStatus }
1610
+ } = serviceOutput;
1611
+ const metadataSanitizer = permissionChecker2.sanitizeOutput;
1612
+ availableLocales = await strapiUtils.async.map(
1613
+ availableLocales,
1614
+ async (localeDocument) => metadataSanitizer(localeDocument)
1615
+ );
1616
+ availableStatus = await strapiUtils.async.map(
1617
+ availableStatus,
1618
+ async (statusDocument) => metadataSanitizer(statusDocument)
1619
+ );
1620
+ return {
1621
+ ...serviceOutput,
1622
+ meta: {
1623
+ availableLocales,
1624
+ availableStatus
1625
+ }
1626
+ };
1589
1627
  };
1590
1628
  const createDocument = async (ctx, opts) => {
1591
1629
  const { userAbility, user } = ctx.state;
@@ -1600,7 +1638,7 @@ const createDocument = async (ctx, opts) => {
1600
1638
  const setCreator = strapiUtils.setCreatorFields({ user });
1601
1639
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1602
1640
  const sanitizedBody = await sanitizeFn(body);
1603
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(body);
1641
+ const { locale, status = "draft" } = await getDocumentLocaleAndStatus(body);
1604
1642
  return documentManager2.create(model, {
1605
1643
  data: sanitizedBody,
1606
1644
  locale,
@@ -1619,7 +1657,7 @@ const updateDocument = async (ctx, opts) => {
1619
1657
  }
1620
1658
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1621
1659
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1622
- const { locale } = getDocumentLocaleAndStatus(body);
1660
+ const { locale } = await getDocumentLocaleAndStatus(body);
1623
1661
  const [documentVersion, documentExists] = await Promise.all([
1624
1662
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1625
1663
  documentManager2.exists(model, id)
@@ -1657,7 +1695,7 @@ const collectionTypes = {
1657
1695
  }
1658
1696
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1659
1697
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1660
- const { locale, status } = getDocumentLocaleAndStatus(query);
1698
+ const { locale, status } = await getDocumentLocaleAndStatus(query);
1661
1699
  const { results: documents, pagination } = await documentManager2.findPage(
1662
1700
  { ...permissionQuery, populate, locale, status },
1663
1701
  model
@@ -1686,14 +1724,13 @@ const collectionTypes = {
1686
1724
  const { userAbility } = ctx.state;
1687
1725
  const { model, id } = ctx.params;
1688
1726
  const documentManager2 = getService$1("document-manager");
1689
- const documentMetadata2 = getService$1("document-metadata");
1690
1727
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1691
1728
  if (permissionChecker2.cannot.read()) {
1692
1729
  return ctx.forbidden();
1693
1730
  }
1694
1731
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1695
1732
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1696
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
1733
+ const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
1697
1734
  const version = await documentManager2.findOne(id, model, {
1698
1735
  populate,
1699
1736
  locale,
@@ -1704,8 +1741,10 @@ const collectionTypes = {
1704
1741
  if (!exists) {
1705
1742
  return ctx.notFound();
1706
1743
  }
1707
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
1744
+ const { meta } = await formatDocumentWithMetadata(
1745
+ permissionChecker2,
1708
1746
  model,
1747
+ // @ts-expect-error TODO: fix
1709
1748
  { id, locale, publishedAt: null },
1710
1749
  { availableLocales: true, availableStatus: false }
1711
1750
  );
@@ -1716,12 +1755,11 @@ const collectionTypes = {
1716
1755
  return ctx.forbidden();
1717
1756
  }
1718
1757
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
1719
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
1758
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1720
1759
  },
1721
1760
  async create(ctx) {
1722
1761
  const { userAbility } = ctx.state;
1723
1762
  const { model } = ctx.params;
1724
- const documentMetadata2 = getService$1("document-metadata");
1725
1763
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1726
1764
  const [totalEntries, document] = await Promise.all([
1727
1765
  strapi.db.query(model).count(),
@@ -1729,7 +1767,7 @@ const collectionTypes = {
1729
1767
  ]);
1730
1768
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
1731
1769
  ctx.status = 201;
1732
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
1770
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1733
1771
  // Empty metadata as it's not relevant for a new document
1734
1772
  availableLocales: false,
1735
1773
  availableStatus: false
@@ -1743,25 +1781,23 @@ const collectionTypes = {
1743
1781
  async update(ctx) {
1744
1782
  const { userAbility } = ctx.state;
1745
1783
  const { model } = ctx.params;
1746
- const documentMetadata2 = getService$1("document-metadata");
1747
1784
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1748
1785
  const updatedVersion = await updateDocument(ctx);
1749
1786
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1750
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedVersion);
1787
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
1751
1788
  },
1752
1789
  async clone(ctx) {
1753
1790
  const { userAbility, user } = ctx.state;
1754
1791
  const { model, sourceId: id } = ctx.params;
1755
1792
  const { body } = ctx.request;
1756
1793
  const documentManager2 = getService$1("document-manager");
1757
- const documentMetadata2 = getService$1("document-metadata");
1758
1794
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1759
1795
  if (permissionChecker2.cannot.create()) {
1760
1796
  return ctx.forbidden();
1761
1797
  }
1762
1798
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1763
1799
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1764
- const { locale } = getDocumentLocaleAndStatus(body);
1800
+ const { locale } = await getDocumentLocaleAndStatus(body);
1765
1801
  const document = await documentManager2.findOne(id, model, {
1766
1802
  populate,
1767
1803
  locale,
@@ -1777,7 +1813,7 @@ const collectionTypes = {
1777
1813
  const sanitizedBody = await sanitizeFn(body);
1778
1814
  const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
1779
1815
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
1780
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
1816
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1781
1817
  // Empty metadata as it's not relevant for a new document
1782
1818
  availableLocales: false,
1783
1819
  availableStatus: false
@@ -1806,7 +1842,7 @@ const collectionTypes = {
1806
1842
  }
1807
1843
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1808
1844
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1809
- const { locale } = getDocumentLocaleAndStatus(ctx.query);
1845
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query);
1810
1846
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1811
1847
  if (documentLocales.length === 0) {
1812
1848
  return ctx.notFound();
@@ -1828,7 +1864,6 @@ const collectionTypes = {
1828
1864
  const { id, model } = ctx.params;
1829
1865
  const { body } = ctx.request;
1830
1866
  const documentManager2 = getService$1("document-manager");
1831
- const documentMetadata2 = getService$1("document-metadata");
1832
1867
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1833
1868
  if (permissionChecker2.cannot.publish()) {
1834
1869
  return ctx.forbidden();
@@ -1840,21 +1875,25 @@ const collectionTypes = {
1840
1875
  if (permissionChecker2.cannot.publish(document)) {
1841
1876
  throw new strapiUtils.errors.ForbiddenError();
1842
1877
  }
1843
- const { locale } = getDocumentLocaleAndStatus(body);
1844
- return documentManager2.publish(document.documentId, model, {
1878
+ const { locale } = await getDocumentLocaleAndStatus(body);
1879
+ const publishResult = await documentManager2.publish(document.documentId, model, {
1845
1880
  locale
1846
1881
  // TODO: Allow setting creator fields on publish
1847
1882
  // data: setCreatorFields({ user, isEdition: true })({}),
1848
1883
  });
1884
+ if (!publishResult || publishResult.length === 0) {
1885
+ throw new strapiUtils.errors.NotFoundError("Document not found or already published.");
1886
+ }
1887
+ return publishResult[0];
1849
1888
  });
1850
1889
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
1851
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
1890
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1852
1891
  },
1853
1892
  async bulkPublish(ctx) {
1854
1893
  const { userAbility } = ctx.state;
1855
1894
  const { model } = ctx.params;
1856
1895
  const { body } = ctx.request;
1857
- const { ids } = body;
1896
+ const { documentIds } = body;
1858
1897
  await validateBulkActionInput(body);
1859
1898
  const documentManager2 = getService$1("document-manager");
1860
1899
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
@@ -1863,8 +1902,11 @@ const collectionTypes = {
1863
1902
  }
1864
1903
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1865
1904
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1866
- const entityPromises = ids.map((id) => documentManager2.findOne(id, model, { populate }));
1867
- const entities = await Promise.all(entityPromises);
1905
+ const { locale } = await getDocumentLocaleAndStatus(body, { allowMultipleLocales: true });
1906
+ const entityPromises = documentIds.map(
1907
+ (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
1908
+ );
1909
+ const entities = (await Promise.all(entityPromises)).flat();
1868
1910
  for (const entity of entities) {
1869
1911
  if (!entity) {
1870
1912
  return ctx.notFound();
@@ -1873,24 +1915,25 @@ const collectionTypes = {
1873
1915
  return ctx.forbidden();
1874
1916
  }
1875
1917
  }
1876
- const { count } = await documentManager2.publishMany(entities, model);
1918
+ const count = await documentManager2.publishMany(model, documentIds, locale);
1877
1919
  ctx.body = { count };
1878
1920
  },
1879
1921
  async bulkUnpublish(ctx) {
1880
1922
  const { userAbility } = ctx.state;
1881
1923
  const { model } = ctx.params;
1882
1924
  const { body } = ctx.request;
1883
- const { ids } = body;
1925
+ const { documentIds } = body;
1884
1926
  await validateBulkActionInput(body);
1885
1927
  const documentManager2 = getService$1("document-manager");
1886
1928
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1887
1929
  if (permissionChecker2.cannot.unpublish()) {
1888
1930
  return ctx.forbidden();
1889
1931
  }
1890
- const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1891
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1892
- const entityPromises = ids.map((id) => documentManager2.findOne(id, model, { populate }));
1893
- const entities = await Promise.all(entityPromises);
1932
+ const { locale } = await getDocumentLocaleAndStatus(body);
1933
+ const entityPromises = documentIds.map(
1934
+ (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1935
+ );
1936
+ const entities = (await Promise.all(entityPromises)).flat();
1894
1937
  for (const entity of entities) {
1895
1938
  if (!entity) {
1896
1939
  return ctx.notFound();
@@ -1899,7 +1942,8 @@ const collectionTypes = {
1899
1942
  return ctx.forbidden();
1900
1943
  }
1901
1944
  }
1902
- const { count } = await documentManager2.unpublishMany(entities, model);
1945
+ const entitiesIds = entities.map((document) => document.documentId);
1946
+ const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
1903
1947
  ctx.body = { count };
1904
1948
  },
1905
1949
  async unpublish(ctx) {
@@ -1909,7 +1953,6 @@ const collectionTypes = {
1909
1953
  body: { discardDraft, ...body }
1910
1954
  } = ctx.request;
1911
1955
  const documentManager2 = getService$1("document-manager");
1912
- const documentMetadata2 = getService$1("document-metadata");
1913
1956
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1914
1957
  if (permissionChecker2.cannot.unpublish()) {
1915
1958
  return ctx.forbidden();
@@ -1919,7 +1962,7 @@ const collectionTypes = {
1919
1962
  }
1920
1963
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1921
1964
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1922
- const { locale } = getDocumentLocaleAndStatus(body);
1965
+ const { locale } = await getDocumentLocaleAndStatus(body);
1923
1966
  const document = await documentManager2.findOne(id, model, {
1924
1967
  populate,
1925
1968
  locale,
@@ -1941,7 +1984,7 @@ const collectionTypes = {
1941
1984
  ctx.body = await strapiUtils.async.pipe(
1942
1985
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
1943
1986
  permissionChecker2.sanitizeOutput,
1944
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
1987
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1945
1988
  )(document);
1946
1989
  });
1947
1990
  },
@@ -1950,14 +1993,13 @@ const collectionTypes = {
1950
1993
  const { id, model } = ctx.params;
1951
1994
  const { body } = ctx.request;
1952
1995
  const documentManager2 = getService$1("document-manager");
1953
- const documentMetadata2 = getService$1("document-metadata");
1954
1996
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1955
1997
  if (permissionChecker2.cannot.discard()) {
1956
1998
  return ctx.forbidden();
1957
1999
  }
1958
2000
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
1959
2001
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1960
- const { locale } = getDocumentLocaleAndStatus(body);
2002
+ const { locale } = await getDocumentLocaleAndStatus(body);
1961
2003
  const document = await documentManager2.findOne(id, model, {
1962
2004
  populate,
1963
2005
  locale,
@@ -1972,14 +2014,14 @@ const collectionTypes = {
1972
2014
  ctx.body = await strapiUtils.async.pipe(
1973
2015
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
1974
2016
  permissionChecker2.sanitizeOutput,
1975
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2017
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1976
2018
  )(document);
1977
2019
  },
1978
2020
  async bulkDelete(ctx) {
1979
2021
  const { userAbility } = ctx.state;
1980
2022
  const { model } = ctx.params;
1981
2023
  const { query, body } = ctx.request;
1982
- const { ids } = body;
2024
+ const { documentIds } = body;
1983
2025
  await validateBulkActionInput(body);
1984
2026
  const documentManager2 = getService$1("document-manager");
1985
2027
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
@@ -1987,14 +2029,22 @@ const collectionTypes = {
1987
2029
  return ctx.forbidden();
1988
2030
  }
1989
2031
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
1990
- const idsWhereClause = { id: { $in: ids } };
1991
- const params = {
1992
- ...permissionQuery,
1993
- filters: {
1994
- $and: [idsWhereClause].concat(permissionQuery.filters || [])
2032
+ const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2033
+ const { locale } = await getDocumentLocaleAndStatus(body);
2034
+ const documentLocales = await documentManager2.findLocales(documentIds, model, {
2035
+ populate,
2036
+ locale
2037
+ });
2038
+ if (documentLocales.length === 0) {
2039
+ return ctx.notFound();
2040
+ }
2041
+ for (const document of documentLocales) {
2042
+ if (permissionChecker2.cannot.delete(document)) {
2043
+ return ctx.forbidden();
1995
2044
  }
1996
- };
1997
- const { count } = await documentManager2.deleteMany(params, model);
2045
+ }
2046
+ const localeDocumentsIds = documentLocales.map((document) => document.documentId);
2047
+ const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
1998
2048
  ctx.body = { count };
1999
2049
  },
2000
2050
  async countDraftRelations(ctx) {
@@ -2007,7 +2057,7 @@ const collectionTypes = {
2007
2057
  }
2008
2058
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2009
2059
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2010
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
2060
+ const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
2011
2061
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2012
2062
  if (!entity) {
2013
2063
  return ctx.notFound();
@@ -2022,7 +2072,7 @@ const collectionTypes = {
2022
2072
  },
2023
2073
  async countManyEntriesDraftRelations(ctx) {
2024
2074
  const { userAbility } = ctx.state;
2025
- const ids = ctx.request.query.ids;
2075
+ const ids = ctx.request.query.documentIds;
2026
2076
  const locale = ctx.request.query.locale;
2027
2077
  const { model } = ctx.params;
2028
2078
  const documentManager2 = getService$1("document-manager");
@@ -2033,7 +2083,7 @@ const collectionTypes = {
2033
2083
  const entities = await documentManager2.findMany(
2034
2084
  {
2035
2085
  filters: {
2036
- id: ids
2086
+ documentId: ids
2037
2087
  },
2038
2088
  locale
2039
2089
  },
@@ -2535,7 +2585,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
2535
2585
  throw new strapiUtils.errors.ForbiddenError();
2536
2586
  }
2537
2587
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2538
- const { locale } = getDocumentLocaleAndStatus(body);
2588
+ const { locale } = await getDocumentLocaleAndStatus(body);
2539
2589
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2540
2590
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2541
2591
  // Find the first document to check if it exists
@@ -2572,12 +2622,11 @@ const singleTypes = {
2572
2622
  const { model } = ctx.params;
2573
2623
  const { query = {} } = ctx.request;
2574
2624
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2575
- const documentMetadata2 = getService$1("document-metadata");
2576
2625
  if (permissionChecker2.cannot.read()) {
2577
2626
  return ctx.forbidden();
2578
2627
  }
2579
2628
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2580
- const { locale, status } = getDocumentLocaleAndStatus(query);
2629
+ const { locale, status } = await getDocumentLocaleAndStatus(query);
2581
2630
  const version = await findDocument(permissionQuery, model, { locale, status });
2582
2631
  if (!version) {
2583
2632
  if (permissionChecker2.cannot.create()) {
@@ -2587,8 +2636,10 @@ const singleTypes = {
2587
2636
  if (!document) {
2588
2637
  return ctx.notFound();
2589
2638
  }
2590
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
2639
+ const { meta } = await formatDocumentWithMetadata(
2640
+ permissionChecker2,
2591
2641
  model,
2642
+ // @ts-expect-error - fix types
2592
2643
  { id: document.documentId, locale, publishedAt: null },
2593
2644
  { availableLocales: true, availableStatus: false }
2594
2645
  );
@@ -2599,16 +2650,15 @@ const singleTypes = {
2599
2650
  return ctx.forbidden();
2600
2651
  }
2601
2652
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
2602
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2653
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2603
2654
  },
2604
2655
  async createOrUpdate(ctx) {
2605
2656
  const { userAbility } = ctx.state;
2606
2657
  const { model } = ctx.params;
2607
- const documentMetadata2 = getService$1("document-metadata");
2608
2658
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2609
2659
  const document = await createOrUpdateDocument(ctx);
2610
2660
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2611
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2661
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2612
2662
  },
2613
2663
  async delete(ctx) {
2614
2664
  const { userAbility } = ctx.state;
@@ -2621,7 +2671,7 @@ const singleTypes = {
2621
2671
  }
2622
2672
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2623
2673
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2624
- const { locale } = getDocumentLocaleAndStatus(query);
2674
+ const { locale } = await getDocumentLocaleAndStatus(query);
2625
2675
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2626
2676
  populate,
2627
2677
  locale
@@ -2644,7 +2694,6 @@ const singleTypes = {
2644
2694
  const { model } = ctx.params;
2645
2695
  const { query = {} } = ctx.request;
2646
2696
  const documentManager2 = getService$1("document-manager");
2647
- const documentMetadata2 = getService$1("document-metadata");
2648
2697
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2649
2698
  if (permissionChecker2.cannot.publish()) {
2650
2699
  return ctx.forbidden();
@@ -2659,11 +2708,12 @@ const singleTypes = {
2659
2708
  if (permissionChecker2.cannot.publish(document)) {
2660
2709
  throw new strapiUtils.errors.ForbiddenError();
2661
2710
  }
2662
- const { locale } = getDocumentLocaleAndStatus(document);
2663
- return documentManager2.publish(document.documentId, model, { locale });
2711
+ const { locale } = await getDocumentLocaleAndStatus(document);
2712
+ const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2713
+ return publishResult.at(0);
2664
2714
  });
2665
2715
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
2666
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2716
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2667
2717
  },
2668
2718
  async unpublish(ctx) {
2669
2719
  const { userAbility } = ctx.state;
@@ -2673,7 +2723,6 @@ const singleTypes = {
2673
2723
  query = {}
2674
2724
  } = ctx.request;
2675
2725
  const documentManager2 = getService$1("document-manager");
2676
- const documentMetadata2 = getService$1("document-metadata");
2677
2726
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2678
2727
  if (permissionChecker2.cannot.unpublish()) {
2679
2728
  return ctx.forbidden();
@@ -2682,7 +2731,7 @@ const singleTypes = {
2682
2731
  return ctx.forbidden();
2683
2732
  }
2684
2733
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2685
- const { locale } = getDocumentLocaleAndStatus(body);
2734
+ const { locale } = await getDocumentLocaleAndStatus(body);
2686
2735
  const document = await findDocument(sanitizedQuery, model, { locale });
2687
2736
  if (!document) {
2688
2737
  return ctx.notFound();
@@ -2700,7 +2749,7 @@ const singleTypes = {
2700
2749
  ctx.body = await strapiUtils.async.pipe(
2701
2750
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
2702
2751
  permissionChecker2.sanitizeOutput,
2703
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2752
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2704
2753
  )(document);
2705
2754
  });
2706
2755
  },
@@ -2709,13 +2758,12 @@ const singleTypes = {
2709
2758
  const { model } = ctx.params;
2710
2759
  const { body, query = {} } = ctx.request;
2711
2760
  const documentManager2 = getService$1("document-manager");
2712
- const documentMetadata2 = getService$1("document-metadata");
2713
2761
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2714
2762
  if (permissionChecker2.cannot.discard()) {
2715
2763
  return ctx.forbidden();
2716
2764
  }
2717
2765
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2718
- const { locale } = getDocumentLocaleAndStatus(body);
2766
+ const { locale } = await getDocumentLocaleAndStatus(body);
2719
2767
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2720
2768
  if (!document) {
2721
2769
  return ctx.notFound();
@@ -2726,7 +2774,7 @@ const singleTypes = {
2726
2774
  ctx.body = await strapiUtils.async.pipe(
2727
2775
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
2728
2776
  permissionChecker2.sanitizeOutput,
2729
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2777
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2730
2778
  )(document);
2731
2779
  },
2732
2780
  async countDraftRelations(ctx) {
@@ -2735,7 +2783,7 @@ const singleTypes = {
2735
2783
  const { query } = ctx.request;
2736
2784
  const documentManager2 = getService$1("document-manager");
2737
2785
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2738
- const { locale } = getDocumentLocaleAndStatus(query);
2786
+ const { locale } = await getDocumentLocaleAndStatus(query);
2739
2787
  if (permissionChecker2.cannot.read()) {
2740
2788
  return ctx.forbidden();
2741
2789
  }
@@ -2756,7 +2804,7 @@ const uid$1 = {
2756
2804
  async generateUID(ctx) {
2757
2805
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2758
2806
  const { query = {} } = ctx.request;
2759
- const { locale } = getDocumentLocaleAndStatus(query);
2807
+ const { locale } = await getDocumentLocaleAndStatus(query);
2760
2808
  await validateUIDField(contentTypeUID, field);
2761
2809
  const uidService = getService$1("uid");
2762
2810
  ctx.body = {
@@ -2768,7 +2816,7 @@ const uid$1 = {
2768
2816
  ctx.request.body
2769
2817
  );
2770
2818
  const { query = {} } = ctx.request;
2771
- const { locale } = getDocumentLocaleAndStatus(query);
2819
+ const { locale } = await getDocumentLocaleAndStatus(query);
2772
2820
  await validateUIDField(contentTypeUID, field);
2773
2821
  const uidService = getService$1("uid");
2774
2822
  const isAvailable = await uidService.checkUIDAvailability({
@@ -3559,7 +3607,7 @@ const permission = ({ strapi: strapi2 }) => ({
3559
3607
  await strapi2.service("admin::permission").actionProvider.registerMany(actions);
3560
3608
  }
3561
3609
  });
3562
- const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils__default.default.contentTypes;
3610
+ const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils__default.default.contentTypes;
3563
3611
  const { isAnyToMany } = strapiUtils__default.default.relations;
3564
3612
  const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils__default.default.contentTypes.constants;
3565
3613
  const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
@@ -3650,6 +3698,42 @@ const getDeepPopulate = (uid2, {
3650
3698
  {}
3651
3699
  );
3652
3700
  };
3701
+ const getValidatableFieldsPopulate = (uid2, {
3702
+ initialPopulate = {},
3703
+ countMany = false,
3704
+ countOne = false,
3705
+ maxLevel = Infinity
3706
+ } = {}, level = 1) => {
3707
+ if (level > maxLevel) {
3708
+ return {};
3709
+ }
3710
+ const model = strapi.getModel(uid2);
3711
+ return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
3712
+ if (!getDoesAttributeRequireValidation(attribute)) {
3713
+ return populateAcc;
3714
+ }
3715
+ if (isScalarAttribute(attribute)) {
3716
+ return fp.merge(populateAcc, {
3717
+ [attributeName]: true
3718
+ });
3719
+ }
3720
+ return fp.merge(
3721
+ populateAcc,
3722
+ getPopulateFor(
3723
+ attributeName,
3724
+ model,
3725
+ {
3726
+ // @ts-expect-error - improve types
3727
+ initialPopulate: initialPopulate?.[attributeName],
3728
+ countMany,
3729
+ countOne,
3730
+ maxLevel
3731
+ },
3732
+ level
3733
+ )
3734
+ );
3735
+ }, {});
3736
+ };
3653
3737
  const getDeepPopulateDraftCount = (uid2) => {
3654
3738
  const model = strapi.getModel(uid2);
3655
3739
  let hasRelations = false;
@@ -3878,41 +3962,70 @@ const AVAILABLE_STATUS_FIELDS = [
3878
3962
  "updatedBy",
3879
3963
  "status"
3880
3964
  ];
3881
- const AVAILABLE_LOCALES_FIELDS = ["id", "locale", "updatedAt", "createdAt", "status"];
3965
+ const AVAILABLE_LOCALES_FIELDS = [
3966
+ "id",
3967
+ "locale",
3968
+ "updatedAt",
3969
+ "createdAt",
3970
+ "status",
3971
+ "publishedAt",
3972
+ "documentId"
3973
+ ];
3882
3974
  const CONTENT_MANAGER_STATUS = {
3883
3975
  PUBLISHED: "published",
3884
3976
  DRAFT: "draft",
3885
3977
  MODIFIED: "modified"
3886
3978
  };
3887
- const areDatesEqual = (date1, date2, threshold) => {
3888
- if (!date1 || !date2) {
3979
+ const getIsVersionLatestModification = (version, otherVersion) => {
3980
+ if (!version || !version.updatedAt) {
3889
3981
  return false;
3890
3982
  }
3891
- const time1 = new Date(date1).getTime();
3892
- const time2 = new Date(date2).getTime();
3893
- const difference = Math.abs(time1 - time2);
3894
- return difference <= threshold;
3983
+ const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
3984
+ const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
3985
+ return versionUpdatedAt > otherUpdatedAt;
3895
3986
  };
3896
3987
  const documentMetadata = ({ strapi: strapi2 }) => ({
3897
3988
  /**
3898
3989
  * Returns available locales of a document for the current status
3899
3990
  */
3900
- getAvailableLocales(uid2, version, allVersions) {
3991
+ async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
3901
3992
  const versionsByLocale = fp.groupBy("locale", allVersions);
3902
3993
  delete versionsByLocale[version.locale];
3903
- return Object.values(versionsByLocale).map((localeVersions) => {
3904
- if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2))) {
3905
- return fp.pick(AVAILABLE_LOCALES_FIELDS, localeVersions[0]);
3994
+ const model = strapi2.getModel(uid2);
3995
+ const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
3996
+ const traversalFunction = async (localeVersion) => strapiUtils.traverseEntity(
3997
+ ({ key }, { remove }) => {
3998
+ if (keysToKeep.includes(key)) {
3999
+ return;
4000
+ }
4001
+ remove(key);
4002
+ },
4003
+ { schema: model, getModel: strapi2.getModel.bind(strapi2) },
4004
+ // @ts-expect-error fix types DocumentVersion incompatible with Data
4005
+ localeVersion
4006
+ );
4007
+ const mappingResult = await strapiUtils.async.map(
4008
+ Object.values(versionsByLocale),
4009
+ async (localeVersions) => {
4010
+ const mappedLocaleVersions = await strapiUtils.async.map(
4011
+ localeVersions,
4012
+ traversalFunction
4013
+ );
4014
+ if (!strapiUtils.contentTypes.hasDraftAndPublish(model)) {
4015
+ return mappedLocaleVersions[0];
4016
+ }
4017
+ const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
4018
+ const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
4019
+ if (!draftVersion) {
4020
+ return;
4021
+ }
4022
+ return {
4023
+ ...draftVersion,
4024
+ status: this.getStatus(draftVersion, otherVersions)
4025
+ };
3906
4026
  }
3907
- const draftVersion = localeVersions.find((v) => v.publishedAt === null);
3908
- const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
3909
- if (!draftVersion)
3910
- return;
3911
- return {
3912
- ...fp.pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
3913
- status: this.getStatus(draftVersion, otherVersions)
3914
- };
3915
- }).filter(Boolean);
4027
+ );
4028
+ return mappingResult.filter(Boolean);
3916
4029
  },
3917
4030
  /**
3918
4031
  * Returns available status of a document for the current locale
@@ -3950,26 +4063,37 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3950
4063
  });
3951
4064
  },
3952
4065
  getStatus(version, otherDocumentStatuses) {
3953
- const isDraft = version.publishedAt === null;
3954
- if (!otherDocumentStatuses?.length) {
3955
- return isDraft ? CONTENT_MANAGER_STATUS.DRAFT : CONTENT_MANAGER_STATUS.PUBLISHED;
4066
+ let draftVersion;
4067
+ let publishedVersion;
4068
+ if (version.publishedAt) {
4069
+ publishedVersion = version;
4070
+ } else {
4071
+ draftVersion = version;
3956
4072
  }
3957
- if (isDraft) {
3958
- const publishedVersion = otherDocumentStatuses?.find((d) => d.publishedAt !== null);
3959
- if (!publishedVersion) {
3960
- return CONTENT_MANAGER_STATUS.DRAFT;
3961
- }
4073
+ const otherVersion = otherDocumentStatuses?.at(0);
4074
+ if (otherVersion?.publishedAt) {
4075
+ publishedVersion = otherVersion;
4076
+ } else if (otherVersion) {
4077
+ draftVersion = otherVersion;
3962
4078
  }
3963
- if (areDatesEqual(version.updatedAt, otherDocumentStatuses.at(0)?.updatedAt, 500)) {
4079
+ if (!draftVersion)
3964
4080
  return CONTENT_MANAGER_STATUS.PUBLISHED;
3965
- }
3966
- return CONTENT_MANAGER_STATUS.MODIFIED;
4081
+ if (!publishedVersion)
4082
+ return CONTENT_MANAGER_STATUS.DRAFT;
4083
+ const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4084
+ return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
3967
4085
  },
4086
+ // TODO is it necessary to return metadata on every page of the CM
4087
+ // We could refactor this so the locales are only loaded when they're
4088
+ // needed. e.g. in the bulk locale action modal.
3968
4089
  async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
4090
+ const populate = getValidatableFieldsPopulate(uid2);
3969
4091
  const versions = await strapi2.db.query(uid2).findMany({
3970
4092
  where: { documentId: version.documentId },
3971
- select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
3972
4093
  populate: {
4094
+ // Populate only fields that require validation for bulk locale actions
4095
+ ...populate,
4096
+ // NOTE: creator fields are selected in this way to avoid exposing sensitive data
3973
4097
  createdBy: {
3974
4098
  select: ["id", "firstname", "lastname", "email"]
3975
4099
  },
@@ -3978,7 +4102,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3978
4102
  }
3979
4103
  }
3980
4104
  });
3981
- const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
4105
+ const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
3982
4106
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
3983
4107
  return {
3984
4108
  availableLocales: availableLocalesResult,
@@ -3991,8 +4115,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3991
4115
  * - Available status of the document for the current locale
3992
4116
  */
3993
4117
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
3994
- if (!document)
4118
+ if (!document) {
3995
4119
  return document;
4120
+ }
3996
4121
  const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
3997
4122
  if (!hasDraftAndPublish) {
3998
4123
  opts.availableStatus = false;
@@ -4042,26 +4167,9 @@ const sumDraftCounts = (entity, uid2) => {
4042
4167
  }, 0);
4043
4168
  };
4044
4169
  const { ApplicationError } = strapiUtils.errors;
4045
- const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
4046
4170
  const { PUBLISHED_AT_ATTRIBUTE } = strapiUtils.contentTypes.constants;
4047
4171
  const omitPublishedAtField = fp.omit(PUBLISHED_AT_ATTRIBUTE);
4048
4172
  const omitIdField = fp.omit("id");
4049
- const emitEvent = async (uid2, event, document) => {
4050
- const modelDef = strapi.getModel(uid2);
4051
- const sanitizedDocument = await strapiUtils.sanitize.sanitizers.defaultSanitizeOutput(
4052
- {
4053
- schema: modelDef,
4054
- getModel(uid22) {
4055
- return strapi.getModel(uid22);
4056
- }
4057
- },
4058
- document
4059
- );
4060
- strapi.eventHub.emit(event, {
4061
- model: modelDef.modelName,
4062
- entry: sanitizedDocument
4063
- });
4064
- };
4065
4173
  const documentManager = ({ strapi: strapi2 }) => {
4066
4174
  return {
4067
4175
  async findOne(id, uid2, opts = {}) {
@@ -4080,6 +4188,9 @@ const documentManager = ({ strapi: strapi2 }) => {
4080
4188
  } else if (opts.locale && opts.locale !== "*") {
4081
4189
  where.locale = opts.locale;
4082
4190
  }
4191
+ if (typeof opts.isPublished === "boolean") {
4192
+ where.publishedAt = { $notNull: opts.isPublished };
4193
+ }
4083
4194
  return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
4084
4195
  },
4085
4196
  async findMany(opts, uid2) {
@@ -4087,20 +4198,16 @@ const documentManager = ({ strapi: strapi2 }) => {
4087
4198
  return strapi2.documents(uid2).findMany(params);
4088
4199
  },
4089
4200
  async findPage(opts, uid2) {
4090
- const page = Number(opts?.page) || 1;
4091
- const pageSize = Number(opts?.pageSize) || 10;
4201
+ const params = strapiUtils.pagination.withDefaultPagination(opts || {}, {
4202
+ maxLimit: 1e3
4203
+ });
4092
4204
  const [documents, total = 0] = await Promise.all([
4093
- strapi2.documents(uid2).findMany(opts),
4094
- strapi2.documents(uid2).count(opts)
4205
+ strapi2.documents(uid2).findMany(params),
4206
+ strapi2.documents(uid2).count(params)
4095
4207
  ]);
4096
4208
  return {
4097
4209
  results: documents,
4098
- pagination: {
4099
- page,
4100
- pageSize,
4101
- pageCount: Math.ceil(total / pageSize),
4102
- total
4103
- }
4210
+ pagination: strapiUtils.pagination.transformPagedPaginationInfo(params, total)
4104
4211
  };
4105
4212
  },
4106
4213
  async create(uid2, opts = {}) {
@@ -4146,70 +4253,36 @@ const documentManager = ({ strapi: strapi2 }) => {
4146
4253
  return {};
4147
4254
  },
4148
4255
  // FIXME: handle relations
4149
- async deleteMany(opts, uid2) {
4150
- const docs = await strapi2.documents(uid2).findMany(opts);
4151
- for (const doc of docs) {
4152
- await strapi2.documents(uid2).delete({ documentId: doc.documentId });
4153
- }
4154
- return { count: docs.length };
4256
+ async deleteMany(documentIds, uid2, opts = {}) {
4257
+ const deletedEntries = await strapi2.db.transaction(async () => {
4258
+ return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
4259
+ });
4260
+ return { count: deletedEntries.length };
4155
4261
  },
4156
4262
  async publish(id, uid2, opts = {}) {
4157
4263
  const populate = await buildDeepPopulate(uid2);
4158
4264
  const params = { ...opts, populate };
4159
- return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries.at(0));
4265
+ return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
4160
4266
  },
4161
- async publishMany(entities, uid2) {
4162
- if (!entities.length) {
4163
- return null;
4164
- }
4165
- await Promise.all(
4166
- entities.map((document) => {
4167
- return strapi2.entityValidator.validateEntityCreation(
4168
- strapi2.getModel(uid2),
4169
- document,
4170
- void 0,
4171
- // @ts-expect-error - FIXME: entity here is unnecessary
4172
- document
4173
- );
4174
- })
4175
- );
4176
- const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4177
- const filters = { id: { $in: entitiesToPublish } };
4178
- const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
4179
- const populate = await buildDeepPopulate(uid2);
4180
- const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4181
- where: filters,
4182
- data
4183
- });
4184
- const publishedEntities = await strapi2.db.query(uid2).findMany({
4185
- where: filters,
4186
- populate
4267
+ async publishMany(uid2, documentIds, locale) {
4268
+ return strapi2.db.transaction(async () => {
4269
+ const results = await Promise.all(
4270
+ documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
4271
+ );
4272
+ const publishedEntitiesCount = results.flat().filter(Boolean).length;
4273
+ return publishedEntitiesCount;
4187
4274
  });
4188
- await Promise.all(
4189
- publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
4190
- );
4191
- return publishedEntitiesCount;
4192
4275
  },
4193
- async unpublishMany(documents, uid2) {
4194
- if (!documents.length) {
4195
- return null;
4196
- }
4197
- const entitiesToUnpublish = documents.filter((doc) => doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4198
- const filters = { id: { $in: entitiesToUnpublish } };
4199
- const data = { [PUBLISHED_AT_ATTRIBUTE]: null };
4200
- const populate = await buildDeepPopulate(uid2);
4201
- const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4202
- where: filters,
4203
- data
4204
- });
4205
- const unpublishedEntities = await strapi2.db.query(uid2).findMany({
4206
- where: filters,
4207
- populate
4276
+ async unpublishMany(documentIds, uid2, opts = {}) {
4277
+ const unpublishedEntries = await strapi2.db.transaction(async () => {
4278
+ return Promise.all(
4279
+ documentIds.map(
4280
+ (id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
4281
+ )
4282
+ );
4208
4283
  });
4209
- await Promise.all(
4210
- unpublishedEntities.map((doc) => emitEvent(uid2, ENTRY_UNPUBLISH, doc))
4211
- );
4212
- return unpublishedEntitiesCount;
4284
+ const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
4285
+ return { count: unpublishedEntitiesCount };
4213
4286
  },
4214
4287
  async unpublish(id, uid2, opts = {}) {
4215
4288
  const populate = await buildDeepPopulate(uid2);
@@ -4234,16 +4307,20 @@ const documentManager = ({ strapi: strapi2 }) => {
4234
4307
  }
4235
4308
  return sumDraftCounts(document, uid2);
4236
4309
  },
4237
- async countManyEntriesDraftRelations(ids, uid2, locale) {
4310
+ async countManyEntriesDraftRelations(documentIds, uid2, locale) {
4238
4311
  const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
4239
4312
  if (!hasRelations) {
4240
4313
  return 0;
4241
4314
  }
4315
+ let localeFilter = {};
4316
+ if (locale) {
4317
+ localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
4318
+ }
4242
4319
  const entities = await strapi2.db.query(uid2).findMany({
4243
4320
  populate,
4244
4321
  where: {
4245
- id: { $in: ids },
4246
- ...locale ? { locale } : {}
4322
+ documentId: { $in: documentIds },
4323
+ ...localeFilter
4247
4324
  }
4248
4325
  });
4249
4326
  const totalNumberDraftRelations = entities.reduce(