@cef-ebsi/ebsi-uri 0.2.0-alpha.1 → 1.0.0-alpha.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 +69 -26
- package/dist/index.d.ts +16 -37
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -56
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
- package/src/index.ts +192 -135
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# EBSI URI scheme library
|
|
4
4
|
|
|
5
|
-
This library supports the [EBSI URI Scheme](https://hub.ebsi.eu/vc-framework/ebsi-uri-scheme). It allows you to parse EBSI URIs, serialize EBSI URI components, transform EBSI URIs into URLs, and URLs into EBSI URIs.
|
|
5
|
+
This library supports the [EBSI URI Scheme](https://hub.ebsi.eu/vc-framework/guidelines/ebsi-uri-scheme). It allows you to parse EBSI URIs, serialize EBSI URI components, transform EBSI URIs into URLs, and URLs into EBSI URIs.
|
|
6
6
|
|
|
7
7
|
## Table of Contents
|
|
8
8
|
|
|
@@ -24,35 +24,71 @@ yarn add @cef-ebsi/ebsi-uri
|
|
|
24
24
|
|
|
25
25
|
## Usage
|
|
26
26
|
|
|
27
|
-
###
|
|
27
|
+
### Configuration
|
|
28
28
|
|
|
29
|
-
The
|
|
29
|
+
All the methods described below require a configuration object. The library exports a TypeScript interface that you can use to properly define the configuration object. Here's an example of such a configuration object:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import type { EbsiUriConfiguration } from "@cef-ebsi/ebsi-uri";
|
|
33
|
+
|
|
34
|
+
const config = {
|
|
35
|
+
// Defines the URI scheme
|
|
36
|
+
scheme: "ebsi",
|
|
37
|
+
|
|
38
|
+
// Defines the network config
|
|
39
|
+
network: {
|
|
40
|
+
// Network component, as it appears in the URI
|
|
41
|
+
name: "pilot",
|
|
42
|
+
|
|
43
|
+
// Whether the network component is optional or not
|
|
44
|
+
isOptional: false,
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// The list of the supported services (with their version number)
|
|
48
|
+
services: {
|
|
49
|
+
"did-registry": "v5",
|
|
50
|
+
"trusted-issuers-registry": "v5",
|
|
51
|
+
"trusted-policies-registry": "v3",
|
|
52
|
+
"trusted-schemas-registry": "v3",
|
|
53
|
+
},
|
|
54
|
+
} as const satisfies EbsiUriConfiguration;
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Parse EBSI URI
|
|
58
|
+
|
|
59
|
+
The `parse` function takes an EBSI URI (string) and returns the URI components `scheme`, `network`, `service`, and `resource`.
|
|
60
|
+
It requires an `EbsiUriConfiguration` object as second parameter.
|
|
30
61
|
|
|
31
62
|
Example:
|
|
32
63
|
|
|
33
64
|
```js
|
|
34
|
-
parse(
|
|
65
|
+
parse(
|
|
66
|
+
"ebsi:test:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
67
|
+
config,
|
|
68
|
+
);
|
|
35
69
|
```
|
|
36
70
|
|
|
37
71
|
returns
|
|
38
72
|
|
|
39
73
|
```json
|
|
40
74
|
{
|
|
41
|
-
"network": "
|
|
42
|
-
"
|
|
43
|
-
"
|
|
75
|
+
"network": "pilot",
|
|
76
|
+
"resource": "/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
77
|
+
"scheme": "ebsi",
|
|
78
|
+
"service": "did-registry"
|
|
44
79
|
}
|
|
45
80
|
```
|
|
46
81
|
|
|
47
82
|
### Parse URL
|
|
48
83
|
|
|
49
|
-
The `parseUrl` function takes
|
|
84
|
+
The `parseUrl` function takes a URL (string) and returns the URI components `scheme`, `network`, `service`, and `resource`. It requires an `EbsiUriConfiguration` object as second parameter.
|
|
50
85
|
|
|
51
86
|
Example:
|
|
52
87
|
|
|
53
88
|
```js
|
|
54
89
|
parseUrl(
|
|
55
|
-
"https://api-
|
|
90
|
+
"https://api-pilot.ebsi.eu/did-registry/v5/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
91
|
+
config,
|
|
56
92
|
);
|
|
57
93
|
```
|
|
58
94
|
|
|
@@ -60,52 +96,59 @@ returns
|
|
|
60
96
|
|
|
61
97
|
```json
|
|
62
98
|
{
|
|
63
|
-
"network": "
|
|
64
|
-
"
|
|
65
|
-
"
|
|
99
|
+
"network": "pilot",
|
|
100
|
+
"resource": "/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
101
|
+
"scheme": "ebsi",
|
|
102
|
+
"service": "did-registry"
|
|
66
103
|
}
|
|
67
104
|
```
|
|
68
105
|
|
|
69
106
|
### Serialize
|
|
70
107
|
|
|
71
|
-
The `serialize` function takes an object containing the URI components `network`, `service`, and `resource`. It returns a string representation of the EBSI URI.
|
|
108
|
+
The `serialize` function takes an object containing the URI components `scheme`, `network`, `service`, and `resource`. It requires an `EbsiUriConfiguration` object as second parameter. It returns a string representation of the EBSI URI.
|
|
72
109
|
|
|
73
110
|
Example:
|
|
74
111
|
|
|
75
112
|
```js
|
|
76
|
-
serialize(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
113
|
+
serialize(
|
|
114
|
+
{
|
|
115
|
+
network: "pilot",
|
|
116
|
+
resource: "/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
117
|
+
scheme: "ebsi",
|
|
118
|
+
service: "did-registry",
|
|
119
|
+
},
|
|
120
|
+
config,
|
|
121
|
+
);
|
|
81
122
|
```
|
|
82
123
|
|
|
83
124
|
returns `ebsi:test:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
|
|
84
125
|
|
|
85
126
|
### Transform EBSI URIs into URLs
|
|
86
127
|
|
|
87
|
-
The `toUrl` function takes an EBSI URI (string) and returns a URL string.
|
|
128
|
+
The `toUrl` function takes an EBSI URI (string) and returns a URL string. You also have to pass the host to use as second parameter, and pass an `EbsiUriConfiguration` object as last parameter.
|
|
88
129
|
|
|
89
130
|
Example:
|
|
90
131
|
|
|
91
132
|
```js
|
|
92
|
-
toUrl(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
133
|
+
toUrl(
|
|
134
|
+
"ebsi:test:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
135
|
+
"api-pilot.ebsi.eu",
|
|
136
|
+
config,
|
|
137
|
+
);
|
|
96
138
|
```
|
|
97
139
|
|
|
98
|
-
returns `https://api-
|
|
140
|
+
returns `https://api-pilot.ebsi.eu/did-registry/v5/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
|
|
99
141
|
|
|
100
142
|
### Transform URLs into EBSI URIs
|
|
101
143
|
|
|
102
|
-
The `fromUrl` function takes
|
|
144
|
+
The `fromUrl` function takes a URL (string) and returns an EBSI URI string. It requires an `EbsiUriConfiguration` object as second parameter. It returns a string representation of the EBSI URI.
|
|
103
145
|
|
|
104
146
|
Example:
|
|
105
147
|
|
|
106
148
|
```js
|
|
107
149
|
fromUrl(
|
|
108
|
-
"https://api-
|
|
150
|
+
"https://api-pilot.ebsi.eu/did-registry/v5/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
151
|
+
config,
|
|
109
152
|
);
|
|
110
153
|
```
|
|
111
154
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,43 +1,22 @@
|
|
|
1
|
-
export
|
|
2
|
-
export declare const PRODUCTION_NETWORK = "production";
|
|
3
|
-
export declare const NETWORKS: readonly ["production", "preprod", "conformance", "pilot", "test"];
|
|
4
|
-
export declare const NETWORKS_PATTERNS: {
|
|
5
|
-
readonly conformance: RegExp;
|
|
6
|
-
readonly pilot: RegExp;
|
|
7
|
-
readonly preprod: RegExp;
|
|
8
|
-
readonly production: RegExp;
|
|
9
|
-
readonly test: RegExp;
|
|
10
|
-
};
|
|
11
|
-
export interface EBSIURIComponents<T extends string = string> {
|
|
1
|
+
export interface EbsiUriComponents<Scheme extends string = string, Network extends string = string, Service extends string = string> {
|
|
12
2
|
network: Network;
|
|
13
3
|
resource: string;
|
|
14
|
-
|
|
4
|
+
scheme: Scheme;
|
|
5
|
+
service: Service;
|
|
15
6
|
}
|
|
16
|
-
export interface
|
|
17
|
-
|
|
7
|
+
export interface EbsiUriConfiguration<Scheme extends string = string, Network extends string = string, Service extends string = string> {
|
|
8
|
+
network: {
|
|
9
|
+
isOptional?: boolean;
|
|
10
|
+
name: Network;
|
|
11
|
+
};
|
|
12
|
+
scheme: Scheme;
|
|
13
|
+
services?: SupportedServices<Service>;
|
|
18
14
|
}
|
|
19
|
-
export interface IParseUrlOptions<T extends string = string> {
|
|
20
|
-
readonly services?: SupportedServices<T>;
|
|
21
|
-
}
|
|
22
|
-
export interface IToUrlOptions<T extends string = string> {
|
|
23
|
-
readonly hosts: Partial<Record<Network, string>>;
|
|
24
|
-
readonly services: SupportedServices<T>;
|
|
25
|
-
}
|
|
26
|
-
export type Network = (typeof NETWORKS)[number];
|
|
27
|
-
export type ServiceName<T extends string = string> = T;
|
|
28
15
|
export type ServiceVersion = `v${number}`;
|
|
29
|
-
export type SupportedServices<
|
|
30
|
-
export declare function fromUrl<
|
|
31
|
-
export declare function parse(uriString: string):
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
};
|
|
36
|
-
export declare function parseUrl<T extends string>(url: string, options?: IParseUrlOptions<T>): {
|
|
37
|
-
network: "production" | "preprod" | "conformance" | "pilot" | "test";
|
|
38
|
-
resource: string;
|
|
39
|
-
service: T;
|
|
40
|
-
};
|
|
41
|
-
export declare function serialize<T extends string>(components: EBSIURIComponents<T>): string;
|
|
42
|
-
export declare function toUrl<T extends string>(uriString: string, options: IToUrlOptions<T>): string;
|
|
16
|
+
export type SupportedServices<Service extends string> = Record<Service, ServiceVersion>;
|
|
17
|
+
export declare function fromUrl<Scheme extends string, Network extends string, Service extends string>(url: string, config: EbsiUriConfiguration<Scheme, Network, Service>): `${Scheme}:${string}`;
|
|
18
|
+
export declare function parse<Scheme extends string, Network extends string, Service extends string>(uriString: string, config: EbsiUriConfiguration<Scheme, Network, Service>): EbsiUriComponents<Scheme, Network, Service>;
|
|
19
|
+
export declare function parseUrl<Scheme extends string, Network extends string, Service extends string>(url: string, config: EbsiUriConfiguration<Scheme, Network, Service>): EbsiUriComponents<Scheme, Network, Service>;
|
|
20
|
+
export declare function serialize<Scheme extends string, Network extends string, Service extends string>(components: EbsiUriComponents<Scheme, Network, Service>, config: EbsiUriConfiguration<Scheme, Network, Service>): `${Scheme}:${string}`;
|
|
21
|
+
export declare function toUrl<Scheme extends string, Network extends string, Service extends string>(uriString: string, host: string, config: EbsiUriConfiguration<Scheme, Network, Service>): string;
|
|
43
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB,CAChC,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,OAAO,SAAS,MAAM,GAAG,MAAM,EAC/B,OAAO,SAAS,MAAM,GAAG,MAAM;IAE/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAKD,MAAM,WAAW,oBAAoB,CACnC,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,OAAO,SAAS,MAAM,GAAG,MAAM,EAC/B,OAAO,SAAS,MAAM,GAAG,MAAM;IAK/B,OAAO,EAAE;QAKP,UAAU,CAAC,EAAE,OAAO,CAAC;QAKrB,IAAI,EAAE,OAAO,CAAC;KACf,CAAC;IAMF,MAAM,EAAE,MAAM,CAAC;IAKf,QAAQ,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,cAAc,GAAG,IAAI,MAAM,EAAE,CAAC;AAE1C,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,MAAM,IAAI,MAAM,CAC5D,OAAO,EACP,cAAc,CACf,CAAC;AAmBF,wBAAgB,OAAO,CACrB,MAAM,SAAS,MAAM,EACrB,OAAO,SAAS,MAAM,EACtB,OAAO,SAAS,MAAM,EACtB,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,yBAIpE;AA8BD,wBAAgB,KAAK,CACnB,MAAM,SAAS,MAAM,EACrB,OAAO,SAAS,MAAM,EACtB,OAAO,SAAS,MAAM,EAEtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,GACrD,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CA2C7C;AA8BD,wBAAgB,QAAQ,CACtB,MAAM,SAAS,MAAM,EACrB,OAAO,SAAS,MAAM,EACtB,OAAO,SAAS,MAAM,EAEtB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,GACrD,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAqD7C;AAwBD,wBAAgB,SAAS,CACvB,MAAM,SAAS,MAAM,EACrB,OAAO,SAAS,MAAM,EACtB,OAAO,SAAS,MAAM,EAEtB,UAAU,EAAE,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EACvD,MAAM,EAAE,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,GACrD,GAAG,MAAM,IAAI,MAAM,EAAE,CAKvB;AAwBD,wBAAgB,KAAK,CACnB,MAAM,SAAS,MAAM,EACrB,OAAO,SAAS,MAAM,EACtB,OAAO,SAAS,MAAM,EAEtB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,GACrD,MAAM,CAcR"}
|
package/dist/index.js
CHANGED
|
@@ -1,46 +1,38 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
PRODUCTION_NETWORK,
|
|
5
|
-
"preprod",
|
|
6
|
-
"conformance",
|
|
7
|
-
"pilot",
|
|
8
|
-
"test",
|
|
9
|
-
];
|
|
10
|
-
export const NETWORKS_PATTERNS = {
|
|
11
|
-
conformance: /^api-conformance\.ebsi\.eu$/,
|
|
12
|
-
pilot: /^api-pilot\.ebsi\./,
|
|
13
|
-
preprod: /^api-preprod\.ebsi\./,
|
|
14
|
-
production: /^api\.ebsi\./,
|
|
15
|
-
test: /^api-test\.ebsi\.eu$/,
|
|
16
|
-
};
|
|
17
|
-
export function fromUrl(url, options) {
|
|
18
|
-
const components = parseUrl(url, options);
|
|
19
|
-
return serialize(components);
|
|
1
|
+
export function fromUrl(url, config) {
|
|
2
|
+
const components = parseUrl(url, config);
|
|
3
|
+
return serialize(components, config);
|
|
20
4
|
}
|
|
21
|
-
export function parse(uriString) {
|
|
5
|
+
export function parse(uriString, config) {
|
|
22
6
|
const [scheme, firstComponent, secondComponent, ...rest] = uriString.split(":");
|
|
23
|
-
if (scheme !==
|
|
24
|
-
throw new Error(`Invalid URI: scheme must be '${
|
|
7
|
+
if (scheme !== config.scheme) {
|
|
8
|
+
throw new Error(`Invalid URI: scheme must be '${config.scheme}'`);
|
|
25
9
|
}
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
:
|
|
29
|
-
|
|
10
|
+
const uriContainsNetwork = firstComponent === config.network.name;
|
|
11
|
+
if (!config.network.isOptional && !uriContainsNetwork) {
|
|
12
|
+
throw new Error(`Invalid URI: network must be '${config.network.name}'`);
|
|
13
|
+
}
|
|
14
|
+
const service = uriContainsNetwork ? secondComponent : firstComponent;
|
|
30
15
|
if (!service || service.startsWith("/")) {
|
|
31
16
|
throw new Error(`No service found in EBSI URI '${uriString}'`);
|
|
32
17
|
}
|
|
33
|
-
|
|
18
|
+
if (config.services) {
|
|
19
|
+
const { services } = config;
|
|
20
|
+
if (!isSupportedService(service, services)) {
|
|
21
|
+
throw new Error(`Unsupported service '${service}'`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const resource = (uriContainsNetwork ? rest : [secondComponent, ...rest]).join(":");
|
|
34
25
|
if (!resource) {
|
|
35
26
|
throw new Error(`No resource found in EBSI URI '${uriString}'`);
|
|
36
27
|
}
|
|
37
28
|
return {
|
|
38
|
-
network,
|
|
29
|
+
network: config.network.name,
|
|
39
30
|
resource,
|
|
40
|
-
|
|
31
|
+
scheme: config.scheme,
|
|
32
|
+
service: service,
|
|
41
33
|
};
|
|
42
34
|
}
|
|
43
|
-
export function parseUrl(url,
|
|
35
|
+
export function parseUrl(url, config) {
|
|
44
36
|
let urlObject;
|
|
45
37
|
try {
|
|
46
38
|
urlObject = new URL(url);
|
|
@@ -48,11 +40,7 @@ export function parseUrl(url, options) {
|
|
|
48
40
|
catch {
|
|
49
41
|
throw new Error("Invalid URL");
|
|
50
42
|
}
|
|
51
|
-
const { hash,
|
|
52
|
-
const network = NETWORKS.find((n) => NETWORKS_PATTERNS[n].test(host));
|
|
53
|
-
if (!network) {
|
|
54
|
-
throw new Error(`Host ${host} doesn't match any EBSI network`);
|
|
55
|
-
}
|
|
43
|
+
const { hash, pathname, search } = urlObject;
|
|
56
44
|
const [service, serviceVersion, ...rest] = pathname
|
|
57
45
|
.split("/")
|
|
58
46
|
.filter(Boolean);
|
|
@@ -65,8 +53,8 @@ export function parseUrl(url, options) {
|
|
|
65
53
|
if (!isServiceVersion(serviceVersion)) {
|
|
66
54
|
throw new Error(`'${serviceVersion}' is not a valid service version`);
|
|
67
55
|
}
|
|
68
|
-
if (
|
|
69
|
-
const services =
|
|
56
|
+
if (config.services) {
|
|
57
|
+
const { services } = config;
|
|
70
58
|
if (!isSupportedService(service, services)) {
|
|
71
59
|
throw new Error(`Unsupported service '${service}'`);
|
|
72
60
|
}
|
|
@@ -77,36 +65,29 @@ export function parseUrl(url, options) {
|
|
|
77
65
|
}
|
|
78
66
|
const resource = `/${rest.join("/")}${search}${hash}`;
|
|
79
67
|
return {
|
|
80
|
-
network,
|
|
68
|
+
network: config.network.name,
|
|
81
69
|
resource,
|
|
70
|
+
scheme: config.scheme,
|
|
82
71
|
service: service,
|
|
83
72
|
};
|
|
84
73
|
}
|
|
85
|
-
export function serialize(components) {
|
|
86
|
-
const { network, resource, service } = components;
|
|
87
|
-
|
|
88
|
-
return `${SCHEME}:${networkName}${service}:${resource}`;
|
|
74
|
+
export function serialize(components, config) {
|
|
75
|
+
const { network, resource, scheme, service } = components;
|
|
76
|
+
return `${scheme}:${config.network.isOptional === true ? "" : `${network}:`}${service}:${resource}`;
|
|
89
77
|
}
|
|
90
|
-
export function toUrl(uriString,
|
|
91
|
-
const {
|
|
92
|
-
const
|
|
93
|
-
if (!
|
|
94
|
-
throw new Error(
|
|
95
|
-
}
|
|
96
|
-
const services = options.services;
|
|
97
|
-
if (!isSupportedService(service, services)) {
|
|
98
|
-
throw new Error(`Unsupported service '${service}'`);
|
|
78
|
+
export function toUrl(uriString, host, config) {
|
|
79
|
+
const { resource, service } = parse(uriString, config);
|
|
80
|
+
const { services } = config;
|
|
81
|
+
if (!services) {
|
|
82
|
+
throw new Error("No services defined");
|
|
99
83
|
}
|
|
100
84
|
const serviceVersion = services[service];
|
|
101
85
|
return `https://${host}/${service}/${serviceVersion}${resource}`;
|
|
102
86
|
}
|
|
103
|
-
function isNetwork(network) {
|
|
104
|
-
return network !== undefined && NETWORKS.includes(network);
|
|
105
|
-
}
|
|
106
87
|
function isServiceVersion(serviceVersion) {
|
|
107
88
|
return typeof serviceVersion === "string" && /v\d*/.test(serviceVersion);
|
|
108
89
|
}
|
|
109
|
-
function isSupportedService(service,
|
|
110
|
-
return service !== undefined && service in
|
|
90
|
+
function isSupportedService(service, services) {
|
|
91
|
+
return (service !== undefined && typeof service === "string" && service in services);
|
|
111
92
|
}
|
|
112
93
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cef-ebsi/ebsi-uri",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-alpha.0",
|
|
4
4
|
"description": "EBSI URIs parser and serializer",
|
|
5
5
|
"license": "EUPL-1.2",
|
|
6
6
|
"publishConfig": {
|
|
@@ -29,6 +29,5 @@
|
|
|
29
29
|
"test:unit": "yarn test unit",
|
|
30
30
|
"test:e2e": "echo \"Info: there's no e2e tests for @cef-ebsi/ebsi-uri\" && exit 0",
|
|
31
31
|
"test:ci": "yarn test:unit --coverage --reporter=default"
|
|
32
|
-
}
|
|
33
|
-
"gitHead": "7ab44e5adb2e695fad489377f888b3e6edd7dfd8"
|
|
32
|
+
}
|
|
34
33
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,72 +1,61 @@
|
|
|
1
|
-
export const SCHEME = "ebsi";
|
|
2
|
-
|
|
3
|
-
export const PRODUCTION_NETWORK = "production";
|
|
4
|
-
|
|
5
|
-
export const NETWORKS = [
|
|
6
|
-
PRODUCTION_NETWORK,
|
|
7
|
-
"preprod",
|
|
8
|
-
"conformance",
|
|
9
|
-
"pilot",
|
|
10
|
-
"test",
|
|
11
|
-
] as const;
|
|
12
|
-
|
|
13
|
-
export const NETWORKS_PATTERNS = {
|
|
14
|
-
conformance: /^api-conformance\.ebsi\.eu$/,
|
|
15
|
-
pilot: /^api-pilot\.ebsi\./,
|
|
16
|
-
preprod: /^api-preprod\.ebsi\./,
|
|
17
|
-
production: /^api\.ebsi\./,
|
|
18
|
-
test: /^api-test\.ebsi\.eu$/,
|
|
19
|
-
} as const satisfies Record<Network, RegExp>;
|
|
20
|
-
|
|
21
1
|
/**
|
|
22
2
|
* Components of an EBSI URI:
|
|
3
|
+
* - a scheme, e.g. "ebsi"
|
|
23
4
|
* - a network, e.g. "pilot"
|
|
24
5
|
* - a service, e.g. "trusted-issuers-registry"
|
|
25
6
|
* - a resource path, e.g. "/issuers/did:ebsi:zZeKyEJfUTGwajhNyNX928z?x=y&z=w#abc
|
|
26
7
|
*/
|
|
27
|
-
export interface
|
|
8
|
+
export interface EbsiUriComponents<
|
|
9
|
+
Scheme extends string = string,
|
|
10
|
+
Network extends string = string,
|
|
11
|
+
Service extends string = string,
|
|
12
|
+
> {
|
|
28
13
|
network: Network;
|
|
29
14
|
resource: string;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
/** Options for the `fromUrl()` function */
|
|
34
|
-
export interface IFromUrlOptions<T extends string = string> {
|
|
35
|
-
/**
|
|
36
|
-
* Map of supported services and their versions
|
|
37
|
-
*/
|
|
38
|
-
readonly services?: SupportedServices<T>;
|
|
15
|
+
scheme: Scheme;
|
|
16
|
+
service: Service;
|
|
39
17
|
}
|
|
40
18
|
|
|
41
|
-
/**
|
|
42
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Configuration for an EBSI URI.
|
|
21
|
+
*/
|
|
22
|
+
export interface EbsiUriConfiguration<
|
|
23
|
+
Scheme extends string = string,
|
|
24
|
+
Network extends string = string,
|
|
25
|
+
Service extends string = string,
|
|
26
|
+
> {
|
|
43
27
|
/**
|
|
44
|
-
*
|
|
28
|
+
* Properties of the current EBSI network.
|
|
45
29
|
*/
|
|
46
|
-
|
|
47
|
-
|
|
30
|
+
network: {
|
|
31
|
+
/**
|
|
32
|
+
* Whether the network segment is optional in the EBSI URI.
|
|
33
|
+
* The network segment is considered mandatory unless this is set to `true`.
|
|
34
|
+
*/
|
|
35
|
+
isOptional?: boolean;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The name of the EBSI network, as it appears in the EBSI URI.
|
|
39
|
+
*/
|
|
40
|
+
name: Network;
|
|
41
|
+
};
|
|
48
42
|
|
|
49
|
-
/** Options for the `toUrl()` function */
|
|
50
|
-
export interface IToUrlOptions<T extends string = string> {
|
|
51
43
|
/**
|
|
52
|
-
*
|
|
44
|
+
* The URI scheme of the EBSI URI.
|
|
45
|
+
* @example "ebsi"
|
|
53
46
|
*/
|
|
54
|
-
|
|
47
|
+
scheme: Scheme;
|
|
55
48
|
|
|
56
49
|
/**
|
|
57
|
-
* Map of supported services and their versions
|
|
50
|
+
* Map of the supported services and their versions.
|
|
58
51
|
*/
|
|
59
|
-
|
|
52
|
+
services?: SupportedServices<Service>;
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
export type Network = (typeof NETWORKS)[number];
|
|
63
|
-
|
|
64
|
-
export type ServiceName<T extends string = string> = T;
|
|
65
|
-
|
|
66
55
|
export type ServiceVersion = `v${number}`;
|
|
67
56
|
|
|
68
|
-
export type SupportedServices<
|
|
69
|
-
|
|
57
|
+
export type SupportedServices<Service extends string> = Record<
|
|
58
|
+
Service,
|
|
70
59
|
ServiceVersion
|
|
71
60
|
>;
|
|
72
61
|
|
|
@@ -74,59 +63,94 @@ export type SupportedServices<T extends string> = Record<
|
|
|
74
63
|
* Transform a URL into an EBSI URI.
|
|
75
64
|
* @example
|
|
76
65
|
* ```js
|
|
77
|
-
* fromUrl(
|
|
66
|
+
* fromUrl(
|
|
67
|
+
* "https://api-pilot.ebsi.eu/did-registry/v5/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
68
|
+
* {
|
|
69
|
+
* network: { name: "pilot" },
|
|
70
|
+
* scheme: "ebsi",
|
|
71
|
+
* },
|
|
72
|
+
* )
|
|
78
73
|
* ```
|
|
79
|
-
* returns `ebsi:
|
|
74
|
+
* returns `ebsi:pilot:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
|
|
80
75
|
* @param url - URL to transform
|
|
81
|
-
* @param
|
|
76
|
+
* @param config - EBSI URI configuration
|
|
82
77
|
* @returns EBSI URI
|
|
83
78
|
*/
|
|
84
|
-
export function fromUrl<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
79
|
+
export function fromUrl<
|
|
80
|
+
Scheme extends string,
|
|
81
|
+
Network extends string,
|
|
82
|
+
Service extends string,
|
|
83
|
+
>(url: string, config: EbsiUriConfiguration<Scheme, Network, Service>) {
|
|
84
|
+
const components = parseUrl(url, config);
|
|
85
|
+
|
|
86
|
+
return serialize(components, config);
|
|
91
87
|
}
|
|
92
88
|
|
|
93
89
|
/**
|
|
94
90
|
* Parse an EBSI URI.
|
|
95
91
|
* @example
|
|
96
92
|
* ```js
|
|
97
|
-
* parse(
|
|
93
|
+
* parse(
|
|
94
|
+
* "ebsi:pilot:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
95
|
+
* {
|
|
96
|
+
* network: { name: "pilot" },
|
|
97
|
+
* scheme: "ebsi",
|
|
98
|
+
* services: {
|
|
99
|
+
* "did-registry": "v5",
|
|
100
|
+
* },
|
|
101
|
+
* },
|
|
102
|
+
* )
|
|
98
103
|
* ```
|
|
99
104
|
* returns
|
|
100
105
|
* ```json
|
|
101
106
|
* {
|
|
102
|
-
* "network": "
|
|
103
|
-
* "
|
|
104
|
-
* "
|
|
107
|
+
* "network": "pilot",
|
|
108
|
+
* "resource": "/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
109
|
+
* "scheme": "ebsi",
|
|
110
|
+
* "service": "did-registry"
|
|
105
111
|
* }
|
|
106
112
|
* ```
|
|
107
|
-
* @param uriString - EBSI URI to parse, e.g. "ebsi:
|
|
113
|
+
* @param uriString - EBSI URI to parse, e.g. "ebsi:pilot:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw"
|
|
114
|
+
* @param config - EBSI URI configuration
|
|
108
115
|
* @returns EBSI URI components
|
|
109
116
|
*/
|
|
110
|
-
export function parse
|
|
117
|
+
export function parse<
|
|
118
|
+
Scheme extends string,
|
|
119
|
+
Network extends string,
|
|
120
|
+
Service extends string,
|
|
121
|
+
>(
|
|
122
|
+
uriString: string,
|
|
123
|
+
config: EbsiUriConfiguration<Scheme, Network, Service>,
|
|
124
|
+
): EbsiUriComponents<Scheme, Network, Service> {
|
|
111
125
|
const [scheme, firstComponent, secondComponent, ...rest] =
|
|
112
126
|
uriString.split(":");
|
|
113
127
|
|
|
114
|
-
if (scheme !==
|
|
115
|
-
throw new Error(`Invalid URI: scheme must be '${
|
|
128
|
+
if (scheme !== config.scheme) {
|
|
129
|
+
throw new Error(`Invalid URI: scheme must be '${config.scheme}'`);
|
|
116
130
|
}
|
|
117
131
|
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
:
|
|
132
|
+
const uriContainsNetwork = firstComponent === config.network.name;
|
|
133
|
+
if (!config.network.isOptional && !uriContainsNetwork) {
|
|
134
|
+
throw new Error(`Invalid URI: network must be '${config.network.name}'`);
|
|
135
|
+
}
|
|
121
136
|
|
|
122
|
-
const service =
|
|
137
|
+
const service = uriContainsNetwork ? secondComponent : firstComponent;
|
|
123
138
|
|
|
124
139
|
if (!service || service.startsWith("/")) {
|
|
125
140
|
throw new Error(`No service found in EBSI URI '${uriString}'`);
|
|
126
141
|
}
|
|
127
142
|
|
|
143
|
+
// Check if the service and its version are supported
|
|
144
|
+
if (config.services) {
|
|
145
|
+
const { services } = config;
|
|
146
|
+
|
|
147
|
+
if (!isSupportedService(service, services)) {
|
|
148
|
+
throw new Error(`Unsupported service '${service}'`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
128
152
|
const resource = (
|
|
129
|
-
|
|
153
|
+
uriContainsNetwork ? rest : [secondComponent, ...rest]
|
|
130
154
|
).join(":");
|
|
131
155
|
|
|
132
156
|
if (!resource) {
|
|
@@ -135,22 +159,49 @@ export function parse(uriString: string) {
|
|
|
135
159
|
|
|
136
160
|
// Return EBSI URI components
|
|
137
161
|
return {
|
|
138
|
-
network,
|
|
162
|
+
network: config.network.name,
|
|
139
163
|
resource,
|
|
140
|
-
|
|
141
|
-
|
|
164
|
+
scheme: config.scheme,
|
|
165
|
+
service: service as Service,
|
|
166
|
+
};
|
|
142
167
|
}
|
|
143
168
|
|
|
144
169
|
/**
|
|
145
170
|
* Extract EBSI URI components from URL.
|
|
171
|
+
* @example
|
|
172
|
+
* ```js
|
|
173
|
+
* parseUrl(
|
|
174
|
+
* "https://api-pilot.ebsi.eu/did-registry/v5/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
175
|
+
* {
|
|
176
|
+
* network: { name: "pilot" },
|
|
177
|
+
* scheme: "ebsi",
|
|
178
|
+
* services: {
|
|
179
|
+
* "did-registry": "v5",
|
|
180
|
+
* },
|
|
181
|
+
* },
|
|
182
|
+
* )
|
|
183
|
+
* ```
|
|
184
|
+
* returns
|
|
185
|
+
* ```json
|
|
186
|
+
* {
|
|
187
|
+
* "network": "pilot",
|
|
188
|
+
* "resource": "/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
189
|
+
* "scheme": "ebsi",
|
|
190
|
+
* "service": "did-registry"
|
|
191
|
+
* }
|
|
192
|
+
* ```
|
|
146
193
|
* @param url - The URL to parse.
|
|
147
|
-
* @param
|
|
194
|
+
* @param config - EBSI URI configuration
|
|
148
195
|
* @returns EBSI URI components
|
|
149
196
|
*/
|
|
150
|
-
export function parseUrl<
|
|
197
|
+
export function parseUrl<
|
|
198
|
+
Scheme extends string,
|
|
199
|
+
Network extends string,
|
|
200
|
+
Service extends string,
|
|
201
|
+
>(
|
|
151
202
|
url: string,
|
|
152
|
-
|
|
153
|
-
) {
|
|
203
|
+
config: EbsiUriConfiguration<Scheme, Network, Service>,
|
|
204
|
+
): EbsiUriComponents<Scheme, Network, Service> {
|
|
154
205
|
// Parse URL
|
|
155
206
|
let urlObject: URL;
|
|
156
207
|
try {
|
|
@@ -159,14 +210,7 @@ export function parseUrl<T extends string>(
|
|
|
159
210
|
throw new Error("Invalid URL");
|
|
160
211
|
}
|
|
161
212
|
|
|
162
|
-
const { hash,
|
|
163
|
-
|
|
164
|
-
// Identify network
|
|
165
|
-
const network = NETWORKS.find((n) => NETWORKS_PATTERNS[n].test(host));
|
|
166
|
-
|
|
167
|
-
if (!network) {
|
|
168
|
-
throw new Error(`Host ${host} doesn't match any EBSI network`);
|
|
169
|
-
}
|
|
213
|
+
const { hash, pathname, search } = urlObject;
|
|
170
214
|
|
|
171
215
|
// Extract service and resource from pathname: /<service>/<serviceVersion>/<resource>
|
|
172
216
|
const [service, serviceVersion, ...rest] = pathname
|
|
@@ -186,8 +230,8 @@ export function parseUrl<T extends string>(
|
|
|
186
230
|
}
|
|
187
231
|
|
|
188
232
|
// Check if the service and its version are supported
|
|
189
|
-
if (
|
|
190
|
-
const services =
|
|
233
|
+
if (config.services) {
|
|
234
|
+
const { services } = config;
|
|
191
235
|
|
|
192
236
|
if (!isSupportedService(service, services)) {
|
|
193
237
|
throw new Error(`Unsupported service '${service}'`);
|
|
@@ -205,10 +249,11 @@ export function parseUrl<T extends string>(
|
|
|
205
249
|
const resource = `/${rest.join("/")}${search}${hash}`;
|
|
206
250
|
|
|
207
251
|
return {
|
|
208
|
-
network,
|
|
252
|
+
network: config.network.name,
|
|
209
253
|
resource,
|
|
210
|
-
|
|
211
|
-
|
|
254
|
+
scheme: config.scheme,
|
|
255
|
+
service: service as Service,
|
|
256
|
+
};
|
|
212
257
|
}
|
|
213
258
|
|
|
214
259
|
/**
|
|
@@ -216,55 +261,74 @@ export function parseUrl<T extends string>(
|
|
|
216
261
|
* @example
|
|
217
262
|
* ```js
|
|
218
263
|
* serialize({
|
|
219
|
-
* "
|
|
264
|
+
* "scheme": "ebsi",
|
|
265
|
+
* "network": "pilot",
|
|
220
266
|
* "service": "did-registry",
|
|
221
267
|
* "resource": "/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw"
|
|
268
|
+
* }, {
|
|
269
|
+
* network: { name: "pilot" },
|
|
270
|
+
* scheme: "ebsi",
|
|
271
|
+
* services: {
|
|
272
|
+
* "did-registry": "v5",
|
|
273
|
+
* },
|
|
222
274
|
* })
|
|
223
275
|
* ```
|
|
224
|
-
* returns `ebsi:
|
|
276
|
+
* returns `ebsi:pilot:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
|
|
225
277
|
* @param components - EBSI URI components
|
|
278
|
+
* @param config - EBSI URI configuration
|
|
226
279
|
* @returns EBSI URI
|
|
227
280
|
*/
|
|
228
|
-
export function serialize<
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
281
|
+
export function serialize<
|
|
282
|
+
Scheme extends string,
|
|
283
|
+
Network extends string,
|
|
284
|
+
Service extends string,
|
|
285
|
+
>(
|
|
286
|
+
components: EbsiUriComponents<Scheme, Network, Service>,
|
|
287
|
+
config: EbsiUriConfiguration<Scheme, Network, Service>,
|
|
288
|
+
): `${Scheme}:${string}` {
|
|
289
|
+
const { network, resource, scheme, service } = components;
|
|
290
|
+
|
|
291
|
+
// Return serialized EBSI URI
|
|
292
|
+
return `${scheme}:${config.network.isOptional === true ? "" : `${network}:`}${service}:${resource}`;
|
|
235
293
|
}
|
|
236
294
|
|
|
237
295
|
/**
|
|
238
296
|
* Transform an EBSI URI into a URL.
|
|
239
297
|
* @example
|
|
240
298
|
* ```js
|
|
241
|
-
* toUrl(
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
299
|
+
* toUrl(
|
|
300
|
+
* "ebsi:pilot:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
|
|
301
|
+
* "api-pilot.ebsi.eu",
|
|
302
|
+
* {
|
|
303
|
+
* network: { name: "pilot" },
|
|
304
|
+
* scheme: "ebsi",
|
|
305
|
+
* services: {
|
|
306
|
+
* "did-registry": "v5",
|
|
307
|
+
* },
|
|
308
|
+
* },
|
|
309
|
+
* )
|
|
245
310
|
* ```
|
|
246
|
-
* returns `https://api-
|
|
311
|
+
* returns `https://api-pilot.ebsi.eu/did-registry/v5/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
|
|
247
312
|
* @param uriString - EBSI URI
|
|
248
|
-
* @param
|
|
249
|
-
* @
|
|
313
|
+
* @param host - Host to use
|
|
314
|
+
* @param config - EBSI URI configuration
|
|
315
|
+
* @returns URL to the resource in the EBSI network.
|
|
250
316
|
*/
|
|
251
|
-
export function toUrl<
|
|
317
|
+
export function toUrl<
|
|
318
|
+
Scheme extends string,
|
|
319
|
+
Network extends string,
|
|
320
|
+
Service extends string,
|
|
321
|
+
>(
|
|
252
322
|
uriString: string,
|
|
253
|
-
|
|
323
|
+
host: string,
|
|
324
|
+
config: EbsiUriConfiguration<Scheme, Network, Service>,
|
|
254
325
|
): string {
|
|
255
|
-
const {
|
|
326
|
+
const { resource, service } = parse(uriString, config);
|
|
256
327
|
|
|
257
|
-
|
|
258
|
-
const host = options.hosts[network];
|
|
328
|
+
const { services } = config;
|
|
259
329
|
|
|
260
|
-
if (!
|
|
261
|
-
throw new Error(
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const services = options.services;
|
|
265
|
-
|
|
266
|
-
if (!isSupportedService(service, services)) {
|
|
267
|
-
throw new Error(`Unsupported service '${service}'`);
|
|
330
|
+
if (!services) {
|
|
331
|
+
throw new Error("No services defined");
|
|
268
332
|
}
|
|
269
333
|
|
|
270
334
|
// Get service version
|
|
@@ -274,22 +338,13 @@ export function toUrl<T extends string>(
|
|
|
274
338
|
return `https://${host}/${service}/${serviceVersion}${resource}`;
|
|
275
339
|
}
|
|
276
340
|
|
|
277
|
-
/**
|
|
278
|
-
* Typeguard that checks if the given string is a supported network.
|
|
279
|
-
* @param network - String to check
|
|
280
|
-
* @returns True if network is a valid network name
|
|
281
|
-
*/
|
|
282
|
-
function isNetwork(network: string | undefined): network is Network {
|
|
283
|
-
return network !== undefined && NETWORKS.includes(network as Network);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
341
|
/**
|
|
287
342
|
* Typeguard that checks if the given string is a supported service version.
|
|
288
343
|
* @param serviceVersion - String to check
|
|
289
344
|
* @returns True if serviceVersion is a valid service version
|
|
290
345
|
*/
|
|
291
346
|
function isServiceVersion(
|
|
292
|
-
serviceVersion:
|
|
347
|
+
serviceVersion: unknown,
|
|
293
348
|
): serviceVersion is ServiceVersion {
|
|
294
349
|
return typeof serviceVersion === "string" && /v\d*/.test(serviceVersion);
|
|
295
350
|
}
|
|
@@ -297,12 +352,14 @@ function isServiceVersion(
|
|
|
297
352
|
/**
|
|
298
353
|
* Typeguard that checks if the given string is a supported service.
|
|
299
354
|
* @param service - String to check
|
|
300
|
-
* @param
|
|
355
|
+
* @param services - Map of the supported services and their versions.
|
|
301
356
|
* @returns True if service is a supported service
|
|
302
357
|
*/
|
|
303
|
-
function isSupportedService<
|
|
304
|
-
service:
|
|
305
|
-
|
|
306
|
-
): service is
|
|
307
|
-
return
|
|
358
|
+
function isSupportedService<Service extends string>(
|
|
359
|
+
service: unknown,
|
|
360
|
+
services: SupportedServices<Service>,
|
|
361
|
+
): service is Service {
|
|
362
|
+
return (
|
|
363
|
+
service !== undefined && typeof service === "string" && service in services
|
|
364
|
+
);
|
|
308
365
|
}
|