@strapi/content-manager 0.0.0-experimental.17b4116f461a49b8ce5386f7c8d79c511d40fb3b → 0.0.0-experimental.19d775295eb622de3e659110caf22fcd2cd5d10d

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 (264) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
  3. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
  4. package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
  5. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
  6. package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs → ComponentConfigurationPage-B_99pmC0.mjs} +4 -4
  7. package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs.map → ComponentConfigurationPage-B_99pmC0.mjs.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js → ComponentConfigurationPage-NeMPjY5M.js} +5 -6
  9. package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js.map → ComponentConfigurationPage-NeMPjY5M.js.map} +1 -1
  10. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-CRbtQEUV.js} +9 -4
  11. package/dist/_chunks/ComponentIcon-CRbtQEUV.js.map +1 -0
  12. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  13. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  14. package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs → EditConfigurationPage-B0kNlNoj.mjs} +4 -4
  15. package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs.map → EditConfigurationPage-B0kNlNoj.mjs.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js → EditConfigurationPage-n7_xHayb.js} +5 -6
  17. package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js.map → EditConfigurationPage-n7_xHayb.js.map} +1 -1
  18. package/dist/_chunks/EditViewPage-BT7Achc-.js +209 -0
  19. package/dist/_chunks/EditViewPage-BT7Achc-.js.map +1 -0
  20. package/dist/_chunks/EditViewPage-DYXZs4_2.mjs +191 -0
  21. package/dist/_chunks/EditViewPage-DYXZs4_2.mjs.map +1 -0
  22. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  23. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  24. package/dist/_chunks/{Form-CQ67ZifP.js → Form-BRmk2Dp3.js} +68 -49
  25. package/dist/_chunks/Form-BRmk2Dp3.js.map +1 -0
  26. package/dist/_chunks/{Form-Jgh5hGTu.mjs → Form-D3paRF1F.mjs} +67 -46
  27. package/dist/_chunks/Form-D3paRF1F.mjs.map +1 -0
  28. package/dist/_chunks/{History-BLEnudTX.js → History-BQpDoOu8.js} +211 -148
  29. package/dist/_chunks/History-BQpDoOu8.js.map +1 -0
  30. package/dist/_chunks/{History-DKhZAPcK.mjs → History-CzQbTOwa.mjs} +204 -139
  31. package/dist/_chunks/History-CzQbTOwa.mjs.map +1 -0
  32. package/dist/_chunks/{Field-kVFO4ZKB.mjs → Input-ww3KFYZr.mjs} +1996 -1730
  33. package/dist/_chunks/Input-ww3KFYZr.mjs.map +1 -0
  34. package/dist/_chunks/{Field-kq1c2TF1.js → Input-yM6HnyQa.js} +2035 -1770
  35. package/dist/_chunks/Input-yM6HnyQa.js.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-Zso_LUjn.js → ListConfigurationPage-B6NsS-0m.js} +72 -63
  37. package/dist/_chunks/ListConfigurationPage-B6NsS-0m.js.map +1 -0
  38. package/dist/_chunks/{ListConfigurationPage-nrXcxNYi.mjs → ListConfigurationPage-Bbw8w5cS.mjs} +68 -57
  39. package/dist/_chunks/ListConfigurationPage-Bbw8w5cS.mjs.map +1 -0
  40. package/dist/_chunks/{ListViewPage-ChhYmA-L.mjs → ListViewPage-DnOP55pM.mjs} +179 -160
  41. package/dist/_chunks/ListViewPage-DnOP55pM.mjs.map +1 -0
  42. package/dist/_chunks/{ListViewPage-DsaOakWQ.js → ListViewPage-Dt8OUTwO.js} +183 -165
  43. package/dist/_chunks/ListViewPage-Dt8OUTwO.js.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-BrdFcN33.mjs → NoContentTypePage-CXKXHNMa.mjs} +3 -3
  45. package/dist/_chunks/NoContentTypePage-CXKXHNMa.mjs.map +1 -0
  46. package/dist/_chunks/{NoContentTypePage-DPCuS9Y1.js → NoContentTypePage-Dgm-uj-6.js} +3 -3
  47. package/dist/_chunks/NoContentTypePage-Dgm-uj-6.js.map +1 -0
  48. package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js → NoPermissionsPage-CLbU5SOt.js} +2 -2
  49. package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js.map → NoPermissionsPage-CLbU5SOt.js.map} +1 -1
  50. package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs → NoPermissionsPage-kaj1rPiW.mjs} +2 -2
  51. package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs.map → NoPermissionsPage-kaj1rPiW.mjs.map} +1 -1
  52. package/dist/_chunks/Preview-Bieh13Ro.mjs +287 -0
  53. package/dist/_chunks/Preview-Bieh13Ro.mjs.map +1 -0
  54. package/dist/_chunks/Preview-CbXHXqBg.js +305 -0
  55. package/dist/_chunks/Preview-CbXHXqBg.js.map +1 -0
  56. package/dist/_chunks/{Relations-DjFiYd7-.mjs → Relations-7rWJcZ3_.mjs} +138 -94
  57. package/dist/_chunks/Relations-7rWJcZ3_.mjs.map +1 -0
  58. package/dist/_chunks/{Relations-CY8Isqdu.js → Relations-CvifV6Y6.js} +142 -100
  59. package/dist/_chunks/Relations-CvifV6Y6.js.map +1 -0
  60. package/dist/_chunks/{en-C-V1_90f.js → en-BR48D_RH.js} +45 -18
  61. package/dist/_chunks/{en-C-V1_90f.js.map → en-BR48D_RH.js.map} +1 -1
  62. package/dist/_chunks/{en-MBPul9Su.mjs → en-D65uIF6Y.mjs} +45 -18
  63. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
  64. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  65. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  66. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  67. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  68. package/dist/_chunks/{fr-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
  69. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
  70. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
  71. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
  72. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  73. package/dist/_chunks/{index-CAc9yTnx.mjs → index-BH2JnYpF.mjs} +2302 -995
  74. package/dist/_chunks/index-BH2JnYpF.mjs.map +1 -0
  75. package/dist/_chunks/{index-DNa1J4HE.js → index-DkJQjlak.js} +2273 -967
  76. package/dist/_chunks/index-DkJQjlak.js.map +1 -0
  77. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  78. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  79. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  80. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  81. package/dist/_chunks/{layout-BqtLA6Lb.js → layout-4BqLFW_b.js} +47 -32
  82. package/dist/_chunks/layout-4BqLFW_b.js.map +1 -0
  83. package/dist/_chunks/{layout-CXsHbc3E.mjs → layout-bbOlPwLA.mjs} +46 -28
  84. package/dist/_chunks/layout-bbOlPwLA.mjs.map +1 -0
  85. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  86. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  87. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  88. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  89. package/dist/_chunks/{relations-mMFEcZRq.mjs → relations-HsflnFpO.mjs} +6 -7
  90. package/dist/_chunks/relations-HsflnFpO.mjs.map +1 -0
  91. package/dist/_chunks/{relations-BHY_KDJ_.js → relations-Yc0Z6A20.js} +6 -7
  92. package/dist/_chunks/relations-Yc0Z6A20.js.map +1 -0
  93. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  94. package/dist/_chunks/useDragAndDrop-BMtgCYzL.js.map +1 -0
  95. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  96. package/dist/_chunks/useDragAndDrop-DJ6jqvZN.mjs.map +1 -0
  97. package/dist/_chunks/usePrev-CZGy2Vjf.mjs +29 -0
  98. package/dist/_chunks/usePrev-CZGy2Vjf.mjs.map +1 -0
  99. package/dist/_chunks/usePrev-D5J_2fEu.js +28 -0
  100. package/dist/_chunks/usePrev-D5J_2fEu.js.map +1 -0
  101. package/dist/admin/index.js +4 -1
  102. package/dist/admin/index.js.map +1 -1
  103. package/dist/admin/index.mjs +10 -7
  104. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  105. package/dist/admin/src/content-manager.d.ts +7 -5
  106. package/dist/admin/src/exports.d.ts +3 -1
  107. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  108. package/dist/admin/src/history/index.d.ts +3 -0
  109. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  110. package/dist/admin/src/hooks/useDocument.d.ts +54 -9
  111. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  112. package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
  113. package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
  114. package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  115. package/dist/admin/src/index.d.ts +1 -0
  116. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  117. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +12 -5
  118. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
  119. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  120. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  121. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  122. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +5 -0
  123. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  124. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  125. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
  126. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
  127. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
  128. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  129. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  130. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  131. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  132. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +16 -53
  133. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
  134. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  135. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  136. package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
  137. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  138. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  139. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  140. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  141. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  142. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  143. package/dist/admin/src/preview/index.d.ts +4 -0
  144. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  145. package/dist/admin/src/preview/routes.d.ts +3 -0
  146. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  147. package/dist/admin/src/router.d.ts +1 -1
  148. package/dist/admin/src/services/api.d.ts +2 -3
  149. package/dist/admin/src/services/components.d.ts +2 -2
  150. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  151. package/dist/admin/src/services/documents.d.ts +31 -20
  152. package/dist/admin/src/services/init.d.ts +2 -2
  153. package/dist/admin/src/services/relations.d.ts +3 -3
  154. package/dist/admin/src/services/uid.d.ts +3 -3
  155. package/dist/admin/src/utils/api.d.ts +4 -18
  156. package/dist/admin/src/utils/validation.d.ts +5 -7
  157. package/dist/server/index.js +959 -543
  158. package/dist/server/index.js.map +1 -1
  159. package/dist/server/index.mjs +960 -543
  160. package/dist/server/index.mjs.map +1 -1
  161. package/dist/server/src/bootstrap.d.ts.map +1 -1
  162. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  163. package/dist/server/src/controllers/index.d.ts.map +1 -1
  164. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  165. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  166. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  167. package/dist/server/src/controllers/utils/metadata.d.ts +23 -0
  168. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  169. package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
  170. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  171. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  172. package/dist/server/src/history/controllers/history-version.d.ts +1 -1
  173. package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
  174. package/dist/server/src/history/services/history.d.ts +3 -3
  175. package/dist/server/src/history/services/history.d.ts.map +1 -1
  176. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  177. package/dist/server/src/history/services/utils.d.ts +8 -12
  178. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  179. package/dist/server/src/index.d.ts +21 -36
  180. package/dist/server/src/index.d.ts.map +1 -1
  181. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  182. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  183. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  184. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  185. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  186. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  187. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  188. package/dist/server/src/preview/index.d.ts +4 -0
  189. package/dist/server/src/preview/index.d.ts.map +1 -0
  190. package/dist/server/src/preview/routes/index.d.ts +8 -0
  191. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  192. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  193. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  194. package/dist/server/src/preview/services/index.d.ts +16 -0
  195. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  196. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  197. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  198. package/dist/server/src/preview/services/preview.d.ts +12 -0
  199. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  200. package/dist/server/src/preview/utils.d.ts +19 -0
  201. package/dist/server/src/preview/utils.d.ts.map +1 -0
  202. package/dist/server/src/register.d.ts.map +1 -1
  203. package/dist/server/src/routes/index.d.ts.map +1 -1
  204. package/dist/server/src/services/document-manager.d.ts +11 -6
  205. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  206. package/dist/server/src/services/document-metadata.d.ts +16 -35
  207. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  208. package/dist/server/src/services/index.d.ts +21 -36
  209. package/dist/server/src/services/index.d.ts.map +1 -1
  210. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  211. package/dist/server/src/services/utils/populate.d.ts +8 -1
  212. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  213. package/dist/server/src/utils/index.d.ts +2 -0
  214. package/dist/server/src/utils/index.d.ts.map +1 -1
  215. package/dist/shared/contracts/collection-types.d.ts +17 -7
  216. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  217. package/dist/shared/contracts/index.d.ts +1 -0
  218. package/dist/shared/contracts/index.d.ts.map +1 -1
  219. package/dist/shared/contracts/preview.d.ts +27 -0
  220. package/dist/shared/contracts/preview.d.ts.map +1 -0
  221. package/dist/shared/contracts/relations.d.ts +2 -2
  222. package/dist/shared/contracts/relations.d.ts.map +1 -1
  223. package/dist/shared/index.js +4 -0
  224. package/dist/shared/index.js.map +1 -1
  225. package/dist/shared/index.mjs +4 -0
  226. package/dist/shared/index.mjs.map +1 -1
  227. package/package.json +22 -22
  228. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  229. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  230. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  231. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  232. package/dist/_chunks/EditViewPage-KRG56aCq.js +0 -224
  233. package/dist/_chunks/EditViewPage-KRG56aCq.js.map +0 -1
  234. package/dist/_chunks/EditViewPage-aUnqL-63.mjs +0 -203
  235. package/dist/_chunks/EditViewPage-aUnqL-63.mjs.map +0 -1
  236. package/dist/_chunks/Field-kVFO4ZKB.mjs.map +0 -1
  237. package/dist/_chunks/Field-kq1c2TF1.js.map +0 -1
  238. package/dist/_chunks/Form-CQ67ZifP.js.map +0 -1
  239. package/dist/_chunks/Form-Jgh5hGTu.mjs.map +0 -1
  240. package/dist/_chunks/History-BLEnudTX.js.map +0 -1
  241. package/dist/_chunks/History-DKhZAPcK.mjs.map +0 -1
  242. package/dist/_chunks/ListConfigurationPage-Zso_LUjn.js.map +0 -1
  243. package/dist/_chunks/ListConfigurationPage-nrXcxNYi.mjs.map +0 -1
  244. package/dist/_chunks/ListViewPage-ChhYmA-L.mjs.map +0 -1
  245. package/dist/_chunks/ListViewPage-DsaOakWQ.js.map +0 -1
  246. package/dist/_chunks/NoContentTypePage-BrdFcN33.mjs.map +0 -1
  247. package/dist/_chunks/NoContentTypePage-DPCuS9Y1.js.map +0 -1
  248. package/dist/_chunks/Relations-CY8Isqdu.js.map +0 -1
  249. package/dist/_chunks/Relations-DjFiYd7-.mjs.map +0 -1
  250. package/dist/_chunks/index-CAc9yTnx.mjs.map +0 -1
  251. package/dist/_chunks/index-DNa1J4HE.js.map +0 -1
  252. package/dist/_chunks/layout-BqtLA6Lb.js.map +0 -1
  253. package/dist/_chunks/layout-CXsHbc3E.mjs.map +0 -1
  254. package/dist/_chunks/relations-BHY_KDJ_.js.map +0 -1
  255. package/dist/_chunks/relations-mMFEcZRq.mjs.map +0 -1
  256. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  257. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  258. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  259. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  260. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +0 -1
  261. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +0 -1
  262. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  263. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
  264. package/strapi-server.js +0 -3
@@ -1,5 +1,5 @@
1
- import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1, pagination, sanitize } from "@strapi/utils";
2
- import { pick, omit, difference, intersection, pipe, propOr, isEqual, isEmpty, set, isNil as isNil$1, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, getOr, propEq, merge, groupBy, castArray } from "lodash/fp";
1
+ import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, traverseEntity, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1, pagination } from "@strapi/utils";
2
+ import { pick, omit, difference, castArray, mergeWith, intersection, pipe, propOr, isEqual, isEmpty, set, isNil as isNil$1, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, getOr, propEq, merge, groupBy } from "lodash/fp";
3
3
  import "@strapi/types";
4
4
  import * as yup from "yup";
5
5
  import { scheduleJob } from "node-schedule";
@@ -7,10 +7,10 @@ import isNil from "lodash/isNil";
7
7
  import _, { intersection as intersection$1, difference as difference$1 } from "lodash";
8
8
  import qs from "qs";
9
9
  import slugify from "@sindresorhus/slugify";
10
- const getService$1 = (name) => {
10
+ const getService$2 = (name) => {
11
11
  return strapi.plugin("content-manager").service(name);
12
12
  };
13
- function getService(strapi2, name) {
13
+ function getService$1(strapi2, name) {
14
14
  return strapi2.service(`plugin::content-manager.${name}`);
15
15
  }
16
16
  const historyRestoreVersionSchema = yup.object().shape({
@@ -46,7 +46,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
46
46
  if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {
47
47
  throw new errors.ForbiddenError("contentType and documentId are required");
48
48
  }
49
- const permissionChecker2 = getService$1("permission-checker").create({
49
+ const permissionChecker2 = getService$2("permission-checker").create({
50
50
  userAbility: ctx.state.userAbility,
51
51
  model: ctx.query.contentType
52
52
  });
@@ -54,7 +54,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
54
54
  return ctx.forbidden();
55
55
  }
56
56
  const query = await permissionChecker2.sanitizeQuery(ctx.query);
57
- const { results, pagination: pagination2 } = await getService(strapi2, "history").findVersionsPage({
57
+ const { results, pagination: pagination2 } = await getService$1(strapi2, "history").findVersionsPage({
58
58
  query: {
59
59
  ...query,
60
60
  ...getValidPagination({ page: query.page, pageSize: query.pageSize })
@@ -79,14 +79,14 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
79
79
  async restoreVersion(ctx) {
80
80
  const request = ctx.request;
81
81
  await validateRestoreVersion(request.body, "contentType is required");
82
- const permissionChecker2 = getService$1("permission-checker").create({
82
+ const permissionChecker2 = getService$2("permission-checker").create({
83
83
  userAbility: ctx.state.userAbility,
84
84
  model: request.body.contentType
85
85
  });
86
86
  if (permissionChecker2.cannot.update()) {
87
87
  throw new errors.ForbiddenError();
88
88
  }
89
- const restoredDocument = await getService(strapi2, "history").restoreVersion(
89
+ const restoredDocument = await getService$1(strapi2, "history").restoreVersion(
90
90
  request.params.versionId
91
91
  );
92
92
  return {
@@ -95,7 +95,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
95
95
  }
96
96
  };
97
97
  };
98
- const controllers$1 = {
98
+ const controllers$2 = {
99
99
  "history-version": createHistoryVersionController
100
100
  /**
101
101
  * Casting is needed because the types aren't aware that Strapi supports
@@ -141,8 +141,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
141
141
  };
142
142
  const getRelationRestoreValue = async (versionRelationData, attribute) => {
143
143
  if (Array.isArray(versionRelationData)) {
144
- if (versionRelationData.length === 0)
145
- return versionRelationData;
144
+ if (versionRelationData.length === 0) return versionRelationData;
146
145
  const existingAndMissingRelations = await Promise.all(
147
146
  versionRelationData.map((relation) => {
148
147
  return strapi2.documents(attribute.target).findOne({
@@ -151,19 +150,16 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
151
150
  });
152
151
  })
153
152
  );
154
- return existingAndMissingRelations.filter(
155
- (relation) => relation !== null
156
- );
153
+ return existingAndMissingRelations.filter((relation) => relation !== null);
157
154
  }
158
155
  return strapi2.documents(attribute.target).findOne({
159
156
  documentId: versionRelationData.documentId,
160
157
  locale: versionRelationData.locale || void 0
161
158
  });
162
159
  };
163
- const getMediaRestoreValue = async (versionRelationData, attribute) => {
164
- if (attribute.multiple) {
160
+ const getMediaRestoreValue = async (versionRelationData) => {
161
+ if (Array.isArray(versionRelationData)) {
165
162
  const existingAndMissingMedias = await Promise.all(
166
- // @ts-expect-error Fix the type definitions so this isn't any
167
163
  versionRelationData.map((media) => {
168
164
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
169
165
  })
@@ -173,10 +169,11 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
173
169
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
174
170
  };
175
171
  const localesService = strapi2.plugin("i18n")?.service("locales");
172
+ const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
176
173
  const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
174
+ const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
177
175
  const getLocaleDictionary = async () => {
178
- if (!localesService)
179
- return {};
176
+ if (!localesService) return {};
180
177
  const locales = await localesService.find() || [];
181
178
  return locales.reduce(
182
179
  (acc, locale) => {
@@ -200,31 +197,53 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
200
197
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
201
198
  return documentMetadataService.getStatus(document, meta.availableStatus);
202
199
  };
203
- const getDeepPopulate2 = (uid2) => {
200
+ const getComponentFields = (componentUID) => {
201
+ return Object.entries(strapi2.getModel(componentUID).attributes).reduce(
202
+ (fieldsAcc, [key, attribute]) => {
203
+ if (!["relation", "media", "component", "dynamiczone"].includes(attribute.type)) {
204
+ fieldsAcc.push(key);
205
+ }
206
+ return fieldsAcc;
207
+ },
208
+ []
209
+ );
210
+ };
211
+ const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
204
212
  const model = strapi2.getModel(uid2);
205
213
  const attributes = Object.entries(model.attributes);
214
+ const fieldSelector = useDatabaseSyntax ? "select" : "fields";
206
215
  return attributes.reduce((acc, [attributeName, attribute]) => {
207
216
  switch (attribute.type) {
208
217
  case "relation": {
218
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
219
+ if (isMorphRelation) {
220
+ break;
221
+ }
209
222
  const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
210
223
  if (isVisible2) {
211
- acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
224
+ acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
212
225
  }
213
226
  break;
214
227
  }
215
228
  case "media": {
216
- acc[attributeName] = { fields: ["id"] };
229
+ acc[attributeName] = { [fieldSelector]: ["id"] };
217
230
  break;
218
231
  }
219
232
  case "component": {
220
233
  const populate = getDeepPopulate2(attribute.component);
221
- acc[attributeName] = { populate };
234
+ acc[attributeName] = {
235
+ populate,
236
+ [fieldSelector]: getComponentFields(attribute.component)
237
+ };
222
238
  break;
223
239
  }
224
240
  case "dynamiczone": {
225
241
  const populatedComponents = (attribute.components || []).reduce(
226
242
  (acc2, componentUID) => {
227
- acc2[componentUID] = { populate: getDeepPopulate2(componentUID) };
243
+ acc2[componentUID] = {
244
+ populate: getDeepPopulate2(componentUID),
245
+ [fieldSelector]: getComponentFields(componentUID)
246
+ };
228
247
  return acc2;
229
248
  },
230
249
  {}
@@ -286,6 +305,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
286
305
  getRelationRestoreValue,
287
306
  getMediaRestoreValue,
288
307
  getDefaultLocale,
308
+ isLocalizedContentType,
289
309
  getLocaleDictionary,
290
310
  getRetentionDays,
291
311
  getVersionStatus,
@@ -308,7 +328,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
308
328
  });
309
329
  },
310
330
  async findVersionsPage(params) {
311
- const locale = params.query.locale || await serviceUtils.getDefaultLocale();
331
+ const schema = strapi2.getModel(params.query.contentType);
332
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(schema);
333
+ const defaultLocale = await serviceUtils.getDefaultLocale();
334
+ let locale = null;
335
+ if (isLocalizedContentType) {
336
+ locale = params.query.locale || defaultLocale;
337
+ }
312
338
  const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
313
339
  query.findPage({
314
340
  ...params.query,
@@ -324,78 +350,76 @@ const createHistoryService = ({ strapi: strapi2 }) => {
324
350
  }),
325
351
  serviceUtils.getLocaleDictionary()
326
352
  ]);
327
- const populateEntryRelations = async (entry) => {
328
- const entryWithRelations = await Object.entries(entry.schema).reduce(
329
- async (currentDataWithRelations, [attributeKey, attributeSchema]) => {
330
- const attributeValue = entry.data[attributeKey];
331
- const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
332
- if (attributeSchema.type === "media") {
333
- const permissionChecker2 = getService$1("permission-checker").create({
334
- userAbility: params.state.userAbility,
335
- model: "plugin::upload.file"
336
- });
337
- const response = await serviceUtils.buildMediaResponse(attributeValues);
338
- const sanitizedResults = await Promise.all(
339
- response.results.map((media) => permissionChecker2.sanitizeOutput(media))
340
- );
341
- return {
342
- ...await currentDataWithRelations,
343
- [attributeKey]: {
344
- results: sanitizedResults,
345
- meta: response.meta
346
- }
347
- };
353
+ const populateEntry = async (entry) => {
354
+ return traverseEntity(
355
+ async (options, utils) => {
356
+ if (!options.attribute) return;
357
+ if (!options.value) return;
358
+ const currentValue = Array.isArray(options.value) ? options.value : [options.value];
359
+ if (options.attribute.type === "component") {
360
+ utils.remove("id");
348
361
  }
349
- if (attributeSchema.type === "relation" && attributeSchema.relation !== "morphToOne" && attributeSchema.relation !== "morphToMany") {
350
- if (attributeSchema.target === "admin::user") {
362
+ if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
363
+ options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
364
+ if (options.attribute.target === "admin::user") {
351
365
  const adminUsers = await Promise.all(
352
- attributeValues.map((userToPopulate) => {
366
+ currentValue.map((userToPopulate) => {
353
367
  if (userToPopulate == null) {
354
368
  return null;
355
369
  }
356
- return strapi2.query("admin::user").findOne({ where: { id: userToPopulate.id } });
370
+ return strapi2.query("admin::user").findOne({
371
+ where: {
372
+ ...userToPopulate.id ? { id: userToPopulate.id } : {},
373
+ ...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
374
+ }
375
+ });
357
376
  })
358
377
  );
359
- return {
360
- ...await currentDataWithRelations,
361
- /**
362
- * Ideally we would return the same "{results: [], meta: {}}" shape, however,
363
- * when sanitizing the data as a whole in the controller before sending to the client,
364
- * the data for admin relation user is completely sanitized if we return an object here as opposed to an array.
365
- */
366
- [attributeKey]: adminUsers
367
- };
378
+ utils.set(options.key, adminUsers);
368
379
  }
369
- const permissionChecker2 = getService$1("permission-checker").create({
380
+ const permissionChecker2 = getService$2("permission-checker").create({
370
381
  userAbility: params.state.userAbility,
371
- model: attributeSchema.target
382
+ model: options.attribute.target
372
383
  });
373
384
  const response = await serviceUtils.buildRelationReponse(
374
- attributeValues,
375
- attributeSchema
385
+ currentValue,
386
+ options.attribute
376
387
  );
377
388
  const sanitizedResults = await Promise.all(
378
389
  response.results.map((media) => permissionChecker2.sanitizeOutput(media))
379
390
  );
380
- return {
381
- ...await currentDataWithRelations,
382
- [attributeKey]: {
383
- results: sanitizedResults,
384
- meta: response.meta
385
- }
386
- };
391
+ utils.set(options.key, {
392
+ results: sanitizedResults,
393
+ meta: response.meta
394
+ });
395
+ }
396
+ if (options.attribute.type === "media") {
397
+ const permissionChecker2 = getService$2("permission-checker").create({
398
+ userAbility: params.state.userAbility,
399
+ model: "plugin::upload.file"
400
+ });
401
+ const response = await serviceUtils.buildMediaResponse(currentValue);
402
+ const sanitizedResults = await Promise.all(
403
+ response.results.map((media) => permissionChecker2.sanitizeOutput(media))
404
+ );
405
+ utils.set(options.key, {
406
+ results: sanitizedResults,
407
+ meta: response.meta
408
+ });
387
409
  }
388
- return currentDataWithRelations;
389
410
  },
390
- Promise.resolve(entry.data)
411
+ {
412
+ schema,
413
+ getModel: strapi2.getModel.bind(strapi2)
414
+ },
415
+ entry.data
391
416
  );
392
- return entryWithRelations;
393
417
  };
394
418
  const formattedResults = await Promise.all(
395
419
  results.map(async (result) => {
396
420
  return {
397
421
  ...result,
398
- data: await populateEntryRelations(result),
422
+ data: await populateEntry(result),
399
423
  meta: {
400
424
  unknownAttributes: serviceUtils.getSchemaAttributesDiff(
401
425
  result.schema,
@@ -426,30 +450,44 @@ const createHistoryService = ({ strapi: strapi2 }) => {
426
450
  // Clone to avoid mutating the original version data
427
451
  structuredClone(version.data)
428
452
  );
429
- const sanitizedSchemaAttributes = omit(
430
- FIELDS_TO_IGNORE,
431
- contentTypeSchemaAttributes
432
- );
433
- const reducer = async.reduce(Object.entries(sanitizedSchemaAttributes));
434
- const dataWithoutMissingRelations = await reducer(
435
- async (previousRelationAttributes, [name, attribute]) => {
436
- const versionRelationData = version.data[name];
437
- if (!versionRelationData) {
438
- return previousRelationAttributes;
453
+ const schema = structuredClone(version.schema);
454
+ schema.attributes = omit(FIELDS_TO_IGNORE, contentTypeSchemaAttributes);
455
+ const dataWithoutMissingRelations = await traverseEntity(
456
+ async (options, utils) => {
457
+ if (!options.attribute) return;
458
+ if (options.attribute.type === "component") {
459
+ utils.remove("id");
460
+ if (options.attribute.repeatable && options.value === null) {
461
+ utils.set(options.key, []);
462
+ }
463
+ }
464
+ if (options.attribute.type === "dynamiczone") {
465
+ if (options.value === null) {
466
+ utils.set(options.key, []);
467
+ }
439
468
  }
440
- if (attribute.type === "relation" && // TODO: handle polymorphic relations
441
- attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
442
- const data2 = await serviceUtils.getRelationRestoreValue(versionRelationData, attribute);
443
- previousRelationAttributes[name] = data2;
469
+ if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
470
+ options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
471
+ if (!options.value) return;
472
+ const data2 = await serviceUtils.getRelationRestoreValue(
473
+ options.value,
474
+ options.attribute
475
+ );
476
+ utils.set(options.key, data2);
444
477
  }
445
- if (attribute.type === "media") {
446
- const data2 = await serviceUtils.getMediaRestoreValue(versionRelationData, attribute);
447
- previousRelationAttributes[name] = data2;
478
+ if (options.attribute.type === "media") {
479
+ if (!options.value) return;
480
+ const data2 = await serviceUtils.getMediaRestoreValue(
481
+ options.value
482
+ );
483
+ utils.set(options.key, data2);
448
484
  }
449
- return previousRelationAttributes;
450
485
  },
451
- // Clone to avoid mutating the original version data
452
- structuredClone(dataWithoutAddedAttributes)
486
+ {
487
+ schema,
488
+ getModel: strapi2.getModel.bind(strapi2)
489
+ },
490
+ dataWithoutAddedAttributes
453
491
  );
454
492
  const data = omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
455
493
  const restoredDocument = await strapi2.documents(version.contentType).update({
@@ -464,13 +502,47 @@ const createHistoryService = ({ strapi: strapi2 }) => {
464
502
  }
465
503
  };
466
504
  };
505
+ const shouldCreateHistoryVersion = (context) => {
506
+ if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
507
+ return false;
508
+ }
509
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
510
+ return false;
511
+ }
512
+ if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
513
+ return false;
514
+ }
515
+ if (!context.contentType.uid.startsWith("api::")) {
516
+ return false;
517
+ }
518
+ return true;
519
+ };
520
+ const getSchemas = (uid2) => {
521
+ const attributesSchema = strapi.getModel(uid2).attributes;
522
+ const componentsSchemas = Object.keys(attributesSchema).reduce(
523
+ (currentComponentSchemas, key) => {
524
+ const fieldSchema = attributesSchema[key];
525
+ if (fieldSchema.type === "component") {
526
+ const componentSchema = strapi.getModel(fieldSchema.component).attributes;
527
+ return {
528
+ ...currentComponentSchemas,
529
+ [fieldSchema.component]: componentSchema
530
+ };
531
+ }
532
+ return currentComponentSchemas;
533
+ },
534
+ {}
535
+ );
536
+ return {
537
+ schema: omit(FIELDS_TO_IGNORE, attributesSchema),
538
+ componentsSchemas
539
+ };
540
+ };
467
541
  const createLifecyclesService = ({ strapi: strapi2 }) => {
468
542
  const state = {
469
543
  deleteExpiredJob: null,
470
544
  isInitialized: false
471
545
  };
472
- const query = strapi2.db.query(HISTORY_VERSION_UID);
473
- const historyService = getService(strapi2, "history");
474
546
  const serviceUtils = createServiceUtils({ strapi: strapi2 });
475
547
  return {
476
548
  async bootstrap() {
@@ -478,65 +550,62 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
478
550
  return;
479
551
  }
480
552
  strapi2.documents.use(async (context, next) => {
481
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
482
- return next();
483
- }
484
- if (context.action !== "create" && context.action !== "update" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
485
- return next();
486
- }
487
- const contentTypeUid = context.contentType.uid;
488
- if (!contentTypeUid.startsWith("api::")) {
489
- return next();
490
- }
491
553
  const result = await next();
492
- const documentContext = context.action === "create" ? { documentId: result.documentId, locale: context.params?.locale } : { documentId: context.params.documentId, locale: context.params?.locale };
554
+ if (!shouldCreateHistoryVersion(context)) {
555
+ return result;
556
+ }
557
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
493
558
  const defaultLocale = await serviceUtils.getDefaultLocale();
494
- const locale = documentContext.locale || defaultLocale;
495
- const document = await strapi2.documents(contentTypeUid).findOne({
496
- documentId: documentContext.documentId,
497
- locale,
498
- populate: serviceUtils.getDeepPopulate(contentTypeUid)
559
+ const locales = castArray(context.params?.locale || defaultLocale);
560
+ if (!locales.length) {
561
+ return result;
562
+ }
563
+ const uid2 = context.contentType.uid;
564
+ const schemas = getSchemas(uid2);
565
+ const model = strapi2.getModel(uid2);
566
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
567
+ const localeEntries = await strapi2.db.query(uid2).findMany({
568
+ where: {
569
+ documentId,
570
+ ...isLocalizedContentType ? { locale: { $in: locales } } : {},
571
+ ...contentTypes$1.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
572
+ },
573
+ populate: serviceUtils.getDeepPopulate(
574
+ uid2,
575
+ true
576
+ /* use database syntax */
577
+ )
499
578
  });
500
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
501
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
502
- const componentsSchemas = Object.keys(
503
- attributesSchema
504
- ).reduce((currentComponentSchemas, key) => {
505
- const fieldSchema = attributesSchema[key];
506
- if (fieldSchema.type === "component") {
507
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
508
- return {
509
- ...currentComponentSchemas,
510
- [fieldSchema.component]: componentSchema
511
- };
512
- }
513
- return currentComponentSchemas;
514
- }, {});
515
579
  await strapi2.db.transaction(async ({ onCommit }) => {
516
- onCommit(() => {
517
- historyService.createVersion({
518
- contentType: contentTypeUid,
519
- data: omit(FIELDS_TO_IGNORE, document),
520
- schema: omit(FIELDS_TO_IGNORE, attributesSchema),
521
- componentsSchemas,
522
- relatedDocumentId: documentContext.documentId,
523
- locale,
524
- status
525
- });
580
+ onCommit(async () => {
581
+ for (const entry of localeEntries) {
582
+ const status = await serviceUtils.getVersionStatus(uid2, entry);
583
+ await getService$1(strapi2, "history").createVersion({
584
+ contentType: uid2,
585
+ data: omit(FIELDS_TO_IGNORE, entry),
586
+ relatedDocumentId: documentId,
587
+ locale: entry.locale,
588
+ status,
589
+ ...schemas
590
+ });
591
+ }
526
592
  });
527
593
  });
528
594
  return result;
529
595
  });
530
- const retentionDays = serviceUtils.getRetentionDays();
531
- state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
532
- const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
596
+ state.deleteExpiredJob = scheduleJob("historyDaily", "0 0 * * *", () => {
597
+ const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
533
598
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
534
- query.deleteMany({
599
+ strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
535
600
  where: {
536
601
  created_at: {
537
- $lt: expirationDate.toISOString()
602
+ $lt: expirationDate
538
603
  }
539
604
  }
605
+ }).catch((error) => {
606
+ if (error instanceof Error) {
607
+ strapi2.log.error("Error deleting expired history versions", error.message);
608
+ }
540
609
  });
541
610
  });
542
611
  state.isInitialized = true;
@@ -548,17 +617,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
548
617
  }
549
618
  };
550
619
  };
551
- const services$1 = {
620
+ const services$2 = {
552
621
  history: createHistoryService,
553
622
  lifecycles: createLifecyclesService
554
623
  };
555
- const info = { pluginName: "content-manager", type: "admin" };
624
+ const info$1 = { pluginName: "content-manager", type: "admin" };
556
625
  const historyVersionRouter = {
557
626
  type: "admin",
558
627
  routes: [
559
628
  {
560
629
  method: "GET",
561
- info,
630
+ info: info$1,
562
631
  path: "/history-versions",
563
632
  handler: "history-version.findMany",
564
633
  config: {
@@ -567,7 +636,7 @@ const historyVersionRouter = {
567
636
  },
568
637
  {
569
638
  method: "PUT",
570
- info,
639
+ info: info$1,
571
640
  path: "/history-versions/:versionId/restore",
572
641
  handler: "history-version.restoreVersion",
573
642
  config: {
@@ -576,7 +645,7 @@ const historyVersionRouter = {
576
645
  }
577
646
  ]
578
647
  };
579
- const routes$1 = {
648
+ const routes$2 = {
580
649
  "history-version": historyVersionRouter
581
650
  };
582
651
  const historyVersion = {
@@ -623,21 +692,21 @@ const historyVersion = {
623
692
  }
624
693
  }
625
694
  };
626
- const getFeature = () => {
695
+ const getFeature$1 = () => {
627
696
  if (strapi.ee.features.isEnabled("cms-content-history")) {
628
697
  return {
629
698
  register({ strapi: strapi2 }) {
630
699
  strapi2.get("models").add(historyVersion);
631
700
  },
632
701
  bootstrap({ strapi: strapi2 }) {
633
- getService(strapi2, "lifecycles").bootstrap();
702
+ getService$1(strapi2, "lifecycles").bootstrap();
634
703
  },
635
704
  destroy({ strapi: strapi2 }) {
636
- getService(strapi2, "lifecycles").destroy();
705
+ getService$1(strapi2, "lifecycles").destroy();
637
706
  },
638
- controllers: controllers$1,
639
- services: services$1,
640
- routes: routes$1
707
+ controllers: controllers$2,
708
+ services: services$2,
709
+ routes: routes$2
641
710
  };
642
711
  }
643
712
  return {
@@ -646,9 +715,201 @@ const getFeature = () => {
646
715
  }
647
716
  };
648
717
  };
649
- const history = getFeature();
718
+ const history = getFeature$1();
719
+ const info = { pluginName: "content-manager", type: "admin" };
720
+ const previewRouter = {
721
+ type: "admin",
722
+ routes: [
723
+ {
724
+ method: "GET",
725
+ info,
726
+ path: "/preview/url/:contentType",
727
+ handler: "preview.getPreviewUrl",
728
+ config: {
729
+ policies: ["admin::isAuthenticatedAdmin"]
730
+ }
731
+ }
732
+ ]
733
+ };
734
+ const routes$1 = {
735
+ preview: previewRouter
736
+ };
737
+ function getService(strapi2, name) {
738
+ return strapi2.service(`plugin::content-manager.${name}`);
739
+ }
740
+ const getPreviewUrlSchema = yup.object().shape({
741
+ // Will be undefined for single types
742
+ documentId: yup.string(),
743
+ locale: yup.string().nullable(),
744
+ status: yup.string()
745
+ }).required();
746
+ const validatePreviewUrl = async (strapi2, uid2, params) => {
747
+ await validateYupSchema(getPreviewUrlSchema)(params);
748
+ const newParams = pick(["documentId", "locale", "status"], params);
749
+ const model = strapi2.getModel(uid2);
750
+ if (!model || model.modelType !== "contentType") {
751
+ throw new errors.ValidationError("Invalid content type");
752
+ }
753
+ const isSingleType = model?.kind === "singleType";
754
+ if (!isSingleType && !params.documentId) {
755
+ throw new errors.ValidationError("documentId is required for Collection Types");
756
+ }
757
+ if (isSingleType) {
758
+ const doc = await strapi2.documents(uid2).findFirst();
759
+ if (!doc) {
760
+ throw new errors.NotFoundError("Document not found");
761
+ }
762
+ newParams.documentId = doc?.documentId;
763
+ }
764
+ if (!newParams.status) {
765
+ const isDPEnabled = model?.options?.draftAndPublish;
766
+ newParams.status = isDPEnabled ? "draft" : "published";
767
+ }
768
+ return newParams;
769
+ };
770
+ const createPreviewController = () => {
771
+ return {
772
+ /**
773
+ * Transforms an entry into a preview URL, so that it can be previewed
774
+ * in the Content Manager.
775
+ */
776
+ async getPreviewUrl(ctx) {
777
+ const uid2 = ctx.params.contentType;
778
+ const query = ctx.request.query;
779
+ const params = await validatePreviewUrl(strapi, uid2, query);
780
+ const previewService = getService(strapi, "preview");
781
+ const url = await previewService.getPreviewUrl(uid2, params);
782
+ if (!url) {
783
+ ctx.status = 204;
784
+ }
785
+ return {
786
+ data: { url }
787
+ };
788
+ }
789
+ };
790
+ };
791
+ const controllers$1 = {
792
+ preview: createPreviewController
793
+ /**
794
+ * Casting is needed because the types aren't aware that Strapi supports
795
+ * passing a controller factory as the value, instead of a controller object directly
796
+ */
797
+ };
798
+ const createPreviewService = ({ strapi: strapi2 }) => {
799
+ const config = getService(strapi2, "preview-config");
800
+ return {
801
+ async getPreviewUrl(uid2, params) {
802
+ const handler = config.getPreviewHandler();
803
+ try {
804
+ return handler(uid2, params);
805
+ } catch (error) {
806
+ strapi2.log.error(`Failed to get preview URL: ${error}`);
807
+ throw new errors.ApplicationError("Failed to get preview URL");
808
+ }
809
+ return;
810
+ }
811
+ };
812
+ };
813
+ const extendMiddlewareConfiguration = (middleware = { name: "", config: {} }) => {
814
+ const middlewares = strapi.config.get("middlewares");
815
+ const configuredMiddlewares = middlewares.map((currentMiddleware) => {
816
+ if (currentMiddleware === middleware.name) {
817
+ return middleware;
818
+ }
819
+ if (currentMiddleware.name === middleware.name) {
820
+ return mergeWith(
821
+ (objValue, srcValue) => {
822
+ if (Array.isArray(objValue)) {
823
+ return objValue.concat(srcValue);
824
+ }
825
+ return void 0;
826
+ },
827
+ currentMiddleware,
828
+ middleware
829
+ );
830
+ }
831
+ return currentMiddleware;
832
+ });
833
+ strapi.config.set("middlewares", configuredMiddlewares);
834
+ };
835
+ const createPreviewConfigService = ({ strapi: strapi2 }) => {
836
+ return {
837
+ register() {
838
+ if (!this.isEnabled()) {
839
+ return;
840
+ }
841
+ const config = strapi2.config.get("admin.preview");
842
+ if (config.config?.allowedOrigins) {
843
+ extendMiddlewareConfiguration({
844
+ name: "strapi::security",
845
+ config: {
846
+ contentSecurityPolicy: {
847
+ directives: {
848
+ "frame-src": config.config.allowedOrigins
849
+ }
850
+ }
851
+ }
852
+ });
853
+ }
854
+ },
855
+ isEnabled() {
856
+ const config = strapi2.config.get("admin.preview");
857
+ if (!config) {
858
+ return false;
859
+ }
860
+ return config?.enabled ?? true;
861
+ },
862
+ /**
863
+ * Validate if the configuration is valid
864
+ */
865
+ validate() {
866
+ if (!this.isEnabled()) {
867
+ return;
868
+ }
869
+ const handler = this.getPreviewHandler();
870
+ if (typeof handler !== "function") {
871
+ throw new errors.ValidationError(
872
+ "Preview configuration is invalid. Handler must be a function"
873
+ );
874
+ }
875
+ },
876
+ /**
877
+ * Utility to get the preview handler from the configuration
878
+ */
879
+ getPreviewHandler() {
880
+ const config = strapi2.config.get("admin.preview");
881
+ const emptyHandler = () => {
882
+ return void 0;
883
+ };
884
+ if (!this.isEnabled()) {
885
+ return emptyHandler;
886
+ }
887
+ return config?.config?.handler || emptyHandler;
888
+ }
889
+ };
890
+ };
891
+ const services$1 = {
892
+ preview: createPreviewService,
893
+ "preview-config": createPreviewConfigService
894
+ };
895
+ const getFeature = () => {
896
+ return {
897
+ register() {
898
+ const config = getService(strapi, "preview-config");
899
+ config.validate();
900
+ config.register();
901
+ },
902
+ bootstrap() {
903
+ },
904
+ routes: routes$1,
905
+ controllers: controllers$1,
906
+ services: services$1
907
+ };
908
+ };
909
+ const preview = getFeature();
650
910
  const register = async ({ strapi: strapi2 }) => {
651
911
  await history.register?.({ strapi: strapi2 });
912
+ await preview.register?.({ strapi: strapi2 });
652
913
  };
653
914
  const ALLOWED_WEBHOOK_EVENTS = {
654
915
  ENTRY_PUBLISH: "entry.publish",
@@ -658,11 +919,12 @@ const bootstrap = async () => {
658
919
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
659
920
  strapi.get("webhookStore").addAllowedEvent(key, value);
660
921
  });
661
- getService$1("field-sizes").setCustomFieldInputSizes();
662
- await getService$1("components").syncConfigurations();
663
- await getService$1("content-types").syncConfigurations();
664
- await getService$1("permission").registerPermissions();
922
+ getService$2("field-sizes").setCustomFieldInputSizes();
923
+ await getService$2("components").syncConfigurations();
924
+ await getService$2("content-types").syncConfigurations();
925
+ await getService$2("permission").registerPermissions();
665
926
  await history.bootstrap?.({ strapi });
927
+ await preview.bootstrap?.({ strapi });
666
928
  };
667
929
  const destroy = async ({ strapi: strapi2 }) => {
668
930
  await history.destroy?.({ strapi: strapi2 });
@@ -1152,7 +1414,8 @@ const admin = {
1152
1414
  };
1153
1415
  const routes = {
1154
1416
  admin,
1155
- ...history.routes ? history.routes : {}
1417
+ ...history.routes ? history.routes : {},
1418
+ ...preview.routes ? preview.routes : {}
1156
1419
  };
1157
1420
  const hasPermissionsSchema = yup$1.object({
1158
1421
  actions: yup$1.array().of(yup$1.string()),
@@ -1163,6 +1426,11 @@ const { createPolicy } = policy;
1163
1426
  const hasPermissions = createPolicy({
1164
1427
  name: "plugin::content-manager.hasPermissions",
1165
1428
  validator: validateHasPermissionsInput,
1429
+ /**
1430
+ * NOTE: Action aliases are currently not checked at this level (policy).
1431
+ * This is currently the intended behavior to avoid changing the behavior of API related permissions.
1432
+ * If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
1433
+ */
1166
1434
  handler(ctx, config = {}) {
1167
1435
  const { actions = [], hasAtLeastOne = false } = config;
1168
1436
  const { userAbility } = ctx.state;
@@ -1210,8 +1478,7 @@ const isSortable = (schema, name) => {
1210
1478
  if (!_.has(schema.attributes, name)) {
1211
1479
  return false;
1212
1480
  }
1213
- if (schema.modelType === "component" && name === "id")
1214
- return false;
1481
+ if (schema.modelType === "component" && name === "id") return false;
1215
1482
  const attribute = schema.attributes[name];
1216
1483
  if (NON_SORTABLES.includes(attribute.type)) {
1217
1484
  return false;
@@ -1356,8 +1623,7 @@ const createDefaultSettings = async (schema) => {
1356
1623
  };
1357
1624
  };
1358
1625
  const syncSettings = async (configuration, schema) => {
1359
- if (isEmpty(configuration.settings))
1360
- return createDefaultSettings(schema);
1626
+ if (isEmpty(configuration.settings)) return createDefaultSettings(schema);
1361
1627
  const defaultField = getDefaultMainField(schema);
1362
1628
  const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
1363
1629
  return {
@@ -1404,7 +1670,7 @@ const createMetadasSchema = (schema) => {
1404
1670
  if (!value) {
1405
1671
  return yup$1.string();
1406
1672
  }
1407
- const targetSchema = getService$1("content-types").findContentType(
1673
+ const targetSchema = getService$2("content-types").findContentType(
1408
1674
  schema.attributes[key].targetModel
1409
1675
  );
1410
1676
  if (!targetSchema) {
@@ -1452,7 +1718,7 @@ const { PaginationError, ValidationError } = errors;
1452
1718
  const TYPES = ["singleType", "collectionType"];
1453
1719
  const kindSchema = yup$1.string().oneOf(TYPES).nullable();
1454
1720
  const bulkActionInputSchema = yup$1.object({
1455
- ids: yup$1.array().of(yup$1.strapiID()).min(1).required()
1721
+ documentIds: yup$1.array().of(yup$1.strapiID()).min(1).required()
1456
1722
  }).required();
1457
1723
  const generateUIDInputSchema = yup$1.object({
1458
1724
  contentTypeUID: yup$1.string().required(),
@@ -1533,8 +1799,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1533
1799
  }
1534
1800
  switch (attribute.type) {
1535
1801
  case "relation": {
1536
- if (canCreate(attributePath))
1537
- return body2;
1802
+ if (canCreate(attributePath)) return body2;
1538
1803
  return set(attributePath, { set: [] }, body2);
1539
1804
  }
1540
1805
  case "component": {
@@ -1544,29 +1809,62 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1544
1809
  ]);
1545
1810
  }
1546
1811
  default: {
1547
- if (canCreate(attributePath))
1548
- return body2;
1812
+ if (canCreate(attributePath)) return body2;
1549
1813
  return set(attributePath, null, body2);
1550
1814
  }
1551
1815
  }
1552
1816
  }, body);
1553
1817
  };
1554
- const getDocumentLocaleAndStatus = (request) => {
1555
- const { locale, status, ...rest } = request || {};
1556
- if (!isNil$1(locale) && typeof locale !== "string") {
1557
- throw new errors.ValidationError(`Invalid locale: ${locale}`);
1558
- }
1559
- if (!isNil$1(status) && !["draft", "published"].includes(status)) {
1560
- throw new errors.ValidationError(`Invalid status: ${status}`);
1818
+ const singleLocaleSchema = yup$1.string().nullable();
1819
+ const multipleLocaleSchema = yup$1.lazy(
1820
+ (value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1821
+ );
1822
+ const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
1823
+ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
1824
+ const { allowMultipleLocales } = opts;
1825
+ const { locale, status: providedStatus, ...rest } = request || {};
1826
+ const defaultStatus = contentTypes$1.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
1827
+ const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
1828
+ const schema = yup$1.object().shape({
1829
+ locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1830
+ status: statusSchema
1831
+ });
1832
+ try {
1833
+ await validateYupSchema(schema, { strict: true, abortEarly: false })(request);
1834
+ return { locale, status, ...rest };
1835
+ } catch (error) {
1836
+ throw new errors.ValidationError(`Validation error: ${error.message}`);
1561
1837
  }
1562
- return { locale, status, ...rest };
1838
+ };
1839
+ const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1840
+ const documentMetadata2 = getService$2("document-metadata");
1841
+ const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1842
+ let {
1843
+ meta: { availableLocales, availableStatus }
1844
+ } = serviceOutput;
1845
+ const metadataSanitizer = permissionChecker2.sanitizeOutput;
1846
+ availableLocales = await async.map(
1847
+ availableLocales,
1848
+ async (localeDocument) => metadataSanitizer(localeDocument)
1849
+ );
1850
+ availableStatus = await async.map(
1851
+ availableStatus,
1852
+ async (statusDocument) => metadataSanitizer(statusDocument)
1853
+ );
1854
+ return {
1855
+ ...serviceOutput,
1856
+ meta: {
1857
+ availableLocales,
1858
+ availableStatus
1859
+ }
1860
+ };
1563
1861
  };
1564
1862
  const createDocument = async (ctx, opts) => {
1565
1863
  const { userAbility, user } = ctx.state;
1566
1864
  const { model } = ctx.params;
1567
1865
  const { body } = ctx.request;
1568
- const documentManager2 = getService$1("document-manager");
1569
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1866
+ const documentManager2 = getService$2("document-manager");
1867
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1570
1868
  if (permissionChecker2.cannot.create()) {
1571
1869
  throw new errors.ForbiddenError();
1572
1870
  }
@@ -1574,7 +1872,7 @@ const createDocument = async (ctx, opts) => {
1574
1872
  const setCreator = setCreatorFields({ user });
1575
1873
  const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
1576
1874
  const sanitizedBody = await sanitizeFn(body);
1577
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(body);
1875
+ const { locale, status } = await getDocumentLocaleAndStatus(body, model);
1578
1876
  return documentManager2.create(model, {
1579
1877
  data: sanitizedBody,
1580
1878
  locale,
@@ -1586,14 +1884,14 @@ const updateDocument = async (ctx, opts) => {
1586
1884
  const { userAbility, user } = ctx.state;
1587
1885
  const { id, model } = ctx.params;
1588
1886
  const { body } = ctx.request;
1589
- const documentManager2 = getService$1("document-manager");
1590
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1887
+ const documentManager2 = getService$2("document-manager");
1888
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1591
1889
  if (permissionChecker2.cannot.update()) {
1592
1890
  throw new errors.ForbiddenError();
1593
1891
  }
1594
1892
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1595
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1596
- const { locale } = getDocumentLocaleAndStatus(body);
1893
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1894
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1597
1895
  const [documentVersion, documentExists] = await Promise.all([
1598
1896
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1599
1897
  documentManager2.exists(model, id)
@@ -1609,7 +1907,7 @@ const updateDocument = async (ctx, opts) => {
1609
1907
  throw new errors.ForbiddenError();
1610
1908
  }
1611
1909
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1612
- const setCreator = setCreatorFields({ user, isEdition: true });
1910
+ const setCreator = documentVersion ? setCreatorFields({ user, isEdition: true }) : setCreatorFields({ user });
1613
1911
  const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
1614
1912
  const sanitizedBody = await sanitizeFn(body);
1615
1913
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1623,15 +1921,15 @@ const collectionTypes = {
1623
1921
  const { userAbility } = ctx.state;
1624
1922
  const { model } = ctx.params;
1625
1923
  const { query } = ctx.request;
1626
- const documentMetadata2 = getService$1("document-metadata");
1627
- const documentManager2 = getService$1("document-manager");
1628
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1924
+ const documentMetadata2 = getService$2("document-metadata");
1925
+ const documentManager2 = getService$2("document-manager");
1926
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1629
1927
  if (permissionChecker2.cannot.read()) {
1630
1928
  return ctx.forbidden();
1631
1929
  }
1632
1930
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1633
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1634
- const { locale, status } = getDocumentLocaleAndStatus(query);
1931
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1932
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1635
1933
  const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
1636
1934
  { ...permissionQuery, populate, locale, status },
1637
1935
  model
@@ -1659,15 +1957,14 @@ const collectionTypes = {
1659
1957
  async findOne(ctx) {
1660
1958
  const { userAbility } = ctx.state;
1661
1959
  const { model, id } = ctx.params;
1662
- const documentManager2 = getService$1("document-manager");
1663
- const documentMetadata2 = getService$1("document-metadata");
1664
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1960
+ const documentManager2 = getService$2("document-manager");
1961
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1665
1962
  if (permissionChecker2.cannot.read()) {
1666
1963
  return ctx.forbidden();
1667
1964
  }
1668
1965
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1669
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1670
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
1966
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1967
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1671
1968
  const version = await documentManager2.findOne(id, model, {
1672
1969
  populate,
1673
1970
  locale,
@@ -1678,9 +1975,11 @@ const collectionTypes = {
1678
1975
  if (!exists) {
1679
1976
  return ctx.notFound();
1680
1977
  }
1681
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
1978
+ const { meta } = await formatDocumentWithMetadata(
1979
+ permissionChecker2,
1682
1980
  model,
1683
- { id, locale, publishedAt: null },
1981
+ // @ts-expect-error TODO: fix
1982
+ { documentId: id, locale, publishedAt: null },
1684
1983
  { availableLocales: true, availableStatus: false }
1685
1984
  );
1686
1985
  ctx.body = { data: {}, meta };
@@ -1690,20 +1989,19 @@ const collectionTypes = {
1690
1989
  return ctx.forbidden();
1691
1990
  }
1692
1991
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
1693
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
1992
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1694
1993
  },
1695
1994
  async create(ctx) {
1696
1995
  const { userAbility } = ctx.state;
1697
1996
  const { model } = ctx.params;
1698
- const documentMetadata2 = getService$1("document-metadata");
1699
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1997
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1700
1998
  const [totalEntries, document] = await Promise.all([
1701
1999
  strapi.db.query(model).count(),
1702
2000
  createDocument(ctx)
1703
2001
  ]);
1704
2002
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
1705
2003
  ctx.status = 201;
1706
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
2004
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1707
2005
  // Empty metadata as it's not relevant for a new document
1708
2006
  availableLocales: false,
1709
2007
  availableStatus: false
@@ -1717,25 +2015,23 @@ const collectionTypes = {
1717
2015
  async update(ctx) {
1718
2016
  const { userAbility } = ctx.state;
1719
2017
  const { model } = ctx.params;
1720
- const documentMetadata2 = getService$1("document-metadata");
1721
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2018
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1722
2019
  const updatedVersion = await updateDocument(ctx);
1723
2020
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1724
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedVersion);
2021
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
1725
2022
  },
1726
2023
  async clone(ctx) {
1727
2024
  const { userAbility, user } = ctx.state;
1728
2025
  const { model, sourceId: id } = ctx.params;
1729
2026
  const { body } = ctx.request;
1730
- const documentManager2 = getService$1("document-manager");
1731
- const documentMetadata2 = getService$1("document-metadata");
1732
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2027
+ const documentManager2 = getService$2("document-manager");
2028
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1733
2029
  if (permissionChecker2.cannot.create()) {
1734
2030
  return ctx.forbidden();
1735
2031
  }
1736
2032
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1737
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1738
- const { locale } = getDocumentLocaleAndStatus(body);
2033
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2034
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1739
2035
  const document = await documentManager2.findOne(id, model, {
1740
2036
  populate,
1741
2037
  locale,
@@ -1751,7 +2047,7 @@ const collectionTypes = {
1751
2047
  const sanitizedBody = await sanitizeFn(body);
1752
2048
  const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
1753
2049
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
1754
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
2050
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1755
2051
  // Empty metadata as it's not relevant for a new document
1756
2052
  availableLocales: false,
1757
2053
  availableStatus: false
@@ -1773,14 +2069,14 @@ const collectionTypes = {
1773
2069
  async delete(ctx) {
1774
2070
  const { userAbility } = ctx.state;
1775
2071
  const { id, model } = ctx.params;
1776
- const documentManager2 = getService$1("document-manager");
1777
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2072
+ const documentManager2 = getService$2("document-manager");
2073
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1778
2074
  if (permissionChecker2.cannot.delete()) {
1779
2075
  return ctx.forbidden();
1780
2076
  }
1781
2077
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1782
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1783
- const { locale } = getDocumentLocaleAndStatus(ctx.query);
2078
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2079
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1784
2080
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1785
2081
  if (documentLocales.length === 0) {
1786
2082
  return ctx.notFound();
@@ -1801,44 +2097,75 @@ const collectionTypes = {
1801
2097
  const { userAbility } = ctx.state;
1802
2098
  const { id, model } = ctx.params;
1803
2099
  const { body } = ctx.request;
1804
- const documentManager2 = getService$1("document-manager");
1805
- const documentMetadata2 = getService$1("document-metadata");
1806
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2100
+ const documentManager2 = getService$2("document-manager");
2101
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1807
2102
  if (permissionChecker2.cannot.publish()) {
1808
2103
  return ctx.forbidden();
1809
2104
  }
1810
2105
  const publishedDocument = await strapi.db.transaction(async () => {
1811
2106
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1812
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1813
- const document = id ? await updateDocument(ctx, { populate }) : await createDocument(ctx, { populate });
2107
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2108
+ let document;
2109
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2110
+ const isCreate = isNil$1(id);
2111
+ if (isCreate) {
2112
+ if (permissionChecker2.cannot.create()) {
2113
+ throw new errors.ForbiddenError();
2114
+ }
2115
+ document = await createDocument(ctx, { populate });
2116
+ }
2117
+ const isUpdate = !isCreate;
2118
+ if (isUpdate) {
2119
+ const documentExists = documentManager2.exists(model, id);
2120
+ if (!documentExists) {
2121
+ throw new errors.NotFoundError("Document not found");
2122
+ }
2123
+ document = await documentManager2.findOne(id, model, { populate, locale });
2124
+ if (!document) {
2125
+ if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
2126
+ throw new errors.ForbiddenError();
2127
+ }
2128
+ document = await updateDocument(ctx);
2129
+ } else if (permissionChecker2.can.update(document)) {
2130
+ await updateDocument(ctx);
2131
+ }
2132
+ }
1814
2133
  if (permissionChecker2.cannot.publish(document)) {
1815
2134
  throw new errors.ForbiddenError();
1816
2135
  }
1817
- const { locale } = getDocumentLocaleAndStatus(body);
1818
- return documentManager2.publish(document.documentId, model, {
2136
+ const publishResult = await documentManager2.publish(document.documentId, model, {
1819
2137
  locale
1820
2138
  // TODO: Allow setting creator fields on publish
1821
2139
  // data: setCreatorFields({ user, isEdition: true })({}),
1822
2140
  });
2141
+ if (!publishResult || publishResult.length === 0) {
2142
+ throw new errors.NotFoundError("Document not found or already published.");
2143
+ }
2144
+ return publishResult[0];
1823
2145
  });
1824
2146
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
1825
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2147
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1826
2148
  },
1827
2149
  async bulkPublish(ctx) {
1828
2150
  const { userAbility } = ctx.state;
1829
2151
  const { model } = ctx.params;
1830
2152
  const { body } = ctx.request;
1831
- const { ids } = body;
2153
+ const { documentIds } = body;
1832
2154
  await validateBulkActionInput(body);
1833
- const documentManager2 = getService$1("document-manager");
1834
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2155
+ const documentManager2 = getService$2("document-manager");
2156
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1835
2157
  if (permissionChecker2.cannot.publish()) {
1836
2158
  return ctx.forbidden();
1837
2159
  }
1838
2160
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1839
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1840
- const entityPromises = ids.map((id) => documentManager2.findOne(id, model, { populate }));
1841
- const entities = await Promise.all(entityPromises);
2161
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2162
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2163
+ allowMultipleLocales: true
2164
+ });
2165
+ const entityPromises = documentIds.map(
2166
+ (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
2167
+ );
2168
+ const entities = (await Promise.all(entityPromises)).flat();
1842
2169
  for (const entity of entities) {
1843
2170
  if (!entity) {
1844
2171
  return ctx.notFound();
@@ -1847,24 +2174,27 @@ const collectionTypes = {
1847
2174
  return ctx.forbidden();
1848
2175
  }
1849
2176
  }
1850
- const { count } = await documentManager2.publishMany(entities, model);
2177
+ const count = await documentManager2.publishMany(model, documentIds, locale);
1851
2178
  ctx.body = { count };
1852
2179
  },
1853
2180
  async bulkUnpublish(ctx) {
1854
2181
  const { userAbility } = ctx.state;
1855
2182
  const { model } = ctx.params;
1856
2183
  const { body } = ctx.request;
1857
- const { ids } = body;
2184
+ const { documentIds } = body;
1858
2185
  await validateBulkActionInput(body);
1859
- const documentManager2 = getService$1("document-manager");
1860
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2186
+ const documentManager2 = getService$2("document-manager");
2187
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1861
2188
  if (permissionChecker2.cannot.unpublish()) {
1862
2189
  return ctx.forbidden();
1863
2190
  }
1864
- const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1865
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1866
- const entityPromises = ids.map((id) => documentManager2.findOne(id, model, { populate }));
1867
- const entities = await Promise.all(entityPromises);
2191
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2192
+ allowMultipleLocales: true
2193
+ });
2194
+ const entityPromises = documentIds.map(
2195
+ (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
2196
+ );
2197
+ const entities = (await Promise.all(entityPromises)).flat();
1868
2198
  for (const entity of entities) {
1869
2199
  if (!entity) {
1870
2200
  return ctx.notFound();
@@ -1873,7 +2203,8 @@ const collectionTypes = {
1873
2203
  return ctx.forbidden();
1874
2204
  }
1875
2205
  }
1876
- const { count } = await documentManager2.unpublishMany(entities, model);
2206
+ const entitiesIds = entities.map((document) => document.documentId);
2207
+ const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
1877
2208
  ctx.body = { count };
1878
2209
  },
1879
2210
  async unpublish(ctx) {
@@ -1882,9 +2213,8 @@ const collectionTypes = {
1882
2213
  const {
1883
2214
  body: { discardDraft, ...body }
1884
2215
  } = ctx.request;
1885
- const documentManager2 = getService$1("document-manager");
1886
- const documentMetadata2 = getService$1("document-metadata");
1887
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2216
+ const documentManager2 = getService$2("document-manager");
2217
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1888
2218
  if (permissionChecker2.cannot.unpublish()) {
1889
2219
  return ctx.forbidden();
1890
2220
  }
@@ -1892,8 +2222,8 @@ const collectionTypes = {
1892
2222
  return ctx.forbidden();
1893
2223
  }
1894
2224
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1895
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1896
- const { locale } = getDocumentLocaleAndStatus(body);
2225
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2226
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1897
2227
  const document = await documentManager2.findOne(id, model, {
1898
2228
  populate,
1899
2229
  locale,
@@ -1915,7 +2245,7 @@ const collectionTypes = {
1915
2245
  ctx.body = await async.pipe(
1916
2246
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
1917
2247
  permissionChecker2.sanitizeOutput,
1918
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2248
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1919
2249
  )(document);
1920
2250
  });
1921
2251
  },
@@ -1923,15 +2253,14 @@ const collectionTypes = {
1923
2253
  const { userAbility } = ctx.state;
1924
2254
  const { id, model } = ctx.params;
1925
2255
  const { body } = ctx.request;
1926
- const documentManager2 = getService$1("document-manager");
1927
- const documentMetadata2 = getService$1("document-metadata");
1928
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2256
+ const documentManager2 = getService$2("document-manager");
2257
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1929
2258
  if (permissionChecker2.cannot.discard()) {
1930
2259
  return ctx.forbidden();
1931
2260
  }
1932
2261
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
1933
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1934
- const { locale } = getDocumentLocaleAndStatus(body);
2262
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2263
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1935
2264
  const document = await documentManager2.findOne(id, model, {
1936
2265
  populate,
1937
2266
  locale,
@@ -1946,42 +2275,50 @@ const collectionTypes = {
1946
2275
  ctx.body = await async.pipe(
1947
2276
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
1948
2277
  permissionChecker2.sanitizeOutput,
1949
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2278
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1950
2279
  )(document);
1951
2280
  },
1952
2281
  async bulkDelete(ctx) {
1953
2282
  const { userAbility } = ctx.state;
1954
2283
  const { model } = ctx.params;
1955
2284
  const { query, body } = ctx.request;
1956
- const { ids } = body;
2285
+ const { documentIds } = body;
1957
2286
  await validateBulkActionInput(body);
1958
- const documentManager2 = getService$1("document-manager");
1959
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2287
+ const documentManager2 = getService$2("document-manager");
2288
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1960
2289
  if (permissionChecker2.cannot.delete()) {
1961
2290
  return ctx.forbidden();
1962
2291
  }
1963
2292
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
1964
- const idsWhereClause = { id: { $in: ids } };
1965
- const params = {
1966
- ...permissionQuery,
1967
- filters: {
1968
- $and: [idsWhereClause].concat(permissionQuery.filters || [])
2293
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2294
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2295
+ const documentLocales = await documentManager2.findLocales(documentIds, model, {
2296
+ populate,
2297
+ locale
2298
+ });
2299
+ if (documentLocales.length === 0) {
2300
+ return ctx.notFound();
2301
+ }
2302
+ for (const document of documentLocales) {
2303
+ if (permissionChecker2.cannot.delete(document)) {
2304
+ return ctx.forbidden();
1969
2305
  }
1970
- };
1971
- const { count } = await documentManager2.deleteMany(params, model);
2306
+ }
2307
+ const localeDocumentsIds = documentLocales.map((document) => document.documentId);
2308
+ const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
1972
2309
  ctx.body = { count };
1973
2310
  },
1974
2311
  async countDraftRelations(ctx) {
1975
2312
  const { userAbility } = ctx.state;
1976
2313
  const { model, id } = ctx.params;
1977
- const documentManager2 = getService$1("document-manager");
1978
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2314
+ const documentManager2 = getService$2("document-manager");
2315
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1979
2316
  if (permissionChecker2.cannot.read()) {
1980
2317
  return ctx.forbidden();
1981
2318
  }
1982
2319
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1983
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1984
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
2320
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2321
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1985
2322
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
1986
2323
  if (!entity) {
1987
2324
  return ctx.notFound();
@@ -1996,24 +2333,24 @@ const collectionTypes = {
1996
2333
  },
1997
2334
  async countManyEntriesDraftRelations(ctx) {
1998
2335
  const { userAbility } = ctx.state;
1999
- const ids = ctx.request.query.ids;
2336
+ const ids = ctx.request.query.documentIds;
2000
2337
  const locale = ctx.request.query.locale;
2001
2338
  const { model } = ctx.params;
2002
- const documentManager2 = getService$1("document-manager");
2003
- 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 });
2004
2341
  if (permissionChecker2.cannot.read()) {
2005
2342
  return ctx.forbidden();
2006
2343
  }
2007
- const entities = await documentManager2.findMany(
2344
+ const documents = await documentManager2.findMany(
2008
2345
  {
2009
2346
  filters: {
2010
- id: ids
2347
+ documentId: ids
2011
2348
  },
2012
2349
  locale
2013
2350
  },
2014
2351
  model
2015
2352
  );
2016
- if (!entities) {
2353
+ if (!documents) {
2017
2354
  return ctx.notFound();
2018
2355
  }
2019
2356
  const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
@@ -2024,13 +2361,13 @@ const collectionTypes = {
2024
2361
  };
2025
2362
  const components$1 = {
2026
2363
  findComponents(ctx) {
2027
- const components2 = getService$1("components").findAllComponents();
2028
- const { toDto } = getService$1("data-mapper");
2364
+ const components2 = getService$2("components").findAllComponents();
2365
+ const { toDto } = getService$2("data-mapper");
2029
2366
  ctx.body = { data: components2.map(toDto) };
2030
2367
  },
2031
2368
  async findComponentConfiguration(ctx) {
2032
2369
  const { uid: uid2 } = ctx.params;
2033
- const componentService = getService$1("components");
2370
+ const componentService = getService$2("components");
2034
2371
  const component = componentService.findComponent(uid2);
2035
2372
  if (!component) {
2036
2373
  return ctx.notFound("component.notFound");
@@ -2047,7 +2384,7 @@ const components$1 = {
2047
2384
  async updateComponentConfiguration(ctx) {
2048
2385
  const { uid: uid2 } = ctx.params;
2049
2386
  const { body } = ctx.request;
2050
- const componentService = getService$1("components");
2387
+ const componentService = getService$2("components");
2051
2388
  const component = componentService.findComponent(uid2);
2052
2389
  if (!component) {
2053
2390
  return ctx.notFound("component.notFound");
@@ -2081,12 +2418,12 @@ const contentTypes = {
2081
2418
  } catch (error) {
2082
2419
  return ctx.send({ error }, 400);
2083
2420
  }
2084
- const contentTypes2 = getService$1("content-types").findContentTypesByKind(kind);
2085
- const { toDto } = getService$1("data-mapper");
2421
+ const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
2422
+ const { toDto } = getService$2("data-mapper");
2086
2423
  ctx.body = { data: contentTypes2.map(toDto) };
2087
2424
  },
2088
2425
  async findContentTypesSettings(ctx) {
2089
- const { findAllContentTypes, findConfiguration } = getService$1("content-types");
2426
+ const { findAllContentTypes, findConfiguration } = getService$2("content-types");
2090
2427
  const contentTypes2 = await findAllContentTypes();
2091
2428
  const configurations = await Promise.all(
2092
2429
  contentTypes2.map(async (contentType) => {
@@ -2100,7 +2437,7 @@ const contentTypes = {
2100
2437
  },
2101
2438
  async findContentTypeConfiguration(ctx) {
2102
2439
  const { uid: uid2 } = ctx.params;
2103
- const contentTypeService = getService$1("content-types");
2440
+ const contentTypeService = getService$2("content-types");
2104
2441
  const contentType = await contentTypeService.findContentType(uid2);
2105
2442
  if (!contentType) {
2106
2443
  return ctx.notFound("contentType.notFound");
@@ -2122,13 +2459,13 @@ const contentTypes = {
2122
2459
  const { userAbility } = ctx.state;
2123
2460
  const { uid: uid2 } = ctx.params;
2124
2461
  const { body } = ctx.request;
2125
- const contentTypeService = getService$1("content-types");
2126
- const metricsService = getService$1("metrics");
2462
+ const contentTypeService = getService$2("content-types");
2463
+ const metricsService = getService$2("metrics");
2127
2464
  const contentType = await contentTypeService.findContentType(uid2);
2128
2465
  if (!contentType) {
2129
2466
  return ctx.notFound("contentType.notFound");
2130
2467
  }
2131
- if (!getService$1("permission").canConfigureContentType({ userAbility, contentType })) {
2468
+ if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
2132
2469
  return ctx.forbidden();
2133
2470
  }
2134
2471
  let input;
@@ -2161,10 +2498,10 @@ const contentTypes = {
2161
2498
  };
2162
2499
  const init = {
2163
2500
  getInitData(ctx) {
2164
- const { toDto } = getService$1("data-mapper");
2165
- const { findAllComponents } = getService$1("components");
2166
- const { getAllFieldSizes } = getService$1("field-sizes");
2167
- const { findAllContentTypes } = getService$1("content-types");
2501
+ const { toDto } = getService$2("data-mapper");
2502
+ const { findAllComponents } = getService$2("components");
2503
+ const { getAllFieldSizes } = getService$2("field-sizes");
2504
+ const { findAllContentTypes } = getService$2("content-types");
2168
2505
  ctx.body = {
2169
2506
  data: {
2170
2507
  fieldSizes: getAllFieldSizes(),
@@ -2200,36 +2537,41 @@ const addFiltersClause = (params, filtersClause) => {
2200
2537
  params.filters.$and.push(filtersClause);
2201
2538
  };
2202
2539
  const sanitizeMainField = (model, mainField, userAbility) => {
2203
- const permissionChecker2 = getService$1("permission-checker").create({
2540
+ const permissionChecker2 = getService$2("permission-checker").create({
2204
2541
  userAbility,
2205
2542
  model: model.uid
2206
2543
  });
2207
- if (!isListable(model, mainField)) {
2544
+ const isMainFieldListable = isListable(model, mainField);
2545
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2546
+ if (!isMainFieldListable || !canReadMainField) {
2208
2547
  return "id";
2209
2548
  }
2210
- if (permissionChecker2.cannot.read(null, mainField)) {
2211
- if (model.uid === "plugin::users-permissions.role") {
2212
- const userPermissionChecker = getService$1("permission-checker").create({
2213
- userAbility,
2214
- model: "plugin::users-permissions.user"
2215
- });
2216
- if (userPermissionChecker.can.read()) {
2217
- return "name";
2218
- }
2219
- }
2220
- return "id";
2549
+ if (model.uid === "plugin::users-permissions.role") {
2550
+ return "name";
2221
2551
  }
2222
2552
  return mainField;
2223
2553
  };
2224
- const addStatusToRelations = async (uid2, relations2) => {
2225
- if (!contentTypes$1.hasDraftAndPublish(strapi.contentTypes[uid2])) {
2554
+ const addStatusToRelations = async (targetUid, relations2) => {
2555
+ if (!contentTypes$1.hasDraftAndPublish(strapi.getModel(targetUid))) {
2556
+ return relations2;
2557
+ }
2558
+ const documentMetadata2 = getService$2("document-metadata");
2559
+ if (!relations2.length) {
2226
2560
  return relations2;
2227
2561
  }
2228
- const documentMetadata2 = getService$1("document-metadata");
2229
- const documentsAvailableStatus = await documentMetadata2.getManyAvailableStatus(uid2, relations2);
2562
+ const firstRelation = relations2[0];
2563
+ const filters = {
2564
+ documentId: { $in: relations2.map((r) => r.documentId) },
2565
+ // NOTE: find the "opposite" status
2566
+ publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
2567
+ };
2568
+ const availableStatus = await strapi.query(targetUid).findMany({
2569
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
2570
+ filters
2571
+ });
2230
2572
  return relations2.map((relation) => {
2231
- const availableStatuses = documentsAvailableStatus.filter(
2232
- (availableDocument) => availableDocument.documentId === relation.documentId
2573
+ const availableStatuses = availableStatus.filter(
2574
+ (availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
2233
2575
  );
2234
2576
  return {
2235
2577
  ...relation,
@@ -2250,11 +2592,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2250
2592
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2251
2593
  const isSourceLocalized = isLocalized(sourceModel);
2252
2594
  const isTargetLocalized = isLocalized(targetModel);
2253
- let validatedLocale = locale;
2254
- if (!targetModel || !isTargetLocalized)
2255
- validatedLocale = void 0;
2256
2595
  return {
2257
- locale: validatedLocale,
2596
+ locale,
2258
2597
  isSourceLocalized,
2259
2598
  isTargetLocalized
2260
2599
  };
@@ -2263,8 +2602,7 @@ const validateStatus = (sourceUid, status) => {
2263
2602
  const sourceModel = strapi.getModel(sourceUid);
2264
2603
  const isDP = contentTypes$1.hasDraftAndPublish;
2265
2604
  const isSourceDP = isDP(sourceModel);
2266
- if (!isSourceDP)
2267
- return { status: void 0 };
2605
+ if (!isSourceDP) return { status: void 0 };
2268
2606
  switch (status) {
2269
2607
  case "published":
2270
2608
  return { status: "published" };
@@ -2294,7 +2632,7 @@ const relations = {
2294
2632
  ctx.request?.query?.locale
2295
2633
  );
2296
2634
  const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
2297
- const permissionChecker2 = getService$1("permission-checker").create({
2635
+ const permissionChecker2 = getService$2("permission-checker").create({
2298
2636
  userAbility,
2299
2637
  model
2300
2638
  });
@@ -2319,7 +2657,7 @@ const relations = {
2319
2657
  where.id = id;
2320
2658
  }
2321
2659
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2322
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2660
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2323
2661
  const currentEntity = await strapi.db.query(model).findOne({
2324
2662
  where,
2325
2663
  populate
@@ -2334,7 +2672,7 @@ const relations = {
2334
2672
  }
2335
2673
  entryId = currentEntity.id;
2336
2674
  }
2337
- const modelConfig = isComponent2 ? await getService$1("components").findConfiguration(sourceSchema) : await getService$1("content-types").findConfiguration(sourceSchema);
2675
+ const modelConfig = isComponent2 ? await getService$2("components").findConfiguration(sourceSchema) : await getService$2("content-types").findConfiguration(sourceSchema);
2338
2676
  const targetSchema = strapi.getModel(targetUid);
2339
2677
  const mainField = flow(
2340
2678
  prop(`metadatas.${targetField}.edit.mainField`),
@@ -2357,7 +2695,7 @@ const relations = {
2357
2695
  attribute,
2358
2696
  fieldsToSelect,
2359
2697
  mainField,
2360
- source: { schema: sourceSchema },
2698
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2361
2699
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2362
2700
  sourceSchema,
2363
2701
  targetSchema,
@@ -2379,7 +2717,8 @@ const relations = {
2379
2717
  fieldsToSelect,
2380
2718
  mainField,
2381
2719
  source: {
2382
- schema: { uid: sourceUid, modelType: sourceModelType }
2720
+ schema: { uid: sourceUid, modelType: sourceModelType },
2721
+ isLocalized: isSourceLocalized
2383
2722
  },
2384
2723
  target: {
2385
2724
  schema: { uid: targetUid },
@@ -2387,7 +2726,7 @@ const relations = {
2387
2726
  }
2388
2727
  } = await this.extractAndValidateRequestInfo(ctx, id);
2389
2728
  const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
2390
- const permissionChecker2 = getService$1("permission-checker").create({
2729
+ const permissionChecker2 = getService$2("permission-checker").create({
2391
2730
  userAbility: ctx.state.userAbility,
2392
2731
  model: targetUid
2393
2732
  });
@@ -2417,12 +2756,16 @@ const relations = {
2417
2756
  } else {
2418
2757
  where.id = id;
2419
2758
  }
2420
- if (status) {
2421
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2759
+ const publishedAt = getPublishedAtClause(status, targetUid);
2760
+ if (!isEmpty(publishedAt)) {
2761
+ where[`${alias}.published_at`] = publishedAt;
2422
2762
  }
2423
- if (filterByLocale) {
2763
+ if (isTargetLocalized && locale) {
2424
2764
  where[`${alias}.locale`] = locale;
2425
2765
  }
2766
+ if (isSourceLocalized && locale) {
2767
+ where.locale = locale;
2768
+ }
2426
2769
  if ((idsToInclude?.length ?? 0) !== 0) {
2427
2770
  where[`${alias}.id`].$notIn = idsToInclude;
2428
2771
  }
@@ -2440,7 +2783,8 @@ const relations = {
2440
2783
  id: { $notIn: uniq(idsToOmit) }
2441
2784
  });
2442
2785
  }
2443
- const res = await strapi.db.query(targetUid).findPage(strapi.get("query-params").transform(targetUid, queryParams));
2786
+ const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
2787
+ const res = await strapi.db.query(targetUid).findPage(dbQuery);
2444
2788
  ctx.body = {
2445
2789
  ...res,
2446
2790
  results: await addStatusToRelations(targetUid, res.results)
@@ -2455,29 +2799,39 @@ const relations = {
2455
2799
  attribute,
2456
2800
  targetField,
2457
2801
  fieldsToSelect,
2458
- source: {
2459
- schema: { uid: sourceUid }
2460
- },
2461
- target: {
2462
- schema: { uid: targetUid }
2463
- }
2802
+ status,
2803
+ source: { schema: sourceSchema },
2804
+ target: { schema: targetSchema }
2464
2805
  } = await this.extractAndValidateRequestInfo(ctx, id);
2465
- const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2806
+ const { uid: sourceUid } = sourceSchema;
2807
+ const { uid: targetUid } = targetSchema;
2808
+ const permissionQuery = await getService$2("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2466
2809
  const dbQuery = strapi.db.query(sourceUid);
2467
2810
  const loadRelations = relations$1.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
2811
+ const filters = {};
2812
+ if (sourceSchema?.options?.draftAndPublish) {
2813
+ if (targetSchema?.options?.draftAndPublish) {
2814
+ if (status === "published") {
2815
+ filters.publishedAt = { $notNull: true };
2816
+ } else {
2817
+ filters.publishedAt = { $null: true };
2818
+ }
2819
+ }
2820
+ } else if (targetSchema?.options?.draftAndPublish) {
2821
+ filters.publishedAt = { $null: true };
2822
+ }
2468
2823
  const res = await loadRelations({ id: entryId }, targetField, {
2469
- select: ["id", "documentId", "locale", "publishedAt"],
2824
+ select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
2470
2825
  ordering: "desc",
2471
2826
  page: ctx.request.query.page,
2472
- pageSize: ctx.request.query.pageSize
2827
+ pageSize: ctx.request.query.pageSize,
2828
+ filters
2473
2829
  });
2474
2830
  const loadedIds = res.results.map((item) => item.id);
2475
2831
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2476
2832
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2477
2833
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2478
- ordering: "desc",
2479
- page: ctx.request.query.page,
2480
- pageSize: ctx.request.query.pageSize
2834
+ ordering: "desc"
2481
2835
  });
2482
2836
  const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
2483
2837
  ctx.body = {
@@ -2492,10 +2846,10 @@ const relations = {
2492
2846
  }
2493
2847
  };
2494
2848
  const buildPopulateFromQuery = async (query, model) => {
2495
- return getService$1("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2849
+ return getService$2("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2496
2850
  };
2497
2851
  const findDocument = async (query, uid2, opts = {}) => {
2498
- const documentManager2 = getService$1("document-manager");
2852
+ const documentManager2 = getService$2("document-manager");
2499
2853
  const populate = await buildPopulateFromQuery(query, uid2);
2500
2854
  return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
2501
2855
  };
@@ -2503,13 +2857,13 @@ const createOrUpdateDocument = async (ctx, opts) => {
2503
2857
  const { user, userAbility } = ctx.state;
2504
2858
  const { model } = ctx.params;
2505
2859
  const { body, query } = ctx.request;
2506
- const documentManager2 = getService$1("document-manager");
2507
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2860
+ const documentManager2 = getService$2("document-manager");
2861
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2508
2862
  if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
2509
2863
  throw new errors.ForbiddenError();
2510
2864
  }
2511
2865
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2512
- const { locale } = getDocumentLocaleAndStatus(body);
2866
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2513
2867
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2514
2868
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2515
2869
  // Find the first document to check if it exists
@@ -2545,13 +2899,12 @@ const singleTypes = {
2545
2899
  const { userAbility } = ctx.state;
2546
2900
  const { model } = ctx.params;
2547
2901
  const { query = {} } = ctx.request;
2548
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2549
- const documentMetadata2 = getService$1("document-metadata");
2902
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2550
2903
  if (permissionChecker2.cannot.read()) {
2551
2904
  return ctx.forbidden();
2552
2905
  }
2553
2906
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2554
- const { locale, status } = getDocumentLocaleAndStatus(query);
2907
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
2555
2908
  const version = await findDocument(permissionQuery, model, { locale, status });
2556
2909
  if (!version) {
2557
2910
  if (permissionChecker2.cannot.create()) {
@@ -2561,9 +2914,11 @@ const singleTypes = {
2561
2914
  if (!document) {
2562
2915
  return ctx.notFound();
2563
2916
  }
2564
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
2917
+ const { meta } = await formatDocumentWithMetadata(
2918
+ permissionChecker2,
2565
2919
  model,
2566
- { id: document.documentId, locale, publishedAt: null },
2920
+ // @ts-expect-error - fix types
2921
+ { documentId: document.documentId, locale, publishedAt: null },
2567
2922
  { availableLocales: true, availableStatus: false }
2568
2923
  );
2569
2924
  ctx.body = { data: {}, meta };
@@ -2573,29 +2928,28 @@ const singleTypes = {
2573
2928
  return ctx.forbidden();
2574
2929
  }
2575
2930
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
2576
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2931
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2577
2932
  },
2578
2933
  async createOrUpdate(ctx) {
2579
2934
  const { userAbility } = ctx.state;
2580
2935
  const { model } = ctx.params;
2581
- const documentMetadata2 = getService$1("document-metadata");
2582
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2936
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2583
2937
  const document = await createOrUpdateDocument(ctx);
2584
2938
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2585
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2939
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2586
2940
  },
2587
2941
  async delete(ctx) {
2588
2942
  const { userAbility } = ctx.state;
2589
2943
  const { model } = ctx.params;
2590
2944
  const { query = {} } = ctx.request;
2591
- const documentManager2 = getService$1("document-manager");
2592
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2945
+ const documentManager2 = getService$2("document-manager");
2946
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2593
2947
  if (permissionChecker2.cannot.delete()) {
2594
2948
  return ctx.forbidden();
2595
2949
  }
2596
2950
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2597
2951
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2598
- const { locale } = getDocumentLocaleAndStatus(query);
2952
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2599
2953
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2600
2954
  populate,
2601
2955
  locale
@@ -2617,9 +2971,8 @@ const singleTypes = {
2617
2971
  const { userAbility } = ctx.state;
2618
2972
  const { model } = ctx.params;
2619
2973
  const { query = {} } = ctx.request;
2620
- const documentManager2 = getService$1("document-manager");
2621
- const documentMetadata2 = getService$1("document-metadata");
2622
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2974
+ const documentManager2 = getService$2("document-manager");
2975
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2623
2976
  if (permissionChecker2.cannot.publish()) {
2624
2977
  return ctx.forbidden();
2625
2978
  }
@@ -2633,11 +2986,12 @@ const singleTypes = {
2633
2986
  if (permissionChecker2.cannot.publish(document)) {
2634
2987
  throw new errors.ForbiddenError();
2635
2988
  }
2636
- const { locale } = getDocumentLocaleAndStatus(document);
2637
- return documentManager2.publish(document.documentId, model, { locale });
2989
+ const { locale } = await getDocumentLocaleAndStatus(document, model);
2990
+ const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2991
+ return publishResult.at(0);
2638
2992
  });
2639
2993
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
2640
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2994
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2641
2995
  },
2642
2996
  async unpublish(ctx) {
2643
2997
  const { userAbility } = ctx.state;
@@ -2646,9 +3000,8 @@ const singleTypes = {
2646
3000
  body: { discardDraft, ...body },
2647
3001
  query = {}
2648
3002
  } = ctx.request;
2649
- const documentManager2 = getService$1("document-manager");
2650
- const documentMetadata2 = getService$1("document-metadata");
2651
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3003
+ const documentManager2 = getService$2("document-manager");
3004
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2652
3005
  if (permissionChecker2.cannot.unpublish()) {
2653
3006
  return ctx.forbidden();
2654
3007
  }
@@ -2656,7 +3009,7 @@ const singleTypes = {
2656
3009
  return ctx.forbidden();
2657
3010
  }
2658
3011
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2659
- const { locale } = getDocumentLocaleAndStatus(body);
3012
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2660
3013
  const document = await findDocument(sanitizedQuery, model, { locale });
2661
3014
  if (!document) {
2662
3015
  return ctx.notFound();
@@ -2674,7 +3027,7 @@ const singleTypes = {
2674
3027
  ctx.body = await async.pipe(
2675
3028
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
2676
3029
  permissionChecker2.sanitizeOutput,
2677
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
3030
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2678
3031
  )(document);
2679
3032
  });
2680
3033
  },
@@ -2682,14 +3035,13 @@ const singleTypes = {
2682
3035
  const { userAbility } = ctx.state;
2683
3036
  const { model } = ctx.params;
2684
3037
  const { body, query = {} } = ctx.request;
2685
- const documentManager2 = getService$1("document-manager");
2686
- const documentMetadata2 = getService$1("document-metadata");
2687
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3038
+ const documentManager2 = getService$2("document-manager");
3039
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2688
3040
  if (permissionChecker2.cannot.discard()) {
2689
3041
  return ctx.forbidden();
2690
3042
  }
2691
3043
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2692
- const { locale } = getDocumentLocaleAndStatus(body);
3044
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2693
3045
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2694
3046
  if (!document) {
2695
3047
  return ctx.notFound();
@@ -2700,16 +3052,16 @@ const singleTypes = {
2700
3052
  ctx.body = await async.pipe(
2701
3053
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
2702
3054
  permissionChecker2.sanitizeOutput,
2703
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
3055
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2704
3056
  )(document);
2705
3057
  },
2706
3058
  async countDraftRelations(ctx) {
2707
3059
  const { userAbility } = ctx.state;
2708
3060
  const { model } = ctx.params;
2709
3061
  const { query } = ctx.request;
2710
- const documentManager2 = getService$1("document-manager");
2711
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2712
- const { locale } = getDocumentLocaleAndStatus(query);
3062
+ const documentManager2 = getService$2("document-manager");
3063
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
3064
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2713
3065
  if (permissionChecker2.cannot.read()) {
2714
3066
  return ctx.forbidden();
2715
3067
  }
@@ -2730,9 +3082,9 @@ const uid$1 = {
2730
3082
  async generateUID(ctx) {
2731
3083
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2732
3084
  const { query = {} } = ctx.request;
2733
- const { locale } = getDocumentLocaleAndStatus(query);
3085
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2734
3086
  await validateUIDField(contentTypeUID, field);
2735
- const uidService = getService$1("uid");
3087
+ const uidService = getService$2("uid");
2736
3088
  ctx.body = {
2737
3089
  data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
2738
3090
  };
@@ -2742,9 +3094,9 @@ const uid$1 = {
2742
3094
  ctx.request.body
2743
3095
  );
2744
3096
  const { query = {} } = ctx.request;
2745
- const { locale } = getDocumentLocaleAndStatus(query);
3097
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2746
3098
  await validateUIDField(contentTypeUID, field);
2747
- const uidService = getService$1("uid");
3099
+ const uidService = getService$2("uid");
2748
3100
  const isAvailable = await uidService.checkUIDAvailability({
2749
3101
  contentTypeUID,
2750
3102
  field,
@@ -2765,7 +3117,8 @@ const controllers = {
2765
3117
  relations,
2766
3118
  "single-types": singleTypes,
2767
3119
  uid: uid$1,
2768
- ...history.controllers ? history.controllers : {}
3120
+ ...history.controllers ? history.controllers : {},
3121
+ ...preview.controllers ? preview.controllers : {}
2769
3122
  };
2770
3123
  const keys = {
2771
3124
  CONFIGURATION: "configuration"
@@ -2894,18 +3247,15 @@ async function syncMetadatas(configuration, schema) {
2894
3247
  _.set(updatedMeta, ["list", "searchable"], false);
2895
3248
  _.set(acc, [key], updatedMeta);
2896
3249
  }
2897
- if (!_.has(edit, "mainField"))
2898
- return acc;
3250
+ if (!_.has(edit, "mainField")) return acc;
2899
3251
  if (!isRelation$1(attr)) {
2900
3252
  _.set(updatedMeta, "edit", _.omit(edit, ["mainField"]));
2901
3253
  _.set(acc, [key], updatedMeta);
2902
3254
  return acc;
2903
3255
  }
2904
- if (edit.mainField === "id")
2905
- return acc;
3256
+ if (edit.mainField === "id") return acc;
2906
3257
  const targetSchema = getTargetSchema(attr.targetModel);
2907
- if (!targetSchema)
2908
- return acc;
3258
+ if (!targetSchema) return acc;
2909
3259
  if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
2910
3260
  _.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
2911
3261
  _.set(acc, [key], updatedMeta);
@@ -2916,12 +3266,12 @@ async function syncMetadatas(configuration, schema) {
2916
3266
  return _.assign(metasWithDefaults, updatedMetas);
2917
3267
  }
2918
3268
  const getTargetSchema = (targetModel) => {
2919
- return getService$1("content-types").findContentType(targetModel);
3269
+ return getService$2("content-types").findContentType(targetModel);
2920
3270
  };
2921
3271
  const DEFAULT_LIST_LENGTH = 4;
2922
3272
  const MAX_ROW_SIZE = 12;
2923
3273
  const isAllowedFieldSize = (type, size) => {
2924
- const { getFieldSize } = getService$1("field-sizes");
3274
+ const { getFieldSize } = getService$2("field-sizes");
2925
3275
  const fieldSize = getFieldSize(type);
2926
3276
  if (!fieldSize.isResizable && size !== fieldSize.default) {
2927
3277
  return false;
@@ -2929,7 +3279,7 @@ const isAllowedFieldSize = (type, size) => {
2929
3279
  return size <= MAX_ROW_SIZE;
2930
3280
  };
2931
3281
  const getDefaultFieldSize = (attribute) => {
2932
- const { hasFieldSize, getFieldSize } = getService$1("field-sizes");
3282
+ const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
2933
3283
  return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
2934
3284
  };
2935
3285
  async function createDefaultLayouts(schema) {
@@ -2950,8 +3300,7 @@ function createDefaultEditLayout(schema) {
2950
3300
  return appendToEditLayout([], keys2, schema);
2951
3301
  }
2952
3302
  function syncLayouts(configuration, schema) {
2953
- if (_.isEmpty(configuration.layouts))
2954
- return createDefaultLayouts(schema);
3303
+ if (_.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
2955
3304
  const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
2956
3305
  let cleanList = list.filter((attr) => isListable(schema, attr));
2957
3306
  const cleanEditRelations = editRelations.filter(
@@ -2962,9 +3311,8 @@ function syncLayouts(configuration, schema) {
2962
3311
  for (const row of edit) {
2963
3312
  const newRow = [];
2964
3313
  for (const el of row) {
2965
- if (!hasEditableAttribute(schema, el.name))
2966
- continue;
2967
- const { hasFieldSize } = getService$1("field-sizes");
3314
+ if (!hasEditableAttribute(schema, el.name)) continue;
3315
+ const { hasFieldSize } = getService$2("field-sizes");
2968
3316
  const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
2969
3317
  if (!isAllowedFieldSize(fieldType, el.size)) {
2970
3318
  elementsToReAppend.push(el.name);
@@ -2994,8 +3342,7 @@ function syncLayouts(configuration, schema) {
2994
3342
  };
2995
3343
  }
2996
3344
  const appendToEditLayout = (layout = [], keysToAppend, schema) => {
2997
- if (keysToAppend.length === 0)
2998
- return layout;
3345
+ if (keysToAppend.length === 0) return layout;
2999
3346
  let currentRowIndex = Math.max(layout.length - 1, 0);
3000
3347
  if (!layout[currentRowIndex]) {
3001
3348
  layout[currentRowIndex] = [];
@@ -3104,17 +3451,17 @@ const configurationService$1 = createConfigurationService({
3104
3451
  isComponent: true,
3105
3452
  prefix: STORE_KEY_PREFIX,
3106
3453
  getModels() {
3107
- const { toContentManagerModel } = getService$1("data-mapper");
3454
+ const { toContentManagerModel } = getService$2("data-mapper");
3108
3455
  return mapValues(toContentManagerModel, strapi.components);
3109
3456
  }
3110
3457
  });
3111
3458
  const components = ({ strapi: strapi2 }) => ({
3112
3459
  findAllComponents() {
3113
- const { toContentManagerModel } = getService$1("data-mapper");
3460
+ const { toContentManagerModel } = getService$2("data-mapper");
3114
3461
  return Object.values(strapi2.components).map(toContentManagerModel);
3115
3462
  },
3116
3463
  findComponent(uid2) {
3117
- const { toContentManagerModel } = getService$1("data-mapper");
3464
+ const { toContentManagerModel } = getService$2("data-mapper");
3118
3465
  const component = strapi2.components[uid2];
3119
3466
  return isNil$1(component) ? component : toContentManagerModel(component);
3120
3467
  },
@@ -3165,17 +3512,17 @@ const configurationService = createConfigurationService({
3165
3512
  storeUtils,
3166
3513
  prefix: "content_types",
3167
3514
  getModels() {
3168
- const { toContentManagerModel } = getService$1("data-mapper");
3515
+ const { toContentManagerModel } = getService$2("data-mapper");
3169
3516
  return mapValues(toContentManagerModel, strapi.contentTypes);
3170
3517
  }
3171
3518
  });
3172
3519
  const service = ({ strapi: strapi2 }) => ({
3173
3520
  findAllContentTypes() {
3174
- const { toContentManagerModel } = getService$1("data-mapper");
3521
+ const { toContentManagerModel } = getService$2("data-mapper");
3175
3522
  return Object.values(strapi2.contentTypes).map(toContentManagerModel);
3176
3523
  },
3177
3524
  findContentType(uid2) {
3178
- const { toContentManagerModel } = getService$1("data-mapper");
3525
+ const { toContentManagerModel } = getService$2("data-mapper");
3179
3526
  const contentType = strapi2.contentTypes[uid2];
3180
3527
  return isNil$1(contentType) ? contentType : toContentManagerModel(contentType);
3181
3528
  },
@@ -3204,7 +3551,7 @@ const service = ({ strapi: strapi2 }) => ({
3204
3551
  return this.findConfiguration(contentType);
3205
3552
  },
3206
3553
  findComponentsConfigurations(contentType) {
3207
- return getService$1("components").findComponentsConfigurations(contentType);
3554
+ return getService$2("components").findComponentsConfigurations(contentType);
3208
3555
  },
3209
3556
  syncConfigurations() {
3210
3557
  return configurationService.syncConfigurations();
@@ -3385,12 +3732,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3385
3732
  ability: userAbility,
3386
3733
  model
3387
3734
  });
3388
- const toSubject = (entity) => entity ? permissionsManager.toSubject(entity, model) : model;
3735
+ const { actionProvider } = strapi2.service("admin::permission");
3736
+ const toSubject = (entity) => {
3737
+ return entity ? permissionsManager.toSubject(entity, model) : model;
3738
+ };
3389
3739
  const can = (action, entity, field) => {
3390
- return userAbility.can(action, toSubject(entity), field);
3740
+ const subject = toSubject(entity);
3741
+ const aliases = actionProvider.unstable_aliases(action, model);
3742
+ return (
3743
+ // Test the original action to see if it passes
3744
+ userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
3745
+ aliases.some((alias) => userAbility.can(alias, subject, field))
3746
+ );
3391
3747
  };
3392
3748
  const cannot = (action, entity, field) => {
3393
- return userAbility.cannot(action, toSubject(entity), field);
3749
+ const subject = toSubject(entity);
3750
+ const aliases = actionProvider.unstable_aliases(action, model);
3751
+ return (
3752
+ // Test both the original action
3753
+ userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
3754
+ aliases.every((alias) => userAbility.cannot(alias, subject, field))
3755
+ );
3394
3756
  };
3395
3757
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3396
3758
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3461,7 +3823,7 @@ const permission = ({ strapi: strapi2 }) => ({
3461
3823
  return userAbility.can(action);
3462
3824
  },
3463
3825
  async registerPermissions() {
3464
- const displayedContentTypes = getService$1("content-types").findDisplayedContentTypes();
3826
+ const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
3465
3827
  const contentTypesUids = displayedContentTypes.map(prop("uid"));
3466
3828
  const actions = [
3467
3829
  {
@@ -3533,7 +3895,7 @@ const permission = ({ strapi: strapi2 }) => ({
3533
3895
  await strapi2.service("admin::permission").actionProvider.registerMany(actions);
3534
3896
  }
3535
3897
  });
3536
- const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils.contentTypes;
3898
+ const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils.contentTypes;
3537
3899
  const { isAnyToMany } = strapiUtils.relations;
3538
3900
  const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils.contentTypes.constants;
3539
3901
  const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
@@ -3546,6 +3908,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
3546
3908
  if (initialPopulate) {
3547
3909
  return initialPopulate;
3548
3910
  }
3911
+ if (attributeName === "localizations") {
3912
+ const validationPopulate = getPopulateForValidation(model.uid);
3913
+ return {
3914
+ populate: validationPopulate.populate
3915
+ };
3916
+ }
3549
3917
  if (!isVisibleAttribute$1(model, attributeName)) {
3550
3918
  return true;
3551
3919
  }
@@ -3605,6 +3973,9 @@ const getDeepPopulate = (uid2, {
3605
3973
  return {};
3606
3974
  }
3607
3975
  const model = strapi.getModel(uid2);
3976
+ if (!model) {
3977
+ return {};
3978
+ }
3608
3979
  return Object.keys(model.attributes).reduce(
3609
3980
  (populateAcc, attributeName) => merge(
3610
3981
  populateAcc,
@@ -3624,6 +3995,48 @@ const getDeepPopulate = (uid2, {
3624
3995
  {}
3625
3996
  );
3626
3997
  };
3998
+ const getPopulateForValidation = (uid2) => {
3999
+ const model = strapi.getModel(uid2);
4000
+ if (!model) {
4001
+ return {};
4002
+ }
4003
+ return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
4004
+ if (isScalarAttribute(attribute)) {
4005
+ if (getDoesAttributeRequireValidation(attribute)) {
4006
+ populateAcc.fields = populateAcc.fields || [];
4007
+ populateAcc.fields.push(attributeName);
4008
+ }
4009
+ return populateAcc;
4010
+ }
4011
+ if (isComponent(attribute)) {
4012
+ const component = attribute.component;
4013
+ const componentResult = getPopulateForValidation(component);
4014
+ if (Object.keys(componentResult).length > 0) {
4015
+ populateAcc.populate = populateAcc.populate || {};
4016
+ populateAcc.populate[attributeName] = componentResult;
4017
+ }
4018
+ return populateAcc;
4019
+ }
4020
+ if (isDynamicZone(attribute)) {
4021
+ const components2 = attribute.components;
4022
+ const componentsResult = (components2 || []).reduce(
4023
+ (acc, componentUID) => {
4024
+ const componentResult = getPopulateForValidation(componentUID);
4025
+ if (Object.keys(componentResult).length > 0) {
4026
+ acc[componentUID] = componentResult;
4027
+ }
4028
+ return acc;
4029
+ },
4030
+ {}
4031
+ );
4032
+ if (Object.keys(componentsResult).length > 0) {
4033
+ populateAcc.populate = populateAcc.populate || {};
4034
+ populateAcc.populate[attributeName] = { on: componentsResult };
4035
+ }
4036
+ }
4037
+ return populateAcc;
4038
+ }, {});
4039
+ };
3627
4040
  const getDeepPopulateDraftCount = (uid2) => {
3628
4041
  const model = strapi.getModel(uid2);
3629
4042
  let hasRelations = false;
@@ -3631,6 +4044,10 @@ const getDeepPopulateDraftCount = (uid2) => {
3631
4044
  const attribute = model.attributes[attributeName];
3632
4045
  switch (attribute.type) {
3633
4046
  case "relation": {
4047
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
4048
+ if (isMorphRelation) {
4049
+ break;
4050
+ }
3634
4051
  if (isVisibleAttribute$1(model, attributeName)) {
3635
4052
  populateAcc[attributeName] = {
3636
4053
  count: true,
@@ -3645,22 +4062,24 @@ const getDeepPopulateDraftCount = (uid2) => {
3645
4062
  attribute.component
3646
4063
  );
3647
4064
  if (childHasRelations) {
3648
- populateAcc[attributeName] = { populate: populate2 };
4065
+ populateAcc[attributeName] = {
4066
+ populate: populate2
4067
+ };
3649
4068
  hasRelations = true;
3650
4069
  }
3651
4070
  break;
3652
4071
  }
3653
4072
  case "dynamiczone": {
3654
- const dzPopulate = (attribute.components || []).reduce((acc, componentUID) => {
3655
- const { populate: populate2, hasRelations: childHasRelations } = getDeepPopulateDraftCount(componentUID);
3656
- if (childHasRelations) {
4073
+ const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
4074
+ const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
4075
+ if (componentHasRelations) {
3657
4076
  hasRelations = true;
3658
- return merge(acc, populate2);
4077
+ return { ...acc, [componentUID]: { populate: componentPopulate } };
3659
4078
  }
3660
4079
  return acc;
3661
4080
  }, {});
3662
- if (!isEmpty(dzPopulate)) {
3663
- populateAcc[attributeName] = { populate: dzPopulate };
4081
+ if (!isEmpty(dzPopulateFragment)) {
4082
+ populateAcc[attributeName] = { on: dzPopulateFragment };
3664
4083
  }
3665
4084
  break;
3666
4085
  }
@@ -3695,7 +4114,7 @@ const getQueryPopulate = async (uid2, query) => {
3695
4114
  return populateQuery;
3696
4115
  };
3697
4116
  const buildDeepPopulate = (uid2) => {
3698
- return getService$1("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
4117
+ return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
3699
4118
  };
3700
4119
  const populateBuilder = (uid2) => {
3701
4120
  let getInitialPopulate = async () => {
@@ -3852,41 +4271,55 @@ const AVAILABLE_STATUS_FIELDS = [
3852
4271
  "updatedBy",
3853
4272
  "status"
3854
4273
  ];
3855
- const AVAILABLE_LOCALES_FIELDS = ["id", "locale", "updatedAt", "createdAt", "status"];
4274
+ const AVAILABLE_LOCALES_FIELDS = [
4275
+ "id",
4276
+ "locale",
4277
+ "updatedAt",
4278
+ "createdAt",
4279
+ "publishedAt",
4280
+ "documentId"
4281
+ ];
3856
4282
  const CONTENT_MANAGER_STATUS = {
3857
4283
  PUBLISHED: "published",
3858
4284
  DRAFT: "draft",
3859
4285
  MODIFIED: "modified"
3860
4286
  };
3861
- const areDatesEqual = (date1, date2, threshold) => {
3862
- if (!date1 || !date2) {
4287
+ const getIsVersionLatestModification = (version, otherVersion) => {
4288
+ if (!version || !version.updatedAt) {
3863
4289
  return false;
3864
4290
  }
3865
- const time1 = new Date(date1).getTime();
3866
- const time2 = new Date(date2).getTime();
3867
- const difference2 = Math.abs(time1 - time2);
3868
- return difference2 <= threshold;
4291
+ const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
4292
+ const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
4293
+ return versionUpdatedAt > otherUpdatedAt;
3869
4294
  };
3870
4295
  const documentMetadata = ({ strapi: strapi2 }) => ({
3871
4296
  /**
3872
4297
  * Returns available locales of a document for the current status
3873
4298
  */
3874
- getAvailableLocales(uid2, version, allVersions) {
4299
+ async getAvailableLocales(uid2, version, allVersions) {
3875
4300
  const versionsByLocale = groupBy("locale", allVersions);
3876
- delete versionsByLocale[version.locale];
3877
- return Object.values(versionsByLocale).map((localeVersions) => {
3878
- if (!contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2))) {
3879
- return pick(AVAILABLE_LOCALES_FIELDS, localeVersions[0]);
3880
- }
3881
- const draftVersion = localeVersions.find((v) => v.publishedAt === null);
3882
- const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
3883
- if (!draftVersion)
3884
- return;
3885
- return {
3886
- ...pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
3887
- status: this.getStatus(draftVersion, otherVersions)
3888
- };
3889
- }).filter(Boolean);
4301
+ if (version.locale) {
4302
+ delete versionsByLocale[version.locale];
4303
+ }
4304
+ const model = strapi2.getModel(uid2);
4305
+ const mappingResult = await async.map(
4306
+ Object.values(versionsByLocale),
4307
+ async (localeVersions) => {
4308
+ if (!contentTypes$1.hasDraftAndPublish(model)) {
4309
+ return localeVersions[0];
4310
+ }
4311
+ const draftVersion = localeVersions.find((v) => v.publishedAt === null);
4312
+ const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
4313
+ if (!draftVersion) {
4314
+ return;
4315
+ }
4316
+ return {
4317
+ ...draftVersion,
4318
+ status: this.getStatus(draftVersion, otherVersions)
4319
+ };
4320
+ }
4321
+ );
4322
+ return mappingResult.filter(Boolean);
3890
4323
  },
3891
4324
  /**
3892
4325
  * Returns available status of a document for the current locale
@@ -3898,8 +4331,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3898
4331
  const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
3899
4332
  return matchLocale && matchStatus;
3900
4333
  });
3901
- if (!availableStatus)
3902
- return availableStatus;
4334
+ if (!availableStatus) return availableStatus;
3903
4335
  return pick(AVAILABLE_STATUS_FIELDS, availableStatus);
3904
4336
  },
3905
4337
  /**
@@ -3909,50 +4341,64 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3909
4341
  * @returns
3910
4342
  */
3911
4343
  async getManyAvailableStatus(uid2, documents) {
3912
- if (!documents.length)
3913
- return [];
4344
+ if (!documents.length) return [];
3914
4345
  const status = documents[0].publishedAt !== null ? "published" : "draft";
3915
- const locale = documents[0]?.locale;
3916
- const otherStatus = status === "published" ? "draft" : "published";
3917
- return strapi2.documents(uid2).findMany({
3918
- filters: {
3919
- documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) }
3920
- },
3921
- status: otherStatus,
3922
- locale,
3923
- fields: ["documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
4346
+ const locales = documents.map((d) => d.locale).filter(Boolean);
4347
+ const where = {
4348
+ documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) },
4349
+ publishedAt: { $null: status === "published" }
4350
+ };
4351
+ if (locales.length) {
4352
+ where.locale = { $in: locales };
4353
+ }
4354
+ return strapi2.query(uid2).findMany({
4355
+ where,
4356
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
3924
4357
  });
3925
4358
  },
3926
4359
  getStatus(version, otherDocumentStatuses) {
3927
- const isDraft = version.publishedAt === null;
3928
- if (!otherDocumentStatuses?.length) {
3929
- return isDraft ? CONTENT_MANAGER_STATUS.DRAFT : CONTENT_MANAGER_STATUS.PUBLISHED;
3930
- }
3931
- if (isDraft) {
3932
- const publishedVersion = otherDocumentStatuses?.find((d) => d.publishedAt !== null);
3933
- if (!publishedVersion) {
3934
- return CONTENT_MANAGER_STATUS.DRAFT;
3935
- }
4360
+ let draftVersion;
4361
+ let publishedVersion;
4362
+ if (version.publishedAt) {
4363
+ publishedVersion = version;
4364
+ } else {
4365
+ draftVersion = version;
3936
4366
  }
3937
- if (areDatesEqual(version.updatedAt, otherDocumentStatuses.at(0)?.updatedAt, 500)) {
3938
- return CONTENT_MANAGER_STATUS.PUBLISHED;
4367
+ const otherVersion = otherDocumentStatuses?.at(0);
4368
+ if (otherVersion?.publishedAt) {
4369
+ publishedVersion = otherVersion;
4370
+ } else if (otherVersion) {
4371
+ draftVersion = otherVersion;
3939
4372
  }
3940
- return CONTENT_MANAGER_STATUS.MODIFIED;
4373
+ if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
4374
+ if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
4375
+ const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4376
+ return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
3941
4377
  },
4378
+ // TODO is it necessary to return metadata on every page of the CM
4379
+ // We could refactor this so the locales are only loaded when they're
4380
+ // needed. e.g. in the bulk locale action modal.
3942
4381
  async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
3943
- const versions = await strapi2.db.query(uid2).findMany({
3944
- where: { documentId: version.documentId },
3945
- select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
4382
+ const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
4383
+ const params = {
3946
4384
  populate: {
4385
+ ...populate,
4386
+ // NOTE: creator fields are selected in this way to avoid exposing sensitive data
3947
4387
  createdBy: {
3948
4388
  select: ["id", "firstname", "lastname", "email"]
3949
4389
  },
3950
4390
  updatedBy: {
3951
4391
  select: ["id", "firstname", "lastname", "email"]
3952
4392
  }
4393
+ },
4394
+ fields: uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
4395
+ filters: {
4396
+ documentId: version.documentId
3953
4397
  }
3954
- });
3955
- const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
4398
+ };
4399
+ const dbParams = strapi2.get("query-params").transform(uid2, params);
4400
+ const versions = await strapi2.db.query(uid2).findMany(dbParams);
4401
+ const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions) : [];
3956
4402
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
3957
4403
  return {
3958
4404
  availableLocales: availableLocalesResult,
@@ -3965,13 +4411,30 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3965
4411
  * - Available status of the document for the current locale
3966
4412
  */
3967
4413
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
3968
- if (!document)
3969
- return document;
4414
+ if (!document) {
4415
+ return {
4416
+ data: document,
4417
+ meta: {
4418
+ availableLocales: [],
4419
+ availableStatus: []
4420
+ }
4421
+ };
4422
+ }
3970
4423
  const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
3971
4424
  if (!hasDraftAndPublish) {
3972
4425
  opts.availableStatus = false;
3973
4426
  }
3974
4427
  const meta = await this.getMetadata(uid2, document, opts);
4428
+ if (document.localizations) {
4429
+ const otherStatus = await this.getManyAvailableStatus(uid2, document.localizations);
4430
+ document.localizations = document.localizations.map((d) => {
4431
+ const status = otherStatus.find((s) => s.documentId === d.documentId);
4432
+ return {
4433
+ ...d,
4434
+ status: this.getStatus(d, status ? [status] : [])
4435
+ };
4436
+ });
4437
+ }
3975
4438
  return {
3976
4439
  data: {
3977
4440
  ...document,
@@ -4016,26 +4479,9 @@ const sumDraftCounts = (entity, uid2) => {
4016
4479
  }, 0);
4017
4480
  };
4018
4481
  const { ApplicationError } = errors;
4019
- const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
4020
4482
  const { PUBLISHED_AT_ATTRIBUTE } = contentTypes$1.constants;
4021
4483
  const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
4022
4484
  const omitIdField = omit("id");
4023
- const emitEvent = async (uid2, event, document) => {
4024
- const modelDef = strapi.getModel(uid2);
4025
- const sanitizedDocument = await sanitize.sanitizers.defaultSanitizeOutput(
4026
- {
4027
- schema: modelDef,
4028
- getModel(uid22) {
4029
- return strapi.getModel(uid22);
4030
- }
4031
- },
4032
- document
4033
- );
4034
- strapi.eventHub.emit(event, {
4035
- model: modelDef.modelName,
4036
- entry: sanitizedDocument
4037
- });
4038
- };
4039
4485
  const documentManager = ({ strapi: strapi2 }) => {
4040
4486
  return {
4041
4487
  async findOne(id, uid2, opts = {}) {
@@ -4054,6 +4500,9 @@ const documentManager = ({ strapi: strapi2 }) => {
4054
4500
  } else if (opts.locale && opts.locale !== "*") {
4055
4501
  where.locale = opts.locale;
4056
4502
  }
4503
+ if (typeof opts.isPublished === "boolean") {
4504
+ where.publishedAt = { $notNull: opts.isPublished };
4505
+ }
4057
4506
  return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
4058
4507
  },
4059
4508
  async findMany(opts, uid2) {
@@ -4087,10 +4536,7 @@ const documentManager = ({ strapi: strapi2 }) => {
4087
4536
  async clone(id, body, uid2) {
4088
4537
  const populate = await buildDeepPopulate(uid2);
4089
4538
  const params = {
4090
- data: {
4091
- ...omitIdField(body),
4092
- [PUBLISHED_AT_ATTRIBUTE]: null
4093
- },
4539
+ data: omitIdField(body),
4094
4540
  populate
4095
4541
  };
4096
4542
  return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
@@ -4116,70 +4562,36 @@ const documentManager = ({ strapi: strapi2 }) => {
4116
4562
  return {};
4117
4563
  },
4118
4564
  // FIXME: handle relations
4119
- async deleteMany(opts, uid2) {
4120
- const docs = await strapi2.documents(uid2).findMany(opts);
4121
- for (const doc of docs) {
4122
- await strapi2.documents(uid2).delete({ documentId: doc.documentId });
4123
- }
4124
- return { count: docs.length };
4565
+ async deleteMany(documentIds, uid2, opts = {}) {
4566
+ const deletedEntries = await strapi2.db.transaction(async () => {
4567
+ return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
4568
+ });
4569
+ return { count: deletedEntries.length };
4125
4570
  },
4126
4571
  async publish(id, uid2, opts = {}) {
4127
4572
  const populate = await buildDeepPopulate(uid2);
4128
4573
  const params = { ...opts, populate };
4129
- return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries.at(0));
4574
+ return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
4130
4575
  },
4131
- async publishMany(entities, uid2) {
4132
- if (!entities.length) {
4133
- return null;
4134
- }
4135
- await Promise.all(
4136
- entities.map((document) => {
4137
- return strapi2.entityValidator.validateEntityCreation(
4138
- strapi2.getModel(uid2),
4139
- document,
4140
- void 0,
4141
- // @ts-expect-error - FIXME: entity here is unnecessary
4142
- document
4143
- );
4144
- })
4145
- );
4146
- const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4147
- const filters = { id: { $in: entitiesToPublish } };
4148
- const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
4149
- const populate = await buildDeepPopulate(uid2);
4150
- const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4151
- where: filters,
4152
- data
4153
- });
4154
- const publishedEntities = await strapi2.db.query(uid2).findMany({
4155
- where: filters,
4156
- populate
4576
+ async publishMany(uid2, documentIds, locale) {
4577
+ return strapi2.db.transaction(async () => {
4578
+ const results = await Promise.all(
4579
+ documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
4580
+ );
4581
+ const publishedEntitiesCount = results.flat().filter(Boolean).length;
4582
+ return publishedEntitiesCount;
4157
4583
  });
4158
- await Promise.all(
4159
- publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
4160
- );
4161
- return publishedEntitiesCount;
4162
4584
  },
4163
- async unpublishMany(documents, uid2) {
4164
- if (!documents.length) {
4165
- return null;
4166
- }
4167
- const entitiesToUnpublish = documents.filter((doc) => doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4168
- const filters = { id: { $in: entitiesToUnpublish } };
4169
- const data = { [PUBLISHED_AT_ATTRIBUTE]: null };
4170
- const populate = await buildDeepPopulate(uid2);
4171
- const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4172
- where: filters,
4173
- data
4174
- });
4175
- const unpublishedEntities = await strapi2.db.query(uid2).findMany({
4176
- where: filters,
4177
- populate
4585
+ async unpublishMany(documentIds, uid2, opts = {}) {
4586
+ const unpublishedEntries = await strapi2.db.transaction(async () => {
4587
+ return Promise.all(
4588
+ documentIds.map(
4589
+ (id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
4590
+ )
4591
+ );
4178
4592
  });
4179
- await Promise.all(
4180
- unpublishedEntities.map((doc) => emitEvent(uid2, ENTRY_UNPUBLISH, doc))
4181
- );
4182
- return unpublishedEntitiesCount;
4593
+ const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
4594
+ return { count: unpublishedEntitiesCount };
4183
4595
  },
4184
4596
  async unpublish(id, uid2, opts = {}) {
4185
4597
  const populate = await buildDeepPopulate(uid2);
@@ -4204,16 +4616,20 @@ const documentManager = ({ strapi: strapi2 }) => {
4204
4616
  }
4205
4617
  return sumDraftCounts(document, uid2);
4206
4618
  },
4207
- async countManyEntriesDraftRelations(ids, uid2, locale) {
4619
+ async countManyEntriesDraftRelations(documentIds, uid2, locale) {
4208
4620
  const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
4209
4621
  if (!hasRelations) {
4210
4622
  return 0;
4211
4623
  }
4624
+ let localeFilter = {};
4625
+ if (locale) {
4626
+ localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
4627
+ }
4212
4628
  const entities = await strapi2.db.query(uid2).findMany({
4213
4629
  populate,
4214
4630
  where: {
4215
- id: { $in: ids },
4216
- ...locale ? { locale } : {}
4631
+ documentId: { $in: documentIds },
4632
+ ...localeFilter
4217
4633
  }
4218
4634
  });
4219
4635
  const totalNumberDraftRelations = entities.reduce(
@@ -4236,7 +4652,8 @@ const services = {
4236
4652
  permission,
4237
4653
  "populate-builder": populateBuilder$1,
4238
4654
  uid,
4239
- ...history.services ? history.services : {}
4655
+ ...history.services ? history.services : {},
4656
+ ...preview.services ? preview.services : {}
4240
4657
  };
4241
4658
  const index = () => {
4242
4659
  return {