gdc-sdk-node-ts 0.8.1 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/discovery/DataspaceResolver.d.ts +1 -24
- package/dist/discovery/DataspaceResolver.js +1 -13
- package/dist/discovery/DefaultFirstDataspaceDiscovery.d.ts +1 -44
- package/dist/discovery/DefaultFirstDataspaceDiscovery.js +1 -162
- package/dist/discovery/HttpDataspaceResolver.d.ts +1 -30
- package/dist/discovery/HttpDataspaceResolver.js +1 -230
- package/dist/discovery/index.d.ts +1 -4
- package/dist/discovery/index.js +1 -4
- package/dist/discovery/types.d.ts +1 -96
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -191,7 +191,8 @@ Documentation consistency rule for this repo family:
|
|
|
191
191
|
Use the Node discovery layer when your backend or BFF needs to:
|
|
192
192
|
|
|
193
193
|
- start from preloaded hosting-operator semantics
|
|
194
|
-
- fetch the canonical
|
|
194
|
+
- fetch the canonical host-scoped
|
|
195
|
+
`/<hosting-operator-network-context>/.well-known/dspace-version` entrypoint
|
|
195
196
|
- derive the participant-scoped `/dsp/catalog/dcat.json` artifact
|
|
196
197
|
- return normalized provider/operator matches to portal or app backends
|
|
197
198
|
|
|
@@ -203,6 +204,11 @@ Primary references:
|
|
|
203
204
|
- [tests/dataspace-resolver-advanced.test.mjs](tests/dataspace-resolver-advanced.test.mjs)
|
|
204
205
|
- [tests/dataspace-resolver.test.mjs](tests/dataspace-resolver.test.mjs)
|
|
205
206
|
|
|
207
|
+
Architecture note:
|
|
208
|
+
|
|
209
|
+
- the reusable discovery resolver logic lives in `gdc-sdk-core-ts`
|
|
210
|
+
- `gdc-sdk-node-ts` re-exports it and supplies the Node runtime surface
|
|
211
|
+
|
|
206
212
|
Copy/paste starting point:
|
|
207
213
|
|
|
208
214
|
```ts
|
|
@@ -1,24 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Backend/BFF-facing abstraction for dataspace discovery resolution.
|
|
4
|
-
*
|
|
5
|
-
* Responsibility boundary:
|
|
6
|
-
* - node runtimes orchestrate VC parsing, host-catalog fetch, and capability
|
|
7
|
-
* filtering
|
|
8
|
-
* - semantic extraction and EU coverage inference come from
|
|
9
|
-
* `gdc-common-utils-ts`
|
|
10
|
-
* - tenant-host linkage is resolved from host public catalogs, not from private
|
|
11
|
-
* tenant VC fields
|
|
12
|
-
*/
|
|
13
|
-
export declare abstract class DataspaceResolver {
|
|
14
|
-
/**
|
|
15
|
-
* Resolves hosting operators whose semantic service metadata matches the
|
|
16
|
-
* requested sector, capability set, and optional coverage dimensions.
|
|
17
|
-
*/
|
|
18
|
-
abstract resolveHostingOperators(input: ResolveHostingOperatorsInput): Promise<HostingOperatorMatch[]>;
|
|
19
|
-
/**
|
|
20
|
-
* Resolves publicly published provider offerings starting from eligible
|
|
21
|
-
* hosting operators and their public discovery catalogs.
|
|
22
|
-
*/
|
|
23
|
-
abstract resolvePublishedProviders(input: ResolvePublishedProvidersInput): Promise<PublishedProviderMatch[]>;
|
|
24
|
-
}
|
|
1
|
+
export { DataspaceResolver } from 'gdc-sdk-core-ts';
|
|
@@ -1,14 +1,2 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
-
|
|
3
|
-
* Backend/BFF-facing abstraction for dataspace discovery resolution.
|
|
4
|
-
*
|
|
5
|
-
* Responsibility boundary:
|
|
6
|
-
* - node runtimes orchestrate VC parsing, host-catalog fetch, and capability
|
|
7
|
-
* filtering
|
|
8
|
-
* - semantic extraction and EU coverage inference come from
|
|
9
|
-
* `gdc-common-utils-ts`
|
|
10
|
-
* - tenant-host linkage is resolved from host public catalogs, not from private
|
|
11
|
-
* tenant VC fields
|
|
12
|
-
*/
|
|
13
|
-
export class DataspaceResolver {
|
|
14
|
-
}
|
|
2
|
+
export { DataspaceResolver } from 'gdc-sdk-core-ts';
|
|
@@ -1,44 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* High-level default-first discovery facade for portal/backend integrations.
|
|
4
|
-
*
|
|
5
|
-
* Intended usage:
|
|
6
|
-
* - configure ICA/hosting defaults once during backend startup
|
|
7
|
-
* - later ask simple questions per request:
|
|
8
|
-
* - `getHosts({ sector, jurisdiction })`
|
|
9
|
-
* - `getIndexProviders({ sector, jurisdiction })`
|
|
10
|
-
* - `getDigitalTwinProviders({ sector, jurisdiction })`
|
|
11
|
-
*
|
|
12
|
-
* The facade keeps the bootstrap-plan plumbing internal so app code does not
|
|
13
|
-
* need to understand the lower-level defaults registry or resolver wiring.
|
|
14
|
-
*/
|
|
15
|
-
export declare class DefaultFirstDataspaceDiscovery {
|
|
16
|
-
private readonly defaultsRegistry;
|
|
17
|
-
private readonly version;
|
|
18
|
-
private readonly networkType;
|
|
19
|
-
private readonly fetcher?;
|
|
20
|
-
constructor(options: DefaultFirstDataspaceDiscoveryOptions);
|
|
21
|
-
/**
|
|
22
|
-
* Returns matching hosting operators for one `sector + jurisdiction`
|
|
23
|
-
* request using the configured default-first bootstrap policy.
|
|
24
|
-
*/
|
|
25
|
-
getHosts(input: GetDataspaceHostsInput): Promise<HostingOperatorMatch[]>;
|
|
26
|
-
/**
|
|
27
|
-
* Returns published `IndexProvider` services for one `sector + jurisdiction`
|
|
28
|
-
* request.
|
|
29
|
-
*/
|
|
30
|
-
getIndexProviders(input: SimpleDataspaceDiscoveryRequest): Promise<PublishedProviderMatch[]>;
|
|
31
|
-
/**
|
|
32
|
-
* Returns published `DigitalTwinProvider` services for one
|
|
33
|
-
* `sector + jurisdiction` request.
|
|
34
|
-
*/
|
|
35
|
-
getDigitalTwinProviders(input: SimpleDataspaceDiscoveryRequest): Promise<PublishedProviderMatch[]>;
|
|
36
|
-
private getProviders;
|
|
37
|
-
private createResolver;
|
|
38
|
-
private buildBootstrapPlan;
|
|
39
|
-
private resolveDefaultPublishedProviders;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Convenience factory for the default-first portal/backend discovery facade.
|
|
43
|
-
*/
|
|
44
|
-
export declare function createDefaultFirstDataspaceDiscovery(options: DefaultFirstDataspaceDiscoveryOptions): DefaultFirstDataspaceDiscovery;
|
|
1
|
+
export { DefaultFirstDataspaceDiscovery, createDefaultFirstDataspaceDiscovery, } from 'gdc-sdk-core-ts';
|
|
@@ -1,163 +1,2 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
-
|
|
3
|
-
import { HttpDataspaceResolver } from './HttpDataspaceResolver.js';
|
|
4
|
-
function normalizeString(value) {
|
|
5
|
-
return typeof value === 'string' ? value.trim() : '';
|
|
6
|
-
}
|
|
7
|
-
function equalsIgnoreCase(left, right) {
|
|
8
|
-
return left.trim().toLowerCase() === right.trim().toLowerCase();
|
|
9
|
-
}
|
|
10
|
-
function splitTokens(value) {
|
|
11
|
-
if (Array.isArray(value)) {
|
|
12
|
-
return value.map((entry) => normalizeString(entry)).filter(Boolean);
|
|
13
|
-
}
|
|
14
|
-
const raw = normalizeString(value);
|
|
15
|
-
if (!raw)
|
|
16
|
-
return [];
|
|
17
|
-
return raw.split(',').map((entry) => entry.trim()).filter(Boolean);
|
|
18
|
-
}
|
|
19
|
-
function buildCoverageTokens(areaServed, filterJurisdiction) {
|
|
20
|
-
const tokens = new Set(splitTokens(areaServed).map((token) => token.toUpperCase()));
|
|
21
|
-
const normalizedJurisdiction = normalizeCountryCode(filterJurisdiction);
|
|
22
|
-
if (normalizedJurisdiction) {
|
|
23
|
-
const inferred = inferCoverageScopeFromCountryCode(normalizedJurisdiction);
|
|
24
|
-
if (inferred)
|
|
25
|
-
tokens.add(inferred.toUpperCase());
|
|
26
|
-
}
|
|
27
|
-
return tokens;
|
|
28
|
-
}
|
|
29
|
-
function matchesProviderCoverage(provider, jurisdiction, coverageScope) {
|
|
30
|
-
const normalizedJurisdiction = normalizeCountryCode(jurisdiction);
|
|
31
|
-
const normalizedCoverageScope = normalizeString(coverageScope).toUpperCase();
|
|
32
|
-
if (!normalizedJurisdiction && !normalizedCoverageScope)
|
|
33
|
-
return true;
|
|
34
|
-
const tokens = buildCoverageTokens(provider.areaServed, jurisdiction);
|
|
35
|
-
if (normalizedJurisdiction && tokens.has(normalizedJurisdiction))
|
|
36
|
-
return true;
|
|
37
|
-
if (normalizedCoverageScope && tokens.has(normalizedCoverageScope))
|
|
38
|
-
return true;
|
|
39
|
-
if (normalizedCoverageScope === DataspaceCoverageScope.EuropeanUnion) {
|
|
40
|
-
return Array.from(tokens).some((token) => inferCoverageScopeFromCountryCode(token) === DataspaceCoverageScope.EuropeanUnion);
|
|
41
|
-
}
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
function matchesDefaultPublishedProvider(provider, input, providerCapability) {
|
|
45
|
-
if (!equalsIgnoreCase(provider.category, input.sector))
|
|
46
|
-
return false;
|
|
47
|
-
if (!isProviderServiceCapability(provider.serviceType))
|
|
48
|
-
return false;
|
|
49
|
-
if (!equalsIgnoreCase(provider.serviceType, providerCapability))
|
|
50
|
-
return false;
|
|
51
|
-
if (!matchesProviderCoverage(provider, input.jurisdiction, input.coverageScope))
|
|
52
|
-
return false;
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
function isDefaultsRegistry(value) {
|
|
56
|
-
return Boolean(value)
|
|
57
|
-
&& typeof value === 'object'
|
|
58
|
-
&& 'buildBootstrapPlan' in value
|
|
59
|
-
&& typeof value.buildBootstrapPlan === 'function';
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* High-level default-first discovery facade for portal/backend integrations.
|
|
63
|
-
*
|
|
64
|
-
* Intended usage:
|
|
65
|
-
* - configure ICA/hosting defaults once during backend startup
|
|
66
|
-
* - later ask simple questions per request:
|
|
67
|
-
* - `getHosts({ sector, jurisdiction })`
|
|
68
|
-
* - `getIndexProviders({ sector, jurisdiction })`
|
|
69
|
-
* - `getDigitalTwinProviders({ sector, jurisdiction })`
|
|
70
|
-
*
|
|
71
|
-
* The facade keeps the bootstrap-plan plumbing internal so app code does not
|
|
72
|
-
* need to understand the lower-level defaults registry or resolver wiring.
|
|
73
|
-
*/
|
|
74
|
-
export class DefaultFirstDataspaceDiscovery {
|
|
75
|
-
constructor(options) {
|
|
76
|
-
this.defaultsRegistry = isDefaultsRegistry(options.defaults)
|
|
77
|
-
? options.defaults
|
|
78
|
-
: createDataspaceDiscoveryDefaultsRegistry(options.defaults);
|
|
79
|
-
this.version = normalizeString(options.version) || DataspaceProtocolVersions.Current;
|
|
80
|
-
this.networkType = normalizeString(options.networkType);
|
|
81
|
-
this.fetcher = options.fetcher;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Returns matching hosting operators for one `sector + jurisdiction`
|
|
85
|
-
* request using the configured default-first bootstrap policy.
|
|
86
|
-
*/
|
|
87
|
-
async getHosts(input) {
|
|
88
|
-
const resolver = this.createResolver(input, input.requiredCapabilities || []);
|
|
89
|
-
return resolver.resolveHostingOperators({
|
|
90
|
-
sector: input.sector,
|
|
91
|
-
jurisdiction: input.jurisdiction,
|
|
92
|
-
coverageScope: input.coverageScope,
|
|
93
|
-
requiredCapabilities: [...(input.requiredCapabilities || [])],
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Returns published `IndexProvider` services for one `sector + jurisdiction`
|
|
98
|
-
* request.
|
|
99
|
-
*/
|
|
100
|
-
async getIndexProviders(input) {
|
|
101
|
-
return this.getProviders(input, ServiceCapabilityToken.IndexProvider);
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Returns published `DigitalTwinProvider` services for one
|
|
105
|
-
* `sector + jurisdiction` request.
|
|
106
|
-
*/
|
|
107
|
-
async getDigitalTwinProviders(input) {
|
|
108
|
-
return this.getProviders(input, ServiceCapabilityToken.DigitalTwinProvider);
|
|
109
|
-
}
|
|
110
|
-
async getProviders(input, providerCapability) {
|
|
111
|
-
const bootstrapPlan = this.buildBootstrapPlan(input, [providerCapability]);
|
|
112
|
-
const defaultPublishedProviders = this.resolveDefaultPublishedProviders(bootstrapPlan.hostingOperators, input, providerCapability);
|
|
113
|
-
if (defaultPublishedProviders.length > 0) {
|
|
114
|
-
return defaultPublishedProviders;
|
|
115
|
-
}
|
|
116
|
-
const resolver = new HttpDataspaceResolver({
|
|
117
|
-
hostingOperators: bootstrapPlan.hostingOperators,
|
|
118
|
-
fetcher: this.fetcher,
|
|
119
|
-
});
|
|
120
|
-
return resolver.resolvePublishedProviders({
|
|
121
|
-
sector: input.sector,
|
|
122
|
-
jurisdiction: input.jurisdiction,
|
|
123
|
-
coverageScope: input.coverageScope,
|
|
124
|
-
providerCapability,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
createResolver(input, requiredCapabilities) {
|
|
128
|
-
const bootstrapPlan = this.buildBootstrapPlan(input, requiredCapabilities);
|
|
129
|
-
return new HttpDataspaceResolver({
|
|
130
|
-
hostingOperators: bootstrapPlan.hostingOperators,
|
|
131
|
-
fetcher: this.fetcher,
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
buildBootstrapPlan(input, requiredCapabilities) {
|
|
135
|
-
return this.defaultsRegistry.buildBootstrapPlan({
|
|
136
|
-
jurisdiction: input.jurisdiction,
|
|
137
|
-
version: this.version,
|
|
138
|
-
networkType: this.networkType,
|
|
139
|
-
sector: input.sector,
|
|
140
|
-
coverageScope: input.coverageScope,
|
|
141
|
-
requiredCapabilities,
|
|
142
|
-
sourceMode: DataspaceDiscoverySourceMode.DefaultFirst,
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
resolveDefaultPublishedProviders(hosts, input, providerCapability) {
|
|
146
|
-
return hosts.flatMap((host) => (host.publishedProviders || [])
|
|
147
|
-
.filter((provider) => matchesDefaultPublishedProvider(provider, input, providerCapability))
|
|
148
|
-
.map((provider) => ({
|
|
149
|
-
providerDid: provider.providerDid,
|
|
150
|
-
record: provider,
|
|
151
|
-
hostingOperator: host.record,
|
|
152
|
-
hostingOperatorDid: host.operatorDid,
|
|
153
|
-
discoveryUrl: provider.discoveryUrl || host.discoveryUrl,
|
|
154
|
-
catalogUrl: provider.catalogUrl || host.catalogUrl,
|
|
155
|
-
})));
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Convenience factory for the default-first portal/backend discovery facade.
|
|
160
|
-
*/
|
|
161
|
-
export function createDefaultFirstDataspaceDiscovery(options) {
|
|
162
|
-
return new DefaultFirstDataspaceDiscovery(options);
|
|
163
|
-
}
|
|
2
|
+
export { DefaultFirstDataspaceDiscovery, createDefaultFirstDataspaceDiscovery, } from 'gdc-sdk-core-ts';
|
|
@@ -1,30 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type { HostingOperatorMatch, HttpDataspaceResolverOptions, PublishedProviderMatch, ResolveHostingOperatorsInput, ResolvePublishedProvidersInput } from './types.js';
|
|
3
|
-
/**
|
|
4
|
-
* Concrete node/BFF resolver that combines preloaded hosting-operator records
|
|
5
|
-
* with each host's public service-autodiscovery catalog.
|
|
6
|
-
*/
|
|
7
|
-
export declare class HttpDataspaceResolver extends DataspaceResolver {
|
|
8
|
-
private readonly hostingOperators;
|
|
9
|
-
private readonly fetcher;
|
|
10
|
-
constructor(options: HttpDataspaceResolverOptions);
|
|
11
|
-
/**
|
|
12
|
-
* Resolves hosting operators from the preloaded semantic records.
|
|
13
|
-
*/
|
|
14
|
-
resolveHostingOperators(input: ResolveHostingOperatorsInput): Promise<HostingOperatorMatch[]>;
|
|
15
|
-
/**
|
|
16
|
-
* Resolves published providers by fetching and filtering eligible host public
|
|
17
|
-
* discovery catalogs.
|
|
18
|
-
*/
|
|
19
|
-
resolvePublishedProviders(input: ResolvePublishedProvidersInput): Promise<PublishedProviderMatch[]>;
|
|
20
|
-
/**
|
|
21
|
-
* Fetches a public discovery catalog for a hosting operator.
|
|
22
|
-
*
|
|
23
|
-
* Resolution order:
|
|
24
|
-
* - canonical DSP entrypoint via `discoveryUrl` (`/.well-known/dspace-version`)
|
|
25
|
-
* - direct catalog artifact compatibility via `catalogUrl`
|
|
26
|
-
*/
|
|
27
|
-
private fetchCatalog;
|
|
28
|
-
private resolveCatalogArtifactUrl;
|
|
29
|
-
private fetchDspaceVersionMetadata;
|
|
30
|
-
}
|
|
1
|
+
export { HttpDataspaceResolver } from 'gdc-sdk-core-ts';
|
|
@@ -1,231 +1,2 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
-
|
|
3
|
-
import { DataspaceResolver } from './DataspaceResolver.js';
|
|
4
|
-
function isObject(value) {
|
|
5
|
-
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
6
|
-
}
|
|
7
|
-
function asString(value) {
|
|
8
|
-
return typeof value === 'string' ? value.trim() : '';
|
|
9
|
-
}
|
|
10
|
-
function equalsIgnoreCase(left, right) {
|
|
11
|
-
return left.trim().toLowerCase() === right.trim().toLowerCase();
|
|
12
|
-
}
|
|
13
|
-
function splitTokens(value) {
|
|
14
|
-
if (Array.isArray(value)) {
|
|
15
|
-
return value.map((entry) => asString(entry)).filter(Boolean);
|
|
16
|
-
}
|
|
17
|
-
const raw = typeof value === 'string' ? value : '';
|
|
18
|
-
if (!raw)
|
|
19
|
-
return [];
|
|
20
|
-
return raw.split(',').map((entry) => entry.trim()).filter(Boolean);
|
|
21
|
-
}
|
|
22
|
-
function hasAllTokens(values, requiredValues) {
|
|
23
|
-
if (!requiredValues?.length)
|
|
24
|
-
return true;
|
|
25
|
-
const normalizedValues = new Set((values || []).map((value) => value.trim().toLowerCase()).filter(Boolean));
|
|
26
|
-
return requiredValues.every((requiredValue) => normalizedValues.has(requiredValue.trim().toLowerCase()));
|
|
27
|
-
}
|
|
28
|
-
function matchSectorValues(values, sector) {
|
|
29
|
-
if (!sector)
|
|
30
|
-
return true;
|
|
31
|
-
return (values || []).some((value) => equalsIgnoreCase(value, sector));
|
|
32
|
-
}
|
|
33
|
-
function buildCoverageTokens(recordCountry, areaServed, coverageScope) {
|
|
34
|
-
const tokens = new Set();
|
|
35
|
-
splitTokens(areaServed).forEach((token) => tokens.add(token.toUpperCase()));
|
|
36
|
-
const normalizedCountry = normalizeCountryCode(recordCountry);
|
|
37
|
-
if (normalizedCountry) {
|
|
38
|
-
tokens.add(normalizedCountry);
|
|
39
|
-
const inferred = inferCoverageScopeFromCountryCode(normalizedCountry);
|
|
40
|
-
if (inferred)
|
|
41
|
-
tokens.add(inferred.toUpperCase());
|
|
42
|
-
}
|
|
43
|
-
if (coverageScope) {
|
|
44
|
-
tokens.add(coverageScope.trim().toUpperCase());
|
|
45
|
-
}
|
|
46
|
-
return tokens;
|
|
47
|
-
}
|
|
48
|
-
function matchesDiscoveryCoverage(recordCountry, areaServed, filterJurisdiction, filterCoverageScope) {
|
|
49
|
-
const normalizedJurisdiction = normalizeCountryCode(filterJurisdiction);
|
|
50
|
-
const normalizedCoverageScope = asString(filterCoverageScope).toUpperCase();
|
|
51
|
-
if (!normalizedJurisdiction && !normalizedCoverageScope)
|
|
52
|
-
return true;
|
|
53
|
-
const tokens = buildCoverageTokens(recordCountry, areaServed, undefined);
|
|
54
|
-
if (normalizedJurisdiction && tokens.has(normalizedJurisdiction))
|
|
55
|
-
return true;
|
|
56
|
-
if (normalizedCoverageScope && tokens.has(normalizedCoverageScope))
|
|
57
|
-
return true;
|
|
58
|
-
if (normalizedJurisdiction) {
|
|
59
|
-
const inferred = inferCoverageScopeFromCountryCode(normalizedJurisdiction);
|
|
60
|
-
if (inferred && tokens.has(inferred.toUpperCase()))
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
if (normalizedCoverageScope === DataspaceCoverageScope.EuropeanUnion) {
|
|
64
|
-
if (Array.from(tokens).some((token) => inferCoverageScopeFromCountryCode(token) === DataspaceCoverageScope.EuropeanUnion)) {
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
function toHostingOperatorCatalog(value) {
|
|
71
|
-
if (!isObject(value))
|
|
72
|
-
return null;
|
|
73
|
-
const providers = value.providers;
|
|
74
|
-
if (!Array.isArray(providers))
|
|
75
|
-
return null;
|
|
76
|
-
const normalizedProviders = providers
|
|
77
|
-
.filter(isObject)
|
|
78
|
-
.map((provider) => {
|
|
79
|
-
const normalized = {
|
|
80
|
-
providerDid: asString(provider.providerDid),
|
|
81
|
-
serviceType: asString(provider.serviceType),
|
|
82
|
-
category: asString(provider.category),
|
|
83
|
-
areaServed: asString(provider.areaServed) || undefined,
|
|
84
|
-
endpointUrl: asString(provider.endpointUrl) || undefined,
|
|
85
|
-
discoveryUrl: asString(provider.discoveryUrl) || undefined,
|
|
86
|
-
catalogUrl: asString(provider.catalogUrl) || undefined,
|
|
87
|
-
};
|
|
88
|
-
return normalized.providerDid && normalized.serviceType && normalized.category
|
|
89
|
-
? normalized
|
|
90
|
-
: null;
|
|
91
|
-
})
|
|
92
|
-
.filter((provider) => Boolean(provider));
|
|
93
|
-
return {
|
|
94
|
-
hostingOperatorDid: asString(value.hostingOperatorDid) || undefined,
|
|
95
|
-
discoveryUrl: asString(value.discoveryUrl) || undefined,
|
|
96
|
-
catalogUrl: asString(value.catalogUrl) || undefined,
|
|
97
|
-
providers: normalizedProviders,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
function matchHostingOperatorRecord(record, input) {
|
|
101
|
-
if (!matchSectorValues(record.categories, input.sector))
|
|
102
|
-
return false;
|
|
103
|
-
if (!hasAllTokens(record.serviceTypes, input.requiredCapabilities))
|
|
104
|
-
return false;
|
|
105
|
-
if (!matchesDiscoveryCoverage(record.addressCountry, record.areaServed, input.jurisdiction, input.coverageScope))
|
|
106
|
-
return false;
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
function matchPublishedProviderRecord(provider, input) {
|
|
110
|
-
if (!equalsIgnoreCase(provider.category, input.sector))
|
|
111
|
-
return false;
|
|
112
|
-
if (!isProviderServiceCapability(provider.serviceType))
|
|
113
|
-
return false;
|
|
114
|
-
if (!equalsIgnoreCase(provider.serviceType, input.providerCapability))
|
|
115
|
-
return false;
|
|
116
|
-
if (!matchesDiscoveryCoverage(undefined, provider.areaServed, input.jurisdiction, input.coverageScope))
|
|
117
|
-
return false;
|
|
118
|
-
return true;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Concrete node/BFF resolver that combines preloaded hosting-operator records
|
|
122
|
-
* with each host's public service-autodiscovery catalog.
|
|
123
|
-
*/
|
|
124
|
-
export class HttpDataspaceResolver extends DataspaceResolver {
|
|
125
|
-
constructor(options) {
|
|
126
|
-
super();
|
|
127
|
-
this.hostingOperators = [...options.hostingOperators];
|
|
128
|
-
this.fetcher = options.fetcher || globalThis.fetch.bind(globalThis);
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Resolves hosting operators from the preloaded semantic records.
|
|
132
|
-
*/
|
|
133
|
-
async resolveHostingOperators(input) {
|
|
134
|
-
return this.hostingOperators
|
|
135
|
-
.filter(({ record }) => matchHostingOperatorRecord(record, input))
|
|
136
|
-
.map(({ operatorDid, discoveryUrl, record, catalogUrl }) => ({
|
|
137
|
-
operatorDid,
|
|
138
|
-
record,
|
|
139
|
-
matchedCapabilities: (input.requiredCapabilities || []).filter((capability) => record.serviceTypes.some((value) => equalsIgnoreCase(value, capability))),
|
|
140
|
-
discoveryUrl,
|
|
141
|
-
catalogUrl,
|
|
142
|
-
}))
|
|
143
|
-
.sort((left, right) => left.operatorDid.localeCompare(right.operatorDid));
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Resolves published providers by fetching and filtering eligible host public
|
|
147
|
-
* discovery catalogs.
|
|
148
|
-
*/
|
|
149
|
-
async resolvePublishedProviders(input) {
|
|
150
|
-
const eligibleHosts = await this.resolveHostingOperators({
|
|
151
|
-
sector: input.sector,
|
|
152
|
-
jurisdiction: input.jurisdiction,
|
|
153
|
-
coverageScope: input.coverageScope,
|
|
154
|
-
requiredCapabilities: [input.providerCapability],
|
|
155
|
-
});
|
|
156
|
-
const catalogs = await Promise.all(eligibleHosts.map(async (host) => ({
|
|
157
|
-
host,
|
|
158
|
-
catalog: await this.fetchCatalog(host.discoveryUrl, host.catalogUrl),
|
|
159
|
-
})));
|
|
160
|
-
return catalogs.flatMap(({ host, catalog }) => {
|
|
161
|
-
if (!catalog)
|
|
162
|
-
return [];
|
|
163
|
-
return catalog.providers
|
|
164
|
-
.filter((record) => matchPublishedProviderRecord(record, input))
|
|
165
|
-
.map((record) => ({
|
|
166
|
-
providerDid: record.providerDid,
|
|
167
|
-
record,
|
|
168
|
-
hostingOperator: host.record,
|
|
169
|
-
hostingOperatorDid: host.operatorDid,
|
|
170
|
-
discoveryUrl: record.discoveryUrl || catalog.discoveryUrl || host.discoveryUrl,
|
|
171
|
-
catalogUrl: record.catalogUrl || catalog.catalogUrl || host.catalogUrl,
|
|
172
|
-
}));
|
|
173
|
-
}).sort((left, right) => left.providerDid.localeCompare(right.providerDid));
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Fetches a public discovery catalog for a hosting operator.
|
|
177
|
-
*
|
|
178
|
-
* Resolution order:
|
|
179
|
-
* - canonical DSP entrypoint via `discoveryUrl` (`/.well-known/dspace-version`)
|
|
180
|
-
* - direct catalog artifact compatibility via `catalogUrl`
|
|
181
|
-
*/
|
|
182
|
-
async fetchCatalog(discoveryUrl, catalogUrl) {
|
|
183
|
-
const resolvedCatalogUrl = await this.resolveCatalogArtifactUrl(discoveryUrl, catalogUrl);
|
|
184
|
-
if (!resolvedCatalogUrl)
|
|
185
|
-
return undefined;
|
|
186
|
-
const response = await this.fetcher(resolvedCatalogUrl, {
|
|
187
|
-
method: 'GET',
|
|
188
|
-
headers: {
|
|
189
|
-
accept: 'application/json',
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
if (!response.ok) {
|
|
193
|
-
return undefined;
|
|
194
|
-
}
|
|
195
|
-
const body = await response.json();
|
|
196
|
-
return toHostingOperatorCatalog(body) || undefined;
|
|
197
|
-
}
|
|
198
|
-
async resolveCatalogArtifactUrl(discoveryUrl, catalogUrl) {
|
|
199
|
-
const normalizedDiscoveryUrl = String(discoveryUrl || '').trim();
|
|
200
|
-
if (normalizedDiscoveryUrl) {
|
|
201
|
-
if (normalizedDiscoveryUrl.endsWith(DataspaceWellKnownPaths.VersionMetadata)) {
|
|
202
|
-
const metadata = await this.fetchDspaceVersionMetadata(normalizedDiscoveryUrl);
|
|
203
|
-
return deriveGwCatalogArtifactUrlFromDspaceVersion(normalizedDiscoveryUrl, metadata, DataspaceProtocolVersions.Current);
|
|
204
|
-
}
|
|
205
|
-
return normalizedDiscoveryUrl;
|
|
206
|
-
}
|
|
207
|
-
const normalizedCatalogUrl = String(catalogUrl || '').trim();
|
|
208
|
-
return normalizedCatalogUrl || undefined;
|
|
209
|
-
}
|
|
210
|
-
async fetchDspaceVersionMetadata(discoveryUrl) {
|
|
211
|
-
const response = await this.fetcher(discoveryUrl, {
|
|
212
|
-
method: 'GET',
|
|
213
|
-
headers: {
|
|
214
|
-
accept: 'application/json',
|
|
215
|
-
},
|
|
216
|
-
});
|
|
217
|
-
if (!response.ok) {
|
|
218
|
-
return undefined;
|
|
219
|
-
}
|
|
220
|
-
const body = await response.json();
|
|
221
|
-
return isDspaceVersionMetadata(body)
|
|
222
|
-
? body
|
|
223
|
-
: undefined;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
function isDspaceVersionMetadata(value) {
|
|
227
|
-
if (!isObject(value))
|
|
228
|
-
return false;
|
|
229
|
-
return Array.isArray(value.protocolVersions)
|
|
230
|
-
&& value.protocolVersions.every((entry) => isObject(entry) && asString(entry.version) && asString(entry.path));
|
|
231
|
-
}
|
|
2
|
+
export { HttpDataspaceResolver } from 'gdc-sdk-core-ts';
|
package/dist/discovery/index.js
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
-
export * from '
|
|
3
|
-
export * from './DefaultFirstDataspaceDiscovery.js';
|
|
4
|
-
export * from './HttpDataspaceResolver.js';
|
|
5
|
-
export * from './types.js';
|
|
2
|
+
export * from 'gdc-sdk-core-ts';
|
|
@@ -1,96 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Input for resolving hosting operators that can serve a given dataspace use
|
|
4
|
-
* case.
|
|
5
|
-
*/
|
|
6
|
-
export type ResolveHostingOperatorsInput = Omit<DataspaceDiscoveryFilter, 'capability'> & Readonly<{
|
|
7
|
-
requiredCapabilities: readonly string[];
|
|
8
|
-
}>;
|
|
9
|
-
/**
|
|
10
|
-
* Input for resolving publicly published providers through hosting-operator
|
|
11
|
-
* catalogs.
|
|
12
|
-
*/
|
|
13
|
-
export type ResolvePublishedProvidersInput = Omit<DataspaceDiscoveryFilter, 'capability' | 'requiredCapabilities'> & Readonly<{
|
|
14
|
-
providerCapability: string;
|
|
15
|
-
}>;
|
|
16
|
-
/**
|
|
17
|
-
* Preloaded semantic hosting-operator record used by the node runtime to
|
|
18
|
-
* resolve public discovery data without re-parsing VCs.
|
|
19
|
-
*/
|
|
20
|
-
export type PreloadedHostingOperatorRecord = Readonly<{
|
|
21
|
-
operatorDid: string;
|
|
22
|
-
/**
|
|
23
|
-
* Canonical DSP discovery entrypoint.
|
|
24
|
-
*
|
|
25
|
-
* For GW CORE this should normally be `/.well-known/dspace-version`.
|
|
26
|
-
*/
|
|
27
|
-
discoveryUrl?: string;
|
|
28
|
-
/**
|
|
29
|
-
* @deprecated Prefer `discoveryUrl`. This remains as a compatibility field
|
|
30
|
-
* for direct catalog artifact URLs.
|
|
31
|
-
*/
|
|
32
|
-
catalogUrl?: string;
|
|
33
|
-
record: HostingOperatorSemanticRecord;
|
|
34
|
-
}>;
|
|
35
|
-
/**
|
|
36
|
-
* Runtime configuration for the HTTP-capable dataspace resolver.
|
|
37
|
-
*/
|
|
38
|
-
export type HttpDataspaceResolverOptions = Readonly<{
|
|
39
|
-
hostingOperators: readonly PreloadedHostingOperatorRecord[];
|
|
40
|
-
fetcher?: typeof fetch;
|
|
41
|
-
requestHeaders?: Record<string, string>;
|
|
42
|
-
}>;
|
|
43
|
-
/**
|
|
44
|
-
* Minimal request shape for portal/backend discovery calls after defaults have
|
|
45
|
-
* already been configured at startup.
|
|
46
|
-
*/
|
|
47
|
-
export type SimpleDataspaceDiscoveryRequest = Readonly<{
|
|
48
|
-
sector: string;
|
|
49
|
-
jurisdiction: string;
|
|
50
|
-
coverageScope?: string;
|
|
51
|
-
}>;
|
|
52
|
-
/**
|
|
53
|
-
* Input for retrieving eligible hosts from the default-first discovery facade.
|
|
54
|
-
*/
|
|
55
|
-
export type GetDataspaceHostsInput = SimpleDataspaceDiscoveryRequest & Readonly<{
|
|
56
|
-
requiredCapabilities?: readonly string[];
|
|
57
|
-
}>;
|
|
58
|
-
/**
|
|
59
|
-
* Construction options for the default-first portal/backend discovery facade.
|
|
60
|
-
*
|
|
61
|
-
* This API intentionally keeps startup configuration separate from the
|
|
62
|
-
* per-request `sector + jurisdiction` queries used later by frontend-facing
|
|
63
|
-
* backends.
|
|
64
|
-
*/
|
|
65
|
-
export type DefaultFirstDataspaceDiscoveryOptions = Readonly<{
|
|
66
|
-
version?: string;
|
|
67
|
-
networkType: string;
|
|
68
|
-
defaults?: DataspaceDiscoveryDefaultsRegistry | DataspaceDiscoveryDefaultsRegistrySeed;
|
|
69
|
-
fetcher?: typeof fetch;
|
|
70
|
-
}>;
|
|
71
|
-
/**
|
|
72
|
-
* Normalized hosting-operator match returned by a node/BFF resolver.
|
|
73
|
-
*/
|
|
74
|
-
export type HostingOperatorMatch = Readonly<{
|
|
75
|
-
operatorDid: string;
|
|
76
|
-
record: HostingOperatorSemanticRecord;
|
|
77
|
-
matchedCapabilities: string[];
|
|
78
|
-
discoveryUrl?: string;
|
|
79
|
-
catalogUrl?: string;
|
|
80
|
-
}>;
|
|
81
|
-
/**
|
|
82
|
-
* Normalized published-provider match returned by a node/BFF resolver.
|
|
83
|
-
*/
|
|
84
|
-
export type PublishedProviderMatch = Readonly<{
|
|
85
|
-
providerDid: string;
|
|
86
|
-
record: PublishedProviderCatalogRecord;
|
|
87
|
-
hostingOperator: HostingOperatorSemanticRecord;
|
|
88
|
-
hostingOperatorDid: string;
|
|
89
|
-
discoveryUrl?: string;
|
|
90
|
-
catalogUrl?: string;
|
|
91
|
-
tenantSemanticRecord?: TenantServiceSemanticRecord;
|
|
92
|
-
}>;
|
|
93
|
-
/**
|
|
94
|
-
* Shared host catalog shape returned by HTTP discovery endpoints.
|
|
95
|
-
*/
|
|
96
|
-
export type HostingOperatorCatalog = HostingOperatorDiscoveryCatalog;
|
|
1
|
+
export type { DefaultFirstDataspaceDiscoveryOptions, GetDataspaceHostsInput, HostingOperatorCatalog, HostingOperatorMatch, HttpDataspaceResolverOptions, PreloadedHostingOperatorRecord, PublishedProviderMatch, ResolveHostingOperatorsInput, ResolvePublishedProvidersInput, SimpleDataspaceDiscoveryRequest, } from 'gdc-sdk-core-ts';
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ export * from './resource-operations.js';
|
|
|
12
12
|
export * from './consent-claim-helpers.js';
|
|
13
13
|
export * from './session.js';
|
|
14
14
|
export * from './node-runtime-client.js';
|
|
15
|
-
export * from './discovery/index.js';
|
|
16
15
|
export * from './gdc-session-bridge.js';
|
|
17
16
|
export * from './orchestration/client-port.js';
|
|
18
17
|
export * from './orchestration/host-onboarding-sdk.js';
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,6 @@ export * from './resource-operations.js';
|
|
|
13
13
|
export * from './consent-claim-helpers.js';
|
|
14
14
|
export * from './session.js';
|
|
15
15
|
export * from './node-runtime-client.js';
|
|
16
|
-
export * from './discovery/index.js';
|
|
17
16
|
export * from './gdc-session-bridge.js';
|
|
18
17
|
export * from './orchestration/client-port.js';
|
|
19
18
|
export * from './orchestration/host-onboarding-sdk.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdc-sdk-node-ts",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Next-generation Node runtime package for the GDC SDK family",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Antifraud Services Inc.",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"test:e2e:live-gw": "npm run build && RUN_LIVE_GW_E2E=1 node --test tests/live-gw-node-runtime.e2e.test.mjs"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"gdc-common-utils-ts": "^1.
|
|
21
|
-
"gdc-sdk-core-ts": "^0.8.
|
|
20
|
+
"gdc-common-utils-ts": "^1.18.1",
|
|
21
|
+
"gdc-sdk-core-ts": "^0.8.3"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^20.14.10",
|