@twin.org/federated-catalogue-service 0.0.3-next.2 → 0.0.3-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,4 @@
1
+ // Copyright 2025 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
1
3
  export {};
2
4
  //# sourceMappingURL=IFederatedCatalogueServiceConstructorOptions.js.map
@@ -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 { ILoggingComponent } from \"@twin.org/logging-models\";\n\n/**\n * Options for the FederatedCatalogueService constructor.\n */\nexport interface IFederatedCatalogueServiceConstructorOptions {\n\t/**\n\t * The type of the entity storage connector for datasets.\n\t */\n\tdatasetStorageConnectorType?: string;\n\n\t/**\n\t * The logging component for the service.\n\t */\n\tloggingComponent?: ILoggingComponent;\n}\n"]}
1
+ {"version":3,"file":"IFederatedCatalogueServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IFederatedCatalogueServiceConstructorOptions.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Options for the FederatedCatalogueService constructor.\n */\nexport interface IFederatedCatalogueServiceConstructorOptions {\n\t/**\n\t * The type of the entity storage connector for datasets.\n\t */\n\tdatasetStorageConnectorType?: string;\n\n\t/**\n\t * The logging component for the service.\n\t */\n\tloggingComponentType?: string;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  // Copyright 2025 IOTA Stiftung.
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
- import { BaseError, Converter, GeneralError, Guards, Is, NotFoundError, ObjectHelper } from "@twin.org/core";
3
+ import { BaseError, ComponentFactory, Converter, GeneralError, Guards, Is, NotFoundError, ObjectHelper } from "@twin.org/core";
4
4
  import { Blake2b } from "@twin.org/crypto";
5
5
  import { JsonLdProcessor } from "@twin.org/data-json-ld";
6
6
  import { EntityStorageConnectorFactory } from "@twin.org/entity-storage-models";
@@ -34,7 +34,7 @@ export class FederatedCatalogueService {
34
34
  * @param options The options for the service.
35
35
  */
36
36
  constructor(options) {
37
- this._logging = options?.loggingComponent;
37
+ this._logging = ComponentFactory.getIfExists(options?.loggingComponentType ?? "logging");
38
38
  this._datasetStorage = EntityStorageConnectorFactory.get(options?.datasetStorageConnectorType ?? "dataset");
39
39
  // Register JSON-LD redirects for offline processing
40
40
  DcatDataTypes.registerRedirects();
@@ -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 {\n\tBaseError,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tNotFoundError,\n\tObjectHelper\n} from \"@twin.org/core\";\nimport { Blake2b } from \"@twin.org/crypto\";\nimport { type IJsonLdContextDefinitionRoot, JsonLdProcessor } from \"@twin.org/data-json-ld\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport type {\n\tIBaseFilter,\n\tIFederatedCatalogueComponent\n} from \"@twin.org/federated-catalogue-models\";\nimport {\n\tFederatedCatalogueContexts,\n\tFederatedCatalogueFilterFactory\n} from \"@twin.org/federated-catalogue-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tDataspaceProtocolContexts,\n\tDataspaceProtocolDataTypes\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\tDcatClasses,\n\tDcatContexts,\n\ttype DcatContextType,\n\tDcatDataTypes,\n\ttype ICatalog,\n\ttype IDataset\n} from \"@twin.org/standards-w3c-dcat\";\nimport type { Dataset } from \"../entities/dataset.js\";\nimport type { IFederatedCatalogueServiceConstructorOptions } from \"../models/IFederatedCatalogueServiceConstructorOptions.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 * 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 = options?.loggingComponent;\n\n\t\tthis._datasetStorage = EntityStorageConnectorFactory.get(\n\t\t\toptions?.datasetStorageConnectorType ?? \"dataset\"\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\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 * @returns The dataset if found.\n\t * @throws NotFoundError if the dataset does not exist.\n\t */\n\tpublic async get(dataSetId: string): Promise<IDataset> {\n\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(dataSetId), dataSetId);\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"datasetRetrieve\",\n\t\t\tdata: { dataSetId }\n\t\t});\n\n\t\tconst datasetEntity = await this._datasetStorage.get(dataSetId);\n\n\t\tif (!datasetEntity) {\n\t\t\tthrow new NotFoundError(FederatedCatalogueService.CLASS_NAME, \"datasetNotFound\", dataSetId);\n\t\t}\n\n\t\treturn datasetEntityToModel(datasetEntity);\n\t}\n\n\t/**\n\t * Insert or update a dataset in the catalogue.\n\t * This method is internal and should not be exposed via REST endpoints.\n\t * @param dataSet The dataset to store.\n\t */\n\tpublic async set(dataSet: IDataset): Promise<void> {\n\t\tGuards.object(FederatedCatalogueService.CLASS_NAME, nameof(dataSet), dataSet);\n\n\t\tconst dataSetId = dataSet[\"@id\"] ?? dataSet[\"dcterms:identifier\"];\n\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(dataSetId), dataSetId);\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"datasetSet\",\n\t\t\tdata: { dataSetId }\n\t\t});\n\n\t\tconst datasetEntity = datasetModelToEntity(dataSet);\n\n\t\tconst allIndexes: { [key: string]: unknown } = {};\n\t\tconst filterNames = FederatedCatalogueFilterFactory.names();\n\t\tfor (const filterType of filterNames) {\n\t\t\ttry {\n\t\t\t\tconst filter = FederatedCatalogueFilterFactory.get(filterType);\n\t\t\t\tconst filterIndexes = await filter.createIndex(dataSet);\n\n\t\t\t\tallIndexes[filterType] = filterIndexes;\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: \"filterIndexPersisted\",\n\t\t\t\t\tdata: { dataSetId, filterType, indexCount: Object.keys(filterIndexes).length }\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"filterIndexCreationFailed\",\n\t\t\t\t\tdata: { dataSetId, filterType },\n\t\t\t\t\terror: BaseError.fromError(error)\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tawait this._datasetStorage.set(datasetEntity);\n\t}\n\n\t/**\n\t * Execute a query against the catalogue using registered filter plugins.\n\t * Returns a complete DCAT Catalog object with proper JSON-LD context, metadata, and datasets.\n\t * The filter payload is evaluated by the appropriate filter plugin based on its structure.\n\t * Pagination properties (cursor, limit) and filter type (@type) are extracted from the filter object.\n\t * @param filter The filter criteria containing @type, optional cursor and limit properties.\n\t * @returns Complete ICatalog object with @context, @id, @type, dcat:dataset, and optional cursor.\n\t * @throws NotFoundError if @type is missing or if the filter type is not registered.\n\t */\n\tpublic async query(filter?: IBaseFilter[]): Promise<ICatalog> {\n\t\tlet datasets: IDataset[];\n\t\tlet resultCursor: string | undefined;\n\n\t\tconst isArray = Is.array(filter);\n\t\tif (!filter || (isArray && filter.length === 0)) {\n\t\t\tconst result = await this._datasetStorage.query();\n\t\t\tdatasets = result.entities.map(entity => datasetEntityToModel(entity));\n\t\t} else if (isArray && filter.length > 1) {\n\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"multipleFiltersNotSupported\");\n\t\t} else {\n\t\t\tconst singleFilter = filter[0];\n\n\t\t\tconst cursor = singleFilter?.cursor;\n\t\t\tconst limit = singleFilter?.limit;\n\t\t\tconst filterType = singleFilter?.[\"@type\"];\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: \"catalogQuery\",\n\t\t\t\tdata: { filterType: filterType ?? \"\", cursor: cursor ?? \"\", limit: limit ?? \"\" }\n\t\t\t});\n\n\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(filterType), filterType);\n\n\t\t\tconst selectedFilter = FederatedCatalogueFilterFactory.get(filterType);\n\n\t\t\tObjectHelper.propertyDelete(filter, \"cursor\");\n\t\t\tObjectHelper.propertyDelete(filter, \"limit\");\n\t\t\tObjectHelper.propertyDelete(filter, \"@type\");\n\t\t\tconst result = await selectedFilter.query(filter);\n\n\t\t\tdatasets = result.datasets;\n\t\t\tresultCursor = result.cursor;\n\t\t}\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"catalogQueryComplete\",\n\t\t\tdata: { resultCount: datasets.length, hasMore: Is.stringValue(resultCursor) }\n\t\t});\n\n\t\t// Generate deterministic catalog ID using canonical hash of dataset IDs\n\t\t// Sort dataset IDs to ensure consistent ordering\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\t// Create deterministic representation for hashing\n\t\tconst canonicalContent = JSON.stringify({\n\t\t\t\"@type\": DcatClasses.Catalog,\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\tconst catalogId = `urn:x-catalog:${catalogHash}`;\n\n\t\t// Return complete catalog with deterministic ID\n\t\tconst catalog: ICatalog = {\n\t\t\t\"@context\": [\n\t\t\t\tDataspaceProtocolContexts.ContextRoot,\n\t\t\t\t{\n\t\t\t\t\tdcat: DcatContexts.ContextRoot,\n\t\t\t\t\tdcterms: DublinCoreContexts.ContextTerms,\n\t\t\t\t\tcursor: `${FederatedCatalogueContexts.ContextRoot}cursor`\n\t\t\t\t}\n\t\t\t] as IJsonLdContextDefinitionRoot as DcatContextType,\n\t\t\t\"@id\": catalogId,\n\t\t\t\"@type\": DcatClasses.Catalog,\n\t\t\t\"dcat:dataset\": datasets\n\t\t};\n\n\t\tif (resultCursor) {\n\t\t\tcatalog.cursor = resultCursor;\n\t\t}\n\n\t\t// Apply JSON-LD compaction to ensure proper context handling\n\t\tconst compactedCatalog = await JsonLdProcessor.compact(catalog, catalog[\"@context\"]);\n\n\t\treturn compactedCatalog;\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 */\n\tpublic async remove(dataSetId: string): Promise<void> {\n\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(dataSetId), dataSetId);\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"datasetRemove\",\n\t\t\tdata: { dataSetId }\n\t\t});\n\n\t\tawait this._datasetStorage.remove(dataSetId);\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 {\n\tBaseError,\n\tComponentFactory,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tNotFoundError,\n\tObjectHelper\n} from \"@twin.org/core\";\nimport { Blake2b } from \"@twin.org/crypto\";\nimport { type IJsonLdContextDefinitionRoot, JsonLdProcessor } from \"@twin.org/data-json-ld\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport type {\n\tIBaseFilter,\n\tIFederatedCatalogueComponent\n} from \"@twin.org/federated-catalogue-models\";\nimport {\n\tFederatedCatalogueContexts,\n\tFederatedCatalogueFilterFactory\n} from \"@twin.org/federated-catalogue-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tDataspaceProtocolContexts,\n\tDataspaceProtocolDataTypes\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\tDcatClasses,\n\tDcatContexts,\n\ttype DcatContextType,\n\tDcatDataTypes,\n\ttype ICatalog,\n\ttype IDataset\n} from \"@twin.org/standards-w3c-dcat\";\nimport type { Dataset } from \"../entities/dataset.js\";\nimport type { IFederatedCatalogueServiceConstructorOptions } from \"../models/IFederatedCatalogueServiceConstructorOptions.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 * 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>(\n\t\t\toptions?.loggingComponentType ?? \"logging\"\n\t\t);\n\n\t\tthis._datasetStorage = EntityStorageConnectorFactory.get(\n\t\t\toptions?.datasetStorageConnectorType ?? \"dataset\"\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\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 * @returns The dataset if found.\n\t * @throws NotFoundError if the dataset does not exist.\n\t */\n\tpublic async get(dataSetId: string): Promise<IDataset> {\n\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(dataSetId), dataSetId);\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"datasetRetrieve\",\n\t\t\tdata: { dataSetId }\n\t\t});\n\n\t\tconst datasetEntity = await this._datasetStorage.get(dataSetId);\n\n\t\tif (!datasetEntity) {\n\t\t\tthrow new NotFoundError(FederatedCatalogueService.CLASS_NAME, \"datasetNotFound\", dataSetId);\n\t\t}\n\n\t\treturn datasetEntityToModel(datasetEntity);\n\t}\n\n\t/**\n\t * Insert or update a dataset in the catalogue.\n\t * This method is internal and should not be exposed via REST endpoints.\n\t * @param dataSet The dataset to store.\n\t */\n\tpublic async set(dataSet: IDataset): Promise<void> {\n\t\tGuards.object(FederatedCatalogueService.CLASS_NAME, nameof(dataSet), dataSet);\n\n\t\tconst dataSetId = dataSet[\"@id\"] ?? dataSet[\"dcterms:identifier\"];\n\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(dataSetId), dataSetId);\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"datasetSet\",\n\t\t\tdata: { dataSetId }\n\t\t});\n\n\t\tconst datasetEntity = datasetModelToEntity(dataSet);\n\n\t\tconst allIndexes: { [key: string]: unknown } = {};\n\t\tconst filterNames = FederatedCatalogueFilterFactory.names();\n\t\tfor (const filterType of filterNames) {\n\t\t\ttry {\n\t\t\t\tconst filter = FederatedCatalogueFilterFactory.get(filterType);\n\t\t\t\tconst filterIndexes = await filter.createIndex(dataSet);\n\n\t\t\t\tallIndexes[filterType] = filterIndexes;\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: \"filterIndexPersisted\",\n\t\t\t\t\tdata: { dataSetId, filterType, indexCount: Object.keys(filterIndexes).length }\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"filterIndexCreationFailed\",\n\t\t\t\t\tdata: { dataSetId, filterType },\n\t\t\t\t\terror: BaseError.fromError(error)\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tawait this._datasetStorage.set(datasetEntity);\n\t}\n\n\t/**\n\t * Execute a query against the catalogue using registered filter plugins.\n\t * Returns a complete DCAT Catalog object with proper JSON-LD context, metadata, and datasets.\n\t * The filter payload is evaluated by the appropriate filter plugin based on its structure.\n\t * Pagination properties (cursor, limit) and filter type (@type) are extracted from the filter object.\n\t * @param filter The filter criteria containing @type, optional cursor and limit properties.\n\t * @returns Complete ICatalog object with @context, @id, @type, dcat:dataset, and optional cursor.\n\t * @throws NotFoundError if @type is missing or if the filter type is not registered.\n\t */\n\tpublic async query(filter?: IBaseFilter[]): Promise<ICatalog> {\n\t\tlet datasets: IDataset[];\n\t\tlet resultCursor: string | undefined;\n\n\t\tconst isArray = Is.array(filter);\n\t\tif (!filter || (isArray && filter.length === 0)) {\n\t\t\tconst result = await this._datasetStorage.query();\n\t\t\tdatasets = result.entities.map(entity => datasetEntityToModel(entity));\n\t\t} else if (isArray && filter.length > 1) {\n\t\t\tthrow new GeneralError(FederatedCatalogueService.CLASS_NAME, \"multipleFiltersNotSupported\");\n\t\t} else {\n\t\t\tconst singleFilter = filter[0];\n\n\t\t\tconst cursor = singleFilter?.cursor;\n\t\t\tconst limit = singleFilter?.limit;\n\t\t\tconst filterType = singleFilter?.[\"@type\"];\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: \"catalogQuery\",\n\t\t\t\tdata: { filterType: filterType ?? \"\", cursor: cursor ?? \"\", limit: limit ?? \"\" }\n\t\t\t});\n\n\t\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(filterType), filterType);\n\n\t\t\tconst selectedFilter = FederatedCatalogueFilterFactory.get(filterType);\n\n\t\t\tObjectHelper.propertyDelete(filter, \"cursor\");\n\t\t\tObjectHelper.propertyDelete(filter, \"limit\");\n\t\t\tObjectHelper.propertyDelete(filter, \"@type\");\n\t\t\tconst result = await selectedFilter.query(filter);\n\n\t\t\tdatasets = result.datasets;\n\t\t\tresultCursor = result.cursor;\n\t\t}\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"catalogQueryComplete\",\n\t\t\tdata: { resultCount: datasets.length, hasMore: Is.stringValue(resultCursor) }\n\t\t});\n\n\t\t// Generate deterministic catalog ID using canonical hash of dataset IDs\n\t\t// Sort dataset IDs to ensure consistent ordering\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\t// Create deterministic representation for hashing\n\t\tconst canonicalContent = JSON.stringify({\n\t\t\t\"@type\": DcatClasses.Catalog,\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\tconst catalogId = `urn:x-catalog:${catalogHash}`;\n\n\t\t// Return complete catalog with deterministic ID\n\t\tconst catalog: ICatalog = {\n\t\t\t\"@context\": [\n\t\t\t\tDataspaceProtocolContexts.ContextRoot,\n\t\t\t\t{\n\t\t\t\t\tdcat: DcatContexts.ContextRoot,\n\t\t\t\t\tdcterms: DublinCoreContexts.ContextTerms,\n\t\t\t\t\tcursor: `${FederatedCatalogueContexts.ContextRoot}cursor`\n\t\t\t\t}\n\t\t\t] as IJsonLdContextDefinitionRoot as DcatContextType,\n\t\t\t\"@id\": catalogId,\n\t\t\t\"@type\": DcatClasses.Catalog,\n\t\t\t\"dcat:dataset\": datasets\n\t\t};\n\n\t\tif (resultCursor) {\n\t\t\tcatalog.cursor = resultCursor;\n\t\t}\n\n\t\t// Apply JSON-LD compaction to ensure proper context handling\n\t\tconst compactedCatalog = await JsonLdProcessor.compact(catalog, catalog[\"@context\"]);\n\n\t\treturn compactedCatalog;\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 */\n\tpublic async remove(dataSetId: string): Promise<void> {\n\t\tGuards.stringValue(FederatedCatalogueService.CLASS_NAME, nameof(dataSetId), dataSetId);\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FederatedCatalogueService.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"datasetRemove\",\n\t\t\tdata: { dataSetId }\n\t\t});\n\n\t\tawait this._datasetStorage.remove(dataSetId);\n\t}\n}\n"]}
@@ -1,4 +1,3 @@
1
- import type { ILoggingComponent } from "@twin.org/logging-models";
2
1
  /**
3
2
  * Options for the FederatedCatalogueService constructor.
4
3
  */
@@ -10,5 +9,5 @@ export interface IFederatedCatalogueServiceConstructorOptions {
10
9
  /**
11
10
  * The logging component for the service.
12
11
  */
13
- loggingComponent?: ILoggingComponent;
12
+ loggingComponentType?: string;
14
13
  }
package/docs/changelog.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @twin.org/federated-catalogue-service - Changelog
2
2
 
3
+ ## [0.0.3-next.3](https://github.com/twinfoundation/federated-catalogue/compare/federated-catalogue-service-v0.0.3-next.2...federated-catalogue-service-v0.0.3-next.3) (2025-11-28)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * service logging constructor type ([35e63cc](https://github.com/twinfoundation/federated-catalogue/commit/35e63cc6a46769b32c817f43157233d9f05346da))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/federated-catalogue-models bumped from 0.0.3-next.2 to 0.0.3-next.3
16
+
3
17
  ## [0.0.3-next.2](https://github.com/twinfoundation/federated-catalogue/compare/federated-catalogue-service-v0.0.3-next.1...federated-catalogue-service-v0.0.3-next.2) (2025-11-28)
4
18
 
5
19
 
@@ -12,8 +12,8 @@ The type of the entity storage connector for datasets.
12
12
 
13
13
  ***
14
14
 
15
- ### loggingComponent?
15
+ ### loggingComponentType?
16
16
 
17
- > `optional` **loggingComponent**: `ILoggingComponent`
17
+ > `optional` **loggingComponentType**: `string`
18
18
 
19
19
  The logging component for the service.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/federated-catalogue-service",
3
- "version": "0.0.3-next.2",
3
+ "version": "0.0.3-next.3",
4
4
  "description": "Federated Catalogue contract implementation and REST endpoint definitions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,7 +20,7 @@
20
20
  "@twin.org/data-json-ld": "next",
21
21
  "@twin.org/entity": "next",
22
22
  "@twin.org/entity-storage-models": "next",
23
- "@twin.org/federated-catalogue-models": "0.0.3-next.2",
23
+ "@twin.org/federated-catalogue-models": "0.0.3-next.3",
24
24
  "@twin.org/logging-models": "next",
25
25
  "@twin.org/nameof": "next",
26
26
  "@twin.org/standards-dataspace-protocol": "next",