@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
@@ -10,8 +10,7 @@ const qs = require("qs");
10
10
  const slugify = require("@sindresorhus/slugify");
11
11
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
12
12
  function _interopNamespace(e) {
13
- if (e && e.__esModule)
14
- return e;
13
+ if (e && e.__esModule) return e;
15
14
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
16
15
  if (e) {
17
16
  for (const k in e) {
@@ -33,10 +32,10 @@ const isNil__default = /* @__PURE__ */ _interopDefault(isNil);
33
32
  const ___default = /* @__PURE__ */ _interopDefault(_);
34
33
  const qs__default = /* @__PURE__ */ _interopDefault(qs);
35
34
  const slugify__default = /* @__PURE__ */ _interopDefault(slugify);
36
- const getService$1 = (name) => {
35
+ const getService$2 = (name) => {
37
36
  return strapi.plugin("content-manager").service(name);
38
37
  };
39
- function getService(strapi2, name) {
38
+ function getService$1(strapi2, name) {
40
39
  return strapi2.service(`plugin::content-manager.${name}`);
41
40
  }
42
41
  const historyRestoreVersionSchema = yup__namespace.object().shape({
@@ -72,7 +71,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
72
71
  if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {
73
72
  throw new strapiUtils.errors.ForbiddenError("contentType and documentId are required");
74
73
  }
75
- const permissionChecker2 = getService$1("permission-checker").create({
74
+ const permissionChecker2 = getService$2("permission-checker").create({
76
75
  userAbility: ctx.state.userAbility,
77
76
  model: ctx.query.contentType
78
77
  });
@@ -80,7 +79,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
80
79
  return ctx.forbidden();
81
80
  }
82
81
  const query = await permissionChecker2.sanitizeQuery(ctx.query);
83
- const { results, pagination } = await getService(strapi2, "history").findVersionsPage({
82
+ const { results, pagination } = await getService$1(strapi2, "history").findVersionsPage({
84
83
  query: {
85
84
  ...query,
86
85
  ...getValidPagination({ page: query.page, pageSize: query.pageSize })
@@ -105,14 +104,14 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
105
104
  async restoreVersion(ctx) {
106
105
  const request = ctx.request;
107
106
  await validateRestoreVersion(request.body, "contentType is required");
108
- const permissionChecker2 = getService$1("permission-checker").create({
107
+ const permissionChecker2 = getService$2("permission-checker").create({
109
108
  userAbility: ctx.state.userAbility,
110
109
  model: request.body.contentType
111
110
  });
112
111
  if (permissionChecker2.cannot.update()) {
113
112
  throw new strapiUtils.errors.ForbiddenError();
114
113
  }
115
- const restoredDocument = await getService(strapi2, "history").restoreVersion(
114
+ const restoredDocument = await getService$1(strapi2, "history").restoreVersion(
116
115
  request.params.versionId
117
116
  );
118
117
  return {
@@ -121,7 +120,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
121
120
  }
122
121
  };
123
122
  };
124
- const controllers$1 = {
123
+ const controllers$2 = {
125
124
  "history-version": createHistoryVersionController
126
125
  /**
127
126
  * Casting is needed because the types aren't aware that Strapi supports
@@ -167,8 +166,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
167
166
  };
168
167
  const getRelationRestoreValue = async (versionRelationData, attribute) => {
169
168
  if (Array.isArray(versionRelationData)) {
170
- if (versionRelationData.length === 0)
171
- return versionRelationData;
169
+ if (versionRelationData.length === 0) return versionRelationData;
172
170
  const existingAndMissingRelations = await Promise.all(
173
171
  versionRelationData.map((relation) => {
174
172
  return strapi2.documents(attribute.target).findOne({
@@ -177,19 +175,16 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
177
175
  });
178
176
  })
179
177
  );
180
- return existingAndMissingRelations.filter(
181
- (relation) => relation !== null
182
- );
178
+ return existingAndMissingRelations.filter((relation) => relation !== null);
183
179
  }
184
180
  return strapi2.documents(attribute.target).findOne({
185
181
  documentId: versionRelationData.documentId,
186
182
  locale: versionRelationData.locale || void 0
187
183
  });
188
184
  };
189
- const getMediaRestoreValue = async (versionRelationData, attribute) => {
190
- if (attribute.multiple) {
185
+ const getMediaRestoreValue = async (versionRelationData) => {
186
+ if (Array.isArray(versionRelationData)) {
191
187
  const existingAndMissingMedias = await Promise.all(
192
- // @ts-expect-error Fix the type definitions so this isn't any
193
188
  versionRelationData.map((media) => {
194
189
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
195
190
  })
@@ -199,10 +194,11 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
199
194
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
200
195
  };
201
196
  const localesService = strapi2.plugin("i18n")?.service("locales");
197
+ const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
202
198
  const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
199
+ const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
203
200
  const getLocaleDictionary = async () => {
204
- if (!localesService)
205
- return {};
201
+ if (!localesService) return {};
206
202
  const locales = await localesService.find() || [];
207
203
  return locales.reduce(
208
204
  (acc, locale) => {
@@ -226,9 +222,21 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
226
222
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
227
223
  return documentMetadataService.getStatus(document, meta.availableStatus);
228
224
  };
229
- const getDeepPopulate2 = (uid2) => {
225
+ const getComponentFields = (componentUID) => {
226
+ return Object.entries(strapi2.getModel(componentUID).attributes).reduce(
227
+ (fieldsAcc, [key, attribute]) => {
228
+ if (!["relation", "media", "component", "dynamiczone"].includes(attribute.type)) {
229
+ fieldsAcc.push(key);
230
+ }
231
+ return fieldsAcc;
232
+ },
233
+ []
234
+ );
235
+ };
236
+ const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
230
237
  const model = strapi2.getModel(uid2);
231
238
  const attributes = Object.entries(model.attributes);
239
+ const fieldSelector = useDatabaseSyntax ? "select" : "fields";
232
240
  return attributes.reduce((acc, [attributeName, attribute]) => {
233
241
  switch (attribute.type) {
234
242
  case "relation": {
@@ -238,23 +246,29 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
238
246
  }
239
247
  const isVisible2 = strapiUtils.contentTypes.isVisibleAttribute(model, attributeName);
240
248
  if (isVisible2) {
241
- acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
249
+ acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
242
250
  }
243
251
  break;
244
252
  }
245
253
  case "media": {
246
- acc[attributeName] = { fields: ["id"] };
254
+ acc[attributeName] = { [fieldSelector]: ["id"] };
247
255
  break;
248
256
  }
249
257
  case "component": {
250
258
  const populate = getDeepPopulate2(attribute.component);
251
- acc[attributeName] = { populate };
259
+ acc[attributeName] = {
260
+ populate,
261
+ [fieldSelector]: getComponentFields(attribute.component)
262
+ };
252
263
  break;
253
264
  }
254
265
  case "dynamiczone": {
255
266
  const populatedComponents = (attribute.components || []).reduce(
256
267
  (acc2, componentUID) => {
257
- acc2[componentUID] = { populate: getDeepPopulate2(componentUID) };
268
+ acc2[componentUID] = {
269
+ populate: getDeepPopulate2(componentUID),
270
+ [fieldSelector]: getComponentFields(componentUID)
271
+ };
258
272
  return acc2;
259
273
  },
260
274
  {}
@@ -316,6 +330,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
316
330
  getRelationRestoreValue,
317
331
  getMediaRestoreValue,
318
332
  getDefaultLocale,
333
+ isLocalizedContentType,
319
334
  getLocaleDictionary,
320
335
  getRetentionDays,
321
336
  getVersionStatus,
@@ -338,7 +353,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
338
353
  });
339
354
  },
340
355
  async findVersionsPage(params) {
341
- const locale = params.query.locale || await serviceUtils.getDefaultLocale();
356
+ const schema = strapi2.getModel(params.query.contentType);
357
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(schema);
358
+ const defaultLocale = await serviceUtils.getDefaultLocale();
359
+ let locale = null;
360
+ if (isLocalizedContentType) {
361
+ locale = params.query.locale || defaultLocale;
362
+ }
342
363
  const [{ results, pagination }, localeDictionary] = await Promise.all([
343
364
  query.findPage({
344
365
  ...params.query,
@@ -354,78 +375,76 @@ const createHistoryService = ({ strapi: strapi2 }) => {
354
375
  }),
355
376
  serviceUtils.getLocaleDictionary()
356
377
  ]);
357
- const populateEntryRelations = async (entry) => {
358
- const entryWithRelations = await Object.entries(entry.schema).reduce(
359
- async (currentDataWithRelations, [attributeKey, attributeSchema]) => {
360
- const attributeValue = entry.data[attributeKey];
361
- const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
362
- if (attributeSchema.type === "media") {
363
- const permissionChecker2 = getService$1("permission-checker").create({
364
- userAbility: params.state.userAbility,
365
- model: "plugin::upload.file"
366
- });
367
- const response = await serviceUtils.buildMediaResponse(attributeValues);
368
- const sanitizedResults = await Promise.all(
369
- response.results.map((media) => permissionChecker2.sanitizeOutput(media))
370
- );
371
- return {
372
- ...await currentDataWithRelations,
373
- [attributeKey]: {
374
- results: sanitizedResults,
375
- meta: response.meta
376
- }
377
- };
378
+ const populateEntry = async (entry) => {
379
+ return strapiUtils.traverseEntity(
380
+ async (options, utils) => {
381
+ if (!options.attribute) return;
382
+ if (!options.value) return;
383
+ const currentValue = Array.isArray(options.value) ? options.value : [options.value];
384
+ if (options.attribute.type === "component") {
385
+ utils.remove("id");
378
386
  }
379
- if (attributeSchema.type === "relation" && attributeSchema.relation !== "morphToOne" && attributeSchema.relation !== "morphToMany") {
380
- if (attributeSchema.target === "admin::user") {
387
+ if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
388
+ options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
389
+ if (options.attribute.target === "admin::user") {
381
390
  const adminUsers = await Promise.all(
382
- attributeValues.map((userToPopulate) => {
391
+ currentValue.map((userToPopulate) => {
383
392
  if (userToPopulate == null) {
384
393
  return null;
385
394
  }
386
- return strapi2.query("admin::user").findOne({ where: { id: userToPopulate.id } });
395
+ return strapi2.query("admin::user").findOne({
396
+ where: {
397
+ ...userToPopulate.id ? { id: userToPopulate.id } : {},
398
+ ...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
399
+ }
400
+ });
387
401
  })
388
402
  );
389
- return {
390
- ...await currentDataWithRelations,
391
- /**
392
- * Ideally we would return the same "{results: [], meta: {}}" shape, however,
393
- * when sanitizing the data as a whole in the controller before sending to the client,
394
- * the data for admin relation user is completely sanitized if we return an object here as opposed to an array.
395
- */
396
- [attributeKey]: adminUsers
397
- };
403
+ utils.set(options.key, adminUsers);
398
404
  }
399
- const permissionChecker2 = getService$1("permission-checker").create({
405
+ const permissionChecker2 = getService$2("permission-checker").create({
400
406
  userAbility: params.state.userAbility,
401
- model: attributeSchema.target
407
+ model: options.attribute.target
402
408
  });
403
409
  const response = await serviceUtils.buildRelationReponse(
404
- attributeValues,
405
- attributeSchema
410
+ currentValue,
411
+ options.attribute
406
412
  );
407
413
  const sanitizedResults = await Promise.all(
408
414
  response.results.map((media) => permissionChecker2.sanitizeOutput(media))
409
415
  );
410
- return {
411
- ...await currentDataWithRelations,
412
- [attributeKey]: {
413
- results: sanitizedResults,
414
- meta: response.meta
415
- }
416
- };
416
+ utils.set(options.key, {
417
+ results: sanitizedResults,
418
+ meta: response.meta
419
+ });
417
420
  }
418
- return currentDataWithRelations;
421
+ if (options.attribute.type === "media") {
422
+ const permissionChecker2 = getService$2("permission-checker").create({
423
+ userAbility: params.state.userAbility,
424
+ model: "plugin::upload.file"
425
+ });
426
+ const response = await serviceUtils.buildMediaResponse(currentValue);
427
+ const sanitizedResults = await Promise.all(
428
+ response.results.map((media) => permissionChecker2.sanitizeOutput(media))
429
+ );
430
+ utils.set(options.key, {
431
+ results: sanitizedResults,
432
+ meta: response.meta
433
+ });
434
+ }
435
+ },
436
+ {
437
+ schema,
438
+ getModel: strapi2.getModel.bind(strapi2)
419
439
  },
420
- Promise.resolve(entry.data)
440
+ entry.data
421
441
  );
422
- return entryWithRelations;
423
442
  };
424
443
  const formattedResults = await Promise.all(
425
444
  results.map(async (result) => {
426
445
  return {
427
446
  ...result,
428
- data: await populateEntryRelations(result),
447
+ data: await populateEntry(result),
429
448
  meta: {
430
449
  unknownAttributes: serviceUtils.getSchemaAttributesDiff(
431
450
  result.schema,
@@ -456,30 +475,44 @@ const createHistoryService = ({ strapi: strapi2 }) => {
456
475
  // Clone to avoid mutating the original version data
457
476
  structuredClone(version.data)
458
477
  );
459
- const sanitizedSchemaAttributes = fp.omit(
460
- FIELDS_TO_IGNORE,
461
- contentTypeSchemaAttributes
462
- );
463
- const reducer = strapiUtils.async.reduce(Object.entries(sanitizedSchemaAttributes));
464
- const dataWithoutMissingRelations = await reducer(
465
- async (previousRelationAttributes, [name, attribute]) => {
466
- const versionRelationData = version.data[name];
467
- if (!versionRelationData) {
468
- return previousRelationAttributes;
478
+ const schema = structuredClone(version.schema);
479
+ schema.attributes = fp.omit(FIELDS_TO_IGNORE, contentTypeSchemaAttributes);
480
+ const dataWithoutMissingRelations = await strapiUtils.traverseEntity(
481
+ async (options, utils) => {
482
+ if (!options.attribute) return;
483
+ if (options.attribute.type === "component") {
484
+ utils.remove("id");
485
+ if (options.attribute.repeatable && options.value === null) {
486
+ utils.set(options.key, []);
487
+ }
488
+ }
489
+ if (options.attribute.type === "dynamiczone") {
490
+ if (options.value === null) {
491
+ utils.set(options.key, []);
492
+ }
469
493
  }
470
- if (attribute.type === "relation" && // TODO: handle polymorphic relations
471
- attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
472
- const data2 = await serviceUtils.getRelationRestoreValue(versionRelationData, attribute);
473
- previousRelationAttributes[name] = data2;
494
+ if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
495
+ options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
496
+ if (!options.value) return;
497
+ const data2 = await serviceUtils.getRelationRestoreValue(
498
+ options.value,
499
+ options.attribute
500
+ );
501
+ utils.set(options.key, data2);
474
502
  }
475
- if (attribute.type === "media") {
476
- const data2 = await serviceUtils.getMediaRestoreValue(versionRelationData, attribute);
477
- previousRelationAttributes[name] = data2;
503
+ if (options.attribute.type === "media") {
504
+ if (!options.value) return;
505
+ const data2 = await serviceUtils.getMediaRestoreValue(
506
+ options.value
507
+ );
508
+ utils.set(options.key, data2);
478
509
  }
479
- return previousRelationAttributes;
480
510
  },
481
- // Clone to avoid mutating the original version data
482
- structuredClone(dataWithoutAddedAttributes)
511
+ {
512
+ schema,
513
+ getModel: strapi2.getModel.bind(strapi2)
514
+ },
515
+ dataWithoutAddedAttributes
483
516
  );
484
517
  const data = fp.omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
485
518
  const restoredDocument = await strapi2.documents(version.contentType).update({
@@ -494,6 +527,42 @@ const createHistoryService = ({ strapi: strapi2 }) => {
494
527
  }
495
528
  };
496
529
  };
530
+ const shouldCreateHistoryVersion = (context) => {
531
+ if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
532
+ return false;
533
+ }
534
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
535
+ return false;
536
+ }
537
+ if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
538
+ return false;
539
+ }
540
+ if (!context.contentType.uid.startsWith("api::")) {
541
+ return false;
542
+ }
543
+ return true;
544
+ };
545
+ const getSchemas = (uid2) => {
546
+ const attributesSchema = strapi.getModel(uid2).attributes;
547
+ const componentsSchemas = Object.keys(attributesSchema).reduce(
548
+ (currentComponentSchemas, key) => {
549
+ const fieldSchema = attributesSchema[key];
550
+ if (fieldSchema.type === "component") {
551
+ const componentSchema = strapi.getModel(fieldSchema.component).attributes;
552
+ return {
553
+ ...currentComponentSchemas,
554
+ [fieldSchema.component]: componentSchema
555
+ };
556
+ }
557
+ return currentComponentSchemas;
558
+ },
559
+ {}
560
+ );
561
+ return {
562
+ schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
563
+ componentsSchemas
564
+ };
565
+ };
497
566
  const createLifecyclesService = ({ strapi: strapi2 }) => {
498
567
  const state = {
499
568
  deleteExpiredJob: null,
@@ -506,76 +575,62 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
506
575
  return;
507
576
  }
508
577
  strapi2.documents.use(async (context, next) => {
509
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
510
- return next();
511
- }
512
- if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
513
- return next();
514
- }
515
- if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
516
- return next();
517
- }
518
- const contentTypeUid = context.contentType.uid;
519
- if (!contentTypeUid.startsWith("api::")) {
520
- return next();
521
- }
522
578
  const result = await next();
523
- const documentContext = {
524
- documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
525
- locale: context.params?.locale
526
- };
579
+ if (!shouldCreateHistoryVersion(context)) {
580
+ return result;
581
+ }
582
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
527
583
  const defaultLocale = await serviceUtils.getDefaultLocale();
528
- const locale = documentContext.locale || defaultLocale;
529
- if (Array.isArray(locale)) {
530
- strapi2.log.warn(
531
- "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
532
- );
533
- return next();
584
+ const locales = fp.castArray(context.params?.locale || defaultLocale);
585
+ if (!locales.length) {
586
+ return result;
534
587
  }
535
- const document = await strapi2.documents(contentTypeUid).findOne({
536
- documentId: documentContext.documentId,
537
- locale,
538
- populate: serviceUtils.getDeepPopulate(contentTypeUid)
588
+ const uid2 = context.contentType.uid;
589
+ const schemas = getSchemas(uid2);
590
+ const model = strapi2.getModel(uid2);
591
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
592
+ const localeEntries = await strapi2.db.query(uid2).findMany({
593
+ where: {
594
+ documentId,
595
+ ...isLocalizedContentType ? { locale: { $in: locales } } : {},
596
+ ...strapiUtils.contentTypes.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
597
+ },
598
+ populate: serviceUtils.getDeepPopulate(
599
+ uid2,
600
+ true
601
+ /* use database syntax */
602
+ )
539
603
  });
540
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
541
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
542
- const componentsSchemas = Object.keys(
543
- attributesSchema
544
- ).reduce((currentComponentSchemas, key) => {
545
- const fieldSchema = attributesSchema[key];
546
- if (fieldSchema.type === "component") {
547
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
548
- return {
549
- ...currentComponentSchemas,
550
- [fieldSchema.component]: componentSchema
551
- };
552
- }
553
- return currentComponentSchemas;
554
- }, {});
555
604
  await strapi2.db.transaction(async ({ onCommit }) => {
556
- onCommit(() => {
557
- getService(strapi2, "history").createVersion({
558
- contentType: contentTypeUid,
559
- data: fp.omit(FIELDS_TO_IGNORE, document),
560
- schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
561
- componentsSchemas,
562
- relatedDocumentId: documentContext.documentId,
563
- locale,
564
- status
565
- });
605
+ onCommit(async () => {
606
+ for (const entry of localeEntries) {
607
+ const status = await serviceUtils.getVersionStatus(uid2, entry);
608
+ await getService$1(strapi2, "history").createVersion({
609
+ contentType: uid2,
610
+ data: fp.omit(FIELDS_TO_IGNORE, entry),
611
+ relatedDocumentId: documentId,
612
+ locale: entry.locale,
613
+ status,
614
+ ...schemas
615
+ });
616
+ }
566
617
  });
567
618
  });
568
619
  return result;
569
620
  });
570
- state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
621
+ state.deleteExpiredJob = nodeSchedule.scheduleJob("historyDaily", "0 0 * * *", () => {
571
622
  const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
572
623
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
573
624
  strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
574
625
  where: {
575
626
  created_at: {
576
- $lt: expirationDate.toISOString()
627
+ $lt: expirationDate
577
628
  }
578
629
  }
630
+ }).catch((error) => {
631
+ if (error instanceof Error) {
632
+ strapi2.log.error("Error deleting expired history versions", error.message);
633
+ }
579
634
  });
580
635
  });
581
636
  state.isInitialized = true;
@@ -587,17 +642,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
587
642
  }
588
643
  };
589
644
  };
590
- const services$1 = {
645
+ const services$2 = {
591
646
  history: createHistoryService,
592
647
  lifecycles: createLifecyclesService
593
648
  };
594
- const info = { pluginName: "content-manager", type: "admin" };
649
+ const info$1 = { pluginName: "content-manager", type: "admin" };
595
650
  const historyVersionRouter = {
596
651
  type: "admin",
597
652
  routes: [
598
653
  {
599
654
  method: "GET",
600
- info,
655
+ info: info$1,
601
656
  path: "/history-versions",
602
657
  handler: "history-version.findMany",
603
658
  config: {
@@ -606,7 +661,7 @@ const historyVersionRouter = {
606
661
  },
607
662
  {
608
663
  method: "PUT",
609
- info,
664
+ info: info$1,
610
665
  path: "/history-versions/:versionId/restore",
611
666
  handler: "history-version.restoreVersion",
612
667
  config: {
@@ -615,7 +670,7 @@ const historyVersionRouter = {
615
670
  }
616
671
  ]
617
672
  };
618
- const routes$1 = {
673
+ const routes$2 = {
619
674
  "history-version": historyVersionRouter
620
675
  };
621
676
  const historyVersion = {
@@ -662,21 +717,21 @@ const historyVersion = {
662
717
  }
663
718
  }
664
719
  };
665
- const getFeature = () => {
720
+ const getFeature$1 = () => {
666
721
  if (strapi.ee.features.isEnabled("cms-content-history")) {
667
722
  return {
668
723
  register({ strapi: strapi2 }) {
669
724
  strapi2.get("models").add(historyVersion);
670
725
  },
671
726
  bootstrap({ strapi: strapi2 }) {
672
- getService(strapi2, "lifecycles").bootstrap();
727
+ getService$1(strapi2, "lifecycles").bootstrap();
673
728
  },
674
729
  destroy({ strapi: strapi2 }) {
675
- getService(strapi2, "lifecycles").destroy();
730
+ getService$1(strapi2, "lifecycles").destroy();
676
731
  },
677
- controllers: controllers$1,
678
- services: services$1,
679
- routes: routes$1
732
+ controllers: controllers$2,
733
+ services: services$2,
734
+ routes: routes$2
680
735
  };
681
736
  }
682
737
  return {
@@ -685,9 +740,201 @@ const getFeature = () => {
685
740
  }
686
741
  };
687
742
  };
688
- const history = getFeature();
743
+ const history = getFeature$1();
744
+ const info = { pluginName: "content-manager", type: "admin" };
745
+ const previewRouter = {
746
+ type: "admin",
747
+ routes: [
748
+ {
749
+ method: "GET",
750
+ info,
751
+ path: "/preview/url/:contentType",
752
+ handler: "preview.getPreviewUrl",
753
+ config: {
754
+ policies: ["admin::isAuthenticatedAdmin"]
755
+ }
756
+ }
757
+ ]
758
+ };
759
+ const routes$1 = {
760
+ preview: previewRouter
761
+ };
762
+ function getService(strapi2, name) {
763
+ return strapi2.service(`plugin::content-manager.${name}`);
764
+ }
765
+ const getPreviewUrlSchema = yup__namespace.object().shape({
766
+ // Will be undefined for single types
767
+ documentId: yup__namespace.string(),
768
+ locale: yup__namespace.string().nullable(),
769
+ status: yup__namespace.string()
770
+ }).required();
771
+ const validatePreviewUrl = async (strapi2, uid2, params) => {
772
+ await strapiUtils.validateYupSchema(getPreviewUrlSchema)(params);
773
+ const newParams = fp.pick(["documentId", "locale", "status"], params);
774
+ const model = strapi2.getModel(uid2);
775
+ if (!model || model.modelType !== "contentType") {
776
+ throw new strapiUtils.errors.ValidationError("Invalid content type");
777
+ }
778
+ const isSingleType = model?.kind === "singleType";
779
+ if (!isSingleType && !params.documentId) {
780
+ throw new strapiUtils.errors.ValidationError("documentId is required for Collection Types");
781
+ }
782
+ if (isSingleType) {
783
+ const doc = await strapi2.documents(uid2).findFirst();
784
+ if (!doc) {
785
+ throw new strapiUtils.errors.NotFoundError("Document not found");
786
+ }
787
+ newParams.documentId = doc?.documentId;
788
+ }
789
+ if (!newParams.status) {
790
+ const isDPEnabled = model?.options?.draftAndPublish;
791
+ newParams.status = isDPEnabled ? "draft" : "published";
792
+ }
793
+ return newParams;
794
+ };
795
+ const createPreviewController = () => {
796
+ return {
797
+ /**
798
+ * Transforms an entry into a preview URL, so that it can be previewed
799
+ * in the Content Manager.
800
+ */
801
+ async getPreviewUrl(ctx) {
802
+ const uid2 = ctx.params.contentType;
803
+ const query = ctx.request.query;
804
+ const params = await validatePreviewUrl(strapi, uid2, query);
805
+ const previewService = getService(strapi, "preview");
806
+ const url = await previewService.getPreviewUrl(uid2, params);
807
+ if (!url) {
808
+ ctx.status = 204;
809
+ }
810
+ return {
811
+ data: { url }
812
+ };
813
+ }
814
+ };
815
+ };
816
+ const controllers$1 = {
817
+ preview: createPreviewController
818
+ /**
819
+ * Casting is needed because the types aren't aware that Strapi supports
820
+ * passing a controller factory as the value, instead of a controller object directly
821
+ */
822
+ };
823
+ const createPreviewService = ({ strapi: strapi2 }) => {
824
+ const config = getService(strapi2, "preview-config");
825
+ return {
826
+ async getPreviewUrl(uid2, params) {
827
+ const handler = config.getPreviewHandler();
828
+ try {
829
+ return handler(uid2, params);
830
+ } catch (error) {
831
+ strapi2.log.error(`Failed to get preview URL: ${error}`);
832
+ throw new strapiUtils.errors.ApplicationError("Failed to get preview URL");
833
+ }
834
+ return;
835
+ }
836
+ };
837
+ };
838
+ const extendMiddlewareConfiguration = (middleware = { name: "", config: {} }) => {
839
+ const middlewares = strapi.config.get("middlewares");
840
+ const configuredMiddlewares = middlewares.map((currentMiddleware) => {
841
+ if (currentMiddleware === middleware.name) {
842
+ return middleware;
843
+ }
844
+ if (currentMiddleware.name === middleware.name) {
845
+ return fp.mergeWith(
846
+ (objValue, srcValue) => {
847
+ if (Array.isArray(objValue)) {
848
+ return objValue.concat(srcValue);
849
+ }
850
+ return void 0;
851
+ },
852
+ currentMiddleware,
853
+ middleware
854
+ );
855
+ }
856
+ return currentMiddleware;
857
+ });
858
+ strapi.config.set("middlewares", configuredMiddlewares);
859
+ };
860
+ const createPreviewConfigService = ({ strapi: strapi2 }) => {
861
+ return {
862
+ register() {
863
+ if (!this.isEnabled()) {
864
+ return;
865
+ }
866
+ const config = strapi2.config.get("admin.preview");
867
+ if (config.config?.allowedOrigins) {
868
+ extendMiddlewareConfiguration({
869
+ name: "strapi::security",
870
+ config: {
871
+ contentSecurityPolicy: {
872
+ directives: {
873
+ "frame-src": config.config.allowedOrigins
874
+ }
875
+ }
876
+ }
877
+ });
878
+ }
879
+ },
880
+ isEnabled() {
881
+ const config = strapi2.config.get("admin.preview");
882
+ if (!config) {
883
+ return false;
884
+ }
885
+ return config?.enabled ?? true;
886
+ },
887
+ /**
888
+ * Validate if the configuration is valid
889
+ */
890
+ validate() {
891
+ if (!this.isEnabled()) {
892
+ return;
893
+ }
894
+ const handler = this.getPreviewHandler();
895
+ if (typeof handler !== "function") {
896
+ throw new strapiUtils.errors.ValidationError(
897
+ "Preview configuration is invalid. Handler must be a function"
898
+ );
899
+ }
900
+ },
901
+ /**
902
+ * Utility to get the preview handler from the configuration
903
+ */
904
+ getPreviewHandler() {
905
+ const config = strapi2.config.get("admin.preview");
906
+ const emptyHandler = () => {
907
+ return void 0;
908
+ };
909
+ if (!this.isEnabled()) {
910
+ return emptyHandler;
911
+ }
912
+ return config?.config?.handler || emptyHandler;
913
+ }
914
+ };
915
+ };
916
+ const services$1 = {
917
+ preview: createPreviewService,
918
+ "preview-config": createPreviewConfigService
919
+ };
920
+ const getFeature = () => {
921
+ return {
922
+ register() {
923
+ const config = getService(strapi, "preview-config");
924
+ config.validate();
925
+ config.register();
926
+ },
927
+ bootstrap() {
928
+ },
929
+ routes: routes$1,
930
+ controllers: controllers$1,
931
+ services: services$1
932
+ };
933
+ };
934
+ const preview = getFeature();
689
935
  const register = async ({ strapi: strapi2 }) => {
690
936
  await history.register?.({ strapi: strapi2 });
937
+ await preview.register?.({ strapi: strapi2 });
691
938
  };
692
939
  const ALLOWED_WEBHOOK_EVENTS = {
693
940
  ENTRY_PUBLISH: "entry.publish",
@@ -697,11 +944,12 @@ const bootstrap = async () => {
697
944
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
698
945
  strapi.get("webhookStore").addAllowedEvent(key, value);
699
946
  });
700
- getService$1("field-sizes").setCustomFieldInputSizes();
701
- await getService$1("components").syncConfigurations();
702
- await getService$1("content-types").syncConfigurations();
703
- await getService$1("permission").registerPermissions();
947
+ getService$2("field-sizes").setCustomFieldInputSizes();
948
+ await getService$2("components").syncConfigurations();
949
+ await getService$2("content-types").syncConfigurations();
950
+ await getService$2("permission").registerPermissions();
704
951
  await history.bootstrap?.({ strapi });
952
+ await preview.bootstrap?.({ strapi });
705
953
  };
706
954
  const destroy = async ({ strapi: strapi2 }) => {
707
955
  await history.destroy?.({ strapi: strapi2 });
@@ -1191,7 +1439,8 @@ const admin = {
1191
1439
  };
1192
1440
  const routes = {
1193
1441
  admin,
1194
- ...history.routes ? history.routes : {}
1442
+ ...history.routes ? history.routes : {},
1443
+ ...preview.routes ? preview.routes : {}
1195
1444
  };
1196
1445
  const hasPermissionsSchema = strapiUtils.yup.object({
1197
1446
  actions: strapiUtils.yup.array().of(strapiUtils.yup.string()),
@@ -1202,6 +1451,11 @@ const { createPolicy } = strapiUtils.policy;
1202
1451
  const hasPermissions = createPolicy({
1203
1452
  name: "plugin::content-manager.hasPermissions",
1204
1453
  validator: validateHasPermissionsInput,
1454
+ /**
1455
+ * NOTE: Action aliases are currently not checked at this level (policy).
1456
+ * This is currently the intended behavior to avoid changing the behavior of API related permissions.
1457
+ * If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
1458
+ */
1205
1459
  handler(ctx, config = {}) {
1206
1460
  const { actions = [], hasAtLeastOne = false } = config;
1207
1461
  const { userAbility } = ctx.state;
@@ -1249,8 +1503,7 @@ const isSortable = (schema, name) => {
1249
1503
  if (!___default.default.has(schema.attributes, name)) {
1250
1504
  return false;
1251
1505
  }
1252
- if (schema.modelType === "component" && name === "id")
1253
- return false;
1506
+ if (schema.modelType === "component" && name === "id") return false;
1254
1507
  const attribute = schema.attributes[name];
1255
1508
  if (NON_SORTABLES.includes(attribute.type)) {
1256
1509
  return false;
@@ -1395,8 +1648,7 @@ const createDefaultSettings = async (schema) => {
1395
1648
  };
1396
1649
  };
1397
1650
  const syncSettings = async (configuration, schema) => {
1398
- if (fp.isEmpty(configuration.settings))
1399
- return createDefaultSettings(schema);
1651
+ if (fp.isEmpty(configuration.settings)) return createDefaultSettings(schema);
1400
1652
  const defaultField = getDefaultMainField(schema);
1401
1653
  const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
1402
1654
  return {
@@ -1443,7 +1695,7 @@ const createMetadasSchema = (schema) => {
1443
1695
  if (!value) {
1444
1696
  return strapiUtils.yup.string();
1445
1697
  }
1446
- const targetSchema = getService$1("content-types").findContentType(
1698
+ const targetSchema = getService$2("content-types").findContentType(
1447
1699
  schema.attributes[key].targetModel
1448
1700
  );
1449
1701
  if (!targetSchema) {
@@ -1572,8 +1824,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1572
1824
  }
1573
1825
  switch (attribute.type) {
1574
1826
  case "relation": {
1575
- if (canCreate(attributePath))
1576
- return body2;
1827
+ if (canCreate(attributePath)) return body2;
1577
1828
  return fp.set(attributePath, { set: [] }, body2);
1578
1829
  }
1579
1830
  case "component": {
@@ -1583,8 +1834,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1583
1834
  ]);
1584
1835
  }
1585
1836
  default: {
1586
- if (canCreate(attributePath))
1587
- return body2;
1837
+ if (canCreate(attributePath)) return body2;
1588
1838
  return fp.set(attributePath, null, body2);
1589
1839
  }
1590
1840
  }
@@ -1612,7 +1862,7 @@ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultiple
1612
1862
  }
1613
1863
  };
1614
1864
  const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1615
- const documentMetadata2 = getService$1("document-metadata");
1865
+ const documentMetadata2 = getService$2("document-metadata");
1616
1866
  const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1617
1867
  let {
1618
1868
  meta: { availableLocales, availableStatus }
@@ -1638,8 +1888,8 @@ const createDocument = async (ctx, opts) => {
1638
1888
  const { userAbility, user } = ctx.state;
1639
1889
  const { model } = ctx.params;
1640
1890
  const { body } = ctx.request;
1641
- const documentManager2 = getService$1("document-manager");
1642
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1891
+ const documentManager2 = getService$2("document-manager");
1892
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1643
1893
  if (permissionChecker2.cannot.create()) {
1644
1894
  throw new strapiUtils.errors.ForbiddenError();
1645
1895
  }
@@ -1659,13 +1909,13 @@ const updateDocument = async (ctx, opts) => {
1659
1909
  const { userAbility, user } = ctx.state;
1660
1910
  const { id, model } = ctx.params;
1661
1911
  const { body } = ctx.request;
1662
- const documentManager2 = getService$1("document-manager");
1663
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1912
+ const documentManager2 = getService$2("document-manager");
1913
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1664
1914
  if (permissionChecker2.cannot.update()) {
1665
1915
  throw new strapiUtils.errors.ForbiddenError();
1666
1916
  }
1667
1917
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1668
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1918
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1669
1919
  const { locale } = await getDocumentLocaleAndStatus(body, model);
1670
1920
  const [documentVersion, documentExists] = await Promise.all([
1671
1921
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
@@ -1682,7 +1932,7 @@ const updateDocument = async (ctx, opts) => {
1682
1932
  throw new strapiUtils.errors.ForbiddenError();
1683
1933
  }
1684
1934
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1685
- const setCreator = strapiUtils.setCreatorFields({ user, isEdition: true });
1935
+ const setCreator = documentVersion ? strapiUtils.setCreatorFields({ user, isEdition: true }) : strapiUtils.setCreatorFields({ user });
1686
1936
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1687
1937
  const sanitizedBody = await sanitizeFn(body);
1688
1938
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1696,14 +1946,14 @@ const collectionTypes = {
1696
1946
  const { userAbility } = ctx.state;
1697
1947
  const { model } = ctx.params;
1698
1948
  const { query } = ctx.request;
1699
- const documentMetadata2 = getService$1("document-metadata");
1700
- const documentManager2 = getService$1("document-manager");
1701
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1949
+ const documentMetadata2 = getService$2("document-metadata");
1950
+ const documentManager2 = getService$2("document-manager");
1951
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1702
1952
  if (permissionChecker2.cannot.read()) {
1703
1953
  return ctx.forbidden();
1704
1954
  }
1705
1955
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1706
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1956
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1707
1957
  const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1708
1958
  const { results: documents, pagination } = await documentManager2.findPage(
1709
1959
  { ...permissionQuery, populate, locale, status },
@@ -1732,13 +1982,13 @@ const collectionTypes = {
1732
1982
  async findOne(ctx) {
1733
1983
  const { userAbility } = ctx.state;
1734
1984
  const { model, id } = ctx.params;
1735
- const documentManager2 = getService$1("document-manager");
1736
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1985
+ const documentManager2 = getService$2("document-manager");
1986
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1737
1987
  if (permissionChecker2.cannot.read()) {
1738
1988
  return ctx.forbidden();
1739
1989
  }
1740
1990
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1741
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1991
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1742
1992
  const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1743
1993
  const version = await documentManager2.findOne(id, model, {
1744
1994
  populate,
@@ -1754,7 +2004,7 @@ const collectionTypes = {
1754
2004
  permissionChecker2,
1755
2005
  model,
1756
2006
  // @ts-expect-error TODO: fix
1757
- { id, locale, publishedAt: null },
2007
+ { documentId: id, locale, publishedAt: null },
1758
2008
  { availableLocales: true, availableStatus: false }
1759
2009
  );
1760
2010
  ctx.body = { data: {}, meta };
@@ -1769,7 +2019,7 @@ const collectionTypes = {
1769
2019
  async create(ctx) {
1770
2020
  const { userAbility } = ctx.state;
1771
2021
  const { model } = ctx.params;
1772
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2022
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1773
2023
  const [totalEntries, document] = await Promise.all([
1774
2024
  strapi.db.query(model).count(),
1775
2025
  createDocument(ctx)
@@ -1790,7 +2040,7 @@ const collectionTypes = {
1790
2040
  async update(ctx) {
1791
2041
  const { userAbility } = ctx.state;
1792
2042
  const { model } = ctx.params;
1793
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2043
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1794
2044
  const updatedVersion = await updateDocument(ctx);
1795
2045
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1796
2046
  ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
@@ -1799,13 +2049,13 @@ const collectionTypes = {
1799
2049
  const { userAbility, user } = ctx.state;
1800
2050
  const { model, sourceId: id } = ctx.params;
1801
2051
  const { body } = ctx.request;
1802
- const documentManager2 = getService$1("document-manager");
1803
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2052
+ const documentManager2 = getService$2("document-manager");
2053
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1804
2054
  if (permissionChecker2.cannot.create()) {
1805
2055
  return ctx.forbidden();
1806
2056
  }
1807
2057
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1808
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2058
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1809
2059
  const { locale } = await getDocumentLocaleAndStatus(body, model);
1810
2060
  const document = await documentManager2.findOne(id, model, {
1811
2061
  populate,
@@ -1844,13 +2094,13 @@ const collectionTypes = {
1844
2094
  async delete(ctx) {
1845
2095
  const { userAbility } = ctx.state;
1846
2096
  const { id, model } = ctx.params;
1847
- const documentManager2 = getService$1("document-manager");
1848
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2097
+ const documentManager2 = getService$2("document-manager");
2098
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1849
2099
  if (permissionChecker2.cannot.delete()) {
1850
2100
  return ctx.forbidden();
1851
2101
  }
1852
2102
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1853
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2103
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1854
2104
  const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1855
2105
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1856
2106
  if (documentLocales.length === 0) {
@@ -1872,19 +2122,42 @@ const collectionTypes = {
1872
2122
  const { userAbility } = ctx.state;
1873
2123
  const { id, model } = ctx.params;
1874
2124
  const { body } = ctx.request;
1875
- const documentManager2 = getService$1("document-manager");
1876
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2125
+ const documentManager2 = getService$2("document-manager");
2126
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1877
2127
  if (permissionChecker2.cannot.publish()) {
1878
2128
  return ctx.forbidden();
1879
2129
  }
1880
2130
  const publishedDocument = await strapi.db.transaction(async () => {
1881
2131
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1882
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1883
- const document = id ? await updateDocument(ctx, { populate }) : await createDocument(ctx, { populate });
2132
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2133
+ let document;
2134
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2135
+ const isCreate = fp.isNil(id);
2136
+ if (isCreate) {
2137
+ if (permissionChecker2.cannot.create()) {
2138
+ throw new strapiUtils.errors.ForbiddenError();
2139
+ }
2140
+ document = await createDocument(ctx, { populate });
2141
+ }
2142
+ const isUpdate = !isCreate;
2143
+ if (isUpdate) {
2144
+ const documentExists = documentManager2.exists(model, id);
2145
+ if (!documentExists) {
2146
+ throw new strapiUtils.errors.NotFoundError("Document not found");
2147
+ }
2148
+ document = await documentManager2.findOne(id, model, { populate, locale });
2149
+ if (!document) {
2150
+ if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
2151
+ throw new strapiUtils.errors.ForbiddenError();
2152
+ }
2153
+ document = await updateDocument(ctx);
2154
+ } else if (permissionChecker2.can.update(document)) {
2155
+ await updateDocument(ctx);
2156
+ }
2157
+ }
1884
2158
  if (permissionChecker2.cannot.publish(document)) {
1885
2159
  throw new strapiUtils.errors.ForbiddenError();
1886
2160
  }
1887
- const { locale } = await getDocumentLocaleAndStatus(body, model);
1888
2161
  const publishResult = await documentManager2.publish(document.documentId, model, {
1889
2162
  locale
1890
2163
  // TODO: Allow setting creator fields on publish
@@ -1904,13 +2177,13 @@ const collectionTypes = {
1904
2177
  const { body } = ctx.request;
1905
2178
  const { documentIds } = body;
1906
2179
  await validateBulkActionInput(body);
1907
- const documentManager2 = getService$1("document-manager");
1908
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2180
+ const documentManager2 = getService$2("document-manager");
2181
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1909
2182
  if (permissionChecker2.cannot.publish()) {
1910
2183
  return ctx.forbidden();
1911
2184
  }
1912
2185
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1913
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2186
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1914
2187
  const { locale } = await getDocumentLocaleAndStatus(body, model, {
1915
2188
  allowMultipleLocales: true
1916
2189
  });
@@ -1935,12 +2208,14 @@ const collectionTypes = {
1935
2208
  const { body } = ctx.request;
1936
2209
  const { documentIds } = body;
1937
2210
  await validateBulkActionInput(body);
1938
- const documentManager2 = getService$1("document-manager");
1939
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2211
+ const documentManager2 = getService$2("document-manager");
2212
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1940
2213
  if (permissionChecker2.cannot.unpublish()) {
1941
2214
  return ctx.forbidden();
1942
2215
  }
1943
- const { locale } = await getDocumentLocaleAndStatus(body, model);
2216
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2217
+ allowMultipleLocales: true
2218
+ });
1944
2219
  const entityPromises = documentIds.map(
1945
2220
  (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1946
2221
  );
@@ -1963,8 +2238,8 @@ const collectionTypes = {
1963
2238
  const {
1964
2239
  body: { discardDraft, ...body }
1965
2240
  } = ctx.request;
1966
- const documentManager2 = getService$1("document-manager");
1967
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2241
+ const documentManager2 = getService$2("document-manager");
2242
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1968
2243
  if (permissionChecker2.cannot.unpublish()) {
1969
2244
  return ctx.forbidden();
1970
2245
  }
@@ -1972,7 +2247,7 @@ const collectionTypes = {
1972
2247
  return ctx.forbidden();
1973
2248
  }
1974
2249
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1975
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2250
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1976
2251
  const { locale } = await getDocumentLocaleAndStatus(body, model);
1977
2252
  const document = await documentManager2.findOne(id, model, {
1978
2253
  populate,
@@ -2003,13 +2278,13 @@ const collectionTypes = {
2003
2278
  const { userAbility } = ctx.state;
2004
2279
  const { id, model } = ctx.params;
2005
2280
  const { body } = ctx.request;
2006
- const documentManager2 = getService$1("document-manager");
2007
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2281
+ const documentManager2 = getService$2("document-manager");
2282
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2008
2283
  if (permissionChecker2.cannot.discard()) {
2009
2284
  return ctx.forbidden();
2010
2285
  }
2011
2286
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
2012
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2287
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2013
2288
  const { locale } = await getDocumentLocaleAndStatus(body, model);
2014
2289
  const document = await documentManager2.findOne(id, model, {
2015
2290
  populate,
@@ -2034,13 +2309,13 @@ const collectionTypes = {
2034
2309
  const { query, body } = ctx.request;
2035
2310
  const { documentIds } = body;
2036
2311
  await validateBulkActionInput(body);
2037
- const documentManager2 = getService$1("document-manager");
2038
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2312
+ const documentManager2 = getService$2("document-manager");
2313
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2039
2314
  if (permissionChecker2.cannot.delete()) {
2040
2315
  return ctx.forbidden();
2041
2316
  }
2042
2317
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
2043
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2318
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2044
2319
  const { locale } = await getDocumentLocaleAndStatus(body, model);
2045
2320
  const documentLocales = await documentManager2.findLocales(documentIds, model, {
2046
2321
  populate,
@@ -2061,13 +2336,13 @@ const collectionTypes = {
2061
2336
  async countDraftRelations(ctx) {
2062
2337
  const { userAbility } = ctx.state;
2063
2338
  const { model, id } = ctx.params;
2064
- const documentManager2 = getService$1("document-manager");
2065
- 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 });
2066
2341
  if (permissionChecker2.cannot.read()) {
2067
2342
  return ctx.forbidden();
2068
2343
  }
2069
2344
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2070
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2345
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2071
2346
  const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
2072
2347
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2073
2348
  if (!entity) {
@@ -2086,8 +2361,8 @@ const collectionTypes = {
2086
2361
  const ids = ctx.request.query.documentIds;
2087
2362
  const locale = ctx.request.query.locale;
2088
2363
  const { model } = ctx.params;
2089
- const documentManager2 = getService$1("document-manager");
2090
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2364
+ const documentManager2 = getService$2("document-manager");
2365
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2091
2366
  if (permissionChecker2.cannot.read()) {
2092
2367
  return ctx.forbidden();
2093
2368
  }
@@ -2111,13 +2386,13 @@ const collectionTypes = {
2111
2386
  };
2112
2387
  const components$1 = {
2113
2388
  findComponents(ctx) {
2114
- const components2 = getService$1("components").findAllComponents();
2115
- const { toDto } = getService$1("data-mapper");
2389
+ const components2 = getService$2("components").findAllComponents();
2390
+ const { toDto } = getService$2("data-mapper");
2116
2391
  ctx.body = { data: components2.map(toDto) };
2117
2392
  },
2118
2393
  async findComponentConfiguration(ctx) {
2119
2394
  const { uid: uid2 } = ctx.params;
2120
- const componentService = getService$1("components");
2395
+ const componentService = getService$2("components");
2121
2396
  const component = componentService.findComponent(uid2);
2122
2397
  if (!component) {
2123
2398
  return ctx.notFound("component.notFound");
@@ -2134,7 +2409,7 @@ const components$1 = {
2134
2409
  async updateComponentConfiguration(ctx) {
2135
2410
  const { uid: uid2 } = ctx.params;
2136
2411
  const { body } = ctx.request;
2137
- const componentService = getService$1("components");
2412
+ const componentService = getService$2("components");
2138
2413
  const component = componentService.findComponent(uid2);
2139
2414
  if (!component) {
2140
2415
  return ctx.notFound("component.notFound");
@@ -2168,12 +2443,12 @@ const contentTypes = {
2168
2443
  } catch (error) {
2169
2444
  return ctx.send({ error }, 400);
2170
2445
  }
2171
- const contentTypes2 = getService$1("content-types").findContentTypesByKind(kind);
2172
- const { toDto } = getService$1("data-mapper");
2446
+ const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
2447
+ const { toDto } = getService$2("data-mapper");
2173
2448
  ctx.body = { data: contentTypes2.map(toDto) };
2174
2449
  },
2175
2450
  async findContentTypesSettings(ctx) {
2176
- const { findAllContentTypes, findConfiguration } = getService$1("content-types");
2451
+ const { findAllContentTypes, findConfiguration } = getService$2("content-types");
2177
2452
  const contentTypes2 = await findAllContentTypes();
2178
2453
  const configurations = await Promise.all(
2179
2454
  contentTypes2.map(async (contentType) => {
@@ -2187,7 +2462,7 @@ const contentTypes = {
2187
2462
  },
2188
2463
  async findContentTypeConfiguration(ctx) {
2189
2464
  const { uid: uid2 } = ctx.params;
2190
- const contentTypeService = getService$1("content-types");
2465
+ const contentTypeService = getService$2("content-types");
2191
2466
  const contentType = await contentTypeService.findContentType(uid2);
2192
2467
  if (!contentType) {
2193
2468
  return ctx.notFound("contentType.notFound");
@@ -2209,13 +2484,13 @@ const contentTypes = {
2209
2484
  const { userAbility } = ctx.state;
2210
2485
  const { uid: uid2 } = ctx.params;
2211
2486
  const { body } = ctx.request;
2212
- const contentTypeService = getService$1("content-types");
2213
- const metricsService = getService$1("metrics");
2487
+ const contentTypeService = getService$2("content-types");
2488
+ const metricsService = getService$2("metrics");
2214
2489
  const contentType = await contentTypeService.findContentType(uid2);
2215
2490
  if (!contentType) {
2216
2491
  return ctx.notFound("contentType.notFound");
2217
2492
  }
2218
- if (!getService$1("permission").canConfigureContentType({ userAbility, contentType })) {
2493
+ if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
2219
2494
  return ctx.forbidden();
2220
2495
  }
2221
2496
  let input;
@@ -2248,10 +2523,10 @@ const contentTypes = {
2248
2523
  };
2249
2524
  const init = {
2250
2525
  getInitData(ctx) {
2251
- const { toDto } = getService$1("data-mapper");
2252
- const { findAllComponents } = getService$1("components");
2253
- const { getAllFieldSizes } = getService$1("field-sizes");
2254
- const { findAllContentTypes } = getService$1("content-types");
2526
+ const { toDto } = getService$2("data-mapper");
2527
+ const { findAllComponents } = getService$2("components");
2528
+ const { getAllFieldSizes } = getService$2("field-sizes");
2529
+ const { findAllContentTypes } = getService$2("content-types");
2255
2530
  ctx.body = {
2256
2531
  data: {
2257
2532
  fieldSizes: getAllFieldSizes(),
@@ -2287,36 +2562,41 @@ const addFiltersClause = (params, filtersClause) => {
2287
2562
  params.filters.$and.push(filtersClause);
2288
2563
  };
2289
2564
  const sanitizeMainField = (model, mainField, userAbility) => {
2290
- const permissionChecker2 = getService$1("permission-checker").create({
2565
+ const permissionChecker2 = getService$2("permission-checker").create({
2291
2566
  userAbility,
2292
2567
  model: model.uid
2293
2568
  });
2294
- if (!isListable(model, mainField)) {
2569
+ const isMainFieldListable = isListable(model, mainField);
2570
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2571
+ if (!isMainFieldListable || !canReadMainField) {
2295
2572
  return "id";
2296
2573
  }
2297
- if (permissionChecker2.cannot.read(null, mainField)) {
2298
- if (model.uid === "plugin::users-permissions.role") {
2299
- const userPermissionChecker = getService$1("permission-checker").create({
2300
- userAbility,
2301
- model: "plugin::users-permissions.user"
2302
- });
2303
- if (userPermissionChecker.can.read()) {
2304
- return "name";
2305
- }
2306
- }
2307
- return "id";
2574
+ if (model.uid === "plugin::users-permissions.role") {
2575
+ return "name";
2308
2576
  }
2309
2577
  return mainField;
2310
2578
  };
2311
- const addStatusToRelations = async (uid2, relations2) => {
2312
- if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.contentTypes[uid2])) {
2579
+ const addStatusToRelations = async (targetUid, relations2) => {
2580
+ if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(targetUid))) {
2313
2581
  return relations2;
2314
2582
  }
2315
- const documentMetadata2 = getService$1("document-metadata");
2316
- const documentsAvailableStatus = await documentMetadata2.getManyAvailableStatus(uid2, relations2);
2583
+ const documentMetadata2 = getService$2("document-metadata");
2584
+ if (!relations2.length) {
2585
+ return relations2;
2586
+ }
2587
+ const firstRelation = relations2[0];
2588
+ const filters = {
2589
+ documentId: { $in: relations2.map((r) => r.documentId) },
2590
+ // NOTE: find the "opposite" status
2591
+ publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
2592
+ };
2593
+ const availableStatus = await strapi.query(targetUid).findMany({
2594
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
2595
+ filters
2596
+ });
2317
2597
  return relations2.map((relation) => {
2318
- const availableStatuses = documentsAvailableStatus.filter(
2319
- (availableDocument) => availableDocument.documentId === relation.documentId
2598
+ const availableStatuses = availableStatus.filter(
2599
+ (availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
2320
2600
  );
2321
2601
  return {
2322
2602
  ...relation,
@@ -2337,11 +2617,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2337
2617
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2338
2618
  const isSourceLocalized = isLocalized(sourceModel);
2339
2619
  const isTargetLocalized = isLocalized(targetModel);
2340
- let validatedLocale = locale;
2341
- if (!targetModel || !isTargetLocalized)
2342
- validatedLocale = void 0;
2343
2620
  return {
2344
- locale: validatedLocale,
2621
+ locale,
2345
2622
  isSourceLocalized,
2346
2623
  isTargetLocalized
2347
2624
  };
@@ -2350,8 +2627,7 @@ const validateStatus = (sourceUid, status) => {
2350
2627
  const sourceModel = strapi.getModel(sourceUid);
2351
2628
  const isDP = strapiUtils.contentTypes.hasDraftAndPublish;
2352
2629
  const isSourceDP = isDP(sourceModel);
2353
- if (!isSourceDP)
2354
- return { status: void 0 };
2630
+ if (!isSourceDP) return { status: void 0 };
2355
2631
  switch (status) {
2356
2632
  case "published":
2357
2633
  return { status: "published" };
@@ -2381,7 +2657,7 @@ const relations = {
2381
2657
  ctx.request?.query?.locale
2382
2658
  );
2383
2659
  const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
2384
- const permissionChecker2 = getService$1("permission-checker").create({
2660
+ const permissionChecker2 = getService$2("permission-checker").create({
2385
2661
  userAbility,
2386
2662
  model
2387
2663
  });
@@ -2406,7 +2682,7 @@ const relations = {
2406
2682
  where.id = id;
2407
2683
  }
2408
2684
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2409
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2685
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2410
2686
  const currentEntity = await strapi.db.query(model).findOne({
2411
2687
  where,
2412
2688
  populate
@@ -2421,7 +2697,7 @@ const relations = {
2421
2697
  }
2422
2698
  entryId = currentEntity.id;
2423
2699
  }
2424
- const modelConfig = isComponent2 ? await getService$1("components").findConfiguration(sourceSchema) : await getService$1("content-types").findConfiguration(sourceSchema);
2700
+ const modelConfig = isComponent2 ? await getService$2("components").findConfiguration(sourceSchema) : await getService$2("content-types").findConfiguration(sourceSchema);
2425
2701
  const targetSchema = strapi.getModel(targetUid);
2426
2702
  const mainField = fp.flow(
2427
2703
  fp.prop(`metadatas.${targetField}.edit.mainField`),
@@ -2444,7 +2720,7 @@ const relations = {
2444
2720
  attribute,
2445
2721
  fieldsToSelect,
2446
2722
  mainField,
2447
- source: { schema: sourceSchema },
2723
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2448
2724
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2449
2725
  sourceSchema,
2450
2726
  targetSchema,
@@ -2466,7 +2742,8 @@ const relations = {
2466
2742
  fieldsToSelect,
2467
2743
  mainField,
2468
2744
  source: {
2469
- schema: { uid: sourceUid, modelType: sourceModelType }
2745
+ schema: { uid: sourceUid, modelType: sourceModelType },
2746
+ isLocalized: isSourceLocalized
2470
2747
  },
2471
2748
  target: {
2472
2749
  schema: { uid: targetUid },
@@ -2474,7 +2751,7 @@ const relations = {
2474
2751
  }
2475
2752
  } = await this.extractAndValidateRequestInfo(ctx, id);
2476
2753
  const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
2477
- const permissionChecker2 = getService$1("permission-checker").create({
2754
+ const permissionChecker2 = getService$2("permission-checker").create({
2478
2755
  userAbility: ctx.state.userAbility,
2479
2756
  model: targetUid
2480
2757
  });
@@ -2504,12 +2781,16 @@ const relations = {
2504
2781
  } else {
2505
2782
  where.id = id;
2506
2783
  }
2507
- if (status) {
2508
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2784
+ const publishedAt = getPublishedAtClause(status, targetUid);
2785
+ if (!fp.isEmpty(publishedAt)) {
2786
+ where[`${alias}.published_at`] = publishedAt;
2509
2787
  }
2510
- if (filterByLocale) {
2788
+ if (isTargetLocalized && locale) {
2511
2789
  where[`${alias}.locale`] = locale;
2512
2790
  }
2791
+ if (isSourceLocalized && locale) {
2792
+ where.locale = locale;
2793
+ }
2513
2794
  if ((idsToInclude?.length ?? 0) !== 0) {
2514
2795
  where[`${alias}.id`].$notIn = idsToInclude;
2515
2796
  }
@@ -2527,7 +2808,8 @@ const relations = {
2527
2808
  id: { $notIn: fp.uniq(idsToOmit) }
2528
2809
  });
2529
2810
  }
2530
- const res = await strapi.db.query(targetUid).findPage(strapi.get("query-params").transform(targetUid, queryParams));
2811
+ const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
2812
+ const res = await strapi.db.query(targetUid).findPage(dbQuery);
2531
2813
  ctx.body = {
2532
2814
  ...res,
2533
2815
  results: await addStatusToRelations(targetUid, res.results)
@@ -2542,29 +2824,39 @@ const relations = {
2542
2824
  attribute,
2543
2825
  targetField,
2544
2826
  fieldsToSelect,
2545
- source: {
2546
- schema: { uid: sourceUid }
2547
- },
2548
- target: {
2549
- schema: { uid: targetUid }
2550
- }
2827
+ status,
2828
+ source: { schema: sourceSchema },
2829
+ target: { schema: targetSchema }
2551
2830
  } = await this.extractAndValidateRequestInfo(ctx, id);
2552
- const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2831
+ const { uid: sourceUid } = sourceSchema;
2832
+ const { uid: targetUid } = targetSchema;
2833
+ const permissionQuery = await getService$2("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2553
2834
  const dbQuery = strapi.db.query(sourceUid);
2554
2835
  const loadRelations = strapiUtils.relations.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
2836
+ const filters = {};
2837
+ if (sourceSchema?.options?.draftAndPublish) {
2838
+ if (targetSchema?.options?.draftAndPublish) {
2839
+ if (status === "published") {
2840
+ filters.publishedAt = { $notNull: true };
2841
+ } else {
2842
+ filters.publishedAt = { $null: true };
2843
+ }
2844
+ }
2845
+ } else if (targetSchema?.options?.draftAndPublish) {
2846
+ filters.publishedAt = { $null: true };
2847
+ }
2555
2848
  const res = await loadRelations({ id: entryId }, targetField, {
2556
- select: ["id", "documentId", "locale", "publishedAt"],
2849
+ select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
2557
2850
  ordering: "desc",
2558
2851
  page: ctx.request.query.page,
2559
- pageSize: ctx.request.query.pageSize
2852
+ pageSize: ctx.request.query.pageSize,
2853
+ filters
2560
2854
  });
2561
2855
  const loadedIds = res.results.map((item) => item.id);
2562
2856
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2563
2857
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2564
2858
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2565
- ordering: "desc",
2566
- page: ctx.request.query.page,
2567
- pageSize: ctx.request.query.pageSize
2859
+ ordering: "desc"
2568
2860
  });
2569
2861
  const relationsUnion = fp.uniqBy("id", fp.concat(sanitizedRes.results, res.results));
2570
2862
  ctx.body = {
@@ -2579,10 +2871,10 @@ const relations = {
2579
2871
  }
2580
2872
  };
2581
2873
  const buildPopulateFromQuery = async (query, model) => {
2582
- return getService$1("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2874
+ return getService$2("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2583
2875
  };
2584
2876
  const findDocument = async (query, uid2, opts = {}) => {
2585
- const documentManager2 = getService$1("document-manager");
2877
+ const documentManager2 = getService$2("document-manager");
2586
2878
  const populate = await buildPopulateFromQuery(query, uid2);
2587
2879
  return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
2588
2880
  };
@@ -2590,8 +2882,8 @@ const createOrUpdateDocument = async (ctx, opts) => {
2590
2882
  const { user, userAbility } = ctx.state;
2591
2883
  const { model } = ctx.params;
2592
2884
  const { body, query } = ctx.request;
2593
- const documentManager2 = getService$1("document-manager");
2594
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2885
+ const documentManager2 = getService$2("document-manager");
2886
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2595
2887
  if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
2596
2888
  throw new strapiUtils.errors.ForbiddenError();
2597
2889
  }
@@ -2632,7 +2924,7 @@ const singleTypes = {
2632
2924
  const { userAbility } = ctx.state;
2633
2925
  const { model } = ctx.params;
2634
2926
  const { query = {} } = ctx.request;
2635
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2927
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2636
2928
  if (permissionChecker2.cannot.read()) {
2637
2929
  return ctx.forbidden();
2638
2930
  }
@@ -2651,7 +2943,7 @@ const singleTypes = {
2651
2943
  permissionChecker2,
2652
2944
  model,
2653
2945
  // @ts-expect-error - fix types
2654
- { id: document.documentId, locale, publishedAt: null },
2946
+ { documentId: document.documentId, locale, publishedAt: null },
2655
2947
  { availableLocales: true, availableStatus: false }
2656
2948
  );
2657
2949
  ctx.body = { data: {}, meta };
@@ -2666,7 +2958,7 @@ const singleTypes = {
2666
2958
  async createOrUpdate(ctx) {
2667
2959
  const { userAbility } = ctx.state;
2668
2960
  const { model } = ctx.params;
2669
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2961
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2670
2962
  const document = await createOrUpdateDocument(ctx);
2671
2963
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2672
2964
  ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
@@ -2675,8 +2967,8 @@ const singleTypes = {
2675
2967
  const { userAbility } = ctx.state;
2676
2968
  const { model } = ctx.params;
2677
2969
  const { query = {} } = ctx.request;
2678
- const documentManager2 = getService$1("document-manager");
2679
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2970
+ const documentManager2 = getService$2("document-manager");
2971
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2680
2972
  if (permissionChecker2.cannot.delete()) {
2681
2973
  return ctx.forbidden();
2682
2974
  }
@@ -2704,8 +2996,8 @@ const singleTypes = {
2704
2996
  const { userAbility } = ctx.state;
2705
2997
  const { model } = ctx.params;
2706
2998
  const { query = {} } = ctx.request;
2707
- const documentManager2 = getService$1("document-manager");
2708
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2999
+ const documentManager2 = getService$2("document-manager");
3000
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2709
3001
  if (permissionChecker2.cannot.publish()) {
2710
3002
  return ctx.forbidden();
2711
3003
  }
@@ -2733,8 +3025,8 @@ const singleTypes = {
2733
3025
  body: { discardDraft, ...body },
2734
3026
  query = {}
2735
3027
  } = ctx.request;
2736
- const documentManager2 = getService$1("document-manager");
2737
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3028
+ const documentManager2 = getService$2("document-manager");
3029
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2738
3030
  if (permissionChecker2.cannot.unpublish()) {
2739
3031
  return ctx.forbidden();
2740
3032
  }
@@ -2768,8 +3060,8 @@ const singleTypes = {
2768
3060
  const { userAbility } = ctx.state;
2769
3061
  const { model } = ctx.params;
2770
3062
  const { body, query = {} } = ctx.request;
2771
- const documentManager2 = getService$1("document-manager");
2772
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3063
+ const documentManager2 = getService$2("document-manager");
3064
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2773
3065
  if (permissionChecker2.cannot.discard()) {
2774
3066
  return ctx.forbidden();
2775
3067
  }
@@ -2792,8 +3084,8 @@ const singleTypes = {
2792
3084
  const { userAbility } = ctx.state;
2793
3085
  const { model } = ctx.params;
2794
3086
  const { query } = ctx.request;
2795
- const documentManager2 = getService$1("document-manager");
2796
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3087
+ const documentManager2 = getService$2("document-manager");
3088
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2797
3089
  const { locale } = await getDocumentLocaleAndStatus(query, model);
2798
3090
  if (permissionChecker2.cannot.read()) {
2799
3091
  return ctx.forbidden();
@@ -2817,7 +3109,7 @@ const uid$1 = {
2817
3109
  const { query = {} } = ctx.request;
2818
3110
  const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2819
3111
  await validateUIDField(contentTypeUID, field);
2820
- const uidService = getService$1("uid");
3112
+ const uidService = getService$2("uid");
2821
3113
  ctx.body = {
2822
3114
  data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
2823
3115
  };
@@ -2829,7 +3121,7 @@ const uid$1 = {
2829
3121
  const { query = {} } = ctx.request;
2830
3122
  const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2831
3123
  await validateUIDField(contentTypeUID, field);
2832
- const uidService = getService$1("uid");
3124
+ const uidService = getService$2("uid");
2833
3125
  const isAvailable = await uidService.checkUIDAvailability({
2834
3126
  contentTypeUID,
2835
3127
  field,
@@ -2850,7 +3142,8 @@ const controllers = {
2850
3142
  relations,
2851
3143
  "single-types": singleTypes,
2852
3144
  uid: uid$1,
2853
- ...history.controllers ? history.controllers : {}
3145
+ ...history.controllers ? history.controllers : {},
3146
+ ...preview.controllers ? preview.controllers : {}
2854
3147
  };
2855
3148
  const keys = {
2856
3149
  CONFIGURATION: "configuration"
@@ -2979,18 +3272,15 @@ async function syncMetadatas(configuration, schema) {
2979
3272
  ___default.default.set(updatedMeta, ["list", "searchable"], false);
2980
3273
  ___default.default.set(acc, [key], updatedMeta);
2981
3274
  }
2982
- if (!___default.default.has(edit, "mainField"))
2983
- return acc;
3275
+ if (!___default.default.has(edit, "mainField")) return acc;
2984
3276
  if (!isRelation$1(attr)) {
2985
3277
  ___default.default.set(updatedMeta, "edit", ___default.default.omit(edit, ["mainField"]));
2986
3278
  ___default.default.set(acc, [key], updatedMeta);
2987
3279
  return acc;
2988
3280
  }
2989
- if (edit.mainField === "id")
2990
- return acc;
3281
+ if (edit.mainField === "id") return acc;
2991
3282
  const targetSchema = getTargetSchema(attr.targetModel);
2992
- if (!targetSchema)
2993
- return acc;
3283
+ if (!targetSchema) return acc;
2994
3284
  if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
2995
3285
  ___default.default.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
2996
3286
  ___default.default.set(acc, [key], updatedMeta);
@@ -3001,12 +3291,12 @@ async function syncMetadatas(configuration, schema) {
3001
3291
  return ___default.default.assign(metasWithDefaults, updatedMetas);
3002
3292
  }
3003
3293
  const getTargetSchema = (targetModel) => {
3004
- return getService$1("content-types").findContentType(targetModel);
3294
+ return getService$2("content-types").findContentType(targetModel);
3005
3295
  };
3006
3296
  const DEFAULT_LIST_LENGTH = 4;
3007
3297
  const MAX_ROW_SIZE = 12;
3008
3298
  const isAllowedFieldSize = (type, size) => {
3009
- const { getFieldSize } = getService$1("field-sizes");
3299
+ const { getFieldSize } = getService$2("field-sizes");
3010
3300
  const fieldSize = getFieldSize(type);
3011
3301
  if (!fieldSize.isResizable && size !== fieldSize.default) {
3012
3302
  return false;
@@ -3014,7 +3304,7 @@ const isAllowedFieldSize = (type, size) => {
3014
3304
  return size <= MAX_ROW_SIZE;
3015
3305
  };
3016
3306
  const getDefaultFieldSize = (attribute) => {
3017
- const { hasFieldSize, getFieldSize } = getService$1("field-sizes");
3307
+ const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
3018
3308
  return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
3019
3309
  };
3020
3310
  async function createDefaultLayouts(schema) {
@@ -3035,8 +3325,7 @@ function createDefaultEditLayout(schema) {
3035
3325
  return appendToEditLayout([], keys2, schema);
3036
3326
  }
3037
3327
  function syncLayouts(configuration, schema) {
3038
- if (___default.default.isEmpty(configuration.layouts))
3039
- return createDefaultLayouts(schema);
3328
+ if (___default.default.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
3040
3329
  const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
3041
3330
  let cleanList = list.filter((attr) => isListable(schema, attr));
3042
3331
  const cleanEditRelations = editRelations.filter(
@@ -3047,9 +3336,8 @@ function syncLayouts(configuration, schema) {
3047
3336
  for (const row of edit) {
3048
3337
  const newRow = [];
3049
3338
  for (const el of row) {
3050
- if (!hasEditableAttribute(schema, el.name))
3051
- continue;
3052
- const { hasFieldSize } = getService$1("field-sizes");
3339
+ if (!hasEditableAttribute(schema, el.name)) continue;
3340
+ const { hasFieldSize } = getService$2("field-sizes");
3053
3341
  const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
3054
3342
  if (!isAllowedFieldSize(fieldType, el.size)) {
3055
3343
  elementsToReAppend.push(el.name);
@@ -3079,8 +3367,7 @@ function syncLayouts(configuration, schema) {
3079
3367
  };
3080
3368
  }
3081
3369
  const appendToEditLayout = (layout = [], keysToAppend, schema) => {
3082
- if (keysToAppend.length === 0)
3083
- return layout;
3370
+ if (keysToAppend.length === 0) return layout;
3084
3371
  let currentRowIndex = Math.max(layout.length - 1, 0);
3085
3372
  if (!layout[currentRowIndex]) {
3086
3373
  layout[currentRowIndex] = [];
@@ -3189,17 +3476,17 @@ const configurationService$1 = createConfigurationService({
3189
3476
  isComponent: true,
3190
3477
  prefix: STORE_KEY_PREFIX,
3191
3478
  getModels() {
3192
- const { toContentManagerModel } = getService$1("data-mapper");
3479
+ const { toContentManagerModel } = getService$2("data-mapper");
3193
3480
  return fp.mapValues(toContentManagerModel, strapi.components);
3194
3481
  }
3195
3482
  });
3196
3483
  const components = ({ strapi: strapi2 }) => ({
3197
3484
  findAllComponents() {
3198
- const { toContentManagerModel } = getService$1("data-mapper");
3485
+ const { toContentManagerModel } = getService$2("data-mapper");
3199
3486
  return Object.values(strapi2.components).map(toContentManagerModel);
3200
3487
  },
3201
3488
  findComponent(uid2) {
3202
- const { toContentManagerModel } = getService$1("data-mapper");
3489
+ const { toContentManagerModel } = getService$2("data-mapper");
3203
3490
  const component = strapi2.components[uid2];
3204
3491
  return fp.isNil(component) ? component : toContentManagerModel(component);
3205
3492
  },
@@ -3250,17 +3537,17 @@ const configurationService = createConfigurationService({
3250
3537
  storeUtils,
3251
3538
  prefix: "content_types",
3252
3539
  getModels() {
3253
- const { toContentManagerModel } = getService$1("data-mapper");
3540
+ const { toContentManagerModel } = getService$2("data-mapper");
3254
3541
  return fp.mapValues(toContentManagerModel, strapi.contentTypes);
3255
3542
  }
3256
3543
  });
3257
3544
  const service = ({ strapi: strapi2 }) => ({
3258
3545
  findAllContentTypes() {
3259
- const { toContentManagerModel } = getService$1("data-mapper");
3546
+ const { toContentManagerModel } = getService$2("data-mapper");
3260
3547
  return Object.values(strapi2.contentTypes).map(toContentManagerModel);
3261
3548
  },
3262
3549
  findContentType(uid2) {
3263
- const { toContentManagerModel } = getService$1("data-mapper");
3550
+ const { toContentManagerModel } = getService$2("data-mapper");
3264
3551
  const contentType = strapi2.contentTypes[uid2];
3265
3552
  return fp.isNil(contentType) ? contentType : toContentManagerModel(contentType);
3266
3553
  },
@@ -3289,7 +3576,7 @@ const service = ({ strapi: strapi2 }) => ({
3289
3576
  return this.findConfiguration(contentType);
3290
3577
  },
3291
3578
  findComponentsConfigurations(contentType) {
3292
- return getService$1("components").findComponentsConfigurations(contentType);
3579
+ return getService$2("components").findComponentsConfigurations(contentType);
3293
3580
  },
3294
3581
  syncConfigurations() {
3295
3582
  return configurationService.syncConfigurations();
@@ -3470,12 +3757,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3470
3757
  ability: userAbility,
3471
3758
  model
3472
3759
  });
3473
- const toSubject = (entity) => entity ? permissionsManager.toSubject(entity, model) : model;
3760
+ const { actionProvider } = strapi2.service("admin::permission");
3761
+ const toSubject = (entity) => {
3762
+ return entity ? permissionsManager.toSubject(entity, model) : model;
3763
+ };
3474
3764
  const can = (action, entity, field) => {
3475
- return userAbility.can(action, toSubject(entity), field);
3765
+ const subject = toSubject(entity);
3766
+ const aliases = actionProvider.unstable_aliases(action, model);
3767
+ return (
3768
+ // Test the original action to see if it passes
3769
+ userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
3770
+ aliases.some((alias) => userAbility.can(alias, subject, field))
3771
+ );
3476
3772
  };
3477
3773
  const cannot = (action, entity, field) => {
3478
- return userAbility.cannot(action, toSubject(entity), field);
3774
+ const subject = toSubject(entity);
3775
+ const aliases = actionProvider.unstable_aliases(action, model);
3776
+ return (
3777
+ // Test both the original action
3778
+ userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
3779
+ aliases.every((alias) => userAbility.cannot(alias, subject, field))
3780
+ );
3479
3781
  };
3480
3782
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3481
3783
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3546,7 +3848,7 @@ const permission = ({ strapi: strapi2 }) => ({
3546
3848
  return userAbility.can(action);
3547
3849
  },
3548
3850
  async registerPermissions() {
3549
- const displayedContentTypes = getService$1("content-types").findDisplayedContentTypes();
3851
+ const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
3550
3852
  const contentTypesUids = displayedContentTypes.map(fp.prop("uid"));
3551
3853
  const actions = [
3552
3854
  {
@@ -3631,6 +3933,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
3631
3933
  if (initialPopulate) {
3632
3934
  return initialPopulate;
3633
3935
  }
3936
+ if (attributeName === "localizations") {
3937
+ const validationPopulate = getPopulateForValidation(model.uid);
3938
+ return {
3939
+ populate: validationPopulate.populate
3940
+ };
3941
+ }
3634
3942
  if (!isVisibleAttribute$1(model, attributeName)) {
3635
3943
  return true;
3636
3944
  }
@@ -3690,6 +3998,9 @@ const getDeepPopulate = (uid2, {
3690
3998
  return {};
3691
3999
  }
3692
4000
  const model = strapi.getModel(uid2);
4001
+ if (!model) {
4002
+ return {};
4003
+ }
3693
4004
  return Object.keys(model.attributes).reduce(
3694
4005
  (populateAcc, attributeName) => fp.merge(
3695
4006
  populateAcc,
@@ -3709,40 +4020,46 @@ const getDeepPopulate = (uid2, {
3709
4020
  {}
3710
4021
  );
3711
4022
  };
3712
- const getValidatableFieldsPopulate = (uid2, {
3713
- initialPopulate = {},
3714
- countMany = false,
3715
- countOne = false,
3716
- maxLevel = Infinity
3717
- } = {}, level = 1) => {
3718
- if (level > maxLevel) {
4023
+ const getPopulateForValidation = (uid2) => {
4024
+ const model = strapi.getModel(uid2);
4025
+ if (!model) {
3719
4026
  return {};
3720
4027
  }
3721
- const model = strapi.getModel(uid2);
3722
4028
  return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
3723
- if (!getDoesAttributeRequireValidation(attribute)) {
4029
+ if (isScalarAttribute(attribute)) {
4030
+ if (getDoesAttributeRequireValidation(attribute)) {
4031
+ populateAcc.fields = populateAcc.fields || [];
4032
+ populateAcc.fields.push(attributeName);
4033
+ }
3724
4034
  return populateAcc;
3725
4035
  }
3726
- if (isScalarAttribute(attribute)) {
3727
- return fp.merge(populateAcc, {
3728
- [attributeName]: true
3729
- });
4036
+ if (isComponent(attribute)) {
4037
+ const component = attribute.component;
4038
+ const componentResult = getPopulateForValidation(component);
4039
+ if (Object.keys(componentResult).length > 0) {
4040
+ populateAcc.populate = populateAcc.populate || {};
4041
+ populateAcc.populate[attributeName] = componentResult;
4042
+ }
4043
+ return populateAcc;
3730
4044
  }
3731
- return fp.merge(
3732
- populateAcc,
3733
- getPopulateFor(
3734
- attributeName,
3735
- model,
3736
- {
3737
- // @ts-expect-error - improve types
3738
- initialPopulate: initialPopulate?.[attributeName],
3739
- countMany,
3740
- countOne,
3741
- maxLevel
4045
+ if (isDynamicZone(attribute)) {
4046
+ const components2 = attribute.components;
4047
+ const componentsResult = (components2 || []).reduce(
4048
+ (acc, componentUID) => {
4049
+ const componentResult = getPopulateForValidation(componentUID);
4050
+ if (Object.keys(componentResult).length > 0) {
4051
+ acc[componentUID] = componentResult;
4052
+ }
4053
+ return acc;
3742
4054
  },
3743
- level
3744
- )
3745
- );
4055
+ {}
4056
+ );
4057
+ if (Object.keys(componentsResult).length > 0) {
4058
+ populateAcc.populate = populateAcc.populate || {};
4059
+ populateAcc.populate[attributeName] = { on: componentsResult };
4060
+ }
4061
+ }
4062
+ return populateAcc;
3746
4063
  }, {});
3747
4064
  };
3748
4065
  const getDeepPopulateDraftCount = (uid2) => {
@@ -3822,7 +4139,7 @@ const getQueryPopulate = async (uid2, query) => {
3822
4139
  return populateQuery;
3823
4140
  };
3824
4141
  const buildDeepPopulate = (uid2) => {
3825
- return getService$1("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
4142
+ return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
3826
4143
  };
3827
4144
  const populateBuilder = (uid2) => {
3828
4145
  let getInitialPopulate = async () => {
@@ -3984,7 +4301,6 @@ const AVAILABLE_LOCALES_FIELDS = [
3984
4301
  "locale",
3985
4302
  "updatedAt",
3986
4303
  "createdAt",
3987
- "status",
3988
4304
  "publishedAt",
3989
4305
  "documentId"
3990
4306
  ];
@@ -4005,34 +4321,20 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4005
4321
  /**
4006
4322
  * Returns available locales of a document for the current status
4007
4323
  */
4008
- async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
4324
+ async getAvailableLocales(uid2, version, allVersions) {
4009
4325
  const versionsByLocale = fp.groupBy("locale", allVersions);
4010
- delete versionsByLocale[version.locale];
4326
+ if (version.locale) {
4327
+ delete versionsByLocale[version.locale];
4328
+ }
4011
4329
  const model = strapi2.getModel(uid2);
4012
- const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
4013
- const traversalFunction = async (localeVersion) => strapiUtils.traverseEntity(
4014
- ({ key }, { remove }) => {
4015
- if (keysToKeep.includes(key)) {
4016
- return;
4017
- }
4018
- remove(key);
4019
- },
4020
- { schema: model, getModel: strapi2.getModel.bind(strapi2) },
4021
- // @ts-expect-error fix types DocumentVersion incompatible with Data
4022
- localeVersion
4023
- );
4024
4330
  const mappingResult = await strapiUtils.async.map(
4025
4331
  Object.values(versionsByLocale),
4026
4332
  async (localeVersions) => {
4027
- const mappedLocaleVersions = await strapiUtils.async.map(
4028
- localeVersions,
4029
- traversalFunction
4030
- );
4031
4333
  if (!strapiUtils.contentTypes.hasDraftAndPublish(model)) {
4032
- return mappedLocaleVersions[0];
4334
+ return localeVersions[0];
4033
4335
  }
4034
- const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
4035
- const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
4336
+ const draftVersion = localeVersions.find((v) => v.publishedAt === null);
4337
+ const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
4036
4338
  if (!draftVersion) {
4037
4339
  return;
4038
4340
  }
@@ -4054,8 +4356,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4054
4356
  const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
4055
4357
  return matchLocale && matchStatus;
4056
4358
  });
4057
- if (!availableStatus)
4058
- return availableStatus;
4359
+ if (!availableStatus) return availableStatus;
4059
4360
  return fp.pick(AVAILABLE_STATUS_FIELDS, availableStatus);
4060
4361
  },
4061
4362
  /**
@@ -4065,18 +4366,19 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4065
4366
  * @returns
4066
4367
  */
4067
4368
  async getManyAvailableStatus(uid2, documents) {
4068
- if (!documents.length)
4069
- return [];
4369
+ if (!documents.length) return [];
4070
4370
  const status = documents[0].publishedAt !== null ? "published" : "draft";
4071
- const locale = documents[0]?.locale;
4072
- const otherStatus = status === "published" ? "draft" : "published";
4073
- return strapi2.documents(uid2).findMany({
4074
- filters: {
4075
- documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) }
4076
- },
4077
- status: otherStatus,
4078
- locale,
4079
- fields: ["documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
4371
+ const locales = documents.map((d) => d.locale).filter(Boolean);
4372
+ const where = {
4373
+ documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) },
4374
+ publishedAt: { $null: status === "published" }
4375
+ };
4376
+ if (locales.length) {
4377
+ where.locale = { $in: locales };
4378
+ }
4379
+ return strapi2.query(uid2).findMany({
4380
+ where,
4381
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
4080
4382
  });
4081
4383
  },
4082
4384
  getStatus(version, otherDocumentStatuses) {
@@ -4093,10 +4395,8 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4093
4395
  } else if (otherVersion) {
4094
4396
  draftVersion = otherVersion;
4095
4397
  }
4096
- if (!draftVersion)
4097
- return CONTENT_MANAGER_STATUS.PUBLISHED;
4098
- if (!publishedVersion)
4099
- return CONTENT_MANAGER_STATUS.DRAFT;
4398
+ if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
4399
+ if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
4100
4400
  const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4101
4401
  return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
4102
4402
  },
@@ -4104,11 +4404,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4104
4404
  // We could refactor this so the locales are only loaded when they're
4105
4405
  // needed. e.g. in the bulk locale action modal.
4106
4406
  async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
4107
- const populate = getValidatableFieldsPopulate(uid2);
4108
- const versions = await strapi2.db.query(uid2).findMany({
4109
- where: { documentId: version.documentId },
4407
+ const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
4408
+ const params = {
4110
4409
  populate: {
4111
- // Populate only fields that require validation for bulk locale actions
4112
4410
  ...populate,
4113
4411
  // NOTE: creator fields are selected in this way to avoid exposing sensitive data
4114
4412
  createdBy: {
@@ -4117,9 +4415,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4117
4415
  updatedBy: {
4118
4416
  select: ["id", "firstname", "lastname", "email"]
4119
4417
  }
4418
+ },
4419
+ fields: fp.uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
4420
+ filters: {
4421
+ documentId: version.documentId
4120
4422
  }
4121
- });
4122
- const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
4423
+ };
4424
+ const dbParams = strapi2.get("query-params").transform(uid2, params);
4425
+ const versions = await strapi2.db.query(uid2).findMany(dbParams);
4426
+ const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions) : [];
4123
4427
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
4124
4428
  return {
4125
4429
  availableLocales: availableLocalesResult,
@@ -4133,13 +4437,29 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4133
4437
  */
4134
4438
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
4135
4439
  if (!document) {
4136
- return document;
4440
+ return {
4441
+ data: document,
4442
+ meta: {
4443
+ availableLocales: [],
4444
+ availableStatus: []
4445
+ }
4446
+ };
4137
4447
  }
4138
4448
  const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
4139
4449
  if (!hasDraftAndPublish) {
4140
4450
  opts.availableStatus = false;
4141
4451
  }
4142
4452
  const meta = await this.getMetadata(uid2, document, opts);
4453
+ if (document.localizations) {
4454
+ const otherStatus = await this.getManyAvailableStatus(uid2, document.localizations);
4455
+ document.localizations = document.localizations.map((d) => {
4456
+ const status = otherStatus.find((s) => s.documentId === d.documentId);
4457
+ return {
4458
+ ...d,
4459
+ status: this.getStatus(d, status ? [status] : [])
4460
+ };
4461
+ });
4462
+ }
4143
4463
  return {
4144
4464
  data: {
4145
4465
  ...document,
@@ -4357,7 +4677,8 @@ const services = {
4357
4677
  permission,
4358
4678
  "populate-builder": populateBuilder$1,
4359
4679
  uid,
4360
- ...history.services ? history.services : {}
4680
+ ...history.services ? history.services : {},
4681
+ ...preview.services ? preview.services : {}
4361
4682
  };
4362
4683
  const index = () => {
4363
4684
  return {