@twin.org/federated-catalogue-service 0.0.3-next.22 → 0.0.3-next.24
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/dist/es/models/IFederatedCatalogueServiceConfig.js.map +1 -1
- package/dist/es/models/IFederatedCatalogueServiceConstructorOptions.js.map +1 -1
- package/dist/es/services/federatedCatalogueService.js +36 -6
- package/dist/es/services/federatedCatalogueService.js.map +1 -1
- package/dist/types/models/IFederatedCatalogueServiceConfig.d.ts +4 -0
- package/dist/types/models/IFederatedCatalogueServiceConstructorOptions.d.ts +4 -0
- package/dist/types/services/federatedCatalogueService.d.ts +5 -0
- package/docs/changelog.md +33 -0
- package/docs/reference/classes/FederatedCatalogueService.md +18 -0
- package/docs/reference/interfaces/IFederatedCatalogueServiceConfig.md +8 -0
- package/docs/reference/interfaces/IFederatedCatalogueServiceConstructorOptions.md +8 -0
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IFederatedCatalogueServiceConfig.js","sourceRoot":"","sources":["../../../src/models/IFederatedCatalogueServiceConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the FederatedCatalogueService.\n */\
|
|
1
|
+
{"version":3,"file":"IFederatedCatalogueServiceConfig.js","sourceRoot":"","sources":["../../../src/models/IFederatedCatalogueServiceConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the FederatedCatalogueService.\n */\nexport interface IFederatedCatalogueServiceConfig {\n\t/**\n\t * Timeout in milliseconds for acquiring a mutex lock, defaults to 5000ms.\n\t */\n\tmutexTimeoutMs?: number;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IFederatedCatalogueServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IFederatedCatalogueServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IFederatedCatalogueServiceConfig } from \"./IFederatedCatalogueServiceConfig.js\";\n\n/**\n * Options for the FederatedCatalogueService constructor.\n */\nexport interface IFederatedCatalogueServiceConstructorOptions {\n\t/**\n\t * The entity storage for datasets.\n\t * @default dataset\n\t */\n\tdatasetEntityStorageType?: string;\n\n\t/**\n\t * The logging component for the service.\n\t */\n\tloggingComponentType?: string;\n\n\t/**\n\t * Trust component type for trust verification.\n\t * @default trust\n\t */\n\ttrustComponentType?: string;\n\n\t/**\n\t * Configuration for the federated catalogue service.\n\t */\n\tconfig?: IFederatedCatalogueServiceConfig;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"IFederatedCatalogueServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IFederatedCatalogueServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IFederatedCatalogueServiceConfig } from \"./IFederatedCatalogueServiceConfig.js\";\n\n/**\n * Options for the FederatedCatalogueService constructor.\n */\nexport interface IFederatedCatalogueServiceConstructorOptions {\n\t/**\n\t * The entity storage for datasets.\n\t * @default dataset\n\t */\n\tdatasetEntityStorageType?: string;\n\n\t/**\n\t * The logging component for the service.\n\t */\n\tloggingComponentType?: string;\n\n\t/**\n\t * Trust component type for trust verification.\n\t * @default trust\n\t */\n\ttrustComponentType?: string;\n\n\t/**\n\t * The component type for the optional telemetry component used for event metrics, defaults to no telemetry.\n\t */\n\ttelemetryComponentType?: string;\n\n\t/**\n\t * Configuration for the federated catalogue service.\n\t */\n\tconfig?: IFederatedCatalogueServiceConfig;\n}\n"]}
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
3
|
import { HttpUrlHelper } from "@twin.org/api-models";
|
|
4
4
|
import { ContextIdKeys } from "@twin.org/context";
|
|
5
|
-
import { ArrayHelper, BaseError, ComponentFactory, Converter, GeneralError, Guards, Is, JsonHelper, Mutex, NotFoundError, ObjectHelper, Url, Urn, Validation } from "@twin.org/core";
|
|
5
|
+
import { ArrayHelper, BaseError, Coerce, ComponentFactory, Converter, GeneralError, Guards, Is, JsonHelper, Mutex, NotFoundError, ObjectHelper, Url, Urn, Validation } from "@twin.org/core";
|
|
6
6
|
import { Blake2b } from "@twin.org/crypto";
|
|
7
7
|
import { JsonLdHelper, JsonLdProcessor } from "@twin.org/data-json-ld";
|
|
8
8
|
import { EntityStorageConnectorFactory } from "@twin.org/entity-storage-models";
|
|
9
|
-
import { FederatedCatalogueFilterFactory } from "@twin.org/federated-catalogue-models";
|
|
9
|
+
import { FederatedCatalogueFilterFactory, FederatedCatalogueMetricIds, FederatedCatalogueMetrics } from "@twin.org/federated-catalogue-models";
|
|
10
10
|
import { DataspaceProtocolCatalogTypes, DataspaceProtocolContexts, DataspaceProtocolDataTypes, DataspaceProtocolHelper } from "@twin.org/standards-dataspace-protocol";
|
|
11
11
|
import { DublinCoreContexts, DublinCoreDataTypes } from "@twin.org/standards-dublin-core";
|
|
12
12
|
import { FoafDataTypes } from "@twin.org/standards-foaf";
|
|
13
13
|
import { DcatContexts, DcatDataTypes } from "@twin.org/standards-w3c-dcat";
|
|
14
14
|
import { OdrlContexts } from "@twin.org/standards-w3c-odrl";
|
|
15
|
+
import { MetricHelper } from "@twin.org/telemetry-models";
|
|
15
16
|
import { TrustHelper } from "@twin.org/trust-models";
|
|
16
17
|
import { transformToCatalogError } from "../utils/catalogErrorUtils.js";
|
|
17
18
|
import { datasetEntityToModel, datasetModelToEntity } from "../utils/datasetConverters.js";
|
|
@@ -39,6 +40,16 @@ export class FederatedCatalogueService {
|
|
|
39
40
|
* @internal
|
|
40
41
|
*/
|
|
41
42
|
_trustComponent;
|
|
43
|
+
/**
|
|
44
|
+
* The optional telemetry component for event metrics.
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
_telemetryComponent;
|
|
48
|
+
/**
|
|
49
|
+
* Timeout in milliseconds for acquiring a mutex lock.
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
52
|
+
_mutexTimeoutMs;
|
|
42
53
|
/**
|
|
43
54
|
* Create a new instance of FederatedCatalogueService.
|
|
44
55
|
* @param options The options for the service.
|
|
@@ -47,6 +58,8 @@ export class FederatedCatalogueService {
|
|
|
47
58
|
this._logging = ComponentFactory.getIfExists(options?.loggingComponentType);
|
|
48
59
|
this._datasetStorage = EntityStorageConnectorFactory.get(options?.datasetEntityStorageType ?? "dataset");
|
|
49
60
|
this._trustComponent = ComponentFactory.get(options?.trustComponentType ?? "trust");
|
|
61
|
+
this._telemetryComponent = ComponentFactory.getIfExists(options?.telemetryComponentType);
|
|
62
|
+
this._mutexTimeoutMs = Coerce.integer(options?.config?.mutexTimeoutMs);
|
|
50
63
|
// Register JSON-LD redirects for offline processing
|
|
51
64
|
DcatDataTypes.registerRedirects();
|
|
52
65
|
DublinCoreDataTypes.registerRedirects();
|
|
@@ -62,6 +75,13 @@ export class FederatedCatalogueService {
|
|
|
62
75
|
className() {
|
|
63
76
|
return FederatedCatalogueService.CLASS_NAME;
|
|
64
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Register all federated catalogue metrics with the telemetry component.
|
|
80
|
+
* @returns A promise that resolves when all metrics have been registered.
|
|
81
|
+
*/
|
|
82
|
+
async start() {
|
|
83
|
+
await MetricHelper.createMetrics(this._telemetryComponent, FederatedCatalogueMetrics);
|
|
84
|
+
}
|
|
65
85
|
/**
|
|
66
86
|
* Retrieve a dataset by its unique identifier.
|
|
67
87
|
* @param datasetId The unique identifier of the dataset.
|
|
@@ -88,6 +108,7 @@ export class FederatedCatalogueService {
|
|
|
88
108
|
// This ensures the payload matches exactly what the DS Protocol mandates
|
|
89
109
|
const normalizedDataset = await DataspaceProtocolHelper.normalize(JsonLdHelper.toNodeObject(dataset));
|
|
90
110
|
const structured = JsonLdHelper.toStructuredObject(normalizedDataset);
|
|
111
|
+
await MetricHelper.metricIncrement(this._telemetryComponent, FederatedCatalogueMetricIds.DatasetsRetrieved);
|
|
91
112
|
return structured;
|
|
92
113
|
}
|
|
93
114
|
catch (error) {
|
|
@@ -145,7 +166,7 @@ export class FederatedCatalogueService {
|
|
|
145
166
|
const datasetEntity = datasetModelToEntity(normalizedDataset, trustInfo.identity);
|
|
146
167
|
// Serialise the read-check-write cycle so concurrent requests for the
|
|
147
168
|
// same dataset cannot both pass the ownership check and overwrite each other.
|
|
148
|
-
await Mutex.lock(datasetId);
|
|
169
|
+
await Mutex.lock(datasetId, { throwOnTimeout: true, timeoutMs: this._mutexTimeoutMs });
|
|
149
170
|
try {
|
|
150
171
|
const existingEntity = await this._datasetStorage.get(datasetId);
|
|
151
172
|
if (!Is.empty(existingEntity) && existingEntity.ownerId !== trustInfo.identity) {
|
|
@@ -174,6 +195,7 @@ export class FederatedCatalogueService {
|
|
|
174
195
|
message: "filterIndexPersisted",
|
|
175
196
|
data: { datasetId, filterType, indexCount: Object.keys(filterIndexes).length }
|
|
176
197
|
});
|
|
198
|
+
await MetricHelper.metricIncrement(this._telemetryComponent, FederatedCatalogueMetricIds.FilterIndexesCreated, { filterType, indexCount: Object.keys(filterIndexes).length });
|
|
177
199
|
}
|
|
178
200
|
catch (error) {
|
|
179
201
|
await this._logging?.log({
|
|
@@ -184,9 +206,11 @@ export class FederatedCatalogueService {
|
|
|
184
206
|
data: { datasetId, filterType },
|
|
185
207
|
error: BaseError.fromError(error)
|
|
186
208
|
});
|
|
209
|
+
await MetricHelper.metricIncrement(this._telemetryComponent, FederatedCatalogueMetricIds.FilterIndexFailures, { filterType });
|
|
187
210
|
}
|
|
188
211
|
}
|
|
189
212
|
await this._datasetStorage.set(datasetEntity);
|
|
213
|
+
await MetricHelper.metricIncrement(this._telemetryComponent, FederatedCatalogueMetricIds.DatasetsStored);
|
|
190
214
|
return datasetId;
|
|
191
215
|
}
|
|
192
216
|
finally {
|
|
@@ -208,7 +232,7 @@ export class FederatedCatalogueService {
|
|
|
208
232
|
try {
|
|
209
233
|
Guards.stringValue(FederatedCatalogueService.CLASS_NAME, "datasetId", datasetId);
|
|
210
234
|
const trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "remove");
|
|
211
|
-
await Mutex.lock(datasetId);
|
|
235
|
+
await Mutex.lock(datasetId, { throwOnTimeout: true, timeoutMs: this._mutexTimeoutMs });
|
|
212
236
|
try {
|
|
213
237
|
const existingEntity = await this._datasetStorage.get(datasetId);
|
|
214
238
|
if (!Is.empty(existingEntity) && existingEntity.ownerId !== trustInfo.identity) {
|
|
@@ -224,6 +248,7 @@ export class FederatedCatalogueService {
|
|
|
224
248
|
data: { datasetId }
|
|
225
249
|
});
|
|
226
250
|
await this._datasetStorage.remove(datasetId);
|
|
251
|
+
await MetricHelper.metricIncrement(this._telemetryComponent, FederatedCatalogueMetricIds.DatasetsRemoved);
|
|
227
252
|
}
|
|
228
253
|
finally {
|
|
229
254
|
Mutex.unlock(datasetId);
|
|
@@ -278,8 +303,12 @@ export class FederatedCatalogueService {
|
|
|
278
303
|
});
|
|
279
304
|
Guards.stringValue(FederatedCatalogueService.CLASS_NAME, "filterType", filterType);
|
|
280
305
|
const selectedFilter = FederatedCatalogueFilterFactory.get(filterType);
|
|
281
|
-
|
|
282
|
-
|
|
306
|
+
// Pass the filter CRITERIA object (filter[0]) to the handler, not the array wrapper,
|
|
307
|
+
// and strip the selector "@type" from that object. Passing the array makes
|
|
308
|
+
// Is.objectValue() false inside the handler, which silently returns ALL datasets
|
|
309
|
+
// unfiltered, so the criteria (e.g. "dcterms:type") never narrows the result.
|
|
310
|
+
ObjectHelper.propertyDelete(singleFilter, "@type");
|
|
311
|
+
const result = await selectedFilter.query(trustInfo, singleFilter, cursor, limit);
|
|
283
312
|
datasets = result.datasets;
|
|
284
313
|
resultCursor = result.cursor;
|
|
285
314
|
}
|
|
@@ -290,6 +319,7 @@ export class FederatedCatalogueService {
|
|
|
290
319
|
message: "catalogQueryComplete",
|
|
291
320
|
data: { resultCount: datasets.length, hasMore: Is.stringValue(resultCursor) }
|
|
292
321
|
});
|
|
322
|
+
await MetricHelper.metricIncrement(this._telemetryComponent, FederatedCatalogueMetricIds.QueriesExecuted, { resultCount: datasets.length, hasMore: Is.stringValue(resultCursor) });
|
|
293
323
|
// Return CatalogError 404 when no datasets exist
|
|
294
324
|
if (!Is.arrayValue(datasets)) {
|
|
295
325
|
throw new NotFoundError(FederatedCatalogueService.CLASS_NAME, "noDatasetsFound");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"federatedCatalogueService.js","sourceRoot":"","sources":["../../../src/services/federatedCatalogueService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { HttpUrlHelper } from \"@twin.org/api-models\";\nimport { ContextIdKeys } from \"@twin.org/context\";\nimport {\n\tArrayHelper,\n\tBaseError,\n\tComponentFactory,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tJsonHelper,\n\tMutex,\n\tNotFoundError,\n\tObjectHelper,\n\tUrl,\n\tUrn,\n\tValidation\n} from \"@twin.org/core\";\nimport { Blake2b } from \"@twin.org/crypto\";\nimport { JsonLdHelper, JsonLdProcessor } from \"@twin.org/data-json-ld\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport {\n\tFederatedCatalogueFilterFactory,\n\ttype IFederatedCatalogueComponent\n} from \"@twin.org/federated-catalogue-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tDataspaceProtocolCatalogTypes,\n\tDataspaceProtocolContexts,\n\tDataspaceProtocolDataTypes,\n\tDataspaceProtocolHelper,\n\ttype IDataspaceProtocolCatalog,\n\ttype IDataspaceProtocolCatalogError\n} from \"@twin.org/standards-dataspace-protocol\";\nimport { DublinCoreContexts, DublinCoreDataTypes } from \"@twin.org/standards-dublin-core\";\nimport { FoafDataTypes } from \"@twin.org/standards-foaf\";\nimport {\n\tDcatContexts,\n\tDcatDataTypes,\n\ttype DcatContextType,\n\ttype IDcatDataset\n} from \"@twin.org/standards-w3c-dcat\";\nimport { OdrlContexts } from \"@twin.org/standards-w3c-odrl\";\nimport { TrustHelper, type ITrustComponent } from \"@twin.org/trust-models\";\nimport type { Dataset } from \"../entities/dataset.js\";\nimport type { IFederatedCatalogueServiceConstructorOptions } from \"../models/IFederatedCatalogueServiceConstructorOptions.js\";\nimport { transformToCatalogError } from \"../utils/catalogErrorUtils.js\";\nimport { datasetEntityToModel, datasetModelToEntity } from \"../utils/datasetConverters.js\";\n\n/**\n * Service for managing federated catalogue operations.\n * Provides Dataspace Protocol-compliant catalog endpoints for dataset registry and query.\n */\nexport class FederatedCatalogueService implements IFederatedCatalogueComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<FederatedCatalogueService>();\n\n\t/**\n\t * The logging component for the federated catalogue service.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The entity storage connector for datasets.\n\t * @internal\n\t */\n\tprivate readonly _datasetStorage: IEntityStorageConnector<Dataset>;\n\n\t/**\n\t * The trust component for token verification and generation.\n\t * @internal\n\t */\n\tprivate readonly _trustComponent: ITrustComponent;\n\n\t/**\n\t * Create a new instance of FederatedCatalogueService.\n\t * @param options The options for the service.\n\t */\n\tconstructor(options?: IFederatedCatalogueServiceConstructorOptions) {\n\t\tthis._logging = ComponentFactory.getIfExists<ILoggingComponent>(options?.loggingComponentType);\n\n\t\tthis._datasetStorage = EntityStorageConnectorFactory.get(\n\t\t\toptions?.datasetEntityStorageType ?? \"dataset\"\n\t\t);\n\n\t\tthis._trustComponent = ComponentFactory.get<ITrustComponent>(\n\t\t\toptions?.trustComponentType ?? \"trust\"\n\t\t);\n\n\t\t// Register JSON-LD redirects for offline processing\n\t\tDcatDataTypes.registerRedirects();\n\t\tDublinCoreDataTypes.registerRedirects();\n\t\tFoafDataTypes.registerRedirects();\n\t\tDataspaceProtocolDataTypes.registerRedirects();\n\n\t\t// Register DS Protocol data types for conformance checking\n\t\tDataspaceProtocolDataTypes.registerTypes();\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn FederatedCatalogueService.CLASS_NAME;\n\t}\n\n\t/**\n\t * Retrieve a dataset by its unique identifier.\n\t * @param datasetId The unique identifier of the dataset.\n\t * @param trustPayload Optional payload for trust evaluation, if applicable.\n\t * @returns A promise that resolves with the dataset if found, or a CatalogError if not found or an error occurs.\n\t */\n\tpublic async get(\n\t\tdatasetId: string,\n\t\ttrustPayload: unknown\n\t): Promise<IDcatDataset | IDataspaceProtocolCatalogError> {\n\t\ttry {\n\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(datasetId), datasetId);\n\t\t\tawait TrustHelper.verifyTrust(this._trustComponent, trustPayload, \"get\");\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"datasetRetrieve\",\n\t\t\t\tdata: { datasetId }\n\t\t\t});\n\n\t\t\tconst datasetEntity = await this._datasetStorage.get(datasetId);\n\n\t\t\tif (!datasetEntity) {\n\t\t\t\tthrow new NotFoundError(FederatedCatalogueService.CLASS_NAME, \"datasetNotFound\", datasetId);\n\t\t\t}\n\n\t\t\tconst dataset = datasetEntityToModel(datasetEntity);\n\n\t\t\t// Normalize to DS Protocol compliant format\n\t\t\t// This ensures the payload matches exactly what the DS Protocol mandates\n\t\t\tconst normalizedDataset = await DataspaceProtocolHelper.normalize(\n\t\t\t\tJsonLdHelper.toNodeObject(dataset)\n\t\t\t);\n\n\t\t\tconst structured = JsonLdHelper.toStructuredObject<IDcatDataset>(normalizedDataset);\n\t\t\treturn structured;\n\t\t} catch (error) {\n\t\t\treturn transformToCatalogError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Insert or update a dataset in the catalogue.\n\t * @param dataset The dataset to store.\n\t * @param trustPayload Optional payload for trust evaluation, if applicable.\n\t * @returns A promise that resolves with the unique identifier of the stored dataset, or a CatalogError if an error occurs.\n\t */\n\tpublic async set(\n\t\tdataset: IDcatDataset,\n\t\ttrustPayload: unknown\n\t): Promise<string | IDataspaceProtocolCatalogError> {\n\t\ttry {\n\t\t\tGuards.object(FederatedCatalogueService.CLASS_NAME, nameof(dataset), dataset);\n\n\t\t\tconst trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, \"set\");\n\n\t\t\t// Normalize @id from dcterms:identifier if provided\n\t\t\tconst datasetId = dataset[\"@id\"] ?? dataset[\"dcterms:identifier\"];\n\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(datasetId), datasetId);\n\n\t\t\t// Set @id if it was derived from dcterms:identifier\n\t\t\tif (Is.empty(dataset[\"@id\"]) && !Is.empty(dataset[\"dcterms:identifier\"])) {\n\t\t\t\tdataset[\"@id\"] = datasetId;\n\t\t\t}\n\n\t\t\t// Validate @id is a valid URI (URN or URL) per DS Protocol\n\t\t\tconst isValidUrn = !Is.empty(Urn.tryParseExact(datasetId));\n\t\t\tconst isValidUrl = !Is.empty(Url.tryParseExact(datasetId));\n\t\t\tif (!isValidUrn && !isValidUrl) {\n\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"datasetIdInvalidUri\", {\n\t\t\t\t\tdatasetId\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Validate @type exists\n\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, \"@type\", dataset[\"@type\"]);\n\n\t\t\t// Validate dcterms:publisher exists (required for multi-participant catalog)\n\t\t\t// The publisher is used to derive participantId when returning catalog query results\n\t\t\tconst publisher = dataset[\"dcterms:publisher\"];\n\t\t\tif (Is.empty(publisher)) {\n\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"datasetMissingPublisher\", {\n\t\t\t\t\tdatasetId\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// DS Protocol compliance validation\n\t\t\tconst validationFailures = await DataspaceProtocolHelper.validate(\n\t\t\t\tJsonLdHelper.toNodeObject(dataset)\n\t\t\t);\n\n\t\t\tValidation.asValidationError(\n\t\t\t\tFederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\"dataset\",\n\t\t\t\tvalidationFailures\n\t\t\t);\n\n\t\t\t// Normalize dataset for storage using JSON-LD compaction\n\t\t\t// This ensures the dataset uses prefixed properties that entity storage expects\n\t\t\t// Entity storage schema uses DCAT-prefixed properties (dcat:distribution, not distribution)\n\t\t\t// Use a standard context with prefixes to ensure proper normalization\n\t\t\tconst storageContext: DcatContextType = {\n\t\t\t\tdcat: DcatContexts.Namespace,\n\t\t\t\tdcterms: DublinCoreContexts.NamespaceTerms,\n\t\t\t\todrl: OdrlContexts.Namespace\n\t\t\t};\n\t\t\tconst normalizedDataset = await JsonLdProcessor.compact(dataset, storageContext);\n\n\t\t\tconst datasetEntity = datasetModelToEntity(normalizedDataset, trustInfo.identity);\n\n\t\t\t// Serialise the read-check-write cycle so concurrent requests for the\n\t\t\t// same dataset cannot both pass the ownership check and overwrite each other.\n\t\t\tawait Mutex.lock(datasetId);\n\t\t\ttry {\n\t\t\t\tconst existingEntity = await this._datasetStorage.get(datasetId);\n\t\t\t\tif (!Is.empty(existingEntity) && existingEntity.ownerId !== trustInfo.identity) {\n\t\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"datasetOwnerMismatch\", {\n\t\t\t\t\t\tdatasetId\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Bake the publishing organization into distribution accessService URLs\n\t\t\t\tawait this.bakeOrganizationIntoDistributions(datasetEntity, trustInfo.identity);\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"datasetSet\",\n\t\t\t\t\tdata: { datasetId }\n\t\t\t\t});\n\n\t\t\t\tconst filterNames = FederatedCatalogueFilterFactory.names();\n\t\t\t\tfor (const filterType of filterNames) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst filter = FederatedCatalogueFilterFactory.get(filterType);\n\t\t\t\t\t\tconst filterIndexes = await filter.createIndex(normalizedDataset);\n\n\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\t\t\tts: Date.now(),\n\t\t\t\t\t\t\tmessage: \"filterIndexPersisted\",\n\t\t\t\t\t\t\tdata: { datasetId, filterType, indexCount: Object.keys(filterIndexes).length }\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\t\t\tts: Date.now(),\n\t\t\t\t\t\t\tmessage: \"filterIndexCreationFailed\",\n\t\t\t\t\t\t\tdata: { datasetId, filterType },\n\t\t\t\t\t\t\terror: BaseError.fromError(error)\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tawait this._datasetStorage.set(datasetEntity);\n\n\t\t\t\treturn datasetId;\n\t\t\t} finally {\n\t\t\t\tMutex.unlock(datasetId);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn transformToCatalogError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Remove a dataset from the catalogue by its unique identifier.\n\t * Indexes are automatically removed as they are stored with the dataset.\n\t * @param datasetId The unique identifier of the dataset to remove.\n\t * @param trustPayload Optional payload for trust evaluation, if applicable.\n\t * @returns A promise that resolves with undefined on success, or a CatalogError if removal fails.\n\t */\n\tpublic async remove(\n\t\tdatasetId: string,\n\t\ttrustPayload: unknown\n\t): Promise<IDataspaceProtocolCatalogError | undefined> {\n\t\ttry {\n\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(datasetId), datasetId);\n\n\t\t\tconst trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, \"remove\");\n\n\t\t\tawait Mutex.lock(datasetId);\n\t\t\ttry {\n\t\t\t\tconst existingEntity = await this._datasetStorage.get(datasetId);\n\t\t\t\tif (!Is.empty(existingEntity) && existingEntity.ownerId !== trustInfo.identity) {\n\t\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"datasetRemoveNotOwner\", {\n\t\t\t\t\t\tdatasetId\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"datasetRemove\",\n\t\t\t\t\tdata: { datasetId }\n\t\t\t\t});\n\n\t\t\t\tawait this._datasetStorage.remove(datasetId);\n\t\t\t} finally {\n\t\t\t\tMutex.unlock(datasetId);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn transformToCatalogError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Execute a query against the catalogue using registered filter plugins.\n\t * Returns a Dataspace Protocol compliant Catalog object with participantId.\n\t *\n\t * The root catalog's participantId is the requesting participant (from context).\n\t * Own datasets (matching requestingParticipantId) go directly in root dataset[].\n\t * Other participants' datasets are grouped in nested catalog[] entries.\n\t *\n\t * For anonymous requests (no context), uses the first publisher found as fallback.\n\t * Returns a CatalogError with status 404 when no datasets exist, or status 400 for invalid requests.\n\t *\n\t * @param filter The filter criteria array, where the first element contains @type.\n\t * @param cursor Optional cursor for pagination.\n\t * @param limit Optional limit for pagination.\n\t * @param trustPayload Optional payload for trust evaluation, if applicable.\n\t * @returns A promise that resolves with the catalog result and optional next-page cursor.\n\t */\n\tpublic async query(\n\t\tfilter: unknown[] | undefined,\n\t\tcursor: string | undefined,\n\t\tlimit: number | undefined,\n\t\ttrustPayload: unknown\n\t): Promise<{\n\t\tresult: IDataspaceProtocolCatalog | IDataspaceProtocolCatalogError;\n\t\tcursor?: string;\n\t}> {\n\t\ttry {\n\t\t\tconst trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, \"query\");\n\n\t\t\tlet datasets: IDcatDataset[];\n\t\t\tlet resultCursor: string | undefined;\n\n\t\t\tif (!Is.empty(filter) && !Is.array(filter)) {\n\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"filterMustBeArray\");\n\t\t\t}\n\n\t\t\tif (!Is.arrayValue(filter)) {\n\t\t\t\tconst result = await this._datasetStorage.query(\n\t\t\t\t\tundefined,\n\t\t\t\t\tundefined,\n\t\t\t\t\tundefined,\n\t\t\t\t\tcursor,\n\t\t\t\t\tlimit\n\t\t\t\t);\n\t\t\t\tdatasets = result.entities.map(entity => datasetEntityToModel(entity));\n\t\t\t\tresultCursor = result.cursor;\n\t\t\t} else if (filter.length > 1) {\n\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"multipleFiltersNotSupported\");\n\t\t\t} else {\n\t\t\t\tconst singleFilter = filter[0] as { \"@type\"?: string } | undefined;\n\n\t\t\t\tconst filterType = singleFilter?.[\"@type\"];\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"catalogQuery\",\n\t\t\t\t\tdata: { filterType: filterType ?? \"\", cursor: cursor ?? \"\", limit: limit ?? \"\" }\n\t\t\t\t});\n\n\t\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(filterType), filterType);\n\n\t\t\t\tconst selectedFilter = FederatedCatalogueFilterFactory.get(filterType);\n\n\t\t\t\tObjectHelper.propertyDelete(filter, \"@type\");\n\t\t\t\tconst result = await selectedFilter.query(trustInfo, filter, cursor, limit);\n\n\t\t\t\tdatasets = result.datasets;\n\t\t\t\tresultCursor = result.cursor;\n\t\t\t}\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"catalogQueryComplete\",\n\t\t\t\tdata: { resultCount: datasets.length, hasMore: Is.stringValue(resultCursor) }\n\t\t\t});\n\n\t\t\t// Return CatalogError 404 when no datasets exist\n\t\t\tif (!Is.arrayValue(datasets)) {\n\t\t\t\tthrow new NotFoundError(FederatedCatalogueService.CLASS_NAME, \"noDatasetsFound\");\n\t\t\t}\n\n\t\t\tlet requestingParticipantId = trustInfo.identity;\n\n\t\t\t// Group datasets by dcterms:publisher (participantId)\n\t\t\tconst datasetsByParticipant = new Map<string, IDcatDataset[]>();\n\t\t\tfor (const dataset of datasets) {\n\t\t\t\tconst publisher = this.extractPublisher(dataset);\n\t\t\t\tconst participantId = publisher ?? \"unknown\";\n\t\t\t\tconst existing = datasetsByParticipant.get(participantId) ?? [];\n\t\t\t\texisting.push(dataset);\n\t\t\t\tdatasetsByParticipant.set(participantId, existing);\n\t\t\t}\n\n\t\t\tconst participantIds = [...datasetsByParticipant.keys()];\n\n\t\t\t// For anonymous requests (no context), use first publisher as fallback\n\t\t\tif (!Is.stringValue(requestingParticipantId)) {\n\t\t\t\trequestingParticipantId = participantIds[0] ?? \"unknown\";\n\t\t\t}\n\n\t\t\t// Separate own datasets from other participants' datasets\n\t\t\tconst ownDatasets = datasetsByParticipant.get(requestingParticipantId) ?? [];\n\t\t\tconst otherParticipantIds = participantIds.filter(id => id !== requestingParticipantId);\n\n\t\t\tlet catalog: IDataspaceProtocolCatalog;\n\n\t\t\tif (!Is.arrayValue(otherParticipantIds)) {\n\t\t\t\t// Only own datasets (or all datasets belong to requesting participant)\n\t\t\t\tconst catalogId = this.generateCatalogId(ownDatasets, requestingParticipantId);\n\n\t\t\t\tcatalog = {\n\t\t\t\t\t\"@context\": [DataspaceProtocolContexts.Context],\n\t\t\t\t\t\"@id\": catalogId,\n\t\t\t\t\t\"@type\": DataspaceProtocolCatalogTypes.Catalog,\n\t\t\t\t\tparticipantId: requestingParticipantId,\n\t\t\t\t\tdataset: ownDatasets as unknown as IDataspaceProtocolCatalog[\"dataset\"]\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\t// Mixed: own datasets at root level, others in nested catalogs\n\t\t\t\tconst nestedCatalogs: IDataspaceProtocolCatalog[] = [];\n\n\t\t\t\tfor (const participantId of otherParticipantIds) {\n\t\t\t\t\tconst participantDatasets = datasetsByParticipant.get(participantId) ?? [];\n\t\t\t\t\tconst subCatalogId = this.generateCatalogId(participantDatasets, participantId);\n\n\t\t\t\t\tconst subCatalog: IDataspaceProtocolCatalog = {\n\t\t\t\t\t\t\"@context\": [DataspaceProtocolContexts.Context],\n\t\t\t\t\t\t\"@id\": subCatalogId,\n\t\t\t\t\t\t\"@type\": DataspaceProtocolCatalogTypes.Catalog,\n\t\t\t\t\t\tparticipantId,\n\t\t\t\t\t\tdataset: participantDatasets as unknown as IDataspaceProtocolCatalog[\"dataset\"]\n\t\t\t\t\t};\n\n\t\t\t\t\tnestedCatalogs.push(subCatalog);\n\t\t\t\t}\n\n\t\t\t\t// Root catalog contains own datasets and nested catalogs for others\n\t\t\t\tconst rootCatalogId = this.generateCatalogId(datasets, requestingParticipantId);\n\n\t\t\t\tcatalog = {\n\t\t\t\t\t\"@context\": [DataspaceProtocolContexts.Context],\n\t\t\t\t\t\"@id\": rootCatalogId,\n\t\t\t\t\t\"@type\": DataspaceProtocolCatalogTypes.Catalog,\n\t\t\t\t\tparticipantId: requestingParticipantId,\n\t\t\t\t\tdataset: ownDatasets as unknown as IDataspaceProtocolCatalog[\"dataset\"],\n\t\t\t\t\tcatalog: nestedCatalogs\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Normalize to DS Protocol compliant format\n\t\t\t// This ensures the payload matches exactly what the DS Protocol mandates\n\t\t\tconst normalizedCatalog = await DataspaceProtocolHelper.normalize(\n\t\t\t\tJsonLdHelper.toNodeObject(catalog)\n\t\t\t);\n\n\t\t\tconst structuredResult: IDataspaceProtocolCatalog =\n\t\t\t\tJsonLdHelper.toStructuredObject(normalizedCatalog);\n\n\t\t\treturn {\n\t\t\t\tresult: structuredResult,\n\t\t\t\tcursor: resultCursor\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tresult: transformToCatalogError(error)\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Extract publisher from dataset.\n\t * Publisher can be a string or an IFoafAgent object with @id.\n\t * @param dataset The dataset to extract publisher from.\n\t * @returns The publisher string or undefined if not found.\n\t * @internal\n\t */\n\tprivate extractPublisher(dataset: IDcatDataset): string | undefined {\n\t\tconst publisher = dataset[\"dcterms:publisher\"];\n\n\t\t// Handle case where publisher is an object with @id (IFoafAgent)\n\t\tif (Is.object<{ \"@id\"?: string }>(publisher)) {\n\t\t\tconst publisherId = publisher[\"@id\"];\n\t\t\treturn Is.stringValue(publisherId) ? publisherId : undefined;\n\t\t}\n\n\t\treturn Is.stringValue(publisher) ? publisher : undefined;\n\t}\n\n\t/**\n\t * Bake the publishing organization token into each distribution's accessService URL.\n\t * @param entity The dataset entity to modify in place.\n\t * @param organizationId The publishing organization id to bake.\n\t * @returns A promise that resolves when all distribution URLs have been updated.\n\t * @internal\n\t */\n\tprivate async bakeOrganizationIntoDistributions(\n\t\tentity: Dataset,\n\t\torganizationId: string\n\t): Promise<void> {\n\t\t// Storage uses the prefixed JSON-LD key \"dcat:accessService\" (not the unprefixed\n\t\t// \"accessService\" that appears in compacted query responses).\n\t\tconst distributions = ArrayHelper.fromObjectOrArray(entity[\"dcat:distribution\"]) ?? [];\n\t\tfor (const dist of distributions) {\n\t\t\tconst accessService = dist?.[\"dcat:accessService\"];\n\t\t\tif (Is.stringValue(accessService)) {\n\t\t\t\tdist[\"dcat:accessService\"] = HttpUrlHelper.addQueryStringParam(\n\t\t\t\t\taccessService,\n\t\t\t\t\tContextIdKeys.Organization,\n\t\t\t\t\torganizationId\n\t\t\t\t);\n\t\t\t} else if (Is.objectValue(accessService)) {\n\t\t\t\t// DCAT object form: a dcat:DataService with an endpointURL.\n\t\t\t\tconst dataService = accessService as { \"dcat:endpointURL\"?: unknown };\n\t\t\t\tif (Is.stringValue(dataService[\"dcat:endpointURL\"])) {\n\t\t\t\t\tdataService[\"dcat:endpointURL\"] = HttpUrlHelper.addQueryStringParam(\n\t\t\t\t\t\tdataService[\"dcat:endpointURL\"],\n\t\t\t\t\t\tContextIdKeys.Organization,\n\t\t\t\t\t\torganizationId\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Generate a deterministic catalog ID using canonical hash.\n\t * @param datasets The datasets to include in the hash.\n\t * @param participantId The participant ID to include in the hash.\n\t * @returns A URN-formatted catalog ID.\n\t * @internal\n\t */\n\tprivate generateCatalogId(datasets: IDcatDataset[], participantId: string): string {\n\t\tconst datasetIds = datasets\n\t\t\t.map(d => d[\"@id\"])\n\t\t\t.filter(id => Is.stringValue(id))\n\t\t\t.sort();\n\n\t\tconst canonicalContent = JsonHelper.canonicalize({\n\t\t\t\"@type\": DataspaceProtocolCatalogTypes.Catalog,\n\t\t\tparticipantId,\n\t\t\tdatasets: datasetIds\n\t\t});\n\n\t\tconst canonicalBytes = Converter.utf8ToBytes(canonicalContent);\n\t\tconst catalogHash = Converter.bytesToHex(Blake2b.sum256(canonicalBytes));\n\t\treturn `urn:x-catalog:${catalogHash}`;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"federatedCatalogueService.js","sourceRoot":"","sources":["../../../src/services/federatedCatalogueService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { HttpUrlHelper } from \"@twin.org/api-models\";\nimport { ContextIdKeys } from \"@twin.org/context\";\nimport {\n\tArrayHelper,\n\tBaseError,\n\tCoerce,\n\tComponentFactory,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tJsonHelper,\n\tMutex,\n\tNotFoundError,\n\tObjectHelper,\n\tUrl,\n\tUrn,\n\tValidation\n} from \"@twin.org/core\";\nimport { Blake2b } from \"@twin.org/crypto\";\nimport { JsonLdHelper, JsonLdProcessor } from \"@twin.org/data-json-ld\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport {\n\tFederatedCatalogueFilterFactory,\n\tFederatedCatalogueMetricIds,\n\tFederatedCatalogueMetrics,\n\ttype IFederatedCatalogueComponent\n} from \"@twin.org/federated-catalogue-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tDataspaceProtocolCatalogTypes,\n\tDataspaceProtocolContexts,\n\tDataspaceProtocolDataTypes,\n\tDataspaceProtocolHelper,\n\ttype IDataspaceProtocolCatalog,\n\ttype IDataspaceProtocolCatalogError\n} from \"@twin.org/standards-dataspace-protocol\";\nimport { DublinCoreContexts, DublinCoreDataTypes } from \"@twin.org/standards-dublin-core\";\nimport { FoafDataTypes } from \"@twin.org/standards-foaf\";\nimport {\n\tDcatContexts,\n\tDcatDataTypes,\n\ttype DcatContextType,\n\ttype IDcatDataset\n} from \"@twin.org/standards-w3c-dcat\";\nimport { OdrlContexts } from \"@twin.org/standards-w3c-odrl\";\nimport { MetricHelper, type ITelemetryComponent } from \"@twin.org/telemetry-models\";\nimport { TrustHelper, type ITrustComponent } from \"@twin.org/trust-models\";\nimport type { Dataset } from \"../entities/dataset.js\";\nimport type { IFederatedCatalogueServiceConstructorOptions } from \"../models/IFederatedCatalogueServiceConstructorOptions.js\";\nimport { transformToCatalogError } from \"../utils/catalogErrorUtils.js\";\nimport { datasetEntityToModel, datasetModelToEntity } from \"../utils/datasetConverters.js\";\n\n/**\n * Service for managing federated catalogue operations.\n * Provides Dataspace Protocol-compliant catalog endpoints for dataset registry and query.\n */\nexport class FederatedCatalogueService implements IFederatedCatalogueComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<FederatedCatalogueService>();\n\n\t/**\n\t * The logging component for the federated catalogue service.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The entity storage connector for datasets.\n\t * @internal\n\t */\n\tprivate readonly _datasetStorage: IEntityStorageConnector<Dataset>;\n\n\t/**\n\t * The trust component for token verification and generation.\n\t * @internal\n\t */\n\tprivate readonly _trustComponent: ITrustComponent;\n\n\t/**\n\t * The optional telemetry component for event metrics.\n\t * @internal\n\t */\n\tprivate readonly _telemetryComponent?: ITelemetryComponent;\n\n\t/**\n\t * Timeout in milliseconds for acquiring a mutex lock.\n\t * @internal\n\t */\n\tprivate readonly _mutexTimeoutMs?: number;\n\n\t/**\n\t * Create a new instance of FederatedCatalogueService.\n\t * @param options The options for the service.\n\t */\n\tconstructor(options?: IFederatedCatalogueServiceConstructorOptions) {\n\t\tthis._logging = ComponentFactory.getIfExists<ILoggingComponent>(options?.loggingComponentType);\n\n\t\tthis._datasetStorage = EntityStorageConnectorFactory.get(\n\t\t\toptions?.datasetEntityStorageType ?? \"dataset\"\n\t\t);\n\n\t\tthis._trustComponent = ComponentFactory.get<ITrustComponent>(\n\t\t\toptions?.trustComponentType ?? \"trust\"\n\t\t);\n\n\t\tthis._telemetryComponent = ComponentFactory.getIfExists<ITelemetryComponent>(\n\t\t\toptions?.telemetryComponentType\n\t\t);\n\t\tthis._mutexTimeoutMs = Coerce.integer(options?.config?.mutexTimeoutMs);\n\n\t\t// Register JSON-LD redirects for offline processing\n\t\tDcatDataTypes.registerRedirects();\n\t\tDublinCoreDataTypes.registerRedirects();\n\t\tFoafDataTypes.registerRedirects();\n\t\tDataspaceProtocolDataTypes.registerRedirects();\n\n\t\t// Register DS Protocol data types for conformance checking\n\t\tDataspaceProtocolDataTypes.registerTypes();\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn FederatedCatalogueService.CLASS_NAME;\n\t}\n\n\t/**\n\t * Register all federated catalogue metrics with the telemetry component.\n\t * @returns A promise that resolves when all metrics have been registered.\n\t */\n\tpublic async start(): Promise<void> {\n\t\tawait MetricHelper.createMetrics(this._telemetryComponent, FederatedCatalogueMetrics);\n\t}\n\n\t/**\n\t * Retrieve a dataset by its unique identifier.\n\t * @param datasetId The unique identifier of the dataset.\n\t * @param trustPayload Optional payload for trust evaluation, if applicable.\n\t * @returns A promise that resolves with the dataset if found, or a CatalogError if not found or an error occurs.\n\t */\n\tpublic async get(\n\t\tdatasetId: string,\n\t\ttrustPayload: unknown\n\t): Promise<IDcatDataset | IDataspaceProtocolCatalogError> {\n\t\ttry {\n\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(datasetId), datasetId);\n\t\t\tawait TrustHelper.verifyTrust(this._trustComponent, trustPayload, \"get\");\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"datasetRetrieve\",\n\t\t\t\tdata: { datasetId }\n\t\t\t});\n\n\t\t\tconst datasetEntity = await this._datasetStorage.get(datasetId);\n\n\t\t\tif (!datasetEntity) {\n\t\t\t\tthrow new NotFoundError(FederatedCatalogueService.CLASS_NAME, \"datasetNotFound\", datasetId);\n\t\t\t}\n\n\t\t\tconst dataset = datasetEntityToModel(datasetEntity);\n\n\t\t\t// Normalize to DS Protocol compliant format\n\t\t\t// This ensures the payload matches exactly what the DS Protocol mandates\n\t\t\tconst normalizedDataset = await DataspaceProtocolHelper.normalize(\n\t\t\t\tJsonLdHelper.toNodeObject(dataset)\n\t\t\t);\n\n\t\t\tconst structured = JsonLdHelper.toStructuredObject<IDcatDataset>(normalizedDataset);\n\n\t\t\tawait MetricHelper.metricIncrement(\n\t\t\t\tthis._telemetryComponent,\n\t\t\t\tFederatedCatalogueMetricIds.DatasetsRetrieved\n\t\t\t);\n\n\t\t\treturn structured;\n\t\t} catch (error) {\n\t\t\treturn transformToCatalogError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Insert or update a dataset in the catalogue.\n\t * @param dataset The dataset to store.\n\t * @param trustPayload Optional payload for trust evaluation, if applicable.\n\t * @returns A promise that resolves with the unique identifier of the stored dataset, or a CatalogError if an error occurs.\n\t */\n\tpublic async set(\n\t\tdataset: IDcatDataset,\n\t\ttrustPayload: unknown\n\t): Promise<string | IDataspaceProtocolCatalogError> {\n\t\ttry {\n\t\t\tGuards.object(FederatedCatalogueService.CLASS_NAME, nameof(dataset), dataset);\n\n\t\t\tconst trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, \"set\");\n\n\t\t\t// Normalize @id from dcterms:identifier if provided\n\t\t\tconst datasetId = dataset[\"@id\"] ?? dataset[\"dcterms:identifier\"];\n\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(datasetId), datasetId);\n\n\t\t\t// Set @id if it was derived from dcterms:identifier\n\t\t\tif (Is.empty(dataset[\"@id\"]) && !Is.empty(dataset[\"dcterms:identifier\"])) {\n\t\t\t\tdataset[\"@id\"] = datasetId;\n\t\t\t}\n\n\t\t\t// Validate @id is a valid URI (URN or URL) per DS Protocol\n\t\t\tconst isValidUrn = !Is.empty(Urn.tryParseExact(datasetId));\n\t\t\tconst isValidUrl = !Is.empty(Url.tryParseExact(datasetId));\n\t\t\tif (!isValidUrn && !isValidUrl) {\n\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"datasetIdInvalidUri\", {\n\t\t\t\t\tdatasetId\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Validate @type exists\n\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, \"@type\", dataset[\"@type\"]);\n\n\t\t\t// Validate dcterms:publisher exists (required for multi-participant catalog)\n\t\t\t// The publisher is used to derive participantId when returning catalog query results\n\t\t\tconst publisher = dataset[\"dcterms:publisher\"];\n\t\t\tif (Is.empty(publisher)) {\n\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"datasetMissingPublisher\", {\n\t\t\t\t\tdatasetId\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// DS Protocol compliance validation\n\t\t\tconst validationFailures = await DataspaceProtocolHelper.validate(\n\t\t\t\tJsonLdHelper.toNodeObject(dataset)\n\t\t\t);\n\n\t\t\tValidation.asValidationError(\n\t\t\t\tFederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\"dataset\",\n\t\t\t\tvalidationFailures\n\t\t\t);\n\n\t\t\t// Normalize dataset for storage using JSON-LD compaction\n\t\t\t// This ensures the dataset uses prefixed properties that entity storage expects\n\t\t\t// Entity storage schema uses DCAT-prefixed properties (dcat:distribution, not distribution)\n\t\t\t// Use a standard context with prefixes to ensure proper normalization\n\t\t\tconst storageContext: DcatContextType = {\n\t\t\t\tdcat: DcatContexts.Namespace,\n\t\t\t\tdcterms: DublinCoreContexts.NamespaceTerms,\n\t\t\t\todrl: OdrlContexts.Namespace\n\t\t\t};\n\t\t\tconst normalizedDataset = await JsonLdProcessor.compact(dataset, storageContext);\n\n\t\t\tconst datasetEntity = datasetModelToEntity(normalizedDataset, trustInfo.identity);\n\n\t\t\t// Serialise the read-check-write cycle so concurrent requests for the\n\t\t\t// same dataset cannot both pass the ownership check and overwrite each other.\n\t\t\tawait Mutex.lock(datasetId, { throwOnTimeout: true, timeoutMs: this._mutexTimeoutMs });\n\t\t\ttry {\n\t\t\t\tconst existingEntity = await this._datasetStorage.get(datasetId);\n\t\t\t\tif (!Is.empty(existingEntity) && existingEntity.ownerId !== trustInfo.identity) {\n\t\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"datasetOwnerMismatch\", {\n\t\t\t\t\t\tdatasetId\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Bake the publishing organization into distribution accessService URLs\n\t\t\t\tawait this.bakeOrganizationIntoDistributions(datasetEntity, trustInfo.identity);\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"datasetSet\",\n\t\t\t\t\tdata: { datasetId }\n\t\t\t\t});\n\n\t\t\t\tconst filterNames = FederatedCatalogueFilterFactory.names();\n\t\t\t\tfor (const filterType of filterNames) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst filter = FederatedCatalogueFilterFactory.get(filterType);\n\t\t\t\t\t\tconst filterIndexes = await filter.createIndex(normalizedDataset);\n\n\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\t\t\tts: Date.now(),\n\t\t\t\t\t\t\tmessage: \"filterIndexPersisted\",\n\t\t\t\t\t\t\tdata: { datasetId, filterType, indexCount: Object.keys(filterIndexes).length }\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tawait MetricHelper.metricIncrement(\n\t\t\t\t\t\t\tthis._telemetryComponent,\n\t\t\t\t\t\t\tFederatedCatalogueMetricIds.FilterIndexesCreated,\n\t\t\t\t\t\t\t{ filterType, indexCount: Object.keys(filterIndexes).length }\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\t\t\tts: Date.now(),\n\t\t\t\t\t\t\tmessage: \"filterIndexCreationFailed\",\n\t\t\t\t\t\t\tdata: { datasetId, filterType },\n\t\t\t\t\t\t\terror: BaseError.fromError(error)\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tawait MetricHelper.metricIncrement(\n\t\t\t\t\t\t\tthis._telemetryComponent,\n\t\t\t\t\t\t\tFederatedCatalogueMetricIds.FilterIndexFailures,\n\t\t\t\t\t\t\t{ filterType }\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tawait this._datasetStorage.set(datasetEntity);\n\n\t\t\t\tawait MetricHelper.metricIncrement(\n\t\t\t\t\tthis._telemetryComponent,\n\t\t\t\t\tFederatedCatalogueMetricIds.DatasetsStored\n\t\t\t\t);\n\n\t\t\t\treturn datasetId;\n\t\t\t} finally {\n\t\t\t\tMutex.unlock(datasetId);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn transformToCatalogError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Remove a dataset from the catalogue by its unique identifier.\n\t * Indexes are automatically removed as they are stored with the dataset.\n\t * @param datasetId The unique identifier of the dataset to remove.\n\t * @param trustPayload Optional payload for trust evaluation, if applicable.\n\t * @returns A promise that resolves with undefined on success, or a CatalogError if removal fails.\n\t */\n\tpublic async remove(\n\t\tdatasetId: string,\n\t\ttrustPayload: unknown\n\t): Promise<IDataspaceProtocolCatalogError | undefined> {\n\t\ttry {\n\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(datasetId), datasetId);\n\n\t\t\tconst trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, \"remove\");\n\n\t\t\tawait Mutex.lock(datasetId, { throwOnTimeout: true, timeoutMs: this._mutexTimeoutMs });\n\t\t\ttry {\n\t\t\t\tconst existingEntity = await this._datasetStorage.get(datasetId);\n\t\t\t\tif (!Is.empty(existingEntity) && existingEntity.ownerId !== trustInfo.identity) {\n\t\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"datasetRemoveNotOwner\", {\n\t\t\t\t\t\tdatasetId\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"datasetRemove\",\n\t\t\t\t\tdata: { datasetId }\n\t\t\t\t});\n\n\t\t\t\tawait this._datasetStorage.remove(datasetId);\n\n\t\t\t\tawait MetricHelper.metricIncrement(\n\t\t\t\t\tthis._telemetryComponent,\n\t\t\t\t\tFederatedCatalogueMetricIds.DatasetsRemoved\n\t\t\t\t);\n\t\t\t} finally {\n\t\t\t\tMutex.unlock(datasetId);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn transformToCatalogError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Execute a query against the catalogue using registered filter plugins.\n\t * Returns a Dataspace Protocol compliant Catalog object with participantId.\n\t *\n\t * The root catalog's participantId is the requesting participant (from context).\n\t * Own datasets (matching requestingParticipantId) go directly in root dataset[].\n\t * Other participants' datasets are grouped in nested catalog[] entries.\n\t *\n\t * For anonymous requests (no context), uses the first publisher found as fallback.\n\t * Returns a CatalogError with status 404 when no datasets exist, or status 400 for invalid requests.\n\t *\n\t * @param filter The filter criteria array, where the first element contains @type.\n\t * @param cursor Optional cursor for pagination.\n\t * @param limit Optional limit for pagination.\n\t * @param trustPayload Optional payload for trust evaluation, if applicable.\n\t * @returns A promise that resolves with the catalog result and optional next-page cursor.\n\t */\n\tpublic async query(\n\t\tfilter: unknown[] | undefined,\n\t\tcursor: string | undefined,\n\t\tlimit: number | undefined,\n\t\ttrustPayload: unknown\n\t): Promise<{\n\t\tresult: IDataspaceProtocolCatalog | IDataspaceProtocolCatalogError;\n\t\tcursor?: string;\n\t}> {\n\t\ttry {\n\t\t\tconst trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, \"query\");\n\n\t\t\tlet datasets: IDcatDataset[];\n\t\t\tlet resultCursor: string | undefined;\n\n\t\t\tif (!Is.empty(filter) && !Is.array(filter)) {\n\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"filterMustBeArray\");\n\t\t\t}\n\n\t\t\tif (!Is.arrayValue(filter)) {\n\t\t\t\tconst result = await this._datasetStorage.query(\n\t\t\t\t\tundefined,\n\t\t\t\t\tundefined,\n\t\t\t\t\tundefined,\n\t\t\t\t\tcursor,\n\t\t\t\t\tlimit\n\t\t\t\t);\n\t\t\t\tdatasets = result.entities.map(entity => datasetEntityToModel(entity));\n\t\t\t\tresultCursor = result.cursor;\n\t\t\t} else if (filter.length > 1) {\n\t\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"multipleFiltersNotSupported\");\n\t\t\t} else {\n\t\t\t\tconst singleFilter = filter[0] as { \"@type\"?: string } | undefined;\n\n\t\t\t\tconst filterType = singleFilter?.[\"@type\"];\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"catalogQuery\",\n\t\t\t\t\tdata: { filterType: filterType ?? \"\", cursor: cursor ?? \"\", limit: limit ?? \"\" }\n\t\t\t\t});\n\n\t\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(filterType), filterType);\n\n\t\t\t\tconst selectedFilter = FederatedCatalogueFilterFactory.get(filterType);\n\n\t\t\t\t// Pass the filter CRITERIA object (filter[0]) to the handler, not the array wrapper,\n\t\t\t\t// and strip the selector \"@type\" from that object. Passing the array makes\n\t\t\t\t// Is.objectValue() false inside the handler, which silently returns ALL datasets\n\t\t\t\t// unfiltered, so the criteria (e.g. \"dcterms:type\") never narrows the result.\n\t\t\t\tObjectHelper.propertyDelete(singleFilter, \"@type\");\n\t\t\t\tconst result = await selectedFilter.query(trustInfo, singleFilter, cursor, limit);\n\n\t\t\t\tdatasets = result.datasets;\n\t\t\t\tresultCursor = result.cursor;\n\t\t\t}\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"catalogQueryComplete\",\n\t\t\t\tdata: { resultCount: datasets.length, hasMore: Is.stringValue(resultCursor) }\n\t\t\t});\n\n\t\t\tawait MetricHelper.metricIncrement(\n\t\t\t\tthis._telemetryComponent,\n\t\t\t\tFederatedCatalogueMetricIds.QueriesExecuted,\n\t\t\t\t{ resultCount: datasets.length, hasMore: Is.stringValue(resultCursor) }\n\t\t\t);\n\n\t\t\t// Return CatalogError 404 when no datasets exist\n\t\t\tif (!Is.arrayValue(datasets)) {\n\t\t\t\tthrow new NotFoundError(FederatedCatalogueService.CLASS_NAME, \"noDatasetsFound\");\n\t\t\t}\n\n\t\t\tlet requestingParticipantId = trustInfo.identity;\n\n\t\t\t// Group datasets by dcterms:publisher (participantId)\n\t\t\tconst datasetsByParticipant = new Map<string, IDcatDataset[]>();\n\t\t\tfor (const dataset of datasets) {\n\t\t\t\tconst publisher = this.extractPublisher(dataset);\n\t\t\t\tconst participantId = publisher ?? \"unknown\";\n\t\t\t\tconst existing = datasetsByParticipant.get(participantId) ?? [];\n\t\t\t\texisting.push(dataset);\n\t\t\t\tdatasetsByParticipant.set(participantId, existing);\n\t\t\t}\n\n\t\t\tconst participantIds = [...datasetsByParticipant.keys()];\n\n\t\t\t// For anonymous requests (no context), use first publisher as fallback\n\t\t\tif (!Is.stringValue(requestingParticipantId)) {\n\t\t\t\trequestingParticipantId = participantIds[0] ?? \"unknown\";\n\t\t\t}\n\n\t\t\t// Separate own datasets from other participants' datasets\n\t\t\tconst ownDatasets = datasetsByParticipant.get(requestingParticipantId) ?? [];\n\t\t\tconst otherParticipantIds = participantIds.filter(id => id !== requestingParticipantId);\n\n\t\t\tlet catalog: IDataspaceProtocolCatalog;\n\n\t\t\tif (!Is.arrayValue(otherParticipantIds)) {\n\t\t\t\t// Only own datasets (or all datasets belong to requesting participant)\n\t\t\t\tconst catalogId = this.generateCatalogId(ownDatasets, requestingParticipantId);\n\n\t\t\t\tcatalog = {\n\t\t\t\t\t\"@context\": [DataspaceProtocolContexts.Context],\n\t\t\t\t\t\"@id\": catalogId,\n\t\t\t\t\t\"@type\": DataspaceProtocolCatalogTypes.Catalog,\n\t\t\t\t\tparticipantId: requestingParticipantId,\n\t\t\t\t\tdataset: ownDatasets as unknown as IDataspaceProtocolCatalog[\"dataset\"]\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\t// Mixed: own datasets at root level, others in nested catalogs\n\t\t\t\tconst nestedCatalogs: IDataspaceProtocolCatalog[] = [];\n\n\t\t\t\tfor (const participantId of otherParticipantIds) {\n\t\t\t\t\tconst participantDatasets = datasetsByParticipant.get(participantId) ?? [];\n\t\t\t\t\tconst subCatalogId = this.generateCatalogId(participantDatasets, participantId);\n\n\t\t\t\t\tconst subCatalog: IDataspaceProtocolCatalog = {\n\t\t\t\t\t\t\"@context\": [DataspaceProtocolContexts.Context],\n\t\t\t\t\t\t\"@id\": subCatalogId,\n\t\t\t\t\t\t\"@type\": DataspaceProtocolCatalogTypes.Catalog,\n\t\t\t\t\t\tparticipantId,\n\t\t\t\t\t\tdataset: participantDatasets as unknown as IDataspaceProtocolCatalog[\"dataset\"]\n\t\t\t\t\t};\n\n\t\t\t\t\tnestedCatalogs.push(subCatalog);\n\t\t\t\t}\n\n\t\t\t\t// Root catalog contains own datasets and nested catalogs for others\n\t\t\t\tconst rootCatalogId = this.generateCatalogId(datasets, requestingParticipantId);\n\n\t\t\t\tcatalog = {\n\t\t\t\t\t\"@context\": [DataspaceProtocolContexts.Context],\n\t\t\t\t\t\"@id\": rootCatalogId,\n\t\t\t\t\t\"@type\": DataspaceProtocolCatalogTypes.Catalog,\n\t\t\t\t\tparticipantId: requestingParticipantId,\n\t\t\t\t\tdataset: ownDatasets as unknown as IDataspaceProtocolCatalog[\"dataset\"],\n\t\t\t\t\tcatalog: nestedCatalogs\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Normalize to DS Protocol compliant format\n\t\t\t// This ensures the payload matches exactly what the DS Protocol mandates\n\t\t\tconst normalizedCatalog = await DataspaceProtocolHelper.normalize(\n\t\t\t\tJsonLdHelper.toNodeObject(catalog)\n\t\t\t);\n\n\t\t\tconst structuredResult: IDataspaceProtocolCatalog =\n\t\t\t\tJsonLdHelper.toStructuredObject(normalizedCatalog);\n\n\t\t\treturn {\n\t\t\t\tresult: structuredResult,\n\t\t\t\tcursor: resultCursor\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tresult: transformToCatalogError(error)\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Extract publisher from dataset.\n\t * Publisher can be a string or an IFoafAgent object with @id.\n\t * @param dataset The dataset to extract publisher from.\n\t * @returns The publisher string or undefined if not found.\n\t * @internal\n\t */\n\tprivate extractPublisher(dataset: IDcatDataset): string | undefined {\n\t\tconst publisher = dataset[\"dcterms:publisher\"];\n\n\t\t// Handle case where publisher is an object with @id (IFoafAgent)\n\t\tif (Is.object<{ \"@id\"?: string }>(publisher)) {\n\t\t\tconst publisherId = publisher[\"@id\"];\n\t\t\treturn Is.stringValue(publisherId) ? publisherId : undefined;\n\t\t}\n\n\t\treturn Is.stringValue(publisher) ? publisher : undefined;\n\t}\n\n\t/**\n\t * Bake the publishing organization token into each distribution's accessService URL.\n\t * @param entity The dataset entity to modify in place.\n\t * @param organizationId The publishing organization id to bake.\n\t * @returns A promise that resolves when all distribution URLs have been updated.\n\t * @internal\n\t */\n\tprivate async bakeOrganizationIntoDistributions(\n\t\tentity: Dataset,\n\t\torganizationId: string\n\t): Promise<void> {\n\t\t// Storage uses the prefixed JSON-LD key \"dcat:accessService\" (not the unprefixed\n\t\t// \"accessService\" that appears in compacted query responses).\n\t\tconst distributions = ArrayHelper.fromObjectOrArray(entity[\"dcat:distribution\"]) ?? [];\n\t\tfor (const dist of distributions) {\n\t\t\tconst accessService = dist?.[\"dcat:accessService\"];\n\t\t\tif (Is.stringValue(accessService)) {\n\t\t\t\tdist[\"dcat:accessService\"] = HttpUrlHelper.addQueryStringParam(\n\t\t\t\t\taccessService,\n\t\t\t\t\tContextIdKeys.Organization,\n\t\t\t\t\torganizationId\n\t\t\t\t);\n\t\t\t} else if (Is.objectValue(accessService)) {\n\t\t\t\t// DCAT object form: a dcat:DataService with an endpointURL.\n\t\t\t\tconst dataService = accessService as { \"dcat:endpointURL\"?: unknown };\n\t\t\t\tif (Is.stringValue(dataService[\"dcat:endpointURL\"])) {\n\t\t\t\t\tdataService[\"dcat:endpointURL\"] = HttpUrlHelper.addQueryStringParam(\n\t\t\t\t\t\tdataService[\"dcat:endpointURL\"],\n\t\t\t\t\t\tContextIdKeys.Organization,\n\t\t\t\t\t\torganizationId\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Generate a deterministic catalog ID using canonical hash.\n\t * @param datasets The datasets to include in the hash.\n\t * @param participantId The participant ID to include in the hash.\n\t * @returns A URN-formatted catalog ID.\n\t * @internal\n\t */\n\tprivate generateCatalogId(datasets: IDcatDataset[], participantId: string): string {\n\t\tconst datasetIds = datasets\n\t\t\t.map(d => d[\"@id\"])\n\t\t\t.filter(id => Is.stringValue(id))\n\t\t\t.sort();\n\n\t\tconst canonicalContent = JsonHelper.canonicalize({\n\t\t\t\"@type\": DataspaceProtocolCatalogTypes.Catalog,\n\t\t\tparticipantId,\n\t\t\tdatasets: datasetIds\n\t\t});\n\n\t\tconst canonicalBytes = Converter.utf8ToBytes(canonicalContent);\n\t\tconst catalogHash = Converter.bytesToHex(Blake2b.sum256(canonicalBytes));\n\t\treturn `urn:x-catalog:${catalogHash}`;\n\t}\n}\n"]}
|
|
@@ -17,6 +17,10 @@ export interface IFederatedCatalogueServiceConstructorOptions {
|
|
|
17
17
|
* @default trust
|
|
18
18
|
*/
|
|
19
19
|
trustComponentType?: string;
|
|
20
|
+
/**
|
|
21
|
+
* The component type for the optional telemetry component used for event metrics, defaults to no telemetry.
|
|
22
|
+
*/
|
|
23
|
+
telemetryComponentType?: string;
|
|
20
24
|
/**
|
|
21
25
|
* Configuration for the federated catalogue service.
|
|
22
26
|
*/
|
|
@@ -21,6 +21,11 @@ export declare class FederatedCatalogueService implements IFederatedCatalogueCom
|
|
|
21
21
|
* @returns The class name of the component.
|
|
22
22
|
*/
|
|
23
23
|
className(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Register all federated catalogue metrics with the telemetry component.
|
|
26
|
+
* @returns A promise that resolves when all metrics have been registered.
|
|
27
|
+
*/
|
|
28
|
+
start(): Promise<void>;
|
|
24
29
|
/**
|
|
25
30
|
* Retrieve a dataset by its unique identifier.
|
|
26
31
|
* @param datasetId The unique identifier of the dataset.
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.3-next.24](https://github.com/iotaledger/twin-federated-catalogue/compare/federated-catalogue-service-v0.0.3-next.23...federated-catalogue-service-v0.0.3-next.24) (2026-06-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* filter plugins that read the array shape must update (twin-supply-chain FilterByRole).
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* pass filter criteria object (not the array) to catalogue filter handlers ([#97](https://github.com/iotaledger/twin-federated-catalogue/issues/97)) ([6b0cd54](https://github.com/iotaledger/twin-federated-catalogue/commit/6b0cd54626a01910c2a1fb6af9e16027542e4824))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Dependencies
|
|
16
|
+
|
|
17
|
+
* The following workspace dependencies were updated
|
|
18
|
+
* dependencies
|
|
19
|
+
* @twin.org/federated-catalogue-models bumped from 0.0.3-next.23 to 0.0.3-next.24
|
|
20
|
+
|
|
21
|
+
## [0.0.3-next.23](https://github.com/iotaledger/twin-federated-catalogue/compare/federated-catalogue-service-v0.0.3-next.22...federated-catalogue-service-v0.0.3-next.23) (2026-06-19)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* add telemetry metrics to federated catalogue ([#93](https://github.com/iotaledger/twin-federated-catalogue/issues/93)) ([abd8965](https://github.com/iotaledger/twin-federated-catalogue/commit/abd89657d3991e6a50f8ed3845186069549df769))
|
|
27
|
+
* configurable timeout for mutex ([b2cd76b](https://github.com/iotaledger/twin-federated-catalogue/commit/b2cd76ba71008e558788eb3fc734b8f02eb7fdc8))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Dependencies
|
|
31
|
+
|
|
32
|
+
* The following workspace dependencies were updated
|
|
33
|
+
* dependencies
|
|
34
|
+
* @twin.org/federated-catalogue-models bumped from 0.0.3-next.22 to 0.0.3-next.23
|
|
35
|
+
|
|
3
36
|
## [0.0.3-next.22](https://github.com/iotaledger/twin-federated-catalogue/compare/federated-catalogue-service-v0.0.3-next.21...federated-catalogue-service-v0.0.3-next.22) (2026-06-18)
|
|
4
37
|
|
|
5
38
|
|
|
@@ -55,6 +55,24 @@ The class name of the component.
|
|
|
55
55
|
|
|
56
56
|
***
|
|
57
57
|
|
|
58
|
+
### start() {#start}
|
|
59
|
+
|
|
60
|
+
> **start**(): `Promise`\<`void`\>
|
|
61
|
+
|
|
62
|
+
Register all federated catalogue metrics with the telemetry component.
|
|
63
|
+
|
|
64
|
+
#### Returns
|
|
65
|
+
|
|
66
|
+
`Promise`\<`void`\>
|
|
67
|
+
|
|
68
|
+
A promise that resolves when all metrics have been registered.
|
|
69
|
+
|
|
70
|
+
#### Implementation of
|
|
71
|
+
|
|
72
|
+
`IFederatedCatalogueComponent.start`
|
|
73
|
+
|
|
74
|
+
***
|
|
75
|
+
|
|
58
76
|
### get() {#get}
|
|
59
77
|
|
|
60
78
|
> **get**(`datasetId`, `trustPayload`): `Promise`\<`IDataspaceProtocolCatalogError` \| `IDcatDataset`\>
|
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
# Interface: IFederatedCatalogueServiceConfig
|
|
2
2
|
|
|
3
3
|
Configuration for the FederatedCatalogueService.
|
|
4
|
+
|
|
5
|
+
## Properties
|
|
6
|
+
|
|
7
|
+
### mutexTimeoutMs? {#mutextimeoutms}
|
|
8
|
+
|
|
9
|
+
> `optional` **mutexTimeoutMs?**: `number`
|
|
10
|
+
|
|
11
|
+
Timeout in milliseconds for acquiring a mutex lock, defaults to 5000ms.
|
|
@@ -40,6 +40,14 @@ trust
|
|
|
40
40
|
|
|
41
41
|
***
|
|
42
42
|
|
|
43
|
+
### telemetryComponentType? {#telemetrycomponenttype}
|
|
44
|
+
|
|
45
|
+
> `optional` **telemetryComponentType?**: `string`
|
|
46
|
+
|
|
47
|
+
The component type for the optional telemetry component used for event metrics, defaults to no telemetry.
|
|
48
|
+
|
|
49
|
+
***
|
|
50
|
+
|
|
43
51
|
### config? {#config}
|
|
44
52
|
|
|
45
53
|
> `optional` **config?**: [`IFederatedCatalogueServiceConfig`](IFederatedCatalogueServiceConfig.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/federated-catalogue-service",
|
|
3
|
-
"version": "0.0.3-next.
|
|
3
|
+
"version": "0.0.3-next.24",
|
|
4
4
|
"description": "Federated Catalogue contract implementation and REST endpoint definitions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -21,13 +21,14 @@
|
|
|
21
21
|
"@twin.org/data-json-ld": "next",
|
|
22
22
|
"@twin.org/entity": "next",
|
|
23
23
|
"@twin.org/entity-storage-models": "next",
|
|
24
|
-
"@twin.org/federated-catalogue-models": "0.0.3-next.
|
|
24
|
+
"@twin.org/federated-catalogue-models": "0.0.3-next.24",
|
|
25
25
|
"@twin.org/logging-models": "next",
|
|
26
26
|
"@twin.org/nameof": "next",
|
|
27
27
|
"@twin.org/standards-dataspace-protocol": "next",
|
|
28
28
|
"@twin.org/standards-dublin-core": "next",
|
|
29
29
|
"@twin.org/standards-foaf": "next",
|
|
30
30
|
"@twin.org/standards-w3c-dcat": "next",
|
|
31
|
+
"@twin.org/telemetry-models": "next",
|
|
31
32
|
"@twin.org/trust-models": "next",
|
|
32
33
|
"@twin.org/vault-models": "next",
|
|
33
34
|
"@twin.org/web": "next"
|