contentful-import 10.2.3 → 10.3.0

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.
package/dist/index.js CHANGED
@@ -2313,8 +2313,8 @@ function getNative(object, key) {
2313
2313
  var getNative_default = getNative;
2314
2314
 
2315
2315
  // node_modules/lodash-es/_WeakMap.js
2316
- var WeakMap = getNative_default(root_default, "WeakMap");
2317
- var WeakMap_default = WeakMap;
2316
+ var WeakMap2 = getNative_default(root_default, "WeakMap");
2317
+ var WeakMap_default = WeakMap2;
2318
2318
 
2319
2319
  // node_modules/lodash-es/_baseCreate.js
2320
2320
  var objectCreate = Object.create;
@@ -3040,12 +3040,12 @@ function memoize(func, resolver) {
3040
3040
  throw new TypeError(FUNC_ERROR_TEXT);
3041
3041
  }
3042
3042
  var memoized = function() {
3043
- var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache;
3044
- if (cache.has(key)) {
3045
- return cache.get(key);
3043
+ var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache2 = memoized.cache;
3044
+ if (cache2.has(key)) {
3045
+ return cache2.get(key);
3046
3046
  }
3047
3047
  var result = func.apply(this, args);
3048
- memoized.cache = cache.set(key, result) || cache;
3048
+ memoized.cache = cache2.set(key, result) || cache2;
3049
3049
  return result;
3050
3050
  };
3051
3051
  memoized.cache = new (memoize.Cache || MapCache_default)();
@@ -3058,12 +3058,12 @@ var memoize_default = memoize;
3058
3058
  var MAX_MEMOIZE_SIZE = 500;
3059
3059
  function memoizeCapped(func) {
3060
3060
  var result = memoize_default(func, function(key) {
3061
- if (cache.size === MAX_MEMOIZE_SIZE) {
3062
- cache.clear();
3061
+ if (cache2.size === MAX_MEMOIZE_SIZE) {
3062
+ cache2.clear();
3063
3063
  }
3064
3064
  return key;
3065
3065
  });
3066
- var cache = result.cache;
3066
+ var cache2 = result.cache;
3067
3067
  return result;
3068
3068
  }
3069
3069
  var memoizeCapped_default = memoizeCapped;
@@ -4106,8 +4106,8 @@ function arraySome(array, predicate) {
4106
4106
  var arraySome_default = arraySome;
4107
4107
 
4108
4108
  // node_modules/lodash-es/_cacheHas.js
4109
- function cacheHas(cache, key) {
4110
- return cache.has(key);
4109
+ function cacheHas(cache2, key) {
4110
+ return cache2.has(key);
4111
4111
  }
4112
4112
  var cacheHas_default = cacheHas;
4113
4113
 
@@ -4889,7 +4889,7 @@ var startCase_default = startCase;
4889
4889
 
4890
4890
  // lib/index.ts
4891
4891
  var import_p_queue = __toESM(require("p-queue"));
4892
- var import_logging10 = __toESM(require_logging());
4892
+ var import_logging12 = __toESM(require_logging());
4893
4893
  var import_listr4 = __toESM(require_listr());
4894
4894
 
4895
4895
  // lib/tasks/init-client.ts
@@ -5245,7 +5245,7 @@ async function getDestinationData({
5245
5245
  // lib/tasks/push-to-space/push-to-space.ts
5246
5246
  var import_listr = __toESM(require("listr"));
5247
5247
  var import_listr_verbose_renderer = __toESM(require("listr-verbose-renderer"));
5248
- var import_logging9 = __toESM(require_logging());
5248
+ var import_logging11 = __toESM(require_logging());
5249
5249
  var import_listr2 = __toESM(require_listr());
5250
5250
 
5251
5251
  // lib/tasks/push-to-space/assets.ts
@@ -5542,21 +5542,103 @@ function getPlainData(entity) {
5542
5542
 
5543
5543
  // lib/tasks/push-to-space/publishing.ts
5544
5544
  var import_get_entity_name3 = __toESM(require_get_entity_name());
5545
+ var import_logging7 = __toESM(require_logging());
5546
+
5547
+ // lib/utils/locale-publishing.ts
5545
5548
  var import_logging6 = __toESM(require_logging());
5546
- function publishEntity(client, spaceId, environmentId, entity) {
5549
+ var LOCALE_PUBLISHING_FEATURES = ["localeBasedPublishing", "localePublishing"];
5550
+ var ENABLE_ON_ENVIRONMENT = 'To preserve it, select "Locale-based (un)publishing" for the destination environment under Settings > Locales > Publishing options.';
5551
+ var NOT_ENTITLED = "Locale-based publishing is only available on some plans \u2014 contact Contentful to have it added.";
5552
+ async function spaceHasLocalePublishingEntitlement(client, spaceId) {
5553
+ try {
5554
+ const space = await client.space.get({ spaceId });
5555
+ const organizationId = space.sys.organization?.sys?.id;
5556
+ if (!organizationId) {
5557
+ return null;
5558
+ }
5559
+ const entitlements = await client.raw.get(
5560
+ `/organizations/${organizationId}/organization_entitlement_set`
5561
+ );
5562
+ const features = entitlements.features;
5563
+ const known = LOCALE_PUBLISHING_FEATURES.filter((feature) => features?.[feature]?.value !== void 0);
5564
+ if (!known.length) {
5565
+ return null;
5566
+ }
5567
+ return known.some((feature) => features?.[feature]?.value === true);
5568
+ } catch {
5569
+ return null;
5570
+ }
5571
+ }
5572
+ var localeScopingUnavailable = /* @__PURE__ */ new WeakSet();
5573
+ var entitlementChecks = /* @__PURE__ */ new WeakMap();
5574
+ async function ensureLocalePublishingEntitlement(client, spaceId) {
5575
+ if (localeScopingUnavailable.has(client)) {
5576
+ return;
5577
+ }
5578
+ let check = entitlementChecks.get(client);
5579
+ if (!check) {
5580
+ check = spaceHasLocalePublishingEntitlement(client, spaceId);
5581
+ entitlementChecks.set(client, check);
5582
+ }
5583
+ if (await check === false) {
5584
+ markLocaleScopingUnavailable(client, "The destination organization is not entitled to locale-based publishing.", NOT_ENTITLED);
5585
+ }
5586
+ }
5587
+ function isLocaleScopingUnavailable(client) {
5588
+ return localeScopingUnavailable.has(client);
5589
+ }
5590
+ function markLocaleScopingUnavailable(client, reason, remedy = ENABLE_ON_ENVIRONMENT) {
5591
+ if (localeScopingUnavailable.has(client)) {
5592
+ return;
5593
+ }
5594
+ localeScopingUnavailable.add(client);
5595
+ import_logging6.logEmitter.emit("warning", `${reason} Publishing every locale instead \u2014 the per-locale publish state in the content file cannot be preserved. ${remedy}`);
5596
+ }
5597
+ function isLocalePublishingRejectedError(err) {
5598
+ if (!(err instanceof Error)) {
5599
+ return false;
5600
+ }
5601
+ const status = err.status ?? err.response?.status;
5602
+ if (status === 403 || status === 400) {
5603
+ return true;
5604
+ }
5605
+ try {
5606
+ const parsed = JSON.parse(err.message)?.status;
5607
+ return parsed === 403 || parsed === 400;
5608
+ } catch {
5609
+ return false;
5610
+ }
5611
+ }
5612
+ function destinationScopedThePublish(publishedEntity) {
5613
+ return Boolean(publishedEntity?.sys?.fieldStatus?.["*"]);
5614
+ }
5615
+
5616
+ // lib/tasks/push-to-space/publishing.ts
5617
+ function publishEntity(client, spaceId, environmentId, entity, locales2) {
5547
5618
  const id = entity.sys.id;
5548
5619
  const type = entity.sys.type;
5549
5620
  if (type === "Entry") {
5550
- return client.entry.publish({ spaceId, environmentId, entryId: id }, entity);
5621
+ return client.entry.publish({ spaceId, environmentId, entryId: id, locales: locales2 }, entity);
5551
5622
  }
5552
5623
  if (type === "Asset") {
5553
- return client.asset.publish({ spaceId, environmentId, assetId: id }, entity);
5624
+ return client.asset.publish({ spaceId, environmentId, assetId: id, locales: locales2 }, entity);
5554
5625
  }
5555
5626
  if (type === "ContentType") {
5556
5627
  return client.contentType.publish({ spaceId, environmentId, contentTypeId: id }, entity);
5557
5628
  }
5558
5629
  throw new Error(`publishEntity: unsupported type "${type}"`);
5559
5630
  }
5631
+ function unpublishEntityLocales(client, spaceId, environmentId, entity, locales2) {
5632
+ const id = entity.sys.id;
5633
+ const type = entity.sys.type;
5634
+ if (type === "Entry") {
5635
+ return client.entry.unpublish({ spaceId, environmentId, entryId: id, locales: locales2 }, entity);
5636
+ }
5637
+ if (type === "Asset") {
5638
+ return client.asset.unpublish({ spaceId, environmentId, assetId: id, locales: locales2 }, entity);
5639
+ }
5640
+ throw new Error(`unpublishEntityLocales: unsupported type "${type}"`);
5641
+ }
5560
5642
  function archiveEntity(client, spaceId, environmentId, entity) {
5561
5643
  const id = entity.sys.id;
5562
5644
  const type = entity.sys.type;
@@ -5568,26 +5650,26 @@ function archiveEntity(client, spaceId, environmentId, entity) {
5568
5650
  }
5569
5651
  throw new Error(`archiveEntity: unsupported type "${type}"`);
5570
5652
  }
5571
- async function publishEntities({ entities, client, spaceId, environmentId, requestQueue }) {
5653
+ async function publishEntities({ entities, client, spaceId, environmentId, requestQueue, localePublishing }) {
5572
5654
  if (entities.length === 0) {
5573
- import_logging6.logEmitter.emit("info", "Skipping publishing since zero valid entities passed");
5655
+ import_logging7.logEmitter.emit("info", "Skipping publishing since zero valid entities passed");
5574
5656
  return [];
5575
5657
  }
5576
5658
  const entity = entities[0];
5577
5659
  const type = entity.sys.type || "unknown type";
5578
- import_logging6.logEmitter.emit("info", `Publishing ${entities.length} ${type}s`);
5579
- const result = await runQueue(entities, [], client, spaceId, environmentId, requestQueue);
5580
- import_logging6.logEmitter.emit("info", `Successfully published ${result.length} ${type}s`);
5660
+ import_logging7.logEmitter.emit("info", `Publishing ${entities.length} ${type}s`);
5661
+ const result = await runQueue(entities, [], client, spaceId, environmentId, requestQueue, localePublishing);
5662
+ import_logging7.logEmitter.emit("info", `Successfully published ${result.length} ${type}s`);
5581
5663
  return result;
5582
5664
  }
5583
5665
  async function archiveEntities({ entities, client, spaceId, environmentId, requestQueue }) {
5584
5666
  if (entities.length === 0) {
5585
- import_logging6.logEmitter.emit("info", "Skipping archiving since zero valid entities passed");
5667
+ import_logging7.logEmitter.emit("info", "Skipping archiving since zero valid entities passed");
5586
5668
  return [];
5587
5669
  }
5588
5670
  const entity = entities[0];
5589
5671
  const type = entity.sys.type || "unknown type";
5590
- import_logging6.logEmitter.emit("info", `Archiving ${entities.length} ${type}s`);
5672
+ import_logging7.logEmitter.emit("info", `Archiving ${entities.length} ${type}s`);
5591
5673
  const pendingArchivedEntities = entities.map((entity2) => {
5592
5674
  return requestQueue.add(async () => {
5593
5675
  try {
@@ -5597,28 +5679,66 @@ async function archiveEntities({ entities, client, spaceId, environmentId, reque
5597
5679
  if (err instanceof ContentfulEntityError) {
5598
5680
  err.entity = entity2;
5599
5681
  }
5600
- import_logging6.logEmitter.emit("error", err);
5682
+ import_logging7.logEmitter.emit("error", err);
5601
5683
  return null;
5602
5684
  }
5603
5685
  });
5604
5686
  });
5605
5687
  const allPossiblyArchivedEntities = await Promise.all(pendingArchivedEntities);
5606
5688
  const allArchivedEntities = allPossiblyArchivedEntities.filter((entity2) => entity2);
5607
- import_logging6.logEmitter.emit("info", `Successfully archived ${allArchivedEntities.length} ${type}s`);
5689
+ import_logging7.logEmitter.emit("info", `Successfully archived ${allArchivedEntities.length} ${type}s`);
5608
5690
  return allArchivedEntities;
5609
5691
  }
5610
- async function runQueue(queue, result = [], client, spaceId, environmentId, requestQueue) {
5692
+ async function publishEntityLocales(client, spaceId, environmentId, entity, locales2, localesToDemote) {
5693
+ let published;
5694
+ try {
5695
+ published = await publishEntity(client, spaceId, environmentId, entity, locales2);
5696
+ } catch (err) {
5697
+ if (!isLocalePublishingRejectedError(err)) {
5698
+ throw err;
5699
+ }
5700
+ markLocaleScopingUnavailable(client, `The destination rejected locale-scoped publishing, starting with ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)}.`);
5701
+ return publishEntity(client, spaceId, environmentId, entity);
5702
+ }
5703
+ if (!destinationScopedThePublish(published)) {
5704
+ markLocaleScopingUnavailable(client, `The destination published ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)} without honouring the requested locales (${locales2.join(", ")}) and reported no per-locale state back.`);
5705
+ return published;
5706
+ }
5707
+ if (!localesToDemote?.length) {
5708
+ return published;
5709
+ }
5710
+ import_logging7.logEmitter.emit("info", `Unpublishing locales ${localesToDemote.join(", ")} of ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)}`);
5711
+ try {
5712
+ return await unpublishEntityLocales(client, spaceId, environmentId, published, localesToDemote);
5713
+ } catch (err) {
5714
+ if (isLocalePublishingRejectedError(err)) {
5715
+ markLocaleScopingUnavailable(client, `The destination rejected locale-scoped unpublishing, starting with ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)}.`);
5716
+ return published;
5717
+ }
5718
+ if (err instanceof ContentfulEntityError) {
5719
+ err.entity = entity;
5720
+ }
5721
+ import_logging7.logEmitter.emit("error", err);
5722
+ return published;
5723
+ }
5724
+ }
5725
+ async function runQueue(queue, result = [], client, spaceId, environmentId, requestQueue, localePublishing) {
5611
5726
  const publishedEntities = [];
5612
5727
  for (const entity of queue) {
5613
- import_logging6.logEmitter.emit("info", `Publishing ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)}`);
5728
+ const locales2 = localePublishing && !isLocaleScopingUnavailable(client) ? localePublishing.localesByEntityId.get(entity.sys.id) : void 0;
5729
+ if (locales2) {
5730
+ import_logging7.logEmitter.emit("info", `Publishing ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)} for locales ${locales2.join(", ")}`);
5731
+ } else {
5732
+ import_logging7.logEmitter.emit("info", `Publishing ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)}`);
5733
+ }
5614
5734
  try {
5615
- const publishedEntity = await requestQueue.add(() => publishEntity(client, spaceId, environmentId, entity));
5735
+ const publishedEntity = await requestQueue.add(() => locales2 ? publishEntityLocales(client, spaceId, environmentId, entity, locales2, localePublishing?.demoteLocalesByEntityId.get(entity.sys.id)) : publishEntity(client, spaceId, environmentId, entity));
5616
5736
  publishedEntities.push(publishedEntity);
5617
5737
  } catch (err) {
5618
5738
  if (err instanceof ContentfulEntityError) {
5619
5739
  err.entity = entity;
5620
5740
  }
5621
- import_logging6.logEmitter.emit("error", err);
5741
+ import_logging7.logEmitter.emit("error", err);
5622
5742
  }
5623
5743
  }
5624
5744
  result = [
@@ -5630,9 +5750,9 @@ async function runQueue(queue, result = [], client, spaceId, environmentId, requ
5630
5750
  if (unpublishedEntities.length > 0) {
5631
5751
  if (queue.length === unpublishedEntities.length) {
5632
5752
  const unpublishedEntityNames = unpublishedEntities.map(import_get_entity_name3.default).join(", ");
5633
- import_logging6.logEmitter.emit("error", `Could not publish the following entities: ${unpublishedEntityNames}`);
5753
+ import_logging7.logEmitter.emit("error", `Could not publish the following entities: ${unpublishedEntityNames}`);
5634
5754
  } else {
5635
- return runQueue(unpublishedEntities, result, client, spaceId, environmentId, requestQueue);
5755
+ return runQueue(unpublishedEntities, result, client, spaceId, environmentId, requestQueue, localePublishing);
5636
5756
  }
5637
5757
  }
5638
5758
  return result;
@@ -5764,18 +5884,18 @@ function sortExperienceFragments(experienceFragments) {
5764
5884
  }
5765
5885
 
5766
5886
  // lib/utils/sort-or-report.ts
5767
- var import_logging7 = __toESM(require_logging());
5887
+ var import_logging8 = __toESM(require_logging());
5768
5888
  function sortOrReport(sortFn) {
5769
5889
  try {
5770
5890
  return sortFn();
5771
5891
  } catch (err) {
5772
- import_logging7.logEmitter.emit("error", err);
5892
+ import_logging8.logEmitter.emit("error", err);
5773
5893
  throw err;
5774
5894
  }
5775
5895
  }
5776
5896
 
5777
5897
  // lib/utils/import-exo-folders.ts
5778
- var import_logging8 = __toESM(require_logging());
5898
+ var import_logging9 = __toESM(require_logging());
5779
5899
  var FOLDER_CONCEPT_PREFIX = "contentful.folder-";
5780
5900
  var PARENT_FOLDER_GROUP_IDS = {
5781
5901
  designToken: "contentful.folder-group-designToken",
@@ -5845,7 +5965,7 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
5845
5965
  existing = await client.concept.get({ organizationId, conceptId: destConceptId });
5846
5966
  } catch (err) {
5847
5967
  if (err?.name !== "NotFound") {
5848
- import_logging8.logEmitter.emit("warning", `Could not fetch destination child concept ${destConceptId}: ${err?.message ?? err}`);
5968
+ import_logging9.logEmitter.emit("warning", `Could not fetch destination child concept ${destConceptId}: ${err?.message ?? err}`);
5849
5969
  }
5850
5970
  }
5851
5971
  if (!existing) {
@@ -5855,9 +5975,9 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
5855
5975
  // @ts-expect-error - CMA.js type needs to be updated to be aware of purpose: 'internal'
5856
5976
  { purpose: "internal", prefLabel, metadata: { spaces: [spaceLink] } }
5857
5977
  );
5858
- import_logging8.logEmitter.emit("info", `Created child folder concept ${destConceptId}`);
5978
+ import_logging9.logEmitter.emit("info", `Created child folder concept ${destConceptId}`);
5859
5979
  } catch (err) {
5860
- import_logging8.logEmitter.emit("error", `Failed to create child folder concept ${destConceptId}: ${err?.message ?? err}`);
5980
+ import_logging9.logEmitter.emit("error", `Failed to create child folder concept ${destConceptId}: ${err?.message ?? err}`);
5861
5981
  }
5862
5982
  } else {
5863
5983
  const patches = [];
@@ -5871,9 +5991,9 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
5871
5991
  { organizationId, conceptId: destConceptId, version: existing.sys.version },
5872
5992
  patches
5873
5993
  );
5874
- import_logging8.logEmitter.emit("info", `Patched child folder concept ${destConceptId} (${patches.map((p) => p.path).join(", ")})`);
5994
+ import_logging9.logEmitter.emit("info", `Patched child folder concept ${destConceptId} (${patches.map((p) => p.path).join(", ")})`);
5875
5995
  } catch (err) {
5876
- import_logging8.logEmitter.emit("error", `Failed to patch child folder concept ${destConceptId}: ${err?.message ?? err}`);
5996
+ import_logging9.logEmitter.emit("error", `Failed to patch child folder concept ${destConceptId}: ${err?.message ?? err}`);
5877
5997
  }
5878
5998
  }
5879
5999
  }
@@ -5891,9 +6011,9 @@ async function linkChildConceptsToParentGroups(client, organizationId, childConc
5891
6011
  [{ op: "add", path: "/concepts/-", value: { sys: { type: "Link", linkType: "TaxonomyConcept", id: destConceptId } } }]
5892
6012
  );
5893
6013
  parentGroups.set(parentGroupId, updated);
5894
- import_logging8.logEmitter.emit("info", `Linked child concept ${destConceptId} to parent group ${parentGroupId}`);
6014
+ import_logging9.logEmitter.emit("info", `Linked child concept ${destConceptId} to parent group ${parentGroupId}`);
5895
6015
  } catch (err) {
5896
- import_logging8.logEmitter.emit("error", `Failed to link child concept ${destConceptId} to parent group ${parentGroupId}: ${err?.message ?? err}`);
6016
+ import_logging9.logEmitter.emit("error", `Failed to link child concept ${destConceptId} to parent group ${parentGroupId}: ${err?.message ?? err}`);
5897
6017
  }
5898
6018
  }
5899
6019
  }
@@ -5915,17 +6035,17 @@ async function importExoFolders({
5915
6035
  }) {
5916
6036
  const sourceSpaceId = getSourceSpaceId(sourceEntities);
5917
6037
  if (sourceSpaceId === destinationSpaceId) {
5918
- import_logging8.logEmitter.emit("info", "Source and destination space are the same \u2014 skipping ExO folder import");
6038
+ import_logging9.logEmitter.emit("info", "Source and destination space are the same \u2014 skipping ExO folder import");
5919
6039
  return;
5920
6040
  }
5921
6041
  const parentGroups = await ensureParentFolderGroupsExist(client, organizationId);
5922
6042
  if (parentGroups.size === 0) {
5923
- import_logging8.logEmitter.emit("warn", "One or more Experience Orchestration folder group concept schemes are missing in the destination organization. Please create them before importing.");
6043
+ import_logging9.logEmitter.emit("warn", "One or more Experience Orchestration folder group concept schemes are missing in the destination organization. Please create them before importing.");
5924
6044
  return;
5925
6045
  }
5926
6046
  const childConceptMap = deriveChildConceptMap(sourceEntities, destinationSpaceId);
5927
6047
  if (childConceptMap.size === 0) return;
5928
- import_logging8.logEmitter.emit("info", `Importing ${childConceptMap.size} ExO folder concept(s) into destination space ${destinationSpaceId}`);
6048
+ import_logging9.logEmitter.emit("info", `Importing ${childConceptMap.size} ExO folder concept(s) into destination space ${destinationSpaceId}`);
5929
6049
  await createOrPatchChildConcepts(client, organizationId, destinationSpaceId, childConceptMap);
5930
6050
  await linkChildConceptsToParentGroups(client, organizationId, childConceptMap, parentGroups);
5931
6051
  const allEntities = [
@@ -5938,6 +6058,79 @@ async function importExoFolders({
5938
6058
  rewriteEntityFolderConcepts(allEntities, childConceptMap);
5939
6059
  }
5940
6060
 
6061
+ // lib/utils/resolve-publish-locales.ts
6062
+ var LIVE_FIELD_STATUSES = ["published", "changed"];
6063
+ function resolvePublishLocales(sys, destinationLocaleCodes) {
6064
+ const fieldStatus = sys.fieldStatus?.["*"];
6065
+ if (!fieldStatus || !destinationLocaleCodes) {
6066
+ return null;
6067
+ }
6068
+ const liveLocales = Object.keys(fieldStatus).filter((locale) => LIVE_FIELD_STATUSES.indexOf(fieldStatus[locale]) !== -1);
6069
+ const availableLocales = liveLocales.filter((locale) => destinationLocaleCodes.indexOf(locale) !== -1);
6070
+ if (availableLocales.length === 0) {
6071
+ return [];
6072
+ }
6073
+ const everyLocaleIsLive = destinationLocaleCodes.every((locale) => availableLocales.indexOf(locale) !== -1);
6074
+ return everyLocaleIsLive ? null : availableLocales;
6075
+ }
6076
+ function resolveLocalesToDemote(sys, destinationSys, destinationLocaleCodes) {
6077
+ const fieldStatus = sys.fieldStatus?.["*"];
6078
+ const destinationFieldStatus = destinationSys?.fieldStatus?.["*"];
6079
+ if (!fieldStatus || !destinationFieldStatus) {
6080
+ return [];
6081
+ }
6082
+ return Object.keys(fieldStatus).filter((locale) => fieldStatus[locale] === "draft").filter((locale) => destinationLocaleCodes.indexOf(locale) !== -1).filter((locale) => LIVE_FIELD_STATUSES.indexOf(destinationFieldStatus[locale]) !== -1);
6083
+ }
6084
+ function buildLocalePublishPlan(sourceEntities, destinationLocaleCodes, { destinationEntitiesById } = {}) {
6085
+ const localesByEntityId = /* @__PURE__ */ new Map();
6086
+ const skippedEntityIds = /* @__PURE__ */ new Set();
6087
+ const demoteLocalesByEntityId = /* @__PURE__ */ new Map();
6088
+ for (const { original } of sourceEntities) {
6089
+ const locales2 = resolvePublishLocales(original.sys, destinationLocaleCodes);
6090
+ if (locales2 === null) {
6091
+ continue;
6092
+ }
6093
+ if (locales2.length === 0) {
6094
+ skippedEntityIds.add(original.sys.id);
6095
+ continue;
6096
+ }
6097
+ localesByEntityId.set(original.sys.id, locales2);
6098
+ if (!destinationEntitiesById) {
6099
+ continue;
6100
+ }
6101
+ const localesToDemote = resolveLocalesToDemote(
6102
+ original.sys,
6103
+ destinationEntitiesById.get(original.sys.id)?.sys,
6104
+ destinationLocaleCodes
6105
+ );
6106
+ if (localesToDemote.length) {
6107
+ demoteLocalesByEntityId.set(original.sys.id, localesToDemote);
6108
+ }
6109
+ }
6110
+ return { localesByEntityId, skippedEntityIds, demoteLocalesByEntityId };
6111
+ }
6112
+
6113
+ // lib/utils/destination-locales.ts
6114
+ var import_logging10 = __toESM(require_logging());
6115
+ var cache = /* @__PURE__ */ new WeakMap();
6116
+ function getDestinationLocaleCodes({ client, spaceId, environmentId, requestQueue }) {
6117
+ let byEnvironment = cache.get(client);
6118
+ if (!byEnvironment) {
6119
+ byEnvironment = /* @__PURE__ */ new Map();
6120
+ cache.set(client, byEnvironment);
6121
+ }
6122
+ const key = `${spaceId}/${environmentId}`;
6123
+ let localeCodes = byEnvironment.get(key);
6124
+ if (!localeCodes) {
6125
+ localeCodes = batchedPageQuery({ client, spaceId, environmentId, type: "locales", requestQueue }).then((items) => items.map((locale) => locale.code)).catch((err) => {
6126
+ import_logging10.logEmitter.emit("warning", `Could not read the locales of the destination environment, falling back to publishing all locales: ${err.message}`);
6127
+ return null;
6128
+ });
6129
+ byEnvironment.set(key, localeCodes);
6130
+ }
6131
+ return localeCodes;
6132
+ }
6133
+
5941
6134
  // lib/tasks/push-to-space/push-to-space.ts
5942
6135
  async function withGraphQLSchemaBackoff(fn) {
5943
6136
  let lastErr;
@@ -5949,7 +6142,7 @@ async function withGraphQLSchemaBackoff(fn) {
5949
6142
  throw err;
5950
6143
  }
5951
6144
  const delay = GRAPHQL_SCHEMA_STALE_DELAYS_MS[attempt];
5952
- import_logging9.logEmitter.emit("warning", `DataAssembly GraphQL schema not yet current, retrying in ${delay}ms (attempt ${attempt + 1}/${GRAPHQL_SCHEMA_STALE_DELAYS_MS.length})`);
6145
+ import_logging11.logEmitter.emit("warning", `DataAssembly GraphQL schema not yet current, retrying in ${delay}ms (attempt ${attempt + 1}/${GRAPHQL_SCHEMA_STALE_DELAYS_MS.length})`);
5953
6146
  await new Promise((resolve2) => setTimeout(resolve2, delay));
5954
6147
  lastErr = err;
5955
6148
  }
@@ -5977,6 +6170,7 @@ function pushToSpace({
5977
6170
  skipContentUpdates,
5978
6171
  skipLocales,
5979
6172
  skipContentPublishing,
6173
+ unpublishDraftLocales,
5980
6174
  timeout,
5981
6175
  retryLimit,
5982
6176
  listrOptions,
@@ -6088,7 +6282,7 @@ function pushToSpace({
6088
6282
  const ctEditorInterface = await requestQueue.add(
6089
6283
  () => client.editorInterface.get({ spaceId, environmentId, contentTypeId: contentType.sys.id })
6090
6284
  );
6091
- import_logging9.logEmitter.emit("info", `Fetched editor interface for ${contentType.name}`);
6285
+ import_logging11.logEmitter.emit("info", `Fetched editor interface for ${contentType.name}`);
6092
6286
  const updatedData = {
6093
6287
  ...ctEditorInterface,
6094
6288
  controls: editorInterface.controls,
@@ -6106,7 +6300,7 @@ function pushToSpace({
6106
6300
  return updatedEditorInterface;
6107
6301
  } catch (err) {
6108
6302
  err.entity = editorInterface;
6109
- import_logging9.logEmitter.emit("error", err);
6303
+ import_logging11.logEmitter.emit("error", err);
6110
6304
  return null;
6111
6305
  }
6112
6306
  });
@@ -6124,7 +6318,7 @@ function pushToSpace({
6124
6318
  for (const file of Object.values(asset.transformed.fields.file)) {
6125
6319
  allPendingUploads.push(requestQueue.add(async () => {
6126
6320
  try {
6127
- import_logging9.logEmitter.emit("info", `Uploading Asset file ${file.upload}`);
6321
+ import_logging11.logEmitter.emit("info", `Uploading Asset file ${file.upload}`);
6128
6322
  const assetStream = await getAssetStreamForURL(file.upload, assetsDirectory);
6129
6323
  const upload = await client.upload.create(
6130
6324
  { spaceId, environmentId },
@@ -6140,7 +6334,7 @@ function pushToSpace({
6140
6334
  };
6141
6335
  return upload;
6142
6336
  } catch (err) {
6143
- import_logging9.logEmitter.emit("error", err);
6337
+ import_logging11.logEmitter.emit("error", err);
6144
6338
  }
6145
6339
  }));
6146
6340
  }
@@ -6185,7 +6379,8 @@ function pushToSpace({
6185
6379
  client,
6186
6380
  spaceId,
6187
6381
  environmentId,
6188
- requestQueue
6382
+ requestQueue,
6383
+ destinationEntitiesById: unpublishDraftLocales ? destinationDataById.assets : void 0
6189
6384
  });
6190
6385
  ctx.data.publishedAssets = publishedAssets;
6191
6386
  }),
@@ -6229,7 +6424,8 @@ function pushToSpace({
6229
6424
  client,
6230
6425
  spaceId,
6231
6426
  environmentId,
6232
- requestQueue
6427
+ requestQueue,
6428
+ destinationEntitiesById: unpublishDraftLocales ? destinationDataById.entries : void 0
6233
6429
  });
6234
6430
  ctx.data.publishedEntries = publishedEntries;
6235
6431
  }),
@@ -6284,7 +6480,7 @@ function pushToSpace({
6284
6480
  }
6285
6481
  });
6286
6482
  } catch (error) {
6287
- import_logging9.logEmitter.emit("warning", `Unable to create Experience Orchestration (ExO) folders, error: ${error}`);
6483
+ import_logging11.logEmitter.emit("warning", `Unable to create Experience Orchestration (ExO) folders, error: ${error}`);
6288
6484
  }
6289
6485
  }),
6290
6486
  skip: () => !includeExperienceOrchestration
@@ -6302,19 +6498,19 @@ function pushToSpace({
6302
6498
  { spaceId, environmentId, dataAssemblyId: entity.sys.id },
6303
6499
  payload
6304
6500
  ));
6305
- import_logging9.logEmitter.emit("info", `UPDATE DataAssembly ${entity.sys.id}`);
6501
+ import_logging11.logEmitter.emit("info", `UPDATE DataAssembly ${entity.sys.id}`);
6306
6502
  } else {
6307
6503
  const payload = { ...omitSys(entity), sys: buildDataAssemblySys(entity, 0) };
6308
6504
  result = await withGraphQLSchemaBackoff(() => client.dataAssembly.update(
6309
6505
  { spaceId, environmentId, dataAssemblyId: entity.sys.id },
6310
6506
  payload
6311
6507
  ));
6312
- import_logging9.logEmitter.emit("info", `CREATE DataAssembly ${entity.sys.id}`);
6508
+ import_logging11.logEmitter.emit("info", `CREATE DataAssembly ${entity.sys.id}`);
6313
6509
  }
6314
6510
  return result;
6315
6511
  } catch (err) {
6316
6512
  err.entity = entity;
6317
- import_logging9.logEmitter.emit("error", err);
6513
+ import_logging11.logEmitter.emit("error", err);
6318
6514
  return null;
6319
6515
  }
6320
6516
  }));
@@ -6344,17 +6540,17 @@ function pushToSpace({
6344
6540
  if (existing) {
6345
6541
  const payload = { ...entity, sys: { id: entity.sys.id, type: "DesignToken", version: existing.sys.version } };
6346
6542
  const result = await client.designToken.upsert({ spaceId, environmentId, designTokenId: entity.sys.id }, payload);
6347
- import_logging9.logEmitter.emit("info", `UPDATE DesignToken ${entity.sys.id}`);
6543
+ import_logging11.logEmitter.emit("info", `UPDATE DesignToken ${entity.sys.id}`);
6348
6544
  return result;
6349
6545
  } else {
6350
6546
  const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "DesignToken" } };
6351
6547
  const result = await client.designToken.upsert({ spaceId, environmentId, designTokenId: entity.sys.id }, payload);
6352
- import_logging9.logEmitter.emit("info", `CREATE DesignToken ${entity.sys.id}`);
6548
+ import_logging11.logEmitter.emit("info", `CREATE DesignToken ${entity.sys.id}`);
6353
6549
  return result;
6354
6550
  }
6355
6551
  } catch (err) {
6356
6552
  err.entity = entity;
6357
- import_logging9.logEmitter.emit("error", err);
6553
+ import_logging11.logEmitter.emit("error", err);
6358
6554
  return null;
6359
6555
  }
6360
6556
  }));
@@ -6373,17 +6569,17 @@ function pushToSpace({
6373
6569
  if (existing) {
6374
6570
  const payload = { ...entity, sys: { id: entity.sys.id, type: "Component", version: existing.sys.version } };
6375
6571
  const result = await client.component.upsert({ spaceId, environmentId, componentId: entity.sys.id }, payload);
6376
- import_logging9.logEmitter.emit("info", `UPDATE Component ${entity.sys.id}`);
6572
+ import_logging11.logEmitter.emit("info", `UPDATE Component ${entity.sys.id}`);
6377
6573
  results.push(result);
6378
6574
  } else {
6379
6575
  const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "Component" } };
6380
6576
  const result = await client.component.upsert({ spaceId, environmentId, componentId: entity.sys.id }, payload);
6381
- import_logging9.logEmitter.emit("info", `CREATE Component ${entity.sys.id}`);
6577
+ import_logging11.logEmitter.emit("info", `CREATE Component ${entity.sys.id}`);
6382
6578
  results.push(result);
6383
6579
  }
6384
6580
  } catch (err) {
6385
6581
  err.entity = entity;
6386
- import_logging9.logEmitter.emit("error", err);
6582
+ import_logging11.logEmitter.emit("error", err);
6387
6583
  }
6388
6584
  }
6389
6585
  ctx.data.components = results;
@@ -6415,17 +6611,17 @@ function pushToSpace({
6415
6611
  if (existing) {
6416
6612
  const payload = { ...entity, sys: { id: entity.sys.id, type: "ExperienceTemplate", version: existing.sys.version } };
6417
6613
  const result = await client.experienceTemplate.upsert({ spaceId, environmentId, experienceTemplateId: entity.sys.id }, payload);
6418
- import_logging9.logEmitter.emit("info", `UPDATE ExperienceTemplate ${entity.sys.id}`);
6614
+ import_logging11.logEmitter.emit("info", `UPDATE ExperienceTemplate ${entity.sys.id}`);
6419
6615
  return result;
6420
6616
  } else {
6421
6617
  const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "ExperienceTemplate" } };
6422
6618
  const result = await client.experienceTemplate.upsert({ spaceId, environmentId, experienceTemplateId: entity.sys.id }, payload);
6423
- import_logging9.logEmitter.emit("info", `CREATE ExperienceTemplate ${entity.sys.id}`);
6619
+ import_logging11.logEmitter.emit("info", `CREATE ExperienceTemplate ${entity.sys.id}`);
6424
6620
  return result;
6425
6621
  }
6426
6622
  } catch (err) {
6427
6623
  err.entity = entity;
6428
- import_logging9.logEmitter.emit("error", err);
6624
+ import_logging11.logEmitter.emit("error", err);
6429
6625
  return null;
6430
6626
  }
6431
6627
  }));
@@ -6457,17 +6653,17 @@ function pushToSpace({
6457
6653
  if (existing) {
6458
6654
  const payload = { ...entity, sys: { id: entity.sys.id, type: "ExperienceFragment", version: existing.sys.version } };
6459
6655
  const result = await client.experienceFragment.upsert({ spaceId, environmentId, experienceFragmentId: entity.sys.id }, payload);
6460
- import_logging9.logEmitter.emit("info", `UPDATE ExperienceFragment ${entity.sys.id}`);
6656
+ import_logging11.logEmitter.emit("info", `UPDATE ExperienceFragment ${entity.sys.id}`);
6461
6657
  results.push(result);
6462
6658
  } else {
6463
6659
  const payload = { ...omitSys(entity), component: entity.sys.component, sys: { id: entity.sys.id, type: "ExperienceFragment" } };
6464
6660
  const result = await client.experienceFragment.upsert({ spaceId, environmentId, experienceFragmentId: entity.sys.id }, payload);
6465
- import_logging9.logEmitter.emit("info", `CREATE ExperienceFragment ${entity.sys.id}`);
6661
+ import_logging11.logEmitter.emit("info", `CREATE ExperienceFragment ${entity.sys.id}`);
6466
6662
  results.push(result);
6467
6663
  }
6468
6664
  } catch (err) {
6469
6665
  err.entity = entity;
6470
- import_logging9.logEmitter.emit("error", err);
6666
+ import_logging11.logEmitter.emit("error", err);
6471
6667
  }
6472
6668
  }
6473
6669
  ctx.data.experienceFragments = results;
@@ -6499,17 +6695,17 @@ function pushToSpace({
6499
6695
  if (existing) {
6500
6696
  const payload = { ...entity, sys: { id: entity.sys.id, type: "Experience", version: existing.sys.version } };
6501
6697
  const result = await client.experience.upsert({ spaceId, environmentId, experienceId: entity.sys.id }, payload);
6502
- import_logging9.logEmitter.emit("info", `UPDATE Experience ${entity.sys.id}`);
6698
+ import_logging11.logEmitter.emit("info", `UPDATE Experience ${entity.sys.id}`);
6503
6699
  return result;
6504
6700
  } else {
6505
6701
  const payload = { ...omitSys(entity), experienceTemplate: entity.sys.experienceTemplate, sys: { id: entity.sys.id, type: "Experience" } };
6506
6702
  const result = await client.experience.upsert({ spaceId, environmentId, experienceId: entity.sys.id }, payload);
6507
- import_logging9.logEmitter.emit("info", `CREATE Experience ${entity.sys.id}`);
6703
+ import_logging11.logEmitter.emit("info", `CREATE Experience ${entity.sys.id}`);
6508
6704
  return result;
6509
6705
  }
6510
6706
  } catch (err) {
6511
6707
  err.entity = entity;
6512
- import_logging9.logEmitter.emit("error", err);
6708
+ import_logging11.logEmitter.emit("error", err);
6513
6709
  return null;
6514
6710
  }
6515
6711
  }));
@@ -6606,10 +6802,41 @@ function archiveEntities2({ entities, sourceEntities, client, spaceId, environme
6606
6802
  const entitiesToArchive = entities.filter((entity) => entityIdsToArchive.indexOf(entity.sys.id) !== -1);
6607
6803
  return archiveEntities({ entities: entitiesToArchive, client, spaceId, environmentId, requestQueue });
6608
6804
  }
6609
- function publishEntities2({ entities, sourceEntities, client, spaceId, environmentId, requestQueue }) {
6805
+ async function publishEntities2({ entities, sourceEntities, client, spaceId, environmentId, requestQueue, destinationEntitiesById }) {
6610
6806
  const entityIdsToPublish = sourceEntities.filter(({ original }) => original.sys.publishedVersion).map(({ original }) => original.sys.id);
6611
- const entitiesToPublish = entities.filter((entity) => entityIdsToPublish.indexOf(entity.sys.id) !== -1);
6612
- return publishEntities({ entities: entitiesToPublish, client, spaceId, environmentId, requestQueue });
6807
+ let entitiesToPublish = entities.filter((entity) => entityIdsToPublish.indexOf(entity.sys.id) !== -1);
6808
+ const publishAllLocales = () => publishEntities({ entities: entitiesToPublish, client, spaceId, environmentId, requestQueue });
6809
+ const hasFieldStatus = sourceEntities.some(({ original }) => original.sys.fieldStatus);
6810
+ if (!hasFieldStatus) {
6811
+ return publishAllLocales();
6812
+ }
6813
+ await ensureLocalePublishingEntitlement(client, spaceId);
6814
+ if (isLocaleScopingUnavailable(client)) {
6815
+ return publishAllLocales();
6816
+ }
6817
+ const destinationLocaleCodes = await getDestinationLocaleCodes({ client, spaceId, environmentId, requestQueue });
6818
+ const localePublishing = buildLocalePublishPlan(
6819
+ sourceEntities,
6820
+ destinationLocaleCodes,
6821
+ { destinationEntitiesById }
6822
+ );
6823
+ if (localePublishing.skippedEntityIds.size) {
6824
+ entitiesToPublish = entitiesToPublish.filter((entity) => {
6825
+ if (!localePublishing.skippedEntityIds.has(entity.sys.id)) {
6826
+ return true;
6827
+ }
6828
+ import_logging11.logEmitter.emit("warning", `Not publishing ${entity.sys.type} ${entity.sys.id} because none of the locales it was published for exist in the destination environment`);
6829
+ return false;
6830
+ });
6831
+ }
6832
+ return publishEntities({
6833
+ entities: entitiesToPublish,
6834
+ client,
6835
+ spaceId,
6836
+ environmentId,
6837
+ requestQueue,
6838
+ localePublishing
6839
+ });
6613
6840
  }
6614
6841
 
6615
6842
  // lib/transform/transformers.ts
@@ -7149,6 +7376,7 @@ async function parseOptions(params) {
7149
7376
  skipContentModel: false,
7150
7377
  skipLocales: false,
7151
7378
  skipContentPublishing: false,
7379
+ unpublishDraftLocales: false,
7152
7380
  skipAssetUpdates: false,
7153
7381
  skipContentUpdates: false,
7154
7382
  useVerboseRenderer: false,
@@ -7257,7 +7485,7 @@ async function runContentfulImport(params) {
7257
7485
  intervalCap: options.rateLimit,
7258
7486
  carryoverConcurrencyCount: true
7259
7487
  });
7260
- (0, import_logging10.setupLogging)(log);
7488
+ (0, import_logging12.setupLogging)(log);
7261
7489
  const infoTable = new import_cli_table3.default(tableOptions);
7262
7490
  infoTable.push([{ colSpan: 2, content: "The following entities are going to be imported:" }]);
7263
7491
  Object.keys(options.content).forEach((type) => {
@@ -7325,6 +7553,7 @@ async function runContentfulImport(params) {
7325
7553
  skipLocales: options.skipLocales,
7326
7554
  skipContentModel: options.skipContentModel,
7327
7555
  skipContentPublishing: options.skipContentPublishing,
7556
+ unpublishDraftLocales: options.unpublishDraftLocales,
7328
7557
  skipAssetUpdates: options.skipAssetUpdates,
7329
7558
  skipContentUpdates: options.skipContentUpdates,
7330
7559
  timeout: options.timeout,
@@ -7366,9 +7595,9 @@ async function runContentfulImport(params) {
7366
7595
  }).then((data) => {
7367
7596
  const errorLog = log.filter((logMessage) => logMessage.level !== "info" && logMessage.level !== "warning");
7368
7597
  const displayLog = log.filter((logMessage) => logMessage.level !== "info");
7369
- (0, import_logging10.displayErrorLog)(displayLog);
7598
+ (0, import_logging12.displayErrorLog)(displayLog);
7370
7599
  if (errorLog.length) {
7371
- return (0, import_logging10.writeErrorLogFile)(options.errorLogFile, errorLog).then(() => {
7600
+ return (0, import_logging12.writeErrorLogFile)(options.errorLogFile, errorLog).then(() => {
7372
7601
  const multiError = new ContentfulMultiError("Errors occurred");
7373
7602
  multiError.name = "ContentfulMultiError";
7374
7603
  multiError.errors = errorLog;