@twin.org/dataspace-control-plane-service 0.9.0 → 0.9.1-next.10

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.
Files changed (46) hide show
  1. package/README.md +1 -1
  2. package/dist/es/dataspaceControlPlaneRoutes.js +79 -7
  3. package/dist/es/dataspaceControlPlaneRoutes.js.map +1 -1
  4. package/dist/es/dataspaceControlPlaneService.js +121 -356
  5. package/dist/es/dataspaceControlPlaneService.js.map +1 -1
  6. package/dist/es/factories/transferHandlerFactory.js +11 -0
  7. package/dist/es/factories/transferHandlerFactory.js.map +1 -0
  8. package/dist/es/handlers/httpDataPostTransferHandler.js +111 -0
  9. package/dist/es/handlers/httpDataPostTransferHandler.js.map +1 -0
  10. package/dist/es/handlers/httpDataPullTransferHandler.js +108 -0
  11. package/dist/es/handlers/httpDataPullTransferHandler.js.map +1 -0
  12. package/dist/es/handlers/httpDataPushTransferHandler.js +114 -0
  13. package/dist/es/handlers/httpDataPushTransferHandler.js.map +1 -0
  14. package/dist/es/index.js +7 -0
  15. package/dist/es/index.js.map +1 -1
  16. package/dist/es/models/IDataspaceControlPlaneServiceConfig.js.map +1 -1
  17. package/dist/es/models/ITransferHandler.js +2 -0
  18. package/dist/es/models/ITransferHandler.js.map +1 -0
  19. package/dist/es/models/ITransferHandlerPrepareContext.js +4 -0
  20. package/dist/es/models/ITransferHandlerPrepareContext.js.map +1 -0
  21. package/dist/es/models/ITransferHandlerStartContext.js +2 -0
  22. package/dist/es/models/ITransferHandlerStartContext.js.map +1 -0
  23. package/dist/types/dataspaceControlPlaneRoutes.d.ts +1 -1
  24. package/dist/types/dataspaceControlPlaneService.d.ts +6 -1
  25. package/dist/types/factories/transferHandlerFactory.d.ts +8 -0
  26. package/dist/types/handlers/httpDataPostTransferHandler.d.ts +63 -0
  27. package/dist/types/handlers/httpDataPullTransferHandler.d.ts +63 -0
  28. package/dist/types/handlers/httpDataPushTransferHandler.d.ts +68 -0
  29. package/dist/types/index.d.ts +7 -0
  30. package/dist/types/models/IDataspaceControlPlaneServiceConfig.d.ts +10 -5
  31. package/dist/types/models/ITransferHandler.d.ts +62 -0
  32. package/dist/types/models/ITransferHandlerPrepareContext.d.ts +21 -0
  33. package/dist/types/models/ITransferHandlerStartContext.d.ts +31 -0
  34. package/docs/changelog.md +190 -0
  35. package/docs/reference/classes/DataspaceControlPlaneService.md +18 -0
  36. package/docs/reference/classes/HttpDataPostTransferHandler.md +235 -0
  37. package/docs/reference/classes/HttpDataPullTransferHandler.md +235 -0
  38. package/docs/reference/classes/HttpDataPushTransferHandler.md +242 -0
  39. package/docs/reference/index.md +7 -0
  40. package/docs/reference/interfaces/IDataspaceControlPlaneServiceConfig.md +10 -5
  41. package/docs/reference/interfaces/ITransferHandler.md +180 -0
  42. package/docs/reference/interfaces/ITransferHandlerPrepareContext.md +35 -0
  43. package/docs/reference/interfaces/ITransferHandlerStartContext.md +51 -0
  44. package/docs/reference/variables/TransferHandlerFactory.md +7 -0
  45. package/locales/en.json +14 -11
  46. package/package.json +18 -18
@@ -0,0 +1,11 @@
1
+ // Copyright 2026 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { Factory } from "@twin.org/core";
4
+ /**
5
+ * Factory for registering and retrieving format-specific ITransferHandler instances.
6
+ * Keys are DataspaceTransferFormat values (e.g. "HttpData-PULL").
7
+ * Throws GeneralError when get() is called with an unregistered format.
8
+ */
9
+ // eslint-disable-next-line @typescript-eslint/naming-convention
10
+ export const TransferHandlerFactory = Factory.createFactory("transfer-handler");
11
+ //# sourceMappingURL=transferHandlerFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transferHandlerFactory.js","sourceRoot":"","sources":["../../../src/factories/transferHandlerFactory.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAGzC;;;;GAIG;AACH,gEAAgE;AAChE,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC,aAAa,CAAmB,kBAAkB,CAAC,CAAC","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Factory } from \"@twin.org/core\";\nimport type { ITransferHandler } from \"../models/ITransferHandler.js\";\n\n/**\n * Factory for registering and retrieving format-specific ITransferHandler instances.\n * Keys are DataspaceTransferFormat values (e.g. \"HttpData-PULL\").\n * Throws GeneralError when get() is called with an unregistered format.\n */\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport const TransferHandlerFactory = Factory.createFactory<ITransferHandler>(\"transfer-handler\");\n"]}
@@ -0,0 +1,111 @@
1
+ // Copyright 2026 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { HttpUrlHelper } from "@twin.org/api-models";
4
+ import { ContextIdKeys } from "@twin.org/context";
5
+ import { GeneralError, Guards, Is } from "@twin.org/core";
6
+ import { DataspaceProtocolEndpointType, DataspaceProtocolTransferProcessTypes } from "@twin.org/standards-dataspace-protocol";
7
+ import { EndpointProperties } from "../models/endpointProperties.js";
8
+ /**
9
+ * Transfer handler for HttpData-POST format (provider-initiated push).
10
+ * The consumer does not supply a dataAddress. The provider returns its own /inbox URL
11
+ * along with a signed JWT so the consumer can authenticate when posting activities there.
12
+ */
13
+ export class HttpDataPostTransferHandler {
14
+ /**
15
+ * Runtime name for the class.
16
+ */
17
+ static CLASS_NAME = "HttpDataPostTransferHandler";
18
+ /**
19
+ * Returns the class name of the component.
20
+ * @returns The class name of the component.
21
+ */
22
+ className() {
23
+ return HttpDataPostTransferHandler.CLASS_NAME;
24
+ }
25
+ /**
26
+ * POST consumers do not supply a dataAddress — provider returns its own /inbox on start.
27
+ * @param ctx Prepare context (unused for POST).
28
+ * @returns undefined.
29
+ */
30
+ buildConsumerDataAddress(ctx) {
31
+ return undefined;
32
+ }
33
+ /**
34
+ * Build the provider's /inbox dataAddress and signed JWT for the TransferStartMessage.
35
+ * @param ctx Start context containing entity, trust component, and path configuration.
36
+ * @returns The provider's ActivityStream inbox dataAddress with bearer token.
37
+ * @throws GeneralError When dataPlanePath is not configured or providerIdentity is missing.
38
+ */
39
+ async buildProviderStartDataAddress(ctx) {
40
+ const { entity, publicOrigin, dataPlanePath, organizationIdentity, trustComponent, overrideTrustGeneratorType } = ctx;
41
+ if (!Is.stringValue(dataPlanePath)) {
42
+ throw new GeneralError(HttpDataPostTransferHandler.CLASS_NAME, "pushTransferDataPathNotConfigured", { consumerPid: entity.consumerPid });
43
+ }
44
+ if (!Is.stringValue(entity.providerIdentity)) {
45
+ throw new GeneralError(HttpDataPostTransferHandler.CLASS_NAME, "providerIdentityMissing");
46
+ }
47
+ const accessToken = await trustComponent.generate(entity.providerIdentity, overrideTrustGeneratorType, {
48
+ subject: {
49
+ consumerPid: entity.consumerPid,
50
+ providerPid: entity.providerPid,
51
+ agreementId: entity.agreementId,
52
+ datasetId: entity.datasetId
53
+ }
54
+ });
55
+ Guards.stringValue(HttpDataPostTransferHandler.CLASS_NAME, "accessToken", accessToken);
56
+ const fullEndpoint = HttpUrlHelper.addQueryStringParam(`${publicOrigin}/${dataPlanePath}/inbox`, ContextIdKeys.Organization, organizationIdentity);
57
+ return {
58
+ "@type": DataspaceProtocolTransferProcessTypes.DataAddress,
59
+ endpointType: DataspaceProtocolEndpointType.HttpsActivityStreamEndpoint,
60
+ endpoint: fullEndpoint,
61
+ endpointProperties: [
62
+ {
63
+ "@type": DataspaceProtocolTransferProcessTypes.EndpointProperty,
64
+ name: EndpointProperties.Authorization,
65
+ value: accessToken
66
+ },
67
+ {
68
+ "@type": DataspaceProtocolTransferProcessTypes.EndpointProperty,
69
+ name: EndpointProperties.AuthType,
70
+ value: "bearer"
71
+ }
72
+ ]
73
+ };
74
+ }
75
+ /**
76
+ * No-op: POST transfers do not involve a provider-managed push subscription on start.
77
+ * @param dataPlaneComponent The data plane component instance.
78
+ * @param consumerPid The consumer process ID.
79
+ * @param previousState The state before the STARTED transition.
80
+ * @returns A promise that resolves immediately.
81
+ */
82
+ async onProviderStart(dataPlaneComponent, consumerPid, previousState) { }
83
+ /**
84
+ * Tear down the data plane subscription when the transfer completes.
85
+ * @param dataPlaneComponent The data plane component instance.
86
+ * @param consumerPid The consumer process ID.
87
+ * @returns A promise that resolves when the subscription is torn down.
88
+ */
89
+ async onComplete(dataPlaneComponent, consumerPid) {
90
+ await dataPlaneComponent.teardownPushSubscription(consumerPid);
91
+ }
92
+ /**
93
+ * Suspend the data plane subscription when the transfer is suspended.
94
+ * @param dataPlaneComponent The data plane component instance.
95
+ * @param consumerPid The consumer process ID.
96
+ * @returns A promise that resolves when the subscription is suspended.
97
+ */
98
+ async onSuspend(dataPlaneComponent, consumerPid) {
99
+ await dataPlaneComponent.suspendPushSubscription(consumerPid);
100
+ }
101
+ /**
102
+ * Tear down the data plane subscription when the transfer terminates.
103
+ * @param dataPlaneComponent The data plane component instance.
104
+ * @param consumerPid The consumer process ID.
105
+ * @returns A promise that resolves when the subscription is torn down.
106
+ */
107
+ async onTerminate(dataPlaneComponent, consumerPid) {
108
+ await dataPlaneComponent.teardownPushSubscription(consumerPid);
109
+ }
110
+ }
111
+ //# sourceMappingURL=httpDataPostTransferHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpDataPostTransferHandler.js","sourceRoot":"","sources":["../../../src/handlers/httpDataPostTransferHandler.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAG1D,OAAO,EACN,6BAA6B,EAC7B,qCAAqC,EACrC,MAAM,wCAAwC,CAAC;AAKhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAKrE;;;;GAIG;AACH,MAAM,OAAO,2BAA2B;IACvC;;OAEG;IACI,MAAM,CAAU,UAAU,iCAAiD;IAElF;;;OAGG;IACI,SAAS;QACf,OAAO,2BAA2B,CAAC,UAAU,CAAC;IAC/C,CAAC;IAED;;;;OAIG;IACI,wBAAwB,CAC9B,GAAmC;QAEnC,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,6BAA6B,CACzC,GAAiC;QAEjC,MAAM,EACL,MAAM,EACN,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,0BAA0B,EAC1B,GAAG,GAAG,CAAC;QAER,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,aAAa,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,YAAY,CACrB,2BAA2B,CAAC,UAAU,EACtC,mCAAmC,EACnC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CACnC,CAAC;QACH,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,YAAY,CAAC,2BAA2B,CAAC,UAAU,EAAE,yBAAyB,CAAC,CAAC;QAC3F,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,QAAQ,CAChD,MAAM,CAAC,gBAAgB,EACvB,0BAA0B,EAC1B;YACC,OAAO,EAAE;gBACR,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;aAC3B;SACD,CACD,CAAC;QAEF,MAAM,CAAC,WAAW,CAAC,2BAA2B,CAAC,UAAU,iBAAuB,WAAW,CAAC,CAAC;QAE7F,MAAM,YAAY,GAAG,aAAa,CAAC,mBAAmB,CACrD,GAAG,YAAY,IAAI,aAAa,QAAQ,EACxC,aAAa,CAAC,YAAY,EAC1B,oBAAoB,CACpB,CAAC;QAEF,OAAO;YACN,OAAO,EAAE,qCAAqC,CAAC,WAAW;YAC1D,YAAY,EAAE,6BAA6B,CAAC,2BAA2B;YACvE,QAAQ,EAAE,YAAY;YACtB,kBAAkB,EAAE;gBACnB;oBACC,OAAO,EAAE,qCAAqC,CAAC,gBAAgB;oBAC/D,IAAI,EAAE,kBAAkB,CAAC,aAAa;oBACtC,KAAK,EAAE,WAAW;iBAClB;gBACD;oBACC,OAAO,EAAE,qCAAqC,CAAC,gBAAgB;oBAC/D,IAAI,EAAE,kBAAkB,CAAC,QAAQ;oBACjC,KAAK,EAAE,QAAQ;iBACf;aACD;SACD,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,eAAe,CAC3B,kBAAgD,EAChD,WAAmB,EACnB,aAAwD,IACvC,CAAC;IAEnB;;;;;OAKG;IACI,KAAK,CAAC,UAAU,CACtB,kBAAgD,EAChD,WAAmB;QAEnB,MAAM,kBAAkB,CAAC,wBAAwB,CAAC,WAAW,CAAC,CAAC;IAChE,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,SAAS,CACrB,kBAAgD,EAChD,WAAmB;QAEnB,MAAM,kBAAkB,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC;IAC/D,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,WAAW,CACvB,kBAAgD,EAChD,WAAmB;QAEnB,MAAM,kBAAkB,CAAC,wBAAwB,CAAC,WAAW,CAAC,CAAC;IAChE,CAAC","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { HttpUrlHelper } from \"@twin.org/api-models\";\nimport { ContextIdKeys } from \"@twin.org/context\";\nimport { GeneralError, Guards, Is } from \"@twin.org/core\";\nimport type { IDataspaceDataPlaneComponent } from \"@twin.org/dataspace-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tDataspaceProtocolEndpointType,\n\tDataspaceProtocolTransferProcessTypes\n} from \"@twin.org/standards-dataspace-protocol\";\nimport type {\n\tDataspaceProtocolTransferProcessStateType,\n\tIDataspaceProtocolDataAddress\n} from \"@twin.org/standards-dataspace-protocol\";\nimport { EndpointProperties } from \"../models/endpointProperties.js\";\nimport type { ITransferHandler } from \"../models/ITransferHandler.js\";\nimport type { ITransferHandlerPrepareContext } from \"../models/ITransferHandlerPrepareContext.js\";\nimport type { ITransferHandlerStartContext } from \"../models/ITransferHandlerStartContext.js\";\n\n/**\n * Transfer handler for HttpData-POST format (provider-initiated push).\n * The consumer does not supply a dataAddress. The provider returns its own /inbox URL\n * along with a signed JWT so the consumer can authenticate when posting activities there.\n */\nexport class HttpDataPostTransferHandler implements ITransferHandler {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<HttpDataPostTransferHandler>();\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 HttpDataPostTransferHandler.CLASS_NAME;\n\t}\n\n\t/**\n\t * POST consumers do not supply a dataAddress — provider returns its own /inbox on start.\n\t * @param ctx Prepare context (unused for POST).\n\t * @returns undefined.\n\t */\n\tpublic buildConsumerDataAddress(\n\t\tctx: ITransferHandlerPrepareContext\n\t): IDataspaceProtocolDataAddress | undefined {\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Build the provider's /inbox dataAddress and signed JWT for the TransferStartMessage.\n\t * @param ctx Start context containing entity, trust component, and path configuration.\n\t * @returns The provider's ActivityStream inbox dataAddress with bearer token.\n\t * @throws GeneralError When dataPlanePath is not configured or providerIdentity is missing.\n\t */\n\tpublic async buildProviderStartDataAddress(\n\t\tctx: ITransferHandlerStartContext\n\t): Promise<IDataspaceProtocolDataAddress | undefined> {\n\t\tconst {\n\t\t\tentity,\n\t\t\tpublicOrigin,\n\t\t\tdataPlanePath,\n\t\t\torganizationIdentity,\n\t\t\ttrustComponent,\n\t\t\toverrideTrustGeneratorType\n\t\t} = ctx;\n\n\t\tif (!Is.stringValue(dataPlanePath)) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tHttpDataPostTransferHandler.CLASS_NAME,\n\t\t\t\t\"pushTransferDataPathNotConfigured\",\n\t\t\t\t{ consumerPid: entity.consumerPid }\n\t\t\t);\n\t\t}\n\n\t\tif (!Is.stringValue(entity.providerIdentity)) {\n\t\t\tthrow new GeneralError(HttpDataPostTransferHandler.CLASS_NAME, \"providerIdentityMissing\");\n\t\t}\n\n\t\tconst accessToken = await trustComponent.generate(\n\t\t\tentity.providerIdentity,\n\t\t\toverrideTrustGeneratorType,\n\t\t\t{\n\t\t\t\tsubject: {\n\t\t\t\t\tconsumerPid: entity.consumerPid,\n\t\t\t\t\tproviderPid: entity.providerPid,\n\t\t\t\t\tagreementId: entity.agreementId,\n\t\t\t\t\tdatasetId: entity.datasetId\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\n\t\tGuards.stringValue(HttpDataPostTransferHandler.CLASS_NAME, nameof(accessToken), accessToken);\n\n\t\tconst fullEndpoint = HttpUrlHelper.addQueryStringParam(\n\t\t\t`${publicOrigin}/${dataPlanePath}/inbox`,\n\t\t\tContextIdKeys.Organization,\n\t\t\torganizationIdentity\n\t\t);\n\n\t\treturn {\n\t\t\t\"@type\": DataspaceProtocolTransferProcessTypes.DataAddress,\n\t\t\tendpointType: DataspaceProtocolEndpointType.HttpsActivityStreamEndpoint,\n\t\t\tendpoint: fullEndpoint,\n\t\t\tendpointProperties: [\n\t\t\t\t{\n\t\t\t\t\t\"@type\": DataspaceProtocolTransferProcessTypes.EndpointProperty,\n\t\t\t\t\tname: EndpointProperties.Authorization,\n\t\t\t\t\tvalue: accessToken\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"@type\": DataspaceProtocolTransferProcessTypes.EndpointProperty,\n\t\t\t\t\tname: EndpointProperties.AuthType,\n\t\t\t\t\tvalue: \"bearer\"\n\t\t\t\t}\n\t\t\t]\n\t\t};\n\t}\n\n\t/**\n\t * No-op: POST transfers do not involve a provider-managed push subscription on start.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @param previousState The state before the STARTED transition.\n\t * @returns A promise that resolves immediately.\n\t */\n\tpublic async onProviderStart(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string,\n\t\tpreviousState: DataspaceProtocolTransferProcessStateType\n\t): Promise<void> {}\n\n\t/**\n\t * Tear down the data plane subscription when the transfer completes.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves when the subscription is torn down.\n\t */\n\tpublic async onComplete(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string\n\t): Promise<void> {\n\t\tawait dataPlaneComponent.teardownPushSubscription(consumerPid);\n\t}\n\n\t/**\n\t * Suspend the data plane subscription when the transfer is suspended.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves when the subscription is suspended.\n\t */\n\tpublic async onSuspend(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string\n\t): Promise<void> {\n\t\tawait dataPlaneComponent.suspendPushSubscription(consumerPid);\n\t}\n\n\t/**\n\t * Tear down the data plane subscription when the transfer terminates.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves when the subscription is torn down.\n\t */\n\tpublic async onTerminate(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string\n\t): Promise<void> {\n\t\tawait dataPlaneComponent.teardownPushSubscription(consumerPid);\n\t}\n}\n"]}
@@ -0,0 +1,108 @@
1
+ // Copyright 2026 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { HttpUrlHelper } from "@twin.org/api-models";
4
+ import { ContextIdKeys } from "@twin.org/context";
5
+ import { GeneralError, Guards, Is } from "@twin.org/core";
6
+ import { DataspaceProtocolEndpointType, DataspaceProtocolTransferProcessTypes } from "@twin.org/standards-dataspace-protocol";
7
+ import { EndpointProperties } from "../models/endpointProperties.js";
8
+ /**
9
+ * Transfer handler for HttpData-PULL format.
10
+ * Consumer queries the provider's data endpoint using a bearer token supplied in the
11
+ * TransferStartMessage dataAddress. No data-plane push subscription is involved.
12
+ */
13
+ export class HttpDataPullTransferHandler {
14
+ /**
15
+ * Runtime name for the class.
16
+ */
17
+ static CLASS_NAME = "HttpDataPullTransferHandler";
18
+ /**
19
+ * Returns the class name of the component.
20
+ * @returns The class name of the component.
21
+ */
22
+ className() {
23
+ return HttpDataPullTransferHandler.CLASS_NAME;
24
+ }
25
+ /**
26
+ * PULL consumers do not supply a dataAddress — the provider generates one on start.
27
+ * @param ctx Prepare context (unused for PULL).
28
+ * @returns undefined.
29
+ */
30
+ buildConsumerDataAddress(ctx) {
31
+ return undefined;
32
+ }
33
+ /**
34
+ * Build the provider's data endpoint and bearer token for the TransferStartMessage.
35
+ * @param ctx Start context containing entity, trust component, and path configuration.
36
+ * @returns The dataAddress carrying the query endpoint and bearer token.
37
+ * @throws GeneralError When dataPlanePath is not configured or providerIdentity is missing.
38
+ */
39
+ async buildProviderStartDataAddress(ctx) {
40
+ const { entity, publicOrigin, dataPlanePath, organizationIdentity, trustComponent, overrideTrustGeneratorType } = ctx;
41
+ if (!Is.stringValue(dataPlanePath)) {
42
+ throw new GeneralError(HttpDataPullTransferHandler.CLASS_NAME, "pullTransfersNotSupported", {
43
+ consumerPid: entity.consumerPid,
44
+ providerPid: entity.providerPid
45
+ });
46
+ }
47
+ if (!Is.stringValue(entity.providerIdentity)) {
48
+ throw new GeneralError(HttpDataPullTransferHandler.CLASS_NAME, "providerIdentityMissing");
49
+ }
50
+ const accessToken = await trustComponent.generate(entity.providerIdentity, overrideTrustGeneratorType, {
51
+ subject: {
52
+ consumerPid: entity.consumerPid,
53
+ providerPid: entity.providerPid,
54
+ agreementId: entity.agreementId,
55
+ datasetId: entity.datasetId
56
+ }
57
+ });
58
+ Guards.stringValue(HttpDataPullTransferHandler.CLASS_NAME, "accessToken", accessToken);
59
+ const fullEndpoint = HttpUrlHelper.addQueryStringParam(`${publicOrigin}/${dataPlanePath}/entities`, ContextIdKeys.Organization, organizationIdentity);
60
+ return {
61
+ "@type": DataspaceProtocolTransferProcessTypes.DataAddress,
62
+ endpointType: DataspaceProtocolEndpointType.HttpsQueryEndpoint,
63
+ endpoint: fullEndpoint,
64
+ endpointProperties: [
65
+ {
66
+ "@type": DataspaceProtocolTransferProcessTypes.EndpointProperty,
67
+ name: EndpointProperties.Authorization,
68
+ value: accessToken
69
+ },
70
+ {
71
+ "@type": DataspaceProtocolTransferProcessTypes.EndpointProperty,
72
+ name: EndpointProperties.AuthType,
73
+ value: "bearer"
74
+ }
75
+ ]
76
+ };
77
+ }
78
+ /**
79
+ * No-op: PULL transfers require no push subscription.
80
+ * @param dataPlaneComponent The data plane component instance.
81
+ * @param consumerPid The consumer process ID.
82
+ * @param previousState The state before the STARTED transition.
83
+ * @returns A promise that resolves immediately.
84
+ */
85
+ async onProviderStart(dataPlaneComponent, consumerPid, previousState) { }
86
+ /**
87
+ * No-op: PULL transfers have no push subscription to tear down.
88
+ * @param dataPlaneComponent The data plane component instance.
89
+ * @param consumerPid The consumer process ID.
90
+ * @returns A promise that resolves immediately.
91
+ */
92
+ async onComplete(dataPlaneComponent, consumerPid) { }
93
+ /**
94
+ * No-op: PULL transfers have no push subscription to suspend.
95
+ * @param dataPlaneComponent The data plane component instance.
96
+ * @param consumerPid The consumer process ID.
97
+ * @returns A promise that resolves immediately.
98
+ */
99
+ async onSuspend(dataPlaneComponent, consumerPid) { }
100
+ /**
101
+ * No-op: PULL transfers have no push subscription to tear down.
102
+ * @param dataPlaneComponent The data plane component instance.
103
+ * @param consumerPid The consumer process ID.
104
+ * @returns A promise that resolves immediately.
105
+ */
106
+ async onTerminate(dataPlaneComponent, consumerPid) { }
107
+ }
108
+ //# sourceMappingURL=httpDataPullTransferHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpDataPullTransferHandler.js","sourceRoot":"","sources":["../../../src/handlers/httpDataPullTransferHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { HttpUrlHelper } from \"@twin.org/api-models\";\nimport { ContextIdKeys } from \"@twin.org/context\";\nimport { GeneralError, Guards, Is } from \"@twin.org/core\";\nimport type { IDataspaceDataPlaneComponent } from \"@twin.org/dataspace-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tDataspaceProtocolEndpointType,\n\tDataspaceProtocolTransferProcessTypes\n} from \"@twin.org/standards-dataspace-protocol\";\nimport type {\n\tDataspaceProtocolTransferProcessStateType,\n\tIDataspaceProtocolDataAddress\n} from \"@twin.org/standards-dataspace-protocol\";\nimport { EndpointProperties } from \"../models/endpointProperties.js\";\nimport type { ITransferHandler } from \"../models/ITransferHandler.js\";\nimport type { ITransferHandlerPrepareContext } from \"../models/ITransferHandlerPrepareContext.js\";\nimport type { ITransferHandlerStartContext } from \"../models/ITransferHandlerStartContext.js\";\n\n/**\n * Transfer handler for HttpData-PULL format.\n * Consumer queries the provider's data endpoint using a bearer token supplied in the\n * TransferStartMessage dataAddress. No data-plane push subscription is involved.\n */\nexport class HttpDataPullTransferHandler implements ITransferHandler {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<HttpDataPullTransferHandler>();\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 HttpDataPullTransferHandler.CLASS_NAME;\n\t}\n\n\t/**\n\t * PULL consumers do not supply a dataAddress — the provider generates one on start.\n\t * @param ctx Prepare context (unused for PULL).\n\t * @returns undefined.\n\t */\n\tpublic buildConsumerDataAddress(\n\t\tctx: ITransferHandlerPrepareContext\n\t): IDataspaceProtocolDataAddress | undefined {\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Build the provider's data endpoint and bearer token for the TransferStartMessage.\n\t * @param ctx Start context containing entity, trust component, and path configuration.\n\t * @returns The dataAddress carrying the query endpoint and bearer token.\n\t * @throws GeneralError When dataPlanePath is not configured or providerIdentity is missing.\n\t */\n\tpublic async buildProviderStartDataAddress(\n\t\tctx: ITransferHandlerStartContext\n\t): Promise<IDataspaceProtocolDataAddress | undefined> {\n\t\tconst {\n\t\t\tentity,\n\t\t\tpublicOrigin,\n\t\t\tdataPlanePath,\n\t\t\torganizationIdentity,\n\t\t\ttrustComponent,\n\t\t\toverrideTrustGeneratorType\n\t\t} = ctx;\n\n\t\tif (!Is.stringValue(dataPlanePath)) {\n\t\t\tthrow new GeneralError(HttpDataPullTransferHandler.CLASS_NAME, \"pullTransfersNotSupported\", {\n\t\t\t\tconsumerPid: entity.consumerPid,\n\t\t\t\tproviderPid: entity.providerPid\n\t\t\t});\n\t\t}\n\n\t\tif (!Is.stringValue(entity.providerIdentity)) {\n\t\t\tthrow new GeneralError(HttpDataPullTransferHandler.CLASS_NAME, \"providerIdentityMissing\");\n\t\t}\n\n\t\tconst accessToken = await trustComponent.generate(\n\t\t\tentity.providerIdentity,\n\t\t\toverrideTrustGeneratorType,\n\t\t\t{\n\t\t\t\tsubject: {\n\t\t\t\t\tconsumerPid: entity.consumerPid,\n\t\t\t\t\tproviderPid: entity.providerPid,\n\t\t\t\t\tagreementId: entity.agreementId,\n\t\t\t\t\tdatasetId: entity.datasetId\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\n\t\tGuards.stringValue(HttpDataPullTransferHandler.CLASS_NAME, nameof(accessToken), accessToken);\n\n\t\tconst fullEndpoint = HttpUrlHelper.addQueryStringParam(\n\t\t\t`${publicOrigin}/${dataPlanePath}/entities`,\n\t\t\tContextIdKeys.Organization,\n\t\t\torganizationIdentity\n\t\t);\n\n\t\treturn {\n\t\t\t\"@type\": DataspaceProtocolTransferProcessTypes.DataAddress,\n\t\t\tendpointType: DataspaceProtocolEndpointType.HttpsQueryEndpoint,\n\t\t\tendpoint: fullEndpoint,\n\t\t\tendpointProperties: [\n\t\t\t\t{\n\t\t\t\t\t\"@type\": DataspaceProtocolTransferProcessTypes.EndpointProperty,\n\t\t\t\t\tname: EndpointProperties.Authorization,\n\t\t\t\t\tvalue: accessToken\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"@type\": DataspaceProtocolTransferProcessTypes.EndpointProperty,\n\t\t\t\t\tname: EndpointProperties.AuthType,\n\t\t\t\t\tvalue: \"bearer\"\n\t\t\t\t}\n\t\t\t]\n\t\t};\n\t}\n\n\t/**\n\t * No-op: PULL transfers require no push subscription.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @param previousState The state before the STARTED transition.\n\t * @returns A promise that resolves immediately.\n\t */\n\tpublic async onProviderStart(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string,\n\t\tpreviousState: DataspaceProtocolTransferProcessStateType\n\t): Promise<void> {}\n\n\t/**\n\t * No-op: PULL transfers have no push subscription to tear down.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves immediately.\n\t */\n\tpublic async onComplete(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string\n\t): Promise<void> {}\n\n\t/**\n\t * No-op: PULL transfers have no push subscription to suspend.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves immediately.\n\t */\n\tpublic async onSuspend(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string\n\t): Promise<void> {}\n\n\t/**\n\t * No-op: PULL transfers have no push subscription to tear down.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves immediately.\n\t */\n\tpublic async onTerminate(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string\n\t): Promise<void> {}\n}\n"]}
@@ -0,0 +1,114 @@
1
+ // Copyright 2026 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { HttpUrlHelper } from "@twin.org/api-models";
4
+ import { ContextIdKeys } from "@twin.org/context";
5
+ import { GeneralError, Is } from "@twin.org/core";
6
+ import { DataspaceProtocolEndpointType, DataspaceProtocolTransferProcessStateType, DataspaceProtocolTransferProcessTypes } from "@twin.org/standards-dataspace-protocol";
7
+ /**
8
+ * Transfer handler for HttpData-PUSH format (consumer-initiated push).
9
+ * The consumer supplies its /inbox endpoint in the TransferRequestMessage dataAddress.
10
+ * The provider pushes ActivityStreams objects to that endpoint, and returns its own
11
+ * /inbox in the TransferStartMessage so the consumer can route data notifications.
12
+ */
13
+ export class HttpDataPushTransferHandler {
14
+ /**
15
+ * Runtime name for the class.
16
+ */
17
+ static CLASS_NAME = "HttpDataPushTransferHandler";
18
+ /**
19
+ * Returns the class name of the component.
20
+ * @returns The class name of the component.
21
+ */
22
+ className() {
23
+ return HttpDataPushTransferHandler.CLASS_NAME;
24
+ }
25
+ /**
26
+ * Build the consumer's /inbox dataAddress for the TransferRequestMessage.
27
+ * @param ctx Prepare context containing path and organization identity.
28
+ * @returns The consumer's ActivityStream inbox dataAddress.
29
+ * @throws GeneralError When dataPlanePath is not configured.
30
+ */
31
+ buildConsumerDataAddress(ctx) {
32
+ const { consumerPid, origin, dataPlanePath, organizationIdentity } = ctx;
33
+ if (!Is.stringValue(dataPlanePath)) {
34
+ throw new GeneralError(HttpDataPushTransferHandler.CLASS_NAME, "pushTransferDataPathNotConfigured", {
35
+ consumerPid
36
+ });
37
+ }
38
+ const inboxEndpoint = HttpUrlHelper.addQueryStringParam(`${origin}/${dataPlanePath}/inbox`, ContextIdKeys.Organization, organizationIdentity);
39
+ return {
40
+ "@type": DataspaceProtocolTransferProcessTypes.DataAddress,
41
+ endpointType: DataspaceProtocolEndpointType.HttpsActivityStreamEndpoint,
42
+ endpoint: inboxEndpoint
43
+ };
44
+ }
45
+ /**
46
+ * Validate the consumer's dataAddress and build the provider's /inbox endpoint
47
+ * for the TransferStartMessage. No bearer token is included — the consumer authenticates
48
+ * via the DSP protocol trust payload on the push POST.
49
+ * @param ctx Start context containing entity and path configuration.
50
+ * @returns The provider's ActivityStream inbox dataAddress.
51
+ * @throws GeneralError When the consumer dataAddress is invalid or dataPlanePath is not configured.
52
+ */
53
+ async buildProviderStartDataAddress(ctx) {
54
+ const { entity, publicOrigin, dataPlanePath, organizationIdentity } = ctx;
55
+ if (!Is.stringValue(entity.dataAddress?.endpoint) ||
56
+ !Is.stringValue(entity.dataAddress?.endpointType)) {
57
+ throw new GeneralError(HttpDataPushTransferHandler.CLASS_NAME, "invalidPushDataAddress", {
58
+ consumerPid: entity.consumerPid
59
+ });
60
+ }
61
+ if (!Is.stringValue(dataPlanePath)) {
62
+ throw new GeneralError(HttpDataPushTransferHandler.CLASS_NAME, "pushTransferDataPathNotConfigured", { consumerPid: entity.consumerPid });
63
+ }
64
+ const fullEndpoint = HttpUrlHelper.addQueryStringParam(`${publicOrigin}/${dataPlanePath}/inbox`, ContextIdKeys.Organization, organizationIdentity);
65
+ return {
66
+ "@type": DataspaceProtocolTransferProcessTypes.DataAddress,
67
+ endpointType: DataspaceProtocolEndpointType.HttpsActivityStreamEndpoint,
68
+ endpoint: fullEndpoint
69
+ };
70
+ }
71
+ /**
72
+ * Set up (or resume) the data-plane push subscription after state is persisted to STARTED.
73
+ * @param dataPlaneComponent The data plane component instance.
74
+ * @param consumerPid The consumer process ID.
75
+ * @param previousState The state before the STARTED transition.
76
+ * @returns A promise that resolves when the subscription is established.
77
+ */
78
+ async onProviderStart(dataPlaneComponent, consumerPid, previousState) {
79
+ if (previousState === DataspaceProtocolTransferProcessStateType.REQUESTED) {
80
+ await dataPlaneComponent.setupPushSubscription(consumerPid);
81
+ }
82
+ else if (previousState === DataspaceProtocolTransferProcessStateType.SUSPENDED) {
83
+ await dataPlaneComponent.resumePushSubscription(consumerPid);
84
+ }
85
+ }
86
+ /**
87
+ * Tear down the push subscription when the transfer completes.
88
+ * @param dataPlaneComponent The data plane component instance.
89
+ * @param consumerPid The consumer process ID.
90
+ * @returns A promise that resolves when the subscription is torn down.
91
+ */
92
+ async onComplete(dataPlaneComponent, consumerPid) {
93
+ await dataPlaneComponent.teardownPushSubscription(consumerPid);
94
+ }
95
+ /**
96
+ * Suspend the push subscription when the transfer is suspended.
97
+ * @param dataPlaneComponent The data plane component instance.
98
+ * @param consumerPid The consumer process ID.
99
+ * @returns A promise that resolves when the subscription is suspended.
100
+ */
101
+ async onSuspend(dataPlaneComponent, consumerPid) {
102
+ await dataPlaneComponent.suspendPushSubscription(consumerPid);
103
+ }
104
+ /**
105
+ * Tear down the push subscription when the transfer terminates.
106
+ * @param dataPlaneComponent The data plane component instance.
107
+ * @param consumerPid The consumer process ID.
108
+ * @returns A promise that resolves when the subscription is torn down.
109
+ */
110
+ async onTerminate(dataPlaneComponent, consumerPid) {
111
+ await dataPlaneComponent.teardownPushSubscription(consumerPid);
112
+ }
113
+ }
114
+ //# sourceMappingURL=httpDataPushTransferHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpDataPushTransferHandler.js","sourceRoot":"","sources":["../../../src/handlers/httpDataPushTransferHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { HttpUrlHelper } from \"@twin.org/api-models\";\nimport { ContextIdKeys } from \"@twin.org/context\";\nimport { GeneralError, Is } from \"@twin.org/core\";\nimport type { IDataspaceDataPlaneComponent } from \"@twin.org/dataspace-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tDataspaceProtocolEndpointType,\n\tDataspaceProtocolTransferProcessStateType,\n\tDataspaceProtocolTransferProcessTypes\n} from \"@twin.org/standards-dataspace-protocol\";\nimport type { IDataspaceProtocolDataAddress } from \"@twin.org/standards-dataspace-protocol\";\nimport type { ITransferHandler } from \"../models/ITransferHandler.js\";\nimport type { ITransferHandlerPrepareContext } from \"../models/ITransferHandlerPrepareContext.js\";\nimport type { ITransferHandlerStartContext } from \"../models/ITransferHandlerStartContext.js\";\n\n/**\n * Transfer handler for HttpData-PUSH format (consumer-initiated push).\n * The consumer supplies its /inbox endpoint in the TransferRequestMessage dataAddress.\n * The provider pushes ActivityStreams objects to that endpoint, and returns its own\n * /inbox in the TransferStartMessage so the consumer can route data notifications.\n */\nexport class HttpDataPushTransferHandler implements ITransferHandler {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<HttpDataPushTransferHandler>();\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 HttpDataPushTransferHandler.CLASS_NAME;\n\t}\n\n\t/**\n\t * Build the consumer's /inbox dataAddress for the TransferRequestMessage.\n\t * @param ctx Prepare context containing path and organization identity.\n\t * @returns The consumer's ActivityStream inbox dataAddress.\n\t * @throws GeneralError When dataPlanePath is not configured.\n\t */\n\tpublic buildConsumerDataAddress(\n\t\tctx: ITransferHandlerPrepareContext\n\t): IDataspaceProtocolDataAddress | undefined {\n\t\tconst { consumerPid, origin, dataPlanePath, organizationIdentity } = ctx;\n\n\t\tif (!Is.stringValue(dataPlanePath)) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tHttpDataPushTransferHandler.CLASS_NAME,\n\t\t\t\t\"pushTransferDataPathNotConfigured\",\n\t\t\t\t{\n\t\t\t\t\tconsumerPid\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tconst inboxEndpoint = HttpUrlHelper.addQueryStringParam(\n\t\t\t`${origin}/${dataPlanePath}/inbox`,\n\t\t\tContextIdKeys.Organization,\n\t\t\torganizationIdentity\n\t\t);\n\n\t\treturn {\n\t\t\t\"@type\": DataspaceProtocolTransferProcessTypes.DataAddress,\n\t\t\tendpointType: DataspaceProtocolEndpointType.HttpsActivityStreamEndpoint,\n\t\t\tendpoint: inboxEndpoint\n\t\t};\n\t}\n\n\t/**\n\t * Validate the consumer's dataAddress and build the provider's /inbox endpoint\n\t * for the TransferStartMessage. No bearer token is included — the consumer authenticates\n\t * via the DSP protocol trust payload on the push POST.\n\t * @param ctx Start context containing entity and path configuration.\n\t * @returns The provider's ActivityStream inbox dataAddress.\n\t * @throws GeneralError When the consumer dataAddress is invalid or dataPlanePath is not configured.\n\t */\n\tpublic async buildProviderStartDataAddress(\n\t\tctx: ITransferHandlerStartContext\n\t): Promise<IDataspaceProtocolDataAddress | undefined> {\n\t\tconst { entity, publicOrigin, dataPlanePath, organizationIdentity } = ctx;\n\n\t\tif (\n\t\t\t!Is.stringValue(entity.dataAddress?.endpoint) ||\n\t\t\t!Is.stringValue(entity.dataAddress?.endpointType)\n\t\t) {\n\t\t\tthrow new GeneralError(HttpDataPushTransferHandler.CLASS_NAME, \"invalidPushDataAddress\", {\n\t\t\t\tconsumerPid: entity.consumerPid\n\t\t\t});\n\t\t}\n\n\t\tif (!Is.stringValue(dataPlanePath)) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tHttpDataPushTransferHandler.CLASS_NAME,\n\t\t\t\t\"pushTransferDataPathNotConfigured\",\n\t\t\t\t{ consumerPid: entity.consumerPid }\n\t\t\t);\n\t\t}\n\n\t\tconst fullEndpoint = HttpUrlHelper.addQueryStringParam(\n\t\t\t`${publicOrigin}/${dataPlanePath}/inbox`,\n\t\t\tContextIdKeys.Organization,\n\t\t\torganizationIdentity\n\t\t);\n\n\t\treturn {\n\t\t\t\"@type\": DataspaceProtocolTransferProcessTypes.DataAddress,\n\t\t\tendpointType: DataspaceProtocolEndpointType.HttpsActivityStreamEndpoint,\n\t\t\tendpoint: fullEndpoint\n\t\t};\n\t}\n\n\t/**\n\t * Set up (or resume) the data-plane push subscription after state is persisted to STARTED.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @param previousState The state before the STARTED transition.\n\t * @returns A promise that resolves when the subscription is established.\n\t */\n\tpublic async onProviderStart(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string,\n\t\tpreviousState: DataspaceProtocolTransferProcessStateType\n\t): Promise<void> {\n\t\tif (previousState === DataspaceProtocolTransferProcessStateType.REQUESTED) {\n\t\t\tawait dataPlaneComponent.setupPushSubscription(consumerPid);\n\t\t} else if (previousState === DataspaceProtocolTransferProcessStateType.SUSPENDED) {\n\t\t\tawait dataPlaneComponent.resumePushSubscription(consumerPid);\n\t\t}\n\t}\n\n\t/**\n\t * Tear down the push subscription when the transfer completes.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves when the subscription is torn down.\n\t */\n\tpublic async onComplete(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string\n\t): Promise<void> {\n\t\tawait dataPlaneComponent.teardownPushSubscription(consumerPid);\n\t}\n\n\t/**\n\t * Suspend the push subscription when the transfer is suspended.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves when the subscription is suspended.\n\t */\n\tpublic async onSuspend(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string\n\t): Promise<void> {\n\t\tawait dataPlaneComponent.suspendPushSubscription(consumerPid);\n\t}\n\n\t/**\n\t * Tear down the push subscription when the transfer terminates.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves when the subscription is torn down.\n\t */\n\tpublic async onTerminate(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string\n\t): Promise<void> {\n\t\tawait dataPlaneComponent.teardownPushSubscription(consumerPid);\n\t}\n}\n"]}
package/dist/es/index.js CHANGED
@@ -3,10 +3,17 @@
3
3
  export * from "./dataspaceControlPlanePolicyRequester.js";
4
4
  export * from "./dataspaceControlPlaneRoutes.js";
5
5
  export * from "./dataspaceControlPlaneService.js";
6
+ export * from "./factories/transferHandlerFactory.js";
7
+ export * from "./handlers/httpDataPostTransferHandler.js";
8
+ export * from "./handlers/httpDataPullTransferHandler.js";
9
+ export * from "./handlers/httpDataPushTransferHandler.js";
6
10
  export * from "./models/endpointProperties.js";
7
11
  export * from "./models/IDataspaceControlPlaneServiceConfig.js";
8
12
  export * from "./models/IDataspaceControlPlaneServiceConstructorOptions.js";
9
13
  export * from "./models/INegotiationState.js";
14
+ export * from "./models/ITransferHandler.js";
15
+ export * from "./models/ITransferHandlerPrepareContext.js";
16
+ export * from "./models/ITransferHandlerStartContext.js";
10
17
  export * from "./restEntryPoints.js";
11
18
  export * from "./schema.js";
12
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,2CAA2C,CAAC;AAC1D,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iDAAiD,CAAC;AAChE,cAAc,6DAA6D,CAAC;AAC5E,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./dataspaceControlPlanePolicyRequester.js\";\nexport * from \"./dataspaceControlPlaneRoutes.js\";\nexport * from \"./dataspaceControlPlaneService.js\";\nexport * from \"./models/endpointProperties.js\";\nexport * from \"./models/IDataspaceControlPlaneServiceConfig.js\";\nexport * from \"./models/IDataspaceControlPlaneServiceConstructorOptions.js\";\nexport * from \"./models/INegotiationState.js\";\nexport * from \"./restEntryPoints.js\";\nexport * from \"./schema.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,2CAA2C,CAAC;AAC1D,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iDAAiD,CAAC;AAChE,cAAc,6DAA6D,CAAC;AAC5E,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,0CAA0C,CAAC;AACzD,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./dataspaceControlPlanePolicyRequester.js\";\nexport * from \"./dataspaceControlPlaneRoutes.js\";\nexport * from \"./dataspaceControlPlaneService.js\";\nexport * from \"./factories/transferHandlerFactory.js\";\nexport * from \"./handlers/httpDataPostTransferHandler.js\";\nexport * from \"./handlers/httpDataPullTransferHandler.js\";\nexport * from \"./handlers/httpDataPushTransferHandler.js\";\nexport * from \"./models/endpointProperties.js\";\nexport * from \"./models/IDataspaceControlPlaneServiceConfig.js\";\nexport * from \"./models/IDataspaceControlPlaneServiceConstructorOptions.js\";\nexport * from \"./models/INegotiationState.js\";\nexport * from \"./models/ITransferHandler.js\";\nexport * from \"./models/ITransferHandlerPrepareContext.js\";\nexport * from \"./models/ITransferHandlerStartContext.js\";\nexport * from \"./restEntryPoints.js\";\nexport * from \"./schema.js\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"IDataspaceControlPlaneServiceConfig.js","sourceRoot":"","sources":["../../../src/models/IDataspaceControlPlaneServiceConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Dataspace Control Plane service configuration.\n */\nexport interface IDataspaceControlPlaneServiceConfig {\n\t/**\n\t * Override the default trust generator type for token generation.\n\t * If not specified, the default trust generator configured in the trust component will be used.\n\t */\n\toverrideTrustGeneratorType?: string;\n\n\t/**\n\t * Data plane endpoint path for PULL transfers (path only, not full URL).\n\t * Will be combined with the public origin.\n\t *\n\t * REQUIRED if PULL transfers are supported.\n\t * If not specified, PULL transfers will not be available.\n\t *\n\t * Example: \"data-plane/data\" or \"api/data-plane/data\"\n\t */\n\tdataPlanePath?: string;\n\n\t/**\n\t * Control plane callback mount path (path only). Combined with this node's public origin to form the\n\t * consumer callbackAddress a provider POSTs DSP transfer messages back to (e.g.\n\t * `<origin>/<callbackPath>/transfers/:pid/start`), with `?organization=` appended for tenant routing.\n\t *\n\t * Example: \"dataspace\" or \"api/dataspace\".\n\t */\n\tcallbackPath?: string;\n\n\t/**\n\t * Whether the provider immediately starts a transfer once it has been requested. This is a\n\t * provider-side decision only; the consumer cannot request or influence auto-start. When false\n\t * (the default) the transfer stays in REQUESTED until the provider explicitly calls transferStarted.\n\t *\n\t * Defaults to false.\n\t */\n\tautoStartTransfers?: boolean;\n\n\t/**\n\t * How long (ms) a negotiation may sit without progress before the periodic cleanup treats it as\n\t * timed out, removes it, and notifies the registered callbacks (onTimeout, falling back to\n\t * onFailed with reason \"negotiationStalled\"). Requires a task-scheduler component to be configured.\n\t *\n\t * Defaults to 1800000 (30 minutes).\n\t */\n\tstalledNegotiationTimeoutMs?: number;\n\n\t/**\n\t * How long (ms) a consumer-initiated transfer may sit in REQUESTED without the provider progressing\n\t * it before the periodic cleanup treats it as timed out, removes it, and notifies the registered\n\t * transfer callbacks (onTimeout, falling back to onFailed with reason \"transferStalled\"). Requires a\n\t * task-scheduler component to be configured.\n\t *\n\t * Defaults to 1800000 (30 minutes).\n\t */\n\tstalledTransferTimeoutMs?: number;\n}\n"]}
1
+ {"version":3,"file":"IDataspaceControlPlaneServiceConfig.js","sourceRoot":"","sources":["../../../src/models/IDataspaceControlPlaneServiceConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Dataspace Control Plane service configuration.\n */\nexport interface IDataspaceControlPlaneServiceConfig {\n\t/**\n\t * Override the default trust generator type for token generation.\n\t * If not specified, the default trust generator configured in the trust component will be used.\n\t */\n\toverrideTrustGeneratorType?: string;\n\n\t/**\n\t * Base route path for the data plane service (path only, not full URL).\n\t * Combined with the public origin to form the `dataAddress.endpoint` sent to PULL consumers\n\t * and the inbox URL sent to PUSH providers.\n\t *\n\t * This must be the mount-point prefix of the data plane routes, NOT a specific route path.\n\t * Do NOT append sub-paths such as `/entities` or `/inbox` — those are appended automatically\n\t * by each transfer handler and by the data plane REST client.\n\t *\n\t * REQUIRED if PULL or PUSH transfers are supported.\n\t * If not specified, PULL and PUSH transfers will not be available.\n\t *\n\t * Example: \"dataspace\"\n\t */\n\tdataPlanePath?: string;\n\n\t/**\n\t * Control plane callback mount path (path only). Combined with this node's public origin to form the\n\t * consumer callbackAddress a provider POSTs DSP transfer messages back to (e.g.\n\t * `<origin>/<callbackPath>/transfers/:pid/start`), with `?organization=` appended for tenant routing.\n\t *\n\t * Example: \"dataspace\" or \"api/dataspace\".\n\t */\n\tcallbackPath?: string;\n\n\t/**\n\t * Whether the provider immediately starts a transfer once it has been requested. This is a\n\t * provider-side decision only; the consumer cannot request or influence auto-start. When false\n\t * (the default) the transfer stays in REQUESTED until the provider explicitly calls transferStarted.\n\t *\n\t * Defaults to false.\n\t */\n\tautoStartTransfers?: boolean;\n\n\t/**\n\t * How long (ms) a negotiation may sit without progress before the periodic cleanup treats it as\n\t * timed out, removes it, and notifies the registered callbacks (onTimeout, falling back to\n\t * onFailed with reason \"negotiationStalled\"). Requires a task-scheduler component to be configured.\n\t *\n\t * Defaults to 1800000 (30 minutes).\n\t */\n\tstalledNegotiationTimeoutMs?: number;\n\n\t/**\n\t * How long (ms) a consumer-initiated transfer may sit in REQUESTED without the provider progressing\n\t * it before the periodic cleanup treats it as timed out, removes it, and notifies the registered\n\t * transfer callbacks (onTimeout, falling back to onFailed with reason \"transferStalled\"). Requires a\n\t * task-scheduler component to be configured.\n\t *\n\t * Defaults to 1800000 (30 minutes).\n\t */\n\tstalledTransferTimeoutMs?: number;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ITransferHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITransferHandler.js","sourceRoot":"","sources":["../../../src/models/ITransferHandler.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IComponent } from \"@twin.org/core\";\nimport type { IDataspaceDataPlaneComponent } from \"@twin.org/dataspace-models\";\nimport type {\n\tDataspaceProtocolTransferProcessStateType,\n\tIDataspaceProtocolDataAddress\n} from \"@twin.org/standards-dataspace-protocol\";\nimport type { ITransferHandlerPrepareContext } from \"./ITransferHandlerPrepareContext.js\";\nimport type { ITransferHandlerStartContext } from \"./ITransferHandlerStartContext.js\";\n\n/**\n * Format-specific handler for transfer process operations.\n * One implementation exists per DataspaceTransferFormat value; the TransferHandlerFactory\n * returns the correct instance keyed on the format string.\n */\nexport interface ITransferHandler extends IComponent {\n\t/**\n\t * Optionally build a consumer dataAddress for the TransferRequestMessage.\n\t * Called during prepareTransfer. Returns undefined for formats that do not\n\t * require a consumer-supplied dataAddress (PULL and POST).\n\t * @param ctx The prepare context.\n\t * @returns The consumer dataAddress, or undefined if not required for this format.\n\t */\n\tbuildConsumerDataAddress(\n\t\tctx: ITransferHandlerPrepareContext\n\t): IDataspaceProtocolDataAddress | undefined;\n\n\t/**\n\t * Build the provider dataAddress for the TransferStartMessage.\n\t * Called during startTransfer (provider role). Throws a GeneralError when\n\t * required configuration (e.g. dataPlanePath) is absent.\n\t * @param ctx The start context.\n\t * @returns The provider dataAddress, or undefined if not applicable.\n\t */\n\tbuildProviderStartDataAddress(\n\t\tctx: ITransferHandlerStartContext\n\t): Promise<IDataspaceProtocolDataAddress | undefined>;\n\n\t/**\n\t * Post-start hook for the provider role. Called after state has been persisted\n\t * to STARTED. PUSH transfers set up (or resume) the data-plane push subscription\n\t * here; all other formats are no-ops.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @param previousState The state before the STARTED transition.\n\t * @returns A promise that resolves when the hook completes.\n\t */\n\tonProviderStart(\n\t\tdataPlaneComponent: IDataspaceDataPlaneComponent,\n\t\tconsumerPid: string,\n\t\tpreviousState: DataspaceProtocolTransferProcessStateType\n\t): Promise<void>;\n\n\t/**\n\t * Called after a transfer transitions to COMPLETED.\n\t * PUSH and POST tear down the push subscription; PULL is a no-op.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves when the hook completes.\n\t */\n\tonComplete(dataPlaneComponent: IDataspaceDataPlaneComponent, consumerPid: string): Promise<void>;\n\n\t/**\n\t * Called after a transfer transitions to SUSPENDED.\n\t * PUSH and POST suspend the push subscription; PULL is a no-op.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves when the hook completes.\n\t */\n\tonSuspend(dataPlaneComponent: IDataspaceDataPlaneComponent, consumerPid: string): Promise<void>;\n\n\t/**\n\t * Called after a transfer transitions to TERMINATED.\n\t * PUSH and POST tear down the push subscription; PULL is a no-op.\n\t * @param dataPlaneComponent The data plane component instance.\n\t * @param consumerPid The consumer process ID.\n\t * @returns A promise that resolves when the hook completes.\n\t */\n\tonTerminate(dataPlaneComponent: IDataspaceDataPlaneComponent, consumerPid: string): Promise<void>;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2026 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=ITransferHandlerPrepareContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITransferHandlerPrepareContext.js","sourceRoot":"","sources":["../../../src/models/ITransferHandlerPrepareContext.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Context supplied to buildConsumerDataAddress during prepareTransfer.\n */\nexport interface ITransferHandlerPrepareContext {\n\t/**\n\t * The consumer process ID.\n\t */\n\tconsumerPid: string;\n\n\t/**\n\t * The consumer's base origin URL.\n\t */\n\torigin: string;\n\n\t/**\n\t * The data plane path segment, if configured.\n\t */\n\tdataPlanePath: string | undefined;\n\n\t/**\n\t * The organization identity resolved from the current context.\n\t */\n\torganizationIdentity: string;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ITransferHandlerStartContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITransferHandlerStartContext.js","sourceRoot":"","sources":["../../../src/models/ITransferHandlerStartContext.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITransferProcess } from \"@twin.org/dataspace-models\";\nimport type { ITrustComponent } from \"@twin.org/trust-models\";\n\n/**\n * Context supplied to buildProviderStartDataAddress during startTransfer (provider role).\n */\nexport interface ITransferHandlerStartContext {\n\t/**\n\t * The transfer process entity.\n\t */\n\tentity: ITransferProcess;\n\n\t/**\n\t * The provider's public origin URL.\n\t */\n\tpublicOrigin: string;\n\n\t/**\n\t * The data plane path segment, if configured.\n\t */\n\tdataPlanePath: string | undefined;\n\n\t/**\n\t * The organization identity resolved from the current context.\n\t */\n\torganizationIdentity: string;\n\n\t/**\n\t * The trust component for generating access tokens.\n\t */\n\ttrustComponent: ITrustComponent;\n\n\t/**\n\t * The override trust generator type, if configured.\n\t */\n\toverrideTrustGeneratorType: string | undefined;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { IRestRoute, ITag } from "@twin.org/api-models";
1
+ import { type IRestRoute, type ITag } from "@twin.org/api-models";
2
2
  /**
3
3
  * The tags to associate with the DSP protocol routes.
4
4
  */
@@ -1,5 +1,5 @@
1
1
  import { type IDataspaceAppDataset, type IDataspaceControlPlaneComponent, type IDataspaceControlPlaneResolverComponent, type INegotiationCallback, type ITransferCallback, type ITransferContext } from "@twin.org/dataspace-models";
2
- import { type IDataspaceProtocolContractNegotiation, type IDataspaceProtocolContractNegotiationError, type IDataspaceProtocolDataset, type IDataspaceProtocolTransferCompletionMessage, type IDataspaceProtocolTransferError, type IDataspaceProtocolTransferProcess, type IDataspaceProtocolTransferRequestMessage, type IDataspaceProtocolTransferStartMessage, type IDataspaceProtocolTransferSuspensionMessage, type IDataspaceProtocolTransferTerminationMessage } from "@twin.org/standards-dataspace-protocol";
2
+ import { type IDataspaceProtocolContractNegotiation, type IDataspaceProtocolContractNegotiationError, type IDataspaceProtocolDataset, type IDataspaceProtocolTransferCompletionMessage, type IDataspaceProtocolTransferError, type IDataspaceProtocolTransferProcess, type IDataspaceProtocolTransferRequestMessage, type IDataspaceProtocolTransferStartMessage, type IDataspaceProtocolTransferSuspensionMessage, type IDataspaceProtocolTransferTerminationMessage, type IDataspaceProtocolVersionResponse } from "@twin.org/standards-dataspace-protocol";
3
3
  import type { IDataspaceControlPlaneServiceConstructorOptions } from "./models/IDataspaceControlPlaneServiceConstructorOptions.js";
4
4
  /**
5
5
  * Dataspace Control Plane Service implementation.
@@ -235,4 +235,9 @@ export declare class DataspaceControlPlaneService implements IDataspaceControlPl
235
235
  * @returns A promise that resolves when the dataset has been removed from storage and the catalogue.
236
236
  */
237
237
  deleteAppDataset(id: string): Promise<void>;
238
+ /**
239
+ * Return the Dataspace Protocol versions supported by this connector.
240
+ * @returns The protocol version response listing all supported DSP versions.
241
+ */
242
+ getProtocolVersions(): Promise<IDataspaceProtocolVersionResponse>;
238
243
  }
@@ -0,0 +1,8 @@
1
+ import { Factory } from "@twin.org/core";
2
+ import type { ITransferHandler } from "../models/ITransferHandler.js";
3
+ /**
4
+ * Factory for registering and retrieving format-specific ITransferHandler instances.
5
+ * Keys are DataspaceTransferFormat values (e.g. "HttpData-PULL").
6
+ * Throws GeneralError when get() is called with an unregistered format.
7
+ */
8
+ export declare const TransferHandlerFactory: Factory<ITransferHandler>;
@@ -0,0 +1,63 @@
1
+ import type { IDataspaceDataPlaneComponent } from "@twin.org/dataspace-models";
2
+ import type { DataspaceProtocolTransferProcessStateType, IDataspaceProtocolDataAddress } from "@twin.org/standards-dataspace-protocol";
3
+ import type { ITransferHandler } from "../models/ITransferHandler.js";
4
+ import type { ITransferHandlerPrepareContext } from "../models/ITransferHandlerPrepareContext.js";
5
+ import type { ITransferHandlerStartContext } from "../models/ITransferHandlerStartContext.js";
6
+ /**
7
+ * Transfer handler for HttpData-POST format (provider-initiated push).
8
+ * The consumer does not supply a dataAddress. The provider returns its own /inbox URL
9
+ * along with a signed JWT so the consumer can authenticate when posting activities there.
10
+ */
11
+ export declare class HttpDataPostTransferHandler implements ITransferHandler {
12
+ /**
13
+ * Runtime name for the class.
14
+ */
15
+ static readonly CLASS_NAME: string;
16
+ /**
17
+ * Returns the class name of the component.
18
+ * @returns The class name of the component.
19
+ */
20
+ className(): string;
21
+ /**
22
+ * POST consumers do not supply a dataAddress — provider returns its own /inbox on start.
23
+ * @param ctx Prepare context (unused for POST).
24
+ * @returns undefined.
25
+ */
26
+ buildConsumerDataAddress(ctx: ITransferHandlerPrepareContext): IDataspaceProtocolDataAddress | undefined;
27
+ /**
28
+ * Build the provider's /inbox dataAddress and signed JWT for the TransferStartMessage.
29
+ * @param ctx Start context containing entity, trust component, and path configuration.
30
+ * @returns The provider's ActivityStream inbox dataAddress with bearer token.
31
+ * @throws GeneralError When dataPlanePath is not configured or providerIdentity is missing.
32
+ */
33
+ buildProviderStartDataAddress(ctx: ITransferHandlerStartContext): Promise<IDataspaceProtocolDataAddress | undefined>;
34
+ /**
35
+ * No-op: POST transfers do not involve a provider-managed push subscription on start.
36
+ * @param dataPlaneComponent The data plane component instance.
37
+ * @param consumerPid The consumer process ID.
38
+ * @param previousState The state before the STARTED transition.
39
+ * @returns A promise that resolves immediately.
40
+ */
41
+ onProviderStart(dataPlaneComponent: IDataspaceDataPlaneComponent, consumerPid: string, previousState: DataspaceProtocolTransferProcessStateType): Promise<void>;
42
+ /**
43
+ * Tear down the data plane subscription when the transfer completes.
44
+ * @param dataPlaneComponent The data plane component instance.
45
+ * @param consumerPid The consumer process ID.
46
+ * @returns A promise that resolves when the subscription is torn down.
47
+ */
48
+ onComplete(dataPlaneComponent: IDataspaceDataPlaneComponent, consumerPid: string): Promise<void>;
49
+ /**
50
+ * Suspend the data plane subscription when the transfer is suspended.
51
+ * @param dataPlaneComponent The data plane component instance.
52
+ * @param consumerPid The consumer process ID.
53
+ * @returns A promise that resolves when the subscription is suspended.
54
+ */
55
+ onSuspend(dataPlaneComponent: IDataspaceDataPlaneComponent, consumerPid: string): Promise<void>;
56
+ /**
57
+ * Tear down the data plane subscription when the transfer terminates.
58
+ * @param dataPlaneComponent The data plane component instance.
59
+ * @param consumerPid The consumer process ID.
60
+ * @returns A promise that resolves when the subscription is torn down.
61
+ */
62
+ onTerminate(dataPlaneComponent: IDataspaceDataPlaneComponent, consumerPid: string): Promise<void>;
63
+ }