contentful-import 10.0.18 → 10.1.0-exo.10

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.d.mts CHANGED
@@ -19,6 +19,7 @@ type RunContentfulImportParams = {
19
19
  headers?: object;
20
20
  errorLogFile?: string;
21
21
  useVerboseRenderer?: boolean;
22
+ includeExperienceOrchestration?: boolean;
22
23
  timeout?: number;
23
24
  retryLimit?: number;
24
25
  config?: string;
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ type RunContentfulImportParams = {
19
19
  headers?: object;
20
20
  errorLogFile?: string;
21
21
  useVerboseRenderer?: boolean;
22
+ includeExperienceOrchestration?: boolean;
22
23
  timeout?: number;
23
24
  retryLimit?: number;
24
25
  config?: string;
package/dist/index.js CHANGED
@@ -60,22 +60,37 @@ function initClient(opts) {
60
60
  };
61
61
  return (0, import_contentful_management.createClient)(config, { type: "legacy" });
62
62
  }
63
+ function initPlainClient(opts) {
64
+ return (0, import_contentful_management.createClient)({
65
+ accessToken: opts.managementToken,
66
+ host: opts.host,
67
+ logHandler
68
+ });
69
+ }
63
70
 
64
71
  // lib/tasks/get-destination-data.ts
65
72
  var import_bluebird = __toESM(require("bluebird"));
66
73
  var import_logging2 = require("contentful-batch-libs/dist/logging");
67
74
  var BATCH_CHAR_LIMIT = 1990;
68
75
  var BATCH_SIZE_LIMIT = 100;
69
- var METHODS = {
76
+ var OFFSET_QUERY_METHODS = {
70
77
  contentTypes: { name: "content types", method: "getContentTypes" },
71
78
  locales: { name: "locales", method: "getLocales" },
72
79
  entries: { name: "entries", method: "getEntries" },
73
80
  assets: { name: "assets", method: "getAssets" },
74
81
  tags: { name: "tags", method: "getTags" }
75
82
  };
83
+ var CURSOR_QUERY_METHODS = {
84
+ designTokens: { name: "design tokens", namespace: "designToken" },
85
+ componentTypes: { name: "component types", namespace: "componentType" },
86
+ templates: { name: "templates", namespace: "template" },
87
+ fragments: { name: "fragments", namespace: "fragment" },
88
+ dataAssemblies: { name: "data assemblies", namespace: "dataAssembly" },
89
+ experiences: { name: "experiences", namespace: "experience" }
90
+ };
76
91
  async function batchedIdQuery({ environment, type, ids, requestQueue }) {
77
- const method = METHODS[type].method;
78
- const entityTypeName = METHODS[type].name;
92
+ const method = OFFSET_QUERY_METHODS[type].method;
93
+ const entityTypeName = OFFSET_QUERY_METHODS[type].name;
79
94
  const batches = getIdBatches(ids);
80
95
  let totalFetched = 0;
81
96
  const allPendingResponses = batches.map((idBatch) => {
@@ -93,8 +108,8 @@ async function batchedIdQuery({ environment, type, ids, requestQueue }) {
93
108
  return responses.flat();
94
109
  }
95
110
  async function batchedPageQuery({ environment, type, requestQueue }) {
96
- const method = METHODS[type].method;
97
- const entityTypeName = METHODS[type].name;
111
+ const method = OFFSET_QUERY_METHODS[type].method;
112
+ const entityTypeName = OFFSET_QUERY_METHODS[type].name;
98
113
  let totalFetched = 0;
99
114
  const { items, total } = await requestQueue.add(async () => {
100
115
  const response = await environment[method]({
@@ -150,14 +165,37 @@ function getPagedBatches(totalFetched, total) {
150
165
  }
151
166
  return batches;
152
167
  }
168
+ async function cursorPaginatedQuery({ plainClient, spaceId, environmentId, type, requestQueue }) {
169
+ const { name: entityTypeName, namespace } = CURSOR_QUERY_METHODS[type];
170
+ let totalFetched = 0;
171
+ let pageNext = void 0;
172
+ const allItems = [];
173
+ do {
174
+ const items = await requestQueue.add(async () => {
175
+ const response = await plainClient[namespace].getMany({
176
+ spaceId,
177
+ environmentId,
178
+ query: { limit: BATCH_SIZE_LIMIT, ...pageNext && { pageNext } }
179
+ });
180
+ totalFetched += response.items.length;
181
+ import_logging2.logEmitter.emit("info", `Fetched ${totalFetched} ${entityTypeName}`);
182
+ pageNext = response.pages?.next;
183
+ return response.items;
184
+ });
185
+ allItems.push(...items);
186
+ } while (pageNext);
187
+ return allItems;
188
+ }
153
189
  async function getDestinationData({
154
190
  client,
191
+ plainClient,
155
192
  spaceId,
156
193
  environmentId,
157
194
  sourceData,
158
195
  contentModelOnly,
159
196
  skipLocales,
160
197
  skipContentModel,
198
+ includeExperienceOrchestration,
161
199
  requestQueue
162
200
  }) {
163
201
  const space = await client.getSpace(spaceId);
@@ -167,7 +205,14 @@ async function getDestinationData({
167
205
  tags: [],
168
206
  locales: [],
169
207
  entries: [],
170
- assets: []
208
+ assets: [],
209
+ experiences: [],
210
+ templates: [],
211
+ componentTypes: [],
212
+ fragments: [],
213
+ dataAssemblies: [],
214
+ designTokens: [],
215
+ webhooks: []
171
216
  };
172
217
  sourceData = {
173
218
  ...result,
@@ -204,7 +249,7 @@ async function getDestinationData({
204
249
  }
205
250
  const entryIds = sourceData.entries?.map((e) => e.sys.id);
206
251
  const assetIds = sourceData.assets?.map((e) => e.sys.id);
207
- if (entryIds) {
252
+ if (entryIds && entryIds.length) {
208
253
  result.entries = batchedIdQuery({
209
254
  environment,
210
255
  type: "entries",
@@ -212,7 +257,7 @@ async function getDestinationData({
212
257
  requestQueue
213
258
  });
214
259
  }
215
- if (assetIds) {
260
+ if (assetIds && assetIds.length) {
216
261
  result.assets = batchedIdQuery({
217
262
  environment,
218
263
  type: "assets",
@@ -220,7 +265,14 @@ async function getDestinationData({
220
265
  requestQueue
221
266
  });
222
267
  }
223
- result.webhooks = [];
268
+ if (includeExperienceOrchestration && plainClient) {
269
+ result.designTokens = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "designTokens", requestQueue });
270
+ result.componentTypes = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "componentTypes", requestQueue });
271
+ result.templates = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "templates", requestQueue });
272
+ result.fragments = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "fragments", requestQueue });
273
+ result.dataAssemblies = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "dataAssemblies", requestQueue });
274
+ result.experiences = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "experiences", requestQueue });
275
+ }
224
276
  return import_bluebird.default.props(result);
225
277
  }
226
278
 
@@ -556,7 +608,138 @@ async function runQueue(queue, result = [], requestQueue) {
556
608
  return result;
557
609
  }
558
610
 
611
+ // lib/utils/graphql-schema-backoff.ts
612
+ var GRAPHQL_SCHEMA_STALE_DELAYS_MS = [500, 1500, 6e3];
613
+ function isGraphQLSchemaStaleError(err) {
614
+ if (!(err instanceof Error)) {
615
+ return false;
616
+ }
617
+ let parsed;
618
+ try {
619
+ parsed = JSON.parse(err.message);
620
+ } catch {
621
+ return false;
622
+ }
623
+ const errors = parsed?.details?.errors;
624
+ if (!Array.isArray(errors)) {
625
+ return false;
626
+ }
627
+ const matched = errors.some(
628
+ (e) => typeof e.message === "string" && (e.message.includes("GraphQL validation error") || e.message.includes("Unknown content type") || e.message.includes("Pointer path does not exist for"))
629
+ );
630
+ return matched;
631
+ }
632
+
633
+ // lib/utils/sort-component-types.ts
634
+ function sortComponentTypes(componentTypes) {
635
+ const idToIndex = /* @__PURE__ */ new Map();
636
+ componentTypes.forEach((ct, i) => idToIndex.set(ct.sys.id, i));
637
+ const URN_PATTERN = /componentTypes\/([^"\\]+)/g;
638
+ function getDeps(ct) {
639
+ const ids = /* @__PURE__ */ new Set();
640
+ const tree = JSON.stringify(ct.componentTree || []);
641
+ let match;
642
+ while ((match = URN_PATTERN.exec(tree)) !== null) {
643
+ const dep = match[1];
644
+ if (dep !== ct.sys.id && idToIndex.has(dep)) {
645
+ ids.add(dep);
646
+ }
647
+ }
648
+ return [...ids];
649
+ }
650
+ const dependents = /* @__PURE__ */ new Map();
651
+ const inDegree = /* @__PURE__ */ new Map();
652
+ componentTypes.forEach((ct) => {
653
+ inDegree.set(ct.sys.id, 0);
654
+ dependents.set(ct.sys.id, []);
655
+ });
656
+ componentTypes.forEach((ct) => {
657
+ for (const dep of getDeps(ct)) {
658
+ dependents.get(dep).push(ct.sys.id);
659
+ inDegree.set(ct.sys.id, (inDegree.get(ct.sys.id) ?? 0) + 1);
660
+ }
661
+ });
662
+ const queue = componentTypes.filter((ct) => inDegree.get(ct.sys.id) === 0).map((ct) => ct.sys.id);
663
+ const sorted = [];
664
+ while (queue.length > 0) {
665
+ const id = queue.shift();
666
+ sorted.push(componentTypes[idToIndex.get(id)]);
667
+ for (const dependent of dependents.get(id) ?? []) {
668
+ const deg = (inDegree.get(dependent) ?? 1) - 1;
669
+ inDegree.set(dependent, deg);
670
+ if (deg === 0) queue.push(dependent);
671
+ }
672
+ }
673
+ componentTypes.forEach((ct) => {
674
+ if (!sorted.includes(ct)) sorted.push(ct);
675
+ });
676
+ return sorted;
677
+ }
678
+
679
+ // lib/utils/sort-fragments.ts
680
+ function sortFragments(fragments) {
681
+ const idToIndex = /* @__PURE__ */ new Map();
682
+ fragments.forEach((f, i) => idToIndex.set(f.sys.id, i));
683
+ const FRAGMENT_URN_PATTERN = /fragments\/([^"\\]+)/g;
684
+ function getDeps(fragment) {
685
+ const ids = /* @__PURE__ */ new Set();
686
+ const json = JSON.stringify({ slots: fragment.slots || [], componentTree: fragment.componentTree || [] });
687
+ let match;
688
+ while ((match = FRAGMENT_URN_PATTERN.exec(json)) !== null) {
689
+ const dep = match[1];
690
+ if (dep !== fragment.sys.id && idToIndex.has(dep)) {
691
+ ids.add(dep);
692
+ }
693
+ }
694
+ return [...ids];
695
+ }
696
+ const dependents = /* @__PURE__ */ new Map();
697
+ const inDegree = /* @__PURE__ */ new Map();
698
+ fragments.forEach((f) => {
699
+ inDegree.set(f.sys.id, 0);
700
+ dependents.set(f.sys.id, []);
701
+ });
702
+ fragments.forEach((f) => {
703
+ for (const dep of getDeps(f)) {
704
+ dependents.get(dep).push(f.sys.id);
705
+ inDegree.set(f.sys.id, (inDegree.get(f.sys.id) ?? 0) + 1);
706
+ }
707
+ });
708
+ const queue = fragments.filter((f) => inDegree.get(f.sys.id) === 0).map((f) => f.sys.id);
709
+ const sorted = [];
710
+ while (queue.length > 0) {
711
+ const id = queue.shift();
712
+ sorted.push(fragments[idToIndex.get(id)]);
713
+ for (const dependent of dependents.get(id) ?? []) {
714
+ const deg = (inDegree.get(dependent) ?? 1) - 1;
715
+ inDegree.set(dependent, deg);
716
+ if (deg === 0) queue.push(dependent);
717
+ }
718
+ }
719
+ fragments.forEach((f) => {
720
+ if (!sorted.includes(f)) sorted.push(f);
721
+ });
722
+ return sorted;
723
+ }
724
+
559
725
  // lib/tasks/push-to-space/push-to-space.ts
726
+ async function withGraphQLSchemaBackoff(fn) {
727
+ let lastErr;
728
+ for (let attempt = 0; attempt <= GRAPHQL_SCHEMA_STALE_DELAYS_MS.length; attempt++) {
729
+ try {
730
+ return await fn();
731
+ } catch (err) {
732
+ if (!isGraphQLSchemaStaleError(err) || attempt === GRAPHQL_SCHEMA_STALE_DELAYS_MS.length) {
733
+ throw err;
734
+ }
735
+ const delay = GRAPHQL_SCHEMA_STALE_DELAYS_MS[attempt];
736
+ import_logging6.logEmitter.emit("warning", `DataAssembly GraphQL schema not yet current, retrying in ${delay}ms (attempt ${attempt + 1}/${GRAPHQL_SCHEMA_STALE_DELAYS_MS.length})`);
737
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
738
+ lastErr = err;
739
+ }
740
+ }
741
+ throw lastErr;
742
+ }
560
743
  var DEFAULT_CONTENT_STRUCTURE = {
561
744
  entries: [],
562
745
  assets: [],
@@ -570,8 +753,10 @@ function pushToSpace({
570
753
  sourceData,
571
754
  destinationData = {},
572
755
  client,
756
+ plainClient,
573
757
  spaceId,
574
758
  environmentId,
759
+ includeExperienceOrchestration,
575
760
  contentModelOnly,
576
761
  skipContentModel,
577
762
  skipContentUpdates,
@@ -847,9 +1032,177 @@ function pushToSpace({
847
1032
  ctx.data.webhooks = webhooks2;
848
1033
  }),
849
1034
  skip: () => contentModelOnly || environmentId !== "master" && "Webhooks can only be imported in master environment"
1035
+ },
1036
+ {
1037
+ title: "Importing Data Assemblies",
1038
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
1039
+ const results = await Promise.all((sourceData.dataAssemblies || []).map(async (entity) => {
1040
+ try {
1041
+ const existing = destinationDataById.dataAssemblies?.get(entity.sys.id);
1042
+ let result;
1043
+ if (existing) {
1044
+ const payload = { ...entity, sys: { ...entity.sys, version: existing.sys.version } };
1045
+ result = await withGraphQLSchemaBackoff(() => plainClient.dataAssembly.update(
1046
+ { spaceId, environmentId, dataAssemblyId: entity.sys.id },
1047
+ payload
1048
+ ));
1049
+ import_logging6.logEmitter.emit("info", `UPDATE DataAssembly ${entity.sys.id}`);
1050
+ } else {
1051
+ const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "DataAssembly", dataType: entity.sys.dataType, ...entity.sys.variant ? { variant: entity.sys.variant } : {}, version: 0 } };
1052
+ result = await withGraphQLSchemaBackoff(() => plainClient.dataAssembly.update(
1053
+ { spaceId, environmentId, dataAssemblyId: entity.sys.id },
1054
+ payload
1055
+ ));
1056
+ import_logging6.logEmitter.emit("info", `CREATE DataAssembly ${entity.sys.id}`);
1057
+ }
1058
+ return result;
1059
+ } catch (err) {
1060
+ import_logging6.logEmitter.emit("error", err);
1061
+ return null;
1062
+ }
1063
+ }));
1064
+ ctx.data.dataAssemblies = results.filter(Boolean);
1065
+ }),
1066
+ skip: () => !includeExperienceOrchestration || !(sourceData.dataAssemblies || []).length
1067
+ },
1068
+ {
1069
+ title: "Importing Design Tokens",
1070
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
1071
+ const results = await Promise.all((sourceData.designTokens || []).map(async (entity) => {
1072
+ try {
1073
+ const existing = destinationDataById.designTokens?.get(entity.sys.id);
1074
+ if (existing) {
1075
+ const payload = { ...entity, sys: { id: entity.sys.id, type: "DesignToken", version: existing.sys.version } };
1076
+ const result = await plainClient.designToken.upsert({ spaceId, environmentId, designTokenId: entity.sys.id }, payload);
1077
+ import_logging6.logEmitter.emit("info", `UPDATE DesignToken ${entity.sys.id}`);
1078
+ return result;
1079
+ } else {
1080
+ const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "DesignToken" } };
1081
+ const result = await plainClient.designToken.upsert({ spaceId, environmentId, designTokenId: entity.sys.id }, payload);
1082
+ import_logging6.logEmitter.emit("info", `CREATE DesignToken ${entity.sys.id}`);
1083
+ return result;
1084
+ }
1085
+ } catch (err) {
1086
+ import_logging6.logEmitter.emit("error", err);
1087
+ return null;
1088
+ }
1089
+ }));
1090
+ ctx.data.designTokens = results.filter(Boolean);
1091
+ }),
1092
+ skip: () => !includeExperienceOrchestration || !(sourceData.designTokens || []).length
1093
+ },
1094
+ {
1095
+ title: "Importing Component Types",
1096
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
1097
+ const sorted = sortComponentTypes(sourceData.componentTypes || []);
1098
+ const results = [];
1099
+ for (const entity of sorted) {
1100
+ try {
1101
+ const existing = destinationDataById.componentTypes?.get(entity.sys.id);
1102
+ if (existing) {
1103
+ const payload = { ...entity, sys: { id: entity.sys.id, type: "ComponentType", version: existing.sys.version } };
1104
+ const result = await plainClient.componentType.upsert({ spaceId, environmentId, componentTypeId: entity.sys.id }, payload);
1105
+ import_logging6.logEmitter.emit("info", `UPDATE ComponentType ${entity.sys.id}`);
1106
+ results.push(result);
1107
+ } else {
1108
+ const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "ComponentType" } };
1109
+ const result = await plainClient.componentType.upsert({ spaceId, environmentId, componentTypeId: entity.sys.id }, payload);
1110
+ import_logging6.logEmitter.emit("info", `CREATE ComponentType ${entity.sys.id}`);
1111
+ results.push(result);
1112
+ }
1113
+ } catch (err) {
1114
+ import_logging6.logEmitter.emit("error", err);
1115
+ }
1116
+ }
1117
+ ctx.data.componentTypes = results;
1118
+ }),
1119
+ skip: () => !includeExperienceOrchestration || !(sourceData.componentTypes || []).length
1120
+ },
1121
+ {
1122
+ title: "Importing Templates",
1123
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
1124
+ const results = await Promise.all((sourceData.templates || []).map(async (entity) => {
1125
+ try {
1126
+ const existing = destinationDataById.templates?.get(entity.sys.id);
1127
+ if (existing) {
1128
+ const payload = { ...entity, sys: { id: entity.sys.id, type: "Template", version: existing.sys.version } };
1129
+ const result = await plainClient.template.upsert({ spaceId, environmentId, templateId: entity.sys.id }, payload);
1130
+ import_logging6.logEmitter.emit("info", `UPDATE Template ${entity.sys.id}`);
1131
+ return result;
1132
+ } else {
1133
+ const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "Template" } };
1134
+ const result = await plainClient.template.upsert({ spaceId, environmentId, templateId: entity.sys.id }, payload);
1135
+ import_logging6.logEmitter.emit("info", `CREATE Template ${entity.sys.id}`);
1136
+ return result;
1137
+ }
1138
+ } catch (err) {
1139
+ import_logging6.logEmitter.emit("error", err);
1140
+ return null;
1141
+ }
1142
+ }));
1143
+ ctx.data.templates = results.filter(Boolean);
1144
+ }),
1145
+ skip: () => !includeExperienceOrchestration || !(sourceData.templates || []).length
1146
+ },
1147
+ {
1148
+ title: "Importing Fragments",
1149
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
1150
+ const sorted = sortFragments(sourceData.fragments || []);
1151
+ const results = [];
1152
+ for (const entity of sorted) {
1153
+ try {
1154
+ const existing = destinationDataById.fragments?.get(entity.sys.id);
1155
+ if (existing) {
1156
+ const payload = { ...entity, componentType: entity.sys.componentType, sys: { id: entity.sys.id, type: "Fragment", version: existing.sys.version } };
1157
+ const result = await plainClient.fragment.upsert({ spaceId, environmentId, fragmentId: entity.sys.id }, payload);
1158
+ import_logging6.logEmitter.emit("info", `UPDATE Fragment ${entity.sys.id}`);
1159
+ results.push(result);
1160
+ } else {
1161
+ const payload = { ...omitSys(entity), componentType: entity.sys.componentType, sys: { id: entity.sys.id, type: "Fragment" } };
1162
+ const result = await plainClient.fragment.upsert({ spaceId, environmentId, fragmentId: entity.sys.id }, payload);
1163
+ import_logging6.logEmitter.emit("info", `CREATE Fragment ${entity.sys.id}`);
1164
+ results.push(result);
1165
+ }
1166
+ } catch (err) {
1167
+ import_logging6.logEmitter.emit("error", err);
1168
+ }
1169
+ }
1170
+ ctx.data.fragments = results;
1171
+ }),
1172
+ skip: () => !includeExperienceOrchestration || !(sourceData.fragments || []).length
1173
+ },
1174
+ {
1175
+ title: "Importing Experiences",
1176
+ task: (0, import_listr2.wrapTask)(async (ctx) => {
1177
+ const results = await Promise.all((sourceData.experiences || []).map(async (entity) => {
1178
+ try {
1179
+ const existing = destinationDataById.experiences?.get(entity.sys.id);
1180
+ if (existing) {
1181
+ const payload = { ...entity, template: entity.sys.template, sys: { id: entity.sys.id, type: "Experience", version: existing.sys.version } };
1182
+ const result = await plainClient.experience.upsert({ spaceId, environmentId, experienceId: entity.sys.id }, payload);
1183
+ import_logging6.logEmitter.emit("info", `UPDATE Experience ${entity.sys.id}`);
1184
+ return result;
1185
+ } else {
1186
+ const payload = { ...omitSys(entity), template: entity.sys.template, sys: { id: entity.sys.id, type: "Experience" } };
1187
+ const result = await plainClient.experience.upsert({ spaceId, environmentId, experienceId: entity.sys.id }, payload);
1188
+ import_logging6.logEmitter.emit("info", `CREATE Experience ${entity.sys.id}`);
1189
+ return result;
1190
+ }
1191
+ } catch (err) {
1192
+ import_logging6.logEmitter.emit("error", err);
1193
+ return null;
1194
+ }
1195
+ }));
1196
+ ctx.data.experiences = results.filter(Boolean);
1197
+ }),
1198
+ skip: () => !includeExperienceOrchestration || !(sourceData.experiences || []).length
850
1199
  }
851
1200
  ], listrOptions);
852
1201
  }
1202
+ function omitSys(entity) {
1203
+ const { sys: _sys, ...rest } = entity;
1204
+ return rest;
1205
+ }
853
1206
  function archiveEntities2({ entities, sourceEntities, requestQueue }) {
854
1207
  const entityIdsToArchive = sourceEntities.filter(({ original }) => original.sys.archivedVersion).map(({ original }) => original.sys.id);
855
1208
  const entitiesToArchive = entities.filter((entity) => entityIdsToArchive.indexOf(entity.sys.id) !== -1);
@@ -1218,7 +1571,13 @@ var SUPPORTED_ENTITY_TYPES = [
1218
1571
  "assets",
1219
1572
  "locales",
1220
1573
  "webhooks",
1221
- "editorInterfaces"
1574
+ "editorInterfaces",
1575
+ "designTokens",
1576
+ "componentTypes",
1577
+ "templates",
1578
+ "dataAssemblies",
1579
+ "fragments",
1580
+ "experiences"
1222
1581
  ];
1223
1582
  async function parseOptions(params) {
1224
1583
  const defaultOptions = {
@@ -1231,7 +1590,8 @@ async function parseOptions(params) {
1231
1590
  environmentId: "master",
1232
1591
  rawProxy: false,
1233
1592
  uploadAssets: false,
1234
- rateLimit: 7
1593
+ rateLimit: 7,
1594
+ includeExperienceOrchestration: false
1235
1595
  };
1236
1596
  const configFile = params.config ? require((0, import_path2.resolve)(process.cwd(), params.config)) : {};
1237
1597
  const options = {
@@ -1344,6 +1704,7 @@ async function runContentfulImport(params) {
1344
1704
  title: "Initialize client",
1345
1705
  task: (0, import_listr4.wrapTask)(async (ctx) => {
1346
1706
  ctx.client = initClient({ ...options, content: void 0 });
1707
+ ctx.plainClient = initPlainClient({ ...options, content: void 0 });
1347
1708
  })
1348
1709
  },
1349
1710
  {
@@ -1351,11 +1712,13 @@ async function runContentfulImport(params) {
1351
1712
  task: (0, import_listr4.wrapTask)(async (ctx) => {
1352
1713
  const destinationData = await getDestinationData({
1353
1714
  client: ctx.client,
1715
+ plainClient: ctx.plainClient,
1354
1716
  spaceId: options.spaceId,
1355
1717
  environmentId: options.environmentId,
1356
1718
  sourceData: options.content,
1357
1719
  skipLocales: options.skipLocales,
1358
1720
  skipContentModel: options.skipContentModel,
1721
+ includeExperienceOrchestration: options.includeExperienceOrchestration,
1359
1722
  requestQueue
1360
1723
  });
1361
1724
  ctx.sourceDataUntransformed = options.content;
@@ -1377,7 +1740,9 @@ async function runContentfulImport(params) {
1377
1740
  sourceData: ctx.sourceData,
1378
1741
  destinationData: ctx.destinationData,
1379
1742
  client: ctx.client,
1743
+ plainClient: ctx.plainClient,
1380
1744
  spaceId: options.spaceId,
1745
+ includeExperienceOrchestration: options.includeExperienceOrchestration,
1381
1746
  environmentId: options.environmentId,
1382
1747
  contentModelOnly: options.contentModelOnly,
1383
1748
  skipLocales: options.skipLocales,
package/dist/index.mjs CHANGED
@@ -33,22 +33,37 @@ function initClient(opts) {
33
33
  };
34
34
  return createClient(config, { type: "legacy" });
35
35
  }
36
+ function initPlainClient(opts) {
37
+ return createClient({
38
+ accessToken: opts.managementToken,
39
+ host: opts.host,
40
+ logHandler
41
+ });
42
+ }
36
43
 
37
44
  // lib/tasks/get-destination-data.ts
38
45
  import Promise2 from "bluebird";
39
46
  import { logEmitter as logEmitter2 } from "contentful-batch-libs/dist/logging";
40
47
  var BATCH_CHAR_LIMIT = 1990;
41
48
  var BATCH_SIZE_LIMIT = 100;
42
- var METHODS = {
49
+ var OFFSET_QUERY_METHODS = {
43
50
  contentTypes: { name: "content types", method: "getContentTypes" },
44
51
  locales: { name: "locales", method: "getLocales" },
45
52
  entries: { name: "entries", method: "getEntries" },
46
53
  assets: { name: "assets", method: "getAssets" },
47
54
  tags: { name: "tags", method: "getTags" }
48
55
  };
56
+ var CURSOR_QUERY_METHODS = {
57
+ designTokens: { name: "design tokens", namespace: "designToken" },
58
+ componentTypes: { name: "component types", namespace: "componentType" },
59
+ templates: { name: "templates", namespace: "template" },
60
+ fragments: { name: "fragments", namespace: "fragment" },
61
+ dataAssemblies: { name: "data assemblies", namespace: "dataAssembly" },
62
+ experiences: { name: "experiences", namespace: "experience" }
63
+ };
49
64
  async function batchedIdQuery({ environment, type, ids, requestQueue }) {
50
- const method = METHODS[type].method;
51
- const entityTypeName = METHODS[type].name;
65
+ const method = OFFSET_QUERY_METHODS[type].method;
66
+ const entityTypeName = OFFSET_QUERY_METHODS[type].name;
52
67
  const batches = getIdBatches(ids);
53
68
  let totalFetched = 0;
54
69
  const allPendingResponses = batches.map((idBatch) => {
@@ -66,8 +81,8 @@ async function batchedIdQuery({ environment, type, ids, requestQueue }) {
66
81
  return responses.flat();
67
82
  }
68
83
  async function batchedPageQuery({ environment, type, requestQueue }) {
69
- const method = METHODS[type].method;
70
- const entityTypeName = METHODS[type].name;
84
+ const method = OFFSET_QUERY_METHODS[type].method;
85
+ const entityTypeName = OFFSET_QUERY_METHODS[type].name;
71
86
  let totalFetched = 0;
72
87
  const { items, total } = await requestQueue.add(async () => {
73
88
  const response = await environment[method]({
@@ -123,14 +138,37 @@ function getPagedBatches(totalFetched, total) {
123
138
  }
124
139
  return batches;
125
140
  }
141
+ async function cursorPaginatedQuery({ plainClient, spaceId, environmentId, type, requestQueue }) {
142
+ const { name: entityTypeName, namespace } = CURSOR_QUERY_METHODS[type];
143
+ let totalFetched = 0;
144
+ let pageNext = void 0;
145
+ const allItems = [];
146
+ do {
147
+ const items = await requestQueue.add(async () => {
148
+ const response = await plainClient[namespace].getMany({
149
+ spaceId,
150
+ environmentId,
151
+ query: { limit: BATCH_SIZE_LIMIT, ...pageNext && { pageNext } }
152
+ });
153
+ totalFetched += response.items.length;
154
+ logEmitter2.emit("info", `Fetched ${totalFetched} ${entityTypeName}`);
155
+ pageNext = response.pages?.next;
156
+ return response.items;
157
+ });
158
+ allItems.push(...items);
159
+ } while (pageNext);
160
+ return allItems;
161
+ }
126
162
  async function getDestinationData({
127
163
  client,
164
+ plainClient,
128
165
  spaceId,
129
166
  environmentId,
130
167
  sourceData,
131
168
  contentModelOnly,
132
169
  skipLocales,
133
170
  skipContentModel,
171
+ includeExperienceOrchestration,
134
172
  requestQueue
135
173
  }) {
136
174
  const space = await client.getSpace(spaceId);
@@ -140,7 +178,14 @@ async function getDestinationData({
140
178
  tags: [],
141
179
  locales: [],
142
180
  entries: [],
143
- assets: []
181
+ assets: [],
182
+ experiences: [],
183
+ templates: [],
184
+ componentTypes: [],
185
+ fragments: [],
186
+ dataAssemblies: [],
187
+ designTokens: [],
188
+ webhooks: []
144
189
  };
145
190
  sourceData = {
146
191
  ...result,
@@ -177,7 +222,7 @@ async function getDestinationData({
177
222
  }
178
223
  const entryIds = sourceData.entries?.map((e) => e.sys.id);
179
224
  const assetIds = sourceData.assets?.map((e) => e.sys.id);
180
- if (entryIds) {
225
+ if (entryIds && entryIds.length) {
181
226
  result.entries = batchedIdQuery({
182
227
  environment,
183
228
  type: "entries",
@@ -185,7 +230,7 @@ async function getDestinationData({
185
230
  requestQueue
186
231
  });
187
232
  }
188
- if (assetIds) {
233
+ if (assetIds && assetIds.length) {
189
234
  result.assets = batchedIdQuery({
190
235
  environment,
191
236
  type: "assets",
@@ -193,7 +238,14 @@ async function getDestinationData({
193
238
  requestQueue
194
239
  });
195
240
  }
196
- result.webhooks = [];
241
+ if (includeExperienceOrchestration && plainClient) {
242
+ result.designTokens = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "designTokens", requestQueue });
243
+ result.componentTypes = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "componentTypes", requestQueue });
244
+ result.templates = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "templates", requestQueue });
245
+ result.fragments = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "fragments", requestQueue });
246
+ result.dataAssemblies = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "dataAssemblies", requestQueue });
247
+ result.experiences = cursorPaginatedQuery({ plainClient, spaceId, environmentId, type: "experiences", requestQueue });
248
+ }
197
249
  return Promise2.props(result);
198
250
  }
199
251
 
@@ -529,7 +581,138 @@ async function runQueue(queue, result = [], requestQueue) {
529
581
  return result;
530
582
  }
531
583
 
584
+ // lib/utils/graphql-schema-backoff.ts
585
+ var GRAPHQL_SCHEMA_STALE_DELAYS_MS = [500, 1500, 6e3];
586
+ function isGraphQLSchemaStaleError(err) {
587
+ if (!(err instanceof Error)) {
588
+ return false;
589
+ }
590
+ let parsed;
591
+ try {
592
+ parsed = JSON.parse(err.message);
593
+ } catch {
594
+ return false;
595
+ }
596
+ const errors = parsed?.details?.errors;
597
+ if (!Array.isArray(errors)) {
598
+ return false;
599
+ }
600
+ const matched = errors.some(
601
+ (e) => typeof e.message === "string" && (e.message.includes("GraphQL validation error") || e.message.includes("Unknown content type") || e.message.includes("Pointer path does not exist for"))
602
+ );
603
+ return matched;
604
+ }
605
+
606
+ // lib/utils/sort-component-types.ts
607
+ function sortComponentTypes(componentTypes) {
608
+ const idToIndex = /* @__PURE__ */ new Map();
609
+ componentTypes.forEach((ct, i) => idToIndex.set(ct.sys.id, i));
610
+ const URN_PATTERN = /componentTypes\/([^"\\]+)/g;
611
+ function getDeps(ct) {
612
+ const ids = /* @__PURE__ */ new Set();
613
+ const tree = JSON.stringify(ct.componentTree || []);
614
+ let match;
615
+ while ((match = URN_PATTERN.exec(tree)) !== null) {
616
+ const dep = match[1];
617
+ if (dep !== ct.sys.id && idToIndex.has(dep)) {
618
+ ids.add(dep);
619
+ }
620
+ }
621
+ return [...ids];
622
+ }
623
+ const dependents = /* @__PURE__ */ new Map();
624
+ const inDegree = /* @__PURE__ */ new Map();
625
+ componentTypes.forEach((ct) => {
626
+ inDegree.set(ct.sys.id, 0);
627
+ dependents.set(ct.sys.id, []);
628
+ });
629
+ componentTypes.forEach((ct) => {
630
+ for (const dep of getDeps(ct)) {
631
+ dependents.get(dep).push(ct.sys.id);
632
+ inDegree.set(ct.sys.id, (inDegree.get(ct.sys.id) ?? 0) + 1);
633
+ }
634
+ });
635
+ const queue = componentTypes.filter((ct) => inDegree.get(ct.sys.id) === 0).map((ct) => ct.sys.id);
636
+ const sorted = [];
637
+ while (queue.length > 0) {
638
+ const id = queue.shift();
639
+ sorted.push(componentTypes[idToIndex.get(id)]);
640
+ for (const dependent of dependents.get(id) ?? []) {
641
+ const deg = (inDegree.get(dependent) ?? 1) - 1;
642
+ inDegree.set(dependent, deg);
643
+ if (deg === 0) queue.push(dependent);
644
+ }
645
+ }
646
+ componentTypes.forEach((ct) => {
647
+ if (!sorted.includes(ct)) sorted.push(ct);
648
+ });
649
+ return sorted;
650
+ }
651
+
652
+ // lib/utils/sort-fragments.ts
653
+ function sortFragments(fragments) {
654
+ const idToIndex = /* @__PURE__ */ new Map();
655
+ fragments.forEach((f, i) => idToIndex.set(f.sys.id, i));
656
+ const FRAGMENT_URN_PATTERN = /fragments\/([^"\\]+)/g;
657
+ function getDeps(fragment) {
658
+ const ids = /* @__PURE__ */ new Set();
659
+ const json = JSON.stringify({ slots: fragment.slots || [], componentTree: fragment.componentTree || [] });
660
+ let match;
661
+ while ((match = FRAGMENT_URN_PATTERN.exec(json)) !== null) {
662
+ const dep = match[1];
663
+ if (dep !== fragment.sys.id && idToIndex.has(dep)) {
664
+ ids.add(dep);
665
+ }
666
+ }
667
+ return [...ids];
668
+ }
669
+ const dependents = /* @__PURE__ */ new Map();
670
+ const inDegree = /* @__PURE__ */ new Map();
671
+ fragments.forEach((f) => {
672
+ inDegree.set(f.sys.id, 0);
673
+ dependents.set(f.sys.id, []);
674
+ });
675
+ fragments.forEach((f) => {
676
+ for (const dep of getDeps(f)) {
677
+ dependents.get(dep).push(f.sys.id);
678
+ inDegree.set(f.sys.id, (inDegree.get(f.sys.id) ?? 0) + 1);
679
+ }
680
+ });
681
+ const queue = fragments.filter((f) => inDegree.get(f.sys.id) === 0).map((f) => f.sys.id);
682
+ const sorted = [];
683
+ while (queue.length > 0) {
684
+ const id = queue.shift();
685
+ sorted.push(fragments[idToIndex.get(id)]);
686
+ for (const dependent of dependents.get(id) ?? []) {
687
+ const deg = (inDegree.get(dependent) ?? 1) - 1;
688
+ inDegree.set(dependent, deg);
689
+ if (deg === 0) queue.push(dependent);
690
+ }
691
+ }
692
+ fragments.forEach((f) => {
693
+ if (!sorted.includes(f)) sorted.push(f);
694
+ });
695
+ return sorted;
696
+ }
697
+
532
698
  // lib/tasks/push-to-space/push-to-space.ts
699
+ async function withGraphQLSchemaBackoff(fn) {
700
+ let lastErr;
701
+ for (let attempt = 0; attempt <= GRAPHQL_SCHEMA_STALE_DELAYS_MS.length; attempt++) {
702
+ try {
703
+ return await fn();
704
+ } catch (err) {
705
+ if (!isGraphQLSchemaStaleError(err) || attempt === GRAPHQL_SCHEMA_STALE_DELAYS_MS.length) {
706
+ throw err;
707
+ }
708
+ const delay = GRAPHQL_SCHEMA_STALE_DELAYS_MS[attempt];
709
+ logEmitter6.emit("warning", `DataAssembly GraphQL schema not yet current, retrying in ${delay}ms (attempt ${attempt + 1}/${GRAPHQL_SCHEMA_STALE_DELAYS_MS.length})`);
710
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
711
+ lastErr = err;
712
+ }
713
+ }
714
+ throw lastErr;
715
+ }
533
716
  var DEFAULT_CONTENT_STRUCTURE = {
534
717
  entries: [],
535
718
  assets: [],
@@ -543,8 +726,10 @@ function pushToSpace({
543
726
  sourceData,
544
727
  destinationData = {},
545
728
  client,
729
+ plainClient,
546
730
  spaceId,
547
731
  environmentId,
732
+ includeExperienceOrchestration,
548
733
  contentModelOnly,
549
734
  skipContentModel,
550
735
  skipContentUpdates,
@@ -820,9 +1005,177 @@ function pushToSpace({
820
1005
  ctx.data.webhooks = webhooks2;
821
1006
  }),
822
1007
  skip: () => contentModelOnly || environmentId !== "master" && "Webhooks can only be imported in master environment"
1008
+ },
1009
+ {
1010
+ title: "Importing Data Assemblies",
1011
+ task: wrapTask(async (ctx) => {
1012
+ const results = await Promise.all((sourceData.dataAssemblies || []).map(async (entity) => {
1013
+ try {
1014
+ const existing = destinationDataById.dataAssemblies?.get(entity.sys.id);
1015
+ let result;
1016
+ if (existing) {
1017
+ const payload = { ...entity, sys: { ...entity.sys, version: existing.sys.version } };
1018
+ result = await withGraphQLSchemaBackoff(() => plainClient.dataAssembly.update(
1019
+ { spaceId, environmentId, dataAssemblyId: entity.sys.id },
1020
+ payload
1021
+ ));
1022
+ logEmitter6.emit("info", `UPDATE DataAssembly ${entity.sys.id}`);
1023
+ } else {
1024
+ const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "DataAssembly", dataType: entity.sys.dataType, ...entity.sys.variant ? { variant: entity.sys.variant } : {}, version: 0 } };
1025
+ result = await withGraphQLSchemaBackoff(() => plainClient.dataAssembly.update(
1026
+ { spaceId, environmentId, dataAssemblyId: entity.sys.id },
1027
+ payload
1028
+ ));
1029
+ logEmitter6.emit("info", `CREATE DataAssembly ${entity.sys.id}`);
1030
+ }
1031
+ return result;
1032
+ } catch (err) {
1033
+ logEmitter6.emit("error", err);
1034
+ return null;
1035
+ }
1036
+ }));
1037
+ ctx.data.dataAssemblies = results.filter(Boolean);
1038
+ }),
1039
+ skip: () => !includeExperienceOrchestration || !(sourceData.dataAssemblies || []).length
1040
+ },
1041
+ {
1042
+ title: "Importing Design Tokens",
1043
+ task: wrapTask(async (ctx) => {
1044
+ const results = await Promise.all((sourceData.designTokens || []).map(async (entity) => {
1045
+ try {
1046
+ const existing = destinationDataById.designTokens?.get(entity.sys.id);
1047
+ if (existing) {
1048
+ const payload = { ...entity, sys: { id: entity.sys.id, type: "DesignToken", version: existing.sys.version } };
1049
+ const result = await plainClient.designToken.upsert({ spaceId, environmentId, designTokenId: entity.sys.id }, payload);
1050
+ logEmitter6.emit("info", `UPDATE DesignToken ${entity.sys.id}`);
1051
+ return result;
1052
+ } else {
1053
+ const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "DesignToken" } };
1054
+ const result = await plainClient.designToken.upsert({ spaceId, environmentId, designTokenId: entity.sys.id }, payload);
1055
+ logEmitter6.emit("info", `CREATE DesignToken ${entity.sys.id}`);
1056
+ return result;
1057
+ }
1058
+ } catch (err) {
1059
+ logEmitter6.emit("error", err);
1060
+ return null;
1061
+ }
1062
+ }));
1063
+ ctx.data.designTokens = results.filter(Boolean);
1064
+ }),
1065
+ skip: () => !includeExperienceOrchestration || !(sourceData.designTokens || []).length
1066
+ },
1067
+ {
1068
+ title: "Importing Component Types",
1069
+ task: wrapTask(async (ctx) => {
1070
+ const sorted = sortComponentTypes(sourceData.componentTypes || []);
1071
+ const results = [];
1072
+ for (const entity of sorted) {
1073
+ try {
1074
+ const existing = destinationDataById.componentTypes?.get(entity.sys.id);
1075
+ if (existing) {
1076
+ const payload = { ...entity, sys: { id: entity.sys.id, type: "ComponentType", version: existing.sys.version } };
1077
+ const result = await plainClient.componentType.upsert({ spaceId, environmentId, componentTypeId: entity.sys.id }, payload);
1078
+ logEmitter6.emit("info", `UPDATE ComponentType ${entity.sys.id}`);
1079
+ results.push(result);
1080
+ } else {
1081
+ const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "ComponentType" } };
1082
+ const result = await plainClient.componentType.upsert({ spaceId, environmentId, componentTypeId: entity.sys.id }, payload);
1083
+ logEmitter6.emit("info", `CREATE ComponentType ${entity.sys.id}`);
1084
+ results.push(result);
1085
+ }
1086
+ } catch (err) {
1087
+ logEmitter6.emit("error", err);
1088
+ }
1089
+ }
1090
+ ctx.data.componentTypes = results;
1091
+ }),
1092
+ skip: () => !includeExperienceOrchestration || !(sourceData.componentTypes || []).length
1093
+ },
1094
+ {
1095
+ title: "Importing Templates",
1096
+ task: wrapTask(async (ctx) => {
1097
+ const results = await Promise.all((sourceData.templates || []).map(async (entity) => {
1098
+ try {
1099
+ const existing = destinationDataById.templates?.get(entity.sys.id);
1100
+ if (existing) {
1101
+ const payload = { ...entity, sys: { id: entity.sys.id, type: "Template", version: existing.sys.version } };
1102
+ const result = await plainClient.template.upsert({ spaceId, environmentId, templateId: entity.sys.id }, payload);
1103
+ logEmitter6.emit("info", `UPDATE Template ${entity.sys.id}`);
1104
+ return result;
1105
+ } else {
1106
+ const payload = { ...omitSys(entity), sys: { id: entity.sys.id, type: "Template" } };
1107
+ const result = await plainClient.template.upsert({ spaceId, environmentId, templateId: entity.sys.id }, payload);
1108
+ logEmitter6.emit("info", `CREATE Template ${entity.sys.id}`);
1109
+ return result;
1110
+ }
1111
+ } catch (err) {
1112
+ logEmitter6.emit("error", err);
1113
+ return null;
1114
+ }
1115
+ }));
1116
+ ctx.data.templates = results.filter(Boolean);
1117
+ }),
1118
+ skip: () => !includeExperienceOrchestration || !(sourceData.templates || []).length
1119
+ },
1120
+ {
1121
+ title: "Importing Fragments",
1122
+ task: wrapTask(async (ctx) => {
1123
+ const sorted = sortFragments(sourceData.fragments || []);
1124
+ const results = [];
1125
+ for (const entity of sorted) {
1126
+ try {
1127
+ const existing = destinationDataById.fragments?.get(entity.sys.id);
1128
+ if (existing) {
1129
+ const payload = { ...entity, componentType: entity.sys.componentType, sys: { id: entity.sys.id, type: "Fragment", version: existing.sys.version } };
1130
+ const result = await plainClient.fragment.upsert({ spaceId, environmentId, fragmentId: entity.sys.id }, payload);
1131
+ logEmitter6.emit("info", `UPDATE Fragment ${entity.sys.id}`);
1132
+ results.push(result);
1133
+ } else {
1134
+ const payload = { ...omitSys(entity), componentType: entity.sys.componentType, sys: { id: entity.sys.id, type: "Fragment" } };
1135
+ const result = await plainClient.fragment.upsert({ spaceId, environmentId, fragmentId: entity.sys.id }, payload);
1136
+ logEmitter6.emit("info", `CREATE Fragment ${entity.sys.id}`);
1137
+ results.push(result);
1138
+ }
1139
+ } catch (err) {
1140
+ logEmitter6.emit("error", err);
1141
+ }
1142
+ }
1143
+ ctx.data.fragments = results;
1144
+ }),
1145
+ skip: () => !includeExperienceOrchestration || !(sourceData.fragments || []).length
1146
+ },
1147
+ {
1148
+ title: "Importing Experiences",
1149
+ task: wrapTask(async (ctx) => {
1150
+ const results = await Promise.all((sourceData.experiences || []).map(async (entity) => {
1151
+ try {
1152
+ const existing = destinationDataById.experiences?.get(entity.sys.id);
1153
+ if (existing) {
1154
+ const payload = { ...entity, template: entity.sys.template, sys: { id: entity.sys.id, type: "Experience", version: existing.sys.version } };
1155
+ const result = await plainClient.experience.upsert({ spaceId, environmentId, experienceId: entity.sys.id }, payload);
1156
+ logEmitter6.emit("info", `UPDATE Experience ${entity.sys.id}`);
1157
+ return result;
1158
+ } else {
1159
+ const payload = { ...omitSys(entity), template: entity.sys.template, sys: { id: entity.sys.id, type: "Experience" } };
1160
+ const result = await plainClient.experience.upsert({ spaceId, environmentId, experienceId: entity.sys.id }, payload);
1161
+ logEmitter6.emit("info", `CREATE Experience ${entity.sys.id}`);
1162
+ return result;
1163
+ }
1164
+ } catch (err) {
1165
+ logEmitter6.emit("error", err);
1166
+ return null;
1167
+ }
1168
+ }));
1169
+ ctx.data.experiences = results.filter(Boolean);
1170
+ }),
1171
+ skip: () => !includeExperienceOrchestration || !(sourceData.experiences || []).length
823
1172
  }
824
1173
  ], listrOptions);
825
1174
  }
1175
+ function omitSys(entity) {
1176
+ const { sys: _sys, ...rest } = entity;
1177
+ return rest;
1178
+ }
826
1179
  function archiveEntities2({ entities, sourceEntities, requestQueue }) {
827
1180
  const entityIdsToArchive = sourceEntities.filter(({ original }) => original.sys.archivedVersion).map(({ original }) => original.sys.id);
828
1181
  const entitiesToArchive = entities.filter((entity) => entityIdsToArchive.indexOf(entity.sys.id) !== -1);
@@ -1188,7 +1541,13 @@ var SUPPORTED_ENTITY_TYPES = [
1188
1541
  "assets",
1189
1542
  "locales",
1190
1543
  "webhooks",
1191
- "editorInterfaces"
1544
+ "editorInterfaces",
1545
+ "designTokens",
1546
+ "componentTypes",
1547
+ "templates",
1548
+ "dataAssemblies",
1549
+ "fragments",
1550
+ "experiences"
1192
1551
  ];
1193
1552
  async function parseOptions(params) {
1194
1553
  const defaultOptions = {
@@ -1201,7 +1560,8 @@ async function parseOptions(params) {
1201
1560
  environmentId: "master",
1202
1561
  rawProxy: false,
1203
1562
  uploadAssets: false,
1204
- rateLimit: 7
1563
+ rateLimit: 7,
1564
+ includeExperienceOrchestration: false
1205
1565
  };
1206
1566
  const configFile = params.config ? __require(resolve(process.cwd(), params.config)) : {};
1207
1567
  const options = {
@@ -1314,6 +1674,7 @@ async function runContentfulImport(params) {
1314
1674
  title: "Initialize client",
1315
1675
  task: wrapTask2(async (ctx) => {
1316
1676
  ctx.client = initClient({ ...options, content: void 0 });
1677
+ ctx.plainClient = initPlainClient({ ...options, content: void 0 });
1317
1678
  })
1318
1679
  },
1319
1680
  {
@@ -1321,11 +1682,13 @@ async function runContentfulImport(params) {
1321
1682
  task: wrapTask2(async (ctx) => {
1322
1683
  const destinationData = await getDestinationData({
1323
1684
  client: ctx.client,
1685
+ plainClient: ctx.plainClient,
1324
1686
  spaceId: options.spaceId,
1325
1687
  environmentId: options.environmentId,
1326
1688
  sourceData: options.content,
1327
1689
  skipLocales: options.skipLocales,
1328
1690
  skipContentModel: options.skipContentModel,
1691
+ includeExperienceOrchestration: options.includeExperienceOrchestration,
1329
1692
  requestQueue
1330
1693
  });
1331
1694
  ctx.sourceDataUntransformed = options.content;
@@ -1347,7 +1710,9 @@ async function runContentfulImport(params) {
1347
1710
  sourceData: ctx.sourceData,
1348
1711
  destinationData: ctx.destinationData,
1349
1712
  client: ctx.client,
1713
+ plainClient: ctx.plainClient,
1350
1714
  spaceId: options.spaceId,
1715
+ includeExperienceOrchestration: options.includeExperienceOrchestration,
1351
1716
  environmentId: options.environmentId,
1352
1717
  contentModelOnly: options.contentModelOnly,
1353
1718
  skipLocales: options.skipLocales,
@@ -29,6 +29,8 @@ declare const _default: {
29
29
  "rate-limit": number;
30
30
  rateLimit: number;
31
31
  header: string | undefined;
32
+ "include-experience-orchestration": boolean;
33
+ includeExperienceOrchestration: boolean;
32
34
  _: (string | number)[];
33
35
  $0: string;
34
36
  } | Promise<{
@@ -62,6 +64,8 @@ declare const _default: {
62
64
  "rate-limit": number;
63
65
  rateLimit: number;
64
66
  header: string | undefined;
67
+ "include-experience-orchestration": boolean;
68
+ includeExperienceOrchestration: boolean;
65
69
  _: (string | number)[];
66
70
  $0: string;
67
71
  }>;
@@ -29,6 +29,8 @@ declare const _default: {
29
29
  "rate-limit": number;
30
30
  rateLimit: number;
31
31
  header: string | undefined;
32
+ "include-experience-orchestration": boolean;
33
+ includeExperienceOrchestration: boolean;
32
34
  _: (string | number)[];
33
35
  $0: string;
34
36
  } | Promise<{
@@ -62,6 +64,8 @@ declare const _default: {
62
64
  "rate-limit": number;
63
65
  rateLimit: number;
64
66
  header: string | undefined;
67
+ "include-experience-orchestration": boolean;
68
+ includeExperienceOrchestration: boolean;
65
69
  _: (string | number)[];
66
70
  $0: string;
67
71
  }>;
@@ -99,4 +99,8 @@ var usageParams_default = import_yargs.default.version(version || "Version only
99
99
  alias: "H",
100
100
  type: "string",
101
101
  describe: "Pass an additional HTTP Header"
102
+ }).option("include-experience-orchestration", {
103
+ describe: "Import Experience Orchestration entities (designTokens, componentTypes, templates, fragments, dataAssemblies, experiences). Requires a space with ExO enabled.",
104
+ type: "boolean",
105
+ default: true
102
106
  }).config("config", "An optional configuration JSON file containing all the options for a single run").argv;
@@ -65,6 +65,10 @@ var usageParams_default = yargs.version(version || "Version only available on in
65
65
  alias: "H",
66
66
  type: "string",
67
67
  describe: "Pass an additional HTTP Header"
68
+ }).option("include-experience-orchestration", {
69
+ describe: "Import Experience Orchestration entities (designTokens, componentTypes, templates, fragments, dataAssemblies, experiences). Requires a space with ExO enabled.",
70
+ type: "boolean",
71
+ default: true
68
72
  }).config("config", "An optional configuration JSON file containing all the options for a single run").argv;
69
73
  export {
70
74
  usageParams_default as default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contentful-import",
3
- "version": "10.0.18",
3
+ "version": "10.1.0-exo.10",
4
4
  "description": "this tool allows you to import JSON dump exported by contentful-export",
5
5
  "main": "dist/index.mjs",
6
6
  "typings": "dist/index.d.ts",
@@ -64,7 +64,7 @@
64
64
  "bluebird": "^3.7.2",
65
65
  "cli-table3": "^0.6.5",
66
66
  "contentful-batch-libs": "^9.7.0",
67
- "contentful-management": "^12.8.0",
67
+ "contentful-management": "^12.12.0",
68
68
  "date-fns": "^2.30.0",
69
69
  "joi": "^18.2.3",
70
70
  "listr": "^0.14.3",
@@ -145,6 +145,6 @@
145
145
  ]
146
146
  },
147
147
  "overrides": {
148
- "undici": "^8.0.0"
148
+ "undici": "^6.27.0"
149
149
  }
150
150
  }