gdc-common-utils-ts 1.12.0 → 1.14.0
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/README.md +61 -2
- package/dist/constants/dataspace-discovery.d.ts +11 -0
- package/dist/constants/dataspace-discovery.js +11 -0
- package/dist/constants/dataspace-protocol.d.ts +27 -0
- package/dist/constants/dataspace-protocol.js +27 -0
- package/dist/constants/index.d.ts +2 -0
- package/dist/constants/index.js +2 -0
- package/dist/constants/network.d.ts +17 -5
- package/dist/constants/network.js +9 -5
- package/dist/examples/dataspace-discovery.d.ts +10 -0
- package/dist/examples/dataspace-discovery.js +16 -4
- package/dist/examples/shared.d.ts +9 -2
- package/dist/examples/shared.js +10 -2
- package/dist/models/dataspace-discovery-defaults.d.ts +78 -0
- package/dist/models/dataspace-discovery-defaults.js +2 -0
- package/dist/models/dataspace-discovery.d.ts +2 -0
- package/dist/models/dataspace-protocol.d.ts +14 -0
- package/dist/models/dataspace-protocol.js +2 -0
- package/dist/models/index.d.ts +2 -0
- package/dist/models/index.js +2 -0
- package/dist/utils/dataspace-discovery-defaults.d.ts +66 -0
- package/dist/utils/dataspace-discovery-defaults.js +172 -0
- package/dist/utils/dataspace-discovery.d.ts +89 -0
- package/dist/utils/dataspace-discovery.js +141 -0
- package/dist/utils/dataspace-protocol.d.ts +66 -0
- package/dist/utils/dataspace-protocol.js +109 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,9 +89,68 @@ import { JweObject, JwtCompactParts } from 'gdc-common-utils-ts/models';
|
|
|
89
89
|
- [docs/DATASPACE_DISCOVERY_ROADMAP.md](docs/DATASPACE_DISCOVERY_ROADMAP.md)
|
|
90
90
|
- cross-repo contract for dataspace discovery semantics, EU coverage
|
|
91
91
|
inference, shared DTOs, and parameterized examples
|
|
92
|
+
- [docs/DATASPACE_DISCOVERY_DEFAULTS_101.md](docs/DATASPACE_DISCOVERY_DEFAULTS_101.md)
|
|
93
|
+
- portal/backend bootstrap guide for `defaults-only`, `default-first`, and
|
|
94
|
+
`internet-first` discovery seeding by `jurisdiction + version + networkType`
|
|
92
95
|
- [docs/consent-access-matrix-task.md](docs/consent-access-matrix-task.md)
|
|
93
96
|
- next-step design/task document for active consent aggregation, explicit deny precedence, controller views, permission-request communications, and SMART access evaluation
|
|
94
97
|
|
|
98
|
+
## Dataspace Protocol And Discovery
|
|
99
|
+
|
|
100
|
+
Use `gdc-common-utils-ts` as the shared source of truth for DSP route building,
|
|
101
|
+
`dspace-version` metadata, and normalized discovery DTOs.
|
|
102
|
+
|
|
103
|
+
Main entry points:
|
|
104
|
+
|
|
105
|
+
- [`src/utils/dataspace-protocol.ts`](src/utils/dataspace-protocol.ts)
|
|
106
|
+
- canonical GW CORE path builders for host-scoped and tenant-scoped DSP
|
|
107
|
+
routes
|
|
108
|
+
- [`src/utils/dataspace-discovery.ts`](src/utils/dataspace-discovery.ts)
|
|
109
|
+
- semantic extraction, provider filtering, default DTO builders, and the
|
|
110
|
+
copy/paste fetcher harness used by docs/tests
|
|
111
|
+
- [`src/utils/dataspace-discovery-defaults.ts`](src/utils/dataspace-discovery-defaults.ts)
|
|
112
|
+
- defaults registry for ICAs and hosting operators plus the backend
|
|
113
|
+
`default-first` bootstrap plan used to unblock portal integration
|
|
114
|
+
- [`src/examples/dataspace-discovery.ts`](src/examples/dataspace-discovery.ts)
|
|
115
|
+
- synthetic provider/operator examples that distinguish discovery URL from
|
|
116
|
+
derived catalog artifact URL
|
|
117
|
+
- [`docs/DATASPACE_DISCOVERY_DEFAULTS_101.md`](docs/DATASPACE_DISCOVERY_DEFAULTS_101.md)
|
|
118
|
+
- copy/paste backend bootstrap guide for portal `default-first` rollout
|
|
119
|
+
- [`__tests__/dataspace-discovery-defaults.101.test.ts`](__tests__/dataspace-discovery-defaults.101.test.ts)
|
|
120
|
+
- executable defaults-registry examples for ICAs, hosting operators, and
|
|
121
|
+
source-mode behavior
|
|
122
|
+
- [`__tests__/dataspace-protocol.test.ts`](__tests__/dataspace-protocol.test.ts)
|
|
123
|
+
- executable path and `dspace-version` examples
|
|
124
|
+
- [`__tests__/dataspace-discovery.test.ts`](__tests__/dataspace-discovery.test.ts)
|
|
125
|
+
- executable semantic extraction and filtering examples
|
|
126
|
+
|
|
127
|
+
Copy/paste example:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import {
|
|
131
|
+
buildDspaceVersionMetadata,
|
|
132
|
+
buildGwCatalogArtifactPath,
|
|
133
|
+
buildGwDspaceVersionWellKnownPath,
|
|
134
|
+
deriveGwCatalogArtifactUrlFromDspaceVersion,
|
|
135
|
+
} from 'gdc-common-utils-ts/utils/dataspace-protocol';
|
|
136
|
+
import { HostNetworkTypes } from 'gdc-common-utils-ts/constants/network';
|
|
137
|
+
|
|
138
|
+
const hostContext = {
|
|
139
|
+
participantId: 'host',
|
|
140
|
+
jurisdiction: 'ES',
|
|
141
|
+
version: 'v1',
|
|
142
|
+
hostNetwork: HostNetworkTypes.Test,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const discoveryPath = buildGwDspaceVersionWellKnownPath(hostContext);
|
|
146
|
+
const metadata = buildDspaceVersionMetadata('/host/cds-ES/v1/test/dsp');
|
|
147
|
+
const catalogPath = buildGwCatalogArtifactPath(hostContext);
|
|
148
|
+
const catalogUrl = deriveGwCatalogArtifactUrlFromDspaceVersion(
|
|
149
|
+
`https://host.example.org${discoveryPath}`,
|
|
150
|
+
metadata,
|
|
151
|
+
);
|
|
152
|
+
```
|
|
153
|
+
|
|
95
154
|
## API Index
|
|
96
155
|
|
|
97
156
|
The canonical API contract should live in JSDoc on exported code. The README acts as a navigable index.
|
|
@@ -116,8 +175,8 @@ The canonical API contract should live in JSDoc on exported code. The README act
|
|
|
116
175
|
- Reusable professional role/permission examples tying actor role, consent action, SMART scope, and expected FHIR resource types together.
|
|
117
176
|
- [`DeviceUserClasses`, `DeviceAppTypes`](src/constants/device.ts)
|
|
118
177
|
- Shared user-class and app/device-type constants used by licensing and SDK flows.
|
|
119
|
-
- [`
|
|
120
|
-
- Shared network/environment labels for
|
|
178
|
+
- [`HostNetworkTypes`](src/constants/network.ts)
|
|
179
|
+
- Shared network/environment labels for host discovery/bootstrap.
|
|
121
180
|
- [`SmartGatewayScopesFhirR4`](src/constants/smart.ts)
|
|
122
181
|
- Current CORE GW SMART scope literals such as `organization/Consent.cruds`.
|
|
123
182
|
- Treat these as optional elevated scopes. Do not add them to the first read-only tutorial by default.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared discovery-source policies used by backend/bootstrap layers that must
|
|
3
|
+
* decide whether to start from configured defaults or from live internet/ICA
|
|
4
|
+
* discovery.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DataspaceDiscoverySourceMode: Readonly<{
|
|
7
|
+
readonly DefaultFirst: "default-first";
|
|
8
|
+
readonly DefaultsOnly: "defaults-only";
|
|
9
|
+
readonly InternetFirst: "internet-first";
|
|
10
|
+
}>;
|
|
11
|
+
export type DataspaceDiscoverySourceModeValue = typeof DataspaceDiscoverySourceMode[keyof typeof DataspaceDiscoverySourceMode];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
/**
|
|
3
|
+
* Shared discovery-source policies used by backend/bootstrap layers that must
|
|
4
|
+
* decide whether to start from configured defaults or from live internet/ICA
|
|
5
|
+
* discovery.
|
|
6
|
+
*/
|
|
7
|
+
export const DataspaceDiscoverySourceMode = Object.freeze({
|
|
8
|
+
DefaultFirst: 'default-first',
|
|
9
|
+
DefaultsOnly: 'defaults-only',
|
|
10
|
+
InternetFirst: 'internet-first',
|
|
11
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical Dataspace Protocol version identifiers used by the current GW/SDK
|
|
3
|
+
* discovery flows.
|
|
4
|
+
*/
|
|
5
|
+
export declare const DataspaceProtocolVersions: Readonly<{
|
|
6
|
+
readonly Current: "2025-1";
|
|
7
|
+
}>;
|
|
8
|
+
/**
|
|
9
|
+
* Canonical well-known paths used by Dataspace Protocol discovery.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DataspaceWellKnownPaths: Readonly<{
|
|
12
|
+
readonly VersionMetadata: "/.well-known/dspace-version";
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Project-local GW CORE DSP binding paths.
|
|
16
|
+
*
|
|
17
|
+
* These preserve the current internal API structure while still ending in the
|
|
18
|
+
* DSP catalog route shapes.
|
|
19
|
+
*/
|
|
20
|
+
export declare const GwDataspaceBindingPaths: Readonly<{
|
|
21
|
+
readonly Base: "/dsp";
|
|
22
|
+
readonly CatalogCollectionSuffix: "/catalog";
|
|
23
|
+
readonly CatalogRequestSuffix: "/catalog/request";
|
|
24
|
+
readonly CatalogArtifactSuffix: "/catalog/dcat.json";
|
|
25
|
+
readonly CatalogDatasetsPrefix: "/catalog/datasets";
|
|
26
|
+
}>;
|
|
27
|
+
export type DataspaceProtocolVersionValue = typeof DataspaceProtocolVersions[keyof typeof DataspaceProtocolVersions];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
/**
|
|
3
|
+
* Canonical Dataspace Protocol version identifiers used by the current GW/SDK
|
|
4
|
+
* discovery flows.
|
|
5
|
+
*/
|
|
6
|
+
export const DataspaceProtocolVersions = Object.freeze({
|
|
7
|
+
Current: '2025-1',
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* Canonical well-known paths used by Dataspace Protocol discovery.
|
|
11
|
+
*/
|
|
12
|
+
export const DataspaceWellKnownPaths = Object.freeze({
|
|
13
|
+
VersionMetadata: '/.well-known/dspace-version',
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* Project-local GW CORE DSP binding paths.
|
|
17
|
+
*
|
|
18
|
+
* These preserve the current internal API structure while still ending in the
|
|
19
|
+
* DSP catalog route shapes.
|
|
20
|
+
*/
|
|
21
|
+
export const GwDataspaceBindingPaths = Object.freeze({
|
|
22
|
+
Base: '/dsp',
|
|
23
|
+
CatalogCollectionSuffix: '/catalog',
|
|
24
|
+
CatalogRequestSuffix: '/catalog/request',
|
|
25
|
+
CatalogArtifactSuffix: '/catalog/dcat.json',
|
|
26
|
+
CatalogDatasetsPrefix: '/catalog/datasets',
|
|
27
|
+
});
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from './actor-session';
|
|
2
2
|
export * from './communication';
|
|
3
3
|
export * from './cryptography';
|
|
4
|
+
export * from './dataspace-discovery';
|
|
5
|
+
export * from './dataspace-protocol';
|
|
4
6
|
export * from './device';
|
|
5
7
|
export * from './did-services';
|
|
6
8
|
export * from './eu-countries';
|
package/dist/constants/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from './actor-session.js';
|
|
2
2
|
export * from './communication.js';
|
|
3
3
|
export * from './cryptography.js';
|
|
4
|
+
export * from './dataspace-discovery.js';
|
|
5
|
+
export * from './dataspace-protocol.js';
|
|
4
6
|
export * from './device.js';
|
|
5
7
|
export * from './did-services.js';
|
|
6
8
|
export * from './eu-countries.js';
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Canonical network/environment labels used to identify
|
|
3
|
-
*
|
|
2
|
+
* Canonical network/environment labels used to identify host networks during
|
|
3
|
+
* discovery/bootstrap flows.
|
|
4
4
|
*
|
|
5
|
-
* These labels do not replace the
|
|
6
|
-
*
|
|
5
|
+
* These labels do not replace the business route `sector`. They describe the
|
|
6
|
+
* host environment itself.
|
|
7
|
+
*/
|
|
8
|
+
export declare const HostNetworkTypes: Readonly<{
|
|
9
|
+
readonly Test: "test";
|
|
10
|
+
readonly TestNetwork: "test-network";
|
|
11
|
+
readonly Network: "network";
|
|
12
|
+
}>;
|
|
13
|
+
export type HostNetworkType = typeof HostNetworkTypes[keyof typeof HostNetworkTypes];
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Use `HostNetworkTypes`.
|
|
7
16
|
*/
|
|
8
17
|
export declare const NodeOperatorNetworkTypes: Readonly<{
|
|
9
18
|
readonly Test: "test";
|
|
10
19
|
readonly TestNetwork: "test-network";
|
|
11
20
|
readonly Network: "network";
|
|
12
21
|
}>;
|
|
13
|
-
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated Use `HostNetworkType`.
|
|
24
|
+
*/
|
|
25
|
+
export type NodeOperatorNetworkType = HostNetworkType;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
2
|
/**
|
|
3
|
-
* Canonical network/environment labels used to identify
|
|
4
|
-
*
|
|
3
|
+
* Canonical network/environment labels used to identify host networks during
|
|
4
|
+
* discovery/bootstrap flows.
|
|
5
5
|
*
|
|
6
|
-
* These labels do not replace the
|
|
7
|
-
*
|
|
6
|
+
* These labels do not replace the business route `sector`. They describe the
|
|
7
|
+
* host environment itself.
|
|
8
8
|
*/
|
|
9
|
-
export const
|
|
9
|
+
export const HostNetworkTypes = Object.freeze({
|
|
10
10
|
Test: 'test',
|
|
11
11
|
TestNetwork: 'test-network',
|
|
12
12
|
Network: 'network',
|
|
13
13
|
});
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Use `HostNetworkTypes`.
|
|
16
|
+
*/
|
|
17
|
+
export const NodeOperatorNetworkTypes = HostNetworkTypes;
|
|
@@ -75,6 +75,11 @@ export declare function buildExampleTenantServiceMetaClaims(input?: ExampleDatas
|
|
|
75
75
|
* Builds a synthetic published-provider record as it would appear in a host
|
|
76
76
|
* service-autodiscovery catalog.
|
|
77
77
|
*
|
|
78
|
+
* URL rule:
|
|
79
|
+
* - `discoveryUrl` is the participant-scoped `/.well-known/dspace-version`
|
|
80
|
+
* entrypoint
|
|
81
|
+
* - `catalogUrl` is the derived `/dsp/catalog/dcat.json` artifact
|
|
82
|
+
*
|
|
78
83
|
* @param input Optional overrides for the synthetic provider publication.
|
|
79
84
|
* @returns Shared host-catalog provider entry.
|
|
80
85
|
*/
|
|
@@ -82,6 +87,11 @@ export declare function buildExamplePublishedProviderCatalogRecord(input?: Examp
|
|
|
82
87
|
/**
|
|
83
88
|
* Builds a synthetic host/operator service-autodiscovery catalog.
|
|
84
89
|
*
|
|
90
|
+
* URL rule:
|
|
91
|
+
* - `discoveryUrl` is the canonical entrypoint clients should fetch first
|
|
92
|
+
* - `catalogUrl` is the read-only DSP artifact derived from the advertised
|
|
93
|
+
* base path
|
|
94
|
+
*
|
|
85
95
|
* @param providers Optional published providers to include.
|
|
86
96
|
* @returns Shared catalog DTO for host-side public service autodiscovery.
|
|
87
97
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
2
|
import { ClaimsOrganizationSchemaorg, ClaimsServiceSchemaorg } from '../constants/schemaorg.js';
|
|
3
3
|
import { serializeServiceCapabilityTokens, ServiceCapabilityToken } from '../constants/service-capabilities.js';
|
|
4
|
-
import {
|
|
4
|
+
import { EXAMPLE_HOSTING_OPERATOR_CATALOG_ARTIFACT_URL, EXAMPLE_HOSTING_OPERATOR_DSPACE_VERSION_URL, EXAMPLE_HOSTING_OPERATOR_DID, EXAMPLE_PROVIDER_PUBLISHED_ENDPOINT_URL, EXAMPLE_JURISDICTION, EXAMPLE_SECTOR, EXAMPLE_TENANT_SERVICE_DID, } from './shared.js';
|
|
5
5
|
function firstOrCsv(values) {
|
|
6
6
|
return values.length <= 1 ? (values[0] || '') : values.join(',');
|
|
7
7
|
}
|
|
@@ -98,6 +98,11 @@ export function buildExampleTenantServiceMetaClaims(input = {}) {
|
|
|
98
98
|
* Builds a synthetic published-provider record as it would appear in a host
|
|
99
99
|
* service-autodiscovery catalog.
|
|
100
100
|
*
|
|
101
|
+
* URL rule:
|
|
102
|
+
* - `discoveryUrl` is the participant-scoped `/.well-known/dspace-version`
|
|
103
|
+
* entrypoint
|
|
104
|
+
* - `catalogUrl` is the derived `/dsp/catalog/dcat.json` artifact
|
|
105
|
+
*
|
|
101
106
|
* @param input Optional overrides for the synthetic provider publication.
|
|
102
107
|
* @returns Shared host-catalog provider entry.
|
|
103
108
|
*/
|
|
@@ -109,21 +114,28 @@ export function buildExamplePublishedProviderCatalogRecord(input = {}) {
|
|
|
109
114
|
providerDid: input.did || EXAMPLE_TENANT_SERVICE_DID,
|
|
110
115
|
serviceType: serviceTypes[0] || ServiceCapabilityToken.IndexProvider,
|
|
111
116
|
category: categories[0] || EXAMPLE_SECTOR,
|
|
112
|
-
areaServed: areaServed
|
|
117
|
+
areaServed: firstOrCsv(areaServed) || 'EU',
|
|
113
118
|
endpointUrl: EXAMPLE_PROVIDER_PUBLISHED_ENDPOINT_URL,
|
|
114
|
-
|
|
119
|
+
discoveryUrl: EXAMPLE_HOSTING_OPERATOR_DSPACE_VERSION_URL,
|
|
120
|
+
catalogUrl: EXAMPLE_HOSTING_OPERATOR_CATALOG_ARTIFACT_URL,
|
|
115
121
|
};
|
|
116
122
|
}
|
|
117
123
|
/**
|
|
118
124
|
* Builds a synthetic host/operator service-autodiscovery catalog.
|
|
119
125
|
*
|
|
126
|
+
* URL rule:
|
|
127
|
+
* - `discoveryUrl` is the canonical entrypoint clients should fetch first
|
|
128
|
+
* - `catalogUrl` is the read-only DSP artifact derived from the advertised
|
|
129
|
+
* base path
|
|
130
|
+
*
|
|
120
131
|
* @param providers Optional published providers to include.
|
|
121
132
|
* @returns Shared catalog DTO for host-side public service autodiscovery.
|
|
122
133
|
*/
|
|
123
134
|
export function buildExampleHostingOperatorDiscoveryCatalog(providers = [buildExamplePublishedProviderCatalogRecord()]) {
|
|
124
135
|
return {
|
|
125
136
|
hostingOperatorDid: EXAMPLE_HOSTING_OPERATOR_DID,
|
|
126
|
-
|
|
137
|
+
discoveryUrl: EXAMPLE_HOSTING_OPERATOR_DSPACE_VERSION_URL,
|
|
138
|
+
catalogUrl: EXAMPLE_HOSTING_OPERATOR_CATALOG_ARTIFACT_URL,
|
|
127
139
|
providers: [...providers],
|
|
128
140
|
};
|
|
129
141
|
}
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
export declare const EXAMPLE_TENANT_IDENTIFIER: "acme-id";
|
|
12
12
|
export declare const EXAMPLE_JURISDICTION: "ES";
|
|
13
|
+
export declare const EXAMPLE_NETWORK_TYPE: "test";
|
|
14
|
+
export declare const EXAMPLE_ROUTE_VERSION: "v1";
|
|
13
15
|
export declare const EXAMPLE_SECTOR: "health-care";
|
|
14
16
|
export declare const EXAMPLE_EMAIL_CONTROLLER_ORG: "controller@acme.org";
|
|
15
17
|
export declare const EXAMPLE_EMAIL_CONTROLLER_INDIVIDUAL: "ana.parent@example.org";
|
|
@@ -20,7 +22,7 @@ export declare const EXAMPLE_TENANT_ROUTE_CONTEXT: {
|
|
|
20
22
|
};
|
|
21
23
|
export declare const EXAMPLE_HOST_ROUTE_CONTEXT: {
|
|
22
24
|
readonly jurisdiction: "ES";
|
|
23
|
-
readonly sector: "
|
|
25
|
+
readonly sector: "test";
|
|
24
26
|
};
|
|
25
27
|
export declare const EXAMPLE_CONTROLLER_DID: "did:web:people.acme.org:controllers:primary";
|
|
26
28
|
export declare const EXAMPLE_CONTROLLER_EMAIL: "controller@acme.org";
|
|
@@ -33,10 +35,15 @@ export declare const EXAMPLE_PROVIDER_ORGANIZATION_DID: "did:web:hospital.acme.o
|
|
|
33
35
|
export declare const EXAMPLE_PROVIDER_ORGANIZATION_URL: "https://hospital.acme.org";
|
|
34
36
|
export declare const EXAMPLE_GATEWAY_PUBLIC_ORIGIN: "https://gateway.example.com";
|
|
35
37
|
export declare const EXAMPLE_HOST_PUBLIC_HOSTNAME: "host.example.com";
|
|
38
|
+
export declare const EXAMPLE_DEFAULT_ICA_URL: "https://ica.example.org";
|
|
39
|
+
export declare const EXAMPLE_DEFAULT_ICA_DID: "did:web:ica.example.org";
|
|
36
40
|
export declare const EXAMPLE_HOSTING_OPERATOR_DID: "did:web:host.example.org";
|
|
37
41
|
export declare const EXAMPLE_TENANT_SERVICE_DID: "did:web:provider.example.org";
|
|
38
42
|
export declare const EXAMPLE_SECONDARY_TENANT_SERVICE_DID: "did:web:provider-b.example.org";
|
|
39
|
-
export declare const
|
|
43
|
+
export declare const EXAMPLE_HOSTING_OPERATOR_DSPACE_VERSION_URL: "https://host.example.org/host/cds-ES/v1/test/.well-known/dspace-version";
|
|
44
|
+
export declare const EXAMPLE_HOSTING_OPERATOR_CATALOG_ARTIFACT_URL: "https://host.example.org/host/cds-ES/v1/test/dsp/catalog/dcat.json";
|
|
45
|
+
/** @deprecated Use `EXAMPLE_HOSTING_OPERATOR_DSPACE_VERSION_URL`. */
|
|
46
|
+
export declare const EXAMPLE_HOSTING_OPERATOR_CATALOG_URL: "https://host.example.org/host/cds-ES/v1/test/.well-known/dspace-version";
|
|
40
47
|
export declare const EXAMPLE_PROVIDER_PUBLISHED_ENDPOINT_URL: "https://host.example.org/catalog/provider-a";
|
|
41
48
|
export declare const EXAMPLE_PROVIDER_LEGAL_NAME: "ACME Health Provider";
|
|
42
49
|
export declare const EXAMPLE_SECONDARY_PROVIDER_LEGAL_NAME: "Reader Only Provider";
|
package/dist/examples/shared.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
2
|
// Always create JSDoc, do not use strings inline in keys nor values, use types instead, and reuse the data test examples.
|
|
3
3
|
import { DataspaceSectors } from '../constants/sectors.js';
|
|
4
|
+
import { HostNetworkTypes } from '../constants/network.js';
|
|
4
5
|
import { HealthcareActorRoles, HealthcareBasicSections, HealthcareConsentPurposes, } from '../constants/healthcare.js';
|
|
5
6
|
import { CommunicationClaim } from '../models/interoperable-claims/communication-claims.js';
|
|
6
7
|
/**
|
|
@@ -15,6 +16,8 @@ import { CommunicationClaim } from '../models/interoperable-claims/communication
|
|
|
15
16
|
*/
|
|
16
17
|
export const EXAMPLE_TENANT_IDENTIFIER = 'acme-id';
|
|
17
18
|
export const EXAMPLE_JURISDICTION = 'ES';
|
|
19
|
+
export const EXAMPLE_NETWORK_TYPE = HostNetworkTypes.Test;
|
|
20
|
+
export const EXAMPLE_ROUTE_VERSION = 'v1';
|
|
18
21
|
export const EXAMPLE_SECTOR = DataspaceSectors.HealthCare;
|
|
19
22
|
export const EXAMPLE_EMAIL_CONTROLLER_ORG = 'controller@acme.org';
|
|
20
23
|
export const EXAMPLE_EMAIL_CONTROLLER_INDIVIDUAL = 'ana.parent@example.org';
|
|
@@ -25,7 +28,7 @@ export const EXAMPLE_TENANT_ROUTE_CONTEXT = {
|
|
|
25
28
|
};
|
|
26
29
|
export const EXAMPLE_HOST_ROUTE_CONTEXT = {
|
|
27
30
|
jurisdiction: EXAMPLE_JURISDICTION,
|
|
28
|
-
sector:
|
|
31
|
+
sector: HostNetworkTypes.Test,
|
|
29
32
|
};
|
|
30
33
|
export const EXAMPLE_CONTROLLER_DID = 'did:web:people.acme.org:controllers:primary';
|
|
31
34
|
export const EXAMPLE_CONTROLLER_EMAIL = EXAMPLE_EMAIL_CONTROLLER_ORG;
|
|
@@ -38,10 +41,15 @@ export const EXAMPLE_PROVIDER_ORGANIZATION_DID = 'did:web:hospital.acme.org';
|
|
|
38
41
|
export const EXAMPLE_PROVIDER_ORGANIZATION_URL = 'https://hospital.acme.org';
|
|
39
42
|
export const EXAMPLE_GATEWAY_PUBLIC_ORIGIN = 'https://gateway.example.com';
|
|
40
43
|
export const EXAMPLE_HOST_PUBLIC_HOSTNAME = 'host.example.com';
|
|
44
|
+
export const EXAMPLE_DEFAULT_ICA_URL = 'https://ica.example.org';
|
|
45
|
+
export const EXAMPLE_DEFAULT_ICA_DID = 'did:web:ica.example.org';
|
|
41
46
|
export const EXAMPLE_HOSTING_OPERATOR_DID = 'did:web:host.example.org';
|
|
42
47
|
export const EXAMPLE_TENANT_SERVICE_DID = 'did:web:provider.example.org';
|
|
43
48
|
export const EXAMPLE_SECONDARY_TENANT_SERVICE_DID = 'did:web:provider-b.example.org';
|
|
44
|
-
export const
|
|
49
|
+
export const EXAMPLE_HOSTING_OPERATOR_DSPACE_VERSION_URL = `https://host.example.org/host/cds-ES/${EXAMPLE_ROUTE_VERSION}/${EXAMPLE_NETWORK_TYPE}/.well-known/dspace-version`;
|
|
50
|
+
export const EXAMPLE_HOSTING_OPERATOR_CATALOG_ARTIFACT_URL = `https://host.example.org/host/cds-ES/${EXAMPLE_ROUTE_VERSION}/${EXAMPLE_NETWORK_TYPE}/dsp/catalog/dcat.json`;
|
|
51
|
+
/** @deprecated Use `EXAMPLE_HOSTING_OPERATOR_DSPACE_VERSION_URL`. */
|
|
52
|
+
export const EXAMPLE_HOSTING_OPERATOR_CATALOG_URL = EXAMPLE_HOSTING_OPERATOR_DSPACE_VERSION_URL;
|
|
45
53
|
export const EXAMPLE_PROVIDER_PUBLISHED_ENDPOINT_URL = 'https://host.example.org/catalog/provider-a';
|
|
46
54
|
export const EXAMPLE_PROVIDER_LEGAL_NAME = 'ACME Health Provider';
|
|
47
55
|
export const EXAMPLE_SECONDARY_PROVIDER_LEGAL_NAME = 'Reader Only Provider';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { DataspaceDiscoverySourceModeValue } from '../constants/dataspace-discovery';
|
|
2
|
+
import type { HostingOperatorSemanticRecord } from './dataspace-discovery';
|
|
3
|
+
/**
|
|
4
|
+
* Shared host/ICA context used to select dataspace discovery defaults.
|
|
5
|
+
*
|
|
6
|
+
* `networkType` belongs to the host/ICA side.
|
|
7
|
+
* Tenant/provider resolution later uses `sector`.
|
|
8
|
+
*/
|
|
9
|
+
export type DataspaceDiscoveryNetworkContext = Readonly<{
|
|
10
|
+
jurisdiction: string;
|
|
11
|
+
version: string;
|
|
12
|
+
networkType: string;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Configured ICA seed for a given host/network context.
|
|
16
|
+
*/
|
|
17
|
+
export type DefaultIcaRegistration = DataspaceDiscoveryNetworkContext & Readonly<{
|
|
18
|
+
icaUrl: string;
|
|
19
|
+
icaDid?: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Configured hosting-operator seed for a given host/network context.
|
|
24
|
+
*
|
|
25
|
+
* This mirrors the record shape consumed later by backend resolvers.
|
|
26
|
+
*/
|
|
27
|
+
export type DefaultHostingOperatorRegistration = DataspaceDiscoveryNetworkContext & Readonly<{
|
|
28
|
+
operatorDid: string;
|
|
29
|
+
discoveryUrl?: string;
|
|
30
|
+
catalogUrl?: string;
|
|
31
|
+
record: HostingOperatorSemanticRecord;
|
|
32
|
+
title?: string;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Optional seed data used when constructing a defaults registry.
|
|
36
|
+
*/
|
|
37
|
+
export type DataspaceDiscoveryDefaultsRegistrySeed = Readonly<{
|
|
38
|
+
icas?: readonly DefaultIcaRegistration[];
|
|
39
|
+
hostingOperators?: readonly DefaultHostingOperatorRegistration[];
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Filter used to list configured ICA defaults for a host/network context.
|
|
43
|
+
*/
|
|
44
|
+
export type DataspaceDiscoveryDefaultIcaFilter = Readonly<Partial<DataspaceDiscoveryNetworkContext>>;
|
|
45
|
+
/**
|
|
46
|
+
* Filter used to list configured hosting-operator defaults for a discovery
|
|
47
|
+
* request.
|
|
48
|
+
*/
|
|
49
|
+
export type DataspaceDiscoveryDefaultHostingFilter = Readonly<Partial<DataspaceDiscoveryNetworkContext> & {
|
|
50
|
+
sector?: string;
|
|
51
|
+
coverageScope?: string;
|
|
52
|
+
requiredCapabilities?: readonly string[];
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* Input used to decide how a backend should bootstrap discovery for a
|
|
56
|
+
* frontend/API request.
|
|
57
|
+
*/
|
|
58
|
+
export type DataspaceDiscoveryBootstrapInput = DataspaceDiscoveryNetworkContext & Readonly<{
|
|
59
|
+
sector: string;
|
|
60
|
+
coverageScope?: string;
|
|
61
|
+
requiredCapabilities?: readonly string[];
|
|
62
|
+
sourceMode?: DataspaceDiscoverySourceModeValue;
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* Bootstrap plan returned by the defaults registry.
|
|
66
|
+
*
|
|
67
|
+
* Backend usage:
|
|
68
|
+
* - use `hostingOperators` immediately when `shouldUseDefaultsFirst` is true
|
|
69
|
+
* - try live ICA/internet only when `shouldTryInternet` is true
|
|
70
|
+
*/
|
|
71
|
+
export type DataspaceDiscoveryBootstrapPlan = Readonly<{
|
|
72
|
+
sourceMode: DataspaceDiscoverySourceModeValue;
|
|
73
|
+
icas: DefaultIcaRegistration[];
|
|
74
|
+
hostingOperators: DefaultHostingOperatorRegistration[];
|
|
75
|
+
hasDefaults: boolean;
|
|
76
|
+
shouldUseDefaultsFirst: boolean;
|
|
77
|
+
shouldTryInternet: boolean;
|
|
78
|
+
}>;
|
|
@@ -38,6 +38,7 @@ export type PublishedProviderCatalogRecord = Readonly<{
|
|
|
38
38
|
category: string;
|
|
39
39
|
areaServed?: string;
|
|
40
40
|
endpointUrl?: string;
|
|
41
|
+
discoveryUrl?: string;
|
|
41
42
|
catalogUrl?: string;
|
|
42
43
|
}>;
|
|
43
44
|
/**
|
|
@@ -61,6 +62,7 @@ export type DataspaceDiscoveryFilter = Readonly<{
|
|
|
61
62
|
*/
|
|
62
63
|
export type HostingOperatorDiscoveryCatalog = Readonly<{
|
|
63
64
|
hostingOperatorDid?: string;
|
|
65
|
+
discoveryUrl?: string;
|
|
64
66
|
catalogUrl?: string;
|
|
65
67
|
providers: PublishedProviderCatalogRecord[];
|
|
66
68
|
}>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One advertised Dataspace Protocol version entry from `/.well-known/dspace-version`.
|
|
3
|
+
*/
|
|
4
|
+
export type DspaceProtocolVersionEntry = Readonly<{
|
|
5
|
+
version: string;
|
|
6
|
+
path: string;
|
|
7
|
+
}>;
|
|
8
|
+
/**
|
|
9
|
+
* Minimal version metadata payload returned by the DSP well-known discovery
|
|
10
|
+
* endpoint.
|
|
11
|
+
*/
|
|
12
|
+
export type DspaceVersionMetadata = Readonly<{
|
|
13
|
+
protocolVersions: readonly DspaceProtocolVersionEntry[];
|
|
14
|
+
}>;
|
package/dist/models/index.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export * from './consent-rule';
|
|
|
13
13
|
export * from './consent-access';
|
|
14
14
|
export * from './crypto';
|
|
15
15
|
export * from './dataspace-discovery';
|
|
16
|
+
export * from './dataspace-discovery-defaults';
|
|
17
|
+
export * from './dataspace-protocol';
|
|
16
18
|
export * from './device-license';
|
|
17
19
|
export * from './did';
|
|
18
20
|
export * from './fhir-documents';
|
package/dist/models/index.js
CHANGED
|
@@ -13,6 +13,8 @@ export * from './consent-rule.js';
|
|
|
13
13
|
export * from './consent-access.js';
|
|
14
14
|
export * from './crypto.js';
|
|
15
15
|
export * from './dataspace-discovery.js';
|
|
16
|
+
export * from './dataspace-discovery-defaults.js';
|
|
17
|
+
export * from './dataspace-protocol.js';
|
|
16
18
|
export * from './device-license.js';
|
|
17
19
|
export * from './did.js';
|
|
18
20
|
export * from './fhir-documents.js';
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { DataspaceDiscoveryBootstrapInput, DataspaceDiscoveryBootstrapPlan, DataspaceDiscoveryDefaultHostingFilter, DataspaceDiscoveryDefaultIcaFilter, DataspaceDiscoveryDefaultsRegistrySeed, DefaultHostingOperatorRegistration, DefaultIcaRegistration } from '../models/dataspace-discovery-defaults';
|
|
2
|
+
/**
|
|
3
|
+
* Mutable in-memory registry for discovery defaults used by portal/backend
|
|
4
|
+
* bootstrap code.
|
|
5
|
+
*
|
|
6
|
+
* Scope:
|
|
7
|
+
* - ICA defaults are indexed by `jurisdiction + version + networkType`
|
|
8
|
+
* - hosting defaults are indexed by `jurisdiction + version + networkType`
|
|
9
|
+
* - sector filtering is applied only when listing hosting operators, because
|
|
10
|
+
* sectors belong to tenant/provider discovery rather than to the host network
|
|
11
|
+
*
|
|
12
|
+
* This registry is intentionally simple and synchronous so backend code can
|
|
13
|
+
* preload defaults during startup and immediately serve the frontend in
|
|
14
|
+
* `defaults-only` or `default-first` mode.
|
|
15
|
+
*/
|
|
16
|
+
export declare class DataspaceDiscoveryDefaultsRegistry {
|
|
17
|
+
private readonly icas;
|
|
18
|
+
private readonly hostingOperators;
|
|
19
|
+
constructor(seed?: DataspaceDiscoveryDefaultsRegistrySeed);
|
|
20
|
+
/**
|
|
21
|
+
* Adds one ICA default for a concrete host/network context.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* registry.addIca({
|
|
26
|
+
* jurisdiction: 'ES',
|
|
27
|
+
* version: 'v1',
|
|
28
|
+
* networkType: 'test',
|
|
29
|
+
* icaUrl: 'https://ica.example.org',
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
addIca(input: DefaultIcaRegistration): this;
|
|
34
|
+
/**
|
|
35
|
+
* Adds one hosting-operator default for a concrete host/network context.
|
|
36
|
+
*
|
|
37
|
+
* The record itself may later serve multiple sectors depending on the
|
|
38
|
+
* semantic categories and capabilities published in `record`.
|
|
39
|
+
*/
|
|
40
|
+
addHostingOperator(input: DefaultHostingOperatorRegistration): this;
|
|
41
|
+
/**
|
|
42
|
+
* Lists configured ICA defaults for a host/network context.
|
|
43
|
+
*/
|
|
44
|
+
listIcas(filter?: DataspaceDiscoveryDefaultIcaFilter): DefaultIcaRegistration[];
|
|
45
|
+
/**
|
|
46
|
+
* Lists configured hosting-operator defaults for a frontend/backend discovery
|
|
47
|
+
* request.
|
|
48
|
+
*
|
|
49
|
+
* Sector and capability filtering are applied against the semantic host
|
|
50
|
+
* record because those dimensions belong to the provider/tenant side.
|
|
51
|
+
*/
|
|
52
|
+
listHostingOperators(filter?: DataspaceDiscoveryDefaultHostingFilter): DefaultHostingOperatorRegistration[];
|
|
53
|
+
/**
|
|
54
|
+
* Builds the backend bootstrap plan for one provider-discovery request.
|
|
55
|
+
*
|
|
56
|
+
* Current default-first policy:
|
|
57
|
+
* - use configured hosting defaults immediately when they exist
|
|
58
|
+
* - only try live ICA/internet when no host defaults match the request and at
|
|
59
|
+
* least one ICA default is configured for the same host/network context
|
|
60
|
+
*/
|
|
61
|
+
buildBootstrapPlan(input: DataspaceDiscoveryBootstrapInput): DataspaceDiscoveryBootstrapPlan;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convenience factory for the in-memory defaults registry.
|
|
65
|
+
*/
|
|
66
|
+
export declare function createDataspaceDiscoveryDefaultsRegistry(seed?: DataspaceDiscoveryDefaultsRegistrySeed): DataspaceDiscoveryDefaultsRegistry;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { DataspaceDiscoverySourceMode, } from '../constants/dataspace-discovery.js';
|
|
3
|
+
import { matchesHostingOperatorDiscoveryFilter } from './dataspace-discovery.js';
|
|
4
|
+
function normalizeString(value) {
|
|
5
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
6
|
+
}
|
|
7
|
+
function normalizeCapabilities(values) {
|
|
8
|
+
return Array.from(new Set((values || []).map((value) => normalizeString(value)).filter(Boolean)));
|
|
9
|
+
}
|
|
10
|
+
function normalizeIcaRegistration(input) {
|
|
11
|
+
return {
|
|
12
|
+
jurisdiction: normalizeString(input.jurisdiction),
|
|
13
|
+
version: normalizeString(input.version),
|
|
14
|
+
networkType: normalizeString(input.networkType),
|
|
15
|
+
icaUrl: normalizeString(input.icaUrl),
|
|
16
|
+
icaDid: normalizeString(input.icaDid) || undefined,
|
|
17
|
+
title: normalizeString(input.title) || undefined,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function normalizeHostingOperatorRegistration(input) {
|
|
21
|
+
return {
|
|
22
|
+
jurisdiction: normalizeString(input.jurisdiction),
|
|
23
|
+
version: normalizeString(input.version),
|
|
24
|
+
networkType: normalizeString(input.networkType),
|
|
25
|
+
operatorDid: normalizeString(input.operatorDid),
|
|
26
|
+
discoveryUrl: normalizeString(input.discoveryUrl) || undefined,
|
|
27
|
+
catalogUrl: normalizeString(input.catalogUrl) || undefined,
|
|
28
|
+
record: {
|
|
29
|
+
...input.record,
|
|
30
|
+
subjectId: normalizeString(input.record.subjectId) || undefined,
|
|
31
|
+
serviceTypes: normalizeCapabilities(input.record.serviceTypes),
|
|
32
|
+
categories: Array.from(new Set((input.record.categories || []).map((value) => normalizeString(value)).filter(Boolean))),
|
|
33
|
+
areaServed: Array.from(new Set((input.record.areaServed || []).map((value) => normalizeString(value)).filter(Boolean))),
|
|
34
|
+
addressCountry: normalizeString(input.record.addressCountry) || undefined,
|
|
35
|
+
coverageScope: normalizeString(input.record.coverageScope) || undefined,
|
|
36
|
+
},
|
|
37
|
+
title: normalizeString(input.title) || undefined,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function matchesNetworkContext(left, right) {
|
|
41
|
+
if (right.jurisdiction && normalizeString(right.jurisdiction) !== left.jurisdiction)
|
|
42
|
+
return false;
|
|
43
|
+
if (right.version && normalizeString(right.version) !== left.version)
|
|
44
|
+
return false;
|
|
45
|
+
if (right.networkType && normalizeString(right.networkType) !== left.networkType)
|
|
46
|
+
return false;
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Mutable in-memory registry for discovery defaults used by portal/backend
|
|
51
|
+
* bootstrap code.
|
|
52
|
+
*
|
|
53
|
+
* Scope:
|
|
54
|
+
* - ICA defaults are indexed by `jurisdiction + version + networkType`
|
|
55
|
+
* - hosting defaults are indexed by `jurisdiction + version + networkType`
|
|
56
|
+
* - sector filtering is applied only when listing hosting operators, because
|
|
57
|
+
* sectors belong to tenant/provider discovery rather than to the host network
|
|
58
|
+
*
|
|
59
|
+
* This registry is intentionally simple and synchronous so backend code can
|
|
60
|
+
* preload defaults during startup and immediately serve the frontend in
|
|
61
|
+
* `defaults-only` or `default-first` mode.
|
|
62
|
+
*/
|
|
63
|
+
export class DataspaceDiscoveryDefaultsRegistry {
|
|
64
|
+
icas = [];
|
|
65
|
+
hostingOperators = [];
|
|
66
|
+
constructor(seed = {}) {
|
|
67
|
+
for (const registration of seed.icas || []) {
|
|
68
|
+
this.addIca(registration);
|
|
69
|
+
}
|
|
70
|
+
for (const registration of seed.hostingOperators || []) {
|
|
71
|
+
this.addHostingOperator(registration);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Adds one ICA default for a concrete host/network context.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* registry.addIca({
|
|
80
|
+
* jurisdiction: 'ES',
|
|
81
|
+
* version: 'v1',
|
|
82
|
+
* networkType: 'test',
|
|
83
|
+
* icaUrl: 'https://ica.example.org',
|
|
84
|
+
* });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
addIca(input) {
|
|
88
|
+
this.icas.push(normalizeIcaRegistration(input));
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Adds one hosting-operator default for a concrete host/network context.
|
|
93
|
+
*
|
|
94
|
+
* The record itself may later serve multiple sectors depending on the
|
|
95
|
+
* semantic categories and capabilities published in `record`.
|
|
96
|
+
*/
|
|
97
|
+
addHostingOperator(input) {
|
|
98
|
+
this.hostingOperators.push(normalizeHostingOperatorRegistration(input));
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Lists configured ICA defaults for a host/network context.
|
|
103
|
+
*/
|
|
104
|
+
listIcas(filter = {}) {
|
|
105
|
+
return this.icas
|
|
106
|
+
.filter((registration) => matchesNetworkContext(registration, filter))
|
|
107
|
+
.map((registration) => ({ ...registration }));
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Lists configured hosting-operator defaults for a frontend/backend discovery
|
|
111
|
+
* request.
|
|
112
|
+
*
|
|
113
|
+
* Sector and capability filtering are applied against the semantic host
|
|
114
|
+
* record because those dimensions belong to the provider/tenant side.
|
|
115
|
+
*/
|
|
116
|
+
listHostingOperators(filter = {}) {
|
|
117
|
+
return this.hostingOperators
|
|
118
|
+
.filter((registration) => matchesNetworkContext(registration, filter))
|
|
119
|
+
.filter((registration) => {
|
|
120
|
+
if (!filter.sector)
|
|
121
|
+
return true;
|
|
122
|
+
return matchesHostingOperatorDiscoveryFilter(registration.record, {
|
|
123
|
+
sector: normalizeString(filter.sector),
|
|
124
|
+
coverageScope: normalizeString(filter.coverageScope) || undefined,
|
|
125
|
+
requiredCapabilities: normalizeCapabilities(filter.requiredCapabilities),
|
|
126
|
+
});
|
|
127
|
+
})
|
|
128
|
+
.map((registration) => ({
|
|
129
|
+
...registration,
|
|
130
|
+
record: {
|
|
131
|
+
...registration.record,
|
|
132
|
+
serviceTypes: [...registration.record.serviceTypes],
|
|
133
|
+
categories: [...registration.record.categories],
|
|
134
|
+
areaServed: [...registration.record.areaServed],
|
|
135
|
+
},
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Builds the backend bootstrap plan for one provider-discovery request.
|
|
140
|
+
*
|
|
141
|
+
* Current default-first policy:
|
|
142
|
+
* - use configured hosting defaults immediately when they exist
|
|
143
|
+
* - only try live ICA/internet when no host defaults match the request and at
|
|
144
|
+
* least one ICA default is configured for the same host/network context
|
|
145
|
+
*/
|
|
146
|
+
buildBootstrapPlan(input) {
|
|
147
|
+
const sourceMode = normalizeString(input.sourceMode)
|
|
148
|
+
|| DataspaceDiscoverySourceMode.DefaultFirst;
|
|
149
|
+
const icas = this.listIcas(input);
|
|
150
|
+
const hostingOperators = this.listHostingOperators(input);
|
|
151
|
+
const hasDefaults = Boolean(icas.length || hostingOperators.length);
|
|
152
|
+
const shouldUseDefaultsFirst = sourceMode !== DataspaceDiscoverySourceMode.InternetFirst;
|
|
153
|
+
const shouldTryInternet = sourceMode !== DataspaceDiscoverySourceMode.DefaultsOnly
|
|
154
|
+
&& icas.length > 0
|
|
155
|
+
&& (sourceMode === DataspaceDiscoverySourceMode.InternetFirst
|
|
156
|
+
|| hostingOperators.length === 0);
|
|
157
|
+
return {
|
|
158
|
+
sourceMode,
|
|
159
|
+
icas,
|
|
160
|
+
hostingOperators,
|
|
161
|
+
hasDefaults,
|
|
162
|
+
shouldUseDefaultsFirst,
|
|
163
|
+
shouldTryInternet,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Convenience factory for the in-memory defaults registry.
|
|
169
|
+
*/
|
|
170
|
+
export function createDataspaceDiscoveryDefaultsRegistry(seed = {}) {
|
|
171
|
+
return new DataspaceDiscoveryDefaultsRegistry(seed);
|
|
172
|
+
}
|
|
@@ -1,4 +1,46 @@
|
|
|
1
1
|
import { type DataspaceDiscoveryFilter, type DataspaceServiceSemanticRecord, type HostingOperatorSemanticRecord, type HostingOperatorDiscoveryCatalog, type PublishedProviderCatalogRecord, type TenantServiceSemanticRecord } from '../models/dataspace-discovery';
|
|
2
|
+
export type DiscoveryCatalogFetchResponse = Readonly<{
|
|
3
|
+
ok: boolean;
|
|
4
|
+
status: number;
|
|
5
|
+
json(): Promise<unknown>;
|
|
6
|
+
text(): Promise<string>;
|
|
7
|
+
}>;
|
|
8
|
+
export declare const DiscoveryCatalogSource: Readonly<{
|
|
9
|
+
readonly Internet: "internet";
|
|
10
|
+
readonly Cache: "cache";
|
|
11
|
+
readonly Default: "default";
|
|
12
|
+
}>;
|
|
13
|
+
export type DiscoveryCatalogSourceValue = typeof DiscoveryCatalogSource[keyof typeof DiscoveryCatalogSource];
|
|
14
|
+
export type DiscoveryCatalogFetcherOptions = Readonly<{
|
|
15
|
+
internetCatalogs?: Record<string, HostingOperatorDiscoveryCatalog>;
|
|
16
|
+
internetJsonByUrl?: Record<string, unknown>;
|
|
17
|
+
defaultCatalogs?: Record<string, HostingOperatorDiscoveryCatalog>;
|
|
18
|
+
}>;
|
|
19
|
+
export type DiscoveryCatalogFetcherHarness = Readonly<{
|
|
20
|
+
fetcher(input: string, init?: unknown): Promise<DiscoveryCatalogFetchResponse>;
|
|
21
|
+
calls: string[];
|
|
22
|
+
sources: Map<string, DiscoveryCatalogSourceValue>;
|
|
23
|
+
cache: Map<string, HostingOperatorDiscoveryCatalog>;
|
|
24
|
+
setInternetCatalog(url: string, catalog: HostingOperatorDiscoveryCatalog): void;
|
|
25
|
+
setInternetJson(url: string, payload: unknown): void;
|
|
26
|
+
setInternetFailure(url: string, status?: number, body?: unknown): void;
|
|
27
|
+
clearInternetRoute(url: string): void;
|
|
28
|
+
}>;
|
|
29
|
+
export type DefaultPublishedProviderCatalogRecordInput = Readonly<{
|
|
30
|
+
providerDid: string;
|
|
31
|
+
serviceType: string;
|
|
32
|
+
category: string;
|
|
33
|
+
areaServed?: string | readonly string[];
|
|
34
|
+
endpointUrl?: string;
|
|
35
|
+
discoveryUrl?: string;
|
|
36
|
+
catalogUrl?: string;
|
|
37
|
+
}>;
|
|
38
|
+
export type DefaultHostingOperatorDiscoveryCatalogInput = Readonly<{
|
|
39
|
+
hostingOperatorDid?: string;
|
|
40
|
+
discoveryUrl?: string;
|
|
41
|
+
catalogUrl?: string;
|
|
42
|
+
providers?: ReadonlyArray<PublishedProviderCatalogRecord>;
|
|
43
|
+
}>;
|
|
2
44
|
/**
|
|
3
45
|
* Parses the CSV or array representation of `serviceType`.
|
|
4
46
|
*
|
|
@@ -144,3 +186,50 @@ export declare function filterPublishedProvidersByDiscoveryFilter(records: Reado
|
|
|
144
186
|
* the requested service-autodiscovery filter.
|
|
145
187
|
*/
|
|
146
188
|
export declare function filterHostingOperatorDiscoveryCatalog(catalog: HostingOperatorDiscoveryCatalog, filter: DataspaceDiscoveryFilter): HostingOperatorDiscoveryCatalog;
|
|
189
|
+
/**
|
|
190
|
+
* Builds a normalized published-provider catalog DTO suitable for:
|
|
191
|
+
*
|
|
192
|
+
* - backend-owned fallback catalogs
|
|
193
|
+
* - default discovery data loaded from configuration
|
|
194
|
+
* - tests that should use the same DTO constructors as production code
|
|
195
|
+
*
|
|
196
|
+
* This helper is intentionally neutral:
|
|
197
|
+
* - no example DIDs
|
|
198
|
+
* - no example URLs
|
|
199
|
+
* - no hidden business defaults
|
|
200
|
+
*
|
|
201
|
+
* @param input Required provider catalog fields plus optional URLs.
|
|
202
|
+
* @returns Normalized published-provider catalog record.
|
|
203
|
+
*/
|
|
204
|
+
export declare function buildDefaultPublishedProviderCatalogRecord(input: DefaultPublishedProviderCatalogRecordInput): PublishedProviderCatalogRecord;
|
|
205
|
+
/**
|
|
206
|
+
* Builds a normalized hosting-operator discovery catalog DTO suitable for:
|
|
207
|
+
*
|
|
208
|
+
* - backend-owned fallback catalogs
|
|
209
|
+
* - default host catalogs assembled from configuration
|
|
210
|
+
* - tests that should reuse the same constructor as production code
|
|
211
|
+
*
|
|
212
|
+
* @param input Optional host identity fields plus the provider list.
|
|
213
|
+
* @returns Normalized host discovery catalog.
|
|
214
|
+
*/
|
|
215
|
+
export declare function buildDefaultHostingOperatorDiscoveryCatalog(input?: DefaultHostingOperatorDiscoveryCatalogInput): HostingOperatorDiscoveryCatalog;
|
|
216
|
+
/**
|
|
217
|
+
* Creates a generic host-catalog fetcher with cache and default fallback.
|
|
218
|
+
*
|
|
219
|
+
* Intended use:
|
|
220
|
+
* - docs
|
|
221
|
+
* - SDK integration examples
|
|
222
|
+
* - tests that need to demonstrate the transport boundary around discovery
|
|
223
|
+
*
|
|
224
|
+
* Behavior:
|
|
225
|
+
* - successful network catalog refreshes cache
|
|
226
|
+
* - later network failures reuse cached catalog when available
|
|
227
|
+
* - when both network and cache are unavailable, configured defaults are used
|
|
228
|
+
*
|
|
229
|
+
* Production integrations may follow the same policy while replacing this
|
|
230
|
+
* in-memory harness with real logging, metrics, and storage.
|
|
231
|
+
*
|
|
232
|
+
* @param options Optional initial network and default catalogs keyed by URL.
|
|
233
|
+
* @returns Fetcher plus observable state and mutation helpers.
|
|
234
|
+
*/
|
|
235
|
+
export declare function createDiscoveryCatalogFetcher(options?: DiscoveryCatalogFetcherOptions): DiscoveryCatalogFetcherHarness;
|
|
@@ -11,6 +11,19 @@ function asObject(value) {
|
|
|
11
11
|
function asNonEmptyString(value) {
|
|
12
12
|
return typeof value === 'string' ? value.trim() : '';
|
|
13
13
|
}
|
|
14
|
+
export const DiscoveryCatalogSource = Object.freeze({
|
|
15
|
+
Internet: 'internet',
|
|
16
|
+
Cache: 'cache',
|
|
17
|
+
Default: 'default',
|
|
18
|
+
});
|
|
19
|
+
function createDiscoveryCatalogFetchResponse(payload, init = {}) {
|
|
20
|
+
return {
|
|
21
|
+
ok: init.ok ?? true,
|
|
22
|
+
status: init.status ?? 200,
|
|
23
|
+
json: async () => payload,
|
|
24
|
+
text: async () => JSON.stringify(payload),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
14
27
|
function toStringList(value) {
|
|
15
28
|
if (Array.isArray(value)) {
|
|
16
29
|
return Array.from(new Set(value
|
|
@@ -339,3 +352,131 @@ export function filterHostingOperatorDiscoveryCatalog(catalog, filter) {
|
|
|
339
352
|
providers: filterPublishedProvidersByDiscoveryFilter(catalog.providers, filter),
|
|
340
353
|
};
|
|
341
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Builds a normalized published-provider catalog DTO suitable for:
|
|
357
|
+
*
|
|
358
|
+
* - backend-owned fallback catalogs
|
|
359
|
+
* - default discovery data loaded from configuration
|
|
360
|
+
* - tests that should use the same DTO constructors as production code
|
|
361
|
+
*
|
|
362
|
+
* This helper is intentionally neutral:
|
|
363
|
+
* - no example DIDs
|
|
364
|
+
* - no example URLs
|
|
365
|
+
* - no hidden business defaults
|
|
366
|
+
*
|
|
367
|
+
* @param input Required provider catalog fields plus optional URLs.
|
|
368
|
+
* @returns Normalized published-provider catalog record.
|
|
369
|
+
*/
|
|
370
|
+
export function buildDefaultPublishedProviderCatalogRecord(input) {
|
|
371
|
+
const normalizedAreaServed = Array.isArray(input.areaServed)
|
|
372
|
+
? normalizeList(input.areaServed.map((value) => asNonEmptyString(value)).filter(Boolean))
|
|
373
|
+
: toStringList(input.areaServed);
|
|
374
|
+
return {
|
|
375
|
+
providerDid: asNonEmptyString(input.providerDid),
|
|
376
|
+
serviceType: asNonEmptyString(input.serviceType),
|
|
377
|
+
category: asNonEmptyString(input.category),
|
|
378
|
+
areaServed: normalizedAreaServed.length ? normalizedAreaServed.join(',') : undefined,
|
|
379
|
+
endpointUrl: asNonEmptyString(input.endpointUrl) || undefined,
|
|
380
|
+
discoveryUrl: asNonEmptyString(input.discoveryUrl) || undefined,
|
|
381
|
+
catalogUrl: asNonEmptyString(input.catalogUrl) || undefined,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Builds a normalized hosting-operator discovery catalog DTO suitable for:
|
|
386
|
+
*
|
|
387
|
+
* - backend-owned fallback catalogs
|
|
388
|
+
* - default host catalogs assembled from configuration
|
|
389
|
+
* - tests that should reuse the same constructor as production code
|
|
390
|
+
*
|
|
391
|
+
* @param input Optional host identity fields plus the provider list.
|
|
392
|
+
* @returns Normalized host discovery catalog.
|
|
393
|
+
*/
|
|
394
|
+
export function buildDefaultHostingOperatorDiscoveryCatalog(input = {}) {
|
|
395
|
+
return {
|
|
396
|
+
hostingOperatorDid: asNonEmptyString(input.hostingOperatorDid) || undefined,
|
|
397
|
+
discoveryUrl: asNonEmptyString(input.discoveryUrl) || undefined,
|
|
398
|
+
catalogUrl: asNonEmptyString(input.catalogUrl) || undefined,
|
|
399
|
+
providers: [...(input.providers || [])],
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
function isHostingOperatorCatalogPayload(value) {
|
|
403
|
+
const objectValue = asObject(value);
|
|
404
|
+
return Boolean(objectValue && Array.isArray(objectValue.providers));
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Creates a generic host-catalog fetcher with cache and default fallback.
|
|
408
|
+
*
|
|
409
|
+
* Intended use:
|
|
410
|
+
* - docs
|
|
411
|
+
* - SDK integration examples
|
|
412
|
+
* - tests that need to demonstrate the transport boundary around discovery
|
|
413
|
+
*
|
|
414
|
+
* Behavior:
|
|
415
|
+
* - successful network catalog refreshes cache
|
|
416
|
+
* - later network failures reuse cached catalog when available
|
|
417
|
+
* - when both network and cache are unavailable, configured defaults are used
|
|
418
|
+
*
|
|
419
|
+
* Production integrations may follow the same policy while replacing this
|
|
420
|
+
* in-memory harness with real logging, metrics, and storage.
|
|
421
|
+
*
|
|
422
|
+
* @param options Optional initial network and default catalogs keyed by URL.
|
|
423
|
+
* @returns Fetcher plus observable state and mutation helpers.
|
|
424
|
+
*/
|
|
425
|
+
export function createDiscoveryCatalogFetcher(options = {}) {
|
|
426
|
+
const internetResponses = new Map([
|
|
427
|
+
...Object.entries(options.internetCatalogs || {}).map(([url, catalog]) => [url, createDiscoveryCatalogFetchResponse(catalog, { ok: true, status: 200 })]),
|
|
428
|
+
...Object.entries(options.internetJsonByUrl || {}).map(([url, payload]) => [url, createDiscoveryCatalogFetchResponse(payload, { ok: true, status: 200 })]),
|
|
429
|
+
]);
|
|
430
|
+
const internetPayloads = new Map([
|
|
431
|
+
...Object.entries(options.internetCatalogs || {}).map(([url, catalog]) => [String(url), catalog]),
|
|
432
|
+
...Object.entries(options.internetJsonByUrl || {}).map(([url, payload]) => [String(url), payload]),
|
|
433
|
+
]);
|
|
434
|
+
const defaultCatalogs = new Map(Object.entries(options.defaultCatalogs || {}));
|
|
435
|
+
const cache = new Map();
|
|
436
|
+
const sources = new Map();
|
|
437
|
+
const calls = [];
|
|
438
|
+
return {
|
|
439
|
+
calls,
|
|
440
|
+
sources,
|
|
441
|
+
cache,
|
|
442
|
+
setInternetCatalog(url, catalog) {
|
|
443
|
+
internetResponses.set(String(url), createDiscoveryCatalogFetchResponse(catalog, { ok: true, status: 200 }));
|
|
444
|
+
internetPayloads.set(String(url), catalog);
|
|
445
|
+
},
|
|
446
|
+
setInternetJson(url, payload) {
|
|
447
|
+
internetResponses.set(String(url), createDiscoveryCatalogFetchResponse(payload, { ok: true, status: 200 }));
|
|
448
|
+
internetPayloads.set(String(url), payload);
|
|
449
|
+
},
|
|
450
|
+
setInternetFailure(url, status = 503, body = { error: 'temporary failure' }) {
|
|
451
|
+
internetResponses.set(String(url), createDiscoveryCatalogFetchResponse(body, { ok: false, status }));
|
|
452
|
+
internetPayloads.delete(String(url));
|
|
453
|
+
},
|
|
454
|
+
clearInternetRoute(url) {
|
|
455
|
+
internetResponses.delete(String(url));
|
|
456
|
+
internetPayloads.delete(String(url));
|
|
457
|
+
},
|
|
458
|
+
async fetcher(input) {
|
|
459
|
+
const key = String(input);
|
|
460
|
+
calls.push(key);
|
|
461
|
+
const internetResponse = internetResponses.get(key);
|
|
462
|
+
if (internetResponse && internetResponse.ok) {
|
|
463
|
+
const payload = internetPayloads.get(key);
|
|
464
|
+
if (isHostingOperatorCatalogPayload(payload)) {
|
|
465
|
+
cache.set(key, payload);
|
|
466
|
+
}
|
|
467
|
+
sources.set(key, DiscoveryCatalogSource.Internet);
|
|
468
|
+
return internetResponse;
|
|
469
|
+
}
|
|
470
|
+
if (cache.has(key)) {
|
|
471
|
+
sources.set(key, DiscoveryCatalogSource.Cache);
|
|
472
|
+
return createDiscoveryCatalogFetchResponse(cache.get(key), { ok: true, status: 200 });
|
|
473
|
+
}
|
|
474
|
+
if (defaultCatalogs.has(key)) {
|
|
475
|
+
sources.set(key, DiscoveryCatalogSource.Default);
|
|
476
|
+
return createDiscoveryCatalogFetchResponse(defaultCatalogs.get(key), { ok: true, status: 200 });
|
|
477
|
+
}
|
|
478
|
+
sources.set(key, DiscoveryCatalogSource.Default);
|
|
479
|
+
return createDiscoveryCatalogFetchResponse({ error: 'not found' }, { ok: false, status: 404 });
|
|
480
|
+
},
|
|
481
|
+
};
|
|
482
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type DataspaceProtocolVersionValue } from '../constants/dataspace-protocol';
|
|
2
|
+
import type { DspaceProtocolVersionEntry, DspaceVersionMetadata } from '../models/dataspace-protocol';
|
|
3
|
+
/**
|
|
4
|
+
* Route context used to build tenant-scoped or host-scoped GW CORE DSP paths.
|
|
5
|
+
*
|
|
6
|
+
* Semantic rule:
|
|
7
|
+
* - `tenantId` participants use `businessSector`
|
|
8
|
+
* - `host`/ICA/runtime participants use `hostNetwork`
|
|
9
|
+
*/
|
|
10
|
+
export type GwDataspaceRouteContext = Readonly<{
|
|
11
|
+
participantId?: string;
|
|
12
|
+
tenantId?: string;
|
|
13
|
+
jurisdiction?: string;
|
|
14
|
+
version?: string;
|
|
15
|
+
hostNetwork?: string;
|
|
16
|
+
/** @deprecated Use `hostNetwork`. */
|
|
17
|
+
hostNetworkOrBusinessSector?: string;
|
|
18
|
+
businessSector?: string;
|
|
19
|
+
sector?: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Builds the GW CORE base DSP path.
|
|
23
|
+
*
|
|
24
|
+
* Participant scope:
|
|
25
|
+
* - `/{participantId}/cds-{jurisdiction}/{version}/{hostNetwork|businessSector}/dsp`
|
|
26
|
+
*/
|
|
27
|
+
export declare function buildGwDataspaceBasePath(input?: GwDataspaceRouteContext): string;
|
|
28
|
+
/**
|
|
29
|
+
* Builds the canonical DSP version-discovery well-known path for GW CORE.
|
|
30
|
+
*
|
|
31
|
+
* Participant scope:
|
|
32
|
+
* - `/{participantId}/cds-{jurisdiction}/{version}/{hostNetwork|businessSector}/.well-known/dspace-version`
|
|
33
|
+
*/
|
|
34
|
+
export declare function buildGwDspaceVersionWellKnownPath(input?: GwDataspaceRouteContext): string;
|
|
35
|
+
/**
|
|
36
|
+
* Builds the project-local GW CORE DSP catalog request endpoint.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildGwCatalogRequestPath(input?: GwDataspaceRouteContext): string;
|
|
39
|
+
/**
|
|
40
|
+
* Builds the GW CORE catalog collection base path.
|
|
41
|
+
*/
|
|
42
|
+
export declare function buildGwCatalogCollectionPath(input?: GwDataspaceRouteContext): string;
|
|
43
|
+
/**
|
|
44
|
+
* Builds the project-local GW CORE catalog artifact URL path used for public
|
|
45
|
+
* read-only autodiscovery.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildGwCatalogArtifactPath(input?: GwDataspaceRouteContext): string;
|
|
48
|
+
/**
|
|
49
|
+
* Builds the project-local GW CORE dataset lookup path.
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildGwCatalogDatasetPath(input?: GwDataspaceRouteContext, datasetId?: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Builds a minimal DSP version metadata payload for a given GW CORE DSP base
|
|
54
|
+
* path.
|
|
55
|
+
*/
|
|
56
|
+
export declare function buildDspaceVersionMetadata(path: string, version?: DataspaceProtocolVersionValue): DspaceVersionMetadata;
|
|
57
|
+
/**
|
|
58
|
+
* Selects the preferred advertised DSP version entry from a `dspace-version`
|
|
59
|
+
* payload.
|
|
60
|
+
*/
|
|
61
|
+
export declare function selectDspaceProtocolVersionEntry(metadata: DspaceVersionMetadata | null | undefined, version?: string): DspaceProtocolVersionEntry | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Derives the GW CORE catalog artifact URL from a `dspace-version` endpoint URL
|
|
64
|
+
* and its parsed payload.
|
|
65
|
+
*/
|
|
66
|
+
export declare function deriveGwCatalogArtifactUrlFromDspaceVersion(dspaceVersionUrl: string, metadata: DspaceVersionMetadata | null | undefined, version?: string): string | undefined;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { DataspaceProtocolVersions, DataspaceWellKnownPaths, GwDataspaceBindingPaths, } from '../constants/dataspace-protocol.js';
|
|
3
|
+
function resolveParticipantId(input) {
|
|
4
|
+
return String(input.participantId || input.tenantId || '').trim();
|
|
5
|
+
}
|
|
6
|
+
function resolveSectorLikeSegment(input) {
|
|
7
|
+
return String(input.hostNetwork
|
|
8
|
+
|| input.hostNetworkOrBusinessSector
|
|
9
|
+
|| input.businessSector
|
|
10
|
+
|| input.sector
|
|
11
|
+
|| '').trim();
|
|
12
|
+
}
|
|
13
|
+
function hasParticipantRouteContext(input) {
|
|
14
|
+
return Boolean(resolveParticipantId(input)
|
|
15
|
+
&& String(input.jurisdiction || '').trim()
|
|
16
|
+
&& String(input.version || '').trim()
|
|
17
|
+
&& resolveSectorLikeSegment(input));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Builds the GW CORE base DSP path.
|
|
21
|
+
*
|
|
22
|
+
* Participant scope:
|
|
23
|
+
* - `/{participantId}/cds-{jurisdiction}/{version}/{hostNetwork|businessSector}/dsp`
|
|
24
|
+
*/
|
|
25
|
+
export function buildGwDataspaceBasePath(input = {}) {
|
|
26
|
+
if (!hasParticipantRouteContext(input)) {
|
|
27
|
+
return GwDataspaceBindingPaths.Base;
|
|
28
|
+
}
|
|
29
|
+
return `/${resolveParticipantId(input)}`
|
|
30
|
+
+ `/cds-${String(input.jurisdiction).trim()}`
|
|
31
|
+
+ `/${String(input.version).trim()}`
|
|
32
|
+
+ `/${resolveSectorLikeSegment(input)}`
|
|
33
|
+
+ GwDataspaceBindingPaths.Base;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Builds the canonical DSP version-discovery well-known path for GW CORE.
|
|
37
|
+
*
|
|
38
|
+
* Participant scope:
|
|
39
|
+
* - `/{participantId}/cds-{jurisdiction}/{version}/{hostNetwork|businessSector}/.well-known/dspace-version`
|
|
40
|
+
*/
|
|
41
|
+
export function buildGwDspaceVersionWellKnownPath(input = {}) {
|
|
42
|
+
if (!hasParticipantRouteContext(input)) {
|
|
43
|
+
return DataspaceWellKnownPaths.VersionMetadata;
|
|
44
|
+
}
|
|
45
|
+
return `/${resolveParticipantId(input)}`
|
|
46
|
+
+ `/cds-${String(input.jurisdiction).trim()}`
|
|
47
|
+
+ `/${String(input.version).trim()}`
|
|
48
|
+
+ `/${resolveSectorLikeSegment(input)}`
|
|
49
|
+
+ DataspaceWellKnownPaths.VersionMetadata;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Builds the project-local GW CORE DSP catalog request endpoint.
|
|
53
|
+
*/
|
|
54
|
+
export function buildGwCatalogRequestPath(input = {}) {
|
|
55
|
+
return `${buildGwDataspaceBasePath(input)}${GwDataspaceBindingPaths.CatalogRequestSuffix}`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Builds the GW CORE catalog collection base path.
|
|
59
|
+
*/
|
|
60
|
+
export function buildGwCatalogCollectionPath(input = {}) {
|
|
61
|
+
return `${buildGwDataspaceBasePath(input)}${GwDataspaceBindingPaths.CatalogCollectionSuffix}`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Builds the project-local GW CORE catalog artifact URL path used for public
|
|
65
|
+
* read-only autodiscovery.
|
|
66
|
+
*/
|
|
67
|
+
export function buildGwCatalogArtifactPath(input = {}) {
|
|
68
|
+
return `${buildGwDataspaceBasePath(input)}${GwDataspaceBindingPaths.CatalogArtifactSuffix}`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Builds the project-local GW CORE dataset lookup path.
|
|
72
|
+
*/
|
|
73
|
+
export function buildGwCatalogDatasetPath(input = {}, datasetId = ':id') {
|
|
74
|
+
return `${buildGwDataspaceBasePath(input)}${GwDataspaceBindingPaths.CatalogDatasetsPrefix}/${datasetId}`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Builds a minimal DSP version metadata payload for a given GW CORE DSP base
|
|
78
|
+
* path.
|
|
79
|
+
*/
|
|
80
|
+
export function buildDspaceVersionMetadata(path, version = DataspaceProtocolVersions.Current) {
|
|
81
|
+
return {
|
|
82
|
+
protocolVersions: [
|
|
83
|
+
{
|
|
84
|
+
version,
|
|
85
|
+
path,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Selects the preferred advertised DSP version entry from a `dspace-version`
|
|
92
|
+
* payload.
|
|
93
|
+
*/
|
|
94
|
+
export function selectDspaceProtocolVersionEntry(metadata, version = DataspaceProtocolVersions.Current) {
|
|
95
|
+
const entries = metadata?.protocolVersions || [];
|
|
96
|
+
return entries.find((entry) => String(entry.version || '').trim() === String(version).trim())
|
|
97
|
+
|| entries[0];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Derives the GW CORE catalog artifact URL from a `dspace-version` endpoint URL
|
|
101
|
+
* and its parsed payload.
|
|
102
|
+
*/
|
|
103
|
+
export function deriveGwCatalogArtifactUrlFromDspaceVersion(dspaceVersionUrl, metadata, version = DataspaceProtocolVersions.Current) {
|
|
104
|
+
const entry = selectDspaceProtocolVersionEntry(metadata, version);
|
|
105
|
+
if (!entry?.path)
|
|
106
|
+
return undefined;
|
|
107
|
+
const base = new URL(dspaceVersionUrl);
|
|
108
|
+
return new URL(`${String(entry.path).trim()}${GwDataspaceBindingPaths.CatalogArtifactSuffix}`, `${base.protocol}//${base.host}`).toString();
|
|
109
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export * from './consent';
|
|
|
8
8
|
export * from './did';
|
|
9
9
|
export * from './did-resolution';
|
|
10
10
|
export * from './dataspace-discovery';
|
|
11
|
+
export * from './dataspace-discovery-defaults';
|
|
12
|
+
export * from './dataspace-protocol';
|
|
11
13
|
export * from './didcomm';
|
|
12
14
|
export * from './didcomm-submit';
|
|
13
15
|
export * from './didcomm-submit-policy';
|
package/dist/utils/index.js
CHANGED
|
@@ -8,6 +8,8 @@ export * from './consent.js';
|
|
|
8
8
|
export * from './did.js';
|
|
9
9
|
export * from './did-resolution.js';
|
|
10
10
|
export * from './dataspace-discovery.js';
|
|
11
|
+
export * from './dataspace-discovery-defaults.js';
|
|
12
|
+
export * from './dataspace-protocol.js';
|
|
11
13
|
export * from './didcomm.js';
|
|
12
14
|
export * from './didcomm-submit.js';
|
|
13
15
|
export * from './didcomm-submit-policy.js';
|