@strapi/content-manager 0.0.0-experimental.5b211b38912691ee2eab22d47b5095ea2fcfec76 → 0.0.0-experimental.5bd54472327d69041855d9b38a3d4e445535c9a3

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 (227) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
  3. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs → ComponentConfigurationPage-9_4yUE9L.mjs} +4 -4
  5. package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs.map → ComponentConfigurationPage-9_4yUE9L.mjs.map} +1 -1
  6. package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js → ComponentConfigurationPage-DBSh-kET.js} +5 -6
  7. package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js.map → ComponentConfigurationPage-DBSh-kET.js.map} +1 -1
  8. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
  9. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
  10. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
  11. package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js → EditConfigurationPage-Bl_U2JgH.js} +5 -6
  12. package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js.map → EditConfigurationPage-Bl_U2JgH.js.map} +1 -1
  13. package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs → EditConfigurationPage-COe6hjPC.mjs} +4 -4
  14. package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs.map → EditConfigurationPage-COe6hjPC.mjs.map} +1 -1
  15. package/dist/_chunks/{EditViewPage-zT3fBr4Y.js → EditViewPage-D4yFJET6.js} +36 -49
  16. package/dist/_chunks/EditViewPage-D4yFJET6.js.map +1 -0
  17. package/dist/_chunks/{EditViewPage-CPj61RMh.mjs → EditViewPage-DrmVmYN0.mjs} +34 -46
  18. package/dist/_chunks/EditViewPage-DrmVmYN0.mjs.map +1 -0
  19. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  20. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  21. package/dist/_chunks/{Form-y5g1SRsh.js → Form-C4rSaGsz.js} +39 -21
  22. package/dist/_chunks/Form-C4rSaGsz.js.map +1 -0
  23. package/dist/_chunks/{Form-DHrru2AV.mjs → Form-DamaxNpG.mjs} +37 -18
  24. package/dist/_chunks/Form-DamaxNpG.mjs.map +1 -0
  25. package/dist/_chunks/{History-Bru_KoeP.mjs → History-D1PreDSY.mjs} +108 -116
  26. package/dist/_chunks/History-D1PreDSY.mjs.map +1 -0
  27. package/dist/_chunks/{History-CqN6K7SX.js → History-DTm8UCCQ.js} +118 -127
  28. package/dist/_chunks/History-DTm8UCCQ.js.map +1 -0
  29. package/dist/_chunks/{Field-Boxf9Ajp.js → Input-B7sapvBG.js} +1431 -1312
  30. package/dist/_chunks/Input-B7sapvBG.js.map +1 -0
  31. package/dist/_chunks/{Field-dha5VnIQ.mjs → Input-CZ1YvjHR.mjs} +1439 -1320
  32. package/dist/_chunks/Input-CZ1YvjHR.mjs.map +1 -0
  33. package/dist/_chunks/{ListConfigurationPage-D8wGABj0.mjs → ListConfigurationPage-Bbi32isk.mjs} +25 -12
  34. package/dist/_chunks/ListConfigurationPage-Bbi32isk.mjs.map +1 -0
  35. package/dist/_chunks/{ListConfigurationPage-R_p-SbHZ.js → ListConfigurationPage-ysFMjKI3.js} +25 -13
  36. package/dist/_chunks/ListConfigurationPage-ysFMjKI3.js.map +1 -0
  37. package/dist/_chunks/{ListViewPage-SID6TRb9.mjs → ListViewPage-Bud_jBDQ.mjs} +122 -78
  38. package/dist/_chunks/ListViewPage-Bud_jBDQ.mjs.map +1 -0
  39. package/dist/_chunks/{ListViewPage-pEw_zug9.js → ListViewPage-DTuuxU3n.js} +121 -78
  40. package/dist/_chunks/ListViewPage-DTuuxU3n.js.map +1 -0
  41. package/dist/_chunks/{NoContentTypePage-C5dcQojD.js → NoContentTypePage-CL7VVeYs.js} +2 -2
  42. package/dist/_chunks/{NoContentTypePage-C5dcQojD.js.map → NoContentTypePage-CL7VVeYs.js.map} +1 -1
  43. package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs → NoContentTypePage-DVhkugsf.mjs} +2 -2
  44. package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs.map → NoContentTypePage-DVhkugsf.mjs.map} +1 -1
  45. package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs → NoPermissionsPage-CMdM-dCo.mjs} +2 -2
  46. package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs.map → NoPermissionsPage-CMdM-dCo.mjs.map} +1 -1
  47. package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js → NoPermissionsPage-v7I599vC.js} +2 -2
  48. package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js.map → NoPermissionsPage-v7I599vC.js.map} +1 -1
  49. package/dist/_chunks/Preview-BNuU0SuQ.mjs +287 -0
  50. package/dist/_chunks/Preview-BNuU0SuQ.mjs.map +1 -0
  51. package/dist/_chunks/Preview-Cxq-uI6D.js +305 -0
  52. package/dist/_chunks/Preview-Cxq-uI6D.js.map +1 -0
  53. package/dist/_chunks/{Relations-B9Crnhnn.mjs → Relations-C2Ahkrdg.mjs} +76 -42
  54. package/dist/_chunks/Relations-C2Ahkrdg.mjs.map +1 -0
  55. package/dist/_chunks/{Relations-DjTQ5kGB.js → Relations-CWS79QQn.js} +76 -43
  56. package/dist/_chunks/Relations-CWS79QQn.js.map +1 -0
  57. package/dist/_chunks/{en-fbKQxLGn.js → en-BR48D_RH.js} +39 -18
  58. package/dist/_chunks/{en-fbKQxLGn.js.map → en-BR48D_RH.js.map} +1 -1
  59. package/dist/_chunks/{en-Ux26r5pl.mjs → en-D65uIF6Y.mjs} +39 -18
  60. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
  61. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  62. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  63. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  64. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  65. package/dist/_chunks/{fr-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
  66. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
  67. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
  68. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
  69. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  70. package/dist/_chunks/{index-DVPWZkbS.js → index-DQsvBb_N.js} +1463 -762
  71. package/dist/_chunks/index-DQsvBb_N.js.map +1 -0
  72. package/dist/_chunks/{index-DJXJw9V5.mjs → index-ZKrsjv-2.mjs} +1481 -780
  73. package/dist/_chunks/index-ZKrsjv-2.mjs.map +1 -0
  74. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  75. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  76. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  77. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  78. package/dist/_chunks/{layout-Dm6fbiQj.js → layout-Cl0NhlQB.js} +26 -14
  79. package/dist/_chunks/layout-Cl0NhlQB.js.map +1 -0
  80. package/dist/_chunks/{layout-Bau7ZfLV.mjs → layout-fQk1rMk9.mjs} +26 -13
  81. package/dist/_chunks/layout-fQk1rMk9.mjs.map +1 -0
  82. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  83. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  84. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  85. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  86. package/dist/_chunks/{relations-CKnpRgrN.js → relations-BRfBxVbX.js} +6 -7
  87. package/dist/_chunks/relations-BRfBxVbX.js.map +1 -0
  88. package/dist/_chunks/{relations-BH_kBSJ0.mjs → relations-BakOFl_1.mjs} +6 -7
  89. package/dist/_chunks/relations-BakOFl_1.mjs.map +1 -0
  90. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  91. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  92. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  93. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  94. package/dist/_chunks/usePrev-CZGy2Vjf.mjs +29 -0
  95. package/dist/_chunks/usePrev-CZGy2Vjf.mjs.map +1 -0
  96. package/dist/_chunks/{usePrev-B9w_-eYc.js → usePrev-D5J_2fEu.js} +14 -1
  97. package/dist/_chunks/usePrev-D5J_2fEu.js.map +1 -0
  98. package/dist/admin/index.js +3 -1
  99. package/dist/admin/index.js.map +1 -1
  100. package/dist/admin/index.mjs +6 -4
  101. package/dist/admin/src/content-manager.d.ts +3 -2
  102. package/dist/admin/src/exports.d.ts +2 -1
  103. package/dist/admin/src/history/index.d.ts +3 -0
  104. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  105. package/dist/admin/src/hooks/useDocument.d.ts +49 -1
  106. package/dist/admin/src/index.d.ts +1 -0
  107. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  108. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +2 -1
  109. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
  110. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  111. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  112. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
  113. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
  114. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
  115. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  116. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  117. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  118. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  119. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
  120. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  121. package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
  122. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  123. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  124. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  125. package/dist/admin/src/preview/index.d.ts +4 -0
  126. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  127. package/dist/admin/src/preview/routes.d.ts +3 -0
  128. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  129. package/dist/admin/src/router.d.ts +1 -1
  130. package/dist/admin/src/services/api.d.ts +1 -1
  131. package/dist/admin/src/services/components.d.ts +2 -2
  132. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  133. package/dist/admin/src/services/documents.d.ts +19 -20
  134. package/dist/admin/src/services/init.d.ts +1 -1
  135. package/dist/admin/src/services/relations.d.ts +2 -2
  136. package/dist/admin/src/services/uid.d.ts +3 -3
  137. package/dist/admin/src/utils/validation.d.ts +4 -1
  138. package/dist/server/index.js +762 -432
  139. package/dist/server/index.js.map +1 -1
  140. package/dist/server/index.mjs +763 -432
  141. package/dist/server/index.mjs.map +1 -1
  142. package/dist/server/src/bootstrap.d.ts.map +1 -1
  143. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  144. package/dist/server/src/controllers/index.d.ts.map +1 -1
  145. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  146. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  147. package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
  148. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  149. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  150. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  151. package/dist/server/src/history/controllers/history-version.d.ts +1 -1
  152. package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
  153. package/dist/server/src/history/services/history.d.ts +3 -3
  154. package/dist/server/src/history/services/history.d.ts.map +1 -1
  155. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  156. package/dist/server/src/history/services/utils.d.ts +8 -12
  157. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  158. package/dist/server/src/index.d.ts +7 -6
  159. package/dist/server/src/index.d.ts.map +1 -1
  160. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  161. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  162. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  163. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  164. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  165. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  166. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  167. package/dist/server/src/preview/index.d.ts +4 -0
  168. package/dist/server/src/preview/index.d.ts.map +1 -0
  169. package/dist/server/src/preview/routes/index.d.ts +8 -0
  170. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  171. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  172. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  173. package/dist/server/src/preview/services/index.d.ts +16 -0
  174. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  175. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  176. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  177. package/dist/server/src/preview/services/preview.d.ts +12 -0
  178. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  179. package/dist/server/src/preview/utils.d.ts +19 -0
  180. package/dist/server/src/preview/utils.d.ts.map +1 -0
  181. package/dist/server/src/register.d.ts.map +1 -1
  182. package/dist/server/src/routes/index.d.ts.map +1 -1
  183. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  184. package/dist/server/src/services/document-metadata.d.ts +12 -10
  185. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  186. package/dist/server/src/services/index.d.ts +7 -6
  187. package/dist/server/src/services/index.d.ts.map +1 -1
  188. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  189. package/dist/server/src/services/utils/populate.d.ts +2 -2
  190. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  191. package/dist/server/src/utils/index.d.ts +2 -0
  192. package/dist/server/src/utils/index.d.ts.map +1 -1
  193. package/dist/shared/contracts/collection-types.d.ts +3 -1
  194. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  195. package/dist/shared/contracts/index.d.ts +1 -0
  196. package/dist/shared/contracts/index.d.ts.map +1 -1
  197. package/dist/shared/contracts/preview.d.ts +27 -0
  198. package/dist/shared/contracts/preview.d.ts.map +1 -0
  199. package/dist/shared/index.js +4 -0
  200. package/dist/shared/index.js.map +1 -1
  201. package/dist/shared/index.mjs +4 -0
  202. package/dist/shared/index.mjs.map +1 -1
  203. package/package.json +17 -16
  204. package/dist/_chunks/EditViewPage-CPj61RMh.mjs.map +0 -1
  205. package/dist/_chunks/EditViewPage-zT3fBr4Y.js.map +0 -1
  206. package/dist/_chunks/Field-Boxf9Ajp.js.map +0 -1
  207. package/dist/_chunks/Field-dha5VnIQ.mjs.map +0 -1
  208. package/dist/_chunks/Form-DHrru2AV.mjs.map +0 -1
  209. package/dist/_chunks/Form-y5g1SRsh.js.map +0 -1
  210. package/dist/_chunks/History-Bru_KoeP.mjs.map +0 -1
  211. package/dist/_chunks/History-CqN6K7SX.js.map +0 -1
  212. package/dist/_chunks/ListConfigurationPage-D8wGABj0.mjs.map +0 -1
  213. package/dist/_chunks/ListConfigurationPage-R_p-SbHZ.js.map +0 -1
  214. package/dist/_chunks/ListViewPage-SID6TRb9.mjs.map +0 -1
  215. package/dist/_chunks/ListViewPage-pEw_zug9.js.map +0 -1
  216. package/dist/_chunks/Relations-B9Crnhnn.mjs.map +0 -1
  217. package/dist/_chunks/Relations-DjTQ5kGB.js.map +0 -1
  218. package/dist/_chunks/index-DJXJw9V5.mjs.map +0 -1
  219. package/dist/_chunks/index-DVPWZkbS.js.map +0 -1
  220. package/dist/_chunks/layout-Bau7ZfLV.mjs.map +0 -1
  221. package/dist/_chunks/layout-Dm6fbiQj.js.map +0 -1
  222. package/dist/_chunks/relations-BH_kBSJ0.mjs.map +0 -1
  223. package/dist/_chunks/relations-CKnpRgrN.js.map +0 -1
  224. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  225. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  226. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  227. 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,31 +222,53 @@ 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": {
243
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
244
+ if (isMorphRelation) {
245
+ break;
246
+ }
235
247
  const isVisible2 = strapiUtils.contentTypes.isVisibleAttribute(model, attributeName);
236
248
  if (isVisible2) {
237
- acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
249
+ acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
238
250
  }
239
251
  break;
240
252
  }
241
253
  case "media": {
242
- acc[attributeName] = { fields: ["id"] };
254
+ acc[attributeName] = { [fieldSelector]: ["id"] };
243
255
  break;
244
256
  }
245
257
  case "component": {
246
258
  const populate = getDeepPopulate2(attribute.component);
247
- acc[attributeName] = { populate };
259
+ acc[attributeName] = {
260
+ populate,
261
+ [fieldSelector]: getComponentFields(attribute.component)
262
+ };
248
263
  break;
249
264
  }
250
265
  case "dynamiczone": {
251
266
  const populatedComponents = (attribute.components || []).reduce(
252
267
  (acc2, componentUID) => {
253
- acc2[componentUID] = { populate: getDeepPopulate2(componentUID) };
268
+ acc2[componentUID] = {
269
+ populate: getDeepPopulate2(componentUID),
270
+ [fieldSelector]: getComponentFields(componentUID)
271
+ };
254
272
  return acc2;
255
273
  },
256
274
  {}
@@ -312,6 +330,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
312
330
  getRelationRestoreValue,
313
331
  getMediaRestoreValue,
314
332
  getDefaultLocale,
333
+ isLocalizedContentType,
315
334
  getLocaleDictionary,
316
335
  getRetentionDays,
317
336
  getVersionStatus,
@@ -334,7 +353,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
334
353
  });
335
354
  },
336
355
  async findVersionsPage(params) {
337
- 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
+ }
338
363
  const [{ results, pagination }, localeDictionary] = await Promise.all([
339
364
  query.findPage({
340
365
  ...params.query,
@@ -350,78 +375,76 @@ const createHistoryService = ({ strapi: strapi2 }) => {
350
375
  }),
351
376
  serviceUtils.getLocaleDictionary()
352
377
  ]);
353
- const populateEntryRelations = async (entry) => {
354
- const entryWithRelations = await Object.entries(entry.schema).reduce(
355
- async (currentDataWithRelations, [attributeKey, attributeSchema]) => {
356
- const attributeValue = entry.data[attributeKey];
357
- const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
358
- if (attributeSchema.type === "media") {
359
- const permissionChecker2 = getService$1("permission-checker").create({
360
- userAbility: params.state.userAbility,
361
- model: "plugin::upload.file"
362
- });
363
- const response = await serviceUtils.buildMediaResponse(attributeValues);
364
- const sanitizedResults = await Promise.all(
365
- response.results.map((media) => permissionChecker2.sanitizeOutput(media))
366
- );
367
- return {
368
- ...await currentDataWithRelations,
369
- [attributeKey]: {
370
- results: sanitizedResults,
371
- meta: response.meta
372
- }
373
- };
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");
374
386
  }
375
- if (attributeSchema.type === "relation" && attributeSchema.relation !== "morphToOne" && attributeSchema.relation !== "morphToMany") {
376
- 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") {
377
390
  const adminUsers = await Promise.all(
378
- attributeValues.map((userToPopulate) => {
391
+ currentValue.map((userToPopulate) => {
379
392
  if (userToPopulate == null) {
380
393
  return null;
381
394
  }
382
- 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
+ });
383
401
  })
384
402
  );
385
- return {
386
- ...await currentDataWithRelations,
387
- /**
388
- * Ideally we would return the same "{results: [], meta: {}}" shape, however,
389
- * when sanitizing the data as a whole in the controller before sending to the client,
390
- * the data for admin relation user is completely sanitized if we return an object here as opposed to an array.
391
- */
392
- [attributeKey]: adminUsers
393
- };
403
+ utils.set(options.key, adminUsers);
394
404
  }
395
- const permissionChecker2 = getService$1("permission-checker").create({
405
+ const permissionChecker2 = getService$2("permission-checker").create({
396
406
  userAbility: params.state.userAbility,
397
- model: attributeSchema.target
407
+ model: options.attribute.target
398
408
  });
399
409
  const response = await serviceUtils.buildRelationReponse(
400
- attributeValues,
401
- attributeSchema
410
+ currentValue,
411
+ options.attribute
402
412
  );
403
413
  const sanitizedResults = await Promise.all(
404
414
  response.results.map((media) => permissionChecker2.sanitizeOutput(media))
405
415
  );
406
- return {
407
- ...await currentDataWithRelations,
408
- [attributeKey]: {
409
- results: sanitizedResults,
410
- meta: response.meta
411
- }
412
- };
416
+ utils.set(options.key, {
417
+ results: sanitizedResults,
418
+ meta: response.meta
419
+ });
413
420
  }
414
- 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)
415
439
  },
416
- Promise.resolve(entry.data)
440
+ entry.data
417
441
  );
418
- return entryWithRelations;
419
442
  };
420
443
  const formattedResults = await Promise.all(
421
444
  results.map(async (result) => {
422
445
  return {
423
446
  ...result,
424
- data: await populateEntryRelations(result),
447
+ data: await populateEntry(result),
425
448
  meta: {
426
449
  unknownAttributes: serviceUtils.getSchemaAttributesDiff(
427
450
  result.schema,
@@ -452,30 +475,44 @@ const createHistoryService = ({ strapi: strapi2 }) => {
452
475
  // Clone to avoid mutating the original version data
453
476
  structuredClone(version.data)
454
477
  );
455
- const sanitizedSchemaAttributes = fp.omit(
456
- FIELDS_TO_IGNORE,
457
- contentTypeSchemaAttributes
458
- );
459
- const reducer = strapiUtils.async.reduce(Object.entries(sanitizedSchemaAttributes));
460
- const dataWithoutMissingRelations = await reducer(
461
- async (previousRelationAttributes, [name, attribute]) => {
462
- const versionRelationData = version.data[name];
463
- if (!versionRelationData) {
464
- 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
+ }
465
488
  }
466
- if (attribute.type === "relation" && // TODO: handle polymorphic relations
467
- attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
468
- const data2 = await serviceUtils.getRelationRestoreValue(versionRelationData, attribute);
469
- previousRelationAttributes[name] = data2;
489
+ if (options.attribute.type === "dynamiczone") {
490
+ if (options.value === null) {
491
+ utils.set(options.key, []);
492
+ }
470
493
  }
471
- if (attribute.type === "media") {
472
- const data2 = await serviceUtils.getMediaRestoreValue(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);
502
+ }
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);
474
509
  }
475
- return previousRelationAttributes;
476
510
  },
477
- // Clone to avoid mutating the original version data
478
- structuredClone(dataWithoutAddedAttributes)
511
+ {
512
+ schema,
513
+ getModel: strapi2.getModel.bind(strapi2)
514
+ },
515
+ dataWithoutAddedAttributes
479
516
  );
480
517
  const data = fp.omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
481
518
  const restoredDocument = await strapi2.documents(version.contentType).update({
@@ -490,6 +527,42 @@ const createHistoryService = ({ strapi: strapi2 }) => {
490
527
  }
491
528
  };
492
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
+ };
493
566
  const createLifecyclesService = ({ strapi: strapi2 }) => {
494
567
  const state = {
495
568
  deleteExpiredJob: null,
@@ -502,76 +575,62 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
502
575
  return;
503
576
  }
504
577
  strapi2.documents.use(async (context, next) => {
505
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
506
- return next();
507
- }
508
- if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
509
- return next();
510
- }
511
- if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
512
- return next();
513
- }
514
- const contentTypeUid = context.contentType.uid;
515
- if (!contentTypeUid.startsWith("api::")) {
516
- return next();
517
- }
518
578
  const result = await next();
519
- const documentContext = {
520
- documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
521
- locale: context.params?.locale
522
- };
579
+ if (!shouldCreateHistoryVersion(context)) {
580
+ return result;
581
+ }
582
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
523
583
  const defaultLocale = await serviceUtils.getDefaultLocale();
524
- const locale = documentContext.locale || defaultLocale;
525
- if (Array.isArray(locale)) {
526
- strapi2.log.warn(
527
- "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
528
- );
529
- return next();
584
+ const locales = fp.castArray(context.params?.locale || defaultLocale);
585
+ if (!locales.length) {
586
+ return result;
530
587
  }
531
- const document = await strapi2.documents(contentTypeUid).findOne({
532
- documentId: documentContext.documentId,
533
- locale,
534
- 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
+ )
535
603
  });
536
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
537
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
538
- const componentsSchemas = Object.keys(
539
- attributesSchema
540
- ).reduce((currentComponentSchemas, key) => {
541
- const fieldSchema = attributesSchema[key];
542
- if (fieldSchema.type === "component") {
543
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
544
- return {
545
- ...currentComponentSchemas,
546
- [fieldSchema.component]: componentSchema
547
- };
548
- }
549
- return currentComponentSchemas;
550
- }, {});
551
604
  await strapi2.db.transaction(async ({ onCommit }) => {
552
- onCommit(() => {
553
- getService(strapi2, "history").createVersion({
554
- contentType: contentTypeUid,
555
- data: fp.omit(FIELDS_TO_IGNORE, document),
556
- schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
557
- componentsSchemas,
558
- relatedDocumentId: documentContext.documentId,
559
- locale,
560
- status
561
- });
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
+ }
562
617
  });
563
618
  });
564
619
  return result;
565
620
  });
566
- state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
621
+ state.deleteExpiredJob = nodeSchedule.scheduleJob("historyDaily", "0 0 * * *", () => {
567
622
  const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
568
623
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
569
624
  strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
570
625
  where: {
571
626
  created_at: {
572
- $lt: expirationDate.toISOString()
627
+ $lt: expirationDate
573
628
  }
574
629
  }
630
+ }).catch((error) => {
631
+ if (error instanceof Error) {
632
+ strapi2.log.error("Error deleting expired history versions", error.message);
633
+ }
575
634
  });
576
635
  });
577
636
  state.isInitialized = true;
@@ -583,17 +642,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
583
642
  }
584
643
  };
585
644
  };
586
- const services$1 = {
645
+ const services$2 = {
587
646
  history: createHistoryService,
588
647
  lifecycles: createLifecyclesService
589
648
  };
590
- const info = { pluginName: "content-manager", type: "admin" };
649
+ const info$1 = { pluginName: "content-manager", type: "admin" };
591
650
  const historyVersionRouter = {
592
651
  type: "admin",
593
652
  routes: [
594
653
  {
595
654
  method: "GET",
596
- info,
655
+ info: info$1,
597
656
  path: "/history-versions",
598
657
  handler: "history-version.findMany",
599
658
  config: {
@@ -602,7 +661,7 @@ const historyVersionRouter = {
602
661
  },
603
662
  {
604
663
  method: "PUT",
605
- info,
664
+ info: info$1,
606
665
  path: "/history-versions/:versionId/restore",
607
666
  handler: "history-version.restoreVersion",
608
667
  config: {
@@ -611,7 +670,7 @@ const historyVersionRouter = {
611
670
  }
612
671
  ]
613
672
  };
614
- const routes$1 = {
673
+ const routes$2 = {
615
674
  "history-version": historyVersionRouter
616
675
  };
617
676
  const historyVersion = {
@@ -658,21 +717,21 @@ const historyVersion = {
658
717
  }
659
718
  }
660
719
  };
661
- const getFeature = () => {
720
+ const getFeature$1 = () => {
662
721
  if (strapi.ee.features.isEnabled("cms-content-history")) {
663
722
  return {
664
723
  register({ strapi: strapi2 }) {
665
724
  strapi2.get("models").add(historyVersion);
666
725
  },
667
726
  bootstrap({ strapi: strapi2 }) {
668
- getService(strapi2, "lifecycles").bootstrap();
727
+ getService$1(strapi2, "lifecycles").bootstrap();
669
728
  },
670
729
  destroy({ strapi: strapi2 }) {
671
- getService(strapi2, "lifecycles").destroy();
730
+ getService$1(strapi2, "lifecycles").destroy();
672
731
  },
673
- controllers: controllers$1,
674
- services: services$1,
675
- routes: routes$1
732
+ controllers: controllers$2,
733
+ services: services$2,
734
+ routes: routes$2
676
735
  };
677
736
  }
678
737
  return {
@@ -681,9 +740,201 @@ const getFeature = () => {
681
740
  }
682
741
  };
683
742
  };
684
- 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();
685
935
  const register = async ({ strapi: strapi2 }) => {
686
936
  await history.register?.({ strapi: strapi2 });
937
+ await preview.register?.({ strapi: strapi2 });
687
938
  };
688
939
  const ALLOWED_WEBHOOK_EVENTS = {
689
940
  ENTRY_PUBLISH: "entry.publish",
@@ -693,11 +944,12 @@ const bootstrap = async () => {
693
944
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
694
945
  strapi.get("webhookStore").addAllowedEvent(key, value);
695
946
  });
696
- getService$1("field-sizes").setCustomFieldInputSizes();
697
- await getService$1("components").syncConfigurations();
698
- await getService$1("content-types").syncConfigurations();
699
- 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();
700
951
  await history.bootstrap?.({ strapi });
952
+ await preview.bootstrap?.({ strapi });
701
953
  };
702
954
  const destroy = async ({ strapi: strapi2 }) => {
703
955
  await history.destroy?.({ strapi: strapi2 });
@@ -1187,7 +1439,8 @@ const admin = {
1187
1439
  };
1188
1440
  const routes = {
1189
1441
  admin,
1190
- ...history.routes ? history.routes : {}
1442
+ ...history.routes ? history.routes : {},
1443
+ ...preview.routes ? preview.routes : {}
1191
1444
  };
1192
1445
  const hasPermissionsSchema = strapiUtils.yup.object({
1193
1446
  actions: strapiUtils.yup.array().of(strapiUtils.yup.string()),
@@ -1198,6 +1451,11 @@ const { createPolicy } = strapiUtils.policy;
1198
1451
  const hasPermissions = createPolicy({
1199
1452
  name: "plugin::content-manager.hasPermissions",
1200
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
+ */
1201
1459
  handler(ctx, config = {}) {
1202
1460
  const { actions = [], hasAtLeastOne = false } = config;
1203
1461
  const { userAbility } = ctx.state;
@@ -1245,8 +1503,7 @@ const isSortable = (schema, name) => {
1245
1503
  if (!___default.default.has(schema.attributes, name)) {
1246
1504
  return false;
1247
1505
  }
1248
- if (schema.modelType === "component" && name === "id")
1249
- return false;
1506
+ if (schema.modelType === "component" && name === "id") return false;
1250
1507
  const attribute = schema.attributes[name];
1251
1508
  if (NON_SORTABLES.includes(attribute.type)) {
1252
1509
  return false;
@@ -1391,8 +1648,7 @@ const createDefaultSettings = async (schema) => {
1391
1648
  };
1392
1649
  };
1393
1650
  const syncSettings = async (configuration, schema) => {
1394
- if (fp.isEmpty(configuration.settings))
1395
- return createDefaultSettings(schema);
1651
+ if (fp.isEmpty(configuration.settings)) return createDefaultSettings(schema);
1396
1652
  const defaultField = getDefaultMainField(schema);
1397
1653
  const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
1398
1654
  return {
@@ -1439,7 +1695,7 @@ const createMetadasSchema = (schema) => {
1439
1695
  if (!value) {
1440
1696
  return strapiUtils.yup.string();
1441
1697
  }
1442
- const targetSchema = getService$1("content-types").findContentType(
1698
+ const targetSchema = getService$2("content-types").findContentType(
1443
1699
  schema.attributes[key].targetModel
1444
1700
  );
1445
1701
  if (!targetSchema) {
@@ -1568,8 +1824,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1568
1824
  }
1569
1825
  switch (attribute.type) {
1570
1826
  case "relation": {
1571
- if (canCreate(attributePath))
1572
- return body2;
1827
+ if (canCreate(attributePath)) return body2;
1573
1828
  return fp.set(attributePath, { set: [] }, body2);
1574
1829
  }
1575
1830
  case "component": {
@@ -1579,8 +1834,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1579
1834
  ]);
1580
1835
  }
1581
1836
  default: {
1582
- if (canCreate(attributePath))
1583
- return body2;
1837
+ if (canCreate(attributePath)) return body2;
1584
1838
  return fp.set(attributePath, null, body2);
1585
1839
  }
1586
1840
  }
@@ -1591,9 +1845,11 @@ const multipleLocaleSchema = strapiUtils.yup.lazy(
1591
1845
  (value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1592
1846
  );
1593
1847
  const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
1594
- const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
1848
+ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
1595
1849
  const { allowMultipleLocales } = opts;
1596
- const { locale, status, ...rest } = request || {};
1850
+ const { locale, status: providedStatus, ...rest } = request || {};
1851
+ const defaultStatus = strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
1852
+ const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
1597
1853
  const schema = strapiUtils.yup.object().shape({
1598
1854
  locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1599
1855
  status: statusSchema
@@ -1606,7 +1862,7 @@ const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales
1606
1862
  }
1607
1863
  };
1608
1864
  const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1609
- const documentMetadata2 = getService$1("document-metadata");
1865
+ const documentMetadata2 = getService$2("document-metadata");
1610
1866
  const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1611
1867
  let {
1612
1868
  meta: { availableLocales, availableStatus }
@@ -1632,8 +1888,8 @@ const createDocument = async (ctx, opts) => {
1632
1888
  const { userAbility, user } = ctx.state;
1633
1889
  const { model } = ctx.params;
1634
1890
  const { body } = ctx.request;
1635
- const documentManager2 = getService$1("document-manager");
1636
- 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 });
1637
1893
  if (permissionChecker2.cannot.create()) {
1638
1894
  throw new strapiUtils.errors.ForbiddenError();
1639
1895
  }
@@ -1641,7 +1897,7 @@ const createDocument = async (ctx, opts) => {
1641
1897
  const setCreator = strapiUtils.setCreatorFields({ user });
1642
1898
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1643
1899
  const sanitizedBody = await sanitizeFn(body);
1644
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(body);
1900
+ const { locale, status } = await getDocumentLocaleAndStatus(body, model);
1645
1901
  return documentManager2.create(model, {
1646
1902
  data: sanitizedBody,
1647
1903
  locale,
@@ -1653,14 +1909,14 @@ const updateDocument = async (ctx, opts) => {
1653
1909
  const { userAbility, user } = ctx.state;
1654
1910
  const { id, model } = ctx.params;
1655
1911
  const { body } = ctx.request;
1656
- const documentManager2 = getService$1("document-manager");
1657
- 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 });
1658
1914
  if (permissionChecker2.cannot.update()) {
1659
1915
  throw new strapiUtils.errors.ForbiddenError();
1660
1916
  }
1661
1917
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1662
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1663
- const { locale } = await getDocumentLocaleAndStatus(body);
1918
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1919
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1664
1920
  const [documentVersion, documentExists] = await Promise.all([
1665
1921
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1666
1922
  documentManager2.exists(model, id)
@@ -1676,7 +1932,7 @@ const updateDocument = async (ctx, opts) => {
1676
1932
  throw new strapiUtils.errors.ForbiddenError();
1677
1933
  }
1678
1934
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1679
- const setCreator = strapiUtils.setCreatorFields({ user, isEdition: true });
1935
+ const setCreator = documentVersion ? strapiUtils.setCreatorFields({ user, isEdition: true }) : strapiUtils.setCreatorFields({ user });
1680
1936
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1681
1937
  const sanitizedBody = await sanitizeFn(body);
1682
1938
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1690,15 +1946,15 @@ const collectionTypes = {
1690
1946
  const { userAbility } = ctx.state;
1691
1947
  const { model } = ctx.params;
1692
1948
  const { query } = ctx.request;
1693
- const documentMetadata2 = getService$1("document-metadata");
1694
- const documentManager2 = getService$1("document-manager");
1695
- 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 });
1696
1952
  if (permissionChecker2.cannot.read()) {
1697
1953
  return ctx.forbidden();
1698
1954
  }
1699
1955
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1700
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1701
- const { locale, status } = await getDocumentLocaleAndStatus(query);
1956
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1957
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1702
1958
  const { results: documents, pagination } = await documentManager2.findPage(
1703
1959
  { ...permissionQuery, populate, locale, status },
1704
1960
  model
@@ -1726,14 +1982,14 @@ const collectionTypes = {
1726
1982
  async findOne(ctx) {
1727
1983
  const { userAbility } = ctx.state;
1728
1984
  const { model, id } = ctx.params;
1729
- const documentManager2 = getService$1("document-manager");
1730
- 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 });
1731
1987
  if (permissionChecker2.cannot.read()) {
1732
1988
  return ctx.forbidden();
1733
1989
  }
1734
1990
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1735
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1736
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
1991
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1992
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1737
1993
  const version = await documentManager2.findOne(id, model, {
1738
1994
  populate,
1739
1995
  locale,
@@ -1748,7 +2004,7 @@ const collectionTypes = {
1748
2004
  permissionChecker2,
1749
2005
  model,
1750
2006
  // @ts-expect-error TODO: fix
1751
- { id, locale, publishedAt: null },
2007
+ { documentId: id, locale, publishedAt: null },
1752
2008
  { availableLocales: true, availableStatus: false }
1753
2009
  );
1754
2010
  ctx.body = { data: {}, meta };
@@ -1763,7 +2019,7 @@ const collectionTypes = {
1763
2019
  async create(ctx) {
1764
2020
  const { userAbility } = ctx.state;
1765
2021
  const { model } = ctx.params;
1766
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2022
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1767
2023
  const [totalEntries, document] = await Promise.all([
1768
2024
  strapi.db.query(model).count(),
1769
2025
  createDocument(ctx)
@@ -1784,7 +2040,7 @@ const collectionTypes = {
1784
2040
  async update(ctx) {
1785
2041
  const { userAbility } = ctx.state;
1786
2042
  const { model } = ctx.params;
1787
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2043
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1788
2044
  const updatedVersion = await updateDocument(ctx);
1789
2045
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1790
2046
  ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
@@ -1793,14 +2049,14 @@ const collectionTypes = {
1793
2049
  const { userAbility, user } = ctx.state;
1794
2050
  const { model, sourceId: id } = ctx.params;
1795
2051
  const { body } = ctx.request;
1796
- const documentManager2 = getService$1("document-manager");
1797
- 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 });
1798
2054
  if (permissionChecker2.cannot.create()) {
1799
2055
  return ctx.forbidden();
1800
2056
  }
1801
2057
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1802
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1803
- const { locale } = await getDocumentLocaleAndStatus(body);
2058
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2059
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1804
2060
  const document = await documentManager2.findOne(id, model, {
1805
2061
  populate,
1806
2062
  locale,
@@ -1838,14 +2094,14 @@ const collectionTypes = {
1838
2094
  async delete(ctx) {
1839
2095
  const { userAbility } = ctx.state;
1840
2096
  const { id, model } = ctx.params;
1841
- const documentManager2 = getService$1("document-manager");
1842
- 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 });
1843
2099
  if (permissionChecker2.cannot.delete()) {
1844
2100
  return ctx.forbidden();
1845
2101
  }
1846
2102
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1847
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1848
- const { locale } = await getDocumentLocaleAndStatus(ctx.query);
2103
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2104
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1849
2105
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1850
2106
  if (documentLocales.length === 0) {
1851
2107
  return ctx.notFound();
@@ -1866,19 +2122,42 @@ const collectionTypes = {
1866
2122
  const { userAbility } = ctx.state;
1867
2123
  const { id, model } = ctx.params;
1868
2124
  const { body } = ctx.request;
1869
- const documentManager2 = getService$1("document-manager");
1870
- 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 });
1871
2127
  if (permissionChecker2.cannot.publish()) {
1872
2128
  return ctx.forbidden();
1873
2129
  }
1874
2130
  const publishedDocument = await strapi.db.transaction(async () => {
1875
2131
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1876
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1877
- 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
+ }
1878
2158
  if (permissionChecker2.cannot.publish(document)) {
1879
2159
  throw new strapiUtils.errors.ForbiddenError();
1880
2160
  }
1881
- const { locale } = await getDocumentLocaleAndStatus(body);
1882
2161
  const publishResult = await documentManager2.publish(document.documentId, model, {
1883
2162
  locale
1884
2163
  // TODO: Allow setting creator fields on publish
@@ -1898,14 +2177,16 @@ const collectionTypes = {
1898
2177
  const { body } = ctx.request;
1899
2178
  const { documentIds } = body;
1900
2179
  await validateBulkActionInput(body);
1901
- const documentManager2 = getService$1("document-manager");
1902
- 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 });
1903
2182
  if (permissionChecker2.cannot.publish()) {
1904
2183
  return ctx.forbidden();
1905
2184
  }
1906
2185
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1907
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1908
- const { locale } = await getDocumentLocaleAndStatus(body, { allowMultipleLocales: true });
2186
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2187
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2188
+ allowMultipleLocales: true
2189
+ });
1909
2190
  const entityPromises = documentIds.map(
1910
2191
  (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
1911
2192
  );
@@ -1927,12 +2208,14 @@ const collectionTypes = {
1927
2208
  const { body } = ctx.request;
1928
2209
  const { documentIds } = body;
1929
2210
  await validateBulkActionInput(body);
1930
- const documentManager2 = getService$1("document-manager");
1931
- 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 });
1932
2213
  if (permissionChecker2.cannot.unpublish()) {
1933
2214
  return ctx.forbidden();
1934
2215
  }
1935
- const { locale } = await getDocumentLocaleAndStatus(body);
2216
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2217
+ allowMultipleLocales: true
2218
+ });
1936
2219
  const entityPromises = documentIds.map(
1937
2220
  (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1938
2221
  );
@@ -1955,8 +2238,8 @@ const collectionTypes = {
1955
2238
  const {
1956
2239
  body: { discardDraft, ...body }
1957
2240
  } = ctx.request;
1958
- const documentManager2 = getService$1("document-manager");
1959
- 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 });
1960
2243
  if (permissionChecker2.cannot.unpublish()) {
1961
2244
  return ctx.forbidden();
1962
2245
  }
@@ -1964,8 +2247,8 @@ const collectionTypes = {
1964
2247
  return ctx.forbidden();
1965
2248
  }
1966
2249
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1967
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1968
- const { locale } = await getDocumentLocaleAndStatus(body);
2250
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2251
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1969
2252
  const document = await documentManager2.findOne(id, model, {
1970
2253
  populate,
1971
2254
  locale,
@@ -1995,14 +2278,14 @@ const collectionTypes = {
1995
2278
  const { userAbility } = ctx.state;
1996
2279
  const { id, model } = ctx.params;
1997
2280
  const { body } = ctx.request;
1998
- const documentManager2 = getService$1("document-manager");
1999
- 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 });
2000
2283
  if (permissionChecker2.cannot.discard()) {
2001
2284
  return ctx.forbidden();
2002
2285
  }
2003
2286
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
2004
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2005
- const { locale } = await getDocumentLocaleAndStatus(body);
2287
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2288
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2006
2289
  const document = await documentManager2.findOne(id, model, {
2007
2290
  populate,
2008
2291
  locale,
@@ -2026,14 +2309,14 @@ const collectionTypes = {
2026
2309
  const { query, body } = ctx.request;
2027
2310
  const { documentIds } = body;
2028
2311
  await validateBulkActionInput(body);
2029
- const documentManager2 = getService$1("document-manager");
2030
- 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 });
2031
2314
  if (permissionChecker2.cannot.delete()) {
2032
2315
  return ctx.forbidden();
2033
2316
  }
2034
2317
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
2035
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2036
- const { locale } = await getDocumentLocaleAndStatus(body);
2318
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2319
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2037
2320
  const documentLocales = await documentManager2.findLocales(documentIds, model, {
2038
2321
  populate,
2039
2322
  locale
@@ -2053,14 +2336,14 @@ const collectionTypes = {
2053
2336
  async countDraftRelations(ctx) {
2054
2337
  const { userAbility } = ctx.state;
2055
2338
  const { model, id } = ctx.params;
2056
- const documentManager2 = getService$1("document-manager");
2057
- 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 });
2058
2341
  if (permissionChecker2.cannot.read()) {
2059
2342
  return ctx.forbidden();
2060
2343
  }
2061
2344
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2062
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2063
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
2345
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2346
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
2064
2347
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2065
2348
  if (!entity) {
2066
2349
  return ctx.notFound();
@@ -2078,8 +2361,8 @@ const collectionTypes = {
2078
2361
  const ids = ctx.request.query.documentIds;
2079
2362
  const locale = ctx.request.query.locale;
2080
2363
  const { model } = ctx.params;
2081
- const documentManager2 = getService$1("document-manager");
2082
- 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 });
2083
2366
  if (permissionChecker2.cannot.read()) {
2084
2367
  return ctx.forbidden();
2085
2368
  }
@@ -2103,13 +2386,13 @@ const collectionTypes = {
2103
2386
  };
2104
2387
  const components$1 = {
2105
2388
  findComponents(ctx) {
2106
- const components2 = getService$1("components").findAllComponents();
2107
- const { toDto } = getService$1("data-mapper");
2389
+ const components2 = getService$2("components").findAllComponents();
2390
+ const { toDto } = getService$2("data-mapper");
2108
2391
  ctx.body = { data: components2.map(toDto) };
2109
2392
  },
2110
2393
  async findComponentConfiguration(ctx) {
2111
2394
  const { uid: uid2 } = ctx.params;
2112
- const componentService = getService$1("components");
2395
+ const componentService = getService$2("components");
2113
2396
  const component = componentService.findComponent(uid2);
2114
2397
  if (!component) {
2115
2398
  return ctx.notFound("component.notFound");
@@ -2126,7 +2409,7 @@ const components$1 = {
2126
2409
  async updateComponentConfiguration(ctx) {
2127
2410
  const { uid: uid2 } = ctx.params;
2128
2411
  const { body } = ctx.request;
2129
- const componentService = getService$1("components");
2412
+ const componentService = getService$2("components");
2130
2413
  const component = componentService.findComponent(uid2);
2131
2414
  if (!component) {
2132
2415
  return ctx.notFound("component.notFound");
@@ -2160,12 +2443,12 @@ const contentTypes = {
2160
2443
  } catch (error) {
2161
2444
  return ctx.send({ error }, 400);
2162
2445
  }
2163
- const contentTypes2 = getService$1("content-types").findContentTypesByKind(kind);
2164
- const { toDto } = getService$1("data-mapper");
2446
+ const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
2447
+ const { toDto } = getService$2("data-mapper");
2165
2448
  ctx.body = { data: contentTypes2.map(toDto) };
2166
2449
  },
2167
2450
  async findContentTypesSettings(ctx) {
2168
- const { findAllContentTypes, findConfiguration } = getService$1("content-types");
2451
+ const { findAllContentTypes, findConfiguration } = getService$2("content-types");
2169
2452
  const contentTypes2 = await findAllContentTypes();
2170
2453
  const configurations = await Promise.all(
2171
2454
  contentTypes2.map(async (contentType) => {
@@ -2179,7 +2462,7 @@ const contentTypes = {
2179
2462
  },
2180
2463
  async findContentTypeConfiguration(ctx) {
2181
2464
  const { uid: uid2 } = ctx.params;
2182
- const contentTypeService = getService$1("content-types");
2465
+ const contentTypeService = getService$2("content-types");
2183
2466
  const contentType = await contentTypeService.findContentType(uid2);
2184
2467
  if (!contentType) {
2185
2468
  return ctx.notFound("contentType.notFound");
@@ -2201,13 +2484,13 @@ const contentTypes = {
2201
2484
  const { userAbility } = ctx.state;
2202
2485
  const { uid: uid2 } = ctx.params;
2203
2486
  const { body } = ctx.request;
2204
- const contentTypeService = getService$1("content-types");
2205
- const metricsService = getService$1("metrics");
2487
+ const contentTypeService = getService$2("content-types");
2488
+ const metricsService = getService$2("metrics");
2206
2489
  const contentType = await contentTypeService.findContentType(uid2);
2207
2490
  if (!contentType) {
2208
2491
  return ctx.notFound("contentType.notFound");
2209
2492
  }
2210
- if (!getService$1("permission").canConfigureContentType({ userAbility, contentType })) {
2493
+ if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
2211
2494
  return ctx.forbidden();
2212
2495
  }
2213
2496
  let input;
@@ -2240,10 +2523,10 @@ const contentTypes = {
2240
2523
  };
2241
2524
  const init = {
2242
2525
  getInitData(ctx) {
2243
- const { toDto } = getService$1("data-mapper");
2244
- const { findAllComponents } = getService$1("components");
2245
- const { getAllFieldSizes } = getService$1("field-sizes");
2246
- 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");
2247
2530
  ctx.body = {
2248
2531
  data: {
2249
2532
  fieldSizes: getAllFieldSizes(),
@@ -2279,36 +2562,41 @@ const addFiltersClause = (params, filtersClause) => {
2279
2562
  params.filters.$and.push(filtersClause);
2280
2563
  };
2281
2564
  const sanitizeMainField = (model, mainField, userAbility) => {
2282
- const permissionChecker2 = getService$1("permission-checker").create({
2565
+ const permissionChecker2 = getService$2("permission-checker").create({
2283
2566
  userAbility,
2284
2567
  model: model.uid
2285
2568
  });
2286
- if (!isListable(model, mainField)) {
2569
+ const isMainFieldListable = isListable(model, mainField);
2570
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2571
+ if (!isMainFieldListable || !canReadMainField) {
2287
2572
  return "id";
2288
2573
  }
2289
- if (permissionChecker2.cannot.read(null, mainField)) {
2290
- if (model.uid === "plugin::users-permissions.role") {
2291
- const userPermissionChecker = getService$1("permission-checker").create({
2292
- userAbility,
2293
- model: "plugin::users-permissions.user"
2294
- });
2295
- if (userPermissionChecker.can.read()) {
2296
- return "name";
2297
- }
2298
- }
2299
- return "id";
2574
+ if (model.uid === "plugin::users-permissions.role") {
2575
+ return "name";
2300
2576
  }
2301
2577
  return mainField;
2302
2578
  };
2303
- const addStatusToRelations = async (uid2, relations2) => {
2304
- if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.contentTypes[uid2])) {
2579
+ const addStatusToRelations = async (targetUid, relations2) => {
2580
+ if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(targetUid))) {
2581
+ return relations2;
2582
+ }
2583
+ const documentMetadata2 = getService$2("document-metadata");
2584
+ if (!relations2.length) {
2305
2585
  return relations2;
2306
2586
  }
2307
- const documentMetadata2 = getService$1("document-metadata");
2308
- const documentsAvailableStatus = await documentMetadata2.getManyAvailableStatus(uid2, relations2);
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
+ });
2309
2597
  return relations2.map((relation) => {
2310
- const availableStatuses = documentsAvailableStatus.filter(
2311
- (availableDocument) => availableDocument.documentId === relation.documentId
2598
+ const availableStatuses = availableStatus.filter(
2599
+ (availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
2312
2600
  );
2313
2601
  return {
2314
2602
  ...relation,
@@ -2329,11 +2617,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2329
2617
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2330
2618
  const isSourceLocalized = isLocalized(sourceModel);
2331
2619
  const isTargetLocalized = isLocalized(targetModel);
2332
- let validatedLocale = locale;
2333
- if (!targetModel || !isTargetLocalized)
2334
- validatedLocale = void 0;
2335
2620
  return {
2336
- locale: validatedLocale,
2621
+ locale,
2337
2622
  isSourceLocalized,
2338
2623
  isTargetLocalized
2339
2624
  };
@@ -2342,8 +2627,7 @@ const validateStatus = (sourceUid, status) => {
2342
2627
  const sourceModel = strapi.getModel(sourceUid);
2343
2628
  const isDP = strapiUtils.contentTypes.hasDraftAndPublish;
2344
2629
  const isSourceDP = isDP(sourceModel);
2345
- if (!isSourceDP)
2346
- return { status: void 0 };
2630
+ if (!isSourceDP) return { status: void 0 };
2347
2631
  switch (status) {
2348
2632
  case "published":
2349
2633
  return { status: "published" };
@@ -2373,7 +2657,7 @@ const relations = {
2373
2657
  ctx.request?.query?.locale
2374
2658
  );
2375
2659
  const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
2376
- const permissionChecker2 = getService$1("permission-checker").create({
2660
+ const permissionChecker2 = getService$2("permission-checker").create({
2377
2661
  userAbility,
2378
2662
  model
2379
2663
  });
@@ -2398,7 +2682,7 @@ const relations = {
2398
2682
  where.id = id;
2399
2683
  }
2400
2684
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2401
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2685
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2402
2686
  const currentEntity = await strapi.db.query(model).findOne({
2403
2687
  where,
2404
2688
  populate
@@ -2413,7 +2697,7 @@ const relations = {
2413
2697
  }
2414
2698
  entryId = currentEntity.id;
2415
2699
  }
2416
- 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);
2417
2701
  const targetSchema = strapi.getModel(targetUid);
2418
2702
  const mainField = fp.flow(
2419
2703
  fp.prop(`metadatas.${targetField}.edit.mainField`),
@@ -2436,7 +2720,7 @@ const relations = {
2436
2720
  attribute,
2437
2721
  fieldsToSelect,
2438
2722
  mainField,
2439
- source: { schema: sourceSchema },
2723
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2440
2724
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2441
2725
  sourceSchema,
2442
2726
  targetSchema,
@@ -2458,7 +2742,8 @@ const relations = {
2458
2742
  fieldsToSelect,
2459
2743
  mainField,
2460
2744
  source: {
2461
- schema: { uid: sourceUid, modelType: sourceModelType }
2745
+ schema: { uid: sourceUid, modelType: sourceModelType },
2746
+ isLocalized: isSourceLocalized
2462
2747
  },
2463
2748
  target: {
2464
2749
  schema: { uid: targetUid },
@@ -2466,7 +2751,7 @@ const relations = {
2466
2751
  }
2467
2752
  } = await this.extractAndValidateRequestInfo(ctx, id);
2468
2753
  const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
2469
- const permissionChecker2 = getService$1("permission-checker").create({
2754
+ const permissionChecker2 = getService$2("permission-checker").create({
2470
2755
  userAbility: ctx.state.userAbility,
2471
2756
  model: targetUid
2472
2757
  });
@@ -2496,12 +2781,16 @@ const relations = {
2496
2781
  } else {
2497
2782
  where.id = id;
2498
2783
  }
2499
- if (status) {
2500
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2784
+ const publishedAt = getPublishedAtClause(status, targetUid);
2785
+ if (!fp.isEmpty(publishedAt)) {
2786
+ where[`${alias}.published_at`] = publishedAt;
2501
2787
  }
2502
- if (filterByLocale) {
2788
+ if (isTargetLocalized && locale) {
2503
2789
  where[`${alias}.locale`] = locale;
2504
2790
  }
2791
+ if (isSourceLocalized && locale) {
2792
+ where.locale = locale;
2793
+ }
2505
2794
  if ((idsToInclude?.length ?? 0) !== 0) {
2506
2795
  where[`${alias}.id`].$notIn = idsToInclude;
2507
2796
  }
@@ -2519,7 +2808,8 @@ const relations = {
2519
2808
  id: { $notIn: fp.uniq(idsToOmit) }
2520
2809
  });
2521
2810
  }
2522
- 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);
2523
2813
  ctx.body = {
2524
2814
  ...res,
2525
2815
  results: await addStatusToRelations(targetUid, res.results)
@@ -2534,29 +2824,39 @@ const relations = {
2534
2824
  attribute,
2535
2825
  targetField,
2536
2826
  fieldsToSelect,
2537
- source: {
2538
- schema: { uid: sourceUid }
2539
- },
2540
- target: {
2541
- schema: { uid: targetUid }
2542
- }
2827
+ status,
2828
+ source: { schema: sourceSchema },
2829
+ target: { schema: targetSchema }
2543
2830
  } = await this.extractAndValidateRequestInfo(ctx, id);
2544
- 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 });
2545
2834
  const dbQuery = strapi.db.query(sourceUid);
2546
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
+ }
2547
2848
  const res = await loadRelations({ id: entryId }, targetField, {
2548
- select: ["id", "documentId", "locale", "publishedAt"],
2849
+ select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
2549
2850
  ordering: "desc",
2550
2851
  page: ctx.request.query.page,
2551
- pageSize: ctx.request.query.pageSize
2852
+ pageSize: ctx.request.query.pageSize,
2853
+ filters
2552
2854
  });
2553
2855
  const loadedIds = res.results.map((item) => item.id);
2554
2856
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2555
2857
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2556
2858
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2557
- ordering: "desc",
2558
- page: ctx.request.query.page,
2559
- pageSize: ctx.request.query.pageSize
2859
+ ordering: "desc"
2560
2860
  });
2561
2861
  const relationsUnion = fp.uniqBy("id", fp.concat(sanitizedRes.results, res.results));
2562
2862
  ctx.body = {
@@ -2571,10 +2871,10 @@ const relations = {
2571
2871
  }
2572
2872
  };
2573
2873
  const buildPopulateFromQuery = async (query, model) => {
2574
- 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();
2575
2875
  };
2576
2876
  const findDocument = async (query, uid2, opts = {}) => {
2577
- const documentManager2 = getService$1("document-manager");
2877
+ const documentManager2 = getService$2("document-manager");
2578
2878
  const populate = await buildPopulateFromQuery(query, uid2);
2579
2879
  return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
2580
2880
  };
@@ -2582,13 +2882,13 @@ const createOrUpdateDocument = async (ctx, opts) => {
2582
2882
  const { user, userAbility } = ctx.state;
2583
2883
  const { model } = ctx.params;
2584
2884
  const { body, query } = ctx.request;
2585
- const documentManager2 = getService$1("document-manager");
2586
- 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 });
2587
2887
  if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
2588
2888
  throw new strapiUtils.errors.ForbiddenError();
2589
2889
  }
2590
2890
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2591
- const { locale } = await getDocumentLocaleAndStatus(body);
2891
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2592
2892
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2593
2893
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2594
2894
  // Find the first document to check if it exists
@@ -2624,12 +2924,12 @@ const singleTypes = {
2624
2924
  const { userAbility } = ctx.state;
2625
2925
  const { model } = ctx.params;
2626
2926
  const { query = {} } = ctx.request;
2627
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2927
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2628
2928
  if (permissionChecker2.cannot.read()) {
2629
2929
  return ctx.forbidden();
2630
2930
  }
2631
2931
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2632
- const { locale, status } = await getDocumentLocaleAndStatus(query);
2932
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
2633
2933
  const version = await findDocument(permissionQuery, model, { locale, status });
2634
2934
  if (!version) {
2635
2935
  if (permissionChecker2.cannot.create()) {
@@ -2643,7 +2943,7 @@ const singleTypes = {
2643
2943
  permissionChecker2,
2644
2944
  model,
2645
2945
  // @ts-expect-error - fix types
2646
- { id: document.documentId, locale, publishedAt: null },
2946
+ { documentId: document.documentId, locale, publishedAt: null },
2647
2947
  { availableLocales: true, availableStatus: false }
2648
2948
  );
2649
2949
  ctx.body = { data: {}, meta };
@@ -2658,7 +2958,7 @@ const singleTypes = {
2658
2958
  async createOrUpdate(ctx) {
2659
2959
  const { userAbility } = ctx.state;
2660
2960
  const { model } = ctx.params;
2661
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2961
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2662
2962
  const document = await createOrUpdateDocument(ctx);
2663
2963
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2664
2964
  ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
@@ -2667,14 +2967,14 @@ const singleTypes = {
2667
2967
  const { userAbility } = ctx.state;
2668
2968
  const { model } = ctx.params;
2669
2969
  const { query = {} } = ctx.request;
2670
- const documentManager2 = getService$1("document-manager");
2671
- 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 });
2672
2972
  if (permissionChecker2.cannot.delete()) {
2673
2973
  return ctx.forbidden();
2674
2974
  }
2675
2975
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2676
2976
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2677
- const { locale } = await getDocumentLocaleAndStatus(query);
2977
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2678
2978
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2679
2979
  populate,
2680
2980
  locale
@@ -2696,8 +2996,8 @@ const singleTypes = {
2696
2996
  const { userAbility } = ctx.state;
2697
2997
  const { model } = ctx.params;
2698
2998
  const { query = {} } = ctx.request;
2699
- const documentManager2 = getService$1("document-manager");
2700
- 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 });
2701
3001
  if (permissionChecker2.cannot.publish()) {
2702
3002
  return ctx.forbidden();
2703
3003
  }
@@ -2711,7 +3011,7 @@ const singleTypes = {
2711
3011
  if (permissionChecker2.cannot.publish(document)) {
2712
3012
  throw new strapiUtils.errors.ForbiddenError();
2713
3013
  }
2714
- const { locale } = await getDocumentLocaleAndStatus(document);
3014
+ const { locale } = await getDocumentLocaleAndStatus(document, model);
2715
3015
  const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2716
3016
  return publishResult.at(0);
2717
3017
  });
@@ -2725,8 +3025,8 @@ const singleTypes = {
2725
3025
  body: { discardDraft, ...body },
2726
3026
  query = {}
2727
3027
  } = ctx.request;
2728
- const documentManager2 = getService$1("document-manager");
2729
- 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 });
2730
3030
  if (permissionChecker2.cannot.unpublish()) {
2731
3031
  return ctx.forbidden();
2732
3032
  }
@@ -2734,7 +3034,7 @@ const singleTypes = {
2734
3034
  return ctx.forbidden();
2735
3035
  }
2736
3036
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2737
- const { locale } = await getDocumentLocaleAndStatus(body);
3037
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2738
3038
  const document = await findDocument(sanitizedQuery, model, { locale });
2739
3039
  if (!document) {
2740
3040
  return ctx.notFound();
@@ -2760,13 +3060,13 @@ const singleTypes = {
2760
3060
  const { userAbility } = ctx.state;
2761
3061
  const { model } = ctx.params;
2762
3062
  const { body, query = {} } = ctx.request;
2763
- const documentManager2 = getService$1("document-manager");
2764
- 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 });
2765
3065
  if (permissionChecker2.cannot.discard()) {
2766
3066
  return ctx.forbidden();
2767
3067
  }
2768
3068
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2769
- const { locale } = await getDocumentLocaleAndStatus(body);
3069
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2770
3070
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2771
3071
  if (!document) {
2772
3072
  return ctx.notFound();
@@ -2784,9 +3084,9 @@ const singleTypes = {
2784
3084
  const { userAbility } = ctx.state;
2785
3085
  const { model } = ctx.params;
2786
3086
  const { query } = ctx.request;
2787
- const documentManager2 = getService$1("document-manager");
2788
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2789
- const { locale } = await getDocumentLocaleAndStatus(query);
3087
+ const documentManager2 = getService$2("document-manager");
3088
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
3089
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2790
3090
  if (permissionChecker2.cannot.read()) {
2791
3091
  return ctx.forbidden();
2792
3092
  }
@@ -2807,9 +3107,9 @@ const uid$1 = {
2807
3107
  async generateUID(ctx) {
2808
3108
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2809
3109
  const { query = {} } = ctx.request;
2810
- const { locale } = await getDocumentLocaleAndStatus(query);
3110
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2811
3111
  await validateUIDField(contentTypeUID, field);
2812
- const uidService = getService$1("uid");
3112
+ const uidService = getService$2("uid");
2813
3113
  ctx.body = {
2814
3114
  data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
2815
3115
  };
@@ -2819,9 +3119,9 @@ const uid$1 = {
2819
3119
  ctx.request.body
2820
3120
  );
2821
3121
  const { query = {} } = ctx.request;
2822
- const { locale } = await getDocumentLocaleAndStatus(query);
3122
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2823
3123
  await validateUIDField(contentTypeUID, field);
2824
- const uidService = getService$1("uid");
3124
+ const uidService = getService$2("uid");
2825
3125
  const isAvailable = await uidService.checkUIDAvailability({
2826
3126
  contentTypeUID,
2827
3127
  field,
@@ -2842,7 +3142,8 @@ const controllers = {
2842
3142
  relations,
2843
3143
  "single-types": singleTypes,
2844
3144
  uid: uid$1,
2845
- ...history.controllers ? history.controllers : {}
3145
+ ...history.controllers ? history.controllers : {},
3146
+ ...preview.controllers ? preview.controllers : {}
2846
3147
  };
2847
3148
  const keys = {
2848
3149
  CONFIGURATION: "configuration"
@@ -2971,18 +3272,15 @@ async function syncMetadatas(configuration, schema) {
2971
3272
  ___default.default.set(updatedMeta, ["list", "searchable"], false);
2972
3273
  ___default.default.set(acc, [key], updatedMeta);
2973
3274
  }
2974
- if (!___default.default.has(edit, "mainField"))
2975
- return acc;
3275
+ if (!___default.default.has(edit, "mainField")) return acc;
2976
3276
  if (!isRelation$1(attr)) {
2977
3277
  ___default.default.set(updatedMeta, "edit", ___default.default.omit(edit, ["mainField"]));
2978
3278
  ___default.default.set(acc, [key], updatedMeta);
2979
3279
  return acc;
2980
3280
  }
2981
- if (edit.mainField === "id")
2982
- return acc;
3281
+ if (edit.mainField === "id") return acc;
2983
3282
  const targetSchema = getTargetSchema(attr.targetModel);
2984
- if (!targetSchema)
2985
- return acc;
3283
+ if (!targetSchema) return acc;
2986
3284
  if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
2987
3285
  ___default.default.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
2988
3286
  ___default.default.set(acc, [key], updatedMeta);
@@ -2993,12 +3291,12 @@ async function syncMetadatas(configuration, schema) {
2993
3291
  return ___default.default.assign(metasWithDefaults, updatedMetas);
2994
3292
  }
2995
3293
  const getTargetSchema = (targetModel) => {
2996
- return getService$1("content-types").findContentType(targetModel);
3294
+ return getService$2("content-types").findContentType(targetModel);
2997
3295
  };
2998
3296
  const DEFAULT_LIST_LENGTH = 4;
2999
3297
  const MAX_ROW_SIZE = 12;
3000
3298
  const isAllowedFieldSize = (type, size) => {
3001
- const { getFieldSize } = getService$1("field-sizes");
3299
+ const { getFieldSize } = getService$2("field-sizes");
3002
3300
  const fieldSize = getFieldSize(type);
3003
3301
  if (!fieldSize.isResizable && size !== fieldSize.default) {
3004
3302
  return false;
@@ -3006,7 +3304,7 @@ const isAllowedFieldSize = (type, size) => {
3006
3304
  return size <= MAX_ROW_SIZE;
3007
3305
  };
3008
3306
  const getDefaultFieldSize = (attribute) => {
3009
- const { hasFieldSize, getFieldSize } = getService$1("field-sizes");
3307
+ const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
3010
3308
  return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
3011
3309
  };
3012
3310
  async function createDefaultLayouts(schema) {
@@ -3027,8 +3325,7 @@ function createDefaultEditLayout(schema) {
3027
3325
  return appendToEditLayout([], keys2, schema);
3028
3326
  }
3029
3327
  function syncLayouts(configuration, schema) {
3030
- if (___default.default.isEmpty(configuration.layouts))
3031
- return createDefaultLayouts(schema);
3328
+ if (___default.default.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
3032
3329
  const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
3033
3330
  let cleanList = list.filter((attr) => isListable(schema, attr));
3034
3331
  const cleanEditRelations = editRelations.filter(
@@ -3039,9 +3336,8 @@ function syncLayouts(configuration, schema) {
3039
3336
  for (const row of edit) {
3040
3337
  const newRow = [];
3041
3338
  for (const el of row) {
3042
- if (!hasEditableAttribute(schema, el.name))
3043
- continue;
3044
- const { hasFieldSize } = getService$1("field-sizes");
3339
+ if (!hasEditableAttribute(schema, el.name)) continue;
3340
+ const { hasFieldSize } = getService$2("field-sizes");
3045
3341
  const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
3046
3342
  if (!isAllowedFieldSize(fieldType, el.size)) {
3047
3343
  elementsToReAppend.push(el.name);
@@ -3071,8 +3367,7 @@ function syncLayouts(configuration, schema) {
3071
3367
  };
3072
3368
  }
3073
3369
  const appendToEditLayout = (layout = [], keysToAppend, schema) => {
3074
- if (keysToAppend.length === 0)
3075
- return layout;
3370
+ if (keysToAppend.length === 0) return layout;
3076
3371
  let currentRowIndex = Math.max(layout.length - 1, 0);
3077
3372
  if (!layout[currentRowIndex]) {
3078
3373
  layout[currentRowIndex] = [];
@@ -3181,17 +3476,17 @@ const configurationService$1 = createConfigurationService({
3181
3476
  isComponent: true,
3182
3477
  prefix: STORE_KEY_PREFIX,
3183
3478
  getModels() {
3184
- const { toContentManagerModel } = getService$1("data-mapper");
3479
+ const { toContentManagerModel } = getService$2("data-mapper");
3185
3480
  return fp.mapValues(toContentManagerModel, strapi.components);
3186
3481
  }
3187
3482
  });
3188
3483
  const components = ({ strapi: strapi2 }) => ({
3189
3484
  findAllComponents() {
3190
- const { toContentManagerModel } = getService$1("data-mapper");
3485
+ const { toContentManagerModel } = getService$2("data-mapper");
3191
3486
  return Object.values(strapi2.components).map(toContentManagerModel);
3192
3487
  },
3193
3488
  findComponent(uid2) {
3194
- const { toContentManagerModel } = getService$1("data-mapper");
3489
+ const { toContentManagerModel } = getService$2("data-mapper");
3195
3490
  const component = strapi2.components[uid2];
3196
3491
  return fp.isNil(component) ? component : toContentManagerModel(component);
3197
3492
  },
@@ -3242,17 +3537,17 @@ const configurationService = createConfigurationService({
3242
3537
  storeUtils,
3243
3538
  prefix: "content_types",
3244
3539
  getModels() {
3245
- const { toContentManagerModel } = getService$1("data-mapper");
3540
+ const { toContentManagerModel } = getService$2("data-mapper");
3246
3541
  return fp.mapValues(toContentManagerModel, strapi.contentTypes);
3247
3542
  }
3248
3543
  });
3249
3544
  const service = ({ strapi: strapi2 }) => ({
3250
3545
  findAllContentTypes() {
3251
- const { toContentManagerModel } = getService$1("data-mapper");
3546
+ const { toContentManagerModel } = getService$2("data-mapper");
3252
3547
  return Object.values(strapi2.contentTypes).map(toContentManagerModel);
3253
3548
  },
3254
3549
  findContentType(uid2) {
3255
- const { toContentManagerModel } = getService$1("data-mapper");
3550
+ const { toContentManagerModel } = getService$2("data-mapper");
3256
3551
  const contentType = strapi2.contentTypes[uid2];
3257
3552
  return fp.isNil(contentType) ? contentType : toContentManagerModel(contentType);
3258
3553
  },
@@ -3281,7 +3576,7 @@ const service = ({ strapi: strapi2 }) => ({
3281
3576
  return this.findConfiguration(contentType);
3282
3577
  },
3283
3578
  findComponentsConfigurations(contentType) {
3284
- return getService$1("components").findComponentsConfigurations(contentType);
3579
+ return getService$2("components").findComponentsConfigurations(contentType);
3285
3580
  },
3286
3581
  syncConfigurations() {
3287
3582
  return configurationService.syncConfigurations();
@@ -3462,12 +3757,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3462
3757
  ability: userAbility,
3463
3758
  model
3464
3759
  });
3465
- 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
+ };
3466
3764
  const can = (action, entity, field) => {
3467
- 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
+ );
3468
3772
  };
3469
3773
  const cannot = (action, entity, field) => {
3470
- 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
+ );
3471
3781
  };
3472
3782
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3473
3783
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3538,7 +3848,7 @@ const permission = ({ strapi: strapi2 }) => ({
3538
3848
  return userAbility.can(action);
3539
3849
  },
3540
3850
  async registerPermissions() {
3541
- const displayedContentTypes = getService$1("content-types").findDisplayedContentTypes();
3851
+ const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
3542
3852
  const contentTypesUids = displayedContentTypes.map(fp.prop("uid"));
3543
3853
  const actions = [
3544
3854
  {
@@ -3623,6 +3933,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
3623
3933
  if (initialPopulate) {
3624
3934
  return initialPopulate;
3625
3935
  }
3936
+ if (attributeName === "localizations") {
3937
+ const validationPopulate = getPopulateForValidation(model.uid);
3938
+ return {
3939
+ populate: validationPopulate.populate
3940
+ };
3941
+ }
3626
3942
  if (!isVisibleAttribute$1(model, attributeName)) {
3627
3943
  return true;
3628
3944
  }
@@ -3682,6 +3998,9 @@ const getDeepPopulate = (uid2, {
3682
3998
  return {};
3683
3999
  }
3684
4000
  const model = strapi.getModel(uid2);
4001
+ if (!model) {
4002
+ return {};
4003
+ }
3685
4004
  return Object.keys(model.attributes).reduce(
3686
4005
  (populateAcc, attributeName) => fp.merge(
3687
4006
  populateAcc,
@@ -3701,40 +4020,46 @@ const getDeepPopulate = (uid2, {
3701
4020
  {}
3702
4021
  );
3703
4022
  };
3704
- const getValidatableFieldsPopulate = (uid2, {
3705
- initialPopulate = {},
3706
- countMany = false,
3707
- countOne = false,
3708
- maxLevel = Infinity
3709
- } = {}, level = 1) => {
3710
- if (level > maxLevel) {
4023
+ const getPopulateForValidation = (uid2) => {
4024
+ const model = strapi.getModel(uid2);
4025
+ if (!model) {
3711
4026
  return {};
3712
4027
  }
3713
- const model = strapi.getModel(uid2);
3714
4028
  return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
3715
- if (!getDoesAttributeRequireValidation(attribute)) {
4029
+ if (isScalarAttribute(attribute)) {
4030
+ if (getDoesAttributeRequireValidation(attribute)) {
4031
+ populateAcc.fields = populateAcc.fields || [];
4032
+ populateAcc.fields.push(attributeName);
4033
+ }
3716
4034
  return populateAcc;
3717
4035
  }
3718
- if (isScalarAttribute(attribute)) {
3719
- return fp.merge(populateAcc, {
3720
- [attributeName]: true
3721
- });
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;
3722
4044
  }
3723
- return fp.merge(
3724
- populateAcc,
3725
- getPopulateFor(
3726
- attributeName,
3727
- model,
3728
- {
3729
- // @ts-expect-error - improve types
3730
- initialPopulate: initialPopulate?.[attributeName],
3731
- countMany,
3732
- countOne,
3733
- 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;
3734
4054
  },
3735
- level
3736
- )
3737
- );
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;
3738
4063
  }, {});
3739
4064
  };
3740
4065
  const getDeepPopulateDraftCount = (uid2) => {
@@ -3744,6 +4069,10 @@ const getDeepPopulateDraftCount = (uid2) => {
3744
4069
  const attribute = model.attributes[attributeName];
3745
4070
  switch (attribute.type) {
3746
4071
  case "relation": {
4072
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
4073
+ if (isMorphRelation) {
4074
+ break;
4075
+ }
3747
4076
  if (isVisibleAttribute$1(model, attributeName)) {
3748
4077
  populateAcc[attributeName] = {
3749
4078
  count: true,
@@ -3810,7 +4139,7 @@ const getQueryPopulate = async (uid2, query) => {
3810
4139
  return populateQuery;
3811
4140
  };
3812
4141
  const buildDeepPopulate = (uid2) => {
3813
- return getService$1("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
4142
+ return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
3814
4143
  };
3815
4144
  const populateBuilder = (uid2) => {
3816
4145
  let getInitialPopulate = async () => {
@@ -3972,7 +4301,6 @@ const AVAILABLE_LOCALES_FIELDS = [
3972
4301
  "locale",
3973
4302
  "updatedAt",
3974
4303
  "createdAt",
3975
- "status",
3976
4304
  "publishedAt",
3977
4305
  "documentId"
3978
4306
  ];
@@ -3993,34 +4321,20 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3993
4321
  /**
3994
4322
  * Returns available locales of a document for the current status
3995
4323
  */
3996
- async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
4324
+ async getAvailableLocales(uid2, version, allVersions) {
3997
4325
  const versionsByLocale = fp.groupBy("locale", allVersions);
3998
- delete versionsByLocale[version.locale];
4326
+ if (version.locale) {
4327
+ delete versionsByLocale[version.locale];
4328
+ }
3999
4329
  const model = strapi2.getModel(uid2);
4000
- const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
4001
- const traversalFunction = async (localeVersion) => strapiUtils.traverseEntity(
4002
- ({ key }, { remove }) => {
4003
- if (keysToKeep.includes(key)) {
4004
- return;
4005
- }
4006
- remove(key);
4007
- },
4008
- { schema: model, getModel: strapi2.getModel.bind(strapi2) },
4009
- // @ts-expect-error fix types DocumentVersion incompatible with Data
4010
- localeVersion
4011
- );
4012
4330
  const mappingResult = await strapiUtils.async.map(
4013
4331
  Object.values(versionsByLocale),
4014
4332
  async (localeVersions) => {
4015
- const mappedLocaleVersions = await strapiUtils.async.map(
4016
- localeVersions,
4017
- traversalFunction
4018
- );
4019
4333
  if (!strapiUtils.contentTypes.hasDraftAndPublish(model)) {
4020
- return mappedLocaleVersions[0];
4334
+ return localeVersions[0];
4021
4335
  }
4022
- const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
4023
- 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);
4024
4338
  if (!draftVersion) {
4025
4339
  return;
4026
4340
  }
@@ -4042,8 +4356,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4042
4356
  const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
4043
4357
  return matchLocale && matchStatus;
4044
4358
  });
4045
- if (!availableStatus)
4046
- return availableStatus;
4359
+ if (!availableStatus) return availableStatus;
4047
4360
  return fp.pick(AVAILABLE_STATUS_FIELDS, availableStatus);
4048
4361
  },
4049
4362
  /**
@@ -4053,18 +4366,19 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4053
4366
  * @returns
4054
4367
  */
4055
4368
  async getManyAvailableStatus(uid2, documents) {
4056
- if (!documents.length)
4057
- return [];
4369
+ if (!documents.length) return [];
4058
4370
  const status = documents[0].publishedAt !== null ? "published" : "draft";
4059
- const locale = documents[0]?.locale;
4060
- const otherStatus = status === "published" ? "draft" : "published";
4061
- return strapi2.documents(uid2).findMany({
4062
- filters: {
4063
- documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) }
4064
- },
4065
- status: otherStatus,
4066
- locale,
4067
- 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"]
4068
4382
  });
4069
4383
  },
4070
4384
  getStatus(version, otherDocumentStatuses) {
@@ -4081,10 +4395,8 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4081
4395
  } else if (otherVersion) {
4082
4396
  draftVersion = otherVersion;
4083
4397
  }
4084
- if (!draftVersion)
4085
- return CONTENT_MANAGER_STATUS.PUBLISHED;
4086
- if (!publishedVersion)
4087
- return CONTENT_MANAGER_STATUS.DRAFT;
4398
+ if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
4399
+ if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
4088
4400
  const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4089
4401
  return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
4090
4402
  },
@@ -4092,11 +4404,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4092
4404
  // We could refactor this so the locales are only loaded when they're
4093
4405
  // needed. e.g. in the bulk locale action modal.
4094
4406
  async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
4095
- const populate = getValidatableFieldsPopulate(uid2);
4096
- const versions = await strapi2.db.query(uid2).findMany({
4097
- where: { documentId: version.documentId },
4407
+ const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
4408
+ const params = {
4098
4409
  populate: {
4099
- // Populate only fields that require validation for bulk locale actions
4100
4410
  ...populate,
4101
4411
  // NOTE: creator fields are selected in this way to avoid exposing sensitive data
4102
4412
  createdBy: {
@@ -4105,9 +4415,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4105
4415
  updatedBy: {
4106
4416
  select: ["id", "firstname", "lastname", "email"]
4107
4417
  }
4418
+ },
4419
+ fields: fp.uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
4420
+ filters: {
4421
+ documentId: version.documentId
4108
4422
  }
4109
- });
4110
- 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) : [];
4111
4427
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
4112
4428
  return {
4113
4429
  availableLocales: availableLocalesResult,
@@ -4121,13 +4437,29 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4121
4437
  */
4122
4438
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
4123
4439
  if (!document) {
4124
- return document;
4440
+ return {
4441
+ data: document,
4442
+ meta: {
4443
+ availableLocales: [],
4444
+ availableStatus: []
4445
+ }
4446
+ };
4125
4447
  }
4126
4448
  const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
4127
4449
  if (!hasDraftAndPublish) {
4128
4450
  opts.availableStatus = false;
4129
4451
  }
4130
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
+ }
4131
4463
  return {
4132
4464
  data: {
4133
4465
  ...document,
@@ -4229,10 +4561,7 @@ const documentManager = ({ strapi: strapi2 }) => {
4229
4561
  async clone(id, body, uid2) {
4230
4562
  const populate = await buildDeepPopulate(uid2);
4231
4563
  const params = {
4232
- data: {
4233
- ...omitIdField(body),
4234
- [PUBLISHED_AT_ATTRIBUTE]: null
4235
- },
4564
+ data: omitIdField(body),
4236
4565
  populate
4237
4566
  };
4238
4567
  return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
@@ -4348,7 +4677,8 @@ const services = {
4348
4677
  permission,
4349
4678
  "populate-builder": populateBuilder$1,
4350
4679
  uid,
4351
- ...history.services ? history.services : {}
4680
+ ...history.services ? history.services : {},
4681
+ ...preview.services ? preview.services : {}
4352
4682
  };
4353
4683
  const index = () => {
4354
4684
  return {