@twin.org/dataspace-control-plane-service 0.0.3-next.16 → 0.0.3-next.18
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/dataspaceControlPlanePolicyRequester.js +4 -3
- package/dist/es/dataspaceControlPlanePolicyRequester.js.map +1 -1
- package/dist/es/dataspaceControlPlaneRoutes.js +6 -0
- package/dist/es/dataspaceControlPlaneRoutes.js.map +1 -1
- package/dist/es/dataspaceControlPlaneService.js +115 -40
- package/dist/es/dataspaceControlPlaneService.js.map +1 -1
- package/dist/es/models/INegotiationState.js +0 -2
- package/dist/es/models/INegotiationState.js.map +1 -1
- package/dist/types/dataspaceControlPlanePolicyRequester.d.ts +4 -4
- package/dist/types/dataspaceControlPlaneService.d.ts +2 -1
- package/dist/types/models/INegotiationState.d.ts +2 -3
- package/docs/changelog.md +34 -0
- package/docs/reference/classes/DataspaceControlPlanePolicyRequester.md +2 -2
- package/docs/reference/classes/DataspaceControlPlaneService.md +7 -1
- package/docs/reference/interfaces/INegotiationState.md +1 -1
- package/locales/en.json +8 -1
- package/package.json +2 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Copyright 2025 IOTA Stiftung.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
3
|
import { ComponentFactory } from "@twin.org/core";
|
|
4
|
+
import { OdrlPolicyHelper } from "@twin.org/rights-management-models";
|
|
4
5
|
import { DataspaceProtocolContractNegotiationStateType } from "@twin.org/standards-dataspace-protocol";
|
|
5
6
|
/**
|
|
6
7
|
* Policy Requester for Dataspace Control Plane.
|
|
@@ -97,7 +98,7 @@ export class DataspaceControlPlanePolicyRequester {
|
|
|
97
98
|
message: "offerReceived",
|
|
98
99
|
data: {
|
|
99
100
|
negotiationId,
|
|
100
|
-
offerId: offer
|
|
101
|
+
offerId: offer["@id"]
|
|
101
102
|
}
|
|
102
103
|
});
|
|
103
104
|
const negotiation = this._negotiations.get(negotiationId);
|
|
@@ -123,7 +124,7 @@ export class DataspaceControlPlanePolicyRequester {
|
|
|
123
124
|
message: "agreementReceived",
|
|
124
125
|
data: {
|
|
125
126
|
negotiationId,
|
|
126
|
-
agreementId: agreement
|
|
127
|
+
agreementId: OdrlPolicyHelper.getUid(agreement) ?? ""
|
|
127
128
|
}
|
|
128
129
|
});
|
|
129
130
|
const negotiation = this._negotiations.get(negotiationId);
|
|
@@ -153,7 +154,7 @@ export class DataspaceControlPlanePolicyRequester {
|
|
|
153
154
|
if (negotiation) {
|
|
154
155
|
negotiation.state = DataspaceProtocolContractNegotiationStateType.FINALIZED;
|
|
155
156
|
negotiation.updatedAt = Date.now();
|
|
156
|
-
const agreementId = negotiation.agreement
|
|
157
|
+
const agreementId = OdrlPolicyHelper.getUid(negotiation.agreement);
|
|
157
158
|
this._negotiations.delete(negotiationId);
|
|
158
159
|
await this._loggingComponent?.log({
|
|
159
160
|
level: "info",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataspaceControlPlanePolicyRequester.js","sourceRoot":"","sources":["../../src/dataspaceControlPlanePolicyRequester.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { ComponentFactory } from \"@twin.org/core\";\nimport type { INegotiationCallback } from \"@twin.org/dataspace-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport type { IPolicyRequester } from \"@twin.org/rights-management-models\";\nimport { DataspaceProtocolContractNegotiationStateType } from \"@twin.org/standards-dataspace-protocol\";\nimport type { IOdrlAgreement, IOdrlOffer } from \"@twin.org/standards-w3c-odrl\";\nimport type { INegotiationState } from \"./models/INegotiationState.js\";\n\n/**\n * Policy Requester for Dataspace Control Plane.\n *\n * Handles contract negotiation callbacks from PNP and forwards state changes\n * to the control plane service via the INegotiationCallback interface.\n *\n * Callback Flow:\n * 1. Control Plane initiates negotiation via PNP.sendRequestToProvider()\n * 2. PNP calls offer() → auto-accept, notify control plane\n * 3. PNP calls agreement() → store agreement, notify control plane\n * 4. PNP calls finalised() → notify control plane with agreementId\n * 5. Control plane notifies upstream caller (e.g. supply-chain)\n */\nexport class DataspaceControlPlanePolicyRequester implements IPolicyRequester {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<DataspaceControlPlanePolicyRequester>();\n\n\t/**\n\t * The logging component.\n\t * @internal\n\t */\n\tprivate readonly _loggingComponent?: ILoggingComponent;\n\n\t/**\n\t * Callback interface for notifying the control plane of negotiation state changes.\n\t * @internal\n\t */\n\tprivate readonly _callback?: INegotiationCallback;\n\n\t/**\n\t * Active negotiations tracked in memory.\n\t * Key: negotiationId\n\t * Value: Negotiation state\n\t * @internal\n\t */\n\tprivate readonly _negotiations: Map<string, INegotiationState>;\n\n\t/**\n\t * Create a new instance of DataspaceControlPlanePolicyRequester.\n\t * @param loggingComponentType Optional logging component type.\n\t * @param callback Optional callback interface for state change notifications.\n\t */\n\tconstructor(loggingComponentType?: string, callback?: INegotiationCallback) {\n\t\tthis._loggingComponent = ComponentFactory.getIfExists<ILoggingComponent>(\n\t\t\tloggingComponentType ?? \"logging\"\n\t\t);\n\t\tthis._callback = callback;\n\t\tthis._negotiations = new Map();\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 DataspaceControlPlanePolicyRequester.CLASS_NAME;\n\t}\n\n\t/**\n\t * Register a negotiation for tracking.\n\t * Called by the control plane service after initiating a negotiation via PNP.\n\t * @param negotiationId The negotiation ID returned by PNP.sendRequestToProvider().\n\t */\n\tpublic trackNegotiation(negotiationId: string): void {\n\t\tconst now = Date.now();\n\t\tthis._negotiations.set(negotiationId, {\n\t\t\tnegotiationId,\n\t\t\tstate: DataspaceProtocolContractNegotiationStateType.REQUESTED,\n\t\t\tstartedAt: now,\n\t\t\tupdatedAt: now\n\t\t});\n\t}\n\n\t/**\n\t * Get all active negotiations (for stalled cleanup).\n\t * @returns Map of negotiationId to negotiation state.\n\t */\n\tpublic getActiveNegotiations(): Map<string, INegotiationState> {\n\t\treturn this._negotiations;\n\t}\n\n\t/**\n\t * Remove a negotiation from tracking (for cleanup).\n\t * @param negotiationId The negotiation ID to remove.\n\t */\n\tpublic removeNegotiation(negotiationId: string): void {\n\t\tthis._negotiations.delete(negotiationId);\n\t}\n\n\t/**\n\t * A policy has been offered by a provider.\n\t * Called by PNP when provider sends an OfferMessage.\n\t * @param negotiationId The id of the negotiation.\n\t * @param offer The offer sent by the provider.\n\t * @returns True if the offer was accepted, false otherwise.\n\t */\n\tpublic async offer(negotiationId: string, offer: IOdrlOffer): Promise<boolean> {\n\t\tawait this._loggingComponent?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"offerReceived\",\n\t\t\tdata: {\n\t\t\t\tnegotiationId,\n\t\t\t\tofferId: offer.uid\n\t\t\t}\n\t\t});\n\n\t\tconst negotiation = this._negotiations.get(negotiationId);\n\t\tif (negotiation) {\n\t\t\tnegotiation.state = DataspaceProtocolContractNegotiationStateType.OFFERED;\n\t\t\tnegotiation.updatedAt = Date.now();\n\t\t}\n\n\t\tawait this._callback?.onStateChanged(\n\t\t\tnegotiationId,\n\t\t\tDataspaceProtocolContractNegotiationStateType.OFFERED,\n\t\t\t{ offer }\n\t\t);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * A policy agreement has been sent by a provider.\n\t * Called by PNP when provider sends an AgreementMessage.\n\t * @param negotiationId The id of the negotiation.\n\t * @param agreement The agreement sent by the provider.\n\t * @returns True if the agreement was accepted, false otherwise.\n\t */\n\tpublic async agreement(negotiationId: string, agreement: IOdrlAgreement): Promise<boolean> {\n\t\tawait this._loggingComponent?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"agreementReceived\",\n\t\t\tdata: {\n\t\t\t\tnegotiationId,\n\t\t\t\tagreementId: agreement.uid\n\t\t\t}\n\t\t});\n\n\t\tconst negotiation = this._negotiations.get(negotiationId);\n\t\tif (negotiation) {\n\t\t\tnegotiation.state = DataspaceProtocolContractNegotiationStateType.AGREED;\n\t\t\tnegotiation.agreement = agreement;\n\t\t\tnegotiation.updatedAt = Date.now();\n\t\t}\n\n\t\tawait this._callback?.onStateChanged(\n\t\t\tnegotiationId,\n\t\t\tDataspaceProtocolContractNegotiationStateType.AGREED,\n\t\t\t{ agreement }\n\t\t);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * A policy finalisation has been sent by a provider.\n\t * Called by PNP when provider sends a FinalizedEvent.\n\t * @param negotiationId The id of the negotiation.\n\t * @returns Nothing.\n\t */\n\tpublic async finalised(negotiationId: string): Promise<void> {\n\t\tawait this._loggingComponent?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"negotiationFinalized\",\n\t\t\tdata: { negotiationId }\n\t\t});\n\n\t\tconst negotiation = this._negotiations.get(negotiationId);\n\t\tif (negotiation) {\n\t\t\tnegotiation.state = DataspaceProtocolContractNegotiationStateType.FINALIZED;\n\t\t\tnegotiation.updatedAt = Date.now();\n\n\t\t\tconst agreementId = negotiation.agreement?.uid;\n\t\t\tthis._negotiations.delete(negotiationId);\n\n\t\t\tawait this._loggingComponent?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"negotiationCompleted\",\n\t\t\t\tdata: {\n\t\t\t\t\tnegotiationId,\n\t\t\t\t\tagreementId,\n\t\t\t\t\tdurationMs: Date.now() - negotiation.startedAt\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (agreementId) {\n\t\t\t\tawait this._callback?.onCompleted(negotiationId, agreementId);\n\t\t\t} else {\n\t\t\t\tawait this._callback?.onFailed(negotiationId, \"negotiationFinalizedNoAgreement\");\n\t\t\t}\n\t\t} else {\n\t\t\tawait this._loggingComponent?.log({\n\t\t\t\tlevel: \"warn\",\n\t\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"unknownNegotiationFinalized\",\n\t\t\t\tdata: { negotiationId }\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * A policy termination has been sent by a provider.\n\t * Called by PNP when provider sends a TerminatedMessage or negotiation fails.\n\t * @param negotiationId The id of the negotiation.\n\t * @returns Nothing.\n\t */\n\tpublic async terminated(negotiationId: string): Promise<void> {\n\t\tawait this._loggingComponent?.log({\n\t\t\tlevel: \"warn\",\n\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"negotiationTerminated\",\n\t\t\tdata: { negotiationId }\n\t\t});\n\n\t\tconst negotiation = this._negotiations.get(negotiationId);\n\t\tif (negotiation) {\n\t\t\tnegotiation.state = DataspaceProtocolContractNegotiationStateType.TERMINATED;\n\t\t\tnegotiation.updatedAt = Date.now();\n\n\t\t\tthis._negotiations.delete(negotiationId);\n\n\t\t\tawait this._loggingComponent?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"negotiationRejected\",\n\t\t\t\tdata: {\n\t\t\t\t\tnegotiationId,\n\t\t\t\t\tdurationMs: Date.now() - negotiation.startedAt\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tawait this._callback?.onFailed(negotiationId, \"negotiationTerminatedByProvider\");\n\t\t} else {\n\t\t\tawait this._loggingComponent?.log({\n\t\t\t\tlevel: \"warn\",\n\t\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"unknownNegotiationTerminated\",\n\t\t\t\tdata: { negotiationId }\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dataspaceControlPlanePolicyRequester.js","sourceRoot":"","sources":["../../src/dataspaceControlPlanePolicyRequester.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { ComponentFactory } from \"@twin.org/core\";\nimport type { INegotiationCallback } from \"@twin.org/dataspace-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { OdrlPolicyHelper, type IPolicyRequester } from \"@twin.org/rights-management-models\";\nimport {\n\tDataspaceProtocolContractNegotiationStateType,\n\ttype IDataspaceProtocolAgreement,\n\ttype IDataspaceProtocolOffer\n} from \"@twin.org/standards-dataspace-protocol\";\nimport type { INegotiationState } from \"./models/INegotiationState.js\";\n\n/**\n * Policy Requester for Dataspace Control Plane.\n *\n * Handles contract negotiation callbacks from PNP and forwards state changes\n * to the control plane service via the INegotiationCallback interface.\n *\n * Callback Flow:\n * 1. Control Plane initiates negotiation via PNP.sendRequestToProvider()\n * 2. PNP calls offer() → auto-accept, notify control plane\n * 3. PNP calls agreement() → store agreement, notify control plane\n * 4. PNP calls finalised() → notify control plane with agreementId\n * 5. Control plane notifies upstream caller (e.g. supply-chain)\n */\nexport class DataspaceControlPlanePolicyRequester implements IPolicyRequester {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<DataspaceControlPlanePolicyRequester>();\n\n\t/**\n\t * The logging component.\n\t * @internal\n\t */\n\tprivate readonly _loggingComponent?: ILoggingComponent;\n\n\t/**\n\t * Callback interface for notifying the control plane of negotiation state changes.\n\t * @internal\n\t */\n\tprivate readonly _callback?: INegotiationCallback;\n\n\t/**\n\t * Active negotiations tracked in memory.\n\t * Key: negotiationId\n\t * Value: Negotiation state\n\t * @internal\n\t */\n\tprivate readonly _negotiations: Map<string, INegotiationState>;\n\n\t/**\n\t * Create a new instance of DataspaceControlPlanePolicyRequester.\n\t * @param loggingComponentType Optional logging component type.\n\t * @param callback Optional callback interface for state change notifications.\n\t */\n\tconstructor(loggingComponentType?: string, callback?: INegotiationCallback) {\n\t\tthis._loggingComponent = ComponentFactory.getIfExists<ILoggingComponent>(\n\t\t\tloggingComponentType ?? \"logging\"\n\t\t);\n\t\tthis._callback = callback;\n\t\tthis._negotiations = new Map();\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 DataspaceControlPlanePolicyRequester.CLASS_NAME;\n\t}\n\n\t/**\n\t * Register a negotiation for tracking.\n\t * Called by the control plane service after initiating a negotiation via PNP.\n\t * @param negotiationId The negotiation ID returned by PNP.sendRequestToProvider().\n\t */\n\tpublic trackNegotiation(negotiationId: string): void {\n\t\tconst now = Date.now();\n\t\tthis._negotiations.set(negotiationId, {\n\t\t\tnegotiationId,\n\t\t\tstate: DataspaceProtocolContractNegotiationStateType.REQUESTED,\n\t\t\tstartedAt: now,\n\t\t\tupdatedAt: now\n\t\t});\n\t}\n\n\t/**\n\t * Get all active negotiations (for stalled cleanup).\n\t * @returns Map of negotiationId to negotiation state.\n\t */\n\tpublic getActiveNegotiations(): Map<string, INegotiationState> {\n\t\treturn this._negotiations;\n\t}\n\n\t/**\n\t * Remove a negotiation from tracking (for cleanup).\n\t * @param negotiationId The negotiation ID to remove.\n\t */\n\tpublic removeNegotiation(negotiationId: string): void {\n\t\tthis._negotiations.delete(negotiationId);\n\t}\n\n\t/**\n\t * A policy has been offered by a provider.\n\t * Called by PNP when provider sends an OfferMessage.\n\t * @param negotiationId The id of the negotiation.\n\t * @param offer The offer sent by the provider.\n\t * @returns True if the offer was accepted, false otherwise.\n\t */\n\tpublic async offer(negotiationId: string, offer: IDataspaceProtocolOffer): Promise<boolean> {\n\t\tawait this._loggingComponent?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"offerReceived\",\n\t\t\tdata: {\n\t\t\t\tnegotiationId,\n\t\t\t\tofferId: offer[\"@id\"]\n\t\t\t}\n\t\t});\n\n\t\tconst negotiation = this._negotiations.get(negotiationId);\n\t\tif (negotiation) {\n\t\t\tnegotiation.state = DataspaceProtocolContractNegotiationStateType.OFFERED;\n\t\t\tnegotiation.updatedAt = Date.now();\n\t\t}\n\n\t\tawait this._callback?.onStateChanged(\n\t\t\tnegotiationId,\n\t\t\tDataspaceProtocolContractNegotiationStateType.OFFERED,\n\t\t\t{ offer }\n\t\t);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * A policy agreement has been sent by a provider.\n\t * Called by PNP when provider sends an AgreementMessage.\n\t * @param negotiationId The id of the negotiation.\n\t * @param agreement The agreement sent by the provider.\n\t * @returns True if the agreement was accepted, false otherwise.\n\t */\n\tpublic async agreement(\n\t\tnegotiationId: string,\n\t\tagreement: IDataspaceProtocolAgreement\n\t): Promise<boolean> {\n\t\tawait this._loggingComponent?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"agreementReceived\",\n\t\t\tdata: {\n\t\t\t\tnegotiationId,\n\t\t\t\tagreementId: OdrlPolicyHelper.getUid(agreement) ?? \"\"\n\t\t\t}\n\t\t});\n\n\t\tconst negotiation = this._negotiations.get(negotiationId);\n\t\tif (negotiation) {\n\t\t\tnegotiation.state = DataspaceProtocolContractNegotiationStateType.AGREED;\n\t\t\tnegotiation.agreement = agreement;\n\t\t\tnegotiation.updatedAt = Date.now();\n\t\t}\n\n\t\tawait this._callback?.onStateChanged(\n\t\t\tnegotiationId,\n\t\t\tDataspaceProtocolContractNegotiationStateType.AGREED,\n\t\t\t{ agreement }\n\t\t);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * A policy finalisation has been sent by a provider.\n\t * Called by PNP when provider sends a FinalizedEvent.\n\t * @param negotiationId The id of the negotiation.\n\t * @returns Nothing.\n\t */\n\tpublic async finalised(negotiationId: string): Promise<void> {\n\t\tawait this._loggingComponent?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"negotiationFinalized\",\n\t\t\tdata: { negotiationId }\n\t\t});\n\n\t\tconst negotiation = this._negotiations.get(negotiationId);\n\t\tif (negotiation) {\n\t\t\tnegotiation.state = DataspaceProtocolContractNegotiationStateType.FINALIZED;\n\t\t\tnegotiation.updatedAt = Date.now();\n\n\t\t\tconst agreementId = OdrlPolicyHelper.getUid(negotiation.agreement);\n\t\t\tthis._negotiations.delete(negotiationId);\n\n\t\t\tawait this._loggingComponent?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"negotiationCompleted\",\n\t\t\t\tdata: {\n\t\t\t\t\tnegotiationId,\n\t\t\t\t\tagreementId,\n\t\t\t\t\tdurationMs: Date.now() - negotiation.startedAt\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (agreementId) {\n\t\t\t\tawait this._callback?.onCompleted(negotiationId, agreementId);\n\t\t\t} else {\n\t\t\t\tawait this._callback?.onFailed(negotiationId, \"negotiationFinalizedNoAgreement\");\n\t\t\t}\n\t\t} else {\n\t\t\tawait this._loggingComponent?.log({\n\t\t\t\tlevel: \"warn\",\n\t\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"unknownNegotiationFinalized\",\n\t\t\t\tdata: { negotiationId }\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * A policy termination has been sent by a provider.\n\t * Called by PNP when provider sends a TerminatedMessage or negotiation fails.\n\t * @param negotiationId The id of the negotiation.\n\t * @returns Nothing.\n\t */\n\tpublic async terminated(negotiationId: string): Promise<void> {\n\t\tawait this._loggingComponent?.log({\n\t\t\tlevel: \"warn\",\n\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"negotiationTerminated\",\n\t\t\tdata: { negotiationId }\n\t\t});\n\n\t\tconst negotiation = this._negotiations.get(negotiationId);\n\t\tif (negotiation) {\n\t\t\tnegotiation.state = DataspaceProtocolContractNegotiationStateType.TERMINATED;\n\t\t\tnegotiation.updatedAt = Date.now();\n\n\t\t\tthis._negotiations.delete(negotiationId);\n\n\t\t\tawait this._loggingComponent?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"negotiationRejected\",\n\t\t\t\tdata: {\n\t\t\t\t\tnegotiationId,\n\t\t\t\t\tdurationMs: Date.now() - negotiation.startedAt\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tawait this._callback?.onFailed(negotiationId, \"negotiationTerminatedByProvider\");\n\t\t} else {\n\t\t\tawait this._loggingComponent?.log({\n\t\t\t\tlevel: \"warn\",\n\t\t\t\tsource: DataspaceControlPlanePolicyRequester.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"unknownNegotiationTerminated\",\n\t\t\t\tdata: { negotiationId }\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
|
|
@@ -37,6 +37,7 @@ export function generateRestRoutesDataspaceControlPlane(baseRouteName, component
|
|
|
37
37
|
tag: tagsDataspaceControlPlane[0].name,
|
|
38
38
|
method: "POST",
|
|
39
39
|
path: `${baseRouteName}/transfers/request`,
|
|
40
|
+
skipAuth: true,
|
|
40
41
|
handler: async (httpRequestContext, request) => requestTransferHandler(httpRequestContext, componentName, request)
|
|
41
42
|
});
|
|
42
43
|
// GET /transfers/:pid - Get Transfer Process state (DSP)
|
|
@@ -46,6 +47,7 @@ export function generateRestRoutesDataspaceControlPlane(baseRouteName, component
|
|
|
46
47
|
tag: tagsDataspaceControlPlane[0].name,
|
|
47
48
|
method: "GET",
|
|
48
49
|
path: `${baseRouteName}/transfers/:pid`,
|
|
50
|
+
skipAuth: true,
|
|
49
51
|
handler: async (httpRequestContext, request) => getTransferProcessHandler(httpRequestContext, componentName, request)
|
|
50
52
|
});
|
|
51
53
|
// POST /transfers/:pid/start - Start Transfer Process (DSP)
|
|
@@ -55,6 +57,7 @@ export function generateRestRoutesDataspaceControlPlane(baseRouteName, component
|
|
|
55
57
|
tag: tagsDataspaceControlPlane[0].name,
|
|
56
58
|
method: "POST",
|
|
57
59
|
path: `${baseRouteName}/transfers/:pid/start`,
|
|
60
|
+
skipAuth: true,
|
|
58
61
|
handler: async (httpRequestContext, request) => startTransferHandler(httpRequestContext, componentName, request)
|
|
59
62
|
});
|
|
60
63
|
// POST /transfers/:pid/complete - Complete Transfer Process (DSP)
|
|
@@ -64,6 +67,7 @@ export function generateRestRoutesDataspaceControlPlane(baseRouteName, component
|
|
|
64
67
|
tag: tagsDataspaceControlPlane[0].name,
|
|
65
68
|
method: "POST",
|
|
66
69
|
path: `${baseRouteName}/transfers/:pid/complete`,
|
|
70
|
+
skipAuth: true,
|
|
67
71
|
handler: async (httpRequestContext, request) => completeTransferHandler(httpRequestContext, componentName, request)
|
|
68
72
|
});
|
|
69
73
|
// POST /transfers/:pid/suspend - Suspend Transfer Process (DSP)
|
|
@@ -73,6 +77,7 @@ export function generateRestRoutesDataspaceControlPlane(baseRouteName, component
|
|
|
73
77
|
tag: tagsDataspaceControlPlane[0].name,
|
|
74
78
|
method: "POST",
|
|
75
79
|
path: `${baseRouteName}/transfers/:pid/suspend`,
|
|
80
|
+
skipAuth: true,
|
|
76
81
|
handler: async (httpRequestContext, request) => suspendTransferHandler(httpRequestContext, componentName, request)
|
|
77
82
|
});
|
|
78
83
|
// POST /transfers/:pid/terminate - Terminate Transfer Process (DSP)
|
|
@@ -82,6 +87,7 @@ export function generateRestRoutesDataspaceControlPlane(baseRouteName, component
|
|
|
82
87
|
tag: tagsDataspaceControlPlane[0].name,
|
|
83
88
|
method: "POST",
|
|
84
89
|
path: `${baseRouteName}/transfers/:pid/terminate`,
|
|
90
|
+
skipAuth: true,
|
|
85
91
|
handler: async (httpRequestContext, request) => terminateTransferHandler(httpRequestContext, componentName, request)
|
|
86
92
|
});
|
|
87
93
|
return routes;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataspaceControlPlaneRoutes.js","sourceRoot":"","sources":["../../src/dataspaceControlPlaneRoutes.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIHostingComponent,\n\tIHttpRequestContext,\n\tIRestRoute,\n\tITag\n} from \"@twin.org/api-models\";\nimport { ComponentFactory, Guards } from \"@twin.org/core\";\nimport type {\n\tIDataspaceControlPlaneComponent,\n\tIRequestTransferRequest,\n\tIRequestTransferResponse,\n\tIGetTransferProcessRequest,\n\tIGetTransferProcessResponse,\n\tIStartTransferRequest,\n\tIStartTransferResponse,\n\tICompleteTransferRequest,\n\tICompleteTransferResponse,\n\tISuspendTransferRequest,\n\tISuspendTransferResponse,\n\tITerminateTransferRequest,\n\tITerminateTransferResponse\n} from \"@twin.org/dataspace-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { HeaderHelper, HeaderTypes } from \"@twin.org/web\";\nimport { transformErrorToStatusCode } from \"./utils/transferErrorUtils.js\";\n\n/**\n * The source used when communicating about these routes.\n */\nconst ROUTES_SOURCE = \"dataspaceControlPlaneRoutes\";\n\n/**\n * The tags to associate with the DSP protocol routes.\n */\nexport const tagsDataspaceControlPlane: ITag[] = [\n\t{\n\t\tname: \"Transfer Process\",\n\t\tdescription:\n\t\t\t\"DSP Transfer Process Protocol endpoints for initiating and managing data transfers.\"\n\t}\n];\n\n/**\n * The REST routes for dataspace control plane (DSP Protocol only).\n * These routes implement the Eclipse Dataspace Protocol Transfer Process Protocol.\n *\n * Contract Negotiation is handled internally via PNP callbacks — no REST endpoints needed.\n * PNP registers its own inbound callback routes for negotiation messages from providers.\n *\n * @param baseRouteName Prefix to prepend to the paths.\n * @param componentName The name of the component to use in the routes stored in the ComponentFactory.\n * @returns The generated DSP protocol routes.\n */\nexport function generateRestRoutesDataspaceControlPlane(\n\tbaseRouteName: string,\n\tcomponentName: string\n): IRestRoute[] {\n\tconst routes: IRestRoute[] = [];\n\n\t// ============================================================================\n\t// TRANSFER PROCESS PROTOCOL (DSP)\n\t// ============================================================================\n\n\t// POST /transfers/request - Request Transfer Process (DSP)\n\troutes.push({\n\t\toperationId: \"requestTransfer\",\n\t\tsummary: \"Request Transfer Process (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/transfers/request`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\trequestTransferHandler(httpRequestContext, componentName, request)\n\t});\n\n\t// GET /transfers/:pid - Get Transfer Process state (DSP)\n\troutes.push({\n\t\toperationId: \"getTransferProcess\",\n\t\tsummary: \"Get Transfer Process state (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"GET\",\n\t\tpath: `${baseRouteName}/transfers/:pid`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tgetTransferProcessHandler(httpRequestContext, componentName, request)\n\t});\n\n\t// POST /transfers/:pid/start - Start Transfer Process (DSP)\n\troutes.push({\n\t\toperationId: \"startTransfer\",\n\t\tsummary: \"Start Transfer Process (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/transfers/:pid/start`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tstartTransferHandler(httpRequestContext, componentName, request)\n\t});\n\n\t// POST /transfers/:pid/complete - Complete Transfer Process (DSP)\n\troutes.push({\n\t\toperationId: \"completeTransfer\",\n\t\tsummary: \"Complete Transfer Process (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/transfers/:pid/complete`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tcompleteTransferHandler(httpRequestContext, componentName, request)\n\t});\n\n\t// POST /transfers/:pid/suspend - Suspend Transfer Process (DSP)\n\troutes.push({\n\t\toperationId: \"suspendTransfer\",\n\t\tsummary: \"Suspend Transfer Process (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/transfers/:pid/suspend`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tsuspendTransferHandler(httpRequestContext, componentName, request)\n\t});\n\n\t// POST /transfers/:pid/terminate - Terminate Transfer Process (DSP)\n\troutes.push({\n\t\toperationId: \"terminateTransfer\",\n\t\tsummary: \"Terminate Transfer Process (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/transfers/:pid/terminate`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tterminateTransferHandler(httpRequestContext, componentName, request)\n\t});\n\n\treturn routes;\n}\n\n// ============================================================================\n// TRANSFER PROCESS PROTOCOL HANDLERS\n// ============================================================================\n\n/**\n * Request Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers and body.\n * @returns The response.\n */\nasync function requestTransferHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: IRequestTransferRequest\n): Promise<IRequestTransferResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.requestTransfer(request.body, trustPayload);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n\n/**\n * Get Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers and path parameters.\n * @returns The response.\n */\nasync function getTransferProcessHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: IGetTransferProcessRequest\n): Promise<IGetTransferProcessResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.pathParams), request.pathParams);\n\tGuards.stringValue(ROUTES_SOURCE, nameof(request.pathParams.pid), request.pathParams.pid);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.getTransferProcess(request.pathParams.pid, trustPayload);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n\n/**\n * Start Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers, path parameters, and body.\n * @returns The response.\n */\nasync function startTransferHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: IStartTransferRequest\n): Promise<IStartTransferResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst hostingComponent = ComponentFactory.get<IHostingComponent>(\n\t\thttpRequestContext.hostingComponentType ?? \"hosting\"\n\t);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.startTransfer(\n\t\trequest.body,\n\t\tawait hostingComponent.getPublicOrigin(httpRequestContext.serverRequest.url),\n\t\ttrustPayload\n\t);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n\n/**\n * Complete Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers, path parameters, and body.\n * @returns The response.\n */\nasync function completeTransferHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: ICompleteTransferRequest\n): Promise<ICompleteTransferResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.completeTransfer(request.body, trustPayload);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n\n/**\n * Suspend Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers, path parameters, and body.\n * @returns The response.\n */\nasync function suspendTransferHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: ISuspendTransferRequest\n): Promise<ISuspendTransferResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.suspendTransfer(request.body, trustPayload);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n\n/**\n * Terminate Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers, path parameters, and body.\n * @returns The response.\n */\nasync function terminateTransferHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: ITerminateTransferRequest\n): Promise<ITerminateTransferResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.terminateTransfer(request.body, trustPayload);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dataspaceControlPlaneRoutes.js","sourceRoot":"","sources":["../../src/dataspaceControlPlaneRoutes.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIHostingComponent,\n\tIHttpRequestContext,\n\tIRestRoute,\n\tITag\n} from \"@twin.org/api-models\";\nimport { ComponentFactory, Guards } from \"@twin.org/core\";\nimport type {\n\tIDataspaceControlPlaneComponent,\n\tIRequestTransferRequest,\n\tIRequestTransferResponse,\n\tIGetTransferProcessRequest,\n\tIGetTransferProcessResponse,\n\tIStartTransferRequest,\n\tIStartTransferResponse,\n\tICompleteTransferRequest,\n\tICompleteTransferResponse,\n\tISuspendTransferRequest,\n\tISuspendTransferResponse,\n\tITerminateTransferRequest,\n\tITerminateTransferResponse\n} from \"@twin.org/dataspace-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { HeaderHelper, HeaderTypes } from \"@twin.org/web\";\nimport { transformErrorToStatusCode } from \"./utils/transferErrorUtils.js\";\n\n/**\n * The source used when communicating about these routes.\n */\nconst ROUTES_SOURCE = \"dataspaceControlPlaneRoutes\";\n\n/**\n * The tags to associate with the DSP protocol routes.\n */\nexport const tagsDataspaceControlPlane: ITag[] = [\n\t{\n\t\tname: \"Transfer Process\",\n\t\tdescription:\n\t\t\t\"DSP Transfer Process Protocol endpoints for initiating and managing data transfers.\"\n\t}\n];\n\n/**\n * The REST routes for dataspace control plane (DSP Protocol only).\n * These routes implement the Eclipse Dataspace Protocol Transfer Process Protocol.\n *\n * Contract Negotiation is handled internally via PNP callbacks — no REST endpoints needed.\n * PNP registers its own inbound callback routes for negotiation messages from providers.\n *\n * @param baseRouteName Prefix to prepend to the paths.\n * @param componentName The name of the component to use in the routes stored in the ComponentFactory.\n * @returns The generated DSP protocol routes.\n */\nexport function generateRestRoutesDataspaceControlPlane(\n\tbaseRouteName: string,\n\tcomponentName: string\n): IRestRoute[] {\n\tconst routes: IRestRoute[] = [];\n\n\t// ============================================================================\n\t// TRANSFER PROCESS PROTOCOL (DSP)\n\t// ============================================================================\n\n\t// POST /transfers/request - Request Transfer Process (DSP)\n\troutes.push({\n\t\toperationId: \"requestTransfer\",\n\t\tsummary: \"Request Transfer Process (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/transfers/request`,\n\t\tskipAuth: true,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\trequestTransferHandler(httpRequestContext, componentName, request)\n\t});\n\n\t// GET /transfers/:pid - Get Transfer Process state (DSP)\n\troutes.push({\n\t\toperationId: \"getTransferProcess\",\n\t\tsummary: \"Get Transfer Process state (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"GET\",\n\t\tpath: `${baseRouteName}/transfers/:pid`,\n\t\tskipAuth: true,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tgetTransferProcessHandler(httpRequestContext, componentName, request)\n\t});\n\n\t// POST /transfers/:pid/start - Start Transfer Process (DSP)\n\troutes.push({\n\t\toperationId: \"startTransfer\",\n\t\tsummary: \"Start Transfer Process (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/transfers/:pid/start`,\n\t\tskipAuth: true,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tstartTransferHandler(httpRequestContext, componentName, request)\n\t});\n\n\t// POST /transfers/:pid/complete - Complete Transfer Process (DSP)\n\troutes.push({\n\t\toperationId: \"completeTransfer\",\n\t\tsummary: \"Complete Transfer Process (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/transfers/:pid/complete`,\n\t\tskipAuth: true,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tcompleteTransferHandler(httpRequestContext, componentName, request)\n\t});\n\n\t// POST /transfers/:pid/suspend - Suspend Transfer Process (DSP)\n\troutes.push({\n\t\toperationId: \"suspendTransfer\",\n\t\tsummary: \"Suspend Transfer Process (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/transfers/:pid/suspend`,\n\t\tskipAuth: true,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tsuspendTransferHandler(httpRequestContext, componentName, request)\n\t});\n\n\t// POST /transfers/:pid/terminate - Terminate Transfer Process (DSP)\n\troutes.push({\n\t\toperationId: \"terminateTransfer\",\n\t\tsummary: \"Terminate Transfer Process (DSP)\",\n\t\ttag: tagsDataspaceControlPlane[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/transfers/:pid/terminate`,\n\t\tskipAuth: true,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tterminateTransferHandler(httpRequestContext, componentName, request)\n\t});\n\n\treturn routes;\n}\n\n// ============================================================================\n// TRANSFER PROCESS PROTOCOL HANDLERS\n// ============================================================================\n\n/**\n * Request Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers and body.\n * @returns The response.\n */\nasync function requestTransferHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: IRequestTransferRequest\n): Promise<IRequestTransferResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.requestTransfer(request.body, trustPayload);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n\n/**\n * Get Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers and path parameters.\n * @returns The response.\n */\nasync function getTransferProcessHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: IGetTransferProcessRequest\n): Promise<IGetTransferProcessResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.pathParams), request.pathParams);\n\tGuards.stringValue(ROUTES_SOURCE, nameof(request.pathParams.pid), request.pathParams.pid);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.getTransferProcess(request.pathParams.pid, trustPayload);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n\n/**\n * Start Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers, path parameters, and body.\n * @returns The response.\n */\nasync function startTransferHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: IStartTransferRequest\n): Promise<IStartTransferResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst hostingComponent = ComponentFactory.get<IHostingComponent>(\n\t\thttpRequestContext.hostingComponentType ?? \"hosting\"\n\t);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.startTransfer(\n\t\trequest.body,\n\t\tawait hostingComponent.getPublicOrigin(httpRequestContext.serverRequest.url),\n\t\ttrustPayload\n\t);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n\n/**\n * Complete Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers, path parameters, and body.\n * @returns The response.\n */\nasync function completeTransferHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: ICompleteTransferRequest\n): Promise<ICompleteTransferResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.completeTransfer(request.body, trustPayload);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n\n/**\n * Suspend Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers, path parameters, and body.\n * @returns The response.\n */\nasync function suspendTransferHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: ISuspendTransferRequest\n): Promise<ISuspendTransferResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.suspendTransfer(request.body, trustPayload);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n\n/**\n * Terminate Transfer Process handler.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use.\n * @param request The API request containing headers, path parameters, and body.\n * @returns The response.\n */\nasync function terminateTransferHandler(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: ITerminateTransferRequest\n): Promise<ITerminateTransferResponse> {\n\tGuards.object(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst trustPayload = HeaderHelper.extractBearer(request.headers[HeaderTypes.Authorization]);\n\n\tconst component = ComponentFactory.get<IDataspaceControlPlaneComponent>(componentName);\n\tconst result = await component.terminateTransfer(request.body, trustPayload);\n\n\treturn {\n\t\tbody: result,\n\t\tstatusCode: transformErrorToStatusCode(result)\n\t};\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ContextIdKeys, ContextIdStore } from "@twin.org/context";
|
|
2
|
-
import { ArrayHelper, BaseError, ComponentFactory, Converter, GeneralError, Guards, Is, NotFoundError,
|
|
2
|
+
import { ArrayHelper, BaseError, ComponentFactory, Converter, GeneralError, Guards, Is, NotFoundError, RandomHelper, StringHelper, UnauthorizedError } from "@twin.org/core";
|
|
3
3
|
import { JsonLdHelper } from "@twin.org/data-json-ld";
|
|
4
4
|
import { DataspaceAppFactory, TransferProcessRole } from "@twin.org/dataspace-models";
|
|
5
5
|
import { EngineCoreFactory } from "@twin.org/engine-models";
|
|
@@ -333,7 +333,7 @@ export class DataspaceControlPlaneService {
|
|
|
333
333
|
* Called by: Consumer when it wants to request a new Transfer Process
|
|
334
334
|
*/
|
|
335
335
|
async requestTransfer(request, trustPayload) {
|
|
336
|
-
await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "requestTransfer");
|
|
336
|
+
const trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "requestTransfer");
|
|
337
337
|
const validationFailures = [];
|
|
338
338
|
const isConformant = await DataspaceProtocolHelper.checkConformance(JsonLdHelper.toNodeObject(request), validationFailures);
|
|
339
339
|
if (!isConformant) {
|
|
@@ -372,9 +372,17 @@ export class DataspaceControlPlaneService {
|
|
|
372
372
|
});
|
|
373
373
|
}
|
|
374
374
|
const assigneeIdentity = OdrlPolicyHelper.extractAssigneeIdentity(agreement);
|
|
375
|
-
|
|
375
|
+
const assigneeIds = ArrayHelper.fromObjectOrArray(assigneeIdentity);
|
|
376
|
+
if (!assigneeIds.includes(trustInfo.identity)) {
|
|
377
|
+
throw new UnauthorizedError(DataspaceControlPlaneService.CLASS_NAME, "callerNotAuthorizedForAgreement");
|
|
378
|
+
}
|
|
379
|
+
consumerIdentity = trustInfo.identity;
|
|
376
380
|
const assignerIdentity = OdrlPolicyHelper.extractAssignerIdentity(agreement);
|
|
377
|
-
|
|
381
|
+
const assignerIds = ArrayHelper.fromObjectOrArray(assignerIdentity);
|
|
382
|
+
if (assignerIds.length > 1) {
|
|
383
|
+
throw new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "multipleAssignersNotSupported");
|
|
384
|
+
}
|
|
385
|
+
providerIdentity = assignerIds[0];
|
|
378
386
|
datasetId = this.extractDatasetId(agreement);
|
|
379
387
|
await this.validateCatalogDataset(datasetId, agreement);
|
|
380
388
|
policies = [agreement];
|
|
@@ -390,8 +398,8 @@ export class DataspaceControlPlaneService {
|
|
|
390
398
|
state: DataspaceProtocolTransferProcessStateType.REQUESTED,
|
|
391
399
|
agreementId: request.agreementId,
|
|
392
400
|
datasetId,
|
|
393
|
-
consumerIdentity
|
|
394
|
-
providerIdentity
|
|
401
|
+
consumerIdentity,
|
|
402
|
+
providerIdentity,
|
|
395
403
|
// offerId should reference Catalog Offer (via Agreement)
|
|
396
404
|
// For now, use agreementId as reference (proper flow: Catalog → Negotiation → Agreement)
|
|
397
405
|
offerId: request.agreementId,
|
|
@@ -437,7 +445,7 @@ export class DataspaceControlPlaneService {
|
|
|
437
445
|
* Role Performed: Provider / Consumer
|
|
438
446
|
*/
|
|
439
447
|
async startTransfer(message, publicOrigin, trustPayload) {
|
|
440
|
-
await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "startTransfer");
|
|
448
|
+
const trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "startTransfer");
|
|
441
449
|
const validationFailures = [];
|
|
442
450
|
const isConformant = await DataspaceProtocolHelper.checkConformance(JsonLdHelper.toNodeObject(message), validationFailures);
|
|
443
451
|
if (!isConformant) {
|
|
@@ -447,6 +455,7 @@ export class DataspaceControlPlaneService {
|
|
|
447
455
|
}
|
|
448
456
|
try {
|
|
449
457
|
const { entity, role } = await this.lookupTransferByMessage(message);
|
|
458
|
+
this.validateCallerIsProvider(trustInfo.identity, entity);
|
|
450
459
|
if (entity.state !== DataspaceProtocolTransferProcessStateType.REQUESTED &&
|
|
451
460
|
entity.state !== DataspaceProtocolTransferProcessStateType.SUSPENDED) {
|
|
452
461
|
return transformToTransferError(new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "invalidStateForStart", {
|
|
@@ -501,13 +510,21 @@ export class DataspaceControlPlaneService {
|
|
|
501
510
|
providerPid: entity.providerPid
|
|
502
511
|
}), message);
|
|
503
512
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
513
|
+
// Provider signs the data access token with its own identity.
|
|
514
|
+
// The subject contains the transfer context claims that the data plane
|
|
515
|
+
// will verify when the consumer presents this token.
|
|
516
|
+
if (!Is.stringValue(entity.providerIdentity)) {
|
|
517
|
+
throw new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "providerIdentityMissing");
|
|
518
|
+
}
|
|
519
|
+
const accessToken = await this._trustComponent.generate(entity.providerIdentity, this._overrideTrustGeneratorType, {
|
|
520
|
+
subject: {
|
|
521
|
+
consumerPid: entity.consumerPid,
|
|
522
|
+
providerPid: entity.providerPid,
|
|
523
|
+
agreementId: entity.agreementId,
|
|
524
|
+
datasetId: entity.datasetId
|
|
525
|
+
}
|
|
509
526
|
});
|
|
510
|
-
const tokenString =
|
|
527
|
+
const tokenString = accessToken;
|
|
511
528
|
const fullEndpoint = `${publicOrigin}/${this._dataPlanePath}`;
|
|
512
529
|
response.dataAddress = {
|
|
513
530
|
"@type": DataspaceProtocolTransferProcessTypes.DataAddress,
|
|
@@ -586,7 +603,7 @@ export class DataspaceControlPlaneService {
|
|
|
586
603
|
* @returns Transfer Process (DSP compliant) with state COMPLETED, or TransferError if the operation fails.
|
|
587
604
|
*/
|
|
588
605
|
async completeTransfer(message, trustPayload) {
|
|
589
|
-
await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "completeTransfer");
|
|
606
|
+
const trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "completeTransfer");
|
|
590
607
|
const validationFailures = [];
|
|
591
608
|
const isConformant = await DataspaceProtocolHelper.checkConformance(JsonLdHelper.toNodeObject(message), validationFailures);
|
|
592
609
|
if (!isConformant) {
|
|
@@ -594,6 +611,7 @@ export class DataspaceControlPlaneService {
|
|
|
594
611
|
}
|
|
595
612
|
try {
|
|
596
613
|
const { entity, role } = await this.lookupTransferByMessage(message);
|
|
614
|
+
this.validateCallerIsConsumer(trustInfo.identity, entity);
|
|
597
615
|
if (entity.state !== DataspaceProtocolTransferProcessStateType.STARTED) {
|
|
598
616
|
return transformToTransferError(new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "invalidStateForComplete", {
|
|
599
617
|
consumerPid: entity.consumerPid,
|
|
@@ -634,7 +652,7 @@ export class DataspaceControlPlaneService {
|
|
|
634
652
|
* @returns Transfer Process (DSP compliant) with state SUSPENDED, or TransferError if the operation fails.
|
|
635
653
|
*/
|
|
636
654
|
async suspendTransfer(message, trustPayload) {
|
|
637
|
-
await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "suspendTransfer");
|
|
655
|
+
const trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "suspendTransfer");
|
|
638
656
|
const validationFailures = [];
|
|
639
657
|
const isConformant = await DataspaceProtocolHelper.checkConformance(JsonLdHelper.toNodeObject(message), validationFailures);
|
|
640
658
|
if (!isConformant) {
|
|
@@ -642,6 +660,7 @@ export class DataspaceControlPlaneService {
|
|
|
642
660
|
}
|
|
643
661
|
try {
|
|
644
662
|
const { entity, role } = await this.lookupTransferByMessage(message);
|
|
663
|
+
this.validateCallerIsTransferParty(trustInfo.identity, entity);
|
|
645
664
|
if (entity.state !== DataspaceProtocolTransferProcessStateType.STARTED) {
|
|
646
665
|
return transformToTransferError(new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "invalidStateForSuspend", {
|
|
647
666
|
consumerPid: entity.consumerPid,
|
|
@@ -683,7 +702,7 @@ export class DataspaceControlPlaneService {
|
|
|
683
702
|
* @returns Transfer Process (DSP compliant) with state TERMINATED, or TransferError if the operation fails.
|
|
684
703
|
*/
|
|
685
704
|
async terminateTransfer(message, trustPayload) {
|
|
686
|
-
await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "terminateTransfer");
|
|
705
|
+
const trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "terminateTransfer");
|
|
687
706
|
const validationFailures = [];
|
|
688
707
|
const isConformant = await DataspaceProtocolHelper.checkConformance(JsonLdHelper.toNodeObject(message), validationFailures);
|
|
689
708
|
if (!isConformant) {
|
|
@@ -691,6 +710,7 @@ export class DataspaceControlPlaneService {
|
|
|
691
710
|
}
|
|
692
711
|
try {
|
|
693
712
|
const { entity, role } = await this.lookupTransferByMessage(message);
|
|
713
|
+
this.validateCallerIsTransferParty(trustInfo.identity, entity);
|
|
694
714
|
entity.state = DataspaceProtocolTransferProcessStateType.TERMINATED;
|
|
695
715
|
entity.dateModified = new Date();
|
|
696
716
|
await this._transferProcessStorage.set(this.modelToStorageEntity(entity));
|
|
@@ -725,9 +745,10 @@ export class DataspaceControlPlaneService {
|
|
|
725
745
|
* @returns Transfer Process (DSP compliant) with current state, or TransferError if the operation fails.
|
|
726
746
|
*/
|
|
727
747
|
async getTransferProcess(pid, trustPayload) {
|
|
728
|
-
await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "getTransferProcess");
|
|
748
|
+
const trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "getTransferProcess");
|
|
729
749
|
try {
|
|
730
750
|
const { entity, role } = await this.lookupTransferByPid(pid);
|
|
751
|
+
this.validateCallerIsTransferParty(trustInfo.identity, entity);
|
|
731
752
|
await this._loggingComponent?.log({
|
|
732
753
|
level: "info",
|
|
733
754
|
source: DataspaceControlPlaneService.CLASS_NAME,
|
|
@@ -759,13 +780,15 @@ export class DataspaceControlPlaneService {
|
|
|
759
780
|
* Returns immediately with a negotiationId. The caller is notified
|
|
760
781
|
* via the registered INegotiationCallback when the negotiation completes.
|
|
761
782
|
*
|
|
783
|
+
* @param datasetId The dataset ID from the provider's catalog.
|
|
762
784
|
* @param offerId The offer ID from the provider's catalog.
|
|
763
785
|
* @param providerEndpoint The provider's contract negotiation endpoint URL.
|
|
764
786
|
* @param publicOrigin The public origin URL of this control plane (for callbacks).
|
|
765
787
|
* @param trustPayload The trust payload for authentication.
|
|
766
788
|
* @returns The negotiation ID. Use the registered callback for completion notification.
|
|
767
789
|
*/
|
|
768
|
-
async negotiateAgreement(offerId, providerEndpoint, publicOrigin, trustPayload) {
|
|
790
|
+
async negotiateAgreement(datasetId, offerId, providerEndpoint, publicOrigin, trustPayload) {
|
|
791
|
+
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "datasetId", datasetId);
|
|
769
792
|
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "offerId", offerId);
|
|
770
793
|
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "providerEndpoint", providerEndpoint);
|
|
771
794
|
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "publicOrigin", publicOrigin);
|
|
@@ -774,17 +797,19 @@ export class DataspaceControlPlaneService {
|
|
|
774
797
|
source: DataspaceControlPlaneService.CLASS_NAME,
|
|
775
798
|
ts: Date.now(),
|
|
776
799
|
message: "startingContractNegotiation",
|
|
777
|
-
data: { offerId, providerEndpoint, publicOrigin }
|
|
800
|
+
data: { datasetId, offerId, providerEndpoint, publicOrigin }
|
|
778
801
|
});
|
|
779
|
-
const catalogResult = await this._federatedCatalogueComponent.get(
|
|
802
|
+
const catalogResult = await this._federatedCatalogueComponent.get(datasetId);
|
|
780
803
|
if (isCatalogError(catalogResult)) {
|
|
781
804
|
if (isCatalogErrorName(catalogResult, NotFoundError.CLASS_NAME)) {
|
|
782
|
-
throw new NotFoundError(DataspaceControlPlaneService.CLASS_NAME, "datasetNotFoundInCatalog",
|
|
805
|
+
throw new NotFoundError(DataspaceControlPlaneService.CLASS_NAME, "datasetNotFoundInCatalog", datasetId, {
|
|
806
|
+
datasetId,
|
|
783
807
|
offerId,
|
|
784
808
|
providerEndpoint
|
|
785
809
|
});
|
|
786
810
|
}
|
|
787
811
|
throw new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "catalogLookupFailedForNegotiation", {
|
|
812
|
+
datasetId,
|
|
788
813
|
offerId,
|
|
789
814
|
providerEndpoint,
|
|
790
815
|
errorCode: catalogResult.code
|
|
@@ -960,13 +985,13 @@ export class DataspaceControlPlaneService {
|
|
|
960
985
|
});
|
|
961
986
|
}
|
|
962
987
|
const assignerIdentity = OdrlPolicyHelper.extractAssignerIdentity(agreement);
|
|
963
|
-
const
|
|
964
|
-
if (
|
|
988
|
+
const assignerIds = ArrayHelper.fromObjectOrArray(assignerIdentity);
|
|
989
|
+
if (!assignerIds.includes(currentOrgId)) {
|
|
965
990
|
throw new UnauthorizedError(DataspaceControlPlaneService.CLASS_NAME, "agreementAssignerMismatch", {
|
|
966
991
|
consumerPid,
|
|
967
992
|
agreementId: OdrlPolicyHelper.getUid(agreement),
|
|
968
993
|
expectedOrgId: currentOrgId,
|
|
969
|
-
actualAssigner:
|
|
994
|
+
actualAssigner: assignerIds.join(", ")
|
|
970
995
|
});
|
|
971
996
|
}
|
|
972
997
|
await this._loggingComponent?.log({
|
|
@@ -1020,26 +1045,27 @@ export class DataspaceControlPlaneService {
|
|
|
1020
1045
|
}
|
|
1021
1046
|
// Extract assigner UID (can be string, array, or IOdrlParty object)
|
|
1022
1047
|
const assignerIdentity = OdrlPolicyHelper.extractAssignerIdentity(agreement);
|
|
1023
|
-
const
|
|
1024
|
-
if (
|
|
1048
|
+
const assignerIds = ArrayHelper.fromObjectOrArray(assignerIdentity);
|
|
1049
|
+
if (!assignerIds.includes(currentOrgId)) {
|
|
1025
1050
|
throw new UnauthorizedError(DataspaceControlPlaneService.CLASS_NAME, "agreementAssignerMismatchProvider", {
|
|
1026
1051
|
providerPid,
|
|
1027
1052
|
agreementId: OdrlPolicyHelper.getUid(agreement),
|
|
1028
1053
|
expectedOrgId: currentOrgId,
|
|
1029
|
-
actualAssigner:
|
|
1054
|
+
actualAssigner: assignerIds.join(", ")
|
|
1030
1055
|
});
|
|
1031
1056
|
}
|
|
1032
1057
|
// Validate that Agreement assignee matches expected consumer identity
|
|
1033
1058
|
// This ensures we're pushing to the correct consumer
|
|
1034
1059
|
// If assignee is undefined but consumerIdentity has a value, this is also a mismatch
|
|
1035
1060
|
const assigneeIdentity = OdrlPolicyHelper.extractAssigneeIdentity(agreement);
|
|
1036
|
-
const
|
|
1037
|
-
if (
|
|
1061
|
+
const assigneeIds = ArrayHelper.fromObjectOrArray(assigneeIdentity);
|
|
1062
|
+
if (!Is.stringValue(entity.consumerIdentity) ||
|
|
1063
|
+
!assigneeIds.includes(entity.consumerIdentity)) {
|
|
1038
1064
|
throw new UnauthorizedError(DataspaceControlPlaneService.CLASS_NAME, "agreementAssigneeMismatch", {
|
|
1039
1065
|
providerPid,
|
|
1040
1066
|
agreementId: OdrlPolicyHelper.getUid(agreement),
|
|
1041
1067
|
expectedConsumerIdentity: entity.consumerIdentity,
|
|
1042
|
-
actualAssignee:
|
|
1068
|
+
actualAssignee: assigneeIds.join(", ")
|
|
1043
1069
|
});
|
|
1044
1070
|
}
|
|
1045
1071
|
await this._loggingComponent?.log({
|
|
@@ -1189,6 +1215,42 @@ export class DataspaceControlPlaneService {
|
|
|
1189
1215
|
}
|
|
1190
1216
|
return agreement;
|
|
1191
1217
|
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Validate that the caller's verified identity matches the consumer of a transfer process.
|
|
1220
|
+
* @param callerIdentity The identity from the verified trust token.
|
|
1221
|
+
* @param entity The transfer process entity.
|
|
1222
|
+
* @throws UnauthorizedError if the caller is not the consumer.
|
|
1223
|
+
* @internal
|
|
1224
|
+
*/
|
|
1225
|
+
validateCallerIsConsumer(callerIdentity, entity) {
|
|
1226
|
+
if (callerIdentity !== entity.consumerIdentity) {
|
|
1227
|
+
throw new UnauthorizedError(DataspaceControlPlaneService.CLASS_NAME, "callerNotAuthorizedAsConsumer");
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Validate that the caller's verified identity matches the provider of a transfer process.
|
|
1232
|
+
* @param callerIdentity The identity from the verified trust token.
|
|
1233
|
+
* @param entity The transfer process entity.
|
|
1234
|
+
* @throws UnauthorizedError if the caller is not the provider.
|
|
1235
|
+
* @internal
|
|
1236
|
+
*/
|
|
1237
|
+
validateCallerIsProvider(callerIdentity, entity) {
|
|
1238
|
+
if (callerIdentity !== entity.providerIdentity) {
|
|
1239
|
+
throw new UnauthorizedError(DataspaceControlPlaneService.CLASS_NAME, "callerNotAuthorizedAsProvider");
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Validate that the caller's verified identity matches either the consumer or provider of a transfer process.
|
|
1244
|
+
* @param callerIdentity The identity from the verified trust token.
|
|
1245
|
+
* @param entity The transfer process entity.
|
|
1246
|
+
* @throws UnauthorizedError if the caller is not a party to the transfer.
|
|
1247
|
+
* @internal
|
|
1248
|
+
*/
|
|
1249
|
+
validateCallerIsTransferParty(callerIdentity, entity) {
|
|
1250
|
+
if (callerIdentity !== entity.consumerIdentity && callerIdentity !== entity.providerIdentity) {
|
|
1251
|
+
throw new UnauthorizedError(DataspaceControlPlaneService.CLASS_NAME, "callerNotAuthorizedForTransfer");
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1192
1254
|
/**
|
|
1193
1255
|
* Extract dataset ID from Agreement target.
|
|
1194
1256
|
* @param agreement Agreement.
|
|
@@ -1236,7 +1298,7 @@ export class DataspaceControlPlaneService {
|
|
|
1236
1298
|
}
|
|
1237
1299
|
throw new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "catalogLookupFailed", {
|
|
1238
1300
|
datasetId,
|
|
1239
|
-
agreementId: agreement
|
|
1301
|
+
agreementId: OdrlPolicyHelper.getUid(agreement) ?? "",
|
|
1240
1302
|
errorCode: catalogResult.code
|
|
1241
1303
|
});
|
|
1242
1304
|
}
|
|
@@ -1247,7 +1309,7 @@ export class DataspaceControlPlaneService {
|
|
|
1247
1309
|
message: "catalogDatasetFound",
|
|
1248
1310
|
data: {
|
|
1249
1311
|
datasetId,
|
|
1250
|
-
agreementId: agreement
|
|
1312
|
+
agreementId: OdrlPolicyHelper.getUid(agreement) ?? "",
|
|
1251
1313
|
datasetTitle: catalogResult["dcterms:title"]
|
|
1252
1314
|
}
|
|
1253
1315
|
});
|
|
@@ -1301,11 +1363,15 @@ export class DataspaceControlPlaneService {
|
|
|
1301
1363
|
getCatalogDatasetPolicies(catalogDataset) {
|
|
1302
1364
|
// Support both "odrl:hasPolicy" and "hasPolicy" to accommodate different catalog implementations
|
|
1303
1365
|
if (Is.object(catalogDataset) && !Is.empty(catalogDataset["odrl:hasPolicy"])) {
|
|
1304
|
-
|
|
1366
|
+
const items = ArrayHelper.fromObjectOrArray(catalogDataset["odrl:hasPolicy"]) ?? [];
|
|
1367
|
+
return items.map(item => ({
|
|
1368
|
+
...item,
|
|
1369
|
+
"@id": OdrlPolicyHelper.getUid(item) ?? ""
|
|
1370
|
+
}));
|
|
1305
1371
|
}
|
|
1306
1372
|
if (Is.object(catalogDataset) &&
|
|
1307
1373
|
!Is.empty(catalogDataset.hasPolicy)) {
|
|
1308
|
-
return
|
|
1374
|
+
return ArrayHelper.fromObjectOrArray(catalogDataset.hasPolicy) ?? [];
|
|
1309
1375
|
}
|
|
1310
1376
|
return [];
|
|
1311
1377
|
}
|
|
@@ -1318,6 +1384,10 @@ export class DataspaceControlPlaneService {
|
|
|
1318
1384
|
async validateAgreementMatchesOffer(agreement, catalogDataset) {
|
|
1319
1385
|
Guards.object(DataspaceControlPlaneService.CLASS_NAME, "agreement", agreement);
|
|
1320
1386
|
Guards.object(DataspaceControlPlaneService.CLASS_NAME, "catalogDataset", catalogDataset);
|
|
1387
|
+
const datasetId = getJsonLdId(catalogDataset);
|
|
1388
|
+
if (!Is.stringValue(datasetId)) {
|
|
1389
|
+
throw new NotFoundError(DataspaceControlPlaneService.CLASS_NAME, "catalogDatasetMissingId");
|
|
1390
|
+
}
|
|
1321
1391
|
const rawOffers = this.getCatalogDatasetPolicies(catalogDataset);
|
|
1322
1392
|
if (!Is.arrayValue(rawOffers)) {
|
|
1323
1393
|
await this._loggingComponent?.log({
|
|
@@ -1327,7 +1397,7 @@ export class DataspaceControlPlaneService {
|
|
|
1327
1397
|
message: "catalogDatasetHasNoOffers",
|
|
1328
1398
|
data: {
|
|
1329
1399
|
datasetId: getJsonLdId(catalogDataset) ?? "",
|
|
1330
|
-
agreementId: agreement
|
|
1400
|
+
agreementId: OdrlPolicyHelper.getUid(agreement) ?? ""
|
|
1331
1401
|
}
|
|
1332
1402
|
});
|
|
1333
1403
|
return;
|
|
@@ -1341,16 +1411,16 @@ export class DataspaceControlPlaneService {
|
|
|
1341
1411
|
message: "catalogDatasetHasNoOffers",
|
|
1342
1412
|
data: {
|
|
1343
1413
|
datasetId: getJsonLdId(catalogDataset) ?? "",
|
|
1344
|
-
agreementId: agreement
|
|
1414
|
+
agreementId: OdrlPolicyHelper.getUid(agreement) ?? ""
|
|
1345
1415
|
}
|
|
1346
1416
|
});
|
|
1347
1417
|
return;
|
|
1348
1418
|
}
|
|
1349
|
-
const matchingOffer = catalogOffers.find((offer) => OdrlPolicyHelper.getUid(offer) === agreement
|
|
1419
|
+
const matchingOffer = catalogOffers.find((offer) => OdrlPolicyHelper.getUid(offer) === OdrlPolicyHelper.getUid(agreement) ||
|
|
1350
1420
|
this.isPolicyDerivedFrom(agreement, offer));
|
|
1351
1421
|
if (!matchingOffer) {
|
|
1352
1422
|
throw new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "agreementNotMatchingOffer", {
|
|
1353
|
-
agreementId: agreement
|
|
1423
|
+
agreementId: OdrlPolicyHelper.getUid(agreement) ?? "",
|
|
1354
1424
|
datasetId: getJsonLdId(catalogDataset) ?? "",
|
|
1355
1425
|
availableOffers: catalogOffers
|
|
1356
1426
|
.map((o) => OdrlPolicyHelper.getUid(o) ?? "unknown")
|
|
@@ -1363,17 +1433,22 @@ export class DataspaceControlPlaneService {
|
|
|
1363
1433
|
ts: Date.now(),
|
|
1364
1434
|
message: "agreementMatchedOffer",
|
|
1365
1435
|
data: {
|
|
1366
|
-
agreementId: agreement
|
|
1436
|
+
agreementId: OdrlPolicyHelper.getUid(agreement) ?? "",
|
|
1367
1437
|
offerId: OdrlPolicyHelper.getUid(matchingOffer) ?? "",
|
|
1368
|
-
datasetId
|
|
1438
|
+
datasetId
|
|
1369
1439
|
}
|
|
1370
1440
|
});
|
|
1371
1441
|
}
|
|
1372
1442
|
/**
|
|
1373
1443
|
* Check if an Agreement is derived from an Offer.
|
|
1444
|
+
* Per the DS Protocol spec, Offers within a Dataset's hasPolicy array must NOT
|
|
1445
|
+
* include an explicit "target" property — the target is implicitly the Dataset itself.
|
|
1446
|
+
* When the offer has no explicit targets, we use the datasetId as the implicit target
|
|
1447
|
+
* so that the comparison with the agreement's target can succeed.
|
|
1374
1448
|
* @param agreement Agreement to check.
|
|
1375
1449
|
* @param offer Offer to compare against.
|
|
1376
1450
|
* @returns True if Agreement appears derived from Offer.
|
|
1451
|
+
* @see https://eclipse-dataspace-protocol-base.github.io/DataspaceProtocol/2025-1-err1/#lower-level-types
|
|
1377
1452
|
* @internal
|
|
1378
1453
|
*/
|
|
1379
1454
|
isPolicyDerivedFrom(agreement, offer) {
|