@nextgis/ngw-connector 1.8.4 → 1.11.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.
@@ -1,4 +1,4 @@
1
- /** Bundle of @nextgis/ngw-connector; version: 1.8.4; author: NextGIS */
1
+ /** Bundle of @nextgis/ngw-connector; version: 1.11.0; author: NextGIS */
2
2
  var events = {exports: {}};
3
3
 
4
4
  var R = typeof Reflect === 'object' ? Reflect : null;
@@ -832,6 +832,23 @@ var CancelablePromise = CancelablePromise$1;
832
832
  */
833
833
  function defined(val) {
834
834
  return val !== undefined && val !== null;
835
+ }
836
+ /**
837
+ * from https://github.com/CesiumGS/cesium/blob/master/Source/Core/defined.js
838
+ *
839
+ * @param val - The object.
840
+ * @returns Returns true if the object is defined and not empty string, returns false otherwise.
841
+ *
842
+ * @example
843
+ * ```javascript
844
+ * full('foo') // true
845
+ * full('') // false
846
+ * full(undefined) // false
847
+ * full(0) // true
848
+ * ```
849
+ */
850
+ function full(val) {
851
+ return typeof val === 'string' ? !!val : defined(val);
835
852
  }
836
853
 
837
854
  function isEqual(a, b, o, p) {
@@ -900,13 +917,45 @@ function fixUrlStr(url) {
900
917
  return url.replace(/([^:]\/)\/+/g, '$1');
901
918
  }
902
919
 
920
+ /**
921
+ * @example
922
+ * ```javascript
923
+ * const cache1 = new Cache();
924
+ * cache1.add('foo', 'value');
925
+ *
926
+ * const cache2 = new Cache();
927
+ * cache2.match('foo'); // value
928
+ *
929
+ * const cache3 = new Cache({ namespace: 'foo' });
930
+ * cache3.match('foo'); // undefined
931
+ * ```
932
+ *
933
+ * @example
934
+ * ```javascript
935
+ * let COUNTER = 0;
936
+ * const createPromise = () => new Promise((res) => {
937
+ * COUNTER++
938
+ * setTimeout(() => res('Ok'), 300)
939
+ * });
940
+ *
941
+ * const cache = new Cache();
942
+ * for (let i = 0; i < 10; i++) {
943
+ * cache.add('foo', createPromise).then((data) => {
944
+ * console.log(data); // 'Ok'
945
+ * });
946
+ * }
947
+ * console.log(COUNTER); // 1
948
+ * ```
949
+ */
903
950
  class Cache$1 {
904
- constructor() {
951
+ constructor(options = {}) {
952
+ var _a;
905
953
  this.cache = [];
906
- if (Cache$1.instance) {
907
- return Cache$1.instance;
954
+ const namespace = (_a = options.namespace) !== null && _a !== void 0 ? _a : 'default';
955
+ if (Cache$1.instance[namespace]) {
956
+ return Cache$1.instance[namespace];
908
957
  }
909
- Cache$1.instance = this;
958
+ Cache$1.instance[namespace] = this;
910
959
  return this;
911
960
  }
912
961
  clean() {
@@ -915,8 +964,33 @@ class Cache$1 {
915
964
  all() {
916
965
  return this.cache;
917
966
  }
918
- add(key, valueToSet, options) {
919
- const exist = this._find(key, options);
967
+ /**
968
+ * Caching only a non-empty value.
969
+ *
970
+ * Useful for get or create strategy
971
+ * @example
972
+ * ```javascript
973
+ * const cache = new Cache();
974
+ * const getItemFunc = () => fetch(url).then((data) => {
975
+ * return data.json(); // undefined
976
+ * });
977
+ * const item = await cache.addFull('foo', getItemFunc);
978
+ * if (!item) {
979
+ * await createItem(); // 'New item'
980
+ * }
981
+ *
982
+ * // somewhere else in the code
983
+ * const item = await cache.addFull('foo', getItemFunc).then((resp) => {
984
+ * console.log(resp); // 'New item'
985
+ * })
986
+ *
987
+ * ```
988
+ */
989
+ addFull(key, valueToSet, props) {
990
+ return this.add(key, valueToSet, props, true);
991
+ }
992
+ add(key, valueToSet, props, onlyFull) {
993
+ const exist = this._find(key, props);
920
994
  if (!exist) {
921
995
  let value;
922
996
  if (valueToSet instanceof Function) {
@@ -925,18 +999,31 @@ class Cache$1 {
925
999
  else {
926
1000
  value = valueToSet;
927
1001
  }
928
- const options_ = options && JSON.parse(JSON.stringify(objectRemoveEmpty(options)));
1002
+ const props_ = props && JSON.parse(JSON.stringify(objectRemoveEmpty(props)));
929
1003
  const cacheItem = {
930
1004
  key,
931
1005
  value,
932
- options: options_,
1006
+ props: props_,
1007
+ // TODO: remove backward compatibility use only props
1008
+ options: props_,
933
1009
  };
1010
+ if (onlyFull && !full(value)) {
1011
+ return value;
1012
+ }
934
1013
  this.cache.push(cacheItem);
935
1014
  if (value instanceof Promise) {
936
1015
  value.catch((er) => {
937
- this.delete(key, options);
1016
+ this.delete(key, props);
938
1017
  throw er;
939
1018
  });
1019
+ if (onlyFull) {
1020
+ value.then((x) => {
1021
+ if (!full(x)) {
1022
+ this.delete(key, props);
1023
+ }
1024
+ return x;
1025
+ });
1026
+ }
940
1027
  return value;
941
1028
  }
942
1029
  return value;
@@ -945,40 +1032,49 @@ class Cache$1 {
945
1032
  return exist.value;
946
1033
  }
947
1034
  }
948
- match(key, options) {
949
- const cacheRecord = this._find(key, options);
1035
+ match(key, props) {
1036
+ const cacheRecord = this._find(key, props);
950
1037
  if (cacheRecord) {
951
1038
  return cacheRecord.value;
952
1039
  }
953
1040
  }
954
- matchAll(key, options) {
1041
+ matchAll(key, props) {
955
1042
  if (key) {
956
1043
  return this.cache
957
- .filter((x) => this._filter(x, key, options))
1044
+ .filter((x) => this._filter(x, key, props))
958
1045
  .map((x) => x.value);
959
1046
  }
960
1047
  return this.cache.map((x) => x.value);
961
1048
  }
962
- delete(key, options) {
963
- const exist = this.cache.filter((x) => this._filter(x, key, options));
1049
+ delete(keyOrItem, props) {
1050
+ let exist = [];
1051
+ if (typeof keyOrItem === 'string') {
1052
+ exist = this.cache.filter((x) => this._filter(x, keyOrItem, props));
1053
+ }
1054
+ else {
1055
+ exist.push(keyOrItem);
1056
+ }
964
1057
  for (const e of exist) {
965
1058
  const index = this.cache.indexOf(e);
966
1059
  this.cache.splice(index, 1);
967
1060
  }
968
1061
  }
969
- _find(key, options) {
970
- return this.cache.find((x) => this._filter(x, key, options));
1062
+ _find(key, props) {
1063
+ return this.cache.find((x) => this._filter(x, key, props));
971
1064
  }
972
- _filter(item, key, options) {
1065
+ _filter(item, key, props) {
973
1066
  if (item.key === key) {
974
- if (options) {
975
- return objectDeepEqual(item.options || {}, objectRemoveEmpty(options));
1067
+ if (props) {
1068
+ // TODO: remove backward compatibility
1069
+ const itemProps = item.props || item.options;
1070
+ return objectDeepEqual(itemProps || {}, objectRemoveEmpty(props));
976
1071
  }
977
1072
  return true;
978
1073
  }
979
1074
  return false;
980
1075
  }
981
- }
1076
+ }
1077
+ Cache$1.instance = {};
982
1078
 
983
1079
  /**
984
1080
  * Caching for asynchronous functions
@@ -1013,6 +1109,10 @@ class NetworkError extends Error {
1013
1109
  }
1014
1110
  }
1015
1111
 
1112
+ function isObject(val) {
1113
+ return Object.prototype.toString.call(val) === '[object Object]';
1114
+ }
1115
+
1016
1116
  let loadData;
1017
1117
  // @ts-ignore
1018
1118
  {
@@ -1046,7 +1146,7 @@ let loadData;
1046
1146
  }
1047
1147
  };
1048
1148
  xhr.onload = () => {
1049
- if ([401, 403, 404, 500].indexOf(xhr.status) !== -1) {
1149
+ if ([401, 403, 404, 422, 500].indexOf(xhr.status) !== -1) {
1050
1150
  error(new NgwError(getResponseText()));
1051
1151
  }
1052
1152
  processingResponse();
@@ -1101,7 +1201,7 @@ let loadData;
1101
1201
  data = new FormData();
1102
1202
  data.append('file', options.file);
1103
1203
  if (options.data) {
1104
- for (const d in data) {
1204
+ for (const d in options.data) {
1105
1205
  data.append(d, data[d]);
1106
1206
  }
1107
1207
  }
@@ -1187,28 +1287,36 @@ function removeConnector(connector) {
1187
1287
  }
1188
1288
  }
1189
1289
 
1190
- function isObject(val) {
1191
- return Object.prototype.toString.call(val) === '[object Object]';
1192
- }
1193
-
1290
+ const exclude = ['description'];
1194
1291
  /**
1292
+ * @remarks
1293
+ * https://docs.nextgis.ru/docs_ngweb_dev/doc/developer/resource.html#search-resources
1294
+ *
1195
1295
  * ```
1196
- * { keyname, parent: { id }} > { keyname, parent__id }
1296
+ * { keyname, owner_user: { id }} > { keyname, owner_user__id }
1197
1297
  * ```
1298
+ *
1198
1299
  * @param resource - Any property from NGW resource item
1199
1300
  */
1200
1301
  function resourceToQuery(resource, prefix = '') {
1201
1302
  prefix = prefix ? prefix + '__' : '';
1202
1303
  const query = {};
1203
- Object.entries(resource).forEach(([key, value]) => {
1204
- if (isObject(value)) {
1205
- const children = resourceToQuery(value, key);
1206
- Object.assign(query, children);
1207
- }
1208
- else if (defined(value)) {
1209
- query[prefix + key] = value;
1304
+ for (const [key, value] of Object.entries(resource)) {
1305
+ if (exclude.indexOf(key) === -1) {
1306
+ if (isObject(value)) {
1307
+ if (key === 'owner_user') {
1308
+ const children = resourceToQuery(value, key);
1309
+ Object.assign(query, children);
1310
+ }
1311
+ else if (key === 'parent' && 'id' in value) {
1312
+ query.parent_id = value.id;
1313
+ }
1314
+ }
1315
+ else if (defined(value)) {
1316
+ query[prefix + key] = value;
1317
+ }
1210
1318
  }
1211
- });
1319
+ }
1212
1320
  return query;
1213
1321
  }
1214
1322
 
@@ -1233,22 +1341,33 @@ class ResourcesControl {
1233
1341
  */
1234
1342
  getOne(resource, requestOptions) {
1235
1343
  const cache = new Cache();
1344
+ const forCache = {};
1345
+ const opt = { ...requestOptions, cache: false };
1346
+ if (typeof resource === 'string') {
1347
+ forCache.keyname = resource;
1348
+ }
1349
+ else if (typeof resource === 'number') {
1350
+ forCache.id = resource;
1351
+ }
1352
+ else if (isObject(resource)) {
1353
+ forCache.id = resource.id;
1354
+ }
1236
1355
  const makeRequest = () => {
1237
1356
  if (typeof resource === 'string') {
1238
- return this._fetchResourceBy({ keyname: resource }, requestOptions);
1357
+ return this._fetchResourceBy({ keyname: resource }, opt);
1239
1358
  }
1240
1359
  else if (typeof resource === 'number') {
1241
- return this._fetchResourceById(resource, requestOptions);
1360
+ return this._fetchResourceById(resource, opt);
1242
1361
  }
1243
1362
  else if (isObject(resource)) {
1244
- return this._fetchResourceBy(resource, requestOptions);
1363
+ return this._fetchResourceBy(resource, opt);
1245
1364
  }
1246
1365
  return CancelablePromise.resolve(undefined);
1247
1366
  };
1248
- return cache.add('resource', makeRequest, { resource });
1367
+ return cache.addFull('resource', makeRequest, forCache);
1249
1368
  }
1250
- getOneOrFail(resource) {
1251
- return this.getOne(resource).then((res) => {
1369
+ getOneOrFail(resource, requestOptions) {
1370
+ return this.getOne(resource, requestOptions).then((res) => {
1252
1371
  if (res) {
1253
1372
  return res;
1254
1373
  }
@@ -1265,12 +1384,12 @@ class ResourcesControl {
1265
1384
  * then this method will come in handy to facilitate the extraction of the identifier
1266
1385
  * if the resource is specified through a keyname or other parameters.
1267
1386
  */
1268
- getId(resource) {
1387
+ getId(resource, requestOptions) {
1269
1388
  if (typeof resource === 'number') {
1270
1389
  return CancelablePromise.resolve(resource);
1271
1390
  }
1272
1391
  else if (typeof resource === 'string' || isObject(resource)) {
1273
- return this.getOne(resource).then((res) => {
1392
+ return this.getOne(resource, requestOptions).then((res) => {
1274
1393
  if (res) {
1275
1394
  return res.resource.id;
1276
1395
  }
@@ -1286,8 +1405,8 @@ class ResourcesControl {
1286
1405
  * Similar with {@link NgwConnector.getResourceId | getResourceId} but rise error if resource is not exist.
1287
1406
  * To not make one more checks if the resource is definitely exists
1288
1407
  */
1289
- getIdOrFail(resource) {
1290
- return this.getId(resource).then((resp) => {
1408
+ getIdOrFail(resource, requestOptions) {
1409
+ return this.getId(resource, requestOptions).then((resp) => {
1291
1410
  if (resp === undefined) {
1292
1411
  throw new Error();
1293
1412
  }
@@ -1311,11 +1430,11 @@ class ResourcesControl {
1311
1430
  })
1312
1431
  .then((resources) => {
1313
1432
  if (resources) {
1314
- resources.forEach((x) => {
1433
+ for (const x of resources) {
1315
1434
  this.cache.add('resource.item', CancelablePromise.resolve(x), {
1316
1435
  id: x.resource.id,
1317
1436
  });
1318
- });
1437
+ }
1319
1438
  }
1320
1439
  return resources;
1321
1440
  });
@@ -1323,18 +1442,18 @@ class ResourcesControl {
1323
1442
  return items;
1324
1443
  });
1325
1444
  }
1326
- getParent(resource) {
1327
- return this.connector.getResource(resource).then((child) => {
1445
+ getParent(resource, requestOptions) {
1446
+ return this.getOne(resource, requestOptions).then((child) => {
1328
1447
  if (child) {
1329
- return this.connector.getResource(child.resource.parent.id);
1448
+ return this.getOne(child.resource.parent.id, requestOptions);
1330
1449
  }
1331
1450
  return CancelablePromise.resolve(undefined);
1332
1451
  });
1333
1452
  }
1334
- getChildrenOf(resource) {
1453
+ getChildrenOf(resource, requestOptions) {
1335
1454
  return this.getId(resource).then((parent) => {
1336
1455
  return this.connector
1337
- .get('resource.collection', { cache: true }, {
1456
+ .get('resource.collection', { cache: true, ...requestOptions }, {
1338
1457
  parent,
1339
1458
  })
1340
1459
  .then((items) => {
@@ -1362,12 +1481,35 @@ class ResourcesControl {
1362
1481
  return this.getId(resource).then((id) => {
1363
1482
  if (id !== undefined) {
1364
1483
  return this.connector.delete('resource.item', null, { id }).then(() => {
1365
- this.cache.delete('resource.item', { id });
1484
+ this._cleanResourceItemCache(id);
1366
1485
  return undefined;
1367
1486
  });
1368
1487
  }
1369
1488
  });
1370
1489
  }
1490
+ async _cleanResourceItemCache(id) {
1491
+ const all = this.cache.all();
1492
+ const toDelete = [];
1493
+ for (const c of all) {
1494
+ const cid = c.options && c.options.id;
1495
+ if (['resource.item', 'resource'].includes(c.key) && cid !== undefined) {
1496
+ if (typeof cid === 'number') {
1497
+ if (cid === id) {
1498
+ toDelete.push(c);
1499
+ }
1500
+ }
1501
+ else {
1502
+ const rid = await this.getId(cid);
1503
+ if (rid === id) {
1504
+ toDelete.push(c);
1505
+ }
1506
+ }
1507
+ }
1508
+ }
1509
+ for (const d of toDelete) {
1510
+ this.cache.delete(d);
1511
+ }
1512
+ }
1371
1513
  _fetchResourceById(id, requestOptions) {
1372
1514
  const promise = () => this.connector.get('resource.item', requestOptions, { id });
1373
1515
  return this.cache
@@ -1571,7 +1713,7 @@ class NgwConnector$1 {
1571
1713
  headers: this.getAuthorizationHeaders(credentials),
1572
1714
  // withCredentials: true
1573
1715
  };
1574
- // Do not use request('auth.current_user') to avoid circular-references
1716
+ // Do not use apiRequest('auth.current_user') to avoid circular-references
1575
1717
  return this.makeQuery('/api/component/auth/current_user', {}, options)
1576
1718
  .then((data) => {
1577
1719
  this.user = data;
@@ -1729,7 +1871,7 @@ class NgwConnector$1 {
1729
1871
  }
1730
1872
  // remove double slash
1731
1873
  url = fixUrlStr(url);
1732
- return this._loadData(url, options);
1874
+ return this._loadData(encodeURI(url), options);
1733
1875
  }
1734
1876
  else {
1735
1877
  throw new Error('Empty `url` not allowed');
@@ -1741,14 +1883,14 @@ class NgwConnector$1 {
1741
1883
  /**
1742
1884
  * {@inheritDoc ResourcesControl.getOne}
1743
1885
  */
1744
- getResource(resource) {
1745
- return this.resources.getOne(resource);
1886
+ getResource(resource, requestOptions) {
1887
+ return this.resources.getOne(resource, requestOptions);
1746
1888
  }
1747
1889
  /**
1748
1890
  * {@inheritDoc ResourcesControl.getOneOrFail}
1749
1891
  */
1750
- getResourceOrFail(resource) {
1751
- return this.resources.getOneOrFail(resource);
1892
+ getResourceOrFail(resource, requestOptions) {
1893
+ return this.resources.getOneOrFail(resource, requestOptions);
1752
1894
  }
1753
1895
  /**
1754
1896
  * @deprecated - use {@link NgwConnector.getResource}
@@ -1771,32 +1913,32 @@ class NgwConnector$1 {
1771
1913
  /**
1772
1914
  * {@inheritDoc ResourcesControl.getId}
1773
1915
  */
1774
- getResourceId(resource) {
1775
- return this.resources.getId(resource);
1916
+ getResourceId(resource, requestOptions) {
1917
+ return this.resources.getId(resource, requestOptions);
1776
1918
  }
1777
1919
  /**
1778
1920
  * {@inheritDoc ResourcesControl.getIdOrFail}
1779
1921
  */
1780
- getResourceIdOrFail(resource) {
1781
- return this.resources.getIdOrFail(resource);
1922
+ getResourceIdOrFail(resource, requestOptions) {
1923
+ return this.resources.getIdOrFail(resource, requestOptions);
1782
1924
  }
1783
1925
  /**
1784
1926
  * {@inheritDoc ResourcesControl.getMany}
1785
1927
  */
1786
- getResourcesBy(resource) {
1787
- return this.resources.getMany(resource);
1928
+ getResourcesBy(resource, requestOptions) {
1929
+ return this.resources.getMany(resource, requestOptions);
1788
1930
  }
1789
1931
  /**
1790
1932
  * {@inheritDoc ResourcesControl.getParent}
1791
1933
  */
1792
- getResourceParent(resource) {
1793
- return this.resources.getParent(resource);
1934
+ getResourceParent(resource, requestOptions) {
1935
+ return this.resources.getParent(resource, requestOptions);
1794
1936
  }
1795
1937
  /**
1796
1938
  * {@inheritDoc ResourcesControl.getChildrenOf}
1797
1939
  */
1798
- getResourceChildren(resource) {
1799
- return this.resources.getChildrenOf(resource);
1940
+ getResourceChildren(resource, requestOptions) {
1941
+ return this.resources.getChildrenOf(resource, requestOptions);
1800
1942
  }
1801
1943
  /**
1802
1944
  * {@inheritDoc ResourcesControl.update}
@@ -1830,7 +1972,7 @@ class NgwConnector$1 {
1830
1972
  else {
1831
1973
  // @ts-ignore
1832
1974
  {
1833
- console.warn(httpError);
1975
+ console.warn('DEV WARN', httpError);
1834
1976
  }
1835
1977
  const er = this._handleHttpError(httpError);
1836
1978
  if (er) {