strapi-plugin-bulk-updater 1.5.5 → 1.5.7

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.
@@ -990,6 +990,151 @@ function formatEntryRecord(entry) {
990
990
  }
991
991
  return formatted;
992
992
  }
993
+ function extractStageName(val) {
994
+ if (val === void 0 || val === null) return "";
995
+ if (typeof val === "string") {
996
+ const trimmed = val.trim();
997
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
998
+ try {
999
+ const parsed = JSON.parse(trimmed);
1000
+ if (parsed && typeof parsed === "object") {
1001
+ const fromParsed = extractStageName(parsed);
1002
+ if (fromParsed) return fromParsed;
1003
+ }
1004
+ } catch {
1005
+ }
1006
+ }
1007
+ return trimmed;
1008
+ }
1009
+ if (typeof val === "number") {
1010
+ return String(val);
1011
+ }
1012
+ if (typeof val === "object") {
1013
+ const candidateProps = [
1014
+ "strapi_stage",
1015
+ "strapi_stage.name",
1016
+ "strapi_stage[name]",
1017
+ "strapi_stage.title",
1018
+ "strapiStage",
1019
+ "Strapi Stage",
1020
+ "strapi-stage",
1021
+ "strapi_stage_name",
1022
+ "stage",
1023
+ "Stage",
1024
+ "stage.name",
1025
+ "stage[name]",
1026
+ "stage_name",
1027
+ "Stage Name",
1028
+ "review_stage",
1029
+ "review_stage.name",
1030
+ "review_stage[name]",
1031
+ "Review Stage",
1032
+ "reviewStage",
1033
+ "workflow_stage",
1034
+ "workflow_stage.name",
1035
+ "Workflow Stage",
1036
+ "workflowStage"
1037
+ ];
1038
+ for (const prop of candidateProps) {
1039
+ if (val[prop] !== void 0 && val[prop] !== null) {
1040
+ const fromProp = extractStageName(val[prop]);
1041
+ if (fromProp) return fromProp;
1042
+ }
1043
+ }
1044
+ const keys = Object.keys(val);
1045
+ for (const k of keys) {
1046
+ const norm = k.toLowerCase().replace(/[\s_\-\.\[\]]+/g, "");
1047
+ if (norm === "strapistage" || norm === "strapistagename" || norm === "stagename" || norm === "reviewstage" || norm === "reviewstagename" || norm === "workflowstage" || norm === "workflowstagename") {
1048
+ if (val[k] !== void 0 && val[k] !== null) {
1049
+ const fromNorm = extractStageName(val[k]);
1050
+ if (fromNorm) return fromNorm;
1051
+ }
1052
+ }
1053
+ }
1054
+ if (val.documentId && !val.color && !val.workflow) {
1055
+ return "";
1056
+ }
1057
+ const candidateStageValues = [
1058
+ val.name,
1059
+ val.title,
1060
+ val.label,
1061
+ val.value,
1062
+ val.stageName,
1063
+ val.stage_name,
1064
+ val.status
1065
+ ];
1066
+ for (const sv of candidateStageValues) {
1067
+ if (sv !== void 0 && sv !== null && typeof sv === "string" && sv.trim()) {
1068
+ return sv.trim();
1069
+ }
1070
+ }
1071
+ }
1072
+ return "";
1073
+ }
1074
+ function isStageApproved(stageVal) {
1075
+ const name = extractStageName(stageVal);
1076
+ return name.toLowerCase() === "approved";
1077
+ }
1078
+ function isStageEditingOrPending(stageVal) {
1079
+ const name = extractStageName(stageVal).toLowerCase();
1080
+ return name === "editing" || name === "in review" || name === "in_review" || name === "pending review" || name === "pending_review";
1081
+ }
1082
+ function inspectPreUpdateStatus(entry, publishedCounterpart) {
1083
+ if (!entry || typeof entry !== "object") {
1084
+ return { hadPublishedVersion: false, isModified: false };
1085
+ }
1086
+ const status = String(entry.status || "").toLowerCase();
1087
+ if (status === "published") {
1088
+ return { hadPublishedVersion: true, isModified: false };
1089
+ }
1090
+ if (status === "modified" || status === "modified draft") {
1091
+ return { hadPublishedVersion: true, isModified: true };
1092
+ }
1093
+ if (status === "draft") {
1094
+ return { hadPublishedVersion: false, isModified: false };
1095
+ }
1096
+ if (publishedCounterpart) {
1097
+ const draftUpdatedTime = new Date(entry.updatedAt || entry.updated_at || 0).getTime();
1098
+ const pubUpdatedTime = new Date(publishedCounterpart.updatedAt || publishedCounterpart.updated_at || 0).getTime();
1099
+ const pubPublishedTime = new Date(publishedCounterpart.publishedAt || publishedCounterpart.published_at || 0).getTime();
1100
+ const lastPublishedTime = Math.max(
1101
+ isNaN(pubUpdatedTime) ? 0 : pubUpdatedTime,
1102
+ isNaN(pubPublishedTime) ? 0 : pubPublishedTime
1103
+ );
1104
+ const isModified = !isNaN(draftUpdatedTime) && lastPublishedTime > 0 && draftUpdatedTime > lastPublishedTime;
1105
+ return { hadPublishedVersion: true, isModified };
1106
+ }
1107
+ const hasPubAt = Boolean(entry.publishedAt || entry.published_at);
1108
+ return { hadPublishedVersion: hasPubAt, isModified: false };
1109
+ }
1110
+ function determineShouldPublish({
1111
+ isDraftAndPublish,
1112
+ hadPublishedVersion,
1113
+ isModified = false,
1114
+ stageValue,
1115
+ publish = true,
1116
+ publishStrategy = "safe",
1117
+ unreviewedConsent = false
1118
+ }) {
1119
+ if (!isDraftAndPublish || !publish) {
1120
+ return false;
1121
+ }
1122
+ if (!hadPublishedVersion) {
1123
+ return false;
1124
+ }
1125
+ const isApproved = isStageApproved(stageValue);
1126
+ const isEditingOrPending = isStageEditingOrPending(stageValue);
1127
+ if (isApproved) {
1128
+ return true;
1129
+ }
1130
+ if (isEditingOrPending) {
1131
+ return false;
1132
+ }
1133
+ if (publishStrategy === "all" || unreviewedConsent) {
1134
+ return true;
1135
+ }
1136
+ return hadPublishedVersion && !isModified;
1137
+ }
993
1138
  async function populateDocumentLifecycleStatus(strapi, uid, entries) {
994
1139
  if (!entries || !Array.isArray(entries) || entries.length === 0) {
995
1140
  return entries;
@@ -1633,15 +1778,45 @@ async function executeBatchInternal(strapi, {
1633
1778
  const getDocumentDeduplicated = (uid, documentId) => {
1634
1779
  const loaderKey = `${uid}@@@${documentId}`;
1635
1780
  if (!documentLoader.has(loaderKey)) {
1781
+ strapi.contentTypes[uid];
1782
+ const findOneArgs = { documentId, populate: ["strapi_stage", "stage"] };
1636
1783
  documentLoader.set(
1637
1784
  loaderKey,
1638
- strapi.documents(uid).findOne({ documentId })
1785
+ strapi.documents(uid).findOne(findOneArgs)
1639
1786
  );
1640
1787
  }
1641
1788
  return documentLoader.get(loaderKey);
1642
1789
  };
1643
1790
  for (let i = 0; i < targets.length; i += CHUNK_SIZE) {
1644
1791
  const chunk = targets.slice(i, i + CHUNK_SIZE);
1792
+ const chunkByUid = /* @__PURE__ */ new Map();
1793
+ for (const t of chunk) {
1794
+ if (t.uid && t.documentId) {
1795
+ if (!chunkByUid.has(t.uid)) chunkByUid.set(t.uid, []);
1796
+ chunkByUid.get(t.uid).push(t.documentId);
1797
+ }
1798
+ }
1799
+ const publishedCounterparts = /* @__PURE__ */ new Map();
1800
+ for (const [colUid, docIds] of chunkByUid.entries()) {
1801
+ const colCt = strapi.contentTypes[colUid];
1802
+ if (colCt?.options?.draftAndPublish && docIds.length > 0) {
1803
+ try {
1804
+ const pubList = await strapi.documents(colUid).findMany({
1805
+ status: "published",
1806
+ filters: { documentId: { $in: docIds } },
1807
+ fields: ["documentId", "updatedAt", "publishedAt"],
1808
+ limit: docIds.length
1809
+ });
1810
+ for (const pub of pubList || []) {
1811
+ if (pub?.documentId) {
1812
+ publishedCounterparts.set(`${colUid}@@@${pub.documentId}`, pub);
1813
+ }
1814
+ }
1815
+ } catch (err) {
1816
+ strapi.log.warn(`[bulk-updater] Failed to pre-fetch published status for ${colUid}:`, err);
1817
+ }
1818
+ }
1819
+ }
1645
1820
  const chunkPromises = chunk.map(async (target) => {
1646
1821
  const contentType = strapi.contentTypes[target.uid];
1647
1822
  const displayName = contentType?.info?.displayName || target.uid;
@@ -1693,13 +1868,42 @@ async function executeBatchInternal(strapi, {
1693
1868
  }
1694
1869
  });
1695
1870
  const isDraftAndPublishComp = Boolean(contentType?.options?.draftAndPublish);
1696
- const isApprovedComp = isDraftAndPublishComp && Boolean(currentEntry?.publishedAt) && currentEntry?.status !== "modified";
1697
- const shouldPublishComp = isDraftAndPublishComp && Boolean(publishOnApproval) && (publishStrategy === "all" ? true : isApprovedComp);
1698
- if (shouldPublishComp) {
1871
+ let pubRecordComp = publishedCounterparts.get(`${target.uid}@@@${target.documentId}`);
1872
+ if (!pubRecordComp && isDraftAndPublishComp && target.documentId) {
1699
1873
  try {
1700
- await strapi.documents(target.uid).publish({
1701
- documentId: target.documentId
1874
+ const singlePub = await strapi.documents(target.uid).findMany({
1875
+ status: "published",
1876
+ filters: { documentId: target.documentId },
1877
+ fields: ["documentId", "updatedAt", "publishedAt"],
1878
+ limit: 1
1702
1879
  });
1880
+ if (singlePub && singlePub.length > 0) {
1881
+ pubRecordComp = singlePub[0];
1882
+ publishedCounterparts.set(`${target.uid}@@@${target.documentId}`, pubRecordComp);
1883
+ }
1884
+ } catch {
1885
+ }
1886
+ }
1887
+ const inspectionTargetComp = target.status || target.publishedAt ? { ...currentEntry, status: target.status, publishedAt: target.publishedAt } : currentEntry;
1888
+ const { hadPublishedVersion: hadPubComp, isModified: isModComp } = inspectPreUpdateStatus(inspectionTargetComp, pubRecordComp);
1889
+ const targetStageComp = attribute.toLowerCase() === "strapi_stage" || attribute.toLowerCase() === "stage" ? value : currentEntry?.strapi_stage ?? currentEntry?.stage ?? target?.strapi_stage ?? target?.stage;
1890
+ const shouldPublishComp = determineShouldPublish({
1891
+ isDraftAndPublish: isDraftAndPublishComp,
1892
+ hadPublishedVersion: hadPubComp,
1893
+ isModified: isModComp,
1894
+ stageValue: targetStageComp,
1895
+ publish: Boolean(publishOnApproval),
1896
+ publishStrategy,
1897
+ unreviewedConsent
1898
+ });
1899
+ if (shouldPublishComp) {
1900
+ try {
1901
+ const pubArgs = { documentId: target.documentId };
1902
+ const candLoc = target.locale || currentEntry?.locale;
1903
+ if (Boolean(contentType?.pluginOptions?.i18n?.localized) && candLoc && candLoc !== "null" && candLoc !== "undefined") {
1904
+ pubArgs.locale = candLoc;
1905
+ }
1906
+ await strapi.documents(target.uid).publish(pubArgs);
1703
1907
  } catch (publishErr) {
1704
1908
  strapi.log.warn(`[bulk-updater] Failed to auto-publish ${target.uid}/${target.documentId}:`, publishErr);
1705
1909
  }
@@ -1709,7 +1913,7 @@ async function executeBatchInternal(strapi, {
1709
1913
  uid: target.uid,
1710
1914
  documentId: target.documentId,
1711
1915
  userId: currentUser?.id,
1712
- statusOverride: shouldPublishComp ? "published" : isDraftAndPublishComp ? "draft" : void 0
1916
+ statusOverride: shouldPublishComp ? "published" : isDraftAndPublishComp ? hadPubComp ? "modified" : "draft" : void 0
1713
1917
  });
1714
1918
  const dzDiffs = isRootDz && affectedMatches.length > 0 ? affectedMatches.map((m) => ({
1715
1919
  index: m.index,
@@ -1792,13 +1996,42 @@ async function executeBatchInternal(strapi, {
1792
1996
  }
1793
1997
  });
1794
1998
  const isDraftAndPublishRel = Boolean(contentType?.options?.draftAndPublish);
1795
- const isApprovedRel = isDraftAndPublishRel && Boolean(currentEntry?.publishedAt) && currentEntry?.status !== "modified";
1796
- const shouldPublishRel = isDraftAndPublishRel && Boolean(publishOnApproval) && (publishStrategy === "all" ? true : isApprovedRel);
1797
- if (shouldPublishRel) {
1999
+ let pubRecordRel = publishedCounterparts.get(`${target.uid}@@@${target.documentId}`);
2000
+ if (!pubRecordRel && isDraftAndPublishRel && target.documentId) {
1798
2001
  try {
1799
- await strapi.documents(target.uid).publish({
1800
- documentId: target.documentId
2002
+ const singlePub = await strapi.documents(target.uid).findMany({
2003
+ status: "published",
2004
+ filters: { documentId: target.documentId },
2005
+ fields: ["documentId", "updatedAt", "publishedAt"],
2006
+ limit: 1
1801
2007
  });
2008
+ if (singlePub && singlePub.length > 0) {
2009
+ pubRecordRel = singlePub[0];
2010
+ publishedCounterparts.set(`${target.uid}@@@${target.documentId}`, pubRecordRel);
2011
+ }
2012
+ } catch {
2013
+ }
2014
+ }
2015
+ const inspectionTargetRel = target.status || target.publishedAt ? { ...currentEntry, status: target.status, publishedAt: target.publishedAt } : currentEntry;
2016
+ const { hadPublishedVersion: hadPubRel, isModified: isModRel } = inspectPreUpdateStatus(inspectionTargetRel, pubRecordRel);
2017
+ const targetStageRel = attribute.toLowerCase() === "strapi_stage" || attribute.toLowerCase() === "stage" ? value : currentEntry?.strapi_stage ?? currentEntry?.stage ?? target?.strapi_stage ?? target?.stage;
2018
+ const shouldPublishRel = determineShouldPublish({
2019
+ isDraftAndPublish: isDraftAndPublishRel,
2020
+ hadPublishedVersion: hadPubRel,
2021
+ isModified: isModRel,
2022
+ stageValue: targetStageRel,
2023
+ publish: Boolean(publishOnApproval),
2024
+ publishStrategy,
2025
+ unreviewedConsent
2026
+ });
2027
+ if (shouldPublishRel) {
2028
+ try {
2029
+ const pubArgs = { documentId: target.documentId };
2030
+ const candLoc = target.locale || currentEntry?.locale;
2031
+ if (Boolean(contentType?.pluginOptions?.i18n?.localized) && candLoc && candLoc !== "null" && candLoc !== "undefined") {
2032
+ pubArgs.locale = candLoc;
2033
+ }
2034
+ await strapi.documents(target.uid).publish(pubArgs);
1802
2035
  } catch (publishErr) {
1803
2036
  strapi.log.warn(`[bulk-updater] Failed to auto-publish ${target.uid}/${target.documentId}:`, publishErr);
1804
2037
  }
@@ -1811,7 +2044,7 @@ async function executeBatchInternal(strapi, {
1811
2044
  uid: target.uid,
1812
2045
  documentId: target.documentId,
1813
2046
  userId: currentUser?.id,
1814
- statusOverride: shouldPublishRel ? "published" : isDraftAndPublishRel ? "draft" : void 0
2047
+ statusOverride: shouldPublishRel ? "published" : isDraftAndPublishRel ? hadPubRel ? "modified" : "draft" : void 0
1815
2048
  });
1816
2049
  return {
1817
2050
  uid: target.uid,
@@ -1837,13 +2070,42 @@ async function executeBatchInternal(strapi, {
1837
2070
  }
1838
2071
  });
1839
2072
  const isDraftAndPublishScalar = Boolean(contentType?.options?.draftAndPublish);
1840
- const isApprovedScalar = isDraftAndPublishScalar && Boolean(currentEntry?.publishedAt) && currentEntry?.status !== "modified";
1841
- const shouldPublishScalar = isDraftAndPublishScalar && Boolean(publishOnApproval) && (publishStrategy === "all" ? true : isApprovedScalar);
1842
- if (shouldPublishScalar) {
2073
+ let pubRecordScalar = publishedCounterparts.get(`${target.uid}@@@${target.documentId}`);
2074
+ if (!pubRecordScalar && isDraftAndPublishScalar && target.documentId) {
1843
2075
  try {
1844
- await strapi.documents(target.uid).publish({
1845
- documentId: target.documentId
2076
+ const singlePub = await strapi.documents(target.uid).findMany({
2077
+ status: "published",
2078
+ filters: { documentId: target.documentId },
2079
+ fields: ["documentId", "updatedAt", "publishedAt"],
2080
+ limit: 1
1846
2081
  });
2082
+ if (singlePub && singlePub.length > 0) {
2083
+ pubRecordScalar = singlePub[0];
2084
+ publishedCounterparts.set(`${target.uid}@@@${target.documentId}`, pubRecordScalar);
2085
+ }
2086
+ } catch {
2087
+ }
2088
+ }
2089
+ const inspectionTargetScalar = target.status || target.publishedAt ? { ...currentEntry, status: target.status, publishedAt: target.publishedAt } : currentEntry;
2090
+ const { hadPublishedVersion: hadPubScalar, isModified: isModScalar } = inspectPreUpdateStatus(inspectionTargetScalar, pubRecordScalar);
2091
+ const targetStageScalar = attribute.toLowerCase() === "strapi_stage" || attribute.toLowerCase() === "stage" ? value : currentEntry?.strapi_stage ?? currentEntry?.stage ?? target?.strapi_stage ?? target?.stage;
2092
+ const shouldPublishScalar = determineShouldPublish({
2093
+ isDraftAndPublish: isDraftAndPublishScalar,
2094
+ hadPublishedVersion: hadPubScalar,
2095
+ isModified: isModScalar,
2096
+ stageValue: targetStageScalar,
2097
+ publish: Boolean(publishOnApproval),
2098
+ publishStrategy,
2099
+ unreviewedConsent
2100
+ });
2101
+ if (shouldPublishScalar) {
2102
+ try {
2103
+ const pubArgs = { documentId: target.documentId };
2104
+ const candLoc = target.locale || currentEntry?.locale;
2105
+ if (Boolean(contentType?.pluginOptions?.i18n?.localized) && candLoc && candLoc !== "null" && candLoc !== "undefined") {
2106
+ pubArgs.locale = candLoc;
2107
+ }
2108
+ await strapi.documents(target.uid).publish(pubArgs);
1847
2109
  } catch (publishErr) {
1848
2110
  strapi.log.warn(`[bulk-updater] Failed to auto-publish ${target.uid}/${target.documentId}:`, publishErr);
1849
2111
  }
@@ -1852,7 +2114,7 @@ async function executeBatchInternal(strapi, {
1852
2114
  uid: target.uid,
1853
2115
  documentId: target.documentId,
1854
2116
  userId: currentUser?.id,
1855
- statusOverride: shouldPublishScalar ? "published" : isDraftAndPublishScalar ? "draft" : void 0
2117
+ statusOverride: shouldPublishScalar ? "published" : isDraftAndPublishScalar ? hadPubScalar ? "modified" : "draft" : void 0
1856
2118
  });
1857
2119
  return {
1858
2120
  uid: target.uid,
@@ -5215,50 +5477,30 @@ function getEffectiveLocale(ct, rowLocale) {
5215
5477
  }
5216
5478
  return trimmed;
5217
5479
  }
5218
- function isRowInEditingStage(row) {
5219
- if (!row || typeof row !== "object") return false;
5220
- const candidates = [
5221
- row.strapi_stage,
5222
- row["strapi_stage"],
5223
- row.strapiStage,
5224
- row["Strapi Stage"],
5225
- row["strapi-stage"],
5226
- row.stage,
5227
- row.Stage,
5228
- row.status,
5229
- row.Status
5230
- ];
5231
- for (const c of candidates) {
5232
- if (c !== void 0 && c !== null) {
5233
- let stageName = "";
5234
- if (typeof c === "object") {
5235
- stageName = String(c.name || c.title || c.status || c.documentId || c.id || "").trim();
5236
- } else if (typeof c === "string") {
5237
- const trimmed = c.trim();
5238
- if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
5239
- try {
5240
- const parsed = JSON.parse(trimmed);
5241
- if (typeof parsed === "object" && parsed !== null) {
5242
- stageName = String(parsed.name || parsed.title || parsed.status || parsed.documentId || parsed.id || "").trim();
5243
- }
5244
- } catch {
5245
- }
5246
- }
5247
- if (!stageName) {
5248
- stageName = trimmed;
5249
- }
5250
- } else {
5251
- stageName = String(c).trim();
5252
- }
5253
- if (stageName) {
5254
- const s = stageName.toLowerCase();
5255
- if (s === "editing" || s === "in review" || s === "in_review" || s === "pending review" || s === "pending_review") {
5256
- return true;
5257
- }
5258
- }
5480
+ function resolveStageValue(row, existing) {
5481
+ if (row && typeof row === "object") {
5482
+ const stageNameFromRow = extractStageName(row);
5483
+ if (stageNameFromRow) return stageNameFromRow;
5484
+ }
5485
+ if (existing && typeof existing === "object") {
5486
+ if (existing.strapi_stage !== void 0 && existing.strapi_stage !== null) {
5487
+ return existing.strapi_stage;
5488
+ }
5489
+ if (existing.stage !== void 0 && existing.stage !== null) {
5490
+ return existing.stage;
5259
5491
  }
5492
+ const stageNameFromExisting = extractStageName(existing);
5493
+ if (stageNameFromExisting) return stageNameFromExisting;
5260
5494
  }
5261
- return false;
5495
+ return void 0;
5496
+ }
5497
+ function isRowInEditingStage(row, existing) {
5498
+ const stage = resolveStageValue(row, existing);
5499
+ return isStageEditingOrPending(stage);
5500
+ }
5501
+ function isRowInApprovedStage(row, existing) {
5502
+ const stage = resolveStageValue(row, existing);
5503
+ return isStageApproved(stage);
5262
5504
  }
5263
5505
  function extractDetailedErrorMessage(err) {
5264
5506
  if (!err) return "Error processing row";
@@ -5456,6 +5698,7 @@ async function findExistingDocument(strapi, uid, targetDocId, docLocale) {
5456
5698
  try {
5457
5699
  const queryArgs = { documentId: targetDocId };
5458
5700
  if (effectiveLocale) queryArgs.locale = effectiveLocale;
5701
+ queryArgs.populate = ["strapi_stage", "stage"];
5459
5702
  const found = await strapi.documents(uid).findOne(queryArgs);
5460
5703
  if (found) return found;
5461
5704
  } catch {
@@ -5835,6 +6078,25 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
5835
6078
  errors: [],
5836
6079
  diffs: []
5837
6080
  };
6081
+ const docIdsInChunk = rows.map((r) => extractDocId(r)).filter(Boolean);
6082
+ const publishedCounterparts = /* @__PURE__ */ new Map();
6083
+ if (isDraftAndPublish && docIdsInChunk.length > 0) {
6084
+ try {
6085
+ const pubList = await strapi.documents(uid).findMany({
6086
+ status: "published",
6087
+ filters: { documentId: { $in: docIdsInChunk } },
6088
+ fields: ["documentId", "updatedAt", "publishedAt"],
6089
+ limit: docIdsInChunk.length
6090
+ });
6091
+ for (const pub of pubList || []) {
6092
+ if (pub?.documentId) {
6093
+ publishedCounterparts.set(String(pub.documentId), pub);
6094
+ }
6095
+ }
6096
+ } catch (err) {
6097
+ strapi.log.warn(`[csv] Failed to pre-fetch published status for CSV chunk:`, err);
6098
+ }
6099
+ }
5838
6100
  for (let i = 0; i < rows.length; i++) {
5839
6101
  const rowNumber = startRowNumber + i;
5840
6102
  const row = rows[i];
@@ -5902,12 +6164,40 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
5902
6164
  };
5903
6165
  if (effectiveLocale) updateArgs.locale = effectiveLocale;
5904
6166
  await strapi.documents(uid).update(updateArgs);
5905
- const isApproved = !isEditing && isDraftAndPublish && Boolean(existing?.publishedAt) && existing?.status !== "modified";
5906
- const shouldPublish = !isEditing && isDraftAndPublish && Boolean(publish) && (publishStrategy === "all" || options.unreviewedConsent ? true : isApproved);
6167
+ let pubRecord = publishedCounterparts.get(String(resolvedDocId));
6168
+ if (!pubRecord && isDraftAndPublish && resolvedDocId) {
6169
+ try {
6170
+ const singlePub = await strapi.documents(uid).findMany({
6171
+ status: "published",
6172
+ filters: { documentId: resolvedDocId },
6173
+ fields: ["documentId", "updatedAt", "publishedAt"],
6174
+ limit: 1
6175
+ });
6176
+ if (singlePub && singlePub.length > 0) {
6177
+ pubRecord = singlePub[0];
6178
+ publishedCounterparts.set(String(resolvedDocId), pubRecord);
6179
+ }
6180
+ } catch {
6181
+ }
6182
+ }
6183
+ const { hadPublishedVersion, isModified } = inspectPreUpdateStatus(existing, pubRecord);
6184
+ const stageVal = resolveStageValue(row, existing);
6185
+ const shouldPublish = determineShouldPublish({
6186
+ isDraftAndPublish,
6187
+ hadPublishedVersion,
6188
+ isModified,
6189
+ stageValue: stageVal,
6190
+ publish: Boolean(publish),
6191
+ publishStrategy,
6192
+ unreviewedConsent: options.unreviewedConsent
6193
+ });
5907
6194
  if (shouldPublish) {
5908
6195
  try {
5909
6196
  const pubArgs = { documentId: resolvedDocId };
5910
- if (effectiveLocale) pubArgs.locale = effectiveLocale;
6197
+ const isLoc = Boolean(ct?.pluginOptions?.i18n?.localized);
6198
+ if (isLoc && effectiveLocale && effectiveLocale !== "null" && effectiveLocale !== "undefined") {
6199
+ pubArgs.locale = effectiveLocale;
6200
+ }
5911
6201
  await strapi.documents(uid).publish(pubArgs);
5912
6202
  } catch (pubErr) {
5913
6203
  strapi.log.warn(`[bulk-updater] Auto-publish failed for ${resolvedDocId}:`, pubErr);
@@ -5918,7 +6208,7 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
5918
6208
  uid,
5919
6209
  documentId: resolvedDocId,
5920
6210
  userId: user?.id,
5921
- statusOverride: shouldPublish ? "published" : isDraftAndPublish ? existing?.publishedAt ? "modified" : "draft" : void 0
6211
+ statusOverride: shouldPublish ? "published" : isDraftAndPublish ? hadPublishedVersion ? "modified" : "draft" : void 0
5922
6212
  });
5923
6213
  } catch {
5924
6214
  }
@@ -5957,12 +6247,38 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
5957
6247
  };
5958
6248
  if (effectiveLocale) updateArgs.locale = effectiveLocale;
5959
6249
  await strapi.documents(uid).update(updateArgs);
5960
- const isApproved = !isEditing && isDraftAndPublish && Boolean(existing?.publishedAt) && existing?.status !== "modified";
5961
- const shouldPublish = !isEditing && isDraftAndPublish && Boolean(publish) && (publishStrategy === "all" || options.unreviewedConsent ? true : isApproved);
6250
+ let pubRecord = publishedCounterparts.get(String(resolvedDocId));
6251
+ if (!pubRecord && isDraftAndPublish && resolvedDocId) {
6252
+ try {
6253
+ const singlePub = await strapi.documents(uid).findMany({
6254
+ status: "published",
6255
+ filters: { documentId: resolvedDocId },
6256
+ fields: ["documentId", "updatedAt", "publishedAt"],
6257
+ limit: 1
6258
+ });
6259
+ if (singlePub && singlePub.length > 0) {
6260
+ pubRecord = singlePub[0];
6261
+ publishedCounterparts.set(String(resolvedDocId), pubRecord);
6262
+ }
6263
+ } catch {
6264
+ }
6265
+ }
6266
+ const { hadPublishedVersion, isModified } = inspectPreUpdateStatus(existing, pubRecord);
6267
+ const stageVal = resolveStageValue(row, existing);
6268
+ const shouldPublish = determineShouldPublish({
6269
+ isDraftAndPublish,
6270
+ hadPublishedVersion,
6271
+ isModified,
6272
+ stageValue: stageVal,
6273
+ publish: Boolean(publish),
6274
+ publishStrategy,
6275
+ unreviewedConsent: options.unreviewedConsent
6276
+ });
5962
6277
  if (shouldPublish) {
5963
6278
  try {
5964
6279
  const pubArgs = { documentId: resolvedDocId };
5965
- if (effectiveLocale) pubArgs.locale = effectiveLocale;
6280
+ const isLoc = Boolean(ct?.pluginOptions?.i18n?.localized);
6281
+ if (isLoc && effectiveLocale && effectiveLocale !== "null" && effectiveLocale !== "undefined") pubArgs.locale = effectiveLocale;
5966
6282
  await strapi.documents(uid).publish(pubArgs);
5967
6283
  } catch (pubErr) {
5968
6284
  strapi.log.warn(`[bulk-updater] Auto-publish failed for ${resolvedDocId}:`, pubErr);
@@ -5973,7 +6289,7 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
5973
6289
  uid,
5974
6290
  documentId: resolvedDocId,
5975
6291
  userId: user?.id,
5976
- statusOverride: shouldPublish ? "published" : isDraftAndPublish ? existing?.publishedAt ? "modified" : "draft" : void 0
6292
+ statusOverride: shouldPublish ? "published" : isDraftAndPublish ? hadPublishedVersion ? "modified" : "draft" : void 0
5977
6293
  });
5978
6294
  } catch {
5979
6295
  }
@@ -5999,11 +6315,13 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
5999
6315
  if (effectiveLocale) createArgs.locale = effectiveLocale;
6000
6316
  const created = await strapi.documents(uid).create(createArgs);
6001
6317
  const newDocId = created?.documentId || docId;
6002
- const shouldPublishNew = !isEditing && isDraftAndPublish && Boolean(publish) && (publishStrategy === "all" || options.unreviewedConsent ? true : false);
6318
+ const isApprovedStage = isRowInApprovedStage(row);
6319
+ const shouldPublishNew = !isEditing && !isApprovedStage && isDraftAndPublish && Boolean(publish) && (publishStrategy === "all" || options.unreviewedConsent ? true : false);
6003
6320
  if (shouldPublishNew && newDocId) {
6004
6321
  try {
6005
6322
  const pubArgs = { documentId: newDocId };
6006
- if (effectiveLocale) pubArgs.locale = effectiveLocale;
6323
+ const isLoc = Boolean(ct?.pluginOptions?.i18n?.localized);
6324
+ if (isLoc && effectiveLocale && effectiveLocale !== "null" && effectiveLocale !== "undefined") pubArgs.locale = effectiveLocale;
6007
6325
  await strapi.documents(uid).publish(pubArgs);
6008
6326
  } catch (pubErr) {
6009
6327
  strapi.log.warn(`[bulk-updater] Auto-publish failed for ${newDocId}:`, pubErr);
@@ -6054,12 +6372,38 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
6054
6372
  };
6055
6373
  if (effectiveLocale) updateArgs.locale = effectiveLocale;
6056
6374
  await strapi.documents(uid).update(updateArgs);
6057
- const isApproved = !isEditing && isDraftAndPublish && Boolean(existing?.publishedAt) && existing?.status !== "modified";
6058
- const shouldPublish = !isEditing && isDraftAndPublish && Boolean(publish) && (publishStrategy === "all" || options.unreviewedConsent ? true : isApproved);
6375
+ let pubRecord = publishedCounterparts.get(String(resolvedDocId));
6376
+ if (!pubRecord && isDraftAndPublish && resolvedDocId) {
6377
+ try {
6378
+ const singlePub = await strapi.documents(uid).findMany({
6379
+ status: "published",
6380
+ filters: { documentId: resolvedDocId },
6381
+ fields: ["documentId", "updatedAt", "publishedAt"],
6382
+ limit: 1
6383
+ });
6384
+ if (singlePub && singlePub.length > 0) {
6385
+ pubRecord = singlePub[0];
6386
+ publishedCounterparts.set(String(resolvedDocId), pubRecord);
6387
+ }
6388
+ } catch {
6389
+ }
6390
+ }
6391
+ const { hadPublishedVersion, isModified } = inspectPreUpdateStatus(existing, pubRecord);
6392
+ const stageVal = resolveStageValue(row, existing);
6393
+ const shouldPublish = determineShouldPublish({
6394
+ isDraftAndPublish,
6395
+ hadPublishedVersion,
6396
+ isModified,
6397
+ stageValue: stageVal,
6398
+ publish: Boolean(publish),
6399
+ publishStrategy,
6400
+ unreviewedConsent: options.unreviewedConsent
6401
+ });
6059
6402
  if (shouldPublish) {
6060
6403
  try {
6061
6404
  const pubArgs = { documentId: resolvedDocId };
6062
- if (effectiveLocale) pubArgs.locale = effectiveLocale;
6405
+ const isLoc = Boolean(ct?.pluginOptions?.i18n?.localized);
6406
+ if (isLoc && effectiveLocale && effectiveLocale !== "null" && effectiveLocale !== "undefined") pubArgs.locale = effectiveLocale;
6063
6407
  await strapi.documents(uid).publish(pubArgs);
6064
6408
  } catch (pubErr) {
6065
6409
  strapi.log.warn(`[bulk-updater] Auto-publish failed for ${resolvedDocId}:`, pubErr);
@@ -6070,7 +6414,7 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
6070
6414
  uid,
6071
6415
  documentId: resolvedDocId,
6072
6416
  userId: user?.id,
6073
- statusOverride: shouldPublish ? "published" : isDraftAndPublish ? existing?.publishedAt ? "modified" : "draft" : void 0
6417
+ statusOverride: shouldPublish ? "published" : isDraftAndPublish ? hadPublishedVersion ? "modified" : "draft" : void 0
6074
6418
  });
6075
6419
  } catch {
6076
6420
  }
@@ -6096,11 +6440,13 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
6096
6440
  if (effectiveLocale) createArgs.locale = effectiveLocale;
6097
6441
  const created = await strapi.documents(uid).create(createArgs);
6098
6442
  const newDocId = created?.documentId || docId;
6099
- const shouldPublishNew = !isEditing && isDraftAndPublish && Boolean(publish) && (publishStrategy === "all" || options.unreviewedConsent ? true : false);
6443
+ const isApprovedStage = isRowInApprovedStage(row);
6444
+ const shouldPublishNew = !isEditing && !isApprovedStage && isDraftAndPublish && Boolean(publish) && (publishStrategy === "all" || options.unreviewedConsent ? true : false);
6100
6445
  if (shouldPublishNew && newDocId) {
6101
6446
  try {
6102
6447
  const pubArgs = { documentId: newDocId };
6103
- if (effectiveLocale) pubArgs.locale = effectiveLocale;
6448
+ const isLoc = Boolean(ct?.pluginOptions?.i18n?.localized);
6449
+ if (isLoc && effectiveLocale && effectiveLocale !== "null" && effectiveLocale !== "undefined") pubArgs.locale = effectiveLocale;
6104
6450
  await strapi.documents(uid).publish(pubArgs);
6105
6451
  } catch (pubErr) {
6106
6452
  strapi.log.warn(`[bulk-updater] Auto-publish failed for ${newDocId}:`, pubErr);
@@ -6688,6 +7034,25 @@ const csvService = ({ strapi }) => ({
6688
7034
  draft: 0,
6689
7035
  unreviewedCount: 0
6690
7036
  };
7037
+ const docIdsInPreflight = rows.map((r) => extractDocId(r)).filter(Boolean);
7038
+ const publishedCounterparts = /* @__PURE__ */ new Map();
7039
+ if (isDraftAndPublish && docIdsInPreflight.length > 0) {
7040
+ try {
7041
+ const pubList = await strapi.documents(uid).findMany({
7042
+ status: "published",
7043
+ filters: { documentId: { $in: docIdsInPreflight } },
7044
+ fields: ["documentId", "updatedAt", "publishedAt"],
7045
+ limit: docIdsInPreflight.length
7046
+ });
7047
+ for (const pub of pubList || []) {
7048
+ if (pub?.documentId) {
7049
+ publishedCounterparts.set(String(pub.documentId), pub);
7050
+ }
7051
+ }
7052
+ } catch (err) {
7053
+ strapi.log.warn(`[csv] Failed to pre-fetch published status for CSV preflight:`, err);
7054
+ }
7055
+ }
6691
7056
  const errors2 = [];
6692
7057
  const warnings = [];
6693
7058
  for (let i = 0; i < rows.length; i++) {
@@ -6696,7 +7061,7 @@ const csvService = ({ strapi }) => ({
6696
7061
  const docId = extractDocId(row);
6697
7062
  const rowLocale = extractLocale(row);
6698
7063
  const effectiveLocale = getEffectiveLocale(ct, rowLocale);
6699
- const isEditing = isRowInEditingStage(row);
7064
+ isRowInEditingStage(row);
6700
7065
  let rowHasError = false;
6701
7066
  let existing = null;
6702
7067
  if (docId) {
@@ -6704,15 +7069,44 @@ const csvService = ({ strapi }) => ({
6704
7069
  }
6705
7070
  if (existing && isDraftAndPublish) {
6706
7071
  lifecycleStats.totalChecked++;
6707
- const isApproved = !isEditing && Boolean(existing.publishedAt) && existing.status !== "modified";
6708
- if (isApproved) {
7072
+ const targetDocId = existing.documentId || docId;
7073
+ let pubRecord = publishedCounterparts.get(String(targetDocId));
7074
+ if (!pubRecord && isDraftAndPublish && targetDocId) {
7075
+ try {
7076
+ const singlePub = await strapi.documents(uid).findMany({
7077
+ status: "published",
7078
+ filters: { documentId: targetDocId },
7079
+ fields: ["documentId", "updatedAt", "publishedAt"],
7080
+ limit: 1
7081
+ });
7082
+ if (singlePub && singlePub.length > 0) {
7083
+ pubRecord = singlePub[0];
7084
+ publishedCounterparts.set(String(targetDocId), pubRecord);
7085
+ }
7086
+ } catch {
7087
+ }
7088
+ }
7089
+ const { hadPublishedVersion, isModified } = inspectPreUpdateStatus(existing, pubRecord);
7090
+ const stageVal = resolveStageValue(row, existing);
7091
+ const willPublish = determineShouldPublish({
7092
+ isDraftAndPublish,
7093
+ hadPublishedVersion,
7094
+ isModified,
7095
+ stageValue: stageVal,
7096
+ publish: true,
7097
+ publishStrategy: options.publishStrategy || "safe",
7098
+ unreviewedConsent: options.unreviewedConsent
7099
+ });
7100
+ if (willPublish) {
6709
7101
  lifecycleStats.published++;
6710
- } else if (existing.status === "modified" || existing.publishedAt && isEditing) {
7102
+ } else if (hadPublishedVersion && (isModified || isRowInEditingStage(row))) {
6711
7103
  lifecycleStats.modified++;
6712
7104
  lifecycleStats.unreviewedCount++;
6713
- } else {
7105
+ } else if (!hadPublishedVersion) {
6714
7106
  lifecycleStats.draft++;
6715
7107
  lifecycleStats.unreviewedCount++;
7108
+ } else {
7109
+ lifecycleStats.published++;
6716
7110
  }
6717
7111
  }
6718
7112
  if (mode === "update") {