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 +21 -0
- package/dist/index.js +5 -2
- package/dist/tasks/download-assets.js +36 -5
- package/dist/tasks/get-space-data.js +6 -3
- package/package.json +2 -1
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
|
|
122
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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.
|
|
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",
|