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.mjs CHANGED
@@ -2280,8 +2280,8 @@ function getNative(object, key) {
2280
2280
  var getNative_default = getNative;
2281
2281
 
2282
2282
  // node_modules/lodash-es/_WeakMap.js
2283
- var WeakMap = getNative_default(root_default, "WeakMap");
2284
- var WeakMap_default = WeakMap;
2283
+ var WeakMap2 = getNative_default(root_default, "WeakMap");
2284
+ var WeakMap_default = WeakMap2;
2285
2285
 
2286
2286
  // node_modules/lodash-es/_baseCreate.js
2287
2287
  var objectCreate = Object.create;
@@ -3007,12 +3007,12 @@ function memoize(func, resolver) {
3007
3007
  throw new TypeError(FUNC_ERROR_TEXT);
3008
3008
  }
3009
3009
  var memoized = function() {
3010
- var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache;
3011
- if (cache.has(key)) {
3012
- return cache.get(key);
3010
+ var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache2 = memoized.cache;
3011
+ if (cache2.has(key)) {
3012
+ return cache2.get(key);
3013
3013
  }
3014
3014
  var result = func.apply(this, args);
3015
- memoized.cache = cache.set(key, result) || cache;
3015
+ memoized.cache = cache2.set(key, result) || cache2;
3016
3016
  return result;
3017
3017
  };
3018
3018
  memoized.cache = new (memoize.Cache || MapCache_default)();
@@ -3025,12 +3025,12 @@ var memoize_default = memoize;
3025
3025
  var MAX_MEMOIZE_SIZE = 500;
3026
3026
  function memoizeCapped(func) {
3027
3027
  var result = memoize_default(func, function(key) {
3028
- if (cache.size === MAX_MEMOIZE_SIZE) {
3029
- cache.clear();
3028
+ if (cache2.size === MAX_MEMOIZE_SIZE) {
3029
+ cache2.clear();
3030
3030
  }
3031
3031
  return key;
3032
3032
  });
3033
- var cache = result.cache;
3033
+ var cache2 = result.cache;
3034
3034
  return result;
3035
3035
  }
3036
3036
  var memoizeCapped_default = memoizeCapped;
@@ -4073,8 +4073,8 @@ function arraySome(array, predicate) {
4073
4073
  var arraySome_default = arraySome;
4074
4074
 
4075
4075
  // node_modules/lodash-es/_cacheHas.js
4076
- function cacheHas(cache, key) {
4077
- return cache.has(key);
4076
+ function cacheHas(cache2, key) {
4077
+ return cache2.has(key);
4078
4078
  }
4079
4079
  var cacheHas_default = cacheHas;
4080
4080
 
@@ -4855,7 +4855,7 @@ var startCase = createCompounder_default(function(result, word, index) {
4855
4855
  var startCase_default = startCase;
4856
4856
 
4857
4857
  // lib/index.ts
4858
- var import_logging10 = __toESM(require_logging());
4858
+ var import_logging12 = __toESM(require_logging());
4859
4859
  var import_listr4 = __toESM(require_listr());
4860
4860
  import PQueue from "p-queue";
4861
4861
 
@@ -5210,7 +5210,7 @@ async function getDestinationData({
5210
5210
  }
5211
5211
 
5212
5212
  // lib/tasks/push-to-space/push-to-space.ts
5213
- var import_logging9 = __toESM(require_logging());
5213
+ var import_logging11 = __toESM(require_logging());
5214
5214
  var import_listr2 = __toESM(require_listr());
5215
5215
  import Listr from "listr";
5216
5216
  import verboseRenderer from "listr-verbose-renderer";
@@ -5509,21 +5509,103 @@ function getPlainData(entity) {
5509
5509
 
5510
5510
  // lib/tasks/push-to-space/publishing.ts
5511
5511
  var import_get_entity_name3 = __toESM(require_get_entity_name());
5512
+ var import_logging7 = __toESM(require_logging());
5513
+
5514
+ // lib/utils/locale-publishing.ts
5512
5515
  var import_logging6 = __toESM(require_logging());
5513
- function publishEntity(client, spaceId, environmentId, entity) {
5516
+ var LOCALE_PUBLISHING_FEATURES = ["localeBasedPublishing", "localePublishing"];
5517
+ var ENABLE_ON_ENVIRONMENT = 'To preserve it, select "Locale-based (un)publishing" for the destination environment under Settings > Locales > Publishing options.';
5518
+ var NOT_ENTITLED = "Locale-based publishing is only available on some plans \u2014 contact Contentful to have it added.";
5519
+ async function spaceHasLocalePublishingEntitlement(client, spaceId) {
5520
+ try {
5521
+ const space = await client.space.get({ spaceId });
5522
+ const organizationId = space.sys.organization?.sys?.id;
5523
+ if (!organizationId) {
5524
+ return null;
5525
+ }
5526
+ const entitlements = await client.raw.get(
5527
+ `/organizations/${organizationId}/organization_entitlement_set`
5528
+ );
5529
+ const features = entitlements.features;
5530
+ const known = LOCALE_PUBLISHING_FEATURES.filter((feature) => features?.[feature]?.value !== void 0);
5531
+ if (!known.length) {
5532
+ return null;
5533
+ }
5534
+ return known.some((feature) => features?.[feature]?.value === true);
5535
+ } catch {
5536
+ return null;
5537
+ }
5538
+ }
5539
+ var localeScopingUnavailable = /* @__PURE__ */ new WeakSet();
5540
+ var entitlementChecks = /* @__PURE__ */ new WeakMap();
5541
+ async function ensureLocalePublishingEntitlement(client, spaceId) {
5542
+ if (localeScopingUnavailable.has(client)) {
5543
+ return;
5544
+ }
5545
+ let check = entitlementChecks.get(client);
5546
+ if (!check) {
5547
+ check = spaceHasLocalePublishingEntitlement(client, spaceId);
5548
+ entitlementChecks.set(client, check);
5549
+ }
5550
+ if (await check === false) {
5551
+ markLocaleScopingUnavailable(client, "The destination organization is not entitled to locale-based publishing.", NOT_ENTITLED);
5552
+ }
5553
+ }
5554
+ function isLocaleScopingUnavailable(client) {
5555
+ return localeScopingUnavailable.has(client);
5556
+ }
5557
+ function markLocaleScopingUnavailable(client, reason, remedy = ENABLE_ON_ENVIRONMENT) {
5558
+ if (localeScopingUnavailable.has(client)) {
5559
+ return;
5560
+ }
5561
+ localeScopingUnavailable.add(client);
5562
+ import_logging6.logEmitter.emit("warning", `${reason} Publishing every locale instead \u2014 the per-locale publish state in the content file cannot be preserved. ${remedy}`);
5563
+ }
5564
+ function isLocalePublishingRejectedError(err) {
5565
+ if (!(err instanceof Error)) {
5566
+ return false;
5567
+ }
5568
+ const status = err.status ?? err.response?.status;
5569
+ if (status === 403 || status === 400) {
5570
+ return true;
5571
+ }
5572
+ try {
5573
+ const parsed = JSON.parse(err.message)?.status;
5574
+ return parsed === 403 || parsed === 400;
5575
+ } catch {
5576
+ return false;
5577
+ }
5578
+ }
5579
+ function destinationScopedThePublish(publishedEntity) {
5580
+ return Boolean(publishedEntity?.sys?.fieldStatus?.["*"]);
5581
+ }
5582
+
5583
+ // lib/tasks/push-to-space/publishing.ts
5584
+ function publishEntity(client, spaceId, environmentId, entity, locales2) {
5514
5585
  const id = entity.sys.id;
5515
5586
  const type = entity.sys.type;
5516
5587
  if (type === "Entry") {
5517
- return client.entry.publish({ spaceId, environmentId, entryId: id }, entity);
5588
+ return client.entry.publish({ spaceId, environmentId, entryId: id, locales: locales2 }, entity);
5518
5589
  }
5519
5590
  if (type === "Asset") {
5520
- return client.asset.publish({ spaceId, environmentId, assetId: id }, entity);
5591
+ return client.asset.publish({ spaceId, environmentId, assetId: id, locales: locales2 }, entity);
5521
5592
  }
5522
5593
  if (type === "ContentType") {
5523
5594
  return client.contentType.publish({ spaceId, environmentId, contentTypeId: id }, entity);
5524
5595
  }
5525
5596
  throw new Error(`publishEntity: unsupported type "${type}"`);
5526
5597
  }
5598
+ function unpublishEntityLocales(client, spaceId, environmentId, entity, locales2) {
5599
+ const id = entity.sys.id;
5600
+ const type = entity.sys.type;
5601
+ if (type === "Entry") {
5602
+ return client.entry.unpublish({ spaceId, environmentId, entryId: id, locales: locales2 }, entity);
5603
+ }
5604
+ if (type === "Asset") {
5605
+ return client.asset.unpublish({ spaceId, environmentId, assetId: id, locales: locales2 }, entity);
5606
+ }
5607
+ throw new Error(`unpublishEntityLocales: unsupported type "${type}"`);
5608
+ }
5527
5609
  function archiveEntity(client, spaceId, environmentId, entity) {
5528
5610
  const id = entity.sys.id;
5529
5611
  const type = entity.sys.type;
@@ -5535,26 +5617,26 @@ function archiveEntity(client, spaceId, environmentId, entity) {
5535
5617
  }
5536
5618
  throw new Error(`archiveEntity: unsupported type "${type}"`);
5537
5619
  }
5538
- async function publishEntities({ entities, client, spaceId, environmentId, requestQueue }) {
5620
+ async function publishEntities({ entities, client, spaceId, environmentId, requestQueue, localePublishing }) {
5539
5621
  if (entities.length === 0) {
5540
- import_logging6.logEmitter.emit("info", "Skipping publishing since zero valid entities passed");
5622
+ import_logging7.logEmitter.emit("info", "Skipping publishing since zero valid entities passed");
5541
5623
  return [];
5542
5624
  }
5543
5625
  const entity = entities[0];
5544
5626
  const type = entity.sys.type || "unknown type";
5545
- import_logging6.logEmitter.emit("info", `Publishing ${entities.length} ${type}s`);
5546
- const result = await runQueue(entities, [], client, spaceId, environmentId, requestQueue);
5547
- import_logging6.logEmitter.emit("info", `Successfully published ${result.length} ${type}s`);
5627
+ import_logging7.logEmitter.emit("info", `Publishing ${entities.length} ${type}s`);
5628
+ const result = await runQueue(entities, [], client, spaceId, environmentId, requestQueue, localePublishing);
5629
+ import_logging7.logEmitter.emit("info", `Successfully published ${result.length} ${type}s`);
5548
5630
  return result;
5549
5631
  }
5550
5632
  async function archiveEntities({ entities, client, spaceId, environmentId, requestQueue }) {
5551
5633
  if (entities.length === 0) {
5552
- import_logging6.logEmitter.emit("info", "Skipping archiving since zero valid entities passed");
5634
+ import_logging7.logEmitter.emit("info", "Skipping archiving since zero valid entities passed");
5553
5635
  return [];
5554
5636
  }
5555
5637
  const entity = entities[0];
5556
5638
  const type = entity.sys.type || "unknown type";
5557
- import_logging6.logEmitter.emit("info", `Archiving ${entities.length} ${type}s`);
5639
+ import_logging7.logEmitter.emit("info", `Archiving ${entities.length} ${type}s`);
5558
5640
  const pendingArchivedEntities = entities.map((entity2) => {
5559
5641
  return requestQueue.add(async () => {
5560
5642
  try {
@@ -5564,28 +5646,66 @@ async function archiveEntities({ entities, client, spaceId, environmentId, reque
5564
5646
  if (err instanceof ContentfulEntityError) {
5565
5647
  err.entity = entity2;
5566
5648
  }
5567
- import_logging6.logEmitter.emit("error", err);
5649
+ import_logging7.logEmitter.emit("error", err);
5568
5650
  return null;
5569
5651
  }
5570
5652
  });
5571
5653
  });
5572
5654
  const allPossiblyArchivedEntities = await Promise.all(pendingArchivedEntities);
5573
5655
  const allArchivedEntities = allPossiblyArchivedEntities.filter((entity2) => entity2);
5574
- import_logging6.logEmitter.emit("info", `Successfully archived ${allArchivedEntities.length} ${type}s`);
5656
+ import_logging7.logEmitter.emit("info", `Successfully archived ${allArchivedEntities.length} ${type}s`);
5575
5657
  return allArchivedEntities;
5576
5658
  }
5577
- async function runQueue(queue, result = [], client, spaceId, environmentId, requestQueue) {
5659
+ async function publishEntityLocales(client, spaceId, environmentId, entity, locales2, localesToDemote) {
5660
+ let published;
5661
+ try {
5662
+ published = await publishEntity(client, spaceId, environmentId, entity, locales2);
5663
+ } catch (err) {
5664
+ if (!isLocalePublishingRejectedError(err)) {
5665
+ throw err;
5666
+ }
5667
+ markLocaleScopingUnavailable(client, `The destination rejected locale-scoped publishing, starting with ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)}.`);
5668
+ return publishEntity(client, spaceId, environmentId, entity);
5669
+ }
5670
+ if (!destinationScopedThePublish(published)) {
5671
+ 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.`);
5672
+ return published;
5673
+ }
5674
+ if (!localesToDemote?.length) {
5675
+ return published;
5676
+ }
5677
+ import_logging7.logEmitter.emit("info", `Unpublishing locales ${localesToDemote.join(", ")} of ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)}`);
5678
+ try {
5679
+ return await unpublishEntityLocales(client, spaceId, environmentId, published, localesToDemote);
5680
+ } catch (err) {
5681
+ if (isLocalePublishingRejectedError(err)) {
5682
+ markLocaleScopingUnavailable(client, `The destination rejected locale-scoped unpublishing, starting with ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)}.`);
5683
+ return published;
5684
+ }
5685
+ if (err instanceof ContentfulEntityError) {
5686
+ err.entity = entity;
5687
+ }
5688
+ import_logging7.logEmitter.emit("error", err);
5689
+ return published;
5690
+ }
5691
+ }
5692
+ async function runQueue(queue, result = [], client, spaceId, environmentId, requestQueue, localePublishing) {
5578
5693
  const publishedEntities = [];
5579
5694
  for (const entity of queue) {
5580
- import_logging6.logEmitter.emit("info", `Publishing ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)}`);
5695
+ const locales2 = localePublishing && !isLocaleScopingUnavailable(client) ? localePublishing.localesByEntityId.get(entity.sys.id) : void 0;
5696
+ if (locales2) {
5697
+ import_logging7.logEmitter.emit("info", `Publishing ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)} for locales ${locales2.join(", ")}`);
5698
+ } else {
5699
+ import_logging7.logEmitter.emit("info", `Publishing ${entity.sys.type} ${(0, import_get_entity_name3.default)(entity)}`);
5700
+ }
5581
5701
  try {
5582
- const publishedEntity = await requestQueue.add(() => publishEntity(client, spaceId, environmentId, entity));
5702
+ const publishedEntity = await requestQueue.add(() => locales2 ? publishEntityLocales(client, spaceId, environmentId, entity, locales2, localePublishing?.demoteLocalesByEntityId.get(entity.sys.id)) : publishEntity(client, spaceId, environmentId, entity));
5583
5703
  publishedEntities.push(publishedEntity);
5584
5704
  } catch (err) {
5585
5705
  if (err instanceof ContentfulEntityError) {
5586
5706
  err.entity = entity;
5587
5707
  }
5588
- import_logging6.logEmitter.emit("error", err);
5708
+ import_logging7.logEmitter.emit("error", err);
5589
5709
  }
5590
5710
  }
5591
5711
  result = [
@@ -5597,9 +5717,9 @@ async function runQueue(queue, result = [], client, spaceId, environmentId, requ
5597
5717
  if (unpublishedEntities.length > 0) {
5598
5718
  if (queue.length === unpublishedEntities.length) {
5599
5719
  const unpublishedEntityNames = unpublishedEntities.map(import_get_entity_name3.default).join(", ");
5600
- import_logging6.logEmitter.emit("error", `Could not publish the following entities: ${unpublishedEntityNames}`);
5720
+ import_logging7.logEmitter.emit("error", `Could not publish the following entities: ${unpublishedEntityNames}`);
5601
5721
  } else {
5602
- return runQueue(unpublishedEntities, result, client, spaceId, environmentId, requestQueue);
5722
+ return runQueue(unpublishedEntities, result, client, spaceId, environmentId, requestQueue, localePublishing);
5603
5723
  }
5604
5724
  }
5605
5725
  return result;
@@ -5731,18 +5851,18 @@ function sortExperienceFragments(experienceFragments) {
5731
5851
  }
5732
5852
 
5733
5853
  // lib/utils/sort-or-report.ts
5734
- var import_logging7 = __toESM(require_logging());
5854
+ var import_logging8 = __toESM(require_logging());
5735
5855
  function sortOrReport(sortFn) {
5736
5856
  try {
5737
5857
  return sortFn();
5738
5858
  } catch (err) {
5739
- import_logging7.logEmitter.emit("error", err);
5859
+ import_logging8.logEmitter.emit("error", err);
5740
5860
  throw err;
5741
5861
  }
5742
5862
  }
5743
5863
 
5744
5864
  // lib/utils/import-exo-folders.ts
5745
- var import_logging8 = __toESM(require_logging());
5865
+ var import_logging9 = __toESM(require_logging());
5746
5866
  var FOLDER_CONCEPT_PREFIX = "contentful.folder-";
5747
5867
  var PARENT_FOLDER_GROUP_IDS = {
5748
5868
  designToken: "contentful.folder-group-designToken",
@@ -5812,7 +5932,7 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
5812
5932
  existing = await client.concept.get({ organizationId, conceptId: destConceptId });
5813
5933
  } catch (err) {
5814
5934
  if (err?.name !== "NotFound") {
5815
- import_logging8.logEmitter.emit("warning", `Could not fetch destination child concept ${destConceptId}: ${err?.message ?? err}`);
5935
+ import_logging9.logEmitter.emit("warning", `Could not fetch destination child concept ${destConceptId}: ${err?.message ?? err}`);
5816
5936
  }
5817
5937
  }
5818
5938
  if (!existing) {
@@ -5822,9 +5942,9 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
5822
5942
  // @ts-expect-error - CMA.js type needs to be updated to be aware of purpose: 'internal'
5823
5943
  { purpose: "internal", prefLabel, metadata: { spaces: [spaceLink] } }
5824
5944
  );
5825
- import_logging8.logEmitter.emit("info", `Created child folder concept ${destConceptId}`);
5945
+ import_logging9.logEmitter.emit("info", `Created child folder concept ${destConceptId}`);
5826
5946
  } catch (err) {
5827
- import_logging8.logEmitter.emit("error", `Failed to create child folder concept ${destConceptId}: ${err?.message ?? err}`);
5947
+ import_logging9.logEmitter.emit("error", `Failed to create child folder concept ${destConceptId}: ${err?.message ?? err}`);
5828
5948
  }
5829
5949
  } else {
5830
5950
  const patches = [];
@@ -5838,9 +5958,9 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
5838
5958
  { organizationId, conceptId: destConceptId, version: existing.sys.version },
5839
5959
  patches
5840
5960
  );
5841
- import_logging8.logEmitter.emit("info", `Patched child folder concept ${destConceptId} (${patches.map((p) => p.path).join(", ")})`);
5961
+ import_logging9.logEmitter.emit("info", `Patched child folder concept ${destConceptId} (${patches.map((p) => p.path).join(", ")})`);
5842
5962
  } catch (err) {
5843
- import_logging8.logEmitter.emit("error", `Failed to patch child folder concept ${destConceptId}: ${err?.message ?? err}`);
5963
+ import_logging9.logEmitter.emit("error", `Failed to patch child folder concept ${destConceptId}: ${err?.message ?? err}`);
5844
5964
  }
5845
5965
  }
5846
5966
  }
@@ -5858,9 +5978,9 @@ async function linkChildConceptsToParentGroups(client, organizationId, childConc
5858
5978
  [{ op: "add", path: "/concepts/-", value: { sys: { type: "Link", linkType: "TaxonomyConcept", id: destConceptId } } }]
5859
5979
  );
5860
5980
  parentGroups.set(parentGroupId, updated);
5861
- import_logging8.logEmitter.emit("info", `Linked child concept ${destConceptId} to parent group ${parentGroupId}`);
5981
+ import_logging9.logEmitter.emit("info", `Linked child concept ${destConceptId} to parent group ${parentGroupId}`);
5862
5982
  } catch (err) {
5863
- import_logging8.logEmitter.emit("error", `Failed to link child concept ${destConceptId} to parent group ${parentGroupId}: ${err?.message ?? err}`);
5983
+ import_logging9.logEmitter.emit("error", `Failed to link child concept ${destConceptId} to parent group ${parentGroupId}: ${err?.message ?? err}`);
5864
5984
  }
5865
5985
  }
5866
5986
  }
@@ -5882,17 +6002,17 @@ async function importExoFolders({
5882
6002
  }) {
5883
6003
  const sourceSpaceId = getSourceSpaceId(sourceEntities);
5884
6004
  if (sourceSpaceId === destinationSpaceId) {
5885
- import_logging8.logEmitter.emit("info", "Source and destination space are the same \u2014 skipping ExO folder import");
6005
+ import_logging9.logEmitter.emit("info", "Source and destination space are the same \u2014 skipping ExO folder import");
5886
6006
  return;
5887
6007
  }
5888
6008
  const parentGroups = await ensureParentFolderGroupsExist(client, organizationId);
5889
6009
  if (parentGroups.size === 0) {
5890
- 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.");
6010
+ 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.");
5891
6011
  return;
5892
6012
  }
5893
6013
  const childConceptMap = deriveChildConceptMap(sourceEntities, destinationSpaceId);
5894
6014
  if (childConceptMap.size === 0) return;
5895
- import_logging8.logEmitter.emit("info", `Importing ${childConceptMap.size} ExO folder concept(s) into destination space ${destinationSpaceId}`);
6015
+ import_logging9.logEmitter.emit("info", `Importing ${childConceptMap.size} ExO folder concept(s) into destination space ${destinationSpaceId}`);
5896
6016
  await createOrPatchChildConcepts(client, organizationId, destinationSpaceId, childConceptMap);
5897
6017
  await linkChildConceptsToParentGroups(client, organizationId, childConceptMap, parentGroups);
5898
6018
  const allEntities = [
@@ -5905,6 +6025,79 @@ async function importExoFolders({
5905
6025
  rewriteEntityFolderConcepts(allEntities, childConceptMap);
5906
6026
  }
5907
6027
 
6028
+ // lib/utils/resolve-publish-locales.ts
6029
+ var LIVE_FIELD_STATUSES = ["published", "changed"];
6030
+ function resolvePublishLocales(sys, destinationLocaleCodes) {
6031
+ const fieldStatus = sys.fieldStatus?.["*"];
6032
+ if (!fieldStatus || !destinationLocaleCodes) {
6033
+ return null;
6034
+ }
6035
+ const liveLocales = Object.keys(fieldStatus).filter((locale) => LIVE_FIELD_STATUSES.indexOf(fieldStatus[locale]) !== -1);
6036
+ const availableLocales = liveLocales.filter((locale) => destinationLocaleCodes.indexOf(locale) !== -1);
6037
+ if (availableLocales.length === 0) {
6038
+ return [];
6039
+ }
6040
+ const everyLocaleIsLive = destinationLocaleCodes.every((locale) => availableLocales.indexOf(locale) !== -1);
6041
+ return everyLocaleIsLive ? null : availableLocales;
6042
+ }
6043
+ function resolveLocalesToDemote(sys, destinationSys, destinationLocaleCodes) {
6044
+ const fieldStatus = sys.fieldStatus?.["*"];
6045
+ const destinationFieldStatus = destinationSys?.fieldStatus?.["*"];
6046
+ if (!fieldStatus || !destinationFieldStatus) {
6047
+ return [];
6048
+ }
6049
+ return Object.keys(fieldStatus).filter((locale) => fieldStatus[locale] === "draft").filter((locale) => destinationLocaleCodes.indexOf(locale) !== -1).filter((locale) => LIVE_FIELD_STATUSES.indexOf(destinationFieldStatus[locale]) !== -1);
6050
+ }
6051
+ function buildLocalePublishPlan(sourceEntities, destinationLocaleCodes, { destinationEntitiesById } = {}) {
6052
+ const localesByEntityId = /* @__PURE__ */ new Map();
6053
+ const skippedEntityIds = /* @__PURE__ */ new Set();
6054
+ const demoteLocalesByEntityId = /* @__PURE__ */ new Map();
6055
+ for (const { original } of sourceEntities) {
6056
+ const locales2 = resolvePublishLocales(original.sys, destinationLocaleCodes);
6057
+ if (locales2 === null) {
6058
+ continue;
6059
+ }
6060
+ if (locales2.length === 0) {
6061
+ skippedEntityIds.add(original.sys.id);
6062
+ continue;
6063
+ }
6064
+ localesByEntityId.set(original.sys.id, locales2);
6065
+ if (!destinationEntitiesById) {
6066
+ continue;
6067
+ }
6068
+ const localesToDemote = resolveLocalesToDemote(
6069
+ original.sys,
6070
+ destinationEntitiesById.get(original.sys.id)?.sys,
6071
+ destinationLocaleCodes
6072
+ );
6073
+ if (localesToDemote.length) {
6074
+ demoteLocalesByEntityId.set(original.sys.id, localesToDemote);
6075
+ }
6076
+ }
6077
+ return { localesByEntityId, skippedEntityIds, demoteLocalesByEntityId };
6078
+ }
6079
+
6080
+ // lib/utils/destination-locales.ts
6081
+ var import_logging10 = __toESM(require_logging());
6082
+ var cache = /* @__PURE__ */ new WeakMap();
6083
+ function getDestinationLocaleCodes({ client, spaceId, environmentId, requestQueue }) {
6084
+ let byEnvironment = cache.get(client);
6085
+ if (!byEnvironment) {
6086
+ byEnvironment = /* @__PURE__ */ new Map();
6087
+ cache.set(client, byEnvironment);
6088
+ }
6089
+ const key = `${spaceId}/${environmentId}`;
6090
+ let localeCodes = byEnvironment.get(key);
6091
+ if (!localeCodes) {
6092
+ localeCodes = batchedPageQuery({ client, spaceId, environmentId, type: "locales", requestQueue }).then((items) => items.map((locale) => locale.code)).catch((err) => {
6093
+ import_logging10.logEmitter.emit("warning", `Could not read the locales of the destination environment, falling back to publishing all locales: ${err.message}`);
6094
+ return null;
6095
+ });
6096
+ byEnvironment.set(key, localeCodes);
6097
+ }
6098
+ return localeCodes;
6099
+ }
6100
+
5908
6101
  // lib/tasks/push-to-space/push-to-space.ts
5909
6102
  async function withGraphQLSchemaBackoff(fn) {
5910
6103
  let lastErr;
@@ -5916,7 +6109,7 @@ async function withGraphQLSchemaBackoff(fn) {
5916
6109
  throw err;
5917
6110
  }
5918
6111
  const delay = GRAPHQL_SCHEMA_STALE_DELAYS_MS[attempt];
5919
- import_logging9.logEmitter.emit("warning", `DataAssembly GraphQL schema not yet current, retrying in ${delay}ms (attempt ${attempt + 1}/${GRAPHQL_SCHEMA_STALE_DELAYS_MS.length})`);
6112
+ import_logging11.logEmitter.emit("warning", `DataAssembly GraphQL schema not yet current, retrying in ${delay}ms (attempt ${attempt + 1}/${GRAPHQL_SCHEMA_STALE_DELAYS_MS.length})`);
5920
6113
  await new Promise((resolve2) => setTimeout(resolve2, delay));
5921
6114
  lastErr = err;
5922
6115
  }
@@ -5944,6 +6137,7 @@ function pushToSpace({
5944
6137
  skipContentUpdates,
5945
6138
  skipLocales,
5946
6139
  skipContentPublishing,
6140
+ unpublishDraftLocales,
5947
6141
  timeout,
5948
6142
  retryLimit,
5949
6143
  listrOptions,
@@ -6055,7 +6249,7 @@ function pushToSpace({
6055
6249
  const ctEditorInterface = await requestQueue.add(
6056
6250
  () => client.editorInterface.get({ spaceId, environmentId, contentTypeId: contentType.sys.id })
6057
6251
  );
6058
- import_logging9.logEmitter.emit("info", `Fetched editor interface for ${contentType.name}`);
6252
+ import_logging11.logEmitter.emit("info", `Fetched editor interface for ${contentType.name}`);
6059
6253
  const updatedData = {
6060
6254
  ...ctEditorInterface,
6061
6255
  controls: editorInterface.controls,
@@ -6073,7 +6267,7 @@ function pushToSpace({
6073
6267
  return updatedEditorInterface;
6074
6268
  } catch (err) {
6075
6269
  err.entity = editorInterface;
6076
- import_logging9.logEmitter.emit("error", err);
6270
+ import_logging11.logEmitter.emit("error", err);
6077
6271
  return null;
6078
6272
  }
6079
6273
  });
@@ -6091,7 +6285,7 @@ function pushToSpace({
6091
6285
  for (const file of Object.values(asset.transformed.fields.file)) {
6092
6286
  allPendingUploads.push(requestQueue.add(async () => {
6093
6287
  try {
6094
- import_logging9.logEmitter.emit("info", `Uploading Asset file ${file.upload}`);
6288
+ import_logging11.logEmitter.emit("info", `Uploading Asset file ${file.upload}`);
6095
6289
  const assetStream = await getAssetStreamForURL(file.upload, assetsDirectory);
6096
6290
  const upload = await client.upload.create(
6097
6291
  { spaceId, environmentId },
@@ -6107,7 +6301,7 @@ function pushToSpace({
6107
6301
  };
6108
6302
  return upload;
6109
6303
  } catch (err) {
6110
- import_logging9.logEmitter.emit("error", err);
6304
+ import_logging11.logEmitter.emit("error", err);
6111
6305
  }
6112
6306
  }));
6113
6307
  }
@@ -6152,7 +6346,8 @@ function pushToSpace({
6152
6346
  client,
6153
6347
  spaceId,
6154
6348
  environmentId,
6155
- requestQueue
6349
+ requestQueue,
6350
+ destinationEntitiesById: unpublishDraftLocales ? destinationDataById.assets : void 0
6156
6351
  });
6157
6352
  ctx.data.publishedAssets = publishedAssets;
6158
6353
  }),
@@ -6196,7 +6391,8 @@ function pushToSpace({
6196
6391
  client,
6197
6392
  spaceId,
6198
6393
  environmentId,
6199
- requestQueue
6394
+ requestQueue,
6395
+ destinationEntitiesById: unpublishDraftLocales ? destinationDataById.entries : void 0
6200
6396
  });
6201
6397
  ctx.data.publishedEntries = publishedEntries;
6202
6398
  }),
@@ -6251,7 +6447,7 @@ function pushToSpace({
6251
6447
  }
6252
6448
  });
6253
6449
  } catch (error) {
6254
- import_logging9.logEmitter.emit("warning", `Unable to create Experience Orchestration (ExO) folders, error: ${error}`);
6450
+ import_logging11.logEmitter.emit("warning", `Unable to create Experience Orchestration (ExO) folders, error: ${error}`);
6255
6451
  }
6256
6452
  }),
6257
6453
  skip: () => !includeExperienceOrchestration
@@ -6269,19 +6465,19 @@ function pushToSpace({
6269
6465
  { spaceId, environmentId, dataAssemblyId: entity.sys.id },
6270
6466
  payload
6271
6467
  ));
6272
- import_logging9.logEmitter.emit("info", `UPDATE DataAssembly ${entity.sys.id}`);
6468
+ import_logging11.logEmitter.emit("info", `UPDATE DataAssembly ${entity.sys.id}`);
6273
6469
  } else {
6274
6470
  const payload = { ...omitSys(entity), sys: buildDataAssemblySys(entity, 0) };
6275
6471
  result = await withGraphQLSchemaBackoff(() => client.dataAssembly.update(
6276
6472
  { spaceId, environmentId, dataAssemblyId: entity.sys.id },
6277
6473
  payload
6278
6474
  ));
6279
- import_logging9.logEmitter.emit("info", `CREATE DataAssembly ${entity.sys.id}`);
6475
+ import_logging11.logEmitter.emit("info", `CREATE DataAssembly ${entity.sys.id}`);
6280
6476
  }
6281
6477
  return result;
6282
6478
  } catch (err) {
6283
6479
  err.entity = entity;
6284
- import_logging9.logEmitter.emit("error", err);
6480
+ import_logging11.logEmitter.emit("error", err);
6285
6481
  return null;
6286
6482
  }
6287
6483
  }));
@@ -6311,17 +6507,17 @@ function pushToSpace({
6311
6507
  if (existing) {
6312
6508
  const payload = { ...entity, sys: { id: entity.sys.id, type: "DesignToken", version: existing.sys.version } };
6313
6509
  const result = await client.designToken.upsert({ spaceId, environmentId, designTokenId: entity.sys.id }, payload);
6314
- import_logging9.logEmitter.emit("info", `UPDATE DesignToken ${entity.sys.id}`);
6510
+ import_logging11.logEmitter.emit("info", `UPDATE DesignToken ${entity.sys.id}`);
6315
6511
  return result;
6316
6512
  } else {
6317
6513
  const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "DesignToken" } };
6318
6514
  const result = await client.designToken.upsert({ spaceId, environmentId, designTokenId: entity.sys.id }, payload);
6319
- import_logging9.logEmitter.emit("info", `CREATE DesignToken ${entity.sys.id}`);
6515
+ import_logging11.logEmitter.emit("info", `CREATE DesignToken ${entity.sys.id}`);
6320
6516
  return result;
6321
6517
  }
6322
6518
  } catch (err) {
6323
6519
  err.entity = entity;
6324
- import_logging9.logEmitter.emit("error", err);
6520
+ import_logging11.logEmitter.emit("error", err);
6325
6521
  return null;
6326
6522
  }
6327
6523
  }));
@@ -6340,17 +6536,17 @@ function pushToSpace({
6340
6536
  if (existing) {
6341
6537
  const payload = { ...entity, sys: { id: entity.sys.id, type: "Component", version: existing.sys.version } };
6342
6538
  const result = await client.component.upsert({ spaceId, environmentId, componentId: entity.sys.id }, payload);
6343
- import_logging9.logEmitter.emit("info", `UPDATE Component ${entity.sys.id}`);
6539
+ import_logging11.logEmitter.emit("info", `UPDATE Component ${entity.sys.id}`);
6344
6540
  results.push(result);
6345
6541
  } else {
6346
6542
  const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "Component" } };
6347
6543
  const result = await client.component.upsert({ spaceId, environmentId, componentId: entity.sys.id }, payload);
6348
- import_logging9.logEmitter.emit("info", `CREATE Component ${entity.sys.id}`);
6544
+ import_logging11.logEmitter.emit("info", `CREATE Component ${entity.sys.id}`);
6349
6545
  results.push(result);
6350
6546
  }
6351
6547
  } catch (err) {
6352
6548
  err.entity = entity;
6353
- import_logging9.logEmitter.emit("error", err);
6549
+ import_logging11.logEmitter.emit("error", err);
6354
6550
  }
6355
6551
  }
6356
6552
  ctx.data.components = results;
@@ -6382,17 +6578,17 @@ function pushToSpace({
6382
6578
  if (existing) {
6383
6579
  const payload = { ...entity, sys: { id: entity.sys.id, type: "ExperienceTemplate", version: existing.sys.version } };
6384
6580
  const result = await client.experienceTemplate.upsert({ spaceId, environmentId, experienceTemplateId: entity.sys.id }, payload);
6385
- import_logging9.logEmitter.emit("info", `UPDATE ExperienceTemplate ${entity.sys.id}`);
6581
+ import_logging11.logEmitter.emit("info", `UPDATE ExperienceTemplate ${entity.sys.id}`);
6386
6582
  return result;
6387
6583
  } else {
6388
6584
  const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "ExperienceTemplate" } };
6389
6585
  const result = await client.experienceTemplate.upsert({ spaceId, environmentId, experienceTemplateId: entity.sys.id }, payload);
6390
- import_logging9.logEmitter.emit("info", `CREATE ExperienceTemplate ${entity.sys.id}`);
6586
+ import_logging11.logEmitter.emit("info", `CREATE ExperienceTemplate ${entity.sys.id}`);
6391
6587
  return result;
6392
6588
  }
6393
6589
  } catch (err) {
6394
6590
  err.entity = entity;
6395
- import_logging9.logEmitter.emit("error", err);
6591
+ import_logging11.logEmitter.emit("error", err);
6396
6592
  return null;
6397
6593
  }
6398
6594
  }));
@@ -6424,17 +6620,17 @@ function pushToSpace({
6424
6620
  if (existing) {
6425
6621
  const payload = { ...entity, sys: { id: entity.sys.id, type: "ExperienceFragment", version: existing.sys.version } };
6426
6622
  const result = await client.experienceFragment.upsert({ spaceId, environmentId, experienceFragmentId: entity.sys.id }, payload);
6427
- import_logging9.logEmitter.emit("info", `UPDATE ExperienceFragment ${entity.sys.id}`);
6623
+ import_logging11.logEmitter.emit("info", `UPDATE ExperienceFragment ${entity.sys.id}`);
6428
6624
  results.push(result);
6429
6625
  } else {
6430
6626
  const payload = { ...omitSys(entity), component: entity.sys.component, sys: { id: entity.sys.id, type: "ExperienceFragment" } };
6431
6627
  const result = await client.experienceFragment.upsert({ spaceId, environmentId, experienceFragmentId: entity.sys.id }, payload);
6432
- import_logging9.logEmitter.emit("info", `CREATE ExperienceFragment ${entity.sys.id}`);
6628
+ import_logging11.logEmitter.emit("info", `CREATE ExperienceFragment ${entity.sys.id}`);
6433
6629
  results.push(result);
6434
6630
  }
6435
6631
  } catch (err) {
6436
6632
  err.entity = entity;
6437
- import_logging9.logEmitter.emit("error", err);
6633
+ import_logging11.logEmitter.emit("error", err);
6438
6634
  }
6439
6635
  }
6440
6636
  ctx.data.experienceFragments = results;
@@ -6466,17 +6662,17 @@ function pushToSpace({
6466
6662
  if (existing) {
6467
6663
  const payload = { ...entity, sys: { id: entity.sys.id, type: "Experience", version: existing.sys.version } };
6468
6664
  const result = await client.experience.upsert({ spaceId, environmentId, experienceId: entity.sys.id }, payload);
6469
- import_logging9.logEmitter.emit("info", `UPDATE Experience ${entity.sys.id}`);
6665
+ import_logging11.logEmitter.emit("info", `UPDATE Experience ${entity.sys.id}`);
6470
6666
  return result;
6471
6667
  } else {
6472
6668
  const payload = { ...omitSys(entity), experienceTemplate: entity.sys.experienceTemplate, sys: { id: entity.sys.id, type: "Experience" } };
6473
6669
  const result = await client.experience.upsert({ spaceId, environmentId, experienceId: entity.sys.id }, payload);
6474
- import_logging9.logEmitter.emit("info", `CREATE Experience ${entity.sys.id}`);
6670
+ import_logging11.logEmitter.emit("info", `CREATE Experience ${entity.sys.id}`);
6475
6671
  return result;
6476
6672
  }
6477
6673
  } catch (err) {
6478
6674
  err.entity = entity;
6479
- import_logging9.logEmitter.emit("error", err);
6675
+ import_logging11.logEmitter.emit("error", err);
6480
6676
  return null;
6481
6677
  }
6482
6678
  }));
@@ -6573,10 +6769,41 @@ function archiveEntities2({ entities, sourceEntities, client, spaceId, environme
6573
6769
  const entitiesToArchive = entities.filter((entity) => entityIdsToArchive.indexOf(entity.sys.id) !== -1);
6574
6770
  return archiveEntities({ entities: entitiesToArchive, client, spaceId, environmentId, requestQueue });
6575
6771
  }
6576
- function publishEntities2({ entities, sourceEntities, client, spaceId, environmentId, requestQueue }) {
6772
+ async function publishEntities2({ entities, sourceEntities, client, spaceId, environmentId, requestQueue, destinationEntitiesById }) {
6577
6773
  const entityIdsToPublish = sourceEntities.filter(({ original }) => original.sys.publishedVersion).map(({ original }) => original.sys.id);
6578
- const entitiesToPublish = entities.filter((entity) => entityIdsToPublish.indexOf(entity.sys.id) !== -1);
6579
- return publishEntities({ entities: entitiesToPublish, client, spaceId, environmentId, requestQueue });
6774
+ let entitiesToPublish = entities.filter((entity) => entityIdsToPublish.indexOf(entity.sys.id) !== -1);
6775
+ const publishAllLocales = () => publishEntities({ entities: entitiesToPublish, client, spaceId, environmentId, requestQueue });
6776
+ const hasFieldStatus = sourceEntities.some(({ original }) => original.sys.fieldStatus);
6777
+ if (!hasFieldStatus) {
6778
+ return publishAllLocales();
6779
+ }
6780
+ await ensureLocalePublishingEntitlement(client, spaceId);
6781
+ if (isLocaleScopingUnavailable(client)) {
6782
+ return publishAllLocales();
6783
+ }
6784
+ const destinationLocaleCodes = await getDestinationLocaleCodes({ client, spaceId, environmentId, requestQueue });
6785
+ const localePublishing = buildLocalePublishPlan(
6786
+ sourceEntities,
6787
+ destinationLocaleCodes,
6788
+ { destinationEntitiesById }
6789
+ );
6790
+ if (localePublishing.skippedEntityIds.size) {
6791
+ entitiesToPublish = entitiesToPublish.filter((entity) => {
6792
+ if (!localePublishing.skippedEntityIds.has(entity.sys.id)) {
6793
+ return true;
6794
+ }
6795
+ 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`);
6796
+ return false;
6797
+ });
6798
+ }
6799
+ return publishEntities({
6800
+ entities: entitiesToPublish,
6801
+ client,
6802
+ spaceId,
6803
+ environmentId,
6804
+ requestQueue,
6805
+ localePublishing
6806
+ });
6580
6807
  }
6581
6808
 
6582
6809
  // lib/transform/transformers.ts
@@ -7113,6 +7340,7 @@ async function parseOptions(params) {
7113
7340
  skipContentModel: false,
7114
7341
  skipLocales: false,
7115
7342
  skipContentPublishing: false,
7343
+ unpublishDraftLocales: false,
7116
7344
  skipAssetUpdates: false,
7117
7345
  skipContentUpdates: false,
7118
7346
  useVerboseRenderer: false,
@@ -7221,7 +7449,7 @@ async function runContentfulImport(params) {
7221
7449
  intervalCap: options.rateLimit,
7222
7450
  carryoverConcurrencyCount: true
7223
7451
  });
7224
- (0, import_logging10.setupLogging)(log);
7452
+ (0, import_logging12.setupLogging)(log);
7225
7453
  const infoTable = new Table(tableOptions);
7226
7454
  infoTable.push([{ colSpan: 2, content: "The following entities are going to be imported:" }]);
7227
7455
  Object.keys(options.content).forEach((type) => {
@@ -7289,6 +7517,7 @@ async function runContentfulImport(params) {
7289
7517
  skipLocales: options.skipLocales,
7290
7518
  skipContentModel: options.skipContentModel,
7291
7519
  skipContentPublishing: options.skipContentPublishing,
7520
+ unpublishDraftLocales: options.unpublishDraftLocales,
7292
7521
  skipAssetUpdates: options.skipAssetUpdates,
7293
7522
  skipContentUpdates: options.skipContentUpdates,
7294
7523
  timeout: options.timeout,
@@ -7330,9 +7559,9 @@ async function runContentfulImport(params) {
7330
7559
  }).then((data) => {
7331
7560
  const errorLog = log.filter((logMessage) => logMessage.level !== "info" && logMessage.level !== "warning");
7332
7561
  const displayLog = log.filter((logMessage) => logMessage.level !== "info");
7333
- (0, import_logging10.displayErrorLog)(displayLog);
7562
+ (0, import_logging12.displayErrorLog)(displayLog);
7334
7563
  if (errorLog.length) {
7335
- return (0, import_logging10.writeErrorLogFile)(options.errorLogFile, errorLog).then(() => {
7564
+ return (0, import_logging12.writeErrorLogFile)(options.errorLogFile, errorLog).then(() => {
7336
7565
  const multiError = new ContentfulMultiError("Errors occurred");
7337
7566
  multiError.name = "ContentfulMultiError";
7338
7567
  multiError.errors = errorLog;