@openeo/js-client 2.0.0 → 2.3.0

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/src/connection.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const Environment = require('./env');
2
2
  const Utils = require('@openeo/js-commons/src/utils');
3
+ const ProcessRegistry = require('@openeo/js-commons/src/processRegistry');
3
4
  const axios = require('axios').default;
4
5
  const StacMigrate = require('@radiantearth/stac-migrate');
5
6
 
@@ -25,27 +26,70 @@ class Connection {
25
26
  /**
26
27
  * Creates a new Connection.
27
28
  *
28
- * @param {string} baseUrl - URL to the back-end
29
+ * @param {string} baseUrl - The versioned URL or the back-end instance.
30
+ * @param {Options} [options={}] - Additional options for the connection.
31
+ * @param {?string} [url=null] - User-provided URL of the backend connected to.
29
32
  */
30
- constructor(baseUrl) {
33
+ constructor(baseUrl, options = {}, url = null) {
31
34
  /**
35
+ * User-provided URL of the backend connected to.
36
+ *
37
+ * `null` if not given and the connection was directly made to a versioned instance of the back-end.
38
+ *
39
+ * @protected
40
+ * @type {string | null}
41
+ */
42
+ this.url = url;
43
+ /**
44
+ * The versioned URL or the back-end instance.
45
+ *
46
+ * @protected
32
47
  * @type {string}
33
48
  */
34
49
  this.baseUrl = Utils.normalizeUrl(baseUrl);
35
50
  /**
51
+ * Auth Provider cache
52
+ *
53
+ * @protected
36
54
  * @type {?Array.<AuthProvider>}
37
55
  */
38
56
  this.authProviderList = null;
39
57
  /**
58
+ * Current auth provider
59
+ *
60
+ * @protected
40
61
  * @type {?AuthProvider}
41
62
  */
42
63
  this.authProvider = null;
43
64
  /**
65
+ * Capability cache
66
+ *
67
+ * @protected
44
68
  * @type {?Capabilities}
45
69
  */
46
70
  this.capabilitiesObject = null;
47
- this.processes = null;
71
+ /**
72
+ * Process cache
73
+ *
74
+ * @protected
75
+ * @type {ProcessRegistry}
76
+ */
77
+ this.processes = new ProcessRegistry([], Boolean(options.addNamespaceToProcess));
78
+ this.processes.listeners.push((...args) => this.emit('processesChanged', ...args));
79
+ /**
80
+ * Listeners for events.
81
+ *
82
+ * @protected
83
+ * @type {object.<string|Function>}
84
+ */
48
85
  this.listeners = {};
86
+ /**
87
+ * Additional options for the connection.
88
+ *
89
+ * @protected
90
+ * @type {Options}
91
+ */
92
+ this.options = options;
49
93
  }
50
94
 
51
95
  /**
@@ -61,14 +105,23 @@ class Connection {
61
105
  }
62
106
 
63
107
  /**
64
- * Returns the URL of the back-end currently connected to.
108
+ * Returns the URL of the versioned back-end instance currently connected to.
65
109
  *
66
- * @returns {string} The URL or the back-end.
110
+ * @returns {string} The versioned URL or the back-end instance.
67
111
  */
68
112
  getBaseUrl() {
69
113
  return this.baseUrl;
70
114
  }
71
115
 
116
+ /**
117
+ * Returns the user-provided URL of the back-end currently connected to.
118
+ *
119
+ * @returns {string} The URL or the back-end.
120
+ */
121
+ getUrl() {
122
+ return this.url || this.baseUrl;
123
+ }
124
+
72
125
  /**
73
126
  * Returns the capabilities of the back-end.
74
127
  *
@@ -156,16 +209,16 @@ class Connection {
156
209
  *
157
210
  * @async
158
211
  * @param {string} collectionId - Collection ID to request items for.
159
- * @param {?Array.<number>} spatialExtent - Limits the items to the given bounding box in WGS84:
212
+ * @param {?Array.<number>} [spatialExtent=null] - Limits the items to the given bounding box in WGS84:
160
213
  * 1. Lower left corner, coordinate axis 1
161
214
  * 2. Lower left corner, coordinate axis 2
162
215
  * 3. Upper right corner, coordinate axis 1
163
216
  * 4. Upper right corner, coordinate axis 2
164
- * @param {?Array.<*>} temporalExtent - Limits the items to the specified temporal interval.
217
+ * @param {?Array.<*>} [temporalExtent=null] - Limits the items to the specified temporal interval.
165
218
  * The interval has to be specified as an array with exactly two elements (start, end) and
166
219
  * each must be either an RFC 3339 compatible string or a Date object.
167
220
  * Also supports open intervals by setting one of the boundaries to `null`, but never both.
168
- * @param {?number} limit - The amount of items per request/page as integer. If `null` (default), the back-end decides.
221
+ * @param {?number} [limit=null] - The amount of items per request/page as integer. If `null` (default), the back-end decides.
169
222
  * @yields {Promise<ItemCollection>} A response compatible to the API specification.
170
223
  * @throws {Error}
171
224
  */
@@ -208,20 +261,35 @@ class Connection {
208
261
  }
209
262
 
210
263
  /**
211
- * List all processes available on the back-end.
264
+ * List processes available on the back-end.
212
265
  *
213
- * Data is cached in memory.
266
+ * Requests pre-defined processes by default.
267
+ * Set the namespace parameter to request processes from a specific namespace.
268
+ *
269
+ * Note: The list of namespaces can be retrieved by calling `listProcesses` without a namespace given.
270
+ * The namespaces are then listed in the property `namespaces`.
214
271
  *
215
272
  * @async
273
+ * @param {?string} [namespace=null] - Namespace of the processes (default to `null`, i.e. pre-defined processes). EXPERIMENTAL!
216
274
  * @returns {Promise<Processes>} - A response compatible to the API specification.
217
275
  * @throws {Error}
218
276
  */
219
- async listProcesses() {
220
- if (this.processes === null) {
221
- let response = await this._get('/processes');
222
- this.processes = response.data;
277
+ async listProcesses(namespace = null) {
278
+ if (!namespace) {
279
+ namespace = 'backend';
280
+ }
281
+ let path = (namespace === 'backend') ? '/processes' : `/processes/${namespace}`;
282
+ let response = await this._get(path);
283
+
284
+ if (!Utils.isObject(response.data) || !Array.isArray(response.data.processes)) {
285
+ throw new Error('Invalid response received for processes');
223
286
  }
224
- return this.processes;
287
+
288
+ // Store processes in cache
289
+ this.processes.remove(null, namespace);
290
+ this.processes.addAll(response.data.processes, namespace);
291
+
292
+ return Object.assign(response.data, {processes: this.processes.namespace(namespace)});
225
293
  }
226
294
 
227
295
  /**
@@ -229,20 +297,30 @@ class Connection {
229
297
  *
230
298
  * @async
231
299
  * @param {string} processId - Collection ID to request further metadata for.
300
+ * @param {?string} [namespace=null] - Namespace of the process (default to `null`, i.e. pre-defined processes). EXPERIMENTAL!
232
301
  * @returns {Promise<?Process>} - A single process as object, or `null` if none is found.
233
302
  * @throws {Error}
234
303
  * @see Connection#listProcesses
235
304
  */
236
- async describeProcess(processId) {
237
- let response = await this.listProcesses();
238
- if (Array.isArray(response.processes)) {
239
- return response.processes.find(process => Utils.isObject(process) && process.id === processId) || null;
305
+ async describeProcess(processId, namespace = null) {
306
+ if (!namespace) {
307
+ namespace = 'backend';
240
308
  }
241
- return null;
309
+ if (namespace === 'backend') {
310
+ await this.listProcesses();
311
+ }
312
+ else {
313
+ let response = await this._get(`/processes/${namespace}/${processId}`);
314
+ if (!Utils.isObject(response.data) || typeof response.data.id !== 'string') {
315
+ throw new Error('Invalid response received for process');
316
+ }
317
+ this.processes.add(response.data, namespace);
318
+ }
319
+ return this.processes.get(processId, namespace);
242
320
  }
243
321
 
244
322
  /**
245
- * Returns an object to simply build user-defined processes.
323
+ * Returns an object to simply build user-defined processes based upon pre-defined processes.
246
324
  *
247
325
  * @async
248
326
  * @param {string} id - A name for the process.
@@ -251,8 +329,8 @@ class Connection {
251
329
  * @see Connection#listProcesses
252
330
  */
253
331
  async buildProcess(id) {
254
- let response = await this.listProcesses();
255
- return new Builder(response.processes, null, id);
332
+ await this.listProcesses();
333
+ return new Builder(this.processes, null, id);
256
334
  }
257
335
 
258
336
  /**
@@ -305,7 +383,7 @@ class Connection {
305
383
  *
306
384
  * @callback oidcProviderFactoryFunction
307
385
  * @param {object.<string, *>} providerInfo - The provider information as provided by the API, having the properties `id`, `issuer`, `title` etc.
308
- * @returns {?AuthProvider}
386
+ * @returns {AuthProvider | null}
309
387
  */
310
388
 
311
389
  /**
@@ -315,7 +393,7 @@ class Connection {
315
393
  * on the AuthProvider interface (or OIDCProvider class), e.g. to use a
316
394
  * OIDC library other than oidc-client-js.
317
395
  *
318
- * @param {?oidcProviderFactoryFunction} providerFactoryFunc
396
+ * @param {?oidcProviderFactoryFunction} [providerFactoryFunc=null]
319
397
  * @see AuthProvider
320
398
  */
321
399
  setOidcProviderFactory(providerFactoryFunc) {
@@ -328,7 +406,7 @@ class Connection {
328
406
  * Returns `null` if OIDC is not supported by the client or an instance
329
407
  * can't be created for whatever reason.
330
408
  *
331
- * @returns {?oidcProviderFactoryFunction}
409
+ * @returns {oidcProviderFactoryFunction | null}
332
410
  * @see AuthProvider
333
411
  */
334
412
  getOidcProviderFactory() {
@@ -390,6 +468,7 @@ class Connection {
390
468
  * Currently supported:
391
469
  * - authProviderChanged(provider): Raised when the auth provider has changed.
392
470
  * - tokenChanged(token): Raised when the access token has changed.
471
+ * - processesChanged(type, data, namespace): Raised when the process registry has changed (i.e. a process was added, updated or deleted).
393
472
  *
394
473
  * @param {string} event
395
474
  * @param {Function} callback
@@ -410,7 +489,7 @@ class Connection {
410
489
  /**
411
490
  * Returns the AuthProvider.
412
491
  *
413
- * @returns {?AuthProvider}
492
+ * @returns {AuthProvider | null}
414
493
  */
415
494
  getAuthProvider() {
416
495
  return this.authProvider;
@@ -487,12 +566,12 @@ class Connection {
487
566
  );
488
567
  }
489
568
 
490
-
491
569
  /**
492
570
  * A callback that is executed on upload progress updates.
493
571
  *
494
572
  * @callback uploadStatusCallback
495
573
  * @param {number} percentCompleted - The percent (0-100) completed.
574
+ * @param {UserFile} file - The file object corresponding to the callback.
496
575
  */
497
576
 
498
577
  /**
@@ -507,15 +586,16 @@ class Connection {
507
586
  * @param {*} source - The source, see method description for details.
508
587
  * @param {?string} [targetPath=null] - The target path on the server, relative to the user workspace. Defaults to the file name of the source file.
509
588
  * @param {?uploadStatusCallback} [statusCallback=null] - Optionally, a callback that is executed on upload progress updates.
589
+ * @param {?AbortController} [abortController=null] - An AbortController object that can be used to cancel the upload process.
510
590
  * @returns {Promise<UserFile>}
511
591
  * @throws {Error}
512
592
  */
513
- async uploadFile(source, targetPath = null, statusCallback = null) {
593
+ async uploadFile(source, targetPath = null, statusCallback = null, abortController = null) {
514
594
  if (targetPath === null) {
515
595
  targetPath = Environment.fileNameForUpload(source);
516
596
  }
517
597
  let file = await this.getFile(targetPath);
518
- return await file.uploadFile(source, statusCallback);
598
+ return await file.uploadFile(source, statusCallback, abortController);
519
599
  }
520
600
 
521
601
  /**
@@ -582,6 +662,15 @@ class Connection {
582
662
  */
583
663
  async listUserProcesses() {
584
664
  let response = await this._get('/process_graphs');
665
+
666
+ if (!Utils.isObject(response.data) || !Array.isArray(response.data.processes)) {
667
+ throw new Error('Invalid response received for processes');
668
+ }
669
+
670
+ // Store processes in cache
671
+ this.processes.remove(null, 'user');
672
+ this.processes.addAll(response.data.processes, 'user');
673
+
585
674
  return response.data.processes.map(
586
675
  pg => new UserProcess(this, pg.id).setAll(pg)
587
676
  );
@@ -623,9 +712,10 @@ class Connection {
623
712
  * @param {Process} process - A user-defined process.
624
713
  * @param {?string} [plan=null] - The billing plan to use for this computation.
625
714
  * @param {?number} [budget=null] - The maximum budget allowed to spend for this computation.
715
+ * @param {?AbortController} [abortController=null] - An AbortController object that can be used to cancel the processing request.
626
716
  * @returns {Promise<SyncResult>} - An object with the data and some metadata.
627
717
  */
628
- async computeResult(process, plan = null, budget = null) {
718
+ async computeResult(process, plan = null, budget = null, abortController = null) {
629
719
  let requestBody = this._normalizeUserProcess(
630
720
  process,
631
721
  {
@@ -633,7 +723,7 @@ class Connection {
633
723
  budget: budget
634
724
  }
635
725
  );
636
- let response = await this._post('/result', requestBody, Environment.getResponseType());
726
+ let response = await this._post('/result', requestBody, Environment.getResponseType(), abortController);
637
727
  let syncResult = {
638
728
  data: response.data,
639
729
  costs: null,
@@ -684,10 +774,11 @@ class Connection {
684
774
  * @param {string} targetPath - The target, see method description for details.
685
775
  * @param {?string} [plan=null] - The billing plan to use for this computation.
686
776
  * @param {?number} [budget=null] - The maximum budget allowed to spend for this computation.
777
+ * @param {?AbortController} [abortController=null] - An AbortController object that can be used to cancel the processing request.
687
778
  * @throws {Error}
688
779
  */
689
- async downloadResult(process, targetPath, plan = null, budget = null) {
690
- let response = await this.computeResult(process, plan, budget);
780
+ async downloadResult(process, targetPath, plan = null, budget = null, abortController = null) {
781
+ let response = await this.computeResult(process, plan, budget, abortController);
691
782
  // @ts-ignore
692
783
  await Environment.saveToFile(response.data, targetPath);
693
784
  }
@@ -824,7 +915,7 @@ class Connection {
824
915
  *
825
916
  * @param {Array.<Link>} links - An array of links.
826
917
  * @param {string} rel - Relation type to find, defaults to `next`.
827
- * @returns {?string}
918
+ * @returns {string | null}
828
919
  * @throws {Error}
829
920
  */
830
921
  _getLinkHref(links, rel = 'next') {
@@ -855,7 +946,7 @@ class Connection {
855
946
  url: path,
856
947
  // Timeout for capabilities requests as they are used for a quick first discovery to check whether the server is a openEO back-end.
857
948
  // Without timeout connecting with a wrong server url may take forever.
858
- timeout: path === '/' ? 3000 : 0,
949
+ timeout: path === '/' ? 5000 : 0,
859
950
  params: query
860
951
  });
861
952
  }
@@ -867,17 +958,19 @@ class Connection {
867
958
  * @param {string} path
868
959
  * @param {*} body
869
960
  * @param {string} responseType - Response type according to axios, defaults to `json`.
961
+ * @param {?AbortController} [abortController=null] - An AbortController object that can be used to cancel the request.
870
962
  * @returns {Promise<AxiosResponse>}
871
963
  * @throws {Error}
872
964
  * @see https://github.com/axios/axios#request-config
873
965
  */
874
- async _post(path, body, responseType) {
875
- return await this._send({
966
+ async _post(path, body, responseType, abortController = null) {
967
+ let options = {
876
968
  method: 'post',
877
969
  responseType: responseType,
878
970
  url: path,
879
971
  data: body
880
- });
972
+ };
973
+ return await this._send(options, abortController);
881
974
  }
882
975
 
883
976
  /**
@@ -963,11 +1056,12 @@ class Connection {
963
1056
  *
964
1057
  * @async
965
1058
  * @param {object.<string, *>} options
1059
+ * @param {?AbortController} [abortController=null] - An AbortController object that can be used to cancel the request.
966
1060
  * @returns {Promise<AxiosResponse>}
967
1061
  * @throws {Error}
968
1062
  * @see https://github.com/axios/axios
969
1063
  */
970
- async _send(options) {
1064
+ async _send(options, abortController = null) {
971
1065
  options.baseURL = this.baseUrl;
972
1066
  if (this.isAuthenticated() && (typeof options.authorization === 'undefined' || options.authorization === true)) {
973
1067
  if (!options.headers) {
@@ -978,6 +1072,9 @@ class Connection {
978
1072
  if (!options.responseType) {
979
1073
  options.responseType = 'json';
980
1074
  }
1075
+ if (abortController) {
1076
+ options.signal = abortController.signal;
1077
+ }
981
1078
 
982
1079
  try {
983
1080
  return await axios(options);
package/src/filetypes.js CHANGED
@@ -64,7 +64,7 @@ class FileTypes {
64
64
  * Returns null if no input file format was found for the given identifier.
65
65
  *
66
66
  * @param {string} type - Case-insensitive file format identifier
67
- * @returns {?FileType}
67
+ * @returns {FileType | null}
68
68
  */
69
69
  getInputType(type) {
70
70
  return this._findType(type, 'input');
@@ -76,7 +76,7 @@ class FileTypes {
76
76
  * Returns null if no output file format was found for the given identifier.
77
77
  *
78
78
  * @param {string} type - Case-insensitive file format identifier
79
- * @returns {?FileType}
79
+ * @returns {FileType | null}
80
80
  */
81
81
  getOutputType(type) {
82
82
  return this._findType(type, 'output');
@@ -87,7 +87,7 @@ class FileTypes {
87
87
  *
88
88
  * @param {string} type - Identifier of the file type
89
89
  * @param {string} io - Either `input` or `output`
90
- * @returns {?FileType}
90
+ * @returns {FileType | null}
91
91
  * @protected
92
92
  */
93
93
  _findType(type, io) {
package/src/job.js CHANGED
@@ -265,6 +265,9 @@ class Job extends BaseEntity {
265
265
  */
266
266
  async getResultsAsStac() {
267
267
  let response = await this.connection._get('/jobs/' + this.id + '/results');
268
+ if (!Utils.isObject(response) || !Utils.isObject(response.data)) {
269
+ throw new Error("Results received from the back-end are invalid");
270
+ }
268
271
  let data = StacMigrate.stac(response.data);
269
272
  if (!Utils.isObject(data.assets)) {
270
273
  data.assets = {};
@@ -271,7 +271,7 @@ class OidcProvider extends AuthProvider {
271
271
  *
272
272
  * This may override a detected default client ID.
273
273
  *
274
- * @param {?string} clientId
274
+ * @param {string | null} clientId
275
275
  */
276
276
  setClientId(clientId) {
277
277
  this.clientId = clientId;
@@ -281,7 +281,7 @@ class OidcProvider extends AuthProvider {
281
281
  * Sets the OIDC User.
282
282
  *
283
283
  * @see https://github.com/IdentityModel/oidc-client-js/wiki#user
284
- * @param {?Oidc.User} user - The OIDC User. Passing `null` resets OIDC authentication details.
284
+ * @param {Oidc.User | null} user - The OIDC User. Passing `null` resets OIDC authentication details.
285
285
  */
286
286
  setUser(user) {
287
287
  if (!user) {
@@ -299,7 +299,7 @@ class OidcProvider extends AuthProvider {
299
299
  *
300
300
  * Sets the grant and client ID accordingly.
301
301
  *
302
- * @returns {?OidcClient}
302
+ * @returns {OidcClient | null}
303
303
  * @see OidcProvider#setGrant
304
304
  * @see OidcProvider#setClientId
305
305
  */
package/src/openeo.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const axios = require('axios').default;
2
+ const { AbortController } = require("node-abort-controller");
2
3
  const Utils = require('@openeo/js-commons/src/utils');
3
4
  const Versions = require('@openeo/js-commons/src/versions');
4
5
 
@@ -43,15 +44,17 @@ class OpenEO {
43
44
  *
44
45
  * @async
45
46
  * @param {string} url - The server URL to connect to.
47
+ * @param {Options} [options={}] - Additional options for the connection.
46
48
  * @returns {Promise<Connection>}
47
49
  * @throws {Error}
48
50
  * @static
49
51
  */
50
- static async connect(url) {
52
+ static async connect(url, options = {}) {
51
53
  let wellKnownUrl = Utils.normalizeUrl(url, '/.well-known/openeo');
54
+ let versionedUrl = url;
52
55
  let response = null;
53
56
  try {
54
- response = await axios.get(wellKnownUrl);
57
+ response = await axios.get(wellKnownUrl, {timeout: 5000});
55
58
 
56
59
  if (!Utils.isObject(response.data) || !Array.isArray(response.data.versions)) {
57
60
  throw new Error("Well-Known Document doesn't list any versions.");
@@ -63,14 +66,16 @@ class OpenEO {
63
66
  if (Utils.isObject(response)) {
64
67
  let version = Versions.findLatest(response.data.versions, true, MIN_API_VERSION, MAX_API_VERSION);
65
68
  if (version !== null) {
66
- url = version.url;
69
+ versionedUrl = version.url;
67
70
  }
68
71
  else {
69
72
  throw new Error("Server not supported. Client only supports the API versions between " + MIN_API_VERSION + " and " + MAX_API_VERSION);
70
73
  }
71
74
  }
72
75
 
73
- return await OpenEO.connectDirect(url);
76
+ let connection = await OpenEO.connectDirect(versionedUrl, options);
77
+ connection.url = url;
78
+ return connection;
74
79
  }
75
80
 
76
81
  /**
@@ -80,12 +85,13 @@ class OpenEO {
80
85
  *
81
86
  * @async
82
87
  * @param {string} versionedUrl - The server URL to connect to.
88
+ * @param {Options} [options={}] - Additional options for the connection.
83
89
  * @returns {Promise<Connection>}
84
90
  * @throws {Error}
85
91
  * @static
86
92
  */
87
- static async connectDirect(versionedUrl) {
88
- let connection = new Connection(versionedUrl);
93
+ static async connectDirect(versionedUrl, options = {}) {
94
+ let connection = new Connection(versionedUrl, options);
89
95
 
90
96
  // Check whether back-end is accessible and supports a compatible version.
91
97
  let capabilities = await connection.init();
@@ -104,7 +110,7 @@ class OpenEO {
104
110
  * @returns {string} Version number (according to SemVer).
105
111
  */
106
112
  static clientVersion() {
107
- return "2.0.0";
113
+ return "2.3.0";
108
114
  }
109
115
 
110
116
  }
@@ -112,6 +118,7 @@ class OpenEO {
112
118
  OpenEO.Environment = require('./env');
113
119
 
114
120
  module.exports = {
121
+ AbortController,
115
122
  AuthProvider,
116
123
  BasicProvider,
117
124
  Capabilities,
package/src/typedefs.js CHANGED
@@ -170,11 +170,20 @@
170
170
  * @property {Array.<Link>} links Links
171
171
  */
172
172
 
173
+ /**
174
+ * Connection options.
175
+ *
176
+ * @typedef Options
177
+ * @type {object}
178
+ * @property {boolean} addNamespaceToProcess Add a namespace property to processes if set to `true`. Defaults to `false`.
179
+ */
180
+
173
181
  /**
174
182
  * @typedef Processes
175
183
  * @type {object}
176
184
  * @property {Array.<Process>} processes
177
185
  * @property {Array.<Link>} links
186
+ * @property {?Array.<string>} namespaces EXPERIMENTAL!
178
187
  */
179
188
 
180
189
  /**
@@ -214,8 +223,9 @@
214
223
  * @typedef UserAccount
215
224
  * @type {object}
216
225
  * @property {string} user_id
217
- * @property {string} name
218
- * @property {UserAccountStorage} storage
226
+ * @property {?string} name
227
+ * @property {?string} default_plan
228
+ * @property {?UserAccountStorage} storage
219
229
  * @property {?number} budget
220
- * @property {Array.<Link>} links
230
+ * @property {?Array.<Link>} links
221
231
  */
package/src/userfile.js CHANGED
@@ -90,10 +90,11 @@ class UserFile extends BaseEntity {
90
90
  * @async
91
91
  * @param {*} source - The source, see method description for details.
92
92
  * @param {?uploadStatusCallback} statusCallback - Optionally, a callback that is executed on upload progress updates.
93
+ * @param {?AbortController} [abortController=null] - An AbortController object that can be used to cancel the upload process.
93
94
  * @returns {Promise<UserFile>}
94
95
  * @throws {Error}
95
96
  */
96
- async uploadFile(source, statusCallback = null) {
97
+ async uploadFile(source, statusCallback = null, abortController = null) {
97
98
  let options = {
98
99
  method: 'put',
99
100
  url: '/files/' + this.path,
@@ -109,7 +110,7 @@ class UserFile extends BaseEntity {
109
110
  };
110
111
  }
111
112
 
112
- let response = await this.connection._send(options);
113
+ let response = await this.connection._send(options, abortController);
113
114
  return this.setAll(response.data);
114
115
  }
115
116
 
@@ -1,4 +1,5 @@
1
1
  const BaseEntity = require('./baseentity');
2
+ const Utils = require('@openeo/js-commons/src/utils');
2
3
 
3
4
  /**
4
5
  * A Stored Process Graph.
@@ -120,6 +121,10 @@ class UserProcess extends BaseEntity {
120
121
  */
121
122
  async describeUserProcess() {
122
123
  let response = await this.connection._get('/process_graphs/' + this.id);
124
+ if (!Utils.isObject(response.data) || typeof response.data.id !== 'string') {
125
+ throw new Error('Invalid response received for user process');
126
+ }
127
+ this.connection.processes.add(response.data, 'user');
123
128
  return this.setAll(response.data);
124
129
  }
125
130
 
@@ -140,7 +145,9 @@ class UserProcess extends BaseEntity {
140
145
  return this.describeUserProcess();
141
146
  }
142
147
  else {
143
- return this.setAll(parameters);
148
+ let obj = this.setAll(parameters);
149
+ this.connection.processes.add(obj.toJSON(), 'user');
150
+ return obj;
144
151
  }
145
152
  }
146
153
 
@@ -152,6 +159,7 @@ class UserProcess extends BaseEntity {
152
159
  */
153
160
  async deleteUserProcess() {
154
161
  await this.connection._delete('/process_graphs/' + this.id);
162
+ this.connection.processes.remove(this.id, 'user');
155
163
  }
156
164
  }
157
165