contentful-export 8.2.1 → 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.
@@ -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.1",
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",