cocoda-sdk 3.0.2 → 3.2.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/README.md CHANGED
@@ -21,6 +21,7 @@
21
21
  - [Registry Methods - General](#registry-methods---general)
22
22
  - [Registry Methods - Concept Schemes](#registry-methods---concept-schemes)
23
23
  - [Registry Methods - Concepts](#registry-methods---concepts)
24
+ - [Registry Methods - Concordances](#registry-methods---concordances)
24
25
  - [Registry Methods - Mappings](#registry-methods---mappings)
25
26
  - [Registry Methods - Annotations](#registry-methods---annotations)
26
27
  - [Registry Methods - Various](#registry-methods---various)
@@ -164,6 +165,8 @@ The following providers are also exported, but have to be added via `cdk.addProv
164
165
  - `SkosmosApi` - access to concept schemes and concepts via a [Skosmos](https://github.com/NatLibFi/Skosmos) API
165
166
  - `LocApi` - access to concept schemes and concepts via the [Library of Congress Linked Data Service](https://id.loc.gov/)
166
167
  - **This integration is currently experimental and only supports LCSH and LCNAF.**
168
+ - `Skohub` - access to concept schemes and concepts via a [SkoHub Vocabs](https://blog.lobid.org/2019/09/27/presenting-skohub-vocabs.html)
169
+ - **This integration is currently experimental. Only vocabularies that use a [slash namespace pattern]([hash](https://www.w3.org/2001/sw/BestPractices/VM/http-examples/2006-01-18/#slash)) with dereferenceable URIs are supported.**
167
170
  - `ReconciliationApi` - access to mapping suggestions via a [OpenRefine Reconciliation API](https://github.com/OpenRefine/OpenRefine/wiki/Reconciliation-Service-API)
168
171
  - `OccurrencesApi` - access to concept occurrences via [occurrences-api](https://github.com/gbv/occurrences-api) (will be changed to [occurrences-server](https://github.com/gbv/occurrences-server) in the future)
169
172
  - `LabelSearchSuggestion` - access to mapping suggestions using other registries' search endpoints (using [jskos-server])
@@ -348,6 +351,23 @@ Please refer to the [documentation](https://gbv.github.io/cocoda-sdk/CocodaSDK.h
348
351
  - [ConceptApiProvider - suggest](https://gbv.github.io/cocoda-sdk/ConceptApiProvider.html#suggest)
349
352
  - [SkosmosApiProvider - suggest](https://gbv.github.io/cocoda-sdk/SkosmosApiProvider.html#suggest)
350
353
 
354
+ ### Registry Methods - Concordances
355
+
356
+ #### `registry.getConcordances`
357
+ - [MappingsApiProvider - getConcordances](https://gbv.github.io/cocoda-sdk/MappingsApiProvider.html#getConcordances)
358
+
359
+ #### `registry.postConcordance`
360
+ - [MappingsApiProvider - postConcordance](https://gbv.github.io/cocoda-sdk/MappingsApiProvider.html#postConcordance)
361
+
362
+ #### `registry.putConcordance`
363
+ - [MappingsApiProvider - putConcordance](https://gbv.github.io/cocoda-sdk/MappingsApiProvider.html#putConcordance)
364
+
365
+ #### `registry.patchConcordance`
366
+ - [MappingsApiProvider - patchConcordance](https://gbv.github.io/cocoda-sdk/MappingsApiProvider.html#patchConcordance)
367
+
368
+ #### `registry.deleteConcordance`
369
+ - [MappingsApiProvider - deleteConcordance](https://gbv.github.io/cocoda-sdk/MappingsApiProvider.html#deleteConcordance)
370
+
351
371
  ### Registry Methods - Mappings
352
372
 
353
373
  #### `registry.getMappings`
@@ -4,27 +4,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __getProtoOf = Object.getPrototypeOf;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
8
7
  var __export = (target, all) => {
9
8
  for (var name in all)
10
9
  __defProp(target, name, { get: all[name], enumerable: true });
11
10
  };
12
- var __reExport = (target, module2, copyDefault, desc) => {
13
- if (module2 && typeof module2 === "object" || typeof module2 === "function") {
14
- for (let key of __getOwnPropNames(module2))
15
- if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default"))
16
- __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
16
  }
18
- return target;
17
+ return to;
19
18
  };
20
- var __toESM = (module2, isNodeMode) => {
21
- return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", !isNodeMode && module2 && module2.__esModule ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
22
- };
23
- var __toCommonJS = /* @__PURE__ */ ((cache) => {
24
- return (module2, temp) => {
25
- return cache && cache.get(module2) || (temp = __reExport(__markAsModule({}), module2, 1), cache && cache.set(module2, temp), temp);
26
- };
27
- })(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0);
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
21
 
29
22
  // src/index.js
30
23
  var src_exports = {};
@@ -38,11 +31,13 @@ __export(src_exports, {
38
31
  MappingsApiProvider: () => MappingsApiProvider,
39
32
  OccurrencesApiProvider: () => OccurrencesApiProvider,
40
33
  ReconciliationApiProvider: () => ReconciliationApiProvider,
34
+ SkohubProvider: () => SkohubProvider,
41
35
  SkosmosApiProvider: () => SkosmosApiProvider,
42
36
  addAllProviders: () => addAllProviders,
43
37
  cdk: () => cdk,
44
38
  errors: () => errors_exports
45
39
  });
40
+ module.exports = __toCommonJS(src_exports);
46
41
 
47
42
  // src/errors/index.js
48
43
  var errors_exports = {};
@@ -114,7 +109,7 @@ var import_omit = __toESM(require("lodash/omit.js"), 1);
114
109
  var import_concat = __toESM(require("lodash/concat.js"), 1);
115
110
 
116
111
  // src/lib/CocodaSDK.js
117
- var import_jskos_tools10 = __toESM(require("jskos-tools"), 1);
112
+ var import_jskos_tools11 = __toESM(require("jskos-tools"), 1);
118
113
 
119
114
  // src/providers/index.js
120
115
  var providers_exports = {};
@@ -127,6 +122,7 @@ __export(providers_exports, {
127
122
  MappingsApiProvider: () => MappingsApiProvider,
128
123
  OccurrencesApiProvider: () => OccurrencesApiProvider,
129
124
  ReconciliationApiProvider: () => ReconciliationApiProvider,
125
+ SkohubProvider: () => SkohubProvider,
130
126
  SkosmosApiProvider: () => SkosmosApiProvider
131
127
  });
132
128
 
@@ -336,10 +332,12 @@ var BaseProvider = class {
336
332
  this._config = {};
337
333
  this.setRetryConfig();
338
334
  this.axios.interceptors.request.use((config) => {
339
- const language = import_uniq.default([].concat(import_get.default(config, "params.language", "").split(","), this.languages, this._defaultLanguages).filter((lang) => lang != "")).join(",");
340
- import_set.default(config, "params.language", language);
341
- if (this.has.auth && this._auth.bearerToken && !import_get.default(config, "headers.Authorization")) {
342
- import_set.default(config, "headers.Authorization", `Bearer ${this._auth.bearerToken}`);
335
+ if (!config._skipAdditionalParameters) {
336
+ const language = import_uniq.default([].concat(import_get.default(config, "params.language", "").split(","), this.languages, this._defaultLanguages).filter((lang) => lang != "")).join(",");
337
+ import_set.default(config, "params.language", language);
338
+ if (this.has.auth && this._auth.bearerToken && !import_get.default(config, "headers.Authorization")) {
339
+ import_set.default(config, "headers.Authorization", `Bearer ${this._auth.bearerToken}`);
340
+ }
343
341
  }
344
342
  if (config.url.startsWith("http:") && typeof window !== "undefined" && window.location.protocol == "https:") {
345
343
  throw new import_axios.default.Cancel("Can't call http API from https.");
@@ -610,7 +608,7 @@ var BaseProvider = class {
610
608
  }
611
609
  const previousRegistry = scheme._registry;
612
610
  scheme._registry = this.cdk && this.cdk.registryForScheme(scheme);
613
- if (!scheme._registry || previousRegistry === scheme._registry) {
611
+ if (!scheme._registry || previousRegistry === scheme._registry || scheme._registry._api.api === this._api.api) {
614
612
  scheme._registry = previousRegistry || this;
615
613
  } else {
616
614
  ["concepts", "topConcepts"].forEach((key) => {
@@ -1072,7 +1070,13 @@ var MappingsApiProvider = class extends BaseProvider {
1072
1070
  this.has.mappings.delete = !!import_get.default(this._config, "mappings.delete");
1073
1071
  this.has.mappings.anonymous = !!import_get.default(this._config, "mappings.anonymous");
1074
1072
  }
1075
- this.has.concordances = !!this._api.concordances;
1073
+ this.has.concordances = this._api.concordances ? {} : false;
1074
+ if (this.has.concordances) {
1075
+ this.has.concordances.read = !!import_get.default(this._config, "concordances.read");
1076
+ this.has.concordances.create = !!import_get.default(this._config, "concordances.create");
1077
+ this.has.concordances.update = !!import_get.default(this._config, "concordances.update");
1078
+ this.has.concordances.delete = !!import_get.default(this._config, "concordances.delete");
1079
+ }
1076
1080
  this.has.annotations = this._api.annotations ? {} : false;
1077
1081
  if (this.has.annotations) {
1078
1082
  this.has.annotations.read = !!import_get.default(this._config, "annotations.read");
@@ -1108,7 +1112,7 @@ var MappingsApiProvider = class extends BaseProvider {
1108
1112
  throw error;
1109
1113
  }
1110
1114
  }
1111
- async getMappings({ from, fromScheme, to, toScheme, creator, type, partOf, offset, limit, direction, mode, identifier, sort, order, ...config }) {
1115
+ async getMappings({ from, fromScheme, to, toScheme, creator, type, partOf, offset, limit, direction, mode, identifier, cardinality, annotatedBy, annotatedFor, annotatedWith, sort, order, ...config }) {
1112
1116
  let params = {}, url = this._api.mappings;
1113
1117
  if (from) {
1114
1118
  params.from = import_isString.default(from) ? from : from.uri;
@@ -1140,6 +1144,18 @@ var MappingsApiProvider = class extends BaseProvider {
1140
1144
  if (direction) {
1141
1145
  params.direction = direction;
1142
1146
  }
1147
+ if (cardinality) {
1148
+ params.cardinality = cardinality;
1149
+ }
1150
+ if (annotatedBy) {
1151
+ params.annotatedBy = annotatedBy;
1152
+ }
1153
+ if (annotatedFor) {
1154
+ params.annotatedFor = annotatedFor;
1155
+ }
1156
+ if (annotatedWith) {
1157
+ params.annotatedWith = annotatedWith;
1158
+ }
1143
1159
  if (mode) {
1144
1160
  params.mode = mode;
1145
1161
  }
@@ -1205,8 +1221,6 @@ var MappingsApiProvider = class extends BaseProvider {
1205
1221
  if (!mapping) {
1206
1222
  throw new InvalidOrMissingParameterError({ parameter: "mapping" });
1207
1223
  }
1208
- mapping = import_jskos_tools3.default.minifyMapping(mapping);
1209
- mapping = import_jskos_tools3.default.addMappingIdentifiers(mapping);
1210
1224
  const uri = mapping.uri;
1211
1225
  if (!uri || !uri.startsWith(this._api.mappings)) {
1212
1226
  throw new InvalidOrMissingParameterError({ parameter: "mapping", message: "URI doesn't seem to be part of this registry." });
@@ -1215,7 +1229,7 @@ var MappingsApiProvider = class extends BaseProvider {
1215
1229
  ...config,
1216
1230
  method: "patch",
1217
1231
  url: uri,
1218
- data: mapping,
1232
+ data: import_omit.default(mapping, "uri"),
1219
1233
  params: {
1220
1234
  ...this._defaultParams,
1221
1235
  ...config.params || {}
@@ -1298,6 +1312,74 @@ var MappingsApiProvider = class extends BaseProvider {
1298
1312
  url: this._api.concordances
1299
1313
  });
1300
1314
  }
1315
+ async postConcordance({ concordance, ...config }) {
1316
+ if (!concordance) {
1317
+ throw new InvalidOrMissingParameterError({ parameter: "concordance" });
1318
+ }
1319
+ return this.axios({
1320
+ ...config,
1321
+ method: "post",
1322
+ url: this._api.concordances,
1323
+ data: concordance,
1324
+ params: {
1325
+ ...this._defaultParams,
1326
+ ...config.params || {}
1327
+ }
1328
+ });
1329
+ }
1330
+ async putConcordance({ concordance, ...config }) {
1331
+ if (!concordance) {
1332
+ throw new InvalidOrMissingParameterError({ parameter: "concordance" });
1333
+ }
1334
+ const uri = concordance.uri;
1335
+ if (!uri || !uri.startsWith(this._api.concordances)) {
1336
+ throw new InvalidOrMissingParameterError({ parameter: "concordance", message: "URI doesn't seem to be part of this registry." });
1337
+ }
1338
+ return this.axios({
1339
+ ...config,
1340
+ method: "put",
1341
+ url: uri,
1342
+ data: concordance,
1343
+ params: {
1344
+ ...this._defaultParams,
1345
+ ...config.params || {}
1346
+ }
1347
+ });
1348
+ }
1349
+ async patchConcordance({ concordance, ...config }) {
1350
+ if (!concordance) {
1351
+ throw new InvalidOrMissingParameterError({ parameter: "concordance" });
1352
+ }
1353
+ const uri = concordance.uri;
1354
+ if (!uri || !uri.startsWith(this._api.concordances)) {
1355
+ throw new InvalidOrMissingParameterError({ parameter: "concordance", message: "URI doesn't seem to be part of this registry." });
1356
+ }
1357
+ return this.axios({
1358
+ ...config,
1359
+ method: "patch",
1360
+ url: uri,
1361
+ data: import_omit.default(concordance, "uri"),
1362
+ params: {
1363
+ ...this._defaultParams,
1364
+ ...config.params || {}
1365
+ }
1366
+ });
1367
+ }
1368
+ async deleteConcordance({ concordance, ...config }) {
1369
+ if (!concordance) {
1370
+ throw new InvalidOrMissingParameterError({ parameter: "concordance" });
1371
+ }
1372
+ const uri = concordance.uri;
1373
+ if (!uri || !uri.startsWith(this._api.concordances)) {
1374
+ throw new InvalidOrMissingParameterError({ parameter: "concordance", message: "URI doesn't seem to be part of this registry." });
1375
+ }
1376
+ await this.axios({
1377
+ ...config,
1378
+ method: "delete",
1379
+ url: uri
1380
+ });
1381
+ return true;
1382
+ }
1301
1383
  };
1302
1384
  MappingsApiProvider.providerName = "MappingsApi";
1303
1385
  MappingsApiProvider.stored = true;
@@ -2517,6 +2599,228 @@ var LocApiProvider = class extends BaseProvider {
2517
2599
  LocApiProvider.providerName = "LocApi";
2518
2600
  LocApiProvider.providerType = "http://bartoc.org/api-type/loc";
2519
2601
 
2602
+ // src/providers/skohub-provider.js
2603
+ var import_jskos_tools10 = __toESM(require("jskos-tools"), 1);
2604
+ var import_flexsearch = __toESM(require("flexsearch"), 1);
2605
+ function decodeUnicode(text) {
2606
+ return text.replace(/\\u[\dA-F]{4}/gi, function(match) {
2607
+ return String.fromCharCode(parseInt(match.replace(/\\u/g, ""), 16));
2608
+ });
2609
+ }
2610
+ var SkohubProvider = class extends BaseProvider {
2611
+ _prepare() {
2612
+ this.has.schemes = true;
2613
+ this.has.top = true;
2614
+ this.has.data = true;
2615
+ this.has.concepts = true;
2616
+ this.has.narrower = true;
2617
+ this.has.ancestors = true;
2618
+ this.has.suggest = true;
2619
+ this.has.search = true;
2620
+ listOfCapabilities.filter((c) => !this.has[c]).forEach((c) => {
2621
+ this.has[c] = false;
2622
+ });
2623
+ }
2624
+ _setup() {
2625
+ this._index = {};
2626
+ this._conceptCache = {};
2627
+ this._schemeCache = {};
2628
+ }
2629
+ static _registryConfigForBartocApiConfig({ url, scheme } = {}) {
2630
+ if (!url || !scheme) {
2631
+ return null;
2632
+ }
2633
+ const newScheme = { uri: url, identifier: import_jskos_tools10.default.getAllUris(scheme).filter((uri) => uri !== url) };
2634
+ return { schemes: [newScheme] };
2635
+ }
2636
+ async _loadScheme({ scheme, ...config }) {
2637
+ let uris = import_jskos_tools10.default.getAllUris(scheme);
2638
+ for (let uri2 of uris) {
2639
+ if (this._schemeCache[uri2]) {
2640
+ return this._schemeCache[uri2];
2641
+ }
2642
+ }
2643
+ const schemeFromList = this.schemes.find((s) => import_jskos_tools10.default.compare(s, scheme));
2644
+ if (!schemeFromList || !schemeFromList.uri) {
2645
+ throw new InvalidRequestError({ message: `Tried to load unsupported scheme (${scheme && scheme.uri})` });
2646
+ }
2647
+ const uri = schemeFromList.uri;
2648
+ uris = import_uniq.default(uris.concat(import_jskos_tools10.default.getAllUris(schemeFromList)));
2649
+ let postfix = ".json";
2650
+ if (uri.endsWith("/")) {
2651
+ postfix = "index.json";
2652
+ }
2653
+ const data = await this.axios({ ...config, url: `${uri}${postfix}`, _skipAdditionalParameters: true });
2654
+ if (data.id !== uri) {
2655
+ throw new InvalidRequestError({ message: "Skohub URL did not return expected concept scheme" });
2656
+ }
2657
+ const { title, preferredNamespaceUri, hasTopConcept, description } = data;
2658
+ scheme = { uri, identifier: uris.filter((u) => u !== uri) };
2659
+ scheme.prefLabel = title;
2660
+ Object.keys(scheme.prefLabel || {}).forEach((key) => {
2661
+ scheme.prefLabel[key] = decodeUnicode(scheme.prefLabel[key]);
2662
+ });
2663
+ scheme.namespace = preferredNamespaceUri;
2664
+ scheme.topConcepts = (hasTopConcept || []).map((c) => this._toJskosConcept(c));
2665
+ scheme.concepts = [null];
2666
+ if (description) {
2667
+ scheme.definition = description;
2668
+ Object.keys(scheme.definition).forEach((key) => {
2669
+ scheme.definition[key] = [decodeUnicode(scheme.definition[key])];
2670
+ });
2671
+ }
2672
+ for (let key of Object.keys(scheme).filter((key2) => !scheme[key2])) {
2673
+ delete scheme[key];
2674
+ }
2675
+ for (let uri2 of uris) {
2676
+ this._schemeCache[uri2] = scheme;
2677
+ }
2678
+ return scheme;
2679
+ }
2680
+ async _loadConcept({ uri, ...config }) {
2681
+ if (this._conceptCache[uri]) {
2682
+ return this._conceptCache[uri];
2683
+ }
2684
+ try {
2685
+ const data = await this.axios({ ...config, url: `${uri}.json`, _skipAdditionalParameters: true });
2686
+ if (data.id !== uri) {
2687
+ throw new InvalidRequestError({ message: "Skohub URL did not return expected concept URI" });
2688
+ }
2689
+ const concept = this._toJskosConcept(data);
2690
+ this._conceptCache[uri] = concept;
2691
+ return concept;
2692
+ } catch (error) {
2693
+ return null;
2694
+ }
2695
+ }
2696
+ _toJskosConcept(data) {
2697
+ const concept = { uri: data.id };
2698
+ concept.prefLabel = data.prefLabel;
2699
+ Object.keys(concept.prefLabel || {}).forEach((key) => {
2700
+ concept.prefLabel[key] = decodeUnicode(concept.prefLabel[key]);
2701
+ });
2702
+ concept.narrower = (data.narrower || []).map((c) => this._toJskosConcept(c));
2703
+ concept.notation = data.notation || [];
2704
+ if (data.broader && data.broader.id) {
2705
+ concept.broader = [{ uri: data.broader.id }];
2706
+ }
2707
+ if (data.inScheme && data.inScheme.id) {
2708
+ concept.inScheme = [{ uri: data.inScheme.id }];
2709
+ }
2710
+ if (data.scopeNote) {
2711
+ concept.scopeNote = data.scopeNote;
2712
+ Object.keys(concept.scopeNote).forEach((key) => {
2713
+ concept.scopeNote[key] = [decodeUnicode(concept.scopeNote[key])];
2714
+ });
2715
+ }
2716
+ return concept;
2717
+ }
2718
+ async getSchemes({ ...config }) {
2719
+ return Promise.all(this.schemes.map((scheme) => this._loadScheme({ ...config, scheme })));
2720
+ }
2721
+ async getTop({ scheme, ...config }) {
2722
+ if (!scheme || !scheme.uri) {
2723
+ throw new InvalidOrMissingParameterError({ parameter: "scheme", message: "Missing scheme URI" });
2724
+ }
2725
+ scheme = await this._loadScheme({ scheme, ...config });
2726
+ return scheme.topConcepts || [];
2727
+ }
2728
+ async getConcepts({ concepts, ...config }) {
2729
+ if (!import_isArray.default(concepts)) {
2730
+ concepts = [concepts];
2731
+ }
2732
+ return (await Promise.all(concepts.map(({ uri }) => this._loadConcept({ ...config, uri })))).filter(Boolean);
2733
+ }
2734
+ async getAncestors({ concept, ...config }) {
2735
+ if (!concept || !concept.uri) {
2736
+ throw new InvalidOrMissingParameterError({ parameter: "concept" });
2737
+ }
2738
+ if (concept.ancestors && concept.ancestors[0] !== null) {
2739
+ return concept.ancestors;
2740
+ }
2741
+ concept = await this._loadConcept({ ...config, uri: concept.uri });
2742
+ if (!concept || !concept.broader || !concept.broader.length) {
2743
+ return [];
2744
+ }
2745
+ const broader = concept.broader[0];
2746
+ return [broader].concat(await this.getAncestors({ concept: broader, ...config })).map((c) => ({ uri: c.uri }));
2747
+ }
2748
+ async getNarrower({ concept, ...config }) {
2749
+ if (!concept || !concept.uri) {
2750
+ throw new InvalidOrMissingParameterError({ parameter: "concept" });
2751
+ }
2752
+ if (concept.narrower && concept.narrower[0] !== null) {
2753
+ return concept.narrower;
2754
+ }
2755
+ concept = await this._loadConcept({ ...config, uri: concept.uri });
2756
+ return concept.narrower;
2757
+ }
2758
+ async search({ search, scheme, limit = 100 }) {
2759
+ if (!scheme || !scheme.uri) {
2760
+ throw new InvalidOrMissingParameterError({ parameter: "scheme" });
2761
+ }
2762
+ if (!search) {
2763
+ throw new InvalidOrMissingParameterError({ parameter: "search" });
2764
+ }
2765
+ let index;
2766
+ if (!this._index[scheme.uri]) {
2767
+ this._index[scheme.uri] = {};
2768
+ }
2769
+ for (const lang of [""].concat(this.languages)) {
2770
+ if (this._index[scheme.uri][lang]) {
2771
+ index = this._index[scheme.uri][lang];
2772
+ break;
2773
+ }
2774
+ if (this._index[scheme.uri][lang] === null) {
2775
+ continue;
2776
+ }
2777
+ try {
2778
+ let postfix = lang ? `.${lang}.index` : ".index";
2779
+ if (scheme.uri.endsWith("/")) {
2780
+ postfix = `index${postfix}`;
2781
+ }
2782
+ const data = await this.axios({ url: `${scheme.uri}${postfix}`, _skipAdditionalParameters: true });
2783
+ if (data.length < 100) {
2784
+ this._index[scheme.uri][lang] = null;
2785
+ continue;
2786
+ }
2787
+ index = import_flexsearch.default.create();
2788
+ index.import(data);
2789
+ this._index[scheme.uri][lang] = index;
2790
+ break;
2791
+ } catch (error) {
2792
+ this._index[scheme.uri][lang] = null;
2793
+ }
2794
+ }
2795
+ if (!index) {
2796
+ throw new InvalidRequestError({ message: "Could not find search index for any of the available languages " + this.languages.join(",") });
2797
+ }
2798
+ const result = index.search(search);
2799
+ const concepts = await this.getConcepts({ concepts: result.map((uri) => ({ uri })) });
2800
+ return concepts.slice(0, limit);
2801
+ }
2802
+ async suggest(config) {
2803
+ config._raw = true;
2804
+ const concepts = await this.search(config);
2805
+ const result = [config.search, [], [], []];
2806
+ for (let concept of concepts) {
2807
+ const notation = import_jskos_tools10.default.notation(concept);
2808
+ const label = import_jskos_tools10.default.prefLabel(concept);
2809
+ result[1].push((notation ? notation + " " : "") + label);
2810
+ result[2].push("");
2811
+ result[3].push(concept.uri);
2812
+ }
2813
+ if (concepts._totalCount != void 0) {
2814
+ result._totalCount = concepts._totalCount;
2815
+ } else {
2816
+ result._totalCount = concepts.length;
2817
+ }
2818
+ return result;
2819
+ }
2820
+ };
2821
+ SkohubProvider.providerName = "Skohub";
2822
+ SkohubProvider.providerType = "http://bartoc.org/api-type/skohub";
2823
+
2520
2824
  // src/lib/CocodaSDK.js
2521
2825
  var providers = {
2522
2826
  [BaseProvider.providerName]: BaseProvider,
@@ -2629,7 +2933,8 @@ var CocodaSDK = class {
2629
2933
  timer: null,
2630
2934
  result: null,
2631
2935
  error: null,
2632
- isPaused: false
2936
+ isPaused: false,
2937
+ interval
2633
2938
  };
2634
2939
  const handleResult = (result) => {
2635
2940
  const previousResult = repeat.result;
@@ -2649,7 +2954,7 @@ var CocodaSDK = class {
2649
2954
  }
2650
2955
  repeat.timer = setTimeout(() => {
2651
2956
  toCall();
2652
- }, interval);
2957
+ }, repeat.interval);
2653
2958
  };
2654
2959
  const call = () => asyncFunc().then(handleResult).catch(handleError).then(() => repeatIfNecessary(call));
2655
2960
  const setup = (_callImmediately = callImmediately) => {
@@ -2672,7 +2977,7 @@ var CocodaSDK = class {
2672
2977
  } else {
2673
2978
  setTimeout(() => {
2674
2979
  repeat.timer && clearTimeout(repeat.timer);
2675
- }, interval);
2980
+ }, repeat.interval);
2676
2981
  }
2677
2982
  },
2678
2983
  get isPaused() {
@@ -2683,6 +2988,12 @@ var CocodaSDK = class {
2683
2988
  },
2684
2989
  get hasErrored() {
2685
2990
  return !!repeat.error;
2991
+ },
2992
+ get interval() {
2993
+ return repeat.interval;
2994
+ },
2995
+ set interval(value) {
2996
+ repeat.interval = value;
2686
2997
  }
2687
2998
  };
2688
2999
  }
@@ -2692,10 +3003,10 @@ var CocodaSDK = class {
2692
3003
  if (registry.has.schemes !== false) {
2693
3004
  let promise = registry.getSchemes(config).then((results) => {
2694
3005
  for (let scheme of results) {
2695
- const currentSchemeRegistry = scheme._registry;
3006
+ scheme._registry = registry;
2696
3007
  scheme.__DETAILSLOADED__ = 1;
2697
3008
  scheme.type = scheme.type || ["http://www.w3.org/2004/02/skos/core#ConceptScheme"];
2698
- let otherScheme = schemes.find((s) => import_jskos_tools10.default.compare(s, scheme)), prio, otherPrio, override = false;
3009
+ let otherScheme = schemes.find((s) => import_jskos_tools11.default.compare(s, scheme)), prio, otherPrio, override = false;
2699
3010
  if (otherScheme) {
2700
3011
  prio = this.config.registries.indexOf(registry);
2701
3012
  if (prio != -1) {
@@ -2717,19 +3028,19 @@ var CocodaSDK = class {
2717
3028
  }
2718
3029
  if (!otherScheme || override) {
2719
3030
  if (override) {
2720
- let otherSchemeIndex = schemes.findIndex((s) => import_jskos_tools10.default.compare(s, otherScheme));
3031
+ let otherSchemeIndex = schemes.findIndex((s) => import_jskos_tools11.default.compare(s, otherScheme));
2721
3032
  if (otherSchemeIndex != -1) {
2722
3033
  schemes.splice(otherSchemeIndex, 1);
2723
3034
  }
2724
- scheme = import_jskos_tools10.default.merge(scheme, import_omit.default(otherScheme, ["concepts", "topConcepts"]), { mergeUris: true, skipPaths: ["_registry"] });
3035
+ scheme = import_jskos_tools11.default.merge(scheme, import_omit.default(otherScheme, ["concepts", "topConcepts"]), { mergeUris: true, skipPaths: ["_registry"] });
2725
3036
  }
2726
- scheme._registry = currentSchemeRegistry;
3037
+ scheme._registry = registry;
2727
3038
  schemes.push(scheme);
2728
3039
  } else {
2729
- const index = schemes.findIndex((s) => import_jskos_tools10.default.compare(s, scheme));
3040
+ const index = schemes.findIndex((s) => import_jskos_tools11.default.compare(s, scheme));
2730
3041
  if (index != -1) {
2731
3042
  const otherSchemeRegistry = schemes[index]._registry;
2732
- schemes[index] = import_jskos_tools10.default.merge(schemes[index], import_omit.default(scheme, ["concepts", "topConcepts"]), { mergeUris: true, skipPaths: ["_registry"] });
3043
+ schemes[index] = import_jskos_tools11.default.merge(schemes[index], import_omit.default(scheme, ["concepts", "topConcepts"]), { mergeUris: true, skipPaths: ["_registry"] });
2733
3044
  schemes[index]._registry = otherSchemeRegistry;
2734
3045
  }
2735
3046
  }
@@ -2741,7 +3052,17 @@ var CocodaSDK = class {
2741
3052
  }
2742
3053
  }
2743
3054
  await Promise.all(promises);
2744
- return import_jskos_tools10.default.sortSchemes(schemes.filter(Boolean));
3055
+ schemes.forEach((scheme) => {
3056
+ const previousRegistry = scheme._registry;
3057
+ delete scheme._registry;
3058
+ const newRegistry = this.registryForScheme(scheme);
3059
+ if (!newRegistry || newRegistry._api.api === previousRegistry._api.api) {
3060
+ scheme._registry = previousRegistry;
3061
+ } else {
3062
+ scheme._registry = newRegistry;
3063
+ }
3064
+ });
3065
+ return import_jskos_tools11.default.sortSchemes(schemes.filter(Boolean));
2745
3066
  }
2746
3067
  registryForScheme(scheme) {
2747
3068
  let registry = scheme._registry;
@@ -2752,7 +3073,7 @@ var CocodaSDK = class {
2752
3073
  const url = config.url;
2753
3074
  if (registryCache[url]) {
2754
3075
  const registry2 = registryCache[url];
2755
- if (Array.isArray(registry2._jskos.schemes) && !import_jskos_tools10.default.isContainedIn(scheme, registry2._jskos.schemes)) {
3076
+ if (Array.isArray(registry2._jskos.schemes) && !import_jskos_tools11.default.isContainedIn(scheme, registry2._jskos.schemes)) {
2756
3077
  registry2._jskos.schemes.push(scheme);
2757
3078
  }
2758
3079
  return registry2;
@@ -2788,7 +3109,6 @@ var cdk = new CocodaSDK();
2788
3109
  function addAllProviders(_cdk) {
2789
3110
  Object.values(providers_exports).forEach((provider) => (_cdk || cdk).addProvider(provider));
2790
3111
  }
2791
- module.exports = __toCommonJS(src_exports);
2792
3112
  // Annotate the CommonJS export names for ESM import in node:
2793
3113
  0 && (module.exports = {
2794
3114
  BaseProvider,
@@ -2800,6 +3120,7 @@ module.exports = __toCommonJS(src_exports);
2800
3120
  MappingsApiProvider,
2801
3121
  OccurrencesApiProvider,
2802
3122
  ReconciliationApiProvider,
3123
+ SkohubProvider,
2803
3124
  SkosmosApiProvider,
2804
3125
  addAllProviders,
2805
3126
  cdk,