contentful-import 10.3.0 → 10.5.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
@@ -263,7 +263,7 @@ var require_logging = __commonJS({
263
263
  throw new Error("Unable to extract API error data");
264
264
  }
265
265
  }
266
- function formatLogMessageOneLine(logMessage) {
266
+ function formatLogMessageOneLine2(logMessage) {
267
267
  const { level } = logMessage;
268
268
  if (!level) {
269
269
  return logMessage.toString().replace(/\s+/g, " ");
@@ -299,7 +299,7 @@ var require_logging = __commonJS({
299
299
  return logMessage.error.toString().replace(/\s+/g, " ");
300
300
  }
301
301
  }
302
- exports2.formatLogMessageOneLine = formatLogMessageOneLine;
302
+ exports2.formatLogMessageOneLine = formatLogMessageOneLine2;
303
303
  function formatLogMessageLogfile(logMessage) {
304
304
  const { level } = logMessage;
305
305
  if (level === "info" || level === "warning") {
@@ -338,7 +338,7 @@ var require_logging = __commonJS({
338
338
 
339
339
  The following ${count.errors} errors and ${count.warnings} warnings occurred:
340
340
  `);
341
- errorLog.map((logMessage) => `${(0, format_1.default)((0, parseISO_1.default)(logMessage.ts), "HH:mm:ss")} - ${formatLogMessageOneLine(logMessage)}`).map((logMessage) => console.log(logMessage));
341
+ errorLog.map((logMessage) => `${(0, format_1.default)((0, parseISO_1.default)(logMessage.ts), "HH:mm:ss")} - ${formatLogMessageOneLine2(logMessage)}`).map((logMessage) => console.log(logMessage));
342
342
  return;
343
343
  }
344
344
  console.log("No errors or warnings occurred");
@@ -385,7 +385,7 @@ The following ${count.errors} errors and ${count.warnings} warnings occurred:
385
385
  exports2.setupLogging = setupLogging2;
386
386
  function logToTaskOutput(task) {
387
387
  function logToTask(logMessage) {
388
- const content = formatLogMessageOneLine(logMessage);
388
+ const content = formatLogMessageOneLine2(logMessage);
389
389
  const symbols = {
390
390
  info: figures_1.default.tick,
391
391
  warning: figures_1.default.warning,
@@ -598,12 +598,12 @@ var require_common = __commonJS({
598
598
  args.unshift("%O");
599
599
  }
600
600
  let index = 0;
601
- args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format2) => {
601
+ args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format3) => {
602
602
  if (match === "%%") {
603
603
  return "%";
604
604
  }
605
605
  index++;
606
- const formatter = createDebug.formatters[format2];
606
+ const formatter = createDebug.formatters[format3];
607
607
  if (typeof formatter === "function") {
608
608
  const val = args[index];
609
609
  match = formatter.call(self2, val);
@@ -2047,7 +2047,7 @@ __export(index_exports, {
2047
2047
  });
2048
2048
  module.exports = __toCommonJS(index_exports);
2049
2049
  var import_cli_table3 = __toESM(require("cli-table3"));
2050
- var import_date_fns2 = require("date-fns");
2050
+ var import_date_fns3 = require("date-fns");
2051
2051
  var import_listr3 = __toESM(require("listr"));
2052
2052
  var import_listr_update_renderer = __toESM(require("listr-update-renderer"));
2053
2053
  var import_listr_verbose_renderer2 = __toESM(require("listr-verbose-renderer"));
@@ -4550,34 +4550,6 @@ var createBaseEach_default = createBaseEach;
4550
4550
  var baseEach = createBaseEach_default(baseForOwn_default);
4551
4551
  var baseEach_default = baseEach;
4552
4552
 
4553
- // node_modules/lodash-es/defaults.js
4554
- var objectProto18 = Object.prototype;
4555
- var hasOwnProperty15 = objectProto18.hasOwnProperty;
4556
- var defaults = baseRest_default(function(object, sources) {
4557
- object = Object(object);
4558
- var index = -1;
4559
- var length = sources.length;
4560
- var guard = length > 2 ? sources[2] : void 0;
4561
- if (guard && isIterateeCall_default(sources[0], sources[1], guard)) {
4562
- length = 1;
4563
- }
4564
- while (++index < length) {
4565
- var source = sources[index];
4566
- var props = keysIn_default(source);
4567
- var propsIndex = -1;
4568
- var propsLength = props.length;
4569
- while (++propsIndex < propsLength) {
4570
- var key = props[propsIndex];
4571
- var value = object[key];
4572
- if (value === void 0 || eq_default(value, objectProto18[key]) && !hasOwnProperty15.call(object, key)) {
4573
- object[key] = source[key];
4574
- }
4575
- }
4576
- }
4577
- return object;
4578
- });
4579
- var defaults_default = defaults;
4580
-
4581
4553
  // node_modules/lodash-es/last.js
4582
4554
  function last(array) {
4583
4555
  var length = array == null ? 0 : array.length;
@@ -4658,10 +4630,10 @@ function map(collection, iteratee) {
4658
4630
  var map_default = map;
4659
4631
 
4660
4632
  // node_modules/lodash-es/_baseHas.js
4661
- var objectProto19 = Object.prototype;
4662
- var hasOwnProperty16 = objectProto19.hasOwnProperty;
4633
+ var objectProto18 = Object.prototype;
4634
+ var hasOwnProperty15 = objectProto18.hasOwnProperty;
4663
4635
  function baseHas(object, key) {
4664
- return object != null && hasOwnProperty16.call(object, key);
4636
+ return object != null && hasOwnProperty15.call(object, key);
4665
4637
  }
4666
4638
  var baseHas_default = baseHas;
4667
4639
 
@@ -4715,8 +4687,8 @@ function negate(predicate) {
4715
4687
  var negate_default = negate;
4716
4688
 
4717
4689
  // node_modules/lodash-es/_baseUnset.js
4718
- var objectProto20 = Object.prototype;
4719
- var hasOwnProperty17 = objectProto20.hasOwnProperty;
4690
+ var objectProto19 = Object.prototype;
4691
+ var hasOwnProperty16 = objectProto19.hasOwnProperty;
4720
4692
  function baseUnset(object, path) {
4721
4693
  path = castPath_default(path, object);
4722
4694
  var index = -1, length = path.length;
@@ -4725,7 +4697,7 @@ function baseUnset(object, path) {
4725
4697
  }
4726
4698
  while (++index < length) {
4727
4699
  var key = toKey_default(path[index]);
4728
- if (key === "__proto__" && !hasOwnProperty17.call(object, "__proto__")) {
4700
+ if (key === "__proto__" && !hasOwnProperty16.call(object, "__proto__")) {
4729
4701
  return false;
4730
4702
  }
4731
4703
  if ((key === "constructor" || key === "prototype") && index < length - 1) {
@@ -4889,7 +4861,7 @@ var startCase_default = startCase;
4889
4861
 
4890
4862
  // lib/index.ts
4891
4863
  var import_p_queue = __toESM(require("p-queue"));
4892
- var import_logging12 = __toESM(require_logging());
4864
+ var import_logging14 = __toESM(require_logging());
4893
4865
  var import_listr4 = __toESM(require_listr());
4894
4866
 
4895
4867
  // lib/tasks/init-client.ts
@@ -4922,17 +4894,17 @@ var import_logging3 = __toESM(require_logging());
4922
4894
 
4923
4895
  // lib/utils/publish-exo-entities.ts
4924
4896
  var import_logging2 = __toESM(require_logging());
4925
- function filterExoEntitiesToPublish(entities, sourceEntities) {
4897
+ function filterExoEntitiesToPublish(entities2, sourceEntities) {
4926
4898
  const entityIdsToPublish = new Set(
4927
4899
  sourceEntities.filter((entity) => entity.sys.publishedVersion).map((entity) => entity.sys.id)
4928
4900
  );
4929
- return entities.filter((entity) => entityIdsToPublish.has(entity.sys.id));
4901
+ return entities2.filter((entity) => entityIdsToPublish.has(entity.sys.id));
4930
4902
  }
4931
- function filterExoEntitiesToUnpublish(entities, sourceEntities) {
4903
+ function filterExoEntitiesToUnpublish(entities2, sourceEntities) {
4932
4904
  const entityIdsPublishedInSource = new Set(
4933
4905
  sourceEntities.filter((entity) => entity.sys.publishedVersion).map((entity) => entity.sys.id)
4934
4906
  );
4935
- return entities.filter((entity) => entity.sys.publishedVersion && !entityIdsPublishedInSource.has(entity.sys.id));
4907
+ return entities2.filter((entity) => entity.sys.publishedVersion && !entityIdsPublishedInSource.has(entity.sys.id));
4936
4908
  }
4937
4909
  async function publishExoEntity(type, entity, publish) {
4938
4910
  try {
@@ -4955,6 +4927,34 @@ async function unpublishExoEntity(type, entity, unpublish) {
4955
4927
  return null;
4956
4928
  }
4957
4929
  }
4930
+ function filterVariantsToPublish(variants) {
4931
+ return variants.filter((v) => v.sys.publishedVersion);
4932
+ }
4933
+ function filterVariantsToArchive(variants) {
4934
+ return variants.filter((v) => v.sys.archivedVersion && !v.sys.publishedVersion);
4935
+ }
4936
+ async function publishVariant(type, entity, publish) {
4937
+ try {
4938
+ const result = await publish();
4939
+ import_logging2.logEmitter.emit("info", `PUBLISH ${type} ${entity.sys.variant}`);
4940
+ return result;
4941
+ } catch (err) {
4942
+ err.entity = entity;
4943
+ import_logging2.logEmitter.emit("error", err);
4944
+ return null;
4945
+ }
4946
+ }
4947
+ async function archiveVariant(type, entity, archive) {
4948
+ try {
4949
+ const result = await archive();
4950
+ import_logging2.logEmitter.emit("info", `ARCHIVE ${type} ${entity.sys.variant}`);
4951
+ return result;
4952
+ } catch (err) {
4953
+ err.entity = entity;
4954
+ import_logging2.logEmitter.emit("error", err);
4955
+ return null;
4956
+ }
4957
+ }
4958
4958
  function isExoEntitlementError(err) {
4959
4959
  if (!(err instanceof Error)) {
4960
4960
  return false;
@@ -4966,6 +4966,17 @@ function isExoEntitlementError(err) {
4966
4966
  return false;
4967
4967
  }
4968
4968
  }
4969
+ function isTimelineEntitlementError(err) {
4970
+ if (!(err instanceof Error)) {
4971
+ return false;
4972
+ }
4973
+ try {
4974
+ const parsed = JSON.parse(err.message);
4975
+ return parsed?.status === 403 && parsed?.details?.reasons === "Timeline is not enabled for this organization";
4976
+ } catch {
4977
+ return false;
4978
+ }
4979
+ }
4969
4980
  var EXO_M1_FEATURE = "exoM1";
4970
4981
  async function spaceHasExoM1Entitlement(client, spaceId) {
4971
4982
  try {
@@ -4992,7 +5003,8 @@ var CURSOR_QUERY_METHODS = {
4992
5003
  experienceTemplates: { name: "experience templates", namespace: "experienceTemplate" },
4993
5004
  experienceFragments: { name: "experience fragments", namespace: "experienceFragment" },
4994
5005
  dataAssemblies: { name: "data assemblies", namespace: "dataAssembly" },
4995
- experiences: { name: "experiences", namespace: "experience" }
5006
+ experiences: { name: "experiences", namespace: "experience" },
5007
+ releases: { name: "releases", namespace: "release" }
4996
5008
  };
4997
5009
  var ENTITY_METHODS = {
4998
5010
  contentTypes: { name: "content types", ns: "contentType" },
@@ -5095,11 +5107,26 @@ async function cursorPaginatedQuery({ client, spaceId, environmentId, type, requ
5095
5107
  const allItems = [];
5096
5108
  do {
5097
5109
  const items = await requestQueue.add(async () => {
5098
- const response = await client[namespace].getMany({
5099
- spaceId,
5100
- environmentId,
5101
- query: { limit: BATCH_SIZE_LIMIT, ...pageNext && { pageNext } }
5102
- });
5110
+ let response;
5111
+ if (type === "releases") {
5112
+ response = await client.release.query({
5113
+ environmentId,
5114
+ spaceId,
5115
+ query: {
5116
+ "metadata.annotations.Contentful:Timeline.type[nin]": "Staging,Hidden",
5117
+ "sys.schemaVersion": "Release.v2",
5118
+ "sys.status[in]": "active",
5119
+ limit: BATCH_SIZE_LIMIT,
5120
+ ...pageNext && { pageNext }
5121
+ }
5122
+ });
5123
+ } else {
5124
+ response = await client[namespace].getMany({
5125
+ spaceId,
5126
+ environmentId,
5127
+ query: { limit: BATCH_SIZE_LIMIT, ...pageNext && { pageNext } }
5128
+ });
5129
+ }
5103
5130
  totalFetched += response.items.length;
5104
5131
  import_logging3.logEmitter.emit("info", `Fetched ${totalFetched} ${entityTypeName}`);
5105
5132
  pageNext = response.pages?.next;
@@ -5116,6 +5143,8 @@ async function cursorPaginatedQueryOrWarn(params) {
5116
5143
  const { name: entityTypeName } = CURSOR_QUERY_METHODS[params.type];
5117
5144
  if (isExoEntitlementError(err)) {
5118
5145
  import_logging3.logEmitter.emit("error", new Error(`Skipping ${entityTypeName} import: Experience Orchestration (ExO) is not enabled for this space`));
5146
+ } else if (isTimelineEntitlementError(err)) {
5147
+ import_logging3.logEmitter.emit("error", new Error(`Skipping ${entityTypeName} import: Timeline (Releases) is not enabled for this organization`));
5119
5148
  } else {
5120
5149
  import_logging3.logEmitter.emit("error", err instanceof Error ? err : new Error(String(err)));
5121
5150
  }
@@ -5145,7 +5174,8 @@ async function getDestinationData({
5145
5174
  experienceFragments: [],
5146
5175
  dataAssemblies: [],
5147
5176
  designTokens: [],
5148
- webhooks: []
5177
+ webhooks: [],
5178
+ releases: []
5149
5179
  };
5150
5180
  sourceData = {
5151
5181
  ...result,
@@ -5206,6 +5236,7 @@ async function getDestinationData({
5206
5236
  requestQueue
5207
5237
  });
5208
5238
  }
5239
+ result.releases = cursorPaginatedQueryOrWarn({ client, spaceId, environmentId, type: "releases", requestQueue });
5209
5240
  if (includeExperienceOrchestration && client) {
5210
5241
  const sourceHasDesignTokens = Boolean(sourceData.designTokens?.length);
5211
5242
  const sourceHasComponents = Boolean(sourceData.components?.length);
@@ -5245,7 +5276,7 @@ async function getDestinationData({
5245
5276
  // lib/tasks/push-to-space/push-to-space.ts
5246
5277
  var import_listr = __toESM(require("listr"));
5247
5278
  var import_listr_verbose_renderer = __toESM(require("listr-verbose-renderer"));
5248
- var import_logging11 = __toESM(require_logging());
5279
+ var import_logging12 = __toESM(require_logging());
5249
5280
  var import_listr2 = __toESM(require_listr());
5250
5281
 
5251
5282
  // lib/tasks/push-to-space/assets.ts
@@ -5345,14 +5376,14 @@ async function processAssets({
5345
5376
  // lib/tasks/push-to-space/creation.ts
5346
5377
  var import_get_entity_name2 = __toESM(require_get_entity_name());
5347
5378
  var import_logging5 = __toESM(require_logging());
5348
- function createEntities({ context, entities, destinationEntitiesById, skipUpdates, requestQueue }) {
5349
- return createEntitiesWithConcurrency({ context, entities, destinationEntitiesById, skipUpdates, requestQueue });
5379
+ function createEntities({ context, entities: entities2, destinationEntitiesById, skipUpdates, requestQueue }) {
5380
+ return createEntitiesWithConcurrency({ context, entities: entities2, destinationEntitiesById, skipUpdates, requestQueue });
5350
5381
  }
5351
- function createLocales({ context, entities, destinationEntitiesById, requestQueue }) {
5352
- return createEntitiesInSequence({ context, entities, destinationEntitiesById, requestQueue });
5382
+ function createLocales({ context, entities: entities2, destinationEntitiesById, requestQueue }) {
5383
+ return createEntitiesInSequence({ context, entities: entities2, destinationEntitiesById, requestQueue });
5353
5384
  }
5354
- async function createEntitiesWithConcurrency({ context, entities, destinationEntitiesById, skipUpdates, requestQueue }) {
5355
- const pendingCreatedEntities = entities.map((entity) => {
5385
+ async function createEntitiesWithConcurrency({ context, entities: entities2, destinationEntitiesById, skipUpdates, requestQueue }) {
5386
+ const pendingCreatedEntities = entities2.map((entity) => {
5356
5387
  const destinationEntity = getDestinationEntityForSourceEntity(destinationEntitiesById, entity.transformed);
5357
5388
  const updateOperation = skipUpdates ? "skip" : "update";
5358
5389
  const operation = destinationEntity ? updateOperation : "create";
@@ -5373,9 +5404,9 @@ async function createEntitiesWithConcurrency({ context, entities, destinationEnt
5373
5404
  const createdEntities = await Promise.all(pendingCreatedEntities);
5374
5405
  return createdEntities.filter((entity) => entity);
5375
5406
  }
5376
- async function createEntitiesInSequence({ context, entities, destinationEntitiesById, requestQueue }) {
5407
+ async function createEntitiesInSequence({ context, entities: entities2, destinationEntitiesById, requestQueue }) {
5377
5408
  const createdEntities = [];
5378
- for (const entity of entities) {
5409
+ for (const entity of entities2) {
5379
5410
  const destinationEntity = getDestinationEntityForSourceEntity(destinationEntitiesById, entity.transformed);
5380
5411
  const operation = destinationEntity ? "update" : "create";
5381
5412
  try {
@@ -5394,8 +5425,8 @@ async function createEntitiesInSequence({ context, entities, destinationEntities
5394
5425
  }
5395
5426
  return createdEntities;
5396
5427
  }
5397
- async function createEntries({ context, entities, destinationEntitiesById, skipUpdates, requestQueue }) {
5398
- const createdEntries = await Promise.all(entities.map((entry) => {
5428
+ async function createEntries({ context, entities: entities2, destinationEntitiesById, skipUpdates, requestQueue }) {
5429
+ const createdEntries = await Promise.all(entities2.map((entry) => {
5399
5430
  return createEntry({ entry, context, destinationEntitiesById, skipUpdates, requestQueue });
5400
5431
  }));
5401
5432
  return createdEntries.filter((entry) => entry);
@@ -5650,27 +5681,27 @@ function archiveEntity(client, spaceId, environmentId, entity) {
5650
5681
  }
5651
5682
  throw new Error(`archiveEntity: unsupported type "${type}"`);
5652
5683
  }
5653
- async function publishEntities({ entities, client, spaceId, environmentId, requestQueue, localePublishing }) {
5654
- if (entities.length === 0) {
5684
+ async function publishEntities({ entities: entities2, client, spaceId, environmentId, requestQueue, localePublishing }) {
5685
+ if (entities2.length === 0) {
5655
5686
  import_logging7.logEmitter.emit("info", "Skipping publishing since zero valid entities passed");
5656
5687
  return [];
5657
5688
  }
5658
- const entity = entities[0];
5689
+ const entity = entities2[0];
5659
5690
  const type = entity.sys.type || "unknown type";
5660
- import_logging7.logEmitter.emit("info", `Publishing ${entities.length} ${type}s`);
5661
- const result = await runQueue(entities, [], client, spaceId, environmentId, requestQueue, localePublishing);
5691
+ import_logging7.logEmitter.emit("info", `Publishing ${entities2.length} ${type}s`);
5692
+ const result = await runQueue(entities2, [], client, spaceId, environmentId, requestQueue, localePublishing);
5662
5693
  import_logging7.logEmitter.emit("info", `Successfully published ${result.length} ${type}s`);
5663
5694
  return result;
5664
5695
  }
5665
- async function archiveEntities({ entities, client, spaceId, environmentId, requestQueue }) {
5666
- if (entities.length === 0) {
5696
+ async function archiveEntities({ entities: entities2, client, spaceId, environmentId, requestQueue }) {
5697
+ if (entities2.length === 0) {
5667
5698
  import_logging7.logEmitter.emit("info", "Skipping archiving since zero valid entities passed");
5668
5699
  return [];
5669
5700
  }
5670
- const entity = entities[0];
5701
+ const entity = entities2[0];
5671
5702
  const type = entity.sys.type || "unknown type";
5672
- import_logging7.logEmitter.emit("info", `Archiving ${entities.length} ${type}s`);
5673
- const pendingArchivedEntities = entities.map((entity2) => {
5703
+ import_logging7.logEmitter.emit("info", `Archiving ${entities2.length} ${type}s`);
5704
+ const pendingArchivedEntities = entities2.map((entity2) => {
5674
5705
  return requestQueue.add(async () => {
5675
5706
  try {
5676
5707
  const archivedEntity = await archiveEntity(client, spaceId, environmentId, entity2);
@@ -5758,6 +5789,55 @@ async function runQueue(queue, result = [], client, spaceId, environmentId, requ
5758
5789
  return result;
5759
5790
  }
5760
5791
 
5792
+ // lib/tasks/push-to-space/releases.ts
5793
+ var import_logging8 = __toESM(require_logging());
5794
+ function partitionReleasesBySchemaVersion(releases2) {
5795
+ return {
5796
+ supported: releases2.filter((release) => release.transformed.sys.schemaVersion === "Release.v2"),
5797
+ unsupported: releases2.filter((release) => release.transformed.sys.schemaVersion !== "Release.v2")
5798
+ };
5799
+ }
5800
+ function logUnsupportedRelease(release) {
5801
+ import_logging8.logEmitter.emit("error", new Error(
5802
+ `Skipping Release "${release.transformed.sys.id}": only Release.v2 ("Releases") is supported, got schemaVersion "${release.transformed.sys.schemaVersion}"`
5803
+ ));
5804
+ }
5805
+ function buildReleaseCreatePayload(release) {
5806
+ const { id: _sourceId, ...sourceSysWithoutId } = release.transformed.sys;
5807
+ return {
5808
+ ...release.transformed,
5809
+ entities: release.transformed.entities,
5810
+ sys: { ...sourceSysWithoutId, type: "Release", schemaVersion: "Release.v2" }
5811
+ };
5812
+ }
5813
+ function buildReleaseUpdatePayload(release) {
5814
+ return {
5815
+ ...release.transformed,
5816
+ entities: release.transformed.entities,
5817
+ sys: { type: "Release", schemaVersion: "Release.v2" }
5818
+ };
5819
+ }
5820
+ async function importRelease(release, existing, context) {
5821
+ const { client, spaceId, environmentId } = context;
5822
+ try {
5823
+ if (existing) {
5824
+ const result2 = await client.release.update(
5825
+ { spaceId, environmentId, releaseId: existing.sys.id, version: existing.sys.version },
5826
+ buildReleaseUpdatePayload(release)
5827
+ );
5828
+ import_logging8.logEmitter.emit("info", `UPDATE Release ${existing.sys.id}`);
5829
+ return result2;
5830
+ }
5831
+ const result = await client.release.create({ spaceId, environmentId }, buildReleaseCreatePayload(release));
5832
+ import_logging8.logEmitter.emit("info", `CREATE Release ${result.sys.id}`);
5833
+ return result;
5834
+ } catch (err) {
5835
+ err.entity = release.transformed;
5836
+ import_logging8.logEmitter.emit("error", err);
5837
+ return null;
5838
+ }
5839
+ }
5840
+
5761
5841
  // lib/utils/graphql-schema-backoff.ts
5762
5842
  var GRAPHQL_SCHEMA_STALE_DELAYS_MS = [500, 1500, 6e3];
5763
5843
  function isGraphQLSchemaStaleError(err) {
@@ -5884,18 +5964,18 @@ function sortExperienceFragments(experienceFragments) {
5884
5964
  }
5885
5965
 
5886
5966
  // lib/utils/sort-or-report.ts
5887
- var import_logging8 = __toESM(require_logging());
5967
+ var import_logging9 = __toESM(require_logging());
5888
5968
  function sortOrReport(sortFn) {
5889
5969
  try {
5890
5970
  return sortFn();
5891
5971
  } catch (err) {
5892
- import_logging8.logEmitter.emit("error", err);
5972
+ import_logging9.logEmitter.emit("error", err);
5893
5973
  throw err;
5894
5974
  }
5895
5975
  }
5896
5976
 
5897
5977
  // lib/utils/import-exo-folders.ts
5898
- var import_logging9 = __toESM(require_logging());
5978
+ var import_logging10 = __toESM(require_logging());
5899
5979
  var FOLDER_CONCEPT_PREFIX = "contentful.folder-";
5900
5980
  var PARENT_FOLDER_GROUP_IDS = {
5901
5981
  designToken: "contentful.folder-group-designToken",
@@ -5912,8 +5992,8 @@ var ENTITY_TYPE_TO_PARENT_GROUP_ID = {
5912
5992
  experiences: PARENT_FOLDER_GROUP_IDS.experience
5913
5993
  };
5914
5994
  function getSourceSpaceId(sourceEntities) {
5915
- for (const entities of Object.values(sourceEntities)) {
5916
- for (const entity of entities ?? []) {
5995
+ for (const entities2 of Object.values(sourceEntities)) {
5996
+ for (const entity of entities2 ?? []) {
5917
5997
  const spaceId = entity.sys?.space?.sys?.id;
5918
5998
  if (spaceId) return spaceId;
5919
5999
  }
@@ -5965,7 +6045,7 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
5965
6045
  existing = await client.concept.get({ organizationId, conceptId: destConceptId });
5966
6046
  } catch (err) {
5967
6047
  if (err?.name !== "NotFound") {
5968
- import_logging9.logEmitter.emit("warning", `Could not fetch destination child concept ${destConceptId}: ${err?.message ?? err}`);
6048
+ import_logging10.logEmitter.emit("warning", `Could not fetch destination child concept ${destConceptId}: ${err?.message ?? err}`);
5969
6049
  }
5970
6050
  }
5971
6051
  if (!existing) {
@@ -5975,9 +6055,9 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
5975
6055
  // @ts-expect-error - CMA.js type needs to be updated to be aware of purpose: 'internal'
5976
6056
  { purpose: "internal", prefLabel, metadata: { spaces: [spaceLink] } }
5977
6057
  );
5978
- import_logging9.logEmitter.emit("info", `Created child folder concept ${destConceptId}`);
6058
+ import_logging10.logEmitter.emit("info", `Created child folder concept ${destConceptId}`);
5979
6059
  } catch (err) {
5980
- import_logging9.logEmitter.emit("error", `Failed to create child folder concept ${destConceptId}: ${err?.message ?? err}`);
6060
+ import_logging10.logEmitter.emit("error", `Failed to create child folder concept ${destConceptId}: ${err?.message ?? err}`);
5981
6061
  }
5982
6062
  } else {
5983
6063
  const patches = [];
@@ -5991,9 +6071,9 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
5991
6071
  { organizationId, conceptId: destConceptId, version: existing.sys.version },
5992
6072
  patches
5993
6073
  );
5994
- import_logging9.logEmitter.emit("info", `Patched child folder concept ${destConceptId} (${patches.map((p) => p.path).join(", ")})`);
6074
+ import_logging10.logEmitter.emit("info", `Patched child folder concept ${destConceptId} (${patches.map((p) => p.path).join(", ")})`);
5995
6075
  } catch (err) {
5996
- import_logging9.logEmitter.emit("error", `Failed to patch child folder concept ${destConceptId}: ${err?.message ?? err}`);
6076
+ import_logging10.logEmitter.emit("error", `Failed to patch child folder concept ${destConceptId}: ${err?.message ?? err}`);
5997
6077
  }
5998
6078
  }
5999
6079
  }
@@ -6011,14 +6091,14 @@ async function linkChildConceptsToParentGroups(client, organizationId, childConc
6011
6091
  [{ op: "add", path: "/concepts/-", value: { sys: { type: "Link", linkType: "TaxonomyConcept", id: destConceptId } } }]
6012
6092
  );
6013
6093
  parentGroups.set(parentGroupId, updated);
6014
- import_logging9.logEmitter.emit("info", `Linked child concept ${destConceptId} to parent group ${parentGroupId}`);
6094
+ import_logging10.logEmitter.emit("info", `Linked child concept ${destConceptId} to parent group ${parentGroupId}`);
6015
6095
  } catch (err) {
6016
- import_logging9.logEmitter.emit("error", `Failed to link child concept ${destConceptId} to parent group ${parentGroupId}: ${err?.message ?? err}`);
6096
+ import_logging10.logEmitter.emit("error", `Failed to link child concept ${destConceptId} to parent group ${parentGroupId}: ${err?.message ?? err}`);
6017
6097
  }
6018
6098
  }
6019
6099
  }
6020
- function rewriteEntityFolderConcepts(entities, childConceptMap) {
6021
- for (const entity of entities) {
6100
+ function rewriteEntityFolderConcepts(entities2, childConceptMap) {
6101
+ for (const entity of entities2) {
6022
6102
  if (!entity.metadata?.concepts) continue;
6023
6103
  entity.metadata.concepts = entity.metadata.concepts.map((link) => {
6024
6104
  const entry = childConceptMap.get(link.sys.id);
@@ -6035,17 +6115,17 @@ async function importExoFolders({
6035
6115
  }) {
6036
6116
  const sourceSpaceId = getSourceSpaceId(sourceEntities);
6037
6117
  if (sourceSpaceId === destinationSpaceId) {
6038
- import_logging9.logEmitter.emit("info", "Source and destination space are the same \u2014 skipping ExO folder import");
6118
+ import_logging10.logEmitter.emit("info", "Source and destination space are the same \u2014 skipping ExO folder import");
6039
6119
  return;
6040
6120
  }
6041
6121
  const parentGroups = await ensureParentFolderGroupsExist(client, organizationId);
6042
6122
  if (parentGroups.size === 0) {
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.");
6123
+ import_logging10.logEmitter.emit("warn", "One or more Experience Orchestration folder group concept schemes are missing in the destination organization. Please create them before importing.");
6044
6124
  return;
6045
6125
  }
6046
6126
  const childConceptMap = deriveChildConceptMap(sourceEntities, destinationSpaceId);
6047
6127
  if (childConceptMap.size === 0) return;
6048
- import_logging9.logEmitter.emit("info", `Importing ${childConceptMap.size} ExO folder concept(s) into destination space ${destinationSpaceId}`);
6128
+ import_logging10.logEmitter.emit("info", `Importing ${childConceptMap.size} ExO folder concept(s) into destination space ${destinationSpaceId}`);
6049
6129
  await createOrPatchChildConcepts(client, organizationId, destinationSpaceId, childConceptMap);
6050
6130
  await linkChildConceptsToParentGroups(client, organizationId, childConceptMap, parentGroups);
6051
6131
  const allEntities = [
@@ -6111,7 +6191,7 @@ function buildLocalePublishPlan(sourceEntities, destinationLocaleCodes, { destin
6111
6191
  }
6112
6192
 
6113
6193
  // lib/utils/destination-locales.ts
6114
- var import_logging10 = __toESM(require_logging());
6194
+ var import_logging11 = __toESM(require_logging());
6115
6195
  var cache = /* @__PURE__ */ new WeakMap();
6116
6196
  function getDestinationLocaleCodes({ client, spaceId, environmentId, requestQueue }) {
6117
6197
  let byEnvironment = cache.get(client);
@@ -6123,7 +6203,7 @@ function getDestinationLocaleCodes({ client, spaceId, environmentId, requestQueu
6123
6203
  let localeCodes = byEnvironment.get(key);
6124
6204
  if (!localeCodes) {
6125
6205
  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}`);
6206
+ import_logging11.logEmitter.emit("warning", `Could not read the locales of the destination environment, falling back to publishing all locales: ${err.message}`);
6127
6207
  return null;
6128
6208
  });
6129
6209
  byEnvironment.set(key, localeCodes);
@@ -6142,7 +6222,7 @@ async function withGraphQLSchemaBackoff(fn) {
6142
6222
  throw err;
6143
6223
  }
6144
6224
  const delay = GRAPHQL_SCHEMA_STALE_DELAYS_MS[attempt];
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})`);
6225
+ import_logging12.logEmitter.emit("warning", `DataAssembly GraphQL schema not yet current, retrying in ${delay}ms (attempt ${attempt + 1}/${GRAPHQL_SCHEMA_STALE_DELAYS_MS.length})`);
6146
6226
  await new Promise((resolve2) => setTimeout(resolve2, delay));
6147
6227
  lastErr = err;
6148
6228
  }
@@ -6165,6 +6245,7 @@ function pushToSpace({
6165
6245
  spaceId,
6166
6246
  environmentId,
6167
6247
  includeExperienceOrchestration,
6248
+ skipExoVariants,
6168
6249
  contentModelOnly,
6169
6250
  skipContentModel,
6170
6251
  skipContentUpdates,
@@ -6187,13 +6268,20 @@ function pushToSpace({
6187
6268
  ...DEFAULT_CONTENT_STRUCTURE,
6188
6269
  ...destinationData
6189
6270
  };
6271
+ const hasOptimizationVariants = [
6272
+ ...sourceData.experiences || [],
6273
+ ...sourceData.experienceFragments || []
6274
+ ].some((parent2) => (parent2.optimizationVariants || []).some(isRealOptimizationVariant));
6275
+ if (includeExperienceOrchestration && !skipExoVariants && hasOptimizationVariants) {
6276
+ import_logging12.logEmitter.emit("warning", "Optimization Variants are imported with new destination IDs and can be duplicated by re-imports. Set skipExoVariants to true to skip them.");
6277
+ }
6190
6278
  listrOptions = listrOptions || {
6191
6279
  renderer: import_listr_verbose_renderer.default
6192
6280
  };
6193
6281
  const destinationDataById = {};
6194
- for (const [entityType, entities] of Object.entries(destinationData)) {
6282
+ for (const [entityType, entities2] of Object.entries(destinationData)) {
6195
6283
  const entitiesById = /* @__PURE__ */ new Map();
6196
- for (const entity of entities) {
6284
+ for (const entity of entities2) {
6197
6285
  entitiesById.set(entity.sys.id, entity);
6198
6286
  }
6199
6287
  destinationDataById[entityType] = entitiesById;
@@ -6282,7 +6370,7 @@ function pushToSpace({
6282
6370
  const ctEditorInterface = await requestQueue.add(
6283
6371
  () => client.editorInterface.get({ spaceId, environmentId, contentTypeId: contentType.sys.id })
6284
6372
  );
6285
- import_logging11.logEmitter.emit("info", `Fetched editor interface for ${contentType.name}`);
6373
+ import_logging12.logEmitter.emit("info", `Fetched editor interface for ${contentType.name}`);
6286
6374
  const updatedData = {
6287
6375
  ...ctEditorInterface,
6288
6376
  controls: editorInterface.controls,
@@ -6300,7 +6388,7 @@ function pushToSpace({
6300
6388
  return updatedEditorInterface;
6301
6389
  } catch (err) {
6302
6390
  err.entity = editorInterface;
6303
- import_logging11.logEmitter.emit("error", err);
6391
+ import_logging12.logEmitter.emit("error", err);
6304
6392
  return null;
6305
6393
  }
6306
6394
  });
@@ -6318,7 +6406,7 @@ function pushToSpace({
6318
6406
  for (const file of Object.values(asset.transformed.fields.file)) {
6319
6407
  allPendingUploads.push(requestQueue.add(async () => {
6320
6408
  try {
6321
- import_logging11.logEmitter.emit("info", `Uploading Asset file ${file.upload}`);
6409
+ import_logging12.logEmitter.emit("info", `Uploading Asset file ${file.upload}`);
6322
6410
  const assetStream = await getAssetStreamForURL(file.upload, assetsDirectory);
6323
6411
  const upload = await client.upload.create(
6324
6412
  { spaceId, environmentId },
@@ -6334,7 +6422,7 @@ function pushToSpace({
6334
6422
  };
6335
6423
  return upload;
6336
6424
  } catch (err) {
6337
- import_logging11.logEmitter.emit("error", err);
6425
+ import_logging12.logEmitter.emit("error", err);
6338
6426
  }
6339
6427
  }));
6340
6428
  }
@@ -6480,7 +6568,7 @@ function pushToSpace({
6480
6568
  }
6481
6569
  });
6482
6570
  } catch (error) {
6483
- import_logging11.logEmitter.emit("warning", `Unable to create Experience Orchestration (ExO) folders, error: ${error}`);
6571
+ import_logging12.logEmitter.emit("warning", `Unable to create Experience Orchestration (ExO) folders, error: ${error}`);
6484
6572
  }
6485
6573
  }),
6486
6574
  skip: () => !includeExperienceOrchestration
@@ -6498,19 +6586,19 @@ function pushToSpace({
6498
6586
  { spaceId, environmentId, dataAssemblyId: entity.sys.id },
6499
6587
  payload
6500
6588
  ));
6501
- import_logging11.logEmitter.emit("info", `UPDATE DataAssembly ${entity.sys.id}`);
6589
+ import_logging12.logEmitter.emit("info", `UPDATE DataAssembly ${entity.sys.id}`);
6502
6590
  } else {
6503
6591
  const payload = { ...omitSys(entity), sys: buildDataAssemblySys(entity, 0) };
6504
6592
  result = await withGraphQLSchemaBackoff(() => client.dataAssembly.update(
6505
6593
  { spaceId, environmentId, dataAssemblyId: entity.sys.id },
6506
6594
  payload
6507
6595
  ));
6508
- import_logging11.logEmitter.emit("info", `CREATE DataAssembly ${entity.sys.id}`);
6596
+ import_logging12.logEmitter.emit("info", `CREATE DataAssembly ${entity.sys.id}`);
6509
6597
  }
6510
6598
  return result;
6511
6599
  } catch (err) {
6512
6600
  err.entity = entity;
6513
- import_logging11.logEmitter.emit("error", err);
6601
+ import_logging12.logEmitter.emit("error", err);
6514
6602
  return null;
6515
6603
  }
6516
6604
  }));
@@ -6540,17 +6628,17 @@ function pushToSpace({
6540
6628
  if (existing) {
6541
6629
  const payload = { ...entity, sys: { id: entity.sys.id, type: "DesignToken", version: existing.sys.version } };
6542
6630
  const result = await client.designToken.upsert({ spaceId, environmentId, designTokenId: entity.sys.id }, payload);
6543
- import_logging11.logEmitter.emit("info", `UPDATE DesignToken ${entity.sys.id}`);
6631
+ import_logging12.logEmitter.emit("info", `UPDATE DesignToken ${entity.sys.id}`);
6544
6632
  return result;
6545
6633
  } else {
6546
6634
  const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "DesignToken" } };
6547
6635
  const result = await client.designToken.upsert({ spaceId, environmentId, designTokenId: entity.sys.id }, payload);
6548
- import_logging11.logEmitter.emit("info", `CREATE DesignToken ${entity.sys.id}`);
6636
+ import_logging12.logEmitter.emit("info", `CREATE DesignToken ${entity.sys.id}`);
6549
6637
  return result;
6550
6638
  }
6551
6639
  } catch (err) {
6552
6640
  err.entity = entity;
6553
- import_logging11.logEmitter.emit("error", err);
6641
+ import_logging12.logEmitter.emit("error", err);
6554
6642
  return null;
6555
6643
  }
6556
6644
  }));
@@ -6569,17 +6657,17 @@ function pushToSpace({
6569
6657
  if (existing) {
6570
6658
  const payload = { ...entity, sys: { id: entity.sys.id, type: "Component", version: existing.sys.version } };
6571
6659
  const result = await client.component.upsert({ spaceId, environmentId, componentId: entity.sys.id }, payload);
6572
- import_logging11.logEmitter.emit("info", `UPDATE Component ${entity.sys.id}`);
6660
+ import_logging12.logEmitter.emit("info", `UPDATE Component ${entity.sys.id}`);
6573
6661
  results.push(result);
6574
6662
  } else {
6575
6663
  const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "Component" } };
6576
6664
  const result = await client.component.upsert({ spaceId, environmentId, componentId: entity.sys.id }, payload);
6577
- import_logging11.logEmitter.emit("info", `CREATE Component ${entity.sys.id}`);
6665
+ import_logging12.logEmitter.emit("info", `CREATE Component ${entity.sys.id}`);
6578
6666
  results.push(result);
6579
6667
  }
6580
6668
  } catch (err) {
6581
6669
  err.entity = entity;
6582
- import_logging11.logEmitter.emit("error", err);
6670
+ import_logging12.logEmitter.emit("error", err);
6583
6671
  }
6584
6672
  }
6585
6673
  ctx.data.components = results;
@@ -6611,17 +6699,17 @@ function pushToSpace({
6611
6699
  if (existing) {
6612
6700
  const payload = { ...entity, sys: { id: entity.sys.id, type: "ExperienceTemplate", version: existing.sys.version } };
6613
6701
  const result = await client.experienceTemplate.upsert({ spaceId, environmentId, experienceTemplateId: entity.sys.id }, payload);
6614
- import_logging11.logEmitter.emit("info", `UPDATE ExperienceTemplate ${entity.sys.id}`);
6702
+ import_logging12.logEmitter.emit("info", `UPDATE ExperienceTemplate ${entity.sys.id}`);
6615
6703
  return result;
6616
6704
  } else {
6617
6705
  const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "ExperienceTemplate" } };
6618
6706
  const result = await client.experienceTemplate.upsert({ spaceId, environmentId, experienceTemplateId: entity.sys.id }, payload);
6619
- import_logging11.logEmitter.emit("info", `CREATE ExperienceTemplate ${entity.sys.id}`);
6707
+ import_logging12.logEmitter.emit("info", `CREATE ExperienceTemplate ${entity.sys.id}`);
6620
6708
  return result;
6621
6709
  }
6622
6710
  } catch (err) {
6623
6711
  err.entity = entity;
6624
- import_logging11.logEmitter.emit("error", err);
6712
+ import_logging12.logEmitter.emit("error", err);
6625
6713
  return null;
6626
6714
  }
6627
6715
  }));
@@ -6651,19 +6739,19 @@ function pushToSpace({
6651
6739
  try {
6652
6740
  const existing = destinationDataById.experienceFragments?.get(entity.sys.id);
6653
6741
  if (existing) {
6654
- const payload = { ...entity, sys: { id: entity.sys.id, type: "ExperienceFragment", version: existing.sys.version } };
6742
+ const payload = { ...omitSysAndOptimizationVariants(entity), sys: { id: entity.sys.id, type: "ExperienceFragment", version: existing.sys.version } };
6655
6743
  const result = await client.experienceFragment.upsert({ spaceId, environmentId, experienceFragmentId: entity.sys.id }, payload);
6656
- import_logging11.logEmitter.emit("info", `UPDATE ExperienceFragment ${entity.sys.id}`);
6744
+ import_logging12.logEmitter.emit("info", `UPDATE ExperienceFragment ${entity.sys.id}`);
6657
6745
  results.push(result);
6658
6746
  } else {
6659
- const payload = { ...omitSys(entity), component: entity.sys.component, sys: { id: entity.sys.id, type: "ExperienceFragment" } };
6747
+ const payload = { ...omitSysAndOptimizationVariants(entity), component: entity.sys.component, sys: { id: entity.sys.id, type: "ExperienceFragment" } };
6660
6748
  const result = await client.experienceFragment.upsert({ spaceId, environmentId, experienceFragmentId: entity.sys.id }, payload);
6661
- import_logging11.logEmitter.emit("info", `CREATE ExperienceFragment ${entity.sys.id}`);
6749
+ import_logging12.logEmitter.emit("info", `CREATE ExperienceFragment ${entity.sys.id}`);
6662
6750
  results.push(result);
6663
6751
  }
6664
6752
  } catch (err) {
6665
6753
  err.entity = entity;
6666
- import_logging11.logEmitter.emit("error", err);
6754
+ import_logging12.logEmitter.emit("error", err);
6667
6755
  }
6668
6756
  }
6669
6757
  ctx.data.experienceFragments = results;
@@ -6693,19 +6781,19 @@ function pushToSpace({
6693
6781
  try {
6694
6782
  const existing = destinationDataById.experiences?.get(entity.sys.id);
6695
6783
  if (existing) {
6696
- const payload = { ...entity, sys: { id: entity.sys.id, type: "Experience", version: existing.sys.version } };
6784
+ const payload = { ...omitSysAndOptimizationVariants(entity), sys: { id: entity.sys.id, type: "Experience", version: existing.sys.version } };
6697
6785
  const result = await client.experience.upsert({ spaceId, environmentId, experienceId: entity.sys.id }, payload);
6698
- import_logging11.logEmitter.emit("info", `UPDATE Experience ${entity.sys.id}`);
6786
+ import_logging12.logEmitter.emit("info", `UPDATE Experience ${entity.sys.id}`);
6699
6787
  return result;
6700
6788
  } else {
6701
- const payload = { ...omitSys(entity), experienceTemplate: entity.sys.experienceTemplate, sys: { id: entity.sys.id, type: "Experience" } };
6789
+ const payload = { ...omitSysAndOptimizationVariants(entity), experienceTemplate: entity.sys.experienceTemplate, sys: { id: entity.sys.id, type: "Experience" } };
6702
6790
  const result = await client.experience.upsert({ spaceId, environmentId, experienceId: entity.sys.id }, payload);
6703
- import_logging11.logEmitter.emit("info", `CREATE Experience ${entity.sys.id}`);
6791
+ import_logging12.logEmitter.emit("info", `CREATE Experience ${entity.sys.id}`);
6704
6792
  return result;
6705
6793
  }
6706
6794
  } catch (err) {
6707
6795
  err.entity = entity;
6708
- import_logging11.logEmitter.emit("error", err);
6796
+ import_logging12.logEmitter.emit("error", err);
6709
6797
  return null;
6710
6798
  }
6711
6799
  }));
@@ -6726,6 +6814,85 @@ function pushToSpace({
6726
6814
  }),
6727
6815
  skip: () => !includeExperienceOrchestration || skipContentPublishing || !(sourceData.experiences || []).length
6728
6816
  },
6817
+ // Optimization Variants are sub-resources nested on their parent Experience/ExperienceFragment
6818
+ // (sourceData.experiences[].optimizationVariants), not a flat top-level array. A variant's
6819
+ // sys.id is borrowed from its parent, not unique, so variant creation/publish/archive is
6820
+ // handled by new, self-contained functions (importVariantsForParents, filterVariantsToPublish,
6821
+ // filterVariantsToArchive, publishVariant, archiveVariant) rather than by generalizing
6822
+ // destinationDataById / filterExoEntitiesToPublish / filterExoEntitiesToUnpublish, which all
6823
+ // assume sys.id uniqueness.
6824
+ //
6825
+ // Unlike the base Experience/Fragment create/update, there is no upsert-by-known-ID for
6826
+ // variants: the upstream API's create endpoint always server-generates a fresh variantId
6827
+ // (crypto.randomUUID()) and its update endpoint 404s on an unknown variantId rather than
6828
+ // creating one. So every import run creates fresh destination variants via POST rather than
6829
+ // matching against any existing destination variant.
6830
+ {
6831
+ title: "Importing Experience Optimization Variants",
6832
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
6833
+ const results = await importVariantsForParents({
6834
+ parents: ctx.data.experiences || [],
6835
+ sourceParents: sourceData.experiences || [],
6836
+ client,
6837
+ spaceId,
6838
+ environmentId,
6839
+ kind: "experience"
6840
+ });
6841
+ ctx.data.experienceVariants = results.flatMap((r) => r.created);
6842
+ }),
6843
+ skip: () => !includeExperienceOrchestration || skipExoVariants || !(sourceData.experiences || []).some((e) => (e.optimizationVariants || []).some(isRealOptimizationVariant))
6844
+ },
6845
+ {
6846
+ title: "Publishing Experience Optimization Variants",
6847
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
6848
+ const toPublish = filterVariantsToPublish(ctx.data.experienceVariants || []);
6849
+ await Promise.all(toPublish.map(
6850
+ (v) => publishVariant("ExperienceVariant", v, () => client.experienceVariant.publish(
6851
+ { spaceId, environmentId, experienceId: v.sys.id, variantId: v.sys.variant, version: v.sys.version }
6852
+ ))
6853
+ ));
6854
+ const toArchive = filterVariantsToArchive(ctx.data.experienceVariants || []);
6855
+ await Promise.all(toArchive.map(
6856
+ (v) => archiveVariant("ExperienceVariant", v, () => client.experienceVariant.archive(
6857
+ { spaceId, environmentId, experienceId: v.sys.id, variantId: v.sys.variant, version: v.sys.version }
6858
+ ))
6859
+ ));
6860
+ }),
6861
+ skip: () => !includeExperienceOrchestration || skipExoVariants || skipContentPublishing || !(sourceData.experiences || []).some((e) => (e.optimizationVariants || []).some(isRealOptimizationVariant))
6862
+ },
6863
+ {
6864
+ title: "Importing Experience Fragment Optimization Variants",
6865
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
6866
+ const results = await importVariantsForParents({
6867
+ parents: ctx.data.experienceFragments || [],
6868
+ sourceParents: sourceData.experienceFragments || [],
6869
+ client,
6870
+ spaceId,
6871
+ environmentId,
6872
+ kind: "experienceFragment"
6873
+ });
6874
+ ctx.data.experienceFragmentVariants = results.flatMap((r) => r.created);
6875
+ }),
6876
+ skip: () => !includeExperienceOrchestration || skipExoVariants || !(sourceData.experienceFragments || []).some((f) => (f.optimizationVariants || []).some(isRealOptimizationVariant))
6877
+ },
6878
+ {
6879
+ title: "Publishing Experience Fragment Optimization Variants",
6880
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
6881
+ const toPublish = filterVariantsToPublish(ctx.data.experienceFragmentVariants || []);
6882
+ await Promise.all(toPublish.map(
6883
+ (v) => publishVariant("ExperienceFragmentVariant", v, () => client.experienceFragmentVariant.publish(
6884
+ { spaceId, environmentId, experienceFragmentId: v.sys.id, variantId: v.sys.variant, version: v.sys.version }
6885
+ ))
6886
+ ));
6887
+ const toArchive = filterVariantsToArchive(ctx.data.experienceFragmentVariants || []);
6888
+ await Promise.all(toArchive.map(
6889
+ (v) => archiveVariant("ExperienceFragmentVariant", v, () => client.experienceFragmentVariant.archive(
6890
+ { spaceId, environmentId, experienceFragmentId: v.sys.id, variantId: v.sys.variant, version: v.sys.version }
6891
+ ))
6892
+ ));
6893
+ }),
6894
+ skip: () => !includeExperienceOrchestration || skipExoVariants || skipContentPublishing || !(sourceData.experienceFragments || []).some((f) => (f.optimizationVariants || []).some(isRealOptimizationVariant))
6895
+ },
6729
6896
  // Unpublishing runs after all Importing/Publishing tasks, in reverse dependency order
6730
6897
  // (Experience first, DataAssembly last) - the API rejects unpublishing an entity that a
6731
6898
  // still-published parent references, so parents must unpublish before the children they embed.
@@ -6790,6 +6957,18 @@ function pushToSpace({
6790
6957
  ));
6791
6958
  }),
6792
6959
  skip: () => !includeExperienceOrchestration || skipContentPublishing || !(sourceData.dataAssemblies || []).length
6960
+ },
6961
+ {
6962
+ title: "Importing Releases",
6963
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
6964
+ const { supported: v2Releases, unsupported: v1Releases } = partitionReleasesBySchemaVersion(sourceData.releases || []);
6965
+ v1Releases.forEach(logUnsupportedRelease);
6966
+ const results = await Promise.all(v2Releases.map(
6967
+ (release) => importRelease(release, destinationDataById.releases?.get(release.transformed.sys.id), { client, spaceId, environmentId })
6968
+ ));
6969
+ ctx.data.releases = results.filter(Boolean);
6970
+ }),
6971
+ skip: () => !(sourceData.releases || []).length
6793
6972
  }
6794
6973
  ], listrOptions);
6795
6974
  }
@@ -6797,14 +6976,56 @@ function omitSys(entity) {
6797
6976
  const { sys: _sys, ...rest } = entity;
6798
6977
  return rest;
6799
6978
  }
6800
- function archiveEntities2({ entities, sourceEntities, client, spaceId, environmentId, requestQueue }) {
6979
+ function omitSysAndOptimizationVariants(entity) {
6980
+ const { sys: _sys, optimizationVariants: _variants, ...rest } = entity;
6981
+ return rest;
6982
+ }
6983
+ function omitVariantSys(variant) {
6984
+ const { sys: _sys, ...rest } = variant;
6985
+ return rest;
6986
+ }
6987
+ function isRealOptimizationVariant(variant) {
6988
+ return Boolean(variant?.sys) && variant.sys.variantType !== "default";
6989
+ }
6990
+ async function importVariantsForParents({
6991
+ parents,
6992
+ sourceParents,
6993
+ client,
6994
+ spaceId,
6995
+ environmentId,
6996
+ kind
6997
+ }) {
6998
+ const ns = kind === "experience" ? client.experienceVariant : client.experienceFragmentVariant;
6999
+ const idParam = kind === "experience" ? "experienceId" : "experienceFragmentId";
7000
+ const label = kind === "experience" ? "ExperienceVariant" : "ExperienceFragmentVariant";
7001
+ const parentRefField = kind === "experience" ? "experienceTemplate" : "component";
7002
+ const sourceParentsById = new Map(sourceParents.map((sourceParent) => [sourceParent.sys.id, sourceParent]));
7003
+ return Promise.all(parents.map(async (parent2) => {
7004
+ const sourceParent = sourceParentsById.get(parent2.sys.id);
7005
+ const sourceVariants = (sourceParent?.optimizationVariants ?? []).filter(isRealOptimizationVariant);
7006
+ const created = [];
7007
+ for (const variant of sourceVariants) {
7008
+ try {
7009
+ const payload = { ...omitVariantSys(variant), [parentRefField]: variant.sys[parentRefField] };
7010
+ const result = await ns.create({ spaceId, environmentId, [idParam]: parent2.sys.id }, payload);
7011
+ import_logging12.logEmitter.emit("info", `CREATE ${label} ${result.sys.variant} (parent ${parent2.sys.id})`);
7012
+ created.push({ ...result, sys: { ...result.sys, publishedVersion: variant.sys.publishedVersion, archivedVersion: variant.sys.archivedVersion } });
7013
+ } catch (err) {
7014
+ err.entity = variant;
7015
+ import_logging12.logEmitter.emit("error", err);
7016
+ }
7017
+ }
7018
+ return { parentId: parent2.sys.id, created };
7019
+ }));
7020
+ }
7021
+ function archiveEntities2({ entities: entities2, sourceEntities, client, spaceId, environmentId, requestQueue }) {
6801
7022
  const entityIdsToArchive = sourceEntities.filter(({ original }) => original.sys.archivedVersion).map(({ original }) => original.sys.id);
6802
- const entitiesToArchive = entities.filter((entity) => entityIdsToArchive.indexOf(entity.sys.id) !== -1);
7023
+ const entitiesToArchive = entities2.filter((entity) => entityIdsToArchive.indexOf(entity.sys.id) !== -1);
6803
7024
  return archiveEntities({ entities: entitiesToArchive, client, spaceId, environmentId, requestQueue });
6804
7025
  }
6805
- async function publishEntities2({ entities, sourceEntities, client, spaceId, environmentId, requestQueue, destinationEntitiesById }) {
7026
+ async function publishEntities2({ entities: entities2, sourceEntities, client, spaceId, environmentId, requestQueue, destinationEntitiesById }) {
6806
7027
  const entityIdsToPublish = sourceEntities.filter(({ original }) => original.sys.publishedVersion).map(({ original }) => original.sys.id);
6807
- let entitiesToPublish = entities.filter((entity) => entityIdsToPublish.indexOf(entity.sys.id) !== -1);
7028
+ let entitiesToPublish = entities2.filter((entity) => entityIdsToPublish.indexOf(entity.sys.id) !== -1);
6808
7029
  const publishAllLocales = () => publishEntities({ entities: entitiesToPublish, client, spaceId, environmentId, requestQueue });
6809
7030
  const hasFieldStatus = sourceEntities.some(({ original }) => original.sys.fieldStatus);
6810
7031
  if (!hasFieldStatus) {
@@ -6825,7 +7046,7 @@ async function publishEntities2({ entities, sourceEntities, client, spaceId, env
6825
7046
  if (!localePublishing.skippedEntityIds.has(entity.sys.id)) {
6826
7047
  return true;
6827
7048
  }
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`);
7049
+ import_logging12.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
7050
  return false;
6830
7051
  });
6831
7052
  }
@@ -6846,6 +7067,7 @@ __export(transformers_exports, {
6846
7067
  contentTypes: () => contentTypes,
6847
7068
  entries: () => entries,
6848
7069
  locales: () => locales,
7070
+ releases: () => releases,
6849
7071
  tags: () => tags,
6850
7072
  webhooks: () => webhooks
6851
7073
  });
@@ -6901,6 +7123,9 @@ function removeMetadataTags(entity, tagsEnabled = false) {
6901
7123
  }
6902
7124
  return entity;
6903
7125
  }
7126
+ function releases(release) {
7127
+ return release;
7128
+ }
6904
7129
 
6905
7130
  // lib/utils/sort-entries.ts
6906
7131
  function sortEntries(entries2) {
@@ -7150,24 +7375,24 @@ function upgradeExoResources(resources) {
7150
7375
  }
7151
7376
 
7152
7377
  // lib/transform/transform-space.ts
7153
- var spaceEntities = [
7378
+ var entities = [
7154
7379
  "contentTypes",
7155
7380
  "entries",
7156
7381
  "assets",
7157
7382
  "locales",
7158
7383
  "webhooks",
7159
- "tags"
7384
+ "tags",
7385
+ "releases"
7160
7386
  ];
7161
- function transform_space_default(sourceData, destinationData, customTransformers, entities = spaceEntities) {
7162
- const transformers = defaults_default(customTransformers, transformers_exports);
7387
+ function transform_space_default(sourceData, destinationData) {
7163
7388
  const baseSpaceData = upgradeExoResources(omit_default(sourceData, ...entities));
7164
7389
  sourceData.locales = sortLocales(sourceData.locales);
7165
7390
  const tagsEnabled = !!destinationData.tags;
7166
7391
  return entities.reduce((transformedSpaceData, type) => {
7167
- const sortedEntities = type === "tags" ? sourceData[type] ?? [] : sortEntries(sourceData[type] ?? []);
7392
+ const sortedEntities = type === "tags" || type === "releases" ? sourceData[type] ?? [] : sortEntries(sourceData[type] ?? []);
7168
7393
  const transformedEntities = sortedEntities.map((entity) => ({
7169
7394
  original: entity,
7170
- transformed: transformers[type](entity, destinationData[type], tagsEnabled)
7395
+ transformed: transformers_exports[type](entity, destinationData[type], tagsEnabled)
7171
7396
  }));
7172
7397
  transformedSpaceData[type] = transformedEntities;
7173
7398
  return transformedSpaceData;
@@ -7257,13 +7482,13 @@ var attachEntityName = (details, payload) => {
7257
7482
  });
7258
7483
  };
7259
7484
  var countInvalidEntities = (validationData) => {
7260
- const entityCount = validationData.reduce((entities, currentDetail) => {
7261
- if (!entities[currentDetail.path[0]]) {
7262
- entities[currentDetail.path[0]] = 1;
7485
+ const entityCount = validationData.reduce((entities2, currentDetail) => {
7486
+ if (!entities2[currentDetail.path[0]]) {
7487
+ entities2[currentDetail.path[0]] = 1;
7263
7488
  } else {
7264
- entities[currentDetail.path[0]]++;
7489
+ entities2[currentDetail.path[0]]++;
7265
7490
  }
7266
- return entities;
7491
+ return entities2;
7267
7492
  }, {});
7268
7493
  return Object.keys(entityCount).map((key) => `${key}:${entityCount[key]}`);
7269
7494
  };
@@ -7369,7 +7594,8 @@ var SUPPORTED_ENTITY_TYPES = [
7369
7594
  "experienceTemplates",
7370
7595
  "dataAssemblies",
7371
7596
  "experienceFragments",
7372
- "experiences"
7597
+ "experiences",
7598
+ "releases"
7373
7599
  ];
7374
7600
  async function parseOptions(params) {
7375
7601
  const defaultOptions = {
@@ -7385,6 +7611,7 @@ async function parseOptions(params) {
7385
7611
  uploadAssets: false,
7386
7612
  rateLimit: 7,
7387
7613
  includeExperienceOrchestration: true,
7614
+ skipExoVariants: false,
7388
7615
  host: "api.contentful.com"
7389
7616
  };
7390
7617
  const configFile = params.config ? require((0, import_path2.resolve)(process.cwd(), params.config)) : {};
@@ -7459,6 +7686,29 @@ async function parseOptions(params) {
7459
7686
  return options;
7460
7687
  }
7461
7688
 
7689
+ // lib/utils/display-error-log.ts
7690
+ var import_date_fns2 = require("date-fns");
7691
+ var import_logging13 = __toESM(require_logging());
7692
+ function displayErrorLog(errorLog) {
7693
+ if (errorLog.length) {
7694
+ const count = errorLog.reduce((count2, curr) => {
7695
+ if (Object.prototype.hasOwnProperty.call(curr, "warning")) {
7696
+ count2.warnings++;
7697
+ } else if (Object.prototype.hasOwnProperty.call(curr, "error")) {
7698
+ count2.errors++;
7699
+ }
7700
+ return count2;
7701
+ }, { warnings: 0, errors: 0 });
7702
+ console.log(`
7703
+
7704
+ The following ${count.errors} errors and ${count.warnings} warnings occurred:
7705
+ `);
7706
+ errorLog.map((logMessage) => `${(0, import_date_fns2.format)((0, import_date_fns2.parseISO)(logMessage.ts), "HH:mm:ss")} - ${(0, import_logging13.formatLogMessageOneLine)(logMessage)}`).map((logMessage) => console.log(logMessage));
7707
+ return;
7708
+ }
7709
+ console.log("No errors or warnings occurred");
7710
+ }
7711
+
7462
7712
  // lib/index.ts
7463
7713
  var ONE_SECOND = 1e3;
7464
7714
  var tableOptions = {
@@ -7485,7 +7735,7 @@ async function runContentfulImport(params) {
7485
7735
  intervalCap: options.rateLimit,
7486
7736
  carryoverConcurrencyCount: true
7487
7737
  });
7488
- (0, import_logging12.setupLogging)(log);
7738
+ (0, import_logging14.setupLogging)(log);
7489
7739
  const infoTable = new import_cli_table3.default(tableOptions);
7490
7740
  infoTable.push([{ colSpan: 2, content: "The following entities are going to be imported:" }]);
7491
7741
  Object.keys(options.content).forEach((type) => {
@@ -7500,6 +7750,20 @@ async function runContentfulImport(params) {
7500
7750
  }
7501
7751
  infoTable.push([startCase_default(type), options.content[type].length]);
7502
7752
  });
7753
+ const experienceVariantCount = (options.content.experiences || []).reduce(
7754
+ (sum, e) => sum + (e.optimizationVariants?.length ?? 0),
7755
+ 0
7756
+ );
7757
+ if (!options.skipExoVariants && experienceVariantCount > 0) {
7758
+ infoTable.push(["Experience Optimization Variants", experienceVariantCount]);
7759
+ }
7760
+ const experienceFragmentVariantCount = (options.content.experienceFragments || []).reduce(
7761
+ (sum, f) => sum + (f.optimizationVariants?.length ?? 0),
7762
+ 0
7763
+ );
7764
+ if (!options.skipExoVariants && experienceFragmentVariantCount > 0) {
7765
+ infoTable.push(["Experience Fragment Optimization Variants", experienceFragmentVariantCount]);
7766
+ }
7503
7767
  console.log(infoTable.toString());
7504
7768
  const tasks = new import_listr3.default([
7505
7769
  {
@@ -7548,6 +7812,7 @@ async function runContentfulImport(params) {
7548
7812
  client: ctx.client,
7549
7813
  spaceId: options.spaceId,
7550
7814
  includeExperienceOrchestration: options.includeExperienceOrchestration,
7815
+ skipExoVariants: options.skipExoVariants,
7551
7816
  environmentId: options.environmentId,
7552
7817
  contentModelOnly: options.contentModelOnly,
7553
7818
  skipLocales: options.skipLocales,
@@ -7582,8 +7847,8 @@ async function runContentfulImport(params) {
7582
7847
  console.log("No data was imported");
7583
7848
  }
7584
7849
  const endTime = /* @__PURE__ */ new Date();
7585
- const durationHuman = (0, import_date_fns2.formatDistance)(endTime, options.startTime);
7586
- const durationSeconds = (0, import_date_fns2.differenceInSeconds)(endTime, options.startTime);
7850
+ const durationHuman = (0, import_date_fns3.formatDistance)(endTime, options.startTime);
7851
+ const durationSeconds = (0, import_date_fns3.differenceInSeconds)(endTime, options.startTime);
7587
7852
  console.log(`The import took ${durationHuman} (${durationSeconds}s)`);
7588
7853
  return ctx.data;
7589
7854
  }).catch((err) => {
@@ -7595,9 +7860,9 @@ async function runContentfulImport(params) {
7595
7860
  }).then((data) => {
7596
7861
  const errorLog = log.filter((logMessage) => logMessage.level !== "info" && logMessage.level !== "warning");
7597
7862
  const displayLog = log.filter((logMessage) => logMessage.level !== "info");
7598
- (0, import_logging12.displayErrorLog)(displayLog);
7863
+ displayErrorLog(displayLog);
7599
7864
  if (errorLog.length) {
7600
- return (0, import_logging12.writeErrorLogFile)(options.errorLogFile, errorLog).then(() => {
7865
+ return (0, import_logging14.writeErrorLogFile)(options.errorLogFile, errorLog).then(() => {
7601
7866
  const multiError = new ContentfulMultiError("Errors occurred");
7602
7867
  multiError.name = "ContentfulMultiError";
7603
7868
  multiError.errors = errorLog;