@openeo/js-client 2.6.0 → 2.8.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/env.js CHANGED
@@ -1,6 +1,16 @@
1
+ let Environment = null;
1
2
  if (typeof window === 'undefined') {
2
- module.exports = require('./node');
3
+ Environment = require('./node');
3
4
  }
4
5
  else {
5
- module.exports = require('./browser');
6
- }
6
+ Environment = require('./browser');
7
+ }
8
+ /**
9
+ * The axios instance to use for HTTP requests.
10
+ *
11
+ * @type {object}
12
+ * @static
13
+ */
14
+ Environment.axios = require('axios');
15
+
16
+ module.exports = Environment;
package/src/logs.js CHANGED
@@ -18,9 +18,26 @@ class Logs {
18
18
  * @type {Connection}
19
19
  */
20
20
  this.connection = connection;
21
+ /**
22
+ * @protected
23
+ * @type {string}
24
+ */
21
25
  this.endpoint = endpoint;
26
+ /**
27
+ * @protected
28
+ * @type {string}
29
+ */
22
30
  this.lastId = "";
31
+ /**
32
+ * @protected
33
+ * @type {?string}
34
+ */
23
35
  this.level = level;
36
+ /**
37
+ * @protected
38
+ * @type {Set<string>}
39
+ */
40
+ this.missing = new Set();
24
41
  }
25
42
 
26
43
  /**
@@ -37,6 +54,19 @@ class Logs {
37
54
  return Array.isArray(response.logs) ? response.logs : [];
38
55
  }
39
56
 
57
+ /**
58
+ * Retrieves the backend identifiers that are (partially) missing in the logs.
59
+ *
60
+ * This is only filled after the first request using `nextLogs` or `next`.
61
+ *
62
+ * @returns {Array.<string>}
63
+ * @see {Logs#nextLogs}
64
+ * @see {Logs#next}
65
+ */
66
+ getMissingBackends() {
67
+ return Array.from(this.missing);
68
+ }
69
+
40
70
  /**
41
71
  * Retrieves the next log entries since the last request.
42
72
  *
@@ -64,7 +94,13 @@ class Logs {
64
94
  else {
65
95
  response.data.logs = [];
66
96
  }
97
+
67
98
  response.data.links = Array.isArray(response.data.links) ? response.data.links : [];
99
+
100
+ if (Array.isArray(response.data["federation:missing"])) {
101
+ response.data["federation:missing"].forEach(backend => this.missing.add(backend));
102
+ }
103
+
68
104
  return response.data;
69
105
  }
70
106
 
package/src/openeo.js CHANGED
@@ -109,7 +109,7 @@ class OpenEO {
109
109
  * @returns {string} Version number (according to SemVer).
110
110
  */
111
111
  static clientVersion() {
112
- return "2.6.0";
112
+ return "2.8.0";
113
113
  }
114
114
 
115
115
  }
package/src/pages.js ADDED
@@ -0,0 +1,349 @@
1
+ /* eslint-disable max-classes-per-file */
2
+
3
+ const Job = require('./job.js');
4
+ const Service = require('./service.js');
5
+ const UserFile = require('./userfile.js');
6
+ const UserProcess = require('./userprocess.js');
7
+ const Utils = require('@openeo/js-commons/src/utils');
8
+ const StacMigrate = require('@radiantearth/stac-migrate');
9
+
10
+ const FED_MISSING = 'federation:missing';
11
+
12
+ /**
13
+ * A class to handle pagination of resources.
14
+ *
15
+ * @abstract
16
+ */
17
+ class Pages {
18
+ /**
19
+ * Creates an instance of Pages.
20
+ *
21
+ * @param {Connection} connection
22
+ * @param {string} endpoint
23
+ * @param {string} key
24
+ * @param {Constructor} cls - Class
25
+ * @param {object} [params={}]
26
+ * @param {string} primaryKey
27
+ */
28
+ constructor(connection, endpoint, key, cls, params = {}, primaryKey = "id") {
29
+ this.connection = connection;
30
+ this.nextUrl = endpoint;
31
+ this.key = key;
32
+ this.primaryKey = primaryKey;
33
+ this.cls = cls;
34
+ if (!(params.limit > 0)) {
35
+ delete params.limit;
36
+ }
37
+ this.params = params;
38
+ }
39
+
40
+ /**
41
+ * Returns true if there are more pages to fetch.
42
+ *
43
+ * @returns {boolean}
44
+ */
45
+ hasNextPage() {
46
+ return this.nextUrl !== null;
47
+ }
48
+
49
+ /**
50
+ * Returns the next page of resources.
51
+ *
52
+ * @async
53
+ * @param {Array.<object>} oldObjects - Existing objects to update, if any.
54
+ * @param {boolean} [toArray=true] - Whether to return the objects as a simplified array or as an object with all information.
55
+ * @returns {Array.<object>}
56
+ * @throws {Error}
57
+ */
58
+ async nextPage(oldObjects = [], toArray = true) {
59
+ // Request data from server
60
+ const response = await this.connection._get(this.nextUrl, this.params);
61
+
62
+ let data = response.data;
63
+ // Check response
64
+ if (!Utils.isObject(data)) {
65
+ throw new Error(`Response is invalid, is not an object`);
66
+ }
67
+ if (!Array.isArray(data[this.key])) {
68
+ throw new Error(`Response is invalid, '${this.key}' property is not an array`);
69
+ }
70
+
71
+ // Update existing objects if needed
72
+ let newObjects = data[this.key].map(updated => {
73
+ let resource = oldObjects.find(old => old[this.primaryKey] === updated[this.primaryKey]);
74
+ if (resource) {
75
+ resource.setAll(updated);
76
+ }
77
+ else {
78
+ resource = this._createObject(updated);
79
+ }
80
+ return resource;
81
+ });
82
+
83
+ // Store objects in cache if needed
84
+ newObjects = this._cache(newObjects);
85
+
86
+ // Add self link if missing
87
+ data.links = this._ensureArray(data.links);
88
+ const selfLink = this.connection._getLinkHref(data.links, 'self');
89
+ if (!selfLink) {
90
+ data.links.push({rel: 'self', href: this.nextUrl});
91
+ }
92
+
93
+ // Check whether a next page is available
94
+ this.nextUrl = this._getNextLink(response);
95
+ // Don't append initial params to the next URL
96
+ this.params = null;
97
+
98
+ // Either return as ResponseArray or full API response body
99
+ if (toArray) {
100
+ newObjects.links = data.links;
101
+ newObjects[FED_MISSING] = this._ensureArray(data[FED_MISSING]);
102
+ return newObjects;
103
+ }
104
+ else {
105
+ data[this.key] = newObjects;
106
+ return data;
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Ensures a variable is an array.
112
+ *
113
+ * @protected
114
+ * @param {*} x
115
+ * @returns {Array}
116
+ */
117
+ _ensureArray(x) {
118
+ return Array.isArray(x) ? x : [];
119
+ }
120
+
121
+ /**
122
+ * Creates a facade for the object, if needed.
123
+ *
124
+ * @protected
125
+ * @param {object} obj
126
+ * @returns {object}
127
+ */
128
+ _createObject(obj) {
129
+ if (this.cls) {
130
+ const cls = this.cls;
131
+ const newObj = new cls(this.connection, obj[this.primaryKey]);
132
+ newObj.setAll(obj);
133
+ return newObj;
134
+ }
135
+ else {
136
+ return obj;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Caches the plain objects if needed.
142
+ *
143
+ * @param {Array.<object>} objects
144
+ * @returns {Array.<object>}
145
+ */
146
+ _cache(objects) {
147
+ return objects;
148
+ }
149
+
150
+ /**
151
+ * Get the URL of the next page from a response.
152
+ *
153
+ * @protected
154
+ * @param {AxiosResponse} response
155
+ * @returns {string | null}
156
+ */
157
+ _getNextLink(response) {
158
+ const links = this.connection.makeLinksAbsolute(response.data.links, response);
159
+ return this.connection._getLinkHref(links, 'next');
160
+ }
161
+
162
+ /**
163
+ * Makes this class asynchronously iterable.
164
+ *
165
+ * @returns {AsyncIterator}
166
+ */
167
+ [Symbol.asyncIterator]() {
168
+ return {
169
+ self: this,
170
+ /**
171
+ * Get the next page of resources.
172
+ *
173
+ * @async
174
+ * @returns {{done: boolean, value: Array.<object>}}
175
+ */
176
+ async next() {
177
+ const done = !this.self.hasNextPage();
178
+ let value;
179
+ if (!done) {
180
+ value = await this.self.nextPage();
181
+ }
182
+ return { done, value };
183
+ }
184
+ }
185
+ }
186
+
187
+ }
188
+
189
+ /**
190
+ * Paginate through jobs.
191
+ */
192
+ class JobPages extends Pages {
193
+ /**
194
+ * Paginate through jobs.
195
+ *
196
+ * @param {Connection} connection
197
+ * @param {?number} limit
198
+ */
199
+ constructor(connection, limit = null) {
200
+ super(connection, "/jobs", "jobs", Job, {limit});
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Paginate through services.
206
+ */
207
+ class ServicePages extends Pages {
208
+ /**
209
+ * Paginate through services.
210
+ *
211
+ * @param {Connection} connection
212
+ * @param {?number} limit
213
+ */
214
+ constructor(connection, limit = null) {
215
+ super(connection, "/services", "services", Service, {limit});
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Paginate through user files.
221
+ */
222
+ class UserFilePages extends Pages {
223
+ /**
224
+ * Paginate through user files.
225
+ *
226
+ * @param {Connection} connection
227
+ * @param {?number} limit
228
+ */
229
+ constructor(connection, limit = null) {
230
+ super(connection, "/files", "files", UserFile, {limit}, "path");
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Paginate through processes.
236
+ */
237
+ class ProcessPages extends Pages {
238
+ /**
239
+ * Paginate through processes.
240
+ *
241
+ * @param {Connection} connection
242
+ * @param {?number} limit
243
+ * @param {?string} namespace
244
+ */
245
+ constructor(connection, limit = null, namespace = null) {
246
+ if (!namespace) {
247
+ namespace = 'backend';
248
+ }
249
+ let endpoint;
250
+ let cls = null
251
+ if (namespace === 'user') {
252
+ endpoint = '/process_graphs';
253
+ cls = UserProcess;
254
+ }
255
+ else {
256
+ endpoint = '/processes';
257
+ if (namespace !== 'backend') {
258
+ const normalized = connection.normalizeNamespace(namespace);
259
+ endpoint += `/${normalized}`;
260
+ }
261
+ }
262
+ super(connection, endpoint, "processes", cls, {limit});
263
+ this.namespace = namespace;
264
+ }
265
+
266
+ /**
267
+ * Caches the objects to the ProcessRegistry.
268
+ *
269
+ * @param {Array.<object>} objects
270
+ * @returns {Array.<object>}
271
+ */
272
+ _cache(objects) {
273
+ const plainObjects = objects.map(p => (typeof p.toJSON === 'function' ? p.toJSON() : p));
274
+ this.connection.processes.addAll(plainObjects, this.namespace);
275
+ if (!this.cls) {
276
+ for (let i in objects) {
277
+ objects[i] = this.connection.processes.get(objects[i].id, this.namespace);
278
+ }
279
+ }
280
+ return objects;
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Paginate through collections.
286
+ */
287
+ class CollectionPages extends Pages {
288
+ /**
289
+ * Paginate through collections.
290
+ *
291
+ * @param {Connection} connection
292
+ * @param {?number} limit
293
+ */
294
+ constructor(connection, limit = null) {
295
+ super(connection, "/collections", "collections", null, {limit});
296
+ }
297
+
298
+ /**
299
+ * Migrates the STAC collection to the latest version.
300
+ *
301
+ * @param {object} obj
302
+ * @returns {Collection}
303
+ */
304
+ _createObject(obj) {
305
+ if (obj.stac_version) {
306
+ return StacMigrate.collection(obj);
307
+ }
308
+ return obj;
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Paginate through collection items.
314
+ */
315
+ class ItemPages extends Pages {
316
+ /**
317
+ * Paginate through collection items.
318
+ *
319
+ * @param {Connection} connection
320
+ * @param {string} collectionId
321
+ * @param {object} params
322
+ */
323
+ constructor(connection, collectionId, params) {
324
+ super(connection, `/collections/${collectionId}/items`, "features", null, params);
325
+ }
326
+
327
+ /**
328
+ * Migrates the STAC item to the latest version.
329
+ *
330
+ * @param {object} obj
331
+ * @returns {Item}
332
+ */
333
+ _createObject(obj) {
334
+ if (obj.stac_version) {
335
+ return StacMigrate.item(obj);
336
+ }
337
+ return obj;
338
+ }
339
+ }
340
+
341
+ module.exports = {
342
+ Pages,
343
+ CollectionPages,
344
+ ItemPages,
345
+ JobPages,
346
+ ProcessPages,
347
+ ServicePages,
348
+ UserFilePages
349
+ }
package/src/typedefs.js CHANGED
@@ -47,6 +47,7 @@
47
47
  * @type {object}
48
48
  * @property {Array.<Collection>} collections
49
49
  * @property {Array.<Link>} links
50
+ * @property {Array.<string>} ["federation:missing"] A list of backends from the federation that are missing in the response data.
50
51
  */
51
52
 
52
53
  /**
@@ -184,6 +185,7 @@
184
185
  * @property {Array.<Process>} processes
185
186
  * @property {Array.<Link>} links
186
187
  * @property {?Array.<string>} namespaces EXPERIMENTAL!
188
+ * @property {Array.<string>} ["federation:missing"] A list of backends from the federation that are missing in the response data.
187
189
  */
188
190
 
189
191
  /**
@@ -193,6 +195,22 @@
193
195
  * @type {object.<string, *>}
194
196
  */
195
197
 
198
+ /**
199
+ * A back-end in the federation.
200
+ *
201
+ * @typedef FederationBackend
202
+ * @type {object}
203
+ * @property {string} id ID of the back-end within the federation.
204
+ * @property {string} url URL to the versioned API endpoint of the back-end.
205
+ * @property {string} title Name of the back-end.
206
+ * @property {string} description A description of the back-end and its specifics.
207
+ * @property {string} status Current status of the back-end (online or offline).
208
+ * @property {string} last_status_check The time at which the status of the back-end was checked last, formatted as a RFC 3339 date-time.
209
+ * @property {string} last_successful_check If the `status` is `offline`: The time at which the back-end was checked and available the last time. Otherwise, this is equal to the property `last_status_check`. Formatted as a RFC 3339 date-time.
210
+ * @property {boolean} experimental Declares the back-end to be experimental.
211
+ * @property {boolean} deprecated Declares the back-end to be deprecated.
212
+ */
213
+
196
214
  /**
197
215
  * An array, but enriched with additional details from an openEO API response.
198
216
  *
@@ -240,4 +258,15 @@
240
258
  * @property {?UserAccountStorage} storage
241
259
  * @property {?number} budget
242
260
  * @property {?Array.<Link>} links
243
- */
261
+ */
262
+
263
+ /**
264
+ * An array, but enriched with additional details from an openEO API response.
265
+ *
266
+ * Adds the property `federation:backends`.
267
+ *
268
+ * @typedef ValidationResult
269
+ * @augments Array
270
+ * @type {Array.<ApiError>}
271
+ * @property {Array.<string>} ["federation:backends"] The back-ends that support / do not support the process.
272
+ */