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

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 (257) 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-DjWJdz6Y.js → ComponentConfigurationPage-BlzvDpbX.js} +5 -6
  7. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js.map → ComponentConfigurationPage-BlzvDpbX.js.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs → ComponentConfigurationPage-DaPOlQaD.mjs} +4 -4
  9. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs.map → ComponentConfigurationPage-DaPOlQaD.mjs.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-DacbqQ_f.mjs → EditConfigurationPage-BZPXItXo.mjs} +4 -4
  15. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs.map → EditConfigurationPage-BZPXItXo.mjs.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js → EditConfigurationPage-uy-v43AR.js} +5 -6
  17. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js.map → EditConfigurationPage-uy-v43AR.js.map} +1 -1
  18. package/dist/_chunks/{EditViewPage-DvNpQkam.js → EditViewPage-DT6A4ayX.js} +102 -54
  19. package/dist/_chunks/EditViewPage-DT6A4ayX.js.map +1 -0
  20. package/dist/_chunks/EditViewPage-oOLeTySr.mjs +254 -0
  21. package/dist/_chunks/EditViewPage-oOLeTySr.mjs.map +1 -0
  22. package/dist/_chunks/{Field-6gvGdPBV.mjs → Field-D7dv2aUX.mjs} +1192 -896
  23. package/dist/_chunks/Field-D7dv2aUX.mjs.map +1 -0
  24. package/dist/_chunks/{Field-DmVKIAOo.js → Field-kYFVIGiP.js} +1238 -943
  25. package/dist/_chunks/Field-kYFVIGiP.js.map +1 -0
  26. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  27. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  28. package/dist/_chunks/{Form-DW6K1IH-.mjs → Form-BxR6sc29.mjs} +67 -46
  29. package/dist/_chunks/Form-BxR6sc29.mjs.map +1 -0
  30. package/dist/_chunks/{Form-CPZC9vWa.js → Form-CCijSg3V.js} +68 -49
  31. package/dist/_chunks/Form-CCijSg3V.js.map +1 -0
  32. package/dist/_chunks/{History-DeAPlvtv.js → History-BMndx49M.js} +182 -147
  33. package/dist/_chunks/History-BMndx49M.js.map +1 -0
  34. package/dist/_chunks/{History-Dmr9fmUA.mjs → History-D8F7aYQU.mjs} +181 -144
  35. package/dist/_chunks/History-D8F7aYQU.mjs.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-DPCwW5Vr.js → ListConfigurationPage-DouY1EWM.js} +72 -63
  37. package/dist/_chunks/ListConfigurationPage-DouY1EWM.js.map +1 -0
  38. package/dist/_chunks/{ListConfigurationPage-DhwvYcNv.mjs → ListConfigurationPage-DqAdSPwC.mjs} +68 -57
  39. package/dist/_chunks/ListConfigurationPage-DqAdSPwC.mjs.map +1 -0
  40. package/dist/_chunks/{ListViewPage-5ySZ-VUs.js → ListViewPage-BPVmh9pq.js} +179 -164
  41. package/dist/_chunks/ListViewPage-BPVmh9pq.js.map +1 -0
  42. package/dist/_chunks/{ListViewPage-BtAwuYLE.mjs → ListViewPage-C73F0jPh.mjs} +175 -159
  43. package/dist/_chunks/ListViewPage-C73F0jPh.mjs.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-DSPxnxxp.mjs → NoContentTypePage-B5w7iJOF.mjs} +3 -3
  45. package/dist/_chunks/NoContentTypePage-B5w7iJOF.mjs.map +1 -0
  46. package/dist/_chunks/{NoContentTypePage-DOC_yWOf.js → NoContentTypePage-BwcL--4H.js} +3 -3
  47. package/dist/_chunks/NoContentTypePage-BwcL--4H.js.map +1 -0
  48. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js → NoPermissionsPage-BMFKVcwJ.js} +2 -2
  49. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js.map → NoPermissionsPage-BMFKVcwJ.js.map} +1 -1
  50. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs → NoPermissionsPage-UnEgMGK4.mjs} +2 -2
  51. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs.map → NoPermissionsPage-UnEgMGK4.mjs.map} +1 -1
  52. package/dist/_chunks/Preview-B7PR3Ok_.js +312 -0
  53. package/dist/_chunks/Preview-B7PR3Ok_.js.map +1 -0
  54. package/dist/_chunks/Preview-DECOhK0D.mjs +294 -0
  55. package/dist/_chunks/Preview-DECOhK0D.mjs.map +1 -0
  56. package/dist/_chunks/{Relations-J8cscLlR.mjs → Relations-DinMQJ4B.mjs} +138 -94
  57. package/dist/_chunks/Relations-DinMQJ4B.mjs.map +1 -0
  58. package/dist/_chunks/{Relations-CgWtgnPe.js → Relations-lndx3aQk.js} +142 -100
  59. package/dist/_chunks/Relations-lndx3aQk.js.map +1 -0
  60. package/dist/_chunks/{en-C-V1_90f.js → en-BK8Xyl5I.js} +38 -18
  61. package/dist/_chunks/{en-C-V1_90f.js.map → en-BK8Xyl5I.js.map} +1 -1
  62. package/dist/_chunks/{en-MBPul9Su.mjs → en-Dtk_ot79.mjs} +38 -18
  63. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-Dtk_ot79.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-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
  69. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
  70. package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
  71. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
  72. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  73. package/dist/_chunks/{index-CwRRo1V9.mjs → index-C2SagWVW.mjs} +2070 -988
  74. package/dist/_chunks/index-C2SagWVW.mjs.map +1 -0
  75. package/dist/_chunks/{index-C6AH2hEl.js → index-Cnw4gqee.js} +2047 -966
  76. package/dist/_chunks/index-Cnw4gqee.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-jIDzX0Fp.mjs → layout-DY_D9MGA.mjs} +46 -28
  82. package/dist/_chunks/layout-DY_D9MGA.mjs.map +1 -0
  83. package/dist/_chunks/{layout-B_SXLhqf.js → layout-ivwIVPnV.js} +47 -32
  84. package/dist/_chunks/layout-ivwIVPnV.js.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-iBMa_OFG.js → relations-B7C7O_Pv.js} +6 -7
  90. package/dist/_chunks/relations-B7C7O_Pv.js.map +1 -0
  91. package/dist/_chunks/{relations-CuvIgCqI.mjs → relations-Boc5Y9kX.mjs} +6 -7
  92. package/dist/_chunks/relations-Boc5Y9kX.mjs.map +1 -0
  93. package/dist/_chunks/useDebounce-CtcjDB3L.js +28 -0
  94. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  95. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  96. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  97. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  98. package/dist/_chunks/useDragAndDrop-BMtgCYzL.js.map +1 -0
  99. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  100. package/dist/_chunks/useDragAndDrop-DJ6jqvZN.mjs.map +1 -0
  101. package/dist/admin/index.js +3 -1
  102. package/dist/admin/index.js.map +1 -1
  103. package/dist/admin/index.mjs +9 -7
  104. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  105. package/dist/admin/src/content-manager.d.ts +6 -5
  106. package/dist/admin/src/exports.d.ts +2 -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 +37 -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 +2 -2
  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/Field.d.ts +1 -1
  126. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
  127. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  128. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  129. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  130. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  131. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +16 -53
  132. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  133. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  134. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  135. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  136. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  137. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  138. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  139. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  140. package/dist/admin/src/preview/index.d.ts +4 -0
  141. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  142. package/dist/admin/src/preview/routes.d.ts +3 -0
  143. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  144. package/dist/admin/src/router.d.ts +1 -1
  145. package/dist/admin/src/services/api.d.ts +2 -3
  146. package/dist/admin/src/services/components.d.ts +2 -2
  147. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  148. package/dist/admin/src/services/documents.d.ts +31 -20
  149. package/dist/admin/src/services/init.d.ts +2 -2
  150. package/dist/admin/src/services/relations.d.ts +3 -3
  151. package/dist/admin/src/services/uid.d.ts +3 -3
  152. package/dist/admin/src/utils/api.d.ts +4 -18
  153. package/dist/admin/src/utils/validation.d.ts +5 -7
  154. package/dist/server/index.js +886 -480
  155. package/dist/server/index.js.map +1 -1
  156. package/dist/server/index.mjs +892 -485
  157. package/dist/server/index.mjs.map +1 -1
  158. package/dist/server/src/bootstrap.d.ts.map +1 -1
  159. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  160. package/dist/server/src/controllers/index.d.ts.map +1 -1
  161. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  162. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  163. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  164. package/dist/server/src/controllers/utils/metadata.d.ts +23 -0
  165. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  166. package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
  167. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  168. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  169. package/dist/server/src/history/services/history.d.ts.map +1 -1
  170. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  171. package/dist/server/src/history/services/utils.d.ts +4 -4
  172. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  173. package/dist/server/src/index.d.ts +22 -42
  174. package/dist/server/src/index.d.ts.map +1 -1
  175. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  176. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  177. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  178. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  179. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  180. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  181. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  182. package/dist/server/src/preview/index.d.ts +4 -0
  183. package/dist/server/src/preview/index.d.ts.map +1 -0
  184. package/dist/server/src/preview/routes/index.d.ts +8 -0
  185. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  186. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  187. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  188. package/dist/server/src/preview/services/index.d.ts +16 -0
  189. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  190. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  191. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  192. package/dist/server/src/preview/services/preview.d.ts +12 -0
  193. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  194. package/dist/server/src/preview/utils.d.ts +19 -0
  195. package/dist/server/src/preview/utils.d.ts.map +1 -0
  196. package/dist/server/src/register.d.ts.map +1 -1
  197. package/dist/server/src/routes/index.d.ts.map +1 -1
  198. package/dist/server/src/services/document-manager.d.ts +13 -12
  199. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  200. package/dist/server/src/services/document-metadata.d.ts +16 -35
  201. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  202. package/dist/server/src/services/index.d.ts +22 -42
  203. package/dist/server/src/services/index.d.ts.map +1 -1
  204. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  205. package/dist/server/src/services/utils/populate.d.ts +8 -1
  206. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  207. package/dist/server/src/utils/index.d.ts +2 -0
  208. package/dist/server/src/utils/index.d.ts.map +1 -1
  209. package/dist/shared/contracts/collection-types.d.ts +17 -7
  210. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  211. package/dist/shared/contracts/index.d.ts +1 -0
  212. package/dist/shared/contracts/index.d.ts.map +1 -1
  213. package/dist/shared/contracts/preview.d.ts +27 -0
  214. package/dist/shared/contracts/preview.d.ts.map +1 -0
  215. package/dist/shared/contracts/relations.d.ts +2 -2
  216. package/dist/shared/contracts/relations.d.ts.map +1 -1
  217. package/dist/shared/index.js +4 -0
  218. package/dist/shared/index.js.map +1 -1
  219. package/dist/shared/index.mjs +4 -0
  220. package/dist/shared/index.mjs.map +1 -1
  221. package/package.json +22 -21
  222. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  223. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  224. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  225. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  226. package/dist/_chunks/EditViewPage-DDS6H9HO.mjs +0 -203
  227. package/dist/_chunks/EditViewPage-DDS6H9HO.mjs.map +0 -1
  228. package/dist/_chunks/EditViewPage-DvNpQkam.js.map +0 -1
  229. package/dist/_chunks/Field-6gvGdPBV.mjs.map +0 -1
  230. package/dist/_chunks/Field-DmVKIAOo.js.map +0 -1
  231. package/dist/_chunks/Form-CPZC9vWa.js.map +0 -1
  232. package/dist/_chunks/Form-DW6K1IH-.mjs.map +0 -1
  233. package/dist/_chunks/History-DeAPlvtv.js.map +0 -1
  234. package/dist/_chunks/History-Dmr9fmUA.mjs.map +0 -1
  235. package/dist/_chunks/ListConfigurationPage-DPCwW5Vr.js.map +0 -1
  236. package/dist/_chunks/ListConfigurationPage-DhwvYcNv.mjs.map +0 -1
  237. package/dist/_chunks/ListViewPage-5ySZ-VUs.js.map +0 -1
  238. package/dist/_chunks/ListViewPage-BtAwuYLE.mjs.map +0 -1
  239. package/dist/_chunks/NoContentTypePage-DOC_yWOf.js.map +0 -1
  240. package/dist/_chunks/NoContentTypePage-DSPxnxxp.mjs.map +0 -1
  241. package/dist/_chunks/Relations-CgWtgnPe.js.map +0 -1
  242. package/dist/_chunks/Relations-J8cscLlR.mjs.map +0 -1
  243. package/dist/_chunks/index-C6AH2hEl.js.map +0 -1
  244. package/dist/_chunks/index-CwRRo1V9.mjs.map +0 -1
  245. package/dist/_chunks/layout-B_SXLhqf.js.map +0 -1
  246. package/dist/_chunks/layout-jIDzX0Fp.mjs.map +0 -1
  247. package/dist/_chunks/relations-CuvIgCqI.mjs.map +0 -1
  248. package/dist/_chunks/relations-iBMa_OFG.js.map +0 -1
  249. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  250. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  251. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  252. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  253. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +0 -1
  254. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +0 -1
  255. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  256. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
  257. 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, 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, 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 } = 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 })
@@ -73,20 +73,20 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
73
73
  );
74
74
  return {
75
75
  data: sanitizedResults,
76
- meta: { pagination }
76
+ meta: { pagination: pagination2 }
77
77
  };
78
78
  },
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({
@@ -173,10 +172,11 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
173
172
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
174
173
  };
175
174
  const localesService = strapi2.plugin("i18n")?.service("locales");
175
+ const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
176
176
  const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
177
+ const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
177
178
  const getLocaleDictionary = async () => {
178
- if (!localesService)
179
- return {};
179
+ if (!localesService) return {};
180
180
  const locales = await localesService.find() || [];
181
181
  return locales.reduce(
182
182
  (acc, locale) => {
@@ -200,31 +200,53 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
200
200
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
201
201
  return documentMetadataService.getStatus(document, meta.availableStatus);
202
202
  };
203
- const getDeepPopulate2 = (uid2) => {
203
+ const getComponentFields = (componentUID) => {
204
+ return Object.entries(strapi2.getModel(componentUID).attributes).reduce(
205
+ (fieldsAcc, [key, attribute]) => {
206
+ if (!["relation", "media", "component", "dynamiczone"].includes(attribute.type)) {
207
+ fieldsAcc.push(key);
208
+ }
209
+ return fieldsAcc;
210
+ },
211
+ []
212
+ );
213
+ };
214
+ const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
204
215
  const model = strapi2.getModel(uid2);
205
216
  const attributes = Object.entries(model.attributes);
217
+ const fieldSelector = useDatabaseSyntax ? "select" : "fields";
206
218
  return attributes.reduce((acc, [attributeName, attribute]) => {
207
219
  switch (attribute.type) {
208
220
  case "relation": {
221
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
222
+ if (isMorphRelation) {
223
+ break;
224
+ }
209
225
  const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
210
226
  if (isVisible2) {
211
- acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
227
+ acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
212
228
  }
213
229
  break;
214
230
  }
215
231
  case "media": {
216
- acc[attributeName] = { fields: ["id"] };
232
+ acc[attributeName] = { [fieldSelector]: ["id"] };
217
233
  break;
218
234
  }
219
235
  case "component": {
220
236
  const populate = getDeepPopulate2(attribute.component);
221
- acc[attributeName] = { populate };
237
+ acc[attributeName] = {
238
+ populate,
239
+ [fieldSelector]: getComponentFields(attribute.component)
240
+ };
222
241
  break;
223
242
  }
224
243
  case "dynamiczone": {
225
244
  const populatedComponents = (attribute.components || []).reduce(
226
245
  (acc2, componentUID) => {
227
- acc2[componentUID] = { populate: getDeepPopulate2(componentUID) };
246
+ acc2[componentUID] = {
247
+ populate: getDeepPopulate2(componentUID),
248
+ [fieldSelector]: getComponentFields(componentUID)
249
+ };
228
250
  return acc2;
229
251
  },
230
252
  {}
@@ -286,6 +308,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
286
308
  getRelationRestoreValue,
287
309
  getMediaRestoreValue,
288
310
  getDefaultLocale,
311
+ isLocalizedContentType,
289
312
  getLocaleDictionary,
290
313
  getRetentionDays,
291
314
  getVersionStatus,
@@ -308,8 +331,14 @@ const createHistoryService = ({ strapi: strapi2 }) => {
308
331
  });
309
332
  },
310
333
  async findVersionsPage(params) {
311
- const locale = params.query.locale || await serviceUtils.getDefaultLocale();
312
- const [{ results, pagination }, localeDictionary] = await Promise.all([
334
+ const model = strapi2.getModel(params.query.contentType);
335
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
336
+ const defaultLocale = await serviceUtils.getDefaultLocale();
337
+ let locale = null;
338
+ if (isLocalizedContentType) {
339
+ locale = params.query.locale || defaultLocale;
340
+ }
341
+ const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
313
342
  query.findPage({
314
343
  ...params.query,
315
344
  where: {
@@ -330,7 +359,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
330
359
  const attributeValue = entry.data[attributeKey];
331
360
  const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
332
361
  if (attributeSchema.type === "media") {
333
- const permissionChecker2 = getService$1("permission-checker").create({
362
+ const permissionChecker2 = getService$2("permission-checker").create({
334
363
  userAbility: params.state.userAbility,
335
364
  model: "plugin::upload.file"
336
365
  });
@@ -353,7 +382,12 @@ const createHistoryService = ({ strapi: strapi2 }) => {
353
382
  if (userToPopulate == null) {
354
383
  return null;
355
384
  }
356
- return strapi2.query("admin::user").findOne({ where: { id: userToPopulate.id } });
385
+ return strapi2.query("admin::user").findOne({
386
+ where: {
387
+ ...userToPopulate.id ? { id: userToPopulate.id } : {},
388
+ ...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
389
+ }
390
+ });
357
391
  })
358
392
  );
359
393
  return {
@@ -366,7 +400,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
366
400
  [attributeKey]: adminUsers
367
401
  };
368
402
  }
369
- const permissionChecker2 = getService$1("permission-checker").create({
403
+ const permissionChecker2 = getService$2("permission-checker").create({
370
404
  userAbility: params.state.userAbility,
371
405
  model: attributeSchema.target
372
406
  });
@@ -408,7 +442,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
408
442
  );
409
443
  return {
410
444
  results: formattedResults,
411
- pagination
445
+ pagination: pagination2
412
446
  };
413
447
  },
414
448
  async restoreVersion(versionId) {
@@ -464,13 +498,47 @@ const createHistoryService = ({ strapi: strapi2 }) => {
464
498
  }
465
499
  };
466
500
  };
501
+ const shouldCreateHistoryVersion = (context) => {
502
+ if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
503
+ return false;
504
+ }
505
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
506
+ return false;
507
+ }
508
+ if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
509
+ return false;
510
+ }
511
+ if (!context.contentType.uid.startsWith("api::")) {
512
+ return false;
513
+ }
514
+ return true;
515
+ };
516
+ const getSchemas = (uid2) => {
517
+ const attributesSchema = strapi.getModel(uid2).attributes;
518
+ const componentsSchemas = Object.keys(attributesSchema).reduce(
519
+ (currentComponentSchemas, key) => {
520
+ const fieldSchema = attributesSchema[key];
521
+ if (fieldSchema.type === "component") {
522
+ const componentSchema = strapi.getModel(fieldSchema.component).attributes;
523
+ return {
524
+ ...currentComponentSchemas,
525
+ [fieldSchema.component]: componentSchema
526
+ };
527
+ }
528
+ return currentComponentSchemas;
529
+ },
530
+ {}
531
+ );
532
+ return {
533
+ schema: omit(FIELDS_TO_IGNORE, attributesSchema),
534
+ componentsSchemas
535
+ };
536
+ };
467
537
  const createLifecyclesService = ({ strapi: strapi2 }) => {
468
538
  const state = {
469
539
  deleteExpiredJob: null,
470
540
  isInitialized: false
471
541
  };
472
- const query = strapi2.db.query(HISTORY_VERSION_UID);
473
- const historyService = getService(strapi2, "history");
474
542
  const serviceUtils = createServiceUtils({ strapi: strapi2 });
475
543
  return {
476
544
  async bootstrap() {
@@ -478,65 +546,62 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
478
546
  return;
479
547
  }
480
548
  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
549
  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 };
550
+ if (!shouldCreateHistoryVersion(context)) {
551
+ return result;
552
+ }
553
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
493
554
  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)
555
+ const locales = castArray(context.params?.locale || defaultLocale);
556
+ if (!locales.length) {
557
+ return result;
558
+ }
559
+ const uid2 = context.contentType.uid;
560
+ const schemas = getSchemas(uid2);
561
+ const model = strapi2.getModel(uid2);
562
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
563
+ const localeEntries = await strapi2.db.query(uid2).findMany({
564
+ where: {
565
+ documentId,
566
+ ...isLocalizedContentType ? { locale: { $in: locales } } : {},
567
+ ...contentTypes$1.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
568
+ },
569
+ populate: serviceUtils.getDeepPopulate(
570
+ uid2,
571
+ true
572
+ /* use database syntax */
573
+ )
499
574
  });
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
575
  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
- });
576
+ onCommit(async () => {
577
+ for (const entry of localeEntries) {
578
+ const status = await serviceUtils.getVersionStatus(uid2, entry);
579
+ await getService$1(strapi2, "history").createVersion({
580
+ contentType: uid2,
581
+ data: omit(FIELDS_TO_IGNORE, entry),
582
+ relatedDocumentId: documentId,
583
+ locale: entry.locale,
584
+ status,
585
+ ...schemas
586
+ });
587
+ }
526
588
  });
527
589
  });
528
590
  return result;
529
591
  });
530
- const retentionDays = serviceUtils.getRetentionDays();
531
- state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
532
- const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
592
+ state.deleteExpiredJob = scheduleJob("historyDaily", "0 0 * * *", () => {
593
+ const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
533
594
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
534
- query.deleteMany({
595
+ strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
535
596
  where: {
536
597
  created_at: {
537
- $lt: expirationDate.toISOString()
598
+ $lt: expirationDate
538
599
  }
539
600
  }
601
+ }).catch((error) => {
602
+ if (error instanceof Error) {
603
+ strapi2.log.error("Error deleting expired history versions", error.message);
604
+ }
540
605
  });
541
606
  });
542
607
  state.isInitialized = true;
@@ -548,17 +613,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
548
613
  }
549
614
  };
550
615
  };
551
- const services$1 = {
616
+ const services$2 = {
552
617
  history: createHistoryService,
553
618
  lifecycles: createLifecyclesService
554
619
  };
555
- const info = { pluginName: "content-manager", type: "admin" };
620
+ const info$1 = { pluginName: "content-manager", type: "admin" };
556
621
  const historyVersionRouter = {
557
622
  type: "admin",
558
623
  routes: [
559
624
  {
560
625
  method: "GET",
561
- info,
626
+ info: info$1,
562
627
  path: "/history-versions",
563
628
  handler: "history-version.findMany",
564
629
  config: {
@@ -567,7 +632,7 @@ const historyVersionRouter = {
567
632
  },
568
633
  {
569
634
  method: "PUT",
570
- info,
635
+ info: info$1,
571
636
  path: "/history-versions/:versionId/restore",
572
637
  handler: "history-version.restoreVersion",
573
638
  config: {
@@ -576,7 +641,7 @@ const historyVersionRouter = {
576
641
  }
577
642
  ]
578
643
  };
579
- const routes$1 = {
644
+ const routes$2 = {
580
645
  "history-version": historyVersionRouter
581
646
  };
582
647
  const historyVersion = {
@@ -623,21 +688,21 @@ const historyVersion = {
623
688
  }
624
689
  }
625
690
  };
626
- const getFeature = () => {
691
+ const getFeature$1 = () => {
627
692
  if (strapi.ee.features.isEnabled("cms-content-history")) {
628
693
  return {
629
694
  register({ strapi: strapi2 }) {
630
695
  strapi2.get("models").add(historyVersion);
631
696
  },
632
697
  bootstrap({ strapi: strapi2 }) {
633
- getService(strapi2, "lifecycles").bootstrap();
698
+ getService$1(strapi2, "lifecycles").bootstrap();
634
699
  },
635
700
  destroy({ strapi: strapi2 }) {
636
- getService(strapi2, "lifecycles").destroy();
701
+ getService$1(strapi2, "lifecycles").destroy();
637
702
  },
638
- controllers: controllers$1,
639
- services: services$1,
640
- routes: routes$1
703
+ controllers: controllers$2,
704
+ services: services$2,
705
+ routes: routes$2
641
706
  };
642
707
  }
643
708
  return {
@@ -646,9 +711,201 @@ const getFeature = () => {
646
711
  }
647
712
  };
648
713
  };
649
- const history = getFeature();
714
+ const history = getFeature$1();
715
+ const info = { pluginName: "content-manager", type: "admin" };
716
+ const previewRouter = {
717
+ type: "admin",
718
+ routes: [
719
+ {
720
+ method: "GET",
721
+ info,
722
+ path: "/preview/url/:contentType",
723
+ handler: "preview.getPreviewUrl",
724
+ config: {
725
+ policies: ["admin::isAuthenticatedAdmin"]
726
+ }
727
+ }
728
+ ]
729
+ };
730
+ const routes$1 = {
731
+ preview: previewRouter
732
+ };
733
+ function getService(strapi2, name) {
734
+ return strapi2.service(`plugin::content-manager.${name}`);
735
+ }
736
+ const getPreviewUrlSchema = yup.object().shape({
737
+ // Will be undefined for single types
738
+ documentId: yup.string(),
739
+ locale: yup.string().nullable(),
740
+ status: yup.string()
741
+ }).required();
742
+ const validatePreviewUrl = async (strapi2, uid2, params) => {
743
+ await validateYupSchema(getPreviewUrlSchema)(params);
744
+ const newParams = pick(["documentId", "locale", "status"], params);
745
+ const model = strapi2.getModel(uid2);
746
+ if (!model || model.modelType !== "contentType") {
747
+ throw new errors.ValidationError("Invalid content type");
748
+ }
749
+ const isSingleType = model?.kind === "singleType";
750
+ if (!isSingleType && !params.documentId) {
751
+ throw new errors.ValidationError("documentId is required for Collection Types");
752
+ }
753
+ if (isSingleType) {
754
+ const doc = await strapi2.documents(uid2).findFirst();
755
+ if (!doc) {
756
+ throw new errors.NotFoundError("Document not found");
757
+ }
758
+ newParams.documentId = doc?.documentId;
759
+ }
760
+ if (!newParams.status) {
761
+ const isDPEnabled = model?.options?.draftAndPublish;
762
+ newParams.status = isDPEnabled ? "draft" : "published";
763
+ }
764
+ return newParams;
765
+ };
766
+ const createPreviewController = () => {
767
+ return {
768
+ /**
769
+ * Transforms an entry into a preview URL, so that it can be previewed
770
+ * in the Content Manager.
771
+ */
772
+ async getPreviewUrl(ctx) {
773
+ const uid2 = ctx.params.contentType;
774
+ const query = ctx.request.query;
775
+ const params = await validatePreviewUrl(strapi, uid2, query);
776
+ const previewService = getService(strapi, "preview");
777
+ const url = await previewService.getPreviewUrl(uid2, params);
778
+ if (!url) {
779
+ ctx.status = 204;
780
+ }
781
+ return {
782
+ data: { url }
783
+ };
784
+ }
785
+ };
786
+ };
787
+ const controllers$1 = {
788
+ preview: createPreviewController
789
+ /**
790
+ * Casting is needed because the types aren't aware that Strapi supports
791
+ * passing a controller factory as the value, instead of a controller object directly
792
+ */
793
+ };
794
+ const createPreviewService = ({ strapi: strapi2 }) => {
795
+ const config = getService(strapi2, "preview-config");
796
+ return {
797
+ async getPreviewUrl(uid2, params) {
798
+ const handler = config.getPreviewHandler();
799
+ try {
800
+ return handler(uid2, params);
801
+ } catch (error) {
802
+ strapi2.log.error(`Failed to get preview URL: ${error}`);
803
+ throw new errors.ApplicationError("Failed to get preview URL");
804
+ }
805
+ return;
806
+ }
807
+ };
808
+ };
809
+ const extendMiddlewareConfiguration = (middleware = { name: "", config: {} }) => {
810
+ const middlewares = strapi.config.get("middlewares");
811
+ const configuredMiddlewares = middlewares.map((currentMiddleware) => {
812
+ if (currentMiddleware === middleware.name) {
813
+ return middleware;
814
+ }
815
+ if (currentMiddleware.name === middleware.name) {
816
+ return mergeWith(
817
+ (objValue, srcValue) => {
818
+ if (Array.isArray(objValue)) {
819
+ return objValue.concat(srcValue);
820
+ }
821
+ return void 0;
822
+ },
823
+ currentMiddleware,
824
+ middleware
825
+ );
826
+ }
827
+ return currentMiddleware;
828
+ });
829
+ strapi.config.set("middlewares", configuredMiddlewares);
830
+ };
831
+ const createPreviewConfigService = ({ strapi: strapi2 }) => {
832
+ return {
833
+ register() {
834
+ if (!this.isEnabled()) {
835
+ return;
836
+ }
837
+ const config = strapi2.config.get("admin.preview");
838
+ if (config.config?.allowedOrigins) {
839
+ extendMiddlewareConfiguration({
840
+ name: "strapi::security",
841
+ config: {
842
+ contentSecurityPolicy: {
843
+ directives: {
844
+ "frame-src": config.config.allowedOrigins
845
+ }
846
+ }
847
+ }
848
+ });
849
+ }
850
+ },
851
+ isEnabled() {
852
+ const config = strapi2.config.get("admin.preview");
853
+ if (!config) {
854
+ return false;
855
+ }
856
+ return config?.enabled ?? true;
857
+ },
858
+ /**
859
+ * Validate if the configuration is valid
860
+ */
861
+ validate() {
862
+ if (!this.isEnabled()) {
863
+ return;
864
+ }
865
+ const handler = this.getPreviewHandler();
866
+ if (typeof handler !== "function") {
867
+ throw new errors.ValidationError(
868
+ "Preview configuration is invalid. Handler must be a function"
869
+ );
870
+ }
871
+ },
872
+ /**
873
+ * Utility to get the preview handler from the configuration
874
+ */
875
+ getPreviewHandler() {
876
+ const config = strapi2.config.get("admin.preview");
877
+ const emptyHandler = () => {
878
+ return void 0;
879
+ };
880
+ if (!this.isEnabled()) {
881
+ return emptyHandler;
882
+ }
883
+ return config?.config?.handler || emptyHandler;
884
+ }
885
+ };
886
+ };
887
+ const services$1 = {
888
+ preview: createPreviewService,
889
+ "preview-config": createPreviewConfigService
890
+ };
891
+ const getFeature = () => {
892
+ return {
893
+ register() {
894
+ const config = getService(strapi, "preview-config");
895
+ config.validate();
896
+ config.register();
897
+ },
898
+ bootstrap() {
899
+ },
900
+ routes: routes$1,
901
+ controllers: controllers$1,
902
+ services: services$1
903
+ };
904
+ };
905
+ const preview = getFeature();
650
906
  const register = async ({ strapi: strapi2 }) => {
651
907
  await history.register?.({ strapi: strapi2 });
908
+ await preview.register?.({ strapi: strapi2 });
652
909
  };
653
910
  const ALLOWED_WEBHOOK_EVENTS = {
654
911
  ENTRY_PUBLISH: "entry.publish",
@@ -658,11 +915,12 @@ const bootstrap = async () => {
658
915
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
659
916
  strapi.get("webhookStore").addAllowedEvent(key, value);
660
917
  });
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();
918
+ getService$2("field-sizes").setCustomFieldInputSizes();
919
+ await getService$2("components").syncConfigurations();
920
+ await getService$2("content-types").syncConfigurations();
921
+ await getService$2("permission").registerPermissions();
665
922
  await history.bootstrap?.({ strapi });
923
+ await preview.bootstrap?.({ strapi });
666
924
  };
667
925
  const destroy = async ({ strapi: strapi2 }) => {
668
926
  await history.destroy?.({ strapi: strapi2 });
@@ -1152,7 +1410,8 @@ const admin = {
1152
1410
  };
1153
1411
  const routes = {
1154
1412
  admin,
1155
- ...history.routes ? history.routes : {}
1413
+ ...history.routes ? history.routes : {},
1414
+ ...preview.routes ? preview.routes : {}
1156
1415
  };
1157
1416
  const hasPermissionsSchema = yup$1.object({
1158
1417
  actions: yup$1.array().of(yup$1.string()),
@@ -1163,6 +1422,11 @@ const { createPolicy } = policy;
1163
1422
  const hasPermissions = createPolicy({
1164
1423
  name: "plugin::content-manager.hasPermissions",
1165
1424
  validator: validateHasPermissionsInput,
1425
+ /**
1426
+ * NOTE: Action aliases are currently not checked at this level (policy).
1427
+ * This is currently the intended behavior to avoid changing the behavior of API related permissions.
1428
+ * If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
1429
+ */
1166
1430
  handler(ctx, config = {}) {
1167
1431
  const { actions = [], hasAtLeastOne = false } = config;
1168
1432
  const { userAbility } = ctx.state;
@@ -1210,8 +1474,7 @@ const isSortable = (schema, name) => {
1210
1474
  if (!_.has(schema.attributes, name)) {
1211
1475
  return false;
1212
1476
  }
1213
- if (schema.modelType === "component" && name === "id")
1214
- return false;
1477
+ if (schema.modelType === "component" && name === "id") return false;
1215
1478
  const attribute = schema.attributes[name];
1216
1479
  if (NON_SORTABLES.includes(attribute.type)) {
1217
1480
  return false;
@@ -1356,8 +1619,7 @@ const createDefaultSettings = async (schema) => {
1356
1619
  };
1357
1620
  };
1358
1621
  const syncSettings = async (configuration, schema) => {
1359
- if (isEmpty(configuration.settings))
1360
- return createDefaultSettings(schema);
1622
+ if (isEmpty(configuration.settings)) return createDefaultSettings(schema);
1361
1623
  const defaultField = getDefaultMainField(schema);
1362
1624
  const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
1363
1625
  return {
@@ -1404,7 +1666,7 @@ const createMetadasSchema = (schema) => {
1404
1666
  if (!value) {
1405
1667
  return yup$1.string();
1406
1668
  }
1407
- const targetSchema = getService$1("content-types").findContentType(
1669
+ const targetSchema = getService$2("content-types").findContentType(
1408
1670
  schema.attributes[key].targetModel
1409
1671
  );
1410
1672
  if (!targetSchema) {
@@ -1452,7 +1714,7 @@ const { PaginationError, ValidationError } = errors;
1452
1714
  const TYPES = ["singleType", "collectionType"];
1453
1715
  const kindSchema = yup$1.string().oneOf(TYPES).nullable();
1454
1716
  const bulkActionInputSchema = yup$1.object({
1455
- ids: yup$1.array().of(yup$1.strapiID()).min(1).required()
1717
+ documentIds: yup$1.array().of(yup$1.strapiID()).min(1).required()
1456
1718
  }).required();
1457
1719
  const generateUIDInputSchema = yup$1.object({
1458
1720
  contentTypeUID: yup$1.string().required(),
@@ -1533,8 +1795,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1533
1795
  }
1534
1796
  switch (attribute.type) {
1535
1797
  case "relation": {
1536
- if (canCreate(attributePath))
1537
- return body2;
1798
+ if (canCreate(attributePath)) return body2;
1538
1799
  return set(attributePath, { set: [] }, body2);
1539
1800
  }
1540
1801
  case "component": {
@@ -1544,29 +1805,62 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1544
1805
  ]);
1545
1806
  }
1546
1807
  default: {
1547
- if (canCreate(attributePath))
1548
- return body2;
1808
+ if (canCreate(attributePath)) return body2;
1549
1809
  return set(attributePath, null, body2);
1550
1810
  }
1551
1811
  }
1552
1812
  }, body);
1553
1813
  };
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}`);
1814
+ const singleLocaleSchema = yup$1.string().nullable();
1815
+ const multipleLocaleSchema = yup$1.lazy(
1816
+ (value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1817
+ );
1818
+ const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
1819
+ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
1820
+ const { allowMultipleLocales } = opts;
1821
+ const { locale, status: providedStatus, ...rest } = request || {};
1822
+ const defaultStatus = contentTypes$1.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
1823
+ const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
1824
+ const schema = yup$1.object().shape({
1825
+ locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1826
+ status: statusSchema
1827
+ });
1828
+ try {
1829
+ await validateYupSchema(schema, { strict: true, abortEarly: false })(request);
1830
+ return { locale, status, ...rest };
1831
+ } catch (error) {
1832
+ throw new errors.ValidationError(`Validation error: ${error.message}`);
1561
1833
  }
1562
- return { locale, status, ...rest };
1834
+ };
1835
+ const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1836
+ const documentMetadata2 = getService$2("document-metadata");
1837
+ const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1838
+ let {
1839
+ meta: { availableLocales, availableStatus }
1840
+ } = serviceOutput;
1841
+ const metadataSanitizer = permissionChecker2.sanitizeOutput;
1842
+ availableLocales = await async.map(
1843
+ availableLocales,
1844
+ async (localeDocument) => metadataSanitizer(localeDocument)
1845
+ );
1846
+ availableStatus = await async.map(
1847
+ availableStatus,
1848
+ async (statusDocument) => metadataSanitizer(statusDocument)
1849
+ );
1850
+ return {
1851
+ ...serviceOutput,
1852
+ meta: {
1853
+ availableLocales,
1854
+ availableStatus
1855
+ }
1856
+ };
1563
1857
  };
1564
1858
  const createDocument = async (ctx, opts) => {
1565
1859
  const { userAbility, user } = ctx.state;
1566
1860
  const { model } = ctx.params;
1567
1861
  const { body } = ctx.request;
1568
- const documentManager2 = getService$1("document-manager");
1569
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1862
+ const documentManager2 = getService$2("document-manager");
1863
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1570
1864
  if (permissionChecker2.cannot.create()) {
1571
1865
  throw new errors.ForbiddenError();
1572
1866
  }
@@ -1574,7 +1868,7 @@ const createDocument = async (ctx, opts) => {
1574
1868
  const setCreator = setCreatorFields({ user });
1575
1869
  const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
1576
1870
  const sanitizedBody = await sanitizeFn(body);
1577
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(body);
1871
+ const { locale, status } = await getDocumentLocaleAndStatus(body, model);
1578
1872
  return documentManager2.create(model, {
1579
1873
  data: sanitizedBody,
1580
1874
  locale,
@@ -1586,14 +1880,14 @@ const updateDocument = async (ctx, opts) => {
1586
1880
  const { userAbility, user } = ctx.state;
1587
1881
  const { id, model } = ctx.params;
1588
1882
  const { body } = ctx.request;
1589
- const documentManager2 = getService$1("document-manager");
1590
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1883
+ const documentManager2 = getService$2("document-manager");
1884
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1591
1885
  if (permissionChecker2.cannot.update()) {
1592
1886
  throw new errors.ForbiddenError();
1593
1887
  }
1594
1888
  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);
1889
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1890
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1597
1891
  const [documentVersion, documentExists] = await Promise.all([
1598
1892
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1599
1893
  documentManager2.exists(model, id)
@@ -1609,7 +1903,7 @@ const updateDocument = async (ctx, opts) => {
1609
1903
  throw new errors.ForbiddenError();
1610
1904
  }
1611
1905
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1612
- const setCreator = setCreatorFields({ user, isEdition: true });
1906
+ const setCreator = documentVersion ? setCreatorFields({ user, isEdition: true }) : setCreatorFields({ user });
1613
1907
  const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
1614
1908
  const sanitizedBody = await sanitizeFn(body);
1615
1909
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1623,16 +1917,16 @@ const collectionTypes = {
1623
1917
  const { userAbility } = ctx.state;
1624
1918
  const { model } = ctx.params;
1625
1919
  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 });
1920
+ const documentMetadata2 = getService$2("document-metadata");
1921
+ const documentManager2 = getService$2("document-manager");
1922
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1629
1923
  if (permissionChecker2.cannot.read()) {
1630
1924
  return ctx.forbidden();
1631
1925
  }
1632
1926
  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);
1635
- const { results: documents, pagination } = await documentManager2.findPage(
1927
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1928
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1929
+ const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
1636
1930
  { ...permissionQuery, populate, locale, status },
1637
1931
  model
1638
1932
  );
@@ -1653,21 +1947,20 @@ const collectionTypes = {
1653
1947
  );
1654
1948
  ctx.body = {
1655
1949
  results,
1656
- pagination
1950
+ pagination: pagination2
1657
1951
  };
1658
1952
  },
1659
1953
  async findOne(ctx) {
1660
1954
  const { userAbility } = ctx.state;
1661
1955
  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 });
1956
+ const documentManager2 = getService$2("document-manager");
1957
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1665
1958
  if (permissionChecker2.cannot.read()) {
1666
1959
  return ctx.forbidden();
1667
1960
  }
1668
1961
  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);
1962
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1963
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1671
1964
  const version = await documentManager2.findOne(id, model, {
1672
1965
  populate,
1673
1966
  locale,
@@ -1678,9 +1971,11 @@ const collectionTypes = {
1678
1971
  if (!exists) {
1679
1972
  return ctx.notFound();
1680
1973
  }
1681
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
1974
+ const { meta } = await formatDocumentWithMetadata(
1975
+ permissionChecker2,
1682
1976
  model,
1683
- { id, locale, publishedAt: null },
1977
+ // @ts-expect-error TODO: fix
1978
+ { documentId: id, locale, publishedAt: null },
1684
1979
  { availableLocales: true, availableStatus: false }
1685
1980
  );
1686
1981
  ctx.body = { data: {}, meta };
@@ -1690,20 +1985,19 @@ const collectionTypes = {
1690
1985
  return ctx.forbidden();
1691
1986
  }
1692
1987
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
1693
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
1988
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1694
1989
  },
1695
1990
  async create(ctx) {
1696
1991
  const { userAbility } = ctx.state;
1697
1992
  const { model } = ctx.params;
1698
- const documentMetadata2 = getService$1("document-metadata");
1699
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1993
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1700
1994
  const [totalEntries, document] = await Promise.all([
1701
1995
  strapi.db.query(model).count(),
1702
1996
  createDocument(ctx)
1703
1997
  ]);
1704
1998
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
1705
1999
  ctx.status = 201;
1706
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
2000
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1707
2001
  // Empty metadata as it's not relevant for a new document
1708
2002
  availableLocales: false,
1709
2003
  availableStatus: false
@@ -1717,25 +2011,23 @@ const collectionTypes = {
1717
2011
  async update(ctx) {
1718
2012
  const { userAbility } = ctx.state;
1719
2013
  const { model } = ctx.params;
1720
- const documentMetadata2 = getService$1("document-metadata");
1721
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2014
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1722
2015
  const updatedVersion = await updateDocument(ctx);
1723
2016
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1724
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedVersion);
2017
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
1725
2018
  },
1726
2019
  async clone(ctx) {
1727
2020
  const { userAbility, user } = ctx.state;
1728
2021
  const { model, sourceId: id } = ctx.params;
1729
2022
  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 });
2023
+ const documentManager2 = getService$2("document-manager");
2024
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1733
2025
  if (permissionChecker2.cannot.create()) {
1734
2026
  return ctx.forbidden();
1735
2027
  }
1736
2028
  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);
2029
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2030
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1739
2031
  const document = await documentManager2.findOne(id, model, {
1740
2032
  populate,
1741
2033
  locale,
@@ -1751,7 +2043,7 @@ const collectionTypes = {
1751
2043
  const sanitizedBody = await sanitizeFn(body);
1752
2044
  const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
1753
2045
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
1754
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
2046
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1755
2047
  // Empty metadata as it's not relevant for a new document
1756
2048
  availableLocales: false,
1757
2049
  availableStatus: false
@@ -1773,14 +2065,14 @@ const collectionTypes = {
1773
2065
  async delete(ctx) {
1774
2066
  const { userAbility } = ctx.state;
1775
2067
  const { id, model } = ctx.params;
1776
- const documentManager2 = getService$1("document-manager");
1777
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2068
+ const documentManager2 = getService$2("document-manager");
2069
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1778
2070
  if (permissionChecker2.cannot.delete()) {
1779
2071
  return ctx.forbidden();
1780
2072
  }
1781
2073
  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);
2074
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2075
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1784
2076
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1785
2077
  if (documentLocales.length === 0) {
1786
2078
  return ctx.notFound();
@@ -1801,44 +2093,75 @@ const collectionTypes = {
1801
2093
  const { userAbility } = ctx.state;
1802
2094
  const { id, model } = ctx.params;
1803
2095
  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 });
2096
+ const documentManager2 = getService$2("document-manager");
2097
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1807
2098
  if (permissionChecker2.cannot.publish()) {
1808
2099
  return ctx.forbidden();
1809
2100
  }
1810
2101
  const publishedDocument = await strapi.db.transaction(async () => {
1811
2102
  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 });
2103
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2104
+ let document;
2105
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2106
+ const isCreate = isNil$1(id);
2107
+ if (isCreate) {
2108
+ if (permissionChecker2.cannot.create()) {
2109
+ throw new errors.ForbiddenError();
2110
+ }
2111
+ document = await createDocument(ctx, { populate });
2112
+ }
2113
+ const isUpdate = !isCreate;
2114
+ if (isUpdate) {
2115
+ const documentExists = documentManager2.exists(model, id);
2116
+ if (!documentExists) {
2117
+ throw new errors.NotFoundError("Document not found");
2118
+ }
2119
+ document = await documentManager2.findOne(id, model, { populate, locale });
2120
+ if (!document) {
2121
+ if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
2122
+ throw new errors.ForbiddenError();
2123
+ }
2124
+ document = await updateDocument(ctx);
2125
+ } else if (permissionChecker2.can.update(document)) {
2126
+ await updateDocument(ctx);
2127
+ }
2128
+ }
1814
2129
  if (permissionChecker2.cannot.publish(document)) {
1815
2130
  throw new errors.ForbiddenError();
1816
2131
  }
1817
- const { locale } = getDocumentLocaleAndStatus(body);
1818
- return documentManager2.publish(document.documentId, model, {
2132
+ const publishResult = await documentManager2.publish(document.documentId, model, {
1819
2133
  locale
1820
2134
  // TODO: Allow setting creator fields on publish
1821
2135
  // data: setCreatorFields({ user, isEdition: true })({}),
1822
2136
  });
2137
+ if (!publishResult || publishResult.length === 0) {
2138
+ throw new errors.NotFoundError("Document not found or already published.");
2139
+ }
2140
+ return publishResult[0];
1823
2141
  });
1824
2142
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
1825
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2143
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1826
2144
  },
1827
2145
  async bulkPublish(ctx) {
1828
2146
  const { userAbility } = ctx.state;
1829
2147
  const { model } = ctx.params;
1830
2148
  const { body } = ctx.request;
1831
- const { ids } = body;
2149
+ const { documentIds } = body;
1832
2150
  await validateBulkActionInput(body);
1833
- const documentManager2 = getService$1("document-manager");
1834
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2151
+ const documentManager2 = getService$2("document-manager");
2152
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1835
2153
  if (permissionChecker2.cannot.publish()) {
1836
2154
  return ctx.forbidden();
1837
2155
  }
1838
2156
  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);
2157
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2158
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2159
+ allowMultipleLocales: true
2160
+ });
2161
+ const entityPromises = documentIds.map(
2162
+ (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
2163
+ );
2164
+ const entities = (await Promise.all(entityPromises)).flat();
1842
2165
  for (const entity of entities) {
1843
2166
  if (!entity) {
1844
2167
  return ctx.notFound();
@@ -1847,24 +2170,27 @@ const collectionTypes = {
1847
2170
  return ctx.forbidden();
1848
2171
  }
1849
2172
  }
1850
- const { count } = await documentManager2.publishMany(entities, model);
2173
+ const count = await documentManager2.publishMany(model, documentIds, locale);
1851
2174
  ctx.body = { count };
1852
2175
  },
1853
2176
  async bulkUnpublish(ctx) {
1854
2177
  const { userAbility } = ctx.state;
1855
2178
  const { model } = ctx.params;
1856
2179
  const { body } = ctx.request;
1857
- const { ids } = body;
2180
+ const { documentIds } = body;
1858
2181
  await validateBulkActionInput(body);
1859
- const documentManager2 = getService$1("document-manager");
1860
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2182
+ const documentManager2 = getService$2("document-manager");
2183
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1861
2184
  if (permissionChecker2.cannot.unpublish()) {
1862
2185
  return ctx.forbidden();
1863
2186
  }
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);
2187
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2188
+ allowMultipleLocales: true
2189
+ });
2190
+ const entityPromises = documentIds.map(
2191
+ (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
2192
+ );
2193
+ const entities = (await Promise.all(entityPromises)).flat();
1868
2194
  for (const entity of entities) {
1869
2195
  if (!entity) {
1870
2196
  return ctx.notFound();
@@ -1873,7 +2199,8 @@ const collectionTypes = {
1873
2199
  return ctx.forbidden();
1874
2200
  }
1875
2201
  }
1876
- const { count } = await documentManager2.unpublishMany(entities, model);
2202
+ const entitiesIds = entities.map((document) => document.documentId);
2203
+ const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
1877
2204
  ctx.body = { count };
1878
2205
  },
1879
2206
  async unpublish(ctx) {
@@ -1882,9 +2209,8 @@ const collectionTypes = {
1882
2209
  const {
1883
2210
  body: { discardDraft, ...body }
1884
2211
  } = 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 });
2212
+ const documentManager2 = getService$2("document-manager");
2213
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1888
2214
  if (permissionChecker2.cannot.unpublish()) {
1889
2215
  return ctx.forbidden();
1890
2216
  }
@@ -1892,8 +2218,8 @@ const collectionTypes = {
1892
2218
  return ctx.forbidden();
1893
2219
  }
1894
2220
  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);
2221
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2222
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1897
2223
  const document = await documentManager2.findOne(id, model, {
1898
2224
  populate,
1899
2225
  locale,
@@ -1915,7 +2241,7 @@ const collectionTypes = {
1915
2241
  ctx.body = await async.pipe(
1916
2242
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
1917
2243
  permissionChecker2.sanitizeOutput,
1918
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2244
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1919
2245
  )(document);
1920
2246
  });
1921
2247
  },
@@ -1923,15 +2249,14 @@ const collectionTypes = {
1923
2249
  const { userAbility } = ctx.state;
1924
2250
  const { id, model } = ctx.params;
1925
2251
  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 });
2252
+ const documentManager2 = getService$2("document-manager");
2253
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1929
2254
  if (permissionChecker2.cannot.discard()) {
1930
2255
  return ctx.forbidden();
1931
2256
  }
1932
2257
  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);
2258
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2259
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1935
2260
  const document = await documentManager2.findOne(id, model, {
1936
2261
  populate,
1937
2262
  locale,
@@ -1946,42 +2271,50 @@ const collectionTypes = {
1946
2271
  ctx.body = await async.pipe(
1947
2272
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
1948
2273
  permissionChecker2.sanitizeOutput,
1949
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2274
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1950
2275
  )(document);
1951
2276
  },
1952
2277
  async bulkDelete(ctx) {
1953
2278
  const { userAbility } = ctx.state;
1954
2279
  const { model } = ctx.params;
1955
2280
  const { query, body } = ctx.request;
1956
- const { ids } = body;
2281
+ const { documentIds } = body;
1957
2282
  await validateBulkActionInput(body);
1958
- const documentManager2 = getService$1("document-manager");
1959
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2283
+ const documentManager2 = getService$2("document-manager");
2284
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1960
2285
  if (permissionChecker2.cannot.delete()) {
1961
2286
  return ctx.forbidden();
1962
2287
  }
1963
2288
  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 || [])
2289
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2290
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2291
+ const documentLocales = await documentManager2.findLocales(documentIds, model, {
2292
+ populate,
2293
+ locale
2294
+ });
2295
+ if (documentLocales.length === 0) {
2296
+ return ctx.notFound();
2297
+ }
2298
+ for (const document of documentLocales) {
2299
+ if (permissionChecker2.cannot.delete(document)) {
2300
+ return ctx.forbidden();
1969
2301
  }
1970
- };
1971
- const { count } = await documentManager2.deleteMany(params, model);
2302
+ }
2303
+ const localeDocumentsIds = documentLocales.map((document) => document.documentId);
2304
+ const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
1972
2305
  ctx.body = { count };
1973
2306
  },
1974
2307
  async countDraftRelations(ctx) {
1975
2308
  const { userAbility } = ctx.state;
1976
2309
  const { model, id } = ctx.params;
1977
- const documentManager2 = getService$1("document-manager");
1978
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2310
+ const documentManager2 = getService$2("document-manager");
2311
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1979
2312
  if (permissionChecker2.cannot.read()) {
1980
2313
  return ctx.forbidden();
1981
2314
  }
1982
2315
  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);
2316
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2317
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1985
2318
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
1986
2319
  if (!entity) {
1987
2320
  return ctx.notFound();
@@ -1996,24 +2329,24 @@ const collectionTypes = {
1996
2329
  },
1997
2330
  async countManyEntriesDraftRelations(ctx) {
1998
2331
  const { userAbility } = ctx.state;
1999
- const ids = ctx.request.query.ids;
2332
+ const ids = ctx.request.query.documentIds;
2000
2333
  const locale = ctx.request.query.locale;
2001
2334
  const { model } = ctx.params;
2002
- const documentManager2 = getService$1("document-manager");
2003
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2335
+ const documentManager2 = getService$2("document-manager");
2336
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2004
2337
  if (permissionChecker2.cannot.read()) {
2005
2338
  return ctx.forbidden();
2006
2339
  }
2007
- const entities = await documentManager2.findMany(
2340
+ const documents = await documentManager2.findMany(
2008
2341
  {
2009
2342
  filters: {
2010
- id: ids
2343
+ documentId: ids
2011
2344
  },
2012
2345
  locale
2013
2346
  },
2014
2347
  model
2015
2348
  );
2016
- if (!entities) {
2349
+ if (!documents) {
2017
2350
  return ctx.notFound();
2018
2351
  }
2019
2352
  const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
@@ -2024,13 +2357,13 @@ const collectionTypes = {
2024
2357
  };
2025
2358
  const components$1 = {
2026
2359
  findComponents(ctx) {
2027
- const components2 = getService$1("components").findAllComponents();
2028
- const { toDto } = getService$1("data-mapper");
2360
+ const components2 = getService$2("components").findAllComponents();
2361
+ const { toDto } = getService$2("data-mapper");
2029
2362
  ctx.body = { data: components2.map(toDto) };
2030
2363
  },
2031
2364
  async findComponentConfiguration(ctx) {
2032
2365
  const { uid: uid2 } = ctx.params;
2033
- const componentService = getService$1("components");
2366
+ const componentService = getService$2("components");
2034
2367
  const component = componentService.findComponent(uid2);
2035
2368
  if (!component) {
2036
2369
  return ctx.notFound("component.notFound");
@@ -2047,7 +2380,7 @@ const components$1 = {
2047
2380
  async updateComponentConfiguration(ctx) {
2048
2381
  const { uid: uid2 } = ctx.params;
2049
2382
  const { body } = ctx.request;
2050
- const componentService = getService$1("components");
2383
+ const componentService = getService$2("components");
2051
2384
  const component = componentService.findComponent(uid2);
2052
2385
  if (!component) {
2053
2386
  return ctx.notFound("component.notFound");
@@ -2081,12 +2414,12 @@ const contentTypes = {
2081
2414
  } catch (error) {
2082
2415
  return ctx.send({ error }, 400);
2083
2416
  }
2084
- const contentTypes2 = getService$1("content-types").findContentTypesByKind(kind);
2085
- const { toDto } = getService$1("data-mapper");
2417
+ const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
2418
+ const { toDto } = getService$2("data-mapper");
2086
2419
  ctx.body = { data: contentTypes2.map(toDto) };
2087
2420
  },
2088
2421
  async findContentTypesSettings(ctx) {
2089
- const { findAllContentTypes, findConfiguration } = getService$1("content-types");
2422
+ const { findAllContentTypes, findConfiguration } = getService$2("content-types");
2090
2423
  const contentTypes2 = await findAllContentTypes();
2091
2424
  const configurations = await Promise.all(
2092
2425
  contentTypes2.map(async (contentType) => {
@@ -2100,7 +2433,7 @@ const contentTypes = {
2100
2433
  },
2101
2434
  async findContentTypeConfiguration(ctx) {
2102
2435
  const { uid: uid2 } = ctx.params;
2103
- const contentTypeService = getService$1("content-types");
2436
+ const contentTypeService = getService$2("content-types");
2104
2437
  const contentType = await contentTypeService.findContentType(uid2);
2105
2438
  if (!contentType) {
2106
2439
  return ctx.notFound("contentType.notFound");
@@ -2122,13 +2455,13 @@ const contentTypes = {
2122
2455
  const { userAbility } = ctx.state;
2123
2456
  const { uid: uid2 } = ctx.params;
2124
2457
  const { body } = ctx.request;
2125
- const contentTypeService = getService$1("content-types");
2126
- const metricsService = getService$1("metrics");
2458
+ const contentTypeService = getService$2("content-types");
2459
+ const metricsService = getService$2("metrics");
2127
2460
  const contentType = await contentTypeService.findContentType(uid2);
2128
2461
  if (!contentType) {
2129
2462
  return ctx.notFound("contentType.notFound");
2130
2463
  }
2131
- if (!getService$1("permission").canConfigureContentType({ userAbility, contentType })) {
2464
+ if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
2132
2465
  return ctx.forbidden();
2133
2466
  }
2134
2467
  let input;
@@ -2161,10 +2494,10 @@ const contentTypes = {
2161
2494
  };
2162
2495
  const init = {
2163
2496
  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");
2497
+ const { toDto } = getService$2("data-mapper");
2498
+ const { findAllComponents } = getService$2("components");
2499
+ const { getAllFieldSizes } = getService$2("field-sizes");
2500
+ const { findAllContentTypes } = getService$2("content-types");
2168
2501
  ctx.body = {
2169
2502
  data: {
2170
2503
  fieldSizes: getAllFieldSizes(),
@@ -2200,36 +2533,41 @@ const addFiltersClause = (params, filtersClause) => {
2200
2533
  params.filters.$and.push(filtersClause);
2201
2534
  };
2202
2535
  const sanitizeMainField = (model, mainField, userAbility) => {
2203
- const permissionChecker2 = getService$1("permission-checker").create({
2536
+ const permissionChecker2 = getService$2("permission-checker").create({
2204
2537
  userAbility,
2205
2538
  model: model.uid
2206
2539
  });
2207
- if (!isListable(model, mainField)) {
2540
+ const isMainFieldListable = isListable(model, mainField);
2541
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2542
+ if (!isMainFieldListable || !canReadMainField) {
2208
2543
  return "id";
2209
2544
  }
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";
2545
+ if (model.uid === "plugin::users-permissions.role") {
2546
+ return "name";
2221
2547
  }
2222
2548
  return mainField;
2223
2549
  };
2224
- const addStatusToRelations = async (uid2, relations2) => {
2225
- if (!contentTypes$1.hasDraftAndPublish(strapi.contentTypes[uid2])) {
2550
+ const addStatusToRelations = async (targetUid, relations2) => {
2551
+ if (!contentTypes$1.hasDraftAndPublish(strapi.getModel(targetUid))) {
2552
+ return relations2;
2553
+ }
2554
+ const documentMetadata2 = getService$2("document-metadata");
2555
+ if (!relations2.length) {
2226
2556
  return relations2;
2227
2557
  }
2228
- const documentMetadata2 = getService$1("document-metadata");
2229
- const documentsAvailableStatus = await documentMetadata2.getManyAvailableStatus(uid2, relations2);
2558
+ const firstRelation = relations2[0];
2559
+ const filters = {
2560
+ documentId: { $in: relations2.map((r) => r.documentId) },
2561
+ // NOTE: find the "opposite" status
2562
+ publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
2563
+ };
2564
+ const availableStatus = await strapi.query(targetUid).findMany({
2565
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
2566
+ filters
2567
+ });
2230
2568
  return relations2.map((relation) => {
2231
- const availableStatuses = documentsAvailableStatus.filter(
2232
- (availableDocument) => availableDocument.documentId === relation.documentId
2569
+ const availableStatuses = availableStatus.filter(
2570
+ (availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
2233
2571
  );
2234
2572
  return {
2235
2573
  ...relation,
@@ -2250,11 +2588,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2250
2588
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2251
2589
  const isSourceLocalized = isLocalized(sourceModel);
2252
2590
  const isTargetLocalized = isLocalized(targetModel);
2253
- let validatedLocale = locale;
2254
- if (!targetModel || !isTargetLocalized)
2255
- validatedLocale = void 0;
2256
2591
  return {
2257
- locale: validatedLocale,
2592
+ locale,
2258
2593
  isSourceLocalized,
2259
2594
  isTargetLocalized
2260
2595
  };
@@ -2263,8 +2598,7 @@ const validateStatus = (sourceUid, status) => {
2263
2598
  const sourceModel = strapi.getModel(sourceUid);
2264
2599
  const isDP = contentTypes$1.hasDraftAndPublish;
2265
2600
  const isSourceDP = isDP(sourceModel);
2266
- if (!isSourceDP)
2267
- return { status: void 0 };
2601
+ if (!isSourceDP) return { status: void 0 };
2268
2602
  switch (status) {
2269
2603
  case "published":
2270
2604
  return { status: "published" };
@@ -2294,7 +2628,7 @@ const relations = {
2294
2628
  ctx.request?.query?.locale
2295
2629
  );
2296
2630
  const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
2297
- const permissionChecker2 = getService$1("permission-checker").create({
2631
+ const permissionChecker2 = getService$2("permission-checker").create({
2298
2632
  userAbility,
2299
2633
  model
2300
2634
  });
@@ -2319,7 +2653,7 @@ const relations = {
2319
2653
  where.id = id;
2320
2654
  }
2321
2655
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2322
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2656
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2323
2657
  const currentEntity = await strapi.db.query(model).findOne({
2324
2658
  where,
2325
2659
  populate
@@ -2334,7 +2668,7 @@ const relations = {
2334
2668
  }
2335
2669
  entryId = currentEntity.id;
2336
2670
  }
2337
- const modelConfig = isComponent2 ? await getService$1("components").findConfiguration(sourceSchema) : await getService$1("content-types").findConfiguration(sourceSchema);
2671
+ const modelConfig = isComponent2 ? await getService$2("components").findConfiguration(sourceSchema) : await getService$2("content-types").findConfiguration(sourceSchema);
2338
2672
  const targetSchema = strapi.getModel(targetUid);
2339
2673
  const mainField = flow(
2340
2674
  prop(`metadatas.${targetField}.edit.mainField`),
@@ -2357,7 +2691,7 @@ const relations = {
2357
2691
  attribute,
2358
2692
  fieldsToSelect,
2359
2693
  mainField,
2360
- source: { schema: sourceSchema },
2694
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2361
2695
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2362
2696
  sourceSchema,
2363
2697
  targetSchema,
@@ -2379,7 +2713,8 @@ const relations = {
2379
2713
  fieldsToSelect,
2380
2714
  mainField,
2381
2715
  source: {
2382
- schema: { uid: sourceUid, modelType: sourceModelType }
2716
+ schema: { uid: sourceUid, modelType: sourceModelType },
2717
+ isLocalized: isSourceLocalized
2383
2718
  },
2384
2719
  target: {
2385
2720
  schema: { uid: targetUid },
@@ -2387,7 +2722,7 @@ const relations = {
2387
2722
  }
2388
2723
  } = await this.extractAndValidateRequestInfo(ctx, id);
2389
2724
  const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
2390
- const permissionChecker2 = getService$1("permission-checker").create({
2725
+ const permissionChecker2 = getService$2("permission-checker").create({
2391
2726
  userAbility: ctx.state.userAbility,
2392
2727
  model: targetUid
2393
2728
  });
@@ -2417,12 +2752,16 @@ const relations = {
2417
2752
  } else {
2418
2753
  where.id = id;
2419
2754
  }
2420
- if (status) {
2421
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2755
+ const publishedAt = getPublishedAtClause(status, targetUid);
2756
+ if (!isEmpty(publishedAt)) {
2757
+ where[`${alias}.published_at`] = publishedAt;
2422
2758
  }
2423
- if (filterByLocale) {
2759
+ if (isTargetLocalized && locale) {
2424
2760
  where[`${alias}.locale`] = locale;
2425
2761
  }
2762
+ if (isSourceLocalized && locale) {
2763
+ where.locale = locale;
2764
+ }
2426
2765
  if ((idsToInclude?.length ?? 0) !== 0) {
2427
2766
  where[`${alias}.id`].$notIn = idsToInclude;
2428
2767
  }
@@ -2440,7 +2779,8 @@ const relations = {
2440
2779
  id: { $notIn: uniq(idsToOmit) }
2441
2780
  });
2442
2781
  }
2443
- const res = await strapi.db.query(targetUid).findPage(strapi.get("query-params").transform(targetUid, queryParams));
2782
+ const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
2783
+ const res = await strapi.db.query(targetUid).findPage(dbQuery);
2444
2784
  ctx.body = {
2445
2785
  ...res,
2446
2786
  results: await addStatusToRelations(targetUid, res.results)
@@ -2455,29 +2795,39 @@ const relations = {
2455
2795
  attribute,
2456
2796
  targetField,
2457
2797
  fieldsToSelect,
2458
- source: {
2459
- schema: { uid: sourceUid }
2460
- },
2461
- target: {
2462
- schema: { uid: targetUid }
2463
- }
2798
+ status,
2799
+ source: { schema: sourceSchema },
2800
+ target: { schema: targetSchema }
2464
2801
  } = await this.extractAndValidateRequestInfo(ctx, id);
2465
- const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2802
+ const { uid: sourceUid } = sourceSchema;
2803
+ const { uid: targetUid } = targetSchema;
2804
+ const permissionQuery = await getService$2("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2466
2805
  const dbQuery = strapi.db.query(sourceUid);
2467
2806
  const loadRelations = relations$1.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
2807
+ const filters = {};
2808
+ if (sourceSchema?.options?.draftAndPublish) {
2809
+ if (targetSchema?.options?.draftAndPublish) {
2810
+ if (status === "published") {
2811
+ filters.publishedAt = { $notNull: true };
2812
+ } else {
2813
+ filters.publishedAt = { $null: true };
2814
+ }
2815
+ }
2816
+ } else if (targetSchema?.options?.draftAndPublish) {
2817
+ filters.publishedAt = { $null: true };
2818
+ }
2468
2819
  const res = await loadRelations({ id: entryId }, targetField, {
2469
- select: ["id", "documentId", "locale", "publishedAt"],
2820
+ select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
2470
2821
  ordering: "desc",
2471
2822
  page: ctx.request.query.page,
2472
- pageSize: ctx.request.query.pageSize
2823
+ pageSize: ctx.request.query.pageSize,
2824
+ filters
2473
2825
  });
2474
2826
  const loadedIds = res.results.map((item) => item.id);
2475
2827
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2476
2828
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2477
2829
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2478
- ordering: "desc",
2479
- page: ctx.request.query.page,
2480
- pageSize: ctx.request.query.pageSize
2830
+ ordering: "desc"
2481
2831
  });
2482
2832
  const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
2483
2833
  ctx.body = {
@@ -2492,10 +2842,10 @@ const relations = {
2492
2842
  }
2493
2843
  };
2494
2844
  const buildPopulateFromQuery = async (query, model) => {
2495
- return getService$1("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2845
+ return getService$2("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2496
2846
  };
2497
2847
  const findDocument = async (query, uid2, opts = {}) => {
2498
- const documentManager2 = getService$1("document-manager");
2848
+ const documentManager2 = getService$2("document-manager");
2499
2849
  const populate = await buildPopulateFromQuery(query, uid2);
2500
2850
  return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
2501
2851
  };
@@ -2503,13 +2853,13 @@ const createOrUpdateDocument = async (ctx, opts) => {
2503
2853
  const { user, userAbility } = ctx.state;
2504
2854
  const { model } = ctx.params;
2505
2855
  const { body, query } = ctx.request;
2506
- const documentManager2 = getService$1("document-manager");
2507
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2856
+ const documentManager2 = getService$2("document-manager");
2857
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2508
2858
  if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
2509
2859
  throw new errors.ForbiddenError();
2510
2860
  }
2511
2861
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2512
- const { locale } = getDocumentLocaleAndStatus(body);
2862
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2513
2863
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2514
2864
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2515
2865
  // Find the first document to check if it exists
@@ -2545,13 +2895,12 @@ const singleTypes = {
2545
2895
  const { userAbility } = ctx.state;
2546
2896
  const { model } = ctx.params;
2547
2897
  const { query = {} } = ctx.request;
2548
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2549
- const documentMetadata2 = getService$1("document-metadata");
2898
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2550
2899
  if (permissionChecker2.cannot.read()) {
2551
2900
  return ctx.forbidden();
2552
2901
  }
2553
2902
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2554
- const { locale, status } = getDocumentLocaleAndStatus(query);
2903
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
2555
2904
  const version = await findDocument(permissionQuery, model, { locale, status });
2556
2905
  if (!version) {
2557
2906
  if (permissionChecker2.cannot.create()) {
@@ -2561,9 +2910,11 @@ const singleTypes = {
2561
2910
  if (!document) {
2562
2911
  return ctx.notFound();
2563
2912
  }
2564
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
2913
+ const { meta } = await formatDocumentWithMetadata(
2914
+ permissionChecker2,
2565
2915
  model,
2566
- { id: document.documentId, locale, publishedAt: null },
2916
+ // @ts-expect-error - fix types
2917
+ { documentId: document.documentId, locale, publishedAt: null },
2567
2918
  { availableLocales: true, availableStatus: false }
2568
2919
  );
2569
2920
  ctx.body = { data: {}, meta };
@@ -2573,29 +2924,28 @@ const singleTypes = {
2573
2924
  return ctx.forbidden();
2574
2925
  }
2575
2926
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
2576
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2927
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2577
2928
  },
2578
2929
  async createOrUpdate(ctx) {
2579
2930
  const { userAbility } = ctx.state;
2580
2931
  const { model } = ctx.params;
2581
- const documentMetadata2 = getService$1("document-metadata");
2582
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2932
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2583
2933
  const document = await createOrUpdateDocument(ctx);
2584
2934
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2585
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2935
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2586
2936
  },
2587
2937
  async delete(ctx) {
2588
2938
  const { userAbility } = ctx.state;
2589
2939
  const { model } = ctx.params;
2590
2940
  const { query = {} } = ctx.request;
2591
- const documentManager2 = getService$1("document-manager");
2592
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2941
+ const documentManager2 = getService$2("document-manager");
2942
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2593
2943
  if (permissionChecker2.cannot.delete()) {
2594
2944
  return ctx.forbidden();
2595
2945
  }
2596
2946
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2597
2947
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2598
- const { locale } = getDocumentLocaleAndStatus(query);
2948
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2599
2949
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2600
2950
  populate,
2601
2951
  locale
@@ -2617,9 +2967,8 @@ const singleTypes = {
2617
2967
  const { userAbility } = ctx.state;
2618
2968
  const { model } = ctx.params;
2619
2969
  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 });
2970
+ const documentManager2 = getService$2("document-manager");
2971
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2623
2972
  if (permissionChecker2.cannot.publish()) {
2624
2973
  return ctx.forbidden();
2625
2974
  }
@@ -2633,11 +2982,12 @@ const singleTypes = {
2633
2982
  if (permissionChecker2.cannot.publish(document)) {
2634
2983
  throw new errors.ForbiddenError();
2635
2984
  }
2636
- const { locale } = getDocumentLocaleAndStatus(document);
2637
- return documentManager2.publish(document.documentId, model, { locale });
2985
+ const { locale } = await getDocumentLocaleAndStatus(document, model);
2986
+ const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2987
+ return publishResult.at(0);
2638
2988
  });
2639
2989
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
2640
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2990
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2641
2991
  },
2642
2992
  async unpublish(ctx) {
2643
2993
  const { userAbility } = ctx.state;
@@ -2646,9 +2996,8 @@ const singleTypes = {
2646
2996
  body: { discardDraft, ...body },
2647
2997
  query = {}
2648
2998
  } = 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 });
2999
+ const documentManager2 = getService$2("document-manager");
3000
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2652
3001
  if (permissionChecker2.cannot.unpublish()) {
2653
3002
  return ctx.forbidden();
2654
3003
  }
@@ -2656,7 +3005,7 @@ const singleTypes = {
2656
3005
  return ctx.forbidden();
2657
3006
  }
2658
3007
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2659
- const { locale } = getDocumentLocaleAndStatus(body);
3008
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2660
3009
  const document = await findDocument(sanitizedQuery, model, { locale });
2661
3010
  if (!document) {
2662
3011
  return ctx.notFound();
@@ -2674,7 +3023,7 @@ const singleTypes = {
2674
3023
  ctx.body = await async.pipe(
2675
3024
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
2676
3025
  permissionChecker2.sanitizeOutput,
2677
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
3026
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2678
3027
  )(document);
2679
3028
  });
2680
3029
  },
@@ -2682,14 +3031,13 @@ const singleTypes = {
2682
3031
  const { userAbility } = ctx.state;
2683
3032
  const { model } = ctx.params;
2684
3033
  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 });
3034
+ const documentManager2 = getService$2("document-manager");
3035
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2688
3036
  if (permissionChecker2.cannot.discard()) {
2689
3037
  return ctx.forbidden();
2690
3038
  }
2691
3039
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2692
- const { locale } = getDocumentLocaleAndStatus(body);
3040
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2693
3041
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2694
3042
  if (!document) {
2695
3043
  return ctx.notFound();
@@ -2700,16 +3048,16 @@ const singleTypes = {
2700
3048
  ctx.body = await async.pipe(
2701
3049
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
2702
3050
  permissionChecker2.sanitizeOutput,
2703
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
3051
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2704
3052
  )(document);
2705
3053
  },
2706
3054
  async countDraftRelations(ctx) {
2707
3055
  const { userAbility } = ctx.state;
2708
3056
  const { model } = ctx.params;
2709
3057
  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);
3058
+ const documentManager2 = getService$2("document-manager");
3059
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
3060
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2713
3061
  if (permissionChecker2.cannot.read()) {
2714
3062
  return ctx.forbidden();
2715
3063
  }
@@ -2730,9 +3078,9 @@ const uid$1 = {
2730
3078
  async generateUID(ctx) {
2731
3079
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2732
3080
  const { query = {} } = ctx.request;
2733
- const { locale } = getDocumentLocaleAndStatus(query);
3081
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2734
3082
  await validateUIDField(contentTypeUID, field);
2735
- const uidService = getService$1("uid");
3083
+ const uidService = getService$2("uid");
2736
3084
  ctx.body = {
2737
3085
  data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
2738
3086
  };
@@ -2742,9 +3090,9 @@ const uid$1 = {
2742
3090
  ctx.request.body
2743
3091
  );
2744
3092
  const { query = {} } = ctx.request;
2745
- const { locale } = getDocumentLocaleAndStatus(query);
3093
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2746
3094
  await validateUIDField(contentTypeUID, field);
2747
- const uidService = getService$1("uid");
3095
+ const uidService = getService$2("uid");
2748
3096
  const isAvailable = await uidService.checkUIDAvailability({
2749
3097
  contentTypeUID,
2750
3098
  field,
@@ -2765,7 +3113,8 @@ const controllers = {
2765
3113
  relations,
2766
3114
  "single-types": singleTypes,
2767
3115
  uid: uid$1,
2768
- ...history.controllers ? history.controllers : {}
3116
+ ...history.controllers ? history.controllers : {},
3117
+ ...preview.controllers ? preview.controllers : {}
2769
3118
  };
2770
3119
  const keys = {
2771
3120
  CONFIGURATION: "configuration"
@@ -2894,18 +3243,15 @@ async function syncMetadatas(configuration, schema) {
2894
3243
  _.set(updatedMeta, ["list", "searchable"], false);
2895
3244
  _.set(acc, [key], updatedMeta);
2896
3245
  }
2897
- if (!_.has(edit, "mainField"))
2898
- return acc;
3246
+ if (!_.has(edit, "mainField")) return acc;
2899
3247
  if (!isRelation$1(attr)) {
2900
3248
  _.set(updatedMeta, "edit", _.omit(edit, ["mainField"]));
2901
3249
  _.set(acc, [key], updatedMeta);
2902
3250
  return acc;
2903
3251
  }
2904
- if (edit.mainField === "id")
2905
- return acc;
3252
+ if (edit.mainField === "id") return acc;
2906
3253
  const targetSchema = getTargetSchema(attr.targetModel);
2907
- if (!targetSchema)
2908
- return acc;
3254
+ if (!targetSchema) return acc;
2909
3255
  if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
2910
3256
  _.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
2911
3257
  _.set(acc, [key], updatedMeta);
@@ -2916,12 +3262,12 @@ async function syncMetadatas(configuration, schema) {
2916
3262
  return _.assign(metasWithDefaults, updatedMetas);
2917
3263
  }
2918
3264
  const getTargetSchema = (targetModel) => {
2919
- return getService$1("content-types").findContentType(targetModel);
3265
+ return getService$2("content-types").findContentType(targetModel);
2920
3266
  };
2921
3267
  const DEFAULT_LIST_LENGTH = 4;
2922
3268
  const MAX_ROW_SIZE = 12;
2923
3269
  const isAllowedFieldSize = (type, size) => {
2924
- const { getFieldSize } = getService$1("field-sizes");
3270
+ const { getFieldSize } = getService$2("field-sizes");
2925
3271
  const fieldSize = getFieldSize(type);
2926
3272
  if (!fieldSize.isResizable && size !== fieldSize.default) {
2927
3273
  return false;
@@ -2929,7 +3275,7 @@ const isAllowedFieldSize = (type, size) => {
2929
3275
  return size <= MAX_ROW_SIZE;
2930
3276
  };
2931
3277
  const getDefaultFieldSize = (attribute) => {
2932
- const { hasFieldSize, getFieldSize } = getService$1("field-sizes");
3278
+ const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
2933
3279
  return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
2934
3280
  };
2935
3281
  async function createDefaultLayouts(schema) {
@@ -2950,8 +3296,7 @@ function createDefaultEditLayout(schema) {
2950
3296
  return appendToEditLayout([], keys2, schema);
2951
3297
  }
2952
3298
  function syncLayouts(configuration, schema) {
2953
- if (_.isEmpty(configuration.layouts))
2954
- return createDefaultLayouts(schema);
3299
+ if (_.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
2955
3300
  const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
2956
3301
  let cleanList = list.filter((attr) => isListable(schema, attr));
2957
3302
  const cleanEditRelations = editRelations.filter(
@@ -2962,9 +3307,8 @@ function syncLayouts(configuration, schema) {
2962
3307
  for (const row of edit) {
2963
3308
  const newRow = [];
2964
3309
  for (const el of row) {
2965
- if (!hasEditableAttribute(schema, el.name))
2966
- continue;
2967
- const { hasFieldSize } = getService$1("field-sizes");
3310
+ if (!hasEditableAttribute(schema, el.name)) continue;
3311
+ const { hasFieldSize } = getService$2("field-sizes");
2968
3312
  const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
2969
3313
  if (!isAllowedFieldSize(fieldType, el.size)) {
2970
3314
  elementsToReAppend.push(el.name);
@@ -2994,8 +3338,7 @@ function syncLayouts(configuration, schema) {
2994
3338
  };
2995
3339
  }
2996
3340
  const appendToEditLayout = (layout = [], keysToAppend, schema) => {
2997
- if (keysToAppend.length === 0)
2998
- return layout;
3341
+ if (keysToAppend.length === 0) return layout;
2999
3342
  let currentRowIndex = Math.max(layout.length - 1, 0);
3000
3343
  if (!layout[currentRowIndex]) {
3001
3344
  layout[currentRowIndex] = [];
@@ -3104,17 +3447,17 @@ const configurationService$1 = createConfigurationService({
3104
3447
  isComponent: true,
3105
3448
  prefix: STORE_KEY_PREFIX,
3106
3449
  getModels() {
3107
- const { toContentManagerModel } = getService$1("data-mapper");
3450
+ const { toContentManagerModel } = getService$2("data-mapper");
3108
3451
  return mapValues(toContentManagerModel, strapi.components);
3109
3452
  }
3110
3453
  });
3111
3454
  const components = ({ strapi: strapi2 }) => ({
3112
3455
  findAllComponents() {
3113
- const { toContentManagerModel } = getService$1("data-mapper");
3456
+ const { toContentManagerModel } = getService$2("data-mapper");
3114
3457
  return Object.values(strapi2.components).map(toContentManagerModel);
3115
3458
  },
3116
3459
  findComponent(uid2) {
3117
- const { toContentManagerModel } = getService$1("data-mapper");
3460
+ const { toContentManagerModel } = getService$2("data-mapper");
3118
3461
  const component = strapi2.components[uid2];
3119
3462
  return isNil$1(component) ? component : toContentManagerModel(component);
3120
3463
  },
@@ -3165,17 +3508,17 @@ const configurationService = createConfigurationService({
3165
3508
  storeUtils,
3166
3509
  prefix: "content_types",
3167
3510
  getModels() {
3168
- const { toContentManagerModel } = getService$1("data-mapper");
3511
+ const { toContentManagerModel } = getService$2("data-mapper");
3169
3512
  return mapValues(toContentManagerModel, strapi.contentTypes);
3170
3513
  }
3171
3514
  });
3172
3515
  const service = ({ strapi: strapi2 }) => ({
3173
3516
  findAllContentTypes() {
3174
- const { toContentManagerModel } = getService$1("data-mapper");
3517
+ const { toContentManagerModel } = getService$2("data-mapper");
3175
3518
  return Object.values(strapi2.contentTypes).map(toContentManagerModel);
3176
3519
  },
3177
3520
  findContentType(uid2) {
3178
- const { toContentManagerModel } = getService$1("data-mapper");
3521
+ const { toContentManagerModel } = getService$2("data-mapper");
3179
3522
  const contentType = strapi2.contentTypes[uid2];
3180
3523
  return isNil$1(contentType) ? contentType : toContentManagerModel(contentType);
3181
3524
  },
@@ -3204,7 +3547,7 @@ const service = ({ strapi: strapi2 }) => ({
3204
3547
  return this.findConfiguration(contentType);
3205
3548
  },
3206
3549
  findComponentsConfigurations(contentType) {
3207
- return getService$1("components").findComponentsConfigurations(contentType);
3550
+ return getService$2("components").findComponentsConfigurations(contentType);
3208
3551
  },
3209
3552
  syncConfigurations() {
3210
3553
  return configurationService.syncConfigurations();
@@ -3385,12 +3728,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3385
3728
  ability: userAbility,
3386
3729
  model
3387
3730
  });
3388
- const toSubject = (entity) => entity ? permissionsManager.toSubject(entity, model) : model;
3731
+ const { actionProvider } = strapi2.service("admin::permission");
3732
+ const toSubject = (entity) => {
3733
+ return entity ? permissionsManager.toSubject(entity, model) : model;
3734
+ };
3389
3735
  const can = (action, entity, field) => {
3390
- return userAbility.can(action, toSubject(entity), field);
3736
+ const subject = toSubject(entity);
3737
+ const aliases = actionProvider.unstable_aliases(action, model);
3738
+ return (
3739
+ // Test the original action to see if it passes
3740
+ userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
3741
+ aliases.some((alias) => userAbility.can(alias, subject, field))
3742
+ );
3391
3743
  };
3392
3744
  const cannot = (action, entity, field) => {
3393
- return userAbility.cannot(action, toSubject(entity), field);
3745
+ const subject = toSubject(entity);
3746
+ const aliases = actionProvider.unstable_aliases(action, model);
3747
+ return (
3748
+ // Test both the original action
3749
+ userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
3750
+ aliases.every((alias) => userAbility.cannot(alias, subject, field))
3751
+ );
3394
3752
  };
3395
3753
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3396
3754
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3461,7 +3819,7 @@ const permission = ({ strapi: strapi2 }) => ({
3461
3819
  return userAbility.can(action);
3462
3820
  },
3463
3821
  async registerPermissions() {
3464
- const displayedContentTypes = getService$1("content-types").findDisplayedContentTypes();
3822
+ const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
3465
3823
  const contentTypesUids = displayedContentTypes.map(prop("uid"));
3466
3824
  const actions = [
3467
3825
  {
@@ -3533,7 +3891,7 @@ const permission = ({ strapi: strapi2 }) => ({
3533
3891
  await strapi2.service("admin::permission").actionProvider.registerMany(actions);
3534
3892
  }
3535
3893
  });
3536
- const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils.contentTypes;
3894
+ const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils.contentTypes;
3537
3895
  const { isAnyToMany } = strapiUtils.relations;
3538
3896
  const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils.contentTypes.constants;
3539
3897
  const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
@@ -3546,6 +3904,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
3546
3904
  if (initialPopulate) {
3547
3905
  return initialPopulate;
3548
3906
  }
3907
+ if (attributeName === "localizations") {
3908
+ const validationPopulate = getPopulateForValidation(model.uid);
3909
+ return {
3910
+ populate: validationPopulate.populate
3911
+ };
3912
+ }
3549
3913
  if (!isVisibleAttribute$1(model, attributeName)) {
3550
3914
  return true;
3551
3915
  }
@@ -3605,6 +3969,9 @@ const getDeepPopulate = (uid2, {
3605
3969
  return {};
3606
3970
  }
3607
3971
  const model = strapi.getModel(uid2);
3972
+ if (!model) {
3973
+ return {};
3974
+ }
3608
3975
  return Object.keys(model.attributes).reduce(
3609
3976
  (populateAcc, attributeName) => merge(
3610
3977
  populateAcc,
@@ -3624,6 +3991,48 @@ const getDeepPopulate = (uid2, {
3624
3991
  {}
3625
3992
  );
3626
3993
  };
3994
+ const getPopulateForValidation = (uid2) => {
3995
+ const model = strapi.getModel(uid2);
3996
+ if (!model) {
3997
+ return {};
3998
+ }
3999
+ return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
4000
+ if (isScalarAttribute(attribute)) {
4001
+ if (getDoesAttributeRequireValidation(attribute)) {
4002
+ populateAcc.fields = populateAcc.fields || [];
4003
+ populateAcc.fields.push(attributeName);
4004
+ }
4005
+ return populateAcc;
4006
+ }
4007
+ if (isComponent(attribute)) {
4008
+ const component = attribute.component;
4009
+ const componentResult = getPopulateForValidation(component);
4010
+ if (Object.keys(componentResult).length > 0) {
4011
+ populateAcc.populate = populateAcc.populate || {};
4012
+ populateAcc.populate[attributeName] = componentResult;
4013
+ }
4014
+ return populateAcc;
4015
+ }
4016
+ if (isDynamicZone(attribute)) {
4017
+ const components2 = attribute.components;
4018
+ const componentsResult = (components2 || []).reduce(
4019
+ (acc, componentUID) => {
4020
+ const componentResult = getPopulateForValidation(componentUID);
4021
+ if (Object.keys(componentResult).length > 0) {
4022
+ acc[componentUID] = componentResult;
4023
+ }
4024
+ return acc;
4025
+ },
4026
+ {}
4027
+ );
4028
+ if (Object.keys(componentsResult).length > 0) {
4029
+ populateAcc.populate = populateAcc.populate || {};
4030
+ populateAcc.populate[attributeName] = { on: componentsResult };
4031
+ }
4032
+ }
4033
+ return populateAcc;
4034
+ }, {});
4035
+ };
3627
4036
  const getDeepPopulateDraftCount = (uid2) => {
3628
4037
  const model = strapi.getModel(uid2);
3629
4038
  let hasRelations = false;
@@ -3631,6 +4040,10 @@ const getDeepPopulateDraftCount = (uid2) => {
3631
4040
  const attribute = model.attributes[attributeName];
3632
4041
  switch (attribute.type) {
3633
4042
  case "relation": {
4043
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
4044
+ if (isMorphRelation) {
4045
+ break;
4046
+ }
3634
4047
  if (isVisibleAttribute$1(model, attributeName)) {
3635
4048
  populateAcc[attributeName] = {
3636
4049
  count: true,
@@ -3645,22 +4058,24 @@ const getDeepPopulateDraftCount = (uid2) => {
3645
4058
  attribute.component
3646
4059
  );
3647
4060
  if (childHasRelations) {
3648
- populateAcc[attributeName] = { populate: populate2 };
4061
+ populateAcc[attributeName] = {
4062
+ populate: populate2
4063
+ };
3649
4064
  hasRelations = true;
3650
4065
  }
3651
4066
  break;
3652
4067
  }
3653
4068
  case "dynamiczone": {
3654
- const dzPopulate = (attribute.components || []).reduce((acc, componentUID) => {
3655
- const { populate: populate2, hasRelations: childHasRelations } = getDeepPopulateDraftCount(componentUID);
3656
- if (childHasRelations) {
4069
+ const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
4070
+ const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
4071
+ if (componentHasRelations) {
3657
4072
  hasRelations = true;
3658
- return merge(acc, populate2);
4073
+ return { ...acc, [componentUID]: { populate: componentPopulate } };
3659
4074
  }
3660
4075
  return acc;
3661
4076
  }, {});
3662
- if (!isEmpty(dzPopulate)) {
3663
- populateAcc[attributeName] = { populate: dzPopulate };
4077
+ if (!isEmpty(dzPopulateFragment)) {
4078
+ populateAcc[attributeName] = { on: dzPopulateFragment };
3664
4079
  }
3665
4080
  break;
3666
4081
  }
@@ -3695,7 +4110,7 @@ const getQueryPopulate = async (uid2, query) => {
3695
4110
  return populateQuery;
3696
4111
  };
3697
4112
  const buildDeepPopulate = (uid2) => {
3698
- return getService$1("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
4113
+ return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
3699
4114
  };
3700
4115
  const populateBuilder = (uid2) => {
3701
4116
  let getInitialPopulate = async () => {
@@ -3852,41 +4267,55 @@ const AVAILABLE_STATUS_FIELDS = [
3852
4267
  "updatedBy",
3853
4268
  "status"
3854
4269
  ];
3855
- const AVAILABLE_LOCALES_FIELDS = ["id", "locale", "updatedAt", "createdAt", "status"];
4270
+ const AVAILABLE_LOCALES_FIELDS = [
4271
+ "id",
4272
+ "locale",
4273
+ "updatedAt",
4274
+ "createdAt",
4275
+ "publishedAt",
4276
+ "documentId"
4277
+ ];
3856
4278
  const CONTENT_MANAGER_STATUS = {
3857
4279
  PUBLISHED: "published",
3858
4280
  DRAFT: "draft",
3859
4281
  MODIFIED: "modified"
3860
4282
  };
3861
- const areDatesEqual = (date1, date2, threshold) => {
3862
- if (!date1 || !date2) {
4283
+ const getIsVersionLatestModification = (version, otherVersion) => {
4284
+ if (!version || !version.updatedAt) {
3863
4285
  return false;
3864
4286
  }
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;
4287
+ const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
4288
+ const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
4289
+ return versionUpdatedAt > otherUpdatedAt;
3869
4290
  };
3870
4291
  const documentMetadata = ({ strapi: strapi2 }) => ({
3871
4292
  /**
3872
4293
  * Returns available locales of a document for the current status
3873
4294
  */
3874
- getAvailableLocales(uid2, version, allVersions) {
4295
+ async getAvailableLocales(uid2, version, allVersions) {
3875
4296
  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);
4297
+ if (version.locale) {
4298
+ delete versionsByLocale[version.locale];
4299
+ }
4300
+ const model = strapi2.getModel(uid2);
4301
+ const mappingResult = await async.map(
4302
+ Object.values(versionsByLocale),
4303
+ async (localeVersions) => {
4304
+ if (!contentTypes$1.hasDraftAndPublish(model)) {
4305
+ return localeVersions[0];
4306
+ }
4307
+ const draftVersion = localeVersions.find((v) => v.publishedAt === null);
4308
+ const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
4309
+ if (!draftVersion) {
4310
+ return;
4311
+ }
4312
+ return {
4313
+ ...draftVersion,
4314
+ status: this.getStatus(draftVersion, otherVersions)
4315
+ };
4316
+ }
4317
+ );
4318
+ return mappingResult.filter(Boolean);
3890
4319
  },
3891
4320
  /**
3892
4321
  * Returns available status of a document for the current locale
@@ -3898,8 +4327,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3898
4327
  const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
3899
4328
  return matchLocale && matchStatus;
3900
4329
  });
3901
- if (!availableStatus)
3902
- return availableStatus;
4330
+ if (!availableStatus) return availableStatus;
3903
4331
  return pick(AVAILABLE_STATUS_FIELDS, availableStatus);
3904
4332
  },
3905
4333
  /**
@@ -3909,50 +4337,62 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3909
4337
  * @returns
3910
4338
  */
3911
4339
  async getManyAvailableStatus(uid2, documents) {
3912
- if (!documents.length)
3913
- return [];
4340
+ if (!documents.length) return [];
3914
4341
  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) }
4342
+ const locales = documents.map((d) => d.locale).filter(Boolean);
4343
+ return strapi2.query(uid2).findMany({
4344
+ where: {
4345
+ documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) },
4346
+ // NOTE: find the "opposite" status
4347
+ publishedAt: { $null: status === "published" },
4348
+ locale: { $in: locales }
3920
4349
  },
3921
- status: otherStatus,
3922
- locale,
3923
- fields: ["documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
4350
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
3924
4351
  });
3925
4352
  },
3926
4353
  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
- }
4354
+ let draftVersion;
4355
+ let publishedVersion;
4356
+ if (version.publishedAt) {
4357
+ publishedVersion = version;
4358
+ } else {
4359
+ draftVersion = version;
3936
4360
  }
3937
- if (areDatesEqual(version.updatedAt, otherDocumentStatuses.at(0)?.updatedAt, 500)) {
3938
- return CONTENT_MANAGER_STATUS.PUBLISHED;
4361
+ const otherVersion = otherDocumentStatuses?.at(0);
4362
+ if (otherVersion?.publishedAt) {
4363
+ publishedVersion = otherVersion;
4364
+ } else if (otherVersion) {
4365
+ draftVersion = otherVersion;
3939
4366
  }
3940
- return CONTENT_MANAGER_STATUS.MODIFIED;
4367
+ if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
4368
+ if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
4369
+ const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4370
+ return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
3941
4371
  },
4372
+ // TODO is it necessary to return metadata on every page of the CM
4373
+ // We could refactor this so the locales are only loaded when they're
4374
+ // needed. e.g. in the bulk locale action modal.
3942
4375
  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"],
4376
+ const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
4377
+ const params = {
3946
4378
  populate: {
4379
+ ...populate,
4380
+ // NOTE: creator fields are selected in this way to avoid exposing sensitive data
3947
4381
  createdBy: {
3948
4382
  select: ["id", "firstname", "lastname", "email"]
3949
4383
  },
3950
4384
  updatedBy: {
3951
4385
  select: ["id", "firstname", "lastname", "email"]
3952
4386
  }
4387
+ },
4388
+ fields: uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
4389
+ filters: {
4390
+ documentId: version.documentId
3953
4391
  }
3954
- });
3955
- const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
4392
+ };
4393
+ const dbParams = strapi2.get("query-params").transform(uid2, params);
4394
+ const versions = await strapi2.db.query(uid2).findMany(dbParams);
4395
+ const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions) : [];
3956
4396
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
3957
4397
  return {
3958
4398
  availableLocales: availableLocalesResult,
@@ -3965,13 +4405,30 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3965
4405
  * - Available status of the document for the current locale
3966
4406
  */
3967
4407
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
3968
- if (!document)
3969
- return document;
4408
+ if (!document) {
4409
+ return {
4410
+ data: document,
4411
+ meta: {
4412
+ availableLocales: [],
4413
+ availableStatus: []
4414
+ }
4415
+ };
4416
+ }
3970
4417
  const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
3971
4418
  if (!hasDraftAndPublish) {
3972
4419
  opts.availableStatus = false;
3973
4420
  }
3974
4421
  const meta = await this.getMetadata(uid2, document, opts);
4422
+ if (document.localizations) {
4423
+ const otherStatus = await this.getManyAvailableStatus(uid2, document.localizations);
4424
+ document.localizations = document.localizations.map((d) => {
4425
+ const status = otherStatus.find((s) => s.documentId === d.documentId);
4426
+ return {
4427
+ ...d,
4428
+ status: this.getStatus(d, status ? [status] : [])
4429
+ };
4430
+ });
4431
+ }
3975
4432
  return {
3976
4433
  data: {
3977
4434
  ...document,
@@ -4016,26 +4473,9 @@ const sumDraftCounts = (entity, uid2) => {
4016
4473
  }, 0);
4017
4474
  };
4018
4475
  const { ApplicationError } = errors;
4019
- const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
4020
4476
  const { PUBLISHED_AT_ATTRIBUTE } = contentTypes$1.constants;
4021
4477
  const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
4022
4478
  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
4479
  const documentManager = ({ strapi: strapi2 }) => {
4040
4480
  return {
4041
4481
  async findOne(id, uid2, opts = {}) {
@@ -4054,6 +4494,9 @@ const documentManager = ({ strapi: strapi2 }) => {
4054
4494
  } else if (opts.locale && opts.locale !== "*") {
4055
4495
  where.locale = opts.locale;
4056
4496
  }
4497
+ if (typeof opts.isPublished === "boolean") {
4498
+ where.publishedAt = { $notNull: opts.isPublished };
4499
+ }
4057
4500
  return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
4058
4501
  },
4059
4502
  async findMany(opts, uid2) {
@@ -4061,20 +4504,16 @@ const documentManager = ({ strapi: strapi2 }) => {
4061
4504
  return strapi2.documents(uid2).findMany(params);
4062
4505
  },
4063
4506
  async findPage(opts, uid2) {
4064
- const page = Number(opts?.page) || 1;
4065
- const pageSize = Number(opts?.pageSize) || 10;
4507
+ const params = pagination.withDefaultPagination(opts || {}, {
4508
+ maxLimit: 1e3
4509
+ });
4066
4510
  const [documents, total = 0] = await Promise.all([
4067
- strapi2.documents(uid2).findMany(opts),
4068
- strapi2.documents(uid2).count(opts)
4511
+ strapi2.documents(uid2).findMany(params),
4512
+ strapi2.documents(uid2).count(params)
4069
4513
  ]);
4070
4514
  return {
4071
4515
  results: documents,
4072
- pagination: {
4073
- page,
4074
- pageSize,
4075
- pageCount: Math.ceil(total / pageSize),
4076
- total
4077
- }
4516
+ pagination: pagination.transformPagedPaginationInfo(params, total)
4078
4517
  };
4079
4518
  },
4080
4519
  async create(uid2, opts = {}) {
@@ -4091,10 +4530,7 @@ const documentManager = ({ strapi: strapi2 }) => {
4091
4530
  async clone(id, body, uid2) {
4092
4531
  const populate = await buildDeepPopulate(uid2);
4093
4532
  const params = {
4094
- data: {
4095
- ...omitIdField(body),
4096
- [PUBLISHED_AT_ATTRIBUTE]: null
4097
- },
4533
+ data: omitIdField(body),
4098
4534
  populate
4099
4535
  };
4100
4536
  return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
@@ -4120,70 +4556,36 @@ const documentManager = ({ strapi: strapi2 }) => {
4120
4556
  return {};
4121
4557
  },
4122
4558
  // FIXME: handle relations
4123
- async deleteMany(opts, uid2) {
4124
- const docs = await strapi2.documents(uid2).findMany(opts);
4125
- for (const doc of docs) {
4126
- await strapi2.documents(uid2).delete({ documentId: doc.documentId });
4127
- }
4128
- return { count: docs.length };
4559
+ async deleteMany(documentIds, uid2, opts = {}) {
4560
+ const deletedEntries = await strapi2.db.transaction(async () => {
4561
+ return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
4562
+ });
4563
+ return { count: deletedEntries.length };
4129
4564
  },
4130
4565
  async publish(id, uid2, opts = {}) {
4131
4566
  const populate = await buildDeepPopulate(uid2);
4132
4567
  const params = { ...opts, populate };
4133
- return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries.at(0));
4568
+ return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
4134
4569
  },
4135
- async publishMany(entities, uid2) {
4136
- if (!entities.length) {
4137
- return null;
4138
- }
4139
- await Promise.all(
4140
- entities.map((document) => {
4141
- return strapi2.entityValidator.validateEntityCreation(
4142
- strapi2.getModel(uid2),
4143
- document,
4144
- void 0,
4145
- // @ts-expect-error - FIXME: entity here is unnecessary
4146
- document
4147
- );
4148
- })
4149
- );
4150
- const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4151
- const filters = { id: { $in: entitiesToPublish } };
4152
- const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
4153
- const populate = await buildDeepPopulate(uid2);
4154
- const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4155
- where: filters,
4156
- data
4157
- });
4158
- const publishedEntities = await strapi2.db.query(uid2).findMany({
4159
- where: filters,
4160
- populate
4570
+ async publishMany(uid2, documentIds, locale) {
4571
+ return strapi2.db.transaction(async () => {
4572
+ const results = await Promise.all(
4573
+ documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
4574
+ );
4575
+ const publishedEntitiesCount = results.flat().filter(Boolean).length;
4576
+ return publishedEntitiesCount;
4161
4577
  });
4162
- await Promise.all(
4163
- publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
4164
- );
4165
- return publishedEntitiesCount;
4166
4578
  },
4167
- async unpublishMany(documents, uid2) {
4168
- if (!documents.length) {
4169
- return null;
4170
- }
4171
- const entitiesToUnpublish = documents.filter((doc) => doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4172
- const filters = { id: { $in: entitiesToUnpublish } };
4173
- const data = { [PUBLISHED_AT_ATTRIBUTE]: null };
4174
- const populate = await buildDeepPopulate(uid2);
4175
- const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4176
- where: filters,
4177
- data
4178
- });
4179
- const unpublishedEntities = await strapi2.db.query(uid2).findMany({
4180
- where: filters,
4181
- populate
4579
+ async unpublishMany(documentIds, uid2, opts = {}) {
4580
+ const unpublishedEntries = await strapi2.db.transaction(async () => {
4581
+ return Promise.all(
4582
+ documentIds.map(
4583
+ (id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
4584
+ )
4585
+ );
4182
4586
  });
4183
- await Promise.all(
4184
- unpublishedEntities.map((doc) => emitEvent(uid2, ENTRY_UNPUBLISH, doc))
4185
- );
4186
- return unpublishedEntitiesCount;
4587
+ const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
4588
+ return { count: unpublishedEntitiesCount };
4187
4589
  },
4188
4590
  async unpublish(id, uid2, opts = {}) {
4189
4591
  const populate = await buildDeepPopulate(uid2);
@@ -4208,16 +4610,20 @@ const documentManager = ({ strapi: strapi2 }) => {
4208
4610
  }
4209
4611
  return sumDraftCounts(document, uid2);
4210
4612
  },
4211
- async countManyEntriesDraftRelations(ids, uid2, locale) {
4613
+ async countManyEntriesDraftRelations(documentIds, uid2, locale) {
4212
4614
  const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
4213
4615
  if (!hasRelations) {
4214
4616
  return 0;
4215
4617
  }
4618
+ let localeFilter = {};
4619
+ if (locale) {
4620
+ localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
4621
+ }
4216
4622
  const entities = await strapi2.db.query(uid2).findMany({
4217
4623
  populate,
4218
4624
  where: {
4219
- id: { $in: ids },
4220
- ...locale ? { locale } : {}
4625
+ documentId: { $in: documentIds },
4626
+ ...localeFilter
4221
4627
  }
4222
4628
  });
4223
4629
  const totalNumberDraftRelations = entities.reduce(
@@ -4240,7 +4646,8 @@ const services = {
4240
4646
  permission,
4241
4647
  "populate-builder": populateBuilder$1,
4242
4648
  uid,
4243
- ...history.services ? history.services : {}
4649
+ ...history.services ? history.services : {},
4650
+ ...preview.services ? preview.services : {}
4244
4651
  };
4245
4652
  const index = () => {
4246
4653
  return {