@strapi/content-manager 0.0.0-experimental.edc24aaa3bb5a90fa5fd4fee208167dd4e2e38d4 → 0.0.0-experimental.f0d4afee92a0d386f80385590c87955656f995ce

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 (171) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs → ComponentConfigurationPage-CIjXcRAB.mjs} +4 -4
  2. package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs.map → ComponentConfigurationPage-CIjXcRAB.mjs.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js → ComponentConfigurationPage-gsCd80MU.js} +4 -4
  4. package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js.map → ComponentConfigurationPage-gsCd80MU.js.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs → EditConfigurationPage-BglmD_BF.mjs} +4 -4
  6. package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs.map → EditConfigurationPage-BglmD_BF.mjs.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js → EditConfigurationPage-DHDQKBzw.js} +4 -4
  8. package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js.map → EditConfigurationPage-DHDQKBzw.js.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-C-ukDOB7.js → EditViewPage-C4iTxUPU.js} +30 -9
  10. package/dist/_chunks/EditViewPage-C4iTxUPU.js.map +1 -0
  11. package/dist/_chunks/{EditViewPage-BLsjc5F-.mjs → EditViewPage-CiwVPMaK.mjs} +30 -9
  12. package/dist/_chunks/EditViewPage-CiwVPMaK.mjs.map +1 -0
  13. package/dist/_chunks/{Field-Cs7duwWd.mjs → Field-DIjL1b5d.mjs} +173 -101
  14. package/dist/_chunks/Field-DIjL1b5d.mjs.map +1 -0
  15. package/dist/_chunks/{Field-Bfph5SOd.js → Field-DhXEK8y1.js} +175 -103
  16. package/dist/_chunks/Field-DhXEK8y1.js.map +1 -0
  17. package/dist/_chunks/{Form-Dg_GS5TQ.mjs → Form-CmNesrvR.mjs} +36 -17
  18. package/dist/_chunks/Form-CmNesrvR.mjs.map +1 -0
  19. package/dist/_chunks/{Form-CPYqIWDG.js → Form-CwmJ4sWe.js} +36 -17
  20. package/dist/_chunks/Form-CwmJ4sWe.js.map +1 -0
  21. package/dist/_chunks/{History-DNQkXANT.js → History-BLCCNgCt.js} +24 -11
  22. package/dist/_chunks/History-BLCCNgCt.js.map +1 -0
  23. package/dist/_chunks/{History-wrnHqf09.mjs → History-D-99Wh30.mjs} +25 -12
  24. package/dist/_chunks/History-D-99Wh30.mjs.map +1 -0
  25. package/dist/_chunks/{ListConfigurationPage-CUQxfpjT.js → ListConfigurationPage-DxWpeZrO.js} +15 -5
  26. package/dist/_chunks/ListConfigurationPage-DxWpeZrO.js.map +1 -0
  27. package/dist/_chunks/{ListConfigurationPage-DScmJVkW.mjs → ListConfigurationPage-JPWZz7Kg.mjs} +15 -5
  28. package/dist/_chunks/ListConfigurationPage-JPWZz7Kg.mjs.map +1 -0
  29. package/dist/_chunks/{ListViewPage-BsLiH2-2.js → ListViewPage-CIQekSFz.js} +61 -41
  30. package/dist/_chunks/ListViewPage-CIQekSFz.js.map +1 -0
  31. package/dist/_chunks/{ListViewPage-C4IvrMgY.mjs → ListViewPage-DSK3f0ST.mjs} +59 -39
  32. package/dist/_chunks/ListViewPage-DSK3f0ST.mjs.map +1 -0
  33. package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js → NoContentTypePage-C5cxKvC2.js} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js.map → NoContentTypePage-C5cxKvC2.js.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs → NoContentTypePage-D99LU1YP.mjs} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs.map → NoContentTypePage-D99LU1YP.mjs.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs → NoPermissionsPage-DBrBw-0y.mjs} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs.map → NoPermissionsPage-DBrBw-0y.mjs.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js → NoPermissionsPage-Oy4tmUrW.js} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js.map → NoPermissionsPage-Oy4tmUrW.js.map} +1 -1
  41. package/dist/_chunks/{Relations-BZr8tL0R.mjs → Relations-BBmhcWFV.mjs} +70 -37
  42. package/dist/_chunks/Relations-BBmhcWFV.mjs.map +1 -0
  43. package/dist/_chunks/{Relations-CtELXYIK.js → Relations-eG-9p_qS.js} +69 -36
  44. package/dist/_chunks/Relations-eG-9p_qS.js.map +1 -0
  45. package/dist/_chunks/{en-uOUIxfcQ.js → en-Bm0D0IWz.js} +13 -12
  46. package/dist/_chunks/{en-uOUIxfcQ.js.map → en-Bm0D0IWz.js.map} +1 -1
  47. package/dist/_chunks/{en-BrCTWlZv.mjs → en-DKV44jRb.mjs} +13 -12
  48. package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-DKV44jRb.mjs.map} +1 -1
  49. package/dist/_chunks/{index-OerGjbAN.js → index-BIWDoFLK.js} +1968 -1781
  50. package/dist/_chunks/index-BIWDoFLK.js.map +1 -0
  51. package/dist/_chunks/{index-c_5DdJi-.mjs → index-BrUzbQ30.mjs} +1987 -1801
  52. package/dist/_chunks/index-BrUzbQ30.mjs.map +1 -0
  53. package/dist/_chunks/{layout-oPBiO7RY.mjs → layout-_5-cXs34.mjs} +22 -9
  54. package/dist/_chunks/layout-_5-cXs34.mjs.map +1 -0
  55. package/dist/_chunks/{layout-Ci7qHlFb.js → layout-lMc9i1-Z.js} +21 -8
  56. package/dist/_chunks/layout-lMc9i1-Z.js.map +1 -0
  57. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  58. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  59. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  60. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  61. package/dist/_chunks/{relations-COBpStiF.js → relations-BRHithi8.js} +3 -7
  62. package/dist/_chunks/relations-BRHithi8.js.map +1 -0
  63. package/dist/_chunks/{relations-BIdWFjdq.mjs → relations-B_VLk-DD.mjs} +3 -7
  64. package/dist/_chunks/relations-B_VLk-DD.mjs.map +1 -0
  65. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  66. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  67. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  68. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  69. package/dist/admin/index.js +2 -1
  70. package/dist/admin/index.js.map +1 -1
  71. package/dist/admin/index.mjs +5 -4
  72. package/dist/admin/src/exports.d.ts +1 -1
  73. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  74. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  75. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  76. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  77. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  78. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  79. package/dist/admin/src/preview/constants.d.ts +1 -0
  80. package/dist/admin/src/preview/index.d.ts +4 -0
  81. package/dist/admin/src/services/api.d.ts +1 -1
  82. package/dist/admin/src/services/components.d.ts +2 -2
  83. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  84. package/dist/admin/src/services/documents.d.ts +19 -17
  85. package/dist/admin/src/services/init.d.ts +1 -1
  86. package/dist/admin/src/services/relations.d.ts +2 -2
  87. package/dist/admin/src/services/uid.d.ts +3 -3
  88. package/dist/admin/src/utils/validation.d.ts +4 -1
  89. package/dist/server/index.js +513 -235
  90. package/dist/server/index.js.map +1 -1
  91. package/dist/server/index.mjs +514 -236
  92. package/dist/server/index.mjs.map +1 -1
  93. package/dist/server/src/bootstrap.d.ts.map +1 -1
  94. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  95. package/dist/server/src/controllers/index.d.ts.map +1 -1
  96. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  97. package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
  98. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  99. package/dist/server/src/history/services/history.d.ts.map +1 -1
  100. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  101. package/dist/server/src/history/services/utils.d.ts +4 -4
  102. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  103. package/dist/server/src/index.d.ts +4 -4
  104. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  105. package/dist/server/src/preview/constants.d.ts +2 -0
  106. package/dist/server/src/preview/constants.d.ts.map +1 -0
  107. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  108. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  109. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  110. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  111. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  112. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  113. package/dist/server/src/preview/index.d.ts +4 -0
  114. package/dist/server/src/preview/index.d.ts.map +1 -0
  115. package/dist/server/src/preview/routes/index.d.ts +8 -0
  116. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  117. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  118. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  119. package/dist/server/src/preview/services/index.d.ts +15 -0
  120. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  121. package/dist/server/src/preview/services/preview-config.d.ts +30 -0
  122. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  123. package/dist/server/src/preview/services/preview.d.ts +12 -0
  124. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  125. package/dist/server/src/preview/utils.d.ts +18 -0
  126. package/dist/server/src/preview/utils.d.ts.map +1 -0
  127. package/dist/server/src/routes/index.d.ts.map +1 -1
  128. package/dist/server/src/services/document-metadata.d.ts +8 -8
  129. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  130. package/dist/server/src/services/index.d.ts +4 -4
  131. package/dist/server/src/services/index.d.ts.map +1 -1
  132. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  133. package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
  134. package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
  135. package/dist/server/src/utils/index.d.ts +2 -0
  136. package/dist/server/src/utils/index.d.ts.map +1 -1
  137. package/dist/shared/contracts/collection-types.d.ts +3 -1
  138. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  139. package/dist/shared/contracts/index.d.ts +1 -0
  140. package/dist/shared/contracts/index.d.ts.map +1 -1
  141. package/dist/shared/contracts/preview.d.ts +27 -0
  142. package/dist/shared/contracts/preview.d.ts.map +1 -0
  143. package/dist/shared/index.js +4 -0
  144. package/dist/shared/index.js.map +1 -1
  145. package/dist/shared/index.mjs +4 -0
  146. package/dist/shared/index.mjs.map +1 -1
  147. package/package.json +13 -13
  148. package/dist/_chunks/EditViewPage-BLsjc5F-.mjs.map +0 -1
  149. package/dist/_chunks/EditViewPage-C-ukDOB7.js.map +0 -1
  150. package/dist/_chunks/Field-Bfph5SOd.js.map +0 -1
  151. package/dist/_chunks/Field-Cs7duwWd.mjs.map +0 -1
  152. package/dist/_chunks/Form-CPYqIWDG.js.map +0 -1
  153. package/dist/_chunks/Form-Dg_GS5TQ.mjs.map +0 -1
  154. package/dist/_chunks/History-DNQkXANT.js.map +0 -1
  155. package/dist/_chunks/History-wrnHqf09.mjs.map +0 -1
  156. package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +0 -1
  157. package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +0 -1
  158. package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +0 -1
  159. package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +0 -1
  160. package/dist/_chunks/Relations-BZr8tL0R.mjs.map +0 -1
  161. package/dist/_chunks/Relations-CtELXYIK.js.map +0 -1
  162. package/dist/_chunks/index-OerGjbAN.js.map +0 -1
  163. package/dist/_chunks/index-c_5DdJi-.mjs.map +0 -1
  164. package/dist/_chunks/layout-Ci7qHlFb.js.map +0 -1
  165. package/dist/_chunks/layout-oPBiO7RY.mjs.map +0 -1
  166. package/dist/_chunks/relations-BIdWFjdq.mjs.map +0 -1
  167. package/dist/_chunks/relations-COBpStiF.js.map +0 -1
  168. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  169. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  170. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  171. package/strapi-server.js +0 -3
@@ -33,10 +33,10 @@ const isNil__default = /* @__PURE__ */ _interopDefault(isNil);
33
33
  const ___default = /* @__PURE__ */ _interopDefault(_);
34
34
  const qs__default = /* @__PURE__ */ _interopDefault(qs);
35
35
  const slugify__default = /* @__PURE__ */ _interopDefault(slugify);
36
- const getService$1 = (name) => {
36
+ const getService$2 = (name) => {
37
37
  return strapi.plugin("content-manager").service(name);
38
38
  };
39
- function getService(strapi2, name) {
39
+ function getService$1(strapi2, name) {
40
40
  return strapi2.service(`plugin::content-manager.${name}`);
41
41
  }
42
42
  const historyRestoreVersionSchema = yup__namespace.object().shape({
@@ -72,7 +72,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
72
72
  if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {
73
73
  throw new strapiUtils.errors.ForbiddenError("contentType and documentId are required");
74
74
  }
75
- const permissionChecker2 = getService$1("permission-checker").create({
75
+ const permissionChecker2 = getService$2("permission-checker").create({
76
76
  userAbility: ctx.state.userAbility,
77
77
  model: ctx.query.contentType
78
78
  });
@@ -80,7 +80,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
80
80
  return ctx.forbidden();
81
81
  }
82
82
  const query = await permissionChecker2.sanitizeQuery(ctx.query);
83
- const { results, pagination } = await getService(strapi2, "history").findVersionsPage({
83
+ const { results, pagination } = await getService$1(strapi2, "history").findVersionsPage({
84
84
  query: {
85
85
  ...query,
86
86
  ...getValidPagination({ page: query.page, pageSize: query.pageSize })
@@ -105,14 +105,14 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
105
105
  async restoreVersion(ctx) {
106
106
  const request = ctx.request;
107
107
  await validateRestoreVersion(request.body, "contentType is required");
108
- const permissionChecker2 = getService$1("permission-checker").create({
108
+ const permissionChecker2 = getService$2("permission-checker").create({
109
109
  userAbility: ctx.state.userAbility,
110
110
  model: request.body.contentType
111
111
  });
112
112
  if (permissionChecker2.cannot.update()) {
113
113
  throw new strapiUtils.errors.ForbiddenError();
114
114
  }
115
- const restoredDocument = await getService(strapi2, "history").restoreVersion(
115
+ const restoredDocument = await getService$1(strapi2, "history").restoreVersion(
116
116
  request.params.versionId
117
117
  );
118
118
  return {
@@ -121,7 +121,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
121
121
  }
122
122
  };
123
123
  };
124
- const controllers$1 = {
124
+ const controllers$2 = {
125
125
  "history-version": createHistoryVersionController
126
126
  /**
127
127
  * Casting is needed because the types aren't aware that Strapi supports
@@ -199,7 +199,9 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
199
199
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
200
200
  };
201
201
  const localesService = strapi2.plugin("i18n")?.service("locales");
202
+ const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
202
203
  const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
204
+ const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
203
205
  const getLocaleDictionary = async () => {
204
206
  if (!localesService)
205
207
  return {};
@@ -226,9 +228,21 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
226
228
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
227
229
  return documentMetadataService.getStatus(document, meta.availableStatus);
228
230
  };
229
- const getDeepPopulate2 = (uid2) => {
231
+ const getComponentFields = (componentUID) => {
232
+ return Object.entries(strapi2.getModel(componentUID).attributes).reduce(
233
+ (fieldsAcc, [key, attribute]) => {
234
+ if (!["relation", "media", "component", "dynamiczone"].includes(attribute.type)) {
235
+ fieldsAcc.push(key);
236
+ }
237
+ return fieldsAcc;
238
+ },
239
+ []
240
+ );
241
+ };
242
+ const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
230
243
  const model = strapi2.getModel(uid2);
231
244
  const attributes = Object.entries(model.attributes);
245
+ const fieldSelector = useDatabaseSyntax ? "select" : "fields";
232
246
  return attributes.reduce((acc, [attributeName, attribute]) => {
233
247
  switch (attribute.type) {
234
248
  case "relation": {
@@ -238,23 +252,29 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
238
252
  }
239
253
  const isVisible2 = strapiUtils.contentTypes.isVisibleAttribute(model, attributeName);
240
254
  if (isVisible2) {
241
- acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
255
+ acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
242
256
  }
243
257
  break;
244
258
  }
245
259
  case "media": {
246
- acc[attributeName] = { fields: ["id"] };
260
+ acc[attributeName] = { [fieldSelector]: ["id"] };
247
261
  break;
248
262
  }
249
263
  case "component": {
250
264
  const populate = getDeepPopulate2(attribute.component);
251
- acc[attributeName] = { populate };
265
+ acc[attributeName] = {
266
+ populate,
267
+ [fieldSelector]: getComponentFields(attribute.component)
268
+ };
252
269
  break;
253
270
  }
254
271
  case "dynamiczone": {
255
272
  const populatedComponents = (attribute.components || []).reduce(
256
273
  (acc2, componentUID) => {
257
- acc2[componentUID] = { populate: getDeepPopulate2(componentUID) };
274
+ acc2[componentUID] = {
275
+ populate: getDeepPopulate2(componentUID),
276
+ [fieldSelector]: getComponentFields(componentUID)
277
+ };
258
278
  return acc2;
259
279
  },
260
280
  {}
@@ -316,6 +336,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
316
336
  getRelationRestoreValue,
317
337
  getMediaRestoreValue,
318
338
  getDefaultLocale,
339
+ isLocalizedContentType,
319
340
  getLocaleDictionary,
320
341
  getRetentionDays,
321
342
  getVersionStatus,
@@ -338,7 +359,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
338
359
  });
339
360
  },
340
361
  async findVersionsPage(params) {
341
- const locale = params.query.locale || await serviceUtils.getDefaultLocale();
362
+ const model = strapi2.getModel(params.query.contentType);
363
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
364
+ const defaultLocale = await serviceUtils.getDefaultLocale();
365
+ let locale = null;
366
+ if (isLocalizedContentType) {
367
+ locale = params.query.locale || defaultLocale;
368
+ }
342
369
  const [{ results, pagination }, localeDictionary] = await Promise.all([
343
370
  query.findPage({
344
371
  ...params.query,
@@ -360,7 +387,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
360
387
  const attributeValue = entry.data[attributeKey];
361
388
  const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
362
389
  if (attributeSchema.type === "media") {
363
- const permissionChecker2 = getService$1("permission-checker").create({
390
+ const permissionChecker2 = getService$2("permission-checker").create({
364
391
  userAbility: params.state.userAbility,
365
392
  model: "plugin::upload.file"
366
393
  });
@@ -383,7 +410,12 @@ const createHistoryService = ({ strapi: strapi2 }) => {
383
410
  if (userToPopulate == null) {
384
411
  return null;
385
412
  }
386
- return strapi2.query("admin::user").findOne({ where: { id: userToPopulate.id } });
413
+ return strapi2.query("admin::user").findOne({
414
+ where: {
415
+ ...userToPopulate.id ? { id: userToPopulate.id } : {},
416
+ ...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
417
+ }
418
+ });
387
419
  })
388
420
  );
389
421
  return {
@@ -396,7 +428,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
396
428
  [attributeKey]: adminUsers
397
429
  };
398
430
  }
399
- const permissionChecker2 = getService$1("permission-checker").create({
431
+ const permissionChecker2 = getService$2("permission-checker").create({
400
432
  userAbility: params.state.userAbility,
401
433
  model: attributeSchema.target
402
434
  });
@@ -494,6 +526,42 @@ const createHistoryService = ({ strapi: strapi2 }) => {
494
526
  }
495
527
  };
496
528
  };
529
+ const shouldCreateHistoryVersion = (context) => {
530
+ if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
531
+ return false;
532
+ }
533
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
534
+ return false;
535
+ }
536
+ if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
537
+ return false;
538
+ }
539
+ if (!context.contentType.uid.startsWith("api::")) {
540
+ return false;
541
+ }
542
+ return true;
543
+ };
544
+ const getSchemas = (uid2) => {
545
+ const attributesSchema = strapi.getModel(uid2).attributes;
546
+ const componentsSchemas = Object.keys(attributesSchema).reduce(
547
+ (currentComponentSchemas, key) => {
548
+ const fieldSchema = attributesSchema[key];
549
+ if (fieldSchema.type === "component") {
550
+ const componentSchema = strapi.getModel(fieldSchema.component).attributes;
551
+ return {
552
+ ...currentComponentSchemas,
553
+ [fieldSchema.component]: componentSchema
554
+ };
555
+ }
556
+ return currentComponentSchemas;
557
+ },
558
+ {}
559
+ );
560
+ return {
561
+ schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
562
+ componentsSchemas
563
+ };
564
+ };
497
565
  const createLifecyclesService = ({ strapi: strapi2 }) => {
498
566
  const state = {
499
567
  deleteExpiredJob: null,
@@ -506,76 +574,62 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
506
574
  return;
507
575
  }
508
576
  strapi2.documents.use(async (context, next) => {
509
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
510
- return next();
511
- }
512
- if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
513
- return next();
514
- }
515
- if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
516
- return next();
517
- }
518
- const contentTypeUid = context.contentType.uid;
519
- if (!contentTypeUid.startsWith("api::")) {
520
- return next();
521
- }
522
577
  const result = await next();
523
- const documentContext = {
524
- documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
525
- locale: context.params?.locale
526
- };
578
+ if (!shouldCreateHistoryVersion(context)) {
579
+ return result;
580
+ }
581
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
527
582
  const defaultLocale = await serviceUtils.getDefaultLocale();
528
- const locale = documentContext.locale || defaultLocale;
529
- if (Array.isArray(locale)) {
530
- strapi2.log.warn(
531
- "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
532
- );
533
- return next();
583
+ const locales = fp.castArray(context.params?.locale || defaultLocale);
584
+ if (!locales.length) {
585
+ return result;
534
586
  }
535
- const document = await strapi2.documents(contentTypeUid).findOne({
536
- documentId: documentContext.documentId,
537
- locale,
538
- populate: serviceUtils.getDeepPopulate(contentTypeUid)
587
+ const uid2 = context.contentType.uid;
588
+ const schemas = getSchemas(uid2);
589
+ const model = strapi2.getModel(uid2);
590
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
591
+ const localeEntries = await strapi2.db.query(uid2).findMany({
592
+ where: {
593
+ documentId,
594
+ ...isLocalizedContentType ? { locale: { $in: locales } } : {},
595
+ ...strapiUtils.contentTypes.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
596
+ },
597
+ populate: serviceUtils.getDeepPopulate(
598
+ uid2,
599
+ true
600
+ /* use database syntax */
601
+ )
539
602
  });
540
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
541
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
542
- const componentsSchemas = Object.keys(
543
- attributesSchema
544
- ).reduce((currentComponentSchemas, key) => {
545
- const fieldSchema = attributesSchema[key];
546
- if (fieldSchema.type === "component") {
547
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
548
- return {
549
- ...currentComponentSchemas,
550
- [fieldSchema.component]: componentSchema
551
- };
552
- }
553
- return currentComponentSchemas;
554
- }, {});
555
603
  await strapi2.db.transaction(async ({ onCommit }) => {
556
- onCommit(() => {
557
- getService(strapi2, "history").createVersion({
558
- contentType: contentTypeUid,
559
- data: fp.omit(FIELDS_TO_IGNORE, document),
560
- schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
561
- componentsSchemas,
562
- relatedDocumentId: documentContext.documentId,
563
- locale,
564
- status
565
- });
604
+ onCommit(async () => {
605
+ for (const entry of localeEntries) {
606
+ const status = await serviceUtils.getVersionStatus(uid2, entry);
607
+ await getService$1(strapi2, "history").createVersion({
608
+ contentType: uid2,
609
+ data: fp.omit(FIELDS_TO_IGNORE, entry),
610
+ relatedDocumentId: documentId,
611
+ locale: entry.locale,
612
+ status,
613
+ ...schemas
614
+ });
615
+ }
566
616
  });
567
617
  });
568
618
  return result;
569
619
  });
570
- state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
620
+ state.deleteExpiredJob = nodeSchedule.scheduleJob("historyDaily", "0 0 * * *", () => {
571
621
  const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
572
622
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
573
623
  strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
574
624
  where: {
575
625
  created_at: {
576
- $lt: expirationDate.toISOString()
626
+ $lt: expirationDate
577
627
  }
578
628
  }
629
+ }).catch((error) => {
630
+ if (error instanceof Error) {
631
+ strapi2.log.error("Error deleting expired history versions", error.message);
632
+ }
579
633
  });
580
634
  });
581
635
  state.isInitialized = true;
@@ -587,17 +641,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
587
641
  }
588
642
  };
589
643
  };
590
- const services$1 = {
644
+ const services$2 = {
591
645
  history: createHistoryService,
592
646
  lifecycles: createLifecyclesService
593
647
  };
594
- const info = { pluginName: "content-manager", type: "admin" };
648
+ const info$1 = { pluginName: "content-manager", type: "admin" };
595
649
  const historyVersionRouter = {
596
650
  type: "admin",
597
651
  routes: [
598
652
  {
599
653
  method: "GET",
600
- info,
654
+ info: info$1,
601
655
  path: "/history-versions",
602
656
  handler: "history-version.findMany",
603
657
  config: {
@@ -606,7 +660,7 @@ const historyVersionRouter = {
606
660
  },
607
661
  {
608
662
  method: "PUT",
609
- info,
663
+ info: info$1,
610
664
  path: "/history-versions/:versionId/restore",
611
665
  handler: "history-version.restoreVersion",
612
666
  config: {
@@ -615,7 +669,7 @@ const historyVersionRouter = {
615
669
  }
616
670
  ]
617
671
  };
618
- const routes$1 = {
672
+ const routes$2 = {
619
673
  "history-version": historyVersionRouter
620
674
  };
621
675
  const historyVersion = {
@@ -662,21 +716,21 @@ const historyVersion = {
662
716
  }
663
717
  }
664
718
  };
665
- const getFeature = () => {
719
+ const getFeature$1 = () => {
666
720
  if (strapi.ee.features.isEnabled("cms-content-history")) {
667
721
  return {
668
722
  register({ strapi: strapi2 }) {
669
723
  strapi2.get("models").add(historyVersion);
670
724
  },
671
725
  bootstrap({ strapi: strapi2 }) {
672
- getService(strapi2, "lifecycles").bootstrap();
726
+ getService$1(strapi2, "lifecycles").bootstrap();
673
727
  },
674
728
  destroy({ strapi: strapi2 }) {
675
- getService(strapi2, "lifecycles").destroy();
729
+ getService$1(strapi2, "lifecycles").destroy();
676
730
  },
677
- controllers: controllers$1,
678
- services: services$1,
679
- routes: routes$1
731
+ controllers: controllers$2,
732
+ services: services$2,
733
+ routes: routes$2
680
734
  };
681
735
  }
682
736
  return {
@@ -685,7 +739,7 @@ const getFeature = () => {
685
739
  }
686
740
  };
687
741
  };
688
- const history = getFeature();
742
+ const history = getFeature$1();
689
743
  const register = async ({ strapi: strapi2 }) => {
690
744
  await history.register?.({ strapi: strapi2 });
691
745
  };
@@ -693,15 +747,165 @@ const ALLOWED_WEBHOOK_EVENTS = {
693
747
  ENTRY_PUBLISH: "entry.publish",
694
748
  ENTRY_UNPUBLISH: "entry.unpublish"
695
749
  };
750
+ const FEATURE_ID = "preview";
751
+ const info = { pluginName: "content-manager", type: "admin" };
752
+ const previewRouter = {
753
+ type: "admin",
754
+ routes: [
755
+ {
756
+ method: "GET",
757
+ info,
758
+ path: "/preview/url/:contentType",
759
+ handler: "preview.getPreviewUrl",
760
+ config: {
761
+ policies: ["admin::isAuthenticatedAdmin"]
762
+ }
763
+ }
764
+ ]
765
+ };
766
+ const routes$1 = {
767
+ preview: previewRouter
768
+ };
769
+ function getService(strapi2, name) {
770
+ return strapi2.service(`plugin::content-manager.${name}`);
771
+ }
772
+ const getPreviewUrlSchema = yup__namespace.object().shape({
773
+ // Will be undefined for single types
774
+ documentId: yup__namespace.string(),
775
+ locale: yup__namespace.string().nullable(),
776
+ status: yup__namespace.string()
777
+ }).required();
778
+ const validatePreviewUrl = async (strapi2, uid2, params) => {
779
+ await strapiUtils.validateYupSchema(getPreviewUrlSchema)(params);
780
+ const newParams = fp.pick(["documentId", "locale", "status"], params);
781
+ const model = strapi2.getModel(uid2);
782
+ if (!model || model.modelType !== "contentType") {
783
+ throw new strapiUtils.errors.ValidationError("Invalid content type");
784
+ }
785
+ const isSingleType = model?.kind === "singleType";
786
+ if (!isSingleType && !params.documentId) {
787
+ throw new strapiUtils.errors.ValidationError("documentId is required for Collection Types");
788
+ }
789
+ if (isSingleType) {
790
+ const doc = await strapi2.documents(uid2).findFirst();
791
+ if (!doc) {
792
+ throw new strapiUtils.errors.NotFoundError("Document not found");
793
+ }
794
+ newParams.documentId = doc?.documentId;
795
+ }
796
+ return newParams;
797
+ };
798
+ const createPreviewController = () => {
799
+ return {
800
+ /**
801
+ * Transforms an entry into a preview URL, so that it can be previewed
802
+ * in the Content Manager.
803
+ */
804
+ async getPreviewUrl(ctx) {
805
+ const uid2 = ctx.params.contentType;
806
+ const query = ctx.request.query;
807
+ const params = await validatePreviewUrl(strapi, uid2, query);
808
+ const previewService = getService(strapi, "preview");
809
+ const url = await previewService.getPreviewUrl(uid2, params);
810
+ if (!url) {
811
+ ctx.status = 204;
812
+ }
813
+ return {
814
+ data: { url }
815
+ };
816
+ }
817
+ };
818
+ };
819
+ const controllers$1 = {
820
+ preview: createPreviewController
821
+ /**
822
+ * Casting is needed because the types aren't aware that Strapi supports
823
+ * passing a controller factory as the value, instead of a controller object directly
824
+ */
825
+ };
826
+ const createPreviewService = ({ strapi: strapi2 }) => {
827
+ const config = getService(strapi2, "preview-config");
828
+ return {
829
+ async getPreviewUrl(uid2, params) {
830
+ const handler = config.getPreviewHandler();
831
+ try {
832
+ return handler(uid2, params);
833
+ } catch (error) {
834
+ strapi2.log.error(`Failed to get preview URL: ${error}`);
835
+ throw new strapiUtils.errors.ApplicationError("Failed to get preview URL");
836
+ }
837
+ return;
838
+ }
839
+ };
840
+ };
841
+ const createPreviewConfigService = ({ strapi: strapi2 }) => {
842
+ return {
843
+ isEnabled() {
844
+ const config = strapi2.config.get("admin.preview");
845
+ if (!config) {
846
+ return false;
847
+ }
848
+ return config?.enabled ?? true;
849
+ },
850
+ /**
851
+ * Validate if the configuration is valid
852
+ */
853
+ validate() {
854
+ if (!this.isEnabled()) {
855
+ return;
856
+ }
857
+ const handler = this.getPreviewHandler();
858
+ if (typeof handler !== "function") {
859
+ throw new strapiUtils.errors.ValidationError(
860
+ "Preview configuration is invalid. Handler must be a function"
861
+ );
862
+ }
863
+ },
864
+ /**
865
+ * Utility to get the preview handler from the configuration
866
+ */
867
+ getPreviewHandler() {
868
+ const config = strapi2.config.get("admin.preview");
869
+ const emptyHandler = () => {
870
+ return void 0;
871
+ };
872
+ if (!this.isEnabled()) {
873
+ return emptyHandler;
874
+ }
875
+ return config?.config?.handler || emptyHandler;
876
+ }
877
+ };
878
+ };
879
+ const services$1 = {
880
+ preview: createPreviewService,
881
+ "preview-config": createPreviewConfigService
882
+ };
883
+ const getFeature = () => {
884
+ if (!strapi.features.future.isEnabled(FEATURE_ID)) {
885
+ return {};
886
+ }
887
+ return {
888
+ bootstrap() {
889
+ console.log("Bootstrapping preview server");
890
+ const config = getService(strapi, "preview-config");
891
+ config.validate();
892
+ },
893
+ routes: routes$1,
894
+ controllers: controllers$1,
895
+ services: services$1
896
+ };
897
+ };
898
+ const preview = getFeature();
696
899
  const bootstrap = async () => {
697
900
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
698
901
  strapi.get("webhookStore").addAllowedEvent(key, value);
699
902
  });
700
- getService$1("field-sizes").setCustomFieldInputSizes();
701
- await getService$1("components").syncConfigurations();
702
- await getService$1("content-types").syncConfigurations();
703
- await getService$1("permission").registerPermissions();
903
+ getService$2("field-sizes").setCustomFieldInputSizes();
904
+ await getService$2("components").syncConfigurations();
905
+ await getService$2("content-types").syncConfigurations();
906
+ await getService$2("permission").registerPermissions();
704
907
  await history.bootstrap?.({ strapi });
908
+ await preview.bootstrap?.({ strapi });
705
909
  };
706
910
  const destroy = async ({ strapi: strapi2 }) => {
707
911
  await history.destroy?.({ strapi: strapi2 });
@@ -1191,7 +1395,8 @@ const admin = {
1191
1395
  };
1192
1396
  const routes = {
1193
1397
  admin,
1194
- ...history.routes ? history.routes : {}
1398
+ ...history.routes ? history.routes : {},
1399
+ ...preview.routes ? preview.routes : {}
1195
1400
  };
1196
1401
  const hasPermissionsSchema = strapiUtils.yup.object({
1197
1402
  actions: strapiUtils.yup.array().of(strapiUtils.yup.string()),
@@ -1202,6 +1407,11 @@ const { createPolicy } = strapiUtils.policy;
1202
1407
  const hasPermissions = createPolicy({
1203
1408
  name: "plugin::content-manager.hasPermissions",
1204
1409
  validator: validateHasPermissionsInput,
1410
+ /**
1411
+ * NOTE: Action aliases are currently not checked at this level (policy).
1412
+ * This is currently the intended behavior to avoid changing the behavior of API related permissions.
1413
+ * If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
1414
+ */
1205
1415
  handler(ctx, config = {}) {
1206
1416
  const { actions = [], hasAtLeastOne = false } = config;
1207
1417
  const { userAbility } = ctx.state;
@@ -1443,7 +1653,7 @@ const createMetadasSchema = (schema) => {
1443
1653
  if (!value) {
1444
1654
  return strapiUtils.yup.string();
1445
1655
  }
1446
- const targetSchema = getService$1("content-types").findContentType(
1656
+ const targetSchema = getService$2("content-types").findContentType(
1447
1657
  schema.attributes[key].targetModel
1448
1658
  );
1449
1659
  if (!targetSchema) {
@@ -1612,7 +1822,7 @@ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultiple
1612
1822
  }
1613
1823
  };
1614
1824
  const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1615
- const documentMetadata2 = getService$1("document-metadata");
1825
+ const documentMetadata2 = getService$2("document-metadata");
1616
1826
  const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1617
1827
  let {
1618
1828
  meta: { availableLocales, availableStatus }
@@ -1638,8 +1848,8 @@ const createDocument = async (ctx, opts) => {
1638
1848
  const { userAbility, user } = ctx.state;
1639
1849
  const { model } = ctx.params;
1640
1850
  const { body } = ctx.request;
1641
- const documentManager2 = getService$1("document-manager");
1642
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1851
+ const documentManager2 = getService$2("document-manager");
1852
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1643
1853
  if (permissionChecker2.cannot.create()) {
1644
1854
  throw new strapiUtils.errors.ForbiddenError();
1645
1855
  }
@@ -1659,13 +1869,13 @@ const updateDocument = async (ctx, opts) => {
1659
1869
  const { userAbility, user } = ctx.state;
1660
1870
  const { id, model } = ctx.params;
1661
1871
  const { body } = ctx.request;
1662
- const documentManager2 = getService$1("document-manager");
1663
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1872
+ const documentManager2 = getService$2("document-manager");
1873
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1664
1874
  if (permissionChecker2.cannot.update()) {
1665
1875
  throw new strapiUtils.errors.ForbiddenError();
1666
1876
  }
1667
1877
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1668
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1878
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1669
1879
  const { locale } = await getDocumentLocaleAndStatus(body, model);
1670
1880
  const [documentVersion, documentExists] = await Promise.all([
1671
1881
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
@@ -1682,7 +1892,7 @@ const updateDocument = async (ctx, opts) => {
1682
1892
  throw new strapiUtils.errors.ForbiddenError();
1683
1893
  }
1684
1894
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1685
- const setCreator = strapiUtils.setCreatorFields({ user, isEdition: true });
1895
+ const setCreator = documentVersion ? strapiUtils.setCreatorFields({ user, isEdition: true }) : strapiUtils.setCreatorFields({ user });
1686
1896
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1687
1897
  const sanitizedBody = await sanitizeFn(body);
1688
1898
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1696,14 +1906,14 @@ const collectionTypes = {
1696
1906
  const { userAbility } = ctx.state;
1697
1907
  const { model } = ctx.params;
1698
1908
  const { query } = ctx.request;
1699
- const documentMetadata2 = getService$1("document-metadata");
1700
- const documentManager2 = getService$1("document-manager");
1701
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1909
+ const documentMetadata2 = getService$2("document-metadata");
1910
+ const documentManager2 = getService$2("document-manager");
1911
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1702
1912
  if (permissionChecker2.cannot.read()) {
1703
1913
  return ctx.forbidden();
1704
1914
  }
1705
1915
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1706
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1916
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1707
1917
  const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1708
1918
  const { results: documents, pagination } = await documentManager2.findPage(
1709
1919
  { ...permissionQuery, populate, locale, status },
@@ -1732,13 +1942,13 @@ const collectionTypes = {
1732
1942
  async findOne(ctx) {
1733
1943
  const { userAbility } = ctx.state;
1734
1944
  const { model, id } = ctx.params;
1735
- const documentManager2 = getService$1("document-manager");
1736
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1945
+ const documentManager2 = getService$2("document-manager");
1946
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1737
1947
  if (permissionChecker2.cannot.read()) {
1738
1948
  return ctx.forbidden();
1739
1949
  }
1740
1950
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1741
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1951
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1742
1952
  const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1743
1953
  const version = await documentManager2.findOne(id, model, {
1744
1954
  populate,
@@ -1754,7 +1964,7 @@ const collectionTypes = {
1754
1964
  permissionChecker2,
1755
1965
  model,
1756
1966
  // @ts-expect-error TODO: fix
1757
- { id, locale, publishedAt: null },
1967
+ { documentId: id, locale, publishedAt: null },
1758
1968
  { availableLocales: true, availableStatus: false }
1759
1969
  );
1760
1970
  ctx.body = { data: {}, meta };
@@ -1769,7 +1979,7 @@ const collectionTypes = {
1769
1979
  async create(ctx) {
1770
1980
  const { userAbility } = ctx.state;
1771
1981
  const { model } = ctx.params;
1772
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1982
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1773
1983
  const [totalEntries, document] = await Promise.all([
1774
1984
  strapi.db.query(model).count(),
1775
1985
  createDocument(ctx)
@@ -1790,7 +2000,7 @@ const collectionTypes = {
1790
2000
  async update(ctx) {
1791
2001
  const { userAbility } = ctx.state;
1792
2002
  const { model } = ctx.params;
1793
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2003
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1794
2004
  const updatedVersion = await updateDocument(ctx);
1795
2005
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1796
2006
  ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
@@ -1799,13 +2009,13 @@ const collectionTypes = {
1799
2009
  const { userAbility, user } = ctx.state;
1800
2010
  const { model, sourceId: id } = ctx.params;
1801
2011
  const { body } = ctx.request;
1802
- const documentManager2 = getService$1("document-manager");
1803
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2012
+ const documentManager2 = getService$2("document-manager");
2013
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1804
2014
  if (permissionChecker2.cannot.create()) {
1805
2015
  return ctx.forbidden();
1806
2016
  }
1807
2017
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1808
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2018
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1809
2019
  const { locale } = await getDocumentLocaleAndStatus(body, model);
1810
2020
  const document = await documentManager2.findOne(id, model, {
1811
2021
  populate,
@@ -1844,13 +2054,13 @@ const collectionTypes = {
1844
2054
  async delete(ctx) {
1845
2055
  const { userAbility } = ctx.state;
1846
2056
  const { id, model } = ctx.params;
1847
- const documentManager2 = getService$1("document-manager");
1848
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2057
+ const documentManager2 = getService$2("document-manager");
2058
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1849
2059
  if (permissionChecker2.cannot.delete()) {
1850
2060
  return ctx.forbidden();
1851
2061
  }
1852
2062
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1853
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2063
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1854
2064
  const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1855
2065
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1856
2066
  if (documentLocales.length === 0) {
@@ -1872,19 +2082,42 @@ const collectionTypes = {
1872
2082
  const { userAbility } = ctx.state;
1873
2083
  const { id, model } = ctx.params;
1874
2084
  const { body } = ctx.request;
1875
- const documentManager2 = getService$1("document-manager");
1876
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2085
+ const documentManager2 = getService$2("document-manager");
2086
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1877
2087
  if (permissionChecker2.cannot.publish()) {
1878
2088
  return ctx.forbidden();
1879
2089
  }
1880
2090
  const publishedDocument = await strapi.db.transaction(async () => {
1881
2091
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1882
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1883
- const document = id ? await updateDocument(ctx, { populate }) : await createDocument(ctx, { populate });
2092
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2093
+ let document;
2094
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2095
+ const isCreate = fp.isNil(id);
2096
+ if (isCreate) {
2097
+ if (permissionChecker2.cannot.create()) {
2098
+ throw new strapiUtils.errors.ForbiddenError();
2099
+ }
2100
+ document = await createDocument(ctx, { populate });
2101
+ }
2102
+ const isUpdate = !isCreate;
2103
+ if (isUpdate) {
2104
+ const documentExists = documentManager2.exists(model, id);
2105
+ if (!documentExists) {
2106
+ throw new strapiUtils.errors.NotFoundError("Document not found");
2107
+ }
2108
+ document = await documentManager2.findOne(id, model, { populate, locale });
2109
+ if (!document) {
2110
+ if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
2111
+ throw new strapiUtils.errors.ForbiddenError();
2112
+ }
2113
+ document = await updateDocument(ctx);
2114
+ } else if (permissionChecker2.can.update(document)) {
2115
+ await updateDocument(ctx);
2116
+ }
2117
+ }
1884
2118
  if (permissionChecker2.cannot.publish(document)) {
1885
2119
  throw new strapiUtils.errors.ForbiddenError();
1886
2120
  }
1887
- const { locale } = await getDocumentLocaleAndStatus(body, model);
1888
2121
  const publishResult = await documentManager2.publish(document.documentId, model, {
1889
2122
  locale
1890
2123
  // TODO: Allow setting creator fields on publish
@@ -1904,13 +2137,13 @@ const collectionTypes = {
1904
2137
  const { body } = ctx.request;
1905
2138
  const { documentIds } = body;
1906
2139
  await validateBulkActionInput(body);
1907
- const documentManager2 = getService$1("document-manager");
1908
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2140
+ const documentManager2 = getService$2("document-manager");
2141
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1909
2142
  if (permissionChecker2.cannot.publish()) {
1910
2143
  return ctx.forbidden();
1911
2144
  }
1912
2145
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1913
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2146
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1914
2147
  const { locale } = await getDocumentLocaleAndStatus(body, model, {
1915
2148
  allowMultipleLocales: true
1916
2149
  });
@@ -1935,12 +2168,14 @@ const collectionTypes = {
1935
2168
  const { body } = ctx.request;
1936
2169
  const { documentIds } = body;
1937
2170
  await validateBulkActionInput(body);
1938
- const documentManager2 = getService$1("document-manager");
1939
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2171
+ const documentManager2 = getService$2("document-manager");
2172
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1940
2173
  if (permissionChecker2.cannot.unpublish()) {
1941
2174
  return ctx.forbidden();
1942
2175
  }
1943
- const { locale } = await getDocumentLocaleAndStatus(body, model);
2176
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2177
+ allowMultipleLocales: true
2178
+ });
1944
2179
  const entityPromises = documentIds.map(
1945
2180
  (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1946
2181
  );
@@ -1963,8 +2198,8 @@ const collectionTypes = {
1963
2198
  const {
1964
2199
  body: { discardDraft, ...body }
1965
2200
  } = ctx.request;
1966
- const documentManager2 = getService$1("document-manager");
1967
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2201
+ const documentManager2 = getService$2("document-manager");
2202
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1968
2203
  if (permissionChecker2.cannot.unpublish()) {
1969
2204
  return ctx.forbidden();
1970
2205
  }
@@ -1972,7 +2207,7 @@ const collectionTypes = {
1972
2207
  return ctx.forbidden();
1973
2208
  }
1974
2209
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1975
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2210
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1976
2211
  const { locale } = await getDocumentLocaleAndStatus(body, model);
1977
2212
  const document = await documentManager2.findOne(id, model, {
1978
2213
  populate,
@@ -2003,13 +2238,13 @@ const collectionTypes = {
2003
2238
  const { userAbility } = ctx.state;
2004
2239
  const { id, model } = ctx.params;
2005
2240
  const { body } = ctx.request;
2006
- const documentManager2 = getService$1("document-manager");
2007
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2241
+ const documentManager2 = getService$2("document-manager");
2242
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2008
2243
  if (permissionChecker2.cannot.discard()) {
2009
2244
  return ctx.forbidden();
2010
2245
  }
2011
2246
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
2012
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2247
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2013
2248
  const { locale } = await getDocumentLocaleAndStatus(body, model);
2014
2249
  const document = await documentManager2.findOne(id, model, {
2015
2250
  populate,
@@ -2034,13 +2269,13 @@ const collectionTypes = {
2034
2269
  const { query, body } = ctx.request;
2035
2270
  const { documentIds } = body;
2036
2271
  await validateBulkActionInput(body);
2037
- const documentManager2 = getService$1("document-manager");
2038
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2272
+ const documentManager2 = getService$2("document-manager");
2273
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2039
2274
  if (permissionChecker2.cannot.delete()) {
2040
2275
  return ctx.forbidden();
2041
2276
  }
2042
2277
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
2043
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2278
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2044
2279
  const { locale } = await getDocumentLocaleAndStatus(body, model);
2045
2280
  const documentLocales = await documentManager2.findLocales(documentIds, model, {
2046
2281
  populate,
@@ -2061,13 +2296,13 @@ const collectionTypes = {
2061
2296
  async countDraftRelations(ctx) {
2062
2297
  const { userAbility } = ctx.state;
2063
2298
  const { model, id } = ctx.params;
2064
- const documentManager2 = getService$1("document-manager");
2065
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2299
+ const documentManager2 = getService$2("document-manager");
2300
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2066
2301
  if (permissionChecker2.cannot.read()) {
2067
2302
  return ctx.forbidden();
2068
2303
  }
2069
2304
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2070
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2305
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2071
2306
  const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
2072
2307
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2073
2308
  if (!entity) {
@@ -2086,8 +2321,8 @@ const collectionTypes = {
2086
2321
  const ids = ctx.request.query.documentIds;
2087
2322
  const locale = ctx.request.query.locale;
2088
2323
  const { model } = ctx.params;
2089
- const documentManager2 = getService$1("document-manager");
2090
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2324
+ const documentManager2 = getService$2("document-manager");
2325
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2091
2326
  if (permissionChecker2.cannot.read()) {
2092
2327
  return ctx.forbidden();
2093
2328
  }
@@ -2111,13 +2346,13 @@ const collectionTypes = {
2111
2346
  };
2112
2347
  const components$1 = {
2113
2348
  findComponents(ctx) {
2114
- const components2 = getService$1("components").findAllComponents();
2115
- const { toDto } = getService$1("data-mapper");
2349
+ const components2 = getService$2("components").findAllComponents();
2350
+ const { toDto } = getService$2("data-mapper");
2116
2351
  ctx.body = { data: components2.map(toDto) };
2117
2352
  },
2118
2353
  async findComponentConfiguration(ctx) {
2119
2354
  const { uid: uid2 } = ctx.params;
2120
- const componentService = getService$1("components");
2355
+ const componentService = getService$2("components");
2121
2356
  const component = componentService.findComponent(uid2);
2122
2357
  if (!component) {
2123
2358
  return ctx.notFound("component.notFound");
@@ -2134,7 +2369,7 @@ const components$1 = {
2134
2369
  async updateComponentConfiguration(ctx) {
2135
2370
  const { uid: uid2 } = ctx.params;
2136
2371
  const { body } = ctx.request;
2137
- const componentService = getService$1("components");
2372
+ const componentService = getService$2("components");
2138
2373
  const component = componentService.findComponent(uid2);
2139
2374
  if (!component) {
2140
2375
  return ctx.notFound("component.notFound");
@@ -2168,12 +2403,12 @@ const contentTypes = {
2168
2403
  } catch (error) {
2169
2404
  return ctx.send({ error }, 400);
2170
2405
  }
2171
- const contentTypes2 = getService$1("content-types").findContentTypesByKind(kind);
2172
- const { toDto } = getService$1("data-mapper");
2406
+ const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
2407
+ const { toDto } = getService$2("data-mapper");
2173
2408
  ctx.body = { data: contentTypes2.map(toDto) };
2174
2409
  },
2175
2410
  async findContentTypesSettings(ctx) {
2176
- const { findAllContentTypes, findConfiguration } = getService$1("content-types");
2411
+ const { findAllContentTypes, findConfiguration } = getService$2("content-types");
2177
2412
  const contentTypes2 = await findAllContentTypes();
2178
2413
  const configurations = await Promise.all(
2179
2414
  contentTypes2.map(async (contentType) => {
@@ -2187,7 +2422,7 @@ const contentTypes = {
2187
2422
  },
2188
2423
  async findContentTypeConfiguration(ctx) {
2189
2424
  const { uid: uid2 } = ctx.params;
2190
- const contentTypeService = getService$1("content-types");
2425
+ const contentTypeService = getService$2("content-types");
2191
2426
  const contentType = await contentTypeService.findContentType(uid2);
2192
2427
  if (!contentType) {
2193
2428
  return ctx.notFound("contentType.notFound");
@@ -2209,13 +2444,13 @@ const contentTypes = {
2209
2444
  const { userAbility } = ctx.state;
2210
2445
  const { uid: uid2 } = ctx.params;
2211
2446
  const { body } = ctx.request;
2212
- const contentTypeService = getService$1("content-types");
2213
- const metricsService = getService$1("metrics");
2447
+ const contentTypeService = getService$2("content-types");
2448
+ const metricsService = getService$2("metrics");
2214
2449
  const contentType = await contentTypeService.findContentType(uid2);
2215
2450
  if (!contentType) {
2216
2451
  return ctx.notFound("contentType.notFound");
2217
2452
  }
2218
- if (!getService$1("permission").canConfigureContentType({ userAbility, contentType })) {
2453
+ if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
2219
2454
  return ctx.forbidden();
2220
2455
  }
2221
2456
  let input;
@@ -2248,10 +2483,10 @@ const contentTypes = {
2248
2483
  };
2249
2484
  const init = {
2250
2485
  getInitData(ctx) {
2251
- const { toDto } = getService$1("data-mapper");
2252
- const { findAllComponents } = getService$1("components");
2253
- const { getAllFieldSizes } = getService$1("field-sizes");
2254
- const { findAllContentTypes } = getService$1("content-types");
2486
+ const { toDto } = getService$2("data-mapper");
2487
+ const { findAllComponents } = getService$2("components");
2488
+ const { getAllFieldSizes } = getService$2("field-sizes");
2489
+ const { findAllContentTypes } = getService$2("content-types");
2255
2490
  ctx.body = {
2256
2491
  data: {
2257
2492
  fieldSizes: getAllFieldSizes(),
@@ -2287,36 +2522,41 @@ const addFiltersClause = (params, filtersClause) => {
2287
2522
  params.filters.$and.push(filtersClause);
2288
2523
  };
2289
2524
  const sanitizeMainField = (model, mainField, userAbility) => {
2290
- const permissionChecker2 = getService$1("permission-checker").create({
2525
+ const permissionChecker2 = getService$2("permission-checker").create({
2291
2526
  userAbility,
2292
2527
  model: model.uid
2293
2528
  });
2294
- if (!isListable(model, mainField)) {
2529
+ const isMainFieldListable = isListable(model, mainField);
2530
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2531
+ if (!isMainFieldListable || !canReadMainField) {
2295
2532
  return "id";
2296
2533
  }
2297
- if (permissionChecker2.cannot.read(null, mainField)) {
2298
- if (model.uid === "plugin::users-permissions.role") {
2299
- const userPermissionChecker = getService$1("permission-checker").create({
2300
- userAbility,
2301
- model: "plugin::users-permissions.user"
2302
- });
2303
- if (userPermissionChecker.can.read()) {
2304
- return "name";
2305
- }
2306
- }
2307
- return "id";
2534
+ if (model.uid === "plugin::users-permissions.role") {
2535
+ return "name";
2308
2536
  }
2309
2537
  return mainField;
2310
2538
  };
2311
- const addStatusToRelations = async (uid2, relations2) => {
2312
- if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.contentTypes[uid2])) {
2539
+ const addStatusToRelations = async (targetUid, relations2) => {
2540
+ if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(targetUid))) {
2541
+ return relations2;
2542
+ }
2543
+ const documentMetadata2 = getService$2("document-metadata");
2544
+ if (!relations2.length) {
2313
2545
  return relations2;
2314
2546
  }
2315
- const documentMetadata2 = getService$1("document-metadata");
2316
- const documentsAvailableStatus = await documentMetadata2.getManyAvailableStatus(uid2, relations2);
2547
+ const firstRelation = relations2[0];
2548
+ const filters = {
2549
+ documentId: { $in: relations2.map((r) => r.documentId) },
2550
+ // NOTE: find the "opposite" status
2551
+ publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
2552
+ };
2553
+ const availableStatus = await strapi.query(targetUid).findMany({
2554
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
2555
+ filters
2556
+ });
2317
2557
  return relations2.map((relation) => {
2318
- const availableStatuses = documentsAvailableStatus.filter(
2319
- (availableDocument) => availableDocument.documentId === relation.documentId
2558
+ const availableStatuses = availableStatus.filter(
2559
+ (availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
2320
2560
  );
2321
2561
  return {
2322
2562
  ...relation,
@@ -2337,11 +2577,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2337
2577
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2338
2578
  const isSourceLocalized = isLocalized(sourceModel);
2339
2579
  const isTargetLocalized = isLocalized(targetModel);
2340
- let validatedLocale = locale;
2341
- if (!targetModel || !isTargetLocalized)
2342
- validatedLocale = void 0;
2343
2580
  return {
2344
- locale: validatedLocale,
2581
+ locale,
2345
2582
  isSourceLocalized,
2346
2583
  isTargetLocalized
2347
2584
  };
@@ -2381,7 +2618,7 @@ const relations = {
2381
2618
  ctx.request?.query?.locale
2382
2619
  );
2383
2620
  const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
2384
- const permissionChecker2 = getService$1("permission-checker").create({
2621
+ const permissionChecker2 = getService$2("permission-checker").create({
2385
2622
  userAbility,
2386
2623
  model
2387
2624
  });
@@ -2406,7 +2643,7 @@ const relations = {
2406
2643
  where.id = id;
2407
2644
  }
2408
2645
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2409
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2646
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2410
2647
  const currentEntity = await strapi.db.query(model).findOne({
2411
2648
  where,
2412
2649
  populate
@@ -2421,7 +2658,7 @@ const relations = {
2421
2658
  }
2422
2659
  entryId = currentEntity.id;
2423
2660
  }
2424
- const modelConfig = isComponent2 ? await getService$1("components").findConfiguration(sourceSchema) : await getService$1("content-types").findConfiguration(sourceSchema);
2661
+ const modelConfig = isComponent2 ? await getService$2("components").findConfiguration(sourceSchema) : await getService$2("content-types").findConfiguration(sourceSchema);
2425
2662
  const targetSchema = strapi.getModel(targetUid);
2426
2663
  const mainField = fp.flow(
2427
2664
  fp.prop(`metadatas.${targetField}.edit.mainField`),
@@ -2444,7 +2681,7 @@ const relations = {
2444
2681
  attribute,
2445
2682
  fieldsToSelect,
2446
2683
  mainField,
2447
- source: { schema: sourceSchema },
2684
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2448
2685
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2449
2686
  sourceSchema,
2450
2687
  targetSchema,
@@ -2466,7 +2703,8 @@ const relations = {
2466
2703
  fieldsToSelect,
2467
2704
  mainField,
2468
2705
  source: {
2469
- schema: { uid: sourceUid, modelType: sourceModelType }
2706
+ schema: { uid: sourceUid, modelType: sourceModelType },
2707
+ isLocalized: isSourceLocalized
2470
2708
  },
2471
2709
  target: {
2472
2710
  schema: { uid: targetUid },
@@ -2474,7 +2712,7 @@ const relations = {
2474
2712
  }
2475
2713
  } = await this.extractAndValidateRequestInfo(ctx, id);
2476
2714
  const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
2477
- const permissionChecker2 = getService$1("permission-checker").create({
2715
+ const permissionChecker2 = getService$2("permission-checker").create({
2478
2716
  userAbility: ctx.state.userAbility,
2479
2717
  model: targetUid
2480
2718
  });
@@ -2504,12 +2742,16 @@ const relations = {
2504
2742
  } else {
2505
2743
  where.id = id;
2506
2744
  }
2507
- if (status) {
2508
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2745
+ const publishedAt = getPublishedAtClause(status, targetUid);
2746
+ if (!fp.isEmpty(publishedAt)) {
2747
+ where[`${alias}.published_at`] = publishedAt;
2509
2748
  }
2510
- if (filterByLocale) {
2749
+ if (isTargetLocalized && locale) {
2511
2750
  where[`${alias}.locale`] = locale;
2512
2751
  }
2752
+ if (isSourceLocalized && locale) {
2753
+ where.locale = locale;
2754
+ }
2513
2755
  if ((idsToInclude?.length ?? 0) !== 0) {
2514
2756
  where[`${alias}.id`].$notIn = idsToInclude;
2515
2757
  }
@@ -2527,7 +2769,8 @@ const relations = {
2527
2769
  id: { $notIn: fp.uniq(idsToOmit) }
2528
2770
  });
2529
2771
  }
2530
- const res = await strapi.db.query(targetUid).findPage(strapi.get("query-params").transform(targetUid, queryParams));
2772
+ const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
2773
+ const res = await strapi.db.query(targetUid).findPage(dbQuery);
2531
2774
  ctx.body = {
2532
2775
  ...res,
2533
2776
  results: await addStatusToRelations(targetUid, res.results)
@@ -2542,29 +2785,39 @@ const relations = {
2542
2785
  attribute,
2543
2786
  targetField,
2544
2787
  fieldsToSelect,
2545
- source: {
2546
- schema: { uid: sourceUid }
2547
- },
2548
- target: {
2549
- schema: { uid: targetUid }
2550
- }
2788
+ status,
2789
+ source: { schema: sourceSchema },
2790
+ target: { schema: targetSchema }
2551
2791
  } = await this.extractAndValidateRequestInfo(ctx, id);
2552
- const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2792
+ const { uid: sourceUid } = sourceSchema;
2793
+ const { uid: targetUid } = targetSchema;
2794
+ const permissionQuery = await getService$2("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2553
2795
  const dbQuery = strapi.db.query(sourceUid);
2554
2796
  const loadRelations = strapiUtils.relations.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
2797
+ const filters = {};
2798
+ if (sourceSchema?.options?.draftAndPublish) {
2799
+ if (targetSchema?.options?.draftAndPublish) {
2800
+ if (status === "published") {
2801
+ filters.publishedAt = { $notNull: true };
2802
+ } else {
2803
+ filters.publishedAt = { $null: true };
2804
+ }
2805
+ }
2806
+ } else if (targetSchema?.options?.draftAndPublish) {
2807
+ filters.publishedAt = { $null: true };
2808
+ }
2555
2809
  const res = await loadRelations({ id: entryId }, targetField, {
2556
- select: ["id", "documentId", "locale", "publishedAt"],
2810
+ select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
2557
2811
  ordering: "desc",
2558
2812
  page: ctx.request.query.page,
2559
- pageSize: ctx.request.query.pageSize
2813
+ pageSize: ctx.request.query.pageSize,
2814
+ filters
2560
2815
  });
2561
2816
  const loadedIds = res.results.map((item) => item.id);
2562
2817
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2563
2818
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2564
2819
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2565
- ordering: "desc",
2566
- page: ctx.request.query.page,
2567
- pageSize: ctx.request.query.pageSize
2820
+ ordering: "desc"
2568
2821
  });
2569
2822
  const relationsUnion = fp.uniqBy("id", fp.concat(sanitizedRes.results, res.results));
2570
2823
  ctx.body = {
@@ -2579,10 +2832,10 @@ const relations = {
2579
2832
  }
2580
2833
  };
2581
2834
  const buildPopulateFromQuery = async (query, model) => {
2582
- return getService$1("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2835
+ return getService$2("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2583
2836
  };
2584
2837
  const findDocument = async (query, uid2, opts = {}) => {
2585
- const documentManager2 = getService$1("document-manager");
2838
+ const documentManager2 = getService$2("document-manager");
2586
2839
  const populate = await buildPopulateFromQuery(query, uid2);
2587
2840
  return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
2588
2841
  };
@@ -2590,8 +2843,8 @@ const createOrUpdateDocument = async (ctx, opts) => {
2590
2843
  const { user, userAbility } = ctx.state;
2591
2844
  const { model } = ctx.params;
2592
2845
  const { body, query } = ctx.request;
2593
- const documentManager2 = getService$1("document-manager");
2594
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2846
+ const documentManager2 = getService$2("document-manager");
2847
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2595
2848
  if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
2596
2849
  throw new strapiUtils.errors.ForbiddenError();
2597
2850
  }
@@ -2632,7 +2885,7 @@ const singleTypes = {
2632
2885
  const { userAbility } = ctx.state;
2633
2886
  const { model } = ctx.params;
2634
2887
  const { query = {} } = ctx.request;
2635
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2888
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2636
2889
  if (permissionChecker2.cannot.read()) {
2637
2890
  return ctx.forbidden();
2638
2891
  }
@@ -2651,7 +2904,7 @@ const singleTypes = {
2651
2904
  permissionChecker2,
2652
2905
  model,
2653
2906
  // @ts-expect-error - fix types
2654
- { id: document.documentId, locale, publishedAt: null },
2907
+ { documentId: document.documentId, locale, publishedAt: null },
2655
2908
  { availableLocales: true, availableStatus: false }
2656
2909
  );
2657
2910
  ctx.body = { data: {}, meta };
@@ -2666,7 +2919,7 @@ const singleTypes = {
2666
2919
  async createOrUpdate(ctx) {
2667
2920
  const { userAbility } = ctx.state;
2668
2921
  const { model } = ctx.params;
2669
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2922
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2670
2923
  const document = await createOrUpdateDocument(ctx);
2671
2924
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2672
2925
  ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
@@ -2675,8 +2928,8 @@ const singleTypes = {
2675
2928
  const { userAbility } = ctx.state;
2676
2929
  const { model } = ctx.params;
2677
2930
  const { query = {} } = ctx.request;
2678
- const documentManager2 = getService$1("document-manager");
2679
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2931
+ const documentManager2 = getService$2("document-manager");
2932
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2680
2933
  if (permissionChecker2.cannot.delete()) {
2681
2934
  return ctx.forbidden();
2682
2935
  }
@@ -2704,8 +2957,8 @@ const singleTypes = {
2704
2957
  const { userAbility } = ctx.state;
2705
2958
  const { model } = ctx.params;
2706
2959
  const { query = {} } = ctx.request;
2707
- const documentManager2 = getService$1("document-manager");
2708
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2960
+ const documentManager2 = getService$2("document-manager");
2961
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2709
2962
  if (permissionChecker2.cannot.publish()) {
2710
2963
  return ctx.forbidden();
2711
2964
  }
@@ -2733,8 +2986,8 @@ const singleTypes = {
2733
2986
  body: { discardDraft, ...body },
2734
2987
  query = {}
2735
2988
  } = ctx.request;
2736
- const documentManager2 = getService$1("document-manager");
2737
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2989
+ const documentManager2 = getService$2("document-manager");
2990
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2738
2991
  if (permissionChecker2.cannot.unpublish()) {
2739
2992
  return ctx.forbidden();
2740
2993
  }
@@ -2768,8 +3021,8 @@ const singleTypes = {
2768
3021
  const { userAbility } = ctx.state;
2769
3022
  const { model } = ctx.params;
2770
3023
  const { body, query = {} } = ctx.request;
2771
- const documentManager2 = getService$1("document-manager");
2772
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3024
+ const documentManager2 = getService$2("document-manager");
3025
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2773
3026
  if (permissionChecker2.cannot.discard()) {
2774
3027
  return ctx.forbidden();
2775
3028
  }
@@ -2792,8 +3045,8 @@ const singleTypes = {
2792
3045
  const { userAbility } = ctx.state;
2793
3046
  const { model } = ctx.params;
2794
3047
  const { query } = ctx.request;
2795
- const documentManager2 = getService$1("document-manager");
2796
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3048
+ const documentManager2 = getService$2("document-manager");
3049
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2797
3050
  const { locale } = await getDocumentLocaleAndStatus(query, model);
2798
3051
  if (permissionChecker2.cannot.read()) {
2799
3052
  return ctx.forbidden();
@@ -2817,7 +3070,7 @@ const uid$1 = {
2817
3070
  const { query = {} } = ctx.request;
2818
3071
  const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2819
3072
  await validateUIDField(contentTypeUID, field);
2820
- const uidService = getService$1("uid");
3073
+ const uidService = getService$2("uid");
2821
3074
  ctx.body = {
2822
3075
  data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
2823
3076
  };
@@ -2829,7 +3082,7 @@ const uid$1 = {
2829
3082
  const { query = {} } = ctx.request;
2830
3083
  const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2831
3084
  await validateUIDField(contentTypeUID, field);
2832
- const uidService = getService$1("uid");
3085
+ const uidService = getService$2("uid");
2833
3086
  const isAvailable = await uidService.checkUIDAvailability({
2834
3087
  contentTypeUID,
2835
3088
  field,
@@ -2850,7 +3103,8 @@ const controllers = {
2850
3103
  relations,
2851
3104
  "single-types": singleTypes,
2852
3105
  uid: uid$1,
2853
- ...history.controllers ? history.controllers : {}
3106
+ ...history.controllers ? history.controllers : {},
3107
+ ...preview.controllers ? preview.controllers : {}
2854
3108
  };
2855
3109
  const keys = {
2856
3110
  CONFIGURATION: "configuration"
@@ -3001,12 +3255,12 @@ async function syncMetadatas(configuration, schema) {
3001
3255
  return ___default.default.assign(metasWithDefaults, updatedMetas);
3002
3256
  }
3003
3257
  const getTargetSchema = (targetModel) => {
3004
- return getService$1("content-types").findContentType(targetModel);
3258
+ return getService$2("content-types").findContentType(targetModel);
3005
3259
  };
3006
3260
  const DEFAULT_LIST_LENGTH = 4;
3007
3261
  const MAX_ROW_SIZE = 12;
3008
3262
  const isAllowedFieldSize = (type, size) => {
3009
- const { getFieldSize } = getService$1("field-sizes");
3263
+ const { getFieldSize } = getService$2("field-sizes");
3010
3264
  const fieldSize = getFieldSize(type);
3011
3265
  if (!fieldSize.isResizable && size !== fieldSize.default) {
3012
3266
  return false;
@@ -3014,7 +3268,7 @@ const isAllowedFieldSize = (type, size) => {
3014
3268
  return size <= MAX_ROW_SIZE;
3015
3269
  };
3016
3270
  const getDefaultFieldSize = (attribute) => {
3017
- const { hasFieldSize, getFieldSize } = getService$1("field-sizes");
3271
+ const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
3018
3272
  return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
3019
3273
  };
3020
3274
  async function createDefaultLayouts(schema) {
@@ -3049,7 +3303,7 @@ function syncLayouts(configuration, schema) {
3049
3303
  for (const el of row) {
3050
3304
  if (!hasEditableAttribute(schema, el.name))
3051
3305
  continue;
3052
- const { hasFieldSize } = getService$1("field-sizes");
3306
+ const { hasFieldSize } = getService$2("field-sizes");
3053
3307
  const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
3054
3308
  if (!isAllowedFieldSize(fieldType, el.size)) {
3055
3309
  elementsToReAppend.push(el.name);
@@ -3189,17 +3443,17 @@ const configurationService$1 = createConfigurationService({
3189
3443
  isComponent: true,
3190
3444
  prefix: STORE_KEY_PREFIX,
3191
3445
  getModels() {
3192
- const { toContentManagerModel } = getService$1("data-mapper");
3446
+ const { toContentManagerModel } = getService$2("data-mapper");
3193
3447
  return fp.mapValues(toContentManagerModel, strapi.components);
3194
3448
  }
3195
3449
  });
3196
3450
  const components = ({ strapi: strapi2 }) => ({
3197
3451
  findAllComponents() {
3198
- const { toContentManagerModel } = getService$1("data-mapper");
3452
+ const { toContentManagerModel } = getService$2("data-mapper");
3199
3453
  return Object.values(strapi2.components).map(toContentManagerModel);
3200
3454
  },
3201
3455
  findComponent(uid2) {
3202
- const { toContentManagerModel } = getService$1("data-mapper");
3456
+ const { toContentManagerModel } = getService$2("data-mapper");
3203
3457
  const component = strapi2.components[uid2];
3204
3458
  return fp.isNil(component) ? component : toContentManagerModel(component);
3205
3459
  },
@@ -3250,17 +3504,17 @@ const configurationService = createConfigurationService({
3250
3504
  storeUtils,
3251
3505
  prefix: "content_types",
3252
3506
  getModels() {
3253
- const { toContentManagerModel } = getService$1("data-mapper");
3507
+ const { toContentManagerModel } = getService$2("data-mapper");
3254
3508
  return fp.mapValues(toContentManagerModel, strapi.contentTypes);
3255
3509
  }
3256
3510
  });
3257
3511
  const service = ({ strapi: strapi2 }) => ({
3258
3512
  findAllContentTypes() {
3259
- const { toContentManagerModel } = getService$1("data-mapper");
3513
+ const { toContentManagerModel } = getService$2("data-mapper");
3260
3514
  return Object.values(strapi2.contentTypes).map(toContentManagerModel);
3261
3515
  },
3262
3516
  findContentType(uid2) {
3263
- const { toContentManagerModel } = getService$1("data-mapper");
3517
+ const { toContentManagerModel } = getService$2("data-mapper");
3264
3518
  const contentType = strapi2.contentTypes[uid2];
3265
3519
  return fp.isNil(contentType) ? contentType : toContentManagerModel(contentType);
3266
3520
  },
@@ -3289,7 +3543,7 @@ const service = ({ strapi: strapi2 }) => ({
3289
3543
  return this.findConfiguration(contentType);
3290
3544
  },
3291
3545
  findComponentsConfigurations(contentType) {
3292
- return getService$1("components").findComponentsConfigurations(contentType);
3546
+ return getService$2("components").findComponentsConfigurations(contentType);
3293
3547
  },
3294
3548
  syncConfigurations() {
3295
3549
  return configurationService.syncConfigurations();
@@ -3470,12 +3724,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3470
3724
  ability: userAbility,
3471
3725
  model
3472
3726
  });
3473
- const toSubject = (entity) => entity ? permissionsManager.toSubject(entity, model) : model;
3727
+ const { actionProvider } = strapi2.service("admin::permission");
3728
+ const toSubject = (entity) => {
3729
+ return entity ? permissionsManager.toSubject(entity, model) : model;
3730
+ };
3474
3731
  const can = (action, entity, field) => {
3475
- return userAbility.can(action, toSubject(entity), field);
3732
+ const subject = toSubject(entity);
3733
+ const aliases = actionProvider.unstable_aliases(action, model);
3734
+ return (
3735
+ // Test the original action to see if it passes
3736
+ userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
3737
+ aliases.some((alias) => userAbility.can(alias, subject, field))
3738
+ );
3476
3739
  };
3477
3740
  const cannot = (action, entity, field) => {
3478
- return userAbility.cannot(action, toSubject(entity), field);
3741
+ const subject = toSubject(entity);
3742
+ const aliases = actionProvider.unstable_aliases(action, model);
3743
+ return (
3744
+ // Test both the original action
3745
+ userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
3746
+ aliases.every((alias) => userAbility.cannot(alias, subject, field))
3747
+ );
3479
3748
  };
3480
3749
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3481
3750
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3546,7 +3815,7 @@ const permission = ({ strapi: strapi2 }) => ({
3546
3815
  return userAbility.can(action);
3547
3816
  },
3548
3817
  async registerPermissions() {
3549
- const displayedContentTypes = getService$1("content-types").findDisplayedContentTypes();
3818
+ const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
3550
3819
  const contentTypesUids = displayedContentTypes.map(fp.prop("uid"));
3551
3820
  const actions = [
3552
3821
  {
@@ -3822,7 +4091,7 @@ const getQueryPopulate = async (uid2, query) => {
3822
4091
  return populateQuery;
3823
4092
  };
3824
4093
  const buildDeepPopulate = (uid2) => {
3825
- return getService$1("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
4094
+ return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
3826
4095
  };
3827
4096
  const populateBuilder = (uid2) => {
3828
4097
  let getInitialPopulate = async () => {
@@ -4007,7 +4276,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4007
4276
  */
4008
4277
  async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
4009
4278
  const versionsByLocale = fp.groupBy("locale", allVersions);
4010
- delete versionsByLocale[version.locale];
4279
+ if (version.locale) {
4280
+ delete versionsByLocale[version.locale];
4281
+ }
4011
4282
  const model = strapi2.getModel(uid2);
4012
4283
  const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
4013
4284
  const traversalFunction = async (localeVersion) => strapiUtils.traverseEntity(
@@ -4133,7 +4404,13 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4133
4404
  */
4134
4405
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
4135
4406
  if (!document) {
4136
- return document;
4407
+ return {
4408
+ data: document,
4409
+ meta: {
4410
+ availableLocales: [],
4411
+ availableStatus: []
4412
+ }
4413
+ };
4137
4414
  }
4138
4415
  const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
4139
4416
  if (!hasDraftAndPublish) {
@@ -4357,7 +4634,8 @@ const services = {
4357
4634
  permission,
4358
4635
  "populate-builder": populateBuilder$1,
4359
4636
  uid,
4360
- ...history.services ? history.services : {}
4637
+ ...history.services ? history.services : {},
4638
+ ...preview.services ? preview.services : {}
4361
4639
  };
4362
4640
  const index = () => {
4363
4641
  return {