@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 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
- ### Parse
27
+ ### Configuration
28
28
 
29
- The `parse` function takes an EBSI URI (string) and returns the URI components `network`, `service`, and `resource`.
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("ebsi:test:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw");
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": "test",
42
- "service": "did-registry",
43
- "resource": "/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw"
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 an URL (string) and returns the URI components `network`, `service`, and `resource`. The function accepts an optional object that contains the list of supported services with their version number, and will throw an error if the URL contains a service or service version that is not supported.
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-test.ebsi.eu/did-registry/v4/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
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": "test",
64
- "service": "did-registry",
65
- "resource": "/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw"
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
- network: "test",
78
- service: "did-registry",
79
- resource: "/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
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. The function also requires that you pass an object containing a list of supported services with their version number, as well as an object containing the host to resolve for each network.
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("ebsi:test:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw", {
93
- services: { "did-registry": "v4" },
94
- hosts: { test: "api-test.ebsi.eu" },
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-test.ebsi.eu/did-registry/v4/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
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 an URL (string) and returns an EBSI URI string. The function accepts an optional object that contains the list of supported services with their version number, and will throw an error if the URL contains a service or service version that is not supported.
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-test.ebsi.eu/did-registry/v4/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw",
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 declare const SCHEME = "ebsi";
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
- service: ServiceName<T>;
4
+ scheme: Scheme;
5
+ service: Service;
15
6
  }
16
- export interface IFromUrlOptions<T extends string = string> {
17
- readonly services?: SupportedServices<T>;
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<T extends string> = Record<ServiceName<T>, ServiceVersion>;
30
- export declare function fromUrl<T extends string>(url: string, options?: IFromUrlOptions<T>): string;
31
- export declare function parse(uriString: string): {
32
- network: "production" | "preprod" | "conformance" | "pilot" | "test";
33
- resource: string;
34
- service: string;
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
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM,SAAS,CAAC;AAE7B,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAE/C,eAAO,MAAM,QAAQ,oEAMX,CAAC;AAEX,eAAO,MAAM,iBAAiB;;;;;;CAMc,CAAC;AAQ7C,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;CACzB;AAGD,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAIxD,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;CAC1C;AAGD,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAIzD,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;CAC1C;AAGD,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAItD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAKjD,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhD,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,IAAI,MAAM,EAAE,CAAC;AAE1C,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,MAAM,IAAI,MAAM,CACtD,WAAW,CAAC,CAAC,CAAC,EACd,cAAc,CACf,CAAC;AAaF,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EACtC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,UAK7B;AAmBD,wBAAgB,KAAK,CAAC,SAAS,EAAE,MAAM;;;;EAgCtC;AAQD,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC;;;aA0DP,CAAC;EAExB;AAgBD,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC,CAAC,UAO3E;AAgBD,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,EACpC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GACxB,MAAM,CAqBR"}
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 const SCHEME = "ebsi";
2
- export const PRODUCTION_NETWORK = "production";
3
- export const NETWORKS = [
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 !== SCHEME) {
24
- throw new Error(`Invalid URI: scheme must be '${SCHEME}'`);
7
+ if (scheme !== config.scheme) {
8
+ throw new Error(`Invalid URI: scheme must be '${config.scheme}'`);
25
9
  }
26
- const network = isNetwork(firstComponent)
27
- ? firstComponent
28
- : PRODUCTION_NETWORK;
29
- const service = isNetwork(firstComponent) ? secondComponent : firstComponent;
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
- const resource = (isNetwork(firstComponent) ? rest : [secondComponent, ...rest]).join(":");
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
- service,
31
+ scheme: config.scheme,
32
+ service: service,
41
33
  };
42
34
  }
43
- export function parseUrl(url, options) {
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, host, pathname, search } = urlObject;
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 (options?.services) {
69
- const services = options.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
- const networkName = network === PRODUCTION_NETWORK ? "" : `${network}:`;
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, options) {
91
- const { network, resource, service } = parse(uriString);
92
- const host = options.hosts[network];
93
- if (!host) {
94
- throw new Error(`No host for network ${network}`);
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, supportedServices) {
110
- return service !== undefined && service in supportedServices;
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":"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"}
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.2.0-alpha.1",
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 EBSIURIComponents<T extends string = string> {
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
- service: ServiceName<T>;
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
- /** Options for the `parseUrl()` function */
42
- export interface IParseUrlOptions<T extends string = string> {
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
- * Map of supported services and their versions
28
+ * Properties of the current EBSI network.
45
29
  */
46
- readonly services?: SupportedServices<T>;
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
- * Map of supported networks and their hosts
44
+ * The URI scheme of the EBSI URI.
45
+ * @example "ebsi"
53
46
  */
54
- readonly hosts: Partial<Record<Network, string>>;
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
- readonly services: SupportedServices<T>;
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<T extends string> = Record<
69
- ServiceName<T>,
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("https://api-test.ebsi.eu/did-registry/v4/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw")
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:test:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
74
+ * returns `ebsi:pilot:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
80
75
  * @param url - URL to transform
81
- * @param options - Supported services
76
+ * @param config - EBSI URI configuration
82
77
  * @returns EBSI URI
83
78
  */
84
- export function fromUrl<T extends string>(
85
- url: string,
86
- options?: IFromUrlOptions<T>,
87
- ) {
88
- const components = parseUrl(url, options);
89
-
90
- return serialize(components);
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("ebsi:test:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw")
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": "test",
103
- * "service": "did-registry",
104
- * "resource": "/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw"
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:test:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw"
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(uriString: string) {
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 !== SCHEME) {
115
- throw new Error(`Invalid URI: scheme must be '${SCHEME}'`);
128
+ if (scheme !== config.scheme) {
129
+ throw new Error(`Invalid URI: scheme must be '${config.scheme}'`);
116
130
  }
117
131
 
118
- const network = isNetwork(firstComponent)
119
- ? firstComponent
120
- : PRODUCTION_NETWORK;
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 = isNetwork(firstComponent) ? secondComponent : firstComponent;
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
- isNetwork(firstComponent) ? rest : [secondComponent, ...rest]
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
- service,
141
- } satisfies EBSIURIComponents<string>;
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 options - Supported services
194
+ * @param config - EBSI URI configuration
148
195
  * @returns EBSI URI components
149
196
  */
150
- export function parseUrl<T extends string>(
197
+ export function parseUrl<
198
+ Scheme extends string,
199
+ Network extends string,
200
+ Service extends string,
201
+ >(
151
202
  url: string,
152
- options?: IParseUrlOptions<T>,
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, host, pathname, search } = urlObject;
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 (options?.services) {
190
- const services = options.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
- service: service as T,
211
- } satisfies EBSIURIComponents<T>;
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
- * "network": "test",
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:test:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
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<T extends string>(components: EBSIURIComponents<T>) {
229
- const { network, resource, service } = components;
230
-
231
- const networkName = network === PRODUCTION_NETWORK ? "" : `${network}:`;
232
-
233
- // Return EBSI URI
234
- return `${SCHEME}:${networkName}${service}:${resource}`;
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("ebsi:test:did-registry:/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw", {
242
- * services: { "did-registry": "v4" },
243
- * hosts: { test: "api-test.ebsi.eu" }
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-test.ebsi.eu/did-registry/v4/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
311
+ * returns `https://api-pilot.ebsi.eu/did-registry/v5/identifiers/did:ebsi:zx23VhpbGYeqF2MRJk3HzPw`
247
312
  * @param uriString - EBSI URI
248
- * @param options - Supported services and hosts
249
- * @returns URL
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<T extends string>(
317
+ export function toUrl<
318
+ Scheme extends string,
319
+ Network extends string,
320
+ Service extends string,
321
+ >(
252
322
  uriString: string,
253
- options: IToUrlOptions<T>,
323
+ host: string,
324
+ config: EbsiUriConfiguration<Scheme, Network, Service>,
254
325
  ): string {
255
- const { network, resource, service } = parse(uriString);
326
+ const { resource, service } = parse(uriString, config);
256
327
 
257
- // Replace host
258
- const host = options.hosts[network];
328
+ const { services } = config;
259
329
 
260
- if (!host) {
261
- throw new Error(`No host for network ${network}`);
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: string | undefined,
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 supportedServices - Supported services
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<T extends string>(
304
- service: string | undefined,
305
- supportedServices: SupportedServices<T>,
306
- ): service is T {
307
- return service !== undefined && service in supportedServices;
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
  }