gdc-sdk-node-ts 0.6.2 → 0.6.4
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 +15 -10
- package/dist/discovery/DefaultFirstDataspaceDiscovery.d.ts +44 -0
- package/dist/discovery/DefaultFirstDataspaceDiscovery.js +163 -0
- package/dist/discovery/index.d.ts +1 -0
- package/dist/discovery/index.js +1 -0
- package/dist/discovery/types.d.ts +29 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -73,10 +73,13 @@ Open these tests when you want to see exact method calls and exact inputs:
|
|
|
73
73
|
- [tests/dataspace-resolver.101.test.mjs](tests/dataspace-resolver.101.test.mjs)
|
|
74
74
|
Dataspace discovery 101 with capability filtering, jurisdiction filtering,
|
|
75
75
|
reader-vs-provider semantics, and fetcher-level fallback/cache examples.
|
|
76
|
+
- [tests/default-first-dataspace-discovery.101.test.mjs](tests/default-first-dataspace-discovery.101.test.mjs)
|
|
77
|
+
Portal-style `default-first` discovery with simple `getHosts(...)`,
|
|
78
|
+
`getIndexProviders(...)`, and `getDigitalTwinProviders(...)` calls.
|
|
76
79
|
|
|
77
80
|
## Dataspace Discovery Quick Map
|
|
78
81
|
|
|
79
|
-
Use the Node
|
|
82
|
+
Use the Node discovery layer when your backend or BFF needs to:
|
|
80
83
|
|
|
81
84
|
- start from preloaded hosting-operator semantics
|
|
82
85
|
- fetch the canonical `/.well-known/dspace-version` entrypoint
|
|
@@ -86,24 +89,26 @@ Use the Node resolver when your backend or BFF needs to:
|
|
|
86
89
|
Primary references:
|
|
87
90
|
|
|
88
91
|
- [docs/DISCOVERY_101.md](./docs/DISCOVERY_101.md)
|
|
92
|
+
- [tests/default-first-dataspace-discovery.101.test.mjs](tests/default-first-dataspace-discovery.101.test.mjs)
|
|
89
93
|
- [tests/dataspace-resolver.101.test.mjs](tests/dataspace-resolver.101.test.mjs)
|
|
90
94
|
- [tests/dataspace-resolver.test.mjs](tests/dataspace-resolver.test.mjs)
|
|
91
95
|
|
|
92
96
|
Copy/paste starting point:
|
|
93
97
|
|
|
94
98
|
```ts
|
|
95
|
-
import {
|
|
96
|
-
import {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
import { createDefaultFirstDataspaceDiscovery } from 'gdc-sdk-node-ts';
|
|
100
|
+
import { DataspaceSectors } from 'gdc-common-utils-ts';
|
|
101
|
+
import { HostNetworkTypes } from 'gdc-common-utils-ts/constants/network';
|
|
102
|
+
|
|
103
|
+
const discovery = createDefaultFirstDataspaceDiscovery({
|
|
104
|
+
version: 'v1',
|
|
105
|
+
networkType: HostNetworkTypes.Test,
|
|
106
|
+
defaults,
|
|
101
107
|
});
|
|
102
108
|
|
|
103
|
-
const providers = await
|
|
104
|
-
sector:
|
|
109
|
+
const providers = await discovery.getIndexProviders({
|
|
110
|
+
sector: DataspaceSectors.AnimalCare,
|
|
105
111
|
jurisdiction: 'ES',
|
|
106
|
-
providerCapability: ServiceCapabilityToken.IndexProvider,
|
|
107
112
|
});
|
|
108
113
|
```
|
|
109
114
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { DefaultFirstDataspaceDiscoveryOptions, GetDataspaceHostsInput, HostingOperatorMatch, PublishedProviderMatch, SimpleDataspaceDiscoveryRequest } from './types.js';
|
|
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;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { DataspaceCoverageScope, DataspaceDiscoverySourceMode, ServiceCapabilityToken, createDataspaceDiscoveryDefaultsRegistry, DataspaceProtocolVersions, inferCoverageScopeFromCountryCode, isProviderServiceCapability, normalizeCountryCode, } from 'gdc-common-utils-ts';
|
|
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
|
+
}
|
package/dist/discovery/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DataspaceDiscoveryFilter, HostingOperatorDiscoveryCatalog, HostingOperatorSemanticRecord, PublishedProviderCatalogRecord, TenantServiceSemanticRecord } from 'gdc-common-utils-ts';
|
|
1
|
+
import type { DataspaceDiscoveryDefaultsRegistry, DataspaceDiscoveryDefaultsRegistrySeed, DataspaceDiscoveryFilter, HostingOperatorDiscoveryCatalog, HostingOperatorSemanticRecord, PublishedProviderCatalogRecord, TenantServiceSemanticRecord } from 'gdc-common-utils-ts';
|
|
2
2
|
/**
|
|
3
3
|
* Input for resolving hosting operators that can serve a given dataspace use
|
|
4
4
|
* case.
|
|
@@ -40,6 +40,34 @@ export type HttpDataspaceResolverOptions = Readonly<{
|
|
|
40
40
|
fetcher?: typeof fetch;
|
|
41
41
|
requestHeaders?: Record<string, string>;
|
|
42
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
|
+
}>;
|
|
43
71
|
/**
|
|
44
72
|
* Normalized hosting-operator match returned by a node/BFF resolver.
|
|
45
73
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdc-sdk-node-ts",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
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,7 +17,7 @@
|
|
|
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": "
|
|
20
|
+
"gdc-common-utils-ts": "file:../gdc-common-utils-ts",
|
|
21
21
|
"gdc-sdk-core-ts": "^0.6.3"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|