contentful-export 8.1.2 → 9.0.0-exo.2

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/README.md CHANGED
@@ -268,6 +268,12 @@ Full path to the error log file
268
268
 
269
269
  Display progress in new lines instead of displaying a busy spinner and the status in the same line. Useful for CI.
270
270
 
271
+ ### Experience Orchestration
272
+
273
+ #### `includeExperienceOrchestration` [boolean] [default: true]
274
+
275
+ Flag controlling whether Experience Orchestration (ExO) entities — Design Tokens, Components, Experience Templates, Data Assemblies, Experience Fragments, and Experiences — are exported when present in the source space. Requires the `exoM1` entitlement on the source space's organization. Set to `false` to opt out. See the "Experience Orchestration (ExO) entities" section below for what happens when the space isn't entitled.
276
+
271
277
  ## :rescue_worker_helmet: Troubleshooting
272
278
 
273
279
  ### Proxy
@@ -324,12 +330,48 @@ This is an overview of the exported data:
324
330
  "tags": [],
325
331
  "webhooks": [],
326
332
  "roles": [],
327
- "editorInterfaces": []
333
+ "editorInterfaces": [],
334
+ "designTokens": [],
335
+ "components": [],
336
+ "experienceTemplates": [],
337
+ "dataAssemblies": [],
338
+ "experienceFragments": [],
339
+ "experiences": []
328
340
  }
329
341
  ```
330
342
 
331
343
  _Note:_ Tags feature is not available for all users. If you do not have access to this feature, the tags array will always be empty.
332
344
 
345
+ _Note:_ `designTokens`, `components`, `experienceTemplates`, `dataAssemblies`, `experienceFragments`, and `experiences` are Experience Orchestration (ExO) entities — present by default; absent only if you explicitly set `includeExperienceOrchestration: false` — see the "Experience Orchestration (ExO) entities" section below.
346
+
347
+ ## :test_tube: Experience Orchestration (ExO) entities
348
+
349
+ Experience Orchestration (ExO) is Contentful's system for composing and rendering structured page experiences. It sits above the traditional entry/content-type layer and provides six dedicated entity types — Design Tokens, Components, Experience Templates, Data Assemblies, Experience Fragments, and Experiences — that together describe how content is fetched, assembled, and laid out.
350
+
351
+ > **Experimental:** ExO entities (`designTokens`, `components`, `experienceTemplates`, `dataAssemblies`, `experienceFragments`, `experiences`) are `@internal` and considered experimental. Their shape and export behavior are subject to change without notice.
352
+
353
+ ExO export is on by default (`includeExperienceOrchestration: true`) — for the CLI and the module API alike. Pass `includeExperienceOrchestration: false` (`--include-experience-orchestration=false` on the CLI) to opt out.
354
+
355
+ ```javascript
356
+ import contentfulExport from 'contentful-export'
357
+
358
+ const options = {
359
+ spaceId: '<space_id>',
360
+ managementToken: '<content_management_api_key>',
361
+ includeExperienceOrchestration: false // opt out; omit to export ExO entities when present (the default)
362
+ }
363
+
364
+ await contentfulExport(options)
365
+ ```
366
+
367
+ If the source space has no ExO entities, or lacks the `exoM1` entitlement, each ExO entity type logs a `Skipping <Entity> export` warning and exports as an empty array — it does not fail the export. Pass `includeExperienceOrchestration: false` if you want to avoid it.
368
+
369
+ Requires the `exoM1` entitlement on the source space's organization. [contentful-cli](https://github.com/contentful/contentful-cli)'s `space export` command doesn't expose this option at all yet, so ExO export isn't reachable through that separate CLI regardless of default.
370
+
371
+ ### Round-tripping into `contentful-import`
372
+
373
+ The ExO entities exported here are designed to be fed directly into [`contentful-import`](https://github.com/contentful/contentful-import), which preserves source IDs, applies dependency ordering (a topological sort for Components and Experience Fragments, since either can reference others of the same type), and upgrades entities from older, pre-rename export files automatically. See `contentful-import`'s README "Experience Orchestration (ExO) entities" section for the import-side details.
374
+
333
375
  ## :warning: Limitations
334
376
 
335
377
  - This tool currently does **not** support the export of space memberships.
package/dist/index.js CHANGED
@@ -18,8 +18,9 @@ var _formatDistance = require("date-fns/formatDistance");
18
18
  var _contentfulBatchLibs = require("contentful-batch-libs");
19
19
  var _downloadAssets = _interopRequireDefault(require("./tasks/download-assets"));
20
20
  var _getSpaceData = _interopRequireDefault(require("./tasks/get-space-data"));
21
- var _initClient = _interopRequireDefault(require("./tasks/init-client"));
21
+ var _initClient = _interopRequireWildcard(require("./tasks/init-client"));
22
22
  var _parseOptions = _interopRequireDefault(require("./parseOptions"));
23
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
23
24
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
24
25
  const accessP = _bluebird.default.promisify(_fs.access);
25
26
  const tableOptions = {
@@ -53,6 +54,7 @@ function runContentfulExport(params) {
53
54
  try {
54
55
  // CMA client
55
56
  ctx.client = (0, _initClient.default)(options);
57
+ ctx.plainClient = (0, _initClient.initPlainClient)(options);
56
58
  if (options.deliveryToken && !options.includeDrafts) {
57
59
  // CDA client for fetching only public entries
58
60
  ctx.cdaClient = (0, _initClient.default)(options, true);
@@ -67,6 +69,7 @@ function runContentfulExport(params) {
67
69
  task: ctx => {
68
70
  return (0, _getSpaceData.default)({
69
71
  client: ctx.client,
72
+ plainClient: ctx.plainClient,
70
73
  cdaClient: ctx.cdaClient,
71
74
  spaceId: options.spaceId,
72
75
  environmentId: options.environmentId,
@@ -76,11 +79,11 @@ function runContentfulExport(params) {
76
79
  skipContentModel: options.skipContentModel,
77
80
  skipEditorInterfaces: options.skipEditorInterfaces,
78
81
  skipContent: options.skipContent,
79
- skipAssets: options.skipAssets,
80
82
  skipWebhooks: options.skipWebhooks,
81
83
  skipRoles: options.skipRoles,
82
84
  skipTags: options.skipTags,
83
85
  stripTags: options.stripTags,
86
+ includeExperienceOrchestration: options.includeExperienceOrchestration,
84
87
  listrOptions,
85
88
  queryEntries: options.queryEntries,
86
89
  queryAssets: options.queryAssets
@@ -113,9 +116,7 @@ function runContentfulExport(params) {
113
116
  task: ctx => {
114
117
  return _bfj.default.write(options.logFilePath, ctx.data, {
115
118
  circular: 'ignore',
116
- space: 2,
117
- bufferLength: 1024,
118
- yieldRate: 16384
119
+ space: 2
119
120
  });
120
121
  }
121
122
  }]);
@@ -26,11 +26,11 @@ function parseOptions(params) {
26
26
  skipContentModel: false,
27
27
  skipEditorInterfaces: false,
28
28
  skipContent: false,
29
- skipAssets: false,
30
29
  skipWebhooks: false,
31
30
  skipTags: false,
32
31
  stripTags: false,
33
32
  maxAllowedLimit: 1000,
33
+ includeExperienceOrchestration: true,
34
34
  saveFile: true,
35
35
  useVerboseRenderer: false,
36
36
  rawProxy: false
@@ -18,12 +18,12 @@ let pageLimit = MAX_ALLOWED_LIMIT;
18
18
  */
19
19
  function getFullSourceSpace({
20
20
  client,
21
+ plainClient,
21
22
  cdaClient,
22
23
  spaceId,
23
24
  environmentId = 'master',
24
25
  skipContentModel,
25
26
  skipContent,
26
- skipAssets,
27
27
  skipWebhooks,
28
28
  skipRoles,
29
29
  skipEditorInterfaces,
@@ -32,6 +32,7 @@ function getFullSourceSpace({
32
32
  includeDrafts,
33
33
  includeArchived,
34
34
  maxAllowedLimit,
35
+ includeExperienceOrchestration,
35
36
  listrOptions,
36
37
  queryEntries,
37
38
  queryAssets
@@ -115,7 +116,7 @@ function getFullSourceSpace({
115
116
  ctx.data.assets = items;
116
117
  });
117
118
  }),
118
- skip: () => skipContent || skipAssets
119
+ skip: () => skipContent
119
120
  }, {
120
121
  title: 'Fetching locales data',
121
122
  task: (0, _contentfulBatchLibs.wrapTask)(ctx => {
@@ -149,6 +150,102 @@ function getFullSourceSpace({
149
150
  });
150
151
  }),
151
152
  skip: () => skipRoles || environmentId !== 'master' && 'Roles can only be exported from master environment'
153
+ }, {
154
+ title: 'Fetching Design Tokens data',
155
+ task: (0, _contentfulBatchLibs.wrapTask)(async ctx => {
156
+ try {
157
+ ctx.data.designTokens = await cursorPagedGet({
158
+ client: plainClient,
159
+ spaceId,
160
+ environmentId,
161
+ method: 'designToken.getMany'
162
+ });
163
+ } catch (err) {
164
+ _contentfulBatchLibs.logEmitter.emit('warning', `Skipping Design Tokens export: ${err.message}`);
165
+ ctx.data.designTokens = [];
166
+ }
167
+ }),
168
+ skip: () => !includeExperienceOrchestration
169
+ }, {
170
+ title: 'Fetching Components data',
171
+ task: (0, _contentfulBatchLibs.wrapTask)(async ctx => {
172
+ try {
173
+ ctx.data.components = await cursorPagedGet({
174
+ client: plainClient,
175
+ spaceId,
176
+ environmentId,
177
+ method: 'component.getMany'
178
+ });
179
+ } catch (err) {
180
+ _contentfulBatchLibs.logEmitter.emit('warning', `Skipping Components export: ${err.message}`);
181
+ ctx.data.components = [];
182
+ }
183
+ }),
184
+ skip: () => !includeExperienceOrchestration
185
+ }, {
186
+ title: 'Fetching Experience Templates data',
187
+ task: (0, _contentfulBatchLibs.wrapTask)(async ctx => {
188
+ try {
189
+ ctx.data.experienceTemplates = await cursorPagedGet({
190
+ client: plainClient,
191
+ spaceId,
192
+ environmentId,
193
+ method: 'experienceTemplate.getMany'
194
+ });
195
+ } catch (err) {
196
+ _contentfulBatchLibs.logEmitter.emit('warning', `Skipping Experience Templates export: ${err.message}`);
197
+ ctx.data.experienceTemplates = [];
198
+ }
199
+ }),
200
+ skip: () => !includeExperienceOrchestration
201
+ }, {
202
+ title: 'Fetching Data Assemblies data',
203
+ task: (0, _contentfulBatchLibs.wrapTask)(async ctx => {
204
+ try {
205
+ ctx.data.dataAssemblies = await cursorPagedGet({
206
+ client: plainClient,
207
+ spaceId,
208
+ environmentId,
209
+ method: 'dataAssembly.getMany'
210
+ });
211
+ } catch (err) {
212
+ _contentfulBatchLibs.logEmitter.emit('warning', `Skipping Data Assemblies export: ${err.message}`);
213
+ ctx.data.dataAssemblies = [];
214
+ }
215
+ }),
216
+ skip: () => !includeExperienceOrchestration
217
+ }, {
218
+ title: 'Fetching Experience Fragments data',
219
+ task: (0, _contentfulBatchLibs.wrapTask)(async ctx => {
220
+ try {
221
+ ctx.data.experienceFragments = await cursorPagedGet({
222
+ client: plainClient,
223
+ spaceId,
224
+ environmentId,
225
+ method: 'experienceFragment.getMany'
226
+ });
227
+ } catch (err) {
228
+ _contentfulBatchLibs.logEmitter.emit('warning', `Skipping Experience Fragments export: ${err.message}`);
229
+ ctx.data.experienceFragments = [];
230
+ }
231
+ }),
232
+ skip: () => !includeExperienceOrchestration
233
+ }, {
234
+ title: 'Fetching Experiences data',
235
+ task: (0, _contentfulBatchLibs.wrapTask)(async ctx => {
236
+ try {
237
+ ctx.data.experiences = await cursorPagedGet({
238
+ client: plainClient,
239
+ spaceId,
240
+ environmentId,
241
+ method: 'experience.getMany'
242
+ });
243
+ } catch (err) {
244
+ _contentfulBatchLibs.logEmitter.emit('warning', `Skipping Experiences export: ${err.message}`);
245
+ ctx.data.experiences = [];
246
+ }
247
+ }),
248
+ skip: () => !includeExperienceOrchestration
152
249
  }], listrOptions);
153
250
  }
154
251
  function getEditorInterfaces(contentTypes) {
@@ -167,6 +264,37 @@ function getEditorInterfaces(contentTypes) {
167
264
  });
168
265
  }
169
266
 
267
+ /**
268
+ * Gets all ExO entities using cursor-based pagination (pageNext/pagePrev tokens).
269
+ * ExO list endpoints do not support skip-based pagination or the order param.
270
+ */
271
+ async function cursorPagedGet({
272
+ client,
273
+ spaceId,
274
+ environmentId,
275
+ method
276
+ }) {
277
+ const [entity, operation] = method.split('.');
278
+ const allItems = [];
279
+ let pageNext = null;
280
+ do {
281
+ var _response$pages$next, _response$pages;
282
+ const query = {
283
+ spaceId,
284
+ environmentId,
285
+ limit: pageLimit
286
+ };
287
+ if (pageNext) {
288
+ query.pageNext = pageNext;
289
+ }
290
+ const response = await client[entity][operation](query);
291
+ allItems.push(...response.items);
292
+ _contentfulBatchLibs.logEmitter.emit('info', `Fetched ${allItems.length} ${entity} items`);
293
+ pageNext = (_response$pages$next = (_response$pages = response.pages) === null || _response$pages === void 0 ? void 0 : _response$pages.next) !== null && _response$pages$next !== void 0 ? _response$pages$next : null;
294
+ } while (pageNext);
295
+ return allItems;
296
+ }
297
+
170
298
  /**
171
299
  * Gets all the existing entities based on pagination parameters.
172
300
  * The first call will have no aggregated response. Subsequent calls will
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = initClient;
7
+ exports.initPlainClient = initPlainClient;
7
8
  var _contentful = require("contentful");
8
9
  var _contentfulBatchLibs = require("contentful-batch-libs");
9
10
  var _contentfulManagement = require("contentful-management");
@@ -34,4 +35,10 @@ function initClient(opts, useCda = false) {
34
35
  type: 'legacy'
35
36
  });
36
37
  }
37
- module.exports = exports.default;
38
+ function initPlainClient(opts) {
39
+ return (0, _contentfulManagement.createClient)({
40
+ accessToken: opts.managementToken,
41
+ host: opts.host,
42
+ logHandler
43
+ });
44
+ }
@@ -41,10 +41,6 @@ var _default = exports.default = _yargs.default.version(_package.default.version
41
41
  describe: 'Skip exporting assets and entries',
42
42
  type: 'boolean',
43
43
  default: false
44
- }).option('skip-assets', {
45
- describe: 'Skip exporting assets',
46
- type: 'boolean',
47
- default: false
48
44
  }).option('skip-roles', {
49
45
  describe: 'Skip exporting roles and permissions',
50
46
  type: 'boolean',
@@ -107,6 +103,10 @@ var _default = exports.default = _yargs.default.version(_package.default.version
107
103
  describe: 'Display progress in new lines instead of displaying a busy spinner and the status in the same line. Useful for CI.',
108
104
  type: 'boolean',
109
105
  default: false
106
+ }).option('include-experience-orchestration', {
107
+ describe: 'Include Experience Orchestration entities (Components, Experience Templates, Data Assemblies, Experience Fragments, Experiences, Design Tokens). Requires exo_m1 entitlement on the source space.',
108
+ type: 'boolean',
109
+ default: true
110
110
  }).option('header', {
111
111
  alias: 'H',
112
112
  type: 'string',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contentful-export",
3
- "version": "8.1.2",
3
+ "version": "9.0.0-exo.2",
4
4
  "description": "this tool allows you to export a space to a JSON dump",
5
5
  "main": "dist/index.js",
6
6
  "types": "types.d.ts",
@@ -51,7 +51,7 @@
51
51
  "cli-table3": "^0.6.0",
52
52
  "contentful": "^11.5.10",
53
53
  "contentful-batch-libs": "^12.0.0",
54
- "contentful-management": "^12.10.0",
54
+ "contentful-management": "^12.13.0",
55
55
  "date-fns": "^4.1.0",
56
56
  "figures": "^3.2.0",
57
57
  "jsonwebtoken": "^9.0.0",
@@ -144,7 +144,6 @@
144
144
  ]
145
145
  },
146
146
  "overrides": {
147
- "cross-spawn": "^7.0.6",
148
- "undici": "^6.27.0"
147
+ "cross-spawn": "^7.0.6"
149
148
  }
150
149
  }
package/types.d.ts CHANGED
@@ -21,7 +21,6 @@ export interface Options {
21
21
  queryAssets?: string[];
22
22
  rawProxy?: boolean;
23
23
  saveFile?: boolean;
24
- skipAssets?: boolean;
25
24
  skipContent?: boolean;
26
25
  skipContentModel?: boolean;
27
26
  skipEditorInterfaces?: boolean;
@@ -29,9 +28,10 @@ export interface Options {
29
28
  skipWebhooks?: boolean;
30
29
  skipTags?: boolean;
31
30
  useVerboseRenderer?: boolean;
31
+ includeExperienceOrchestration?: boolean;
32
32
  }
33
33
 
34
- type ContentfulExportField = 'contentTypes' | 'entries' | 'assets' | 'locales' | 'tags' | 'webhooks' | 'roles' | 'editorInterfaces';
34
+ type ContentfulExportField = 'contentTypes' | 'entries' | 'assets' | 'locales' | 'tags' | 'webhooks' | 'roles' | 'editorInterfaces' | 'designTokens' | 'components' | 'experienceTemplates' | 'dataAssemblies' | 'experienceFragments' | 'experiences';
35
35
 
36
36
  declare const runContentfulExport: (params: Options) => Promise<Record<ContentfulExportField, unknown[]>>
37
37
  export default runContentfulExport