@openeo/js-client 2.5.1 → 2.7.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/openeo.js CHANGED
@@ -1,138 +1,137 @@
1
- const axios = require('axios').default;
2
- const { AbortController } = require("node-abort-controller");
3
- const Utils = require('@openeo/js-commons/src/utils');
4
- const Versions = require('@openeo/js-commons/src/versions');
5
-
6
- // API wrapper
7
- const Connection = require('./connection');
8
- const Job = require('./job');
9
- const Logs = require('./logs');
10
- const UserFile = require('./userfile');
11
- const UserProcess = require('./userprocess');
12
- const Service = require('./service');
13
-
14
- // Auth Providers
15
- const AuthProvider = require('./authprovider');
16
- const BasicProvider = require('./basicprovider');
17
- const OidcProvider = require('./oidcprovider');
18
-
19
- // Response wrapper
20
- const Capabilities = require('./capabilities');
21
- const FileTypes = require('./filetypes');
22
-
23
- // Builder
24
- const Builder = require('./builder/builder');
25
- const BuilderNode = require('./builder/node');
26
- const Parameter = require('./builder/parameter');
27
- const Formula = require('./builder/formula');
28
-
29
- const MIN_API_VERSION = '1.0.0-rc.2';
30
- const MAX_API_VERSION = '1.x.x';
31
-
32
- /**
33
- * Main class to start with openEO. Allows to connect to a server.
34
- *
35
- * @hideconstructor
36
- */
37
- class OpenEO {
38
-
39
- /**
40
- * Connect to a back-end with version discovery (recommended).
41
- *
42
- * Includes version discovery (request to `GET /well-known/openeo`) and connects to the most suitable version compatible to this JS client version.
43
- * Requests the capabilities and authenticates where required.
44
- *
45
- * @async
46
- * @param {string} url - The server URL to connect to.
47
- * @param {Options} [options={}] - Additional options for the connection.
48
- * @returns {Promise<Connection>}
49
- * @throws {Error}
50
- * @static
51
- */
52
- static async connect(url, options = {}) {
53
- let wellKnownUrl = Utils.normalizeUrl(url, '/.well-known/openeo');
54
- let versionedUrl = url;
55
- let response = null;
56
- try {
57
- response = await axios.get(wellKnownUrl, {timeout: 5000});
58
-
59
- if (!Utils.isObject(response.data) || !Array.isArray(response.data.versions)) {
60
- throw new Error("Well-Known Document doesn't list any versions.");
61
- }
62
- } catch(error) {
63
- console.warn("Can't read well-known document, connecting directly to the specified URL as fallback mechanism. Reason: " + error.message);
64
- }
65
-
66
- if (Utils.isObject(response)) {
67
- let version = Versions.findLatest(response.data.versions, true, MIN_API_VERSION, MAX_API_VERSION);
68
- if (version !== null) {
69
- versionedUrl = version.url;
70
- }
71
- else {
72
- throw new Error("Server not supported. Client only supports the API versions between " + MIN_API_VERSION + " and " + MAX_API_VERSION);
73
- }
74
- }
75
-
76
- let connection = await OpenEO.connectDirect(versionedUrl, options);
77
- connection.url = url;
78
- return connection;
79
- }
80
-
81
- /**
82
- * Connects directly to a back-end instance, without version discovery (NOT recommended).
83
- *
84
- * Doesn't do version discovery, therefore a URL of a versioned API must be specified. Requests the capabilities and authenticates where required.
85
- *
86
- * @async
87
- * @param {string} versionedUrl - The server URL to connect to.
88
- * @param {Options} [options={}] - Additional options for the connection.
89
- * @returns {Promise<Connection>}
90
- * @throws {Error}
91
- * @static
92
- */
93
- static async connectDirect(versionedUrl, options = {}) {
94
- let connection = new Connection(versionedUrl, options);
95
-
96
- // Check whether back-end is accessible and supports a compatible version.
97
- let capabilities = await connection.init();
98
- if (Versions.compare(capabilities.apiVersion(), MIN_API_VERSION, "<") || Versions.compare(capabilities.apiVersion(), MAX_API_VERSION, ">")) {
99
- throw new Error("Client only supports the API versions between " + MIN_API_VERSION + " and " + MAX_API_VERSION);
100
- }
101
-
102
- return connection;
103
- }
104
-
105
- /**
106
- * Returns the version number of the client.
107
- *
108
- * Not to confuse with the API version(s) supported by the client.
109
- *
110
- * @returns {string} Version number (according to SemVer).
111
- */
112
- static clientVersion() {
113
- return "2.5.1";
114
- }
115
-
116
- }
117
-
118
- OpenEO.Environment = require('./env');
119
-
120
- module.exports = {
121
- AbortController,
122
- AuthProvider,
123
- BasicProvider,
124
- Capabilities,
125
- Connection,
126
- FileTypes,
127
- Job,
128
- Logs,
129
- OidcProvider,
130
- OpenEO,
131
- Service,
132
- UserFile,
133
- UserProcess,
134
- Builder,
135
- BuilderNode,
136
- Parameter,
137
- Formula
138
- };
1
+ const axios = require('axios');
2
+ const Utils = require('@openeo/js-commons/src/utils');
3
+ const Versions = require('@openeo/js-commons/src/versions');
4
+
5
+ // API wrapper
6
+ const Connection = require('./connection');
7
+ const Job = require('./job');
8
+ const Logs = require('./logs');
9
+ const UserFile = require('./userfile');
10
+ const UserProcess = require('./userprocess');
11
+ const Service = require('./service');
12
+
13
+ // Auth Providers
14
+ const AuthProvider = require('./authprovider');
15
+ const BasicProvider = require('./basicprovider');
16
+ const OidcProvider = require('./oidcprovider');
17
+
18
+ // Response wrapper
19
+ const Capabilities = require('./capabilities');
20
+ const FileTypes = require('./filetypes');
21
+
22
+ // Builder
23
+ const Builder = require('./builder/builder');
24
+ const BuilderNode = require('./builder/node');
25
+ const Parameter = require('./builder/parameter');
26
+ const Formula = require('./builder/formula');
27
+
28
+ const MIN_API_VERSION = '1.0.0-rc.2';
29
+ const MAX_API_VERSION = '1.x.x';
30
+
31
+ /**
32
+ * Main class to start with openEO. Allows to connect to a server.
33
+ *
34
+ * @hideconstructor
35
+ */
36
+ class OpenEO {
37
+
38
+ /**
39
+ * Connect to a back-end with version discovery (recommended).
40
+ *
41
+ * Includes version discovery (request to `GET /well-known/openeo`) and connects to the most suitable version compatible to this JS client version.
42
+ * Requests the capabilities and authenticates where required.
43
+ *
44
+ * @async
45
+ * @param {string} url - The server URL to connect to.
46
+ * @param {Options} [options={}] - Additional options for the connection.
47
+ * @returns {Promise<Connection>}
48
+ * @throws {Error}
49
+ * @static
50
+ */
51
+ static async connect(url, options = {}) {
52
+ let wellKnownUrl = Utils.normalizeUrl(url, '/.well-known/openeo');
53
+ let versionedUrl = url;
54
+ let response = null;
55
+ try {
56
+ response = await axios.get(wellKnownUrl, {timeout: 5000});
57
+
58
+ if (!Utils.isObject(response.data) || !Array.isArray(response.data.versions)) {
59
+ throw new Error("Well-Known Document doesn't list any versions.");
60
+ }
61
+ } catch(error) {
62
+ console.warn("Can't read well-known document, connecting directly to the specified URL as fallback mechanism. Reason: " + error.message);
63
+ }
64
+
65
+ if (Utils.isObject(response)) {
66
+ let version = Versions.findLatest(response.data.versions, true, MIN_API_VERSION, MAX_API_VERSION);
67
+ if (version !== null) {
68
+ versionedUrl = version.url;
69
+ }
70
+ else {
71
+ throw new Error("Server not supported. Client only supports the API versions between " + MIN_API_VERSION + " and " + MAX_API_VERSION);
72
+ }
73
+ }
74
+
75
+ let connection = await OpenEO.connectDirect(versionedUrl, options);
76
+ connection.url = url;
77
+ return connection;
78
+ }
79
+
80
+ /**
81
+ * Connects directly to a back-end instance, without version discovery (NOT recommended).
82
+ *
83
+ * Doesn't do version discovery, therefore a URL of a versioned API must be specified. Requests the capabilities and authenticates where required.
84
+ *
85
+ * @async
86
+ * @param {string} versionedUrl - The server URL to connect to.
87
+ * @param {Options} [options={}] - Additional options for the connection.
88
+ * @returns {Promise<Connection>}
89
+ * @throws {Error}
90
+ * @static
91
+ */
92
+ static async connectDirect(versionedUrl, options = {}) {
93
+ let connection = new Connection(versionedUrl, options);
94
+
95
+ // Check whether back-end is accessible and supports a compatible version.
96
+ let capabilities = await connection.init();
97
+ if (Versions.compare(capabilities.apiVersion(), MIN_API_VERSION, "<") || Versions.compare(capabilities.apiVersion(), MAX_API_VERSION, ">")) {
98
+ throw new Error("Client only supports the API versions between " + MIN_API_VERSION + " and " + MAX_API_VERSION);
99
+ }
100
+
101
+ return connection;
102
+ }
103
+
104
+ /**
105
+ * Returns the version number of the client.
106
+ *
107
+ * Not to confuse with the API version(s) supported by the client.
108
+ *
109
+ * @returns {string} Version number (according to SemVer).
110
+ */
111
+ static clientVersion() {
112
+ return "2.7.0";
113
+ }
114
+
115
+ }
116
+
117
+ OpenEO.Environment = require('./env');
118
+
119
+ module.exports = {
120
+ AbortController,
121
+ AuthProvider,
122
+ BasicProvider,
123
+ Capabilities,
124
+ Connection,
125
+ FileTypes,
126
+ Job,
127
+ Logs,
128
+ OidcProvider,
129
+ OpenEO,
130
+ Service,
131
+ UserFile,
132
+ UserProcess,
133
+ Builder,
134
+ BuilderNode,
135
+ Parameter,
136
+ Formula
137
+ };
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
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
+ }