@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,276 @@
1
+ import type {
2
+ CryptoApi,
3
+ LocalKeyManager,
4
+ InferKeyGeneratorAlgorithm,
5
+ } from '@enbox/crypto';
6
+
7
+ import type { BearerDid } from '../bearer-did.js';
8
+ import type { DidMetadata } from '../types/portable-did.js';
9
+ import type {
10
+ DidDocument,
11
+ DidResolutionResult,
12
+ DidResolutionOptions,
13
+ DidVerificationMethod,
14
+ } from '../types/did-core.js';
15
+
16
+ import { DidVerificationRelationship } from '../types/did-core.js';
17
+
18
+ /**
19
+ * Represents options during the creation of a Decentralized Identifier (DID).
20
+ *
21
+ * Implementations of this interface may contain properties and methods that provide specific
22
+ * options or metadata during the DID creation processes following specific DID method
23
+ * specifications.
24
+ */
25
+ export interface DidCreateOptions<TKms> {
26
+ /**
27
+ * Optional. An array of verification methods to be included in the DID document.
28
+ */
29
+ verificationMethods?: DidCreateVerificationMethod<TKms>[];
30
+ }
31
+
32
+ /**
33
+ * Options for additional verification methods added to the DID Document during the creation of a
34
+ * new Decentralized Identifier (DID).
35
+ */
36
+ export interface DidCreateVerificationMethod<TKms> extends Pick<Partial<DidVerificationMethod>, 'controller' | 'id' | 'type'> {
37
+ /**
38
+ * The name of the cryptographic algorithm to be used for key generation.
39
+ *
40
+ * Examples might include `Ed25519` and `ES256K` but will vary depending on the DID method
41
+ * specification and the key management system in use.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * const verificationMethod: DidCreateVerificationMethod = {
46
+ * algorithm: 'Ed25519'
47
+ * };
48
+ * ```
49
+ */
50
+ algorithm: TKms extends CryptoApi
51
+ ? InferKeyGeneratorAlgorithm<TKms>
52
+ : InferKeyGeneratorAlgorithm<LocalKeyManager>;
53
+
54
+ /**
55
+ * Optionally specify the purposes for which a verification method is intended to be used in a DID
56
+ * document.
57
+ *
58
+ * The `purposes` property defines the specific
59
+ * {@link DidVerificationRelationship | verification relationships} between the DID subject and
60
+ * the verification method. This enables the verification method to be utilized for distinct
61
+ * actions such as authentication, assertion, key agreement, capability delegation, and others. It
62
+ * is important for verifiers to recognize that a verification method must be associated with the
63
+ * relevant purpose in the DID document to be valid for that specific use case.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const verificationMethod: DidCreateVerificationMethod = {
68
+ * algorithm: 'Ed25519',
69
+ * controller: 'did:example:1234',
70
+ * purposes: ['authentication', 'assertionMethod']
71
+ * };
72
+ * ```
73
+ */
74
+ purposes?: (DidVerificationRelationship | keyof typeof DidVerificationRelationship)[];
75
+ }
76
+
77
+ /**
78
+ * Defines the API for a specific DID method. It includes functionalities for creating and resolving
79
+ * DIDs.
80
+ *
81
+ * @typeparam T - The type of the DID instance associated with this method.
82
+ * @typeparam O - The type of the options used for creating the DID.
83
+ */
84
+ export interface DidMethodApi<
85
+ TKms extends CryptoApi | undefined = CryptoApi,
86
+ TDid extends BearerDid = BearerDid,
87
+ TOptions extends DidCreateOptions<TKms> = DidCreateOptions<TKms>
88
+ > extends DidMethodResolver {
89
+ /**
90
+ * The name of the DID method.
91
+ *
92
+ * For example, in the DID `did:example:123456`, "example" would be the method name.
93
+ */
94
+ methodName: string;
95
+
96
+ new (): DidMethod;
97
+
98
+ /**
99
+ * Creates a new DID.
100
+ *
101
+ * This function should generate a new DID in accordance with the DID method specification being
102
+ * implemented, using the provided `keyManager`, and optionally, any provided `options`.
103
+ *
104
+ * @param params - The parameters used to create the DID.
105
+ * @param params.keyManager - Optional. The cryptographic API used for key management.
106
+ * @param params.options - Optional. The options used for creating the DID.
107
+ * @returns A promise that resolves to the newly created DID instance.
108
+ */
109
+ create(params: {
110
+ keyManager?: TKms;
111
+ options?: TOptions;
112
+ }): Promise<TDid>;
113
+
114
+ /**
115
+ * Given a DID Document, return the verification method that will be used for signing messages and
116
+ * credentials.
117
+ *
118
+ * If given, the `methodId` parameter is used to select the verification method. If not given, a
119
+ * DID method specific approach is taken to selecting the verification method to return.
120
+ *
121
+ * @param params - The parameters for the `getSigningMethod` operation.
122
+ * @param params.didDocument - DID Document to get the verification method from.
123
+ * @param params.methodId - ID of the verification method to use for signing.
124
+ * @returns A promise that resolves to the erification method to use for signing.
125
+ */
126
+ getSigningMethod(params: {
127
+ didDocument: DidDocument;
128
+ methodId?: string;
129
+ }): Promise<DidVerificationMethod>;
130
+ }
131
+
132
+ /**
133
+ * Defines the interface for resolving a DID using a specific DID method.
134
+ *
135
+ * A DID resolver takes a DID URI as input and returns a {@link DidResolutionResult} object.
136
+ *
137
+ * @property {string} methodName - The name of the DID method.
138
+ * @method resolve - Asynchronous method to resolve a DID URI. Takes the DID URI and optional resolution options.
139
+ */
140
+ export interface DidMethodResolver {
141
+ /**
142
+ * The name of the DID method.
143
+ *
144
+ * For example, in the DID `did:example:123456`, "example" would be the method name.
145
+ */
146
+ methodName: string;
147
+
148
+ new (): DidMethod;
149
+
150
+ /**
151
+ * Resolves a DID URI.
152
+ *
153
+ * This function should resolve the DID URI in accordance with the DID method specification being
154
+ * implemented, using the provided `options`.
155
+ *
156
+ * @param didUri - The DID URI to be resolved.
157
+ * @param options - Optional. The options used for resolving the DID.
158
+ * @returns A {@link DidResolutionResult} object containing the DID document and metadata or an error.
159
+ */
160
+ resolve(didUri: string, options?: DidResolutionOptions): Promise<DidResolutionResult>;
161
+ }
162
+
163
+ /**
164
+ * Represents the result of a Decentralized Identifier (DID) registration operation.
165
+ *
166
+ * This type encapsulates the complete outcome of registering a DID, including the registration
167
+ * metadata, the DID document (if registration is successful), and metadata about the DID document.
168
+ */
169
+ export interface DidRegistrationResult {
170
+ /**
171
+ * The DID document resulting from the registration process, if successful.
172
+ *
173
+ * If the registration operation was successful, this MUST contain a DID document
174
+ * corresponding to the DID. If the registration is unsuccessful, this value MUST be empty.
175
+ *
176
+ * @see {@link https://www.w3.org/TR/did-core/#dfn-diddocument | DID Core Specification, § DID Document}
177
+ */
178
+ didDocument: DidDocument | null;
179
+
180
+ /**
181
+ * Metadata about the DID Document.
182
+ *
183
+ * This structure contains information about the DID Document like creation and update timestamps,
184
+ * deactivation status, versioning information, and other details relevant to the DID Document.
185
+ *
186
+ * @see {@link https://www.w3.org/TR/did-core/#dfn-diddocumentmetadata | DID Core Specification, § DID Document Metadata}
187
+ */
188
+ didDocumentMetadata: DidMetadata;
189
+
190
+ /**
191
+ * A metadata structure consisting of values relating to the results of the DID registration
192
+ * process.
193
+ *
194
+ * This structure is REQUIRED, and in the case of an error in the registration process,
195
+ * this MUST NOT be empty. If the registration is not successful, this structure MUST contain an
196
+ * `error` property describing the error.
197
+ */
198
+ didRegistrationMetadata: DidRegistrationMetadata;
199
+ }
200
+
201
+ /**
202
+ * Represents metadata related to the result of a DID registration operation.
203
+ *
204
+ * This type includes fields that provide information about the outcome of a DID registration
205
+ * process (e.g., create, update, deactivate), including any errors that occurred.
206
+ *
207
+ * This metadata typically changes between invocations of the `create`, `update`, and `deactivate`
208
+ * functions, as it represents data about the registration process itself.
209
+ */
210
+ export type DidRegistrationMetadata = {
211
+ /**
212
+ * An error code indicating issues encountered during the DID registration process.
213
+ *
214
+ * While the DID Core specification does not define a specific set of error codes for the result
215
+ * returned by the `create`, `update`, or `deactivate` functions, it is recommended to use the
216
+ * error codes defined in the DID Specification Registries for
217
+ * {@link https://www.w3.org/TR/did-spec-registries/#error | DID Resolution Metadata }.
218
+ *
219
+ * Recommended error codes include:
220
+ * - `internalError`: An unexpected error occurred during DID registration process.
221
+ * - `invalidDid`: The provided DID is invalid.
222
+ * - `invalidDidDocument`: The provided DID document does not conform to valid syntax.
223
+ * - `invalidDidDocumentLength`: The byte length of the provided DID document does not match the expected value.
224
+ * - `invalidSignature`: Verification of a signature failed.
225
+ * - `methodNotSupported`: The DID method specified is not supported.
226
+ * - Custom error codes can also be provided as strings.
227
+ */
228
+ error?: string;
229
+
230
+ // Additional output metadata generated during DID registration.
231
+ [key: string]: any;
232
+ };
233
+
234
+ /**
235
+ * Base abstraction for all Decentralized Identifier (DID) method implementations.
236
+ *
237
+ * This base class serves as a foundational structure upon which specific DID methods
238
+ * can be implemented. Subclasses should furnish particular method and data models adherent
239
+ * to various DID methods, taking care to adhere to the
240
+ * {@link https://www.w3.org/TR/did-core/ | W3C DID Core specification} and the
241
+ * respective DID method specifications.
242
+ */
243
+ export class DidMethod {
244
+ /**
245
+ * MUST be implemented by all DID method implementations that extend {@link DidMethod}.
246
+ *
247
+ * Given the W3C DID Document of a DID, return the verification method that will be used for
248
+ * signing messages and credentials. If given, the `methodId` parameter is used to select the
249
+ * verification method. If not given, each DID method implementation will select a default
250
+ * verification method from the DID Document.
251
+ *
252
+ * @param _params - The parameters for the `getSigningMethod` operation.
253
+ * @param _params.didDocument - DID Document to get the verification method from.
254
+ * @param _params.methodId - ID of the verification method to use for signing.
255
+ * @returns Verification method to use for signing.
256
+ */
257
+ public static async getSigningMethod(_params: {
258
+ didDocument: DidDocument;
259
+ methodId?: string;
260
+ }): Promise<DidVerificationMethod | undefined> {
261
+ throw new Error(`Not implemented: Classes extending DidMethod must implement getSigningMethod()`);
262
+ }
263
+
264
+ /**
265
+ * MUST be implemented by all DID method implementations that extend {@link DidMethod}.
266
+ *
267
+ * Resolves a DID URI to a DID Document.
268
+ *
269
+ * @param _didUri - The DID to be resolved.
270
+ * @param _options - Optional parameters for resolving the DID.
271
+ * @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
272
+ */
273
+ public static async resolve(_didUri: string, _options?: DidResolutionOptions): Promise<DidResolutionResult> {
274
+ throw new Error(`Not implemented: Classes extending DidMethod must implement resolve()`);
275
+ }
276
+ }
@@ -0,0 +1,96 @@
1
+ import type { DidDocument, DidResolutionOptions, DidResolutionResult } from '../types/did-core.js';
2
+
3
+ import { Did } from '../did.js';
4
+ import { DidMethod } from './did-method.js';
5
+ import { EMPTY_DID_RESOLUTION_RESULT } from '../types/did-resolution.js';
6
+
7
+ /**
8
+ * The `DidWeb` class provides an implementation of the `did:web` DID method.
9
+ *
10
+ * Features:
11
+ * - DID Resolution: Resolve a `did:web` to its corresponding DID Document.
12
+ *
13
+ * @remarks
14
+ * The `did:web` method uses a web domain's existing reputation and aims to integrate decentralized
15
+ * identities with the existing web infrastructure to drive adoption. It leverages familiar web
16
+ * security models and domain ownership to provide accessible, interoperable digital identity
17
+ * management.
18
+ *
19
+ * @see {@link https://w3c-ccg.github.io/did-method-web/ | DID Web Specification}
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * // DID Resolution
24
+ * const resolutionResult = await DidWeb.resolve({ did: did.uri });
25
+ * ```
26
+ */
27
+ export class DidWeb extends DidMethod {
28
+
29
+ /**
30
+ * Name of the DID method, as defined in the DID Web specification.
31
+ */
32
+ public static methodName = 'web';
33
+
34
+ /**
35
+ * Resolves a `did:web` identifier to a DID Document.
36
+ *
37
+ * @param didUri - The DID to be resolved.
38
+ * @param _options - Optional parameters for resolving the DID. Unused by this DID method.
39
+ * @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
40
+ */
41
+ public static async resolve(didUri: string, _options?: DidResolutionOptions): Promise<DidResolutionResult> {
42
+ // Attempt to parse the DID URI.
43
+ const parsedDid = Did.parse(didUri);
44
+
45
+ // If parsing failed, the DID is invalid.
46
+ if (!parsedDid) {
47
+ return {
48
+ ...EMPTY_DID_RESOLUTION_RESULT,
49
+ didResolutionMetadata: { error: 'invalidDid' }
50
+ };
51
+ }
52
+
53
+ // If the DID method is not "web", return an error.
54
+ if (parsedDid.method !== DidWeb.methodName) {
55
+ return {
56
+ ...EMPTY_DID_RESOLUTION_RESULT,
57
+ didResolutionMetadata: { error: 'methodNotSupported' }
58
+ };
59
+ }
60
+
61
+ // Replace ":" with "/" in the identifier and prepend "https://" to obtain the fully qualified
62
+ // domain name and optional path.
63
+ let baseUrl = `https://${parsedDid.id.replace(/:/g, '/')}`;
64
+
65
+ // If the domain contains a percent encoded port value, decode the colon.
66
+ baseUrl = decodeURIComponent(baseUrl);
67
+
68
+ // Append the expected location of the DID document depending on whether a path was specified.
69
+ const didDocumentUrl = parsedDid.id.includes(':') ?
70
+ `${baseUrl}/did.json` :
71
+ `${baseUrl}/.well-known/did.json`;
72
+
73
+ try {
74
+ // Perform an HTTP GET request to obtain the DID document.
75
+ const response = await fetch(didDocumentUrl);
76
+
77
+ // If the response status code is not 200, return an error.
78
+ if (!response.ok) throw new Error('HTTP error status code returned');
79
+
80
+ // Parse the DID document.
81
+ const didDocument = await response.json() as DidDocument;
82
+
83
+ return {
84
+ ...EMPTY_DID_RESOLUTION_RESULT,
85
+ didDocument,
86
+ };
87
+
88
+ } catch (error: any) {
89
+ // If the DID document could not be retrieved, return an error.
90
+ return {
91
+ ...EMPTY_DID_RESOLUTION_RESULT,
92
+ didResolutionMetadata: { error: 'notFound' }
93
+ };
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,163 @@
1
+ import type { AbstractLevel } from 'abstract-level';
2
+
3
+ import ms from 'ms';
4
+ import { Level } from 'level';
5
+
6
+ import type { DidResolutionResult } from '../types/did-core.js';
7
+ import type { DidResolverCache } from '../types/did-resolution.js';
8
+
9
+ /**
10
+ * Configuration parameters for creating a LevelDB-based cache for DID resolution results.
11
+ *
12
+ * Allows customization of the underlying database instance, storage location, and cache
13
+ * time-to-live (TTL) settings.
14
+ */
15
+ export type DidResolverCacheLevelParams = {
16
+ /**
17
+ * Optional. An instance of `AbstractLevel` to use as the database. If not provided, a new
18
+ * LevelDB instance will be created at the specified `location`.
19
+ */
20
+ db?: AbstractLevel<string | Buffer | Uint8Array, string, string>;
21
+
22
+ /**
23
+ * Optional. The file system path or IndexedDB name where the LevelDB store will be created.
24
+ * Defaults to 'DATA/DID_RESOLVERCACHE' if not specified.
25
+ */
26
+ location?: string;
27
+
28
+ /**
29
+ * Optional. The time-to-live for cache entries, expressed as a string (e.g., '1h', '15m').
30
+ * Determines how long a cache entry should remain valid before being considered expired. Defaults
31
+ * to '15m' if not specified.
32
+ */
33
+ ttl?: string;
34
+ }
35
+
36
+ /**
37
+ * Encapsulates a DID resolution result along with its expiration information for caching purposes.
38
+ *
39
+ * This type is used internally by the `DidResolverCacheLevel` to store DID resolution results
40
+ * with an associated time-to-live (TTL) value. The TTL is represented in milliseconds and
41
+ * determines when the cached entry is considered expired and eligible for removal.
42
+ */
43
+ type CachedDidResolutionResult = {
44
+ /**
45
+ * The expiration time of the cache entry in milliseconds since the Unix epoch.
46
+ *
47
+ * This value is used to calculate whether the cached entry is still valid or has expired.
48
+ */
49
+ ttlMillis: number;
50
+
51
+ /**
52
+ * The DID resolution result being cached.
53
+ *
54
+ * This object contains the resolved DID document and associated metadata.
55
+ */
56
+ value: DidResolutionResult;
57
+ }
58
+
59
+ /**
60
+ * A Level-based cache implementation for storing and retrieving DID resolution results.
61
+ *
62
+ * This cache uses LevelDB for storage, allowing data persistence across process restarts or
63
+ * browser refreshes. It's suitable for both Node.js and browser environments.
64
+ *
65
+ * @remarks
66
+ * The LevelDB cache keeps data in memory for fast access and also writes to the filesystem in
67
+ * Node.js or indexedDB in browsers. Time-to-live (TTL) for cache entries is configurable.
68
+ *
69
+ * @example
70
+ * ```
71
+ * const cache = new DidResolverCacheLevel({ ttl: '15m' });
72
+ * ```
73
+ */
74
+ export class DidResolverCacheLevel implements DidResolverCache {
75
+ /** The underlying LevelDB store used for caching. */
76
+ protected cache;
77
+
78
+ /** The time-to-live for cache entries in milliseconds. */
79
+ protected ttl: number;
80
+
81
+ constructor({
82
+ db,
83
+ location = 'DATA/DID_RESOLVERCACHE',
84
+ ttl = '15m'
85
+ }: DidResolverCacheLevelParams = {}) {
86
+ this.cache = db ?? new Level<string, string>(location);
87
+ this.ttl = ms(ttl);
88
+ }
89
+
90
+ /**
91
+ * Retrieves a DID resolution result from the cache.
92
+ *
93
+ * If the cached item has exceeded its TTL, it's scheduled for deletion and undefined is returned.
94
+ *
95
+ * @param did - The DID string used as the key for retrieving the cached result.
96
+ * @returns The cached DID resolution result or undefined if not found or expired.
97
+ */
98
+ async get(did: string): Promise<DidResolutionResult | void> {
99
+ try {
100
+ const str = await this.cache.get(did);
101
+ const cachedDidResolutionResult: CachedDidResolutionResult = JSON.parse(str);
102
+
103
+ if (Date.now() >= cachedDidResolutionResult.ttlMillis) {
104
+ // defer deletion to be called in the next tick of the js event loop
105
+ this.cache.nextTick(() => this.cache.del(did));
106
+
107
+ return;
108
+ } else {
109
+ return cachedDidResolutionResult.value;
110
+ }
111
+
112
+ } catch(error: any) {
113
+ // Don't throw when a key wasn't found.
114
+ if (error.notFound) {
115
+ return;
116
+ }
117
+
118
+ throw error;
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Stores a DID resolution result in the cache with a TTL.
124
+ *
125
+ * @param did - The DID string used as the key for storing the result.
126
+ * @param value - The DID resolution result to be cached.
127
+ * @returns A promise that resolves when the operation is complete.
128
+ */
129
+ set(did: string, value: DidResolutionResult): Promise<void> {
130
+ const cachedDidResolutionResult: CachedDidResolutionResult = { ttlMillis: Date.now() + this.ttl, value };
131
+ const str = JSON.stringify(cachedDidResolutionResult);
132
+
133
+ return this.cache.put(did, str);
134
+ }
135
+
136
+ /**
137
+ * Deletes a DID resolution result from the cache.
138
+ *
139
+ * @param did - The DID string used as the key for deletion.
140
+ * @returns A promise that resolves when the operation is complete.
141
+ */
142
+ delete(did: string): Promise<void> {
143
+ return this.cache.del(did);
144
+ }
145
+
146
+ /**
147
+ * Clears all entries from the cache.
148
+ *
149
+ * @returns A promise that resolves when the operation is complete.
150
+ */
151
+ clear(): Promise<void> {
152
+ return this.cache.clear();
153
+ }
154
+
155
+ /**
156
+ * Closes the underlying LevelDB store.
157
+ *
158
+ * @returns A promise that resolves when the store is closed.
159
+ */
160
+ close(): Promise<void> {
161
+ return this.cache.close();
162
+ }
163
+ }
@@ -0,0 +1,26 @@
1
+ import type { DidResolutionResult } from '../types/did-core.js';
2
+ import type { DidResolverCache } from '../types/did-resolution.js';
3
+
4
+ /**
5
+ * No-op cache that is used as the default cache for did-resolver.
6
+ *
7
+ * The motivation behind using a no-op cache as the default stems from the desire to maximize the
8
+ * potential for this library to be used in as many JS runtimes as possible.
9
+ */
10
+ export const DidResolverCacheNoop: DidResolverCache = {
11
+ get: function (_key: string): Promise<DidResolutionResult> {
12
+ return null as any;
13
+ },
14
+ set: function (_key: string, _value: DidResolutionResult): Promise<void> {
15
+ return null as any;
16
+ },
17
+ delete: function (_key: string): Promise<void> {
18
+ return null as any;
19
+ },
20
+ clear: function (): Promise<void> {
21
+ return null as any;
22
+ },
23
+ close: function (): Promise<void> {
24
+ return null as any;
25
+ }
26
+ };