contentful-export 8.2.0 → 8.2.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
@@ -216,6 +216,14 @@ Skip exporting webhooks
216
216
 
217
217
  Untag assets and entries
218
218
 
219
+ #### `includeExperienceOrchestration` [boolean] [default: true]
220
+
221
+ Export Experience Orchestration (ExO) entities: Design Tokens, Components, Experience Templates, Data Assemblies, Experience Fragments, and Experiences.
222
+
223
+ Requires the Organization to have the `exo_m1` entitlement. If the Organization is not entitled, the export will not throw — each ExO array will be empty and a warning will be logged.
224
+
225
+ See [docs/exo-export.md](./docs/exo-export.md) for full details.
226
+
219
227
  #### `contentOnly` [boolean] [default: false]
220
228
 
221
229
  Only export entries and assets
@@ -340,6 +348,19 @@ This is an overview of the exported data:
340
348
  }
341
349
  ```
342
350
 
351
+ When `includeExperienceOrchestration: true` is set, six additional arrays are included:
352
+
353
+ ```json
354
+ {
355
+ "designTokens": [],
356
+ "components": [],
357
+ "experienceTemplates": [],
358
+ "dataAssemblies": [],
359
+ "experienceFragments": [],
360
+ "experiences": []
361
+ }
362
+ ```
363
+
343
364
  _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.
344
365
 
345
366
  _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.
package/dist/index.js CHANGED
@@ -118,8 +118,11 @@ function runContentfulExport(params) {
118
118
  return _bfj.default.write(options.logFilePath, ctx.data, {
119
119
  circular: 'ignore',
120
120
  space: 2,
121
- bufferLength: 1024,
122
- yieldRate: 16384
121
+ // Do not set `yieldRate` -- values above `bufferLength`
122
+ // make bfj 9's serialization quadratic and it never
123
+ // finishes. See DX-1343.
124
+ bufferLength: 65536,
125
+ highWaterMark: 1024 * 1024
123
126
  });
124
127
  }
125
128
  }]);
@@ -13,19 +13,26 @@ var _stream = require("stream");
13
13
  var _util = require("util");
14
14
  var _embargoedAssets = require("../utils/embargoedAssets");
15
15
  var _axios = _interopRequireDefault(require("axios"));
16
+ var _axiosRetry = _interopRequireDefault(require("axios-retry"));
16
17
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
18
  const streamPipeline = (0, _util.promisify)(_stream.pipeline);
18
19
 
20
+ // For streaming responses, axios timeout applies to time-to-first-byte, not total transfer duration
21
+ const DEFAULT_DOWNLOAD_TIMEOUT_MS = 30000;
22
+ const DEFAULT_RETRY_LIMIT = 3;
23
+
19
24
  /**
20
25
  * @param {Object} options - The options for downloading the asset.
21
26
  * @param {string} options.url - The URL of the asset to download.
22
27
  * @param {string} options.directory - The directory where the asset should be saved.
23
28
  * @param {import('axios').AxiosInstance} options.httpClient - The HTTP client to use for downloading the asset.
29
+ * @param {string} options.assetId - The ID of the asset being downloaded, used in error messages.
24
30
  */
25
31
  async function downloadAsset({
26
32
  url,
27
33
  directory,
28
- httpClient
34
+ httpClient,
35
+ assetId
29
36
  }) {
30
37
  // handle urls without protocol
31
38
  if (url.startsWith('//')) {
@@ -57,7 +64,14 @@ async function downloadAsset({
57
64
  * @type {import('axios').AxiosError}
58
65
  */
59
66
  const axiosError = e;
60
- throw new Error(`error response status: ${axiosError.response.status}`);
67
+ if (axiosError.response) {
68
+ throw new Error(`error downloading asset ${assetId} (${url}): HTTP ${axiosError.response.status} ${axiosError.response.statusText}`, {
69
+ cause: axiosError
70
+ });
71
+ }
72
+ throw new Error(`error downloading asset ${assetId} (${url}): ${e.message}`, {
73
+ cause: e
74
+ });
61
75
  }
62
76
  }
63
77
  function downloadAssets(options) {
@@ -67,11 +81,24 @@ function downloadAssets(options) {
67
81
  let errorCount = 0;
68
82
  const httpClient = _axios.default.create({
69
83
  headers: options.headers,
70
- timeout: options.timeout,
84
+ timeout: DEFAULT_DOWNLOAD_TIMEOUT_MS,
71
85
  httpAgent: options.httpAgent,
72
86
  httpsAgent: options.httpsAgent,
73
87
  proxy: options.proxy
74
88
  });
89
+ (0, _axiosRetry.default)(httpClient, {
90
+ retries: DEFAULT_RETRY_LIMIT,
91
+ retryDelay: _axiosRetry.default.exponentialDelay,
92
+ shouldResetTimeout: true,
93
+ retryCondition: error => {
94
+ var _error$response;
95
+ return _axiosRetry.default.isNetworkOrIdempotentRequestError(error) || ((_error$response = error.response) === null || _error$response === void 0 ? void 0 : _error$response.status) === 429;
96
+ },
97
+ onRetry: (retryCount, error) => {
98
+ const status = error.response ? `HTTP ${error.response.status}` : error.code || error.message;
99
+ _contentfulBatchLibs.logEmitter.emit('warning', `Asset download failed (${status}), retrying (attempt ${retryCount})...`);
100
+ }
101
+ });
75
102
  return _bluebird.default.map(ctx.data.assets, asset => {
76
103
  const entityName = (0, _contentfulBatchLibs.getEntityName)(asset);
77
104
  if (!asset.fields.file) {
@@ -87,10 +114,12 @@ function downloadAssets(options) {
87
114
  errorCount++;
88
115
  return _bluebird.default.resolve();
89
116
  }
117
+ const assetId = asset.sys.id;
90
118
  let startingPromise = _bluebird.default.resolve({
91
119
  url,
92
120
  directory: options.exportDir,
93
- httpClient
121
+ httpClient,
122
+ assetId
94
123
  });
95
124
  if ((0, _embargoedAssets.isEmbargoedAsset)(url)) {
96
125
  const {
@@ -103,13 +132,15 @@ function downloadAssets(options) {
103
132
  startingPromise = (0, _embargoedAssets.signUrl)(host, accessToken, spaceId, environmentId, url, expiresAtMs, httpClient).then(signedUrl => ({
104
133
  url: signedUrl,
105
134
  directory: options.exportDir,
106
- httpClient
135
+ httpClient,
136
+ assetId
107
137
  }));
108
138
  }
109
139
  return startingPromise.then(downloadAsset).then(() => {
110
140
  task.output = `${_figures.default.tick} downloaded ${entityName} (${url})`;
111
141
  successCount++;
112
142
  }).catch(error => {
143
+ _contentfulBatchLibs.logEmitter.emit('warning', error.message);
113
144
  task.output = `${_figures.default.cross} error downloading ${url}: ${error.message}`;
114
145
  errorCount++;
115
146
  });
@@ -71,8 +71,11 @@ function getFullSourceSpace({
71
71
  method: 'getTags'
72
72
  }).then(extractItems).then(items => {
73
73
  ctx.data.tags = items;
74
- }).catch(() => {
75
- ctx.data.tags = [];
74
+ }).catch(err => {
75
+ _contentfulBatchLibs.logEmitter.emit('error', new Error(`Fetching tags failed: ${err.message}`, {
76
+ cause: err
77
+ }));
78
+ throw err;
76
79
  });
77
80
  }),
78
81
  skip: () => skipTags
@@ -257,7 +260,7 @@ function getEditorInterfaces(contentTypes) {
257
260
  }).catch(() => {
258
261
  // old contentTypes may not have an editor interface but we'll handle in a later stage
259
262
  // but it should not stop getting the data process
260
- _contentfulBatchLibs.logEmitter.emit('warning', `No editor interface found for ${contentType}`);
263
+ _contentfulBatchLibs.logEmitter.emit('warning', `No editor interface found for ${contentType.name || contentType.sys.id}`);
261
264
  return _bluebird.default.resolve(null);
262
265
  });
263
266
  }, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contentful-export",
3
- "version": "8.2.0",
3
+ "version": "8.2.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",
@@ -46,6 +46,7 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "axios": "^1.13.5",
49
+ "axios-retry": "^4.5.0",
49
50
  "bfj": "^9.1.3",
50
51
  "bluebird": "^3.3.3",
51
52
  "cli-table3": "^0.6.0",