@strapi/content-manager 0.0.0-experimental.32c4b04580cc12400710050c8198e46b3644cfd4 → 0.0.0-experimental.332a7d5b6b1d23635d7e205657f0ff39ec133c9e

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 (215) hide show
  1. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
  2. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs → ComponentConfigurationPage-D4H-v0et.mjs} +4 -4
  4. package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs.map → ComponentConfigurationPage-D4H-v0et.mjs.map} +1 -1
  5. package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js → ComponentConfigurationPage-DdkVGfXC.js} +5 -6
  6. package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js.map → ComponentConfigurationPage-DdkVGfXC.js.map} +1 -1
  7. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
  8. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
  9. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
  10. package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs → EditConfigurationPage-D1nvB7Br.mjs} +4 -4
  11. package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs.map → EditConfigurationPage-D1nvB7Br.mjs.map} +1 -1
  12. package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js → EditConfigurationPage-LYEvR4fW.js} +5 -6
  13. package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js.map → EditConfigurationPage-LYEvR4fW.js.map} +1 -1
  14. package/dist/_chunks/{EditViewPage-BLsjc5F-.mjs → EditViewPage-Bcnff6Vd.mjs} +34 -46
  15. package/dist/_chunks/EditViewPage-Bcnff6Vd.mjs.map +1 -0
  16. package/dist/_chunks/{EditViewPage-C-ukDOB7.js → EditViewPage-DqelJ9UK.js} +36 -49
  17. package/dist/_chunks/EditViewPage-DqelJ9UK.js.map +1 -0
  18. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  19. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  20. package/dist/_chunks/{Form-CPYqIWDG.js → Form-CnHfBeiB.js} +39 -21
  21. package/dist/_chunks/Form-CnHfBeiB.js.map +1 -0
  22. package/dist/_chunks/{Form-Dg_GS5TQ.mjs → Form-CzPCJi3B.mjs} +37 -18
  23. package/dist/_chunks/Form-CzPCJi3B.mjs.map +1 -0
  24. package/dist/_chunks/{History-wrnHqf09.mjs → History-CcmSn3Mj.mjs} +71 -104
  25. package/dist/_chunks/History-CcmSn3Mj.mjs.map +1 -0
  26. package/dist/_chunks/{History-DNQkXANT.js → History-zArjENzj.js} +81 -115
  27. package/dist/_chunks/History-zArjENzj.js.map +1 -0
  28. package/dist/_chunks/{Field-Bfph5SOd.js → Input-CDHKQd7o.js} +1334 -1239
  29. package/dist/_chunks/Input-CDHKQd7o.js.map +1 -0
  30. package/dist/_chunks/{Field-Cs7duwWd.mjs → Input-aV8SSoTa.mjs} +1192 -1097
  31. package/dist/_chunks/Input-aV8SSoTa.mjs.map +1 -0
  32. package/dist/_chunks/{ListConfigurationPage-DScmJVkW.mjs → ListConfigurationPage-BPvzENJJ.mjs} +19 -8
  33. package/dist/_chunks/ListConfigurationPage-BPvzENJJ.mjs.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-CUQxfpjT.js → ListConfigurationPage-ByZAO_9H.js} +19 -9
  35. package/dist/_chunks/ListConfigurationPage-ByZAO_9H.js.map +1 -0
  36. package/dist/_chunks/{ListViewPage-BsLiH2-2.js → ListViewPage-BVKBeQAA.js} +108 -74
  37. package/dist/_chunks/ListViewPage-BVKBeQAA.js.map +1 -0
  38. package/dist/_chunks/{ListViewPage-C4IvrMgY.mjs → ListViewPage-HljQVnFH.mjs} +109 -74
  39. package/dist/_chunks/ListViewPage-HljQVnFH.mjs.map +1 -0
  40. package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js → NoContentTypePage-BV5zfDxr.js} +2 -2
  41. package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js.map → NoContentTypePage-BV5zfDxr.js.map} +1 -1
  42. package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs → NoContentTypePage-BfHaSM-K.mjs} +2 -2
  43. package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs.map → NoContentTypePage-BfHaSM-K.mjs.map} +1 -1
  44. package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs → NoPermissionsPage-D6ze2nQL.mjs} +2 -2
  45. package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs.map → NoPermissionsPage-D6ze2nQL.mjs.map} +1 -1
  46. package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js → NoPermissionsPage-vdNpc6jb.js} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js.map → NoPermissionsPage-vdNpc6jb.js.map} +1 -1
  48. package/dist/_chunks/Preview-DEHdENT1.js +305 -0
  49. package/dist/_chunks/Preview-DEHdENT1.js.map +1 -0
  50. package/dist/_chunks/Preview-vfWOtPG5.mjs +287 -0
  51. package/dist/_chunks/Preview-vfWOtPG5.mjs.map +1 -0
  52. package/dist/_chunks/{Relations-BZr8tL0R.mjs → Relations-B7_hbF0w.mjs} +79 -44
  53. package/dist/_chunks/Relations-B7_hbF0w.mjs.map +1 -0
  54. package/dist/_chunks/{Relations-CtELXYIK.js → Relations-DcoOBejP.js} +79 -45
  55. package/dist/_chunks/Relations-DcoOBejP.js.map +1 -0
  56. package/dist/_chunks/{en-uOUIxfcQ.js → en-BR48D_RH.js} +35 -15
  57. package/dist/_chunks/{en-uOUIxfcQ.js.map → en-BR48D_RH.js.map} +1 -1
  58. package/dist/_chunks/{en-BrCTWlZv.mjs → en-D65uIF6Y.mjs} +35 -15
  59. package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
  60. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  61. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  62. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  63. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  64. package/dist/_chunks/{fr-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
  65. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
  66. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
  67. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
  68. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  69. package/dist/_chunks/{index-OerGjbAN.js → index-CxLSGwnk.js} +1304 -750
  70. package/dist/_chunks/index-CxLSGwnk.js.map +1 -0
  71. package/dist/_chunks/{index-c_5DdJi-.mjs → index-EH8ZtHd5.mjs} +1323 -769
  72. package/dist/_chunks/index-EH8ZtHd5.mjs.map +1 -0
  73. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  74. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  75. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  76. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  77. package/dist/_chunks/{layout-oPBiO7RY.mjs → layout-CxDMdJ13.mjs} +23 -10
  78. package/dist/_chunks/layout-CxDMdJ13.mjs.map +1 -0
  79. package/dist/_chunks/{layout-Ci7qHlFb.js → layout-DSeUTfMv.js} +23 -11
  80. package/dist/_chunks/layout-DSeUTfMv.js.map +1 -0
  81. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  82. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  83. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  84. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  85. package/dist/_chunks/{relations-BIdWFjdq.mjs → relations-B8_Uu38Q.mjs} +21 -8
  86. package/dist/_chunks/relations-B8_Uu38Q.mjs.map +1 -0
  87. package/dist/_chunks/{relations-COBpStiF.js → relations-S5nNKdN3.js} +20 -7
  88. package/dist/_chunks/relations-S5nNKdN3.js.map +1 -0
  89. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  90. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  91. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  92. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  93. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -1
  94. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -1
  95. package/dist/admin/index.js +3 -1
  96. package/dist/admin/index.js.map +1 -1
  97. package/dist/admin/index.mjs +6 -4
  98. package/dist/admin/src/content-manager.d.ts +3 -2
  99. package/dist/admin/src/exports.d.ts +2 -1
  100. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  101. package/dist/admin/src/hooks/useDocument.d.ts +49 -1
  102. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  103. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -1
  104. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
  105. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  106. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  107. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
  108. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
  109. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
  110. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  111. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  112. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  113. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
  114. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  115. package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
  116. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  117. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  118. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  119. package/dist/admin/src/preview/index.d.ts +4 -0
  120. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  121. package/dist/admin/src/preview/routes.d.ts +3 -0
  122. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  123. package/dist/admin/src/router.d.ts +1 -1
  124. package/dist/admin/src/services/api.d.ts +1 -1
  125. package/dist/admin/src/services/components.d.ts +2 -2
  126. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  127. package/dist/admin/src/services/documents.d.ts +19 -20
  128. package/dist/admin/src/services/init.d.ts +1 -1
  129. package/dist/admin/src/services/relations.d.ts +2 -2
  130. package/dist/admin/src/services/uid.d.ts +3 -3
  131. package/dist/admin/src/utils/validation.d.ts +4 -1
  132. package/dist/server/index.js +727 -406
  133. package/dist/server/index.js.map +1 -1
  134. package/dist/server/index.mjs +728 -406
  135. package/dist/server/index.mjs.map +1 -1
  136. package/dist/server/src/bootstrap.d.ts.map +1 -1
  137. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  138. package/dist/server/src/controllers/index.d.ts.map +1 -1
  139. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  140. package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
  141. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  142. package/dist/server/src/history/controllers/history-version.d.ts +1 -1
  143. package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
  144. package/dist/server/src/history/services/history.d.ts +3 -3
  145. package/dist/server/src/history/services/history.d.ts.map +1 -1
  146. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  147. package/dist/server/src/history/services/utils.d.ts +8 -12
  148. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  149. package/dist/server/src/index.d.ts +7 -6
  150. package/dist/server/src/index.d.ts.map +1 -1
  151. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  152. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  153. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  154. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  155. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  156. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  157. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  158. package/dist/server/src/preview/index.d.ts +4 -0
  159. package/dist/server/src/preview/index.d.ts.map +1 -0
  160. package/dist/server/src/preview/routes/index.d.ts +8 -0
  161. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  162. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  163. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  164. package/dist/server/src/preview/services/index.d.ts +16 -0
  165. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  166. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  167. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  168. package/dist/server/src/preview/services/preview.d.ts +12 -0
  169. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  170. package/dist/server/src/preview/utils.d.ts +19 -0
  171. package/dist/server/src/preview/utils.d.ts.map +1 -0
  172. package/dist/server/src/register.d.ts.map +1 -1
  173. package/dist/server/src/routes/index.d.ts.map +1 -1
  174. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  175. package/dist/server/src/services/document-metadata.d.ts +12 -10
  176. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  177. package/dist/server/src/services/index.d.ts +7 -6
  178. package/dist/server/src/services/index.d.ts.map +1 -1
  179. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  180. package/dist/server/src/services/utils/populate.d.ts +2 -2
  181. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  182. package/dist/server/src/utils/index.d.ts +2 -0
  183. package/dist/server/src/utils/index.d.ts.map +1 -1
  184. package/dist/shared/contracts/collection-types.d.ts +3 -1
  185. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  186. package/dist/shared/contracts/index.d.ts +1 -0
  187. package/dist/shared/contracts/index.d.ts.map +1 -1
  188. package/dist/shared/contracts/preview.d.ts +27 -0
  189. package/dist/shared/contracts/preview.d.ts.map +1 -0
  190. package/dist/shared/index.js +4 -0
  191. package/dist/shared/index.js.map +1 -1
  192. package/dist/shared/index.mjs +4 -0
  193. package/dist/shared/index.mjs.map +1 -1
  194. package/package.json +17 -16
  195. package/dist/_chunks/EditViewPage-BLsjc5F-.mjs.map +0 -1
  196. package/dist/_chunks/EditViewPage-C-ukDOB7.js.map +0 -1
  197. package/dist/_chunks/Field-Bfph5SOd.js.map +0 -1
  198. package/dist/_chunks/Field-Cs7duwWd.mjs.map +0 -1
  199. package/dist/_chunks/Form-CPYqIWDG.js.map +0 -1
  200. package/dist/_chunks/Form-Dg_GS5TQ.mjs.map +0 -1
  201. package/dist/_chunks/History-DNQkXANT.js.map +0 -1
  202. package/dist/_chunks/History-wrnHqf09.mjs.map +0 -1
  203. package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +0 -1
  204. package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +0 -1
  205. package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +0 -1
  206. package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +0 -1
  207. package/dist/_chunks/Relations-BZr8tL0R.mjs.map +0 -1
  208. package/dist/_chunks/Relations-CtELXYIK.js.map +0 -1
  209. package/dist/_chunks/index-OerGjbAN.js.map +0 -1
  210. package/dist/_chunks/index-c_5DdJi-.mjs.map +0 -1
  211. package/dist/_chunks/layout-Ci7qHlFb.js.map +0 -1
  212. package/dist/_chunks/layout-oPBiO7RY.mjs.map +0 -1
  213. package/dist/_chunks/relations-BIdWFjdq.mjs.map +0 -1
  214. package/dist/_chunks/relations-COBpStiF.js.map +0 -1
  215. package/strapi-server.js +0 -3
@@ -1,5 +1,5 @@
1
- import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1, traverseEntity, pagination } from "@strapi/utils";
2
- import { pick, omit, difference, intersection, pipe, propOr, isEqual, isEmpty, set, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, isNil as isNil$1, getOr, propEq, merge, groupBy, castArray } from "lodash/fp";
1
+ import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, traverseEntity, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1, pagination } from "@strapi/utils";
2
+ import { pick, omit, difference, castArray, mergeWith, intersection, pipe, propOr, isEqual, isEmpty, set, isNil as isNil$1, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, getOr, propEq, merge, groupBy } from "lodash/fp";
3
3
  import "@strapi/types";
4
4
  import * as yup from "yup";
5
5
  import { scheduleJob } from "node-schedule";
@@ -7,10 +7,10 @@ import isNil from "lodash/isNil";
7
7
  import _, { intersection as intersection$1, difference as difference$1 } from "lodash";
8
8
  import qs from "qs";
9
9
  import slugify from "@sindresorhus/slugify";
10
- const getService$1 = (name) => {
10
+ const getService$2 = (name) => {
11
11
  return strapi.plugin("content-manager").service(name);
12
12
  };
13
- function getService(strapi2, name) {
13
+ function getService$1(strapi2, name) {
14
14
  return strapi2.service(`plugin::content-manager.${name}`);
15
15
  }
16
16
  const historyRestoreVersionSchema = yup.object().shape({
@@ -46,7 +46,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
46
46
  if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {
47
47
  throw new errors.ForbiddenError("contentType and documentId are required");
48
48
  }
49
- const permissionChecker2 = getService$1("permission-checker").create({
49
+ const permissionChecker2 = getService$2("permission-checker").create({
50
50
  userAbility: ctx.state.userAbility,
51
51
  model: ctx.query.contentType
52
52
  });
@@ -54,7 +54,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
54
54
  return ctx.forbidden();
55
55
  }
56
56
  const query = await permissionChecker2.sanitizeQuery(ctx.query);
57
- const { results, pagination: pagination2 } = await getService(strapi2, "history").findVersionsPage({
57
+ const { results, pagination: pagination2 } = await getService$1(strapi2, "history").findVersionsPage({
58
58
  query: {
59
59
  ...query,
60
60
  ...getValidPagination({ page: query.page, pageSize: query.pageSize })
@@ -79,14 +79,14 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
79
79
  async restoreVersion(ctx) {
80
80
  const request = ctx.request;
81
81
  await validateRestoreVersion(request.body, "contentType is required");
82
- const permissionChecker2 = getService$1("permission-checker").create({
82
+ const permissionChecker2 = getService$2("permission-checker").create({
83
83
  userAbility: ctx.state.userAbility,
84
84
  model: request.body.contentType
85
85
  });
86
86
  if (permissionChecker2.cannot.update()) {
87
87
  throw new errors.ForbiddenError();
88
88
  }
89
- const restoredDocument = await getService(strapi2, "history").restoreVersion(
89
+ const restoredDocument = await getService$1(strapi2, "history").restoreVersion(
90
90
  request.params.versionId
91
91
  );
92
92
  return {
@@ -95,7 +95,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
95
95
  }
96
96
  };
97
97
  };
98
- const controllers$1 = {
98
+ const controllers$2 = {
99
99
  "history-version": createHistoryVersionController
100
100
  /**
101
101
  * Casting is needed because the types aren't aware that Strapi supports
@@ -141,8 +141,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
141
141
  };
142
142
  const getRelationRestoreValue = async (versionRelationData, attribute) => {
143
143
  if (Array.isArray(versionRelationData)) {
144
- if (versionRelationData.length === 0)
145
- return versionRelationData;
144
+ if (versionRelationData.length === 0) return versionRelationData;
146
145
  const existingAndMissingRelations = await Promise.all(
147
146
  versionRelationData.map((relation) => {
148
147
  return strapi2.documents(attribute.target).findOne({
@@ -151,19 +150,16 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
151
150
  });
152
151
  })
153
152
  );
154
- return existingAndMissingRelations.filter(
155
- (relation) => relation !== null
156
- );
153
+ return existingAndMissingRelations.filter((relation) => relation !== null);
157
154
  }
158
155
  return strapi2.documents(attribute.target).findOne({
159
156
  documentId: versionRelationData.documentId,
160
157
  locale: versionRelationData.locale || void 0
161
158
  });
162
159
  };
163
- const getMediaRestoreValue = async (versionRelationData, attribute) => {
164
- if (attribute.multiple) {
160
+ const getMediaRestoreValue = async (versionRelationData) => {
161
+ if (Array.isArray(versionRelationData)) {
165
162
  const existingAndMissingMedias = await Promise.all(
166
- // @ts-expect-error Fix the type definitions so this isn't any
167
163
  versionRelationData.map((media) => {
168
164
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
169
165
  })
@@ -173,10 +169,11 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
173
169
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
174
170
  };
175
171
  const localesService = strapi2.plugin("i18n")?.service("locales");
172
+ const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
176
173
  const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
174
+ const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
177
175
  const getLocaleDictionary = async () => {
178
- if (!localesService)
179
- return {};
176
+ if (!localesService) return {};
180
177
  const locales = await localesService.find() || [];
181
178
  return locales.reduce(
182
179
  (acc, locale) => {
@@ -200,9 +197,21 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
200
197
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
201
198
  return documentMetadataService.getStatus(document, meta.availableStatus);
202
199
  };
203
- const getDeepPopulate2 = (uid2) => {
200
+ const getComponentFields = (componentUID) => {
201
+ return Object.entries(strapi2.getModel(componentUID).attributes).reduce(
202
+ (fieldsAcc, [key, attribute]) => {
203
+ if (!["relation", "media", "component", "dynamiczone"].includes(attribute.type)) {
204
+ fieldsAcc.push(key);
205
+ }
206
+ return fieldsAcc;
207
+ },
208
+ []
209
+ );
210
+ };
211
+ const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
204
212
  const model = strapi2.getModel(uid2);
205
213
  const attributes = Object.entries(model.attributes);
214
+ const fieldSelector = useDatabaseSyntax ? "select" : "fields";
206
215
  return attributes.reduce((acc, [attributeName, attribute]) => {
207
216
  switch (attribute.type) {
208
217
  case "relation": {
@@ -212,23 +221,29 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
212
221
  }
213
222
  const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
214
223
  if (isVisible2) {
215
- acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
224
+ acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
216
225
  }
217
226
  break;
218
227
  }
219
228
  case "media": {
220
- acc[attributeName] = { fields: ["id"] };
229
+ acc[attributeName] = { [fieldSelector]: ["id"] };
221
230
  break;
222
231
  }
223
232
  case "component": {
224
233
  const populate = getDeepPopulate2(attribute.component);
225
- acc[attributeName] = { populate };
234
+ acc[attributeName] = {
235
+ populate,
236
+ [fieldSelector]: getComponentFields(attribute.component)
237
+ };
226
238
  break;
227
239
  }
228
240
  case "dynamiczone": {
229
241
  const populatedComponents = (attribute.components || []).reduce(
230
242
  (acc2, componentUID) => {
231
- acc2[componentUID] = { populate: getDeepPopulate2(componentUID) };
243
+ acc2[componentUID] = {
244
+ populate: getDeepPopulate2(componentUID),
245
+ [fieldSelector]: getComponentFields(componentUID)
246
+ };
232
247
  return acc2;
233
248
  },
234
249
  {}
@@ -290,6 +305,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
290
305
  getRelationRestoreValue,
291
306
  getMediaRestoreValue,
292
307
  getDefaultLocale,
308
+ isLocalizedContentType,
293
309
  getLocaleDictionary,
294
310
  getRetentionDays,
295
311
  getVersionStatus,
@@ -312,7 +328,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
312
328
  });
313
329
  },
314
330
  async findVersionsPage(params) {
315
- const locale = params.query.locale || await serviceUtils.getDefaultLocale();
331
+ const schema = strapi2.getModel(params.query.contentType);
332
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(schema);
333
+ const defaultLocale = await serviceUtils.getDefaultLocale();
334
+ let locale = null;
335
+ if (isLocalizedContentType) {
336
+ locale = params.query.locale || defaultLocale;
337
+ }
316
338
  const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
317
339
  query.findPage({
318
340
  ...params.query,
@@ -328,78 +350,76 @@ const createHistoryService = ({ strapi: strapi2 }) => {
328
350
  }),
329
351
  serviceUtils.getLocaleDictionary()
330
352
  ]);
331
- const populateEntryRelations = async (entry) => {
332
- const entryWithRelations = await Object.entries(entry.schema).reduce(
333
- async (currentDataWithRelations, [attributeKey, attributeSchema]) => {
334
- const attributeValue = entry.data[attributeKey];
335
- const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
336
- if (attributeSchema.type === "media") {
337
- const permissionChecker2 = getService$1("permission-checker").create({
338
- userAbility: params.state.userAbility,
339
- model: "plugin::upload.file"
340
- });
341
- const response = await serviceUtils.buildMediaResponse(attributeValues);
342
- const sanitizedResults = await Promise.all(
343
- response.results.map((media) => permissionChecker2.sanitizeOutput(media))
344
- );
345
- return {
346
- ...await currentDataWithRelations,
347
- [attributeKey]: {
348
- results: sanitizedResults,
349
- meta: response.meta
350
- }
351
- };
353
+ const populateEntry = async (entry) => {
354
+ return traverseEntity(
355
+ async (options, utils) => {
356
+ if (!options.attribute) return;
357
+ if (!options.value) return;
358
+ const currentValue = Array.isArray(options.value) ? options.value : [options.value];
359
+ if (options.attribute.type === "component") {
360
+ utils.remove("id");
352
361
  }
353
- if (attributeSchema.type === "relation" && attributeSchema.relation !== "morphToOne" && attributeSchema.relation !== "morphToMany") {
354
- if (attributeSchema.target === "admin::user") {
362
+ if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
363
+ options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
364
+ if (options.attribute.target === "admin::user") {
355
365
  const adminUsers = await Promise.all(
356
- attributeValues.map((userToPopulate) => {
366
+ currentValue.map((userToPopulate) => {
357
367
  if (userToPopulate == null) {
358
368
  return null;
359
369
  }
360
- return strapi2.query("admin::user").findOne({ where: { id: userToPopulate.id } });
370
+ return strapi2.query("admin::user").findOne({
371
+ where: {
372
+ ...userToPopulate.id ? { id: userToPopulate.id } : {},
373
+ ...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
374
+ }
375
+ });
361
376
  })
362
377
  );
363
- return {
364
- ...await currentDataWithRelations,
365
- /**
366
- * Ideally we would return the same "{results: [], meta: {}}" shape, however,
367
- * when sanitizing the data as a whole in the controller before sending to the client,
368
- * the data for admin relation user is completely sanitized if we return an object here as opposed to an array.
369
- */
370
- [attributeKey]: adminUsers
371
- };
378
+ utils.set(options.key, adminUsers);
372
379
  }
373
- const permissionChecker2 = getService$1("permission-checker").create({
380
+ const permissionChecker2 = getService$2("permission-checker").create({
374
381
  userAbility: params.state.userAbility,
375
- model: attributeSchema.target
382
+ model: options.attribute.target
376
383
  });
377
384
  const response = await serviceUtils.buildRelationReponse(
378
- attributeValues,
379
- attributeSchema
385
+ currentValue,
386
+ options.attribute
380
387
  );
381
388
  const sanitizedResults = await Promise.all(
382
389
  response.results.map((media) => permissionChecker2.sanitizeOutput(media))
383
390
  );
384
- return {
385
- ...await currentDataWithRelations,
386
- [attributeKey]: {
387
- results: sanitizedResults,
388
- meta: response.meta
389
- }
390
- };
391
+ utils.set(options.key, {
392
+ results: sanitizedResults,
393
+ meta: response.meta
394
+ });
391
395
  }
392
- return currentDataWithRelations;
396
+ if (options.attribute.type === "media") {
397
+ const permissionChecker2 = getService$2("permission-checker").create({
398
+ userAbility: params.state.userAbility,
399
+ model: "plugin::upload.file"
400
+ });
401
+ const response = await serviceUtils.buildMediaResponse(currentValue);
402
+ const sanitizedResults = await Promise.all(
403
+ response.results.map((media) => permissionChecker2.sanitizeOutput(media))
404
+ );
405
+ utils.set(options.key, {
406
+ results: sanitizedResults,
407
+ meta: response.meta
408
+ });
409
+ }
410
+ },
411
+ {
412
+ schema,
413
+ getModel: strapi2.getModel.bind(strapi2)
393
414
  },
394
- Promise.resolve(entry.data)
415
+ entry.data
395
416
  );
396
- return entryWithRelations;
397
417
  };
398
418
  const formattedResults = await Promise.all(
399
419
  results.map(async (result) => {
400
420
  return {
401
421
  ...result,
402
- data: await populateEntryRelations(result),
422
+ data: await populateEntry(result),
403
423
  meta: {
404
424
  unknownAttributes: serviceUtils.getSchemaAttributesDiff(
405
425
  result.schema,
@@ -430,30 +450,44 @@ const createHistoryService = ({ strapi: strapi2 }) => {
430
450
  // Clone to avoid mutating the original version data
431
451
  structuredClone(version.data)
432
452
  );
433
- const sanitizedSchemaAttributes = omit(
434
- FIELDS_TO_IGNORE,
435
- contentTypeSchemaAttributes
436
- );
437
- const reducer = async.reduce(Object.entries(sanitizedSchemaAttributes));
438
- const dataWithoutMissingRelations = await reducer(
439
- async (previousRelationAttributes, [name, attribute]) => {
440
- const versionRelationData = version.data[name];
441
- if (!versionRelationData) {
442
- return previousRelationAttributes;
453
+ const schema = structuredClone(version.schema);
454
+ schema.attributes = omit(FIELDS_TO_IGNORE, contentTypeSchemaAttributes);
455
+ const dataWithoutMissingRelations = await traverseEntity(
456
+ async (options, utils) => {
457
+ if (!options.attribute) return;
458
+ if (options.attribute.type === "component") {
459
+ utils.remove("id");
460
+ if (options.attribute.repeatable && options.value === null) {
461
+ utils.set(options.key, []);
462
+ }
463
+ }
464
+ if (options.attribute.type === "dynamiczone") {
465
+ if (options.value === null) {
466
+ utils.set(options.key, []);
467
+ }
443
468
  }
444
- if (attribute.type === "relation" && // TODO: handle polymorphic relations
445
- attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
446
- const data2 = await serviceUtils.getRelationRestoreValue(versionRelationData, attribute);
447
- previousRelationAttributes[name] = data2;
469
+ if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
470
+ options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
471
+ if (!options.value) return;
472
+ const data2 = await serviceUtils.getRelationRestoreValue(
473
+ options.value,
474
+ options.attribute
475
+ );
476
+ utils.set(options.key, data2);
448
477
  }
449
- if (attribute.type === "media") {
450
- const data2 = await serviceUtils.getMediaRestoreValue(versionRelationData, attribute);
451
- previousRelationAttributes[name] = data2;
478
+ if (options.attribute.type === "media") {
479
+ if (!options.value) return;
480
+ const data2 = await serviceUtils.getMediaRestoreValue(
481
+ options.value
482
+ );
483
+ utils.set(options.key, data2);
452
484
  }
453
- return previousRelationAttributes;
454
485
  },
455
- // Clone to avoid mutating the original version data
456
- structuredClone(dataWithoutAddedAttributes)
486
+ {
487
+ schema,
488
+ getModel: strapi2.getModel.bind(strapi2)
489
+ },
490
+ dataWithoutAddedAttributes
457
491
  );
458
492
  const data = omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
459
493
  const restoredDocument = await strapi2.documents(version.contentType).update({
@@ -468,6 +502,42 @@ const createHistoryService = ({ strapi: strapi2 }) => {
468
502
  }
469
503
  };
470
504
  };
505
+ const shouldCreateHistoryVersion = (context) => {
506
+ if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
507
+ return false;
508
+ }
509
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
510
+ return false;
511
+ }
512
+ if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
513
+ return false;
514
+ }
515
+ if (!context.contentType.uid.startsWith("api::")) {
516
+ return false;
517
+ }
518
+ return true;
519
+ };
520
+ const getSchemas = (uid2) => {
521
+ const attributesSchema = strapi.getModel(uid2).attributes;
522
+ const componentsSchemas = Object.keys(attributesSchema).reduce(
523
+ (currentComponentSchemas, key) => {
524
+ const fieldSchema = attributesSchema[key];
525
+ if (fieldSchema.type === "component") {
526
+ const componentSchema = strapi.getModel(fieldSchema.component).attributes;
527
+ return {
528
+ ...currentComponentSchemas,
529
+ [fieldSchema.component]: componentSchema
530
+ };
531
+ }
532
+ return currentComponentSchemas;
533
+ },
534
+ {}
535
+ );
536
+ return {
537
+ schema: omit(FIELDS_TO_IGNORE, attributesSchema),
538
+ componentsSchemas
539
+ };
540
+ };
471
541
  const createLifecyclesService = ({ strapi: strapi2 }) => {
472
542
  const state = {
473
543
  deleteExpiredJob: null,
@@ -480,76 +550,62 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
480
550
  return;
481
551
  }
482
552
  strapi2.documents.use(async (context, next) => {
483
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
484
- return next();
485
- }
486
- if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
487
- return next();
488
- }
489
- if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
490
- return next();
491
- }
492
- const contentTypeUid = context.contentType.uid;
493
- if (!contentTypeUid.startsWith("api::")) {
494
- return next();
495
- }
496
553
  const result = await next();
497
- const documentContext = {
498
- documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
499
- locale: context.params?.locale
500
- };
554
+ if (!shouldCreateHistoryVersion(context)) {
555
+ return result;
556
+ }
557
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
501
558
  const defaultLocale = await serviceUtils.getDefaultLocale();
502
- const locale = documentContext.locale || defaultLocale;
503
- if (Array.isArray(locale)) {
504
- strapi2.log.warn(
505
- "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
506
- );
507
- return next();
559
+ const locales = castArray(context.params?.locale || defaultLocale);
560
+ if (!locales.length) {
561
+ return result;
508
562
  }
509
- const document = await strapi2.documents(contentTypeUid).findOne({
510
- documentId: documentContext.documentId,
511
- locale,
512
- populate: serviceUtils.getDeepPopulate(contentTypeUid)
563
+ const uid2 = context.contentType.uid;
564
+ const schemas = getSchemas(uid2);
565
+ const model = strapi2.getModel(uid2);
566
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
567
+ const localeEntries = await strapi2.db.query(uid2).findMany({
568
+ where: {
569
+ documentId,
570
+ ...isLocalizedContentType ? { locale: { $in: locales } } : {},
571
+ ...contentTypes$1.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
572
+ },
573
+ populate: serviceUtils.getDeepPopulate(
574
+ uid2,
575
+ true
576
+ /* use database syntax */
577
+ )
513
578
  });
514
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
515
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
516
- const componentsSchemas = Object.keys(
517
- attributesSchema
518
- ).reduce((currentComponentSchemas, key) => {
519
- const fieldSchema = attributesSchema[key];
520
- if (fieldSchema.type === "component") {
521
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
522
- return {
523
- ...currentComponentSchemas,
524
- [fieldSchema.component]: componentSchema
525
- };
526
- }
527
- return currentComponentSchemas;
528
- }, {});
529
579
  await strapi2.db.transaction(async ({ onCommit }) => {
530
- onCommit(() => {
531
- getService(strapi2, "history").createVersion({
532
- contentType: contentTypeUid,
533
- data: omit(FIELDS_TO_IGNORE, document),
534
- schema: omit(FIELDS_TO_IGNORE, attributesSchema),
535
- componentsSchemas,
536
- relatedDocumentId: documentContext.documentId,
537
- locale,
538
- status
539
- });
580
+ onCommit(async () => {
581
+ for (const entry of localeEntries) {
582
+ const status = await serviceUtils.getVersionStatus(uid2, entry);
583
+ await getService$1(strapi2, "history").createVersion({
584
+ contentType: uid2,
585
+ data: omit(FIELDS_TO_IGNORE, entry),
586
+ relatedDocumentId: documentId,
587
+ locale: entry.locale,
588
+ status,
589
+ ...schemas
590
+ });
591
+ }
540
592
  });
541
593
  });
542
594
  return result;
543
595
  });
544
- state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
596
+ state.deleteExpiredJob = scheduleJob("historyDaily", "0 0 * * *", () => {
545
597
  const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
546
598
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
547
599
  strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
548
600
  where: {
549
601
  created_at: {
550
- $lt: expirationDate.toISOString()
602
+ $lt: expirationDate
551
603
  }
552
604
  }
605
+ }).catch((error) => {
606
+ if (error instanceof Error) {
607
+ strapi2.log.error("Error deleting expired history versions", error.message);
608
+ }
553
609
  });
554
610
  });
555
611
  state.isInitialized = true;
@@ -561,17 +617,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
561
617
  }
562
618
  };
563
619
  };
564
- const services$1 = {
620
+ const services$2 = {
565
621
  history: createHistoryService,
566
622
  lifecycles: createLifecyclesService
567
623
  };
568
- const info = { pluginName: "content-manager", type: "admin" };
624
+ const info$1 = { pluginName: "content-manager", type: "admin" };
569
625
  const historyVersionRouter = {
570
626
  type: "admin",
571
627
  routes: [
572
628
  {
573
629
  method: "GET",
574
- info,
630
+ info: info$1,
575
631
  path: "/history-versions",
576
632
  handler: "history-version.findMany",
577
633
  config: {
@@ -580,7 +636,7 @@ const historyVersionRouter = {
580
636
  },
581
637
  {
582
638
  method: "PUT",
583
- info,
639
+ info: info$1,
584
640
  path: "/history-versions/:versionId/restore",
585
641
  handler: "history-version.restoreVersion",
586
642
  config: {
@@ -589,7 +645,7 @@ const historyVersionRouter = {
589
645
  }
590
646
  ]
591
647
  };
592
- const routes$1 = {
648
+ const routes$2 = {
593
649
  "history-version": historyVersionRouter
594
650
  };
595
651
  const historyVersion = {
@@ -636,21 +692,21 @@ const historyVersion = {
636
692
  }
637
693
  }
638
694
  };
639
- const getFeature = () => {
695
+ const getFeature$1 = () => {
640
696
  if (strapi.ee.features.isEnabled("cms-content-history")) {
641
697
  return {
642
698
  register({ strapi: strapi2 }) {
643
699
  strapi2.get("models").add(historyVersion);
644
700
  },
645
701
  bootstrap({ strapi: strapi2 }) {
646
- getService(strapi2, "lifecycles").bootstrap();
702
+ getService$1(strapi2, "lifecycles").bootstrap();
647
703
  },
648
704
  destroy({ strapi: strapi2 }) {
649
- getService(strapi2, "lifecycles").destroy();
705
+ getService$1(strapi2, "lifecycles").destroy();
650
706
  },
651
- controllers: controllers$1,
652
- services: services$1,
653
- routes: routes$1
707
+ controllers: controllers$2,
708
+ services: services$2,
709
+ routes: routes$2
654
710
  };
655
711
  }
656
712
  return {
@@ -659,9 +715,201 @@ const getFeature = () => {
659
715
  }
660
716
  };
661
717
  };
662
- const history = getFeature();
718
+ const history = getFeature$1();
719
+ const info = { pluginName: "content-manager", type: "admin" };
720
+ const previewRouter = {
721
+ type: "admin",
722
+ routes: [
723
+ {
724
+ method: "GET",
725
+ info,
726
+ path: "/preview/url/:contentType",
727
+ handler: "preview.getPreviewUrl",
728
+ config: {
729
+ policies: ["admin::isAuthenticatedAdmin"]
730
+ }
731
+ }
732
+ ]
733
+ };
734
+ const routes$1 = {
735
+ preview: previewRouter
736
+ };
737
+ function getService(strapi2, name) {
738
+ return strapi2.service(`plugin::content-manager.${name}`);
739
+ }
740
+ const getPreviewUrlSchema = yup.object().shape({
741
+ // Will be undefined for single types
742
+ documentId: yup.string(),
743
+ locale: yup.string().nullable(),
744
+ status: yup.string()
745
+ }).required();
746
+ const validatePreviewUrl = async (strapi2, uid2, params) => {
747
+ await validateYupSchema(getPreviewUrlSchema)(params);
748
+ const newParams = pick(["documentId", "locale", "status"], params);
749
+ const model = strapi2.getModel(uid2);
750
+ if (!model || model.modelType !== "contentType") {
751
+ throw new errors.ValidationError("Invalid content type");
752
+ }
753
+ const isSingleType = model?.kind === "singleType";
754
+ if (!isSingleType && !params.documentId) {
755
+ throw new errors.ValidationError("documentId is required for Collection Types");
756
+ }
757
+ if (isSingleType) {
758
+ const doc = await strapi2.documents(uid2).findFirst();
759
+ if (!doc) {
760
+ throw new errors.NotFoundError("Document not found");
761
+ }
762
+ newParams.documentId = doc?.documentId;
763
+ }
764
+ if (!newParams.status) {
765
+ const isDPEnabled = model?.options?.draftAndPublish;
766
+ newParams.status = isDPEnabled ? "draft" : "published";
767
+ }
768
+ return newParams;
769
+ };
770
+ const createPreviewController = () => {
771
+ return {
772
+ /**
773
+ * Transforms an entry into a preview URL, so that it can be previewed
774
+ * in the Content Manager.
775
+ */
776
+ async getPreviewUrl(ctx) {
777
+ const uid2 = ctx.params.contentType;
778
+ const query = ctx.request.query;
779
+ const params = await validatePreviewUrl(strapi, uid2, query);
780
+ const previewService = getService(strapi, "preview");
781
+ const url = await previewService.getPreviewUrl(uid2, params);
782
+ if (!url) {
783
+ ctx.status = 204;
784
+ }
785
+ return {
786
+ data: { url }
787
+ };
788
+ }
789
+ };
790
+ };
791
+ const controllers$1 = {
792
+ preview: createPreviewController
793
+ /**
794
+ * Casting is needed because the types aren't aware that Strapi supports
795
+ * passing a controller factory as the value, instead of a controller object directly
796
+ */
797
+ };
798
+ const createPreviewService = ({ strapi: strapi2 }) => {
799
+ const config = getService(strapi2, "preview-config");
800
+ return {
801
+ async getPreviewUrl(uid2, params) {
802
+ const handler = config.getPreviewHandler();
803
+ try {
804
+ return handler(uid2, params);
805
+ } catch (error) {
806
+ strapi2.log.error(`Failed to get preview URL: ${error}`);
807
+ throw new errors.ApplicationError("Failed to get preview URL");
808
+ }
809
+ return;
810
+ }
811
+ };
812
+ };
813
+ const extendMiddlewareConfiguration = (middleware = { name: "", config: {} }) => {
814
+ const middlewares = strapi.config.get("middlewares");
815
+ const configuredMiddlewares = middlewares.map((currentMiddleware) => {
816
+ if (currentMiddleware === middleware.name) {
817
+ return middleware;
818
+ }
819
+ if (currentMiddleware.name === middleware.name) {
820
+ return mergeWith(
821
+ (objValue, srcValue) => {
822
+ if (Array.isArray(objValue)) {
823
+ return objValue.concat(srcValue);
824
+ }
825
+ return void 0;
826
+ },
827
+ currentMiddleware,
828
+ middleware
829
+ );
830
+ }
831
+ return currentMiddleware;
832
+ });
833
+ strapi.config.set("middlewares", configuredMiddlewares);
834
+ };
835
+ const createPreviewConfigService = ({ strapi: strapi2 }) => {
836
+ return {
837
+ register() {
838
+ if (!this.isEnabled()) {
839
+ return;
840
+ }
841
+ const config = strapi2.config.get("admin.preview");
842
+ if (config.config?.allowedOrigins) {
843
+ extendMiddlewareConfiguration({
844
+ name: "strapi::security",
845
+ config: {
846
+ contentSecurityPolicy: {
847
+ directives: {
848
+ "frame-src": config.config.allowedOrigins
849
+ }
850
+ }
851
+ }
852
+ });
853
+ }
854
+ },
855
+ isEnabled() {
856
+ const config = strapi2.config.get("admin.preview");
857
+ if (!config) {
858
+ return false;
859
+ }
860
+ return config?.enabled ?? true;
861
+ },
862
+ /**
863
+ * Validate if the configuration is valid
864
+ */
865
+ validate() {
866
+ if (!this.isEnabled()) {
867
+ return;
868
+ }
869
+ const handler = this.getPreviewHandler();
870
+ if (typeof handler !== "function") {
871
+ throw new errors.ValidationError(
872
+ "Preview configuration is invalid. Handler must be a function"
873
+ );
874
+ }
875
+ },
876
+ /**
877
+ * Utility to get the preview handler from the configuration
878
+ */
879
+ getPreviewHandler() {
880
+ const config = strapi2.config.get("admin.preview");
881
+ const emptyHandler = () => {
882
+ return void 0;
883
+ };
884
+ if (!this.isEnabled()) {
885
+ return emptyHandler;
886
+ }
887
+ return config?.config?.handler || emptyHandler;
888
+ }
889
+ };
890
+ };
891
+ const services$1 = {
892
+ preview: createPreviewService,
893
+ "preview-config": createPreviewConfigService
894
+ };
895
+ const getFeature = () => {
896
+ return {
897
+ register() {
898
+ const config = getService(strapi, "preview-config");
899
+ config.validate();
900
+ config.register();
901
+ },
902
+ bootstrap() {
903
+ },
904
+ routes: routes$1,
905
+ controllers: controllers$1,
906
+ services: services$1
907
+ };
908
+ };
909
+ const preview = getFeature();
663
910
  const register = async ({ strapi: strapi2 }) => {
664
911
  await history.register?.({ strapi: strapi2 });
912
+ await preview.register?.({ strapi: strapi2 });
665
913
  };
666
914
  const ALLOWED_WEBHOOK_EVENTS = {
667
915
  ENTRY_PUBLISH: "entry.publish",
@@ -671,11 +919,12 @@ const bootstrap = async () => {
671
919
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
672
920
  strapi.get("webhookStore").addAllowedEvent(key, value);
673
921
  });
674
- getService$1("field-sizes").setCustomFieldInputSizes();
675
- await getService$1("components").syncConfigurations();
676
- await getService$1("content-types").syncConfigurations();
677
- await getService$1("permission").registerPermissions();
922
+ getService$2("field-sizes").setCustomFieldInputSizes();
923
+ await getService$2("components").syncConfigurations();
924
+ await getService$2("content-types").syncConfigurations();
925
+ await getService$2("permission").registerPermissions();
678
926
  await history.bootstrap?.({ strapi });
927
+ await preview.bootstrap?.({ strapi });
679
928
  };
680
929
  const destroy = async ({ strapi: strapi2 }) => {
681
930
  await history.destroy?.({ strapi: strapi2 });
@@ -1165,7 +1414,8 @@ const admin = {
1165
1414
  };
1166
1415
  const routes = {
1167
1416
  admin,
1168
- ...history.routes ? history.routes : {}
1417
+ ...history.routes ? history.routes : {},
1418
+ ...preview.routes ? preview.routes : {}
1169
1419
  };
1170
1420
  const hasPermissionsSchema = yup$1.object({
1171
1421
  actions: yup$1.array().of(yup$1.string()),
@@ -1176,6 +1426,11 @@ const { createPolicy } = policy;
1176
1426
  const hasPermissions = createPolicy({
1177
1427
  name: "plugin::content-manager.hasPermissions",
1178
1428
  validator: validateHasPermissionsInput,
1429
+ /**
1430
+ * NOTE: Action aliases are currently not checked at this level (policy).
1431
+ * This is currently the intended behavior to avoid changing the behavior of API related permissions.
1432
+ * If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
1433
+ */
1179
1434
  handler(ctx, config = {}) {
1180
1435
  const { actions = [], hasAtLeastOne = false } = config;
1181
1436
  const { userAbility } = ctx.state;
@@ -1223,8 +1478,7 @@ const isSortable = (schema, name) => {
1223
1478
  if (!_.has(schema.attributes, name)) {
1224
1479
  return false;
1225
1480
  }
1226
- if (schema.modelType === "component" && name === "id")
1227
- return false;
1481
+ if (schema.modelType === "component" && name === "id") return false;
1228
1482
  const attribute = schema.attributes[name];
1229
1483
  if (NON_SORTABLES.includes(attribute.type)) {
1230
1484
  return false;
@@ -1369,8 +1623,7 @@ const createDefaultSettings = async (schema) => {
1369
1623
  };
1370
1624
  };
1371
1625
  const syncSettings = async (configuration, schema) => {
1372
- if (isEmpty(configuration.settings))
1373
- return createDefaultSettings(schema);
1626
+ if (isEmpty(configuration.settings)) return createDefaultSettings(schema);
1374
1627
  const defaultField = getDefaultMainField(schema);
1375
1628
  const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
1376
1629
  return {
@@ -1417,7 +1670,7 @@ const createMetadasSchema = (schema) => {
1417
1670
  if (!value) {
1418
1671
  return yup$1.string();
1419
1672
  }
1420
- const targetSchema = getService$1("content-types").findContentType(
1673
+ const targetSchema = getService$2("content-types").findContentType(
1421
1674
  schema.attributes[key].targetModel
1422
1675
  );
1423
1676
  if (!targetSchema) {
@@ -1546,8 +1799,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1546
1799
  }
1547
1800
  switch (attribute.type) {
1548
1801
  case "relation": {
1549
- if (canCreate(attributePath))
1550
- return body2;
1802
+ if (canCreate(attributePath)) return body2;
1551
1803
  return set(attributePath, { set: [] }, body2);
1552
1804
  }
1553
1805
  case "component": {
@@ -1557,8 +1809,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1557
1809
  ]);
1558
1810
  }
1559
1811
  default: {
1560
- if (canCreate(attributePath))
1561
- return body2;
1812
+ if (canCreate(attributePath)) return body2;
1562
1813
  return set(attributePath, null, body2);
1563
1814
  }
1564
1815
  }
@@ -1586,7 +1837,7 @@ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultiple
1586
1837
  }
1587
1838
  };
1588
1839
  const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1589
- const documentMetadata2 = getService$1("document-metadata");
1840
+ const documentMetadata2 = getService$2("document-metadata");
1590
1841
  const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1591
1842
  let {
1592
1843
  meta: { availableLocales, availableStatus }
@@ -1612,8 +1863,8 @@ const createDocument = async (ctx, opts) => {
1612
1863
  const { userAbility, user } = ctx.state;
1613
1864
  const { model } = ctx.params;
1614
1865
  const { body } = ctx.request;
1615
- const documentManager2 = getService$1("document-manager");
1616
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1866
+ const documentManager2 = getService$2("document-manager");
1867
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1617
1868
  if (permissionChecker2.cannot.create()) {
1618
1869
  throw new errors.ForbiddenError();
1619
1870
  }
@@ -1633,13 +1884,13 @@ const updateDocument = async (ctx, opts) => {
1633
1884
  const { userAbility, user } = ctx.state;
1634
1885
  const { id, model } = ctx.params;
1635
1886
  const { body } = ctx.request;
1636
- const documentManager2 = getService$1("document-manager");
1637
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1887
+ const documentManager2 = getService$2("document-manager");
1888
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1638
1889
  if (permissionChecker2.cannot.update()) {
1639
1890
  throw new errors.ForbiddenError();
1640
1891
  }
1641
1892
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1642
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1893
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1643
1894
  const { locale } = await getDocumentLocaleAndStatus(body, model);
1644
1895
  const [documentVersion, documentExists] = await Promise.all([
1645
1896
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
@@ -1656,7 +1907,7 @@ const updateDocument = async (ctx, opts) => {
1656
1907
  throw new errors.ForbiddenError();
1657
1908
  }
1658
1909
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1659
- const setCreator = setCreatorFields({ user, isEdition: true });
1910
+ const setCreator = documentVersion ? setCreatorFields({ user, isEdition: true }) : setCreatorFields({ user });
1660
1911
  const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
1661
1912
  const sanitizedBody = await sanitizeFn(body);
1662
1913
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1670,14 +1921,14 @@ const collectionTypes = {
1670
1921
  const { userAbility } = ctx.state;
1671
1922
  const { model } = ctx.params;
1672
1923
  const { query } = ctx.request;
1673
- const documentMetadata2 = getService$1("document-metadata");
1674
- const documentManager2 = getService$1("document-manager");
1675
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1924
+ const documentMetadata2 = getService$2("document-metadata");
1925
+ const documentManager2 = getService$2("document-manager");
1926
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1676
1927
  if (permissionChecker2.cannot.read()) {
1677
1928
  return ctx.forbidden();
1678
1929
  }
1679
1930
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1680
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1931
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1681
1932
  const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1682
1933
  const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
1683
1934
  { ...permissionQuery, populate, locale, status },
@@ -1706,13 +1957,13 @@ const collectionTypes = {
1706
1957
  async findOne(ctx) {
1707
1958
  const { userAbility } = ctx.state;
1708
1959
  const { model, id } = ctx.params;
1709
- const documentManager2 = getService$1("document-manager");
1710
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1960
+ const documentManager2 = getService$2("document-manager");
1961
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1711
1962
  if (permissionChecker2.cannot.read()) {
1712
1963
  return ctx.forbidden();
1713
1964
  }
1714
1965
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1715
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1966
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1716
1967
  const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1717
1968
  const version = await documentManager2.findOne(id, model, {
1718
1969
  populate,
@@ -1728,7 +1979,7 @@ const collectionTypes = {
1728
1979
  permissionChecker2,
1729
1980
  model,
1730
1981
  // @ts-expect-error TODO: fix
1731
- { id, locale, publishedAt: null },
1982
+ { documentId: id, locale, publishedAt: null },
1732
1983
  { availableLocales: true, availableStatus: false }
1733
1984
  );
1734
1985
  ctx.body = { data: {}, meta };
@@ -1743,7 +1994,7 @@ const collectionTypes = {
1743
1994
  async create(ctx) {
1744
1995
  const { userAbility } = ctx.state;
1745
1996
  const { model } = ctx.params;
1746
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1997
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1747
1998
  const [totalEntries, document] = await Promise.all([
1748
1999
  strapi.db.query(model).count(),
1749
2000
  createDocument(ctx)
@@ -1764,7 +2015,7 @@ const collectionTypes = {
1764
2015
  async update(ctx) {
1765
2016
  const { userAbility } = ctx.state;
1766
2017
  const { model } = ctx.params;
1767
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2018
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1768
2019
  const updatedVersion = await updateDocument(ctx);
1769
2020
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1770
2021
  ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
@@ -1773,13 +2024,13 @@ const collectionTypes = {
1773
2024
  const { userAbility, user } = ctx.state;
1774
2025
  const { model, sourceId: id } = ctx.params;
1775
2026
  const { body } = ctx.request;
1776
- const documentManager2 = getService$1("document-manager");
1777
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2027
+ const documentManager2 = getService$2("document-manager");
2028
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1778
2029
  if (permissionChecker2.cannot.create()) {
1779
2030
  return ctx.forbidden();
1780
2031
  }
1781
2032
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1782
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2033
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1783
2034
  const { locale } = await getDocumentLocaleAndStatus(body, model);
1784
2035
  const document = await documentManager2.findOne(id, model, {
1785
2036
  populate,
@@ -1818,13 +2069,13 @@ const collectionTypes = {
1818
2069
  async delete(ctx) {
1819
2070
  const { userAbility } = ctx.state;
1820
2071
  const { id, model } = ctx.params;
1821
- const documentManager2 = getService$1("document-manager");
1822
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2072
+ const documentManager2 = getService$2("document-manager");
2073
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1823
2074
  if (permissionChecker2.cannot.delete()) {
1824
2075
  return ctx.forbidden();
1825
2076
  }
1826
2077
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1827
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2078
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1828
2079
  const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1829
2080
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1830
2081
  if (documentLocales.length === 0) {
@@ -1846,19 +2097,42 @@ const collectionTypes = {
1846
2097
  const { userAbility } = ctx.state;
1847
2098
  const { id, model } = ctx.params;
1848
2099
  const { body } = ctx.request;
1849
- const documentManager2 = getService$1("document-manager");
1850
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2100
+ const documentManager2 = getService$2("document-manager");
2101
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1851
2102
  if (permissionChecker2.cannot.publish()) {
1852
2103
  return ctx.forbidden();
1853
2104
  }
1854
2105
  const publishedDocument = await strapi.db.transaction(async () => {
1855
2106
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1856
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1857
- const document = id ? await updateDocument(ctx, { populate }) : await createDocument(ctx, { populate });
2107
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2108
+ let document;
2109
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2110
+ const isCreate = isNil$1(id);
2111
+ if (isCreate) {
2112
+ if (permissionChecker2.cannot.create()) {
2113
+ throw new errors.ForbiddenError();
2114
+ }
2115
+ document = await createDocument(ctx, { populate });
2116
+ }
2117
+ const isUpdate = !isCreate;
2118
+ if (isUpdate) {
2119
+ const documentExists = documentManager2.exists(model, id);
2120
+ if (!documentExists) {
2121
+ throw new errors.NotFoundError("Document not found");
2122
+ }
2123
+ document = await documentManager2.findOne(id, model, { populate, locale });
2124
+ if (!document) {
2125
+ if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
2126
+ throw new errors.ForbiddenError();
2127
+ }
2128
+ document = await updateDocument(ctx);
2129
+ } else if (permissionChecker2.can.update(document)) {
2130
+ await updateDocument(ctx);
2131
+ }
2132
+ }
1858
2133
  if (permissionChecker2.cannot.publish(document)) {
1859
2134
  throw new errors.ForbiddenError();
1860
2135
  }
1861
- const { locale } = await getDocumentLocaleAndStatus(body, model);
1862
2136
  const publishResult = await documentManager2.publish(document.documentId, model, {
1863
2137
  locale
1864
2138
  // TODO: Allow setting creator fields on publish
@@ -1878,13 +2152,13 @@ const collectionTypes = {
1878
2152
  const { body } = ctx.request;
1879
2153
  const { documentIds } = body;
1880
2154
  await validateBulkActionInput(body);
1881
- const documentManager2 = getService$1("document-manager");
1882
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2155
+ const documentManager2 = getService$2("document-manager");
2156
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1883
2157
  if (permissionChecker2.cannot.publish()) {
1884
2158
  return ctx.forbidden();
1885
2159
  }
1886
2160
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1887
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2161
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1888
2162
  const { locale } = await getDocumentLocaleAndStatus(body, model, {
1889
2163
  allowMultipleLocales: true
1890
2164
  });
@@ -1909,12 +2183,14 @@ const collectionTypes = {
1909
2183
  const { body } = ctx.request;
1910
2184
  const { documentIds } = body;
1911
2185
  await validateBulkActionInput(body);
1912
- const documentManager2 = getService$1("document-manager");
1913
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2186
+ const documentManager2 = getService$2("document-manager");
2187
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1914
2188
  if (permissionChecker2.cannot.unpublish()) {
1915
2189
  return ctx.forbidden();
1916
2190
  }
1917
- const { locale } = await getDocumentLocaleAndStatus(body, model);
2191
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2192
+ allowMultipleLocales: true
2193
+ });
1918
2194
  const entityPromises = documentIds.map(
1919
2195
  (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1920
2196
  );
@@ -1937,8 +2213,8 @@ const collectionTypes = {
1937
2213
  const {
1938
2214
  body: { discardDraft, ...body }
1939
2215
  } = ctx.request;
1940
- const documentManager2 = getService$1("document-manager");
1941
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2216
+ const documentManager2 = getService$2("document-manager");
2217
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1942
2218
  if (permissionChecker2.cannot.unpublish()) {
1943
2219
  return ctx.forbidden();
1944
2220
  }
@@ -1946,7 +2222,7 @@ const collectionTypes = {
1946
2222
  return ctx.forbidden();
1947
2223
  }
1948
2224
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1949
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2225
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1950
2226
  const { locale } = await getDocumentLocaleAndStatus(body, model);
1951
2227
  const document = await documentManager2.findOne(id, model, {
1952
2228
  populate,
@@ -1977,13 +2253,13 @@ const collectionTypes = {
1977
2253
  const { userAbility } = ctx.state;
1978
2254
  const { id, model } = ctx.params;
1979
2255
  const { body } = ctx.request;
1980
- const documentManager2 = getService$1("document-manager");
1981
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2256
+ const documentManager2 = getService$2("document-manager");
2257
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1982
2258
  if (permissionChecker2.cannot.discard()) {
1983
2259
  return ctx.forbidden();
1984
2260
  }
1985
2261
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
1986
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2262
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1987
2263
  const { locale } = await getDocumentLocaleAndStatus(body, model);
1988
2264
  const document = await documentManager2.findOne(id, model, {
1989
2265
  populate,
@@ -2008,13 +2284,13 @@ const collectionTypes = {
2008
2284
  const { query, body } = ctx.request;
2009
2285
  const { documentIds } = body;
2010
2286
  await validateBulkActionInput(body);
2011
- const documentManager2 = getService$1("document-manager");
2012
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2287
+ const documentManager2 = getService$2("document-manager");
2288
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2013
2289
  if (permissionChecker2.cannot.delete()) {
2014
2290
  return ctx.forbidden();
2015
2291
  }
2016
2292
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
2017
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2293
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2018
2294
  const { locale } = await getDocumentLocaleAndStatus(body, model);
2019
2295
  const documentLocales = await documentManager2.findLocales(documentIds, model, {
2020
2296
  populate,
@@ -2035,13 +2311,13 @@ const collectionTypes = {
2035
2311
  async countDraftRelations(ctx) {
2036
2312
  const { userAbility } = ctx.state;
2037
2313
  const { model, id } = ctx.params;
2038
- const documentManager2 = getService$1("document-manager");
2039
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2314
+ const documentManager2 = getService$2("document-manager");
2315
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2040
2316
  if (permissionChecker2.cannot.read()) {
2041
2317
  return ctx.forbidden();
2042
2318
  }
2043
2319
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2044
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2320
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2045
2321
  const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
2046
2322
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2047
2323
  if (!entity) {
@@ -2060,8 +2336,8 @@ const collectionTypes = {
2060
2336
  const ids = ctx.request.query.documentIds;
2061
2337
  const locale = ctx.request.query.locale;
2062
2338
  const { model } = ctx.params;
2063
- const documentManager2 = getService$1("document-manager");
2064
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2339
+ const documentManager2 = getService$2("document-manager");
2340
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2065
2341
  if (permissionChecker2.cannot.read()) {
2066
2342
  return ctx.forbidden();
2067
2343
  }
@@ -2085,13 +2361,13 @@ const collectionTypes = {
2085
2361
  };
2086
2362
  const components$1 = {
2087
2363
  findComponents(ctx) {
2088
- const components2 = getService$1("components").findAllComponents();
2089
- const { toDto } = getService$1("data-mapper");
2364
+ const components2 = getService$2("components").findAllComponents();
2365
+ const { toDto } = getService$2("data-mapper");
2090
2366
  ctx.body = { data: components2.map(toDto) };
2091
2367
  },
2092
2368
  async findComponentConfiguration(ctx) {
2093
2369
  const { uid: uid2 } = ctx.params;
2094
- const componentService = getService$1("components");
2370
+ const componentService = getService$2("components");
2095
2371
  const component = componentService.findComponent(uid2);
2096
2372
  if (!component) {
2097
2373
  return ctx.notFound("component.notFound");
@@ -2108,7 +2384,7 @@ const components$1 = {
2108
2384
  async updateComponentConfiguration(ctx) {
2109
2385
  const { uid: uid2 } = ctx.params;
2110
2386
  const { body } = ctx.request;
2111
- const componentService = getService$1("components");
2387
+ const componentService = getService$2("components");
2112
2388
  const component = componentService.findComponent(uid2);
2113
2389
  if (!component) {
2114
2390
  return ctx.notFound("component.notFound");
@@ -2142,12 +2418,12 @@ const contentTypes = {
2142
2418
  } catch (error) {
2143
2419
  return ctx.send({ error }, 400);
2144
2420
  }
2145
- const contentTypes2 = getService$1("content-types").findContentTypesByKind(kind);
2146
- const { toDto } = getService$1("data-mapper");
2421
+ const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
2422
+ const { toDto } = getService$2("data-mapper");
2147
2423
  ctx.body = { data: contentTypes2.map(toDto) };
2148
2424
  },
2149
2425
  async findContentTypesSettings(ctx) {
2150
- const { findAllContentTypes, findConfiguration } = getService$1("content-types");
2426
+ const { findAllContentTypes, findConfiguration } = getService$2("content-types");
2151
2427
  const contentTypes2 = await findAllContentTypes();
2152
2428
  const configurations = await Promise.all(
2153
2429
  contentTypes2.map(async (contentType) => {
@@ -2161,7 +2437,7 @@ const contentTypes = {
2161
2437
  },
2162
2438
  async findContentTypeConfiguration(ctx) {
2163
2439
  const { uid: uid2 } = ctx.params;
2164
- const contentTypeService = getService$1("content-types");
2440
+ const contentTypeService = getService$2("content-types");
2165
2441
  const contentType = await contentTypeService.findContentType(uid2);
2166
2442
  if (!contentType) {
2167
2443
  return ctx.notFound("contentType.notFound");
@@ -2183,13 +2459,13 @@ const contentTypes = {
2183
2459
  const { userAbility } = ctx.state;
2184
2460
  const { uid: uid2 } = ctx.params;
2185
2461
  const { body } = ctx.request;
2186
- const contentTypeService = getService$1("content-types");
2187
- const metricsService = getService$1("metrics");
2462
+ const contentTypeService = getService$2("content-types");
2463
+ const metricsService = getService$2("metrics");
2188
2464
  const contentType = await contentTypeService.findContentType(uid2);
2189
2465
  if (!contentType) {
2190
2466
  return ctx.notFound("contentType.notFound");
2191
2467
  }
2192
- if (!getService$1("permission").canConfigureContentType({ userAbility, contentType })) {
2468
+ if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
2193
2469
  return ctx.forbidden();
2194
2470
  }
2195
2471
  let input;
@@ -2222,10 +2498,10 @@ const contentTypes = {
2222
2498
  };
2223
2499
  const init = {
2224
2500
  getInitData(ctx) {
2225
- const { toDto } = getService$1("data-mapper");
2226
- const { findAllComponents } = getService$1("components");
2227
- const { getAllFieldSizes } = getService$1("field-sizes");
2228
- const { findAllContentTypes } = getService$1("content-types");
2501
+ const { toDto } = getService$2("data-mapper");
2502
+ const { findAllComponents } = getService$2("components");
2503
+ const { getAllFieldSizes } = getService$2("field-sizes");
2504
+ const { findAllContentTypes } = getService$2("content-types");
2229
2505
  ctx.body = {
2230
2506
  data: {
2231
2507
  fieldSizes: getAllFieldSizes(),
@@ -2261,36 +2537,41 @@ const addFiltersClause = (params, filtersClause) => {
2261
2537
  params.filters.$and.push(filtersClause);
2262
2538
  };
2263
2539
  const sanitizeMainField = (model, mainField, userAbility) => {
2264
- const permissionChecker2 = getService$1("permission-checker").create({
2540
+ const permissionChecker2 = getService$2("permission-checker").create({
2265
2541
  userAbility,
2266
2542
  model: model.uid
2267
2543
  });
2268
- if (!isListable(model, mainField)) {
2544
+ const isMainFieldListable = isListable(model, mainField);
2545
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2546
+ if (!isMainFieldListable || !canReadMainField) {
2269
2547
  return "id";
2270
2548
  }
2271
- if (permissionChecker2.cannot.read(null, mainField)) {
2272
- if (model.uid === "plugin::users-permissions.role") {
2273
- const userPermissionChecker = getService$1("permission-checker").create({
2274
- userAbility,
2275
- model: "plugin::users-permissions.user"
2276
- });
2277
- if (userPermissionChecker.can.read()) {
2278
- return "name";
2279
- }
2280
- }
2281
- return "id";
2549
+ if (model.uid === "plugin::users-permissions.role") {
2550
+ return "name";
2282
2551
  }
2283
2552
  return mainField;
2284
2553
  };
2285
- const addStatusToRelations = async (uid2, relations2) => {
2286
- if (!contentTypes$1.hasDraftAndPublish(strapi.contentTypes[uid2])) {
2554
+ const addStatusToRelations = async (targetUid, relations2) => {
2555
+ if (!contentTypes$1.hasDraftAndPublish(strapi.getModel(targetUid))) {
2287
2556
  return relations2;
2288
2557
  }
2289
- const documentMetadata2 = getService$1("document-metadata");
2290
- const documentsAvailableStatus = await documentMetadata2.getManyAvailableStatus(uid2, relations2);
2558
+ const documentMetadata2 = getService$2("document-metadata");
2559
+ if (!relations2.length) {
2560
+ return relations2;
2561
+ }
2562
+ const firstRelation = relations2[0];
2563
+ const filters = {
2564
+ documentId: { $in: relations2.map((r) => r.documentId) },
2565
+ // NOTE: find the "opposite" status
2566
+ publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
2567
+ };
2568
+ const availableStatus = await strapi.query(targetUid).findMany({
2569
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
2570
+ filters
2571
+ });
2291
2572
  return relations2.map((relation) => {
2292
- const availableStatuses = documentsAvailableStatus.filter(
2293
- (availableDocument) => availableDocument.documentId === relation.documentId
2573
+ const availableStatuses = availableStatus.filter(
2574
+ (availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
2294
2575
  );
2295
2576
  return {
2296
2577
  ...relation,
@@ -2311,11 +2592,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2311
2592
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2312
2593
  const isSourceLocalized = isLocalized(sourceModel);
2313
2594
  const isTargetLocalized = isLocalized(targetModel);
2314
- let validatedLocale = locale;
2315
- if (!targetModel || !isTargetLocalized)
2316
- validatedLocale = void 0;
2317
2595
  return {
2318
- locale: validatedLocale,
2596
+ locale,
2319
2597
  isSourceLocalized,
2320
2598
  isTargetLocalized
2321
2599
  };
@@ -2324,8 +2602,7 @@ const validateStatus = (sourceUid, status) => {
2324
2602
  const sourceModel = strapi.getModel(sourceUid);
2325
2603
  const isDP = contentTypes$1.hasDraftAndPublish;
2326
2604
  const isSourceDP = isDP(sourceModel);
2327
- if (!isSourceDP)
2328
- return { status: void 0 };
2605
+ if (!isSourceDP) return { status: void 0 };
2329
2606
  switch (status) {
2330
2607
  case "published":
2331
2608
  return { status: "published" };
@@ -2355,7 +2632,7 @@ const relations = {
2355
2632
  ctx.request?.query?.locale
2356
2633
  );
2357
2634
  const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
2358
- const permissionChecker2 = getService$1("permission-checker").create({
2635
+ const permissionChecker2 = getService$2("permission-checker").create({
2359
2636
  userAbility,
2360
2637
  model
2361
2638
  });
@@ -2380,7 +2657,7 @@ const relations = {
2380
2657
  where.id = id;
2381
2658
  }
2382
2659
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2383
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2660
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2384
2661
  const currentEntity = await strapi.db.query(model).findOne({
2385
2662
  where,
2386
2663
  populate
@@ -2395,7 +2672,7 @@ const relations = {
2395
2672
  }
2396
2673
  entryId = currentEntity.id;
2397
2674
  }
2398
- const modelConfig = isComponent2 ? await getService$1("components").findConfiguration(sourceSchema) : await getService$1("content-types").findConfiguration(sourceSchema);
2675
+ const modelConfig = isComponent2 ? await getService$2("components").findConfiguration(sourceSchema) : await getService$2("content-types").findConfiguration(sourceSchema);
2399
2676
  const targetSchema = strapi.getModel(targetUid);
2400
2677
  const mainField = flow(
2401
2678
  prop(`metadatas.${targetField}.edit.mainField`),
@@ -2418,7 +2695,7 @@ const relations = {
2418
2695
  attribute,
2419
2696
  fieldsToSelect,
2420
2697
  mainField,
2421
- source: { schema: sourceSchema },
2698
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2422
2699
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2423
2700
  sourceSchema,
2424
2701
  targetSchema,
@@ -2440,7 +2717,8 @@ const relations = {
2440
2717
  fieldsToSelect,
2441
2718
  mainField,
2442
2719
  source: {
2443
- schema: { uid: sourceUid, modelType: sourceModelType }
2720
+ schema: { uid: sourceUid, modelType: sourceModelType },
2721
+ isLocalized: isSourceLocalized
2444
2722
  },
2445
2723
  target: {
2446
2724
  schema: { uid: targetUid },
@@ -2448,7 +2726,7 @@ const relations = {
2448
2726
  }
2449
2727
  } = await this.extractAndValidateRequestInfo(ctx, id);
2450
2728
  const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
2451
- const permissionChecker2 = getService$1("permission-checker").create({
2729
+ const permissionChecker2 = getService$2("permission-checker").create({
2452
2730
  userAbility: ctx.state.userAbility,
2453
2731
  model: targetUid
2454
2732
  });
@@ -2478,12 +2756,16 @@ const relations = {
2478
2756
  } else {
2479
2757
  where.id = id;
2480
2758
  }
2481
- if (status) {
2482
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2759
+ const publishedAt = getPublishedAtClause(status, targetUid);
2760
+ if (!isEmpty(publishedAt)) {
2761
+ where[`${alias}.published_at`] = publishedAt;
2483
2762
  }
2484
- if (filterByLocale) {
2763
+ if (isTargetLocalized && locale) {
2485
2764
  where[`${alias}.locale`] = locale;
2486
2765
  }
2766
+ if (isSourceLocalized && locale) {
2767
+ where.locale = locale;
2768
+ }
2487
2769
  if ((idsToInclude?.length ?? 0) !== 0) {
2488
2770
  where[`${alias}.id`].$notIn = idsToInclude;
2489
2771
  }
@@ -2501,7 +2783,8 @@ const relations = {
2501
2783
  id: { $notIn: uniq(idsToOmit) }
2502
2784
  });
2503
2785
  }
2504
- const res = await strapi.db.query(targetUid).findPage(strapi.get("query-params").transform(targetUid, queryParams));
2786
+ const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
2787
+ const res = await strapi.db.query(targetUid).findPage(dbQuery);
2505
2788
  ctx.body = {
2506
2789
  ...res,
2507
2790
  results: await addStatusToRelations(targetUid, res.results)
@@ -2516,29 +2799,39 @@ const relations = {
2516
2799
  attribute,
2517
2800
  targetField,
2518
2801
  fieldsToSelect,
2519
- source: {
2520
- schema: { uid: sourceUid }
2521
- },
2522
- target: {
2523
- schema: { uid: targetUid }
2524
- }
2802
+ status,
2803
+ source: { schema: sourceSchema },
2804
+ target: { schema: targetSchema }
2525
2805
  } = await this.extractAndValidateRequestInfo(ctx, id);
2526
- const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2806
+ const { uid: sourceUid } = sourceSchema;
2807
+ const { uid: targetUid } = targetSchema;
2808
+ const permissionQuery = await getService$2("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2527
2809
  const dbQuery = strapi.db.query(sourceUid);
2528
2810
  const loadRelations = relations$1.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
2811
+ const filters = {};
2812
+ if (sourceSchema?.options?.draftAndPublish) {
2813
+ if (targetSchema?.options?.draftAndPublish) {
2814
+ if (status === "published") {
2815
+ filters.publishedAt = { $notNull: true };
2816
+ } else {
2817
+ filters.publishedAt = { $null: true };
2818
+ }
2819
+ }
2820
+ } else if (targetSchema?.options?.draftAndPublish) {
2821
+ filters.publishedAt = { $null: true };
2822
+ }
2529
2823
  const res = await loadRelations({ id: entryId }, targetField, {
2530
- select: ["id", "documentId", "locale", "publishedAt"],
2824
+ select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
2531
2825
  ordering: "desc",
2532
2826
  page: ctx.request.query.page,
2533
- pageSize: ctx.request.query.pageSize
2827
+ pageSize: ctx.request.query.pageSize,
2828
+ filters
2534
2829
  });
2535
2830
  const loadedIds = res.results.map((item) => item.id);
2536
2831
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2537
2832
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2538
2833
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2539
- ordering: "desc",
2540
- page: ctx.request.query.page,
2541
- pageSize: ctx.request.query.pageSize
2834
+ ordering: "desc"
2542
2835
  });
2543
2836
  const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
2544
2837
  ctx.body = {
@@ -2553,10 +2846,10 @@ const relations = {
2553
2846
  }
2554
2847
  };
2555
2848
  const buildPopulateFromQuery = async (query, model) => {
2556
- return getService$1("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2849
+ return getService$2("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2557
2850
  };
2558
2851
  const findDocument = async (query, uid2, opts = {}) => {
2559
- const documentManager2 = getService$1("document-manager");
2852
+ const documentManager2 = getService$2("document-manager");
2560
2853
  const populate = await buildPopulateFromQuery(query, uid2);
2561
2854
  return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
2562
2855
  };
@@ -2564,8 +2857,8 @@ const createOrUpdateDocument = async (ctx, opts) => {
2564
2857
  const { user, userAbility } = ctx.state;
2565
2858
  const { model } = ctx.params;
2566
2859
  const { body, query } = ctx.request;
2567
- const documentManager2 = getService$1("document-manager");
2568
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2860
+ const documentManager2 = getService$2("document-manager");
2861
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2569
2862
  if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
2570
2863
  throw new errors.ForbiddenError();
2571
2864
  }
@@ -2606,7 +2899,7 @@ const singleTypes = {
2606
2899
  const { userAbility } = ctx.state;
2607
2900
  const { model } = ctx.params;
2608
2901
  const { query = {} } = ctx.request;
2609
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2902
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2610
2903
  if (permissionChecker2.cannot.read()) {
2611
2904
  return ctx.forbidden();
2612
2905
  }
@@ -2625,7 +2918,7 @@ const singleTypes = {
2625
2918
  permissionChecker2,
2626
2919
  model,
2627
2920
  // @ts-expect-error - fix types
2628
- { id: document.documentId, locale, publishedAt: null },
2921
+ { documentId: document.documentId, locale, publishedAt: null },
2629
2922
  { availableLocales: true, availableStatus: false }
2630
2923
  );
2631
2924
  ctx.body = { data: {}, meta };
@@ -2640,7 +2933,7 @@ const singleTypes = {
2640
2933
  async createOrUpdate(ctx) {
2641
2934
  const { userAbility } = ctx.state;
2642
2935
  const { model } = ctx.params;
2643
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2936
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2644
2937
  const document = await createOrUpdateDocument(ctx);
2645
2938
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2646
2939
  ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
@@ -2649,8 +2942,8 @@ const singleTypes = {
2649
2942
  const { userAbility } = ctx.state;
2650
2943
  const { model } = ctx.params;
2651
2944
  const { query = {} } = ctx.request;
2652
- const documentManager2 = getService$1("document-manager");
2653
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2945
+ const documentManager2 = getService$2("document-manager");
2946
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2654
2947
  if (permissionChecker2.cannot.delete()) {
2655
2948
  return ctx.forbidden();
2656
2949
  }
@@ -2678,8 +2971,8 @@ const singleTypes = {
2678
2971
  const { userAbility } = ctx.state;
2679
2972
  const { model } = ctx.params;
2680
2973
  const { query = {} } = ctx.request;
2681
- const documentManager2 = getService$1("document-manager");
2682
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2974
+ const documentManager2 = getService$2("document-manager");
2975
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2683
2976
  if (permissionChecker2.cannot.publish()) {
2684
2977
  return ctx.forbidden();
2685
2978
  }
@@ -2707,8 +3000,8 @@ const singleTypes = {
2707
3000
  body: { discardDraft, ...body },
2708
3001
  query = {}
2709
3002
  } = ctx.request;
2710
- const documentManager2 = getService$1("document-manager");
2711
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3003
+ const documentManager2 = getService$2("document-manager");
3004
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2712
3005
  if (permissionChecker2.cannot.unpublish()) {
2713
3006
  return ctx.forbidden();
2714
3007
  }
@@ -2742,8 +3035,8 @@ const singleTypes = {
2742
3035
  const { userAbility } = ctx.state;
2743
3036
  const { model } = ctx.params;
2744
3037
  const { body, query = {} } = ctx.request;
2745
- const documentManager2 = getService$1("document-manager");
2746
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3038
+ const documentManager2 = getService$2("document-manager");
3039
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2747
3040
  if (permissionChecker2.cannot.discard()) {
2748
3041
  return ctx.forbidden();
2749
3042
  }
@@ -2766,8 +3059,8 @@ const singleTypes = {
2766
3059
  const { userAbility } = ctx.state;
2767
3060
  const { model } = ctx.params;
2768
3061
  const { query } = ctx.request;
2769
- const documentManager2 = getService$1("document-manager");
2770
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3062
+ const documentManager2 = getService$2("document-manager");
3063
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2771
3064
  const { locale } = await getDocumentLocaleAndStatus(query, model);
2772
3065
  if (permissionChecker2.cannot.read()) {
2773
3066
  return ctx.forbidden();
@@ -2791,7 +3084,7 @@ const uid$1 = {
2791
3084
  const { query = {} } = ctx.request;
2792
3085
  const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2793
3086
  await validateUIDField(contentTypeUID, field);
2794
- const uidService = getService$1("uid");
3087
+ const uidService = getService$2("uid");
2795
3088
  ctx.body = {
2796
3089
  data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
2797
3090
  };
@@ -2803,7 +3096,7 @@ const uid$1 = {
2803
3096
  const { query = {} } = ctx.request;
2804
3097
  const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2805
3098
  await validateUIDField(contentTypeUID, field);
2806
- const uidService = getService$1("uid");
3099
+ const uidService = getService$2("uid");
2807
3100
  const isAvailable = await uidService.checkUIDAvailability({
2808
3101
  contentTypeUID,
2809
3102
  field,
@@ -2824,7 +3117,8 @@ const controllers = {
2824
3117
  relations,
2825
3118
  "single-types": singleTypes,
2826
3119
  uid: uid$1,
2827
- ...history.controllers ? history.controllers : {}
3120
+ ...history.controllers ? history.controllers : {},
3121
+ ...preview.controllers ? preview.controllers : {}
2828
3122
  };
2829
3123
  const keys = {
2830
3124
  CONFIGURATION: "configuration"
@@ -2953,18 +3247,15 @@ async function syncMetadatas(configuration, schema) {
2953
3247
  _.set(updatedMeta, ["list", "searchable"], false);
2954
3248
  _.set(acc, [key], updatedMeta);
2955
3249
  }
2956
- if (!_.has(edit, "mainField"))
2957
- return acc;
3250
+ if (!_.has(edit, "mainField")) return acc;
2958
3251
  if (!isRelation$1(attr)) {
2959
3252
  _.set(updatedMeta, "edit", _.omit(edit, ["mainField"]));
2960
3253
  _.set(acc, [key], updatedMeta);
2961
3254
  return acc;
2962
3255
  }
2963
- if (edit.mainField === "id")
2964
- return acc;
3256
+ if (edit.mainField === "id") return acc;
2965
3257
  const targetSchema = getTargetSchema(attr.targetModel);
2966
- if (!targetSchema)
2967
- return acc;
3258
+ if (!targetSchema) return acc;
2968
3259
  if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
2969
3260
  _.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
2970
3261
  _.set(acc, [key], updatedMeta);
@@ -2975,12 +3266,12 @@ async function syncMetadatas(configuration, schema) {
2975
3266
  return _.assign(metasWithDefaults, updatedMetas);
2976
3267
  }
2977
3268
  const getTargetSchema = (targetModel) => {
2978
- return getService$1("content-types").findContentType(targetModel);
3269
+ return getService$2("content-types").findContentType(targetModel);
2979
3270
  };
2980
3271
  const DEFAULT_LIST_LENGTH = 4;
2981
3272
  const MAX_ROW_SIZE = 12;
2982
3273
  const isAllowedFieldSize = (type, size) => {
2983
- const { getFieldSize } = getService$1("field-sizes");
3274
+ const { getFieldSize } = getService$2("field-sizes");
2984
3275
  const fieldSize = getFieldSize(type);
2985
3276
  if (!fieldSize.isResizable && size !== fieldSize.default) {
2986
3277
  return false;
@@ -2988,7 +3279,7 @@ const isAllowedFieldSize = (type, size) => {
2988
3279
  return size <= MAX_ROW_SIZE;
2989
3280
  };
2990
3281
  const getDefaultFieldSize = (attribute) => {
2991
- const { hasFieldSize, getFieldSize } = getService$1("field-sizes");
3282
+ const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
2992
3283
  return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
2993
3284
  };
2994
3285
  async function createDefaultLayouts(schema) {
@@ -3009,8 +3300,7 @@ function createDefaultEditLayout(schema) {
3009
3300
  return appendToEditLayout([], keys2, schema);
3010
3301
  }
3011
3302
  function syncLayouts(configuration, schema) {
3012
- if (_.isEmpty(configuration.layouts))
3013
- return createDefaultLayouts(schema);
3303
+ if (_.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
3014
3304
  const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
3015
3305
  let cleanList = list.filter((attr) => isListable(schema, attr));
3016
3306
  const cleanEditRelations = editRelations.filter(
@@ -3021,9 +3311,8 @@ function syncLayouts(configuration, schema) {
3021
3311
  for (const row of edit) {
3022
3312
  const newRow = [];
3023
3313
  for (const el of row) {
3024
- if (!hasEditableAttribute(schema, el.name))
3025
- continue;
3026
- const { hasFieldSize } = getService$1("field-sizes");
3314
+ if (!hasEditableAttribute(schema, el.name)) continue;
3315
+ const { hasFieldSize } = getService$2("field-sizes");
3027
3316
  const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
3028
3317
  if (!isAllowedFieldSize(fieldType, el.size)) {
3029
3318
  elementsToReAppend.push(el.name);
@@ -3053,8 +3342,7 @@ function syncLayouts(configuration, schema) {
3053
3342
  };
3054
3343
  }
3055
3344
  const appendToEditLayout = (layout = [], keysToAppend, schema) => {
3056
- if (keysToAppend.length === 0)
3057
- return layout;
3345
+ if (keysToAppend.length === 0) return layout;
3058
3346
  let currentRowIndex = Math.max(layout.length - 1, 0);
3059
3347
  if (!layout[currentRowIndex]) {
3060
3348
  layout[currentRowIndex] = [];
@@ -3163,17 +3451,17 @@ const configurationService$1 = createConfigurationService({
3163
3451
  isComponent: true,
3164
3452
  prefix: STORE_KEY_PREFIX,
3165
3453
  getModels() {
3166
- const { toContentManagerModel } = getService$1("data-mapper");
3454
+ const { toContentManagerModel } = getService$2("data-mapper");
3167
3455
  return mapValues(toContentManagerModel, strapi.components);
3168
3456
  }
3169
3457
  });
3170
3458
  const components = ({ strapi: strapi2 }) => ({
3171
3459
  findAllComponents() {
3172
- const { toContentManagerModel } = getService$1("data-mapper");
3460
+ const { toContentManagerModel } = getService$2("data-mapper");
3173
3461
  return Object.values(strapi2.components).map(toContentManagerModel);
3174
3462
  },
3175
3463
  findComponent(uid2) {
3176
- const { toContentManagerModel } = getService$1("data-mapper");
3464
+ const { toContentManagerModel } = getService$2("data-mapper");
3177
3465
  const component = strapi2.components[uid2];
3178
3466
  return isNil$1(component) ? component : toContentManagerModel(component);
3179
3467
  },
@@ -3224,17 +3512,17 @@ const configurationService = createConfigurationService({
3224
3512
  storeUtils,
3225
3513
  prefix: "content_types",
3226
3514
  getModels() {
3227
- const { toContentManagerModel } = getService$1("data-mapper");
3515
+ const { toContentManagerModel } = getService$2("data-mapper");
3228
3516
  return mapValues(toContentManagerModel, strapi.contentTypes);
3229
3517
  }
3230
3518
  });
3231
3519
  const service = ({ strapi: strapi2 }) => ({
3232
3520
  findAllContentTypes() {
3233
- const { toContentManagerModel } = getService$1("data-mapper");
3521
+ const { toContentManagerModel } = getService$2("data-mapper");
3234
3522
  return Object.values(strapi2.contentTypes).map(toContentManagerModel);
3235
3523
  },
3236
3524
  findContentType(uid2) {
3237
- const { toContentManagerModel } = getService$1("data-mapper");
3525
+ const { toContentManagerModel } = getService$2("data-mapper");
3238
3526
  const contentType = strapi2.contentTypes[uid2];
3239
3527
  return isNil$1(contentType) ? contentType : toContentManagerModel(contentType);
3240
3528
  },
@@ -3263,7 +3551,7 @@ const service = ({ strapi: strapi2 }) => ({
3263
3551
  return this.findConfiguration(contentType);
3264
3552
  },
3265
3553
  findComponentsConfigurations(contentType) {
3266
- return getService$1("components").findComponentsConfigurations(contentType);
3554
+ return getService$2("components").findComponentsConfigurations(contentType);
3267
3555
  },
3268
3556
  syncConfigurations() {
3269
3557
  return configurationService.syncConfigurations();
@@ -3444,12 +3732,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3444
3732
  ability: userAbility,
3445
3733
  model
3446
3734
  });
3447
- const toSubject = (entity) => entity ? permissionsManager.toSubject(entity, model) : model;
3735
+ const { actionProvider } = strapi2.service("admin::permission");
3736
+ const toSubject = (entity) => {
3737
+ return entity ? permissionsManager.toSubject(entity, model) : model;
3738
+ };
3448
3739
  const can = (action, entity, field) => {
3449
- return userAbility.can(action, toSubject(entity), field);
3740
+ const subject = toSubject(entity);
3741
+ const aliases = actionProvider.unstable_aliases(action, model);
3742
+ return (
3743
+ // Test the original action to see if it passes
3744
+ userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
3745
+ aliases.some((alias) => userAbility.can(alias, subject, field))
3746
+ );
3450
3747
  };
3451
3748
  const cannot = (action, entity, field) => {
3452
- return userAbility.cannot(action, toSubject(entity), field);
3749
+ const subject = toSubject(entity);
3750
+ const aliases = actionProvider.unstable_aliases(action, model);
3751
+ return (
3752
+ // Test both the original action
3753
+ userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
3754
+ aliases.every((alias) => userAbility.cannot(alias, subject, field))
3755
+ );
3453
3756
  };
3454
3757
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3455
3758
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3520,7 +3823,7 @@ const permission = ({ strapi: strapi2 }) => ({
3520
3823
  return userAbility.can(action);
3521
3824
  },
3522
3825
  async registerPermissions() {
3523
- const displayedContentTypes = getService$1("content-types").findDisplayedContentTypes();
3826
+ const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
3524
3827
  const contentTypesUids = displayedContentTypes.map(prop("uid"));
3525
3828
  const actions = [
3526
3829
  {
@@ -3605,6 +3908,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
3605
3908
  if (initialPopulate) {
3606
3909
  return initialPopulate;
3607
3910
  }
3911
+ if (attributeName === "localizations") {
3912
+ const validationPopulate = getPopulateForValidation(model.uid);
3913
+ return {
3914
+ populate: validationPopulate.populate
3915
+ };
3916
+ }
3608
3917
  if (!isVisibleAttribute$1(model, attributeName)) {
3609
3918
  return true;
3610
3919
  }
@@ -3664,6 +3973,9 @@ const getDeepPopulate = (uid2, {
3664
3973
  return {};
3665
3974
  }
3666
3975
  const model = strapi.getModel(uid2);
3976
+ if (!model) {
3977
+ return {};
3978
+ }
3667
3979
  return Object.keys(model.attributes).reduce(
3668
3980
  (populateAcc, attributeName) => merge(
3669
3981
  populateAcc,
@@ -3683,40 +3995,46 @@ const getDeepPopulate = (uid2, {
3683
3995
  {}
3684
3996
  );
3685
3997
  };
3686
- const getValidatableFieldsPopulate = (uid2, {
3687
- initialPopulate = {},
3688
- countMany = false,
3689
- countOne = false,
3690
- maxLevel = Infinity
3691
- } = {}, level = 1) => {
3692
- if (level > maxLevel) {
3998
+ const getPopulateForValidation = (uid2) => {
3999
+ const model = strapi.getModel(uid2);
4000
+ if (!model) {
3693
4001
  return {};
3694
4002
  }
3695
- const model = strapi.getModel(uid2);
3696
4003
  return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
3697
- if (!getDoesAttributeRequireValidation(attribute)) {
4004
+ if (isScalarAttribute(attribute)) {
4005
+ if (getDoesAttributeRequireValidation(attribute)) {
4006
+ populateAcc.fields = populateAcc.fields || [];
4007
+ populateAcc.fields.push(attributeName);
4008
+ }
3698
4009
  return populateAcc;
3699
4010
  }
3700
- if (isScalarAttribute(attribute)) {
3701
- return merge(populateAcc, {
3702
- [attributeName]: true
3703
- });
4011
+ if (isComponent(attribute)) {
4012
+ const component = attribute.component;
4013
+ const componentResult = getPopulateForValidation(component);
4014
+ if (Object.keys(componentResult).length > 0) {
4015
+ populateAcc.populate = populateAcc.populate || {};
4016
+ populateAcc.populate[attributeName] = componentResult;
4017
+ }
4018
+ return populateAcc;
3704
4019
  }
3705
- return merge(
3706
- populateAcc,
3707
- getPopulateFor(
3708
- attributeName,
3709
- model,
3710
- {
3711
- // @ts-expect-error - improve types
3712
- initialPopulate: initialPopulate?.[attributeName],
3713
- countMany,
3714
- countOne,
3715
- maxLevel
4020
+ if (isDynamicZone(attribute)) {
4021
+ const components2 = attribute.components;
4022
+ const componentsResult = (components2 || []).reduce(
4023
+ (acc, componentUID) => {
4024
+ const componentResult = getPopulateForValidation(componentUID);
4025
+ if (Object.keys(componentResult).length > 0) {
4026
+ acc[componentUID] = componentResult;
4027
+ }
4028
+ return acc;
3716
4029
  },
3717
- level
3718
- )
3719
- );
4030
+ {}
4031
+ );
4032
+ if (Object.keys(componentsResult).length > 0) {
4033
+ populateAcc.populate = populateAcc.populate || {};
4034
+ populateAcc.populate[attributeName] = { on: componentsResult };
4035
+ }
4036
+ }
4037
+ return populateAcc;
3720
4038
  }, {});
3721
4039
  };
3722
4040
  const getDeepPopulateDraftCount = (uid2) => {
@@ -3796,7 +4114,7 @@ const getQueryPopulate = async (uid2, query) => {
3796
4114
  return populateQuery;
3797
4115
  };
3798
4116
  const buildDeepPopulate = (uid2) => {
3799
- return getService$1("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
4117
+ return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
3800
4118
  };
3801
4119
  const populateBuilder = (uid2) => {
3802
4120
  let getInitialPopulate = async () => {
@@ -3958,7 +4276,6 @@ const AVAILABLE_LOCALES_FIELDS = [
3958
4276
  "locale",
3959
4277
  "updatedAt",
3960
4278
  "createdAt",
3961
- "status",
3962
4279
  "publishedAt",
3963
4280
  "documentId"
3964
4281
  ];
@@ -3979,34 +4296,20 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3979
4296
  /**
3980
4297
  * Returns available locales of a document for the current status
3981
4298
  */
3982
- async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
4299
+ async getAvailableLocales(uid2, version, allVersions) {
3983
4300
  const versionsByLocale = groupBy("locale", allVersions);
3984
- delete versionsByLocale[version.locale];
4301
+ if (version.locale) {
4302
+ delete versionsByLocale[version.locale];
4303
+ }
3985
4304
  const model = strapi2.getModel(uid2);
3986
- const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
3987
- const traversalFunction = async (localeVersion) => traverseEntity(
3988
- ({ key }, { remove }) => {
3989
- if (keysToKeep.includes(key)) {
3990
- return;
3991
- }
3992
- remove(key);
3993
- },
3994
- { schema: model, getModel: strapi2.getModel.bind(strapi2) },
3995
- // @ts-expect-error fix types DocumentVersion incompatible with Data
3996
- localeVersion
3997
- );
3998
4305
  const mappingResult = await async.map(
3999
4306
  Object.values(versionsByLocale),
4000
4307
  async (localeVersions) => {
4001
- const mappedLocaleVersions = await async.map(
4002
- localeVersions,
4003
- traversalFunction
4004
- );
4005
4308
  if (!contentTypes$1.hasDraftAndPublish(model)) {
4006
- return mappedLocaleVersions[0];
4309
+ return localeVersions[0];
4007
4310
  }
4008
- const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
4009
- const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
4311
+ const draftVersion = localeVersions.find((v) => v.publishedAt === null);
4312
+ const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
4010
4313
  if (!draftVersion) {
4011
4314
  return;
4012
4315
  }
@@ -4028,8 +4331,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4028
4331
  const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
4029
4332
  return matchLocale && matchStatus;
4030
4333
  });
4031
- if (!availableStatus)
4032
- return availableStatus;
4334
+ if (!availableStatus) return availableStatus;
4033
4335
  return pick(AVAILABLE_STATUS_FIELDS, availableStatus);
4034
4336
  },
4035
4337
  /**
@@ -4039,18 +4341,19 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4039
4341
  * @returns
4040
4342
  */
4041
4343
  async getManyAvailableStatus(uid2, documents) {
4042
- if (!documents.length)
4043
- return [];
4344
+ if (!documents.length) return [];
4044
4345
  const status = documents[0].publishedAt !== null ? "published" : "draft";
4045
- const locale = documents[0]?.locale;
4046
- const otherStatus = status === "published" ? "draft" : "published";
4047
- return strapi2.documents(uid2).findMany({
4048
- filters: {
4049
- documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) }
4050
- },
4051
- status: otherStatus,
4052
- locale,
4053
- fields: ["documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
4346
+ const locales = documents.map((d) => d.locale).filter(Boolean);
4347
+ const where = {
4348
+ documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) },
4349
+ publishedAt: { $null: status === "published" }
4350
+ };
4351
+ if (locales.length) {
4352
+ where.locale = { $in: locales };
4353
+ }
4354
+ return strapi2.query(uid2).findMany({
4355
+ where,
4356
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
4054
4357
  });
4055
4358
  },
4056
4359
  getStatus(version, otherDocumentStatuses) {
@@ -4067,10 +4370,8 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4067
4370
  } else if (otherVersion) {
4068
4371
  draftVersion = otherVersion;
4069
4372
  }
4070
- if (!draftVersion)
4071
- return CONTENT_MANAGER_STATUS.PUBLISHED;
4072
- if (!publishedVersion)
4073
- return CONTENT_MANAGER_STATUS.DRAFT;
4373
+ if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
4374
+ if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
4074
4375
  const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4075
4376
  return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
4076
4377
  },
@@ -4078,11 +4379,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4078
4379
  // We could refactor this so the locales are only loaded when they're
4079
4380
  // needed. e.g. in the bulk locale action modal.
4080
4381
  async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
4081
- const populate = getValidatableFieldsPopulate(uid2);
4082
- const versions = await strapi2.db.query(uid2).findMany({
4083
- where: { documentId: version.documentId },
4382
+ const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
4383
+ const params = {
4084
4384
  populate: {
4085
- // Populate only fields that require validation for bulk locale actions
4086
4385
  ...populate,
4087
4386
  // NOTE: creator fields are selected in this way to avoid exposing sensitive data
4088
4387
  createdBy: {
@@ -4091,9 +4390,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4091
4390
  updatedBy: {
4092
4391
  select: ["id", "firstname", "lastname", "email"]
4093
4392
  }
4393
+ },
4394
+ fields: uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
4395
+ filters: {
4396
+ documentId: version.documentId
4094
4397
  }
4095
- });
4096
- const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
4398
+ };
4399
+ const dbParams = strapi2.get("query-params").transform(uid2, params);
4400
+ const versions = await strapi2.db.query(uid2).findMany(dbParams);
4401
+ const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions) : [];
4097
4402
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
4098
4403
  return {
4099
4404
  availableLocales: availableLocalesResult,
@@ -4107,13 +4412,29 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4107
4412
  */
4108
4413
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
4109
4414
  if (!document) {
4110
- return document;
4415
+ return {
4416
+ data: document,
4417
+ meta: {
4418
+ availableLocales: [],
4419
+ availableStatus: []
4420
+ }
4421
+ };
4111
4422
  }
4112
4423
  const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
4113
4424
  if (!hasDraftAndPublish) {
4114
4425
  opts.availableStatus = false;
4115
4426
  }
4116
4427
  const meta = await this.getMetadata(uid2, document, opts);
4428
+ if (document.localizations) {
4429
+ const otherStatus = await this.getManyAvailableStatus(uid2, document.localizations);
4430
+ document.localizations = document.localizations.map((d) => {
4431
+ const status = otherStatus.find((s) => s.documentId === d.documentId);
4432
+ return {
4433
+ ...d,
4434
+ status: this.getStatus(d, status ? [status] : [])
4435
+ };
4436
+ });
4437
+ }
4117
4438
  return {
4118
4439
  data: {
4119
4440
  ...document,
@@ -4331,7 +4652,8 @@ const services = {
4331
4652
  permission,
4332
4653
  "populate-builder": populateBuilder$1,
4333
4654
  uid,
4334
- ...history.services ? history.services : {}
4655
+ ...history.services ? history.services : {},
4656
+ ...preview.services ? preview.services : {}
4335
4657
  };
4336
4658
  const index = () => {
4337
4659
  return {