@twin.org/federated-catalogue-service 0.0.2-next.4 → 0.0.2-next.5

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.
@@ -12,8 +12,6 @@ var identityModels = require('@twin.org/identity-models');
12
12
  var crypto = require('@twin.org/crypto');
13
13
  var standardsW3cDid = require('@twin.org/standards-w3c-did');
14
14
 
15
- // Copyright 2024 IOTA Stiftung.
16
- // SPDX-License-Identifier: Apache-2.0.
17
15
  /**
18
16
  * Data Resource Entry.
19
17
  */
@@ -71,6 +69,10 @@ exports.DataResourceEntry = class DataResourceEntry {
71
69
  * Evidences
72
70
  */
73
71
  evidence;
72
+ /**
73
+ * Extended data of a Data Resource entry.
74
+ */
75
+ extraData;
74
76
  };
75
77
  __decorate([
76
78
  entity.property({ type: "string", isPrimary: true }),
@@ -124,12 +126,14 @@ __decorate([
124
126
  entity.property({ type: "array" }),
125
127
  __metadata("design:type", Array)
126
128
  ], exports.DataResourceEntry.prototype, "evidence", void 0);
129
+ __decorate([
130
+ entity.property({ type: "object", optional: true }),
131
+ __metadata("design:type", Object)
132
+ ], exports.DataResourceEntry.prototype, "extraData", void 0);
127
133
  exports.DataResourceEntry = __decorate([
128
134
  entity.entity()
129
135
  ], exports.DataResourceEntry);
130
136
 
131
- // Copyright 2024 IOTA Stiftung.
132
- // SPDX-License-Identifier: Apache-2.0.
133
137
  /**
134
138
  * Data Space Connector Entry.
135
139
  */
@@ -194,6 +198,10 @@ exports.DataSpaceConnectorEntry = class DataSpaceConnectorEntry {
194
198
  * Evidences
195
199
  */
196
200
  evidence;
201
+ /**
202
+ * Extended data of a DS Connector entry.
203
+ */
204
+ extraData;
197
205
  };
198
206
  __decorate([
199
207
  entity.property({ type: "string", isPrimary: true }),
@@ -255,12 +263,14 @@ __decorate([
255
263
  entity.property({ type: "array" }),
256
264
  __metadata("design:type", Array)
257
265
  ], exports.DataSpaceConnectorEntry.prototype, "evidence", void 0);
266
+ __decorate([
267
+ entity.property({ type: "object", optional: true }),
268
+ __metadata("design:type", Object)
269
+ ], exports.DataSpaceConnectorEntry.prototype, "extraData", void 0);
258
270
  exports.DataSpaceConnectorEntry = __decorate([
259
271
  entity.entity()
260
272
  ], exports.DataSpaceConnectorEntry);
261
273
 
262
- // Copyright 2024 IOTA Stiftung.
263
- // SPDX-License-Identifier: Apache-2.0.
264
274
  /**
265
275
  * Participant entry.
266
276
  */
@@ -301,6 +311,10 @@ exports.ParticipantEntry = class ParticipantEntry {
301
311
  * Evidences
302
312
  */
303
313
  evidence;
314
+ /**
315
+ * Extended data of a Participant entry.
316
+ */
317
+ extraData;
304
318
  };
305
319
  __decorate([
306
320
  entity.property({ type: "string", isPrimary: true }),
@@ -338,12 +352,14 @@ __decorate([
338
352
  entity.property({ type: "array" }),
339
353
  __metadata("design:type", Array)
340
354
  ], exports.ParticipantEntry.prototype, "evidence", void 0);
355
+ __decorate([
356
+ entity.property({ type: "object", optional: true }),
357
+ __metadata("design:type", Object)
358
+ ], exports.ParticipantEntry.prototype, "extraData", void 0);
341
359
  exports.ParticipantEntry = __decorate([
342
360
  entity.entity()
343
361
  ], exports.ParticipantEntry);
344
362
 
345
- // Copyright 2024 IOTA Stiftung.
346
- // SPDX-License-Identifier: Apache-2.0.
347
363
  /**
348
364
  * Service Offering Entry.
349
365
  */
@@ -396,6 +412,10 @@ exports.ServiceOfferingEntry = class ServiceOfferingEntry {
396
412
  * Evidences
397
413
  */
398
414
  evidence;
415
+ /**
416
+ * Extended data of a Service Offering entry.
417
+ */
418
+ extraData;
399
419
  };
400
420
  __decorate([
401
421
  entity.property({ type: "string", isPrimary: true }),
@@ -445,6 +465,10 @@ __decorate([
445
465
  entity.property({ type: "array" }),
446
466
  __metadata("design:type", Array)
447
467
  ], exports.ServiceOfferingEntry.prototype, "evidence", void 0);
468
+ __decorate([
469
+ entity.property({ type: "object", optional: true }),
470
+ __metadata("design:type", Object)
471
+ ], exports.ServiceOfferingEntry.prototype, "extraData", void 0);
448
472
  exports.ServiceOfferingEntry = __decorate([
449
473
  entity.entity()
450
474
  ], exports.ServiceOfferingEntry);
@@ -1047,7 +1071,7 @@ async function complianceCredentialPresentation(baseRouteName, httpRequestContex
1047
1071
  */
1048
1072
  async function participantList(httpRequestContext, factoryServiceName, request) {
1049
1073
  const service = core.ComponentFactory.get(factoryServiceName);
1050
- const itemsAndCursor = await service.queryParticipants(request?.query?.id, request?.query?.registrationNumber, request?.query?.lrnType, request?.query?.cursor, core.Coerce.integer(request?.query?.pageSize));
1074
+ const itemsAndCursor = await service.queryParticipants(request?.query?.id, request?.query?.registrationNumber, request?.query?.lrnType, request?.query?.cursor, core.Coerce.integer(request?.query?.limit));
1051
1075
  return {
1052
1076
  body: itemsAndCursor
1053
1077
  };
@@ -1101,7 +1125,7 @@ async function serviceOfferingCredentialPresentation(baseRouteName, httpRequestC
1101
1125
  */
1102
1126
  async function serviceOfferingList(httpRequestContext, factoryServiceName, request) {
1103
1127
  const service = core.ComponentFactory.get(factoryServiceName);
1104
- const itemsAndCursor = await service.queryServiceOfferings(request?.query?.id, request?.query?.providedBy, request?.query?.cursor, core.Coerce.integer(request?.query?.pageSize));
1128
+ const itemsAndCursor = await service.queryServiceOfferings(request?.query?.id, request?.query?.providedBy, request?.query?.cursor, core.Coerce.integer(request?.query?.limit));
1105
1129
  return {
1106
1130
  body: itemsAndCursor
1107
1131
  };
@@ -1155,7 +1179,7 @@ async function dataResourceCredentialPresentation(baseRouteName, httpRequestCont
1155
1179
  */
1156
1180
  async function dataResourceList(httpRequestContext, factoryServiceName, request) {
1157
1181
  const service = core.ComponentFactory.get(factoryServiceName);
1158
- const itemsAndCursor = await service.queryDataResources(request?.query?.id, request?.query?.producedBy, request?.query?.cursor, core.Coerce.integer(request?.query?.pageSize));
1182
+ const itemsAndCursor = await service.queryDataResources(request?.query?.id, request?.query?.producedBy, request?.query?.cursor, core.Coerce.integer(request?.query?.limit));
1159
1183
  return {
1160
1184
  body: itemsAndCursor
1161
1185
  };
@@ -1206,7 +1230,7 @@ async function dataSpaceConnectorCredentialPresentation(baseRouteName, httpReque
1206
1230
  */
1207
1231
  async function dataSpaceConnectorList(httpRequestContext, factoryServiceName, request) {
1208
1232
  const service = core.ComponentFactory.get(factoryServiceName);
1209
- const itemsAndCursor = await service.queryDataSpaceConnectors(request?.query?.id, request?.query?.maintainedBy, request?.query?.cursor, core.Coerce.integer(request?.query?.pageSize));
1233
+ const itemsAndCursor = await service.queryDataSpaceConnectors(request?.query?.id, request?.query?.maintainedBy, request?.query?.cursor, core.Coerce.integer(request?.query?.limit));
1210
1234
  return {
1211
1235
  body: itemsAndCursor
1212
1236
  };
@@ -1234,9 +1258,9 @@ async function dataSpaceConnectorGet(httpRequestContext, factoryServiceName, req
1234
1258
  */
1235
1259
  class ComplianceCredentialVerificationService {
1236
1260
  /**
1237
- * Class name
1261
+ * Runtime name for the class.
1238
1262
  */
1239
- CLASS_NAME = "ComplianceCredentialVerificationService";
1263
+ static CLASS_NAME = "ComplianceCredentialVerificationService";
1240
1264
  /**
1241
1265
  * Resolver component.
1242
1266
  * @internal
@@ -1367,10 +1391,10 @@ class ComplianceCredentialVerificationService {
1367
1391
  */
1368
1392
  async verifyEvidence(evidence) {
1369
1393
  // The credential associated to the evidence has to be retrieved, then verified
1370
- core.Guards.object(this.CLASS_NAME, "IComplianceEvidence", evidence);
1394
+ core.Guards.object(ComplianceCredentialVerificationService.CLASS_NAME, "IComplianceEvidence", evidence);
1371
1395
  const credentialUrl = evidence.id;
1372
1396
  this._logger?.log({
1373
- source: this.CLASS_NAME,
1397
+ source: ComplianceCredentialVerificationService.CLASS_NAME,
1374
1398
  level: "info",
1375
1399
  message: "verifyingEvidenceCredential",
1376
1400
  ts: Date.now(),
@@ -1378,10 +1402,10 @@ class ComplianceCredentialVerificationService {
1378
1402
  credentialUrl
1379
1403
  }
1380
1404
  });
1381
- const credentialResponse = await web.FetchHelper.fetch(this.CLASS_NAME, credentialUrl, "GET", undefined, { cacheTtlMs: this._subResourceCacheTtlMs });
1405
+ const credentialResponse = await web.FetchHelper.fetch(ComplianceCredentialVerificationService.CLASS_NAME, credentialUrl, "GET", undefined, { cacheTtlMs: this._subResourceCacheTtlMs });
1382
1406
  if (!credentialResponse.ok) {
1383
1407
  this._logger?.log({
1384
- source: this.CLASS_NAME,
1408
+ source: ComplianceCredentialVerificationService.CLASS_NAME,
1385
1409
  level: "error",
1386
1410
  message: "credentialCannotBeRetrieved",
1387
1411
  ts: Date.now(),
@@ -1412,7 +1436,7 @@ class ComplianceCredentialVerificationService {
1412
1436
  hashToCheck = core.Converter.bytesToBase64(crypto.Sha512.sum512(core.Converter.utf8ToBytes(canonicalized)));
1413
1437
  }
1414
1438
  else {
1415
- throw new core.UnprocessableError(this.CLASS_NAME, "unknownHashingAlgorithm", { hashingAlg });
1439
+ throw new core.UnprocessableError(ComplianceCredentialVerificationService.CLASS_NAME, "unknownHashingAlgorithm", { hashingAlg });
1416
1440
  }
1417
1441
  if (hashToCheck !== hash) {
1418
1442
  return {
@@ -1422,7 +1446,7 @@ class ComplianceCredentialVerificationService {
1422
1446
  }
1423
1447
  const { id } = identityModels.DocumentHelper.parseId(proof.verificationMethod);
1424
1448
  const documentId = theCredential.issuer ?? id;
1425
- core.Guards.stringValue(this.CLASS_NAME, "documentId", documentId);
1449
+ core.Guards.stringValue(ComplianceCredentialVerificationService.CLASS_NAME, "documentId", documentId);
1426
1450
  let verified = false;
1427
1451
  try {
1428
1452
  const document = await this._resolver.identityResolve(documentId);
@@ -1431,7 +1455,7 @@ class ComplianceCredentialVerificationService {
1431
1455
  }
1432
1456
  catch (error) {
1433
1457
  this._logger?.log({
1434
- source: this.CLASS_NAME,
1458
+ source: ComplianceCredentialVerificationService.CLASS_NAME,
1435
1459
  level: "error",
1436
1460
  message: "credentialVerificationError",
1437
1461
  ts: Date.now(),
@@ -1446,7 +1470,7 @@ class ComplianceCredentialVerificationService {
1446
1470
  };
1447
1471
  }
1448
1472
  this._logger?.log({
1449
- source: this.CLASS_NAME,
1473
+ source: ComplianceCredentialVerificationService.CLASS_NAME,
1450
1474
  level: "info",
1451
1475
  message: "credentialEvidenceVerified",
1452
1476
  ts: Date.now(),
@@ -1467,15 +1491,15 @@ class ComplianceCredentialVerificationService {
1467
1491
  * Service for performing logging operations to a connector.
1468
1492
  */
1469
1493
  class FederatedCatalogueService {
1494
+ /**
1495
+ * Runtime name for the class.
1496
+ */
1497
+ static CLASS_NAME = "FederatedCatalogueService";
1470
1498
  /**
1471
1499
  * Fields to skip when persisting entries to the Catalogue
1472
1500
  * @internal
1473
1501
  */
1474
1502
  static _FIELDS_TO_SKIP = ["@context", "type"];
1475
- /**
1476
- * Runtime name for the class.
1477
- */
1478
- CLASS_NAME = "FederatedCatalogueService";
1479
1503
  /**
1480
1504
  * The identity resolver used to dereference DIDs.
1481
1505
  * @internal
@@ -1531,32 +1555,34 @@ class FederatedCatalogueService {
1531
1555
  * @returns The Id of the Participant (DID usually).
1532
1556
  */
1533
1557
  async registerComplianceCredential(credentialJwt) {
1534
- core.Guards.string(this.CLASS_NAME, "credentialJwt", credentialJwt);
1558
+ core.Guards.string(FederatedCatalogueService.CLASS_NAME, "credentialJwt", credentialJwt);
1535
1559
  // This will raise exceptions as it has been coded reusing code from Gaia-X
1536
1560
  const complianceCredential = await this.decodeJwt(credentialJwt);
1537
1561
  const result = await this._complianceCredentialVerifier.verify(complianceCredential);
1538
1562
  if (!result.verified) {
1539
1563
  this._logging?.log({
1540
1564
  level: "error",
1541
- source: this.CLASS_NAME,
1565
+ source: FederatedCatalogueService.CLASS_NAME,
1542
1566
  ts: Date.now(),
1543
1567
  message: "complianceCredentialNotVerified",
1544
1568
  data: { result }
1545
1569
  });
1546
- throw new core.UnprocessableError(this.CLASS_NAME, "complianceCredentialNotVerified", {
1570
+ throw new core.UnprocessableError(FederatedCatalogueService.CLASS_NAME, "complianceCredentialNotVerified", {
1547
1571
  reason: result.verificationFailureReason
1548
1572
  });
1549
1573
  }
1550
1574
  const targetCredential = result.credentials.find(credential => credential.credentialSubject.type === standardsGaiaX.GaiaXTypes.LegalPerson);
1551
1575
  if (core.Is.undefined(targetCredential)) {
1552
- throw new core.UnprocessableError(this.CLASS_NAME, "noEvidence");
1576
+ throw new core.UnprocessableError(FederatedCatalogueService.CLASS_NAME, "noEvidence");
1553
1577
  }
1554
- const participantEntry = this.extractParticipantEntry(complianceCredential, targetCredential);
1578
+ const { participantEntry, extraData } = this.extractParticipantEntry(complianceCredential, targetCredential);
1555
1579
  const theEntry = core.ObjectHelper.omit(participantEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
1556
- await this._entityStorageParticipants.set(theEntry);
1580
+ const extended = theEntry;
1581
+ extended.extraData = extraData;
1582
+ await this._entityStorageParticipants.set(extended);
1557
1583
  await this._logging?.log({
1558
1584
  level: "info",
1559
- source: this.CLASS_NAME,
1585
+ source: FederatedCatalogueService.CLASS_NAME,
1560
1586
  ts: Date.now(),
1561
1587
  message: "complianceCredentialVerified",
1562
1588
  data: {
@@ -1571,13 +1597,13 @@ class FederatedCatalogueService {
1571
1597
  * @param id The identity of the participant.
1572
1598
  * @param legalRegistrationNumber The legal registration number.
1573
1599
  * @param lrnType The legal registration number type (EORI, VATID, GLEIF, KENYA_PIN, etc.)
1574
- * @param cursor The cursor to request the next page of entities.
1575
- * @param pageSize The maximum number of entities in a page.
1600
+ * @param cursor The cursor to request the next chunk of entities.
1601
+ * @param limit Limit the number of entities to return.
1576
1602
  * @returns All the entities for the storage matching the conditions,
1577
1603
  * and a cursor which can be used to request more entities.
1578
1604
  * @throws NotImplementedError if the implementation does not support retrieval.
1579
1605
  */
1580
- async queryParticipants(id, legalRegistrationNumber, lrnType, cursor, pageSize) {
1606
+ async queryParticipants(id, legalRegistrationNumber, lrnType, cursor, limit) {
1581
1607
  const conditions = [];
1582
1608
  if (core.Is.stringValue(id)) {
1583
1609
  const condition = {
@@ -1603,15 +1629,16 @@ class FederatedCatalogueService {
1603
1629
  };
1604
1630
  conditions.push(condition);
1605
1631
  }
1606
- const entries = await this._entityStorageParticipants.query({ conditions }, undefined, undefined, cursor, pageSize);
1632
+ const entries = await this._entityStorageParticipants.query({ conditions }, undefined, undefined, cursor, limit);
1607
1633
  const itemList = entries.entities.map(entry => {
1608
1634
  entry.type = standardsGaiaX.GaiaXTypes.LegalPerson;
1609
1635
  return entry;
1610
1636
  });
1637
+ const { finalItemList, extraDataLdContext } = this.normalizeExtraData(itemList);
1611
1638
  const result = {
1612
- "@context": federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
1639
+ "@context": dataJsonLd.JsonLdProcessor.combineContexts(federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST, extraDataLdContext),
1613
1640
  type: standardsSchemaOrg.SchemaOrgTypes.ItemList,
1614
- itemListElement: itemList,
1641
+ itemListElement: finalItemList,
1615
1642
  nextItem: entries.cursor
1616
1643
  };
1617
1644
  return dataJsonLd.JsonLdProcessor.compact(result, result["@context"]);
@@ -1624,7 +1651,7 @@ class FederatedCatalogueService {
1624
1651
  * @throws NotFoundError if not found.
1625
1652
  */
1626
1653
  async getEntry(entryType, entryId) {
1627
- core.Guards.stringValue(this.CLASS_NAME, "entryId", entryId);
1654
+ core.Guards.stringValue(FederatedCatalogueService.CLASS_NAME, "entryId", entryId);
1628
1655
  let itemsAndCursor;
1629
1656
  switch (entryType) {
1630
1657
  case standardsGaiaX.GaiaXTypes.LegalPerson:
@@ -1641,17 +1668,19 @@ class FederatedCatalogueService {
1641
1668
  itemsAndCursor = await this.queryDataResources(entryId);
1642
1669
  break;
1643
1670
  default:
1644
- throw new core.GeneralError(this.CLASS_NAME, "unknownEntryType", { entryType });
1671
+ throw new core.GeneralError(FederatedCatalogueService.CLASS_NAME, "unknownEntryType", {
1672
+ entryType
1673
+ });
1645
1674
  }
1646
1675
  if (core.Is.arrayValue(itemsAndCursor?.itemListElement)) {
1647
1676
  const entry = {
1648
1677
  ...itemsAndCursor.itemListElement[0],
1649
- "@context": federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY
1678
+ "@context": dataJsonLd.JsonLdProcessor.combineContexts(federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY, itemsAndCursor["@context"])
1650
1679
  };
1651
1680
  const result = await dataJsonLd.JsonLdProcessor.compact(entry, entry["@context"]);
1652
1681
  return result;
1653
1682
  }
1654
- throw new core.NotFoundError(this.CLASS_NAME, "entryNotFound", entryId);
1683
+ throw new core.NotFoundError(FederatedCatalogueService.CLASS_NAME, "entryNotFound", entryId);
1655
1684
  }
1656
1685
  /**
1657
1686
  * Registers a compliance Credential concerning a Data Space Connector.
@@ -1659,19 +1688,19 @@ class FederatedCatalogueService {
1659
1688
  * @returns The identifier of the Data Space Connector registered.
1660
1689
  */
1661
1690
  async registerDataSpaceConnectorCredential(credentialJwt) {
1662
- core.Guards.string(this.CLASS_NAME, "credentialJwt", credentialJwt);
1691
+ core.Guards.string(FederatedCatalogueService.CLASS_NAME, "credentialJwt", credentialJwt);
1663
1692
  // This will raise exceptions as it has been coded reusing code from Gaia-X
1664
1693
  const complianceCredential = await this.decodeJwt(credentialJwt);
1665
1694
  const result = await this._complianceCredentialVerifier.verify(complianceCredential);
1666
1695
  if (!result.verified) {
1667
1696
  this._logging?.log({
1668
1697
  level: "error",
1669
- source: this.CLASS_NAME,
1698
+ source: FederatedCatalogueService.CLASS_NAME,
1670
1699
  ts: Date.now(),
1671
1700
  message: "complianceCredentialNotVerified",
1672
1701
  data: { result }
1673
1702
  });
1674
- throw new core.UnprocessableError(this.CLASS_NAME, "complianceCredentialNotVerified", {
1703
+ throw new core.UnprocessableError(FederatedCatalogueService.CLASS_NAME, "complianceCredentialNotVerified", {
1675
1704
  reason: result.verificationFailureReason
1676
1705
  });
1677
1706
  }
@@ -1683,21 +1712,25 @@ class FederatedCatalogueService {
1683
1712
  });
1684
1713
  const dataResourceCredentials = result.credentials.filter(credential => credential.credentialSubject.type === standardsGaiaX.GaiaXTypes.DataResource);
1685
1714
  if (core.Is.undefined(targetCredential)) {
1686
- throw new core.UnprocessableError(this.CLASS_NAME, "noEvidence");
1715
+ throw new core.UnprocessableError(FederatedCatalogueService.CLASS_NAME, "noEvidence");
1687
1716
  }
1688
1717
  await this.checkParticipantExists(targetCredential.issuer);
1689
- const dataSpaceConnectorEntry = this.extractDataSpaceConnectorEntry(complianceCredential, result.credentials[0]);
1718
+ const { dataSpaceConnectorEntry, extraData } = this.extractDataSpaceConnectorEntry(complianceCredential, result.credentials[0]);
1690
1719
  const theEntry = core.ObjectHelper.omit(dataSpaceConnectorEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
1691
- await this._entityStorageDataSpaceConnectors.set(theEntry);
1720
+ const extended = theEntry;
1721
+ extended.extraData = extraData;
1722
+ await this._entityStorageDataSpaceConnectors.set(extended);
1692
1723
  for (const dataResourceCredential of dataResourceCredentials) {
1693
1724
  await this.checkParticipantExists(dataResourceCredential.issuer);
1694
- const dataResourceEntry = this.extractDataResourceEntry(complianceCredential, dataResourceCredential);
1695
- const drEntry = core.ObjectHelper.omit(dataResourceEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
1696
- await this._entityStorageDataResources.set(drEntry);
1725
+ const { dataResourceEntry, extraData: extraDataResourceData } = this.extractDataResourceEntry(complianceCredential, dataResourceCredential);
1726
+ const finalDataResourceEntry = core.ObjectHelper.omit(dataResourceEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
1727
+ const extendedDataResourceEntry = finalDataResourceEntry;
1728
+ extendedDataResourceEntry.extraData = extraDataResourceData;
1729
+ await this._entityStorageDataResources.set(extendedDataResourceEntry);
1697
1730
  }
1698
1731
  await this._logging?.log({
1699
1732
  level: "info",
1700
- source: this.CLASS_NAME,
1733
+ source: FederatedCatalogueService.CLASS_NAME,
1701
1734
  ts: Date.now(),
1702
1735
  message: "complianceCredentialVerified",
1703
1736
  data: {
@@ -1713,36 +1746,38 @@ class FederatedCatalogueService {
1713
1746
  * @returns The list of Data Resources created.
1714
1747
  */
1715
1748
  async registerDataResourceCredential(credentialJwt) {
1716
- core.Guards.string(this.CLASS_NAME, "credentialJwt", credentialJwt);
1749
+ core.Guards.string(FederatedCatalogueService.CLASS_NAME, "credentialJwt", credentialJwt);
1717
1750
  const complianceCredential = await this.decodeJwt(credentialJwt);
1718
1751
  const result = await this._complianceCredentialVerifier.verify(complianceCredential);
1719
1752
  if (!result.verified) {
1720
1753
  this._logging?.log({
1721
1754
  level: "error",
1722
- source: this.CLASS_NAME,
1755
+ source: FederatedCatalogueService.CLASS_NAME,
1723
1756
  ts: Date.now(),
1724
1757
  message: "complianceCredentialNotVerified",
1725
1758
  data: { result }
1726
1759
  });
1727
- throw new core.UnprocessableError(this.CLASS_NAME, "complianceCredentialNotVerified", {
1760
+ throw new core.UnprocessableError(FederatedCatalogueService.CLASS_NAME, "complianceCredentialNotVerified", {
1728
1761
  reason: result.verificationFailureReason
1729
1762
  });
1730
1763
  }
1731
1764
  const dataResourceCredentials = result.credentials.filter(credential => credential.credentialSubject.type === standardsGaiaX.GaiaXTypes.DataResource);
1732
1765
  if (dataResourceCredentials.length === 0) {
1733
- throw new core.UnprocessableError(this.CLASS_NAME, "noEvidence");
1766
+ throw new core.UnprocessableError(FederatedCatalogueService.CLASS_NAME, "noEvidence");
1734
1767
  }
1735
1768
  const dataResourceIds = [];
1736
1769
  for (const dataResourceCredential of dataResourceCredentials) {
1737
1770
  await this.checkParticipantExists(dataResourceCredential.issuer);
1738
- const dataResourceEntry = this.extractDataResourceEntry(complianceCredential, dataResourceCredential);
1771
+ const { dataResourceEntry, extraData } = this.extractDataResourceEntry(complianceCredential, dataResourceCredential);
1739
1772
  const theEntry = core.ObjectHelper.omit(dataResourceEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
1740
- await this._entityStorageDataResources.set(theEntry);
1773
+ const extended = theEntry;
1774
+ extended.extraData = extraData;
1775
+ await this._entityStorageDataResources.set(extended);
1741
1776
  dataResourceIds.push(dataResourceEntry.id);
1742
1777
  }
1743
1778
  await this._logging?.log({
1744
1779
  level: "info",
1745
- source: this.CLASS_NAME,
1780
+ source: FederatedCatalogueService.CLASS_NAME,
1746
1781
  ts: Date.now(),
1747
1782
  message: "complianceCredentialVerified",
1748
1783
  data: {
@@ -1756,13 +1791,13 @@ class FederatedCatalogueService {
1756
1791
  * Query the federated catalogue.
1757
1792
  * @param id The identity of the participant.
1758
1793
  * @param maintainer The DS Connector maintainer.
1759
- * @param cursor The cursor to request the next page of entities.
1760
- * @param pageSize The maximum number of entities in a page.
1794
+ * @param cursor The cursor to request the next chunk of entities.
1795
+ * @param limit Limit the number of entities to return.
1761
1796
  * @returns All the entities for the storage matching the conditions,
1762
1797
  * and a cursor which can be used to request more entities.
1763
1798
  * @throws NotImplementedError if the implementation does not support retrieval.
1764
1799
  */
1765
- async queryDataSpaceConnectors(id, maintainer, cursor, pageSize) {
1800
+ async queryDataSpaceConnectors(id, maintainer, cursor, limit) {
1766
1801
  const conditions = [];
1767
1802
  if (core.Is.stringValue(id)) {
1768
1803
  const condition = {
@@ -1780,7 +1815,7 @@ class FederatedCatalogueService {
1780
1815
  };
1781
1816
  conditions.push(condition);
1782
1817
  }
1783
- const entries = await this._entityStorageDataSpaceConnectors.query({ conditions }, undefined, undefined, cursor, pageSize);
1818
+ const entries = await this._entityStorageDataSpaceConnectors.query({ conditions }, undefined, undefined, cursor, limit);
1784
1819
  const itemList = entries.entities.map(entry => {
1785
1820
  entry.type = [
1786
1821
  standardsGaiaX.GaiaXTypes.DataExchangeComponent,
@@ -1788,10 +1823,11 @@ class FederatedCatalogueService {
1788
1823
  ];
1789
1824
  return entry;
1790
1825
  });
1826
+ const { finalItemList, extraDataLdContext } = this.normalizeExtraData(itemList);
1791
1827
  const result = {
1792
- "@context": federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
1828
+ "@context": dataJsonLd.JsonLdProcessor.combineContexts(federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST, extraDataLdContext),
1793
1829
  type: standardsSchemaOrg.SchemaOrgTypes.ItemList,
1794
- itemListElement: itemList,
1830
+ itemListElement: finalItemList,
1795
1831
  nextItem: entries.cursor
1796
1832
  };
1797
1833
  return dataJsonLd.JsonLdProcessor.compact(result, result["@context"]);
@@ -1802,44 +1838,48 @@ class FederatedCatalogueService {
1802
1838
  * @returns Nothing.
1803
1839
  */
1804
1840
  async registerServiceOfferingCredential(credentialJwt) {
1805
- core.Guards.string(this.CLASS_NAME, "credentialJwt", credentialJwt);
1841
+ core.Guards.string(FederatedCatalogueService.CLASS_NAME, "credentialJwt", credentialJwt);
1806
1842
  // This will raise exceptions as it has been coded reusing code from Gaia-X
1807
1843
  const sdComplianceCredential = await this.decodeJwt(credentialJwt);
1808
1844
  const result = await this._complianceCredentialVerifier.verify(sdComplianceCredential);
1809
1845
  if (!result.verified) {
1810
1846
  this._logging?.log({
1811
1847
  level: "error",
1812
- source: this.CLASS_NAME,
1848
+ source: FederatedCatalogueService.CLASS_NAME,
1813
1849
  ts: Date.now(),
1814
1850
  message: "complianceCredentialNotVerified",
1815
1851
  data: { result }
1816
1852
  });
1817
- throw new core.UnprocessableError(this.CLASS_NAME, "complianceCredentialNotVerified", {
1853
+ throw new core.UnprocessableError(FederatedCatalogueService.CLASS_NAME, "complianceCredentialNotVerified", {
1818
1854
  reason: result.verificationFailureReason
1819
1855
  });
1820
1856
  }
1821
1857
  const serviceOfferingCredentials = result.credentials.filter(credential => credential.credentialSubject.type === standardsGaiaX.GaiaXTypes.ServiceOffering);
1822
1858
  const dataResourceCredentials = result.credentials.filter(credential => credential.credentialSubject.type === standardsGaiaX.GaiaXTypes.DataResource);
1823
1859
  if (serviceOfferingCredentials.length === 0) {
1824
- throw new core.UnprocessableError(this.CLASS_NAME, "noEvidence");
1860
+ throw new core.UnprocessableError(FederatedCatalogueService.CLASS_NAME, "noEvidence");
1825
1861
  }
1826
1862
  const serviceOfferingIds = [];
1827
1863
  for (const serviceOfferingCredential of serviceOfferingCredentials) {
1828
1864
  const serviceIssuer = serviceOfferingCredential.issuer;
1829
1865
  await this.checkParticipantExists(serviceIssuer);
1830
- const serviceOfferingEntry = this.extractServiceOfferingEntry(sdComplianceCredential, serviceOfferingCredential);
1866
+ const { serviceOfferingEntry, extraData } = this.extractServiceOfferingEntry(sdComplianceCredential, serviceOfferingCredential);
1831
1867
  const theEntry = core.ObjectHelper.omit(serviceOfferingEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
1832
- await this._entityStorageServiceOfferings.set(theEntry);
1868
+ const extended = theEntry;
1869
+ extended.extraData = extraData;
1870
+ await this._entityStorageServiceOfferings.set(extended);
1833
1871
  serviceOfferingIds.push(serviceOfferingEntry.id);
1834
1872
  }
1835
1873
  for (const dataResourceCredential of dataResourceCredentials) {
1836
1874
  await this.checkParticipantExists(dataResourceCredential.issuer);
1837
- const dataResourceEntry = this.extractDataResourceEntry(sdComplianceCredential, dataResourceCredential);
1838
- await this._entityStorageDataResources.set(dataResourceEntry);
1875
+ const { dataResourceEntry, extraData } = this.extractDataResourceEntry(sdComplianceCredential, dataResourceCredential);
1876
+ const extended = core.ObjectHelper.omit(dataResourceEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
1877
+ extended.extraData = extraData;
1878
+ await this._entityStorageDataResources.set(extended);
1839
1879
  }
1840
1880
  await this._logging?.log({
1841
1881
  level: "info",
1842
- source: this.CLASS_NAME,
1882
+ source: FederatedCatalogueService.CLASS_NAME,
1843
1883
  ts: Date.now(),
1844
1884
  message: "complianceCredentialVerified",
1845
1885
  data: {
@@ -1853,13 +1893,13 @@ class FederatedCatalogueService {
1853
1893
  * Query the federated catalogue.
1854
1894
  * @param id Service Id.
1855
1895
  * @param providedBy The identity of the participant.
1856
- * @param cursor The cursor to request the next page of entities.
1857
- * @param pageSize The maximum number of entities in a page.
1896
+ * @param cursor The cursor to request the next chunk of entities.
1897
+ * @param limit Limit the number of entities to return.
1858
1898
  * @returns All the entities for the storage matching the conditions,
1859
1899
  * and a cursor which can be used to request more entities.
1860
1900
  * @throws NotImplementedError if the implementation does not support retrieval.
1861
1901
  */
1862
- async queryServiceOfferings(id, providedBy, cursor, pageSize) {
1902
+ async queryServiceOfferings(id, providedBy, cursor, limit) {
1863
1903
  const conditions = [];
1864
1904
  if (core.Is.stringValue(providedBy)) {
1865
1905
  const condition = {
@@ -1877,15 +1917,16 @@ class FederatedCatalogueService {
1877
1917
  };
1878
1918
  conditions.push(condition);
1879
1919
  }
1880
- const entries = await this._entityStorageServiceOfferings.query({ conditions }, undefined, undefined, cursor, pageSize);
1920
+ const entries = await this._entityStorageServiceOfferings.query({ conditions }, undefined, undefined, cursor, limit);
1881
1921
  const itemList = entries.entities.map(entry => {
1882
1922
  entry.type = standardsGaiaX.GaiaXTypes.ServiceOffering;
1883
1923
  return entry;
1884
1924
  });
1925
+ const { finalItemList, extraDataLdContext } = this.normalizeExtraData(itemList);
1885
1926
  const result = {
1886
- "@context": federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
1927
+ "@context": dataJsonLd.JsonLdProcessor.combineContexts(federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST, extraDataLdContext),
1887
1928
  type: standardsSchemaOrg.SchemaOrgTypes.ItemList,
1888
- itemListElement: itemList,
1929
+ itemListElement: finalItemList,
1889
1930
  nextItem: entries.cursor
1890
1931
  };
1891
1932
  return dataJsonLd.JsonLdProcessor.compact(result, result["@context"]);
@@ -1894,13 +1935,13 @@ class FederatedCatalogueService {
1894
1935
  * Query the federated catalogue.
1895
1936
  * @param id The identity of the DataResource.
1896
1937
  * @param producedBy The identity of the participant.
1897
- * @param cursor The cursor to request the next page of entities.
1898
- * @param pageSize The maximum number of entities in a page.
1938
+ * @param cursor The cursor to request the next chunk of entities.
1939
+ * @param limit Limit the number of entities to return.
1899
1940
  * @returns All the entities for the storage matching the conditions,
1900
1941
  * and a cursor which can be used to request more entities.
1901
1942
  * @throws NotImplementedError if the implementation does not support retrieval.
1902
1943
  */
1903
- async queryDataResources(id, producedBy, cursor, pageSize) {
1944
+ async queryDataResources(id, producedBy, cursor, limit) {
1904
1945
  const conditions = [];
1905
1946
  if (core.Is.stringValue(producedBy)) {
1906
1947
  const condition = {
@@ -1918,23 +1959,44 @@ class FederatedCatalogueService {
1918
1959
  };
1919
1960
  conditions.push(condition);
1920
1961
  }
1921
- const entries = await this._entityStorageDataResources.query({ conditions }, undefined, undefined, cursor, pageSize);
1962
+ const entries = await this._entityStorageDataResources.query({ conditions }, undefined, undefined, cursor, limit);
1922
1963
  const itemList = entries.entities.map(entry => {
1923
1964
  entry.type = standardsGaiaX.GaiaXTypes.DataResource;
1924
1965
  return entry;
1925
1966
  });
1967
+ const { finalItemList, extraDataLdContext } = this.normalizeExtraData(itemList);
1926
1968
  const result = {
1927
- "@context": federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
1969
+ "@context": dataJsonLd.JsonLdProcessor.combineContexts(federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST, extraDataLdContext),
1928
1970
  type: standardsSchemaOrg.SchemaOrgTypes.ItemList,
1929
- itemListElement: itemList,
1971
+ itemListElement: finalItemList,
1930
1972
  nextItem: entries.cursor
1931
1973
  };
1932
1974
  return dataJsonLd.JsonLdProcessor.compact(result, result["@context"]);
1933
1975
  }
1976
+ /**
1977
+ * Normalizes the extra data adding it to each entry.
1978
+ * @param itemList The item list.
1979
+ * @returns the final item list plus the additional LD Context
1980
+ * @internal
1981
+ */
1982
+ normalizeExtraData(itemList) {
1983
+ let extraDataLdContext;
1984
+ const finalItemList = itemList.map(entry => {
1985
+ const extraData = core.ObjectHelper.extractProperty(entry, "extraData", true);
1986
+ if (!core.Is.undefined(extraData?.["@context"])) {
1987
+ const ldContext = extraData["@context"];
1988
+ extraDataLdContext = dataJsonLd.JsonLdProcessor.combineContexts(extraDataLdContext, ldContext);
1989
+ return core.ObjectHelper.merge(entry, extraData);
1990
+ }
1991
+ return entry;
1992
+ });
1993
+ return { finalItemList, extraDataLdContext };
1994
+ }
1934
1995
  /**
1935
1996
  * Decodes the JWT.
1936
1997
  * @param jwt JWT.
1937
1998
  * @returns Decoded.
1999
+ * @internal
1938
2000
  */
1939
2001
  async decodeJwt(jwt) {
1940
2002
  const { payload } = await identityModels.VerificationHelper.verifyJwt(this._resolver, jwt);
@@ -1944,6 +2006,7 @@ class FederatedCatalogueService {
1944
2006
  * Returns the trusted Issuer id.
1945
2007
  * @param complianceCredential The compliance credential.
1946
2008
  * @returns The trusted issuer.
2009
+ * @internal
1947
2010
  */
1948
2011
  getTrustedIssuerId(complianceCredential) {
1949
2012
  const trustedIssuerId = core.Is.object(complianceCredential.issuer)
@@ -1956,16 +2019,18 @@ class FederatedCatalogueService {
1956
2019
  * @param complianceCredential Compliance credential
1957
2020
  * @param participantCredential The Participant credential extracted.
1958
2021
  * @returns Participant Entry to be saved on the Database.
2022
+ * @internal
1959
2023
  */
1960
2024
  extractParticipantEntry(complianceCredential, participantCredential) {
1961
2025
  const participantData = participantCredential.credentialSubject;
1962
- core.Guards.objectValue(this.CLASS_NAME, "participantData", participantData);
2026
+ core.Guards.objectValue(FederatedCatalogueService.CLASS_NAME, "participantData", participantData);
1963
2027
  const evidences = [];
1964
2028
  for (const evidence of complianceCredential.evidence) {
1965
2029
  evidences.push(evidence.id);
1966
2030
  }
2031
+ const { data, extraData } = this.extractExtraData(participantData, entity.EntitySchemaFactory.get("ParticipantEntry"));
1967
2032
  const result = {
1968
- ...participantData,
2033
+ ...data,
1969
2034
  "@context": federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
1970
2035
  issuer: this.getTrustedIssuerId(complianceCredential),
1971
2036
  validFrom: complianceCredential.validFrom,
@@ -1973,18 +2038,20 @@ class FederatedCatalogueService {
1973
2038
  dateCreated: new Date().toISOString(),
1974
2039
  evidence: evidences
1975
2040
  };
1976
- return result;
2041
+ return { participantEntry: result, extraData };
1977
2042
  }
1978
2043
  /**
1979
2044
  * Extracts Data Space Connector description entry from the credentials.
1980
2045
  * @param complianceCredential Compliance Credential.
1981
2046
  * @param dataSpaceConnectorCredential Evidence Credential.
1982
2047
  * @returns Service Description Entry to be saved on the Database.
2048
+ * @internal
1983
2049
  */
1984
2050
  extractDataSpaceConnectorEntry(complianceCredential, dataSpaceConnectorCredential) {
1985
2051
  const credentialData = dataSpaceConnectorCredential.credentialSubject;
1986
- core.Guards.objectValue(this.CLASS_NAME, "credentialData", credentialData);
1987
- const { offeredResource, ...deStructuredData } = credentialData;
2052
+ core.Guards.objectValue(FederatedCatalogueService.CLASS_NAME, "credentialData", credentialData);
2053
+ const { extraData, data } = this.extractExtraData(credentialData, entity.EntitySchemaFactory.get("DataSpaceConnectorEntry"));
2054
+ const { offeredResource, ...deStructuredData } = data;
1988
2055
  const result = {
1989
2056
  ...deStructuredData,
1990
2057
  "@context": federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
@@ -1995,18 +2062,20 @@ class FederatedCatalogueService {
1995
2062
  dateCreated: new Date().toISOString(),
1996
2063
  evidence: [dataSpaceConnectorCredential.id]
1997
2064
  };
1998
- return result;
2065
+ return { dataSpaceConnectorEntry: result, extraData };
1999
2066
  }
2000
2067
  /**
2001
2068
  * Extracts service offering entry from the credentials.
2002
2069
  * @param complianceCredential The Compliance Credential.
2003
2070
  * @param serviceOfferingCredential Service Offering credential (evidence).
2004
2071
  * @returns Service Offering Entry to be saved on the Database.
2072
+ * @internal
2005
2073
  */
2006
2074
  extractServiceOfferingEntry(complianceCredential, serviceOfferingCredential) {
2007
2075
  const credentialData = serviceOfferingCredential.credentialSubject;
2008
- core.Guards.objectValue(this.CLASS_NAME, "credentialData", credentialData);
2009
- const { providedBy, aggregationOfResources, servicePolicy, ...deStructuredData } = credentialData;
2076
+ core.Guards.objectValue(FederatedCatalogueService.CLASS_NAME, "credentialData", credentialData);
2077
+ const { data, extraData } = this.extractExtraData(credentialData, entity.EntitySchemaFactory.get("ServiceOfferingEntry"));
2078
+ const { providedBy, aggregationOfResources, servicePolicy, ...deStructuredData } = data;
2010
2079
  const result = {
2011
2080
  ...deStructuredData,
2012
2081
  "@context": federatedCatalogueModels.FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
@@ -2019,18 +2088,20 @@ class FederatedCatalogueService {
2019
2088
  evidence: [serviceOfferingCredential.id],
2020
2089
  servicePolicy: core.ArrayHelper.fromObjectOrArray(servicePolicy)
2021
2090
  };
2022
- return result;
2091
+ return { serviceOfferingEntry: result, extraData };
2023
2092
  }
2024
2093
  /**
2025
2094
  * Extracts data resource entry from the credentials.
2026
2095
  * @param complianceCredential The Compliance Credential.
2027
2096
  * @param dataResourceCredential Data Resource credential.
2028
2097
  * @returns DataResource Entry to be saved on the Database.
2098
+ * @internal
2029
2099
  */
2030
2100
  extractDataResourceEntry(complianceCredential, dataResourceCredential) {
2031
2101
  const credentialData = dataResourceCredential.credentialSubject;
2032
- core.Guards.objectValue(this.CLASS_NAME, "credentialData", credentialData);
2033
- const { producedBy, copyrightOwnedBy, exposedThrough, resourcePolicy, ...deStructuredData } = credentialData;
2102
+ core.Guards.objectValue(FederatedCatalogueService.CLASS_NAME, "credentialData", credentialData);
2103
+ const { data, extraData } = this.extractExtraData(credentialData, entity.EntitySchemaFactory.get("DataResourceEntry"));
2104
+ const { producedBy, copyrightOwnedBy, exposedThrough, resourcePolicy, ...deStructuredData } = data;
2034
2105
  let producedByValue = producedBy;
2035
2106
  if (core.Is.object(producedByValue)) {
2036
2107
  producedByValue = producedByValue.id;
@@ -2052,27 +2123,50 @@ class FederatedCatalogueService {
2052
2123
  evidence: [dataResourceCredential.id],
2053
2124
  resourcePolicy: core.ArrayHelper.fromObjectOrArray(resourcePolicy)
2054
2125
  };
2055
- return result;
2126
+ return { dataResourceEntry: result, extraData };
2056
2127
  }
2057
2128
  /**
2058
2129
  * Checks whether the Participant exists.
2059
2130
  * @param participantId The Participant identifier
2131
+ * @internal
2060
2132
  */
2061
2133
  async checkParticipantExists(participantId) {
2062
2134
  const participantData = await this._entityStorageParticipants.get(participantId);
2063
2135
  if (!participantData) {
2064
2136
  this._logging?.log({
2065
2137
  level: "error",
2066
- source: this.CLASS_NAME,
2138
+ source: FederatedCatalogueService.CLASS_NAME,
2067
2139
  ts: Date.now(),
2068
2140
  message: "providerIsNotParticipant",
2069
2141
  data: { providedBy: participantId }
2070
2142
  });
2071
- throw new core.UnprocessableError(this.CLASS_NAME, "providerIsNotParticipant", {
2143
+ throw new core.UnprocessableError(FederatedCatalogueService.CLASS_NAME, "providerIsNotParticipant", {
2072
2144
  providedBy: participantId
2073
2145
  });
2074
2146
  }
2075
2147
  }
2148
+ /**
2149
+ * Extracts extra data from an object.
2150
+ * @param originalData The original data to extract from
2151
+ * @param schema The entity storage that is used to store
2152
+ * @returns The extraData and the data.
2153
+ * @internal
2154
+ */
2155
+ extractExtraData(originalData, schema) {
2156
+ const entityProperties = schema.properties ?? [];
2157
+ // Type and @context is also an extra known property
2158
+ const knownProperties = entityProperties.map(property => property.property).concat(["type", "@context"]);
2159
+ const splitObjects = core.ObjectHelper.split(originalData, knownProperties);
2160
+ return {
2161
+ data: splitObjects.picked,
2162
+ extraData: core.Is.objectValue(splitObjects.omitted)
2163
+ ? {
2164
+ "@context": originalData["@context"],
2165
+ ...splitObjects.omitted
2166
+ }
2167
+ : undefined
2168
+ };
2169
+ }
2076
2170
  }
2077
2171
 
2078
2172
  const restEntryPoints = [