scratch-storage 6.1.11 → 6.2.1
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/dist/node/scratch-storage.js +46 -39
- package/dist/node/scratch-storage.js.map +1 -1
- package/dist/types/WebHelper.d.ts +11 -5
- package/dist/web/scratch-storage.js +46 -39
- package/dist/web/scratch-storage.js.map +1 -1
- package/dist/web/scratch-storage.min.js +1 -1
- package/package.json +10 -10
- package/src/WebHelper.ts +89 -65
- package/test/integration/download-known-assets.test.js +47 -0
|
@@ -4,12 +4,18 @@ import { ScratchGetRequest, ScratchSendRequest, Tool } from './Tool';
|
|
|
4
4
|
import { AssetType } from './AssetType';
|
|
5
5
|
import { DataFormat } from './DataFormat';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* The result of a UrlFunction, which can be a string URL or a full request configuration
|
|
8
|
+
* object, or a promise for either of those.
|
|
9
|
+
*
|
|
10
|
+
* If set to null or undefined, the WebHelper will skip that store and move on to the
|
|
11
|
+
* next one. This allows stores to be registered that only provide a subset of their
|
|
12
|
+
* declared asset types at a given time.
|
|
11
13
|
*/
|
|
12
|
-
|
|
14
|
+
type RequestFnResult = null | undefined | string | ScratchGetRequest | ScratchSendRequest;
|
|
15
|
+
/**
|
|
16
|
+
* A function which computes a URL from asset information.
|
|
17
|
+
*/
|
|
18
|
+
export type UrlFunction = (asset: Asset) => RequestFnResult | Promise<RequestFnResult>;
|
|
13
19
|
interface StoreRecord {
|
|
14
20
|
types: string[];
|
|
15
21
|
get: UrlFunction;
|
|
@@ -4886,7 +4886,12 @@ function WebHelper_toPrimitive(t, r) { if ("object" != typeof t || !t) return t;
|
|
|
4886
4886
|
|
|
4887
4887
|
|
|
4888
4888
|
|
|
4889
|
-
|
|
4889
|
+
/**
|
|
4890
|
+
* Ensure that the provided request configuration is in object form, converting from
|
|
4891
|
+
* string if necessary.
|
|
4892
|
+
*/
|
|
4893
|
+
const ensureRequestConfig = async reqConfig => {
|
|
4894
|
+
reqConfig = await reqConfig;
|
|
4890
4895
|
if (typeof reqConfig === 'string') {
|
|
4891
4896
|
return {
|
|
4892
4897
|
url: reqConfig
|
|
@@ -4955,8 +4960,8 @@ class WebHelper extends Helper {
|
|
|
4955
4960
|
* @param {DataFormat} dataFormat - The file format / file extension of the asset to fetch: PNG, JPG, etc.
|
|
4956
4961
|
* @returns {Promise.<Asset>} A promise for the contents of the asset.
|
|
4957
4962
|
*/
|
|
4958
|
-
load(assetType, assetId, dataFormat) {
|
|
4959
|
-
/** @type {
|
|
4963
|
+
async load(assetType, assetId, dataFormat) {
|
|
4964
|
+
/** @type {unknown[]} List of errors encountered while attempting to load the asset. */
|
|
4960
4965
|
const errors = [];
|
|
4961
4966
|
const stores = this.stores.slice().filter(store => store.types.indexOf(assetType.name) >= 0);
|
|
4962
4967
|
// New empty asset but it doesn't have data yet
|
|
@@ -4965,33 +4970,29 @@ class WebHelper extends Helper {
|
|
|
4965
4970
|
if (assetType.name === 'Project') {
|
|
4966
4971
|
tool = this.projectTool;
|
|
4967
4972
|
}
|
|
4968
|
-
|
|
4969
|
-
const tryNextSource = err => {
|
|
4970
|
-
if (err) {
|
|
4971
|
-
errors.push(err);
|
|
4972
|
-
}
|
|
4973
|
-
const store = stores[storeIndex++];
|
|
4974
|
-
/** @type {UrlFunction} */
|
|
4973
|
+
for (const store of stores) {
|
|
4975
4974
|
const reqConfigFunction = store && store.get;
|
|
4976
4975
|
if (reqConfigFunction) {
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4976
|
+
try {
|
|
4977
|
+
const reqConfig = await ensureRequestConfig(reqConfigFunction(asset));
|
|
4978
|
+
if (!reqConfig) {
|
|
4979
|
+
continue;
|
|
4980
|
+
}
|
|
4981
|
+
const body = await tool.get(reqConfig);
|
|
4982
4982
|
if (body) {
|
|
4983
4983
|
asset.setData(body, dataFormat);
|
|
4984
4984
|
return asset;
|
|
4985
4985
|
}
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
return Promise.reject(errors);
|
|
4986
|
+
} catch (err) {
|
|
4987
|
+
errors.push(err);
|
|
4988
|
+
}
|
|
4990
4989
|
}
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4990
|
+
}
|
|
4991
|
+
if (errors.length > 0) {
|
|
4992
|
+
return Promise.reject(errors);
|
|
4993
|
+
}
|
|
4994
|
+
// no stores matching asset
|
|
4995
|
+
return Promise.resolve(null);
|
|
4995
4996
|
}
|
|
4996
4997
|
/**
|
|
4997
4998
|
* Create or update an asset with provided data. The create function is called if no asset id is provided
|
|
@@ -5001,33 +5002,38 @@ class WebHelper extends Helper {
|
|
|
5001
5002
|
* @param {?string} assetId - The ID of the asset to fetch: a project ID, MD5, etc.
|
|
5002
5003
|
* @returns {Promise.<object>} A promise for the response from the create or update request
|
|
5003
5004
|
*/
|
|
5004
|
-
store(assetType, dataFormat, data, assetId) {
|
|
5005
|
+
async store(assetType, dataFormat, data, assetId) {
|
|
5005
5006
|
const asset = new Asset(assetType, assetId, dataFormat);
|
|
5006
5007
|
// If we have an asset id, we should update, otherwise create to get an id
|
|
5007
5008
|
const create = assetId === '' || assetId === null || typeof assetId === 'undefined';
|
|
5008
|
-
|
|
5009
|
-
const store = this.stores.filter(s =>
|
|
5009
|
+
const candidateStores = this.stores.filter(s =>
|
|
5010
5010
|
// Only use stores for the incoming asset type
|
|
5011
5011
|
s.types.indexOf(assetType.name) !== -1 && (
|
|
5012
5012
|
// Only use stores that have a create function if this is a create request
|
|
5013
5013
|
// or an update function if this is an update request
|
|
5014
|
-
create && s.create || s.update))
|
|
5014
|
+
create && s.create || s.update));
|
|
5015
5015
|
const method = create ? 'post' : 'put';
|
|
5016
|
-
if (
|
|
5016
|
+
if (candidateStores.length === 0) {
|
|
5017
|
+
return Promise.reject(new Error('No appropriate stores'));
|
|
5018
|
+
}
|
|
5017
5019
|
let tool = this.assetTool;
|
|
5018
5020
|
if (assetType.name === 'Project') {
|
|
5019
5021
|
tool = this.projectTool;
|
|
5020
5022
|
}
|
|
5021
|
-
const
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5023
|
+
for (const store of candidateStores) {
|
|
5024
|
+
const reqConfig = await ensureRequestConfig(
|
|
5025
|
+
// The non-nullability of this gets checked above while looking up the store.
|
|
5026
|
+
// Making TS understand that is going to require code refactoring which we currently don't
|
|
5027
|
+
// feel safe to do.
|
|
5028
|
+
create ? store.create(asset) : store.update(asset));
|
|
5029
|
+
if (!reqConfig) {
|
|
5030
|
+
continue;
|
|
5031
|
+
}
|
|
5032
|
+
const reqBodyConfig = Object.assign({
|
|
5033
|
+
body: data,
|
|
5034
|
+
method
|
|
5035
|
+
}, reqConfig);
|
|
5036
|
+
let body = await tool.send(reqBodyConfig);
|
|
5031
5037
|
// xhr makes it difficult to both send FormData and
|
|
5032
5038
|
// automatically parse a JSON response. So try to parse
|
|
5033
5039
|
// everything as JSON.
|
|
@@ -5044,7 +5050,8 @@ class WebHelper extends Helper {
|
|
|
5044
5050
|
return Object.assign({
|
|
5045
5051
|
id: body['content-name'] || assetId
|
|
5046
5052
|
}, body);
|
|
5047
|
-
}
|
|
5053
|
+
}
|
|
5054
|
+
return Promise.reject(new Error('No store could handle the request'));
|
|
5048
5055
|
}
|
|
5049
5056
|
}
|
|
5050
5057
|
;// ./src/ScratchStorage.ts
|