@sanity/export 0.136.3-gql-rtb.375 → 0.136.3-purple-unicorn-patch.5629
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/LICENSE +1 -1
- package/README.md +8 -5
- package/lib/AssetHandler.js +213 -178
- package/lib/export.js +145 -140
- package/lib/filterDrafts.js +1 -1
- package/lib/filterSystemDocuments.js +1 -1
- package/lib/getDocumentsStream.js +6 -3
- package/lib/logFirstChunk.js +18 -0
- package/lib/rejectOnApiError.js +6 -1
- package/lib/requestStream.js +60 -4
- package/lib/stringifyStream.js +1 -1
- package/lib/tryParseJson.js +25 -0
- package/lib/validateOptions.js +8 -4
- package/package.json +18 -17
- package/src/AssetHandler.js +168 -52
- package/src/export.js +59 -22
- package/src/filterDocumentTypes.js +1 -1
- package/src/filterDrafts.js +8 -7
- package/src/filterSystemDocuments.js +9 -8
- package/src/getDocumentsStream.js +3 -2
- package/src/logFirstChunk.js +15 -0
- package/src/rejectOnApiError.js +13 -7
- package/src/requestStream.js +54 -5
- package/src/stringifyStream.js +2 -3
- package/src/tryParseJson.js +21 -0
- package/src/validateOptions.js +7 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -20,8 +20,8 @@ exportDataset({
|
|
|
20
20
|
// Name of dataset to export
|
|
21
21
|
dataset: 'myDataset',
|
|
22
22
|
|
|
23
|
-
// Path to write
|
|
24
|
-
outputPath: '/home/your-user/myDataset.
|
|
23
|
+
// Path to write tar.gz-archive file to, or `-` for stdout
|
|
24
|
+
outputPath: '/home/your-user/myDataset.tar.gz',
|
|
25
25
|
|
|
26
26
|
// Whether or not to export assets. Note that this operation is currently slightly lossy;
|
|
27
27
|
// metadata stored on the asset document itself (original filename, for instance) might be lost
|
|
@@ -38,14 +38,17 @@ exportDataset({
|
|
|
38
38
|
|
|
39
39
|
// Export only given document types (`_type`)
|
|
40
40
|
// Optional, default: all types
|
|
41
|
-
types: ['products', 'shops']
|
|
41
|
+
types: ['products', 'shops'],
|
|
42
|
+
|
|
43
|
+
// Run 12 concurrent asset downloads
|
|
44
|
+
assetConcurrency: 12
|
|
42
45
|
})
|
|
43
46
|
```
|
|
44
47
|
|
|
45
48
|
## Future improvements
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
- Restore original filenames, keep track of duplicates, increase counter (`filename (<num>).ext`)
|
|
51
|
+
- Skip archiving on raw/no-asset mode?
|
|
49
52
|
|
|
50
53
|
## CLI-tool
|
|
51
54
|
|
package/lib/AssetHandler.js
CHANGED
|
@@ -1,37 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
|
|
4
|
-
|
|
5
|
-
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
|
|
6
|
-
|
|
7
|
-
function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
|
|
8
|
-
|
|
9
|
-
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
10
|
-
|
|
11
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
|
|
12
|
-
|
|
13
|
-
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
14
|
-
|
|
15
|
-
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
16
|
-
|
|
17
|
-
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
18
|
-
|
|
19
|
-
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
20
|
-
|
|
21
3
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
22
4
|
|
|
23
5
|
const path = require('path');
|
|
24
6
|
|
|
25
7
|
const crypto = require('crypto');
|
|
26
8
|
|
|
9
|
+
const {
|
|
10
|
+
parse: parseUrl,
|
|
11
|
+
format: formatUrl
|
|
12
|
+
} = require('url');
|
|
13
|
+
|
|
27
14
|
const fse = require('fs-extra');
|
|
28
15
|
|
|
29
16
|
const miss = require('mississippi');
|
|
30
17
|
|
|
31
18
|
const PQueue = require('p-queue');
|
|
32
19
|
|
|
33
|
-
const
|
|
34
|
-
|
|
20
|
+
const {
|
|
21
|
+
omit,
|
|
22
|
+
noop
|
|
23
|
+
} = require('lodash');
|
|
35
24
|
|
|
36
25
|
const pkg = require('../package.json');
|
|
37
26
|
|
|
@@ -42,51 +31,31 @@ const debug = require('./debug');
|
|
|
42
31
|
const EXCLUDE_PROPS = ['_id', '_type', 'assetId', 'extension', 'mimeType', 'path', 'url'];
|
|
43
32
|
const ACTION_REMOVE = 'remove';
|
|
44
33
|
const ACTION_REWRITE = 'rewrite';
|
|
34
|
+
const ASSET_DOWNLOAD_CONCURRENCY = 8;
|
|
45
35
|
|
|
46
36
|
class AssetHandler {
|
|
47
37
|
constructor(options) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
_this.assetsSeen.set(doc._id, type);
|
|
59
|
-
|
|
60
|
-
_this.queueAssetDownload(doc, filePath, type);
|
|
61
|
-
|
|
62
|
-
callback();
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
callback(null, (yield _this.findAndModify(doc, ACTION_REWRITE)));
|
|
67
|
-
});
|
|
38
|
+
_defineProperty(this, "rewriteAssets", miss.through.obj(async (doc, enc, callback) => {
|
|
39
|
+
if (['sanity.imageAsset', 'sanity.fileAsset'].includes(doc._type)) {
|
|
40
|
+
const type = doc._type === 'sanity.imageAsset' ? 'image' : 'file';
|
|
41
|
+
const filePath = "".concat(type, "s/").concat(generateFilename(doc._id));
|
|
42
|
+
this.assetsSeen.set(doc._id, type);
|
|
43
|
+
this.queueAssetDownload(doc, filePath, type);
|
|
44
|
+
callback();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
68
47
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
};
|
|
72
|
-
}()));
|
|
73
|
-
|
|
74
|
-
_defineProperty(this, "stripAssets", miss.through.obj(
|
|
75
|
-
/*#__PURE__*/
|
|
76
|
-
function () {
|
|
77
|
-
var _ref2 = _asyncToGenerator(function* (doc, enc, callback) {
|
|
78
|
-
if (['sanity.imageAsset', 'sanity.fileAsset'].includes(doc._type)) {
|
|
79
|
-
callback();
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
48
|
+
callback(null, this.findAndModify(doc, ACTION_REWRITE));
|
|
49
|
+
}));
|
|
82
50
|
|
|
83
|
-
|
|
84
|
-
|
|
51
|
+
_defineProperty(this, "stripAssets", miss.through.obj(async (doc, enc, callback) => {
|
|
52
|
+
if (['sanity.imageAsset', 'sanity.fileAsset'].includes(doc._type)) {
|
|
53
|
+
callback();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
85
56
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
};
|
|
89
|
-
}()));
|
|
57
|
+
callback(null, this.findAndModify(doc, ACTION_REMOVE));
|
|
58
|
+
}));
|
|
90
59
|
|
|
91
60
|
_defineProperty(this, "skipAssets", miss.through.obj((doc, enc, callback) => {
|
|
92
61
|
const isAsset = ['sanity.imageAsset', 'sanity.fileAsset'].includes(doc._type);
|
|
@@ -101,97 +70,69 @@ class AssetHandler {
|
|
|
101
70
|
|
|
102
71
|
_defineProperty(this, "noop", miss.through.obj((doc, enc, callback) => callback(null, doc)));
|
|
103
72
|
|
|
104
|
-
_defineProperty(this, "findAndModify",
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const children = yield Promise.all(item.map(child => _this.findAndModify(child, action)));
|
|
110
|
-
return children.filter(Boolean);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (!item || typeof item !== 'object') {
|
|
114
|
-
return item;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const isAsset = isAssetField(item);
|
|
118
|
-
|
|
119
|
-
if (isAsset && action === ACTION_REMOVE) {
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (isAsset && action === ACTION_REWRITE) {
|
|
124
|
-
const asset = item.asset,
|
|
125
|
-
other = _objectWithoutProperties(item, ["asset"]);
|
|
126
|
-
|
|
127
|
-
const assetId = asset._ref;
|
|
73
|
+
_defineProperty(this, "findAndModify", (item, action) => {
|
|
74
|
+
if (Array.isArray(item)) {
|
|
75
|
+
const children = item.map(child => this.findAndModify(child, action));
|
|
76
|
+
return children.filter(Boolean);
|
|
77
|
+
}
|
|
128
78
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return _objectSpread({
|
|
133
|
-
_sanityAsset: `${assetType}@file://./${filePath}`
|
|
134
|
-
}, other);
|
|
135
|
-
} // Legacy asset
|
|
79
|
+
if (!item || typeof item !== 'object') {
|
|
80
|
+
return item;
|
|
81
|
+
}
|
|
136
82
|
|
|
83
|
+
const isAsset = isAssetField(item);
|
|
137
84
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
_sanityAsset: `${type}@file://./${filePath}`
|
|
142
|
-
}, other);
|
|
143
|
-
}
|
|
85
|
+
if (isAsset && action === ACTION_REMOVE) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
144
88
|
|
|
145
|
-
|
|
146
|
-
const
|
|
89
|
+
if (isAsset && action === ACTION_REWRITE) {
|
|
90
|
+
const {
|
|
91
|
+
asset,
|
|
92
|
+
...other
|
|
93
|
+
} = item;
|
|
94
|
+
const assetId = asset._ref;
|
|
95
|
+
const assetType = getAssetType(item);
|
|
96
|
+
const filePath = "".concat(assetType, "s/").concat(generateFilename(assetId));
|
|
97
|
+
return {
|
|
98
|
+
_sanityAsset: "".concat(assetType, "@file://./").concat(filePath),
|
|
99
|
+
...this.findAndModify(other, action)
|
|
100
|
+
};
|
|
101
|
+
}
|
|
147
102
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const value = item[key]; // eslint-disable-next-line no-await-in-loop
|
|
103
|
+
const newItem = {};
|
|
104
|
+
const keys = Object.keys(item);
|
|
151
105
|
|
|
152
|
-
|
|
106
|
+
for (let i = 0; i < keys.length; i++) {
|
|
107
|
+
const key = keys[i];
|
|
108
|
+
const value = item[key];
|
|
109
|
+
newItem[key] = this.findAndModify(value, action);
|
|
153
110
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
111
|
+
if (typeof newItem[key] === 'undefined') {
|
|
112
|
+
delete newItem[key];
|
|
157
113
|
}
|
|
114
|
+
}
|
|
158
115
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return function (_x7, _x8) {
|
|
163
|
-
return _ref3.apply(this, arguments);
|
|
164
|
-
};
|
|
165
|
-
}());
|
|
166
|
-
|
|
167
|
-
_defineProperty(this, "lookupAssetType",
|
|
168
|
-
/*#__PURE__*/
|
|
169
|
-
function () {
|
|
170
|
-
var _ref4 = _asyncToGenerator(function* (assetId) {
|
|
171
|
-
const docType = yield _this.client.fetch('*[_id == $id][0]._type', {
|
|
172
|
-
id: assetId
|
|
173
|
-
});
|
|
174
|
-
return docType === 'sanity.imageAsset' ? 'image' : 'file';
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
return function (_x9) {
|
|
178
|
-
return _ref4.apply(this, arguments);
|
|
179
|
-
};
|
|
180
|
-
}());
|
|
116
|
+
return newItem;
|
|
117
|
+
});
|
|
181
118
|
|
|
119
|
+
const concurrency = options.concurrency || ASSET_DOWNLOAD_CONCURRENCY;
|
|
120
|
+
debug('Using asset download concurrency of %d', concurrency);
|
|
182
121
|
this.client = options.client;
|
|
183
122
|
this.tmpDir = options.tmpDir;
|
|
184
123
|
this.assetDirsCreated = false;
|
|
124
|
+
this.downloading = [];
|
|
185
125
|
this.assetsSeen = new Map();
|
|
186
126
|
this.assetMap = {};
|
|
187
127
|
this.filesWritten = 0;
|
|
188
128
|
this.queueSize = 0;
|
|
189
129
|
this.queue = options.queue || new PQueue({
|
|
190
|
-
concurrency
|
|
130
|
+
concurrency
|
|
191
131
|
});
|
|
132
|
+
this.rejectedError = null;
|
|
192
133
|
|
|
193
|
-
this.reject =
|
|
194
|
-
|
|
134
|
+
this.reject = err => {
|
|
135
|
+
this.rejectedError = err;
|
|
195
136
|
};
|
|
196
137
|
}
|
|
197
138
|
|
|
@@ -203,6 +144,11 @@ class AssetHandler {
|
|
|
203
144
|
|
|
204
145
|
finish() {
|
|
205
146
|
return new Promise((resolve, reject) => {
|
|
147
|
+
if (this.rejectedError) {
|
|
148
|
+
reject(this.rejectedError);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
206
152
|
this.reject = reject;
|
|
207
153
|
this.queue.onIdle().then(() => resolve(this.assetMap));
|
|
208
154
|
});
|
|
@@ -218,58 +164,126 @@ class AssetHandler {
|
|
|
218
164
|
|
|
219
165
|
debug('Adding download task for %s (destination: %s)', assetDoc._id, dstPath);
|
|
220
166
|
this.queueSize++;
|
|
167
|
+
this.downloading.push(assetDoc.url);
|
|
221
168
|
this.queue.add(() => this.downloadAsset(assetDoc, dstPath));
|
|
222
169
|
}
|
|
223
170
|
|
|
224
|
-
|
|
225
|
-
|
|
171
|
+
maybeCreateAssetDirs() {
|
|
172
|
+
if (this.assetDirsCreated) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
/* eslint-disable no-sync */
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
fse.ensureDirSync(path.join(this.tmpDir, 'files'));
|
|
179
|
+
fse.ensureDirSync(path.join(this.tmpDir, 'images'));
|
|
180
|
+
/* eslint-enable no-sync */
|
|
181
|
+
|
|
182
|
+
this.assetDirsCreated = true;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
getAssetRequestOptions(assetDoc) {
|
|
186
|
+
const token = this.client.config().token;
|
|
187
|
+
const headers = {
|
|
188
|
+
'User-Agent': "".concat(pkg.name, "@").concat(pkg.version)
|
|
189
|
+
};
|
|
190
|
+
const isImage = assetDoc._type === 'sanity.imageAsset';
|
|
191
|
+
const url = parseUrl(assetDoc.url, true);
|
|
226
192
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
'
|
|
193
|
+
if (isImage && ['cdn.sanity.io', 'cdn.sanity.work'].includes(url.hostname)) {
|
|
194
|
+
headers.Authorization = "Bearer ".concat(token);
|
|
195
|
+
url.query = { ...(url.query || {}),
|
|
196
|
+
dlRaw: 'true'
|
|
231
197
|
};
|
|
232
|
-
|
|
233
|
-
url,
|
|
234
|
-
headers
|
|
235
|
-
});
|
|
198
|
+
}
|
|
236
199
|
|
|
237
|
-
|
|
238
|
-
|
|
200
|
+
return {
|
|
201
|
+
url: formatUrl(url),
|
|
202
|
+
headers
|
|
203
|
+
};
|
|
204
|
+
}
|
|
239
205
|
|
|
240
|
-
|
|
206
|
+
async downloadAsset(assetDoc, dstPath) {
|
|
207
|
+
let attemptNum = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
208
|
+
const {
|
|
209
|
+
url
|
|
210
|
+
} = assetDoc;
|
|
211
|
+
const options = this.getAssetRequestOptions(assetDoc);
|
|
212
|
+
let stream;
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
stream = await requestStream(options);
|
|
216
|
+
} catch (err) {
|
|
217
|
+
this.reject(err);
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
241
220
|
|
|
242
|
-
|
|
221
|
+
if (stream.statusCode !== 200) {
|
|
222
|
+
this.queue.clear();
|
|
223
|
+
const err = await tryGetErrorFromStream(stream);
|
|
224
|
+
let errMsg = "Referenced asset URL \"".concat(url, "\" returned HTTP ").concat(stream.statusCode);
|
|
225
|
+
|
|
226
|
+
if (err) {
|
|
227
|
+
errMsg = "".concat(errMsg, ":\n\n").concat(err);
|
|
243
228
|
}
|
|
244
229
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
fse.ensureDirSync(path.join(_this2.tmpDir, 'images'));
|
|
249
|
-
/* eslint-enable no-sync */
|
|
230
|
+
this.reject(new Error(errMsg));
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
250
233
|
|
|
251
|
-
|
|
252
|
-
|
|
234
|
+
this.maybeCreateAssetDirs();
|
|
235
|
+
debug('Asset stream ready, writing to filesystem at %s', dstPath);
|
|
236
|
+
const tmpPath = path.join(this.tmpDir, dstPath);
|
|
237
|
+
const {
|
|
238
|
+
sha1,
|
|
239
|
+
md5,
|
|
240
|
+
size
|
|
241
|
+
} = await writeHashedStream(tmpPath, stream); // Verify it against our downloaded stream to make sure we have the same copy
|
|
242
|
+
|
|
243
|
+
const contentLength = stream.headers['content-length'];
|
|
244
|
+
const remoteSha1 = stream.headers['x-sanity-sha1'];
|
|
245
|
+
const remoteMd5 = stream.headers['x-sanity-md5'];
|
|
246
|
+
const hasHash = Boolean(remoteSha1 || remoteMd5);
|
|
247
|
+
const method = md5 ? 'md5' : 'sha1';
|
|
248
|
+
let differs = false;
|
|
249
|
+
|
|
250
|
+
if (remoteMd5 && md5) {
|
|
251
|
+
differs = remoteMd5 !== md5;
|
|
252
|
+
} else if (remoteSha1 && sha1) {
|
|
253
|
+
differs = remoteSha1 !== sha1;
|
|
254
|
+
}
|
|
253
255
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const
|
|
256
|
+
if (differs && attemptNum < 3) {
|
|
257
|
+
debug('%s does not match downloaded asset, retrying (#%d) [%s]', method, attemptNum + 1, url);
|
|
258
|
+
return this.downloadAsset(assetDoc, dstPath, attemptNum + 1);
|
|
259
|
+
} else if (differs) {
|
|
260
|
+
const details = [hasHash && (method === 'md5' ? "md5 should be ".concat(remoteMd5, ", got ").concat(md5) : "sha1 should be ".concat(remoteSha1, ", got ").concat(sha1)), contentLength && parseInt(contentLength, 10) !== size && "Asset should be ".concat(contentLength, " bytes, got ").concat(size), "Did not succeed after ".concat(attemptNum, " attempts.")];
|
|
261
|
+
const detailsString = "Details:\n - ".concat(details.filter(Boolean).join('\n - '));
|
|
262
|
+
await fse.unlink(tmpPath);
|
|
263
|
+
this.queue.clear();
|
|
264
|
+
const error = new Error("Failed to download asset at ".concat(assetDoc.url, ", giving up. ").concat(detailsString));
|
|
265
|
+
this.reject(error);
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
259
268
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
269
|
+
const isImage = assetDoc._type === 'sanity.imageAsset';
|
|
270
|
+
const type = isImage ? 'image' : 'file';
|
|
271
|
+
const id = "".concat(type, "-").concat(sha1);
|
|
272
|
+
const metaProps = omit(assetDoc, EXCLUDE_PROPS);
|
|
263
273
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
274
|
+
if (Object.keys(metaProps).length > 0) {
|
|
275
|
+
this.assetMap[id] = metaProps;
|
|
276
|
+
}
|
|
267
277
|
|
|
278
|
+
this.downloading.splice(this.downloading.findIndex(datUrl => datUrl === url), 1);
|
|
279
|
+
this.filesWritten++;
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
268
282
|
|
|
269
283
|
}
|
|
270
284
|
|
|
271
285
|
function isAssetField(item) {
|
|
272
|
-
return item.asset && item.asset._ref;
|
|
286
|
+
return item.asset && item.asset._ref && isSanityAsset(item.asset._ref);
|
|
273
287
|
}
|
|
274
288
|
|
|
275
289
|
function getAssetType(item) {
|
|
@@ -277,36 +291,57 @@ function getAssetType(item) {
|
|
|
277
291
|
return null;
|
|
278
292
|
}
|
|
279
293
|
|
|
280
|
-
const
|
|
281
|
-
_ref6 = _slicedToArray(_ref5, 2),
|
|
282
|
-
type = _ref6[1];
|
|
283
|
-
|
|
294
|
+
const [, type] = item.asset._ref.match(/^(image|file)-/) || [];
|
|
284
295
|
return type || null;
|
|
285
296
|
}
|
|
286
297
|
|
|
287
|
-
function
|
|
288
|
-
return /^(
|
|
298
|
+
function isSanityAsset(assetId) {
|
|
299
|
+
return /^image-[a-f0-9]{40}-\d+x\d+-[a-z]+$/.test(assetId) || /^file-[a-f0-9]{40}-[a-z0-9]+$/.test(assetId);
|
|
289
300
|
}
|
|
290
301
|
|
|
291
302
|
function generateFilename(assetId) {
|
|
292
|
-
const
|
|
293
|
-
_ref8 = _slicedToArray(_ref7, 4),
|
|
294
|
-
asset = _ref8[2],
|
|
295
|
-
ext = _ref8[3];
|
|
296
|
-
|
|
303
|
+
const [,, asset, ext] = assetId.match(/^(image|file)-(.*?)(-[a-z]+)?$/) || [];
|
|
297
304
|
const extension = (ext || 'bin').replace(/^-/, '');
|
|
298
|
-
return asset ?
|
|
305
|
+
return asset ? "".concat(asset, ".").concat(extension) : "".concat(assetId, ".bin");
|
|
299
306
|
}
|
|
300
307
|
|
|
301
308
|
function writeHashedStream(filePath, stream) {
|
|
302
|
-
|
|
309
|
+
let size = 0;
|
|
310
|
+
const md5 = crypto.createHash('md5');
|
|
311
|
+
const sha1 = crypto.createHash('sha1');
|
|
303
312
|
const hasher = miss.through((chunk, enc, cb) => {
|
|
304
|
-
|
|
313
|
+
size += chunk.length;
|
|
314
|
+
md5.update(chunk);
|
|
315
|
+
sha1.update(chunk);
|
|
305
316
|
cb(null, chunk);
|
|
306
317
|
});
|
|
307
318
|
return new Promise((resolve, reject) => miss.pipe(stream, hasher, fse.createWriteStream(filePath), err => {
|
|
308
|
-
|
|
319
|
+
if (err) {
|
|
320
|
+
reject(err);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
resolve({
|
|
325
|
+
size,
|
|
326
|
+
sha1: sha1.digest('hex'),
|
|
327
|
+
md5: md5.digest('hex')
|
|
328
|
+
});
|
|
309
329
|
}));
|
|
310
330
|
}
|
|
311
331
|
|
|
332
|
+
function tryGetErrorFromStream(stream) {
|
|
333
|
+
return new Promise((resolve, reject) => {
|
|
334
|
+
miss.pipe(stream, miss.concat(parse), err => err ? reject(err) : noop);
|
|
335
|
+
|
|
336
|
+
function parse(body) {
|
|
337
|
+
try {
|
|
338
|
+
const parsed = JSON.parse(body.toString('utf8'));
|
|
339
|
+
resolve(parsed.message || parsed.error || null);
|
|
340
|
+
} catch (err) {
|
|
341
|
+
resolve(body.toString('utf8').slice(0, 16000));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
312
347
|
module.exports = AssetHandler;
|