@enbox/dids 0.0.1

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.
Files changed (104) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +1 -0
  3. package/dist/browser.js +77 -0
  4. package/dist/browser.js.map +7 -0
  5. package/dist/browser.mjs +77 -0
  6. package/dist/browser.mjs.map +7 -0
  7. package/dist/cjs/index.js +6303 -0
  8. package/dist/cjs/index.js.map +7 -0
  9. package/dist/cjs/package.json +1 -0
  10. package/dist/cjs/utils.js +245 -0
  11. package/dist/cjs/utils.js.map +7 -0
  12. package/dist/esm/bearer-did.js +201 -0
  13. package/dist/esm/bearer-did.js.map +1 -0
  14. package/dist/esm/did-error.js +62 -0
  15. package/dist/esm/did-error.js.map +1 -0
  16. package/dist/esm/did.js +114 -0
  17. package/dist/esm/did.js.map +1 -0
  18. package/dist/esm/index.js +16 -0
  19. package/dist/esm/index.js.map +1 -0
  20. package/dist/esm/methods/did-dht.js +1241 -0
  21. package/dist/esm/methods/did-dht.js.map +1 -0
  22. package/dist/esm/methods/did-ion.js +570 -0
  23. package/dist/esm/methods/did-ion.js.map +1 -0
  24. package/dist/esm/methods/did-jwk.js +298 -0
  25. package/dist/esm/methods/did-jwk.js.map +1 -0
  26. package/dist/esm/methods/did-key.js +983 -0
  27. package/dist/esm/methods/did-key.js.map +1 -0
  28. package/dist/esm/methods/did-method.js +53 -0
  29. package/dist/esm/methods/did-method.js.map +1 -0
  30. package/dist/esm/methods/did-web.js +83 -0
  31. package/dist/esm/methods/did-web.js.map +1 -0
  32. package/dist/esm/resolver/resolver-cache-level.js +101 -0
  33. package/dist/esm/resolver/resolver-cache-level.js.map +1 -0
  34. package/dist/esm/resolver/resolver-cache-noop.js +24 -0
  35. package/dist/esm/resolver/resolver-cache-noop.js.map +1 -0
  36. package/dist/esm/resolver/universal-resolver.js +187 -0
  37. package/dist/esm/resolver/universal-resolver.js.map +1 -0
  38. package/dist/esm/types/did-core.js +51 -0
  39. package/dist/esm/types/did-core.js.map +1 -0
  40. package/dist/esm/types/did-resolution.js +12 -0
  41. package/dist/esm/types/did-resolution.js.map +1 -0
  42. package/dist/esm/types/multibase.js +2 -0
  43. package/dist/esm/types/multibase.js.map +1 -0
  44. package/dist/esm/types/portable-did.js +2 -0
  45. package/dist/esm/types/portable-did.js.map +1 -0
  46. package/dist/esm/utils.js +458 -0
  47. package/dist/esm/utils.js.map +1 -0
  48. package/dist/types/bearer-did.d.ts +143 -0
  49. package/dist/types/bearer-did.d.ts.map +1 -0
  50. package/dist/types/did-error.d.ts +50 -0
  51. package/dist/types/did-error.d.ts.map +1 -0
  52. package/dist/types/did.d.ts +125 -0
  53. package/dist/types/did.d.ts.map +1 -0
  54. package/dist/types/index.d.ts +18 -0
  55. package/dist/types/index.d.ts.map +1 -0
  56. package/dist/types/methods/did-dht.d.ts +682 -0
  57. package/dist/types/methods/did-dht.d.ts.map +1 -0
  58. package/dist/types/methods/did-ion.d.ts +492 -0
  59. package/dist/types/methods/did-ion.d.ts.map +1 -0
  60. package/dist/types/methods/did-jwk.d.ts +236 -0
  61. package/dist/types/methods/did-jwk.d.ts.map +1 -0
  62. package/dist/types/methods/did-key.d.ts +499 -0
  63. package/dist/types/methods/did-key.d.ts.map +1 -0
  64. package/dist/types/methods/did-method.d.ts +238 -0
  65. package/dist/types/methods/did-method.d.ts.map +1 -0
  66. package/dist/types/methods/did-web.d.ts +37 -0
  67. package/dist/types/methods/did-web.d.ts.map +1 -0
  68. package/dist/types/resolver/resolver-cache-level.d.ts +86 -0
  69. package/dist/types/resolver/resolver-cache-level.d.ts.map +1 -0
  70. package/dist/types/resolver/resolver-cache-noop.d.ts +9 -0
  71. package/dist/types/resolver/resolver-cache-noop.d.ts.map +1 -0
  72. package/dist/types/resolver/universal-resolver.d.ts +109 -0
  73. package/dist/types/resolver/universal-resolver.d.ts.map +1 -0
  74. package/dist/types/types/did-core.d.ts +523 -0
  75. package/dist/types/types/did-core.d.ts.map +1 -0
  76. package/dist/types/types/did-resolution.d.ts +85 -0
  77. package/dist/types/types/did-resolution.d.ts.map +1 -0
  78. package/dist/types/types/multibase.d.ts +28 -0
  79. package/dist/types/types/multibase.d.ts.map +1 -0
  80. package/dist/types/types/portable-did.d.ts +59 -0
  81. package/dist/types/types/portable-did.d.ts.map +1 -0
  82. package/dist/types/utils.d.ts +378 -0
  83. package/dist/types/utils.d.ts.map +1 -0
  84. package/dist/utils.js +28 -0
  85. package/dist/utils.js.map +7 -0
  86. package/package.json +116 -0
  87. package/src/bearer-did.ts +287 -0
  88. package/src/did-error.ts +75 -0
  89. package/src/did.ts +186 -0
  90. package/src/index.ts +21 -0
  91. package/src/methods/did-dht.ts +1637 -0
  92. package/src/methods/did-ion.ts +887 -0
  93. package/src/methods/did-jwk.ts +410 -0
  94. package/src/methods/did-key.ts +1248 -0
  95. package/src/methods/did-method.ts +276 -0
  96. package/src/methods/did-web.ts +96 -0
  97. package/src/resolver/resolver-cache-level.ts +163 -0
  98. package/src/resolver/resolver-cache-noop.ts +26 -0
  99. package/src/resolver/universal-resolver.ts +238 -0
  100. package/src/types/did-core.ts +580 -0
  101. package/src/types/did-resolution.ts +93 -0
  102. package/src/types/multibase.ts +29 -0
  103. package/src/types/portable-did.ts +64 -0
  104. package/src/utils.ts +532 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Represents a cryptographic key with associated multicodec metadata.
3
+ *
4
+ * The `KeyWithMulticodec` type encapsulates a cryptographic key along with optional multicodec
5
+ * information. It is primarily used in functions that convert between cryptographic keys and their
6
+ * string representations, ensuring that the key's format and encoding are preserved and understood
7
+ * across different systems and applications.
8
+ */
9
+ export type KeyWithMulticodec = {
10
+ /**
11
+ * A `Uint8Array` representing the raw bytes of the cryptographic key. This is the primary data of
12
+ * the type and is essential for cryptographic operations.
13
+ */
14
+ keyBytes: Uint8Array,
15
+
16
+ /**
17
+ * An optional number representing the multicodec code. This code uniquely identifies the encoding
18
+ * format or protocol associated with the key. The presence of this code is crucial for decoding
19
+ * the key correctly in different contexts.
20
+ */
21
+ multicodecCode?: number,
22
+
23
+ /**
24
+ * An optional string representing the human-readable name of the multicodec. This name provides
25
+ * an easier way to identify the encoding format or protocol of the key, especially when the
26
+ * numerical code is not immediately recognizable.
27
+ */
28
+ multicodecName?: string
29
+ };
@@ -0,0 +1,64 @@
1
+ import type { Jwk } from '@enbox/crypto';
2
+
3
+ import type { DidDocument, DidDocumentMetadata } from './did-core.js';
4
+
5
+ /**
6
+ * Represents metadata about a DID resulting from create, update, or deactivate operations.
7
+ */
8
+ export interface DidMetadata extends DidDocumentMetadata {
9
+ /**
10
+ * For DID methods that support publishing, the `published` property indicates whether the DID
11
+ * document has been published to the respective network.
12
+ *
13
+ * A `true` value signifies that the DID document is publicly accessible on the network (e.g.,
14
+ * Mainline DHT), allowing it to be resolved by others. A `false` value implies the DID document
15
+ * is not published, limiting its visibility to public resolution. Absence of this property
16
+ * indicates that the DID method does not support publishing.
17
+ */
18
+ published?: boolean;
19
+ }
20
+
21
+ /**
22
+ * Format to document a DID identifier, along with its associated data, which can be exported,
23
+ * saved to a file, or imported. The intent is bundle all of the necessary metadata to enable usage
24
+ * of the DID in different contexts.
25
+ */
26
+ /**
27
+ * Format that documents the key material and metadata of a Decentralized Identifier (DID) to enable
28
+ * usage of the DID in different contexts.
29
+ *
30
+ * This format is useful for exporting, saving to a file, or importing a DID across process
31
+ * boundaries or between different DID method implementations.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * // Generate a new DID.
36
+ * const did = await DidExample.create();
37
+ *
38
+ * // Export to a PortableDid.
39
+ * const portableDid = await did.export();
40
+ *
41
+ * // Instantiate a BearerDid object from a PortableDid.
42
+ * const importedDid = await DidExample.import(portableDid);
43
+ * // The `importedDid` object should be equivalent to the original `did` object.
44
+ * ```
45
+ */
46
+ export interface PortableDid {
47
+ /** {@inheritDoc Did#uri} */
48
+ uri: string;
49
+
50
+ /**
51
+ * The DID document associated with this DID.
52
+ *
53
+ * @see {@link https://www.w3.org/TR/did-core/#dfn-diddocument | DID Core Specification, § DID Document}
54
+ */
55
+ document: DidDocument;
56
+
57
+ /** {@inheritDoc DidMetadata} */
58
+ metadata: DidMetadata;
59
+
60
+ /**
61
+ * An optional array of private keys associated with the DID document's verification methods.
62
+ */
63
+ privateKeys?: Jwk[];
64
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,532 @@
1
+ import type { Jwk } from '@enbox/crypto';
2
+ import type { RequireOnly } from '@enbox/common';
3
+
4
+ import { Convert, Multicodec } from '@enbox/common';
5
+ import { computeJwkThumbprint } from '@enbox/crypto';
6
+
7
+ import type { KeyWithMulticodec } from './types/multibase.js';
8
+
9
+ import { DidError, DidErrorCode } from './did-error.js';
10
+ import {
11
+ DidService,
12
+ DidDocument,
13
+ DidVerificationMethod,
14
+ DidVerificationRelationship,
15
+ } from './types/did-core.js';
16
+
17
+ /**
18
+ * Represents a Decentralized Web Node (DWN) service in a DID Document.
19
+ *
20
+ * A DWN DID service is a specialized type of DID service with the `type` set to
21
+ * `DecentralizedWebNode`. It includes specific properties `enc` and `sig` that are used to identify
22
+ * the public keys that can be used to interact with the DID Subject. The values of these properties
23
+ * are strings or arrays of strings containing one or more verification method `id` values present in
24
+ * the same DID document. If the `enc` and/or `sig` properties are an array of strings, an entity
25
+ * interacting with the DID subject is expected to use the verification methods in the order they
26
+ * are listed.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const service: DwnDidService = {
31
+ * id: 'did:example:123#dwn',
32
+ * type: 'DecentralizedWebNode',
33
+ * serviceEndpoint: 'https://enbox-production.up.railway.app',
34
+ * enc: 'did:example:123#key-1',
35
+ * sig: 'did:example:123#key-2'
36
+ * }
37
+ * ```
38
+ *
39
+ * @see {@link https://identity.foundation/decentralized-web-node/spec/ | DIF Decentralized Web Node (DWN) Specification}
40
+ */
41
+ export interface DwnDidService extends DidService {
42
+ /**
43
+ * One or more verification method `id` values that can be used to encrypt information
44
+ * intended for the DID subject.
45
+ */
46
+ enc?: string | string[];
47
+
48
+ /**
49
+ * One or more verification method `id` values that will be used by the DID subject to sign data
50
+ * or by another entity to verify signatures created by the DID subject.
51
+ */
52
+ sig: string | string[];
53
+ }
54
+
55
+ /**
56
+ * Extracts the fragment part of a Decentralized Identifier (DID) verification method identifier.
57
+ *
58
+ * This function takes any input and aims to return only the fragment of a DID identifier,
59
+ * which comes after the '#' symbol in a DID string. It's designed specifically for handling
60
+ * DID verification method identifiers. The function returns undefined for non-string inputs, inputs
61
+ * that do not contain a '#', or complex data structures like objects or arrays, ensuring that only
62
+ * the fragment part of a DID string is extracted when present.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * console.log(extractDidFragment("did:example:123#key-1")); // Output: "key-1"
67
+ * console.log(extractDidFragment("did:example:123")); // Output: undefined
68
+ * console.log(extractDidFragment({ id: "did:example:123#0", type: "JsonWebKey" })); // Output: undefined
69
+ * console.log(extractDidFragment(undefined)); // Output: undefined
70
+ * ```
71
+ *
72
+ * @param input - The input to be processed. Can be of any type, but the function is designed
73
+ * to work with strings that represent DID verification method identifiers.
74
+ * @returns The fragment part of the DID identifier if the input is a string containing a '#'.
75
+ * Returns an empty string for all other inputs, including non-string types, strings
76
+ * without a '#', and complex data structures.
77
+ */
78
+ export function extractDidFragment(input: unknown): string | undefined {
79
+ if (typeof input !== 'string') return undefined;
80
+ if (input.length === 0) return undefined;
81
+ return input.split('#').pop();
82
+ }
83
+
84
+ /**
85
+ * Retrieves services from a given DID document, optionally filtered by `id` or `type`.
86
+ *
87
+ * If no `id` or `type` filters are provided, all defined services are returned.
88
+ *
89
+ * The given DID Document must adhere to the
90
+ * {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * const didDocument = { ... }; // W3C DID document
95
+ * const services = getServices({ didDocument, type: 'DecentralizedWebNode' });
96
+ * ```
97
+ *
98
+ * @param params - An object containing input parameters for retrieving services.
99
+ * @param params.didDocument - The DID document from which services are retrieved.
100
+ * @param params.id - Optional. A string representing the specific service ID to match. If provided, only the service with this ID will be returned.
101
+ * @param params.type - Optional. A string representing the specific service type to match. If provided, only the service(s) of this type will be returned.
102
+ * @returns An array of services. If no matching service is found, an empty array is returned.
103
+ */
104
+ export function getServices({ didDocument, id, type }: {
105
+ didDocument: DidDocument;
106
+ id?: string;
107
+ type?: string;
108
+ }): DidService[] {
109
+ return didDocument?.service?.filter(service => {
110
+ if (id && service.id !== id) return false;
111
+ if (type && service.type !== type) return false;
112
+ return true;
113
+ }) ?? [];
114
+ }
115
+
116
+ /**
117
+ * Retrieves a verification method object from a DID document if there is a match for the given
118
+ * public key.
119
+ *
120
+ * This function searches the verification methods in a given DID document for a match with the
121
+ * provided public key (either in JWK or multibase format). If a matching verification method is
122
+ * found it is returned. If no match is found `null` is returned.
123
+ *
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * const didDocument = {
128
+ * // ... contents of a DID document ...
129
+ * };
130
+ * const publicKeyJwk = { kty: 'OKP', crv: 'Ed25519', x: '...' };
131
+ *
132
+ * const verificationMethod = await getVerificationMethodByKey({
133
+ * didDocument,
134
+ * publicKeyJwk
135
+ * });
136
+ * ```
137
+ *
138
+ * @param params - An object containing input parameters for retrieving the verification method ID.
139
+ * @param params.didDocument - The DID document to search for the verification method.
140
+ * @param params.publicKeyJwk - The public key in JSON Web Key (JWK) format to match against the verification methods in the DID document.
141
+ * @param params.publicKeyMultibase - The public key as a multibase encoded string to match against the verification methods in the DID document.
142
+ * @returns A promise that resolves with the matching verification method, or `null` if no match is found.
143
+ * @throws Throws an `Error` if the `didDocument` parameter is missing or if the `didDocument` does not contain any verification methods.
144
+ */
145
+ export async function getVerificationMethodByKey({ didDocument, publicKeyJwk, publicKeyMultibase }: {
146
+ didDocument: DidDocument;
147
+ publicKeyJwk?: Jwk;
148
+ publicKeyMultibase?: string;
149
+ }): Promise<DidVerificationMethod | null> {
150
+ // Collect all verification methods from the DID document.
151
+ const verificationMethods = getVerificationMethods({ didDocument });
152
+
153
+ for (let method of verificationMethods) {
154
+ if (publicKeyJwk && method.publicKeyJwk) {
155
+ const publicKeyThumbprint = await computeJwkThumbprint({ jwk: publicKeyJwk });
156
+ if (publicKeyThumbprint === await computeJwkThumbprint({ jwk: method.publicKeyJwk })) {
157
+ return method;
158
+ }
159
+ } else if (publicKeyMultibase && method.publicKeyMultibase) {
160
+ if (publicKeyMultibase === method.publicKeyMultibase) {
161
+ return method;
162
+ }
163
+ }
164
+ }
165
+
166
+ return null;
167
+ }
168
+
169
+ /**
170
+ * Retrieves all verification methods from a given DID document, including embedded methods.
171
+ *
172
+ * This function consolidates all verification methods into a single array for easy access and
173
+ * processing. It checks both the primary `verificationMethod` array and the individual verification
174
+ * relationship properties `authentication`, `assertionMethod`, `keyAgreement`,
175
+ * `capabilityInvocation`, and `capabilityDelegation` for embedded methods.
176
+ *
177
+ * The given DID Document must adhere to the
178
+ * {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * const didDocument = { ... }; // W3C DID document
183
+ * const verificationMethods = getVerificationMethods({ didDocument });
184
+ * ```
185
+ *
186
+ * @param params - An object containing input parameters for retrieving verification methods.
187
+ * @param params.didDocument - The DID document from which verification methods are retrieved.
188
+ * @returns An array of `DidVerificationMethod`. If no verification methods are found, an empty array is returned.
189
+ * @throws Throws an `TypeError` if the `didDocument` parameter is missing.
190
+ */
191
+ export function getVerificationMethods({ didDocument }: {
192
+ didDocument: DidDocument;
193
+ }): DidVerificationMethod[] {
194
+ if (!didDocument) throw new TypeError(`Required parameter missing: 'didDocument'`);
195
+
196
+ const verificationMethods: DidVerificationMethod[] = [];
197
+
198
+ // Check the 'verificationMethod' array.
199
+ verificationMethods.push(...didDocument.verificationMethod?.filter(isDidVerificationMethod) ?? []);
200
+
201
+ // Check verification relationship properties for embedded verification methods.
202
+ Object.keys(DidVerificationRelationship).forEach((relationship) => {
203
+ verificationMethods.push(
204
+ ...(didDocument[relationship as keyof DidDocument] as (string | DidVerificationMethod)[])
205
+ ?.filter(isDidVerificationMethod) ?? []
206
+ );
207
+ });
208
+
209
+ return verificationMethods;
210
+ }
211
+
212
+ /**
213
+ * Retrieves all DID verification method types from a given DID document.
214
+ *
215
+ * The given DID Document must adhere to the
216
+ * {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
217
+ *
218
+ * @example
219
+ * ```ts
220
+ * const didDocument = {
221
+ * verificationMethod: [
222
+ * {
223
+ * 'id' : 'did:example:123#key-0',
224
+ * 'type' : 'Ed25519VerificationKey2018',
225
+ * 'controller' : 'did:example:123',
226
+ * 'publicKeyBase58' : '3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J'
227
+ * },
228
+ * {
229
+ * 'id' : 'did:example:123#key-1',
230
+ * 'type' : 'X25519KeyAgreementKey2019',
231
+ * 'controller' : 'did:example:123',
232
+ * 'publicKeyBase58' : 'FbQWLPRhTH95MCkQUeFYdiSoQt8zMwetqfWoxqPgaq7x'
233
+ * },
234
+ * {
235
+ * 'id' : 'did:example:123#key-3',
236
+ * 'type' : 'JsonWebKey2020',
237
+ * 'controller' : 'did:example:123',
238
+ * 'publicKeyJwk' : {
239
+ * 'kty' : 'EC',
240
+ * 'crv' : 'P-256',
241
+ * 'x' : 'Er6KSSnAjI70ObRWhlaMgqyIOQYrDJTE94ej5hybQ2M',
242
+ * 'y' : 'pPVzCOTJwgikPjuUE6UebfZySqEJ0ZtsWFpj7YSPGEk'
243
+ * }
244
+ * }
245
+ * ]
246
+ * },
247
+ * const vmTypes = getVerificationMethodTypes({ didDocument });
248
+ * console.log(vmTypes);
249
+ * // Output: ['Ed25519VerificationKey2018', 'X25519KeyAgreementKey2019', 'JsonWebKey2020']
250
+ * ```
251
+ *
252
+ * @param params - An object containing input parameters for retrieving types.
253
+ * @param params.didDocument - The DID document from which types are retrieved.
254
+ * @returns An array of types. If no types were found, an empty array is returned.
255
+ */
256
+ export function getVerificationMethodTypes({ didDocument }: {
257
+ didDocument: DidDocument;
258
+ }): string[] {
259
+ // Collect all verification methods from the DID document.
260
+ const verificationMethods = getVerificationMethods({ didDocument });
261
+
262
+ // Map to extract 'type' from each verification method.
263
+ const types = verificationMethods.map(method => method.type);
264
+
265
+ return [...new Set(types)]; // Return only unique types.
266
+ }
267
+
268
+ /**
269
+ * Retrieves a list of DID verification relationships by a specific method ID from a DID document.
270
+ *
271
+ * This function examines the specified DID document to identify any verification relationships
272
+ * (e.g., `authentication`, `assertionMethod`) that reference a verification method by its method ID
273
+ * or contain an embedded verification method matching the method ID. The method ID is typically a
274
+ * fragment of a DID (e.g., `did:example:123#key-1`) that uniquely identifies a verification method
275
+ * within the DID document.
276
+ *
277
+ * The search considers both direct references to verification methods by their IDs and verification
278
+ * methods embedded within the verification relationship arrays. It returns an array of
279
+ * `DidVerificationRelationship` enums corresponding to the verification relationships that contain
280
+ * the specified method ID.
281
+ *
282
+ * @param params - An object containing input parameters for retrieving verification relationships.
283
+ * @param params.didDocument - The DID document to search for verification relationships.
284
+ * @param params.methodId - The method ID to search for within the verification relationships.
285
+ * @returns An array of `DidVerificationRelationship` enums representing the types of verification
286
+ * relationships that reference the specified method ID.
287
+ *
288
+ * @example
289
+ * ```ts
290
+ * const didDocument: DidDocument = {
291
+ * // ...contents of a DID document...
292
+ * };
293
+ *
294
+ * const relationships = getVerificationRelationshipsById({
295
+ * didDocument,
296
+ * methodId: 'key-1'
297
+ * });
298
+ * console.log(relationships);
299
+ * // Output might include ['authentication', 'assertionMethod'] if those relationships
300
+ * // reference or contain the specified method ID.
301
+ * ```
302
+ */
303
+ export function getVerificationRelationshipsById({ didDocument, methodId }: {
304
+ didDocument: DidDocument;
305
+ methodId: string;
306
+ }): DidVerificationRelationship[] {
307
+ const relationships: DidVerificationRelationship[] = [];
308
+
309
+ Object.keys(DidVerificationRelationship).forEach((relationship) => {
310
+ if (Array.isArray(didDocument[relationship as keyof DidDocument])) {
311
+ const relationshipMethods = didDocument[relationship as keyof DidDocument] as (string | DidVerificationMethod)[];
312
+
313
+ const methodIdFragment = extractDidFragment(methodId);
314
+
315
+ // Check if the verification relationship property contains a matching method ID either
316
+ // directly referenced or as an embedded verification method.
317
+ const containsMethodId = relationshipMethods.some(method => {
318
+ const isByReferenceMatch = extractDidFragment(method) === methodIdFragment;
319
+ const isEmbeddedMethodMatch = isDidVerificationMethod(method) && extractDidFragment(method.id) === methodIdFragment;
320
+ return isByReferenceMatch || isEmbeddedMethodMatch;
321
+ });
322
+
323
+ if (containsMethodId) {
324
+ relationships.push(relationship as DidVerificationRelationship);
325
+ }
326
+ }
327
+ });
328
+
329
+ return relationships;
330
+ }
331
+
332
+ /**
333
+ * Checks if a given object is a {@link DidService}.
334
+ *
335
+ * A {@link DidService} in the context of DID resources must include the properties `id`, `type`,
336
+ * and `serviceEndpoint`. The `serviceEndpoint` can be a `DidServiceEndpoint` or an array of
337
+ * `DidServiceEndpoint` objects.
338
+ *
339
+ * @example
340
+ * ```ts
341
+ * const service = {
342
+ * id: "did:example:123#service-1",
343
+ * type: "OidcService",
344
+ * serviceEndpoint: "https://example.com/oidc"
345
+ * };
346
+ *
347
+ * if (isDidService(service)) {
348
+ * console.log('The object is a DidService');
349
+ * } else {
350
+ * console.log('The object is not a DidService');
351
+ * }
352
+ * ```
353
+ *
354
+ * @param obj - The object to be checked.
355
+ * @returns `true` if `obj` is a `DidService`; otherwise, `false`.
356
+ */
357
+ export function isDidService(obj: unknown): obj is DidService {
358
+ // Validate that the given value is an object.
359
+ if (!obj || typeof obj !== 'object' || obj === null) return false;
360
+
361
+ // Validate that the object has the necessary properties of DidService.
362
+ return 'id' in obj && 'type' in obj && 'serviceEndpoint' in obj;
363
+ }
364
+
365
+ /**
366
+ * Checks if a given object is a {@link DwnDidService}.
367
+ *
368
+ * A {@link DwnDidService} is defined as {@link DidService} object with a `type` of
369
+ * "DecentralizedWebNode" and `enc` and `sig` properties, where both properties are either strings
370
+ * or arrays of strings.
371
+ *
372
+ * @example
373
+ * ```ts
374
+ * const didDocument: DidDocument = {
375
+ * id: 'did:example:123',
376
+ * verificationMethod: [
377
+ * {
378
+ * id: 'did:example:123#key-1',
379
+ * type: 'JsonWebKey2020',
380
+ * controller: 'did:example:123',
381
+ * publicKeyJwk: { ... }
382
+ * },
383
+ * {
384
+ * id: 'did:example:123#key-2',
385
+ * type: 'JsonWebKey2020',
386
+ * controller: 'did:example:123',
387
+ * publicKeyJwk: { ... }
388
+ * }
389
+ * ],
390
+ * service: [
391
+ * {
392
+ * id: 'did:example:123#dwn',
393
+ * type: 'DecentralizedWebNode',
394
+ * serviceEndpoint: 'https://enbox-production.up.railway.app',
395
+ * enc: 'did:example:123#key-1',
396
+ * sig: 'did:example:123#key-2'
397
+ * }
398
+ * ]
399
+ * };
400
+ *
401
+ * if (isDwnService(didDocument.service[0])) {
402
+ * console.log('The object is a DwnDidService');
403
+ * } else {
404
+ * console.log('The object is not a DwnDidService');
405
+ * }
406
+ * ```
407
+ *
408
+ * @see {@link https://identity.foundation/decentralized-web-node/spec/ | Decentralized Web Node (DWN) Specification}
409
+ *
410
+ * @param obj - The object to be checked.
411
+ * @returns `true` if `obj` is a DwnDidService; otherwise, `false`.
412
+ */
413
+ export function isDwnDidService(obj: unknown): obj is DwnDidService {
414
+ // Validate that the given value is a {@link DidService}.
415
+ if (!isDidService(obj)) return false;
416
+
417
+ // Validate that the `type` property is `DecentralizedWebNode`.
418
+ if (obj.type !== 'DecentralizedWebNode') return false;
419
+
420
+ // Validate that the given object has the `enc` and `sig` properties.
421
+ if (!('enc' in obj && 'sig' in obj)) return false;
422
+
423
+ // Validate that the `enc` and `sig` properties are either strings or arrays of strings.
424
+ const isStringOrStringArray = (prop: any): boolean =>
425
+ typeof prop === 'string' || Array.isArray(prop) && prop.every(item => typeof item === 'string');
426
+ return (isStringOrStringArray(obj.enc)) && (isStringOrStringArray(obj.sig));
427
+ }
428
+
429
+ /**
430
+ * Checks if a given object is a DID Verification Method.
431
+ *
432
+ * A {@link DidVerificationMethod} in the context of DID resources must include the properties `id`,
433
+ * `type`, and `controller`.
434
+ *
435
+ * @example
436
+ * ```ts
437
+ * const resource = {
438
+ * id : "did:example:123#0",
439
+ * type : "JsonWebKey2020",
440
+ * controller : "did:example:123",
441
+ * publicKeyJwk : { ... }
442
+ * };
443
+ *
444
+ * if (isDidVerificationMethod(resource)) {
445
+ * console.log('The resource is a DidVerificationMethod');
446
+ * } else {
447
+ * console.log('The resource is not a DidVerificationMethod');
448
+ * }
449
+ * ```
450
+ *
451
+ * @param obj - The object to be checked.
452
+ * @returns `true` if `obj` is a `DidVerificationMethod`; otherwise, `false`.
453
+ */
454
+ export function isDidVerificationMethod(obj: unknown): obj is DidVerificationMethod {
455
+ // Validate that the given value is an object.
456
+ if (!obj || typeof obj !== 'object' || obj === null) return false;
457
+
458
+ // Validate that the object has the necessary properties of a DidVerificationMethod.
459
+ if (!('id' in obj && 'type' in obj && 'controller' in obj)) return false;
460
+
461
+ if (typeof obj.id !== 'string') return false;
462
+ if (typeof obj.type !== 'string') return false;
463
+ if (typeof obj.controller !== 'string') return false;
464
+
465
+ return true;
466
+ }
467
+
468
+ /**
469
+ * Converts a cryptographic key to a multibase identifier.
470
+ *
471
+ * @remarks
472
+ * This method provides a way to represent a cryptographic key as a multibase identifier.
473
+ * It takes a `Uint8Array` representing the key, and either the multicodec code or multicodec name
474
+ * as input. The method first adds the multicodec prefix to the key, then encodes it into Base58
475
+ * format. Finally, it converts the Base58 encoded key into a multibase identifier.
476
+ *
477
+ * @example
478
+ * ```ts
479
+ * const key = new Uint8Array([...]); // Cryptographic key as Uint8Array
480
+ * const multibaseId = keyBytesToMultibaseId({ key, multicodecName: 'ed25519-pub' });
481
+ * ```
482
+ *
483
+ * @param params - The parameters for the conversion.
484
+ * @returns The multibase identifier as a string.
485
+ */
486
+ export function keyBytesToMultibaseId({ keyBytes, multicodecCode, multicodecName }:
487
+ RequireOnly<KeyWithMulticodec, 'keyBytes'>
488
+ ): string {
489
+ const prefixedKey = Multicodec.addPrefix({
490
+ code : multicodecCode,
491
+ data : keyBytes,
492
+ name : multicodecName
493
+ });
494
+ const prefixedKeyB58 = Convert.uint8Array(prefixedKey).toBase58Btc();
495
+ const multibaseKeyId = Convert.base58Btc(prefixedKeyB58).toMultibase();
496
+
497
+ return multibaseKeyId;
498
+ }
499
+
500
+ /**
501
+ * Converts a multibase identifier to a cryptographic key.
502
+ *
503
+ * @remarks
504
+ * This function decodes a multibase identifier back into a cryptographic key. It first decodes the
505
+ * identifier from multibase format into Base58 format, and then converts it into a `Uint8Array`.
506
+ * Afterward, it removes the multicodec prefix, extracting the raw key data along with the
507
+ * multicodec code and name.
508
+ *
509
+ * @example
510
+ * ```ts
511
+ * const multibaseKeyId = '...'; // Multibase identifier of the key
512
+ * const { key, multicodecCode, multicodecName } = multibaseIdToKey({ multibaseKeyId });
513
+ * ```
514
+ *
515
+ * @param params - The parameters for the conversion.
516
+ * @param params.multibaseKeyId - The multibase identifier string of the key.
517
+ * @returns An object containing the key as a `Uint8Array` and its multicodec code and name.
518
+ * @throws `DidError` if the multibase identifier is invalid.
519
+ */
520
+ export function multibaseIdToKeyBytes({ multibaseKeyId }: {
521
+ multibaseKeyId: string
522
+ }): Required<KeyWithMulticodec> {
523
+ try {
524
+ const prefixedKeyB58 = Convert.multibase(multibaseKeyId).toBase58Btc();
525
+ const prefixedKey = Convert.base58Btc(prefixedKeyB58).toUint8Array();
526
+ const { code, data, name } = Multicodec.removePrefix({ prefixedData: prefixedKey });
527
+
528
+ return { keyBytes: data, multicodecCode: code, multicodecName: name };
529
+ } catch (error: any) {
530
+ throw new DidError(DidErrorCode.InvalidDid, `Invalid multibase identifier: ${multibaseKeyId}`);
531
+ }
532
+ }